?? trclib.c
字號:
/* trcLib.c - i80x86 stack trace library *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01g,16sep02,pai Cleaned up data types & formatting. Added additional instruction patterns. Moved manifest constants to common header file. Added notes on IA-32 cross-compiler stack frame structures.01f,16jan02,pai replaced obsolete symFindByValue (_func_symFindByValue) with symByValueFind. Removed FAST variable qualifier. Cleaned up formatting and updated copyright for T2.2.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.INTERNALThe IA-32 architecture supports procedure calls in the following twodifferent ways: o CALL and RET instructions. o ENTER and LEAVE instructions, in conjuntion with the CALL and RET instructions.Both of these procedure call mechanisms use the procedure stack ("thestack") to save the state of the calling procedure, pass parameters to thecalled procedure, and store local variables for the currently executingprocedure.The processor's facilities for handling interrupts and exceptions aresimilar to those used by the CALL and RET instructions.The stack is a contiguous array of memory locations. Each VxWorks taskhas its own stack of a size and location specified when the task wascreated.The next available memory location on the stack is called the top ofstack. At any given time, the stack pointer (contained in the ESPregister) gives the address (the offset from the base of the stacksegement) to the top of the stack.Items are placed on the stack using a PUSH instruction and removed fromthe stack using the POP instruction. When an item is pushed onto thestack, the processor decrements the ESP register, then writes the item atthe new top of stack. When an item is popped off the stack, the processorreads the item from the top of stack, then increments the ESP register.In this manner, the stack grows down in memory (towards lower addresses)when items are pushd on the stack and shrinks up (towards higheraddresses) when the items are popped from the stack.The processor provides two pointers for linking of procedures: thestack-frame base pointer and the return instruction pointer. Thesepointers are intended to permit reliable and coherent linking ofprocedures.The stack is typically divided into frames. Each frame can contain localvariables, parameters to be passed to another procedure, and procedurelinking information. The stack-frame base pointer (contained in the EBPregister) identifies a fixed reference point within the stack frame forthe called procedure. To use the stack-frame base pointer, the calledprocedure typically saves the current EBP contents (by pushing theregister), then copies the contents of the ESP register into the EBPregister. The EBP value is then used as a base address for accessingprocedure parameters and local variables for the life of the procedure.Before returning, the procedure will restore ESP from EBP and pop thesaved EBP register value from the stack.Prior to branching to the first instruction of the called procedure, theCALL instruction pushes the address in the EIP register onto the currentstack. This address is then called the return-instruction pointer and itpoints to the instruction where execution of the calling procedure shouldresume following a return from the called procedure. Upon returning froma called procedure, the RET instruction pops the return-instructionpointer from the stack back into the EIP register.The IA-32 processors have a few variations on CALL and RET operations.For example, there are procedure call variations that allow calls todifferent segments and different privilege levels, as well as variationsrelated to interrupt and exception handlers. In addition, arguments canbe passed in registers or on the stack.The IA-32 calling convention for the VxWorks C/C++ cross-compilers andruntime are fairly straight-forward (with one major exception) andconsistent with what is used in several major IA-32 developmentenvironments. Generally C-language source functions are compiled downto procedures using the near CALL and RET operation. When executing anear call, the processor does the following: (1) Parameters to a procedure are pushed on the stack in order from right to left (as the parameters appear in the source code). (2) The CALL instruction pushes the current value of EIP on the stack. (3) The offset of the called procedure is loaded into the EIP register. (4) The called procedure begins executing.When executing a near return, the processor does the following: (1) The return instruction pointer is popped into the EIP register. (2) If the RET instruction has an optional <n> argument, the stack pointer is incremented by the number of bytes specified with the <n> operand to release parameters from the stack. VxWorks code does not do this - the caller cleans the stack, not the callee. (3) Execution is resumed at the caller on instructions that clean the stack (increment the stack pointer) based on the number of parameters passed to the routine being returned from.A hypothetical stack frame for a routine with (3) 32-bit paramaters and (2)local variables might appear as follows:.bS High Memory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Previous ESP -->| | |------------------------------| Stack grows downwards | parameter 3 | | |------------------------------| | | parameter 2 | | |------------------------------| v | parameter 1 | [EBP+8] |------------------------------| | return address | [EBP+4] |------------------------------|New EBP ------->| previous EBP | [EBP] |------------------------------| | local variable 1 | [EBP-4] |------------------------------|New ESP ------->| local variable 2 | [EBP-8] |------------------------------| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Low Memory.bEIn the example above, the EBP register is used as the stack "frame pointer".The EBP register, once initialized on function entry, can be used to accessany of the procedure parameters and local variables in addition to theprocedure return address. The usual prologue and epilogue code used tosupport this model is as follows (Intel assembly syntax):.CS foo: push ebp mov ebp, esp ... mov esp, ebp pop ebp ret.CEThe ENTER and LEAVE instructions support an alternate method for creatingand destroying stack frames. The ENTER instruction has two operands. Itis not necessary to understand the use of these operands in this stacktracing library. With respect to ENTER and LEAVE instructions, it isimportant to note that an EBP-based stack frame is created and destroyedin a manner that is equivalent to the preceding example..CS foo: enter m,n ; push EBP, then copy ESP to EBP ... leave ; copy EBP to ESP, then pop EBP ret.CEThe Tornado 2.2 IA-32 cross-compiler does not generate subroutine stacksetup code in the manner described above when the -msse compiler flag isused. The -msse flag will cause the compiler to generate prologue andepilogue code which is used to dynamically align stack variables on16-byte addresses, as required for most SSE/SSE2 memory operands. Themechanics behind this alignment and other SSE/SSE2 ABI conventionsintroduced in the Intel compiler are discussed in the Intel ApplicationNote AP-589. Note that the Tornado 2.2 IA-32 cross-compiler (version2.9-PentiumIII-010221) is essentially the "Intel C/C++ Compiler".A 128-bit vendor-specific data type named __m128 may imply the followingextensions to the IA-32 ABI: o Functions that use Streaming SIMD Extensions data provide a 16-byte-aligned stack frame. o __m128 parameters are aligned, possibly creating "holes" (padding) in the argument block. o __m128 parameters may be passed in registers. o The first (3) __m128 parameters are passed in registers xmm0, xmm1, and xmm2. Additional __m128 parameters are passed on the stack as usual. o __m128 return values are passed in xmm0. o Registers xmm0 through xmm7 are caller-save.Subroutines that use the __m128 data type must have 16-byte-aligned stackframes (for local variables of type __m128) to meet alignment requirementsfor SSE memory operands.The current Intel compiler resolves the 16-byte-alignment requirement byinserting function prologue and epilogue code to dynamically align the stackappropriately.As an optimization, an alternate entry point will be created that can becalled when proper stack alignment is guaranteed by the caller. Throughcall graph analysis, calls to the unaligned entry point can be optimizedinto calls to the aligned entry point when the stack can be proven to beproperly aligned.SEE ALSO: dbgLib, tt(),.pG "Debugging"*//* includes */#include "vxWorks.h"#include "dbgLib.h"#include "regs.h"#include "stdio.h"#include "stdlib.h"#include "symLib.h"#include "sysSymTbl.h"#include "taskLib.h"#include "private/funcBindP.h"/* imports */IMPORT int vxTaskEntry ();/* globals *//* default number of arguments printed from trcDefaultPrint() */int trcDefaultArgs = 5;/* forward declarations */LOCAL const INSTR * trcFindCall (const INSTR *);LOCAL const INSTR * trcFindFuncStart (const INSTR *);LOCAL const INSTR * trcFindReturnAddr (const int *, const INSTR *);LOCAL const INSTR * trcFindDest (const INSTR *);LOCAL const INSTR * trcFollowJmp (const INSTR *);LOCAL void trcDefaultPrint (const INSTR *, const INSTR *, int, const int *);LOCAL void trcStackLvl (const int *, const INSTR *, const char *, const char *, FUNCPTR);LOCAL int trcCountArgs (const INSTR *);/********************************************************************************* 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* (* 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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -