From a5606eee5ec10851d09a8e2709354c7e0931a99c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 29 Jan 2008 17:52:47 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 29 + gdb/breakpoint.c | 512 +++++++++--------- gdb/breakpoint.h | 9 +- gdb/testsuite/ChangeLog | 6 + gdb/testsuite/gdb.base/watchpoint-solib-shr.c | 25 + gdb/testsuite/gdb.base/watchpoint-solib.c | 68 +++ gdb/testsuite/gdb.base/watchpoint-solib.exp | 91 ++++ 7 files changed, 483 insertions(+), 257 deletions(-) create mode 100644 gdb/testsuite/gdb.base/watchpoint-solib-shr.c create mode 100644 gdb/testsuite/gdb.base/watchpoint-solib.c create mode 100644 gdb/testsuite/gdb.base/watchpoint-solib.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index dda1c033518..120144d61d6 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,32 @@ +2008-01-29 Vladimir Prus + + 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 Don't reset watchpoint block on solib load. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index ecc24786012..0bed4efa028 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -200,6 +200,15 @@ static void free_bp_location (struct bp_location *loc); 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. */ /* 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 void -free_valchain (struct bp_location *b) +static int +is_hardware_watchpoint (struct breakpoint *bpt) { - struct value *v; - struct value *n; - - /* 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; + return (bpt->type == bp_hardware_watchpoint + || bpt->type == bp_read_watchpoint + || bpt->type == bp_access_watchpoint); } +/* 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. Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS, 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... */ && bpt->owner->disposition != disp_del_at_next_stop) { - /* FIXME drow/2003-09-08: This code sets multiple hardware watchpoints - based on the expression. Ideally this should happen at a higher level, - and there should be one bp_location for each computed address we - must watch. As soon as a many-to-one mapping is available I'll - 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; + val = target_insert_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type); + bpt->inserted = (val != -1); } else if (bpt->owner->type == bp_catch_fork @@ -1178,6 +1219,7 @@ in which its expression is valid.\n"), void insert_breakpoints (void) { + struct breakpoint *bpt; struct bp_location *b, *temp; int error = 0; int val = 0; @@ -1192,6 +1234,10 @@ insert_breakpoints (void) there was an error. */ 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) { if (!breakpoint_enabled (b->owner)) @@ -1203,19 +1249,6 @@ insert_breakpoints (void) && !valid_thread_id (b->owner->thread)) 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, &disabled_breaks, &process_warning, &hw_breakpoint_error); @@ -1223,6 +1256,39 @@ insert_breakpoints (void) 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 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; b->inserted = (is == mark_inserted); } - else if (b->loc_type == bp_loc_hardware_watchpoint - && breakpoint_enabled (b->owner) - && !b->duplicate) + else if (b->loc_type == bp_loc_hardware_watchpoint) { struct value *v; struct value *n; b->inserted = (is == mark_inserted); - /* Walk down the saved value chain. */ - for (v = b->owner->val_chain; v; v = value_next (v)) - { - /* 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)); + val = target_remove_watchpoint (b->address, b->length, + b->watchpoint_type); - 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. */ if ((is == mark_uninserted) && (b->inserted)) 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_access_watchpoint) { + struct bp_location *loc; struct value *v; b->watchpoint_triggered = watch_triggered_no; - for (v = b->val_chain; v; v = value_next (v)) - { - if (VALUE_LVAL (v) == lval_memory && ! value_lazy (v)) - { - struct type *vtype = check_typedef (value_type (v)); - - if (v == b->val_chain - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && 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; - } - } - } - } + for (loc = b->loc; loc; loc = loc->next) + /* Exact match not required. Within range is + sufficient. */ + if (addr >= loc->address + && addr < loc->address + loc->length) + { + b->watchpoint_triggered = watch_triggered_yes; + break; + } } 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)) 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 */ 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_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 (); insert_breakpoints (); break; @@ -3629,10 +3663,14 @@ print_one_breakpoint (struct breakpoint *b, disabled, we print it as if it had several locations, since otherwise it's hard to 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 + && !is_hardware_watchpoint (b) && (b->loc->next || !b->loc->enabled) - && !ui_out_is_mi_like_p (uiout)) + && !ui_out_is_mi_like_p (uiout)) { struct bp_location *loc; int n = 1; @@ -6829,9 +6867,7 @@ delete_breakpoint (struct breakpoint *bpt) { if (loc->inserted) remove_breakpoint (loc, mark_inserted); - - free_valchain (loc); - + if (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 be reevaluated again when enabled. */ - - 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. */ - } + update_watchpoint (b, 1 /* reparse */); break; /* We needn't really do anything to reset these, since the mask that requests them is unaffected by e.g., new libraries being diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 91667ab118c..7b72e196525 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -273,6 +273,12 @@ struct bp_location bp_loc_other. */ 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 associated with the address. Used primarily for overlay debugging. */ asection *section; @@ -388,9 +394,6 @@ struct breakpoint /* Value of the watchpoint the last time we checked it. */ 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 when using watchpoints on local variables (might the concept of a related breakpoint be useful elsewhere, if not just call diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index f3858ed3b87..a5d59203454 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2008-01-29 Vladimir Prus + + * gdb.base/watchpoint-solib.exp: New. + * gdb.base/watchpoint-solib.c: New. + * gdb.base/watchpoint-solib-shr.c: New. + 2008-01-29 Pierre Muller * gdb.base/gdb1056.exp: Add unsigned integer test. diff --git a/gdb/testsuite/gdb.base/watchpoint-solib-shr.c b/gdb/testsuite/gdb.base/watchpoint-solib-shr.c new file mode 100644 index 00000000000..699f559af92 --- /dev/null +++ b/gdb/testsuite/gdb.base/watchpoint-solib-shr.c @@ -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 . */ + +#include + +int g = 0; + +void foo (int i) +{ + g = i; +} diff --git a/gdb/testsuite/gdb.base/watchpoint-solib.c b/gdb/testsuite/gdb.base/watchpoint-solib.c new file mode 100644 index 00000000000..b316024b513 --- /dev/null +++ b/gdb/testsuite/gdb.base/watchpoint-solib.c @@ -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 . */ + +#include +#include + +#ifdef __WIN32__ +#include +#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 +#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; +} diff --git a/gdb/testsuite/gdb.base/watchpoint-solib.exp b/gdb/testsuite/gdb.base/watchpoint-solib.exp new file mode 100644 index 00000000000..f883f915034 --- /dev/null +++ b/gdb/testsuite/gdb.base/watchpoint-solib.exp @@ -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 . + +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" + + + + +