C++怎么实现java中的Exception.printStackTrace

C++语言 码拜 9年前 (2016-04-03) 1869次浏览
就是抛出异常的时候将调用栈堆记录下来以保证能快速找到出错的原因,像调试器就都用这样的功能
解决方案

10

http://www.codeproject.com搜“stack trace”

10

出错时先转储 各个寄存器的值,   加载的其他 so 的基地址,   再按需要转储当前堆栈 数据, 一般转储个 256K 就够了,  按这样的格式输出
00 01 02 03   04 05 06 07   08 09 0A 0B  0C 0D 0E 0F     aaaaaaaaaaaa
32位程序:
0x03020100
0x07060504
0x0B0A0908
0x0F0E0D0C
64位程序:
0x0706050403020100
0x0F0E0D0C0B0A0908
拿着这数据, 根据 mapfile, 人肉做 backtrace 没问题的, 就是累点,  在 mapfile 里查找像  0x0B0A0908  地址对应什么函数, 偏移多少,   顺便还能恢复出出错时各个参数, 变量的值,  苦逼的嵌入式程序员对这应该相当熟悉了( 实际上大部分时候就看看 ip 位置, 有当前出错的函数位置, 连猜带蒙就够了).
假如要稍微简单点, 编译的时候就设置不要省略栈帧,   M$VC 加编译选项 /Oy-  ,   gcc不要加编译选项 -fomit-frame-pointer , 假如是 arm 程序,  再加上 -mapcs-frame 编译选项 …  然后假如是用 glibc , 你就可以直接调用 backtrace …  假如不是 glibc, 本人写个 backtrace 也很简单说, 例如 x86 下,
;
; — default stack size : 256K  —
;
; int __fastcall _x_peer_backtrace(void* [], int)
%ifndef backtrace_stack_size
%define backtrace_stack_size 0x40000
%endif
x4c_asm_i386_proc _x_peer_backtrace , 8
push edi
push ebx
push ebp
xor  eax   , eax
test edx   , edx
jle short backtrace_done ; if( n <= 0 ) return 0
mov  ebx   , [esp+12] ;
mov  [ecx] , ebx ;
lea  edi   , [esp+backtrace_stack_size] ; end of stack
get_next_frame:
lea  ecx   , [ecx+4]
lea  eax   , [eax+1]
add  edx   , -1
jz  short backtrace_done ;
test ebp   , 3
jnz short backtrace_done ; if( !dword_aligned( stack_frame) ) break
cmp  ebp   , esp ; if( stack_frame < stack ) break
jb  short backtrace_done
cmp  ebp   , edi ; if( stack_frame > stack + backtrace_stack_size ) break
ja  short backtrace_done
mov  ebx   , [ebp+4]
or  ebx   , ebx
jz  short backtrace_done
mov  [ecx] , ebx
mov  ebp   , [ebp+0] ;
jmp short get_next_frame
backtrace_done:
pop  ebp
pop  ebx
pop  edi
ret
arm 下
struct stackframe {
struct stackframe *fp;
void* sp;
void* lr;
};
int _x_peer_backtrace ( void* syms[] , int size )
{
int i;
struct stackframe *tail = NULL;
void   *sptr ;
if( size <= 0 )
return 0;
__asm__ __volatile__ (
“mov %0 , fp\n\t”
“mov %1 , sp\n\t”
: “=&r”(tail) , “=&r”(sptr) );
if( NULL == tail– )
return 0;
for( i = 0; tail && i<size; )
{
if( (void*)tail < sptr ||
(void*)tail > (void*)( (unsigned char*)sptr + BACKTRACESTACKSIZE ) )
break;
syms[i++] = tail->lr;
tail = tail->fp;
if( NULL == tail )
break;
–tail ;
}
return i;
}

30

BOOL WINAPI StackWalk64(
__in      DWORD MachineType,
__in      HANDLE hProcess,
__in      HANDLE hThread,
__inout   LPSTACKFRAME64 StackFrame,
__inout   PVOID ContextRecord,
__in_opt  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
__in_opt  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
__in_opt  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
__in_opt  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
获取全部调用栈的信息

10

而且得在unwind之前用API导出调用栈,然后得配合调试信息解析出函数名。不同的平台上方法也不一样。这样生成stack trace代价要比Java那种的高得多。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C++怎么实现java中的Exception.printStackTrace
喜欢 (0)
[1034331897@qq.com]
分享 (0)