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) 1993,1992,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.14  93/11/17  16:35:37  dbg
   30  *      Reorganized a little, splitting out db_i386_stack_trace().
   31  *      Added Cthreads debugging support.
   32  *      [93/09/24            af]
   33  * 
   34  * Revision 2.13  93/05/17  17:13:23  rvb
   35  *      machparam.h -> machspl.h
   36  *      Cleanup's to make gcc generate less warnings.
   37  * 
   38  * Revision 2.12  93/01/14  17:28:48  danner
   39  *      Proper spl typing.  db_symbol_values() changed.
   40  *      [92/11/30            af]
   41  * 
   42  * Revision 2.11  92/03/10  16:25:36  jsb
   43  *      Changed db_numargs to use patchable variable db_numargs_default
   44  *      when it needs to guess the number of arguments, instead of just
   45  *      using the embedded constant '5'.
   46  *      [92/03/10  14:21:55  jsb]
   47  * 
   48  * Revision 2.10  91/11/12  11:50:39  rvb
   49  *      Removed redundant printing of the continuation.
   50  *      Fixed the log.
   51  *      [91/11/07            rpd]
   52  * 
   53  * Revision 2.9  91/10/09  16:06:49  af
   54  *      Supported stack trace and register access of non current thread.
   55  *      Supported user register access.
   56  *      Fixed incorrect next frame check.
   57  *      [91/08/29            tak]
   58  * 
   59  *      Fixed stack tracing for threads without kernel stacks.  Yes, again.
   60  *      [91/09/26            rpd]
   61  * 
   62  * Revision 2.8  91/08/28  11:11:34  jsb
   63  *      In stack traces, print file/line info if available.
   64  *      [91/08/13  18:15:57  jsb]
   65  * 
   66  * Revision 2.7  91/05/14  16:06:12  mrt
   67  *      Correcting copyright
   68  * 
   69  * Revision 2.6  91/02/05  17:11:21  mrt
   70  *      Changed to new Mach copyright
   71  *      [91/02/01  17:31:32  mrt]
   72  * 
   73  * Revision 2.5  91/01/09  19:55:27  rpd
   74  *      Fixed stack tracing for threads without kernel stacks.
   75  *      [91/01/09            rpd]
   76  * 
   77  * Revision 2.4  91/01/08  15:10:22  rpd
   78  *      Reorganized the pcb.
   79  *      [90/12/11            rpd]
   80  * 
   81  * Revision 2.3  90/11/05  14:27:07  rpd
   82  *      If we can not guess the number of args to a function, use 5 vs 0.
   83  *      [90/11/02            rvb]
   84  * 
   85  * Revision 2.2  90/08/27  21:56:20  dbg
   86  *      Import db_sym.h.
   87  *      [90/08/21            dbg]
   88  *      Fix includes.
   89  *      [90/08/08            dbg]
   90  *      Created from rvb's code for new debugger.
   91  *      [90/07/11            dbg]
   92  * 
   93  */
   94 
   95 #include <mach/boolean.h>
   96 #include <vm/vm_map.h>
   97 #include <kern/thread.h>
   98 #include <kern/task.h>
   99 
  100 #include <machine/db_machdep.h>
  101 #include <machine/machspl.h>
  102 
  103 #include <ddb/db_access.h>
  104 #include <ddb/db_command.h>
  105 #include <ddb/db_output.h>
  106 #include <ddb/db_sym.h>
  107 #include <ddb/db_variables.h>
  108 #include <ddb/db_task_thread.h>
  109 
  110 void db_i386_reg_value(
  111         struct db_variable      *vp,
  112         db_expr_t               *valuep,
  113         int                     flag,
  114         struct db_var_aux_param *ap);           /* forward */
  115 
  116 /*
  117  * Machine register set.
  118  */
  119 struct db_variable db_regs[] = {
  120         { "cs", (int *)&ddb_regs.cs,  db_i386_reg_value },
  121         { "ds", (int *)&ddb_regs.ds,  db_i386_reg_value },
  122         { "es", (int *)&ddb_regs.es,  db_i386_reg_value },
  123         { "fs", (int *)&ddb_regs.fs,  db_i386_reg_value },
  124         { "gs", (int *)&ddb_regs.gs,  db_i386_reg_value },
  125         { "ss", (int *)&ddb_regs.ss,  db_i386_reg_value },
  126         { "eax",(int *)&ddb_regs.eax, db_i386_reg_value },
  127         { "ecx",(int *)&ddb_regs.ecx, db_i386_reg_value },
  128         { "edx",(int *)&ddb_regs.edx, db_i386_reg_value },
  129         { "ebx",(int *)&ddb_regs.ebx, db_i386_reg_value },
  130         { "esp",(int *)&ddb_regs.uesp,db_i386_reg_value },
  131         { "ebp",(int *)&ddb_regs.ebp, db_i386_reg_value },
  132         { "esi",(int *)&ddb_regs.esi, db_i386_reg_value },
  133         { "edi",(int *)&ddb_regs.edi, db_i386_reg_value },
  134         { "eip",(int *)&ddb_regs.eip, db_i386_reg_value },
  135         { "efl",(int *)&ddb_regs.efl, db_i386_reg_value },
  136 };
  137 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
  138 
  139 /*
  140  * Stack trace.
  141  */
  142 #define INKERNEL(va)    (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
  143 
  144 struct i386_frame {
  145         struct i386_frame       *f_frame;
  146         int                     f_retaddr;
  147         int                     f_arg0;
  148 };
  149 
  150 #define TRAP            1
  151 #define INTERRUPT       2
  152 #define SYSCALL         3
  153 
  154 db_addr_t       db_user_trap_symbol_value = 0;
  155 db_addr_t       db_kernel_trap_symbol_value = 0;
  156 db_addr_t       db_interrupt_symbol_value = 0;
  157 db_addr_t       db_return_to_iret_symbol_value = 0;
  158 db_addr_t       db_syscall_symbol_value = 0;
  159 boolean_t       db_trace_symbols_found = FALSE;
  160 
  161 struct i386_kregs {
  162         char    *name;
  163         int     offset;
  164 } i386_kregs[] = {
  165         { "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
  166         { "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
  167         { "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
  168         { "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
  169         { "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
  170         { "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
  171         { 0 },
  172 };
  173 
  174 int *
  175 db_lookup_i386_kreg(
  176         char    *name,
  177         int     *kregp)
  178 {
  179         register struct i386_kregs *kp;
  180 
  181         for (kp = i386_kregs; kp->name; kp++) {
  182             if (strcmp(name, kp->name) == 0)
  183                 return (int *)((int)kregp + kp->offset);
  184         }
  185         return 0;
  186 }
  187         
  188 void
  189 db_i386_reg_value(
  190         struct  db_variable     *vp,
  191         db_expr_t               *valuep,
  192         int                     flag,
  193         db_var_aux_param_t      ap)
  194 {
  195         int                     *dp = 0;
  196         db_expr_t               null_reg = 0;
  197         register thread_t       thread = ap->thread;
  198         extern unsigned         int_stack_high;
  199 
  200         if (db_option(ap->modif, 'u')) {
  201             if (thread == THREAD_NULL) {
  202                 if ((thread = current_thread()) == THREAD_NULL)
  203                     db_error("no user registers\n");
  204             }
  205             if (thread == current_thread()) {
  206                 if (ddb_regs.cs & 0x3)
  207                     dp = vp->valuep;
  208                 else if (ddb_regs.ebp < int_stack_high)
  209                     db_error("cannot get/set user registers in nested interrupt\n");
  210             }
  211         } else {
  212             if (thread == THREAD_NULL || thread == current_thread()) {
  213                 dp = vp->valuep;
  214             } else if ((thread->state & TH_SWAPPED) == 0 && 
  215                         thread->kernel_stack) {
  216                 dp = db_lookup_i386_kreg(vp->name,
  217                                 (int *)(STACK_IKS(thread->kernel_stack)));
  218                 if (dp == 0)
  219                     dp = &null_reg;
  220             } else if ((thread->state & TH_SWAPPED) &&
  221                         thread->swap_func != thread_exception_return) {
  222 /*.....this breaks t/t $taskN.0...*/
  223                 /* only EIP is valid */
  224                 if (vp->valuep == (int *) &ddb_regs.eip) {
  225                     dp = (int *)(&thread->swap_func);
  226                 } else {
  227                     dp = &null_reg;
  228                 }
  229             }
  230         }
  231         if (dp == 0) {
  232             if (thread->pcb == 0)
  233                 db_error("no pcb\n");
  234             dp = (int *)((int)(&thread->pcb->iss) + 
  235                                     ((int)vp->valuep - (int)&ddb_regs));
  236         }
  237         if (flag == DB_VAR_SET)
  238             *dp = *valuep;
  239         else
  240             *valuep = *dp;
  241 }
  242 
  243 void
  244 db_find_trace_symbols(void)
  245 {
  246         db_expr_t       value;
  247         if (db_value_of_name("_user_trap", &value))
  248             db_user_trap_symbol_value = (db_addr_t) value;
  249         if (db_value_of_name("_kernel_trap", &value))
  250             db_kernel_trap_symbol_value = (db_addr_t) value;
  251         if (db_value_of_name("_interrupt", &value))
  252             db_interrupt_symbol_value = (db_addr_t) value;
  253         if (db_value_of_name("_return_to_iret", &value))
  254             db_return_to_iret_symbol_value = (db_addr_t) value;
  255         if (db_value_of_name("_syscall", &value))
  256             db_syscall_symbol_value = (db_addr_t) value;
  257         db_trace_symbols_found = TRUE;
  258 }
  259 
  260 /*
  261  * Figure out how many arguments were passed into the frame at "fp".
  262  */
  263 int db_numargs_default = 5;
  264 
  265 int
  266 db_numargs(
  267         struct i386_frame *fp,
  268         task_t task)
  269 {
  270         int     *argp;
  271         int     inst;
  272         int     args;
  273         extern char     etext[];
  274 
  275         argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
  276         if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
  277             args = db_numargs_default;
  278         else if (!DB_CHECK_ACCESS((int)argp, 4, task))
  279             args = db_numargs_default;
  280         else {
  281             inst = db_get_task_value((int)argp, 4, FALSE, task);
  282             if ((inst & 0xff) == 0x59)  /* popl %ecx */
  283                 args = 1;
  284             else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
  285                 args = ((inst >> 16) & 0xff) / 4;
  286             else
  287                 args = db_numargs_default;
  288         }
  289         return args;
  290 }
  291 
  292 struct interrupt_frame {
  293         struct i386_frame *if_frame;    /* point to next frame */
  294         int               if_retaddr;   /* return address to _interrupt */
  295         int               if_unit;      /* unit number */
  296         spl_t             if_spl;       /* saved spl */
  297         int               if_iretaddr;  /* _return_to_{iret,iret_i} */
  298         int               if_edx;       /* old sp(iret) or saved edx(iret_i) */
  299         int               if_ecx;       /* saved ecx(iret_i) */
  300         int               if_eax;       /* saved eax(iret_i) */
  301         int               if_eip;       /* saved eip(iret_i) */
  302         int               if_cs;        /* saved cs(iret_i) */
  303         int               if_efl;       /* saved efl(iret_i) */
  304 };
  305 
  306 /* 
  307  * Figure out the next frame up in the call stack.  
  308  * For trap(), we print the address of the faulting instruction and 
  309  *   proceed with the calling frame.  We return the ip that faulted.
  310  *   If the trap was caused by jumping through a bogus pointer, then
  311  *   the next line in the backtrace will list some random function as 
  312  *   being called.  It should get the argument list correct, though.  
  313  *   It might be possible to dig out from the next frame up the name
  314  *   of the function that faulted, but that could get hairy.
  315  */
  316 void
  317 db_nextframe(
  318         struct i386_frame **lfp,        /* in/out */
  319         struct i386_frame **fp,         /* in/out */
  320         db_addr_t         *ip,          /* out */
  321         int               frame_type,   /* in */
  322         thread_t          thread)       /* in */
  323 {
  324         extern char *   trap_type[];
  325         extern int      TRAP_TYPES;
  326 
  327         struct i386_saved_state *saved_regs;
  328         struct interrupt_frame *ifp;
  329         task_t task = (thread != THREAD_NULL)? thread->task: TASK_NULL;
  330 
  331         switch(frame_type) {
  332         case TRAP:
  333             /*
  334              * We know that trap() has 1 argument and we know that
  335              * it is an (struct i386_saved_state *).
  336              */
  337             saved_regs = (struct i386_saved_state *)
  338                         db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
  339             if (saved_regs->trapno < TRAP_TYPES) {      /* trapno is unsigned */
  340                 db_printf(">>>>> %s trap at ",
  341                         trap_type[saved_regs->trapno]);
  342             } else {
  343                 db_printf(">>>>> trap (number %d) at ",
  344                         saved_regs->trapno & 0xffff);
  345             }
  346             db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
  347             db_printf(" <<<<<\n");
  348             *fp = (struct i386_frame *)saved_regs->ebp;
  349             *ip = (db_addr_t)saved_regs->eip;
  350             break;
  351         case INTERRUPT:
  352             if (*lfp == 0) {
  353                 db_printf(">>>>> interrupt <<<<<\n");
  354                 goto miss_frame;
  355             }
  356             db_printf(">>>>> interrupt at "); 
  357             ifp = (struct interrupt_frame *)(*lfp);
  358             *fp = ifp->if_frame;
  359             if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
  360                 *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
  361             else
  362                 *ip = (db_addr_t) ifp->if_eip;
  363             db_task_printsym(*ip, DB_STGY_PROC, task);
  364             db_printf(" <<<<<\n");
  365             break;
  366         case SYSCALL:
  367             if (thread != THREAD_NULL && thread->pcb) {
  368                 *ip = (db_addr_t) thread->pcb->iss.eip;
  369                 *fp = (struct i386_frame *) thread->pcb->iss.ebp;
  370                 break;
  371             }
  372             /* falling down for unknown case */
  373         default:
  374         miss_frame:
  375             *ip = (db_addr_t)
  376                 db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
  377             *lfp = *fp;
  378             *fp = (struct i386_frame *)
  379                 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
  380             break;
  381         }
  382 }
  383 
  384 void
  385 db_i386_stack_trace(
  386         thread_t        th,
  387         struct i386_frame *frame,
  388         db_addr_t       callpc,
  389         db_expr_t       count,
  390         int             flags);         /* forward */
  391 
  392 #define F_USER_TRACE    1
  393 #define F_TRACE_THREAD  2
  394 
  395 void
  396 db_stack_trace_cmd(
  397         db_expr_t       addr,
  398         boolean_t       have_addr,
  399         db_expr_t       count,
  400         char            *modif)
  401 {
  402         boolean_t       trace_thread = FALSE;
  403         struct i386_frame *frame;
  404         db_addr_t       callpc;
  405         int             flags = 0;
  406         thread_t        th;
  407 
  408         {
  409             register char *cp = modif;
  410             register char c;
  411 
  412             while ((c = *cp++) != 0) {
  413                 if (c == 't')
  414                     trace_thread = TRUE;
  415                 if (c == 'u')
  416                     flags |= F_USER_TRACE;
  417             }
  418         }
  419 
  420         if (!have_addr && !trace_thread) {
  421             frame = (struct i386_frame *)ddb_regs.ebp;
  422             callpc = (db_addr_t)ddb_regs.eip;
  423             th = current_thread();
  424         } else if (trace_thread) {
  425             if (have_addr) {
  426                 th = (thread_t) addr;
  427                 if (!db_check_thread_address_valid((db_addr_t)th))
  428                     return;
  429             } else {
  430                 th = db_default_thread;
  431                 if (th == THREAD_NULL)
  432                    th = current_thread();
  433                 if (th == THREAD_NULL) {
  434                    db_printf("no active thread\n");
  435                    return;
  436                 }
  437             }
  438             if (th == current_thread()) {
  439                 frame = (struct i386_frame *)ddb_regs.ebp;
  440                 callpc = (db_addr_t)ddb_regs.eip;
  441             } else {
  442                 if (th->pcb == 0) {
  443                     db_printf("thread has no pcb\n");
  444                     return;
  445                 }
  446                 if ((th->state & TH_SWAPPED) || th->kernel_stack == 0) {
  447                     register struct i386_saved_state *iss = &th->pcb->iss;
  448 
  449                     db_printf("Continuation ");
  450                     db_task_printsym((db_expr_t)th->swap_func,
  451                                       DB_STGY_PROC,
  452                                       th->task);
  453                     db_printf("\n");
  454 
  455                     frame = (struct i386_frame *) (iss->ebp);
  456                     callpc = (db_addr_t) (iss->eip);
  457                 } else {
  458                     register struct i386_kernel_state *iks;
  459                     iks = STACK_IKS(th->kernel_stack);
  460                     frame = (struct i386_frame *) (iks->k_ebp);
  461                     callpc = (db_addr_t) (iks->k_eip);
  462                 }
  463             }
  464         } else {
  465             frame = (struct i386_frame *)addr;
  466             th = (db_default_thread)? db_default_thread: current_thread();
  467             callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr, 4, 
  468                                                   FALSE,
  469                                                   (th == THREAD_NULL) ? TASK_NULL : th->task);
  470         }
  471 
  472         db_i386_stack_trace( th, frame, callpc, count, flags );
  473 }
  474 
  475 
  476 void
  477 db_i386_stack_trace(
  478         thread_t        th,
  479         struct i386_frame *frame,
  480         db_addr_t       callpc,
  481         db_expr_t       count,
  482         int             flags)
  483 {
  484         task_t          task;
  485         boolean_t       kernel_only;
  486         int             *argp;
  487         int             user_frame = 0;
  488         struct i386_frame *lastframe;
  489         int             frame_type;
  490         char            *filename;
  491         int             linenum;
  492         extern unsigned int db_maxoff;
  493 
  494         if (count == -1)
  495             count = 65535;
  496 
  497         kernel_only = (flags & F_USER_TRACE) == 0;
  498 
  499         task = (th == THREAD_NULL) ? TASK_NULL : th->task;
  500 
  501         if (!db_trace_symbols_found)
  502             db_find_trace_symbols();
  503 
  504         if (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)) {
  505             db_printf(">>>>> user space <<<<<\n");
  506             user_frame++;
  507         }
  508 
  509         lastframe = 0;
  510         while (count-- && frame != 0) {
  511             register int narg;
  512             char *      name;
  513             db_expr_t   offset;
  514 
  515             if (INKERNEL((unsigned)callpc) && user_frame == 0) {
  516                 db_addr_t call_func = 0;
  517 
  518                 db_symbol_values(0, db_search_task_symbol(callpc, 
  519                                         DB_STGY_XTRN, (db_addr_t *)&offset,
  520                                         TASK_NULL),
  521                                  &name, (db_expr_t *)&call_func);
  522                 if (call_func == db_user_trap_symbol_value ||
  523                     call_func == db_kernel_trap_symbol_value) {
  524                     frame_type = TRAP;
  525                     narg = 1;
  526                 } else if (call_func == db_interrupt_symbol_value) {
  527                     frame_type = INTERRUPT;
  528                     goto next_frame;
  529                 } else if (call_func == db_syscall_symbol_value) {
  530                     frame_type = SYSCALL;
  531                     goto next_frame;
  532                 } else {
  533                     frame_type = 0;
  534                     narg = db_numargs(frame, task);
  535                 }
  536             } else if (INKERNEL((unsigned)callpc) ^ INKERNEL((unsigned)frame)) {
  537                 frame_type = 0;
  538                 narg = -1;
  539             } else {
  540                 frame_type = 0;
  541                 narg = db_numargs(frame, task);
  542             }
  543 
  544             db_find_task_sym_and_offset(callpc, &name,
  545                                         (db_addr_t *)&offset, task);
  546             if (name == 0 || offset > db_maxoff) {
  547                 db_printf("0x%x(", callpc);
  548                 offset = 0;
  549             } else
  550                 db_printf("%s(", name);
  551 
  552             argp = &frame->f_arg0;
  553             while (narg > 0) {
  554                 db_printf("%x", db_get_task_value((int)argp,4,FALSE,task));
  555                 argp++;
  556                 if (--narg != 0)
  557                     db_printf(",");
  558             }
  559             if (narg < 0)
  560                 db_printf("...");
  561             db_printf(")");
  562             if (offset) {
  563                 db_printf("+%x", offset);
  564             }
  565             if (db_line_at_pc(0, &filename, &linenum, callpc)) {
  566                 db_printf(" [%s", filename);
  567                 if (linenum > 0)
  568                     db_printf(":%d", linenum);
  569                 db_printf("]");
  570             }
  571             db_printf("\n");
  572 
  573         next_frame:
  574             db_nextframe(&lastframe, &frame, &callpc, frame_type, th);
  575 
  576             if (frame == 0) {
  577                 /* end of chain */
  578                 break;
  579             }
  580             if (!INKERNEL(lastframe) ||
  581                 (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)))
  582                 user_frame++;
  583             if (user_frame == 1) {
  584                 db_printf(">>>>> user space <<<<<\n");
  585                 if (kernel_only)
  586                     break;
  587             }
  588             if (frame <= lastframe) {
  589                 if (INKERNEL(lastframe) && !INKERNEL(frame))
  590                     continue;
  591                 db_printf("Bad frame pointer: 0x%x\n", frame);
  592                 break;
  593             }
  594         }
  595 }
  596 
  597 #define CTHREADS_SUPPORT        1
  598 
  599 #if     CTHREADS_SUPPORT
  600 
  601 thread_t
  602 db_find_kthread(
  603         vm_offset_t     ustack_base,
  604         vm_size_t       ustack_top,
  605         task_t          task)
  606 {
  607         thread_t thread;
  608 
  609         queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
  610                 vm_offset_t     usp = thread->pcb->iss.uesp/*ebp works*/;
  611                 if (usp >= ustack_base && usp < ustack_top)
  612                         return thread;
  613         }
  614         return THREAD_NULL;
  615 }
  616 
  617 static void db_cproc_state(
  618         int     state,
  619         char    s[4])
  620 {
  621         if (state == 0) {
  622                 *s++ = 'R';
  623         } else {
  624                 if (state & 1) *s++ = 'S';
  625                 if (state & 2) *s++ = 'B';
  626                 if (state & 4) *s++ = 'C';
  627         }
  628         *s = 0;
  629 }
  630 
  631 /* offsets in a cproc structure */
  632 int db_cproc_next_offset = 0 * 4;
  633 int db_cproc_incarnation_offset = 1 * 4;
  634 int db_cproc_list_offset = 2 * 4;
  635 int db_cproc_wait_offset = 3 * 4;
  636 int db_cproc_context_offset = 5 * 4;
  637 int db_cproc_state_offset = 7 * 4;
  638 int db_cproc_stack_base_offset = 10 * 4 + sizeof(mach_msg_header_t);
  639 int db_cproc_stack_size_offset = 11 * 4 + sizeof(mach_msg_header_t);
  640 
  641 /* offsets in a cproc_switch context structure */
  642 int db_cprocsw_framep_offset = 3 * 4;
  643 int db_cprocsw_pc_offset = 4 * 4;
  644 
  645 #include <machine/setjmp.h>
  646 
  647 extern jmp_buf_t *db_recover;
  648 
  649 void db_trace_cproc(
  650         vm_offset_t     cproc,
  651         thread_t        thread)
  652 {
  653         jmp_buf_t       db_jmpbuf;
  654         jmp_buf_t       *prev = db_recover;
  655         task_t          task;
  656         db_addr_t       pc, fp;
  657 
  658         task = (thread == THREAD_NULL)? TASK_NULL: thread->task;
  659 
  660         if (!_setjmp(db_recover = &db_jmpbuf)) {
  661                 char pstate[4];
  662                 unsigned int s, w, n, c, cth;
  663 
  664                 s = db_get_task_value(cproc + db_cproc_state_offset, 4, FALSE, task);
  665                 w = db_get_task_value(cproc + db_cproc_wait_offset, 4, FALSE, task);
  666                 n = db_get_task_value(cproc + db_cproc_next_offset, 4, FALSE, task);
  667                 c = db_get_task_value(cproc + db_cproc_context_offset, 4, FALSE, task);
  668                 cth = db_get_task_value(cproc + db_cproc_incarnation_offset, 4, FALSE, task);
  669 
  670                 db_cproc_state(s, pstate);
  671 
  672                 db_printf("CThread %x (cproc %x) %s", cth, cproc, pstate);
  673                 if (w) db_printf(" awaits %x", w);
  674                 if (n) db_printf(" next %x", n);
  675                 db_printf("\n");
  676 
  677                 if ((s != 0) && (c != 0)) {
  678                         pc = db_get_task_value(c + db_cprocsw_pc_offset, 4, FALSE, task);
  679                         fp = c + db_cprocsw_framep_offset;
  680                 } else {
  681                         db_addr_t sb;
  682                         vm_size_t ss;
  683 
  684                         sb = db_get_task_value(cproc + db_cproc_stack_base_offset, sizeof(db_expr_t), FALSE, task);
  685                         ss = db_get_task_value(cproc + db_cproc_stack_size_offset, sizeof(db_expr_t), FALSE, task);
  686                         db_printf(" Stack base: %x\n", sb);
  687                         /*
  688                          *  Lessee now..
  689                          */
  690                         thread = db_find_kthread(sb, sb+ss, task);
  691                         if (thread != THREAD_NULL) {
  692                             pc = thread->pcb->iss.eip;
  693                             fp = thread->pcb->iss.ebp;
  694                         } else
  695                             fp = -1;
  696                 }
  697 
  698                 if (fp != -1)
  699                         db_i386_stack_trace(thread, (struct i386_frame*)fp, pc,
  700                                                 -1, F_USER_TRACE);
  701         }
  702 
  703         db_recover = prev;
  704 }
  705 
  706 void db_all_cprocs(
  707         task_t          task,
  708         db_expr_t       cproc_list)
  709 {
  710         jmp_buf_t       db_jmpbuf;
  711         jmp_buf_t       *prev = db_recover;
  712         thread_t        thread;
  713         db_expr_t       cproc, next;
  714 
  715 
  716         if (task != TASK_NULL) {
  717                 thread = (thread_t) queue_first(&task->thread_list);
  718         } else
  719                 thread = current_thread();
  720 
  721         if (cproc_list != 0)
  722                 next = cproc_list;
  723         else
  724                 if (!db_value_of_name("unix::cproc_list", &next)) {
  725                         db_printf("No cprocs.\n");
  726                         return;
  727                 }
  728 
  729 
  730         while (next) {
  731                 if (_setjmp(db_recover = &db_jmpbuf))
  732                         break;
  733 
  734                 cproc = db_get_task_value(next, 4, FALSE, TASK_NULL);
  735                 if (cproc == 0) break;
  736                 next = cproc + db_cproc_list_offset;
  737 
  738                 db_trace_cproc(cproc, thread);
  739         }
  740 
  741         db_recover = prev;
  742 }
  743 
  744 #endif  /* CTHREADS_SUPPORT */

Cache object: b36f021c36ad0e32c0e3ea17c36d9dba


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