diff options
Diffstat (limited to 'kernel/kgdb.c')
| -rw-r--r-- | kernel/kgdb.c | 205 |
1 files changed, 103 insertions, 102 deletions
diff --git a/kernel/kgdb.c b/kernel/kgdb.c index 761fdd2b3034..11f3515ca83f 100644 --- a/kernel/kgdb.c +++ b/kernel/kgdb.c | |||
| @@ -69,9 +69,16 @@ struct kgdb_state { | |||
| 69 | struct pt_regs *linux_regs; | 69 | struct pt_regs *linux_regs; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | /* Exception state values */ | ||
| 73 | #define DCPU_WANT_MASTER 0x1 /* Waiting to become a master kgdb cpu */ | ||
| 74 | #define DCPU_NEXT_MASTER 0x2 /* Transition from one master cpu to another */ | ||
| 75 | #define DCPU_IS_SLAVE 0x4 /* Slave cpu enter exception */ | ||
| 76 | #define DCPU_SSTEP 0x8 /* CPU is single stepping */ | ||
| 77 | |||
| 72 | static struct debuggerinfo_struct { | 78 | static struct debuggerinfo_struct { |
| 73 | void *debuggerinfo; | 79 | void *debuggerinfo; |
| 74 | struct task_struct *task; | 80 | struct task_struct *task; |
| 81 | int exception_state; | ||
| 75 | } kgdb_info[NR_CPUS]; | 82 | } kgdb_info[NR_CPUS]; |
| 76 | 83 | ||
| 77 | /** | 84 | /** |
| @@ -391,27 +398,22 @@ int kgdb_mem2hex(char *mem, char *buf, int count) | |||
| 391 | 398 | ||
| 392 | /* | 399 | /* |
| 393 | * Copy the binary array pointed to by buf into mem. Fix $, #, and | 400 | * Copy the binary array pointed to by buf into mem. Fix $, #, and |
| 394 | * 0x7d escaped with 0x7d. Return a pointer to the character after | 401 | * 0x7d escaped with 0x7d. Return -EFAULT on failure or 0 on success. |
| 395 | * the last byte written. | 402 | * The input buf is overwitten with the result to write to mem. |
| 396 | */ | 403 | */ |
| 397 | static int kgdb_ebin2mem(char *buf, char *mem, int count) | 404 | static int kgdb_ebin2mem(char *buf, char *mem, int count) |
| 398 | { | 405 | { |
| 399 | int err = 0; | 406 | int size = 0; |
| 400 | char c; | 407 | char *c = buf; |
| 401 | 408 | ||
| 402 | while (count-- > 0) { | 409 | while (count-- > 0) { |
| 403 | c = *buf++; | 410 | c[size] = *buf++; |
| 404 | if (c == 0x7d) | 411 | if (c[size] == 0x7d) |
| 405 | c = *buf++ ^ 0x20; | 412 | c[size] = *buf++ ^ 0x20; |
| 406 | 413 | size++; | |
| 407 | err = probe_kernel_write(mem, &c, 1); | ||
| 408 | if (err) | ||
| 409 | break; | ||
| 410 | |||
| 411 | mem++; | ||
| 412 | } | 414 | } |
| 413 | 415 | ||
| 414 | return err; | 416 | return probe_kernel_write(mem, c, size); |
| 415 | } | 417 | } |
| 416 | 418 | ||
| 417 | /* | 419 | /* |
| @@ -563,49 +565,6 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid) | |||
| 563 | } | 565 | } |
| 564 | 566 | ||
| 565 | /* | 567 | /* |
| 566 | * CPU debug state control: | ||
| 567 | */ | ||
| 568 | |||
| 569 | #ifdef CONFIG_SMP | ||
| 570 | static void kgdb_wait(struct pt_regs *regs) | ||
| 571 | { | ||
| 572 | unsigned long flags; | ||
| 573 | int cpu; | ||
| 574 | |||
| 575 | local_irq_save(flags); | ||
| 576 | cpu = raw_smp_processor_id(); | ||
| 577 | kgdb_info[cpu].debuggerinfo = regs; | ||
| 578 | kgdb_info[cpu].task = current; | ||
| 579 | /* | ||
| 580 | * Make sure the above info reaches the primary CPU before | ||
| 581 | * our cpu_in_kgdb[] flag setting does: | ||
| 582 | */ | ||
| 583 | smp_wmb(); | ||
| 584 | atomic_set(&cpu_in_kgdb[cpu], 1); | ||
| 585 | |||
| 586 | /* Disable any cpu specific hw breakpoints */ | ||
| 587 | kgdb_disable_hw_debug(regs); | ||
| 588 | |||
| 589 | /* Wait till primary CPU is done with debugging */ | ||
| 590 | while (atomic_read(&passive_cpu_wait[cpu])) | ||
| 591 | cpu_relax(); | ||
| 592 | |||
| 593 | kgdb_info[cpu].debuggerinfo = NULL; | ||
| 594 | kgdb_info[cpu].task = NULL; | ||
| 595 | |||
| 596 | /* fix up hardware debug registers on local cpu */ | ||
| 597 | if (arch_kgdb_ops.correct_hw_break) | ||
| 598 | arch_kgdb_ops.correct_hw_break(); | ||
| 599 | |||
| 600 | /* Signal the primary CPU that we are done: */ | ||
| 601 | atomic_set(&cpu_in_kgdb[cpu], 0); | ||
| 602 | touch_softlockup_watchdog_sync(); | ||
| 603 | clocksource_touch_watchdog(); | ||
| 604 | local_irq_restore(flags); | ||
| 605 | } | ||
| 606 | #endif | ||
| 607 | |||
| 608 | /* | ||
| 609 | * Some architectures need cache flushes when we set/clear a | 568 | * Some architectures need cache flushes when we set/clear a |
| 610 | * breakpoint: | 569 | * breakpoint: |
| 611 | */ | 570 | */ |
| @@ -1400,34 +1359,13 @@ static int kgdb_reenter_check(struct kgdb_state *ks) | |||
| 1400 | return 1; | 1359 | return 1; |
| 1401 | } | 1360 | } |
| 1402 | 1361 | ||
| 1403 | /* | 1362 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) |
| 1404 | * kgdb_handle_exception() - main entry point from a kernel exception | ||
| 1405 | * | ||
| 1406 | * Locking hierarchy: | ||
| 1407 | * interface locks, if any (begin_session) | ||
| 1408 | * kgdb lock (kgdb_active) | ||
| 1409 | */ | ||
| 1410 | int | ||
| 1411 | kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | ||
| 1412 | { | 1363 | { |
| 1413 | struct kgdb_state kgdb_var; | ||
| 1414 | struct kgdb_state *ks = &kgdb_var; | ||
| 1415 | unsigned long flags; | 1364 | unsigned long flags; |
| 1416 | int sstep_tries = 100; | 1365 | int sstep_tries = 100; |
| 1417 | int error = 0; | 1366 | int error = 0; |
| 1418 | int i, cpu; | 1367 | int i, cpu; |
| 1419 | 1368 | int trace_on = 0; | |
| 1420 | ks->cpu = raw_smp_processor_id(); | ||
| 1421 | ks->ex_vector = evector; | ||
| 1422 | ks->signo = signo; | ||
| 1423 | ks->ex_vector = evector; | ||
| 1424 | ks->err_code = ecode; | ||
| 1425 | ks->kgdb_usethreadid = 0; | ||
| 1426 | ks->linux_regs = regs; | ||
| 1427 | |||
| 1428 | if (kgdb_reenter_check(ks)) | ||
| 1429 | return 0; /* Ouch, double exception ! */ | ||
| 1430 | |||
| 1431 | acquirelock: | 1369 | acquirelock: |
| 1432 | /* | 1370 | /* |
| 1433 | * Interrupts will be restored by the 'trap return' code, except when | 1371 | * Interrupts will be restored by the 'trap return' code, except when |
| @@ -1435,13 +1373,43 @@ acquirelock: | |||
| 1435 | */ | 1373 | */ |
| 1436 | local_irq_save(flags); | 1374 | local_irq_save(flags); |
| 1437 | 1375 | ||
| 1438 | cpu = raw_smp_processor_id(); | 1376 | cpu = ks->cpu; |
| 1377 | kgdb_info[cpu].debuggerinfo = regs; | ||
| 1378 | kgdb_info[cpu].task = current; | ||
| 1379 | /* | ||
| 1380 | * Make sure the above info reaches the primary CPU before | ||
| 1381 | * our cpu_in_kgdb[] flag setting does: | ||
| 1382 | */ | ||
| 1383 | atomic_inc(&cpu_in_kgdb[cpu]); | ||
| 1439 | 1384 | ||
| 1440 | /* | 1385 | /* |
| 1441 | * Acquire the kgdb_active lock: | 1386 | * CPU will loop if it is a slave or request to become a kgdb |
| 1387 | * master cpu and acquire the kgdb_active lock: | ||
| 1442 | */ | 1388 | */ |
| 1443 | while (atomic_cmpxchg(&kgdb_active, -1, cpu) != -1) | 1389 | while (1) { |
| 1390 | if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | ||
| 1391 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) | ||
| 1392 | break; | ||
| 1393 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { | ||
| 1394 | if (!atomic_read(&passive_cpu_wait[cpu])) | ||
| 1395 | goto return_normal; | ||
| 1396 | } else { | ||
| 1397 | return_normal: | ||
| 1398 | /* Return to normal operation by executing any | ||
| 1399 | * hw breakpoint fixup. | ||
| 1400 | */ | ||
| 1401 | if (arch_kgdb_ops.correct_hw_break) | ||
| 1402 | arch_kgdb_ops.correct_hw_break(); | ||
| 1403 | if (trace_on) | ||
| 1404 | tracing_on(); | ||
| 1405 | atomic_dec(&cpu_in_kgdb[cpu]); | ||
| 1406 | touch_softlockup_watchdog_sync(); | ||
| 1407 | clocksource_touch_watchdog(); | ||
| 1408 | local_irq_restore(flags); | ||
| 1409 | return 0; | ||
| 1410 | } | ||
| 1444 | cpu_relax(); | 1411 | cpu_relax(); |
| 1412 | } | ||
| 1445 | 1413 | ||
| 1446 | /* | 1414 | /* |
| 1447 | * For single stepping, try to only enter on the processor | 1415 | * For single stepping, try to only enter on the processor |
| @@ -1475,9 +1443,6 @@ acquirelock: | |||
| 1475 | if (kgdb_io_ops->pre_exception) | 1443 | if (kgdb_io_ops->pre_exception) |
| 1476 | kgdb_io_ops->pre_exception(); | 1444 | kgdb_io_ops->pre_exception(); |
| 1477 | 1445 | ||
| 1478 | kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs; | ||
| 1479 | kgdb_info[ks->cpu].task = current; | ||
| 1480 | |||
| 1481 | kgdb_disable_hw_debug(ks->linux_regs); | 1446 | kgdb_disable_hw_debug(ks->linux_regs); |
| 1482 | 1447 | ||
| 1483 | /* | 1448 | /* |
| @@ -1486,15 +1451,9 @@ acquirelock: | |||
| 1486 | */ | 1451 | */ |
| 1487 | if (!kgdb_single_step) { | 1452 | if (!kgdb_single_step) { |
| 1488 | for (i = 0; i < NR_CPUS; i++) | 1453 | for (i = 0; i < NR_CPUS; i++) |
| 1489 | atomic_set(&passive_cpu_wait[i], 1); | 1454 | atomic_inc(&passive_cpu_wait[i]); |
| 1490 | } | 1455 | } |
| 1491 | 1456 | ||
| 1492 | /* | ||
| 1493 | * spin_lock code is good enough as a barrier so we don't | ||
| 1494 | * need one here: | ||
| 1495 | */ | ||
| 1496 | atomic_set(&cpu_in_kgdb[ks->cpu], 1); | ||
| 1497 | |||
| 1498 | #ifdef CONFIG_SMP | 1457 | #ifdef CONFIG_SMP |
| 1499 | /* Signal the other CPUs to enter kgdb_wait() */ | 1458 | /* Signal the other CPUs to enter kgdb_wait() */ |
| 1500 | if ((!kgdb_single_step) && kgdb_do_roundup) | 1459 | if ((!kgdb_single_step) && kgdb_do_roundup) |
| @@ -1518,6 +1477,9 @@ acquirelock: | |||
| 1518 | kgdb_single_step = 0; | 1477 | kgdb_single_step = 0; |
| 1519 | kgdb_contthread = current; | 1478 | kgdb_contthread = current; |
| 1520 | exception_level = 0; | 1479 | exception_level = 0; |
| 1480 | trace_on = tracing_is_on(); | ||
| 1481 | if (trace_on) | ||
| 1482 | tracing_off(); | ||
| 1521 | 1483 | ||
| 1522 | /* Talk to debugger with gdbserial protocol */ | 1484 | /* Talk to debugger with gdbserial protocol */ |
| 1523 | error = gdb_serial_stub(ks); | 1485 | error = gdb_serial_stub(ks); |
| @@ -1526,13 +1488,11 @@ acquirelock: | |||
| 1526 | if (kgdb_io_ops->post_exception) | 1488 | if (kgdb_io_ops->post_exception) |
| 1527 | kgdb_io_ops->post_exception(); | 1489 | kgdb_io_ops->post_exception(); |
| 1528 | 1490 | ||
| 1529 | kgdb_info[ks->cpu].debuggerinfo = NULL; | 1491 | atomic_dec(&cpu_in_kgdb[ks->cpu]); |
| 1530 | kgdb_info[ks->cpu].task = NULL; | ||
| 1531 | atomic_set(&cpu_in_kgdb[ks->cpu], 0); | ||
| 1532 | 1492 | ||
| 1533 | if (!kgdb_single_step) { | 1493 | if (!kgdb_single_step) { |
| 1534 | for (i = NR_CPUS-1; i >= 0; i--) | 1494 | for (i = NR_CPUS-1; i >= 0; i--) |
| 1535 | atomic_set(&passive_cpu_wait[i], 0); | 1495 | atomic_dec(&passive_cpu_wait[i]); |
| 1536 | /* | 1496 | /* |
| 1537 | * Wait till all the CPUs have quit | 1497 | * Wait till all the CPUs have quit |
| 1538 | * from the debugger. | 1498 | * from the debugger. |
| @@ -1551,6 +1511,8 @@ kgdb_restore: | |||
| 1551 | else | 1511 | else |
| 1552 | kgdb_sstep_pid = 0; | 1512 | kgdb_sstep_pid = 0; |
| 1553 | } | 1513 | } |
| 1514 | if (trace_on) | ||
| 1515 | tracing_on(); | ||
| 1554 | /* Free kgdb_active */ | 1516 | /* Free kgdb_active */ |
| 1555 | atomic_set(&kgdb_active, -1); | 1517 | atomic_set(&kgdb_active, -1); |
| 1556 | touch_softlockup_watchdog_sync(); | 1518 | touch_softlockup_watchdog_sync(); |
| @@ -1560,13 +1522,52 @@ kgdb_restore: | |||
| 1560 | return error; | 1522 | return error; |
| 1561 | } | 1523 | } |
| 1562 | 1524 | ||
| 1525 | /* | ||
| 1526 | * kgdb_handle_exception() - main entry point from a kernel exception | ||
| 1527 | * | ||
| 1528 | * Locking hierarchy: | ||
| 1529 | * interface locks, if any (begin_session) | ||
| 1530 | * kgdb lock (kgdb_active) | ||
| 1531 | */ | ||
| 1532 | int | ||
| 1533 | kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | ||
| 1534 | { | ||
| 1535 | struct kgdb_state kgdb_var; | ||
| 1536 | struct kgdb_state *ks = &kgdb_var; | ||
| 1537 | int ret; | ||
| 1538 | |||
| 1539 | ks->cpu = raw_smp_processor_id(); | ||
| 1540 | ks->ex_vector = evector; | ||
| 1541 | ks->signo = signo; | ||
| 1542 | ks->ex_vector = evector; | ||
| 1543 | ks->err_code = ecode; | ||
| 1544 | ks->kgdb_usethreadid = 0; | ||
| 1545 | ks->linux_regs = regs; | ||
| 1546 | |||
| 1547 | if (kgdb_reenter_check(ks)) | ||
| 1548 | return 0; /* Ouch, double exception ! */ | ||
| 1549 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | ||
| 1550 | ret = kgdb_cpu_enter(ks, regs); | ||
| 1551 | kgdb_info[ks->cpu].exception_state &= ~DCPU_WANT_MASTER; | ||
| 1552 | return ret; | ||
| 1553 | } | ||
| 1554 | |||
| 1563 | int kgdb_nmicallback(int cpu, void *regs) | 1555 | int kgdb_nmicallback(int cpu, void *regs) |
| 1564 | { | 1556 | { |
| 1565 | #ifdef CONFIG_SMP | 1557 | #ifdef CONFIG_SMP |
| 1558 | struct kgdb_state kgdb_var; | ||
| 1559 | struct kgdb_state *ks = &kgdb_var; | ||
| 1560 | |||
| 1561 | memset(ks, 0, sizeof(struct kgdb_state)); | ||
| 1562 | ks->cpu = cpu; | ||
| 1563 | ks->linux_regs = regs; | ||
| 1564 | |||
| 1566 | if (!atomic_read(&cpu_in_kgdb[cpu]) && | 1565 | if (!atomic_read(&cpu_in_kgdb[cpu]) && |
| 1567 | atomic_read(&kgdb_active) != cpu && | 1566 | atomic_read(&kgdb_active) != -1 && |
| 1568 | atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) { | 1567 | atomic_read(&kgdb_active) != cpu) { |
| 1569 | kgdb_wait((struct pt_regs *)regs); | 1568 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; |
| 1569 | kgdb_cpu_enter(ks, regs); | ||
| 1570 | kgdb_info[cpu].exception_state &= ~DCPU_IS_SLAVE; | ||
| 1570 | return 0; | 1571 | return 0; |
| 1571 | } | 1572 | } |
| 1572 | #endif | 1573 | #endif |
| @@ -1742,11 +1743,11 @@ EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); | |||
| 1742 | */ | 1743 | */ |
| 1743 | void kgdb_breakpoint(void) | 1744 | void kgdb_breakpoint(void) |
| 1744 | { | 1745 | { |
| 1745 | atomic_set(&kgdb_setting_breakpoint, 1); | 1746 | atomic_inc(&kgdb_setting_breakpoint); |
| 1746 | wmb(); /* Sync point before breakpoint */ | 1747 | wmb(); /* Sync point before breakpoint */ |
| 1747 | arch_kgdb_breakpoint(); | 1748 | arch_kgdb_breakpoint(); |
| 1748 | wmb(); /* Sync point after breakpoint */ | 1749 | wmb(); /* Sync point after breakpoint */ |
| 1749 | atomic_set(&kgdb_setting_breakpoint, 0); | 1750 | atomic_dec(&kgdb_setting_breakpoint); |
| 1750 | } | 1751 | } |
| 1751 | EXPORT_SYMBOL_GPL(kgdb_breakpoint); | 1752 | EXPORT_SYMBOL_GPL(kgdb_breakpoint); |
| 1752 | 1753 | ||
