void GetBacktrace( const void **buf, size_t size, const BacktraceContext *ctx ) { InitializeBacktrace(); BacktraceContext CurrentCtx; if( ctx == NULL ) { ctx = &CurrentCtx; CurrentCtx.ip = NULL; CurrentCtx.bp = __builtin_frame_address(0); CurrentCtx.sp = __builtin_frame_address(0); CurrentCtx.pid = GetCurrentThreadId(); } do_backtrace( buf, size, ctx ); }
void CrashHandler::InitializeCrashHandler() { InitializeBacktrace(); }
void GetBacktrace( const void **buf, size_t size, const BacktraceContext *ctx ) { InitializeBacktrace(); if( g_StackPointer == 0 ) { buf[0] = BACKTRACE_METHOD_NOT_AVAILABLE; buf[1] = NULL; return; } BacktraceContext CurrentCtx; if( ctx == NULL ) { ctx = &CurrentCtx; CurrentCtx.ip = NULL; CurrentCtx.bp = __builtin_frame_address(0); CurrentCtx.sp = __builtin_frame_address(0); } mach_port_t self = mach_task_self(); vm_address_t stackPointer = 0; vm_prot_t protection = 0; vm_address_t start = 0; size_t i = 0; if( i < size-1 && ctx->ip ) buf[i++] = ctx->ip; if( GetRegionInfo(self, ctx->sp, stackPointer, protection) && protection == (VM_PROT_READ|VM_PROT_WRITE) ) { const void *p = *(const void **)ctx->sp; if( GetRegionInfo(self, p, start, protection) && (protection & (VM_PROT_READ|VM_PROT_EXECUTE)) == (VM_PROT_READ|VM_PROT_EXECUTE) && PointsToValidCall(start, p) && i < size-1 ) { buf[i++] = p; } } GetRegionInfo( self, ctx->sp, stackPointer, protection ); if( protection != PROT_RW ) { /* There isn't much we can do if this is the case. The stack should be read/write * and since it isn't, give up. */ buf[i] = NULL; return; } const Frame *frame = (Frame *)ctx->sp; while( i < size-1 ) { // Make sure this is on the stack if( !GetRegionInfo(self, frame, start, protection) || protection != PROT_RW ) break; if( (start != g_StackPointer && start != stackPointer) || uintptr_t(frame)-uintptr_t(start) < sizeof(Frame) ) break; /* The stack pointer is always 16 byte aligned _before_ the call. Thus a valid frame * should look like the follwoing. * | | * | Caller's frame | * -------------------- 16 byte boundary * | Linkage | This is return_address * - - - - - - - - - - * | Saved %ebp | This is link * - - - - - - - - - - * | Rest of | * | Callee's frame | * * Therefore, frame + 8 should be on a 16 byte boundary, the frame link should be * at a higher address, the link should be on the stack and it should be RW. The * return address should be EXE and point to a valid call (well, just after). */ if( (((uintptr_t)frame+8) & 0xF) != 0 ||// boundary frame->link <= frame || // the frame link goes up !GetRegionInfo(self, frame->link, start, protection) || (start != g_StackPointer && start != stackPointer) || // the link is on the stack protection != PROT_RW || // RW !GetRegionInfo(self, frame->return_address, start, protection) || protection != PROT_EXE || // EXE !PointsToValidCall(start, frame->return_address) )// follows a CALL { /* This is not a valid frame but we might be in code compiled with * -fomit-frame-pointer so look at each address on the stack that is * 4 bytes below a 16 byte boundary. */ if( (((uintptr_t)frame+4) & 0xF) == 0 ) { void *p = *(void **)frame; if( GetRegionInfo(self, p, start, protection) && protection == PROT_EXE && PointsToValidCall(start, p) ) { buf[i++] = p; } } frame = (Frame *)(intptr_t(frame)+4); continue; } // Valid. buf[i++] = frame->return_address; frame = frame->link; } buf[i] = NULL; }