The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/db_trace.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Mach Operating System
    3  * Copyright (c) 1991,1990 Carnegie Mellon University
    4  * All Rights Reserved.
    5  *
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  *
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  *
   16  * Carnegie Mellon requests users of this software to return to
   17  *
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  *
   23  * any improvements or extensions that they make and grant Carnegie the
   24  * rights to redistribute these changes.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 
   32 #include <machine/cpu.h>
   33 
   34 #include <vm/vm.h>
   35 #include <vm/vm_param.h>
   36 #include <vm/pmap.h>
   37 #include <ddb/ddb.h>
   38 
   39 #include <ddb/db_access.h>
   40 #include <ddb/db_sym.h>
   41 #include <ddb/db_variables.h>
   42 
   43 /*
   44  * Machine register set.
   45  */
   46 struct db_variable db_regs[] = {
   47         "cs",   &ddb_regs.tf_cs,  FCN_NULL,
   48         "ds",   &ddb_regs.tf_ds,  FCN_NULL,
   49         "es",   &ddb_regs.tf_es,  FCN_NULL,
   50 #if 0
   51         "fs",   &ddb_regs.tf_fs,  FCN_NULL,
   52         "gs",   &ddb_regs.tf_gs,  FCN_NULL,
   53 #endif
   54         "ss",   &ddb_regs.tf_ss,  FCN_NULL,
   55         "eax",  &ddb_regs.tf_eax, FCN_NULL,
   56         "ecx",  &ddb_regs.tf_ecx, FCN_NULL,
   57         "edx",  &ddb_regs.tf_edx, FCN_NULL,
   58         "ebx",  &ddb_regs.tf_ebx, FCN_NULL,
   59         "esp",  &ddb_regs.tf_esp, FCN_NULL,
   60         "ebp",  &ddb_regs.tf_ebp, FCN_NULL,
   61         "esi",  &ddb_regs.tf_esi, FCN_NULL,
   62         "edi",  &ddb_regs.tf_edi, FCN_NULL,
   63         "eip",  &ddb_regs.tf_eip, FCN_NULL,
   64         "efl",  &ddb_regs.tf_eflags, FCN_NULL,
   65 };
   66 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
   67 
   68 /*
   69  * Stack trace.
   70  */
   71 #define INKERNEL(va)    (((vm_offset_t)(va)) >= USRSTACK)
   72 
   73 struct i386_frame {
   74         struct i386_frame       *f_frame;
   75         int                     f_retaddr;
   76         int                     f_arg0;
   77 };
   78 
   79 #define NORMAL          0
   80 #define TRAP            1
   81 #define INTERRUPT       2
   82 #define SYSCALL         3
   83 
   84 static void db_nextframe __P((struct i386_frame **, db_addr_t *));
   85 static int db_numargs __P((struct i386_frame *));
   86 static void db_print_stack_entry __P((char *, int, char **, int *, db_addr_t));
   87 
   88 /*
   89  * Figure out how many arguments were passed into the frame at "fp".
   90  */
   91 static int
   92 db_numargs(fp)
   93         struct i386_frame *fp;
   94 {
   95         int     *argp;
   96         int     inst;
   97         int     args;
   98 
   99         argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
  100         /*
  101          * XXX etext is wrong for LKMs.  We should attempt to interpret
  102          * the instruction at the return address in all cases.  This
  103          * may require better fault handling.
  104          */
  105         if (argp < (int *)btext || argp >= (int *)etext) {
  106                 args = 5;
  107         } else {
  108                 inst = db_get_value((int)argp, 4, FALSE);
  109                 if ((inst & 0xff) == 0x59)      /* popl %ecx */
  110                         args = 1;
  111                 else if ((inst & 0xffff) == 0xc483)     /* addl $Ibs, %esp */
  112                         args = ((inst >> 16) & 0xff) / 4;
  113                 else
  114                         args = 5;
  115         }
  116         return (args);
  117 }
  118 
  119 static void
  120 db_print_stack_entry(name, narg, argnp, argp, callpc)
  121         char *name;
  122         int narg;
  123         char **argnp;
  124         int *argp;
  125         db_addr_t callpc;
  126 {
  127         db_printf("%s(", name);
  128         while (narg) {
  129                 if (argnp)
  130                         db_printf("%s=", *argnp++);
  131                 db_printf("%r", db_get_value((int)argp, 4, FALSE));
  132                 argp++;
  133                 if (--narg != 0)
  134                         db_printf(",");
  135         }
  136         db_printf(") at ");
  137         db_printsym(callpc, DB_STGY_PROC);
  138         db_printf("\n");
  139 }
  140 
  141 /*
  142  * Figure out the next frame up in the call stack.
  143  */
  144 static void
  145 db_nextframe(fp, ip)
  146         struct i386_frame **fp;         /* in/out */
  147         db_addr_t       *ip;            /* out */
  148 {
  149         struct trapframe *tf;
  150         int frame_type;
  151         int eip, esp, ebp;
  152         db_expr_t offset;
  153         char *sym, *name;
  154 
  155         eip = db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
  156         ebp = db_get_value((int) &(*fp)->f_frame, 4, FALSE);
  157 
  158         /*
  159          * Figure out frame type.
  160          */
  161 
  162         frame_type = NORMAL;
  163 
  164         sym = db_search_symbol(eip, DB_STGY_ANY, &offset);
  165         db_symbol_values(sym, &name, NULL);
  166         if (name != NULL) {
  167                 if (!strcmp(name, "calltrap")) {
  168                         frame_type = TRAP;
  169                 } else if (!strncmp(name, "Xresume", 7)) {
  170                         frame_type = INTERRUPT;
  171                 } else if (!strcmp(name, "_Xsyscall")) {
  172                         frame_type = SYSCALL;
  173                 }
  174         }
  175 
  176         /*
  177          * Normal frames need no special processing.
  178          */
  179         if (frame_type == NORMAL) {
  180                 *ip = (db_addr_t) eip;
  181                 *fp = (struct i386_frame *) ebp;
  182                 return;
  183         }
  184 
  185         db_print_stack_entry(name, 0, 0, 0, eip);
  186 
  187         /*
  188          * Point to base of trapframe which is just above the
  189          * current frame.
  190          */
  191         tf = (struct trapframe *) ((int)*fp + 8);
  192 
  193         esp = (ISPL(tf->tf_cs) == SEL_UPL) ?  tf->tf_esp : (int)&tf->tf_esp;
  194         switch (frame_type) {
  195         case TRAP:
  196                 if (INKERNEL((int) tf)) {
  197                         eip = tf->tf_eip;
  198                         ebp = tf->tf_ebp;
  199                         db_printf(
  200                     "--- trap %#r, eip = %#r, esp = %#r, ebp = %#r ---\n",
  201                             tf->tf_trapno, eip, esp, ebp);
  202                 }
  203                 break;
  204         case SYSCALL:
  205                 if (INKERNEL((int) tf)) {
  206                         eip = tf->tf_eip;
  207                         ebp = tf->tf_ebp;
  208                         db_printf(
  209                     "--- syscall %#r, eip = %#r, esp = %#r, ebp = %#r ---\n",
  210                             tf->tf_eax, eip, esp, ebp);
  211                 }
  212                 break;
  213         case INTERRUPT:
  214                 tf = (struct trapframe *)((int)*fp + 16);
  215                 if (INKERNEL((int) tf)) {
  216                         eip = tf->tf_eip;
  217                         ebp = tf->tf_ebp;
  218                         db_printf(
  219                     "--- interrupt, eip = %#r, esp = %#r, ebp = %#r ---\n",
  220                             eip, esp, ebp);
  221                 }
  222                 break;
  223         default:
  224                 break;
  225         }
  226 
  227         *ip = (db_addr_t) eip;
  228         *fp = (struct i386_frame *) ebp;
  229 }
  230 
  231 void
  232 db_stack_trace_cmd(addr, have_addr, count, modif)
  233         db_expr_t addr;
  234         boolean_t have_addr;
  235         db_expr_t count;
  236         char *modif;
  237 {
  238         struct i386_frame *frame;
  239         int *argp;
  240         db_addr_t callpc;
  241         boolean_t first;
  242 
  243         if (count == -1)
  244                 count = 65535;
  245 
  246         if (!have_addr) {
  247                 frame = (struct i386_frame *)ddb_regs.tf_ebp;
  248                 if (frame == NULL)
  249                         frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
  250                 callpc = (db_addr_t)ddb_regs.tf_eip;
  251         } else {
  252                 frame = (struct i386_frame *)addr;
  253                 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
  254         }
  255 
  256         first = TRUE;
  257         while (count--) {
  258                 struct i386_frame *actframe;
  259                 int             narg;
  260                 char *  name;
  261                 db_expr_t       offset;
  262                 db_sym_t        sym;
  263 #define MAXNARG 16
  264                 char    *argnames[MAXNARG], **argnp = NULL;
  265 
  266                 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
  267                 db_symbol_values(sym, &name, NULL);
  268 
  269                 /*
  270                  * Attempt to determine a (possibly fake) frame that gives
  271                  * the caller's pc.  It may differ from `frame' if the
  272                  * current function never sets up a standard frame or hasn't
  273                  * set one up yet or has just discarded one.  The last two
  274                  * cases can be guessed fairly reliably for code generated
  275                  * by gcc.  The first case is too much trouble to handle in
  276                  * general because the amount of junk on the stack depends
  277                  * on the pc (the special handling of "calltrap", etc. in
  278                  * db_nextframe() works because the `next' pc is special).
  279                  */
  280                 actframe = frame;
  281                 if (first && !have_addr) {
  282                         int instr;
  283 
  284                         instr = db_get_value(callpc, 4, FALSE);
  285                         if ((instr & 0x00ffffff) == 0x00e58955) {
  286                                 /* pushl %ebp; movl %esp, %ebp */
  287                                 actframe = (struct i386_frame *)
  288                                            (ddb_regs.tf_esp - 4);
  289                         } else if ((instr & 0x0000ffff) == 0x0000e589) {
  290                                 /* movl %esp, %ebp */
  291                                 actframe = (struct i386_frame *)
  292                                            ddb_regs.tf_esp;
  293                                 if (ddb_regs.tf_ebp == 0) {
  294                                         /* Fake the caller's frame better. */
  295                                         frame = actframe;
  296                                 }
  297                         } else if ((instr & 0x000000ff) == 0x000000c3) {
  298                                 /* ret */
  299                                 actframe = (struct i386_frame *)
  300                                            (ddb_regs.tf_esp - 4);
  301                         } else if (offset == 0) {
  302                                 /* Probably a symbol in assembler code. */
  303                                 actframe = (struct i386_frame *)
  304                                            (ddb_regs.tf_esp - 4);
  305                         }
  306                 }
  307                 first = FALSE;
  308 
  309                 argp = &actframe->f_arg0;
  310                 narg = MAXNARG;
  311                 if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
  312                         argnp = argnames;
  313                 } else {
  314                         narg = db_numargs(frame);
  315                 }
  316 
  317                 db_print_stack_entry(name, narg, argnp, argp, callpc);
  318 
  319                 if (actframe != frame) {
  320                         /* `frame' belongs to caller. */
  321                         callpc = (db_addr_t)
  322                             db_get_value((int)&actframe->f_retaddr, 4, FALSE);
  323                         continue;
  324                 }
  325 
  326                 db_nextframe(&frame, &callpc);
  327 
  328                 if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) {
  329                         sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
  330                         db_symbol_values(sym, &name, NULL);
  331                         db_print_stack_entry(name, 0, 0, 0, callpc);
  332                         break;
  333                 }
  334                 if (!INKERNEL((int) frame)) {
  335                         break;
  336                 }
  337         }
  338 }

Cache object: 203789fe7ad339c8d4f8af01407c364e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.