Example #1
0
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();
}
Example #3
0
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;	
}