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/mips/mips/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  * Copyright (c) 2004-2005, Juniper Networks, Inc.
    3  * All rights reserved.
    4  *
    5  *      JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta
    6  */
    7 
    8 #include <sys/cdefs.h>
    9 __FBSDID("$FreeBSD$");
   10 
   11 #include <sys/param.h>
   12 #include <sys/systm.h>
   13 #include <sys/kdb.h>
   14 #include <sys/proc.h>
   15 #include <sys/stack.h>
   16 #include <sys/sysent.h>
   17 
   18 #include <machine/db_machdep.h>
   19 #include <machine/md_var.h>
   20 #include <machine/mips_opcode.h>
   21 #include <machine/pcb.h>
   22 #include <machine/trap.h>
   23 
   24 #include <ddb/ddb.h>
   25 #include <ddb/db_sym.h>
   26 
   27 extern char _locore[];
   28 extern char _locoreEnd[];
   29 extern char edata[];
   30 
   31 /*
   32  * A function using a stack frame has the following instruction as the first
   33  * one: addiu sp,sp,-<frame_size>
   34  *
   35  * We make use of this to detect starting address of a function. This works
   36  * better than using 'j ra' instruction to signify end of the previous
   37  * function (for e.g. functions like boot() or panic() do not actually
   38  * emit a 'j ra' instruction).
   39  *
   40  * XXX the abi does not require that the addiu instruction be the first one.
   41  */
   42 #define MIPS_START_OF_FUNCTION(ins)     (((ins) & 0xffff8000) == 0x27bd8000)
   43 
   44 /*
   45  * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
   46  *
   47  * XXX gcc doesn't do this for functions with __noreturn__ attribute.
   48  */
   49 #define MIPS_END_OF_FUNCTION(ins)       ((ins) == 0x03e00008)
   50 
   51 /*
   52  * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word
   53  */
   54 #define kdbpeekD(addr)  kdbpeek(((int *)(addr)) + 1)
   55 
   56 /*
   57  * Functions ``special'' enough to print by name
   58  */
   59 #ifdef __STDC__
   60 #define Name(_fn)  { (void*)_fn, # _fn }
   61 #else
   62 #define Name(_fn) { _fn, "_fn"}
   63 #endif
   64 static struct {
   65         void *addr;
   66         char *name;
   67 }      names[] = {
   68 
   69         Name(trap),
   70         Name(MipsKernGenException),
   71         Name(MipsUserGenException),
   72         Name(MipsKernIntr),
   73         Name(MipsUserIntr),
   74         Name(cpu_switch),
   75         {
   76                 0, 0
   77         }
   78 };
   79 
   80 /*
   81  * Map a function address to a string name, if known; or a hex string.
   82  */
   83 static char *
   84 fn_name(uintptr_t addr)
   85 {
   86         static char buf[17];
   87         int i = 0;
   88 
   89         db_expr_t diff;
   90         c_db_sym_t sym;
   91         char *symname;
   92 
   93         diff = 0;
   94         symname = NULL;
   95         sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff);
   96         db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0);
   97         if (symname && diff == 0)
   98                 return (symname);
   99 
  100         for (i = 0; names[i].name; i++)
  101                 if (names[i].addr == (void *)addr)
  102                         return (names[i].name);
  103         sprintf(buf, "%jx", (uintmax_t)addr);
  104         return (buf);
  105 }
  106 
  107 void
  108 stacktrace_subr(register_t pc, register_t sp, register_t ra,
  109         int (*printfn) (const char *,...))
  110 {
  111         InstFmt i;
  112         /*
  113          * Arrays for a0..a3 registers and flags if content
  114          * of these registers is valid, e.g. obtained from the stack
  115          */
  116         int valid_args[4];
  117         uintptr_t args[4];
  118         uintptr_t va, subr;
  119         unsigned instr, mask;
  120         unsigned int frames = 0;
  121         int more, stksize, j;
  122 
  123 /* Jump here when done with a frame, to start a new one */
  124 loop:
  125 
  126         /*
  127          * Invalidate arguments values
  128          */
  129         valid_args[0] = 0;
  130         valid_args[1] = 0;
  131         valid_args[2] = 0;
  132         valid_args[3] = 0;
  133 /* Jump here after a nonstandard (interrupt handler) frame */
  134         stksize = 0;
  135         subr = 0;
  136         if (frames++ > 100) {
  137                 (*printfn) ("\nstackframe count exceeded\n");
  138                 /* return breaks stackframe-size heuristics with gcc -O2 */
  139                 goto finish;    /* XXX */
  140         }
  141         /* check for bad SP: could foul up next frame */
  142         /*XXX MIPS64 bad: this hard-coded SP is lame */
  143         if (sp & 3 || (uintptr_t)sp < 0x80000000u) {
  144                 (*printfn) ("SP 0x%x: not in kernel\n", sp);
  145                 ra = 0;
  146                 subr = 0;
  147                 goto done;
  148         }
  149 #define Between(x, y, z) \
  150                 ( ((x) <= (y)) && ((y) < (z)) )
  151 #define pcBetween(a,b) \
  152                 Between((uintptr_t)a, pc, (uintptr_t)b)
  153 
  154         /*
  155          * Check for current PC in  exception handler code that don't have a
  156          * preceding "j ra" at the tail of the preceding function. Depends
  157          * on relative ordering of functions in exception.S, swtch.S.
  158          */
  159         if (pcBetween(MipsKernGenException, MipsUserGenException))
  160                 subr = (uintptr_t)MipsKernGenException;
  161         else if (pcBetween(MipsUserGenException, MipsKernIntr))
  162                 subr = (uintptr_t)MipsUserGenException;
  163         else if (pcBetween(MipsKernIntr, MipsUserIntr))
  164                 subr = (uintptr_t)MipsKernIntr;
  165         else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
  166                 subr = (uintptr_t)MipsUserIntr;
  167         else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException))
  168                 subr = (uintptr_t)MipsTLBInvalidException;
  169         else if (pcBetween(fork_trampoline, savectx))
  170                 subr = (uintptr_t)fork_trampoline;
  171         else if (pcBetween(savectx, cpu_throw))
  172                 subr = (uintptr_t)savectx;
  173         else if (pcBetween(cpu_throw, cpu_switch))
  174                 subr = (uintptr_t)cpu_throw;
  175         else if (pcBetween(cpu_switch, MipsSwitchFPState))
  176                 subr = (uintptr_t)cpu_switch;
  177         else if (pcBetween(_locore, _locoreEnd)) {
  178                 subr = (uintptr_t)_locore;
  179                 ra = 0;
  180                 goto done;
  181         }
  182         /* check for bad PC */
  183         /*XXX MIPS64 bad: These hard coded constants are lame */
  184         if (pc & 3 || pc < (uintptr_t)0x80000000) {
  185                 (*printfn) ("PC 0x%x: not in kernel\n", pc);
  186                 ra = 0;
  187                 goto done;
  188         }
  189         /*
  190          * Find the beginning of the current subroutine by scanning
  191          * backwards from the current PC for the end of the previous
  192          * subroutine.
  193          */
  194         if (!subr) {
  195                 va = pc - sizeof(int);
  196                 while (1) {
  197                         instr = kdbpeek((int *)va);
  198 
  199                         if (MIPS_START_OF_FUNCTION(instr))
  200                                 break;
  201 
  202                         if (MIPS_END_OF_FUNCTION(instr)) {
  203                                 /* skip over branch-delay slot instruction */
  204                                 va += 2 * sizeof(int);
  205                                 break;
  206                         }
  207 
  208                         va -= sizeof(int);
  209                 }
  210 
  211                 /* skip over nulls which might separate .o files */
  212                 while ((instr = kdbpeek((int *)va)) == 0)
  213                         va += sizeof(int);
  214                 subr = va;
  215         }
  216         /* scan forwards to find stack size and any saved registers */
  217         stksize = 0;
  218         more = 3;
  219         mask = 0;
  220         for (va = subr; more; va += sizeof(int),
  221             more = (more == 3) ? 3 : more - 1) {
  222                 /* stop if hit our current position */
  223                 if (va >= pc)
  224                         break;
  225                 instr = kdbpeek((int *)va);
  226                 i.word = instr;
  227                 switch (i.JType.op) {
  228                 case OP_SPECIAL:
  229                         switch (i.RType.func) {
  230                         case OP_JR:
  231                         case OP_JALR:
  232                                 more = 2;       /* stop after next instruction */
  233                                 break;
  234 
  235                         case OP_SYSCALL:
  236                         case OP_BREAK:
  237                                 more = 1;       /* stop now */
  238                         };
  239                         break;
  240 
  241                 case OP_BCOND:
  242                 case OP_J:
  243                 case OP_JAL:
  244                 case OP_BEQ:
  245                 case OP_BNE:
  246                 case OP_BLEZ:
  247                 case OP_BGTZ:
  248                         more = 2;       /* stop after next instruction */
  249                         break;
  250 
  251                 case OP_COP0:
  252                 case OP_COP1:
  253                 case OP_COP2:
  254                 case OP_COP3:
  255                         switch (i.RType.rs) {
  256                         case OP_BCx:
  257                         case OP_BCy:
  258                                 more = 2;       /* stop after next instruction */
  259                         };
  260                         break;
  261 
  262                 case OP_SW:
  263                         /* look for saved registers on the stack */
  264                         if (i.IType.rs != 29)
  265                                 break;
  266                         /* only restore the first one */
  267                         if (mask & (1 << i.IType.rt))
  268                                 break;
  269                         mask |= (1 << i.IType.rt);
  270                         switch (i.IType.rt) {
  271                         case 4:/* a0 */
  272                                 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
  273                                 valid_args[0] = 1;
  274                                 break;
  275 
  276                         case 5:/* a1 */
  277                                 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
  278                                 valid_args[1] = 1;
  279                                 break;
  280 
  281                         case 6:/* a2 */
  282                                 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
  283                                 valid_args[2] = 1;
  284                                 break;
  285 
  286                         case 7:/* a3 */
  287                                 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
  288                                 valid_args[3] = 1;
  289                                 break;
  290 
  291                         case 31:        /* ra */
  292                                 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
  293                         }
  294                         break;
  295 
  296                 case OP_SD:
  297                         /* look for saved registers on the stack */
  298                         if (i.IType.rs != 29)
  299                                 break;
  300                         /* only restore the first one */
  301                         if (mask & (1 << i.IType.rt))
  302                                 break;
  303                         mask |= (1 << i.IType.rt);
  304                         switch (i.IType.rt) {
  305                         case 4:/* a0 */
  306                                 args[0] = kdbpeekD((int *)(sp + (short)i.IType.imm));
  307                                 valid_args[0] = 1;
  308                                 break;
  309 
  310                         case 5:/* a1 */
  311                                 args[1] = kdbpeekD((int *)(sp + (short)i.IType.imm));
  312                                 valid_args[1] = 1;
  313                                 break;
  314 
  315                         case 6:/* a2 */
  316                                 args[2] = kdbpeekD((int *)(sp + (short)i.IType.imm));
  317                                 valid_args[2] = 1;
  318                                 break;
  319 
  320                         case 7:/* a3 */
  321                                 args[3] = kdbpeekD((int *)(sp + (short)i.IType.imm));
  322                                 valid_args[3] = 1;
  323                                 break;
  324 
  325                         case 31:        /* ra */
  326                                 ra = kdbpeekD((int *)(sp + (short)i.IType.imm));
  327                         }
  328                         break;
  329 
  330                 case OP_ADDI:
  331                 case OP_ADDIU:
  332                         /* look for stack pointer adjustment */
  333                         if (i.IType.rs != 29 || i.IType.rt != 29)
  334                                 break;
  335                         stksize = -((short)i.IType.imm);
  336                 }
  337         }
  338 
  339 done:
  340         (*printfn) ("%s+%x (", fn_name(subr), pc - subr);
  341         for (j = 0; j < 4; j ++) {
  342                 if (j > 0)
  343                         (*printfn)(",");
  344                 if (valid_args[j])
  345                         (*printfn)("%x", args[j]);
  346                 else
  347                         (*printfn)("?");
  348         }
  349 
  350         (*printfn) (") ra %x sp %x sz %d\n", ra, sp, stksize);
  351 
  352         if (ra) {
  353                 if (pc == ra && stksize == 0)
  354                         (*printfn) ("stacktrace: loop!\n");
  355                 else {
  356                         pc = ra;
  357                         sp += stksize;
  358                         ra = 0;
  359                         goto loop;
  360                 }
  361         } else {
  362 finish:
  363                 if (curproc)
  364                         (*printfn) ("pid %d\n", curproc->p_pid);
  365                 else
  366                         (*printfn) ("curproc NULL\n");
  367         }
  368 }
  369 
  370 
  371 int
  372 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
  373 {
  374 
  375         return(0);
  376 }
  377 
  378 
  379 int
  380 db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
  381 {
  382 
  383         return(0);
  384 }
  385 
  386 
  387 void
  388 db_md_list_watchpoints()
  389 {
  390 }
  391 
  392 void
  393 db_trace_self(void)
  394 {
  395         db_trace_thread (curthread, -1);
  396         return;
  397 }
  398 
  399 int
  400 db_trace_thread(struct thread *thr, int count)
  401 {
  402         register_t pc, ra, sp;
  403         struct pcb *ctx;
  404 
  405         if (thr == curthread) {
  406                 sp = (register_t)(intptr_t)__builtin_frame_address(0);
  407                 ra = (register_t)(intptr_t)__builtin_return_address(0);
  408 
  409                 __asm __volatile(
  410                         "jal 99f\n"
  411                         "nop\n"
  412                         "99:\n"
  413                          "move %0, $31\n" /* get ra */
  414                          "move $31, %1\n" /* restore ra */
  415                          : "=r" (pc)
  416                          : "r" (ra));
  417 
  418         } else {
  419                 ctx = kdb_thr_ctx(thr);
  420                 sp = (register_t)ctx->pcb_context[PREG_SP];
  421                 pc = (register_t)ctx->pcb_context[PREG_PC];
  422                 ra = (register_t)ctx->pcb_context[PREG_RA];
  423         }
  424 
  425         stacktrace_subr(pc, sp, ra,
  426             (int (*) (const char *, ...))db_printf);
  427 
  428         return (0);
  429 }
  430 
  431 void
  432 db_show_mdpcpu(struct pcpu *pc)
  433 {
  434 
  435         db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
  436         db_printf("next ASID    = %d\n", pc->pc_next_asid);
  437         db_printf("GENID        = %d\n", pc->pc_asid_generation);
  438         return;
  439 }

Cache object: cc26047a0073c849a6a58e5e6691c030


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