【问题标题】:Using WinDbg, is it possible to highlight the source line in MFC source code with WinDbg command?使用 WinDbg,是否可以使用 WinDbg 命令突出显示 MFC 源代码中的源代码行?
【发布时间】:2019-09-19 14:45:29
【问题描述】:

背景:

有时,我的 MFC dApp 正在开发的程序中出现泄漏。 MFC 很好地将检测到的泄漏块转储到 Visual Studio 的输出窗格中,显示它们的 {block number} 和十六进制地址。一些泄漏没有源文件路径和行号,除了 fx strcore.cpp 等。这些泄漏的来源很难找到,需要更好的解决方案。

研究 WinDbg Preview 及其 Time Travel Debugging (TTD),我可以看到这是快速找到 MFC 硬漏洞的正确工具。

泄漏查找测试:

我创建了一个小型 MFC 程序并在其中放了一个漏洞:

void LeakInThread()
{
  int* intLeak = new int[ 500 ];
}

wchar* leak = new wchar[ 100 ];
std::thread t1( LeakInThread ); // added leak in thread
t1.join();   

节目制作:{274698} normal block at 0x000001AFA34D9790, 200 bytes long.

我使用 WinDbg 创建了一个 Trace 文件,Time Traveled 到最后以确保创建了泄漏,并使用 WinDbg commnd !heap -i x000001AFA34D9790 来定位发生错误的 TTD 块。这是输出:

0:000> !heap -i 0x00000180F42E3790 Detailed information for block entry 00000180f42e3790 Assumed heap : 0x0000000000000000 (Use !heap -i NewHeapHandle to change) Header content : 0xCDCDCDCD 0xCDCDCDCD Block flags : 0x1 LFH (busy ) Total block size : 0x0 units (0x0 bytes) Requested size : 0xffffec00 bytes (unused 0x1400 bytes) Subsegment : 0x25dac2f1e46abc2eUser blocks not available

问题:是否有 WinDbg 命令在 WinDbg 源代码窗格中显示文件和行号?

编辑1:

用这个查询命令做实验:

dx -g @$MemRes = @$cursession.TTD.Resources.HeapMemory

得到:

======================================================================================================================================
=           = ResourceId       = ResourceIdNew    = Size    = Function                   = ThreadId  = UniqueThreadId = Position     =
======================================================================================================================================
= [0x0]     - 0x180f4282870    - 0x0              - 0x4c    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - C819:58      =
= [0x1]     - 0x180f42b79d0    - 0x0              - 0x48    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - 5545:62      =
= [0x2]     - 0x180f4282870    - 0x0              - 0x0     - ntdll!RtlFreeHeap          - 0x59e4    - 0x2            - C827:13F     =
= [0x3]     - 0x180f42b32a0    - 0x0              - 0x6a    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - 2E1C:58      =
= [0x4]     - 0x180f744d330    - 0x0              - 0x24    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - 9609:4C      =
= [0x5]     - 0x180f74572e0    - 0x0              - 0x48    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - 960C:20D     =
= [0x6]     - 0x180f42b32a0    - 0x0              - 0x0     - ntdll!RtlFreeHeap          - 0x59e4    - 0x2            - 2E23:147     =
= [0x7]     - 0x180f42c1990    - 0x0              - 0x6a    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - FB23:58      =
= [0x8]     - 0x180f42d9fd0    - 0x0              - 0x0     - ntdll!RtlFreeHeap          - 0x59e4    - 0x2            - 12D1B:13F    =
= [0x9]     - 0x180f42c1990    - 0x0              - 0x0     - ntdll!RtlFreeHeap          - 0x59e4    - 0x2            - FB2A:147     =
= [0xa]     - 0x180f7453160    - 0x0              - 0x30    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - 9625:4C      =
= [0xb]     - 0x180f42c0810    - 0x0              - 0x6a    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - FB2E:58      =
= [0xc]     - 0x180f42b9160    - 0x0              - 0x0     - ntdll!RtlFreeHeap          - 0x59e4    - 0x2            - 2E25:4B      =
= [0xd]     - 0x180f42e9bd0    - 0x0              - 0x0     - ntdll!RtlFreeHeap          - 0x59e4    - 0x2            - 15481:13F    =
= [0xe]     - 0x180f42d9fd0    - 0x0              - 0x4c    - ntdll!RtlAllocateHeap      - 0x59e4    - 0x2            - 12D0D:58     =
= [...]

由于ResourceID 看起来类似于 MFC 输出地址,我使用此选择查询缩小了输出范围:

dx -g @$MemRes.Where(x => x.ResourceId == 0x00000180F42E3790)

但输出网格没有结果。

编辑2:

“如果泄漏发生在 MainFrame 线程中,源文件和行号也会显示。当泄漏发生在另一个衍生线程中时不会。”不是真的。但是确实会发生不指向其源和行号的泄漏。 MFC 调试器程序仍有可能缺少某些源路径定义,允许它找到源代码。需要更多的研究。

编辑3:

经过进一步审查,我的 MFC 程序产生的泄漏,即使在启动后没有按下任何键,每次运行时都有不同的数据地址。 (泄漏是在许多签到之前引入的,直到现在才被注意到)。这意味着我不能使用 WinDbg TTD 的 dx ... 命令迭代跟踪的帧,将数据地址与帧 LocalVariables Values 进行比较,因为每次程序运行时泄漏的数据地址都会不同,包括何时正在记录跟踪。但是,可以使用命令来确定程序结束时堆分配是否未完成。

【问题讨论】:

  • 你的意思是你有汇编列表中的地址并想找到与该地址对应的来源?如果是 .open -a {your Address Here} 应该将您分配到源代码行或使用 lsa 。在哪里 。表示当前的 rip/eip
  • 我尝试.open -a 0x180f42e3790 没有结果。查看堆栈帧中的 LocalVariables 我找到了leak 0x180f42e3790 : "췍췍췍췍췍췍췍췍췍췍췍췍췍췍췍췍췍???" wchar_t *,所以我知道该地址是一个有效的程序集列表值并且在 Trace 中。
  • 您的意思是您正在寻找与 new 运算符返回的内存地址相对应的源代码行,该操作符在幕后使用 heapalloc 或 virtualalloc?你不能得到它它是一个动态地址没有src行
  • 如果您需要跟踪句柄、对象、调试堆、页面堆等,那么您可能需要查看 gflags.exe 选项并启用标志以获取这些堆栈跟踪
  • 或分享您在说您制作了样本时被困在其中的垃圾箱

标签: debugging memory-leaks mfc windbg


【解决方案1】:

正如评论我不确定你在寻找什么,这些是你可以尝试的几个选项

1) 您可以更改.asm 选项以使反汇编列表显示行号和文件名

如下图

.asm

1:001> .asm
Assembly options: <default>
1:001> u .
vect!main [f:\src\vect\vect.cpp @ 9]:
00007ff6`e1d7efb0 4881ec98000000  sub     rsp,98h
00007ff6`e1d7efb7 48c7442460feffffff mov   qword ptr [rsp+60h],0FFFFFFFFFFFFFFFEh
00007ff6`e1d7efc0 488d4c2448      lea     rcx,[rsp+48h]
00007ff6`e1d7efc5 e8576dffff      call    vect!ILT+19740(??0?
00007ff6`e1d7efca 90              nop
00007ff6`e1d7efcb c744242001000000 mov     dword ptr [rsp+20h],1
00007ff6`e1d7efd3 eb0a            jmp     vect!main+0x2f (00007ff6`e1d7efdf)
00007ff6`e1d7efd5 8b442420        mov     eax,dword ptr [rsp+20h]
1:001> .asm source_line
Assembly options: source_line
1:001> u .
vect!main [f:\src\vect\vect.cpp @ 9]:
    9 00007ff6`e1d7efb0 4881ec98000000  sub     rsp,98h
    9 00007ff6`e1d7efb7 48c7442460feffffff mov   qword ptr [rsp+60h],0FFFFFFFFFFFFFFFEh
   10 00007ff6`e1d7efc0 488d4c2448      lea     rcx,[rsp+48h]
   10 00007ff6`e1d7efc5 e8576dffff      call    vect!ILT+19740(??0?
   10 00007ff6`e1d7efca 90              nop
   12 00007ff6`e1d7efcb c744242001000000 mov     dword ptr [rsp+20h],1
   12 00007ff6`e1d7efd3 eb0a            jmp     vect!main+0x2f (00007ff6`e1d7efdf)
   12 00007ff6`e1d7efd5 8b442420        mov     eax,dword ptr [rsp+20h]

或者你可以使用 .open -a 地址打开一个新的源窗口

例如

.open -a .

打开与当前 Rip/Eip 对应的源。 (dot ) 表示当前指令指针

或者你可以使用ls命令来

打印源代码行(使用lsp配置前后行数计数默认为5行pre 5行post)

1:001> lsa .
     5: 
     6: using namespace std; 
     7: 
     8: int main() 
>    9: { 
    10:     vector<int> g1; 
    11: 
    12:     for (int i = 1; i <= 5; i++) 
    13:         g1.push_back(i); 
    14: 

【讨论】:

  • 如果指令指针中的地址,.asm 和 .open 的地址参数都有效。源自我的 MFC 程序中的转储的内存泄漏地址是数据地址。因此,这些 WinDbg 命令没有用,因此不回答问题。正如我在原始帖子中指出的那样,遍历堆分配仍然是我认为可以解决此问题的唯一方法。
【解决方案2】:

为了识别 C++ 应用程序中泄漏的代码,我使用以下链接中提供的命令。 https://www.codeproject.com/Articles/31382/Memory-Leak-Detection-Using-Windbg 希望这可以帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-18
    • 2011-04-26
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    相关资源
    最近更新 更多