trcLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:20k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* trcLib.c - i80x86 stack trace library */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01f,16jan02,pai  replaced obsolete symFindByValue (_func_symFindByValue) with
  8.                  symByValueFind.  Removed FAST variable qualifier.
  9.                  Cleaned up formatting and updated copyright for T2.2.
  10. 01e,12may95,p_m  adapted to support host based tt().
  11. 01d,26oct94,hdn  added a MAX_LOOPCOUNT to avoid infinite loop.
  12. 01c,09dec93,hdn  added a forward declaration of trcCountArgs().
  13.                  commented out trcFollowJmp(pc) in trcFindFuncStart().
  14. 01b,01jun93,hdn  added third parameter tid to trcStack().
  15.                  updated to 5.1.
  16.                   - changed functions to ansi style
  17.                   - changed VOID to void
  18.                   - changed copyright notice
  19. 01a,16jul92,hdn  written based on TRON version.
  20. */
  21. /*
  22. This module provides a routine, trcStack(), which traces a stack
  23. given the current frame pointer, stack pointer, and program counter.
  24. The resulting stack trace lists the nested routine calls and their arguments.
  25. This module provides the low-level stack trace facility.
  26. A higher-level symbolic stack trace, implemented on top of this facility,
  27. is provided by the routine tt() in dbgLib.
  28. SEE ALSO: dbgLib, tt(),
  29. .pG "Debugging"
  30. */
  31. #include "vxWorks.h"
  32. #include "regs.h"
  33. #include "stdio.h"
  34. #include "stdlib.h"
  35. #include "symLib.h"
  36. #include "sysSymTbl.h"
  37. #include "private/funcBindP.h"
  38. #define MAX_TRACE_DEPTH       40  /* max number of levels of stack to trace */
  39. #define MAX_LOOPCOUNT        128  /* max loop count */
  40. /* instruction patterns and masks */
  41. #define ADDI08_0                0x83
  42. #define ADDI08_1                0xc4
  43. #define ADDI32_0                0x81
  44. #define ADDI32_1                0xc4
  45. #define LEAD08_0                0x8d
  46. #define LEAD08_1                0x64
  47. #define LEAD08_2                0x24
  48. #define LEAD32_0                0x8d
  49. #define LEAD32_1                0xa4
  50. #define LEAD32_2                0x24
  51. #define JMPD08                  0xeb
  52. #define JMPD32                  0xe9
  53. #define ENTER                   0xc8
  54. #define PUSH_EBP                0x55
  55. #define MOV_ESP0                0x89
  56. #define MOV_ESP1                0xe5
  57. #define LEAVE                   0xc9
  58. #define RET                     0xc3
  59. #define RETADD                  0xc2
  60. #define CALL_DIR                0xe8
  61. #define CALL_INDIR0             0xff
  62. #define CALL_INDIR1             0x10
  63. #define ADDI08_0_MASK           0xff
  64. #define ADDI08_1_MASK           0xff
  65. #define ADDI32_0_MASK           0xff
  66. #define ADDI32_1_MASK           0xff
  67. #define LEAD08_0_MASK           0xff
  68. #define LEAD08_1_MASK           0xff
  69. #define LEAD08_2_MASK           0xff
  70. #define LEAD32_0_MASK           0xff
  71. #define LEAD32_1_MASK           0xff
  72. #define LEAD32_2_MASK           0xff
  73. #define JMPD08_MASK             0xff
  74. #define JMPD32_MASK             0xff
  75. #define ENTER_MASK              0xff
  76. #define PUSH_EBP_MASK           0xff
  77. #define MOV_ESP0_MASK           0xff
  78. #define MOV_ESP1_MASK           0xff
  79. #define LEAVE_MASK              0xff
  80. #define RET_MASK                0xff
  81. #define RETADD_MASK             0xff
  82. #define CALL_DIR_MASK           0xff
  83. #define CALL_INDIR0_MASK        0xff
  84. #define CALL_INDIR1_MASK        0x38
  85. #define DSM(addr,inst,mask)     ((*(addr) & (mask)) == (inst))
  86. /* globals */
  87. int trcDefaultArgs = 5;         /* default # of args to print if trc
  88.                                  * can't figure out how many */
  89. /* forward declarations */
  90. LOCAL INSTR * trcFindCall (INSTR * returnAdrs);
  91. LOCAL INSTR * trcFindFuncStart (int * fp, INSTR * pc);
  92. LOCAL INSTR * trcFindDest (INSTR * callAdrs);
  93. LOCAL INSTR * trcFollowJmp (INSTR * addr);
  94. LOCAL void    trcDefaultPrint (INSTR * callAdrs, INSTR * funcAdrs, int nargs,
  95.                                int * args);
  96. LOCAL void    trcStackLvl (int * fp, INSTR * pc, int depth, FUNCPTR printRtn);
  97. LOCAL int     trcCountArgs (INSTR * returnAdrs);
  98. /*******************************************************************************
  99. *
  100. * trcStack - print a trace of function calls from the stack
  101. *
  102. * This routine provides the low-level stack trace function.  A higher-level
  103. * symbolic stack trace, built on top of trcStack(), is provided by tt() in
  104. * dbgLib.
  105. *
  106. * This routine prints a list of the nested routine calls that are on the
  107. * stack, showing each routine with its parameters.
  108. *
  109. * The stack being traced should be quiescent.  The caller should avoid
  110. * tracing its own stack.
  111. *
  112. * PRINT ROUTINE
  113. * In order to allow symbolic or alternative printout formats, the call to
  114. * this routine includes the <printRtn> parameter, which specifies a
  115. * user-supplied routine to be called at each nesting level to print out the
  116. * routine name and its arguments.  This routine should be declared as
  117. * follows:
  118. * .ne 7
  119. * .CS
  120. *     void printRtn
  121. *         (
  122. *         INSTR *  callAdrs,  /@ address from which routine was called @/
  123. *         int      rtnAdrs,   /@ address of routine called             @/
  124. *         int      nargs,     /@ number of arguments in call           @/
  125. *         int *    args       /@ pointer to arguments                  @/
  126. *         )
  127. * .CE
  128. * If <printRtn> is NULL, a default routine will be used that prints out just
  129. * the call address, the function address, and the arguments as hexadecimal
  130. * values.
  131. *
  132. * CAVEAT
  133. * In order to do the trace, a number of assumptions are made.  In general,
  134. * the trace will work for all C language routines and for assembly language
  135. * routines that start with an PUSH %EBP MOV %ESP %EBP instruction.  Most 
  136. * VxWorks assembly language routines include PUSH %EBP MOV %ESP %EBP 
  137. * instructions for exactly this reason.
  138. * However, routines written in other languages, strange entries into
  139. * routines, or tasks with corrupted stacks can confuse the trace.  Also,
  140. * all parameters are assumed to be 32-bit quantities, therefore structures
  141. * passed as parameters will be displayed as a number of long integers.
  142. *
  143. * EXAMPLE
  144. * The following sequence can be used
  145. * to trace a VxWorks task given a pointer to the task's TCB:
  146. * .CS
  147. * REG_SET regSet;        /@ task's data registers @/
  148. *
  149. * taskRegsGet (taskId, &regSet);
  150. * trcStack (&regSet, (FUNCPTR)printRtn, tid);
  151. * .CE
  152. *
  153. * SEE ALSO: tt()
  154. *
  155. * NOMANUAL
  156. */
  157. void trcStack
  158.     (
  159.     REG_SET * pRegSet,        /* pointer to register set */
  160.     FUNCPTR   printRtn,       /* routine to print single function call */
  161.     int       tid             /* task's id */
  162.     )
  163.     {
  164.     int       val;            /* address gotten from symbol table */
  165.     SYM_TYPE  type;           /* type associated with val */
  166.     INSTR *   addr;           /* next instruction */
  167.     int       stackSave;
  168.     char *    pName = NULL;   /* string associated with val */
  169.     INSTR *   pc    = pRegSet->pc;             /* program counter */
  170.     int *     fp    = (int *)pRegSet->fpReg;   /* stack frame pointer (EBP) */
  171.     int *     sp    = (int *)pRegSet->spReg;   /* stack pointer */
  172.     /* use default print routine if none specified */
  173.     if (printRtn == NULL)
  174.         printRtn = (FUNCPTR)trcDefaultPrint;
  175.     /*
  176.      * if the current routine doesn't have a stack frame, then we fake one
  177.      * by putting the old one on the stack and making fp point to that;
  178.      * we KNOW we don't have a stack frame in a few restricted but useful
  179.      * cases:
  180.      *  1) we are at a PUSH %EBP MOV %ESP %EBP or RET or ENTER instruction,
  181.      *  2) we are the first instruction of a subroutine (this may NOT be
  182.      *     a PUSH %EBP MOV %ESP %EBP instruction with some compilers)
  183.      */
  184.     addr = trcFollowJmp (pc);
  185.     if ((DSM(addr,   PUSH_EBP, PUSH_EBP_MASK) && 
  186.          DSM(addr+1, MOV_ESP0, MOV_ESP0_MASK) &&
  187.          DSM(addr+2, MOV_ESP1, MOV_ESP1_MASK)) ||
  188.         (DSM(addr,   ENTER,    ENTER_MASK))    ||
  189.         (DSM(addr,   RET,      RET_MASK))      ||
  190.         (DSM(addr,   RETADD,   RETADD_MASK))   ||
  191.         ((sysSymTbl != NULL) &&
  192.          (symByValueFind (sysSymTbl, (UINT) pc, &pName, &val, &type) == OK) &&
  193.          (val == (int) pc)))
  194.         {
  195.         /* no stack frame - fake one */
  196.         stackSave = *(sp - 1);      /* save value we're going to clobber */
  197.         *(sp - 1) = (int)fp;        /* make new frame pointer by */
  198.                                     /* sticking old one on stack */
  199.         fp = sp - 1;                /* and pointing to it */
  200.         trcStackLvl (fp, pc, 0, printRtn);        /* do stack trace */
  201.         *(sp - 1) = stackSave;                    /* restore stack */
  202.         }
  203.     else if ((DSM(addr-1, PUSH_EBP, PUSH_EBP_MASK) && 
  204.               DSM(addr,   MOV_ESP0, MOV_ESP0_MASK) &&
  205.               DSM(addr+1, MOV_ESP1, MOV_ESP1_MASK)))
  206.         {
  207.         fp = sp;
  208.         trcStackLvl (fp, pc, 0, printRtn);        /* do stack trace */
  209.         }
  210.     else
  211.         {
  212.         trcStackLvl (fp, pc, 0, printRtn);        /* do stack trace */
  213.         }
  214.     if (pName != NULL)
  215.         {
  216.         free (pName);  /* new API requires this */
  217.         }
  218.     }
  219. /************************************************************************
  220. *
  221. * trcStackLvl - recursive stack trace routine
  222. *
  223. * This routine is recursive, being called once for each level of routine
  224. * nesting.  The maximum recursion depth is limited to 40 to prevent
  225. * garbage stacks from causing this routine to continue unbounded.
  226. * The "depth" parameter on the original call should be 0.
  227. */
  228. LOCAL void trcStackLvl
  229.     (
  230.     int *    fp,        /* stack frame pointer (EBP) */
  231.     INSTR *  pc,        /* program counter */
  232.     int      depth,     /* recursion depth */
  233.     FUNCPTR  printRtn   /* routine to print single function call */
  234.     )
  235.     {
  236.     INSTR *  returnAdrs;
  237.     if (fp == NULL)
  238.         return;        /* stack is untraceable */
  239.     returnAdrs = (INSTR *) *(fp + 1);
  240.     /* handle oldest calls first, up to MAX_TRACE_DEPTH of them */
  241.     if (((void *)*fp != NULL) && (depth < MAX_TRACE_DEPTH))
  242.         {
  243.         trcStackLvl ((int *) *fp, returnAdrs, depth + 1, printRtn);
  244.         }
  245.     (* printRtn) (trcFindCall (returnAdrs), trcFindFuncStart (fp, pc),
  246.                   trcCountArgs (returnAdrs), fp + 2);
  247.     }
  248. /*******************************************************************************
  249. *
  250. * trcDefaultPrint - print a function call
  251. *
  252. * This routine is called by trcStack to print each level in turn.
  253. *
  254. * If nargs is specified as 0, then a default number of args (trcDefaultArgs)
  255. * is printed in brackets ("[..]"), since this often indicates that the
  256. * number of args is unknown.
  257. */
  258. LOCAL void trcDefaultPrint
  259.     (
  260.     INSTR * callAdrs,   /* address from which function was called */
  261.     INSTR * funcAdrs,   /* address of function called */
  262.     int     nargs,      /* number of arguments in function call */
  263.     int *   args        /* pointer to function args */
  264.     )
  265.     {
  266.     int     i;
  267.     BOOL    doingDefault = FALSE;
  268.     /* if there is no printErr routine do nothing */
  269.     if (_func_printErr == NULL)
  270.         return;
  271.     /* print call address and function address */
  272.     (* _func_printErr) ("%8x: %x (", callAdrs, funcAdrs);
  273.     /* if no args are specified, print out default number (see doc at top) */
  274.     if ((nargs == 0) && (trcDefaultArgs != 0))
  275.         {
  276.         doingDefault = TRUE;
  277.         nargs = trcDefaultArgs;
  278.         (* _func_printErr) ("[");
  279.         }
  280.     /* print args */
  281.     for (i = 0; i < nargs; ++i)
  282.         {
  283.         if (i != 0)
  284.             {
  285.             (* _func_printErr) (", ");
  286.             }
  287.         (* _func_printErr) ("%x", args[i]);
  288.         }
  289.     if (doingDefault)
  290.         {
  291.         (* _func_printErr) ("]");
  292.         }
  293.     (* _func_printErr) (")n");
  294.     }
  295. /****************************************************************************
  296. *
  297. * trcFindCall - get address from which function was called
  298. *
  299. * RETURNS: address from which current subroutine was called, or NULL.
  300. */
  301. LOCAL INSTR * trcFindCall
  302.     (
  303.     INSTR * returnAdrs     /* return address */
  304.     )
  305.     {
  306.     INSTR * addr;
  307.     int     ix = 0;
  308.     /* starting at the word preceding the return adrs, search for CALL */
  309.     for (addr = returnAdrs - 1; addr != NULL; --addr)
  310.         {
  311.         if ((DSM(addr,   CALL_INDIR0, CALL_INDIR0_MASK) &&
  312.              DSM(addr+1, CALL_INDIR1, CALL_INDIR1_MASK)) ||
  313.             (DSM(addr,   CALL_DIR,    CALL_DIR_MASK)))
  314.             {
  315.             return (addr);              /* found it */
  316.             }
  317.         if (ix++ > MAX_LOOPCOUNT)       /* XXX */
  318.             {
  319.             break;
  320.             }
  321.         }
  322.     return (NULL);                      /* not found */
  323.     }
  324. /****************************************************************************
  325. *
  326. * trcFindDest - find destination of call instruction
  327. *
  328. * RETURNS: address to which call instruction (CALL) will branch or NULL if
  329. * unknown
  330. */
  331. LOCAL INSTR * trcFindDest
  332.     (
  333.     INSTR * callAdrs
  334.     )
  335.     {
  336.     if (DSM(callAdrs, CALL_DIR, CALL_DIR_MASK))
  337.         {
  338.         /* PC relative offset */
  339.         int displacement = *(int *)(callAdrs + 1);
  340.         /* program counter */
  341.         INSTR * pc = (INSTR *)((int)callAdrs + 1 + sizeof(int));
  342.         return ((INSTR *) ((int)pc + displacement));
  343.         }
  344.     
  345.     return (NULL);           /* don't know destination */
  346.     }
  347. /****************************************************************************
  348. *
  349. * trcCountArgs - find number of arguments to function
  350. *
  351. * This routine finds the number of arguments passed to the called function
  352. * by examining the stack-pop at the return address.  Many compilers offer
  353. * optimization that defeats this (e.g. by coalescing stack-pops), so a return
  354. * value of 0, may mean "don't know".
  355. *
  356. * RETURNS: number of arguments of function
  357. */
  358. LOCAL int trcCountArgs
  359.     (
  360.     INSTR * returnAdrs    /* return address of function call */
  361.     )
  362.     {
  363.     INSTR * addr;
  364.     int     nbytes;
  365.     /* if inst is a JMP, use the target of the JMP as the returnAdrs */
  366.     addr = trcFollowJmp (returnAdrs);
  367.     if (DSM(addr,   ADDI08_0, ADDI08_0_MASK) &&
  368.         DSM(addr+1, ADDI08_1, ADDI08_1_MASK))
  369.         {
  370.         nbytes = *(char *)(addr + 2);
  371.         }
  372.     else if (DSM(addr,   ADDI32_0, ADDI32_0_MASK) &&
  373.              DSM(addr+1, ADDI32_1, ADDI32_1_MASK))
  374.         {
  375.         nbytes = *(int *)(addr + 2);
  376.         }
  377.     else if (DSM(addr,   LEAD08_0, LEAD08_0_MASK) &&
  378.              DSM(addr+1, LEAD08_1, LEAD08_1_MASK) &&
  379.              DSM(addr+2, LEAD08_2, LEAD08_2_MASK))
  380.         {
  381.         nbytes = *(char *)(addr + 3);
  382.         }
  383.     else if (DSM(addr,   LEAD32_0, LEAD32_0_MASK) &&
  384.              DSM(addr+1, LEAD32_1, LEAD32_1_MASK) &&
  385.              DSM(addr+2, LEAD08_2, LEAD08_2_MASK))
  386.         {
  387.         nbytes = *(int *)(addr + 3);
  388.         }
  389.     else
  390.         {
  391.         nbytes = 0;                                /* no args, or unknown */
  392.         }
  393.     if (nbytes < 0)
  394.         nbytes = 0 - nbytes;
  395.     return (nbytes >> 2);
  396.     }
  397. /****************************************************************************
  398. *
  399. * trcFindFuncStart - find the starting address of a function
  400. *
  401. * This routine finds the starting address of a function by one of several ways.
  402. *
  403. * If the given frame pointer points to a legitimate frame pointer, then the
  404. * long word following the frame pointer pointed to by the frame pointer should
  405. * be the return address of the function call. Then the instruction preceding
  406. * the return address would be the function call, and the address can be gotten
  407. * from there, provided that the CALL was to an pc-relative address. If it was,
  408. * use that address as the function address.  Note that a routine that is
  409. * called by other than a call-direct (e.g. indirectly) will not meet these
  410. * requirements.
  411. * If the above check fails, we search backward from the given pc until a
  412. * PUSH %EBP MOV %ESP %EBP instruction is found.  If the compiler is putting 
  413. * PUSH %EBP MOV %ESP %EBP instructions
  414. * as the first instruction of ALL subroutines, then this will reliably find
  415. * the start of the routine.  However, some compilers allow routines, especially
  416. * "leaf" routines that don't call any other routines, to NOT have stack frames,
  417. * which will cause this search to fail.
  418. *
  419. * In either of the above cases, the value is bounded by the nearest
  420. * routine in the system symbol table, if there is one.
  421. * If neither method returns a legitimate value, then the value from the
  422. * symbol table is use.  Note that the routine may not be in the
  423. * symbol table if it is LOCAL, etc.
  424. *
  425. * Note that the start of a routine that is not called by call-direct and
  426. * doesn't start with a PUSH %EBP MOV %ESP %EBP and isn't in the symbol table,
  427. * may not be possible to locate.
  428. */
  429. LOCAL INSTR * trcFindFuncStart
  430.     (
  431.     int *    fp,              /* frame pointer resulting from function call */
  432.     INSTR *  pc               /* address somewhere within the function */
  433.     )
  434.     {
  435.     INSTR *  ip;              /* instruction pointer */
  436.     INSTR *  minPc;           /* lower bound on program counter */
  437.     int      val;             /* address gotten from symbol table */
  438.     SYM_TYPE type;            /* type associated with val */
  439.     char *   pName = NULL;    /* string associated with val */
  440.     int      ix    = 0;
  441.     /*
  442.      * if there is a symbol table, use value from table that's <= pc as
  443.      * lower bound for function start 
  444.      */
  445.     minPc = NULL;
  446.     if ((sysSymTbl != NULL) && (symByValueFind
  447.         (sysSymTbl, (int) pc, &pName, &val, &type) == OK))
  448.         {
  449.         minPc = (INSTR *) val;
  450.         }
  451.     if (pName != NULL)
  452.         {
  453.         free (pName);  /* new API requires this */
  454.         }
  455.     /* try to find current function by looking up call */
  456.     if (fp != NULL)    /* frame pointer legit? */
  457.         {
  458.         ip = trcFindCall ((INSTR *) *(fp + 1));
  459.         if (ip != NULL)
  460.             {
  461.             ip = trcFindDest (ip);
  462.             if ((ip != NULL) && (ip >= minPc) && (ip <= pc))
  463.                 return (ip);
  464.             }
  465.         }
  466.     /* search backward for PUSH %EBP MOV %ESP %EBP */
  467.     for (; pc >= minPc; --pc)
  468.         {
  469.         /* XXX 
  470.          * it often causes an exception in excTask then shell doesn't restart.
  471.          * ip = trcFollowJmp (pc);
  472.          */
  473.         ip = pc;
  474.         if ((DSM(ip,   PUSH_EBP, PUSH_EBP_MASK) &&
  475.              DSM(ip+1, MOV_ESP0, MOV_ESP0_MASK) &&
  476.              DSM(ip+2, MOV_ESP1, MOV_ESP1_MASK)) ||
  477.             (DSM(ip,   ENTER,    ENTER_MASK)))
  478.             {
  479.             return (pc);             /* return address of PUSH or ENTER */
  480.             }
  481.         if (ix++ > MAX_LOOPCOUNT)    /* XXX */
  482.             {
  483.             break;
  484.             }
  485.         }
  486.     return (minPc);   /* return nearest symbol in symtbl */
  487.     }
  488. /*********************************************************************
  489. *
  490. * trcFollowJmp - resolve any JMP instructions to final destination
  491. *
  492. * This routine returns a pointer to the next non-JMP instruction to be
  493. * executed if the pc were at the specified <adrs>.  That is, if the instruction
  494. * at <adrs> is not a JMP, then <adrs> is returned.  Otherwise, if the
  495. * instruction at <adrs> is a JMP, then the destination of the JMP is
  496. * computed, which then becomes the new <adrs> which is tested as before.
  497. * Thus we will eventually return the address of the first non-JMP instruction
  498. * to be executed.
  499. *
  500. * The need for this arises because compilers may put JMPs to instructions
  501. * that we are interested in, instead of the instruction itself.  For example,
  502. * optimizers may replace a stack pop with a JMP to a stack pop.  Or in very
  503. * UNoptimized code, the first instruction of a subroutine may be a JMP to
  504. * a PUSH %EBP MOV %ESP %EBP, instead of a PUSH %EBP MOV %ESP %EBP (compiler
  505. * may omit routine "post-amble" at end of parsing the routine!).  We call
  506. * this routine anytime we are looking for a specific kind of instruction,
  507. * to help handle such cases.
  508. *
  509. * RETURNS: address that chain of branches points to.
  510. */
  511. LOCAL INSTR * trcFollowJmp
  512.     (
  513.     INSTR * addr
  514.     )
  515.     {
  516.     int     displacement;        /* PC relative offset */
  517.     int     length;              /* instruction length */
  518.     /* while instruction is a JMP, get destination adrs */
  519.     while (DSM(addr, JMPD08, JMPD08_MASK) ||
  520.            DSM(addr, JMPD32, JMPD32_MASK))
  521.         {
  522.         if (DSM(addr, JMPD08, JMPD08_MASK))
  523.             {
  524.             displacement = *(char *)(addr + 1);
  525.             length = 2;
  526.             addr = (INSTR *) (addr + length + displacement);
  527.             }
  528.         else if (DSM(addr, JMPD32, JMPD32_MASK))
  529.             {
  530.             displacement = *(int *)(addr + 1);
  531.             length = 5;
  532.             addr = (INSTR *) (addr + length + displacement);
  533.             }
  534.         }
  535.     return (addr);
  536.     }