【发布时间】:2017-02-05 14:12:57
【问题描述】:
我一直在编写代码以尝试监视堆栈跟踪,并想尝试使用调试寄存器和矢量异常处理(对于 x86)。我制作了一个示例程序,它将输出访问当前返回地址的任何地址。如果在调用的函数中发生堆栈跟踪,则此方法有效。如果没有(注释掉读取返回地址的代码),则在返回指令上触发异常。从这里开始,我的异常处理程序没有被调用,程序抛出另一个异常,然后以 stackhash 错误终止。有没有办法让它在发生堆栈跟踪时捕获它,但如果没有发生堆栈跟踪,也不会在返回时崩溃?
这是我为 Visual Studio 2012 (C, x86) 编写的测试程序的代码
#include <Windows.h>
#include <stdio.h>
DWORD WINAPI myFunction(void);
void myFunction2(void);
DWORD WINAPI ExceptionHandler(EXCEPTION_POINTERS *pExceptionInfo);
int main()
{
HANDLE thread = GetCurrentThread();
static CONTEXT context;
AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)ExceptionHandler);
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(thread, &context);
context.Dr6 = 0;
context.Dr7 = 0;
context.Dr7 |= (3 << 16); //set bits 16-17 to 1 - break read/write
context.Dr7 |= (3 << 18); //set bits 18-19 to 1 - size = 4
context.Dr7 |= 0x101; //enable local hardware breakpoint on dr0
context.Dr7 |= 1 << 13;
_asm {
push offset label //push return address
lea eax, [esp]
mov context.Dr0, esp
}
SetThreadContext(thread, &context);
__asm
{
jmp myFunction // "call" myFunction
label:
}
printf("Return from my function\n");
getchar();
return 0;
}
// try windows api stack trace
DWORD WINAPI myFunction(void)
{
PVOID out[10];
CaptureStackBackTrace(0, 10, out, 0);
return 0;
}
// simple pull return address from esp
void __declspec(naked) myFunction2(void)
{
__asm{
mov eax, [esp]
ret
}
}
DWORD WINAPI ExceptionHandler(EXCEPTION_POINTERS *pExceptionInfo)
{
//Handle hwbp
if(pExceptionInfo->ExceptionRecord->ExceptionCode==EXCEPTION_SINGLE_STEP && //hardware breakpoints are SINGLE_STEP
(pExceptionInfo->ContextRecord->Dr6 & 1)) //check to see that instruction occured on Dr0
{
pExceptionInfo->ContextRecord->Dr7 &= 0xfffffffe; // disable Dr0
printf("Hardware breakpoint triggered at %08Xh\n", pExceptionInfo->ExceptionRecord->ExceptionAddress);
return EXCEPTION_CONTINUE_EXECUTION;
}
printf("Other exception\n");
return EXCEPTION_CONTINUE_SEARCH;
}
【问题讨论】:
-
首先您必须在
ExceptionHandler中设置pExceptionInfo->ContextRecord->ContextFlags |= CONTEXT_DEBUG_REGISTERS;,否则您的所有修改都会丢失