diff options
| -rw-r--r-- | arch/arm/kernel/kgdb.c | 5 | ||||
| -rw-r--r-- | arch/mips/kernel/kgdb.c | 5 | ||||
| -rw-r--r-- | arch/powerpc/kernel/kgdb.c | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/kgdb.c | 5 | ||||
| -rw-r--r-- | include/linux/kgdb.h | 11 | ||||
| -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 | ||||
| -rw-r--r-- | lib/Kconfig.kgdb | 8 |
9 files changed, 186 insertions, 20 deletions
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index a5b846b9895d..c868a8864117 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
| @@ -98,6 +98,11 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) | |||
| 98 | gdb_regs[_CPSR] = thread_regs->ARM_cpsr; | 98 | gdb_regs[_CPSR] = thread_regs->ARM_cpsr; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | ||
| 102 | { | ||
| 103 | regs->ARM_pc = pc; | ||
| 104 | } | ||
| 105 | |||
| 101 | static int compiled_break; | 106 | static int compiled_break; |
| 102 | 107 | ||
| 103 | int kgdb_arch_handle_exception(int exception_vector, int signo, | 108 | int kgdb_arch_handle_exception(int exception_vector, int signo, |
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 50c9bb880667..6ed4c83c869b 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c | |||
| @@ -180,6 +180,11 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 180 | *(ptr++) = regs->cp0_epc; | 180 | *(ptr++) = regs->cp0_epc; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | ||
| 184 | { | ||
| 185 | regs->cp0_epc = pc; | ||
| 186 | } | ||
| 187 | |||
| 183 | /* | 188 | /* |
| 184 | * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, | 189 | * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, |
| 185 | * then try to fall into the debugger | 190 | * then try to fall into the debugger |
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 41bada0298c8..c81e3de1306e 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c | |||
| @@ -309,6 +309,11 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 309 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | 309 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | ||
| 313 | { | ||
| 314 | regs->nip = pc; | ||
| 315 | } | ||
| 316 | |||
| 312 | /* | 317 | /* |
| 313 | * This function does PowerPC specific procesing for interfacing to gdb. | 318 | * This function does PowerPC specific procesing for interfacing to gdb. |
| 314 | */ | 319 | */ |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index b2258ca91003..f95a2c0b915c 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
| @@ -690,6 +690,11 @@ unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs) | |||
| 690 | return instruction_pointer(regs); | 690 | return instruction_pointer(regs); |
| 691 | } | 691 | } |
| 692 | 692 | ||
| 693 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) | ||
| 694 | { | ||
| 695 | regs->ip = ip; | ||
| 696 | } | ||
| 697 | |||
| 693 | struct kgdb_arch arch_kgdb_ops = { | 698 | struct kgdb_arch arch_kgdb_ops = { |
| 694 | /* Breakpoint instruction: */ | 699 | /* Breakpoint instruction: */ |
| 695 | .gdb_bpt_instr = { 0xcc }, | 700 | .gdb_bpt_instr = { 0xcc }, |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 4830142ec339..5b37df00000d 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
| @@ -16,10 +16,12 @@ | |||
| 16 | #include <linux/serial_8250.h> | 16 | #include <linux/serial_8250.h> |
| 17 | #include <linux/linkage.h> | 17 | #include <linux/linkage.h> |
| 18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
| 19 | |||
| 20 | #include <asm/atomic.h> | 19 | #include <asm/atomic.h> |
| 20 | #ifdef CONFIG_HAVE_ARCH_KGDB | ||
| 21 | #include <asm/kgdb.h> | 21 | #include <asm/kgdb.h> |
| 22 | #endif | ||
| 22 | 23 | ||
| 24 | #ifdef CONFIG_KGDB | ||
| 23 | struct pt_regs; | 25 | struct pt_regs; |
| 24 | 26 | ||
| 25 | /** | 27 | /** |
| @@ -262,6 +264,7 @@ extern struct kgdb_arch arch_kgdb_ops; | |||
| 262 | 264 | ||
| 263 | extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs); | 265 | extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs); |
| 264 | 266 | ||
| 267 | extern void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc); | ||
| 265 | extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); | 268 | extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); |
| 266 | extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); | 269 | extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); |
| 267 | extern struct kgdb_io *dbg_io_ops; | 270 | extern struct kgdb_io *dbg_io_ops; |
| @@ -279,5 +282,9 @@ extern int kgdb_nmicallback(int cpu, void *regs); | |||
| 279 | 282 | ||
| 280 | extern int kgdb_single_step; | 283 | extern int kgdb_single_step; |
| 281 | extern atomic_t kgdb_active; | 284 | extern atomic_t kgdb_active; |
| 282 | 285 | #define in_dbg_master() \ | |
| 286 | (raw_smp_processor_id() == atomic_read(&kgdb_active)) | ||
| 287 | #else /* ! CONFIG_KGDB */ | ||
| 288 | #define in_dbg_master() (0) | ||
| 289 | #endif /* ! CONFIG_KGDB */ | ||
| 283 | #endif /* _KGDB_H_ */ | 290 | #endif /* _KGDB_H_ */ |
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 | } | ||
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb index 9b5d1d7f2ef7..78de43a5e902 100644 --- a/lib/Kconfig.kgdb +++ b/lib/Kconfig.kgdb | |||
| @@ -3,7 +3,7 @@ config HAVE_ARCH_KGDB | |||
| 3 | bool | 3 | bool |
| 4 | 4 | ||
| 5 | menuconfig KGDB | 5 | menuconfig KGDB |
| 6 | bool "KGDB: kernel debugging with remote gdb" | 6 | bool "KGDB: kernel debugger" |
| 7 | depends on HAVE_ARCH_KGDB | 7 | depends on HAVE_ARCH_KGDB |
| 8 | depends on DEBUG_KERNEL && EXPERIMENTAL | 8 | depends on DEBUG_KERNEL && EXPERIMENTAL |
| 9 | help | 9 | help |
| @@ -57,4 +57,10 @@ config KGDB_TESTS_BOOT_STRING | |||
| 57 | information about other strings you could use beyond the | 57 | information about other strings you could use beyond the |
| 58 | default of V1F100. | 58 | default of V1F100. |
| 59 | 59 | ||
| 60 | config KGDB_KDB | ||
| 61 | bool "KGDB_KDB: include kdb frontend for kgdb" | ||
| 62 | default n | ||
| 63 | help | ||
| 64 | KDB frontend for kernel | ||
| 65 | |||
| 60 | endif # KGDB | 66 | endif # KGDB |
