From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27539 invoked by alias); 11 Mar 2011 05:05:25 -0000 Received: (qmail 27527 invoked by uid 22791); 11 Mar 2011 05:05:21 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,TW_DB,T_FILL_THIS_FORM_SHORT,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 11 Mar 2011 05:05:12 +0000 Received: (qmail 13474 invoked from network); 11 Mar 2011 05:05:09 -0000 Received: from unknown (HELO ?192.168.0.102?) (yao@127.0.0.2) by mail.codesourcery.com with ESMTPA; 11 Mar 2011 05:05:09 -0000 Message-ID: <4D79AD80.5050803@codesourcery.com> Date: Fri, 11 Mar 2011 06:39:00 -0000 From: Yao Qi User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20101208 Lightning/1.0b2 Thunderbird/3.1.7 MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: [try 2nd, patch] Move common macros to i386-dbg-reg.h References: <4D57AB12.1050708@codesourcery.com> In-Reply-To: <4D57AB12.1050708@codesourcery.com> Content-Type: multipart/mixed; boundary="------------070002020106000209030607" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-03/txt/msg00650.txt.bz2 This is a multi-part message in MIME format. --------------070002020106000209030607 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-length: 480 On 02/13/2011 05:57 PM, Yao Qi wrote: > Some macros are duplicated in gdb/i386-nat and gdb/gdbserver/i386-low. > This patch is to move common macros to gdb/common/i386-common.h. > > There are also some duplicated functions, which should be moved in next > step. > Compared with last version, two changes are in this new patch, 1) rename i386-common.h to i386-dbg-reg.h, 2) add dependency tracking in gdbserver. OK for mainline after 7.3 branch is created? -- Yao (齐尧) --------------070002020106000209030607 Content-Type: text/x-patch; name="i386-dbg-reg-h-0311.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="i386-dbg-reg-h-0311.patch" Content-length: 37815 gdb/ * i386-nat.h: Include i386-dbg-reg.h. Move macros to i386-dbg-reg.h. * i386-nat.c: Move macros and structs to i386-dbg-reg.h. New variable struct i386_debug_reg_state state to replace other variables dr_mirror, dr_ref_count, dr_control_mirror, and dr_status_mirror. (i386_insert_aligned_watchpoint): Add one formal parameter struct i386_debug_reg_state *STATE. Update code using these variables. (i386_remove_aligned_watchpoint, i386_show_dr): Likewise. (i386_cleanup_dregs): Likewise. (i386_handle_nonaligned_watchpoint): Likewise. * common/i386-dbg-reg.h: New. Common macros and structs. gdb/gdbserver/ * i386-low.h: Include i386-dbg-reg.h. Move macros to i386-dbg-reg.h. * i386-low.c (i386_set_debug_register_length): New. (i386_low_init_dregs): Call i386_set_debug_register_length. * Makefile.in (i386_low_h) Depends on i386-dbg-reg.h. diff --git a/gdb/common/i386-dbg-reg.h b/gdb/common/i386-dbg-reg.h new file mode 100644 index 0000000..0870b76 --- /dev/null +++ b/gdb/common/i386-dbg-reg.h @@ -0,0 +1,230 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef I386_DBG_REG_H +#define I386_DBG_REG_H 1 + +/* DR7 Debug Control register fields. */ + +/* How many bits to skip in DR7 to get to R/W and LEN fields. */ +#define DR_CONTROL_SHIFT 16 +/* How many bits in DR7 per R/W and LEN field for each watchpoint. */ +#define DR_CONTROL_SIZE 4 + +/* Watchpoint/breakpoint read/write fields in DR7. */ +#define DR_RW_EXECUTE (0x0) /* Break on instruction execution. */ +#define DR_RW_WRITE (0x1) /* Break on data writes. */ +#define DR_RW_READ (0x3) /* Break on data reads or writes. */ +/* This is here for completeness. No platform supports this + functionality yet (as of March 2001). Note that the DE flag in the + CR4 register needs to be set to support this. */ +#ifndef DR_RW_IORW +#define DR_RW_IORW (0x2) /* Break on I/O reads or writes. */ +#endif + +/* Debug registers' indices. */ +#define DR_NADDR 4 /* The number of debug address registers. */ +#define DR_STATUS 6 /* Index of debug status register (DR6). */ +#define DR_CONTROL 7 /* Index of debug control register (DR7). */ + +/* Watchpoint/breakpoint length fields in DR7. The 2-bit left shift + is so we could OR this with the read/write field defined above. */ +#define DR_LEN_1 (0x0 << 2) /* 1-byte region watch or breakpoint. */ +#define DR_LEN_2 (0x1 << 2) /* 2-byte region watch. */ +#define DR_LEN_4 (0x3 << 2) /* 4-byte region watch. */ +#define DR_LEN_8 (0x2 << 2) /* 8-byte region watch (AMD64). */ + +/* Local and Global Enable flags in DR7. + + When the Local Enable flag is set, the breakpoint/watchpoint is + enabled only for the current task; the processor automatically + clears this flag on every task switch. When the Global Enable flag + is set, the breakpoint/watchpoint is enabled for all tasks; the + processor never clears this flag. + + Currently, all watchpoint are locally enabled. If you need to + enable them globally, read the comment which pertains to this in + i386_insert_aligned_watchpoint below. */ +#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ +#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ +#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ + +/* Local and global exact breakpoint enable flags (a.k.a. slowdown + flags). These are only required on i386, to allow detection of the + exact instruction which caused a watchpoint to break; i486 and + later processors do that automatically. We set these flags for + backwards compatibility. */ +#define DR_LOCAL_SLOWDOWN (0x100) +#define DR_GLOBAL_SLOWDOWN (0x200) + +/* Fields reserved by Intel. This includes the GD (General Detect + Enable) flag, which causes a debug exception to be generated when a + MOV instruction accesses one of the debug registers. + + FIXME: My Intel manual says we should use 0xF800, not 0xFC00. */ +#define DR_CONTROL_RESERVED (0xFC00) + +/* Auxiliary helper macros. */ + +/* A value that masks all fields in DR7 that are reserved by Intel. */ +#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED) + +#ifndef DR_FIRSTADDR +#define DR_FIRSTADDR 0 +#endif + +#ifndef DR_LASTADDR +#define DR_LASTADDR 3 +#endif + +/* Types of operations supported by i386_handle_nonaligned_watchpoint. */ +typedef enum { WP_INSERT, WP_REMOVE, WP_COUNT } i386_wp_op_t; + +/* Return the value of a 4-bit field for DR7 suitable for watching a + region of LEN bytes for accesses of type TYPE. LEN is assumed to + have the value of 1, 2, or 4. */ +/* +static unsigned i386_length_and_rw_bits (int len, enum target_hw_bp_type type); +*/ + +/* Global state needed to track h/w watchpoints. */ + +struct i386_debug_reg_state +{ + /* Mirror the inferior's DRi registers. We keep the status and + control registers separated because they don't hold addresses. + Note that since we can change these mirrors while threads are + running, we never trust them to explain a cause of a trap. + For that, we need to peek directly in the inferior registers. */ + CORE_ADDR dr_mirror[DR_NADDR]; + unsigned dr_status_mirror, dr_control_mirror; + + /* Reference counts for each debug register. */ + int dr_ref_count[DR_NADDR]; +}; + +/* Support for hardware watchpoints and breakpoints using the i386 + debug registers. + + This provides several functions for inserting and removing + hardware-assisted breakpoints and watchpoints, testing if one or + more of the watchpoints triggered and at what address, checking + whether a given region can be watched, etc. + + The functions below implement debug registers sharing by reference + counts, and allow to watch regions up to 16 bytes long. */ + +/* Support for hardware watchpoints and breakpoints using the i386 + debug registers. + + This provides several functions for inserting and removing + hardware-assisted breakpoints and watchpoints, testing if one or + more of the watchpoints triggered and at what address, checking + whether a given region can be watched, etc. + + In addition, each target should provide several low-level functions + regrouped into i386_dr_low_type struct below. These functions + that will be called to insert watchpoints and hardware breakpoints + into the inferior, remove them, and check their status. These + functions are: + + set_control -- set the debug control (DR7) + register to a given value for all LWPs + + set_addr -- put an address into one debug + register for all LWPs + + reset_addr -- reset the address stored in + one debug register for all LWPs + + get_status -- return the value of the debug + status (DR6) register for current LWP + + unset_status -- unset the specified bits of the debug + status (DR6) register for all LWPs + + Additionally, the native file should set the debug_register_length + field to 4 or 8 depending on the number of bytes used for + deubg registers. */ + +struct i386_dr_low_type + { + void (*set_control) (unsigned long); + void (*set_addr) (int, CORE_ADDR); + void (*reset_addr) (int); + unsigned long (*get_status) (void); + void (*unset_status) (unsigned long); + int debug_register_length; + }; + +extern struct i386_dr_low_type i386_dr_low; + +/* Support for 8-byte wide hw watchpoints. */ +#define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8) + +/* Auxiliary helper macros. */ + +/* A value that masks all fields in DR7 that are reserved by Intel. */ +#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED) + +/* The I'th debug register is vacant if its Local and Global Enable + bits are reset in the Debug Control register. */ +#define I386_DR_VACANT(state, i) \ + (((state)->dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0) + +/* Locally enable the break/watchpoint in the I'th debug register. */ +#define I386_DR_LOCAL_ENABLE(state, i) \ + do { \ + (state)->dr_control_mirror |= \ + (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))); \ + } while (0) + +/* Globally enable the break/watchpoint in the I'th debug register. */ +#define I386_DR_GLOBAL_ENABLE(state, i) \ + do { \ + (state)->dr_control_mirror |= \ + (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))); \ + } while (0) + +/* Disable the break/watchpoint in the I'th debug register. */ +#define I386_DR_DISABLE(state, i) \ + do { \ + (state)->dr_control_mirror &= \ + ~(3 << (DR_ENABLE_SIZE * (i))); \ + } while (0) + +/* Set in DR7 the RW and LEN fields for the I'th debug register. */ +#define I386_DR_SET_RW_LEN(state, i,rwlen) \ + do { \ + (state)->dr_control_mirror &= \ + ~(0x0f << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \ + (state)->dr_control_mirror |= \ + ((rwlen) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \ + } while (0) + +/* Get from DR7 the RW and LEN fields for the I'th debug register. */ +#define I386_DR_GET_RW_LEN(dr7, i) \ + (((dr7) \ + >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) + +/* Did the watchpoint whose address is in the I'th register break? */ +#define I386_DR_WATCH_HIT(dr6, i) ((dr6) & (1 << (i))) + +/* A macro to loop over all debug registers. */ +#define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) + +#endif diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 1fabe59..e70c8b5 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -402,7 +402,7 @@ vasprintf.o: $(srcdir)/../../libiberty/vasprintf.c vsnprintf.o: $(srcdir)/../../libiberty/vsnprintf.c $(CC) -o vsnprintf.o -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -i386_low_h = $(srcdir)/i386-low.h +i386_low_h = $(srcdir)/i386-low.h $(srcdir)/../common/i386-dbg-reg.h i386-low.o: i386-low.c $(i386_low_h) $(server_h) $(target_h) diff --git a/gdb/gdbserver/i386-low.c b/gdb/gdbserver/i386-low.c index 1baa23d..ca157b7 100644 --- a/gdb/gdbserver/i386-low.c +++ b/gdb/gdbserver/i386-low.c @@ -21,11 +21,7 @@ #include "target.h" #include "i386-low.h" -/* Support for 8-byte wide hw watchpoints. */ -#ifndef TARGET_HAS_DR_LEN_8 -/* NOTE: sizeof (long) == 4 on win64. */ -#define TARGET_HAS_DR_LEN_8 (sizeof (void *) == 8) -#endif +struct i386_dr_low_type i386_dr_low; enum target_hw_bp_type { @@ -35,120 +31,18 @@ enum target_hw_bp_type hw_execute = 3 /* Execute HW breakpoint */ }; -/* DR7 Debug Control register fields. */ - -/* How many bits to skip in DR7 to get to R/W and LEN fields. */ -#define DR_CONTROL_SHIFT 16 -/* How many bits in DR7 per R/W and LEN field for each watchpoint. */ -#define DR_CONTROL_SIZE 4 - -/* Watchpoint/breakpoint read/write fields in DR7. */ -#define DR_RW_EXECUTE (0x0) /* Break on instruction execution. */ -#define DR_RW_WRITE (0x1) /* Break on data writes. */ -#define DR_RW_READ (0x3) /* Break on data reads or writes. */ - -/* This is here for completeness. No platform supports this - functionality yet (as of March 2001). Note that the DE flag in the - CR4 register needs to be set to support this. */ -#ifndef DR_RW_IORW -#define DR_RW_IORW (0x2) /* Break on I/O reads or writes. */ -#endif +static void +i386_set_debug_register_length (int len) +{ + gdb_assert (i386_dr_low.debug_register_length == 0); + gdb_assert (len == 4 || len == 8); + i386_dr_low.debug_register_length = len; +} -/* Watchpoint/breakpoint length fields in DR7. The 2-bit left shift - is so we could OR this with the read/write field defined above. */ -#define DR_LEN_1 (0x0 << 2) /* 1-byte region watch or breakpoint. */ -#define DR_LEN_2 (0x1 << 2) /* 2-byte region watch. */ -#define DR_LEN_4 (0x3 << 2) /* 4-byte region watch. */ -#define DR_LEN_8 (0x2 << 2) /* 8-byte region watch (AMD64). */ - -/* Local and Global Enable flags in DR7. - - When the Local Enable flag is set, the breakpoint/watchpoint is - enabled only for the current task; the processor automatically - clears this flag on every task switch. When the Global Enable flag - is set, the breakpoint/watchpoint is enabled for all tasks; the - processor never clears this flag. - - Currently, all watchpoint are locally enabled. If you need to - enable them globally, read the comment which pertains to this in - i386_insert_aligned_watchpoint below. */ -#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ -#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ -#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ - -/* Local and global exact breakpoint enable flags (a.k.a. slowdown - flags). These are only required on i386, to allow detection of the - exact instruction which caused a watchpoint to break; i486 and - later processors do that automatically. We set these flags for - backwards compatibility. */ -#define DR_LOCAL_SLOWDOWN (0x100) -#define DR_GLOBAL_SLOWDOWN (0x200) - -/* Fields reserved by Intel. This includes the GD (General Detect - Enable) flag, which causes a debug exception to be generated when a - MOV instruction accesses one of the debug registers. - - FIXME: My Intel manual says we should use 0xF800, not 0xFC00. */ -#define DR_CONTROL_RESERVED (0xFC00) - -/* Auxiliary helper macros. */ - -/* A value that masks all fields in DR7 that are reserved by Intel. */ -#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED) - -/* The I'th debug register is vacant if its Local and Global Enable - bits are reset in the Debug Control register. */ -#define I386_DR_VACANT(state, i) \ - (((state)->dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0) - -/* Locally enable the break/watchpoint in the I'th debug register. */ -#define I386_DR_LOCAL_ENABLE(state, i) \ - do { \ - (state)->dr_control_mirror |= \ - (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))); \ - } while (0) - -/* Globally enable the break/watchpoint in the I'th debug register. */ -#define I386_DR_GLOBAL_ENABLE(state, i) \ - do { \ - (state)->dr_control_mirror |= \ - (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))); \ - } while (0) - -/* Disable the break/watchpoint in the I'th debug register. */ -#define I386_DR_DISABLE(state, i) \ - do { \ - (state)->dr_control_mirror &= \ - ~(3 << (DR_ENABLE_SIZE * (i))); \ - } while (0) - -/* Set in DR7 the RW and LEN fields for the I'th debug register. */ -#define I386_DR_SET_RW_LEN(state, i,rwlen) \ - do { \ - (state)->dr_control_mirror &= \ - ~(0x0f << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \ - (state)->dr_control_mirror |= \ - ((rwlen) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \ - } while (0) - -/* Get from DR7 the RW and LEN fields for the I'th debug register. */ -#define I386_DR_GET_RW_LEN(dr7, i) \ - (((dr7) \ - >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) - -/* Did the watchpoint whose address is in the I'th register break? */ -#define I386_DR_WATCH_HIT(dr6, i) ((dr6) & (1 << (i))) - -/* A macro to loop over all debug registers. */ -#define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) - -/* Types of operations supported by i386_handle_nonaligned_watchpoint. */ -typedef enum { WP_INSERT, WP_REMOVE, WP_COUNT } i386_wp_op_t; - /* Implementation. */ /* Clear the reference counts and forget everything we knew about the - debug registers. */ + debug registers. Also set the length of debug register. */ void i386_low_init_dregs (struct i386_debug_reg_state *state) @@ -162,6 +56,8 @@ i386_low_init_dregs (struct i386_debug_reg_state *state) } state->dr_control_mirror = 0; state->dr_status_mirror = 0; + + i386_set_debug_register_length (sizeof (void *)); } /* Print the values of the mirrored debug registers. This is enabled via diff --git a/gdb/gdbserver/i386-low.h b/gdb/gdbserver/i386-low.h index bbfbc10..97b3464 100644 --- a/gdb/gdbserver/i386-low.h +++ b/gdb/gdbserver/i386-low.h @@ -29,29 +29,12 @@ counts, and allow to watch regions up to 16 bytes long (32 bytes on 64 bit hosts). */ +#include "i386-dbg-reg.h" /* Debug registers' indices. */ #define DR_FIRSTADDR 0 #define DR_LASTADDR 3 -#define DR_NADDR 4 /* The number of debug address registers. */ -#define DR_STATUS 6 -#define DR_CONTROL 7 - -/* Global state needed to track h/w watchpoints. */ - -struct i386_debug_reg_state -{ - /* Mirror the inferior's DRi registers. We keep the status and - control registers separated because they don't hold addresses. - Note that since we can change these mirrors while threads are - running, we never trust them to explain a cause of a trap. - For that, we need to peek directly in the inferior registers. */ - CORE_ADDR dr_mirror[DR_NADDR]; - unsigned dr_status_mirror, dr_control_mirror; - - /* Reference counts for each debug register. */ - int dr_ref_count[DR_NADDR]; -}; + /* Initialize STATE. */ extern void i386_low_init_dregs (struct i386_debug_reg_state *state); diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c index 7e6814e..50b9ee6 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -39,127 +39,13 @@ struct i386_dr_low_type i386_dr_low; - -/* Support for 8-byte wide hw watchpoints. */ -#define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8) - -/* Debug registers' indices. */ -#define DR_NADDR 4 /* The number of debug address registers. */ -#define DR_STATUS 6 /* Index of debug status register (DR6). */ -#define DR_CONTROL 7 /* Index of debug control register (DR7). */ - -/* DR7 Debug Control register fields. */ - -/* How many bits to skip in DR7 to get to R/W and LEN fields. */ -#define DR_CONTROL_SHIFT 16 -/* How many bits in DR7 per R/W and LEN field for each watchpoint. */ -#define DR_CONTROL_SIZE 4 - -/* Watchpoint/breakpoint read/write fields in DR7. */ -#define DR_RW_EXECUTE (0x0) /* Break on instruction execution. */ -#define DR_RW_WRITE (0x1) /* Break on data writes. */ -#define DR_RW_READ (0x3) /* Break on data reads or writes. */ - -/* This is here for completeness. No platform supports this - functionality yet (as of March 2001). Note that the DE flag in the - CR4 register needs to be set to support this. */ -#ifndef DR_RW_IORW -#define DR_RW_IORW (0x2) /* Break on I/O reads or writes. */ -#endif - -/* Watchpoint/breakpoint length fields in DR7. The 2-bit left shift - is so we could OR this with the read/write field defined above. */ -#define DR_LEN_1 (0x0 << 2) /* 1-byte region watch or breakpoint. */ -#define DR_LEN_2 (0x1 << 2) /* 2-byte region watch. */ -#define DR_LEN_4 (0x3 << 2) /* 4-byte region watch. */ -#define DR_LEN_8 (0x2 << 2) /* 8-byte region watch (AMD64). */ - -/* Local and Global Enable flags in DR7. - - When the Local Enable flag is set, the breakpoint/watchpoint is - enabled only for the current task; the processor automatically - clears this flag on every task switch. When the Global Enable flag - is set, the breakpoint/watchpoint is enabled for all tasks; the - processor never clears this flag. - - Currently, all watchpoint are locally enabled. If you need to - enable them globally, read the comment which pertains to this in - i386_insert_aligned_watchpoint below. */ -#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */ -#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */ -#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */ - -/* Local and global exact breakpoint enable flags (a.k.a. slowdown - flags). These are only required on i386, to allow detection of the - exact instruction which caused a watchpoint to break; i486 and - later processors do that automatically. We set these flags for - backwards compatibility. */ -#define DR_LOCAL_SLOWDOWN (0x100) -#define DR_GLOBAL_SLOWDOWN (0x200) - -/* Fields reserved by Intel. This includes the GD (General Detect - Enable) flag, which causes a debug exception to be generated when a - MOV instruction accesses one of the debug registers. - - FIXME: My Intel manual says we should use 0xF800, not 0xFC00. */ -#define DR_CONTROL_RESERVED (0xFC00) - -/* Auxiliary helper macros. */ - -/* A value that masks all fields in DR7 that are reserved by Intel. */ -#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED) - -/* The I'th debug register is vacant if its Local and Global Enable - bits are reset in the Debug Control register. */ -#define I386_DR_VACANT(i) \ - ((dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0) - -/* Locally enable the break/watchpoint in the I'th debug register. */ -#define I386_DR_LOCAL_ENABLE(i) \ - dr_control_mirror |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) - -/* Globally enable the break/watchpoint in the I'th debug register. */ -#define I386_DR_GLOBAL_ENABLE(i) \ - dr_control_mirror |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) - -/* Disable the break/watchpoint in the I'th debug register. */ -#define I386_DR_DISABLE(i) \ - dr_control_mirror &= ~(3 << (DR_ENABLE_SIZE * (i))) - -/* Set in DR7 the RW and LEN fields for the I'th debug register. */ -#define I386_DR_SET_RW_LEN(i,rwlen) \ - do { \ - dr_control_mirror &= ~(0x0f << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \ - dr_control_mirror |= ((rwlen) << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \ - } while (0) - -/* Get from DR7 the RW and LEN fields for the I'th debug register. */ -#define I386_DR_GET_RW_LEN(i) \ - ((dr_control_mirror >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) - -/* Mask that this I'th watchpoint has triggered. */ -#define I386_DR_WATCH_MASK(i) (1 << (i)) - -/* Did the watchpoint whose address is in the I'th register break? */ -#define I386_DR_WATCH_HIT(i) (dr_status_mirror & I386_DR_WATCH_MASK (i)) - -/* A macro to loop over all debug registers. */ -#define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) - /* Mirror the inferior's DRi registers. We keep the status and control registers separated because they don't hold addresses. */ -static CORE_ADDR dr_mirror[DR_NADDR]; -static unsigned long dr_status_mirror, dr_control_mirror; - -/* Reference counts for each debug register. */ -static int dr_ref_count[DR_NADDR]; +static struct i386_debug_reg_state state; /* Whether or not to print the mirrored debug registers. */ static int maint_show_dr; -/* Types of operations supported by i386_handle_nonaligned_watchpoint. */ -typedef enum { WP_INSERT, WP_REMOVE, WP_COUNT } i386_wp_op_t; - /* Internal functions. */ /* Return the value of a 4-bit field for DR7 suitable for watching a @@ -172,7 +58,8 @@ static unsigned i386_length_and_rw_bits (int len, enum target_hw_bp_type type); value of the bit-field from DR7 which describes the length and access type of the region to be watched by this watchpoint. Return 0 on success, -1 on failure. */ -static int i386_insert_aligned_watchpoint (CORE_ADDR addr, +static int i386_insert_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits); /* Remove a watchpoint at address ADDR, which is assumed to be aligned @@ -180,7 +67,8 @@ static int i386_insert_aligned_watchpoint (CORE_ADDR addr, value of the bits from DR7 which describes the length and access type of the region watched by this watchpoint. Return 0 on success, -1 on failure. */ -static int i386_remove_aligned_watchpoint (CORE_ADDR addr, +static int i386_remove_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits); /* Insert or remove a (possibly non-aligned) watchpoint, or count the @@ -189,7 +77,8 @@ static int i386_remove_aligned_watchpoint (CORE_ADDR addr, successful insertion or removal, a positive number when queried about the number of registers, or -1 on failure. If WHAT is not a valid value, bombs through internal_error. */ -static int i386_handle_nonaligned_watchpoint (i386_wp_op_t what, +static int i386_handle_nonaligned_watchpoint (struct i386_debug_reg_state *state, + i386_wp_op_t what, CORE_ADDR addr, int len, enum target_hw_bp_type type); @@ -205,11 +94,11 @@ i386_cleanup_dregs (void) ALL_DEBUG_REGISTERS(i) { - dr_mirror[i] = 0; - dr_ref_count[i] = 0; + state.dr_mirror[i] = 0; + state.dr_ref_count[i] = 0; } - dr_control_mirror = 0; - dr_status_mirror = 0; + state.dr_control_mirror = 0; + state.dr_status_mirror = 0; } /* Print the values of the mirrored debug registers. This is called @@ -217,8 +106,8 @@ i386_cleanup_dregs (void) show-debug-regs" at GDB's prompt. */ static void -i386_show_dr (const char *func, CORE_ADDR addr, - int len, enum target_hw_bp_type type) +i386_show_dr (struct i386_debug_reg_state *state, const char *func, + CORE_ADDR addr, int len, enum target_hw_bp_type type) { int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; int i; @@ -239,13 +128,16 @@ i386_show_dr (const char *func, CORE_ADDR addr, : "??unknown??")))); puts_unfiltered (":\n"); printf_unfiltered ("\tCONTROL (DR7): %s STATUS (DR6): %s\n", - phex (dr_control_mirror, 8), phex (dr_status_mirror, 8)); + phex (state->dr_control_mirror, 8), + phex (state->dr_status_mirror, 8)); ALL_DEBUG_REGISTERS(i) { printf_unfiltered ("\ \tDR%d: addr=0x%s, ref.count=%d DR%d: addr=0x%s, ref.count=%d\n", - i, phex (dr_mirror[i], addr_size), dr_ref_count[i], - i+1, phex (dr_mirror[i+1], addr_size), dr_ref_count[i+1]); + i, phex (state->dr_mirror[i], addr_size), + state->dr_ref_count[i], i+1, + phex (state->dr_mirror[i+1], addr_size), + state->dr_ref_count[i+1]); i++; } } @@ -311,7 +203,8 @@ Invalid hardware breakpoint length %d in i386_length_and_rw_bits.\n"), len); success, -1 on failure. */ static int -i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) +i386_insert_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits) { int i; @@ -323,11 +216,11 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) reuse it for this watchpoint as well (and save a register). */ ALL_DEBUG_REGISTERS(i) { - if (!I386_DR_VACANT (i) - && dr_mirror[i] == addr - && I386_DR_GET_RW_LEN (i) == len_rw_bits) + if (!I386_DR_VACANT (state, i) + && state->dr_mirror[i] == addr + && I386_DR_GET_RW_LEN (state->dr_control_mirror, i) == len_rw_bits) { - dr_ref_count[i]++; + state->dr_ref_count[i]++; return 0; } } @@ -335,7 +228,7 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) /* Next, look for a vacant debug register. */ ALL_DEBUG_REGISTERS(i) { - if (I386_DR_VACANT (i)) + if (I386_DR_VACANT (state, i)) break; } @@ -346,9 +239,9 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) /* Now set up the register I to watch our region. */ /* Record the info in our local mirrored array. */ - dr_mirror[i] = addr; - dr_ref_count[i] = 1; - I386_DR_SET_RW_LEN (i, len_rw_bits); + state->dr_mirror[i] = addr; + state->dr_ref_count[i] = 1; + I386_DR_SET_RW_LEN (state, i, len_rw_bits); /* Note: we only enable the watchpoint locally, i.e. in the current task. Currently, no i386 target allows or supports global watchpoints; however, if any target would want that in the @@ -356,17 +249,17 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) to enable watchpoints globally or locally, and the code below should use global or local enable and slow-down flags as appropriate. */ - I386_DR_LOCAL_ENABLE (i); - dr_control_mirror |= DR_LOCAL_SLOWDOWN; - dr_control_mirror &= I386_DR_CONTROL_MASK; + I386_DR_LOCAL_ENABLE (state, i); + state->dr_control_mirror |= DR_LOCAL_SLOWDOWN; + state->dr_control_mirror &= I386_DR_CONTROL_MASK; /* Finally, actually pass the info to the inferior. */ i386_dr_low.set_addr (i, addr); - i386_dr_low.set_control (dr_control_mirror); + i386_dr_low.set_control (state->dr_control_mirror); /* Only a sanity check for leftover bits (set possibly only by inferior). */ if (i386_dr_low.unset_status) - i386_dr_low.unset_status (I386_DR_WATCH_MASK (i)); + i386_dr_low.unset_status ((1<dr_mirror[i] == addr + && I386_DR_GET_RW_LEN (state->dr_control_mirror, i) == len_rw_bits) { - if (--dr_ref_count[i] == 0) /* no longer in use? */ + if (--state->dr_ref_count[i] == 0) /* no longer in use? */ { /* Reset our mirror. */ - dr_mirror[i] = 0; - I386_DR_DISABLE (i); + state->dr_mirror[i] = 0; + I386_DR_DISABLE (state, i); /* Reset it in the inferior. */ - i386_dr_low.set_control (dr_control_mirror); + i386_dr_low.set_control (state->dr_control_mirror); if (i386_dr_low.reset_addr) i386_dr_low.reset_addr (i); } @@ -413,7 +307,8 @@ i386_remove_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) valid value, bombs through internal_error. */ static int -i386_handle_nonaligned_watchpoint (i386_wp_op_t what, CORE_ADDR addr, int len, +i386_handle_nonaligned_watchpoint (struct i386_debug_reg_state *state, + i386_wp_op_t what, CORE_ADDR addr, int len, enum target_hw_bp_type type) { int retval = 0, status = 0; @@ -454,9 +349,9 @@ i386_handle_nonaligned_watchpoint (i386_wp_op_t what, CORE_ADDR addr, int len, unsigned len_rw = i386_length_and_rw_bits (size, type); if (what == WP_INSERT) - status = i386_insert_aligned_watchpoint (addr, len_rw); + status = i386_insert_aligned_watchpoint (state, addr, len_rw); else if (what == WP_REMOVE) - status = i386_remove_aligned_watchpoint (addr, len_rw); + status = i386_remove_aligned_watchpoint (state, addr, len_rw); else internal_error (__FILE__, __LINE__, _("\ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"), @@ -496,16 +391,17 @@ i386_insert_watchpoint (CORE_ADDR addr, int len, int type, if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8)) || addr % len != 0) - retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type); + retval = i386_handle_nonaligned_watchpoint (&state, WP_INSERT, addr, len, + type); else { unsigned len_rw = i386_length_and_rw_bits (len, type); - retval = i386_insert_aligned_watchpoint (addr, len_rw); + retval = i386_insert_aligned_watchpoint (&state, addr, len_rw); } if (maint_show_dr) - i386_show_dr ("insert_watchpoint", addr, len, type); + i386_show_dr (&state, "insert_watchpoint", addr, len, type); return retval; } @@ -521,16 +417,17 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type, if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8)) || addr % len != 0) - retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type); + retval = i386_handle_nonaligned_watchpoint (&state, WP_REMOVE, addr, len, + type); else { unsigned len_rw = i386_length_and_rw_bits (len, type); - retval = i386_remove_aligned_watchpoint (addr, len_rw); + retval = i386_remove_aligned_watchpoint (&state, addr, len_rw); } if (maint_show_dr) - i386_show_dr ("remove_watchpoint", addr, len, type); + i386_show_dr (&state, "remove_watchpoint", addr, len, type); return retval; } @@ -545,7 +442,8 @@ i386_region_ok_for_watchpoint (CORE_ADDR addr, int len) /* Compute how many aligned watchpoints we would need to cover this region. */ - nregs = i386_handle_nonaligned_watchpoint (WP_COUNT, addr, len, hw_write); + nregs = i386_handle_nonaligned_watchpoint (&state, WP_COUNT, addr, len, + hw_write); return nregs <= DR_NADDR ? 1 : 0; } @@ -560,29 +458,29 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) int i; int rc = 0; - dr_status_mirror = i386_dr_low.get_status (); + state.dr_status_mirror = i386_dr_low.get_status (); ALL_DEBUG_REGISTERS(i) { - if (I386_DR_WATCH_HIT (i) + if (I386_DR_WATCH_HIT (state.dr_status_mirror, i) /* This second condition makes sure DRi is set up for a data watchpoint, not a hardware breakpoint. The reason is that GDB doesn't call the target_stopped_data_address method except for data watchpoints. In other words, I'm being paranoiac. */ - && I386_DR_GET_RW_LEN (i) != 0 + && I386_DR_GET_RW_LEN (state.dr_control_mirror, i) != 0 /* This third condition makes sure DRi is not vacant, this avoids false positives in windows-nat.c. */ - && !I386_DR_VACANT (i)) + && !I386_DR_VACANT (&state, i)) { - addr = dr_mirror[i]; + addr = state.dr_mirror[i]; rc = 1; if (maint_show_dr) - i386_show_dr ("watchpoint_hit", addr, -1, hw_write); + i386_show_dr (&state, "watchpoint_hit", addr, -1, hw_write); } } if (maint_show_dr && addr == 0) - i386_show_dr ("stopped_data_addr", 0, 0, hw_write); + i386_show_dr (&state, "stopped_data_addr", 0, 0, hw_write); if (rc) *addr_p = addr; @@ -604,10 +502,11 @@ i386_insert_hw_breakpoint (struct gdbarch *gdbarch, { unsigned len_rw = i386_length_and_rw_bits (1, hw_execute); CORE_ADDR addr = bp_tgt->placed_address; - int retval = i386_insert_aligned_watchpoint (addr, len_rw) ? EBUSY : 0; + int retval = i386_insert_aligned_watchpoint (&state, addr, len_rw) + ? EBUSY : 0; if (maint_show_dr) - i386_show_dr ("insert_hwbp", addr, 1, hw_execute); + i386_show_dr (&state, "insert_hwbp", addr, 1, hw_execute); return retval; } @@ -621,10 +520,10 @@ i386_remove_hw_breakpoint (struct gdbarch *gdbarch, { unsigned len_rw = i386_length_and_rw_bits (1, hw_execute); CORE_ADDR addr = bp_tgt->placed_address; - int retval = i386_remove_aligned_watchpoint (addr, len_rw); + int retval = i386_remove_aligned_watchpoint (&state, addr, len_rw); if (maint_show_dr) - i386_show_dr ("remove_hwbp", addr, 1, hw_execute); + i386_show_dr (&state, "remove_hwbp", addr, 1, hw_execute); return retval; } diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h index 819c6b8..c990229 100644 --- a/gdb/i386-nat.h +++ b/gdb/i386-nat.h @@ -21,6 +21,7 @@ along with this program. If not, see . */ #include "defs.h" +#include "i386-dbg-reg.h" #ifndef I386_NAT_H #define I386_NAT_H 1 @@ -33,50 +34,6 @@ struct target_ops; extern void i386_use_watchpoints (struct target_ops *); -/* Support for hardware watchpoints and breakpoints using the i386 - debug registers. - - This provides several functions for inserting and removing - hardware-assisted breakpoints and watchpoints, testing if one or - more of the watchpoints triggered and at what address, checking - whether a given region can be watched, etc. - - In addition, each target should provide several low-level functions - regrouped into i386_dr_low_type struct below. These functions - that will be called to insert watchpoints and hardware breakpoints - into the inferior, remove them, and check their status. These - functions are: - - set_control -- set the debug control (DR7) - register to a given value for all LWPs - - set_addr -- put an address into one debug - register for all LWPs - - reset_addr -- reset the address stored in - one debug register for all LWPs - - get_status -- return the value of the debug - status (DR6) register for current LWP - - unset_status -- unset the specified bits of the debug - status (DR6) register for all LWPs - - Additionally, the native file should set the debug_register_length - field to 4 or 8 depending on the number of bytes used for - deubg registers. */ - -struct i386_dr_low_type - { - void (*set_control) (unsigned long); - void (*set_addr) (int, CORE_ADDR); - void (*reset_addr) (int); - unsigned long (*get_status) (void); - void (*unset_status) (unsigned long); - int debug_register_length; - }; - -extern struct i386_dr_low_type i386_dr_low; /* Use this function to set i386_dr_low debug_register_length field rather than setting it directly to check that the length is only --------------070002020106000209030607--