SymEnumSymbols возвращает ERROR_SUCCESS, но не дает результатов

Я пытаюсь перечислить символы из DLL, которую я загрузил. Для тех, кто заинтересован, это часть CPPCoverage проект, и для некоторых функций мне нужны данные символов.

Разбивка проблемы

Когда процесс запускается или загружается DLL, необходимо перечислить символы для некоторых запланированных новых функций.

В основном, процесс создан, и dbghelp используется для получения информации о символах. Далее символы повторяются с помощью SymEnumSymbols, Есть два момента, когда это происходит:

  1. Когда процесс запущен (CREATE_PROCESS_DEBUG_EVENT)
  2. Когда 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
}

4

Решение

Брр, довольно тупик. Я получил репродукцию для этого в VS2017, используя простой целевой исполняемый файл, созданный из шаблона проекта консоли Win32. Ничто из того, что я пробовал, не могло убедить SymEnumSymbols () перечислить любые символы. Затем я расширил код, также перехватывая уведомление LOAD_DLL_DEBUG_EVENT:

if (debugEvent.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) {
auto base = SymLoadModule64(pi.hProcess, debugEvent.u.LoadDll.hFile, NULL, NULL, NULL, 0);
if (!base) {
auto err = GetLastError();
std::cout << err << std::endl;
}
else {
CloseHandle(debugEvent.u.LoadDll.hFile);
SymEnumSymbols(pi.hProcess, base, NULL, EnumerateSymbols, nullptr);
}
}

Наряду с правильной настройкой пути поиска символов в SymInitialize (), он работал нормально и правильно перечислял символы в ntdll.dll и т. Д.

Заключение: что-то не так с файлом PDB

Это окупилось. Microsoft занимается созданием файлов PDB, начиная с VS2015. Они добавили / DEBUG: опция FASTLINK. Обратите внимание, что связанные документы вводят в заблуждение, это также по умолчанию в VS2015. Полученный файл PDB не может быть правильно перечислен версией операционной системы DbgHelp.dll. Код GetLastError () вводил в заблуждение, и я потратил на него слишком много времени, я думаю, он просто указывает на то, что «я ничего не перечислил». Обратите внимание, как этот код задокументирован для других функций API DbgHelp, таких как SymSetContext и SymLoadModuleEx.

В VS2015 используйте Project> Properties> Linker> Debug> Generate Debug Info = «Оптимизировать для отладки (/ DEBUG)».

В VS2017 используйте «Проект»> «Свойства»> «Линкер»> «Отладка»> «Создать информацию об отладке» = «Создать информацию об отладке, оптимизированную для совместного использования и публикации (/ DEBUG: FULL)».

Подчеркивая, что эти настройки важны для целевого проекта, а не для проекта отладчика. В идеале должна быть версия DbgHelp.dll, которая также может считывать отладочную информацию из версии fastlink PDB. Я не мог найти один, те, которые шли вместе с SDK 8.1 и SDK 10, не решили проблему. Еще один случай, когда группы DevDiv и Windows не работают вместе.

3

Другие решения

После комментария от @SimonMournier я провел много других тестов. В конце концов я смог выяснить, в чем здесь проблема. Как оказалось, флаг компоновщика /DEBUG:FastLink в Visual Studio на самом деле вызывает проблему.

После некоторого google’ing я нашел это уведомление на форумах сообщества: https://developercommunity.visualstudio.com/content/problem/4631/dia-sdk-still-doesnt-support-debugfastlink.html

[…] Команда отладчиков Windows была проинформирована о создании нового dbghelp.dll со статическими библиотеками VS 2017 PDB / DIA, а следующий публичный выпуск Windows SDK (или наборы отладчиков) будет содержать dbghelp.dll, который может работать с быстрые ссылки PDB. Последний предварительный выпуск VS 2017 установит новый dbghelp.dll в установочном каталоге VS, который работает с PDB fastlink.

Короче говоря, он просто не будет работать с Visual Studio 2015, потому что DIA просто не поддерживает его. Когда мы обновляемся до VS2017, это будет автоматически исправлено. Также при связывании с /DEBUG , все будет хорошо.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector