📄 trclib.c
字号:
(val == (int) pc))) { /* no stack frame - fake one */ stackSave[0] = *(sp - 1); /* save values we're going to clobber */ stackSave[1] = *(sp - 2); stackSave[2] = *(sp - 3); stackSave[3] = *(sp - 4); *(sp - 1) = (int)pc;#if (ARM_THUMB) *(sp - 2) = (int)lr; /* use the extracted return address */#else *(sp - 2) = (int)pRegSet->r[14];#endif *(sp - 3) = (int)pRegSet->spReg; *(sp - 4) = (int)fp; fp = sp - 1; /* points at saved PC */ if (vxMemProbe ((char *)fp, VX_READ, 2, (char *)&insn) != OK || tcb->pStackBase < (char *)fp || tcb->pStackEnd > (char *)fp || vxMemProbe ((char *)pc, VX_READ, 2, (char *)&insn) != OK) { if (_func_printErr != NULL) (* _func_printErr) ("trcStack aborted: error in top frame\n"); return; /* stack is untraceable */ } trcStackLvl (tcb, fp, pc, 0, printRtn); /* do stack trace */ *(sp - 1) = stackSave[0]; /* restore stack */ *(sp - 2) = stackSave[1]; *(sp - 3) = stackSave[2]; *(sp - 4) = stackSave[3]; } else { if (vxMemProbe ((char *)fp, VX_READ, 2, (char *)&insn) != OK || tcb->pStackBase < (char *)fp || tcb->pStackEnd > (char *)fp || vxMemProbe ((char *)pc, VX_READ, 2, (char *)&insn) != OK) { if (_func_printErr != NULL) (* _func_printErr) ("trcStack aborted: error in top frame\n"); return; /* stack is untraceable */ } trcStackLvl (tcb, 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 ( WIND_TCB *tcb, /* task control block */ FAST int *fp, /* stack frame pointer */ INSTR *pc, /* program counter */ int depth, /* recursion depth */ FUNCPTR printRtn /* routine to print single function call */ ) { FAST INSTR *returnAdrs; INSTR insn; if (fp == NULL || vxMemProbe ((char *)fp, VX_READ, 2, (char *)&insn) != OK || vxMemProbe ((char *)(fp - 1), VX_READ, 2, (char *)&insn) != OK || vxMemProbe ((char *)(fp - 3), VX_READ, 2, (char *)&insn) != OK || tcb->pStackBase < (char *)fp || tcb->pStackEnd > (char *)fp || vxMemProbe ((char *)pc, VX_READ, 2, (char *)&insn) != OK) { if (_func_printErr != NULL) (* _func_printErr) ("trcStack aborted: error in frame\n"); return; /* stack is untraceable */ } returnAdrs = (INSTR *) *(fp - 1); /* * Handle oldest calls first, up to MAX_TRACE_DEPTH of them * Note: unlike on other architectures, the previous fp is not * found at *fp but at *(fp - 3). */ if ((*(fp - 3) != 0) && (depth < MAX_TRACE_DEPTH)) trcStackLvl (tcb, (int *) *(fp - 3), returnAdrs, depth + 1, printRtn); (* printRtn) (trcFindCall (returnAdrs), trcFindFuncStart (fp, pc), trcCountArgs (returnAdrs), fp + 1); }/********************************************************************************* 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.** NOTE: no args can be printed as code generator of gccarm provides no* way to determine what they are.*/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 ix; BOOL doingDefault = FALSE; /* if there is no printErr routine do nothing */ if (_func_printErr == NULL) return; /* print call address and function address */ (* _func_printErr) ("%6x: %x (", callAdrs, funcAdrs); /* if no args are specified, print out default number (see doc at top) */ if ((nargs == 0) && (trcDefaultArgs != 0)) { doingDefault = TRUE; nargs = trcDefaultArgs; (* _func_printErr) ("["); } /* print args */ for (ix = 0; ix < nargs; ++ix) { if (ix != 0) (* _func_printErr) (", "); (* _func_printErr) ("%x", args[ix]); } if (doingDefault) (* _func_printErr) ("]"); (* _func_printErr) (")\n"); }/********************************************************************************* trcFindCall - get address from which function was called** RETURNS: address from which current subroutine was called, or NULL.*/LOCAL INSTR *trcFindCall ( INSTR *returnAdrs /* return address */ ) { FAST INSTR *addr; INSTR insn; /* check for bad return address */ if (returnAdrs == NULL || vxMemProbe ((char *)returnAdrs, VX_READ, 2, (char *)&insn) != OK) { return NULL; } /* * Starting at the word preceding the return adrs, search for an * instruction which changes the PC. The ARM version, just like the 68K * one, keeps stepping back until it finds one or hits 0. It could stop * after n instructions. */#if (ARM_THUMB) /* return address will have bit 0 set; mask it off */ for (addr = (INSTR *)((UINT32)returnAdrs & ~1) - 1; addr != NULL; --addr) if (thumbInstrChangesPc(addr)) return addr; /* found it */#else for (addr = returnAdrs - 1; addr != NULL; --addr) if (armInstrChangesPc(addr)) return addr; /* found it */#endif return NULL; /* not found */ }/********************************************************************************* trcFindDest - find destination of call instruction** RETURNS: address to which call instruction will branch, or NULL if* unknown*/LOCAL INSTR *trcFindDest ( INSTR *callAdrs ) { /* * Extract offset, sign extend it and add it to current PC, * adjusting for the pipeline. */#if (ARM_THUMB) /* BL comes in two halves */ if (INSTR_IS(*callAdrs, T_BL0) && INSTR_IS(*(callAdrs + 1), T_BL1)) return (INSTR *)((INT32)callAdrs + 4 + (((((INT32)*callAdrs) << 21) >> 9) | ((((INT32)*(callAdrs+1)) & 0x07FF) << 1)));#else if (INSTR_IS(*callAdrs, BL)) return (INSTR *)((INT32)callAdrs + 8 + ((INT32)(*callAdrs << 8) >> 6));#endif return NULL; /* don't know destination */ }/********************************************************************************* trcCountArgs - find number of arguments to function** This routine finds the number of arguments passed to the called function* by examining the stack-pop at the return address. Many compilers offer* optimization that defeats this (e.g., by coalescing stack-pops), so a return* value of 0 may mean "don't know".** RETURNS: number of arguments of function** NOTE: no args can be printed as code generator of gccarm provides no* way to determine what they are.*/LOCAL int trcCountArgs ( FAST INSTR *returnAdrs /* return address of function call */ ) { return 0; /* no args or unknown */ }/********************************************************************************* trcFindFuncStart - find the starting address of a function** This routine finds the starting address of a function by one of several ways.** If the given frame pointer points to a legitimate frame pointer, then the* long word preceding the long word pointed to by the frame pointer should* be the return address of the function call. Then the instruction preceding* the return address would be the function call, and the address can be gotten* from there, provided that the call was to an absolute address. If it was,* use that address as the function address. Note that a routine that is* called by other than a BL (e.g., indirectly) will not meet these* requirements.** If the above check fails, we search backward from the given pc until a* routine entry sequence is found (see trcStack() above for description of* routine prologues).** If the compiler is inserting these sequences at the beginning of ALL* subroutines, then this will reliably find the start of the routine.* However, some compilers allow routines, especially "leaf" routines that* don't call any other routines, NOT to have stack frames, which will cause* this search to fail.** In either of the above cases, the value is bounded by the nearest routine* in the system symbol table, if there is one. If neither method returns a* legitimate value, then the value from the symbol table is used. Note that* the routine may not be in the symbol table if it is LOCAL, etc.** Note that the start of a routine that is not called by BL and* doesn't start with a frame creation sequence and isn't in the symbol table,* may not be possible to locate.*/LOCAL INSTR *trcFindFuncStart ( int *fp, /* frame pointer resulting from function call */ FAST INSTR *pc /* address somewhere within the function */ ) { FAST INSTR *ip; /* instruction pointer */ FAST INSTR *minPc; /* lower bound on program counter */ 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 insn; /* * if there is a symbol table, use value from table that's <= pc as * lower bound for function start */ minPc = NULL; if ((sysSymTbl != NULL) && (_func_symFindByValue != NULL) && ((* _func_symFindByValue) (sysSymTbl, (int) pc, name, &val, &type) == OK)) { minPc = (INSTR *) val; } /* try to find current function by looking up call */ if (fp != NULL && vxMemProbe ((char *)(fp - 1), VX_READ, 2, (char *)&insn) == OK) /* frame pointer valid? */ { ip = trcFindCall ((INSTR *) *(fp - 1)); if (ip != NULL) { ip = trcFindDest (ip); if ((ip != NULL) && (ip >= minPc) && (ip <= pc)) return (ip); } } /* * Search backward for routine entry sequence (prologue), * for possible sequences, refer to trcStack() above. */#if (ARM_THUMB) for (; pc >= minPc; --pc) { if ((INSTR_IS(pc[0], T_PUSH_LO) && INSTR_IS(pc[1], T_SUB_SP_16) && INSTR_IS(pc[2], T_PUSH) && INSTR_IS(pc[3], T_ADD_LO_SP)) || (INSTR_IS(pc[0], T_SUB_SP_16) && INSTR_IS(pc[1], T_PUSH) && INSTR_IS(pc[2], T_ADD_LO_SP)) || (INSTR_IS(pc[0], T_SUB_SP_16) && INSTR_IS(pc[1], T_ADD_LO_SP))) return pc; /* return address of first instruction of prologue */ }#else for (; pc >= minPc; --pc) { if (INSTR_IS(pc[0], MOV_IP_SP) && ((INSTR_IS(pc[1], STMDB_SPP_FP_IP_LR_PC) && INSTR_IS(pc[2], SUB_FP_IP_4)) || (INSTR_IS(pc[2], STMDB_SPP_FP_IP_LR_PC) && INSTR_IS(pc[3], SUB_FP_IP_4PLUS) && (INSTR_IS(pc[1], STMDB_SPP_AREGS) || INSTR_IS(pc[1], SUB_SP_SP))))) return pc; /* return address of MOV ip,sp */ }#endif return minPc; /* return nearest symbol in sym tbl */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -