【问题标题】:How do you use SymLoadModuleEx to load a PDB file?如何使用 SymLoadModuleEx 加载 PDB 文件?
【发布时间】:2011-02-01 19:39:03
【问题描述】:

我正在尝试调用 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 文件中查找与给定地址对应的符号?

【问题讨论】:

    标签: c winapi pdb-files dbghelp


    【解决方案1】:

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

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

    1. 共同创建 DIA 数据源(参见“示例”部分 here)。
    2. 使用IDiaDataSource::loadDataFromPdb 加载特定的PDB(不需要DLL 大小和基地址)。
    3. 使用IDiaDataSource::openSession 为您的数据源获取IDiaSession
    4. 根据您拥有的是绝对虚拟地址 (VA) 还是相对虚拟地址 (RVA),您可以分别使用 findSymbolByVAfindSymbolByRVA 来获取与该地址关联的 IDiaSymbol
    5. 最后,您可以使用IDiaSymbol::get_name 获取包含您指定的地址的函数名。

    这些都不需要原始图像;只有 PDB 是必需的。假设您使用的是 Visual Studio,DIA 的标头和库位于(例如):
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\DIA SDK

    【讨论】:

      【解决方案2】:

      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】:

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

        1. 是的,DbgHelp 是 DIA 的包装器,仅在静态库方面。 DIA 静态链接到 DbgHelp.dll。 DbgHelp 绕过 COM 直接调用 Dia 的 COM 类工厂 (IClassFactory) 实现。我说的是 6.1.7601.17514 版本。所以 DbgHelp.dll 是自包含的(结合 symcrv.dll 和 srcsrv.dll)
        2. Dia COM 对象随 Visual Studio 一起提供(与 dbgeng.dll 位于同一位置),因此解决方案我们不适用于未安装 VS 的环境(但您仍然可以尝试使用 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。

        所以原始问题仍然存在。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-09
          • 2023-04-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多