Article View: gnu.gdb.bug
Article #10148Watchpoints for gdb 3.5
From: John R. Levine
Date: Tue, 20 Mar 1990 05:18
Date: Tue, 20 Mar 1990 05:18
825 lines
24564 bytes
24564 bytes
Here are some changes to gdb 3.5 that add watchpoints. The framework is
intended to be machine independent, although the only implementation is
for the Intel 386, a machine that handles them in hardware.
Watchpoints are implemented as a different kind of breakpoint. They're
stored in the same table as breakpoints, and most of the breakpoint
related gdb commands such as enable, disable, and commands apply equally
to watchpoints. You set a watchpoint by "watch foo" which breaks when foo
changes or "rwatch foo" which breaks on any reference. Foo can be any
address or expression.
This implementation, although quite useful, could stand considerable
improvement:
* Watchpoints are always set on a four-byte wide area, no matter what the
width of the item you're watching is.
* Watchpoints don't show the old or new values at a break. I usually use
"commands" to force a print command when it breaks.
* If you set a watchpoint on an automatic variable, you get a break any
time its location is referenced even though the routine may have returned
and the stack location reused by something completely unrelated. It would
at least be handy to turn off such a watchpoint when its scope returns, it
might also be useful to have them inserted and removed when the function
is called and returns. Note that you can also fake this pretty well using
"commands."
* You are limited to the number of watchpoints the hardware provides, on
the 386 you get four.
* If your machine doesn't give you hardware help for watchpoints, you
lose.
This set of diffs also has some patches for Makefile.dist to let you build
your watchpoint version of gdb in a separate directory from the regular
one, using gmake's VPATH feature to find the unmodified source files in
the regular directory. I found this useful for making this sort of
relatively small change to gdb.
---cut here---cut here---cut here---cut here---cut here---cut here---
diff -2c gdb-3.5/Makefile.dist gdb-watch/Makefile.dist
*** gdb-3.5/Makefile.dist Thu Mar 1 10:54:00 1990
--- gdb-watch/Makefile.dist Fri Mar 9 12:53:37 1990
***************
*** 20,24 ****
distribution will fix your include files up. */
/* CC=gcc -traditional */
! CC=gcc -O
/* It is also possible that you will need to add -I/usr/include/sys to the
--- 20,26 ----
distribution will fix your include files up. */
/* CC=gcc -traditional */
! CC=gcc
! GDIR=/u/src/Gnu/gdb-3.5
! VPATH = .:${GDIR}
/* It is also possible that you will need to add -I/usr/include/sys to the
***************
*** 29,33 ****
/* YACC=yacc */
SHELL=/bin/sh
! MAKE=make
/* Set this up with gcc if you have gnu ld and the loader will print out
--- 31,35 ----
/* YACC=yacc */
SHELL=/bin/sh
! /* MAKE=make */
/* Set this up with gcc if you have gnu ld and the loader will print out
***************
*** 48,52 ****
/* CFLAGS for both GDB and readline. */
GLOBAL_CFLAGS = -g M_CFLAGS
! CFLAGS = -I. ${HAVE_VPRINTF_DEFINE} ${GLOBAL_CFLAGS}
/* None of the things in CFLAGS will do any harm, and on some systems
(e.g. SunOS4) it is important to use the M_CFLAGS. */
--- 50,54 ----
/* CFLAGS for both GDB and readline. */
GLOBAL_CFLAGS = -g M_CFLAGS
! CFLAGS = -I. -I${GDIR} ${HAVE_VPRINTF_DEFINE} ${GLOBAL_CFLAGS}
/* None of the things in CFLAGS will do any harm, and on some systems
(e.g. SunOS4) it is important to use the M_CFLAGS. */
***************
*** 201,209 ****
TARGET_ARCH=
! all: gdb $(XGDB)
! install: gdb $(XGDB)
! cp gdb $(bindir)/gdb.new
! mv $(bindir)/gdb.new $(bindir)/gdb
-if [ "$(XGDB)" = xgdb ]; then \
cp xgdb $(xbindir)/xgdb.new; \
--- 203,211 ----
TARGET_ARCH=
! all: qgdb $(XGDB)
! install: qgdb $(XGDB)
! cp qgdb $(bindir)/qgdb.new
! mv $(bindir)/qgdb.new $(bindir)/qgdb
-if [ "$(XGDB)" = xgdb ]; then \
cp xgdb $(xbindir)/xgdb.new; \
***************
*** 211,218 ****
fi
! gdb : $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB}
rm -f init.c
./munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c
! ${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) ${RL_LIB} $(CLIBS)
/* This is useful when debugging GDB, because Unix doesn't let you run GDB
--- 213,220 ----
fi
! qgdb : $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB}
rm -f init.c
./munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c
! ${CC-LD} $(LDFLAGS) -o $@ init.c $(OBS) $(TSOBS) ${RL_LIB} $(CLIBS)
/* This is useful when debugging GDB, because Unix doesn't let you run GDB
***************
*** 219,224 ****
on itself without copying the executable. So "make gdb1" will make
gdb and put a copy in gdb1, and you can run it with "gdb gdb1". */
! gdb1 : gdb
! cp gdb gdb1
Makefile : Makefile.dist
--- 221,226 ----
on itself without copying the executable. So "make gdb1" will make
gdb and put a copy in gdb1, and you can run it with "gdb gdb1". */
! qgdb1 : qgdb
! cp qgdb qgdb1
Makefile : Makefile.dist
***************
*** 298,306 ****
expread.tab.c : expread.y
@echo 'Expect 4 shift/reduce conflict.'
! ${YACC} expread.y
mv y.tab.c expread.tab.c
expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h
! $(CC) -c ${CFLAGS} expread.tab.c
mv expread.tab.o expread.o
--- 300,308 ----
expread.tab.c : expread.y
@echo 'Expect 4 shift/reduce conflict.'
! ${YACC} $<
mv y.tab.c expread.tab.c
expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h
! $(CC) -c ${CFLAGS} $<
mv expread.tab.o expread.o
diff -2c gdb-3.5/breakpoint.c gdb-watch/breakpoint.c
*** gdb-3.5/breakpoint.c Wed Jan 10 18:49:07 1990
--- gdb-watch/breakpoint.c Fri Mar 9 12:40:49 1990
***************
*** 23,26 ****
--- 23,27 ----
#include "symtab.h"
#include "frame.h"
+ #include "value.h"
/* This is the sequence of bytes we insert for a breakpoint. */
***************
*** 34,37 ****
--- 35,43 ----
enum enable { disabled, enabled, temporary, delete};
+ /* types of breakpoint, `execstop' is a regular one, `readstop'
+ and `writestop' are watchpoints */
+
+ enum breaktype { execstop, readstop, writestop };
+
/* Not that the ->silent field is not currently used by any commands
(though the code is in there if it was to be and set_raw_breakpoint
***************
*** 74,77 ****
--- 80,87 ----
/* Conditional. Break only if this expression's value is nonzero. */
struct expression *cond;
+ /* break or watch, zero is a regular breakpoint */
+ enum breaktype breaktype;
+ /* size of area if it's a watchpoint */
+ int watchpoint_size;
};
***************
*** 274,277 ****
--- 284,297 ----
if (b->enable != disabled && ! b->inserted && ! b->duplicate)
{
+ #ifdef INSERT_WATCHPOINT
+ if(b->breaktype != execstop) {
+ val = INSERT_WATCHPOINT(b, b->breaktype == writestop,
+ b->address, b->watchpoint_size);
+ if(val)
+ return val;
+ b->inserted = 1;
+ continue;
+ }
+ #endif /* INSERT_WATCHPOINT */
read_memory (b->address, b->shadow_contents, sizeof break_insn);
val = write_memory (b->address, break_insn, sizeof break_insn);
***************
*** 300,303 ****
--- 320,328 ----
if (b->inserted)
{
+ #ifdef REMOVE_WATCHPOINT
+ if(b->breaktype != execstop)
+ val = REMOVE_WATCHPOINT(b);
+ else
+ #endif /* REMOVE_WATCHPOINT */
val = write_memory (b->address, b->shadow_contents, sizeof break_insn);
if (val)
***************
*** 336,340 ****
ALL_BREAKPOINTS (b)
! if (b->enable != disabled && b->address == pc)
return 1;
--- 361,365 ----
ALL_BREAKPOINTS (b)
! if (b->enable != disabled && b->breaktype == execstop && b->address == pc)
return 1;
***************
*** 372,377 ****
ALL_BREAKPOINTS (b)
! if (b->enable != disabled && b->address == pc)
{
if (b->frame && b->frame != frame_address)
cont = -1;
--- 397,465 ----
ALL_BREAKPOINTS (b)
! if (b->enable != disabled && b->breaktype == execstop && b->address == pc)
! {
! if (b->frame && b->frame != frame_address)
! cont = -1;
! else
! {
! int value_zero;
! if (b->cond)
! {
! /* Need to select the frame, with all that implies
! so that the conditions will have the right context. */
! select_frame (get_current_frame (), 0);
! value_zero
! = catch_errors (breakpoint_cond_eval, b->cond,
! "Error occurred in testing breakpoint condition.");
! free_all_values ();
! }
! if (b->cond && value_zero)
! {
! cont = -1;
! }
! else if (b->ignore_count > 0)
! {
! b->ignore_count--;
! cont = -1;
! }
! else
! {
! if (b->enable == temporary)
! b->enable = disabled;
! breakpoint_commands = b->commands;
! if (b->silent
! || (breakpoint_commands
! && !strcmp ("silent", breakpoint_commands->line)))
! {
! if (breakpoint_commands)
! breakpoint_commands = breakpoint_commands->next;
! return (b->number > 0 ?
! 0x1000000 + b->number :
! b->number - 0x1000000);
! }
! return b->number;
! }
! }
! }
!
! return cont;
! }
! /* same thing, but for watchpoints */
!
! int
! watchpoint_stop_status (pc, frame_address)
! CORE_ADDR pc;
! FRAME_ADDR frame_address;
! {
! #ifdef WATCHPOINT_STOP_STATUS
! register struct breakpoint *b;
! register int cont = 0;
!
! ALL_BREAKPOINTS (b)
! if (b->enable != disabled && b->breaktype != execstop)
{
+ if( !WATCHPOINT_STOP_STATUS(b, pc, frame_addr) )
+ continue;
+
if (b->frame && b->frame != frame_address)
cont = -1;
***************
*** 419,422 ****
--- 507,513 ----
return cont;
+ #else
+ return 0; /* no watchpoints */
+ #endif
}
***************
*** 584,587 ****
--- 675,679 ----
b->line_number = sal.line;
b->enable = enabled;
+ b->breaktype = execstop;
b->next = 0;
b->silent = 0;
***************
*** 633,636 ****
--- 725,763 ----
}
}
+ static struct breakpoint *
+ set_raw_watchpoint (addr, size, type)
+ CORE_ADDR addr;
+ int size;
+ enum breaktype type;
+ {
+ register struct breakpoint *b, *b1;
+
+ b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+ bzero (b, sizeof *b);
+ b->address = addr;
+ b->symtab = 0;
+ b->line_number = 0;
+ b->enable = enabled;
+ b->breaktype = type;
+ b->watchpoint_size = size;
+ b->next = 0;
+ b->silent = 0;
+
+ /* Add this breakpoint to the end of the chain
+ so that a list of breakpoints will come out in order
+ of increasing numbers. */
+
+ b1 = breakpoint_chain;
+ if (b1 == 0)
+ breakpoint_chain = b;
+ else
+ {
+ while (b1->next)
+ b1 = b1->next;
+ b1->next = b;
+ }
+
+ return b;
+ }
/* Set a breakpoint from a symtab and line.
***************
*** 794,797 ****
--- 921,964 ----
break_command_1 (arg, 1, from_tty);
}
+
+ void
+ watch_command_1 (arg, type)
+ char *arg;
+ enum breaktype type;
+ {
+ CORE_ADDR addr;
+ int size;
+ register struct breakpoint *b;
+ value val = parse_and_eval(arg); /* get a value thingie */
+
+ if(VALUE_LVAL(val) == lval_memory)
+ addr = VALUE_ADDRESS(val) + VALUE_OFFSET(val);
+ else
+ addr = value_as_long(val);
+
+ /* always sewt watchpoints on full words for the moment */
+ b = set_raw_watchpoint (addr, 4, type);
+ b->number = ++breakpoint_count;
+ b->cond = 0;
+
+ printf ("Watchpoint %d at 0x%x", b->number, b->address);
+ printf ("\n");
+ }
+
+ static void
+ watch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+ {
+ watch_command_1 (arg, writestop);
+ }
+
+ static void
+ rwatch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+ {
+ watch_command_1 (arg, readstop);
+ }
/*
***************
*** 954,957 ****
--- 1121,1129 ----
if (bpt->inserted)
+ #ifdef REMOVE_WATCHPOINT
+ if(bpt->breaktype != execstop)
+ REMOVE_WATCHPOINT(bpt);
+ else
+ #endif /* REMOVE_WATCHPOINT */
write_memory (bpt->address, bpt->shadow_contents, sizeof break_insn);
***************
*** 1370,1373 ****
--- 1542,1559 ----
Convenience variable \"$_\" and default examine address for \"x\"\n\
are set to the address of the last breakpoint listed.");
+ add_com ("watch", class_breakpoint, watch_command,
+ "Set a write watchpoint on the specified variable.\n\
+ Argument must be a variable name or an address.\n\
+ \n\
+ Multiple watchpoints at one place are asking for trouble.\n\
+ \n\
+ Do \"help breakpoints\" for info on other commands dealing with watchpoints.");
+ add_com ("rwatch", class_breakpoint, rwatch_command,
+ "Set a read watchpoint on the specified variable.\n\
+ Argument must be a variable name or an address.\n\
+ \n\
+ Multiple watchpoints at one place are asking for trouble.\n\
+ \n\
+ Do \"help breakpoints\" for info on other commands dealing with watchpoints.");
}
diff -2c gdb-3.5/i386-dep.c gdb-watch/i386-dep.c
*** gdb-3.5/i386-dep.c Wed Jan 10 18:58:05 1990
--- gdb-watch/i386-dep.c Thu Mar 8 17:23:17 1990
***************
*** 35,38 ****
--- 35,40 ----
#include <fcntl.h>
+ #include <sys/debugreg.h> /* handle 386 debug registers */
+
#ifdef COFF_ENCAPSULATE
#include "a.out.encap.h"
***************
*** 55,58 ****
--- 57,65 ----
extern int errno;
+
+ int debugreg[8]; /* my copy of the debug registers */
+ struct watch_status {
+ struct breakpoint *bpt; /* which breakpoint is hooked to this one */
+ } watch_status[WATCHPOINT_MAX];
/* This function simply calls ptrace with the given arguments.
***************
*** 131,134 ****
--- 138,146 ----
supply_register (regno, buf);
}
+ /* get back the debug registers */
+ offset = (char *) &u.u_debugreg - (char *)&u;
+
+ /* just need the status register */
+ debugreg[DR_STATUS] = ptrace(3, inferior_pid, offset+DR_STATUS*sizeof(int), 0);
}
***************
*** 1273,1275 ****
--- 1285,1413 ----
print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
}
+
+ /* handle watchpoints using the 386's debug registers */
+ int
+ watchpoint_386_stop_status(b)
+ struct breakpoint *b;
+ {
+ register i;
+ for(i = 0; i < WATCHPOINT_MAX; i++) {
+ if(watch_status[i].bpt != b)
+ continue;
+
+ /* now check the status register and see if this one */
+ /* was triggered */
+ return ( debugreg[DR_STATUS] & (DR_TRAP0 << i) );
+ }
+ return 0; /* not inserted or something */
+ }
+
+ /* call this routine to insert watchpoints */
+ int
+ watchpoint_386_insert(b, type, address, size)
+ register struct breakpoint *b;
+ int type; /* nonzero means write stop, zero means read stop */
+ CORE_ADDR address;
+ int size;
+ {
+ int i;
+
+ for(i = 0; i < WATCHPOINT_MAX; i++) {
+ int code;
+ int offset;
+ struct user u;
+
+ if(watch_status[i].bpt)
+ continue;
+ watch_status[i].bpt = b;
+ debugreg[i] = address;
+
+ if(size == 4)
+ code = DR_LEN_4;
+ else if(size == 2)
+ code = DR_LEN_2;
+ else
+ code = DR_LEN_1; /* close enough */
+
+ /* add in the read/write flag */
+ code |= type? DR_RW_WRITE: DR_RW_READ;
+
+ /* whomp in the code */
+ debugreg[DR_CONTROL] &=
+ ~((DR_RW_MASK|DR_LEN_MASK) <<
+ (DR_CONTROL_SHIFT + i*DR_CONTROL_SIZE));
+ debugreg[DR_CONTROL] |= code
+ << (DR_CONTROL_SHIFT + i*DR_CONTROL_SIZE);
+
+ /* turn on the enable bit */
+ debugreg[DR_CONTROL] |= 1 <<
+ (DR_LOCAL_ENABLE_SHIFT + i*DR_ENABLE_SIZE);
+
+ /* and the slowdown bit */
+ debugreg[DR_CONTROL] |= DR_LOCAL_SLOWDOWN;
+
+ /* now send it to the nether reaches */
+ offset = (char *) &u.u_debugreg - (char *)&u;
+
+ ptrace(6, inferior_pid, offset+i*sizeof(int), debugreg[i]);
+ ptrace(6, inferior_pid, offset+DR_CONTROL*sizeof(int),
+ debugreg[DR_CONTROL]);
+
+ return 0;
+ }
+ return 7; /* too many watchpoints */
+ }
+
+ /* and this one to remove them */
+ int
+ watchpoint_386_remove(b)
+ register struct breakpoint *b;
+ {
+ register int i;
+
+ for(i = 0; i < WATCHPOINT_MAX; i++) {
+ int code;
+ int offset;
+ struct user u;
+
+ if(watch_status[i].bpt != b)
+ continue;
+
+ watch_status[i].bpt = 0; /* give this one back */
+
+ /* turn off the enable bit */
+ debugreg[DR_CONTROL] &= ~(1 <<
+ (DR_LOCAL_ENABLE_SHIFT + i*DR_ENABLE_SIZE));
+
+ /* and maybe the slowdown bit */
+ if(!(debugreg[DR_CONTROL] & DR_LOCAL_ENABLE_MASK))
+ debugreg[DR_CONTROL] &= ~DR_LOCAL_SLOWDOWN;
+
+ /* now send it to the nether reaches */
+ offset = (char *) &u.u_debugreg - (char *)&u;
+
+ ptrace(6, inferior_pid, offset+DR_CONTROL*sizeof(int),
+ debugreg[DR_CONTROL]);
+
+ return 0;
+ }
+ return 0; /* wasn't really active */
+ }
+
+ #ifdef BREAKPOINT_DEBUG
+ void
+ show_debug_regs(void)
+ {
+ struct user u;
+ int offset = (char *)&u.u_debugreg - (char*)&u;
+ int i;
+
+ fprintf(stderr, "Debug registers:\n");
+ for(i = 0; i < 8; i++) {
+ fprintf(stderr, " %08X",
+ ptrace(3, inferior_pid, offset +4*i, 0));
+ }
+ fprintf(stderr, "\n");
+ }
+ #endif BREAKPOINT_DEBUG
diff -2c gdb-3.5/infcmd.c gdb-watch/infcmd.c
*** gdb-3.5/infcmd.c Thu Jan 18 13:56:33 1990
--- gdb-watch/infcmd.c Thu Mar 8 17:24:46 1990
***************
*** 64,67 ****
--- 64,71 ----
int stop_breakpoint;
+ /* number of watchpoint it stopped at, or 0 if none. */
+
+ int stop_watchpoint;
+
/* Nonzero if stopped due to a step command. */
diff -2c gdb-3.5/inferior.h gdb-watch/inferior.h
*** gdb-3.5/inferior.h Thu Sep 21 20:31:33 1989
--- gdb-watch/inferior.h Thu Mar 8 17:25:42 1990
***************
*** 33,36 ****
--- 33,37 ----
int stop_frame_address;
int stop_breakpoint;
+ int stop_watchpoint;
int stop_step;
int stop_stack_dummy;
***************
*** 83,86 ****
--- 84,91 ----
extern int stop_breakpoint;
+
+ /* number of watchpoint it stopped at, or 0 if none. */
+
+ extern int stop_watchpoint;
/* Nonzero if stopped due to a step command. */
diff -2c gdb-3.5/infrun.c gdb-watch/infrun.c
*** gdb-3.5/infrun.c Tue Jan 23 18:10:35 1990
--- gdb-watch/infrun.c Thu Mar 8 17:33:07 1990
***************
*** 568,571 ****
--- 568,572 ----
another_trap = 0;
stop_breakpoint = 0;
+ stop_watchpoint = 0;
stop_step = 0;
stop_stack_dummy = 0;
***************
*** 640,643 ****
--- 641,646 ----
else
{
+ stop_watchpoint =
+ watchpoint_stop_status (stop_pc, stop_frame_address);
stop_breakpoint =
breakpoint_stop_status (stop_pc, stop_frame_address);
***************
*** 645,649 ****
function. */
stop_print_frame = 1;
! if (stop_breakpoint && DECR_PC_AFTER_BREAK)
{
stop_pc -= DECR_PC_AFTER_BREAK;
--- 648,653 ----
function. */
stop_print_frame = 1;
! if (stop_breakpoint && DECR_PC_AFTER_BREAK
! && !stop_watchpoint)
{
stop_pc -= DECR_PC_AFTER_BREAK;
***************
*** 660,664 ****
if (stop_signal == SIGTRAP)
random_signal
! = !(stop_breakpoint || trap_expected
|| stop_step_resume_break
#ifndef CANNOT_EXECUTE_STACK
--- 664,668 ----
if (stop_signal == SIGTRAP)
random_signal
! = !(stop_breakpoint || stop_watchpoint || trap_expected
|| stop_step_resume_break
#ifndef CANNOT_EXECUTE_STACK
***************
*** 672,676 ****
{
random_signal
! = !(stop_breakpoint
|| stop_step_resume_break
#ifdef sony_news
--- 676,680 ----
{
random_signal
! = !(stop_breakpoint || stop_watchpoint
|| stop_step_resume_break
#ifdef sony_news
***************
*** 722,726 ****
if (!random_signal
! && (stop_breakpoint || stop_step_resume_break))
{
/* Does a breakpoint want us to stop? */
--- 726,730 ----
if (!random_signal
! && (stop_breakpoint || stop_watchpoint || stop_step_resume_break))
{
/* Does a breakpoint want us to stop? */
***************
*** 743,746 ****
--- 747,769 ----
break;
}
+ /* Does a watchpoint want us to stop? */
+ if (stop_watchpoint && stop_watchpoint != -1
+ && stop_watchpoint != -0x1000001)
+ {
+ /* 0x1000000 is set in stop_watchpoint as returned by
+ watchpoint_stop_status to indicate a silent
+ watchpoint. */
+ if ((stop_watchpoint > 0 ? stop_watchpoint :
+ -stop_watchpoint)
+ & 0x1000000)
+ {
+ stop_print_frame = 0;
+ if (stop_watchpoint > 0)
+ stop_watchpoint -= 0x1000000;
+ else
+ stop_watchpoint += 0x1000000;
+ }
+ break;
+ }
/* But if we have hit the step-resumption breakpoint,
remove it. It has done its job getting us here.
***************
*** 1122,1125 ****
--- 1145,1150 ----
if (stop_breakpoint > 0)
printf ("\nBpt %d, ", stop_breakpoint);
+ if (stop_watchpoint > 0)
+ printf ("\nWpt %d, ", stop_watchpoint);
print_sel_frame (stop_step
&& step_frame_address == stop_frame_address
***************
*** 1304,1307 ****
--- 1329,1333 ----
inf_status->stop_frame_address = stop_frame_address;
inf_status->stop_breakpoint = stop_breakpoint;
+ inf_status->stop_watchpoint = stop_watchpoint;
inf_status->stop_step = stop_step;
inf_status->stop_stack_dummy = stop_stack_dummy;
***************
*** 1337,1340 ****
--- 1363,1367 ----
stop_frame_address = inf_status->stop_frame_address;
stop_breakpoint = inf_status->stop_breakpoint;
+ stop_watchpoint = inf_status->stop_watchpoint;
stop_step = inf_status->stop_step;
stop_stack_dummy = inf_status->stop_stack_dummy;
diff -2c gdb-3.5/m-i386.h gdb-watch/m-i386.h
*** gdb-3.5/m-i386.h Fri Jan 26 15:14:33 1990
--- gdb-watch/m-i386.h Thu Mar 8 17:31:54 1990
***************
*** 132,135 ****
--- 132,151 ----
#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3)
+ /* take advantage of watchpoint hardware */
+
+ /* call this to see if this watchpoint was just hit */
+ #define WATCHPOINT_STOP_STATUS(b, pc, frame_addr) \
+ (watchpoint_386_stop_status(b))
+
+ /* call this routine to insert watchpoints */
+ #define INSERT_WATCHPOINT(p,type,addr,size) \
+ (watchpoint_386_insert(p,type,addr,size))
+
+ /* and this one to remove them */
+ #define REMOVE_WATCHPOINT(p) (watchpoint_386_remove(p))
+
+ #define WATCHPOINT_MAX 4 /* maximum number of watchpoints */
+
+
/* Return 1 if P points to an invalid floating point value.
LEN is the length in bytes -- not relevant on the 386. */
diff -2c gdb-3.5/version.c gdb-watch/version.c
*** gdb-3.5/version.c Thu Feb 8 01:13:31 1990
--- gdb-watch/version.c Thu Mar 8 17:33:02 1990
***************
*** 18,20 ****
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
! char *version = "3.5";
--- 18,20 ----
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
! char *version = "3.5J";
--
John R. Levine, Segue Software, POB 349, Cambridge MA 02238, +1 617 864 9650
johnl@esegue.segue.boston.ma.us, {ima|lotus|spdcc}!esegue!johnl
"Now, we are all jelly doughnuts."
Technical Details
Message-ID:
<1990Mar20.051836.6524@esegue.segue.boston.ma.us>Path:
arc1-ca.pugleaf.net!gmdzi!unido!mcsun!uunet!snorkelwacker!spdcc!esegue!johnlShow Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: f5053,c88c468d27293ea1,start X-Google-Attributes: gidf5053,public X-Google-ArrivalTime: 1990-03-20 20:00:25 PST Path: arc1-ca.pugleaf.net!gmdzi!unido!mcsun!uunet!snorkelwacker!spdcc!esegue!johnl From: johnl@esegue.segue.boston.ma.us (John R. Levine) Newsgroups: gnu.gdb.bug Subject: Watchpoints for gdb 3.5 Message-ID: <1990Mar20.051836.6524@esegue.segue.boston.ma.us> Date: 20 Mar 90 05:18:36 GMT Reply-To: johnl@esegue.segue.boston.ma.us (John R. Levine) Organization: Segue Software, Cambridge MA Lines: 825 Posted: Tue Mar 20 06:18:36 1990