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