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@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
db_fetch_word(const void * uaddr)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
db_stack_trace_print(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif,void (* pr)(const char *,...))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