ia64/xen-unstable

view tools/debugger/pdb/linux-2.6-module/debug.c @ 6316:f7dfaa2af90c

merge?
author cl349@firebug.cl.cam.ac.uk
date Sun Aug 21 11:02:00 2005 +0000 (2005-08-21)
parents 1872e09bfba3
children 6721abf6b16d
line source
1 /*
2 * debug.c
3 * pdb debug functionality for processes.
4 */
6 #include <linux/module.h>
7 #include <linux/mm.h>
8 #include <linux/sched.h>
9 #include <asm-i386/kdebug.h>
10 #include <asm-xen/asm-i386/processor.h>
11 #include <asm-xen/asm-i386/ptrace.h>
12 #include <asm-xen/asm-i386/tlbflush.h>
13 #include <asm-xen/xen-public/xen.h>
14 #include "pdb_module.h"
15 #include "pdb_debug.h"
18 static int pdb_debug_fn (struct pt_regs *regs, long error_code,
19 unsigned int condition);
20 static int pdb_int3_fn (struct pt_regs *regs, long error_code);
21 static int pdb_page_fault_fn (struct pt_regs *regs, long error_code,
22 unsigned int condition);
24 /***********************************************************************/
26 typedef struct bwcpoint /* break/watch/catch point */
27 {
28 struct list_head list;
29 unsigned long address;
30 int length;
32 u8 type; /* BWC_??? */
33 u8 mode; /* for BWC_PAGE, the current protection mode */
34 u32 process;
35 u8 error; /* error occured when enabling: don't disable. */
37 /* original values */
38 u8 orig_bkpt; /* single byte breakpoint */
39 pte_t orig_pte;
41 struct list_head watchpt_read_list; /* read watchpoints on this page */
42 struct list_head watchpt_write_list; /* write */
43 struct list_head watchpt_access_list; /* access */
44 struct list_head watchpt_disabled_list; /* disabled */
46 struct bwcpoint *parent; /* watchpoint: bwc_watch (the page) */
47 struct bwcpoint *watchpoint; /* bwc_watch_step: original watchpoint */
48 } bwcpoint_t, *bwcpoint_p;
50 static struct list_head bwcpoint_list = LIST_HEAD_INIT(bwcpoint_list);
52 #define _pdb_bwcpoint_alloc(_var) \
53 { \
54 if ( (_var = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL)) == NULL ) \
55 printk("error: unable to allocate memory %d\n", __LINE__); \
56 else { \
57 memset(_var, 0, sizeof(bwcpoint_t)); \
58 INIT_LIST_HEAD(&_var->watchpt_read_list); \
59 INIT_LIST_HEAD(&_var->watchpt_write_list); \
60 INIT_LIST_HEAD(&_var->watchpt_access_list); \
61 INIT_LIST_HEAD(&_var->watchpt_disabled_list); \
62 } \
63 }
65 /***********************************************************************/
67 static void _pdb_bwc_print_list (struct list_head *, char *, int);
69 static void
70 _pdb_bwc_print (bwcpoint_p bwc, char *label, int level)
71 {
72 printk("%s%03d 0x%08lx:0x%02x %c\n", label, bwc->type,
73 bwc->address, bwc->length, bwc->error ? 'e' : '-');
75 if ( !list_empty(&bwc->watchpt_read_list) )
76 _pdb_bwc_print_list(&bwc->watchpt_read_list, "r", level);
77 if ( !list_empty(&bwc->watchpt_write_list) )
78 _pdb_bwc_print_list(&bwc->watchpt_write_list, "w", level);
79 if ( !list_empty(&bwc->watchpt_access_list) )
80 _pdb_bwc_print_list(&bwc->watchpt_access_list, "a", level);
81 if ( !list_empty(&bwc->watchpt_disabled_list) )
82 _pdb_bwc_print_list(&bwc->watchpt_disabled_list, "d", level);
83 }
85 static void
86 _pdb_bwc_print_list (struct list_head *bwc_list, char *label, int level)
87 {
88 struct list_head *ptr;
89 int counter = 0;
91 list_for_each(ptr, bwc_list)
92 {
93 bwcpoint_p bwc = list_entry(ptr, bwcpoint_t, list);
94 printk(" %s[%02d]%s ", level > 0 ? " " : "", counter++,
95 level > 0 ? "" : " ");
96 _pdb_bwc_print(bwc, label, level+1);
97 }
99 if (counter == 0)
100 {
101 printk(" empty list\n");
102 }
103 }
105 void
106 pdb_bwc_print_list (void)
107 {
108 _pdb_bwc_print_list(&bwcpoint_list, " ", 0);
109 }
111 bwcpoint_p
112 pdb_search_watchpoint (u32 process, unsigned long address)
113 {
114 bwcpoint_p bwc_watch = (bwcpoint_p) 0;
115 bwcpoint_p bwc_entry = (bwcpoint_p) 0;
116 struct list_head *ptr;
118 list_for_each(ptr, &bwcpoint_list) /* find bwc page entry */
119 {
120 bwc_watch = list_entry(ptr, bwcpoint_t, list);
121 if (bwc_watch->address == (address & PAGE_MASK)) break;
122 }
124 if ( !bwc_watch )
125 {
126 return (bwcpoint_p) 0;
127 }
129 #define __pdb_search_watchpoint_list(__list) \
130 list_for_each(ptr, (__list)) \
131 { \
132 bwc_entry = list_entry(ptr, bwcpoint_t, list); \
133 if ( bwc_entry->process == process && \
134 bwc_entry->address <= address && \
135 bwc_entry->address + bwc_entry->length > address ) \
136 return bwc_entry; \
137 }
139 __pdb_search_watchpoint_list(&bwc_watch->watchpt_read_list);
140 __pdb_search_watchpoint_list(&bwc_watch->watchpt_write_list);
141 __pdb_search_watchpoint_list(&bwc_watch->watchpt_access_list);
143 #undef __pdb_search_watchpoint_list
145 return (bwcpoint_p) 0;
146 }
148 /*************************************************************/
150 int
151 pdb_suspend (struct task_struct *target)
152 {
153 u32 rc = 0;
155 force_sig(SIGSTOP, target); /* force_sig_specific ??? */
157 return rc;
158 }
160 int
161 pdb_resume (struct task_struct *target)
162 {
163 int rc = 0;
165 wake_up_process(target);
167 return rc;
168 }
170 /*
171 * from linux-2.6.11/arch/i386/kernel/ptrace.c::getreg()
172 */
173 static unsigned long
174 _pdb_get_register (struct task_struct *target, int reg)
175 {
176 unsigned long result = ~0UL;
177 unsigned long offset;
178 unsigned char *stack = 0L;
180 switch (reg)
181 {
182 case LINUX_FS:
183 result = target->thread.fs;
184 break;
185 case LINUX_GS:
186 result = target->thread.gs;
187 break;
188 case LINUX_DS:
189 case LINUX_ES:
190 case LINUX_SS:
191 case LINUX_CS:
192 result = 0xffff;
193 /* fall through */
194 default:
195 if (reg > LINUX_GS)
196 reg -= 2;
198 offset = reg * sizeof(long);
199 offset -= sizeof(struct pt_regs);
200 stack = (unsigned char *)target->thread.esp0;
201 stack += offset;
202 result &= *((int *)stack);
203 }
205 return result;
206 }
208 /*
209 * from linux-2.6.11/arch/i386/kernel/ptrace.c::putreg()
210 */
211 static void
212 _pdb_set_register (struct task_struct *target, int reg, unsigned long val)
213 {
214 unsigned long offset;
215 unsigned char *stack;
216 unsigned long value = val;
218 switch (reg)
219 {
220 case LINUX_FS:
221 target->thread.fs = value;
222 return;
223 case LINUX_GS:
224 target->thread.gs = value;
225 return;
226 case LINUX_DS:
227 case LINUX_ES:
228 value &= 0xffff;
229 break;
230 case LINUX_SS:
231 case LINUX_CS:
232 value &= 0xffff;
233 break;
234 case LINUX_EFL:
235 break;
236 }
238 if (reg > LINUX_GS)
239 reg -= 2;
240 offset = reg * sizeof(long);
241 offset -= sizeof(struct pt_regs);
242 stack = (unsigned char *)target->thread.esp0;
243 stack += offset;
244 *(unsigned long *) stack = value;
246 return;
247 }
249 int
250 pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op)
251 {
252 int rc = 0;
254 switch (op->reg)
255 {
256 case 0: op->value = _pdb_get_register(target, LINUX_EAX); break;
257 case 1: op->value = _pdb_get_register(target, LINUX_ECX); break;
258 case 2: op->value = _pdb_get_register(target, LINUX_EDX); break;
259 case 3: op->value = _pdb_get_register(target, LINUX_EBX); break;
260 case 4: op->value = _pdb_get_register(target, LINUX_ESP); break;
261 case 5: op->value = _pdb_get_register(target, LINUX_EBP); break;
262 case 6: op->value = _pdb_get_register(target, LINUX_ESI); break;
263 case 7: op->value = _pdb_get_register(target, LINUX_EDI); break;
264 case 8: op->value = _pdb_get_register(target, LINUX_EIP); break;
265 case 9: op->value = _pdb_get_register(target, LINUX_EFL); break;
267 case 10: op->value = _pdb_get_register(target, LINUX_CS); break;
268 case 11: op->value = _pdb_get_register(target, LINUX_SS); break;
269 case 12: op->value = _pdb_get_register(target, LINUX_DS); break;
270 case 13: op->value = _pdb_get_register(target, LINUX_ES); break;
271 case 14: op->value = _pdb_get_register(target, LINUX_FS); break;
272 case 15: op->value = _pdb_get_register(target, LINUX_GS); break;
273 }
275 return rc;
276 }
278 int
279 pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op)
280 {
281 int rc = 0;
283 op->reg[ 0] = _pdb_get_register(target, LINUX_EAX);
284 op->reg[ 1] = _pdb_get_register(target, LINUX_ECX);
285 op->reg[ 2] = _pdb_get_register(target, LINUX_EDX);
286 op->reg[ 3] = _pdb_get_register(target, LINUX_EBX);
287 op->reg[ 4] = _pdb_get_register(target, LINUX_ESP);
288 op->reg[ 5] = _pdb_get_register(target, LINUX_EBP);
289 op->reg[ 6] = _pdb_get_register(target, LINUX_ESI);
290 op->reg[ 7] = _pdb_get_register(target, LINUX_EDI);
291 op->reg[ 8] = _pdb_get_register(target, LINUX_EIP);
292 op->reg[ 9] = _pdb_get_register(target, LINUX_EFL);
294 op->reg[10] = _pdb_get_register(target, LINUX_CS);
295 op->reg[11] = _pdb_get_register(target, LINUX_SS);
296 op->reg[12] = _pdb_get_register(target, LINUX_DS);
297 op->reg[13] = _pdb_get_register(target, LINUX_ES);
298 op->reg[14] = _pdb_get_register(target, LINUX_FS);
299 op->reg[15] = _pdb_get_register(target, LINUX_GS);
301 return rc;
302 }
304 int
305 pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op)
306 {
307 int rc = 0;
309 _pdb_set_register(target, op->reg, op->value);
311 return rc;
312 }
314 int
315 pdb_access_memory (struct task_struct *target, unsigned long address,
316 void *buffer, int length, int write)
317 {
318 int rc = 0;
320 access_process_vm(target, address, buffer, length, write);
322 return rc;
323 }
325 int
326 pdb_continue (struct task_struct *target)
327 {
328 int rc = 0;
329 unsigned long eflags;
331 eflags = _pdb_get_register(target, LINUX_EFL);
332 eflags &= ~X86_EFLAGS_TF;
333 _pdb_set_register(target, LINUX_EFL, eflags);
335 wake_up_process(target);
337 return rc;
338 }
340 int
341 pdb_step (struct task_struct *target)
342 {
343 int rc = 0;
344 unsigned long eflags;
345 bwcpoint_p bkpt;
347 eflags = _pdb_get_register(target, LINUX_EFL);
348 eflags |= X86_EFLAGS_TF;
349 _pdb_set_register(target, LINUX_EFL, eflags);
351 _pdb_bwcpoint_alloc(bkpt);
352 if ( bkpt == NULL ) return -1;
354 bkpt->process = target->pid;
355 bkpt->address = 0;
356 bkpt->type = BWC_DEBUG;
358 list_add_tail(&bkpt->list, &bwcpoint_list);
360 wake_up_process(target);
362 return rc;
363 }
365 int
366 pdb_insert_memory_breakpoint (struct task_struct *target,
367 unsigned long address, u32 length)
368 {
369 int rc = 0;
370 bwcpoint_p bkpt;
371 u8 breakpoint_opcode = 0xcc;
373 printk("insert breakpoint %d:%lx len: %d\n", target->pid, address, length);
375 if ( length != 1 )
376 {
377 printk("error: breakpoint length should be 1\n");
378 return -1;
379 }
381 _pdb_bwcpoint_alloc(bkpt);
382 if ( bkpt == NULL ) return -1;
384 bkpt->process = target->pid;
385 bkpt->address = address;
386 bkpt->type = BWC_INT3;
388 pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_READ);
389 pdb_access_memory(target, address, &breakpoint_opcode, 1, PDB_MEM_WRITE);
391 list_add_tail(&bkpt->list, &bwcpoint_list);
393 printk("breakpoint_set %d:%lx OLD: 0x%x\n",
394 target->pid, address, bkpt->orig_bkpt);
395 pdb_bwc_print_list();
397 return rc;
398 }
400 int
401 pdb_remove_memory_breakpoint (struct task_struct *target,
402 unsigned long address, u32 length)
403 {
404 int rc = 0;
405 bwcpoint_p bkpt = NULL;
407 printk ("remove breakpoint %d:%lx\n", target->pid, address);
409 struct list_head *entry;
410 list_for_each(entry, &bwcpoint_list)
411 {
412 bkpt = list_entry(entry, bwcpoint_t, list);
413 if ( target->pid == bkpt->process &&
414 address == bkpt->address &&
415 bkpt->type == BWC_INT3 )
416 break;
417 }
419 if (entry == &bwcpoint_list)
420 {
421 printk ("error: no breakpoint found\n");
422 return -1;
423 }
425 pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_WRITE);
427 list_del(&bkpt->list);
428 kfree(bkpt);
430 pdb_bwc_print_list();
432 return rc;
433 }
435 #define PDB_PTE_UPDATE 1
436 #define PDB_PTE_RESTORE 2
438 int
439 pdb_change_pte (struct task_struct *target, bwcpoint_p bwc, int mode)
440 {
441 int rc = 0;
442 pgd_t *pgd;
443 pud_t *pud;
444 pmd_t *pmd;
445 pte_t *ptep;
447 pgd = pgd_offset(target->mm, bwc->address);
448 if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) return -1;
450 pud = pud_offset(pgd, bwc->address);
451 if (pud_none(*pud) || unlikely(pud_bad(*pud))) return -2;
453 pmd = pmd_offset(pud, bwc->address);
454 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) return -3;
456 ptep = pte_offset_map(pmd, bwc->address);
457 if (!ptep) return -4;
459 switch ( mode )
460 {
461 case PDB_PTE_UPDATE: /* added or removed a watchpoint. update pte. */
462 {
463 pte_t new_pte;
465 if ( pte_val(bwc->parent->orig_pte) == 0 ) /* new watchpoint page */
466 {
467 bwc->parent->orig_pte = *ptep;
468 }
470 new_pte = bwc->parent->orig_pte;
472 if ( !list_empty(&bwc->parent->watchpt_read_list) ||
473 !list_empty(&bwc->parent->watchpt_access_list) )
474 {
475 new_pte = pte_rdprotect(new_pte);
476 }
478 if ( !list_empty(&bwc->parent->watchpt_write_list) ||
479 !list_empty(&bwc->parent->watchpt_access_list) )
480 {
481 new_pte = pte_wrprotect(new_pte);
482 }
484 if ( pte_val(new_pte) != pte_val(*ptep) )
485 {
486 *ptep = new_pte;
487 flush_tlb_mm(target->mm);
488 }
489 break;
490 }
491 case PDB_PTE_RESTORE : /* suspend watchpoint by restoring original pte */
492 {
493 *ptep = bwc->parent->orig_pte;
494 flush_tlb_mm(target->mm);
495 break;
496 }
497 default :
498 {
499 printk("(linux) unknown mode %d %d\n", mode, __LINE__);
500 break;
501 }
502 }
504 pte_unmap(ptep); /* can i flush the tlb before pte_unmap? */
506 return rc;
507 }
509 int
510 pdb_insert_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
511 {
512 int rc = 0;
514 bwcpoint_p bwc_watch;
515 bwcpoint_p bwc_entry;
516 struct list_head *ptr;
517 unsigned long page = watchpt->address & PAGE_MASK;
518 struct list_head *watchpoint_list;
520 printk("insert watchpoint: %d %x %x\n",
521 watchpt->type, watchpt->address, watchpt->length);
523 list_for_each(ptr, &bwcpoint_list) /* find existing bwc page entry */
524 {
525 bwc_watch = list_entry(ptr, bwcpoint_t, list);
527 if (bwc_watch->address == page) goto got_bwc_watch;
528 }
530 _pdb_bwcpoint_alloc(bwc_watch); /* create new bwc:watch */
531 if ( bwc_watch == NULL ) return -1;
533 bwc_watch->type = BWC_WATCH;
534 bwc_watch->process = target->pid;
535 bwc_watch->address = page;
537 list_add_tail(&bwc_watch->list, &bwcpoint_list);
539 got_bwc_watch:
541 switch (watchpt->type)
542 {
543 case BWC_WATCH_READ:
544 watchpoint_list = &bwc_watch->watchpt_read_list; break;
545 case BWC_WATCH_WRITE:
546 watchpoint_list = &bwc_watch->watchpt_write_list; break;
547 case BWC_WATCH_ACCESS:
548 watchpoint_list = &bwc_watch->watchpt_access_list; break;
549 default:
550 printk("unknown type %d\n", watchpt->type); return -2;
551 }
553 _pdb_bwcpoint_alloc(bwc_entry); /* create new bwc:entry */
554 if ( bwc_entry == NULL ) return -1;
556 bwc_entry->process = target->pid;
557 bwc_entry->address = watchpt->address;
558 bwc_entry->length = watchpt->length;
559 bwc_entry->type = watchpt->type;
560 bwc_entry->parent = bwc_watch;
562 list_add_tail(&bwc_entry->list, watchpoint_list);
563 pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
565 pdb_bwc_print_list();
567 return rc;
568 }
570 int
571 pdb_remove_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
572 {
573 int rc = 0;
574 bwcpoint_p bwc_watch = (bwcpoint_p) NULL;
575 bwcpoint_p bwc_entry = (bwcpoint_p) NULL;
576 unsigned long page = watchpt->address & PAGE_MASK;
577 struct list_head *ptr;
578 struct list_head *watchpoint_list;
580 printk("remove watchpoint: %d %x %x\n",
581 watchpt->type, watchpt->address, watchpt->length);
583 list_for_each(ptr, &bwcpoint_list) /* find bwc page entry */
584 {
585 bwc_watch = list_entry(ptr, bwcpoint_t, list);
586 if (bwc_watch->address == page) break;
587 }
589 if ( !bwc_watch )
590 {
591 printk("(linux) delete watchpoint: can't find bwc page 0x%08x\n",
592 watchpt->address);
593 return -1;
594 }
596 switch (watchpt->type)
597 {
598 case BWC_WATCH_READ:
599 watchpoint_list = &bwc_watch->watchpt_read_list; break;
600 case BWC_WATCH_WRITE:
601 watchpoint_list = &bwc_watch->watchpt_write_list; break;
602 case BWC_WATCH_ACCESS:
603 watchpoint_list = &bwc_watch->watchpt_access_list; break;
604 default:
605 printk("unknown type %d\n", watchpt->type); return -2;
606 }
608 list_for_each(ptr, watchpoint_list) /* find watchpoint */
609 {
610 bwc_entry = list_entry(ptr, bwcpoint_t, list);
611 if ( bwc_entry->address == watchpt->address &&
612 bwc_entry->length == watchpt->length ) break;
613 }
615 if ( !bwc_entry ) /* or ptr == watchpoint_list */
616 {
617 printk("(linux) delete watchpoint: can't find watchpoint 0x%08x\n",
618 watchpt->address);
619 return -1;
620 }
622 list_del(&bwc_entry->list);
623 pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
624 kfree(bwc_entry);
627 if ( list_empty(&bwc_watch->watchpt_read_list) &&
628 list_empty(&bwc_watch->watchpt_write_list) &&
629 list_empty(&bwc_watch->watchpt_access_list) )
630 {
631 list_del(&bwc_watch->list);
632 kfree(bwc_watch);
633 }
635 pdb_bwc_print_list();
637 return rc;
638 }
641 /***************************************************************/
643 int
644 pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
645 void *data)
646 {
647 struct die_args *args = (struct die_args *)data;
649 switch (val)
650 {
651 case DIE_DEBUG:
652 if ( pdb_debug_fn(args->regs, args->trapnr, args->err) )
653 return NOTIFY_STOP;
654 break;
655 case DIE_TRAP:
656 if ( args->trapnr == 3 && pdb_int3_fn(args->regs, args->err) )
657 return NOTIFY_STOP;
658 break;
659 case DIE_INT3: /* without kprobes, we should never see DIE_INT3 */
660 if ( pdb_int3_fn(args->regs, args->err) )
661 return NOTIFY_STOP;
662 break;
663 case DIE_PAGE_FAULT:
664 if ( pdb_page_fault_fn(args->regs, args->trapnr, args->err) )
665 return NOTIFY_STOP;
666 break;
667 case DIE_GPF:
668 printk("---------------GPF\n");
669 break;
670 default:
671 break;
672 }
674 return NOTIFY_DONE;
675 }
678 static int
679 pdb_debug_fn (struct pt_regs *regs, long error_code,
680 unsigned int condition)
681 {
682 pdb_response_t resp;
683 bwcpoint_p bkpt = NULL;
684 struct list_head *entry;
686 printk("pdb_debug_fn\n");
688 list_for_each(entry, &bwcpoint_list)
689 {
690 bkpt = list_entry(entry, bwcpoint_t, list);
691 if ( current->pid == bkpt->process &&
692 (bkpt->type == BWC_DEBUG || /* single step */
693 bkpt->type == BWC_WATCH_STEP)) /* single step over watchpoint */
694 break;
695 }
697 if (entry == &bwcpoint_list)
698 {
699 printk("not my debug 0x%x 0x%lx\n", current->pid, regs->eip);
700 return 0;
701 }
703 pdb_suspend(current);
705 printk("(pdb) %s pid: %d, eip: 0x%08lx\n",
706 bkpt->type == BWC_DEBUG ? "debug" : "watch-step",
707 current->pid, regs->eip);
709 regs->eflags &= ~X86_EFLAGS_TF;
710 set_tsk_thread_flag(current, TIF_SINGLESTEP);
712 switch (bkpt->type)
713 {
714 case BWC_DEBUG:
715 resp.operation = PDB_OPCODE_STEP;
716 break;
717 case BWC_WATCH_STEP:
718 {
719 struct list_head *watchpoint_list;
720 bwcpoint_p watch_page = bkpt->watchpoint->parent;
722 switch (bkpt->watchpoint->type)
723 {
724 case BWC_WATCH_READ:
725 watchpoint_list = &watch_page->watchpt_read_list; break;
726 case BWC_WATCH_WRITE:
727 watchpoint_list = &watch_page->watchpt_write_list; break;
728 case BWC_WATCH_ACCESS:
729 watchpoint_list = &watch_page->watchpt_access_list; break;
730 default:
731 printk("unknown type %d\n", bkpt->watchpoint->type); return 0;
732 }
734 resp.operation = PDB_OPCODE_WATCHPOINT;
735 list_del_init(&bkpt->watchpoint->list);
736 list_add_tail(&bkpt->watchpoint->list, watchpoint_list);
737 pdb_change_pte(current, bkpt->watchpoint, PDB_PTE_UPDATE);
738 pdb_bwc_print_list();
739 break;
740 }
741 default:
742 printk("unknown breakpoint type %d %d\n", __LINE__, bkpt->type);
743 return 0;
744 }
746 resp.process = current->pid;
747 resp.status = PDB_RESPONSE_OKAY;
749 pdb_send_response(&resp);
751 list_del(&bkpt->list);
752 kfree(bkpt);
754 return 1;
755 }
758 static int
759 pdb_int3_fn (struct pt_regs *regs, long error_code)
760 {
761 pdb_response_t resp;
762 bwcpoint_p bkpt = NULL;
763 unsigned long address = regs->eip - 1;
765 struct list_head *entry;
766 list_for_each(entry, &bwcpoint_list)
767 {
768 bkpt = list_entry(entry, bwcpoint_t, list);
769 if ( current->pid == bkpt->process &&
770 address == bkpt->address &&
771 bkpt->type == BWC_INT3 )
772 break;
773 }
775 if (entry == &bwcpoint_list)
776 {
777 printk("not my int3 bkpt 0x%x 0x%lx\n", current->pid, address);
778 return 0;
779 }
781 printk("(pdb) int3 pid: %d, eip: 0x%08lx\n", current->pid, address);
783 pdb_suspend(current);
785 resp.operation = PDB_OPCODE_CONTINUE;
786 resp.process = current->pid;
787 resp.status = PDB_RESPONSE_OKAY;
789 pdb_send_response(&resp);
791 return 1;
792 }
794 static int
795 pdb_page_fault_fn (struct pt_regs *regs, long error_code,
796 unsigned int condition)
797 {
798 unsigned long cr2;
799 unsigned long cr3;
800 bwcpoint_p bwc;
801 bwcpoint_p watchpt;
802 bwcpoint_p bkpt;
804 __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
805 __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : );
807 bwc = pdb_search_watchpoint(current->pid, cr2);
808 if ( !bwc )
809 {
810 return 0; /* not mine */
811 }
813 printk("page_fault cr2:%08lx err:%lx eip:%08lx\n",
814 cr2, error_code, regs->eip);
816 /* disable the watchpoint */
817 watchpt = bwc->watchpoint;
818 list_del_init(&bwc->list);
819 list_add_tail(&bwc->list, &bwc->parent->watchpt_disabled_list);
820 pdb_change_pte(current, bwc, PDB_PTE_RESTORE);
822 /* single step the faulting instruction */
823 regs->eflags |= X86_EFLAGS_TF;
825 /* create a bwcpoint entry so we know what to do once we regain control */
826 _pdb_bwcpoint_alloc(bkpt);
827 if ( bkpt == NULL ) return -1;
829 bkpt->process = current->pid;
830 bkpt->address = 0;
831 bkpt->type = BWC_WATCH_STEP;
832 bkpt->watchpoint = bwc;
834 /* add to head so we see it first the next time we break */
835 list_add(&bkpt->list, &bwcpoint_list);
837 pdb_bwc_print_list();
838 return 1;
839 }
842 /*
843 * Local variables:
844 * mode: C
845 * c-set-style: "BSD"
846 * c-basic-offset: 4
847 * tab-width: 4
848 * indent-tabs-mode: nil
849 * End:
850 */