⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 morebacktrace.c

📁 MPI stands for the Message Passing Interface. Written by the MPI Forum (a large committee comprising
💻 C
📖 第 1 页 / 共 4 页
字号:
		&& (context->arch != NULL)		&& (context->task != MACH_PORT_NULL)		&& (context->readBytes != NULL)		&& (context->sigTrampLowerBound != 0)		&& (context->sigTrampLowerBound < context->sigTrampUpperBound)		&& (context->stackBottom <= context->stackTop)		&& ((context->frameArrayCount == 0) || (context->frameArray != NULL))		&& (context->threadState != NULL);}static int ReadAddr(MoreBTContext *context, MoreBTAddr addr, MoreBTAddr *valuePtr)	// Reads an address (that is, a pointer) from the target task, 	// returning an error if the memory is unmapped.	//	// On entry, context will be a valid context (as determined by ValidateContext).	// On entry, addr can be any value.	// On entry, valuePtr must not be NULL.	// Returns an errno-style error code.	// On success, *valuePtr will be the value of the pointer stored at addr in 	// the target task.{	int			err;	MoreBTAddr	value;		assert(ValidateContext(context));	assert(valuePtr != NULL);		if (context->arch->is64Bit) {		// Read directly into value, and then swap all 8 bytes.				err = context->readBytes(context, addr, &value, sizeof(value));		if (err == 0) {			if (context->swapBytes) {				value = OSSwapInt64(value);			}		}	} else {		uint32_t	tmpAddr;				// Read into a temporary address, swap 4 bytes, then copy that 		// into value.  tmpAddr is unsigned, so we zero fill the top 		// 32 bits.				err = context->readBytes(context, addr, &tmpAddr, sizeof(tmpAddr));		if (err == 0) {			if (context->swapBytes) {				tmpAddr = OSSwapInt32(tmpAddr);			}			value = tmpAddr;		}	}	if (err == 0) {		*valuePtr = value;	}		return err;}static void AddFrame(MoreBTContext *context, MoreBTAddr pc, MoreBTAddr fp, MoreBTFlags flags)	// Adds a frame to the end of the output array with the 	// value specified by pc, fp, and flags.	//	// On entry, context will be a valid context (as determined by ValidateContext).{	// Only actually output the frame if the client supplied an array 	// and we we haven't filled it up yet.		assert(ValidateContext(context));		if ( (context->frameArray != NULL) && (context->frameCountOut < context->frameArrayCount) ) {		MoreBTFrame *	frameOutPtr;		frameOutPtr = &context->frameArray[context->frameCountOut];		frameOutPtr->pc    = pc;		frameOutPtr->fp    = fp;		frameOutPtr->flags = flags;	}		// Always increment the frame count.		context->frameCountOut += 1;	}static int InitSigTrampAddress(MoreBTContext *context)	// Fills out the sigTrampLowerBound and sigTrampUpperBound fields of 	// the context to be the address and bound of the _sigtramp routine.  	// I need this information to be able to detect and cross signal 	// frames correctly.	//	// Doing this correctly requires the ability to map symbols to addresses 	// in the remote task, something for which I haven't yet written the code.  	// So, we just make some risky assumptions:	//	// o _sigtramp is at the same address in the target task as it is in 	//   our task.  This would fail if the target task was a different 	//   architecture, so we outlaw that.  It can also fail if System 	//   frameworks was relocated in the target task, something that's 	//   possible and, with my current code base, hard to detect.	//	// o I assume a fixed length of 0x100 for the _sigtramp code.  Needless to 	//   say, this is completely bogus.	//	// On entry, context isn't yet a fully valid context because the 	// sigtramp fields haven't been set up yet.	// Returns an errno-style error code.	// On success, context is a valid context.{	int	err;	extern void _sigtramp(void);		assert(context != NULL);		if ( context->arch != GetTaskArch(mach_task_self()) ) {		fprintf(stderr, "MoreBacktrace: Cross architecture backtrace not supported because of problems finding _sigtramp.\n");		err = ENOTSUP;	} else {		context->sigTrampLowerBound = (uintptr_t) &_sigtramp;		context->sigTrampUpperBound = context->sigTrampLowerBound + 0x100;		err = 0;	}		assert( (err != 0) || ValidateContext(context) );	return err;}static OSRelease gOSRelease;static int InitContext(	MoreBTContext *			context,	const MoreBTArchInfo *	arch,	task_t					task,	const void *			threadState,	MoreBTReadBytesProc		readBytes,	void *					readBytesRefCon,	MoreBTAddr				stackBottom, 	MoreBTAddr				stackTop,	MoreBTFrame *			frameArray, 	size_t					frameArrayCount)	// Initialises a MoreBTContext to appropriate values based on 	// the input parameters and various default values and values 	// derived from the input parameters.	//	// On entry, context must not be NULL (but it's not yet a valid context).	// On entry, arch must not be NULL.	// On entry, task must not be MACH_PORT_NULL.	// On entry, threadState must not be NULL.	// On entry, readBytes must not be NULL.	// Returns an errno-style error code.	// On success, context will be a valid context.{	int err;	assert(context != NULL);	assert(arch != NULL);	assert(task != MACH_PORT_NULL);	assert(threadState != NULL);	assert(readBytes != NULL);			memset(context, 0, sizeof(*context));		// We don't check these input parameters here.  Instead the 	// check is done by the ValidateContext call below.		context->stackBottom     = stackBottom;	context->stackTop        = stackTop;	context->frameArray      = frameArray;	context->frameArrayCount = frameArrayCount;		context->arch            = arch;	context->task            = task;	context->threadState     = threadState;	context->readBytes       = readBytes;	context->readBytesRefCon = readBytesRefCon;		context->swapBytes = (arch->byteOrder != NXGetLocalArchInfo()->byteorder);	err = 0;	if (gOSRelease.major == 0) {		err = GetOSRelease(&gOSRelease);	}	if (err == 0) {		err = InitSigTrampAddress(context);	}	assert( (err != 0) || ValidateContext(context) );		return err;}static int BacktraceCore(MoreBTContext *context)	// The core backtrace code.  This routine is called by all of the various 	// exported routines.  It implements the core backtrace functionality. 	// All of the parameters to this routine are contained within 	// the context.  This routine traces back through the stack (using the 	// readBytes callback in the context to actually read memory) creating 	// a backtrace.{	int				err;	MoreBTAddr		thisPC;	MoreBTAddr		thisFrame;	MoreBTAddr		lowerBound;	MoreBTAddr		upperBound;	bool			stopNow;		assert(ValidateContext(context));		lowerBound = context->stackBottom;	upperBound = context->stackTop;	if (upperBound == 0) {		if (context->arch->is64Bit) {			// This actually generates a theoretical off-by-one error (a fp of 			// 0xFFFFFFFF FFFFFFFF is falsely considered invalid), but that's 			// not a problem in practice.			upperBound = 0xFFFFFFFFFFFFFFFFLL;		} else {			upperBound = 0x0000000100000000LL;		}	}		// If you supply bounds, they must make sense.		assert(upperBound >= lowerBound);	// Handle any leaf frames, and also return to us the initial 	// PC and FP.	assert(context->frameCountOut == 0);			// set up by memset in InitContext	err = context->arch->handleLeaf(context, &thisPC, &thisFrame);		// Handle the normal frames.		if (err == 0) {		stopNow = false;		do {			MoreBTFrame *   frameOutPtr;			MoreBTFrame		tmpFrameOut;			MoreBTAddr 		nextFrame;			MoreBTAddr 		nextPC;						// Output to a tmpFrameOut unless the client has supplied 			// a buffer and there's sufficient space left in it.			//			// IMPORTANT:			// You can't just add the frame information (possibly by calling 			// AddFrame) at the end of this loop, because the crossSignalFrame 			// callback may add its own frame, and we have to make sure that 			// this frame is allocated before that one.						if ( (context->frameArray != NULL) && (context->frameCountOut < context->frameArrayCount) ) {				frameOutPtr = &context->frameArray[context->frameCountOut];			} else {				frameOutPtr = &tmpFrameOut;			}			context->frameCountOut += 1;			// Record this entry.						frameOutPtr->pc    = thisPC;			frameOutPtr->fp    = thisFrame;			frameOutPtr->flags = 0;						// Now set the flags to indicate the validity of specific information. 						// Check the validity of the PC.  Don't set the err here; a bad PC value 			// does not cause us to quit the backtrace.						if ( ! context->arch->validPC(context, thisPC) ) {				frameOutPtr->flags |= kMoreBTPCBadMask;			} else {				// On PowerPC I used to report the address of the call, 				// rather than the return address.  That was easy: I just 				// decremented the returned PC by 4.  However, this is 				// much harder on Intel, where instructions are of variable 				// length.  So, I decided to do what Apple's tools do, 				// and just report the return address.			}						// Check the validity of the frame pointer.  A bad frame pointer *does* 			// cause us to stop tracing.						if (	(thisFrame == 0) 				 || (thisFrame & context->arch->frameAlignMask) 				 || (thisFrame < lowerBound) 				 || (thisFrame >= upperBound) 			   ) {				frameOutPtr->flags |= kMoreBTFrameBadMask;				stopNow = true;			}			if ( (err == 0) && ! stopNow) {								// Move to the next frame, either by crossing a signal handler frame 				// or by the usual mechanism.								if (	!(frameOutPtr->flags & kMoreBTPCBadMask) 					  && ( thisPC >= context->sigTrampLowerBound ) 					  && ( thisPC <  context->sigTrampUpperBound ) 				   ) {					// If this frame is running in _sigtramp, get nextPC and nextFrame 					// by delving into the signal handler stack block.					frameOutPtr->flags |= kMoreBTSignalHandlerMask;					err = context->arch->crossSignalFrame(context, thisFrame, &nextPC, &nextFrame);				} else {									// Read the next frame pointer.  A failure here causes us to quit 					// backtracing.  Note that we set kMoreBTFrameBadMask in frameOutPtr 					// because, if we can't read the contents of the frame pointer, the 					// frame pointer itself must be bad.										err = ReadAddr(context, thisFrame, &nextFrame);					if (err != 0) {						frameOutPtr->flags |= kMoreBTFrameBadMask;						nextFrame = (MoreBTAddr) -1;						// No need to set stopNow because err != 0 will 						// terminate loop.					}										// Also get the PC of the next frame, or set it to dummy value if 					// there is no next frame or we can't get the PC from that frame.					if (	(frameOutPtr->flags & kMoreBTFrameBadMask) 						 || (context->arch->getFrameNextPC(context, thisFrame, nextFrame, &nextPC) != 0) 					   ) {						nextPC = (MoreBTAddr) -1;		// an odd value, to trigger above check on next iteration					}				}				// Set up for the next iteration.								if (err == 0) {					lowerBound = thisFrame;					thisPC     = nextPC;					thisFrame  = nextFrame;				}			}		} while ( (err == 0) && ! stopNow );	}	assert(ValidateContext(context));		return err;}#pragma mark ***** Mach Infrastructurestatic int MachReadBytes(MoreBTContext *context, MoreBTAddr src, void *dst, size_t size)	// A memory read callback for Mach.  This simply calls through 	// to the Mach [mach_]vm_read primitive, which does more-or-less 	// what we want.	//	// See the description of MoreBTReadBytesProc for information about 	// the parameters.{	int						err;	int						junk;	vm_offset_t				dataRead;	mach_msg_type_number_t	sizeRead;		assert(ValidateContext(context));	assert(dst != NULL);	assert(size > 0);	// I used to use mach_vm_read_overwrite, which has a better semantic match for 	// what I'm trying to do than mach_vm_read, but it has some serious problems 	// on some systems (at least Mac OS X 10.4.4 on PowerPC G4 and G5).  So I've 	// reverting to using [mach_]vm_read, which means I have to vm_deallocate 	// the space afterwards.  Such is life, kerplunk.	#ifdef HAVE_MACH_VM_READ	if (mach_vm_read != NULL) {		err = mach_vm_read(			context->task,			src,			size,			&dataRead,			&sizeRead		);	} else #endif /* HAVE_MACH_VM_READ */        {		#if MORE_DEBUG			// If I'm running 32-bits, vm_read's arguments are only 32-bits, 			// and thus an attempt to read a 64-bit address is bad.  This 			// should never happen because systems that support 64-bit 			// addresses also support mach_vm_read.  But if it does happen, 			// I want to know about it (and investigate what's going on).						if ( ! TaskIs64Bits(mach_task_self()) ) {				assert( (src & 0xFFFFFFFF00000000LL) == 0 );				assert( ((src + size) & 0xFFFFFFFF00000000LL) == 0 );			}		#endif				err = vm_read(			context->task,			(vm_address_t) src,			size,			&dataRead,			&sizeRead		);	}	if (err == 0) {		if (sizeRead != size)  {			err = KERN_FAILURE;		} else {			memcpy(dst, (void *) dataRead, size);		}				// Note that I can use vm_deallocate instead of mach_vm_deallocate because 		// I know that the thing I'm deallocating is in the my address space, and 		// thus vm_deallocate, whose parameters scale with the caller's address space, 		// is just fine.  mach_vm_deallocate would work just as well, but that would 		// put another unnecessary dependency on Mac OS X 10.4.				junk = vm_deallocate(mach_task_self(), dataRead, sizeRead);		assert(junk == 0);	}	return err;}static int MoreBacktraceMach(	const MoreBTArchInfo *	arch,	task_t					task, 	const void *			threadState,	MoreBTAddr				stackBottom, 	MoreBTAddr				stackTop,	MoreBTFrame *			frameArray, 	size_t					frameArrayCount, 	size_t *				frameCountPtr)	// Common code for the two exported backtrace routines. 	// Backtraces a given task, of a given architecture, starting 	// with the specified thread state.  The other parameters 	// are directly from the client.	//	// Returns an errno-style error code.{	int				err;	MoreBTContext	context;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -