Document the use of SDT_SYS386IGT vs SDT_SYS386TGT when setting up the
[dragonfly.git] / sys / i386 / i386 / db_interface.c
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: src/sys/i386/i386/db_interface.c,v 1.48.2.1 2000/07/07 00:38:46 obrien Exp $
27  * $DragonFly: src/sys/i386/i386/Attic/db_interface.c,v 1.12 2005/12/24 20:34:04 swildner Exp $
28  */
29
30 /*
31  * Interface to new debugger.
32  */
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/reboot.h>
36 #include <sys/cons.h>
37
38 #include <machine/cpu.h>
39 #include <machine/smp.h>
40 #include <machine/globaldata.h>
41
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44
45 #include <ddb/ddb.h>
46
47 #include <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 static int      db_global_jmpbuf_valid;
59
60 #ifdef __GNUC__
61 #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
62 #endif
63
64 /*
65  *  kdb_trap - field a TRACE or BPT trap
66  */
67 int
68 kdb_trap(type, code, regs)
69         int     type, code;
70         struct i386_saved_state *regs;
71 {
72         volatile int ddb_mode = !(boothowto & RB_GDB);
73
74         /*
75          * XXX try to do nothing if the console is in graphics mode.
76          * Handle trace traps (and hardware breakpoints...) by ignoring
77          * them except for forgetting about them.  Return 0 for other
78          * traps to say that we haven't done anything.  The trap handler
79          * will usually panic.  We should handle breakpoint traps for
80          * our breakpoints by disarming our breakpoints and fixing up
81          * %eip.
82          */
83         if (cons_unavail && ddb_mode) {
84             if (type == T_TRCTRAP) {
85                 regs->tf_eflags &= ~PSL_T;
86                 return (1);
87             }
88             return (0);
89         }
90
91         switch (type) {
92             case T_BPTFLT:      /* breakpoint */
93             case T_TRCTRAP:     /* debug exception */
94                 break;
95
96             default:
97                 /*
98                  * XXX this is almost useless now.  In most cases,
99                  * trap_fatal() has already printed a much more verbose
100                  * message.  However, it is dangerous to print things in
101                  * trap_fatal() - printf() might be reentered and trap.
102                  * The debugger should be given control first.
103                  */
104                 if (ddb_mode)
105                     db_printf("kernel: type %d trap, code=%x\n", type, code);
106
107                 if (db_nofault) {
108                     jmp_buf *no_fault = db_nofault;
109                     db_nofault = 0;
110                     longjmp(*no_fault, 1);
111                 }
112         }
113
114         /*
115          * This handles unexpected traps in ddb commands, including calls to
116          * non-ddb functions.  db_nofault only applies to memory accesses by
117          * internal ddb commands.
118          */
119         if (db_global_jmpbuf_valid)
120             longjmp(db_global_jmpbuf, 1);
121
122         /*
123          * XXX We really should switch to a local stack here.
124          */
125         ddb_regs = *regs;
126
127         /*
128          * If in kernel mode, esp and ss are not saved, so dummy them up.
129          */
130         if (ISPL(regs->tf_cs) == 0) {
131             ddb_regs.tf_esp = (int)&regs->tf_esp;
132             ddb_regs.tf_ss = rss();
133         }
134
135 #ifdef SMP
136         db_printf("\nCPU%d stopping CPUs: 0x%08x\n", 
137             mycpu->gd_cpuid, mycpu->gd_other_cpus);
138
139         /* We stop all CPUs except ourselves (obviously) */
140         stop_cpus(mycpu->gd_other_cpus);
141
142         db_printf(" stopped\n");
143 #endif /* SMP */
144
145         setjmp(db_global_jmpbuf);
146         db_global_jmpbuf_valid = TRUE;
147         db_active++;
148         if (ddb_mode) {
149             cndbctl(TRUE);
150             db_trap(type, code);
151             cndbctl(FALSE);
152         } else
153             gdb_handle_exception(&ddb_regs, type, code);
154         db_active--;
155         db_global_jmpbuf_valid = FALSE;
156
157 #ifdef SMP
158         db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
159             mycpu->gd_cpuid, stopped_cpus);
160
161         /* Restart all the CPUs we previously stopped */
162         if (stopped_cpus != mycpu->gd_other_cpus) {
163                 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
164                           mycpu->gd_other_cpus, stopped_cpus);
165                 panic("stop_cpus() failed");
166         }
167         restart_cpus(stopped_cpus);
168
169         db_printf(" restarted\n");
170 #endif /* SMP */
171
172         regs->tf_eip    = ddb_regs.tf_eip;
173         regs->tf_eflags = ddb_regs.tf_eflags;
174         regs->tf_eax    = ddb_regs.tf_eax;
175         regs->tf_ecx    = ddb_regs.tf_ecx;
176         regs->tf_edx    = ddb_regs.tf_edx;
177         regs->tf_ebx    = ddb_regs.tf_ebx;
178
179         /*
180          * If in user mode, the saved ESP and SS were valid, restore them.
181          */
182         if (ISPL(regs->tf_cs)) {
183             regs->tf_esp = ddb_regs.tf_esp;
184             regs->tf_ss  = ddb_regs.tf_ss & 0xffff;
185         }
186
187         regs->tf_ebp    = ddb_regs.tf_ebp;
188         regs->tf_esi    = ddb_regs.tf_esi;
189         regs->tf_edi    = ddb_regs.tf_edi;
190         regs->tf_es     = ddb_regs.tf_es & 0xffff;
191         regs->tf_fs     = ddb_regs.tf_fs & 0xffff;
192         regs->tf_cs     = ddb_regs.tf_cs & 0xffff;
193         regs->tf_ds     = ddb_regs.tf_ds & 0xffff;
194         return (1);
195 }
196
197 /*
198  * Read bytes from kernel address space for debugger.
199  */
200 void
201 db_read_bytes(addr, size, data)
202         vm_offset_t     addr;
203         size_t  size;
204         char    *data;
205 {
206         char    *src;
207
208         db_nofault = &db_jmpbuf;
209
210         src = (char *)addr;
211         while (size-- > 0)
212             *data++ = *src++;
213
214         db_nofault = 0;
215 }
216
217 /*
218  * Write bytes to kernel address space for debugger.
219  */
220 void
221 db_write_bytes(addr, size, data)
222         vm_offset_t     addr;
223         size_t  size;
224         char    *data;
225 {
226         char    *dst;
227
228         unsigned        *ptep0 = NULL;
229         unsigned        oldmap0 = 0;
230         vm_offset_t     addr1;
231         unsigned        *ptep1 = NULL;
232         unsigned        oldmap1 = 0;
233
234         db_nofault = &db_jmpbuf;
235
236         if (addr > trunc_page((vm_offset_t)btext) - size &&
237             addr < round_page((vm_offset_t)etext)) {
238
239             ptep0 = pmap_pte(kernel_pmap, addr);
240             oldmap0 = *ptep0;
241             *ptep0 |= PG_RW;
242
243             /* Map another page if the data crosses a page boundary. */
244             if ((*ptep0 & PG_PS) == 0) {
245                 addr1 = trunc_page(addr + size - 1);
246                 if (trunc_page(addr) != addr1) {
247                     ptep1 = pmap_pte(kernel_pmap, addr1);
248                     oldmap1 = *ptep1;
249                     *ptep1 |= PG_RW;
250                 }
251             } else {
252                 addr1 = trunc_4mpage(addr + size - 1);
253                 if (trunc_4mpage(addr) != addr1) {
254                     ptep1 = pmap_pte(kernel_pmap, addr1);
255                     oldmap1 = *ptep1;
256                     *ptep1 |= PG_RW;
257                 }
258             }
259
260             cpu_invltlb();
261         }
262
263         dst = (char *)addr;
264
265         while (size-- > 0)
266             *dst++ = *data++;
267
268         db_nofault = 0;
269
270         if (ptep0) {
271             *ptep0 = oldmap0;
272
273             if (ptep1)
274                 *ptep1 = oldmap1;
275
276             cpu_invltlb();
277         }
278 }
279
280 /*
281  * The debugger sometimes needs to know the actual KVM address represented
282  * by the instruction pointer, stack pointer, or base pointer.  Normally
283  * the actual KVM address is simply the contents of the register.  However,
284  * if the debugger is entered from the BIOS or VM86 we need to figure out
285  * the offset from the segment register.
286  */
287 db_addr_t
288 PC_REGS(db_regs_t *regs)
289 {
290     struct soft_segment_descriptor softseg;
291
292     sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_cs & 0xffff)].sd, &softseg);
293     return(regs->tf_eip + softseg.ssd_base);
294 }
295
296 db_addr_t
297 SP_REGS(db_regs_t *regs)
298 {
299     struct soft_segment_descriptor softseg;
300
301     sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_ss & 0xffff)].sd, &softseg);
302     return(regs->tf_esp + softseg.ssd_base);
303 }
304
305 db_addr_t
306 BP_REGS(db_regs_t *regs)
307 {
308     struct soft_segment_descriptor softseg;
309
310     sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_ds & 0xffff)].sd, &softseg);
311     return(regs->tf_ebp + softseg.ssd_base);
312 }
313
314 /*
315  * XXX
316  * Move this to machdep.c and allow it to be called if any debugger is
317  * installed.
318  */
319 void
320 Debugger(msg)
321         const char *msg;
322 {
323         static volatile u_char in_Debugger;
324
325         /*
326          * XXX
327          * Do nothing if the console is in graphics mode.  This is
328          * OK if the call is for the debugger hotkey but not if the call
329          * is a weak form of panicing.
330          */
331         if (cons_unavail && !(boothowto & RB_GDB))
332             return;
333
334         if (!in_Debugger) {
335             in_Debugger = 1;
336             db_printf("Debugger(\"%s\")\n", msg);
337             breakpoint();
338             in_Debugger = 0;
339         }
340 }