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

📄 trclib.c

📁 VxWorks BSP框架源代码包含头文件和驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* trcLib.c - ARM stack trace library *//* Copyright 1996-1998 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01f,07may01,m_h  validate fp before using it.01e,04sep98,cdp  make Thumb support dependent on ARM_THUMB.01d,27oct97,kkk  took out "***EOF***" line from end of file.01c,10oct97,jpd  added further Thumb support.01b,01may97,cdp  added new function prologues, basic Thumb support, tidied.01a,22jul96,cdp  created, based on 68K.c*//*This module provides a routine, trcStack(), which traces a stackgiven the current frame pointer, stack pointer, and program counter.The resulting stack trace lists the nested routine calls and their arguments.This module provides the low-level stack trace facility.A higher-level symbolic stack trace, implemented on top of this facility,is provided by the routine tt() in dbgLib.SEE ALSO: dbgLib, tt(),.pG "Debugging,".I "ARM Architecture Reference Manual,".I "ARM Procedure Call Standard,".I "Thumb Procedure Call Standard."*/#include "vxWorks.h"#include "regs.h"#include "symLib.h"#include "taskLib.h"#include "dsmLib.h"#include "sysSymTbl.h"#include "vxLib.h"#include "private/funcBindP.h"/* * Check that this compiler does sign extension when an int is shifted right * because code below relies on its doing so. */#if (((INT32)-1L) >> 1) > 0#	error right shifting an int does not perform sign extension#endif#define MAX_TRACE_DEPTH 40 /* maximum number of levels of stack to trace *//* globals */int trcDefaultArgs = 0;			/* default # of args to print if */					/* can't figure out how many *//* imported functions */#if (ARM_THUMB)IMPORT BOOL thumbInstrChangesPc (INSTR *);#elseIMPORT BOOL armInstrChangesPc (INSTR *);#endif/* forward static functions */LOCAL void trcStackLvl (WIND_TCB *tcb, int *fp, INSTR *pc, int depth, FUNCPTR printRtn);LOCAL void trcDefaultPrint (INSTR *callAdrs, INSTR *funcAdrs, int nargs, int		*args);LOCAL INSTR *trcFindCall (INSTR *returnAdrs);LOCAL INSTR *trcFindDest (INSTR *callAdrs);LOCAL int trcCountArgs (INSTR *returnAdrs);LOCAL INSTR *trcFindFuncStart (int *fp, INSTR *pc);/********************************************************************************* trcStack - print a trace of function calls from the stack** This routine provides the low-level stack trace function.  A higher-level* symbolic stack trace, built on top of trcStack(), is provided by tt() in* dbgLib.** This routine prints a list of the nested routine calls that are on the* stack, showing each routine with its parameters.** The stack being traced should be quiescent.  The caller should avoid* tracing its own stack.** PRINT ROUTINE* In order to allow symbolic or alternative printout formats, the call to* this routine includes the <printRtn> parameter, which specifies a* user-supplied routine to be called at each nesting level to print out the* routine name and its arguments.  This routine should be declared as* follows:* .ne 7* .CS*     void printRtn (callAdrs, rtnAdrs, nargs, args)*         INSTR  *callAdrs;  /@ address from which routine was called **         int    rtnAdrs;    /@ address of routine called **         int    nargs;	     /@ number of arguments in call **         int    *args;	     /@ pointer to arguments ** .CE* If <printRtn> is NULL, a default routine will be used that prints out just* the call address, the function address, and the arguments as hexadecimal* values.** CAVEAT* In order to do the trace, a number of assumptions are made.  In general,* the trace will work for all C language routines and for assembly language* routines that start with a standard entry sequence which establishes a* stack frame conforming with the ARM Procedure Call Standard (APCS) or* the Thumb Procedure Call Standard (TPCS).** Most VxWorks assembly language routines establish a stack frame in this* fashion for exactly this reason. However, routines written in other* languages, strange entries into routines, or tasks with corrupted stacks* can confuse the trace.  Also, all parameters are assumed to be 32-bit* quantities, therefore structures passed as parameters will be displayed* as a number of long integers.** .ne 14* EXAMPLE* The following sequence can be used to trace a VxWorks task given a pointer* to the task's TCB:* .CS* REG_SET regSet;  /@ task's data registers *** taskRegsGet (taskId, &regSet);* trcStack (&regSet, (FUNCPTR)NULL, taskId);* .CE** RETURNS: N/A** SEE ALSO: tt()** NOMANUAL*/void trcStack    (    REG_SET *pRegSet,		/* pointer to register set */    FUNCPTR printRtn,           /* routine to print single function call */    int     tid			/* task's id */    )    {    int		val;			/* address from symbol table */    char	name[MAX_SYS_SYM_LEN];	/* string associated with val */    SYM_TYPE	type;			/* type associated with val */    int		stackSave[4];    int		i;			/* an index */    BOOL	in_entry_exit;		/* boolean: whether in entry or exit */    FAST INSTR *pc = pRegSet->pc;    FAST int *fp = (int *) pRegSet->fpReg;    FAST int *sp = (int *) pRegSet->spReg;#if (ARM_THUMB)    FAST int *lr = (int *) pRegSet->r[14];    int	reg;#endif    WIND_TCB   *tcb= taskTcb (tid);    INSTR       insn;    /* use default print routine if none specified */    if (printRtn == NULL)	printRtn = (FUNCPTR) trcDefaultPrint;    /*     * if the current routine doesn't have a stack frame, then we fake one     * by putting the old one on the stack and making fp point to that.     * We KNOW we don't have a complete stack frame for the current     * routine in a few particular cases.     *  1) We are in the entry sequence of a routine which establishes the     *     stack frame. We try to cope with this;     *  2) We are in the exit sequence of a routine, which collapses the     *     stack frame (Thumb only). We try to cope with this;     *  3) We are in a routine which doesn't create a stack frame. We cannot     *     do much about this.     */#if (!ARM_THUMB)    /*     * ARM     * So far, we have identified 3 types of function prologue (and are still     * trying to get a useful statement from Cygnus about others):     *     *  normal:     *          mov     ip,sp     *          stmdb   sp!,{v_regs,fp,ip,lr,pc}     *          sub     fp,ip,#4     *     *  varargs:     *          mov     ip,sp     *          stmdb   sp!,{a_regs}     *          stmdb   sp!,{v_regs,fp,ip,lr,pc}     *          sub     fp,ip,#4+n*4     *     *  structure arg passed by value:     *          mov     ip,sp     *          sub     sp,sp,#n     *          stmdb   sp!,{fp,ip,lr,pc}     *          sub     fp,ip,#4+n     *     * Combining 'varargs' and 'structure arg passed by value' does not     * seem to generate a different prologue.     */#else    /*     * Thumb     * We have identified the following routine prologues. They vary     * substantially depending on the type of routine and, notably, do     * not always start with the same instruction. The prologue may be     * changed later, to be made more efficient.     *     *		push	{a_regs}	/@ only present if required @/     *		sub	sp,#16     *		push	{v_regs}	/@ only present if required @/     *					/@ includes lr if non-leaf routine @/     *		add	rx,sp,#n     *		str	rx,[sp,#]     *		mov	rx,pc		/@ 1 @/     *		str	rx,[sp,#]	/@ 2 @/     *		mov	rx,fp		/@ 3 @/     *		str	rx,[sp,#]	/@ 4 @/     *		mov	rx,lr     *		str	rx,[sp,#]     *		add	rx,sp,#n     *		mov	fp,rx     *     * The instructions labelled 1, 2, 3 and 4 can appear in the order 3,4,1,2     * in some routines.     *     * For Thumb we also need to be aware of routine epilogues, as,     * unlike the ARM epilogue, which is atomic (one instruction), the     * Thumb epilogue takes several instructions, during which the frame     * is collapsed. The epilogue is not currently "strictly-conforming"     * in that fp does not always point to a valid frame: there is a     * window between the popping of part of the frame and the changing     * of fp to point to the previous frame.     *     * The routine epilogue does not appear to vary much:     *     * leaf:     *		pop	{v_regs}	/@ only present if required @/     *		pop	{rx, ry}     *		mov	fp,rx     *		mov	sp,ry     *		bx	lr     * non-leaf:     *		pop	{v_regs}	/@ only present if required @/     *		pop	{rx, ry, rz}     *		mov	fp,ry     *		mov	sp,rz     *		bx	rx     */#endif#if (ARM_THUMB)    /*     * First look to see if we are in the epilogue.     *     * Search backwards from current instruction to find the first     * instruction of the epilogue.     */    for (i = 0; i >= -3 ; --i)	if (INSTR_IS(pc[i],     T_POP_LO) &&	    INSTR_IS(pc[i + 1], T_MOV_FP_LO) &&	    INSTR_IS(pc[i + 2], T_MOV_SP_LO) &&	    INSTR_IS(pc[i + 3], T_BX_LO))	    break;    if (in_entry_exit = (i >= -3), in_entry_exit)	{	/* If we have not yet executed the POP instruction, then fp	 * still points to a valid frame, so pretend we're not in the	 * epilogue. We have at least proved we're not in the prologue,	 * which is useful as otherwise we might have a false match on the	 * MOV FP,	 */	if (i == 0)	    in_entry_exit = FALSE;	else	    {	    /*	     * If we are in the epilogue, then at the least, the frame	     * pointer and stack pointer will have been popped from the	     * stack. i.e. there is no longer a valid stack frame on the	     * stack (and not possibly overwritten).	    */	    if (i == -1)		{		/*		 * Then fp has not yet been restored, old fp value will		 * be in the register used in the MOV fp, loreg		 * instruction. Extract the register number from that		 * instruction, then get that register from the reg set		 * and make that our dummy fp which we will use to		 * construct a dummy frame.		 */		reg = (pc[i + 1] & 0x38) >> 3;	/* reg num in MOV fp instr */		fp = (int *)pRegSet->r[reg];		}	    /*	     * We must find the return address from the current routine	     * to put into our dummy frame later. Extract it from the	     * register used in the BX instruction used to exit the	     * routine.	     */	    reg = (pc[i + 3] & 0x38) >> 3;	/* reg num in BX instr*/	    lr = (int *) pRegSet->r[reg];	/* get from reg set */	    }	}    else	{	/*	 * We are not in the epilogue, we may be in the prologue.	 *	 * Look for the last instruction of the prologue. This can be up	 * to twelve instructions after the current one.	 */	for (i = 0; i <= 12 ; i++)	    if (INSTR_IS(pc[i], T_MOV_FP_LO))		break;	/*	 * Check to see if this really is the prologue, by matching	 * another instruction earlier in the prologue. We have	 * attempted to choose instructions which should not occur much	 * elsewhere.	 */	in_entry_exit = (i <= 12 &&		    (INSTR_IS(pc[i - 5], T_MOV_LO_PC) ||		     INSTR_IS(pc[i - 5], T_MOV_LO_FP)));	}#else    /*     * Look for the first instruction of the prologue. This can be up     * to three instructions before the current pc.     */    for (i = 0; i >= -3 ; --i)	if (INSTR_IS(pc[i], MOV_IP_SP))	    break;    in_entry_exit = (i >= -2 &&		INSTR_IS(pc[i + 1], STMDB_SPP_FP_IP_LR_PC) &&		INSTR_IS(pc[i + 2], SUB_FP_IP_4)) ||	       (i >= -3 &&		INSTR_IS(pc[i + 2], STMDB_SPP_FP_IP_LR_PC) &&		INSTR_IS(pc[i + 3], SUB_FP_IP_4PLUS) &&		(INSTR_IS(pc[i + 1], STMDB_SPP_AREGS) ||		 INSTR_IS(pc[i + 1], SUB_SP_SP)));#endif /* (ARM_THUMB) */    /*     * if we're in the entry or exit sequence or, failing that, at a     * function address that's in the symbol table, fake a stack frame     * (if at a symbol, then we must be at the first instruction of a     * routine).     */    if (in_entry_exit ||        ((sysSymTbl != NULL) && (_func_symFindByValue != NULL) &&	 ((* _func_symFindByValue) (sysSymTbl, (int) pc, name,				    &val, &type) == OK) &&

⌨️ 快捷键说明

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