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 | */ |
55 | const 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 | }; |
81 | const 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 | */ |
90 | int |
91 | db_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 | */ |
106 | int |
107 | db_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 | |
190 | db_sym_t |
191 | db_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 | |