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/sparc64/sparc64/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) 2001 Jake Burkholder.
    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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kdb.h>
   33 #include <sys/linker_set.h>
   34 #include <sys/proc.h>
   35 #include <sys/stack.h>
   36 #include <sys/sysent.h>
   37 
   38 #include <vm/vm.h>
   39 #include <vm/vm_page.h>
   40 #include <vm/vm_map.h>
   41 
   42 #include <machine/cpu.h>
   43 #include <machine/pcb.h>
   44 #include <machine/trap.h>
   45 #include <machine/vmparam.h>
   46 
   47 #include <ddb/ddb.h>
   48 #include <ddb/db_access.h>
   49 #include <ddb/db_sym.h>
   50 #include <ddb/db_variables.h>
   51 #include <ddb/db_watch.h>
   52 
   53 extern char tl_trap_begin[];
   54 extern char tl_trap_end[];
   55 extern char tl_text_begin[];
   56 extern char tl_text_end[];
   57 
   58 #define INKERNEL(va) \
   59         ((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
   60 
   61 static db_varfcn_t db_frame;
   62 
   63 #define DB_OFFSET(x)    (db_expr_t *)offsetof(struct trapframe, x)
   64 struct  db_variable db_regs[] = {
   65         { "g0",         DB_OFFSET(tf_global[0]),        db_frame },
   66         { "g1",         DB_OFFSET(tf_global[1]),        db_frame },
   67         { "g2",         DB_OFFSET(tf_global[2]),        db_frame },
   68         { "g3",         DB_OFFSET(tf_global[3]),        db_frame },
   69         { "g4",         DB_OFFSET(tf_global[4]),        db_frame },
   70         { "g5",         DB_OFFSET(tf_global[5]),        db_frame },
   71         { "g6",         DB_OFFSET(tf_global[6]),        db_frame },
   72         { "g7",         DB_OFFSET(tf_global[7]),        db_frame },
   73         { "i0",         DB_OFFSET(tf_out[0]),           db_frame },
   74         { "i1",         DB_OFFSET(tf_out[1]),           db_frame },
   75         { "i2",         DB_OFFSET(tf_out[2]),           db_frame },
   76         { "i3",         DB_OFFSET(tf_out[3]),           db_frame },
   77         { "i4",         DB_OFFSET(tf_out[4]),           db_frame },
   78         { "i5",         DB_OFFSET(tf_out[5]),           db_frame },
   79         { "i6",         DB_OFFSET(tf_out[6]),           db_frame },
   80         { "i7",         DB_OFFSET(tf_out[7]),           db_frame },
   81         { "tnpc",       DB_OFFSET(tf_tnpc),             db_frame },
   82         { "tpc",        DB_OFFSET(tf_tpc),              db_frame },
   83         { "tstate",     DB_OFFSET(tf_tstate),           db_frame },
   84 };
   85 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
   86 
   87 static int
   88 db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
   89 {
   90         uint64_t *reg;
   91 
   92         if (kdb_frame == NULL)
   93                 return (0);
   94         reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
   95         if (op == DB_VAR_GET)
   96                 *valuep = *reg;
   97         else
   98                 *reg = *valuep;
   99         return (1);
  100 }
  101 
  102 /*
  103  * User stack trace (debugging aid).
  104  */
  105 static void
  106 db_utrace(struct thread *td, struct trapframe *tf, int count)
  107 {
  108         struct pcb *pcb;
  109         db_addr_t sp, rsp, o7, pc;
  110         int i, found;
  111 
  112         pcb = td->td_pcb;
  113         sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
  114         o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
  115             FALSE);
  116         pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
  117         db_printf("user trace: trap %%o7=%#lx\n", o7);
  118         while (count-- && sp != 0 && !db_pager_quit) {
  119                 db_printf("pc %#lx, sp %#lx\n", pc, sp);
  120                 /* First, check whether the frame is in the pcb. */
  121                 found = 0;
  122                 for (i = 0; i < pcb->pcb_nsaved; i++) {
  123                         if (pcb->pcb_rwsp[i] == sp) {
  124                                 found = 1;
  125                                 sp = pcb->pcb_rw[i].rw_in[6];
  126                                 pc = pcb->pcb_rw[i].rw_in[7];
  127                                 break;
  128                         }
  129                 }
  130                 if (!found) {
  131                         rsp = sp + SPOFF;
  132                         sp = 0;
  133                         if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
  134                             &sp, sizeof(sp)) != 0 ||
  135                             copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
  136                             &pc, sizeof(pc)) != 0)
  137                                 break;
  138                 }
  139         }
  140         db_printf("done\n");
  141 }
  142 
  143 static int
  144 db_print_trap(struct thread *td, struct trapframe *tf, int count)
  145 {
  146         struct proc *p;
  147         const char *symname;
  148         c_db_sym_t sym;
  149         db_expr_t diff;
  150         db_addr_t func;
  151         db_addr_t tpc;
  152         u_long type;
  153         u_long sfar;
  154         u_long sfsr;
  155         u_long tar;
  156         u_long level;
  157         u_long pil;
  158         u_long code;
  159         u_long o7;
  160         int user;
  161 
  162         p = td->td_proc;
  163         type = db_get_value((db_addr_t)&tf->tf_type,
  164             sizeof(tf->tf_type), FALSE);
  165         db_printf("-- %s", trap_msg[type & ~T_KERNEL]);
  166         switch (type & ~T_KERNEL) {
  167         case T_DATA_PROTECTION:
  168                 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
  169                     sizeof(tf->tf_tar), FALSE);
  170                 db_printf(" tar=%#lx", tar);
  171                 /* fall through */
  172         case T_DATA_EXCEPTION:
  173         case T_INSTRUCTION_EXCEPTION:
  174         case T_MEM_ADDRESS_NOT_ALIGNED:
  175                 sfar = (u_long)db_get_value((db_addr_t)&tf->tf_sfar,
  176                     sizeof(tf->tf_sfar), FALSE);
  177                 sfsr = (u_long)db_get_value((db_addr_t)&tf->tf_sfsr,
  178                     sizeof(tf->tf_sfsr), FALSE);
  179                 db_printf(" sfar=%#lx sfsr=%#lx", sfar, sfsr);
  180                 break;
  181         case T_DATA_MISS:
  182         case T_INSTRUCTION_MISS:
  183                 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
  184                     sizeof(tf->tf_tar), FALSE);
  185                 db_printf(" tar=%#lx", tar);
  186                 break;
  187         case T_SYSCALL:
  188                 code = db_get_value((db_addr_t)&tf->tf_global[1],
  189                     sizeof(tf->tf_global[1]), FALSE);
  190                 db_printf(" (%ld", code);
  191                 if (code >= 0 && code < p->p_sysent->sv_size) {
  192                         func = (db_addr_t)p->p_sysent->sv_table[code].sy_call;
  193                         sym = db_search_symbol(func, DB_STGY_ANY, &diff);
  194                         if (sym != DB_SYM_NULL && diff == 0) {
  195                                 db_symbol_values(sym, &symname, NULL);
  196                                 db_printf(", %s, %s", p->p_sysent->sv_name,
  197                                     symname);
  198                         }
  199                         db_printf(")");
  200                 }
  201                 break;
  202         case T_INTERRUPT:
  203                 level = (u_long)db_get_value((db_addr_t)&tf->tf_level,
  204                     sizeof(tf->tf_level), FALSE);
  205                 pil = (u_long)db_get_value((db_addr_t)&tf->tf_pil,
  206                     sizeof(tf->tf_pil), FALSE);
  207                 db_printf(" level=%#lx pil=%#lx", level, pil);
  208                 break;
  209         default:
  210                 break;
  211         }
  212         o7 = (u_long)db_get_value((db_addr_t)&tf->tf_out[7],
  213             sizeof(tf->tf_out[7]), FALSE);
  214         db_printf(" %%o7=%#lx --\n", o7);
  215         user = (type & T_KERNEL) == 0;
  216         if (user) {
  217                 tpc = db_get_value((db_addr_t)&tf->tf_tpc,
  218                     sizeof(tf->tf_tpc), FALSE);
  219                 db_printf("userland() at ");
  220                 db_printsym(tpc, DB_STGY_PROC);
  221                 db_printf("\n");
  222                 db_utrace(td, tf, count);
  223         }
  224         return (user);
  225 }
  226 
  227 static int
  228 db_backtrace(struct thread *td, struct frame *fp, int count)
  229 {
  230         struct trapframe *tf;
  231         const char *name;
  232         c_db_sym_t sym;
  233         db_expr_t offset;
  234         db_expr_t value;
  235         db_addr_t npc;
  236         db_addr_t pc;
  237         int trap;
  238         int user;
  239 
  240         if (count == -1)
  241                 count = 1024;
  242 
  243         trap = 0;
  244         user = 0;
  245         npc = 0;
  246         while (count-- && !user && !db_pager_quit) {
  247                 pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
  248                     sizeof(fp->fr_pc), FALSE);
  249                 if (trap) {
  250                         pc = npc;
  251                         trap = 0;
  252                 }
  253                 if (!INKERNEL((vm_offset_t)pc))
  254                         break;
  255                 sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
  256                 if (sym == C_DB_SYM_NULL) {
  257                         value = 0;
  258                         name = NULL;
  259                 } else
  260                         db_symbol_values(sym, &name, &value);
  261                 if (name == NULL)
  262                         name = "(null)";
  263                 fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
  264                    sizeof(fp->fr_fp), FALSE) + SPOFF);
  265                 if ((value > (u_long)tl_trap_begin &&
  266                     value < (u_long)tl_trap_end) ||
  267                     (value > (u_long)tl_text_begin &&
  268                     value < (u_long)tl_text_end)) {
  269                         tf = (struct trapframe *)(fp + 1);
  270                         npc = db_get_value((db_addr_t)&tf->tf_tpc,
  271                             sizeof(tf->tf_tpc), FALSE);
  272                         user = db_print_trap(td, tf, count);
  273                         trap = 1;
  274                 } else {
  275                         db_printf("%s() at ", name);
  276                         db_printsym(pc, DB_STGY_PROC);
  277                         db_printf("\n");
  278                 }
  279         }
  280         return (0);
  281 }
  282 
  283 void
  284 db_trace_self(void)
  285 {
  286         db_expr_t addr;
  287 
  288         addr = (db_expr_t)__builtin_frame_address(1);
  289         db_backtrace(curthread, (struct frame *)(addr + SPOFF), -1);
  290 }
  291 
  292 int
  293 db_trace_thread(struct thread *td, int count)
  294 {
  295         struct pcb *ctx;
  296 
  297         ctx = kdb_thr_ctx(td);
  298         return (db_backtrace(td, (struct frame*)(ctx->pcb_sp + SPOFF), count));
  299 }
  300 
  301 void
  302 stack_save(struct stack *st)
  303 {
  304         struct frame *fp;
  305         db_expr_t addr;
  306         vm_offset_t callpc;
  307 
  308         stack_zero(st);
  309         addr = (db_expr_t)__builtin_frame_address(1);
  310         fp = (struct frame *)(addr + SPOFF);
  311         while (1) {
  312                 callpc = fp->fr_pc;
  313                 if (!INKERNEL(callpc))
  314                         break;
  315                 /* Don't bother traversing trap frames. */
  316                 if ((callpc > (u_long)tl_trap_begin &&
  317                     callpc < (u_long)tl_trap_end) ||
  318                     (callpc > (u_long)tl_text_begin &&
  319                     callpc < (u_long)tl_text_end))
  320                         break;
  321                 if (stack_put(st, callpc) == -1)
  322                         break;
  323                 fp = (struct frame *)(fp->fr_fp + SPOFF);
  324         }
  325 }

Cache object: 3680382a0991c52f7021dee2a0beb0e5


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