From: Greg Kroah-Hartman Date: Thu, 5 Apr 2012 17:34:47 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.3.2~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=44523b877719b26f207165c87fc911b7a7de9866;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch kgdbts-fix-kernel-oops-with-config_debug_rodata.patch x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch --- diff --git a/queue-3.0/kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch b/queue-3.0/kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch new file mode 100644 index 00000000000..7fb9bb7233a --- /dev/null +++ b/queue-3.0/kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch @@ -0,0 +1,175 @@ +From 98b54aa1a2241b59372468bd1e9c2d207bdba54b Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Wed, 21 Mar 2012 10:17:03 -0500 +Subject: kgdb,debug_core: pass the breakpoint struct instead of address and memory + +From: Jason Wessel + +commit 98b54aa1a2241b59372468bd1e9c2d207bdba54b upstream. + +There is extra state information that needs to be exposed in the +kgdb_bpt structure for tracking how a breakpoint was installed. The +debug_core only uses the the probe_kernel_write() to install +breakpoints, but this is not enough for all the archs. Some arch such +as x86 need to use text_poke() in order to install a breakpoint into a +read only page. + +Passing the kgdb_bpt structure to kgdb_arch_set_breakpoint() and +kgdb_arch_remove_breakpoint() allows other archs to set the type +variable which indicates how the breakpoint was installed. + +Signed-off-by: Jason Wessel +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/kgdb.h | 4 +-- + kernel/debug/debug_core.c | 53 ++++++++++++++++++++-------------------------- + 2 files changed, 26 insertions(+), 31 deletions(-) + +--- a/include/linux/kgdb.h ++++ b/include/linux/kgdb.h +@@ -207,8 +207,8 @@ extern void kgdb_arch_set_pc(struct pt_r + + /* Optional functions. */ + extern int kgdb_validate_break_address(unsigned long addr); +-extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); +-extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); ++extern int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt); ++extern int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt); + + /** + * kgdb_arch_late - Perform any architecture specific initalization. +--- a/kernel/debug/debug_core.c ++++ b/kernel/debug/debug_core.c +@@ -157,37 +157,39 @@ early_param("nokgdbroundup", opt_nokgdbr + * Weak aliases for breakpoint management, + * can be overriden by architectures when needed: + */ +-int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) ++int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) + { + int err; + +- err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE); ++ err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, ++ BREAK_INSTR_SIZE); + if (err) + return err; +- +- return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr, +- BREAK_INSTR_SIZE); ++ err = probe_kernel_write((char *)bpt->bpt_addr, ++ arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); ++ return err; + } + +-int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) ++int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) + { +- return probe_kernel_write((char *)addr, +- (char *)bundle, BREAK_INSTR_SIZE); ++ return probe_kernel_write((char *)bpt->bpt_addr, ++ (char *)bpt->saved_instr, BREAK_INSTR_SIZE); + } + + int __weak kgdb_validate_break_address(unsigned long addr) + { +- char tmp_variable[BREAK_INSTR_SIZE]; ++ struct kgdb_bkpt tmp; + int err; +- /* Validate setting the breakpoint and then removing it. In the ++ /* Validate setting the breakpoint and then removing it. If the + * remove fails, the kernel needs to emit a bad message because we + * are deep trouble not being able to put things back the way we + * found them. + */ +- err = kgdb_arch_set_breakpoint(addr, tmp_variable); ++ tmp.bpt_addr = addr; ++ err = kgdb_arch_set_breakpoint(&tmp); + if (err) + return err; +- err = kgdb_arch_remove_breakpoint(addr, tmp_variable); ++ err = kgdb_arch_remove_breakpoint(&tmp); + if (err) + printk(KERN_ERR "KGDB: Critical breakpoint error, kernel " + "memory destroyed at: %lx", addr); +@@ -231,7 +233,6 @@ static void kgdb_flush_swbreak_addr(unsi + */ + int dbg_activate_sw_breakpoints(void) + { +- unsigned long addr; + int error; + int ret = 0; + int i; +@@ -240,16 +241,15 @@ int dbg_activate_sw_breakpoints(void) + if (kgdb_break[i].state != BP_SET) + continue; + +- addr = kgdb_break[i].bpt_addr; +- error = kgdb_arch_set_breakpoint(addr, +- kgdb_break[i].saved_instr); ++ error = kgdb_arch_set_breakpoint(&kgdb_break[i]); + if (error) { + ret = error; +- printk(KERN_INFO "KGDB: BP install failed: %lx", addr); ++ printk(KERN_INFO "KGDB: BP install failed: %lx", ++ kgdb_break[i].bpt_addr); + continue; + } + +- kgdb_flush_swbreak_addr(addr); ++ kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr); + kgdb_break[i].state = BP_ACTIVE; + } + return ret; +@@ -298,7 +298,6 @@ int dbg_set_sw_break(unsigned long addr) + + int dbg_deactivate_sw_breakpoints(void) + { +- unsigned long addr; + int error; + int ret = 0; + int i; +@@ -306,15 +305,14 @@ int dbg_deactivate_sw_breakpoints(void) + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != BP_ACTIVE) + continue; +- addr = kgdb_break[i].bpt_addr; +- error = kgdb_arch_remove_breakpoint(addr, +- kgdb_break[i].saved_instr); ++ error = kgdb_arch_remove_breakpoint(&kgdb_break[i]); + if (error) { +- printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr); ++ printk(KERN_INFO "KGDB: BP remove failed: %lx\n", ++ kgdb_break[i].bpt_addr); + ret = error; + } + +- kgdb_flush_swbreak_addr(addr); ++ kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr); + kgdb_break[i].state = BP_SET; + } + return ret; +@@ -348,7 +346,6 @@ int kgdb_isremovedbreak(unsigned long ad + + int dbg_remove_all_break(void) + { +- unsigned long addr; + int error; + int i; + +@@ -356,12 +353,10 @@ int dbg_remove_all_break(void) + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state != BP_ACTIVE) + goto setundefined; +- addr = kgdb_break[i].bpt_addr; +- error = kgdb_arch_remove_breakpoint(addr, +- kgdb_break[i].saved_instr); ++ error = kgdb_arch_remove_breakpoint(&kgdb_break[i]); + if (error) + printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n", +- addr); ++ kgdb_break[i].bpt_addr); + setundefined: + kgdb_break[i].state = BP_UNDEFINED; + } diff --git a/queue-3.0/kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch b/queue-3.0/kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch new file mode 100644 index 00000000000..989eee949b3 --- /dev/null +++ b/queue-3.0/kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch @@ -0,0 +1,209 @@ +From 486c5987a00a89d56c2c04c506417ef8f823ca2e Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Thu, 29 Mar 2012 17:41:24 -0500 +Subject: kgdbts: (1 of 2) fix single step awareness to work correctly with SMP + +From: Jason Wessel + +commit 486c5987a00a89d56c2c04c506417ef8f823ca2e upstream. + +The do_fork and sys_open tests have never worked properly on anything +other than a UP configuration with the kgdb test suite. This is +because the test suite did not fully implement the behavior of a real +debugger. A real debugger tracks the state of what thread it asked to +single step and can correctly continue other threads of execution or +conditionally stop while waiting for the original thread single step +request to return. + +Below is a simple method to cause a fatal kernel oops with the kgdb +test suite on a 4 processor x86 system: + +while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& +while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& +while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& +while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& +echo V1I1F1000 > /sys/module/kgdbts/parameters/kgdbts + +Very soon after starting the test the kernel will oops with a message like: + +kgdbts: BP mismatch 3b7da66480 expected ffffffff8106a590 +WARNING: at drivers/misc/kgdbts.c:303 check_and_rewind_pc+0xe0/0x100() +Call Trace: + [] check_and_rewind_pc+0xe0/0x100 + [] validate_simple_test+0x25/0xc0 + [] run_simple_test+0x107/0x2c0 + [] kgdbts_put_char+0x18/0x20 + +The warn will turn to a hard kernel crash shortly after that because +the pc will not get properly rewound to the right value after hitting +a breakpoint leading to a hard lockup. + +This change is broken up into 2 pieces because archs that have hw +single stepping (2.6.26 and up) need different changes than archs that +do not have hw single stepping (3.0 and up). This change implements +the correct behavior for an arch that supports hw single stepping. + +A minor defect was fixed where sys_open should be do_sys_open +for the sys_open break point test. This solves the problem of running +a 64 bit with a 32 bit user space. The sys_open() never gets called +when using the 32 bit file system for the kgdb testsuite because the +32 bit binaries invoke the compat_sys_open() call leading to the test +never completing. + +In order to mimic a real debugger, the kgdb test suite now tracks the +most recent thread that was continued (cont_thread_id), with the +intent to single step just this thread. When the response to the +single step request stops in a different thread that hit the original +break point that thread will now get continued, while the debugger +waits for the thread with the single step pending. Here is a high +level description of the sequence of events. + + cont_instead_of_sstep = 0; + +1) set breakpoint at do_fork +2) continue +3) Save the thread id where we stop to cont_thread_id +4) Remove breakpoint at do_fork +5) Reset the PC if needed depending on kernel exception type +6) if (cont_instead_of_sstep) { continue } else { single step } +7) Check where we stopped + if current thread != cont_thread_id { + cont_instead_of_sstep = 1; + goto step 5 + } else { + cont_instead_of_sstep = 0; + } +8) clean up and run test again if needed + +Signed-off-by: Jason Wessel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/kgdbts.c | 54 +++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 43 insertions(+), 11 deletions(-) + +--- a/drivers/misc/kgdbts.c ++++ b/drivers/misc/kgdbts.c +@@ -133,6 +133,9 @@ static int force_hwbrks; + static int hwbreaks_ok; + static int hw_break_val; + static int hw_break_val2; ++static int cont_instead_of_sstep; ++static unsigned long cont_thread_id; ++static unsigned long sstep_thread_id; + #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) + static int arch_needs_sstep_emulation = 1; + #else +@@ -210,7 +213,7 @@ static unsigned long lookup_addr(char *a + if (!strcmp(arg, "kgdbts_break_test")) + addr = (unsigned long)kgdbts_break_test; + else if (!strcmp(arg, "sys_open")) +- addr = (unsigned long)sys_open; ++ addr = (unsigned long)do_sys_open; + else if (!strcmp(arg, "do_fork")) + addr = (unsigned long)do_fork; + else if (!strcmp(arg, "hw_break_val")) +@@ -282,6 +285,16 @@ static void hw_break_val_write(void) + hw_break_val++; + } + ++static int get_thread_id_continue(char *put_str, char *arg) ++{ ++ char *ptr = &put_str[11]; ++ ++ if (put_str[1] != 'T' || put_str[2] != '0') ++ return 1; ++ kgdb_hex2long(&ptr, &cont_thread_id); ++ return 0; ++} ++ + static int check_and_rewind_pc(char *put_str, char *arg) + { + unsigned long addr = lookup_addr(arg); +@@ -323,6 +336,18 @@ static int check_single_step(char *put_s + gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); + v2printk("Singlestep stopped at IP: %lx\n", + instruction_pointer(&kgdbts_regs)); ++ ++ if (sstep_thread_id != cont_thread_id && !arch_needs_sstep_emulation) { ++ /* ++ * Ensure we stopped in the same thread id as before, else the ++ * debugger should continue until the original thread that was ++ * single stepped is scheduled again, emulating gdb's behavior. ++ */ ++ v2printk("ThrID does not match: %lx\n", cont_thread_id); ++ cont_instead_of_sstep = 1; ++ ts.idx -= 4; ++ return 0; ++ } + if (instruction_pointer(&kgdbts_regs) == addr) { + eprintk("kgdbts: SingleStep failed at %lx\n", + instruction_pointer(&kgdbts_regs)); +@@ -367,7 +392,12 @@ static int got_break(char *put_str, char + static void emul_sstep_get(char *arg) + { + if (!arch_needs_sstep_emulation) { +- fill_get_buf(arg); ++ if (cont_instead_of_sstep) { ++ cont_instead_of_sstep = 0; ++ fill_get_buf("c"); ++ } else { ++ fill_get_buf(arg); ++ } + return; + } + switch (sstep_state) { +@@ -397,9 +427,11 @@ static void emul_sstep_get(char *arg) + static int emul_sstep_put(char *put_str, char *arg) + { + if (!arch_needs_sstep_emulation) { +- if (!strncmp(put_str+1, arg, 2)) +- return 0; +- return 1; ++ char *ptr = &put_str[11]; ++ if (put_str[1] != 'T' || put_str[2] != '0') ++ return 1; ++ kgdb_hex2long(&ptr, &sstep_thread_id); ++ return 0; + } + switch (sstep_state) { + case 1: +@@ -501,10 +533,10 @@ static struct test_struct bad_read_test[ + static struct test_struct singlestep_break_test[] = { + { "?", "S0*" }, /* Clear break points */ + { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ +- { "c", "T0*", }, /* Continue */ ++ { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ ++ { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, + { "write", "OK", write_regs }, /* Write registers */ +- { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ + { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ + { "g", "kgdbts_break_test", NULL, check_single_step }, + { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ +@@ -522,10 +554,10 @@ static struct test_struct singlestep_bre + static struct test_struct do_fork_test[] = { + { "?", "S0*" }, /* Clear break points */ + { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ +- { "c", "T0*", }, /* Continue */ ++ { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ ++ { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */ + { "write", "OK", write_regs }, /* Write registers */ +- { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ + { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ + { "g", "do_fork", NULL, check_single_step }, + { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ +@@ -540,10 +572,10 @@ static struct test_struct do_fork_test[] + static struct test_struct sys_open_test[] = { + { "?", "S0*" }, /* Clear break points */ + { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ +- { "c", "T0*", }, /* Continue */ ++ { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ ++ { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ + { "write", "OK", write_regs }, /* Write registers */ +- { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ + { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ + { "g", "sys_open", NULL, check_single_step }, + { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ diff --git a/queue-3.0/kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch b/queue-3.0/kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch new file mode 100644 index 00000000000..e6150e9f551 --- /dev/null +++ b/queue-3.0/kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch @@ -0,0 +1,263 @@ +From 23bbd8e346f1ef3fc1219c79cea53d8d52b207d8 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Thu, 29 Mar 2012 17:41:24 -0500 +Subject: kgdbts: (2 of 2) fix single step awareness to work correctly with SMP + +From: Jason Wessel + +commit 23bbd8e346f1ef3fc1219c79cea53d8d52b207d8 upstream. + +The do_fork and sys_open tests have never worked properly on anything +other than a UP configuration with the kgdb test suite. This is +because the test suite did not fully implement the behavior of a real +debugger. A real debugger tracks the state of what thread it asked to +single step and can correctly continue other threads of execution or +conditionally stop while waiting for the original thread single step +request to return. + +Below is a simple method to cause a fatal kernel oops with the kgdb +test suite on a 2 processor ARM system: + +while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& +while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& +echo V1I1F100 > /sys/module/kgdbts/parameters/kgdbts + +Very soon after starting the test the kernel will start warning with +messages like: + +kgdbts: BP mismatch c002487c expected c0024878 +------------[ cut here ]------------ +WARNING: at drivers/misc/kgdbts.c:317 check_and_rewind_pc+0x9c/0xc4() +[] (check_and_rewind_pc+0x9c/0xc4) +[] (validate_simple_test+0x3c/0xc4) +[] (run_simple_test+0x1e8/0x274) + +The kernel will eventually recovers, but the test suite has completely +failed to test anything useful. + +This patch implements behavior similar to a real debugger that does +not rely on hardware single stepping by using only software planted +breakpoints. + +In order to mimic a real debugger, the kgdb test suite now tracks the +most recent thread that was continued (cont_thread_id), with the +intent to single step just this thread. When the response to the +single step request stops in a different thread that hit the original +break point that thread will now get continued, while the debugger +waits for the thread with the single step pending. Here is a high +level description of the sequence of events. + + cont_instead_of_sstep = 0; + +1) set breakpoint at do_fork +2) continue +3) Save the thread id where we stop to cont_thread_id +4) Remove breakpoint at do_fork +5) Reset the PC if needed depending on kernel exception type +6) soft single step +7) Check where we stopped + if current thread != cont_thread_id { + if (here for more than 2 times for the same thead) { + ### must be a really busy system, start test again ### + goto step 1 + } + goto step 5 + } else { + cont_instead_of_sstep = 0; + } +8) clean up and run test again if needed +9) Clear out any threads that were waiting on a break point at the + point in time the test is ended with get_cont_catch(). This + happens sometimes because breakpoints are used in place of single + stepping and some threads could have been in the debugger exception + handling queue because breakpoints were hit concurrently on + different CPUs. This also means we wait at least one second before + unplumbing the debugger connection at the very end, so as respond + to any debug threads waiting to be serviced. + +Signed-off-by: Jason Wessel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/kgdbts.c | 73 ++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 62 insertions(+), 11 deletions(-) + +--- a/drivers/misc/kgdbts.c ++++ b/drivers/misc/kgdbts.c +@@ -141,7 +141,9 @@ static int arch_needs_sstep_emulation = + #else + static int arch_needs_sstep_emulation; + #endif ++static unsigned long cont_addr; + static unsigned long sstep_addr; ++static int restart_from_top_after_write; + static int sstep_state; + + /* Storage for the registers, in GDB format. */ +@@ -189,7 +191,8 @@ static int kgdbts_unreg_thread(void *ptr + */ + while (!final_ack) + msleep_interruptible(1500); +- ++ /* Pause for any other threads to exit after final ack. */ ++ msleep_interruptible(1000); + if (configured) + kgdb_unregister_io_module(&kgdbts_io_ops); + configured = 0; +@@ -311,13 +314,21 @@ static int check_and_rewind_pc(char *put + if (addr + BREAK_INSTR_SIZE == ip) + offset = -BREAK_INSTR_SIZE; + #endif +- if (strcmp(arg, "silent") && ip + offset != addr) { ++ ++ if (arch_needs_sstep_emulation && sstep_addr && ++ ip + offset == sstep_addr && ++ ((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) { ++ /* This is special case for emulated single step */ ++ v2printk("Emul: rewind hit single step bp\n"); ++ restart_from_top_after_write = 1; ++ } else if (strcmp(arg, "silent") && ip + offset != addr) { + eprintk("kgdbts: BP mismatch %lx expected %lx\n", + ip + offset, addr); + return 1; + } + /* Readjust the instruction pointer if needed */ + ip += offset; ++ cont_addr = ip; + #ifdef GDB_ADJUSTS_BREAK_OFFSET + instruction_pointer_set(&kgdbts_regs, ip); + #endif +@@ -327,6 +338,8 @@ static int check_and_rewind_pc(char *put + static int check_single_step(char *put_str, char *arg) + { + unsigned long addr = lookup_addr(arg); ++ static int matched_id; ++ + /* + * From an arch indepent point of view the instruction pointer + * should be on a different instruction +@@ -337,17 +350,28 @@ static int check_single_step(char *put_s + v2printk("Singlestep stopped at IP: %lx\n", + instruction_pointer(&kgdbts_regs)); + +- if (sstep_thread_id != cont_thread_id && !arch_needs_sstep_emulation) { ++ if (sstep_thread_id != cont_thread_id) { + /* + * Ensure we stopped in the same thread id as before, else the + * debugger should continue until the original thread that was + * single stepped is scheduled again, emulating gdb's behavior. + */ + v2printk("ThrID does not match: %lx\n", cont_thread_id); ++ if (arch_needs_sstep_emulation) { ++ if (matched_id && ++ instruction_pointer(&kgdbts_regs) != addr) ++ goto continue_test; ++ matched_id++; ++ ts.idx -= 2; ++ sstep_state = 0; ++ return 0; ++ } + cont_instead_of_sstep = 1; + ts.idx -= 4; + return 0; + } ++continue_test: ++ matched_id = 0; + if (instruction_pointer(&kgdbts_regs) == addr) { + eprintk("kgdbts: SingleStep failed at %lx\n", + instruction_pointer(&kgdbts_regs)); +@@ -389,6 +413,31 @@ static int got_break(char *put_str, char + return 1; + } + ++static void get_cont_catch(char *arg) ++{ ++ /* Always send detach because the test is completed at this point */ ++ fill_get_buf("D"); ++} ++ ++static int put_cont_catch(char *put_str, char *arg) ++{ ++ /* This is at the end of the test and we catch any and all input */ ++ v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id); ++ ts.idx--; ++ return 0; ++} ++ ++static int emul_reset(char *put_str, char *arg) ++{ ++ if (strncmp(put_str, "$OK", 3)) ++ return 1; ++ if (restart_from_top_after_write) { ++ restart_from_top_after_write = 0; ++ ts.idx = -1; ++ } ++ return 0; ++} ++ + static void emul_sstep_get(char *arg) + { + if (!arch_needs_sstep_emulation) { +@@ -442,8 +491,7 @@ static int emul_sstep_put(char *put_str, + v2printk("Stopped at IP: %lx\n", + instruction_pointer(&kgdbts_regs)); + /* Want to stop at IP + break instruction size by default */ +- sstep_addr = instruction_pointer(&kgdbts_regs) + +- BREAK_INSTR_SIZE; ++ sstep_addr = cont_addr + BREAK_INSTR_SIZE; + break; + case 2: + if (strncmp(put_str, "$OK", 3)) { +@@ -455,6 +503,9 @@ static int emul_sstep_put(char *put_str, + if (strncmp(put_str, "$T0", 3)) { + eprintk("kgdbts: failed continue sstep\n"); + return 1; ++ } else { ++ char *ptr = &put_str[11]; ++ kgdb_hex2long(&ptr, &sstep_thread_id); + } + break; + case 4: +@@ -557,13 +608,13 @@ static struct test_struct do_fork_test[] + { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ + { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */ +- { "write", "OK", write_regs }, /* Write registers */ ++ { "write", "OK", write_regs, emul_reset }, /* Write registers */ + { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ + { "g", "do_fork", NULL, check_single_step }, + { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ + { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ + { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ +- { "", "" }, ++ { "", "", get_cont_catch, put_cont_catch }, + }; + + /* Test for hitting a breakpoint at sys_open for what ever the number +@@ -575,13 +626,13 @@ static struct test_struct sys_open_test[ + { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ + { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ +- { "write", "OK", write_regs }, /* Write registers */ ++ { "write", "OK", write_regs, emul_reset }, /* Write registers */ + { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ + { "g", "sys_open", NULL, check_single_step }, + { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ + { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ + { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ +- { "", "" }, ++ { "", "", get_cont_catch, put_cont_catch }, + }; + + /* +@@ -724,8 +775,8 @@ static int run_simple_test(int is_get_ch + /* This callback is a put char which is when kgdb sends data to + * this I/O module. + */ +- if (ts.tst[ts.idx].get[0] == '\0' && +- ts.tst[ts.idx].put[0] == '\0') { ++ if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' && ++ !ts.tst[ts.idx].get_handler) { + eprintk("kgdbts: ERROR: beyond end of test on" + " '%s' line %i\n", ts.name, ts.idx); + return 0; diff --git a/queue-3.0/kgdbts-fix-kernel-oops-with-config_debug_rodata.patch b/queue-3.0/kgdbts-fix-kernel-oops-with-config_debug_rodata.patch new file mode 100644 index 00000000000..1e232fb059b --- /dev/null +++ b/queue-3.0/kgdbts-fix-kernel-oops-with-config_debug_rodata.patch @@ -0,0 +1,119 @@ +From 456ca7ff24841bf2d2a2dfd690fe7d42ef70d932 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Thu, 29 Mar 2012 06:55:44 -0500 +Subject: kgdbts: Fix kernel oops with CONFIG_DEBUG_RODATA + +From: Jason Wessel + +commit 456ca7ff24841bf2d2a2dfd690fe7d42ef70d932 upstream. + +On x86 the kgdb test suite will oops when the kernel is compiled with +CONFIG_DEBUG_RODATA and you run the tests after boot time. This is +regression has existed since 2.6.26 by commit: b33cb815 (kgdbts: Use +HW breakpoints with CONFIG_DEBUG_RODATA). + +The test suite can use hw breakpoints for all the tests, but it has to +execute the hardware breakpoint specific tests first in order to +determine that the hw breakpoints actually work. Specifically the +very first test causes an oops: + +# echo V1I1 > /sys/module/kgdbts/parameters/kgdbts +kgdb: Registered I/O driver kgdbts. +kgdbts:RUN plant and detach test + +Entering kdb (current=0xffff880017aa9320, pid 1078) on processor 0 due to Keyboard Entry +[0]kdb> kgdbts: ERROR PUT: end of test buffer on 'plant_and_detach_test' line 1 expected OK got $E14#aa +WARNING: at drivers/misc/kgdbts.c:730 run_simple_test+0x151/0x2c0() +[...oops clipped...] + +This commit re-orders the running of the tests and puts the RODATA +check into its own function so as to correctly avoid the kernel oops +by detecting and using the hw breakpoints. + +Signed-off-by: Jason Wessel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/kgdbts.c | 52 ++++++++++++++++++++++++++------------------------ + 1 file changed, 28 insertions(+), 24 deletions(-) + +--- a/drivers/misc/kgdbts.c ++++ b/drivers/misc/kgdbts.c +@@ -884,6 +884,22 @@ static void run_singlestep_break_test(vo + kgdbts_break_test(); + } + ++static void test_debug_rodata(void) ++{ ++#ifdef CONFIG_DEBUG_RODATA ++ /* Until there is an api to write to read-only text segments, use ++ * HW breakpoints for the remainder of any tests, else print a ++ * failure message if hw breakpoints do not work. ++ */ ++ if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) { ++ eprintk("kgdbts: HW breakpoints BROKEN, ending tests\n"); ++ return; ++ } ++ force_hwbrks = 1; ++ v1printk("kgdbts:Using HW breakpoints for SW breakpoint tests\n"); ++#endif /* CONFIG_DEBUG_RODATA */ ++} ++ + static void kgdbts_run_tests(void) + { + char *ptr; +@@ -906,6 +922,18 @@ static void kgdbts_run_tests(void) + if (ptr) + sstep_test = simple_strtol(ptr+1, NULL, 10); + ++ /* All HW break point tests */ ++ if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { ++ hwbreaks_ok = 1; ++ v1printk("kgdbts:RUN hw breakpoint test\n"); ++ run_breakpoint_test(1); ++ v1printk("kgdbts:RUN hw write breakpoint test\n"); ++ run_hw_break_test(1); ++ v1printk("kgdbts:RUN access write breakpoint test\n"); ++ run_hw_break_test(0); ++ } ++ test_debug_rodata(); ++ + /* required internal KGDB tests */ + v1printk("kgdbts:RUN plant and detach test\n"); + run_plant_and_detach_test(0); +@@ -923,35 +951,11 @@ static void kgdbts_run_tests(void) + + /* ===Optional tests=== */ + +- /* All HW break point tests */ +- if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { +- hwbreaks_ok = 1; +- v1printk("kgdbts:RUN hw breakpoint test\n"); +- run_breakpoint_test(1); +- v1printk("kgdbts:RUN hw write breakpoint test\n"); +- run_hw_break_test(1); +- v1printk("kgdbts:RUN access write breakpoint test\n"); +- run_hw_break_test(0); +- } +- + if (nmi_sleep) { + v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep); + run_nmi_sleep_test(nmi_sleep); + } + +-#ifdef CONFIG_DEBUG_RODATA +- /* Until there is an api to write to read-only text segments, use +- * HW breakpoints for the remainder of any tests, else print a +- * failure message if hw breakpoints do not work. +- */ +- if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) { +- eprintk("kgdbts: HW breakpoints do not work," +- "skipping remaining tests\n"); +- return; +- } +- force_hwbrks = 1; +-#endif /* CONFIG_DEBUG_RODATA */ +- + /* If the do_fork test is run it will be the last test that is + * executed because a kernel thread will be spawned at the very + * end to unregister the debug hooks. diff --git a/queue-3.0/series b/queue-3.0/series index f29a9a0e5ac..e44e01e6ef1 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -19,3 +19,8 @@ drm-i915-no-lvds-quirk-on-msi-dc500.patch drm-i915-sanitize-bios-debugging-bits-from-pipeconf.patch drm-i915-add-lock-on-drm_helper_resume_force_mode.patch drm-i915-quirk-away-broken-opregion-vbt.patch +kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch +kgdbts-fix-kernel-oops-with-config_debug_rodata.patch +kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch +kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch +x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch diff --git a/queue-3.0/x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch b/queue-3.0/x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch new file mode 100644 index 00000000000..c1b9d6434bf --- /dev/null +++ b/queue-3.0/x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch @@ -0,0 +1,159 @@ +From 3751d3e85cf693e10e2c47c03c8caa65e171099b Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 23 Mar 2012 09:35:05 -0500 +Subject: x86,kgdb: Fix DEBUG_RODATA limitation using text_poke() + +From: Jason Wessel + +commit 3751d3e85cf693e10e2c47c03c8caa65e171099b upstream. + +There has long been a limitation using software breakpoints with a +kernel compiled with CONFIG_DEBUG_RODATA going back to 2.6.26. For +this particular patch, it will apply cleanly and has been tested all +the way back to 2.6.36. + +The kprobes code uses the text_poke() function which accommodates +writing a breakpoint into a read-only page. The x86 kgdb code can +solve the problem similarly by overriding the default breakpoint +set/remove routines and using text_poke() directly. + +The x86 kgdb code will first attempt to use the traditional +probe_kernel_write(), and next try using a the text_poke() function. +The break point install method is tracked such that the correct break +point removal routine will get called later on. + +Cc: x86@kernel.org +Cc: Thomas Gleixner +Cc: Ingo Molnar +Cc: H. Peter Anvin +Inspried-by: Masami Hiramatsu +Signed-off-by: Jason Wessel +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/kgdb.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/misc/kgdbts.c | 17 ------------- + include/linux/kgdb.h | 3 +- + 3 files changed, 62 insertions(+), 18 deletions(-) + +--- a/arch/x86/kernel/kgdb.c ++++ b/arch/x86/kernel/kgdb.c +@@ -43,6 +43,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -710,6 +712,64 @@ void kgdb_arch_set_pc(struct pt_regs *re + regs->ip = ip; + } + ++int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) ++{ ++ int err; ++ char opc[BREAK_INSTR_SIZE]; ++ ++ bpt->type = BP_BREAKPOINT; ++ err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, ++ BREAK_INSTR_SIZE); ++ if (err) ++ return err; ++ err = probe_kernel_write((char *)bpt->bpt_addr, ++ arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); ++#ifdef CONFIG_DEBUG_RODATA ++ if (!err) ++ return err; ++ /* ++ * It is safe to call text_poke() because normal kernel execution ++ * is stopped on all cores, so long as the text_mutex is not locked. ++ */ ++ if (mutex_is_locked(&text_mutex)) ++ return -EBUSY; ++ text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr, ++ BREAK_INSTR_SIZE); ++ err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); ++ if (err) ++ return err; ++ if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE)) ++ return -EINVAL; ++ bpt->type = BP_POKE_BREAKPOINT; ++#endif /* CONFIG_DEBUG_RODATA */ ++ return err; ++} ++ ++int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) ++{ ++#ifdef CONFIG_DEBUG_RODATA ++ int err; ++ char opc[BREAK_INSTR_SIZE]; ++ ++ if (bpt->type != BP_POKE_BREAKPOINT) ++ goto knl_write; ++ /* ++ * It is safe to call text_poke() because normal kernel execution ++ * is stopped on all cores, so long as the text_mutex is not locked. ++ */ ++ if (mutex_is_locked(&text_mutex)) ++ goto knl_write; ++ text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE); ++ err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); ++ if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE)) ++ goto knl_write; ++ return err; ++knl_write: ++#endif /* CONFIG_DEBUG_RODATA */ ++ return probe_kernel_write((char *)bpt->bpt_addr, ++ (char *)bpt->saved_instr, BREAK_INSTR_SIZE); ++} ++ + struct kgdb_arch arch_kgdb_ops = { + /* Breakpoint instruction: */ + .gdb_bpt_instr = { 0xcc }, +--- a/drivers/misc/kgdbts.c ++++ b/drivers/misc/kgdbts.c +@@ -967,22 +967,6 @@ static void run_singlestep_break_test(vo + kgdbts_break_test(); + } + +-static void test_debug_rodata(void) +-{ +-#ifdef CONFIG_DEBUG_RODATA +- /* Until there is an api to write to read-only text segments, use +- * HW breakpoints for the remainder of any tests, else print a +- * failure message if hw breakpoints do not work. +- */ +- if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) { +- eprintk("kgdbts: HW breakpoints BROKEN, ending tests\n"); +- return; +- } +- force_hwbrks = 1; +- v1printk("kgdbts:Using HW breakpoints for SW breakpoint tests\n"); +-#endif /* CONFIG_DEBUG_RODATA */ +-} +- + static void kgdbts_run_tests(void) + { + char *ptr; +@@ -1015,7 +999,6 @@ static void kgdbts_run_tests(void) + v1printk("kgdbts:RUN access write breakpoint test\n"); + run_hw_break_test(0); + } +- test_debug_rodata(); + + /* required internal KGDB tests */ + v1printk("kgdbts:RUN plant and detach test\n"); +--- a/include/linux/kgdb.h ++++ b/include/linux/kgdb.h +@@ -63,7 +63,8 @@ enum kgdb_bptype { + BP_HARDWARE_BREAKPOINT, + BP_WRITE_WATCHPOINT, + BP_READ_WATCHPOINT, +- BP_ACCESS_WATCHPOINT ++ BP_ACCESS_WATCHPOINT, ++ BP_POKE_BREAKPOINT, + }; + + enum kgdb_bpstate {