diff options
Diffstat (limited to 'kernel/kgdb.c')
| -rw-r--r-- | kernel/kgdb.c | 58 |
1 files changed, 41 insertions, 17 deletions
diff --git a/kernel/kgdb.c b/kernel/kgdb.c index 9147a3190c9d..2eb517e23514 100644 --- a/kernel/kgdb.c +++ b/kernel/kgdb.c | |||
| @@ -129,6 +129,7 @@ struct task_struct *kgdb_usethread; | |||
| 129 | struct task_struct *kgdb_contthread; | 129 | struct task_struct *kgdb_contthread; |
| 130 | 130 | ||
| 131 | int kgdb_single_step; | 131 | int kgdb_single_step; |
| 132 | pid_t kgdb_sstep_pid; | ||
| 132 | 133 | ||
| 133 | /* Our I/O buffers. */ | 134 | /* Our I/O buffers. */ |
| 134 | static char remcom_in_buffer[BUFMAX]; | 135 | static char remcom_in_buffer[BUFMAX]; |
| @@ -541,12 +542,17 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid) | |||
| 541 | */ | 542 | */ |
| 542 | if (tid == 0 || tid == -1) | 543 | if (tid == 0 || tid == -1) |
| 543 | tid = -atomic_read(&kgdb_active) - 2; | 544 | tid = -atomic_read(&kgdb_active) - 2; |
| 544 | if (tid < 0) { | 545 | if (tid < -1 && tid > -NR_CPUS - 2) { |
| 545 | if (kgdb_info[-tid - 2].task) | 546 | if (kgdb_info[-tid - 2].task) |
| 546 | return kgdb_info[-tid - 2].task; | 547 | return kgdb_info[-tid - 2].task; |
| 547 | else | 548 | else |
| 548 | return idle_task(-tid - 2); | 549 | return idle_task(-tid - 2); |
| 549 | } | 550 | } |
| 551 | if (tid <= 0) { | ||
| 552 | printk(KERN_ERR "KGDB: Internal thread select error\n"); | ||
| 553 | dump_stack(); | ||
| 554 | return NULL; | ||
| 555 | } | ||
| 550 | 556 | ||
| 551 | /* | 557 | /* |
| 552 | * find_task_by_pid_ns() does not take the tasklist lock anymore | 558 | * find_task_by_pid_ns() does not take the tasklist lock anymore |
| @@ -619,7 +625,8 @@ static void kgdb_flush_swbreak_addr(unsigned long addr) | |||
| 619 | static int kgdb_activate_sw_breakpoints(void) | 625 | static int kgdb_activate_sw_breakpoints(void) |
| 620 | { | 626 | { |
| 621 | unsigned long addr; | 627 | unsigned long addr; |
| 622 | int error = 0; | 628 | int error; |
| 629 | int ret = 0; | ||
| 623 | int i; | 630 | int i; |
| 624 | 631 | ||
| 625 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { | 632 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { |
| @@ -629,13 +636,16 @@ static int kgdb_activate_sw_breakpoints(void) | |||
| 629 | addr = kgdb_break[i].bpt_addr; | 636 | addr = kgdb_break[i].bpt_addr; |
| 630 | error = kgdb_arch_set_breakpoint(addr, | 637 | error = kgdb_arch_set_breakpoint(addr, |
| 631 | kgdb_break[i].saved_instr); | 638 | kgdb_break[i].saved_instr); |
| 632 | if (error) | 639 | if (error) { |
| 633 | return error; | 640 | ret = error; |
| 641 | printk(KERN_INFO "KGDB: BP install failed: %lx", addr); | ||
| 642 | continue; | ||
| 643 | } | ||
| 634 | 644 | ||
| 635 | kgdb_flush_swbreak_addr(addr); | 645 | kgdb_flush_swbreak_addr(addr); |
| 636 | kgdb_break[i].state = BP_ACTIVE; | 646 | kgdb_break[i].state = BP_ACTIVE; |
| 637 | } | 647 | } |
| 638 | return 0; | 648 | return ret; |
| 639 | } | 649 | } |
| 640 | 650 | ||
| 641 | static int kgdb_set_sw_break(unsigned long addr) | 651 | static int kgdb_set_sw_break(unsigned long addr) |
| @@ -682,7 +692,8 @@ static int kgdb_set_sw_break(unsigned long addr) | |||
| 682 | static int kgdb_deactivate_sw_breakpoints(void) | 692 | static int kgdb_deactivate_sw_breakpoints(void) |
| 683 | { | 693 | { |
| 684 | unsigned long addr; | 694 | unsigned long addr; |
| 685 | int error = 0; | 695 | int error; |
| 696 | int ret = 0; | ||
| 686 | int i; | 697 | int i; |
| 687 | 698 | ||
| 688 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { | 699 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { |
| @@ -691,13 +702,15 @@ static int kgdb_deactivate_sw_breakpoints(void) | |||
| 691 | addr = kgdb_break[i].bpt_addr; | 702 | addr = kgdb_break[i].bpt_addr; |
| 692 | error = kgdb_arch_remove_breakpoint(addr, | 703 | error = kgdb_arch_remove_breakpoint(addr, |
| 693 | kgdb_break[i].saved_instr); | 704 | kgdb_break[i].saved_instr); |
| 694 | if (error) | 705 | if (error) { |
| 695 | return error; | 706 | printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr); |
| 707 | ret = error; | ||
| 708 | } | ||
| 696 | 709 | ||
| 697 | kgdb_flush_swbreak_addr(addr); | 710 | kgdb_flush_swbreak_addr(addr); |
| 698 | kgdb_break[i].state = BP_SET; | 711 | kgdb_break[i].state = BP_SET; |
| 699 | } | 712 | } |
| 700 | return 0; | 713 | return ret; |
| 701 | } | 714 | } |
| 702 | 715 | ||
| 703 | static int kgdb_remove_sw_break(unsigned long addr) | 716 | static int kgdb_remove_sw_break(unsigned long addr) |
| @@ -870,7 +883,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks) | |||
| 870 | 883 | ||
| 871 | /* | 884 | /* |
| 872 | * All threads that don't have debuggerinfo should be | 885 | * All threads that don't have debuggerinfo should be |
| 873 | * in __schedule() sleeping, since all other CPUs | 886 | * in schedule() sleeping, since all other CPUs |
| 874 | * are in kgdb_wait, and thus have debuggerinfo. | 887 | * are in kgdb_wait, and thus have debuggerinfo. |
| 875 | */ | 888 | */ |
| 876 | if (local_debuggerinfo) { | 889 | if (local_debuggerinfo) { |
| @@ -1204,8 +1217,10 @@ static int gdb_cmd_exception_pass(struct kgdb_state *ks) | |||
| 1204 | return 1; | 1217 | return 1; |
| 1205 | 1218 | ||
| 1206 | } else { | 1219 | } else { |
| 1207 | error_packet(remcom_out_buffer, -EINVAL); | 1220 | kgdb_msg_write("KGDB only knows signal 9 (pass)" |
| 1208 | return 0; | 1221 | " and 15 (pass and disconnect)\n" |
| 1222 | "Executing a continue without signal passing\n", 0); | ||
| 1223 | remcom_in_buffer[0] = 'c'; | ||
| 1209 | } | 1224 | } |
| 1210 | 1225 | ||
| 1211 | /* Indicate fall through */ | 1226 | /* Indicate fall through */ |
| @@ -1395,6 +1410,7 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 1395 | struct kgdb_state kgdb_var; | 1410 | struct kgdb_state kgdb_var; |
| 1396 | struct kgdb_state *ks = &kgdb_var; | 1411 | struct kgdb_state *ks = &kgdb_var; |
| 1397 | unsigned long flags; | 1412 | unsigned long flags; |
| 1413 | int sstep_tries = 100; | ||
| 1398 | int error = 0; | 1414 | int error = 0; |
| 1399 | int i, cpu; | 1415 | int i, cpu; |
| 1400 | 1416 | ||
| @@ -1425,13 +1441,14 @@ acquirelock: | |||
| 1425 | cpu_relax(); | 1441 | cpu_relax(); |
| 1426 | 1442 | ||
| 1427 | /* | 1443 | /* |
| 1428 | * Do not start the debugger connection on this CPU if the last | 1444 | * For single stepping, try to only enter on the processor |
| 1429 | * instance of the exception handler wanted to come into the | 1445 | * that was single stepping. To gaurd against a deadlock, the |
| 1430 | * debugger on a different CPU via a single step | 1446 | * kernel will only try for the value of sstep_tries before |
| 1447 | * giving up and continuing on. | ||
| 1431 | */ | 1448 | */ |
| 1432 | if (atomic_read(&kgdb_cpu_doing_single_step) != -1 && | 1449 | if (atomic_read(&kgdb_cpu_doing_single_step) != -1 && |
| 1433 | atomic_read(&kgdb_cpu_doing_single_step) != cpu) { | 1450 | (kgdb_info[cpu].task && |
| 1434 | 1451 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { | |
| 1435 | atomic_set(&kgdb_active, -1); | 1452 | atomic_set(&kgdb_active, -1); |
| 1436 | touch_softlockup_watchdog(); | 1453 | touch_softlockup_watchdog(); |
| 1437 | clocksource_touch_watchdog(); | 1454 | clocksource_touch_watchdog(); |
| @@ -1524,6 +1541,13 @@ acquirelock: | |||
| 1524 | } | 1541 | } |
| 1525 | 1542 | ||
| 1526 | kgdb_restore: | 1543 | kgdb_restore: |
| 1544 | if (atomic_read(&kgdb_cpu_doing_single_step) != -1) { | ||
| 1545 | int sstep_cpu = atomic_read(&kgdb_cpu_doing_single_step); | ||
| 1546 | if (kgdb_info[sstep_cpu].task) | ||
| 1547 | kgdb_sstep_pid = kgdb_info[sstep_cpu].task->pid; | ||
| 1548 | else | ||
| 1549 | kgdb_sstep_pid = 0; | ||
| 1550 | } | ||
| 1527 | /* Free kgdb_active */ | 1551 | /* Free kgdb_active */ |
| 1528 | atomic_set(&kgdb_active, -1); | 1552 | atomic_set(&kgdb_active, -1); |
| 1529 | touch_softlockup_watchdog(); | 1553 | touch_softlockup_watchdog(); |
