diff options
Diffstat (limited to 'kernel/debug')
-rw-r--r-- | kernel/debug/debug_core.c | 107 | ||||
-rw-r--r-- | kernel/debug/debug_core.h | 24 | ||||
-rw-r--r-- | kernel/debug/gdbstub.c | 36 |
3 files changed, 150 insertions, 17 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 7e03969330bc..6e1fa829fdeb 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/sysrq.h> | 43 | #include <linux/sysrq.h> |
44 | #include <linux/init.h> | 44 | #include <linux/init.h> |
45 | #include <linux/kgdb.h> | 45 | #include <linux/kgdb.h> |
46 | #include <linux/kdb.h> | ||
46 | #include <linux/pid.h> | 47 | #include <linux/pid.h> |
47 | #include <linux/smp.h> | 48 | #include <linux/smp.h> |
48 | #include <linux/mm.h> | 49 | #include <linux/mm.h> |
@@ -77,6 +78,11 @@ static DEFINE_SPINLOCK(kgdb_registration_lock); | |||
77 | static int kgdb_con_registered; | 78 | static int kgdb_con_registered; |
78 | /* determine if kgdb console output should be used */ | 79 | /* determine if kgdb console output should be used */ |
79 | static int kgdb_use_con; | 80 | static int kgdb_use_con; |
81 | /* Next cpu to become the master debug core */ | ||
82 | int dbg_switch_cpu; | ||
83 | |||
84 | /* Use kdb or gdbserver mode */ | ||
85 | static int dbg_kdb_mode = 1; | ||
80 | 86 | ||
81 | static int __init opt_kgdb_con(char *str) | 87 | static int __init opt_kgdb_con(char *str) |
82 | { | 88 | { |
@@ -100,6 +106,7 @@ static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = { | |||
100 | * The CPU# of the active CPU, or -1 if none: | 106 | * The CPU# of the active CPU, or -1 if none: |
101 | */ | 107 | */ |
102 | atomic_t kgdb_active = ATOMIC_INIT(-1); | 108 | atomic_t kgdb_active = ATOMIC_INIT(-1); |
109 | EXPORT_SYMBOL_GPL(kgdb_active); | ||
103 | 110 | ||
104 | /* | 111 | /* |
105 | * We use NR_CPUs not PERCPU, in case kgdb is used to debug early | 112 | * We use NR_CPUs not PERCPU, in case kgdb is used to debug early |
@@ -301,7 +308,7 @@ int dbg_set_sw_break(unsigned long addr) | |||
301 | return 0; | 308 | return 0; |
302 | } | 309 | } |
303 | 310 | ||
304 | static int kgdb_deactivate_sw_breakpoints(void) | 311 | int dbg_deactivate_sw_breakpoints(void) |
305 | { | 312 | { |
306 | unsigned long addr; | 313 | unsigned long addr; |
307 | int error; | 314 | int error; |
@@ -395,8 +402,14 @@ static int kgdb_io_ready(int print_wait) | |||
395 | return 1; | 402 | return 1; |
396 | if (atomic_read(&kgdb_setting_breakpoint)) | 403 | if (atomic_read(&kgdb_setting_breakpoint)) |
397 | return 1; | 404 | return 1; |
398 | if (print_wait) | 405 | if (print_wait) { |
406 | #ifdef CONFIG_KGDB_KDB | ||
407 | if (!dbg_kdb_mode) | ||
408 | printk(KERN_CRIT "KGDB: waiting... or $3#33 for KDB\n"); | ||
409 | #else | ||
399 | printk(KERN_CRIT "KGDB: Waiting for remote debugger\n"); | 410 | printk(KERN_CRIT "KGDB: Waiting for remote debugger\n"); |
411 | #endif | ||
412 | } | ||
400 | return 1; | 413 | return 1; |
401 | } | 414 | } |
402 | 415 | ||
@@ -410,7 +423,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks) | |||
410 | /* Panic on recursive debugger calls: */ | 423 | /* Panic on recursive debugger calls: */ |
411 | exception_level++; | 424 | exception_level++; |
412 | addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs); | 425 | addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs); |
413 | kgdb_deactivate_sw_breakpoints(); | 426 | dbg_deactivate_sw_breakpoints(); |
414 | 427 | ||
415 | /* | 428 | /* |
416 | * If the break point removed ok at the place exception | 429 | * If the break point removed ok at the place exception |
@@ -443,11 +456,24 @@ static int kgdb_reenter_check(struct kgdb_state *ks) | |||
443 | return 1; | 456 | return 1; |
444 | } | 457 | } |
445 | 458 | ||
459 | static void dbg_cpu_switch(int cpu, int next_cpu) | ||
460 | { | ||
461 | /* Mark the cpu we are switching away from as a slave when it | ||
462 | * holds the kgdb_active token. This must be done so that the | ||
463 | * that all the cpus wait in for the debug core will not enter | ||
464 | * again as the master. */ | ||
465 | if (cpu == atomic_read(&kgdb_active)) { | ||
466 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; | ||
467 | kgdb_info[cpu].exception_state &= ~DCPU_WANT_MASTER; | ||
468 | } | ||
469 | kgdb_info[next_cpu].exception_state |= DCPU_NEXT_MASTER; | ||
470 | } | ||
471 | |||
446 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) | 472 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) |
447 | { | 473 | { |
448 | unsigned long flags; | 474 | unsigned long flags; |
449 | int sstep_tries = 100; | 475 | int sstep_tries = 100; |
450 | int error = 0; | 476 | int error; |
451 | int i, cpu; | 477 | int i, cpu; |
452 | int trace_on = 0; | 478 | int trace_on = 0; |
453 | acquirelock: | 479 | acquirelock: |
@@ -460,6 +486,8 @@ acquirelock: | |||
460 | cpu = ks->cpu; | 486 | cpu = ks->cpu; |
461 | kgdb_info[cpu].debuggerinfo = regs; | 487 | kgdb_info[cpu].debuggerinfo = regs; |
462 | kgdb_info[cpu].task = current; | 488 | kgdb_info[cpu].task = current; |
489 | kgdb_info[cpu].ret_state = 0; | ||
490 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; | ||
463 | /* | 491 | /* |
464 | * Make sure the above info reaches the primary CPU before | 492 | * Make sure the above info reaches the primary CPU before |
465 | * our cpu_in_kgdb[] flag setting does: | 493 | * our cpu_in_kgdb[] flag setting does: |
@@ -471,7 +499,11 @@ acquirelock: | |||
471 | * master cpu and acquire the kgdb_active lock: | 499 | * master cpu and acquire the kgdb_active lock: |
472 | */ | 500 | */ |
473 | while (1) { | 501 | while (1) { |
474 | if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | 502 | cpu_loop: |
503 | if (kgdb_info[cpu].exception_state & DCPU_NEXT_MASTER) { | ||
504 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; | ||
505 | goto cpu_master_loop; | ||
506 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | ||
475 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) | 507 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) |
476 | break; | 508 | break; |
477 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { | 509 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { |
@@ -513,7 +545,7 @@ return_normal: | |||
513 | } | 545 | } |
514 | 546 | ||
515 | if (!kgdb_io_ready(1)) { | 547 | if (!kgdb_io_ready(1)) { |
516 | error = 1; | 548 | kgdb_info[cpu].ret_state = 1; |
517 | goto kgdb_restore; /* No I/O connection, resume the system */ | 549 | goto kgdb_restore; /* No I/O connection, resume the system */ |
518 | } | 550 | } |
519 | 551 | ||
@@ -548,7 +580,7 @@ return_normal: | |||
548 | * Wait for the other CPUs to be notified and be waiting for us: | 580 | * Wait for the other CPUs to be notified and be waiting for us: |
549 | */ | 581 | */ |
550 | for_each_online_cpu(i) { | 582 | for_each_online_cpu(i) { |
551 | while (!atomic_read(&cpu_in_kgdb[i])) | 583 | while (kgdb_do_roundup && !atomic_read(&cpu_in_kgdb[i])) |
552 | cpu_relax(); | 584 | cpu_relax(); |
553 | } | 585 | } |
554 | 586 | ||
@@ -557,7 +589,7 @@ return_normal: | |||
557 | * in the debugger and all secondary CPUs are quiescent | 589 | * in the debugger and all secondary CPUs are quiescent |
558 | */ | 590 | */ |
559 | kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code); | 591 | kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code); |
560 | kgdb_deactivate_sw_breakpoints(); | 592 | dbg_deactivate_sw_breakpoints(); |
561 | kgdb_single_step = 0; | 593 | kgdb_single_step = 0; |
562 | kgdb_contthread = current; | 594 | kgdb_contthread = current; |
563 | exception_level = 0; | 595 | exception_level = 0; |
@@ -565,8 +597,26 @@ return_normal: | |||
565 | if (trace_on) | 597 | if (trace_on) |
566 | tracing_off(); | 598 | tracing_off(); |
567 | 599 | ||
568 | /* Talk to debugger with gdbserial protocol */ | 600 | while (1) { |
569 | error = gdb_serial_stub(ks); | 601 | cpu_master_loop: |
602 | if (dbg_kdb_mode) { | ||
603 | kgdb_connected = 1; | ||
604 | error = kdb_stub(ks); | ||
605 | } else { | ||
606 | error = gdb_serial_stub(ks); | ||
607 | } | ||
608 | |||
609 | if (error == DBG_PASS_EVENT) { | ||
610 | dbg_kdb_mode = !dbg_kdb_mode; | ||
611 | kgdb_connected = 0; | ||
612 | } else if (error == DBG_SWITCH_CPU_EVENT) { | ||
613 | dbg_cpu_switch(cpu, dbg_switch_cpu); | ||
614 | goto cpu_loop; | ||
615 | } else { | ||
616 | kgdb_info[cpu].ret_state = error; | ||
617 | break; | ||
618 | } | ||
619 | } | ||
570 | 620 | ||
571 | /* Call the I/O driver's post_exception routine */ | 621 | /* Call the I/O driver's post_exception routine */ |
572 | if (dbg_io_ops->post_exception) | 622 | if (dbg_io_ops->post_exception) |
@@ -578,11 +628,16 @@ return_normal: | |||
578 | for (i = NR_CPUS-1; i >= 0; i--) | 628 | for (i = NR_CPUS-1; i >= 0; i--) |
579 | atomic_dec(&passive_cpu_wait[i]); | 629 | atomic_dec(&passive_cpu_wait[i]); |
580 | /* | 630 | /* |
581 | * Wait till all the CPUs have quit | 631 | * Wait till all the CPUs have quit from the debugger, |
582 | * from the debugger. | 632 | * but allow a CPU that hit an exception and is |
633 | * waiting to become the master to remain in the debug | ||
634 | * core. | ||
583 | */ | 635 | */ |
584 | for_each_online_cpu(i) { | 636 | for_each_online_cpu(i) { |
585 | while (atomic_read(&cpu_in_kgdb[i])) | 637 | while (kgdb_do_roundup && |
638 | atomic_read(&cpu_in_kgdb[i]) && | ||
639 | !(kgdb_info[i].exception_state & | ||
640 | DCPU_WANT_MASTER)) | ||
586 | cpu_relax(); | 641 | cpu_relax(); |
587 | } | 642 | } |
588 | } | 643 | } |
@@ -603,7 +658,7 @@ kgdb_restore: | |||
603 | clocksource_touch_watchdog(); | 658 | clocksource_touch_watchdog(); |
604 | local_irq_restore(flags); | 659 | local_irq_restore(flags); |
605 | 660 | ||
606 | return error; | 661 | return kgdb_info[cpu].ret_state; |
607 | } | 662 | } |
608 | 663 | ||
609 | /* | 664 | /* |
@@ -632,7 +687,8 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
632 | return 0; /* Ouch, double exception ! */ | 687 | return 0; /* Ouch, double exception ! */ |
633 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | 688 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; |
634 | ret = kgdb_cpu_enter(ks, regs); | 689 | ret = kgdb_cpu_enter(ks, regs); |
635 | kgdb_info[ks->cpu].exception_state &= ~DCPU_WANT_MASTER; | 690 | kgdb_info[ks->cpu].exception_state &= ~(DCPU_WANT_MASTER | |
691 | DCPU_IS_SLAVE); | ||
636 | return ret; | 692 | return ret; |
637 | } | 693 | } |
638 | 694 | ||
@@ -665,7 +721,7 @@ static void kgdb_console_write(struct console *co, const char *s, | |||
665 | 721 | ||
666 | /* If we're debugging, or KGDB has not connected, don't try | 722 | /* If we're debugging, or KGDB has not connected, don't try |
667 | * and print. */ | 723 | * and print. */ |
668 | if (!kgdb_connected || atomic_read(&kgdb_active) != -1) | 724 | if (!kgdb_connected || atomic_read(&kgdb_active) != -1 || dbg_kdb_mode) |
669 | return; | 725 | return; |
670 | 726 | ||
671 | local_irq_save(flags); | 727 | local_irq_save(flags); |
@@ -687,8 +743,14 @@ static void sysrq_handle_dbg(int key, struct tty_struct *tty) | |||
687 | printk(KERN_CRIT "ERROR: No KGDB I/O module available\n"); | 743 | printk(KERN_CRIT "ERROR: No KGDB I/O module available\n"); |
688 | return; | 744 | return; |
689 | } | 745 | } |
690 | if (!kgdb_connected) | 746 | if (!kgdb_connected) { |
747 | #ifdef CONFIG_KGDB_KDB | ||
748 | if (!dbg_kdb_mode) | ||
749 | printk(KERN_CRIT "KGDB or $3#33 for KDB\n"); | ||
750 | #else | ||
691 | printk(KERN_CRIT "Entering KGDB\n"); | 751 | printk(KERN_CRIT "Entering KGDB\n"); |
752 | #endif | ||
753 | } | ||
692 | 754 | ||
693 | kgdb_breakpoint(); | 755 | kgdb_breakpoint(); |
694 | } | 756 | } |
@@ -817,6 +879,16 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops) | |||
817 | } | 879 | } |
818 | EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); | 880 | EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); |
819 | 881 | ||
882 | int dbg_io_get_char(void) | ||
883 | { | ||
884 | int ret = dbg_io_ops->read_char(); | ||
885 | if (!dbg_kdb_mode) | ||
886 | return ret; | ||
887 | if (ret == 127) | ||
888 | return 8; | ||
889 | return ret; | ||
890 | } | ||
891 | |||
820 | /** | 892 | /** |
821 | * kgdb_breakpoint - generate breakpoint exception | 893 | * kgdb_breakpoint - generate breakpoint exception |
822 | * | 894 | * |
@@ -839,6 +911,7 @@ static int __init opt_kgdb_wait(char *str) | |||
839 | { | 911 | { |
840 | kgdb_break_asap = 1; | 912 | kgdb_break_asap = 1; |
841 | 913 | ||
914 | kdb_init(KDB_INIT_EARLY); | ||
842 | if (kgdb_io_module_registered) | 915 | if (kgdb_io_module_registered) |
843 | kgdb_initial_breakpoint(); | 916 | kgdb_initial_breakpoint(); |
844 | 917 | ||
diff --git a/kernel/debug/debug_core.h b/kernel/debug/debug_core.h index db554f9be51d..44cf3de8cf9e 100644 --- a/kernel/debug/debug_core.h +++ b/kernel/debug/debug_core.h | |||
@@ -38,6 +38,8 @@ struct debuggerinfo_struct { | |||
38 | void *debuggerinfo; | 38 | void *debuggerinfo; |
39 | struct task_struct *task; | 39 | struct task_struct *task; |
40 | int exception_state; | 40 | int exception_state; |
41 | int ret_state; | ||
42 | int irq_depth; | ||
41 | }; | 43 | }; |
42 | 44 | ||
43 | extern struct debuggerinfo_struct kgdb_info[]; | 45 | extern struct debuggerinfo_struct kgdb_info[]; |
@@ -47,9 +49,31 @@ extern int dbg_remove_all_break(void); | |||
47 | extern int dbg_set_sw_break(unsigned long addr); | 49 | extern int dbg_set_sw_break(unsigned long addr); |
48 | extern int dbg_remove_sw_break(unsigned long addr); | 50 | extern int dbg_remove_sw_break(unsigned long addr); |
49 | extern int dbg_activate_sw_breakpoints(void); | 51 | extern int dbg_activate_sw_breakpoints(void); |
52 | extern int dbg_deactivate_sw_breakpoints(void); | ||
53 | |||
54 | /* polled character access to i/o module */ | ||
55 | extern int dbg_io_get_char(void); | ||
56 | |||
57 | /* stub return value for switching between the gdbstub and kdb */ | ||
58 | #define DBG_PASS_EVENT -12345 | ||
59 | /* Switch from one cpu to another */ | ||
60 | #define DBG_SWITCH_CPU_EVENT -123456 | ||
61 | extern int dbg_switch_cpu; | ||
50 | 62 | ||
51 | /* gdbstub interface functions */ | 63 | /* gdbstub interface functions */ |
52 | extern int gdb_serial_stub(struct kgdb_state *ks); | 64 | extern int gdb_serial_stub(struct kgdb_state *ks); |
53 | extern void gdbstub_msg_write(const char *s, int len); | 65 | extern void gdbstub_msg_write(const char *s, int len); |
54 | 66 | ||
67 | /* gdbstub functions used for kdb <-> gdbstub transition */ | ||
68 | extern int gdbstub_state(struct kgdb_state *ks, char *cmd); | ||
69 | |||
70 | #ifdef CONFIG_KGDB_KDB | ||
71 | extern int kdb_stub(struct kgdb_state *ks); | ||
72 | #else /* ! CONFIG_KGDB_KDB */ | ||
73 | static inline int kdb_stub(struct kgdb_state *ks) | ||
74 | { | ||
75 | return DBG_PASS_EVENT; | ||
76 | } | ||
77 | #endif /* CONFIG_KGDB_KDB */ | ||
78 | |||
55 | #endif /* _DEBUG_CORE_H_ */ | 79 | #endif /* _DEBUG_CORE_H_ */ |
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index ccdf0929f12d..188203a19657 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c | |||
@@ -887,6 +887,13 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
887 | case 'Z': /* Break point set */ | 887 | case 'Z': /* Break point set */ |
888 | gdb_cmd_break(ks); | 888 | gdb_cmd_break(ks); |
889 | break; | 889 | break; |
890 | #ifdef CONFIG_KGDB_KDB | ||
891 | case '3': /* Escape into back into kdb */ | ||
892 | if (remcom_in_buffer[1] == '\0') { | ||
893 | gdb_cmd_detachkill(ks); | ||
894 | return DBG_PASS_EVENT; | ||
895 | } | ||
896 | #endif | ||
890 | case 'C': /* Exception passing */ | 897 | case 'C': /* Exception passing */ |
891 | tmp = gdb_cmd_exception_pass(ks); | 898 | tmp = gdb_cmd_exception_pass(ks); |
892 | if (tmp > 0) | 899 | if (tmp > 0) |
@@ -932,3 +939,32 @@ kgdb_exit: | |||
932 | error = 1; | 939 | error = 1; |
933 | return error; | 940 | return error; |
934 | } | 941 | } |
942 | |||
943 | int gdbstub_state(struct kgdb_state *ks, char *cmd) | ||
944 | { | ||
945 | int error; | ||
946 | |||
947 | switch (cmd[0]) { | ||
948 | case 'e': | ||
949 | error = kgdb_arch_handle_exception(ks->ex_vector, | ||
950 | ks->signo, | ||
951 | ks->err_code, | ||
952 | remcom_in_buffer, | ||
953 | remcom_out_buffer, | ||
954 | ks->linux_regs); | ||
955 | return error; | ||
956 | case 's': | ||
957 | case 'c': | ||
958 | strcpy(remcom_in_buffer, cmd); | ||
959 | return 0; | ||
960 | case '?': | ||
961 | gdb_cmd_status(ks); | ||
962 | break; | ||
963 | case '\0': | ||
964 | strcpy(remcom_out_buffer, ""); | ||
965 | break; | ||
966 | } | ||
967 | dbg_io_ops->write_char('+'); | ||
968 | put_packet(remcom_out_buffer); | ||
969 | return 0; | ||
970 | } | ||