1 /* $NetBSD: db_machdep.c,v 1.15 2022/12/24 14:47:47 uwe 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 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.15 2022/12/24 14:47:47 uwe Exp $");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34 #include <sys/syscall.h>
35
36 #include <machine/frame.h>
37 #include <machine/trap.h>
38 #include <machine/intrdefs.h>
39
40 #include <machine/db_machdep.h>
41 #include <ddb/db_sym.h>
42 #include <ddb/db_access.h>
43 #include <ddb/db_variables.h>
44 #include <ddb/db_output.h>
45 #include <ddb/db_interface.h>
46 #include <ddb/db_user.h>
47 #include <ddb/db_proc.h>
48 #include <ddb/db_command.h>
49 #include <x86/db_machdep.h>
50
51 #define dbreg(xx) (long *)offsetof(db_regs_t, tf_ ## xx)
52
53 /*
54 * Machine register set.
55 */
56 const struct db_variable db_regs[] = {
57 { "ds", dbreg(ds), db_x86_regop, NULL },
58 { "es", dbreg(es), db_x86_regop, NULL },
59 { "fs", dbreg(fs), db_x86_regop, NULL },
60 { "gs", dbreg(gs), db_x86_regop, NULL },
61 { "rdi", dbreg(rdi), db_x86_regop, NULL },
62 { "rsi", dbreg(rsi), db_x86_regop, NULL },
63 { "rbp", dbreg(rbp), db_x86_regop, NULL },
64 { "rbx", dbreg(rbx), db_x86_regop, NULL },
65 { "rdx", dbreg(rdx), db_x86_regop, NULL },
66 { "rcx", dbreg(rcx), db_x86_regop, NULL },
67 { "rax", dbreg(rax), db_x86_regop, NULL },
68 { "r8", dbreg(r8), db_x86_regop, NULL },
69 { "r9", dbreg(r9), db_x86_regop, NULL },
70 { "r10", dbreg(r10), db_x86_regop, NULL },
71 { "r11", dbreg(r11), db_x86_regop, NULL },
72 { "r12", dbreg(r12), db_x86_regop, NULL },
73 { "r13", dbreg(r13), db_x86_regop, NULL },
74 { "r14", dbreg(r14), db_x86_regop, NULL },
75 { "r15", dbreg(r15), db_x86_regop, NULL },
76 { "rip", dbreg(rip), db_x86_regop, NULL },
77 { "cs", dbreg(cs), db_x86_regop, NULL },
78 { "rflags", dbreg(rflags), db_x86_regop, NULL },
79 { "rsp", dbreg(rsp), db_x86_regop, NULL },
80 { "ss", dbreg(ss), db_x86_regop, NULL },
81 };
82 const struct db_variable * const db_eregs =
83 db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
84
85 /*
86 * Figure out how many arguments were passed into the frame at "fp".
87 * We can probably figure out how many arguments where passed above
88 * the first 6 (which are in registers), but since we can't
89 * reliably determine the values currently, just return 0.
90 */
91 int
db_numargs(long * retaddrp)92 db_numargs(long *retaddrp)
93 {
94 return 0;
95 }
96
97 /*
98 * Figure out the next frame up in the call stack.
99 * For trap(), we print the address of the faulting instruction and
100 * proceed with the calling frame. We return the ip that faulted.
101 * If the trap was caused by jumping through a bogus pointer, then
102 * the next line in the backtrace will list some random function as
103 * being called. It should get the argument list correct, though.
104 * It might be possible to dig out from the next frame up the name
105 * of the function that faulted, but that could get hairy.
106 */
107 int
db_nextframe(long ** nextframe,long ** retaddr,long ** arg0,db_addr_t * ip,long * argp,int is_trap,void (* pr)(const char *,...))108 db_nextframe(long **nextframe, long **retaddr, long **arg0, db_addr_t *ip,
109 long *argp, int is_trap, void (*pr)(const char *, ...))
110 {
111 struct trapframe *tf;
112 struct x86_64_frame *fp;
113 struct intrframe *ifp;
114 int trapno, err, i;
115 db_expr_t syscallno;
116
117 switch (is_trap) {
118 case NONE:
119 *ip = (db_addr_t)
120 db_get_value((long)*retaddr, 8, false);
121 fp = (struct x86_64_frame *)
122 db_get_value((long)*nextframe, 8, false);
123 if (fp == NULL)
124 return 0;
125 *nextframe = (long *)&fp->f_frame;
126 *retaddr = (long *)&fp->f_retaddr;
127 *arg0 = (long *)&fp->f_arg0;
128 break;
129
130 case SYSCALL:
131 tf = (struct trapframe *)argp;
132 syscallno = db_get_value((long)&tf->tf_rax, 8, false);
133 if (syscallno == SYS_syscall || syscallno == SYS___syscall) {
134 syscallno = db_get_value((long)&tf->tf_rdi, 8, false);
135 (*pr)("--- syscall (number %"DDB_EXPR_FMT"u"
136 " via SYS_syscall) ---\n",
137 syscallno);
138 } else {
139 (*pr)("--- syscall (number %"DDB_EXPR_FMT"u) ---\n",
140 syscallno);
141 }
142 return 0;
143
144 case TRAP:
145 case INTERRUPT:
146 default:
147
148 /* The only argument to trap() is the trapframe. */
149 tf = (struct trapframe *)argp;
150 switch (is_trap) {
151 case TRAP:
152 (*pr)("--- trap (number %"DDB_EXPR_FMT"u) ---\n",
153 db_get_value((long)&tf->tf_trapno, 8, false));
154 break;
155 case INTERRUPT:
156 (*pr)("--- interrupt ---\n");
157 break;
158 }
159 *ip = (db_addr_t)db_get_value((long)&tf->tf_rip, 8, false);
160 fp = (struct x86_64_frame *)
161 db_get_value((long)&tf->tf_rbp, 8, false);
162 if (fp == NULL)
163 return 0;
164 if (((uintptr_t)fp & 7) != 0)
165 return 0;
166 *nextframe = (long *)&fp->f_frame;
167 *retaddr = (long *)&fp->f_retaddr;
168 *arg0 = (long *)&fp->f_arg0;
169 break;
170 }
171
172 /*
173 * A bit of a hack. Since %rbp may be used in the stub code,
174 * walk the stack looking for a valid interrupt frame. Such
175 * a frame can be recognized by always having
176 * err 0 or IREENT_MAGIC and trapno T_ASTFLT.
177 */
178 int traptype = NONE;
179 db_sym_t sym = db_frame_info(*nextframe, (db_addr_t)*ip,
180 NULL, NULL, &traptype, NULL);
181 if (sym != DB_SYM_NULL && traptype == INTERRUPT) {
182 for (i = 0; i < 4; i++) {
183 ifp = (struct intrframe *)(argp + i);
184 err = db_get_value((long)&ifp->if_tf.tf_err,
185 sizeof(long), false);
186 trapno = db_get_value((long)&ifp->if_tf.tf_trapno,
187 sizeof(long), false);
188 if ((err == 0 || err == IREENT_MAGIC)
189 && trapno == T_ASTFLT) {
190 *nextframe = (long *)ifp - 1;
191 break;
192 }
193 }
194 if (i == 4) {
195 (*pr)("DDB lost frame for ");
196 db_printsym(*ip, DB_STGY_ANY, pr);
197 (*pr)(", trying %p\n",argp);
198 *nextframe = argp;
199 }
200 }
201 return 1;
202 }
203
204 db_sym_t
db_frame_info(long * frame,db_addr_t callpc,const char ** namep,db_expr_t * offp,int * is_trap,int * nargp)205 db_frame_info(long *frame, db_addr_t callpc, const char **namep,
206 db_expr_t *offp, int *is_trap, int *nargp)
207 {
208 db_expr_t offset;
209 db_sym_t sym;
210 int narg;
211 const char *name;
212
213 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
214 if (sym != DB_SYM_NULL && offset == 0) {
215 sym = db_search_symbol(callpc - 1, DB_STGY_ANY, &offset);
216 offset++;
217 }
218 db_symbol_values(sym, &name, NULL);
219 if (sym == DB_SYM_NULL)
220 return DB_SYM_NULL;
221
222 *is_trap = NONE;
223 narg = 0;
224
225 if (INKERNEL((long)frame) && name) {
226 /*
227 * XXX traps should be based off of the Xtrap*
228 * locations rather than on trap, since some traps
229 * (e.g., npxdna) don't go through trap()
230 */
231 if (!strcmp(name, "trap")) {
232 *is_trap = TRAP;
233 narg = 0;
234 } else if (!strcmp(name, "syscall") ||
235 !strcmp(name, "handle_syscall")) {
236 *is_trap = SYSCALL;
237 narg = 0;
238 } else if (name[0] == 'X') {
239 if (!strncmp(name, "Xintr", 5) ||
240 !strncmp(name, "Xhandle", 7) ||
241 !strncmp(name, "Xresume", 7) ||
242 !strncmp(name, "Xstray", 6) ||
243 !strncmp(name, "Xhold", 5) ||
244 !strncmp(name, "Xrecurse", 8) ||
245 !strcmp(name, "Xdoreti") ||
246 !strncmp(name, "Xsoft", 5)) {
247 *is_trap = INTERRUPT;
248 narg = 0;
249 }
250 }
251 }
252
253 if (offp != NULL)
254 *offp = offset;
255 if (nargp != NULL)
256 *nargp = narg;
257 if (namep != NULL)
258 *namep = name;
259 return sym;
260 }
261