📄 trclib.c
字号:
* trcStack (®Set, (FUNCPTR) printRtn, tid);* .CE** SEE ALSO: tt()** NOMANUAL*/void trcStack ( REG_SET * pRegSet, /* pointer to a task register set */ FUNCPTR printRtn, /* routine to print single function call */ int tid /* task's id */ ) { STATUS symStatus = ERROR; int val = 0; /* Extract the program counter (EIP), stack pointer (ESP), and * frame pointer (EBP) values from the register structure. */ const INSTR * const pc = pRegSet->pc; const int * const sp = (int *) pRegSet->esp; const int * fp = (int *) pRegSet->ebp; const char * const pStackBase = taskTcb(tid)->pStackBase; const char * const pStackLimit = taskTcb(tid)->pStackLimit; /* Find the address of the next instruction that is not a JMP. */ const INSTR * const addr = trcFollowJmp (pc); /* use default print routine if none specified */ if (printRtn == NULL) { printRtn = (FUNCPTR) trcDefaultPrint; } /* If there is a symbol table, use it to test whether (pc) is on * the first instruction of a subroutine. */ if (sysSymTbl != NULL) { char * pName = NULL; /* function name from symbol table */ SYM_TYPE type; /* function type from symbol table */ symStatus = symByValueFind (sysSymTbl, (int) pc, &pName, &val, &type); if (pName != NULL) { free (pName); /* new API requires this */ } } /* * 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) */ 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)) || ((symStatus == OK) && (val == (int) pc))) { /* The stack frame is not created yet, so we'll simulate one by * first saving the value (ESP-1), storing the current EBP value * at that location, then setting EBP to the location where its * old value was saved. This is approximately equivalent to: * * func: * push ebp * mov ebp, esp * ... */ int stackSave = *(sp - 1); *((int *) sp - 1) = (int) fp; fp = (sp - 1); trcStackLvl (fp, pc, pStackBase, pStackLimit, printRtn); *((int *) sp - 1) = stackSave; /* restore saved stack variable */ } 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, pStackBase, pStackLimit, printRtn); } else { trcStackLvl (fp, pc, pStackBase, pStackLimit, printRtn); } }/********************************************************************************* trcStackLvl - recursive stack trace routine** This routine is recursive, being called once for each level of routine* nesting.** INTERNAL* Whether or not the return address is at (frame ptr + 1) really depends* upon whether the current frame was compiled with -msse and whether the* current routine has locals passed from the caller. In the latter case,* EBX is pushed, in addition to EBP and ESI for the former case. The* following fragments illustrate the cases typically encountered when* -msse is used to build a body of code:** int foo (int) { int x; ... }* -------------------------------------------* foo:* 55 push %ebp* 56 push %esi* 53 push %ebx* 89 e6 mov %esp,%esi* ...* foo.aligned:* 55 push %ebp* 56 push %esi* 53 push %ebx* 89 e6 mov %esp,%esi* ...** int foo (int) { ... }* -------------------------------------------* foo:* 55 push %ebp* 56 push %esi* 89 e6 mov %esp,%esi* ...* foo.aligned:* 55 push %ebp* 56 push %esi* 89 e6 mov %esp,%esi* ...** RETURNS: N/A** NOMANUAL*/LOCAL void trcStackLvl ( const int * fp, /* stack frame pointer */ const INSTR * pc, /* program counter */ const char * pStackBase, /* stack bottom (highest memory address) */ const char * pStackLimit, /* stack top (lowest memory address) */ FUNCPTR printRtn /* routine to print single function call */ ) { const INSTR * returnAdrs; /* XXX NOTE XXX * (fp+2) is supposed to represent the stack address of the arguments * passed to this frame. This value should be wrapped in a macro in * case there is a requirement to change it. */ if ((((char *)(fp + 2) + (MAX_TASK_ARGS * sizeof(int))) > pStackBase) || ((char *)(fp) < pStackLimit)) { return; } /* XXX NOTE XXX * This assumption does not work in the case of stack frames generated * with the -msse compiler option. We have to dynamically determine * whether we are in a routine where the return address is at a scaled * offset of 1, 2, or 3 from the frame pointer for the current routine. * * returnAdrs = (const INSTR *) *(fp + 1); */ returnAdrs = trcFindReturnAddr (fp, pc); /* handle oldest calls first */ trcStackLvl ((const int *)(*fp), returnAdrs, pStackBase, pStackLimit, printRtn); (* printRtn) (trcFindCall (returnAdrs), trcFindFuncStart (pc), trcCountArgs (returnAdrs), fp + 2); }/********************************************************************************* trcFindReturnAddr - find the return address of a function** Given a program counter <pc> and a frame pointer <fp> for a function* with an "activated" stack frame, this routine will find the address in* the calling function to which the function will return.** INTERNAL* The Tornado 2.2 cross-compiler subroutine prologues are typically* generated as follows:** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* ...* 8b 65 00 mov 0x0(%ebp),%esp* 5e pop %esi* 5d pop %ebp* c3 ret** = 8b65005e 5dc3 ==> [esp+8] has the return address** OR* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* ...* 8b 65 00 mov 0x0(%ebp),%esp* 5b pop %ebx* 5e pop %esi* 5d pop %ebp* c3 ret** = 8b65 005b5e5d c3 ==> [esp+12] has the return address** In other words, extract unaligned stack pointer from the location* specified in EBP, then get the return address at an offset from the* unaligned stack pointer.** RETURNS: The return address for some active function.** NOMANUAL*/LOCAL const INSTR * trcFindReturnAddr ( const int * fp, /* stack frame pointer */ const INSTR * pc /* program counter */ ) { FOREVER { if (DSM (pc, LEAVE, LEAVE_MASK)) { return (const INSTR *) *(fp + 1); } if (DSM (pc, RET, RET_MASK) || DSM (pc, RETADD, RETADD_MASK)) { if ((UINT32) *(pc - 4) == 0x5d5e5b00) { /* this is not exactly right ... */ fp += 3; return (const INSTR *) (*fp); } else if ((UINT32) *(pc - 4) == 0x5d5e0065) { /* this is not exactly right ... */ fp += 2; return (const INSTR *) (*fp); } ++fp; return (const INSTR *) (*fp); } ++pc; } }/********************************************************************************* 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.** RETURNS: N/A** NOMANUAL*/LOCAL void trcDefaultPrint ( const INSTR * callAdrs, /* address from which function was called */ const INSTR * funcAdrs, /* address of function called */ int nargs, /* number of arguments in function call */ const int * args /* pointer to function args */ ) { int i; BOOL doingDefault = FALSE; /* if there is no printErr routine do nothing */ if (_func_printErr == NULL) return; /* print call address and function address */ (* _func_printErr) ("%8x: %x (", callAdrs, funcAdrs); /* if no args are specified, print out default number (see doc at top) */ if ((nargs == 0) && (trcDefaultArgs != 0)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -