Home | History | Annotate | Line # | Download | only in sparc
      1 /*	$NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $ */
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1991,1990 Carnegie Mellon University
      6  * All Rights Reserved.
      7  *
      8  * Permission to use, copy, modify and distribute this software and its
      9  * documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/proc.h>
     34 #include <sys/cpu.h>
     35 #include <sys/systm.h>
     36 
     37 #include <machine/db_machdep.h>
     38 
     39 #include <ddb/db_access.h>
     40 #include <ddb/db_user.h>
     41 #include <ddb/db_sym.h>
     42 #include <ddb/db_interface.h>
     43 #include <ddb/db_output.h>
     44 
     45 #define INKERNEL(va)	(((vaddr_t)(va)) >= USRSTACK)
     46 #ifdef _KERNEL
     47 #define ONINTSTACK(fr)	(						\
     48 	(u_int)(fr) <  (u_int)ddb_cpuinfo->eintstack &&		 	\
     49 	(u_int)(fr) >= (u_int)ddb_cpuinfo->eintstack - INT_STACK_SIZE	\
     50 )
     51 #else
     52 #define ONINTSTACK(fr)	(0)
     53 #endif
     54 
     55 #ifdef _KERNEL
     56 static db_addr_t
     57 db_fetch_word(const void *uaddr)
     58 {
     59 	u_int val;
     60 
     61 	if (ufetch_int(uaddr, &val) != 0)
     62 		val = (u_int)-1;
     63 	return val;
     64 }
     65 #endif /* _KERNEL */
     66 
     67 void
     68 db_stack_trace_print(db_expr_t addr, bool have_addr,
     69 		     db_expr_t count, const char *modif,
     70 		     void (*pr)(const char *, ...))
     71 {
     72 	struct frame	*frame, *prevframe;
     73 	db_addr_t	pc;
     74 	bool		kernel_only = true;
     75 	bool		trace_thread = false;
     76 	bool		lwpaddr = false;
     77 	const char	*cp = modif;
     78 	char		c;
     79 
     80 #ifdef _KERNEL
     81 	if (ddb_cpuinfo == NULL)
     82 		ddb_cpuinfo = curcpu();
     83 #endif
     84 
     85 	while ((c = *cp++) != 0) {
     86 		if (c == 'a') {
     87 			lwpaddr = true;
     88 			trace_thread = true;
     89 		}
     90 		if (c == 't')
     91 			trace_thread = true;
     92 		if (c == 'u')
     93 			kernel_only = false;
     94 	}
     95 
     96 	if (!have_addr) {
     97 		frame = (struct frame *)DDB_TF->tf_out[6];
     98 		pc = DDB_TF->tf_pc;
     99 	} else {
    100 		if (trace_thread) {
    101 			struct proc *p;
    102 			struct pcb *pcb;
    103 			struct lwp *l;
    104 			if (lwpaddr) {
    105 				l = (struct lwp *)addr;
    106 				p = l->l_proc;
    107 				(*pr)("trace: pid %d ", p->p_pid);
    108 			} else {
    109 				(*pr)("trace: pid %d ", (int)addr);
    110 #ifdef _KERNEL
    111 				p = proc_find_raw(addr);
    112 				if (p == NULL) {
    113 					(*pr)("not found\n");
    114 					return;
    115 				}
    116 				l = LIST_FIRST(&p->p_lwps);
    117 				KASSERT(l != NULL);
    118 #else
    119 				(*pr)("no proc_find_raw() in crash\n");
    120 				return;
    121 #endif
    122 			}
    123 			(*pr)("lid %d ", l->l_lid);
    124 			pcb = lwp_getpcb(l);
    125 			frame = (struct frame *)pcb->pcb_sp;
    126 			pc = pcb->pcb_pc;
    127 			(*pr)("at %p\n", frame);
    128 		} else {
    129 			frame = (struct frame *)addr;
    130 			pc = 0;
    131 		}
    132 	}
    133 
    134 	while (count--) {
    135 		int		i;
    136 		db_expr_t	offset;
    137 		const char	*name;
    138 		db_addr_t	prevpc;
    139 
    140 #ifdef _KERNEL
    141 #define FR(framep,field) (INKERNEL(framep)			\
    142 				? (u_int)(framep)->field	\
    143 				: db_fetch_word(&(framep)->field))
    144 #else
    145 /* XXX fix me, this is probably wrong */
    146 #define FR(framep,field) ((u_int)(framep)->field)
    147 #endif
    148 
    149 		/* Fetch return address and arguments frame */
    150 		prevpc = (db_addr_t)FR(frame, fr_pc);
    151 		prevframe = (struct frame *)FR(frame, fr_fp);
    152 
    153 		/*
    154 		 * Switch to frame that contains arguments
    155 		 */
    156 		if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only))
    157 			return;
    158 
    159 		if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) ||
    160 		    (INKERNEL(frame) && !INKERNEL(prevframe))) {
    161 			/* We're crossing a trap frame; pc = %l1 */
    162 			prevpc = (db_addr_t)FR(frame, fr_local[1]);
    163 		}
    164 
    165 		name = NULL;
    166 		if (INKERNEL(pc))
    167 			db_find_sym_and_offset(pc, &name, &offset);
    168 		if (name == NULL)
    169 			(*pr)("0x%lx(", pc);
    170 		else
    171 			(*pr)("%s(", name);
    172 
    173 		/*
    174 		 * Print %i0..%i5, hope these still reflect the
    175 		 * actual arguments somewhat...
    176 		 */
    177 		for (i = 0; i < 6; i++)
    178 			(*pr)("0x%x%s", FR(frame, fr_arg[i]),
    179 				(i < 5) ? ", " : ") at ");
    180 		if (INKERNEL(prevpc))
    181 			db_printsym(prevpc, DB_STGY_PROC, pr);
    182 		else
    183 			(*pr)("0x%lx", prevpc);
    184 		(*pr)("\n");
    185 
    186 		pc = prevpc;
    187 		frame = prevframe;
    188 	}
    189 }
    190