1*deefc290Suwe /* $NetBSD: db_machdep.c,v 1.10 2022/12/24 14:47:47 uwe Exp $ */
2821b547bSchristos
3821b547bSchristos /*
4821b547bSchristos * Mach Operating System
5821b547bSchristos * Copyright (c) 1991,1990 Carnegie Mellon University
6821b547bSchristos * All Rights Reserved.
7821b547bSchristos *
8821b547bSchristos * Permission to use, copy, modify and distribute this software and its
9821b547bSchristos * documentation is hereby granted, provided that both the copyright
10821b547bSchristos * notice and this permission notice appear in all copies of the
11821b547bSchristos * software, derivative works or modified versions, and any portions
12821b547bSchristos * thereof, and that both notices appear in supporting documentation.
13821b547bSchristos *
14821b547bSchristos * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15821b547bSchristos * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16821b547bSchristos * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17821b547bSchristos *
18821b547bSchristos * Carnegie Mellon requests users of this software to return to
19821b547bSchristos *
20821b547bSchristos * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21821b547bSchristos * School of Computer Science
22821b547bSchristos * Carnegie Mellon University
23821b547bSchristos * Pittsburgh PA 15213-3890
24821b547bSchristos *
25821b547bSchristos * any improvements or extensions that they make and grant Carnegie the
26821b547bSchristos * rights to redistribute these changes.
27821b547bSchristos */
28821b547bSchristos
29821b547bSchristos #include <sys/cdefs.h>
30*deefc290Suwe __KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.10 2022/12/24 14:47:47 uwe Exp $");
31821b547bSchristos
32821b547bSchristos #include <sys/param.h>
33821b547bSchristos #include <sys/systm.h>
34821b547bSchristos #include <sys/proc.h>
35821b547bSchristos
367d987dd7Smrg #ifndef _KERNEL
377d987dd7Smrg #include <stdbool.h>
387d987dd7Smrg #endif
397d987dd7Smrg
40821b547bSchristos #include <machine/frame.h>
41821b547bSchristos #include <machine/trap.h>
42821b547bSchristos #include <machine/intrdefs.h>
437d987dd7Smrg #include <machine/cpu.h>
447d987dd7Smrg
457d987dd7Smrg #include <uvm/uvm_prot.h>
467d987dd7Smrg /* We need to include both for ddb and crash(8). */
477d987dd7Smrg #include <uvm/uvm_pmap.h>
487d987dd7Smrg #include <machine/pmap.h>
49821b547bSchristos
50821b547bSchristos #include <machine/db_machdep.h>
51821b547bSchristos #include <ddb/db_sym.h>
52821b547bSchristos #include <ddb/db_access.h>
53821b547bSchristos #include <ddb/db_variables.h>
54821b547bSchristos #include <ddb/db_output.h>
55821b547bSchristos #include <ddb/db_interface.h>
56821b547bSchristos #include <ddb/db_user.h>
57821b547bSchristos #include <ddb/db_proc.h>
58821b547bSchristos #include <ddb/db_command.h>
59821b547bSchristos #include <ddb/db_cpu.h>
60821b547bSchristos #include <x86/db_machdep.h>
61821b547bSchristos
62821b547bSchristos #define dbreg(xx) (long *)offsetof(db_regs_t, tf_ ## xx)
63821b547bSchristos
64f54b4a9bSmaxv /*
65f54b4a9bSmaxv * Machine register set.
66f54b4a9bSmaxv */
67821b547bSchristos const struct db_variable db_regs[] = {
68821b547bSchristos { "ds", dbreg(ds), db_x86_regop, NULL },
69821b547bSchristos { "es", dbreg(es), db_x86_regop, NULL },
70821b547bSchristos { "fs", dbreg(fs), db_x86_regop, NULL },
71821b547bSchristos { "gs", dbreg(gs), db_x86_regop, NULL },
72821b547bSchristos { "edi", dbreg(edi), db_x86_regop, NULL },
73821b547bSchristos { "esi", dbreg(esi), db_x86_regop, NULL },
74821b547bSchristos { "ebp", dbreg(ebp), db_x86_regop, NULL },
75821b547bSchristos { "ebx", dbreg(ebx), db_x86_regop, NULL },
76821b547bSchristos { "edx", dbreg(edx), db_x86_regop, NULL },
77821b547bSchristos { "ecx", dbreg(ecx), db_x86_regop, NULL },
78821b547bSchristos { "eax", dbreg(eax), db_x86_regop, NULL },
79821b547bSchristos { "eip", dbreg(eip), db_x86_regop, NULL },
80821b547bSchristos { "cs", dbreg(cs), db_x86_regop, NULL },
81821b547bSchristos { "eflags", dbreg(eflags), db_x86_regop, NULL },
82821b547bSchristos { "esp", dbreg(esp), db_x86_regop, NULL },
83821b547bSchristos { "ss", dbreg(ss), db_x86_regop, NULL },
84821b547bSchristos };
85821b547bSchristos const struct db_variable * const db_eregs =
86821b547bSchristos db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
87821b547bSchristos
88821b547bSchristos /*
89821b547bSchristos * Figure out how many arguments were passed into the frame at "fp".
90821b547bSchristos */
91821b547bSchristos int
db_numargs(long * retaddrp)92821b547bSchristos db_numargs(long *retaddrp)
93821b547bSchristos {
94821b547bSchristos int *argp;
95821b547bSchristos int inst;
96821b547bSchristos int args;
97821b547bSchristos extern char etext[];
98821b547bSchristos
99821b547bSchristos argp = (int *)db_get_value((int)retaddrp, 4, false);
100821b547bSchristos if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) {
101821b547bSchristos args = 10;
102821b547bSchristos } else {
103821b547bSchristos inst = db_get_value((int)argp, 4, false);
104821b547bSchristos if ((inst & 0xff) == 0x59) /* popl %ecx */
105821b547bSchristos args = 1;
106821b547bSchristos else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
107821b547bSchristos args = ((inst >> 16) & 0xff) / 4;
108821b547bSchristos else
109821b547bSchristos args = 10;
110821b547bSchristos }
111821b547bSchristos return (args);
112821b547bSchristos }
113821b547bSchristos
114821b547bSchristos /*
115821b547bSchristos * Figure out the next frame up in the call stack.
116821b547bSchristos * For trap(), we print the address of the faulting instruction and
117821b547bSchristos * proceed with the calling frame. We return the ip that faulted.
118821b547bSchristos * If the trap was caused by jumping through a bogus pointer, then
119821b547bSchristos * the next line in the backtrace will list some random function as
120821b547bSchristos * being called. It should get the argument list correct, though.
121821b547bSchristos * It might be possible to dig out from the next frame up the name
122821b547bSchristos * of the function that faulted, but that could get hairy.
123821b547bSchristos */
124821b547bSchristos int
db_nextframe(long ** nextframe,long ** retaddr,long ** arg0,db_addr_t * ip,long * argp,int is_trap,void (* pr)(const char *,...))125f54b4a9bSmaxv db_nextframe(long **nextframe, long **retaddr, long **arg0, db_addr_t *ip,
126f54b4a9bSmaxv long *argp, int is_trap, void (*pr)(const char *, ...))
127821b547bSchristos {
128821b547bSchristos static struct trapframe tf;
129821b547bSchristos static struct i386tss tss;
130821b547bSchristos struct i386_frame *fp;
131821b547bSchristos uintptr_t ptr;
132821b547bSchristos
133821b547bSchristos switch (is_trap) {
134821b547bSchristos case NONE:
135821b547bSchristos *ip = (db_addr_t)
136821b547bSchristos db_get_value((int)*retaddr, 4, false);
137821b547bSchristos fp = (struct i386_frame *)
138821b547bSchristos db_get_value((int)*nextframe, 4, false);
139821b547bSchristos if (fp == NULL)
140821b547bSchristos return 0;
141821b547bSchristos *nextframe = (long *)&fp->f_frame;
142821b547bSchristos *retaddr = (long *)&fp->f_retaddr;
143821b547bSchristos *arg0 = (long *)&fp->f_arg0;
144821b547bSchristos break;
145821b547bSchristos
146821b547bSchristos case TRAP_TSS:
147821b547bSchristos case INTERRUPT_TSS:
148821b547bSchristos ptr = db_get_value((int)argp, 4, false);
149821b547bSchristos db_read_bytes((db_addr_t)ptr, sizeof(tss), (char *)&tss);
150821b547bSchristos *ip = tss.__tss_eip;
151821b547bSchristos fp = (struct i386_frame *)tss.tss_ebp;
152821b547bSchristos if (fp == NULL)
153821b547bSchristos return 0;
154821b547bSchristos *nextframe = (long *)&fp->f_frame;
155821b547bSchristos *retaddr = (long *)&fp->f_retaddr;
156821b547bSchristos *arg0 = (long *)&fp->f_arg0;
157821b547bSchristos if (is_trap == INTERRUPT_TSS)
158821b547bSchristos (*pr)("--- interrupt via task gate ---\n");
159821b547bSchristos else
160821b547bSchristos (*pr)("--- trap via task gate ---\n");
161821b547bSchristos break;
162821b547bSchristos
163821b547bSchristos case TRAP:
164821b547bSchristos case SYSCALL:
165821b547bSchristos case INTERRUPT:
166afbdb61fSchristos case SOFTINTR:
167821b547bSchristos default:
168821b547bSchristos /* The only argument to trap() or syscall() is the trapframe. */
169821b547bSchristos switch (is_trap) {
170821b547bSchristos case TRAP:
1719ffd8532Syamt ptr = db_get_value((int)argp, 4, false);
1729ffd8532Syamt db_read_bytes((db_addr_t)ptr, sizeof(tf), (char *)&tf);
173821b547bSchristos (*pr)("--- trap (number %d) ---\n", tf.tf_trapno);
174821b547bSchristos break;
175821b547bSchristos case SYSCALL:
1769ffd8532Syamt ptr = db_get_value((int)argp, 4, false);
1779ffd8532Syamt db_read_bytes((db_addr_t)ptr, sizeof(tf), (char *)&tf);
178821b547bSchristos (*pr)("--- syscall (number %d) ---\n", tf.tf_eax);
179821b547bSchristos break;
180821b547bSchristos case INTERRUPT:
181821b547bSchristos (*pr)("--- interrupt ---\n");
182821b547bSchristos /*
1839ffd8532Syamt * see the "XXX -1 here is a hack" comment below.
184821b547bSchristos */
1859ffd8532Syamt db_read_bytes((db_addr_t)argp, sizeof(tf), (char *)&tf);
186821b547bSchristos break;
187afbdb61fSchristos case SOFTINTR:
188afbdb61fSchristos (*pr)("--- softint ---\n");
189afbdb61fSchristos tf.tf_eip = 0;
190afbdb61fSchristos tf.tf_ebp = 0;
191afbdb61fSchristos break;
192821b547bSchristos }
193821b547bSchristos *ip = (db_addr_t)tf.tf_eip;
194821b547bSchristos fp = (struct i386_frame *)tf.tf_ebp;
195821b547bSchristos if (fp == NULL)
196821b547bSchristos return 0;
197821b547bSchristos *nextframe = (long *)&fp->f_frame;
198821b547bSchristos *retaddr = (long *)&fp->f_retaddr;
199821b547bSchristos *arg0 = (long *)&fp->f_arg0;
200821b547bSchristos break;
201821b547bSchristos }
202821b547bSchristos
203821b547bSchristos /*
204821b547bSchristos * A bit of a hack. Since %ebp may be used in the stub code,
205821b547bSchristos * walk the stack looking for a valid interrupt frame. Such
206821b547bSchristos * a frame can be recognized by always having
207821b547bSchristos * err 0 or IREENT_MAGIC and trapno T_ASTFLT.
208821b547bSchristos */
209*deefc290Suwe int traptype = NONE;
210*deefc290Suwe db_sym_t sym = db_frame_info(*nextframe, (db_addr_t)*ip,
211*deefc290Suwe NULL, NULL, &traptype, NULL);
212*deefc290Suwe if (sym != DB_SYM_NULL && traptype == INTERRUPT) {
2139ffd8532Syamt struct intrframe *ifp;
2149ffd8532Syamt int trapno;
2159ffd8532Syamt int err;
2169ffd8532Syamt
2179ffd8532Syamt /*
2189ffd8532Syamt * 2nd argument of interrupt handlers is a pointer to intrframe.
2199ffd8532Syamt */
2209ffd8532Syamt ifp = (struct intrframe *)
2219ffd8532Syamt db_get_value((db_addr_t)(argp + 1), sizeof(ifp), false);
2229ffd8532Syamt /*
2239ffd8532Syamt * check if it's a valid intrframe.
2249ffd8532Syamt */
2259ffd8532Syamt err = db_get_value((db_addr_t)&ifp->__if_err,
2269ffd8532Syamt sizeof(ifp->__if_err), false);
2279ffd8532Syamt trapno = db_get_value((db_addr_t)&ifp->__if_trapno,
2289ffd8532Syamt sizeof(ifp->__if_trapno), false);
229821b547bSchristos if ((err == 0 || err == IREENT_MAGIC) && trapno == T_ASTFLT) {
2309ffd8532Syamt /*
2319ffd8532Syamt * found seemingly valid intrframe.
2329ffd8532Syamt *
2339ffd8532Syamt * XXX -1 here is a hack.
2349ffd8532Syamt * for the next frame, we will be called with
2359ffd8532Syamt * argp = *nextframe + 2. (long *)if - 1 + 2 = &tf.
2369ffd8532Syamt */
237821b547bSchristos *nextframe = (long *)ifp - 1;
2389ffd8532Syamt } else {
239821b547bSchristos (*pr)("DDB lost frame for ");
240821b547bSchristos db_printsym(*ip, DB_STGY_ANY, pr);
241821b547bSchristos (*pr)(", trying %p\n",argp);
242821b547bSchristos *nextframe = argp;
243821b547bSchristos }
244821b547bSchristos }
245821b547bSchristos return 1;
246821b547bSchristos }
247821b547bSchristos
248f54b4a9bSmaxv db_sym_t
db_frame_info(long * frame,db_addr_t callpc,const char ** namep,db_expr_t * offp,int * is_trap,int * nargp)249f54b4a9bSmaxv db_frame_info(long *frame, db_addr_t callpc, const char **namep,
250f54b4a9bSmaxv db_expr_t *offp, int *is_trap, int *nargp)
251f54b4a9bSmaxv {
252f54b4a9bSmaxv db_expr_t offset;
253f54b4a9bSmaxv db_sym_t sym;
254f54b4a9bSmaxv int narg;
255f54b4a9bSmaxv const char *name;
256f54b4a9bSmaxv
257f54b4a9bSmaxv sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
2589f580511Suwe if (sym != DB_SYM_NULL && offset == 0) {
2590c672fb9Schs sym = db_search_symbol(callpc - 1, DB_STGY_ANY, &offset);
2600c672fb9Schs offset++;
2610c672fb9Schs }
262f54b4a9bSmaxv db_symbol_values(sym, &name, NULL);
2639f580511Suwe if (sym == DB_SYM_NULL)
2649f580511Suwe return DB_SYM_NULL;
265f54b4a9bSmaxv
266f54b4a9bSmaxv *is_trap = NONE;
267f54b4a9bSmaxv narg = MAXNARG;
268f54b4a9bSmaxv
269f54b4a9bSmaxv if (INKERNEL((int)frame) && name) {
270f54b4a9bSmaxv /*
271f54b4a9bSmaxv * XXX traps should be based off of the Xtrap*
272f54b4a9bSmaxv * locations rather than on trap, since some traps
273f54b4a9bSmaxv * (e.g., npxdna) don't go through trap()
274f54b4a9bSmaxv */
275f54b4a9bSmaxv if (!strcmp(name, "trap_tss")) {
276f54b4a9bSmaxv *is_trap = TRAP_TSS;
277f54b4a9bSmaxv narg = 0;
278f54b4a9bSmaxv } else if (!strcmp(name, "trap")) {
279f54b4a9bSmaxv *is_trap = TRAP;
280f54b4a9bSmaxv narg = 0;
281f54b4a9bSmaxv } else if (!strcmp(name, "syscall")) {
282f54b4a9bSmaxv *is_trap = SYSCALL;
283f54b4a9bSmaxv narg = 0;
284f54b4a9bSmaxv } else if (name[0] == 'X') {
285f54b4a9bSmaxv if (!strncmp(name, "Xintr", 5) ||
286f54b4a9bSmaxv !strncmp(name, "Xresume", 7) ||
287f54b4a9bSmaxv !strncmp(name, "Xstray", 6) ||
288f54b4a9bSmaxv !strncmp(name, "Xhold", 5) ||
289f54b4a9bSmaxv !strncmp(name, "Xrecurse", 8) ||
290f54b4a9bSmaxv !strcmp(name, "Xdoreti")) {
291f54b4a9bSmaxv *is_trap = INTERRUPT;
292f54b4a9bSmaxv narg = 0;
293f54b4a9bSmaxv } else if (!strcmp(name, "Xsoftintr")) {
294f54b4a9bSmaxv *is_trap = SOFTINTR;
295f54b4a9bSmaxv narg = 0;
296f54b4a9bSmaxv } else if (!strncmp(name, "Xtss_", 5)) {
297f54b4a9bSmaxv *is_trap = INTERRUPT_TSS;
298f54b4a9bSmaxv narg = 0;
299f54b4a9bSmaxv }
300f54b4a9bSmaxv }
301f54b4a9bSmaxv }
302f54b4a9bSmaxv
303f54b4a9bSmaxv if (offp != NULL)
304f54b4a9bSmaxv *offp = offset;
305f54b4a9bSmaxv if (nargp != NULL)
306f54b4a9bSmaxv *nargp = narg;
307f54b4a9bSmaxv if (namep != NULL)
308f54b4a9bSmaxv *namep = name;
309f54b4a9bSmaxv return sym;
310f54b4a9bSmaxv }
311f54b4a9bSmaxv
312821b547bSchristos bool
db_intrstack_p(const void * vp)313821b547bSchristos db_intrstack_p(const void *vp)
314821b547bSchristos {
315821b547bSchristos struct cpu_info *ci;
316821b547bSchristos const char *cp;
317821b547bSchristos
318821b547bSchristos for (ci = db_cpu_first(); ci != NULL; ci = db_cpu_next(ci)) {
319821b547bSchristos db_read_bytes((db_addr_t)&ci->ci_intrstack, sizeof(cp),
320821b547bSchristos (char *)&cp);
321821b547bSchristos if (cp == NULL) {
322821b547bSchristos continue;
323821b547bSchristos }
324821b547bSchristos if ((cp - INTRSTACKSIZE + 4) <= (const char *)vp &&
325821b547bSchristos (const char *)vp <= cp) {
326821b547bSchristos return true;
327821b547bSchristos }
328821b547bSchristos }
329821b547bSchristos return false;
330821b547bSchristos }
331