如何使用SymLoadModuleEx加载PDB文件?

时间:2011-02-01 19:39:03

标签: c winapi pdb-files dbghelp

我正在尝试调用SymLoadModuleEx从PDB文件加载符号,然后使用SymFromAddr从该PDB中查找符号。但是,我无法弄清楚要为参数BaseOfDllDllSize传递什么 - 文档明确说明在加载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");
}

如何确定加载PDB文件时传入的BaseOfDllDllSize?有问题的PDB文件是不同程序可执行文件(不是DLL)的符号文件,只是为了参数,假设您无权访问生成PDB的原始EXE。

或者,是否有更好的方法从PDB文件中查找与给定地址对应的符号?

4 个答案:

答案 0 :(得分:10)

此处的dbghelp.dll和Sym*方法使用Debug Interface Access(DIA)SDK。1
DIA本身是基于COM的,比DbgHelp提供的更灵活。

具体来说,要加载已知的PDB并根据地址查找符号,您可以执行以下操作:

  1. CoC创建DIA数据源(请参阅“示例”部分here)。
  2. 使用IDiaDataSource::loadDataFromPdb加载特定的PDB(不需要DLL大小和基址)。
  3. 使用IDiaDataSource::openSession获取数据源的IDiaSession
  4. 根据您是否拥有绝对虚拟地址(VA)或相对虚拟地址(RVA),您可以分别使用findSymbolByVAfindSymbolByRVA来获取与IDiaSymbol关联的内容那个地址。
  5. 最后,您可以使用IDiaSymbol::get_name获取包含您指定地址的函数名称。
  6. 这些都不需要原始图像;只需要PDB。假设您使用的是Visual Studio,DIA的标题和库可以在(例如)下使用:
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\DIA SDK

答案 1 :(得分:3)

查看SymLoadPdb.cpp示例here

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我没有评论的权限,所以将在单独的答案中这样做。

  1. 是的,DbgHelp是DIA的包装器,仅限于静态库。 DIA静态链接到DbgHelp.dll。 DbgHelp直接调用Dia的COM类工厂(IClassFactory)实现绕过COM。我正在谈论6.1.7601.17514版本。所以DbgHelp.dll是自包含的(与symcrv.dll和srcsrv.dll结合使用)
  2. Dia COM对象随Visual Studio一起提供(与dbgeng.dll位置相同),因此解决方案我们无法在未安装VS的envs上工作(但您仍然可以尝试使用msdia120.dll作为指向它的私有程序集ActivateActCtx,但还需要部署依赖项(如果存在)
  3. DbgHelp是紧凑型的,建议Microsoft通过您的应用程序分发私有副本。 See "The redistribution policies for these included DLLs were specifically designed to make it as easy as possible for people to include these files in their own packages and release"

  4. 我没有找到使用DIA接口下载PDB文件的方法。 Sym API允许这样做。它委托调用SymSrv.dll。

  5. 所以原始问题仍然存在。