1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 *
26 * $FreeBSD: releng/5.1/sys/amd64/amd64/db_interface.c 115403 2003-05-30 01:01:07Z peter $
27 */
28
29 /*
30 * Interface to new debugger.
31 */
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/reboot.h>
35 #include <sys/cons.h>
36 #include <sys/pcpu.h>
37 #include <sys/proc.h>
38 #include <sys/smp.h>
39
40 #include <machine/cpu.h>
41
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44
45 #include <ddb/ddb.h>
46
47 #include <machine/setjmp.h>
48
49 static jmp_buf *db_nofault = 0;
50 extern jmp_buf db_jmpbuf;
51
52 extern void gdb_handle_exception(db_regs_t *, int, int);
53
54 int db_active;
55 db_regs_t ddb_regs;
56
57 static jmp_buf db_global_jmpbuf;
58
59 static __inline u_short
60 rss(void)
61 {
62 u_short ss;
63 #ifdef __GNUC__
64 __asm __volatile("mov %%ss,%0" : "=r" (ss));
65 #else
66 ss = 0; /* XXXX Fix for other compilers. */
67 #endif
68 return ss;
69 }
70
71 /*
72 * kdb_trap - field a TRACE or BPT trap
73 */
74 int
75 kdb_trap(int type, int code, struct amd64_saved_state *regs)
76 {
77 u_long ef;
78 volatile int ddb_mode = !(boothowto & RB_GDB);
79
80 /*
81 * XXX try to do nothing if the console is in graphics mode.
82 * Handle trace traps (and hardware breakpoints...) by ignoring
83 * them except for forgetting about them. Return 0 for other
84 * traps to say that we haven't done anything. The trap handler
85 * will usually panic. We should handle breakpoint traps for
86 * our breakpoints by disarming our breakpoints and fixing up
87 * %eip.
88 */
89 if (cons_unavail && ddb_mode) {
90 if (type == T_TRCTRAP) {
91 regs->tf_rflags &= ~PSL_T;
92 return (1);
93 }
94 return (0);
95 }
96
97 ef = read_rflags();
98 disable_intr();
99
100 switch (type) {
101 case T_BPTFLT: /* breakpoint */
102 case T_TRCTRAP: /* debug exception */
103 break;
104
105 default:
106 /*
107 * XXX this is almost useless now. In most cases,
108 * trap_fatal() has already printed a much more verbose
109 * message. However, it is dangerous to print things in
110 * trap_fatal() - printf() might be reentered and trap.
111 * The debugger should be given control first.
112 */
113 if (ddb_mode)
114 db_printf("kernel: type %d trap, code=%x\n", type, code);
115
116 if (db_nofault) {
117 jmp_buf *no_fault = db_nofault;
118 db_nofault = 0;
119 longjmp(*no_fault, 1);
120 }
121 }
122
123 /*
124 * This handles unexpected traps in ddb commands, including calls to
125 * non-ddb functions. db_nofault only applies to memory accesses by
126 * internal ddb commands.
127 */
128 if (db_active)
129 longjmp(db_global_jmpbuf, 1);
130
131 /*
132 * XXX We really should switch to a local stack here.
133 */
134 ddb_regs = *regs;
135
136 /*
137 * If in kernel mode, esp and ss are not saved, so dummy them up.
138 */
139 if (ISPL(regs->tf_cs) == 0) {
140 ddb_regs.tf_rsp = (long)®s->tf_rsp;
141 ddb_regs.tf_ss = rss();
142 }
143
144 (void) setjmp(db_global_jmpbuf);
145 if (ddb_mode) {
146 if (!db_active)
147 cndbctl(TRUE);
148 db_active = 1;
149 db_trap(type, code);
150 cndbctl(FALSE);
151 } else {
152 db_active = 1;
153 gdb_handle_exception(&ddb_regs, type, code);
154 }
155 db_active = 0;
156
157 regs->tf_rip = ddb_regs.tf_rip;
158 regs->tf_rflags = ddb_regs.tf_rflags;
159 regs->tf_rax = ddb_regs.tf_rax;
160 regs->tf_rcx = ddb_regs.tf_rcx;
161 regs->tf_rdx = ddb_regs.tf_rdx;
162 regs->tf_rbx = ddb_regs.tf_rbx;
163
164 /*
165 * If in user mode, the saved ESP and SS were valid, restore them.
166 */
167 if (ISPL(regs->tf_cs)) {
168 regs->tf_rsp = ddb_regs.tf_rsp;
169 regs->tf_ss = ddb_regs.tf_ss & 0xffff;
170 }
171
172 regs->tf_rbp = ddb_regs.tf_rbp;
173 regs->tf_rsi = ddb_regs.tf_rsi;
174 regs->tf_rdi = ddb_regs.tf_rdi;
175
176 regs->tf_r8 = ddb_regs.tf_r8;
177 regs->tf_r9 = ddb_regs.tf_r9;
178 regs->tf_r10 = ddb_regs.tf_r10;
179 regs->tf_r11 = ddb_regs.tf_r11;
180 regs->tf_r12 = ddb_regs.tf_r12;
181 regs->tf_r13 = ddb_regs.tf_r13;
182 regs->tf_r14 = ddb_regs.tf_r14;
183 regs->tf_r15 = ddb_regs.tf_r15;
184
185 #if 0
186 regs->tf_es = ddb_regs.tf_es & 0xffff;
187 regs->tf_fs = ddb_regs.tf_fs & 0xffff;
188 #endif
189 regs->tf_cs = ddb_regs.tf_cs & 0xffff;
190 #if 0
191 regs->tf_ds = ddb_regs.tf_ds & 0xffff;
192 #endif
193
194 write_rflags(ef);
195
196 return (1);
197 }
198
199 /*
200 * Read bytes from kernel address space for debugger.
201 */
202 void
203 db_read_bytes(vm_offset_t addr, size_t size, char *data)
204 {
205 char *src;
206
207 db_nofault = &db_jmpbuf;
208
209 src = (char *)addr;
210 while (size-- > 0)
211 *data++ = *src++;
212
213 db_nofault = 0;
214 }
215
216 /*
217 * Write bytes to kernel address space for debugger.
218 */
219 void
220 db_write_bytes(vm_offset_t addr, size_t size, char *data)
221 {
222 char *dst;
223
224 pt_entry_t *ptep0 = NULL;
225 pt_entry_t oldmap0 = 0;
226 vm_offset_t addr1;
227 pt_entry_t *ptep1 = NULL;
228 pt_entry_t oldmap1 = 0;
229
230 db_nofault = &db_jmpbuf;
231
232 if (addr > trunc_page((vm_offset_t)btext) - size &&
233 addr < round_page((vm_offset_t)etext)) {
234
235 ptep0 = vtopte(addr);
236 oldmap0 = *ptep0;
237 *ptep0 |= PG_RW;
238
239 /* Map another page if the data crosses a page boundary. */
240 if ((*ptep0 & PG_PS) == 0) {
241 addr1 = trunc_page(addr + size - 1);
242 if (trunc_page(addr) != addr1) {
243 ptep1 = vtopte(addr1);
244 oldmap1 = *ptep1;
245 *ptep1 |= PG_RW;
246 }
247 } else {
248 addr1 = trunc_2mpage(addr + size - 1);
249 if (trunc_2mpage(addr) != addr1) {
250 ptep1 = vtopte(addr1);
251 oldmap1 = *ptep1;
252 *ptep1 |= PG_RW;
253 }
254 }
255
256 invltlb();
257 }
258
259 dst = (char *)addr;
260
261 while (size-- > 0)
262 *dst++ = *data++;
263
264 db_nofault = 0;
265
266 if (ptep0) {
267 *ptep0 = oldmap0;
268
269 if (ptep1)
270 *ptep1 = oldmap1;
271
272 invltlb();
273 }
274 }
275
276 /*
277 * XXX
278 * Move this to machdep.c and allow it to be called if any debugger is
279 * installed.
280 */
281 void
282 Debugger(const char *msg)
283 {
284 static volatile u_int in_Debugger;
285
286 /*
287 * XXX
288 * Do nothing if the console is in graphics mode. This is
289 * OK if the call is for the debugger hotkey but not if the call
290 * is a weak form of panicing.
291 */
292 if (cons_unavail && !(boothowto & RB_GDB))
293 return;
294
295 if (atomic_cmpset_acq_int(&in_Debugger, 0, 1)) {
296 db_printf("Debugger(\"%s\")\n", msg);
297 breakpoint();
298 atomic_store_rel_int(&in_Debugger, 0);
299 }
300 }
301
302 void
303 db_show_mdpcpu(struct pcpu *pc)
304 {
305
306 #if 0
307 db_printf("currentldt = 0x%x\n", pc->pc_currentldt);
308 #endif
309 }
Cache object: cdcbd8eab41ca0e38662becfe1d02631
|