我正在尝试从已加载的 DLL 中枚举符号。对于那些感兴趣的人,这是CPPCoverage 项目的一部分,对于某些功能,我需要符号数据。
问题的分解
当进程启动或加载 DLL 时,需要为一些已计划的新功能枚举符号。
基本上,创建了一个进程,dbghelp
用于获取符号信息。接下来,使用 迭代符号SymEnumSymbols
。发生这种情况有两个时刻:
- 进程启动时 (
CREATE_PROCESS_DEBUG_EVENT
) - 加载 DLL 时 (
LOAD_DLL_DEBUG_EVENT
)
在 (2) 期间一切正常。但是,在 (1) 期间不能枚举符号。
行为是一切正常,直到SymEnumSymbols
调用。返回值告诉我有一个错误,但GetLastError
返回成功。此外,不会调用回调函数。
更奇怪的是,调用SymGetSymFromName
确实有效。
最小测试用例
static BOOL CALLBACK EnumerateSymbols(
PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
{
std::cout << "Symbol: " << pSymInfo->Name << std::endl;
return TRUE;
}
void Test()
{
SymSetOptions(SYMOPT_LOAD_ANYTHING);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
auto str = "FullPathToSomeExeWithPDB.exe";
auto result = CreateProcess(str, NULL, NULL, NULL, FALSE,
DEBUG_PROCESS, NULL, NULL, &si, &pi);
if (result == 0)
{
auto err = GetLastError();
std::cout << "Error running process: " << err << std::endl;
return;
}
if (!SymInitialize(pi.hProcess, NULL, FALSE))
{
auto err = GetLastError();
std::cout << "Symbol initialization failed: " << err << std::endl;
return;
}
bool first = false;
DEBUG_EVENT debugEvent = { 0 };
while (!first)
{
if (!WaitForDebugEvent(&debugEvent, INFINITE))
{
auto err = GetLastError();
std::cout << "Wait for debug event failed: " << err << std::endl;
return;
}
if (debugEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
{
auto dllBase = SymLoadModuleEx(
pi.hProcess,
debugEvent.u.CreateProcessInfo.hFile,
str,
NULL,
reinterpret_cast<DWORD64>(debugEvent.u.CreateProcessInfo.lpBaseOfImage),
0,
NULL,
0);
if (!dllBase)
{
auto err = GetLastError();
std::cout << "Loading the module failed: " << err << std::endl;
return;
}
if (!SymEnumSymbols(pi.hProcess, dllBase, NULL, EnumerateSymbols, nullptr))
{
auto err = GetLastError();
std::cout << "Error: " << err << std::endl;
}
first = true;
}
}
// cleanup code is omitted
}