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

📄 morebacktrace.c

📁 MPI stands for the Message Passing Interface. Written by the MPI Forum (a large committee comprising
💻 C
📖 第 1 页 / 共 4 页
字号:
			// Read the instructions at that offset from the PC and see if they're 			// the standard _sysenter_trap code.			//			// It's a happy coincidence that the size of the _sysenter_trap code is 			// 5 bytes, which is also the size of the buffer that I have lying around 			// to read the instructions in front of the PC.  The upshot is that I can 			// reuse buf rather than needing a second one.						err = context->readBytes(context, pc + sysEnterOffset, buf, sizeof(buf));			if (err == 0) {				isSystemCall = (buf[0] == 0x5a)								// pop      %edx							&& (buf[1] == 0x89)	&& (buf[2] == 0xe1)			// mov      %esp,%ecx							&& (buf[3] == 0x0f) && (buf[4] == 0x34);		// sysenter			}		}	}	return isSystemCall;}static int IntelHandleLeaf(MoreBTContext *context, MoreBTAddr *pcPtr, MoreBTAddr *framePtr)	// This is the handleLeaf routine for the Intel 	// architecture.  See the description of MoreBTHandleLeafProc 	// for a detailed discussion of its parameters.	// 	// I don't have the experience or the time to fully analyse 	// the leaf routine problem for Intel.  Rather, I just implemented 	// a simple system call check, much like I did on PowerPC.  This 	// seems to be effective in the cases that I care about.{	int			err;	MoreBTAddr	pc;		pc = ((const i386_thread_state_t *) context->threadState)->eip;	// If the PC is a system call, add a dummy leaf for that PC 	// and then get the next frame's PC from the top of stack.	err = 0;	if ( IntelIsSystemCall(context, pc) ) {		AddFrame(context, pc, 0, kMoreBTFrameBadMask);		err = ReadAddr(context, ((const i386_thread_state_t *) context->threadState)->esp, &pc);	}	if (err == 0) {		*pcPtr = pc;		*framePtr = ((const i386_thread_state_t *) context->threadState)->ebp;	}		return err;}static bool  IntelValidPC(MoreBTContext *context, MoreBTAddr pc)	// This is the validPC routine for the Intel 	// architecture.  See the description of 	// MoreBTValidPCProc for a detailed discussion 	// of its parameters.	//	// Intel instructions are not aligned in any way.  All, I can do 	// is check for known bad values ((MoreBTAddr) -1 is used as a 	// known bad value by the core) and check that I can read at least 	// byte of instruction from the address.{	uint8_t	junkInst;		return (pc != (MoreBTAddr) -1) && (context->readBytes(context, pc, &junkInst, sizeof(junkInst)) == 0);}static int IntelGetFrameNextPC(MoreBTContext *context, MoreBTAddr thisFrame, MoreBTAddr nextFrame, MoreBTAddr *nextPCPtr)	// This is the getFrameNextPC routine for the Intel 	// architecture.  See the description of 	// MoreBTGetFrameNextPCProc for a detailed discussion 	// of its parameters.	//	// This is very easy on Intel, because it's the return address, 	// which is at a fixed offset in the frame.{	return ReadAddr(context, thisFrame + 4, nextPCPtr);	}/*	Intel Signal Stack Frames	-------------------------	Cross signal stack frames is much more reliable on Intel.  The parameters 	to _sigtramp are stored on the stack, and you can reliably pick them up 	from there.					Size	Purpose					----	-------	low memory		frame  ->		0x004	pre-signal frame pointer					0x018	struct sigframe					0x020?	pad					0x258	struct mcontext								0x00c	i386_exception_state_t								0x040	i386_thread_state_t								0x20c	i386_float_state_t					0x040	siginfo_t					0x020	struct ucontext	high memory		Things to note about the above:		o The kernel aligns the stack such that the catcher field of the 	  sigframe structure is aligned on a 16 byte boundary.  This means that 	  there's a variable amount of pad between sigframe and mcontext.  	  This isn't a problem because the sigframe structure contains a 	  field (sinfo) that's a pointer to the siginfo_t.		The sinfo field of the sigframe structure is at offset 0x10.  Once you 	account for the pre-signal frame pointer that's pushed on to the stack 	by _sigtramp, you need to go 0x14 bytes up the frame to get the sinfo 	field, which is a pointer to a siginfo_t structure.  The kernel places 	the pre-signal PC and SP in fields in that structure (si_addr and 	pad[0], offset 0x18 and 0x24 respectively).		Finally, if we detect a frameless leaf routine past the signal frame, 	we extract its return address from the top of stack.*/static int IntelCrossSignalFrame(MoreBTContext *context, MoreBTAddr thisFrame, MoreBTAddr *nextPCPtr, MoreBTAddr *nextFramePtr)	// This is the crossSignalFrame routine for the Intel 	// architecture.  See the description of 	// MoreBTCrossSignalFrameProc for a detailed discussion 	// of its parameters.{	int	err;	MoreBTAddr	sigInfo;	MoreBTAddr	preSignalSP;		// Get the siginfo_t pointer from the parameters to _sigtramp 	// (the sinfo field of sigframe).		err = ReadAddr(context, thisFrame + 0x14, &sigInfo);		// Get the previous PC from si_addr field of siginfo_t.		if (err == 0) {		err = ReadAddr(context, sigInfo + 0x18, nextPCPtr);	}		// Get the previous frame by simply reading from the frame pointer. 	// Because of the way things work, this ends up being correct.		if (err == 0) {		err = ReadAddr(context, thisFrame, nextFramePtr);	}		// Finally, if we detect a leaf routine, add a dummy frame for it 	// and then get the pre-signal SP (from the pad[0] of siginfo_t) 	// and, assuming that the top word on the stack is a return address, 	// use it for the next PC.		if ( (err == 0) && IntelIsSystemCall(context, *nextPCPtr) ) {		AddFrame(context, *nextPCPtr, 0, kMoreBTFrameBadMask);				err = ReadAddr(context, sigInfo + 0x24, &preSignalSP);		if (err == 0) {			err = ReadAddr(context, preSignalSP, nextPCPtr);		}	}		return err;}#endif /* #ifdef CPU_TYPE_X86 */// kArchitectures is an array of all the architectures we support.  // Things to notes://// o GetTaskArch processes this in a forward direction.  If you //   list a more-specific architecture, you should list it before //   the less-specific one.//// o The table is terminated by a NULL architecture, signified by //   a 0 in the cputype field.//// See the comments near MoreBTArchInfo for a detailed description of // each field.static const MoreBTArchInfo kArchitectures[] = {	{	// PowerPC		CPU_TYPE_POWERPC,			// cputype		0,							// subcputype		false,						// is64Bit		NX_BigEndian,				// byteOrder		15,							// frameAlignMask		PowerPCHandleLeaf,			// handleLeaf		PowerPCValidPC,				// validPC		PowerPCGetFrameNextPC,		// getFrameNextPC		PowerPCCrossSignalFrame,	// crossSignalFrame		PPC_THREAD_STATE,			// stateFlavor		PPC_THREAD_STATE_COUNT		// stateCount	},	{	// PowerPC64		CPU_TYPE_POWERPC,			// cputype		0,							// subcputype		true,						// is64Bit		NX_BigEndian,				// byteOrder		15,							// frameAlignMask		PowerPCHandleLeaf,			// handleLeaf		PowerPCValidPC,				// validPC		PowerPCGetFrameNextPC,		// getFrameNextPC		PowerPCCrossSignalFrame,	// crossSignalFrame		PPC_THREAD_STATE64,			// stateFlavor		PPC_THREAD_STATE64_COUNT	// stateCount	},#ifdef CPU_TYPE_X86	{	// Intel		CPU_TYPE_X86,				// cputype		0,							// subcputype		false,						// is64Bit		NX_LittleEndian,			// byteOrder		3,							// frameAlignMask									// Apple's i386 API requires that the stack be 16 byte aligned, 									// but it says nothing about the frame.  It turns out that the 									// frame is typically 8 byte aligned, but I can't find any 									// documentation that requires that, so I'm only checking 4 byte 									// alignment.		IntelHandleLeaf,			// handleLeaf		IntelValidPC,				// validPC		IntelGetFrameNextPC,		// getFrameNextPC		IntelCrossSignalFrame,		// crossSignalFrame		i386_THREAD_STATE,			// stateFlavor		i386_THREAD_STATE_COUNT		// stateCount	}#endif /* #ifdef CPU_TYPE_X86 */	 /* null terminator */	};#pragma mark ***** Public Interfaceextern int MoreBacktraceMachThread(	task_t			task, 	thread_t		thread,	MoreBTAddr		stackBottom, 	MoreBTAddr		stackTop,	MoreBTFrame *	frameArray, 	size_t			frameArrayCount, 	size_t *		frameCountPtr)	// See comments in header.{	int						err;	const MoreBTArchInfo *	arch;	mach_msg_type_number_t 	stateCount;	void *					threadState;	assert(task != MACH_PORT_NULL);	assert(thread != MACH_PORT_NULL);	assert( ((stackBottom == 0) && (stackBottom == stackTop)) || (stackBottom < stackTop) );	assert( (frameArrayCount == 0) || (frameArray != NULL) );	assert( frameCountPtr != NULL );	threadState = NULL;		// Get the architecture of the task, and us that to allocate enough 	// space for the thread's state.		err = 0;	arch = GetTaskArch(task);	if (arch == NULL) {		err = EINVAL;	}	if (err == 0) {		stateCount = arch->stateCount;				threadState = malloc(stateCount * sizeof(int));		if (threadState == NULL) {			err = ENOMEM;		}	}		// Get the thread state.		if (err == 0) {		err = thread_get_state(thread, arch->stateFlavor, (thread_state_t) threadState, &stateCount);	}		// Do the backtrace.		if (err == 0) {		err = MoreBacktraceMach(			arch,			task,			threadState,			stackBottom,			stackTop,			frameArray, 			frameArrayCount, 			frameCountPtr		);	}		// Clean up.		free(threadState);		return err;}// InitThreadState is a macro that initialises an architecture-specific // thread state structure from the current CPU registers.  This only // initialises enough fields to support a backtrace.#if TARGET_CPU_PPC#if 0 /* OMPI CHANGE */	#define InitThreadState(threadState)	\		do {								\			uint32_t tmpPC = 0;				\			uint32_t tmpFP = 0;				\			asm {							\					bl		next ;			\			next:	mflr	tmpPC ;			\					mr		tmpFP,sp		\			}								\			((ppc_thread_state_t *) threadState)->srr0 = tmpPC;		\			((ppc_thread_state_t *) threadState)->r1   = tmpFP;		\		} while (0)#else /* OMPI CHANGE */	#define InitThreadState(threadState)	                                \		do {								\			uint32_t tmpPC = 0;				        \			uint32_t tmpFP = 0;				        \                        asm("\tmflr %0\n"                                  \                            "\tmr %1,r1"                                        \                            : "=r"(tmpPC), "=r"(tmpFP));                        \			((ppc_thread_state_t *) threadState)->srr0 = tmpPC;	\			((ppc_thread_state_t *) threadState)->r1   = tmpFP;	\		} while (0)#endif /* OMPI CHANGE */#elif TARGET_CPU_PPC64#if 0 /* OMPI CHANGE */	#define InitThreadState(threadState)	\		do {								\			uint64_t tmpPC = 0;				\			uint64_t tmpFP = 0;				\			asm {							\					bl		next ;			\			next:	mflr	tmpPC ;			\					mr		tmpFP,sp		\			}								\			((ppc_thread_state64_t *) threadState)->srr0 = tmpPC;	\			((ppc_thread_state64_t *) threadState)->r1   = tmpFP;	\		} while (0)#else /* OMPI CHANGE */	#define InitThreadState(threadState)	                                \		do {								\			uint64_t tmpPC = 0;				        \			uint64_t tmpFP = 0;				        \                        asm("\tmflr %0\n"                                  \                            "\tmr %1,r1"                                        \                            : "=r"(tmpPC), "=r"(tmpFP));                        \			((ppc_thread_state64_t *) threadState)->srr0 = tmpPC;	\			((ppc_thread_state64_t *) threadState)->r1   = tmpFP;	\		} while (0)#endif /* OMPI CHANGE */#elif TARGET_CPU_X86	// Have to use bizarr-o GCC syntax because the compiler is barfing on the 	// block syntax, but only for Intel.  *sigh*		#define InitThreadState(threadState)			\		do {										\			uint32_t tmpPC = 0;						\			uint32_t tmpFP = 0;						\			asm( "\tcall Lnext\nLnext: pop %0\n"	\			     "\tmov %%ebp,%1"					\				 : "=r" (tmpPC) , "=r" (tmpFP) );	\			((i386_thread_state_t *) threadState)->eip = tmpPC;		\			((i386_thread_state_t *) threadState)->ebp = tmpFP;		\		} while (0)		#else	#error What architecture?#endifextern int MoreBacktraceMachSelf(	MoreBTAddr		stackBottom, 	MoreBTAddr		stackTop,	MoreBTFrame *	frameArray, 	size_t			frameArrayCount, 	size_t *		frameCountPtr)	// See comments in header.{	int						err;	const MoreBTArchInfo *	arch;	void *					threadState;	assert( ((stackBottom == 0) && (stackBottom == stackTop)) || (stackBottom < stackTop) );	assert( (frameArrayCount == 0) || (frameArray != NULL) );	assert( frameCountPtr != NULL );	threadState = NULL;		// Get the architecture of the current task, and us that to allocate 	// enough space for our thread's state.	err = 0;	arch = GetTaskArch(mach_task_self());	if (arch == NULL) {		err = EINVAL;	}	if (err == 0) {		threadState = calloc(arch->stateCount, sizeof(int));		if (threadState == NULL) {			err = ENOMEM;		}	}		// Initialise the thread state, then do the backtrace.		if (err == 0) {		InitThreadState(threadState);		err = MoreBacktraceMach(			GetTaskArch(mach_task_self()),			mach_task_self(),			threadState,			stackBottom, 			stackTop,			frameArray, 			frameArrayCount, 			frameCountPtr		);	}		// Clean up.		free(threadState);		return err;}

⌨️ 快捷键说明

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