c – 如何记录或重放在崩溃之前立即执行的行或指令

我经常在Windows上调试崩溃的C程序,我可以重现崩溃,但很难确定代码中的哪些指令序列导致崩溃(例如,另一个线程覆盖崩溃线程的内存).在这种情况下,即使是调用堆栈也无济于事.通常我会通过注释掉源代码的部分来缩小崩溃原因,但这非常繁琐.

有没有人知道Windows的工具可以报告或重放最后几个源代码行或在崩溃前立即在所有线程中执行的机器代码指令?即类似于gdb的反向调试功能或类似Mutek的BugTrapper(不再可用).我正在寻找一个发布且稳定的工具(我知道SoftwareVerify的’Bug Validator’和Hexray的IDA Pro 6.3 Trace Replayer,两者都在封闭测试程序中).

我已经尝试过的是WinDbg跟踪命令wt和ta @ $ra,但是这两个命令都有缺点,它们会在几秒钟后自动停止.我需要在崩溃发生之前运行的跟踪命令,并跟踪正在运行的程序的所有线程.

注意:我不是在寻找一个旨在解决特定问题的调试工具,如gflags,pageheap,Memory Validator,Purify等.我正在寻找已发布且稳定的工具来跟踪或重放指令级别.

最佳答案
如果你面对另一个线程覆盖崩溃线程的内存,使用gflags(GFlags and PageHeap )是很有用的.它不是告诉你在崩溃之前执行的几行,而是告诉你算法覆盖正确分配的内存块的确切位置.

您首先激活此类检查:

gflags / p /启用your_app.exe / full或
gflags / p /启用your_app.exe / full / backwards

检查您是否已正确激活
gflags / p

运行应用程序并收集转储文件

然后禁用gflags检查:

gflags / p /禁用your_app.exe

更新1

它不会立即检测到* p = 0等问题;其中p是无效指针
至少检测到一些问题.
例如:

#include <stdio.h>
int main(int argc, char *argv[])
{
  int *p = new int;
  printf("1) p=%p\n",p);
  *p = 1;
  delete p;
  printf("2) p=%p\n",p);
  *p = 2;
  printf("Done\n");
  return 0;    
}

当我运行gflags运行时,我得到一个转储文件,并正确识别问题:

STACK_TEXT:  
0018ff44 00401215 00000001 03e5dfb8 03dfdf48 mem_alloc_3!main+0x5b [c:\src\tests\test.cpp\mem_alloc\mem_alloc\mem_alloc.3.cpp @ 11]
0018ff88 75f8339a 7efde000 0018ffd4 77bb9ef2 mem_alloc_3!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 586]
0018ff94 77bb9ef2 7efde000 2558d82c 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77bb9ec5 004013bc 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 004013bc 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
     7:   printf("1) p=%p\n",p);
     8:   *p = 1;
     9:   delete p;
    10:   printf("2) p=%p\n",p);
>   11:   *p = 2;
    12:   printf("Done\n");
    13:   return 0;
    14: 
    15: }

更新2

来自@fmunkert的另一个例子:

#include <stdio.h>

int main()
{

        int *p = new int;  
        printf("1) p=%p\n",p);  
        *p = 1;  
        p++;
        printf("2) p=%p\n",p);
        *p =  2;   // <==== Illegal memory access
        printf("Done\n");  
        return 0;

}

gflags / p /启用mem_alloc.3.exe / full / unaligned

STACK_TEXT:  
0018ff44 00401205 00000001 0505ffbe 04ffdf44 mem_alloc_3!main+0x52 [c:\src\tests\test.cpp\mem_alloc\mem_alloc\mem_alloc.3.cpp @ 12]
0018ff88 75f8339a 7efde000 0018ffd4 77bb9ef2 mem_alloc_3!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 586]
0018ff94 77bb9ef2 7efde000 2577c47c 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77bb9ec5 004013ac 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 004013ac 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
     8:         printf("1) p=%p\n",p);  
     9:         *p = 1;  
    10:         p++;
    11:         printf("2) p=%p\n",p);
>   12:         *p =  2;   // <==== Illegal memory access
    13:         printf("Done\n");  
    14:         return 0;
    15: 
    16: }

不幸的是,/ unaligned选项可能导致程序无法正常工作(How to use Pageheap.exe):

Some programs make assumptions about 8-byte alignment and they stop
working correctly with the /unaligned parameter. Microsoft Internet
Explorer is one such program.

转载注明原文:c – 如何记录或重放在崩溃之前立即执行的行或指令 - 代码日志