]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'for_linus-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jwesse...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Apr 2012 00:26:08 +0000 (17:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Apr 2012 00:26:08 +0000 (17:26 -0700)
Pull KGDB/KDB regression fixes from Jason Wessel:
 - Fix a Smatch warning that appeared in the 3.4 merge window
 - Fix kgdb test suite with SMP for all archs without HW single stepping
 - Fix kgdb sw breakpoints with CONFIG_DEBUG_RODATA=y limitations on x86
 - Fix oops on kgdb test suite with CONFIG_DEBUG_RODATA
 - Fix kgdb test suite with SMP for all archs with HW single stepping

* tag 'for_linus-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb:
  x86,kgdb: Fix DEBUG_RODATA limitation using text_poke()
  kgdb,debug_core: pass the breakpoint struct instead of address and memory
  kgdbts: (2 of 2) fix single step awareness to work correctly with SMP
  kgdbts: (1 of 2) fix single step awareness to work correctly with SMP
  kgdbts: Fix kernel oops with CONFIG_DEBUG_RODATA
  kdb: Fix smatch warning on dbg_io_ops->is_console

1  2 
arch/x86/kernel/kgdb.c
kernel/debug/debug_core.c

diff --combined arch/x86/kernel/kgdb.c
index db6720edfdd04f6d6a5e57da090c36db7a28eb31,b9bd9d8de665ada43b98864108ac4412b78a3f8c..8bfb6146f7530634d30fa9f25d1718111a214649
  #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>
 -#include <asm/system.h>
  #include <asm/apic.h>
  #include <asm/nmi.h>
  
@@@ -741,6 -744,64 +743,64 @@@ void kgdb_arch_set_pc(struct pt_regs *r
        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 },
index 1dc53bae56e1f6974a7f7cdb7f9d82815d85a22c,a7e52ca9456396a0bffb67c670656c7ce4cb5060..0557f24c6bca0d1da04f620c163a70010930737e
@@@ -53,6 -53,7 +53,6 @@@
  #include <asm/cacheflush.h>
  #include <asm/byteorder.h>
  #include <linux/atomic.h>
 -#include <asm/system.h>
  
  #include "debug_core.h"
  
@@@ -160,37 -161,39 +160,39 @@@ early_param("nokgdbroundup", opt_nokgdb
   * 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);
@@@ -234,7 -237,6 +236,6 @@@ static void kgdb_flush_swbreak_addr(uns
   */
  int dbg_activate_sw_breakpoints(void)
  {
-       unsigned long addr;
        int error;
        int ret = 0;
        int i;
                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;
@@@ -301,7 -302,6 +301,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;
        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;
@@@ -351,7 -350,6 +349,6 @@@ int kgdb_isremovedbreak(unsigned long a
  
  int dbg_remove_all_break(void)
  {
-       unsigned long addr;
        int error;
        int i;
  
        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;
        }