Use multiple locations for hardware watchpoints.

This eliminates the need to traverse value chain, doing
	various checks, in three different places.

        * breakpoint.h (struct bp_location): New fields
        lengths and watchpoint_type.
        (struct breakpoint): Remove the val_chain field.
        * breakpoint.c (is_hardware_watchpoint): New.
        (free_valchain): Remove.
        (update_watchpoint): New.
        (insert_bp_location): For hardware watchpoint, just
        directly insert it.
        (insert_breakpoints): Call update_watchpoint_locations
        on all watchpoints.  If we have failed to insert
        any location of a hardware watchpoint, remove all inserted
        locations.
        (remove_breakpoint): For hardware watchpoints, directly
        remove location.
        (watchpoints_triggered): Iterate over locations.
        (bpstat_stop_status): Use only first location of
        a resource watchpoint.
        (delete_breakpoint): Don't call free_valchain.
        (print_one_breakpoint): Don't print all
        locations for watchpoints.
        (breakpoint_re_set_one): Use update_watchpoint for
        watchpoints.
This commit is contained in:
Vladimir Prus
2008-01-29 17:52:47 +00:00
parent 0b3de036ef
commit a5606eee5e
7 changed files with 483 additions and 257 deletions

View File

@ -1,3 +1,32 @@
2008-01-29 Vladimir Prus <vladimir@codesourcery.com>
Use multiple locations for hardware watchpoints.
This eliminates the need to traverse value chain, doing
various checks, in three different places.
* breakpoint.h (struct bp_location): New fields
lengths and watchpoint_type.
(struct breakpoint): Remove the val_chain field.
* breakpoint.c (is_hardware_watchpoint): New.
(free_valchain): Remove.
(update_watchpoint): New.
(insert_bp_location): For hardware watchpoint, just
directly insert it.
(insert_breakpoints): Call update_watchpoint_locations
on all watchpoints. If we have failed to insert
any location of a hardware watchpoint, remove all inserted
locations.
(remove_breakpoint): For hardware watchpoints, directly
remove location.
(watchpoints_triggered): Iterate over locations.
(bpstat_stop_status): Use only first location of
a resource watchpoint.
(delete_breakpoint): Don't call free_valchain.
(print_one_breakpoint): Don't print all
locations for watchpoints.
(breakpoint_re_set_one): Use update_watchpoint for
watchpoints.
2008-01-29 Vladimir Prus <vladimir@codesourcery.com> 2008-01-29 Vladimir Prus <vladimir@codesourcery.com>
Don't reset watchpoint block on solib load. Don't reset watchpoint block on solib load.

View File

@ -200,6 +200,15 @@ static void free_bp_location (struct bp_location *loc);
static void mark_breakpoints_out (void); static void mark_breakpoints_out (void);
static struct bp_location *
allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type);
static void
unlink_locations_from_global_list (struct breakpoint *bpt);
static int
is_hardware_watchpoint (struct breakpoint *bpt);
/* Prototypes for exported functions. */ /* Prototypes for exported functions. */
/* If FALSE, gdb will not use hardware support for watchpoints, even /* If FALSE, gdb will not use hardware support for watchpoints, even
@ -808,24 +817,182 @@ insert_catchpoint (struct ui_out *uo, void *args)
} }
} }
/* Helper routine: free the value chain for a breakpoint (watchpoint). */ static int
is_hardware_watchpoint (struct breakpoint *bpt)
static void
free_valchain (struct bp_location *b)
{ {
struct value *v; return (bpt->type == bp_hardware_watchpoint
struct value *n; || bpt->type == bp_read_watchpoint
|| bpt->type == bp_access_watchpoint);
/* Free the saved value chain. We will construct a new one
the next time the watchpoint is inserted. */
for (v = b->owner->val_chain; v; v = n)
{
n = value_next (v);
value_free (v);
}
b->owner->val_chain = NULL;
} }
/* Assuming that B is a hardware breakpoint:
- Reparse watchpoint expression, is REPARSE is non-zero
- Evaluate expression and store the result in B->val
- Update the list of values that must be watched in B->loc.
If the watchpoint is disabled, do nothing. If this is
local watchpoint that is out of scope, delete it. */
static void
update_watchpoint (struct breakpoint *b, int reparse)
{
int within_current_scope;
struct value *mark = value_mark ();
struct frame_id saved_frame_id;
struct bp_location *loc;
bpstat bs;
unlink_locations_from_global_list (b);
for (loc = b->loc; loc;)
{
struct bp_location *loc_next = loc->next;
remove_breakpoint (loc, mark_uninserted);
xfree (loc);
loc = loc_next;
}
b->loc = NULL;
if (b->disposition == disp_del_at_next_stop)
return;
/* Save the current frame's ID so we can restore it after
evaluating the watchpoint expression on its own frame. */
/* FIXME drow/2003-09-09: It would be nice if evaluate_expression
took a frame parameter, so that we didn't have to change the
selected frame. */
saved_frame_id = get_frame_id (get_selected_frame (NULL));
/* Determine if the watchpoint is within scope. */
if (b->exp_valid_block == NULL)
within_current_scope = 1;
else
{
struct frame_info *fi;
fi = frame_find_by_id (b->watchpoint_frame);
within_current_scope = (fi != NULL);
if (within_current_scope)
select_frame (fi);
}
if (within_current_scope && reparse)
{
char *s;
if (b->exp)
{
xfree (b->exp);
b->exp = NULL;
}
s = b->exp_string;
b->exp = parse_exp_1 (&s, b->exp_valid_block, 0);
/* If the meaning of expression itself changed, the old value is
no longer relevant. We don't want to report a watchpoint hit
to the user when the old value and the new value may actually
be completely different objects. */
value_free (b->val);
b->val = NULL;
}
/* If we failed to parse the expression, for example because
it refers to a global variable in a not-yet-loaded shared library,
don't try to insert watchpoint. We don't automatically delete
such watchpoint, though, since failure to parse expression
is different from out-of-scope watchpoint. */
if (within_current_scope && b->exp)
{
struct value *v, *next;
/* Evaluate the expression and make sure it's not lazy, so that
after target stops again, we have a non-lazy previous value
to compare with. Also, making the value non-lazy will fetch
intermediate values as needed, which we use to decide which
addresses to watch.
The value returned by evaluate_expression is stored in b->val.
In addition, we look at all values which were created
during evaluation, and set watchoints at addresses as needed.
Those values are explicitly deleted here. */
v = evaluate_expression (b->exp);
/* Avoid setting b->val if it's already set. The meaning of
b->val is 'the last value' user saw, and we should update
it only if we reported that last value to user. As it
happens, the code that reports it updates b->val directly. */
if (b->val == NULL)
b->val = v;
value_contents (v);
value_release_to_mark (mark);
/* Look at each value on the value chain. */
for (; v; v = next)
{
/* If it's a memory location, and GDB actually needed
its contents to evaluate the expression, then we
must watch it. */
if (VALUE_LVAL (v) == lval_memory
&& ! value_lazy (v))
{
struct type *vtype = check_typedef (value_type (v));
/* We only watch structs and arrays if user asked
for it explicitly, never if they just happen to
appear in the middle of some value chain. */
if (v == b->val
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
int len, type;
struct bp_location *loc, **tmp;
addr = VALUE_ADDRESS (v) + value_offset (v);
len = TYPE_LENGTH (value_type (v));
type = hw_write;
if (b->type == bp_read_watchpoint)
type = hw_read;
else if (b->type == bp_access_watchpoint)
type = hw_access;
loc = allocate_bp_location (b, bp_hardware_watchpoint);
for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
;
*tmp = loc;
loc->address = addr;
loc->length = len;
loc->watchpoint_type = type;
}
}
next = value_next (v);
if (v != b->val)
value_free (v);
}
if (reparse && b->cond_string != NULL)
{
char *s = b->cond_string;
if (b->loc->cond)
{
xfree (b->loc->cond);
b->loc->cond = NULL;
}
b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
}
}
else if (!within_current_scope)
{
printf_filtered (_("\
Hardware watchpoint %d deleted because the program has left the block \n\
in which its expression is valid.\n"),
b->number);
if (b->related_breakpoint)
b->related_breakpoint->disposition = disp_del_at_next_stop;
b->disposition = disp_del_at_next_stop;
}
/* Restore the selected frame. */
select_frame (frame_find_by_id (saved_frame_id));
}
/* Insert a low-level "breakpoint" of some type. BPT is the breakpoint. /* Insert a low-level "breakpoint" of some type. BPT is the breakpoint.
Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS, Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS,
PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems. PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems.
@ -1016,136 +1183,10 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
watchpoints. It's not clear that it's necessary... */ watchpoints. It's not clear that it's necessary... */
&& bpt->owner->disposition != disp_del_at_next_stop) && bpt->owner->disposition != disp_del_at_next_stop)
{ {
/* FIXME drow/2003-09-08: This code sets multiple hardware watchpoints val = target_insert_watchpoint (bpt->address,
based on the expression. Ideally this should happen at a higher level, bpt->length,
and there should be one bp_location for each computed address we bpt->watchpoint_type);
must watch. As soon as a many-to-one mapping is available I'll bpt->inserted = (val != -1);
convert this. */
int within_current_scope;
struct value *mark = value_mark ();
struct value *v;
struct frame_id saved_frame_id;
/* Save the current frame's ID so we can restore it after
evaluating the watchpoint expression on its own frame. */
/* FIXME drow/2003-09-09: It would be nice if evaluate_expression
took a frame parameter, so that we didn't have to change the
selected frame. */
saved_frame_id = get_frame_id (get_selected_frame (NULL));
/* Determine if the watchpoint is within scope. */
if (bpt->owner->exp_valid_block == NULL)
within_current_scope = 1;
else
{
struct frame_info *fi;
fi = frame_find_by_id (bpt->owner->watchpoint_frame);
within_current_scope = (fi != NULL);
if (within_current_scope)
select_frame (fi);
}
if (within_current_scope)
{
free_valchain (bpt);
/* Evaluate the expression and cut the chain of values
produced off from the value chain.
Make sure the value returned isn't lazy; we use
laziness to determine what memory GDB actually needed
in order to compute the value of the expression. */
v = evaluate_expression (bpt->owner->exp);
value_contents (v);
value_release_to_mark (mark);
bpt->owner->val_chain = v;
bpt->inserted = 1;
/* Look at each value on the value chain. */
for (; v; v = value_next (v))
{
/* If it's a memory location, and GDB actually needed
its contents to evaluate the expression, then we
must watch it. */
if (VALUE_LVAL (v) == lval_memory
&& ! value_lazy (v))
{
struct type *vtype = check_typedef (value_type (v));
/* We only watch structs and arrays if user asked
for it explicitly, never if they just happen to
appear in the middle of some value chain. */
if (v == bpt->owner->val_chain
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
int len, type;
addr = VALUE_ADDRESS (v) + value_offset (v);
len = TYPE_LENGTH (value_type (v));
type = hw_write;
if (bpt->owner->type == bp_read_watchpoint)
type = hw_read;
else if (bpt->owner->type == bp_access_watchpoint)
type = hw_access;
val = target_insert_watchpoint (addr, len, type);
if (val == -1)
{
/* Don't exit the loop, try to insert
every value on the value chain. That's
because we will be removing all the
watches below, and removing a
watchpoint we didn't insert could have
adverse effects. */
bpt->inserted = 0;
}
val = 0;
}
}
}
if (bpt->owner->cond_string != NULL)
{
char *s = bpt->owner->cond_string;
if (bpt->cond)
{
xfree (bpt->cond);
bpt->cond = NULL;
}
bpt->cond = parse_exp_1 (&s, bpt->owner->exp_valid_block, 0);
}
/* Failure to insert a watchpoint on any memory value in the
value chain brings us here. */
if (!bpt->inserted)
{
remove_breakpoint (bpt, mark_uninserted);
*hw_breakpoint_error = 1;
fprintf_unfiltered (tmp_error_stream,
"Could not insert hardware watchpoint %d.\n",
bpt->owner->number);
val = -1;
}
}
else
{
printf_filtered (_("\
Hardware watchpoint %d deleted because the program has left the block \n\
in which its expression is valid.\n"),
bpt->owner->number);
if (bpt->owner->related_breakpoint)
bpt->owner->related_breakpoint->disposition = disp_del_at_next_stop;
bpt->owner->disposition = disp_del_at_next_stop;
}
/* Restore the selected frame. */
select_frame (frame_find_by_id (saved_frame_id));
return val;
} }
else if (bpt->owner->type == bp_catch_fork else if (bpt->owner->type == bp_catch_fork
@ -1178,6 +1219,7 @@ in which its expression is valid.\n"),
void void
insert_breakpoints (void) insert_breakpoints (void)
{ {
struct breakpoint *bpt;
struct bp_location *b, *temp; struct bp_location *b, *temp;
int error = 0; int error = 0;
int val = 0; int val = 0;
@ -1192,6 +1234,10 @@ insert_breakpoints (void)
there was an error. */ there was an error. */
fprintf_unfiltered (tmp_error_stream, "Warning:\n"); fprintf_unfiltered (tmp_error_stream, "Warning:\n");
ALL_BREAKPOINTS (bpt)
if (is_hardware_watchpoint (bpt))
update_watchpoint (bpt, 0 /* don't reparse */);
ALL_BP_LOCATIONS_SAFE (b, temp) ALL_BP_LOCATIONS_SAFE (b, temp)
{ {
if (!breakpoint_enabled (b->owner)) if (!breakpoint_enabled (b->owner))
@ -1203,19 +1249,6 @@ insert_breakpoints (void)
&& !valid_thread_id (b->owner->thread)) && !valid_thread_id (b->owner->thread))
continue; continue;
/* FIXME drow/2003-10-07: This code should be pushed elsewhere when
hardware watchpoints are split into multiple loc breakpoints. */
if ((b->loc_type == bp_loc_hardware_watchpoint
|| b->owner->type == bp_watchpoint) && !b->owner->val)
{
struct value *val;
val = evaluate_expression (b->owner->exp);
release_value (val);
if (value_lazy (val))
value_fetch_lazy (val);
b->owner->val = val;
}
val = insert_bp_location (b, tmp_error_stream, val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks, &process_warning, &disabled_breaks, &process_warning,
&hw_breakpoint_error); &hw_breakpoint_error);
@ -1223,6 +1256,39 @@ insert_breakpoints (void)
error = val; error = val;
} }
/* If we failed to insert all locations of a watchpoint,
remove them, as half-inserted watchpoint is of limited use. */
ALL_BREAKPOINTS (bpt)
{
int some_failed = 0;
struct bp_location *loc;
if (!is_hardware_watchpoint (bpt))
continue;
if (bpt->enable_state != bp_enabled)
continue;
for (loc = bpt->loc; loc; loc = loc->next)
if (!loc->inserted)
{
some_failed = 1;
break;
}
if (some_failed)
{
for (loc = bpt->loc; loc; loc = loc->next)
if (loc->inserted)
remove_breakpoint (loc, mark_uninserted);
hw_breakpoint_error = 1;
fprintf_unfiltered (tmp_error_stream,
"Could not insert hardware watchpoint %d.\n",
bpt->number);
error = -1;
}
}
if (error) if (error)
{ {
/* If a hardware breakpoint or watchpoint was inserted, add a /* If a hardware breakpoint or watchpoint was inserted, add a
@ -1508,46 +1574,15 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is)
return val; return val;
b->inserted = (is == mark_inserted); b->inserted = (is == mark_inserted);
} }
else if (b->loc_type == bp_loc_hardware_watchpoint else if (b->loc_type == bp_loc_hardware_watchpoint)
&& breakpoint_enabled (b->owner)
&& !b->duplicate)
{ {
struct value *v; struct value *v;
struct value *n; struct value *n;
b->inserted = (is == mark_inserted); b->inserted = (is == mark_inserted);
/* Walk down the saved value chain. */ val = target_remove_watchpoint (b->address, b->length,
for (v = b->owner->val_chain; v; v = value_next (v)) b->watchpoint_type);
{
/* For each memory reference remove the watchpoint
at that address. */
if (VALUE_LVAL (v) == lval_memory
&& ! value_lazy (v))
{
struct type *vtype = check_typedef (value_type (v));
if (v == b->owner->val_chain
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR addr;
int len, type;
addr = VALUE_ADDRESS (v) + value_offset (v);
len = TYPE_LENGTH (value_type (v));
type = hw_write;
if (b->owner->type == bp_read_watchpoint)
type = hw_read;
else if (b->owner->type == bp_access_watchpoint)
type = hw_access;
val = target_remove_watchpoint (addr, len, type);
if (val == -1)
b->inserted = 1;
val = 0;
}
}
}
/* Failure to remove any of the hardware watchpoints comes here. */ /* Failure to remove any of the hardware watchpoints comes here. */
if ((is == mark_uninserted) && (b->inserted)) if ((is == mark_uninserted) && (b->inserted))
warning (_("Could not remove hardware watchpoint %d."), warning (_("Could not remove hardware watchpoint %d."),
@ -2451,33 +2486,19 @@ watchpoints_triggered (struct target_waitstatus *ws)
|| b->type == bp_read_watchpoint || b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint) || b->type == bp_access_watchpoint)
{ {
struct bp_location *loc;
struct value *v; struct value *v;
b->watchpoint_triggered = watch_triggered_no; b->watchpoint_triggered = watch_triggered_no;
for (v = b->val_chain; v; v = value_next (v)) for (loc = b->loc; loc; loc = loc->next)
{ /* Exact match not required. Within range is
if (VALUE_LVAL (v) == lval_memory && ! value_lazy (v)) sufficient. */
{ if (addr >= loc->address
struct type *vtype = check_typedef (value_type (v)); && addr < loc->address + loc->length)
{
if (v == b->val_chain b->watchpoint_triggered = watch_triggered_yes;
|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT break;
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) }
{
CORE_ADDR vaddr;
vaddr = VALUE_ADDRESS (v) + value_offset (v);
/* Exact match not required. Within range is
sufficient. */
if (addr >= vaddr
&& addr < vaddr + TYPE_LENGTH (value_type (v)))
{
b->watchpoint_triggered = watch_triggered_yes;
break;
}
}
}
}
} }
return 1; return 1;
@ -2716,6 +2737,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
&& !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname)) && !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
continue; continue;
/* For hardware watchpoints, we look only at the first location.
The watchpoint_check function will work on entire expression,
not the individual locations. For read watchopints, the
watchpoints_triggered function have checked all locations
alrea
*/
if (b->type == bp_hardware_watchpoint && bl != b->loc)
continue;
/* Come here if it's a watchpoint, or if the break address matches */ /* Come here if it's a watchpoint, or if the break address matches */
bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */ bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
@ -2909,6 +2939,10 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
|| bs->breakpoint_at->owner->type == bp_read_watchpoint || bs->breakpoint_at->owner->type == bp_read_watchpoint
|| bs->breakpoint_at->owner->type == bp_access_watchpoint)) || bs->breakpoint_at->owner->type == bp_access_watchpoint))
{ {
/* remove/insert can invalidate bs->breakpoint_at, if this
location is no longer used by the watchpoint. Prevent
further code from trying to use it. */
bs->breakpoint_at = NULL;
remove_breakpoints (); remove_breakpoints ();
insert_breakpoints (); insert_breakpoints ();
break; break;
@ -3629,10 +3663,14 @@ print_one_breakpoint (struct breakpoint *b,
disabled, we print it as if it had disabled, we print it as if it had
several locations, since otherwise it's hard to several locations, since otherwise it's hard to
represent "breakpoint enabled, location disabled" represent "breakpoint enabled, location disabled"
situation. */ situation.
Note that while hardware watchpoints have
several locations internally, that's no a property
exposed to user. */
if (b->loc if (b->loc
&& !is_hardware_watchpoint (b)
&& (b->loc->next || !b->loc->enabled) && (b->loc->next || !b->loc->enabled)
&& !ui_out_is_mi_like_p (uiout)) && !ui_out_is_mi_like_p (uiout))
{ {
struct bp_location *loc; struct bp_location *loc;
int n = 1; int n = 1;
@ -6829,9 +6867,7 @@ delete_breakpoint (struct breakpoint *bpt)
{ {
if (loc->inserted) if (loc->inserted)
remove_breakpoint (loc, mark_inserted); remove_breakpoint (loc, mark_inserted);
free_valchain (loc);
if (loc->cond) if (loc->cond)
xfree (loc->cond); xfree (loc->cond);
@ -7265,39 +7301,7 @@ breakpoint_re_set_one (void *bint)
Don't do anything about disabled watchpoints, since they will Don't do anything about disabled watchpoints, since they will
be reevaluated again when enabled. */ be reevaluated again when enabled. */
update_watchpoint (b, 1 /* reparse */);
if (!breakpoint_enabled (b))
break;
if (b->exp_valid_block == NULL
|| frame_find_by_id (b->watchpoint_frame) != NULL)
{
if (b->exp)
{
xfree (b->exp);
b->exp = NULL;
}
s = b->exp_string;
b->exp = parse_exp_1 (&s, b->exp_valid_block, 0);
/* Since we reparsed expression, we need to update the
value. I'm not aware of any way a single solib load or unload
can change a valid value into different valid value, but:
- even if the value is no longer valid, we have to record
this fact, so that when it becomes valid we reports this
as value change
- unloaded followed by load can change the value for sure.
We set value to NULL, and insert_breakpoints will
update the value. */
if (b->val)
value_free (b->val);
b->val = NULL;
/* Loading of new shared library change the meaning of
watchpoint condition. However, insert_bp_location will
recompute watchpoint condition anyway, nothing to do here. */
}
break; break;
/* We needn't really do anything to reset these, since the mask /* We needn't really do anything to reset these, since the mask
that requests them is unaffected by e.g., new libraries being that requests them is unaffected by e.g., new libraries being

View File

@ -273,6 +273,12 @@ struct bp_location
bp_loc_other. */ bp_loc_other. */
CORE_ADDR address; CORE_ADDR address;
/* For hardware watchpoints, the size of data ad ADDRESS being watches. */
int length;
/* Type of hardware watchpoint. */
enum target_hw_bp_type watchpoint_type;
/* For any breakpoint type with an address, this is the BFD section /* For any breakpoint type with an address, this is the BFD section
associated with the address. Used primarily for overlay debugging. */ associated with the address. Used primarily for overlay debugging. */
asection *section; asection *section;
@ -388,9 +394,6 @@ struct breakpoint
/* Value of the watchpoint the last time we checked it. */ /* Value of the watchpoint the last time we checked it. */
struct value *val; struct value *val;
/* Holds the value chain for a hardware watchpoint expression. */
struct value *val_chain;
/* Holds the address of the related watchpoint_scope breakpoint /* Holds the address of the related watchpoint_scope breakpoint
when using watchpoints on local variables (might the concept when using watchpoints on local variables (might the concept
of a related breakpoint be useful elsewhere, if not just call of a related breakpoint be useful elsewhere, if not just call

View File

@ -1,3 +1,9 @@
2008-01-29 Vladimir Prus <vladimir@codesourcery.com>
* gdb.base/watchpoint-solib.exp: New.
* gdb.base/watchpoint-solib.c: New.
* gdb.base/watchpoint-solib-shr.c: New.
2008-01-29 Pierre Muller <muller@ics.u-strasbg.fr> 2008-01-29 Pierre Muller <muller@ics.u-strasbg.fr>
* gdb.base/gdb1056.exp: Add unsigned integer test. * gdb.base/gdb1056.exp: Add unsigned integer test.

View File

@ -0,0 +1,25 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2004, 2007 Free Software Foundation, Inc.
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 <http://www.gnu.org/licenses/>. */
#include <stdio.h>
int g = 0;
void foo (int i)
{
g = i;
}

View File

@ -0,0 +1,68 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2004, 2007 Free Software Foundation, Inc.
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 <http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#ifdef __WIN32__
#include <windows.h>
#define dlopen(name, mode) LoadLibrary (TEXT (name))
#ifdef _WIN32_WCE
# define dlsym(handle, func) GetProcAddress (handle, TEXT (func))
#else
# define dlsym(handle, func) GetProcAddress (handle, func)
#endif
#define dlclose(handle) FreeLibrary (handle)
#define dlerror() "error %d occurred", GetLastError ()
#else
#include <dlfcn.h>
#endif
void open_shlib ()
{
void *handle;
void (*foo) (int);
handle = dlopen (SHLIB_NAME, RTLD_LAZY);
if (!handle)
{
fprintf (stderr, dlerror ());
exit (1);
}
foo = (void (*)(int))dlsym (handle, "foo");
if (!foo)
{
fprintf (stderr, dlerror ());
exit (1);
}
foo (1); // call to foo
foo (2);
dlclose (handle);
}
int main()
{
open_shlib ();
return 0;
}

View File

@ -0,0 +1,91 @@
# Copyright 2007 Free Software Foundation, Inc.
# 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 <http://www.gnu.org/licenses/>.
if $tracelevel then {
strace $tracelevel
}
#
# test running programs
#
set prms_id 0
set bug_id 0
if {[skip_shlib_tests]} {
return 0
}
# TODO: Use LoadLibrary on this target instead of dlopen.
if {[istarget arm*-*-symbianelf*]} {
return 0
}
set testfile "watchpoint-solib"
set libfile "watchpoint-solib-shr"
set libname "${libfile}.sl"
set libsrcfile ${libfile}.c
set srcfile $srcdir/$subdir/$testfile.c
set binfile $objdir/$subdir/$testfile
set shlibdir ${objdir}/${subdir}
set libsrc $srcdir/$subdir/$libfile.c
set lib_sl $objdir/$subdir/$libname
if [get_compiler_info ${binfile}] {
return -1
}
set lib_opts debug
set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${libname}\"]
if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
|| [gdb_compile $srcfile $binfile executable $exec_opts] != ""} {
untested "Couldn't compile $libsrc or $srcfile."
return -1
}
# Start with a fresh gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_load_shlibs $lib_sl
if [target_info exists gdb_stub] {
gdb_step_for_stub;
}
runto_main
# Test that if we set a watchpoint on a global variable
# in a explicitly loaded shared library, and then
# re-run the application, gdb does not crash.
gdb_test_multiple "break foo" "set pending breakpoint" {
-re ".*Make breakpoint pending.*y or \\\[n\\\]. $" {
gdb_test "y" "Breakpoint.*foo.*pending." "set pending breakpoint"
}
}
gdb_test "continue" ".*Breakpoint 2.*foo.*" "continue to foo"
gdb_test "watch g" "Hardware watchpoint 3: g" "set watchpoint on g"
gdb_test "continue" ".*New value = 1.*" "continue to watchpoint hit"
rerun_to_main
gdb_test "continue" ".*Breakpoint 2.*foo.*" "continue to foo again"
gdb_test "continue" ".*New value = 1.*" "continue to watchpoint hit again"