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

Cache object: 88e47bfd2f3e805440e5c6a7844e256c


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