调试:有没有办法在C ++调用堆栈中识别导出的DLL函数

时间:2017-06-27 13:02:45

标签: c++ windows visual-c++ windbg visual-studio-debugging

有没有办法预测/计算模块内存中函数的位置?

*叹气* 你要告诉我的第一件事是:你必须有符号才能让事情顺利进行。我知道。 (哦!我知道!)这不是我的选择,所以我希望充分利用我所拥有的。我不是试图获取局部变量或任何东西的值(这需要熟悉编译器优化等)。我只想知道我们所处的DLL功能。

我从崩溃的进程中获得了内存转储。该过程加载了许多DLL,每个DLL都有一些导出的函数。进程中的一个线程在此DLL的“内部”调用堆栈中有一些项目。 Visual Studio调试器将它们报告为(更改名称以保护无辜的):

msvcr120.dll!abort() Line 90     
msvcr120.dll!_XcptFilter(unsigned long xcptnum, _EXCEPTION_POINTERS * pxcptinfoptrs) Line 366    
MyProcess.exe!016c9a9a()     
[Frames below may be incorrect and/or missing, no symbols loaded for Mach4GUI.exe]   
[External Code]  
MyProcess.exe!016ca390()     
[External Code]  
ExtLib01.dll!6eb1f75c()  
ExtLib01.dll!6eb95991()  
ExtLib01.dll!6e658979()  
ExtLib01.dll!6e653bab()  
ExtLib01.dll!6e66d5dd()  
[External Code]  

DLL不是为调试而构建的,我没有.PDB或其他符号源。

Visual Studio报告了有关DLL模块的信息:

Name            Path                     Address
----            ----                     -------
ExtLib01.dll    C:\MyProj\ExtLib01.dll   6E5E0000-6FE8800

当然,DLL有一些导出的函数(由dumpbin /exports ExtLib01.dll报告),如:

    ordinal hint RVA      name

          1    0 0009CE30 LibFunc1@16
          2    1 0009CDF0 LibFunc2@4
          3    2 0009CE60 LibFunc3@4
...
        482  1E1 0010FB40 LibFunc482
        483  1E2 0010FBD0 LibFunc483
        484  1E3 0010FAC0 LibFunc484

不知道更好,似乎这里可能有足够的信息来确定调用堆栈中的函数(如果返回地址是“其中一个DLL函数内”)。

对调用堆栈中的第一项0x6eb1f75c-0x6E5E0000进行一些简单的算术,会在内存中的ExtLib01.dll“模块”中产生一个偏移:+0x0053f75c,但这根本不对应DLL导出中列出的相对虚拟地址。

因此,Visual Studio只告诉我调用堆栈中的模块名称和地址(在该模块内)。有人可能会认为这是因为没有更多信息。我使用微软产品的经验表明他们可能没有实现这样的功能 - 虽然在他们的旗舰开发工具的情况下,肯定他们会努力使其有用。

更令人困惑的是,WinDbg告诉我有关同一线程的调用堆栈的不同内容。

# ChildEBP RetAddr  
00 0022cdb8 7740171a ntdll!NtWaitForMultipleObjects+0x15
01 0022ce54 76c519fc KERNELBASE!WaitForMultipleObjectsEx+0x100
02 0022ce9c 76c541d8 kernel32!WaitForMultipleObjectsExImplementation+0xe0
03 0022ceb8 76c780bc kernel32!WaitForMultipleObjects+0x18
04 0022cf24 76c77f7b kernel32!WerpReportFaultInternal+0x186
05 0022cf38 76c77870 kernel32!WerpReportFault+0x70
06 0022cf48 76c777ef kernel32!BasepReportFault+0x20
07 0022cfd4 74fb4820 kernel32!UnhandledExceptionFilter+0x1af
08 0022cfe0 74fb4611 msvcr120!__crtUnhandledException+0x14 [f:\dd\vctools\crt\crtw32\misc\winapisupp.c @ 259] 
09 0022d318 74fb7676 msvcr120!_call_reportfault+0xfe [f:\dd\vctools\crt\crtw32\misc\invarg.c @ 201] 
0a 0022d328 74fb4e38 msvcr120!abort+0x38 [f:\dd\vctools\crt\crtw32\misc\abort.c @ 90] 
0b 0022d340 016c9a9a msvcr120!_XcptFilter+0x14b [f:\dd\vctools\crt\crtw32\misc\winxfltr.c @ 366] 
WARNING: Stack unwind information not available. Following frames may be wrong.
0c 0022f8c8 76c5336a MyProcess!SomeSymbol+0xa0d71a
0d 0022f8d4 77b39902 kernel32!BaseThreadInitThunk+0xe
0e 0022f914 77b398d5 ntdll!__RtlUserThreadStart+0x70
0f 0022f92c 00000000 ntdll!_RtlUserThreadStart+0x1b

我或许可以理解列表顶部的一些项目(UnhandledExceptionFilter以上的所有内容,其中Windows错误报告正在执行其操作,捕获内存转储等),但为什么之间存在差异两个调用堆栈?我看到两者都报道“以下帧可能是错误的”。 此信息是否完全不可靠?可从现有信息中了解或辨别哪些信息?

从可用信息中可以看出调用堆栈中的项目是什么?

是否可以知道加载的DLL中的函数在正在运行的进程的内存中的位置?

如果有帮助,我愿意使用WinDbg。我愿意在Visual Studio的NuGet控制台中使用PowerShell。我不是不愿意做一些工作,但我不知道是否有可能知道这些DLL功能。

注意:我意识到答案很可能是,“不。这是不可能的。”我正在寻找一个很好的答案,一个解释(或引用一些权威的来源和解释)关于如何加载DLL及其函数调用以及为什么内存转储不包含足够的信息来找出哪里任何给定的函数在内存中“启动”。

0 个答案:

没有答案