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/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 "AS IS"
   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 Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        db_trace.c,v $
   29  * Revision 2.13  93/05/17  17:13:23  rvb
   30  *      machparam.h -> machspl.h
   31  *      Cleanup's to make gcc generate less warnings.
   32  * 
   33  * Revision 2.12  93/01/14  17:28:48  danner
   34  *      Proper spl typing.  db_symbol_values() changed.
   35  *      [92/11/30            af]
   36  * 
   37  * Revision 2.11  92/03/10  16:25:36  jsb
   38  *      Changed db_numargs to use patchable variable db_numargs_default
   39  *      when it needs to guess the number of arguments, instead of just
   40  *      using the embedded constant '5'.
   41  *      [92/03/10  14:21:55  jsb]
   42  * 
   43  * Revision 2.10  91/11/12  11:50:39  rvb
   44  *      Removed redundant printing of the continuation.
   45  *      Fixed the log.
   46  *      [91/11/07            rpd]
   47  * 
   48  * Revision 2.9  91/10/09  16:06:49  af
   49  *      Supported stack trace and register access of non current thread.
   50  *      Supported user register access.
   51  *      Fixed incorrect next frame check.
   52  *      [91/08/29            tak]
   53  * 
   54  *      Fixed stack tracing for threads without kernel stacks.  Yes, again.
   55  *      [91/09/26            rpd]
   56  * 
   57  * Revision 2.8  91/08/28  11:11:34  jsb
   58  *      In stack traces, print file/line info if available.
   59  *      [91/08/13  18:15:57  jsb]
   60  * 
   61  * Revision 2.7  91/05/14  16:06:12  mrt
   62  *      Correcting copyright
   63  * 
   64  * Revision 2.6  91/02/05  17:11:21  mrt
   65  *      Changed to new Mach copyright
   66  *      [91/02/01  17:31:32  mrt]
   67  * 
   68  * Revision 2.5  91/01/09  19:55:27  rpd
   69  *      Fixed stack tracing for threads without kernel stacks.
   70  *      [91/01/09            rpd]
   71  * 
   72  * Revision 2.4  91/01/08  15:10:22  rpd
   73  *      Reorganized the pcb.
   74  *      [90/12/11            rpd]
   75  * 
   76  * Revision 2.3  90/11/05  14:27:07  rpd
   77  *      If we can not guess the number of args to a function, use 5 vs 0.
   78  *      [90/11/02            rvb]
   79  * 
   80  * Revision 2.2  90/08/27  21:56:20  dbg
   81  *      Import db_sym.h.
   82  *      [90/08/21            dbg]
   83  *      Fix includes.
   84  *      [90/08/08            dbg]
   85  *      Created from rvb's code for new debugger.
   86  *      [90/07/11            dbg]
   87  * 
   88  */
   89 
   90 #include <mach/boolean.h>
   91 #include <vm/vm_map.h>
   92 #include <kern/thread.h>
   93 #include <kern/task.h>
   94 
   95 #include <machine/db_machdep.h>
   96 #include <machine/machspl.h>
   97 
   98 #include <ddb/db_access.h>
   99 #include <ddb/db_sym.h>
  100 #include <ddb/db_variables.h>
  101 #include <ddb/db_task_thread.h>
  102 
  103 int db_i386_reg_value();
  104 int db_i386_kreg_value();
  105 
  106 struct i386_kernel_state ddb_null_kregs;
  107 
  108 /*
  109  * Machine register set.
  110  */
  111 struct db_variable db_regs[] = {
  112         { "cs", (int *)&ddb_regs.cs,  db_i386_reg_value },
  113         { "ds", (int *)&ddb_regs.ds,  db_i386_reg_value },
  114         { "es", (int *)&ddb_regs.es,  db_i386_reg_value },
  115         { "fs", (int *)&ddb_regs.fs,  db_i386_reg_value },
  116         { "gs", (int *)&ddb_regs.gs,  db_i386_reg_value },
  117         { "ss", (int *)&ddb_regs.ss,  db_i386_reg_value },
  118         { "eax",(int *)&ddb_regs.eax, db_i386_reg_value },
  119         { "ecx",(int *)&ddb_regs.ecx, db_i386_reg_value },
  120         { "edx",(int *)&ddb_regs.edx, db_i386_reg_value },
  121         { "ebx",(int *)&ddb_regs.ebx, db_i386_reg_value },
  122         { "esp",(int *)&ddb_regs.uesp,db_i386_reg_value },
  123         { "ebp",(int *)&ddb_regs.ebp, db_i386_reg_value },
  124         { "esi",(int *)&ddb_regs.esi, db_i386_reg_value },
  125         { "edi",(int *)&ddb_regs.edi, db_i386_reg_value },
  126         { "eip",(int *)&ddb_regs.eip, db_i386_reg_value },
  127         { "efl",(int *)&ddb_regs.efl, db_i386_reg_value },
  128 };
  129 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
  130 
  131 /*
  132  * Stack trace.
  133  */
  134 #define INKERNEL(va)    (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
  135 
  136 struct i386_frame {
  137         struct i386_frame       *f_frame;
  138         int                     f_retaddr;
  139         int                     f_arg0;
  140 };
  141 
  142 #define TRAP            1
  143 #define INTERRUPT       2
  144 #define SYSCALL         3
  145 
  146 db_addr_t       db_user_trap_symbol_value = 0;
  147 db_addr_t       db_kernel_trap_symbol_value = 0;
  148 db_addr_t       db_interrupt_symbol_value = 0;
  149 db_addr_t       db_return_to_iret_symbol_value = 0;
  150 db_addr_t       db_syscall_symbol_value = 0;
  151 boolean_t       db_trace_symbols_found = FALSE;
  152 
  153 struct i386_kregs {
  154         char    *name;
  155         int     offset;
  156 } i386_kregs[] = {
  157         { "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
  158         { "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
  159         { "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
  160         { "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
  161         { "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
  162         { "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
  163         { 0 },
  164 };
  165 
  166 int *
  167 db_lookup_i386_kreg(name, kregp)
  168         char *name;
  169         int *kregp;
  170 {
  171         register struct i386_kregs *kp;
  172 
  173         for (kp = i386_kregs; kp->name; kp++) {
  174             if (strcmp(name, kp->name) == 0)
  175                 return((int *)((int)kregp + kp->offset));
  176         }
  177         return(0);
  178 }
  179         
  180 int
  181 db_i386_reg_value(vp, valuep, flag, ap)
  182         struct  db_variable     *vp;
  183         db_expr_t               *valuep;
  184         int                     flag;
  185         db_var_aux_param_t      ap;
  186 {
  187         int                     *dp = 0;
  188         db_expr_t               null_reg = 0;
  189         register thread_t       thread = ap->thread;
  190         extern unsigned         int_stack_high;
  191 
  192         if (db_option(ap->modif, 'u')) {
  193             if (thread == THREAD_NULL) {
  194                 if ((thread = current_thread()) == THREAD_NULL)
  195                     db_error("no user registers\n");
  196             }
  197             if (thread == current_thread()) {
  198                 if (ddb_regs.cs & 0x3)
  199                     dp = vp->valuep;
  200                 else if (ddb_regs.ebp < int_stack_high)
  201                     db_error("cannot get/set user registers in nested interrupt\n");
  202             }
  203         } else {
  204             if (thread == THREAD_NULL || thread == current_thread()) {
  205                 dp = vp->valuep;
  206             } else if ((thread->state & TH_SWAPPED) == 0 && 
  207                         thread->kernel_stack) {
  208                 dp = db_lookup_i386_kreg(vp->name,
  209                                 (int *)(STACK_IKS(thread->kernel_stack)));
  210                 if (dp == 0)
  211                     dp = &null_reg;
  212             } else if ((thread->state & TH_SWAPPED) &&
  213                         thread->swap_func != thread_exception_return) {
  214                 /* only EIP is valid */
  215                 if (vp->valuep == (int *) &ddb_regs.eip) {
  216                     dp = (int *)(&thread->swap_func);
  217                 } else {
  218                     dp = &null_reg;
  219                 }
  220             }
  221         }
  222         if (dp == 0) {
  223             if (thread->pcb == 0)
  224                 db_error("no pcb\n");
  225             dp = (int *)((int)(&thread->pcb->iss) + 
  226                                     ((int)vp->valuep - (int)&ddb_regs));
  227         }
  228         if (flag == DB_VAR_SET)
  229             *dp = *valuep;
  230         else
  231             *valuep = *dp;
  232         return(0);
  233 }
  234 
  235 void
  236 db_find_trace_symbols()
  237 {
  238         db_expr_t       value;
  239         if (db_value_of_name("_user_trap", &value))
  240             db_user_trap_symbol_value = (db_addr_t) value;
  241         if (db_value_of_name("_kernel_trap", &value))
  242             db_kernel_trap_symbol_value = (db_addr_t) value;
  243         if (db_value_of_name("_interrupt", &value))
  244             db_interrupt_symbol_value = (db_addr_t) value;
  245         if (db_value_of_name("_return_to_iret", &value))
  246             db_return_to_iret_symbol_value = (db_addr_t) value;
  247         if (db_value_of_name("_syscall", &value))
  248             db_syscall_symbol_value = (db_addr_t) value;
  249         db_trace_symbols_found = TRUE;
  250 }
  251 
  252 /*
  253  * Figure out how many arguments were passed into the frame at "fp".
  254  */
  255 int db_numargs_default = 5;
  256 
  257 int
  258 db_numargs(fp, task)
  259         struct i386_frame *fp;
  260         task_t task;
  261 {
  262         int     *argp;
  263         int     inst;
  264         int     args;
  265         extern char     etext[];
  266 
  267         argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
  268         if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
  269             args = db_numargs_default;
  270         else if (!DB_CHECK_ACCESS((int)argp, 4, task))
  271             args = db_numargs_default;
  272         else {
  273             inst = db_get_task_value((int)argp, 4, FALSE, task);
  274             if ((inst & 0xff) == 0x59)  /* popl %ecx */
  275                 args = 1;
  276             else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
  277                 args = ((inst >> 16) & 0xff) / 4;
  278             else
  279                 args = db_numargs_default;
  280         }
  281         return (args);
  282 }
  283 
  284 struct interrupt_frame {
  285         struct i386_frame *if_frame;    /* point to next frame */
  286         int               if_retaddr;   /* return address to _interrupt */
  287         int               if_unit;      /* unit number */
  288         spl_t             if_spl;       /* saved spl */
  289         int               if_iretaddr;  /* _return_to_{iret,iret_i} */
  290         int               if_edx;       /* old sp(iret) or saved edx(iret_i) */
  291         int               if_ecx;       /* saved ecx(iret_i) */
  292         int               if_eax;       /* saved eax(iret_i) */
  293         int               if_eip;       /* saved eip(iret_i) */
  294         int               if_cs;        /* saved cs(iret_i) */
  295         int               if_efl;       /* saved efl(iret_i) */
  296 };
  297 
  298 /* 
  299  * Figure out the next frame up in the call stack.  
  300  * For trap(), we print the address of the faulting instruction and 
  301  *   proceed with the calling frame.  We return the ip that faulted.
  302  *   If the trap was caused by jumping through a bogus pointer, then
  303  *   the next line in the backtrace will list some random function as 
  304  *   being called.  It should get the argument list correct, though.  
  305  *   It might be possible to dig out from the next frame up the name
  306  *   of the function that faulted, but that could get hairy.
  307  */
  308 void
  309 db_nextframe(lfp, fp, ip, frame_type, thread)
  310         struct i386_frame **lfp;        /* in/out */
  311         struct i386_frame **fp;         /* in/out */
  312         db_addr_t       *ip;            /* out */
  313         int frame_type;                 /* in */
  314         thread_t        thread;         /* in */
  315 {
  316         extern char *   trap_type[];
  317         extern int      TRAP_TYPES;
  318 
  319         struct i386_saved_state *saved_regs;
  320         struct interrupt_frame *ifp;
  321         struct i386_interrupt_state *isp;
  322         task_t task = (thread != THREAD_NULL)? thread->task: TASK_NULL;
  323 
  324         switch(frame_type) {
  325         case TRAP:
  326             /*
  327              * We know that trap() has 1 argument and we know that
  328              * it is an (strcut i386_saved_state *).
  329              */
  330             saved_regs = (struct i386_saved_state *)
  331                         db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
  332             if (saved_regs->trapno >= 0 && saved_regs->trapno < TRAP_TYPES) {
  333                 db_printf(">>>>> %s trap at ",
  334                         trap_type[saved_regs->trapno]);
  335             } else {
  336                 db_printf(">>>>> trap (number %d) at ",
  337                         saved_regs->trapno & 0xffff);
  338             }
  339             db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
  340             db_printf(" <<<<<\n");
  341             *fp = (struct i386_frame *)saved_regs->ebp;
  342             *ip = (db_addr_t)saved_regs->eip;
  343             break;
  344         case INTERRUPT:
  345             if (*lfp == 0) {
  346                 db_printf(">>>>> interrupt <<<<<\n");
  347                 goto miss_frame;
  348             }
  349             db_printf(">>>>> interrupt at "); 
  350             ifp = (struct interrupt_frame *)(*lfp);
  351             *fp = ifp->if_frame;
  352             if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
  353                 *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
  354             else
  355                 *ip = (db_addr_t) ifp->if_eip;
  356             db_task_printsym(*ip, DB_STGY_PROC, task);
  357             db_printf(" <<<<<\n");
  358             break;
  359         case SYSCALL:
  360             if (thread != THREAD_NULL && thread->pcb) {
  361                 *ip = (db_addr_t) thread->pcb->iss.eip;
  362                 *fp = (struct i386_frame *) thread->pcb->iss.ebp;
  363                 break;
  364             }
  365             /* falling down for unknown case */
  366         default:
  367         miss_frame:
  368             *ip = (db_addr_t)
  369                 db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
  370             *lfp = *fp;
  371             *fp = (struct i386_frame *)
  372                 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
  373             break;
  374         }
  375 }
  376 
  377 void
  378 db_stack_trace_cmd(addr, have_addr, count, modif)
  379         db_expr_t       addr;
  380         boolean_t       have_addr;
  381         db_expr_t       count;
  382         char            *modif;
  383 {
  384         struct i386_frame *frame, *lastframe;
  385         int             *argp;
  386         db_addr_t       callpc;
  387         int             frame_type;
  388         boolean_t       kernel_only = TRUE;
  389         boolean_t       trace_thread = FALSE;
  390         char            *filename;
  391         int             linenum;
  392         task_t          task;
  393         thread_t        th;
  394         int             user_frame = 0;
  395         extern unsigned db_maxoff;
  396 
  397         if (!db_trace_symbols_found)
  398             db_find_trace_symbols();
  399 
  400         {
  401             register char *cp = modif;
  402             register char c;
  403 
  404             while ((c = *cp++) != 0) {
  405                 if (c == 't')
  406                     trace_thread = TRUE;
  407                 if (c == 'u')
  408                     kernel_only = FALSE;
  409             }
  410         }
  411 
  412         if (count == -1)
  413             count = 65535;
  414 
  415         if (!have_addr && !trace_thread) {
  416             frame = (struct i386_frame *)ddb_regs.ebp;
  417             callpc = (db_addr_t)ddb_regs.eip;
  418             th = current_thread();
  419             task = (th != THREAD_NULL)? th->task: TASK_NULL;
  420         } else if (trace_thread) {
  421             if (have_addr) {
  422                 th = (thread_t) addr;
  423                 if (!db_check_thread_address_valid(th))
  424                     return;
  425             } else {
  426                 th = db_default_thread;
  427                 if (th == THREAD_NULL)
  428                    th = current_thread();
  429                 if (th == THREAD_NULL) {
  430                    db_printf("no active thread\n");
  431                    return;
  432                 }
  433             }
  434             task = th->task;
  435             if (th == current_thread()) {
  436                 frame = (struct i386_frame *)ddb_regs.ebp;
  437                 callpc = (db_addr_t)ddb_regs.eip;
  438             } else {
  439                 if (th->pcb == 0) {
  440                     db_printf("thread has no pcb\n");
  441                     return;
  442                 }
  443                 if ((th->state & TH_SWAPPED) || th->kernel_stack == 0) {
  444                     register struct i386_saved_state *iss = &th->pcb->iss;
  445 
  446                     db_printf("Continuation ");
  447                     db_task_printsym((db_expr_t)th->swap_func, DB_STGY_PROC, task);
  448                     db_printf("\n");
  449 
  450                     frame = (struct i386_frame *) (iss->ebp);
  451                     callpc = (db_addr_t) (iss->eip);
  452                 } else {
  453                     register struct i386_kernel_state *iks;
  454                     iks = STACK_IKS(th->kernel_stack);
  455                     frame = (struct i386_frame *) (iks->k_ebp);
  456                     callpc = (db_addr_t) (iks->k_eip);
  457                 }
  458             }
  459         } else {
  460             frame = (struct i386_frame *)addr;
  461             th = (db_default_thread)? db_default_thread: current_thread();
  462             task = (th != THREAD_NULL)? th->task: TASK_NULL;
  463             callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr, 4, 
  464                                                         FALSE, task);
  465         }
  466 
  467         if (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)) {
  468             db_printf(">>>>> user space <<<<<\n");
  469             user_frame++;
  470         }
  471 
  472         lastframe = 0;
  473         while (count-- && frame != 0) {
  474             register int narg;
  475             char *      name;
  476             db_expr_t   offset;
  477 
  478             if (INKERNEL((unsigned)callpc) && user_frame == 0) {
  479                 db_addr_t call_func = 0;
  480 
  481                 db_symbol_values(0, db_search_task_symbol(callpc, 
  482                                         DB_STGY_XTRN, (db_addr_t *)&offset,
  483                                         TASK_NULL),
  484                                  &name, (db_expr_t *)&call_func);
  485                 if (call_func == db_user_trap_symbol_value ||
  486                     call_func == db_kernel_trap_symbol_value) {
  487                     frame_type = TRAP;
  488                     narg = 1;
  489                 } else if (call_func == db_interrupt_symbol_value) {
  490                     frame_type = INTERRUPT;
  491                     goto next_frame;
  492                 } else if (call_func == db_syscall_symbol_value) {
  493                     frame_type = SYSCALL;
  494                     goto next_frame;
  495                 } else {
  496                     frame_type = 0;
  497                     narg = db_numargs(frame, task);
  498                 }
  499             } else if (INKERNEL((unsigned)callpc) ^ INKERNEL((unsigned)frame)) {
  500                 frame_type = 0;
  501                 narg = -1;
  502             } else {
  503                 frame_type = 0;
  504                 narg = db_numargs(frame, task);
  505             }
  506 
  507             db_find_task_sym_and_offset(callpc, &name, (db_addr_t *)&offset, task);
  508             if (name == 0 || offset > db_maxoff) {
  509                 db_printf("0x%x(", callpc);
  510                 offset = 0;
  511             } else
  512                 db_printf("%s(", name);
  513 
  514             argp = &frame->f_arg0;
  515             while (narg > 0) {
  516                 db_printf("%x", db_get_task_value((int)argp,4,FALSE,task));
  517                 argp++;
  518                 if (--narg != 0)
  519                     db_printf(",");
  520             }
  521             if (narg < 0)
  522                 db_printf("...");
  523             db_printf(")");
  524             if (offset) {
  525                 db_printf("+%x", offset);
  526             }
  527             if (db_line_at_pc(0, &filename, &linenum, callpc)) {
  528                 db_printf(" [%s", filename);
  529                 if (linenum > 0)
  530                     db_printf(":%d", linenum);
  531                 printf("]");
  532             }
  533             db_printf("\n");
  534 
  535         next_frame:
  536             db_nextframe(&lastframe, &frame, &callpc, frame_type, th);
  537 
  538             if (frame == 0) {
  539                 /* end of chain */
  540                 break;
  541             }
  542             if (!INKERNEL(lastframe) ||
  543                 (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)))
  544                 user_frame++;
  545             if (user_frame == 1) {
  546                 db_printf(">>>>> user space <<<<<\n");
  547                 if (kernel_only)
  548                     break;
  549             }
  550             if (frame <= lastframe) {
  551                 if (INKERNEL(lastframe) && !INKERNEL(frame))
  552                     continue;
  553                 db_printf("Bad frame pointer: 0x%x\n", frame);
  554                 break;
  555             }
  556         }
  557 }

Cache object: 638589381db93c233fb999d535119573


[ 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.