mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-28 12:33:36 +08:00
* config/i386/nm-go32.h <top level>: Don't include nm-i386v.h,
include nm-i386.h instead. (TARGET_HAS_HARDWARE_WATCHPOINTS, HAVE_CONTINUABLE_WATCHPOINT) (TARGET_CAN_USE_HARDWARE_WATCHPOINT, STOPPED_BY_WATCHPOINT) (TARGET_REGION_OK_FOR_HW_WATCHPOINT, DECR_PC_AFTER_HW_BREAK) (target_stopped_data_address, target_insert_watchpoint) (target_remove_watchpoint, target_insert_hw_breakpoint) (target_remove_hw_breakpoint): Don't define. (I386_USE_GENERIC_WATCHPOINTS, I386_DR_LOW_SET_CONTROL) (I386_DR_LOW_SET_ADDR, I386_DR_LOW_RESET_ADDR) (I386_DR_LOW_GET_STATUS): Define to call appropriate go32_* functions from go32-nat.c. * config/i386/go32.mh (NATDEPFILES): Add i386-nat.o. * go32-nat.c <top level>: Remove prototypes for watchpoint- related functions. Remove definitions of watchpoint-related macros. (go32_mourn_inferior): Call i386_cleanup_dregs instead of the private cleanup_dregs function. (cleanup_dregs, go32_insert_watchpoint) (go32_insert_aligned_watchpoint, go32_handle_nonaligned_watchpoint) (go32_remove_watchpoint, go32_remove_aligned_watchpoint) (go32_region_ok_for_watchpoint, go32_stopped_by_watchpoint) (go32_remove_hw_breakpoint, go32_insert_hw_breakpoint): Remove. (go32_set_dr, go32_set_dr7, go32_get_dr6): New functions.
This commit is contained in:
parent
469b781cfb
commit
e24d4c64ff
@ -1,3 +1,35 @@
|
||||
2001-03-22 Eli Zaretskii <eliz@is.elta.co.il>
|
||||
|
||||
Make DJGPP use the new unified support for hardware
|
||||
breakpoints and watchpoints on x86 targets:
|
||||
|
||||
* config/i386/nm-go32.h <top level>: Don't include nm-i386v.h,
|
||||
include nm-i386.h instead.
|
||||
(TARGET_HAS_HARDWARE_WATCHPOINTS, HAVE_CONTINUABLE_WATCHPOINT)
|
||||
(TARGET_CAN_USE_HARDWARE_WATCHPOINT, STOPPED_BY_WATCHPOINT)
|
||||
(TARGET_REGION_OK_FOR_HW_WATCHPOINT, DECR_PC_AFTER_HW_BREAK)
|
||||
(target_stopped_data_address, target_insert_watchpoint)
|
||||
(target_remove_watchpoint, target_insert_hw_breakpoint)
|
||||
(target_remove_hw_breakpoint): Don't define.
|
||||
(I386_USE_GENERIC_WATCHPOINTS, I386_DR_LOW_SET_CONTROL)
|
||||
(I386_DR_LOW_SET_ADDR, I386_DR_LOW_RESET_ADDR)
|
||||
(I386_DR_LOW_GET_STATUS): Define to call appropriate go32_*
|
||||
functions from go32-nat.c.
|
||||
|
||||
* config/i386/go32.mh (NATDEPFILES): Add i386-nat.o.
|
||||
|
||||
* go32-nat.c <top level>: Remove prototypes for watchpoint-
|
||||
related functions. Remove definitions of watchpoint-related
|
||||
macros.
|
||||
(go32_mourn_inferior): Call i386_cleanup_dregs instead of the
|
||||
private cleanup_dregs function.
|
||||
(cleanup_dregs, go32_insert_watchpoint)
|
||||
(go32_insert_aligned_watchpoint, go32_handle_nonaligned_watchpoint)
|
||||
(go32_remove_watchpoint, go32_remove_aligned_watchpoint)
|
||||
(go32_region_ok_for_watchpoint, go32_stopped_by_watchpoint)
|
||||
(go32_remove_hw_breakpoint, go32_insert_hw_breakpoint): Remove.
|
||||
(go32_set_dr, go32_set_dr7, go32_get_dr6): New functions.
|
||||
|
||||
2001-03-21 Kevin Buettner <kevinb@redhat.com>
|
||||
|
||||
* ia64-tdep.c (fetch_instruction): Warn about slot numbers greater
|
||||
|
@ -8,9 +8,9 @@ XM_FILE= xm-go32.h
|
||||
XDEPFILES=
|
||||
|
||||
NAT_FILE= nm-go32.h
|
||||
NATDEPFILES= go32-nat.o i387-nat.o
|
||||
NATDEPFILES= go32-nat.o i386-nat.o i387-nat.o
|
||||
|
||||
TERMCAP=
|
||||
TERMCAP=
|
||||
HOST_IPC=
|
||||
CC= gcc
|
||||
XM_CLIBS= -ldbg
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Native definitions for Intel x86 running DJGPP.
|
||||
Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
|
||||
Copyright (C) 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
@ -20,65 +20,19 @@
|
||||
|
||||
#define NO_PTRACE_H
|
||||
|
||||
#include "i386/nm-i386v.h"
|
||||
#define I386_USE_GENERIC_WATCHPOINTS
|
||||
|
||||
#define TARGET_HAS_HARDWARE_WATCHPOINTS
|
||||
#include "i386/nm-i386.h"
|
||||
|
||||
/* Returns the number of hardware watchpoints of type TYPE that we can
|
||||
set. Value is positive if we can set CNT watchpoints, zero if
|
||||
setting watchpoints of type TYPE is not supported, and negative if
|
||||
CNT is more than the maximum number of watchpoints of type TYPE
|
||||
that we can support. TYPE is one of bp_hardware_watchpoint,
|
||||
bp_read_watchpoint, bp_write_watchpoint, or bp_hardware_breakpoint.
|
||||
CNT is the number of such watchpoints used so far (including this
|
||||
one). OTHERTYPE is non-zero if other types of watchpoints are
|
||||
currently enabled.
|
||||
/* Support for hardware-assisted breakpoints and watchpoints. */
|
||||
|
||||
We always return 1 here because we don't have enough information
|
||||
about possible overlap of addresses that they want to watch. As
|
||||
an extreme example, consider the case where all the watchpoints
|
||||
watch the same address and the same region length: then we can
|
||||
handle a virtually unlimited number of watchpoints, due to debug
|
||||
register sharing implemented via reference counts in go32-nat.c. */
|
||||
#define I386_DR_LOW_SET_CONTROL(VAL) go32_set_dr7 (VAL)
|
||||
extern void go32_set_dr7 (unsigned);
|
||||
|
||||
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
|
||||
#define I386_DR_LOW_SET_ADDR(N,ADDR) go32_set_dr (N,ADDR)
|
||||
extern void go32_set_dr (int, CORE_ADDR);
|
||||
|
||||
/* Returns non-zero if we can use hardware watchpoints to watch a region
|
||||
whose address is ADDR and whose length is LEN. */
|
||||
#define I386_DR_LOW_RESET_ADDR(N)
|
||||
|
||||
#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr,len) \
|
||||
go32_region_ok_for_watchpoint(addr,len)
|
||||
extern int go32_region_ok_for_watchpoint (CORE_ADDR, int);
|
||||
|
||||
/* After a watchpoint trap, the PC points to the instruction after the
|
||||
one that caused the trap. Therefore we don't need to step over it.
|
||||
But we do need to reset the status register to avoid another trap. */
|
||||
|
||||
#define HAVE_CONTINUABLE_WATCHPOINT
|
||||
|
||||
#define STOPPED_BY_WATCHPOINT(W) \
|
||||
go32_stopped_by_watchpoint (inferior_pid, 0)
|
||||
|
||||
#define target_stopped_data_address() \
|
||||
go32_stopped_by_watchpoint (inferior_pid, 1)
|
||||
extern CORE_ADDR go32_stopped_by_watchpoint (int, int);
|
||||
|
||||
/* Use these macros for watchpoint insertion/removal. */
|
||||
|
||||
#define target_insert_watchpoint(addr, len, type) \
|
||||
go32_insert_watchpoint (inferior_pid, addr, len, type)
|
||||
extern int go32_insert_watchpoint (int, CORE_ADDR, int, int);
|
||||
|
||||
#define target_remove_watchpoint(addr, len, type) \
|
||||
go32_remove_watchpoint (inferior_pid, addr, len, type)
|
||||
extern int go32_remove_watchpoint (int, CORE_ADDR, int, int);
|
||||
|
||||
#define target_insert_hw_breakpoint(addr, shadow) \
|
||||
go32_insert_hw_breakpoint(addr, shadow)
|
||||
extern int go32_insert_hw_breakpoint (CORE_ADDR, void *);
|
||||
|
||||
#define target_remove_hw_breakpoint(addr, shadow) \
|
||||
go32_remove_hw_breakpoint(addr, shadow)
|
||||
extern int go32_remove_hw_breakpoint (CORE_ADDR, void *);
|
||||
|
||||
#define DECR_PC_AFTER_HW_BREAK 0
|
||||
#define I386_DR_LOW_GET_STATUS() go32_get_dr6 ()
|
||||
extern unsigned go32_get_dr6 (void);
|
||||
|
409
gdb/go32-nat.c
409
gdb/go32-nat.c
@ -1,5 +1,5 @@
|
||||
/* Native debugging support for Intel x86 running DJGPP.
|
||||
Copyright 1997, 1999, 2001 Free Software Foundation, Inc.
|
||||
Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
Written by Robert Hoehne.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -166,15 +166,8 @@ static void go32_files_info (struct target_ops *target);
|
||||
static void go32_stop (void);
|
||||
static void go32_kill_inferior (void);
|
||||
static void go32_create_inferior (char *exec_file, char *args, char **env);
|
||||
static void cleanup_dregs (void);
|
||||
static void go32_mourn_inferior (void);
|
||||
static int go32_can_run (void);
|
||||
static int go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
|
||||
int len, int rw);
|
||||
static int go32_remove_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
|
||||
int len, int rw);
|
||||
static int go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr,
|
||||
CORE_ADDR addr, int len, int rw);
|
||||
|
||||
static struct target_ops go32_ops;
|
||||
static void go32_terminal_init (void);
|
||||
@ -645,7 +638,7 @@ go32_mourn_inferior (void)
|
||||
be nice if GDB itself would take care to remove all breakpoints
|
||||
at all times, but it doesn't, probably under an assumption that
|
||||
the OS cleans up when the debuggee exits. */
|
||||
cleanup_dregs ();
|
||||
i386_cleanup_dregs ();
|
||||
go32_kill_inferior ();
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
@ -658,393 +651,35 @@ go32_can_run (void)
|
||||
|
||||
/* Hardware watchpoint support. */
|
||||
|
||||
#define DR_STATUS 6
|
||||
#define DR_CONTROL 7
|
||||
#define DR_ENABLE_SIZE 2
|
||||
#define DR_LOCAL_ENABLE_SHIFT 0
|
||||
#define DR_GLOBAL_ENABLE_SHIFT 1
|
||||
#define DR_LOCAL_SLOWDOWN 0x100
|
||||
#define DR_GLOBAL_SLOWDOWN 0x200
|
||||
#define DR_CONTROL_SHIFT 16
|
||||
#define DR_CONTROL_SIZE 4
|
||||
#define DR_RW_READWRITE 0x3
|
||||
#define DR_RW_WRITE 0x1
|
||||
#define DR_CONTROL_MASK 0xf
|
||||
#define DR_ENABLE_MASK 0x3
|
||||
#define DR_LEN_1 0x0
|
||||
#define DR_LEN_2 0x4
|
||||
#define DR_LEN_4 0xc
|
||||
|
||||
#define D_REGS edi.dr
|
||||
#define CONTROL D_REGS[DR_CONTROL]
|
||||
#define STATUS D_REGS[DR_STATUS]
|
||||
#define CONTROL D_REGS[7]
|
||||
#define STATUS D_REGS[6]
|
||||
|
||||
#define IS_REG_FREE(index) \
|
||||
(!(CONTROL & (3 << (DR_ENABLE_SIZE * (index)))))
|
||||
|
||||
#define LOCAL_ENABLE_REG(index) \
|
||||
(CONTROL |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
|
||||
|
||||
#define GLOBAL_ENABLE_REG(index) \
|
||||
(CONTROL |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
|
||||
|
||||
#define DISABLE_REG(index) \
|
||||
(CONTROL &= ~(3 << (DR_ENABLE_SIZE * (index))))
|
||||
|
||||
#define SET_LOCAL_EXACT() \
|
||||
(CONTROL |= DR_LOCAL_SLOWDOWN)
|
||||
|
||||
#define SET_GLOBAL_EXACT() \
|
||||
(CONTROL |= DR_GLOBAL_SLOWDOWN)
|
||||
|
||||
#define RESET_LOCAL_EXACT() \
|
||||
(CONTROL &= ~(DR_LOCAL_SLOWDOWN))
|
||||
|
||||
#define RESET_GLOBAL_EXACT() \
|
||||
(CONTROL &= ~(DR_GLOBAL_SLOWDOWN))
|
||||
|
||||
#define SET_BREAK(index,address) \
|
||||
do {\
|
||||
CONTROL &= ~(DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index)));\
|
||||
D_REGS[index] = address;\
|
||||
dr_ref_count[index]++;\
|
||||
} while(0)
|
||||
|
||||
#define SET_WATCH(index,address,rw,len) \
|
||||
do {\
|
||||
SET_BREAK(index,address);\
|
||||
CONTROL |= ((len)|(rw)) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index));\
|
||||
} while (0)
|
||||
|
||||
#define IS_WATCH(index) \
|
||||
(CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE*(index))))
|
||||
|
||||
#define WATCH_HIT(index) ((STATUS & (1 << (index))) && IS_WATCH(index))
|
||||
|
||||
#define DR_DEF(index) \
|
||||
((CONTROL >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index))) & 0x0f)
|
||||
|
||||
|
||||
#if 0 /* use debugging macro */
|
||||
#define SHOW_DR(text,len) \
|
||||
do { \
|
||||
if (!getenv ("GDB_SHOW_DR")) break; \
|
||||
fprintf(stderr,"%08x %08x ",edi.dr[7],edi.dr[6]); \
|
||||
fprintf(stderr,"%08x %d %08x %d ", \
|
||||
edi.dr[0],dr_ref_count[0],edi.dr[1],dr_ref_count[1]); \
|
||||
fprintf(stderr,"%08x %d %08x %d ", \
|
||||
edi.dr[2],dr_ref_count[2],edi.dr[3],dr_ref_count[3]); \
|
||||
fprintf(stderr,(len)?"(%s:%d)\n":"(%s)\n",#text,len); \
|
||||
} while (0)
|
||||
#else
|
||||
#define SHOW_DR(text,len) do {} while (0)
|
||||
#endif
|
||||
|
||||
static void
|
||||
cleanup_dregs (void)
|
||||
/* Pass the address ADDR to the inferior in the I'th debug register.
|
||||
Here we just store the address in D_REGS, the watchpoint will be
|
||||
actually set up when go32_wait runs the debuggee. */
|
||||
void
|
||||
go32_set_dr (int i, CORE_ADDR addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
CONTROL = 0;
|
||||
STATUS = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
D_REGS[i] = 0;
|
||||
dr_ref_count[i] = 0;
|
||||
}
|
||||
D_REGS[i] = addr;
|
||||
}
|
||||
|
||||
/* Insert a watchpoint. */
|
||||
|
||||
int
|
||||
go32_insert_watchpoint (int pid ATTRIBUTE_UNUSED, CORE_ADDR addr,
|
||||
int len, int rw)
|
||||
/* Pass the value VAL to the inferior in the DR7 debug control
|
||||
register. Here we just store the address in D_REGS, the watchpoint
|
||||
will be actually set up when go32_wait runs the debuggee. */
|
||||
void
|
||||
go32_set_dr7 (unsigned val)
|
||||
{
|
||||
int ret = go32_insert_aligned_watchpoint (addr, addr, len, rw);
|
||||
|
||||
SHOW_DR (insert_watch, len);
|
||||
return ret;
|
||||
CONTROL = val;
|
||||
}
|
||||
|
||||
static int
|
||||
go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
|
||||
int len, int rw)
|
||||
/* Get the value of the DR6 debug status register from the inferior.
|
||||
Here we just return the value stored in D_REGS, as we've got it
|
||||
from the last go32_wait call. */
|
||||
unsigned
|
||||
go32_get_dr6 (void)
|
||||
{
|
||||
int i;
|
||||
int read_write_bits, len_bits;
|
||||
|
||||
/* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
|
||||
However, x86 doesn't support read-only data breakpoints. */
|
||||
read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
|
||||
|
||||
switch (len)
|
||||
{
|
||||
case 4:
|
||||
len_bits = DR_LEN_4;
|
||||
break;
|
||||
case 2:
|
||||
len_bits = DR_LEN_2;
|
||||
break;
|
||||
case 1:
|
||||
len_bits = DR_LEN_1;
|
||||
break;
|
||||
default:
|
||||
/* The debug registers only have 2 bits for the length, so
|
||||
so this value will always fail the loop below. */
|
||||
len_bits = 0x10;
|
||||
}
|
||||
|
||||
/* Look for an occupied debug register with the same address and the
|
||||
same RW and LEN definitions. If we find one, we can use it for
|
||||
this watchpoint as well (and save a register). */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (!IS_REG_FREE (i) && D_REGS[i] == addr
|
||||
&& DR_DEF (i) == (unsigned)(len_bits | read_write_bits))
|
||||
{
|
||||
dr_ref_count[i]++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for a free debug register. */
|
||||
for (i = 0; i <= 3; i++)
|
||||
{
|
||||
if (IS_REG_FREE (i))
|
||||
break;
|
||||
}
|
||||
|
||||
/* No more debug registers! */
|
||||
if (i > 3)
|
||||
return -1;
|
||||
|
||||
if (len == 2)
|
||||
{
|
||||
if (addr % 2)
|
||||
return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
|
||||
len, rw);
|
||||
}
|
||||
else if (len == 4)
|
||||
{
|
||||
if (addr % 4)
|
||||
return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
|
||||
len, rw);
|
||||
}
|
||||
else if (len != 1)
|
||||
return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr, len, rw);
|
||||
|
||||
SET_WATCH (i, addr, read_write_bits, len_bits);
|
||||
LOCAL_ENABLE_REG (i);
|
||||
SET_LOCAL_EXACT ();
|
||||
SET_GLOBAL_EXACT ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr, CORE_ADDR addr,
|
||||
int len, int rw)
|
||||
{
|
||||
int align;
|
||||
int size;
|
||||
int rv = 0, status = 0;
|
||||
|
||||
static int size_try_array[4][4] =
|
||||
{
|
||||
{ 1, 1, 1, 1 }, /* trying size one */
|
||||
{ 2, 1, 2, 1 }, /* trying size two */
|
||||
{ 2, 1, 2, 1 }, /* trying size three */
|
||||
{ 4, 1, 2, 1 } /* trying size four */
|
||||
};
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
align = addr % 4;
|
||||
/* Four is the maximum length a 386 debug register can watch. */
|
||||
size = size_try_array[len > 4 ? 3 : len - 1][align];
|
||||
if (what == wp_insert)
|
||||
status = go32_insert_aligned_watchpoint (waddr, addr, size, rw);
|
||||
else if (what == wp_remove)
|
||||
status = go32_remove_aligned_watchpoint (waddr, addr, size, rw);
|
||||
else if (what == wp_count)
|
||||
rv++;
|
||||
else
|
||||
status = EINVAL;
|
||||
/* We keep the loop going even after a failure, because some of
|
||||
the other aligned watchpoints might still succeed, e.g. if
|
||||
they watch addresses that are already watched, and thus just
|
||||
increment the reference counts of occupied debug registers.
|
||||
If we break out of the loop too early, we could cause those
|
||||
addresses watched by other watchpoints to be disabled when
|
||||
GDB reacts to our failure to insert this watchpoint and tries
|
||||
to remove it. */
|
||||
if (status)
|
||||
rv = status;
|
||||
addr += size;
|
||||
len -= size;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Remove a watchpoint. */
|
||||
|
||||
int
|
||||
go32_remove_watchpoint (int pid ATTRIBUTE_UNUSED, CORE_ADDR addr,
|
||||
int len, int rw)
|
||||
{
|
||||
int ret = go32_remove_aligned_watchpoint (addr, addr, len, rw);
|
||||
|
||||
SHOW_DR (remove_watch, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
go32_remove_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
|
||||
int len, int rw)
|
||||
{
|
||||
int i;
|
||||
int read_write_bits, len_bits;
|
||||
|
||||
/* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
|
||||
However, x86 doesn't support read-only data breakpoints. */
|
||||
read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
|
||||
|
||||
switch (len)
|
||||
{
|
||||
case 4:
|
||||
len_bits = DR_LEN_4;
|
||||
break;
|
||||
case 2:
|
||||
len_bits = DR_LEN_2;
|
||||
break;
|
||||
case 1:
|
||||
len_bits = DR_LEN_1;
|
||||
break;
|
||||
default:
|
||||
/* The debug registers only have 2 bits for the length, so
|
||||
so this value will always fail the loop below. */
|
||||
len_bits = 0x10;
|
||||
}
|
||||
|
||||
if (len == 2)
|
||||
{
|
||||
if (addr % 2)
|
||||
return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr,
|
||||
len, rw);
|
||||
}
|
||||
else if (len == 4)
|
||||
{
|
||||
if (addr % 4)
|
||||
return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr,
|
||||
len, rw);
|
||||
}
|
||||
else if (len != 1)
|
||||
return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr, len, rw);
|
||||
|
||||
for (i = 0; i <= 3; i++)
|
||||
{
|
||||
if (!IS_REG_FREE (i) && D_REGS[i] == addr
|
||||
&& DR_DEF (i) == (unsigned)(len_bits | read_write_bits))
|
||||
{
|
||||
dr_ref_count[i]--;
|
||||
if (dr_ref_count[i] == 0)
|
||||
DISABLE_REG (i);
|
||||
}
|
||||
}
|
||||
RESET_LOCAL_EXACT ();
|
||||
RESET_GLOBAL_EXACT ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Can we use debug registers to watch a region whose address is ADDR
|
||||
and whose length is LEN bytes? */
|
||||
|
||||
int
|
||||
go32_region_ok_for_watchpoint (CORE_ADDR addr, int len)
|
||||
{
|
||||
/* Compute how many aligned watchpoints we would need to cover this
|
||||
region. */
|
||||
int nregs = go32_handle_nonaligned_watchpoint (wp_count, addr, addr, len, 0);
|
||||
|
||||
return nregs <= 4 ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Check if stopped by a data watchpoint. If so, return the address
|
||||
whose access triggered the watchpoint. */
|
||||
|
||||
CORE_ADDR
|
||||
go32_stopped_by_watchpoint (int pid ATTRIBUTE_UNUSED, int data_watchpoint)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int status;
|
||||
|
||||
status = edi.dr[DR_STATUS];
|
||||
SHOW_DR (stopped_by, 0);
|
||||
for (i = 0; i <= 3; i++)
|
||||
{
|
||||
if (WATCH_HIT (i) && data_watchpoint)
|
||||
{
|
||||
SHOW_DR (WP_HIT, 0);
|
||||
ret = D_REGS[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove a breakpoint. */
|
||||
|
||||
int
|
||||
go32_remove_hw_breakpoint (CORE_ADDR addr, void *shadow ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= 3; i++)
|
||||
{
|
||||
if (!IS_REG_FREE (i) && D_REGS[i] == addr && DR_DEF (i) == 0)
|
||||
{
|
||||
dr_ref_count[i]--;
|
||||
if (dr_ref_count[i] == 0)
|
||||
DISABLE_REG (i);
|
||||
}
|
||||
}
|
||||
SHOW_DR (remove_hw, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
go32_insert_hw_breakpoint (CORE_ADDR addr, void *shadow ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Look for an occupied debug register with the same address and the
|
||||
same RW and LEN definitions. If we find one, we can use it for
|
||||
this breakpoint as well (and save a register). */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (!IS_REG_FREE (i) && D_REGS[i] == addr && DR_DEF (i) == 0)
|
||||
{
|
||||
dr_ref_count[i]++;
|
||||
SHOW_DR (insert_hw, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for a free debug register. */
|
||||
for (i = 0; i <= 3; i++)
|
||||
{
|
||||
if (IS_REG_FREE (i))
|
||||
break;
|
||||
}
|
||||
|
||||
/* No more debug registers? */
|
||||
if (i < 4)
|
||||
{
|
||||
SET_BREAK (i, addr);
|
||||
LOCAL_ENABLE_REG (i);
|
||||
}
|
||||
SHOW_DR (insert_hw, 0);
|
||||
|
||||
return i < 4 ? 0 : EBUSY;
|
||||
return STATUS;
|
||||
}
|
||||
|
||||
/* Put the device open on handle FD into either raw or cooked
|
||||
|
Loading…
Reference in New Issue
Block a user