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  * LLD will insert invalid instruction traps between functions.
   71  * Currently this is 0xefefefef but it may change in the future.
   72  */
   73 #define MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(ins) ((ins) == 0xefefefef)
   74 
   75 #if defined(__mips_n64)
   76 #       define  MIPS_IS_VALID_KERNELADDR(reg)   ((((reg) & 3) == 0) && \
   77                                         ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
   78 #else
   79 #       define  MIPS_IS_VALID_KERNELADDR(reg)   ((((reg) & 3) == 0) && \
   80                                         ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
   81 #endif
   82 
   83 static void
   84 stacktrace_subr(register_t pc, register_t sp, register_t ra)
   85 {
   86         InstFmt i;
   87         /*
   88          * Arrays for a0..a3 registers and flags if content
   89          * of these registers is valid, e.g. obtained from the stack
   90          */
   91         int valid_args[4];
   92         register_t args[4];
   93         register_t va, subr, cause, badvaddr;
   94         unsigned instr, mask;
   95         unsigned int frames = 0;
   96         int more, stksize, j;
   97         register_t      next_ra;
   98         bool trapframe;
   99 
  100 /* Jump here when done with a frame, to start a new one */
  101 loop:
  102 
  103         /*
  104          * Invalidate arguments values
  105          */
  106         valid_args[0] = 0;
  107         valid_args[1] = 0;
  108         valid_args[2] = 0;
  109         valid_args[3] = 0;
  110         next_ra = 0;
  111         stksize = 0;
  112         subr = 0;
  113         trapframe = false;
  114         if (frames++ > 100) {
  115                 db_printf("\nstackframe count exceeded\n");
  116                 return;
  117         }
  118 
  119         /* Check for bad SP: could foul up next frame. */
  120         if (!MIPS_IS_VALID_KERNELADDR(sp)) {
  121                 db_printf("SP 0x%jx: not in kernel\n", (uintmax_t)sp);
  122                 ra = 0;
  123                 subr = 0;
  124                 goto done;
  125         }
  126 #define Between(x, y, z) \
  127                 ( ((x) <= (y)) && ((y) < (z)) )
  128 #define pcBetween(a,b) \
  129                 Between((uintptr_t)a, pc, (uintptr_t)b)
  130 
  131         /*
  132          * Check for current PC in  exception handler code that don't have a
  133          * preceding "j ra" at the tail of the preceding function. Depends
  134          * on relative ordering of functions in exception.S, swtch.S.
  135          */
  136         if (pcBetween(MipsKernGenException, MipsUserGenException)) {
  137                 subr = (uintptr_t)MipsKernGenException;
  138                 trapframe = true;
  139         } else if (pcBetween(MipsUserGenException, MipsKernIntr))
  140                 subr = (uintptr_t)MipsUserGenException;
  141         else if (pcBetween(MipsKernIntr, MipsUserIntr)) {
  142                 subr = (uintptr_t)MipsKernIntr;
  143                 trapframe = true;
  144         } else if (pcBetween(MipsUserIntr, MipsTLBInvalidException))
  145                 subr = (uintptr_t)MipsUserIntr;
  146         else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) {
  147                 subr = (uintptr_t)MipsTLBInvalidException;
  148                 if (pc == (uintptr_t)MipsKStackOverflow)
  149                         trapframe = true;
  150         } else if (pcBetween(fork_trampoline, savectx))
  151                 subr = (uintptr_t)fork_trampoline;
  152         else if (pcBetween(savectx, cpu_throw))
  153                 subr = (uintptr_t)savectx;
  154         else if (pcBetween(cpu_throw, cpu_switch))
  155                 subr = (uintptr_t)cpu_throw;
  156         else if (pcBetween(cpu_switch, MipsSwitchFPState))
  157                 subr = (uintptr_t)cpu_switch;
  158         else if (pcBetween(_locore, _locoreEnd)) {
  159                 subr = (uintptr_t)_locore;
  160                 ra = 0;
  161                 goto done;
  162         }
  163 
  164         /* Check for bad PC. */
  165         if (!MIPS_IS_VALID_KERNELADDR(pc)) {
  166                 db_printf("PC 0x%jx: not in kernel\n", (uintmax_t)pc);
  167                 ra = 0;
  168                 goto done;
  169         }
  170 
  171         /*
  172          * For a trapframe, skip to the output and afterwards pull the
  173          * previous registers out of the trapframe instead of decoding
  174          * the function prologue.
  175          */
  176         if (trapframe)
  177                 goto done;
  178 
  179         /*
  180          * Find the beginning of the current subroutine by scanning
  181          * backwards from the current PC for the end of the previous
  182          * subroutine.
  183          */
  184         if (!subr) {
  185                 va = pc;
  186                 while (1) {
  187                         instr = kdbpeek((int *)va);
  188 
  189                         /* LLD fills padding between functions with 0xefefefef */
  190                         if (MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr))
  191                                 break;
  192 
  193                         if (MIPS_START_OF_FUNCTION(instr))
  194                                 break;
  195 
  196                         va -= sizeof(int);
  197                 }
  198 
  199                 /*
  200                  * Skip over nulls/trap padding which might separate
  201                  * object files or functions.
  202                  */
  203                 instr = kdbpeek((int *)va);
  204                 while (instr == 0 || MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr)) {
  205                         va += sizeof(int);
  206                         instr = kdbpeek((int *)va);
  207                 }
  208                 subr = va;
  209         }
  210 
  211         /* scan forwards to find stack size and any saved registers */
  212         stksize = 0;
  213         more = 3;
  214         mask = 0;
  215         for (va = subr; more; va += sizeof(int),
  216             more = (more == 3) ? 3 : more - 1) {
  217                 /* stop if hit our current position */
  218                 if (va >= pc)
  219                         break;
  220                 instr = kdbpeek((int *)va);
  221                 i.word = instr;
  222                 switch (i.JType.op) {
  223                 case OP_SPECIAL:
  224                         switch (i.RType.func) {
  225                         case OP_JR:
  226                         case OP_JALR:
  227                                 more = 2;       /* stop after next instruction */
  228                                 break;
  229 
  230                         case OP_SYSCALL:
  231                         case OP_BREAK:
  232                                 more = 1;       /* stop now */
  233                         }
  234                         break;
  235 
  236                 case OP_BCOND:
  237                 case OP_J:
  238                 case OP_JAL:
  239                 case OP_BEQ:
  240                 case OP_BNE:
  241                 case OP_BLEZ:
  242                 case OP_BGTZ:
  243                         more = 2;       /* stop after next instruction */
  244                         break;
  245 
  246                 case OP_COP0:
  247                 case OP_COP1:
  248                 case OP_COP2:
  249                 case OP_COP3:
  250                         switch (i.RType.rs) {
  251                         case OP_BCx:
  252                         case OP_BCy:
  253                                 more = 2;       /* stop after next instruction */
  254                         }
  255                         break;
  256 
  257                 case OP_SW:
  258                         /* look for saved registers on the stack */
  259                         if (i.IType.rs != 29)
  260                                 break;
  261                         /*
  262                          * only restore the first one except RA for
  263                          * MipsKernGenException case
  264                          */
  265                         if (mask & (1 << i.IType.rt)) {
  266                                 if (subr == (uintptr_t)MipsKernGenException &&
  267                                     i.IType.rt == 31)
  268                                         next_ra = kdbpeek((int *)(sp +
  269                                             (short)i.IType.imm));
  270                                 break;
  271                         }
  272                         mask |= (1 << i.IType.rt);
  273                         switch (i.IType.rt) {
  274                         case 4:/* a0 */
  275                                 args[0] = kdbpeek((int *)(sp + (short)i.IType.imm));
  276                                 valid_args[0] = 1;
  277                                 break;
  278 
  279                         case 5:/* a1 */
  280                                 args[1] = kdbpeek((int *)(sp + (short)i.IType.imm));
  281                                 valid_args[1] = 1;
  282                                 break;
  283 
  284                         case 6:/* a2 */
  285                                 args[2] = kdbpeek((int *)(sp + (short)i.IType.imm));
  286                                 valid_args[2] = 1;
  287                                 break;
  288 
  289                         case 7:/* a3 */
  290                                 args[3] = kdbpeek((int *)(sp + (short)i.IType.imm));
  291                                 valid_args[3] = 1;
  292                                 break;
  293 
  294                         case 31:        /* ra */
  295                                 ra = kdbpeek((int *)(sp + (short)i.IType.imm));
  296                         }
  297                         break;
  298 
  299                 case OP_SD:
  300                         /* look for saved registers on the stack */
  301                         if (i.IType.rs != 29)
  302                                 break;
  303                         /* only restore the first one */
  304                         if (mask & (1 << i.IType.rt))
  305                                 break;
  306                         mask |= (1 << i.IType.rt);
  307                         switch (i.IType.rt) {
  308                         case 4:/* a0 */
  309                                 args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm));
  310                                 valid_args[0] = 1;
  311                                 break;
  312 
  313                         case 5:/* a1 */
  314                                 args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm));
  315                                 valid_args[1] = 1;
  316                                 break;
  317 
  318                         case 6:/* a2 */
  319                                 args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm));
  320                                 valid_args[2] = 1;
  321                                 break;
  322 
  323                         case 7:/* a3 */
  324                                 args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm));
  325                                 valid_args[3] = 1;
  326                                 break;
  327 
  328                         case 31:        /* ra */
  329                                 ra = kdbpeekd((int *)(sp + (short)i.IType.imm));
  330                         }
  331                         break;
  332 
  333                 case OP_ADDI:
  334                 case OP_ADDIU:
  335                 case OP_DADDI:
  336                 case OP_DADDIU:
  337                         /* look for stack pointer adjustment */
  338                         if (i.IType.rs != 29 || i.IType.rt != 29)
  339                                 break;
  340                         stksize = -((short)i.IType.imm);
  341                 }
  342         }
  343 
  344 done:
  345         db_printsym(pc, DB_STGY_PROC);
  346         db_printf(" (");
  347         for (j = 0; j < 4; j ++) {
  348                 if (j > 0)
  349                         db_printf(",");
  350                 if (valid_args[j])
  351                         db_printf("%jx", (uintmax_t)(u_register_t)args[j]);
  352                 else
  353                         db_printf("?");
  354         }
  355 
  356         db_printf(") ra %jx sp %jx sz %d\n",
  357             (uintmax_t)(u_register_t) ra,
  358             (uintmax_t)(u_register_t) sp,
  359             stksize);
  360 
  361         if (trapframe) {
  362 #define TF_REG(base, reg)       ((base) + CALLFRAME_SIZ + ((reg) * SZREG))
  363 #if defined(__mips_n64) || defined(__mips_n32)
  364                 pc = kdbpeekd((int *)TF_REG(sp, PC));
  365                 ra = kdbpeekd((int *)TF_REG(sp, RA));
  366                 sp = kdbpeekd((int *)TF_REG(sp, SP));
  367                 cause = kdbpeekd((int *)TF_REG(sp, CAUSE));
  368                 badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR));
  369 #else
  370                 pc = kdbpeek((int *)TF_REG(sp, PC));
  371                 ra = kdbpeek((int *)TF_REG(sp, RA));
  372                 sp = kdbpeek((int *)TF_REG(sp, SP));
  373                 cause = kdbpeek((int *)TF_REG(sp, CAUSE));
  374                 badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR));
  375 #endif
  376 #undef TF_REG
  377                 db_printf("--- exception, cause %jx badvaddr %jx ---\n",
  378                     (uintmax_t)cause, (uintmax_t)badvaddr);
  379                 goto loop;
  380         } else if (ra) {
  381                 /*
  382                  * We subtract two instructions from ra to convert it
  383                  * from a return address to a calling address,
  384                  * accounting for the delay slot.
  385                  */
  386                 register_t next_pc = ra - 2 * sizeof(int);
  387                 if (pc == next_pc && stksize == 0)
  388                         db_printf("stacktrace: loop!\n");
  389                 else {
  390                         pc = next_pc;
  391                         sp += stksize;
  392                         ra = next_ra;
  393                         goto loop;
  394                 }
  395         }
  396 }
  397 
  398 void
  399 db_md_list_watchpoints()
  400 {
  401 }
  402 
  403 void
  404 db_trace_self(void)
  405 {
  406         register_t pc, ra, sp;
  407 
  408         sp = (register_t)(intptr_t)__builtin_frame_address(0);
  409         ra = (register_t)(intptr_t)__builtin_return_address(0);
  410 
  411         __asm __volatile(
  412                 "jal 99f\n"
  413                 "nop\n"
  414                 "99:\n"
  415                  "move %0, $31\n" /* get ra */
  416                  "move $31, %1\n" /* restore ra */
  417                  : "=r" (pc)
  418                  : "r" (ra));
  419         stacktrace_subr(pc, sp, ra);
  420         return;
  421 }
  422 
  423 int
  424 db_trace_thread(struct thread *thr, int count)
  425 {
  426         register_t pc, ra, sp;
  427         struct pcb *ctx;
  428 
  429         ctx = kdb_thr_ctx(thr);
  430         sp = (register_t)ctx->pcb_context[PCB_REG_SP];
  431         pc = (register_t)ctx->pcb_context[PCB_REG_PC];
  432         ra = (register_t)ctx->pcb_context[PCB_REG_RA];
  433         stacktrace_subr(pc, sp, ra);
  434 
  435         return (0);
  436 }
  437 
  438 void
  439 db_show_mdpcpu(struct pcpu *pc)
  440 {
  441 
  442         db_printf("ipis         = 0x%x\n", pc->pc_pending_ipis);
  443         db_printf("next ASID    = %d\n", pc->pc_next_asid);
  444         db_printf("GENID        = %d\n", pc->pc_asid_generation);
  445         return;
  446 }

Cache object: 43278118cfa81b09c9e460c2d3e4262c


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