📄 trclib.c
字号:
/* trcLib.c - i80x86 stack trace library *//* Copyright 1984-1995 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01e,12may95,p_m adapted to support host based tt().01d,26oct94,hdn added a MAX_LOOPCOUNT to avoid infinite loop.01c,09dec93,hdn added a forward declaration of trcCountArgs(). commented out trcFollowJmp(pc) in trcFindFuncStart().01b,01jun93,hdn added third parameter tid to trcStack(). updated to 5.1. - changed functions to ansi style - changed VOID to void - changed copyright notice01a,16jul92,hdn written based on TRON version.*//*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"*/#include "vxWorks.h"#include "regs.h"#include "stdio.h"#include "symLib.h"#include "sysSymTbl.h"#include "private/funcBindP.h"#define MAX_TRACE_DEPTH 40 /* max number of levels of stack to trace */#define MAX_LOOPCOUNT 128 /* max loop count *//* instruction patterns and masks */#define ADDI08_0 0x83#define ADDI08_1 0xc4#define ADDI32_0 0x81#define ADDI32_1 0xc4#define LEAD08_0 0x8d#define LEAD08_1 0x64#define LEAD08_2 0x24#define LEAD32_0 0x8d#define LEAD32_1 0xa4#define LEAD32_2 0x24#define JMPD08 0xeb#define JMPD32 0xe9#define ENTER 0xc8#define PUSH_EBP 0x55#define MOV_ESP0 0x89#define MOV_ESP1 0xe5#define LEAVE 0xc9#define RET 0xc3#define RETADD 0xc2#define CALL_DIR 0xe8#define CALL_INDIR0 0xff#define CALL_INDIR1 0x10#define ADDI08_0_MASK 0xff#define ADDI08_1_MASK 0xff#define ADDI32_0_MASK 0xff#define ADDI32_1_MASK 0xff#define LEAD08_0_MASK 0xff#define LEAD08_1_MASK 0xff#define LEAD08_2_MASK 0xff#define LEAD32_0_MASK 0xff#define LEAD32_1_MASK 0xff#define LEAD32_2_MASK 0xff#define JMPD08_MASK 0xff#define JMPD32_MASK 0xff#define ENTER_MASK 0xff#define PUSH_EBP_MASK 0xff#define MOV_ESP0_MASK 0xff#define MOV_ESP1_MASK 0xff#define LEAVE_MASK 0xff#define RET_MASK 0xff#define RETADD_MASK 0xff#define CALL_DIR_MASK 0xff#define CALL_INDIR0_MASK 0xff#define CALL_INDIR1_MASK 0x38#define DSM(addr,inst,mask) ((*(addr) & (mask)) == (inst))/* globals */int trcDefaultArgs = 5; /* default # of args to print if trc * can't figure out how many *//* forward declarations */LOCAL INSTR *trcFindCall (INSTR *returnAdrs);LOCAL INSTR *trcFindFuncStart (int *fp, INSTR *pc);LOCAL INSTR *trcFindDest (INSTR *callAdrs);LOCAL INSTR *trcFollowJmp (INSTR *addr);LOCAL void trcDefaultPrint (INSTR *callAdrs, INSTR *funcAdrs, int nargs, int *args);LOCAL void trcStackLvl (int *fp, INSTR *pc, int depth, FUNCPTR printRtn);LOCAL int trcCountArgs (INSTR *returnAdrs);/********************************************************************************* 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 an PUSH %EBP MOV %ESP %EBP instruction. Most * VxWorks assembly language routines include PUSH %EBP MOV %ESP %EBP * instructions 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.** 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, ®Set);* trcStack (®Set, (FUNCPTR)printRtn, tid);* .CE** 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 gotten from symbol table */ char name[MAX_SYS_SYM_LEN]; /* string associated with val */ SYM_TYPE type; /* type associated with val */ INSTR *addr; /* next instruction */ int stackSave; FAST INSTR *pc = pRegSet->pc; /* program counter */ FAST int *fp = (int *)pRegSet->fpReg; /* stack frame pointer (A6) */ FAST int *sp = (int *)pRegSet->spReg; /* stack pointer */ /* 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 stack frame in a few restricted but useful * cases: * 1) we are at a PUSH %EBP MOV %ESP %EBP or RET or ENTER instruction, * 2) we are the first instruction of a subroutine (this may NOT be * a PUSH %EBP MOV %ESP %EBP instruction with some compilers) */ addr = trcFollowJmp (pc); if ((DSM(addr, PUSH_EBP, PUSH_EBP_MASK) && DSM(addr+1, MOV_ESP0, MOV_ESP0_MASK) && DSM(addr+2, MOV_ESP1, MOV_ESP1_MASK)) || (DSM(addr, ENTER, ENTER_MASK)) || (DSM(addr, RET, RET_MASK)) || (DSM(addr, RETADD, RETADD_MASK)) || ((sysSymTbl != NULL) && ((_func_symFindByValue) != NULL) && ((* _func_symFindByValue) (sysSymTbl, (int) pc, name, &val, &type) == OK) && (val == (int) pc))) { /* no stack frame - fake one */ stackSave = *(sp - 1); /* save value we're going to clobber */ *(sp - 1) = (int)fp; /* make new frame pointer by */ /* sticking old one on stack */ fp = sp - 1; /* and pointing to it */ trcStackLvl (fp, pc, 0, printRtn); /* do stack trace */ *(sp - 1) = stackSave; /* restore stack */ } else if ((DSM(addr-1, PUSH_EBP, PUSH_EBP_MASK) && DSM(addr, MOV_ESP0, MOV_ESP0_MASK) && DSM(addr+1, MOV_ESP1, MOV_ESP1_MASK))) { fp = sp; trcStackLvl (fp, pc, 0, printRtn); /* do stack trace */ } else { trcStackLvl (fp, pc, 0, printRtn); /* do stack trace */ } }/************************************************************************** trcStackLvl - recursive stack trace routine** This routine is recursive, being called once for each level of routine* nesting. The maximum recursion depth is limited to 40 to prevent* garbage stacks from causing this routine to continue unbounded.* The "depth" parameter on the original call should be 0.*/LOCAL void trcStackLvl ( FAST int *fp, /* stack frame pointer (A6) */ INSTR *pc, /* program counter */ int depth, /* recursion depth */ FUNCPTR printRtn /* routine to print single function call */ ) { FAST INSTR *returnAdrs; if (fp == NULL) return; /* stack is untraceable */ returnAdrs = (INSTR *) *(fp + 1); /* handle oldest calls first, up to MAX_TRACE_DEPTH of them */ if ((*fp != NULL) && (depth < MAX_TRACE_DEPTH)) trcStackLvl ((int *) *fp, returnAdrs, depth + 1, printRtn); (* printRtn) (trcFindCall (returnAdrs), trcFindFuncStart (fp, pc), trcCountArgs (returnAdrs), fp + 2); }/********************************************************************************* trcDefaultPrint - print a function call** This routine is called by trcStack to print each level in turn.** If nargs is specified as 0, then a default number of args (trcDefaultArgs)* is printed in brackets ("[..]"), since this often indicates that the* number of args is unknown.*/LOCAL void trcDefaultPrint ( INSTR *callAdrs, /* address from which function was called */ INSTR *funcAdrs, /* address of function called */ FAST int nargs, /* number of arguments in function call */ int *args /* pointer to function args */ ) { FAST int i; BOOL doingDefault = FALSE; /* if there is no printErr routine do nothing */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -