Как вы используете SymLoadModuleEx для загрузки файла PDB? - PullRequest
8 голосов
/ 01 февраля 2011

Я пытаюсь вызвать SymLoadModuleEx, чтобы загрузить символы из файла PDB, а затем использовать SymFromAddr, чтобы найти символы из этой PDB.Однако я не могу понять, что передать для параметров BaseOfDll и DllSize - в документации явно сказано, что при загрузке файла PDB эти параметры не могут быть равны 0, и действительно попытка передать 0 приводит кс ошибкой ERROR_INVALID_PARAMETER.

Вот как выглядит мой код:

SymSetOptions(SYMOPT_LOAD_LINES);
HANDLE hprocess = GetCurrentProcess();
if (!SymInitialize(hprocess, NULL, FALSE))
    die("SymInitialize");

if(SymLoadModuleEx(hprocess, NULL, "full path to some PDB file.pdb", NULL,
                   0,  // What to pass here?
                   0,  // What to pass here?
                   NULL, 0) == 0)
{
    die("SymLoadModuleEx");
}

Как выяснить, что BaseOfDll и DllSize передать при загрузке файла PDB?Рассматриваемый файл PDB является файлом символов для другого исполняемого файла программы (не DLL), и просто ради аргумента предположим, что у вас нет доступа к исходному EXE, из которого была сгенерирована PDB.

В качестве альтернативы, есть ли лучший способ поиска символов, соответствующих данному адресу, из файла PDB?

Ответы [ 4 ]

10 голосов
/ 02 февраля 2011

dbghelp.dll и методы Sym* здесь используют Доступ к интерфейсу отладки (DIA) SDK. 1
Само DIA являетсяОснованный на COM и гораздо более гибкий, чем предлагает DbgHelp.

В частности, для загрузки известной PDB и поиска символа на основе адреса вы можете сделать следующее:

  1. CoCreateисточник данных DIA (см. раздел «Пример» здесь ).
  2. Используйте IDiaDataSource::loadDataFromPdb для загрузки конкретной PDB (размер DLL и базовый адрес не нужны).
  3. Используйте IDiaDataSource::openSession, чтобы получить IDiaSession для вашего источника данных.
  4. В зависимости от наличия абсолютного виртуального адреса(VA) или относительный виртуальный адрес (RVA), вы можете использовать findSymbolByVA или findSymbolByRVA соответственно, чтобы получить IDiaSymbol, связанный сэтот адрес.
  5. Наконец, вы можете использовать IDiaSymbol::get_name, чтобы получить имя функции, содержащее указанный вами адрес.

Ничего из этого не требуеторигинальное изображение;требуется только PDB.Предполагая, что вы используете Visual Studio, заголовки и библиотеки для DIA доступны в (например):
C:\Program Files (x86)\Microsoft Visual Studio 10.0\DIA SDK.

3 голосов
/ 02 февраля 2011

Посмотрите на образец SymLoadPdb.cpp здесь .

0 голосов
/ 15 декабря 2015

У меня нет разрешений для комментариев, поэтому я сделаю это в отдельном ответе.

  1. Да, DbgHelp - оболочка для DIA, только с точки зрения статической библиотеки. DIA статически связана с DbgHelp.dll. DbgHelp напрямую вызывает реализацию фабрики классов COM (IClassFactory) Dia, минуя COM. Я говорю о версии 6.1.7601.17514. Таким образом, DbgHelp.dll является автономным (в сочетании с symcrv.dll и srcsrv.dll)
  2. Dia COM-объекты поставляются с Visual Studio (в том же месте, что и dbgeng.dll), поэтому мы не работаем с envs, где VS не установлен (но вы все равно можете попытаться использовать msdia120.dll как частную сборку, указывая на нее через ActivateActCtx , но также необходимо развернуть зависимости, если они присутствуют)
  3. DbgHelp компактен и рекомендуется для распространения личных копий вместе с приложением от Microsoft. См. «Политики перераспределения для этих включенных библиотек DLL были специально разработаны для того, чтобы люди могли как можно проще включать эти файлы в свои собственные пакеты и выпускать»

  4. Я не нашел способа загрузки файлов PDB с использованием интерфейсов DIA. Sym API позволяет это. он делегирует вызовы SymSrv.dll.

Итак, оригинальный вопрос все еще актуален.

0 голосов
/ 19 мая 2014

Образец Dia2Dump хорошо работает для меня при преобразовании относительного виртуального адреса (адрес загрузки eip-программы) в pdb для неразрешенных указателей функций.Вот как я пытаюсь:

    DWORD64  dwAddress = _wcstoui64(argv[i], NULL, 16);
    DWORD64 dwRVA  = dwAddress - dwLoadAddress;
    long displacement = 0;
    IDiaSymbol* pFunc = 0;
    error = (DWORD)g_pDiaSession->findSymbolByRVAEx(dwRVA, SymTagFunction, &pFunc, &displacement );

    if (!error && pFunc)
    {
        BSTR bstrName;

        if (pFunc->get_name(&bstrName) != S_OK) {
            wprintf(L"(???)\n\n");
        }

        else {
            wprintf(L"%s \n\n", bstrName);
            if (displacement)
                wprintf(L"+ 0x%x \n\n", displacement);
            else
                wprintf(L" \n\n");
            SysFreeString(bstrName);
        }
    }

Например: Функция: [00447B60] [0001: 00446B60] ServerConfig :: getSSLConfig (public: struct ssl_config __cdecl ServerConfig :: getSSLConfig (void) __ptr64)

Здесь RVA - 00447B60 [eip - адрес загрузки процесса], сегмент - 0001, смещение - 00446B60

.
...