I'm attempting to enumerate symbols from a DLL that I have loaded. For those interested, this is part of the CPPCoverage project, and for some functionality I need symbol data.
Breakdown of the problem
When the process is started or a DLL is loaded, symbols need to be enumerated for some of the new functionality that has been planned.
Basically, a process is created, and dbghelp
is used to get symbol information. Next, symbols are iterated using SymEnumSymbols
. There are two moments when this happens:
- When the process is started (
CREATE_PROCESS_DEBUG_EVENT
) - When a DLL is loaded (
LOAD_DLL_DEBUG_EVENT
)
Everything works fine during (2). However, symbols cannot be enumerated during (1).
Behavior is that everything works fine, until the SymEnumSymbols
call. The return value tells me there's an error, but GetLastError
returns SUCCESS. Also, the callback function isn't called.
To make it even more weird, a call to SymGetSymFromName
does actually work.
Minimal test case
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
}