1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,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 "AS IS"
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 Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_interface.c,v $
29 * Revision 2.13 93/11/17 16:35:19 dbg
30 * ANSI-fied.
31 * [93/11/03 dbg]
32 *
33 * Added option of faulting in pages in db_user_to_kernel_address(),
34 * controlled by the global variable db_no_vm_fault, same as mips/alpha.
35 * [93/09/25 af]
36 *
37 * Revision 2.12 93/05/15 19:13:52 mrt
38 * machparam.h -> machspl.h
39 *
40 * Revision 2.11 93/01/14 17:28:37 danner
41 * Pick up multiprocessor DDB changes from Grenoble.
42 * [92/10/23 dbg]
43 *
44 * Revision 2.10 92/02/19 16:29:17 elf
45 * MD debugger support.
46 * [92/02/07 rvb]
47 *
48 * Revision 2.9 92/01/03 20:05:13 dbg
49 * Always enter debugger - ignore RB_KDB.
50 * [91/10/30 dbg]
51 *
52 * Revision 2.8 91/10/09 16:06:14 af
53 * Added user space access and check routines.
54 * Added U*X task information print routines.
55 * Changed db_trap to db_task_trap.
56 * [91/08/29 tak]
57 *
58 * Revision 2.7 91/07/31 17:35:23 dbg
59 * Registers are in different locations on keyboard interrupt.
60 * [91/07/30 16:48:52 dbg]
61 *
62 * Revision 2.6 91/05/14 16:05:37 mrt
63 * Correcting copyright
64 *
65 * Revision 2.5 91/03/16 14:44:00 rpd
66 * Fixed kdb_trap to skip over permanent breakpoints.
67 * [91/03/15 rpd]
68 *
69 * Changed kdb_trap to use db_recover.
70 * [91/01/14 rpd]
71 *
72 * Fixed kdb_trap to disable interrupts.
73 * [91/01/12 rpd]
74 *
75 * Revision 2.4 91/02/05 17:11:13 mrt
76 * Changed to new Mach copyright
77 * [91/02/01 17:31:17 mrt]
78 *
79 * Revision 2.3 90/12/04 14:45:55 jsb
80 * Changes for merged intel/pmap.{c,h}.
81 * [90/12/04 11:14:41 jsb]
82 *
83 * Revision 2.2 90/10/25 14:44:43 rwd
84 * Added watchpoint support.
85 * [90/10/18 rpd]
86 *
87 * Created.
88 * [90/07/25 dbg]
89 *
90 */
91
92 /*
93 * Interface to new debugger.
94 */
95
96 #include <cpus.h>
97
98 #include <sys/reboot.h>
99
100 #include <mach/vm_param.h>
101
102 #include <kern/cpu_number.h>
103 #include <kern/kern_io.h>
104 #include <kern/task.h>
105 #include <kern/thread.h>
106
107 #include <vm/pmap.h>
108 #include <vm/vm_fault.h>
109 #include <vm/vm_map.h>
110
111 #include <ddb/db_access.h>
112 #include <ddb/db_command.h> /* db_error */
113 #include <ddb/db_output.h>
114 #include <ddb/db_task_thread.h>
115
116 #include <i386/db_machdep.h>
117 #include <i386/machspl.h>
118 #include <i386/pmap.h>
119 #include <i386/seg.h>
120 #include <i386/setjmp.h>
121 #include <i386/thread.h>
122 #include <i386/trap.h>
123
124
125 struct i386_saved_state *i386_last_saved_statep;
126 struct i386_saved_state i386_nested_saved_state;
127 unsigned i386_last_kdb_sp;
128
129 extern thread_t db_default_thread;
130
131 extern char * trap_type[];
132 extern int TRAP_TYPES;
133
134 /*
135 * Print trap reason.
136 */
137 void kdbprinttrap(
138 int type,
139 int code)
140 {
141 db_printf("kernel: ");
142 if (type > TRAP_TYPES)
143 db_printf("type %d", type);
144 else
145 db_printf("%s", trap_type[type]);
146 db_printf(" trap, code=%x\n", code);
147 }
148
149 /*
150 * kdb_trap - field a TRACE or BPT trap
151 */
152
153 extern jmp_buf_t *db_recover;
154 spl_t saved_ipl[NCPUS]; /* just to know what was IPL before trap */
155
156 boolean_t
157 kdb_trap(
158 int type,
159 int code,
160 register struct i386_saved_state *regs)
161 {
162 spl_t s;
163
164 s = splhigh();
165 saved_ipl[cpu_number()] = s;
166
167 switch (type) {
168 case T_DEBUG: /* single_step */
169 {
170 extern int dr_addr[];
171 int addr;
172 int status = dr6();
173
174 if (status & 0xf) { /* hmm hdw break */
175 addr = status & 0x8 ? dr_addr[3] :
176 status & 0x4 ? dr_addr[2] :
177 status & 0x2 ? dr_addr[1] :
178 dr_addr[0];
179 regs->efl |= EFL_RF;
180 db_single_step_cmd(addr, 0, 1, "p");
181 }
182 }
183 case T_INT3: /* breakpoint */
184 case T_WATCHPOINT: /* watchpoint */
185 case -1: /* keyboard interrupt */
186 break;
187
188 default:
189 if (db_recover) {
190 i386_nested_saved_state = *regs;
191 db_printf("Caught ");
192 if (type > TRAP_TYPES)
193 db_printf("type %d", type);
194 else
195 db_printf("%s", trap_type[type]);
196 db_printf(" trap, code = %x, pc = %x\n",
197 code, regs->eip);
198 db_error("");
199 /*NOTREACHED*/
200 }
201 kdbprinttrap(type, code);
202 }
203
204 #if NCPUS > 1
205 if (db_enter())
206 #endif /* NCPUS > 1 */
207 {
208 i386_last_saved_statep = regs;
209 i386_last_kdb_sp = (unsigned) &type;
210
211 /* XXX Should switch to ddb`s own stack here. */
212
213 ddb_regs = *regs;
214 if ((regs->cs & 0x3) == 0) {
215 /*
216 * Kernel mode - esp and ss not saved
217 */
218 ddb_regs.uesp = (int)®s->uesp; /* kernel stack pointer */
219 ddb_regs.ss = KERNEL_DS;
220 }
221
222 cnpollc(TRUE);
223 db_task_trap(type, code, (regs->cs & 0x3) != 0);
224 cnpollc(FALSE);
225
226 regs->eip = ddb_regs.eip;
227 regs->efl = ddb_regs.efl;
228 regs->eax = ddb_regs.eax;
229 regs->ecx = ddb_regs.ecx;
230 regs->edx = ddb_regs.edx;
231 regs->ebx = ddb_regs.ebx;
232 if (regs->cs & 0x3) {
233 /*
234 * user mode - saved esp and ss valid
235 */
236 regs->uesp = ddb_regs.uesp; /* user stack pointer */
237 regs->ss = ddb_regs.ss & 0xffff; /* user stack segment */
238 }
239 regs->ebp = ddb_regs.ebp;
240 regs->esi = ddb_regs.esi;
241 regs->edi = ddb_regs.edi;
242 regs->es = ddb_regs.es & 0xffff;
243 regs->cs = ddb_regs.cs & 0xffff;
244 regs->ds = ddb_regs.ds & 0xffff;
245 regs->fs = ddb_regs.fs & 0xffff;
246 regs->gs = ddb_regs.gs & 0xffff;
247
248 if ((type == T_INT3) &&
249 (db_get_task_value(regs->eip, BKPT_SIZE, FALSE, TASK_NULL)
250 == BKPT_INST))
251 regs->eip += BKPT_SIZE;
252 }
253 #if NCPUS > 1
254 db_leave();
255 #endif /* NCPUS > 1 */
256
257 splx(s);
258 return 1;
259 }
260
261 /*
262 * Enter KDB through a keyboard trap.
263 * We show the registers as of the keyboard interrupt
264 * instead of those at its call to KDB.
265 */
266 struct int_regs {
267 int gs;
268 int fs;
269 int edi;
270 int esi;
271 int ebp;
272 int ebx;
273 struct i386_interrupt_state *is;
274 };
275
276 void
277 kdb_kentry(
278 struct int_regs *int_regs)
279 {
280 struct i386_interrupt_state *is = int_regs->is;
281 spl_t s = splhigh();
282
283 #if NCPUS > 1
284 if (db_enter())
285 #endif /* NCPUS > 1 */
286 {
287 if (is->cs & 0x3) {
288 ddb_regs.uesp = ((int *)(is+1))[0];
289 ddb_regs.ss = ((int *)(is+1))[1];
290 }
291 else {
292 ddb_regs.ss = KERNEL_DS;
293 ddb_regs.uesp= (int)(is+1);
294 }
295 ddb_regs.efl = is->efl;
296 ddb_regs.cs = is->cs;
297 ddb_regs.eip = is->eip;
298 ddb_regs.eax = is->eax;
299 ddb_regs.ecx = is->ecx;
300 ddb_regs.edx = is->edx;
301 ddb_regs.ebx = int_regs->ebx;
302 ddb_regs.ebp = int_regs->ebp;
303 ddb_regs.esi = int_regs->esi;
304 ddb_regs.edi = int_regs->edi;
305 ddb_regs.ds = is->ds;
306 ddb_regs.es = is->es;
307 ddb_regs.fs = int_regs->fs;
308 ddb_regs.gs = int_regs->gs;
309
310 cnpollc(TRUE);
311 db_task_trap(-1, 0, (ddb_regs.cs & 0x3) != 0);
312 cnpollc(FALSE);
313
314 if (ddb_regs.cs & 0x3) {
315 ((int *)(is+1))[0] = ddb_regs.uesp;
316 ((int *)(is+1))[1] = ddb_regs.ss & 0xffff;
317 }
318 is->efl = ddb_regs.efl;
319 is->cs = ddb_regs.cs & 0xffff;
320 is->eip = ddb_regs.eip;
321 is->eax = ddb_regs.eax;
322 is->ecx = ddb_regs.ecx;
323 is->edx = ddb_regs.edx;
324 int_regs->ebx = ddb_regs.ebx;
325 int_regs->ebp = ddb_regs.ebp;
326 int_regs->esi = ddb_regs.esi;
327 int_regs->edi = ddb_regs.edi;
328 is->ds = ddb_regs.ds & 0xffff;
329 is->es = ddb_regs.es & 0xffff;
330 int_regs->fs = ddb_regs.fs & 0xffff;
331 int_regs->gs = ddb_regs.gs & 0xffff;
332 }
333 #if NCPUS > 1
334 db_leave();
335 #endif /* NCPUS > 1 */
336
337 splx(s);
338 }
339
340 boolean_t db_no_vm_fault = TRUE;
341
342 int
343 db_user_to_kernel_address(
344 task_t task,
345 vm_offset_t addr,
346 unsigned *kaddr,
347 int flag)
348 {
349 register pt_entry_t *ptp;
350 boolean_t faulted = FALSE;
351
352 retry:
353 ptp = pmap_pte(task->map->pmap, addr);
354 if (ptp == PT_ENTRY_NULL || (*ptp & INTEL_PTE_VALID) == 0) {
355 if (!faulted && !db_no_vm_fault) {
356 kern_return_t err;
357
358 faulted = TRUE;
359 err = vm_fault( task->map,
360 trunc_page(addr),
361 VM_PROT_READ,
362 FALSE, FALSE, 0);
363 if (err == KERN_SUCCESS)
364 goto retry;
365 }
366 if (flag) {
367 db_printf("\nno memory is assigned to address %08x\n", addr);
368 db_error(0);
369 /* NOTREACHED */
370 }
371 return -1;
372 }
373 *kaddr = (unsigned)ptetokv(*ptp) + (addr & (INTEL_PGBYTES-1));
374 return 0;
375 }
376
377 /*
378 * Read bytes from kernel address space for debugger.
379 */
380
381 void
382 db_read_bytes(
383 vm_offset_t addr,
384 register int size,
385 register char *data,
386 task_t task)
387 {
388 register char *src;
389 register int n;
390 unsigned kern_addr;
391
392 src = (char *)addr;
393 if (addr >= VM_MIN_KERNEL_ADDRESS || task == TASK_NULL) {
394 if (task == TASK_NULL)
395 task = db_current_task();
396 while (--size >= 0) {
397 if (addr++ < VM_MIN_KERNEL_ADDRESS && task == TASK_NULL) {
398 db_printf("\nbad address %x\n", addr);
399 db_error(0);
400 /* NOTREACHED */
401 }
402 *data++ = *src++;
403 }
404 return;
405 }
406 while (size > 0) {
407 if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
408 return;
409 src = (char *)kern_addr;
410 n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
411 if (n > size)
412 n = size;
413 size -= n;
414 addr += n;
415 while (--n >= 0)
416 *data++ = *src++;
417 }
418 }
419
420 /*
421 * Write bytes to kernel address space for debugger.
422 */
423 void
424 db_write_bytes(
425 vm_offset_t addr,
426 register int size,
427 register char *data,
428 task_t task)
429 {
430 register char *dst;
431
432 register pt_entry_t *ptep0 = 0;
433 pt_entry_t oldmap0 = 0;
434 vm_offset_t addr1;
435 register pt_entry_t *ptep1 = 0;
436 pt_entry_t oldmap1 = 0;
437 extern char etext;
438 void db_write_bytes_user_space();
439
440 if ((addr < VM_MIN_KERNEL_ADDRESS) ^
441 ((addr + size) <= VM_MIN_KERNEL_ADDRESS)) {
442 db_error("\ncannot write data into mixed space\n");
443 /* NOTREACHED */
444 }
445 if (addr < VM_MIN_KERNEL_ADDRESS) {
446 if (task) {
447 db_write_bytes_user_space(addr, size, data, task);
448 return;
449 } else if (db_current_task() == TASK_NULL) {
450 db_printf("\nbad address %x\n", addr);
451 db_error(0);
452 /* NOTREACHED */
453 }
454 }
455
456 if (addr >= VM_MIN_KERNEL_ADDRESS &&
457 addr <= (vm_offset_t)&etext)
458 {
459 ptep0 = pmap_pte(kernel_pmap, addr);
460 oldmap0 = *ptep0;
461 *ptep0 |= INTEL_PTE_WRITE;
462
463 addr1 = i386_trunc_page(addr + size - 1);
464 if (i386_trunc_page(addr) != addr1) {
465 /* data crosses a page boundary */
466
467 ptep1 = pmap_pte(kernel_pmap, addr1);
468 oldmap1 = *ptep1;
469 *ptep1 |= INTEL_PTE_WRITE;
470 }
471 flush_tlb();
472 }
473
474 dst = (char *)addr;
475
476 while (--size >= 0)
477 *dst++ = *data++;
478
479 if (ptep0) {
480 *ptep0 = oldmap0;
481 if (ptep1) {
482 *ptep1 = oldmap1;
483 }
484 flush_tlb();
485 }
486 }
487
488 void
489 db_write_bytes_user_space(
490 vm_offset_t addr,
491 register int size,
492 register char *data,
493 task_t task)
494 {
495 register char *dst;
496 register int n;
497 unsigned kern_addr;
498
499 while (size > 0) {
500 if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
501 return;
502 dst = (char *)kern_addr;
503 n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
504 if (n > size)
505 n = size;
506 size -= n;
507 addr += n;
508 while (--n >= 0)
509 *dst++ = *data++;
510 }
511 }
512
513 boolean_t
514 db_check_access(
515 vm_offset_t addr,
516 register int size,
517 task_t task)
518 {
519 register n;
520 vm_offset_t kern_addr;
521
522 if (addr >= VM_MIN_KERNEL_ADDRESS) {
523 if (kernel_task == TASK_NULL)
524 return TRUE;
525 task = kernel_task;
526 } else if (task == TASK_NULL) {
527 if (current_thread() == THREAD_NULL)
528 return FALSE;
529 task = current_thread()->task;
530 }
531 while (size > 0) {
532 if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0)
533 return FALSE;
534 n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
535 if (n > size)
536 n = size;
537 size -= n;
538 addr += n;
539 }
540 return TRUE;
541 }
542
543 boolean_t
544 db_phys_eq(
545 task_t task1,
546 vm_offset_t addr1,
547 task_t task2,
548 vm_offset_t addr2)
549 {
550 vm_offset_t kern_addr1, kern_addr2;
551
552 if (addr1 >= VM_MIN_KERNEL_ADDRESS || addr2 >= VM_MIN_KERNEL_ADDRESS)
553 return FALSE;
554 if ((addr1 & (INTEL_PGBYTES-1)) != (addr2 & (INTEL_PGBYTES-1)))
555 return FALSE;
556 if (task1 == TASK_NULL) {
557 if (current_thread() == THREAD_NULL)
558 return FALSE;
559 task1 = current_thread()->task;
560 }
561 if (db_user_to_kernel_address(task1, addr1, &kern_addr1, 0) < 0
562 || db_user_to_kernel_address(task2, addr2, &kern_addr2, 0) < 0)
563 return FALSE;
564 return(kern_addr1 == kern_addr2);
565 }
566
567 #define DB_USER_STACK_ADDR (VM_MIN_KERNEL_ADDRESS)
568 #define DB_NAME_SEARCH_LIMIT (DB_USER_STACK_ADDR-(INTEL_PGBYTES*3))
569
570 static boolean_t
571 db_search_null(
572 task_t task,
573 vm_offset_t *svaddr,
574 vm_offset_t evaddr,
575 vm_offset_t *skaddr,
576 int flag)
577 {
578 register unsigned vaddr;
579 register unsigned *kaddr;
580
581 kaddr = (unsigned *)*skaddr;
582 for (vaddr = *svaddr; vaddr > evaddr; vaddr -= sizeof(unsigned)) {
583 if (vaddr % INTEL_PGBYTES == 0) {
584 vaddr -= sizeof(unsigned);
585 if (db_user_to_kernel_address(task, vaddr, skaddr, 0) < 0)
586 return FALSE;
587 kaddr = (vm_offset_t *)*skaddr;
588 } else {
589 vaddr -= sizeof(unsigned);
590 kaddr--;
591 }
592 if ((*kaddr == 0) ^ (flag == 0)) {
593 *svaddr = vaddr;
594 *skaddr = (unsigned)kaddr;
595 return TRUE;
596 }
597 }
598 return FALSE;
599 }
600
601 void
602 db_task_name(
603 task_t task)
604 {
605 register char *p;
606 register n;
607 unsigned vaddr, kaddr;
608
609 vaddr = DB_USER_STACK_ADDR;
610 kaddr = 0;
611
612 /*
613 * skip nulls at the end
614 */
615 if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 0)) {
616 db_printf(DB_NULL_TASK_NAME);
617 return;
618 }
619 /*
620 * search start of args
621 */
622 if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 1)) {
623 db_printf(DB_NULL_TASK_NAME);
624 return;
625 }
626
627 n = DB_TASK_NAME_LEN-1;
628 p = (char *)kaddr + sizeof(unsigned);
629 for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR && n > 0;
630 vaddr++, p++, n--) {
631 if (vaddr % INTEL_PGBYTES == 0) {
632 (void)db_user_to_kernel_address(task, vaddr, &kaddr, 0);
633 p = (char*)kaddr;
634 }
635 db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p);
636 }
637 while (n-- >= 0) /* compare with >= 0 for one more space */
638 db_printf(" ");
639 }
Cache object: 519aec7388fea19c0a0faa3622ec49d0
|