I rolled up several patches along with my changes to fix HW breakpoints on x86_64 and i386. I also deprecated some of the #defines in favor of using the kgdb_ops to control the HW breakpoints for other non IA archs at the point that these are implemented.

Until such time that there is a common interface for kernel HW breakpoints, if a user space application uses HW breakpoints the kernel breakpoints will disappear. I tested execution, data access and data write breakpoints and all work with gdb 6.6.

If there are no objections, I am going to replace the i386.patch with i386_hw_breakpoints.patch and x86_64_breakpoints.patch and merge the core changes for arch breakpoints to core-lite.patch.

Signed-off-by: Jason Wessel <[EMAIL PROTECTED]>


---
 arch/i386/kernel/kgdb.c    |   92 +++++++++++++++++++++++++++++------
 arch/x86_64/kernel/kgdb.c  |  117 +++++++++++++++++++++++++++++++++++++++++++--
 include/asm-generic/kgdb.h |   40 ---------------
 include/linux/kgdb.h       |    2 
 kernel/kgdb.c              |   12 ++--
 lib/Kconfig.kgdb           |    8 ---
 6 files changed, 199 insertions(+), 72 deletions(-)

Index: linux-2.6.21.1/lib/Kconfig.kgdb
===================================================================
--- linux-2.6.21.1.orig/lib/Kconfig.kgdb
+++ linux-2.6.21.1/lib/Kconfig.kgdb
@@ -21,14 +21,6 @@ config KGDB
          at http://kgdb.sourceforge.net as well as in DocBook form
          in Documentation/DocBook/.  If unsure, say N.
 
-config KGDB_ARCH_HAS_HARDWARE_BREAKPOINTS
-       bool
-       depends on KGDB
-       default n
-       help
-         If you say Y here, KGDB will make use of hardware breakpoints
-         rather than software breakpoints.  If unsure, say N.
-
 config KGDB_ARCH_HAS_SHADOW_INFO
        bool
 
Index: linux-2.6.21.1/arch/i386/kernel/kgdb.c
===================================================================
--- linux-2.6.21.1.orig/arch/i386/kernel/kgdb.c
+++ linux-2.6.21.1/arch/i386/kernel/kgdb.c
@@ -14,12 +14,14 @@
 
 /*
  * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2007 Wind River Systems, Inc.
  */
 /*
  *  Contributor:     Lake Stevens Instrument Division$
  *  Written by:      Glenn Engel $
  *  Updated by:             Amit Kale<[EMAIL PROTECTED]>
  *  Updated by:             Tom Rini <[EMAIL PROTECTED]>
+ *  Updated by:             Jason Wessel <[EMAIL PROTECTED]>
  *  Modified for 386 by Jim Kingdon, Cygnus Support.
  *  Origianl kgdb, compatibility with 2.1.xx kernel by
  *  David Grothe <[EMAIL PROTECTED]>
@@ -126,8 +128,53 @@ static struct hw_breakpoint {
        { .enabled = 0 },
 };
 
-#ifdef CONFIG_KGDB_ARCH_HAS_HARDWARE_BREAKPOINTS
-int kgdb_remove_hw_break(unsigned long addr)
+static void kgdb_correct_hw_break(void)
+{
+       int breakno;
+       int correctit;
+       int breakbit;
+       unsigned long dr7;
+
+       get_debugreg(dr7, 7);
+       correctit = 0;
+       for (breakno = 0; breakno < 3; breakno++) {
+               breakbit = 2 << (breakno << 1);
+               if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+                       correctit = 1;
+                       dr7 |= breakbit;
+                       dr7 &= ~(0xf0000 << (breakno << 2));
+                       dr7 |= (((breakinfo[breakno].len << 2) |
+                                breakinfo[breakno].type) << 16) <<
+                           (breakno << 2);
+                       switch (breakno) {
+                       case 0:
+                               set_debugreg(breakinfo[breakno].addr, 0);
+                               break;
+
+                       case 1:
+                               set_debugreg(breakinfo[breakno].addr, 1);
+                               break;
+
+                       case 2:
+                               set_debugreg(breakinfo[breakno].addr, 2);
+                               break;
+
+                       case 3:
+                               set_debugreg(breakinfo[breakno].addr, 3);
+                               break;
+                       }
+               } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+                       correctit = 1;
+                       dr7 &= ~breakbit;
+                       dr7 &= ~(0xf0000 << (breakno << 2));
+               }
+       }
+       if (correctit)
+               set_debugreg(dr7, 7);
+}
+
+static int kgdb_remove_hw_break(unsigned long addr, int len,
+                                                enum kgdb_bptype bptype)
 {
        int i, idx = -1;
        for (i = 0; i < 4; i++) {
@@ -143,20 +190,17 @@ int kgdb_remove_hw_break(unsigned long a
        return 0;
 }
 
-void kgdb_remove_all_hw_break(void)
+static void kgdb_remove_all_hw_break(void)
 {
        int i;
 
        for (i = 0; i < 4; i++) {
-               if (breakinfo[i].enabled) {
-                       /* Do what? */
-                       ;
-               }
                memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
        }
 }
 
-int kgdb_set_hw_break(unsigned long addr)
+static int kgdb_set_hw_break(unsigned long addr, int len,
+                                         enum kgdb_bptype bptype)
 {
        int i, idx = -1;
        for (i = 0; i < 4; i++) {
@@ -167,19 +211,32 @@ int kgdb_set_hw_break(unsigned long addr
        }
        if (idx == -1)
                return -1;
-
+       if (bptype == bp_hardware_breakpoint) {
+               breakinfo[idx].type = 0;
+               breakinfo[idx].len = 0;
+       } else if (bptype == bp_write_watchpoint) {
+               breakinfo[idx].type = 1;
+               if (len == 1 || len == 2 || len == 4)
+                       breakinfo[idx].len = len - 1;
+               else
+                       return -1;
+       } else if (bptype == bp_access_watchpoint) {
+               breakinfo[idx].type = 3;
+               if (len == 1 || len == 2 || len == 4)
+                       breakinfo[idx].len = len - 1;
+               else
+                       return -1;
+       } else
+               return -1;
        breakinfo[idx].enabled = 1;
-       breakinfo[idx].type = 1;
-       breakinfo[idx].len = 1;
        breakinfo[idx].addr = addr;
        return 0;
 }
-#endif /* CONFIG_KGDB_ARCH_HAS_HARDWARE_BREAKPOINTS */
 
 void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
        /* Disable hardware debugging while we are in kgdb */
-       asm volatile ("movl %0,%%db7": /* no output */ :"r" (0));
+       set_debugreg(0, 7);
 }
 
 void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code)
@@ -225,7 +282,7 @@ int kgdb_arch_handle_exception(int e_vec
                        
atomic_set(&cpu_doing_single_step,raw_smp_processor_id());
                }
 
-               asm volatile ("movl %%db6, %0\n":"=r" (dr6));
+               get_debugreg(dr6, 6);
                if (!(dr6 & 0x4000)) {
                        long breakno;
                        for (breakno = 0; breakno < 4; ++breakno) {
@@ -237,7 +294,8 @@ int kgdb_arch_handle_exception(int e_vec
                                }
                        }
                }
-               asm volatile ("movl %0, %%db6\n"::"r" (0));
+               set_debugreg(0, 6);
+               kgdb_correct_hw_break();
 
                return (0);
        }                       /* switch */
@@ -322,4 +380,8 @@ unsigned long kgdb_arch_pc(int exception
 struct kgdb_arch arch_kgdb_ops = {
        .gdb_bpt_instr = {0xcc},
        .flags = KGDB_HW_BREAKPOINT,
+       .set_hw_breakpoint = kgdb_set_hw_break,
+       .remove_hw_breakpoint = kgdb_remove_hw_break,
+       .remove_all_hw_break = kgdb_remove_all_hw_break,
+       .correct_hw_break = kgdb_correct_hw_break,
 };
Index: linux-2.6.21.1/arch/x86_64/kernel/kgdb.c
===================================================================
--- linux-2.6.21.1.orig/arch/x86_64/kernel/kgdb.c
+++ linux-2.6.21.1/arch/x86_64/kernel/kgdb.c
@@ -17,6 +17,7 @@
  * Copyright (C) 2000-2001 VERITAS Software Corporation.
  * Copyright (C) 2002 Andi Kleen, SuSE Labs
  * Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd.
+ * Copyright (C) 2007 Jason Wessel, Wind River Systems, Inc.
  */
 /****************************************************************************
  *  Contributor:     Lake Stevens Instrument Division$
@@ -136,10 +137,115 @@ enabled:0}, {
 enabled:0}, {
 enabled:0}};
 
+static void kgdb_correct_hw_break(void)
+{
+       int breakno;
+       int correctit;
+       int breakbit;
+       unsigned long dr7;
+
+       get_debugreg(dr7, 7);
+       correctit = 0;
+       for (breakno = 0; breakno < 3; breakno++) {
+               breakbit = 2 << (breakno << 1);
+               if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+                       correctit = 1;
+                       dr7 |= breakbit;
+                       dr7 &= ~(0xf0000 << (breakno << 2));
+                       dr7 |= (((breakinfo[breakno].len << 2) |
+                                breakinfo[breakno].type) << 16) <<
+                           (breakno << 2);
+                       switch (breakno) {
+                       case 0:
+                               set_debugreg(breakinfo[breakno].addr, 0);
+                               break;
+
+                       case 1:
+                               set_debugreg(breakinfo[breakno].addr, 1);
+                               break;
+
+                       case 2:
+                               set_debugreg(breakinfo[breakno].addr, 2);
+                               break;
+
+                       case 3:
+                               set_debugreg(breakinfo[breakno].addr, 3);
+                               break;
+                       }
+               } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+                       correctit = 1;
+                       dr7 &= ~breakbit;
+                       dr7 &= ~(0xf0000 << (breakno << 2));
+               }
+       }
+       if (correctit)
+               set_debugreg(dr7, 7);
+}
+
+static int kgdb_remove_hw_break(unsigned long addr, int len,
+                                                enum kgdb_bptype bptype)
+{
+       int i, idx = -1;
+       for (i = 0; i < 4; i++) {
+               if (breakinfo[i].addr == addr && breakinfo[i].enabled) {
+                       idx = i;
+                       break;
+               }
+       }
+       if (idx == -1)
+               return -1;
+
+       breakinfo[idx].enabled = 0;
+       return 0;
+}
+
+static void kgdb_remove_all_hw_break(void)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
+       }
+}
+
+static int kgdb_set_hw_break(unsigned long addr, int len,
+                                         enum kgdb_bptype bptype)
+{
+       int i, idx = -1;
+       for (i = 0; i < 4; i++) {
+               if (!breakinfo[i].enabled) {
+                       idx = i;
+                       break;
+               }
+       }
+       if (idx == -1)
+               return -1;
+       if (bptype == bp_hardware_breakpoint) {
+               breakinfo[idx].type = 0;
+               breakinfo[idx].len = 0;
+       } else if (bptype == bp_write_watchpoint) {
+               breakinfo[idx].type = 1;
+               if (len == 1 || len == 2 || len == 4)
+                       breakinfo[idx].len = len - 1;
+               else
+                       return -1;
+       } else if (bptype == bp_access_watchpoint) {
+               breakinfo[idx].type = 3;
+               if (len == 1 || len == 2 || len == 4)
+                       breakinfo[idx].len = len - 1;
+               else
+                       return -1;
+       } else
+               return -1;
+       breakinfo[idx].enabled = 1;
+       breakinfo[idx].addr = addr;
+       return 0;
+}
+
 void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
        /* Disable hardware debugging while we are in kgdb */
-       asm volatile ("movq %0,%%db7": /* no output */ :"r" (0UL));
+       set_debugreg(0UL, 7);
 }
 
 void kgdb_post_master_code(struct pt_regs *regs, int e_vector, int err_code)
@@ -187,7 +293,7 @@ int kgdb_arch_handle_exception(int e_vec
 
                }
 
-               asm volatile ("movq %%db6, %0\n":"=r" (dr6));
+               get_debugreg(dr6, 6);
                if (!(dr6 & 0x4000)) {
                        for (breakno = 0; breakno < 4; ++breakno) {
                                if (dr6 & (1 << breakno)) {
@@ -200,7 +306,8 @@ int kgdb_arch_handle_exception(int e_vec
                                }
                        }
                }
-               asm volatile ("movq %0, %%db6\n"::"r" (0UL));
+               set_debugreg(0UL, 6);
+               kgdb_correct_hw_break();
 
                return (0);
        }                       /* switch */
@@ -346,4 +453,8 @@ struct kgdb_arch arch_kgdb_ops = {
        .gdb_bpt_instr = {0xcc},
        .flags = KGDB_HW_BREAKPOINT,
        .shadowth = 1,
+       .set_hw_breakpoint = kgdb_set_hw_break,
+       .remove_hw_breakpoint = kgdb_remove_hw_break,
+       .remove_all_hw_break = kgdb_remove_all_hw_break,
+       .correct_hw_break = kgdb_correct_hw_break,
 };
Index: linux-2.6.21.1/include/asm-generic/kgdb.h
===================================================================
--- linux-2.6.21.1.orig/include/asm-generic/kgdb.h
+++ linux-2.6.21.1/include/asm-generic/kgdb.h
@@ -60,46 +60,6 @@ extern void kgdb_disable_hw_debug(struct
 #define kgdb_post_master_code(regs, v, c)      do { } while (0)
 #endif
 
-#ifdef CONFIG_KGDB_ARCH_HAS_HARDWARE_BREAKPOINTS
-/**
- *     kgdb_set_hw_break - Set a hardware breakpoint at @addr.
- *     @addr: The address to set a hardware breakpoint at.
- */
-extern int kgdb_set_hw_break(unsigned long addr);
-
-/**
- *     kgdb_remove_hw_break - Remove a hardware breakpoint at @addr.
- *     @addr: The address to remove a hardware breakpoint from.
- */
-extern int kgdb_remove_hw_break(unsigned long addr);
-
-/**
- *     kgdb_remove_all_hw_break - Clear all hardware breakpoints.
- */
-extern void kgdb_remove_all_hw_break(void);
-
-/**
- *     kgdb_correct_hw_break - Correct hardware breakpoints.
- *
- *     A hook to allow for changes to the hardware breakpoint, called
- *     after a single step (s) or continue (c) packet, and once we're about
- *     to let the kernel continue running.
- *
- *     This is used to set the hardware breakpoint registers for all the
- *     slave cpus on an SMP configuration. This must be called after any
- *     changes are made to the hardware breakpoints (such as by a single
- *     step (s) or continue (c) packet. This is only required on
- *     architectures that support SMP and every processor has its own set
- *     of breakpoint registers.
- */
-extern void kgdb_correct_hw_break(void);
-#else
-#define kgdb_set_hw_break(addr)                        0
-#define kgdb_remove_hw_break(addr)             0
-#define kgdb_remove_all_hw_break()             do { } while (0)
-#define kgdb_correct_hw_break()                        do { } while (0)
-#endif
-
 #ifdef CONFIG_KGDB_ARCH_HAS_SHADOW_INFO
 /**
  *     kgdb_shadowinfo - Get shadowed information on @threadid.
Index: linux-2.6.21.1/include/linux/kgdb.h
===================================================================
--- linux-2.6.21.1.orig/include/linux/kgdb.h
+++ linux-2.6.21.1/include/linux/kgdb.h
@@ -220,6 +220,8 @@ struct kgdb_arch {
        int (*remove_breakpoint)(unsigned long, char *);
        int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
        int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
+       void (*remove_all_hw_break)(void);
+       void (*correct_hw_break)(void);
 };
 
 /* Thread reference */
Index: linux-2.6.21.1/kernel/kgdb.c
===================================================================
--- linux-2.6.21.1.orig/kernel/kgdb.c
+++ linux-2.6.21.1/kernel/kgdb.c
@@ -609,6 +609,9 @@ static void kgdb_wait(struct pt_regs *re
        kgdb_info[processor].debuggerinfo = NULL;
        kgdb_info[processor].task = NULL;
 
+       /* fix up hardware debug registers on local cpu */
+       if (kgdb_ops->correct_hw_break)
+               kgdb_ops->correct_hw_break();
        /* Signal the master processor that we are done */
        atomic_set(&procindebug[processor], 0);
        spin_unlock(&slavecpulocks[processor]);
@@ -782,7 +785,8 @@ int remove_all_break(void)
        }
 
        /* Clear hardware breakpoints. */
-       kgdb_remove_all_hw_break();
+       if (kgdb_ops->remove_all_hw_break)
+               kgdb_ops->remove_all_hw_break();
 
        return 0;
 }
@@ -1313,7 +1317,7 @@ int kgdb_handle_exception(int ex_vector,
                        /* Test if this is a hardware breakpoint, and
                         * if we support it. */
                        if (*bpt_type == '1' &&
-                           !kgdb_ops->flags & KGDB_HW_BREAKPOINT)
+                           !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
                                /* Unsupported. */
                                break;
 
@@ -1334,12 +1338,8 @@ int kgdb_handle_exception(int ex_vector,
 
                        if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0')
                                error = kgdb_set_sw_break(addr);
-                       else if (remcom_in_buffer[0] == 'Z' && *bpt_type == '1')
-                               error = kgdb_set_hw_break(addr);
                        else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')
                                error = kgdb_remove_sw_break(addr);
-                       else if (remcom_in_buffer[0] == 'z' && *bpt_type == '1')
-                               error = kgdb_remove_hw_break(addr);
                        else if (remcom_in_buffer[0] == 'Z')
                                error = kgdb_ops->set_hw_breakpoint(addr,
                                                                    (int)length,
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Kgdb-bugreport mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kgdb-bugreport

Reply via email to