aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/kgdb.c60
-rw-r--r--drivers/misc/kgdbts.c17
-rw-r--r--include/linux/kgdb.h3
3 files changed, 62 insertions, 18 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index fdc37b3d0ce3..b9bd9d8de665 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -43,6 +43,8 @@
43#include <linux/smp.h> 43#include <linux/smp.h>
44#include <linux/nmi.h> 44#include <linux/nmi.h>
45#include <linux/hw_breakpoint.h> 45#include <linux/hw_breakpoint.h>
46#include <linux/uaccess.h>
47#include <linux/memory.h>
46 48
47#include <asm/debugreg.h> 49#include <asm/debugreg.h>
48#include <asm/apicdef.h> 50#include <asm/apicdef.h>
@@ -742,6 +744,64 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
742 regs->ip = ip; 744 regs->ip = ip;
743} 745}
744 746
747int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
748{
749 int err;
750 char opc[BREAK_INSTR_SIZE];
751
752 bpt->type = BP_BREAKPOINT;
753 err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
754 BREAK_INSTR_SIZE);
755 if (err)
756 return err;
757 err = probe_kernel_write((char *)bpt->bpt_addr,
758 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
759#ifdef CONFIG_DEBUG_RODATA
760 if (!err)
761 return err;
762 /*
763 * It is safe to call text_poke() because normal kernel execution
764 * is stopped on all cores, so long as the text_mutex is not locked.
765 */
766 if (mutex_is_locked(&text_mutex))
767 return -EBUSY;
768 text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr,
769 BREAK_INSTR_SIZE);
770 err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
771 if (err)
772 return err;
773 if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE))
774 return -EINVAL;
775 bpt->type = BP_POKE_BREAKPOINT;
776#endif /* CONFIG_DEBUG_RODATA */
777 return err;
778}
779
780int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
781{
782#ifdef CONFIG_DEBUG_RODATA
783 int err;
784 char opc[BREAK_INSTR_SIZE];
785
786 if (bpt->type != BP_POKE_BREAKPOINT)
787 goto knl_write;
788 /*
789 * It is safe to call text_poke() because normal kernel execution
790 * is stopped on all cores, so long as the text_mutex is not locked.
791 */
792 if (mutex_is_locked(&text_mutex))
793 goto knl_write;
794 text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE);
795 err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
796 if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE))
797 goto knl_write;
798 return err;
799knl_write:
800#endif /* CONFIG_DEBUG_RODATA */
801 return probe_kernel_write((char *)bpt->bpt_addr,
802 (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
803}
804
745struct kgdb_arch arch_kgdb_ops = { 805struct kgdb_arch arch_kgdb_ops = {
746 /* Breakpoint instruction: */ 806 /* Breakpoint instruction: */
747 .gdb_bpt_instr = { 0xcc }, 807 .gdb_bpt_instr = { 0xcc },
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index d087456ba089..3aa9a969b373 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -968,22 +968,6 @@ static void run_singlestep_break_test(void)
968 kgdbts_break_test(); 968 kgdbts_break_test();
969} 969}
970 970
971static void test_debug_rodata(void)
972{
973#ifdef CONFIG_DEBUG_RODATA
974 /* Until there is an api to write to read-only text segments, use
975 * HW breakpoints for the remainder of any tests, else print a
976 * failure message if hw breakpoints do not work.
977 */
978 if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) {
979 eprintk("kgdbts: HW breakpoints BROKEN, ending tests\n");
980 return;
981 }
982 force_hwbrks = 1;
983 v1printk("kgdbts:Using HW breakpoints for SW breakpoint tests\n");
984#endif /* CONFIG_DEBUG_RODATA */
985}
986
987static void kgdbts_run_tests(void) 971static void kgdbts_run_tests(void)
988{ 972{
989 char *ptr; 973 char *ptr;
@@ -1016,7 +1000,6 @@ static void kgdbts_run_tests(void)
1016 v1printk("kgdbts:RUN access write breakpoint test\n"); 1000 v1printk("kgdbts:RUN access write breakpoint test\n");
1017 run_hw_break_test(0); 1001 run_hw_break_test(0);
1018 } 1002 }
1019 test_debug_rodata();
1020 1003
1021 /* required internal KGDB tests */ 1004 /* required internal KGDB tests */
1022 v1printk("kgdbts:RUN plant and detach test\n"); 1005 v1printk("kgdbts:RUN plant and detach test\n");
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index e5d689c1d774..c4d2fc194ede 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -63,7 +63,8 @@ enum kgdb_bptype {
63 BP_HARDWARE_BREAKPOINT, 63 BP_HARDWARE_BREAKPOINT,
64 BP_WRITE_WATCHPOINT, 64 BP_WRITE_WATCHPOINT,
65 BP_READ_WATCHPOINT, 65 BP_READ_WATCHPOINT,
66 BP_ACCESS_WATCHPOINT 66 BP_ACCESS_WATCHPOINT,
67 BP_POKE_BREAKPOINT,
67}; 68};
68 69
69enum kgdb_bpstate { 70enum kgdb_bpstate {