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

Cache object: bfa3a7eeef91cad3b4a2e3164cde5cde


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