📄 trclib.c
字号:
/* 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)) { doingDefault = TRUE; nargs = trcDefaultArgs; (* _func_printErr) ("["); } /* print args */ for (i = 0; i < nargs; ++i) { if (i != 0) { (* _func_printErr) (", "); } (* _func_printErr) ("%x", args[i]); } 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 */ ) { INSTR * addr; int ix = 0; /* starting at the word preceding the return adrs, search for CALL */ for (addr = returnAdrs - 1; addr != NULL; --addr) { if ((DSM(addr, CALL_INDIR0, CALL_INDIR0_MASK) && DSM(addr+1, CALL_INDIR1, CALL_INDIR1_MASK)) || (DSM(addr, CALL_DIR, CALL_DIR_MASK))) { return (addr); /* found it */ } if (ix++ > MAX_LOOPCOUNT) /* XXX */ { break; } } return (NULL); /* not found */ }/****************************************************************************** trcFindDest - find destination of call instruction** RETURNS: address to which call instruction (CALL) will branch or NULL if* unknown*/LOCAL INSTR * trcFindDest ( INSTR * callAdrs ) { if (DSM(callAdrs, CALL_DIR, CALL_DIR_MASK)) { /* PC relative offset */ int displacement = *(int *)(callAdrs + 1); /* program counter */ INSTR * pc = (INSTR *)((int)callAdrs + 1 + sizeof(int)); return ((INSTR *) ((int)pc + displacement)); } 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*/LOCAL int trcCountArgs ( INSTR * returnAdrs /* return address of function call */ ) { INSTR * addr; int nbytes; /* if inst is a JMP, use the target of the JMP as the returnAdrs */ addr = trcFollowJmp (returnAdrs); if (DSM(addr, ADDI08_0, ADDI08_0_MASK) && DSM(addr+1, ADDI08_1, ADDI08_1_MASK)) { nbytes = *(char *)(addr + 2); } else if (DSM(addr, ADDI32_0, ADDI32_0_MASK) && DSM(addr+1, ADDI32_1, ADDI32_1_MASK)) { nbytes = *(int *)(addr + 2); } else if (DSM(addr, LEAD08_0, LEAD08_0_MASK) && DSM(addr+1, LEAD08_1, LEAD08_1_MASK) && DSM(addr+2, LEAD08_2, LEAD08_2_MASK)) { nbytes = *(char *)(addr + 3); } else if (DSM(addr, LEAD32_0, LEAD32_0_MASK) && DSM(addr+1, LEAD32_1, LEAD32_1_MASK) && DSM(addr+2, LEAD08_2, LEAD08_2_MASK)) { nbytes = *(int *)(addr + 3); } else { nbytes = 0; /* no args, or unknown */ } if (nbytes < 0) nbytes = 0 - nbytes; return (nbytes >> 2); }/****************************************************************************** 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 following the frame pointer 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 pc-relative address. If it was,* use that address as the function address. Note that a routine that is* called by other than a call-direct (e.g. indirectly) will not meet these* requirements.* * If the above check fails, we search backward from the given pc until a* PUSH %EBP MOV %ESP %EBP instruction is found. If the compiler is putting * PUSH %EBP MOV %ESP %EBP instructions* as the first instruction 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, to NOT 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 use. 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 call-direct and* doesn't start with a PUSH %EBP MOV %ESP %EBP and isn't in the symbol table,* may not be possible to locate.*/LOCAL INSTR * trcFindFuncStart ( int * fp, /* frame pointer resulting from function call */ INSTR * pc /* address somewhere within the function */ ) { INSTR * ip; /* instruction pointer */ INSTR * minPc; /* lower bound on program counter */ int val; /* address gotten from symbol table */ SYM_TYPE type; /* type associated with val */ char * pName = NULL; /* string associated with val */ int ix = 0; /* * if there is a symbol table, use value from table that's <= pc as * lower bound for function start */ minPc = NULL; if ((sysSymTbl != NULL) && (symByValueFind (sysSymTbl, (int) pc, &pName, &val, &type) == OK)) { minPc = (INSTR *) val; } if (pName != NULL) { free (pName); /* new API requires this */ } /* try to find current function by looking up call */ if (fp != NULL) /* frame pointer legit? */ { ip = trcFindCall ((INSTR *) *(fp + 1)); if (ip != NULL) { ip = trcFindDest (ip); if ((ip != NULL) && (ip >= minPc) && (ip <= pc)) return (ip); } } /* search backward for PUSH %EBP MOV %ESP %EBP */ for (; pc >= minPc; --pc) { /* XXX * it often causes an exception in excTask then shell doesn't restart. * ip = trcFollowJmp (pc); */ ip = pc; if ((DSM(ip, PUSH_EBP, PUSH_EBP_MASK) && DSM(ip+1, MOV_ESP0, MOV_ESP0_MASK) && DSM(ip+2, MOV_ESP1, MOV_ESP1_MASK)) || (DSM(ip, ENTER, ENTER_MASK))) { return (pc); /* return address of PUSH or ENTER */ } if (ix++ > MAX_LOOPCOUNT) /* XXX */ { break; } } return (minPc); /* return nearest symbol in symtbl */ }/*********************************************************************** trcFollowJmp - resolve any JMP instructions to final destination** This routine returns a pointer to the next non-JMP instruction to be* executed if the pc were at the specified <adrs>. That is, if the instruction* at <adrs> is not a JMP, then <adrs> is returned. Otherwise, if the* instruction at <adrs> is a JMP, then the destination of the JMP is* computed, which then becomes the new <adrs> which is tested as before.* Thus we will eventually return the address of the first non-JMP instruction* to be executed.** The need for this arises because compilers may put JMPs to instructions* that we are interested in, instead of the instruction itself. For example,* optimizers may replace a stack pop with a JMP to a stack pop. Or in very* UNoptimized code, the first instruction of a subroutine may be a JMP to* a PUSH %EBP MOV %ESP %EBP, instead of a PUSH %EBP MOV %ESP %EBP (compiler* may omit routine "post-amble" at end of parsing the routine!). We call* this routine anytime we are looking for a specific kind of instruction,* to help handle such cases.** RETURNS: address that chain of branches points to.*/LOCAL INSTR * trcFollowJmp ( INSTR * addr ) { int displacement; /* PC relative offset */ int length; /* instruction length */ /* while instruction is a JMP, get destination adrs */ while (DSM(addr, JMPD08, JMPD08_MASK) || DSM(addr, JMPD32, JMPD32_MASK)) { if (DSM(addr, JMPD08, JMPD08_MASK)) { displacement = *(char *)(addr + 1); length = 2; addr = (INSTR *) (addr + length + displacement); } else if (DSM(addr, JMPD32, JMPD32_MASK)) { displacement = *(int *)(addr + 1); length = 5; addr = (INSTR *) (addr + length + displacement); } } return (addr); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -