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