用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)

Command line client to resolve win64 stack trace (with access to a symbol server)

我有大量 windows 堆栈跟踪,格式如下(在文本文件中):

MyApplication 0x00000000678d0000 + 1093618 
MyApplication 0x00000000678d0000 + 106e1fd 
MyApplication 0x00000000678d0000 + 1089314 
MyApplication 0x00000000678d0000 + 149554e 
MyApplication 0x00000000678d0000 + 3a5e57 
MyApplication 0x00000000678d0000 + 1cec589 
MyApplication 0x00000000678d0000 + 149fd17 
MyApplication 0x00000000678d0000 + c7e557 
KERNEL32 0x00000000152e0000 + 17bd4 
ntdll 0x00000000153e0000 + 6ced1

而且我还设置了一个带有(压缩的)符号信息的符号服务器。

有没有办法让一些脚本(可能利用 windbg 的一些命令行命令?)将地址转换为源代码行?我从未在 Visual Studio 之外使用过堆栈跟踪,因此非常感谢任何指向正确方向的指针。

假设您的 MyApplication.exe

有正确的 pdb

可以使用windbg包自带的dbh.exe

:\>dbh dumpfuncs.exe laddr 1001000

   file : c:\users\xx\source\repos\dumpfuncs\dumpfuncs.cpp
   line : 5
   addr :  1001000
    key : 00000000
disp : 0

:\>tail -n+5 dumpfuncs.cpp |head -1
__declspec ( noinline ) LPSTR CmdLn(void) {

:\>dbh dumpfuncs.exe m 1001000

 index            address     name
   148            1001000 :   CmdLn

:\>

下面的代码应该类似于 Jesper Juhl 关于 addr2line 的评论

#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
#include <fstream>
#include <string>
#pragma comment(lib,"dbghelp.lib")
int main(int argc,char* argv[]){
    if( argc != 3) {
        printf("usage %s \"Module/Path\" \"Offset as hex 0x1010\"\n",argv[0]);
        return FALSE;
    }
    DWORD64 offset = _strtoui64(argv[2], NULL, 16);
    SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS |SYMOPT_LOAD_LINES);
    HANDLE hProcess = GetCurrentProcess();
    if (!SymInitialize(hProcess, NULL, FALSE))    {
        printf("SymInitialize returned error : %u\n", GetLastError());
        return FALSE;
    }    
    DWORD64 ModBase = SymLoadModuleEx (hProcess,NULL, argv[1], NULL,0,0,NULL,0);
    if( (ModBase == 0) && (GetLastError() != ERROR_SUCCESS) )    {
        printf("SymLoadModuleEx returned error : %u\n", GetLastError());
        return FALSE;        
    }
    DWORD64 SymAddr = ModBase + offset;
    printf("Module %s Loaded At 0x%I64x SymAddr = 0x%I64x\n",argv[1],ModBase ,SymAddr);
    IMAGEHLP_LINE64 line ={0};
    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
    DWORD dwDisplacement =0;
    if(!SymGetLineFromAddr64(hProcess, SymAddr, &dwDisplacement, &line)){
        printf("SymGetLineFromAddr64 returned error : %u\n", GetLastError());
        return FALSE;
    }
    printf("Source= %s # %u @ %I64x\n",line.FileName,line.LineNumber,line.Address);
    std::ifstream fs;
    fs.open(line.FileName);
    if(fs.is_open()){
        std::string buff;
        unsigned  int lineno = 0;
        while (lineno != line.LineNumber && getline(fs, buff)){
            ++lineno;
        }
        printf("%s\n",buff.c_str());
        fs.close();
    }else{
        printf("cannot open %s\n",line.FileName);        
    }
}

编译并执行

:\>bld.bat AddrToLineWin

:\>cl /Zi /W4 /analyze /EHsc /nologo /Od AddrToLineWin.cpp /link /nologo /release
AddrToLineWin.cpp

:\>AddrToLineWin.exe ..\dumpfuncs\dumpfuncs.exe 0x1010
Module ..\dumpfuncs\dumpfuncs.exe Loaded At 0x400000 SymAddr = 0x401010
Source= c:\users\xx\source\repos\dumpfuncs\dumpfuncs.cpp # 8 @ 401010
__declspec ( noinline ) LPSTR FileName (void) {

:\>AddrToLineWin.exe ..\dumpfuncs\dumpfuncs.exe 0x1008
Module ..\dumpfuncs\dumpfuncs.exe Loaded At 0x400000 SymAddr = 0x401008
Source= c:\users\xx\source\repos\dumpfuncs\dumpfuncs.cpp # 6 @ 401003
    return GetCommandLineA();

尝试这样的事情:

ln MyApplication + 0n1093618 

请注意,对于十进制(非十六进制)值,请使用 0n 后跟数字。 如果您有符号,此命令将为您提供函数和源代码行号。

如果它是托管代码,它将无法工作。 您必须改用 SOS:

!ip2md MyApplication + 0n1093618