]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.3-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Apr 2012 17:12:55 +0000 (10:12 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Apr 2012 17:12:55 +0000 (10:12 -0700)
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

queue-3.3/kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch [new file with mode: 0644]
queue-3.3/kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch [new file with mode: 0644]
queue-3.3/kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch [new file with mode: 0644]
queue-3.3/kgdbts-fix-kernel-oops-with-config_debug_rodata.patch [new file with mode: 0644]
queue-3.3/series
queue-3.3/x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch [new file with mode: 0644]

diff --git a/queue-3.3/kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch b/queue-3.3/kgdb-debug_core-pass-the-breakpoint-struct-instead-of-address-and-memory.patch
new file mode 100644 (file)
index 0000000..7fb9bb7
--- /dev/null
@@ -0,0 +1,175 @@
+From 98b54aa1a2241b59372468bd1e9c2d207bdba54b Mon Sep 17 00:00:00 2001
+From: Jason Wessel <jason.wessel@windriver.com>
+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 <jason.wessel@windriver.com>
+
+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 <jason.wessel@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.3/kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch b/queue-3.3/kgdbts-1-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch
new file mode 100644 (file)
index 0000000..b698e3d
--- /dev/null
@@ -0,0 +1,209 @@
+From 486c5987a00a89d56c2c04c506417ef8f823ca2e Mon Sep 17 00:00:00 2001
+From: Jason Wessel <jason.wessel@windriver.com>
+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 <jason.wessel@windriver.com>
+
+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:
+ [<ffffffff812994a0>] check_and_rewind_pc+0xe0/0x100
+ [<ffffffff81298945>] validate_simple_test+0x25/0xc0
+ [<ffffffff81298f77>] run_simple_test+0x107/0x2c0
+ [<ffffffff81298a18>] 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 <jason.wessel@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/misc/kgdbts.c |   54 +++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 43 insertions(+), 11 deletions(-)
+
+--- a/drivers/misc/kgdbts.c
++++ b/drivers/misc/kgdbts.c
+@@ -134,6 +134,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
+@@ -211,7 +214,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"))
+@@ -283,6 +286,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);
+@@ -324,6 +337,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));
+@@ -368,7 +393,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) {
+@@ -398,9 +428,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:
+@@ -502,10 +534,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 */
+@@ -523,10 +555,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 */
+@@ -541,10 +573,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.3/kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch b/queue-3.3/kgdbts-2-of-2-fix-single-step-awareness-to-work-correctly-with-smp.patch
new file mode 100644 (file)
index 0000000..65b04fc
--- /dev/null
@@ -0,0 +1,263 @@
+From 23bbd8e346f1ef3fc1219c79cea53d8d52b207d8 Mon Sep 17 00:00:00 2001
+From: Jason Wessel <jason.wessel@windriver.com>
+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 <jason.wessel@windriver.com>
+
+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()
+[<c01f6520>] (check_and_rewind_pc+0x9c/0xc4)
+[<c01f595c>] (validate_simple_test+0x3c/0xc4)
+[<c01f60d4>] (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 <jason.wessel@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/misc/kgdbts.c |   73 ++++++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 62 insertions(+), 11 deletions(-)
+
+--- a/drivers/misc/kgdbts.c
++++ b/drivers/misc/kgdbts.c
+@@ -142,7 +142,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. */
+@@ -190,7 +192,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;
+@@ -312,13 +315,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
+@@ -328,6 +339,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
+@@ -338,17 +351,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));
+@@ -390,6 +414,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) {
+@@ -443,8 +492,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)) {
+@@ -456,6 +504,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:
+@@ -558,13 +609,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
+@@ -576,13 +627,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 },
+ };
+ /*
+@@ -725,8 +776,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.3/kgdbts-fix-kernel-oops-with-config_debug_rodata.patch b/queue-3.3/kgdbts-fix-kernel-oops-with-config_debug_rodata.patch
new file mode 100644 (file)
index 0000000..ac59a62
--- /dev/null
@@ -0,0 +1,119 @@
+From 456ca7ff24841bf2d2a2dfd690fe7d42ef70d932 Mon Sep 17 00:00:00 2001
+From: Jason Wessel <jason.wessel@windriver.com>
+Date: Thu, 29 Mar 2012 06:55:44 -0500
+Subject: kgdbts: Fix kernel oops with CONFIG_DEBUG_RODATA
+
+From: Jason Wessel <jason.wessel@windriver.com>
+
+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 <jason.wessel@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/misc/kgdbts.c |   52 ++++++++++++++++++++++++++------------------------
+ 1 file changed, 28 insertions(+), 24 deletions(-)
+
+--- a/drivers/misc/kgdbts.c
++++ b/drivers/misc/kgdbts.c
+@@ -885,6 +885,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;
+@@ -907,6 +923,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);
+@@ -924,35 +952,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.
index 539ceb901103e2fc4264dd6894bc5293bdec556c..8a61d0b78699a7c588ee3b132bc4199f55403476 100644 (file)
@@ -43,3 +43,8 @@ pm-runtime-don-t-forget-to-wake-up-waitqueue-on-failure.patch
 pm-hibernate-disable-usermode-helpers-right-before-freezing-tasks.patch
 pm-sleep-move-disabling-of-usermode-helpers-to-the-freezer.patch
 pm-sleep-mitigate-race-between-the-freezer-and-request_firmware.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.3/x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch b/queue-3.3/x86-kgdb-fix-debug_rodata-limitation-using-text_poke.patch
new file mode 100644 (file)
index 0000000..942d593
--- /dev/null
@@ -0,0 +1,159 @@
+From 3751d3e85cf693e10e2c47c03c8caa65e171099b Mon Sep 17 00:00:00 2001
+From: Jason Wessel <jason.wessel@windriver.com>
+Date: Fri, 23 Mar 2012 09:35:05 -0500
+Subject: x86,kgdb: Fix DEBUG_RODATA limitation using text_poke()
+
+From: Jason Wessel <jason.wessel@windriver.com>
+
+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 <tglx@linutronix.de>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: H. Peter Anvin <hpa@zytor.com>
+Inspried-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/smp.h>
+ #include <linux/nmi.h>
+ #include <linux/hw_breakpoint.h>
++#include <linux/uaccess.h>
++#include <linux/memory.h>
+ #include <asm/debugreg.h>
+ #include <asm/apicdef.h>
+@@ -740,6 +742,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
+@@ -968,22 +968,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;
+@@ -1016,7 +1000,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 {