2004-12-13 21:48:04 +00:00
|
|
|
|
2004-12-13 Jeff Johnston <jjohnstn@redhat.com>
|
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
* linux-nat.c: (stop_wait_callback, linux-nat-wait): Notify
|
|
|
|
|
observers of a sigtrap.
|
2004-12-13 21:48:04 +00:00
|
|
|
|
(delete_lwp): Free the saved_trap_data if present.
|
|
|
|
|
* linux-nat.h (struct lwp_info): Add saved_trap_data field.
|
|
|
|
|
(struct linux_watchpoint): New struct.
|
2006-07-11 06:33:02 +00:00
|
|
|
|
* linux-thread-db.c: Add support to always keep lwp info in ptids.
|
2004-12-13 21:48:04 +00:00
|
|
|
|
(attach_thread): Notify observers of a linux
|
|
|
|
|
new thread.
|
|
|
|
|
(thread_db_wait): Call check_event if SIGILL occurs.
|
2006-07-11 06:33:02 +00:00
|
|
|
|
* infrun.c: (handle_inferior_event): For platforms that
|
2004-12-13 21:48:04 +00:00
|
|
|
|
hit watchpoints prior to the data write, mark the watchpoints
|
|
|
|
|
so we know to check them after we step through the write.
|
|
|
|
|
* breakpoint.c (bpstat_stop_status): Fix up watchpoint code.
|
|
|
|
|
(insert_watchpoints_for_new_thread): New function.
|
|
|
|
|
(mark_triggered_watchpoints): Ditto.
|
|
|
|
|
* breakpoint.h (insert_watchpoints_for_new_thread): New prototype.
|
|
|
|
|
(mark_triggered_watchpoints): Ditto.
|
|
|
|
|
* i386-linux-nat.c (i386_linux_dr_get, i386_linux_dr_set): Use
|
|
|
|
|
TIDGET to get PTRACE lpw, otherwise fall back to PIDGET.
|
|
|
|
|
* amd64-linux-nat.c (amd64_linux_dr_get, amd64_linux_dr_set): Ditto.
|
|
|
|
|
* ia64-linux-nat.c: Add support for removing and inserting watchpoints
|
|
|
|
|
on all threads.
|
|
|
|
|
* s390-nat.c: Ditto.
|
|
|
|
|
* Makefile.in: Add observer.h and linux-nat.h to ia64-linux-nat.o
|
|
|
|
|
and s390-nat.o.
|
|
|
|
|
* doc/observer.texi: Add two new observers for linux_new_thread
|
|
|
|
|
and sigtrap.
|
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/doc/observer.texi
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/doc/observer.texi 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/doc/observer.texi 2006-07-11 02:29:49.000000000 -0300
|
|
|
|
|
@@ -122,3 +122,13 @@ haven't been loaded yet.
|
|
|
|
|
@deftypefun void solib_unloaded (struct so_list *@var{solib})
|
|
|
|
|
The shared library specified by @var{solib} has been unloaded.
|
2004-12-13 21:48:04 +00:00
|
|
|
|
@end deftypefun
|
2006-07-11 06:33:02 +00:00
|
|
|
|
+
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+@deftypefun void linux_new_thread (ptid_t @var{ptid})
|
|
|
|
|
+A new linux thread described by @var{ptid} has been officially attached
|
|
|
|
|
+to by gdb.
|
|
|
|
|
+@end deftypefun
|
|
|
|
|
+
|
|
|
|
|
+@deftypefun void sigtrap (void * @var{data})
|
|
|
|
|
+A low-level SIGTRAP has been discovered. This notification can be used to save
|
|
|
|
|
+additional state necessary if the trap is deferred for later handling.
|
|
|
|
|
+@end deftypefun
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/infrun.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/infrun.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/infrun.c 2006-07-11 02:29:55.000000000 -0300
|
|
|
|
|
@@ -1703,9 +1703,19 @@ handle_inferior_event (struct execution_
|
2004-12-15 21:21:25 +00:00
|
|
|
|
single step over a watchpoint without disabling the watchpoint. */
|
|
|
|
|
if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
|
|
|
|
|
{
|
|
|
|
|
+ CORE_ADDR addr = 0;
|
|
|
|
|
+
|
2006-07-11 06:33:02 +00:00
|
|
|
|
if (debug_infrun)
|
|
|
|
|
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
|
|
|
|
|
- resume (1, 0);
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+
|
|
|
|
|
+ target_stopped_data_address (¤t_target, &addr);
|
|
|
|
|
+ mark_triggered_watchpoints (addr);
|
|
|
|
|
+ registers_changed ();
|
|
|
|
|
+ target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
|
|
|
|
|
+
|
|
|
|
|
+ ecs->waiton_ptid = ecs->ptid;
|
|
|
|
|
+ ecs->wp = &(ecs->ws);
|
|
|
|
|
+ ecs->infwait_state = infwait_nonstep_watch_state;
|
|
|
|
|
prepare_to_wait (ecs);
|
|
|
|
|
return;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
}
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -1715,6 +1725,8 @@ handle_inferior_event (struct execution_
|
2004-12-15 21:21:25 +00:00
|
|
|
|
register or page protection watchpoint scheme need here? */
|
|
|
|
|
if (HAVE_NONSTEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
|
|
|
|
|
{
|
|
|
|
|
+ CORE_ADDR addr = 0;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
/* At this point, we are stopped at an instruction which has
|
|
|
|
|
attempted to write to a piece of memory under control of
|
|
|
|
|
a watchpoint. The instruction hasn't actually executed
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -1722,15 +1734,12 @@ handle_inferior_event (struct execution_
|
2004-12-15 21:21:25 +00:00
|
|
|
|
now, we would get the old value, and therefore no change
|
|
|
|
|
would seem to have occurred.
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- In order to make watchpoints work `right', we really need
|
|
|
|
|
- to complete the memory write, and then evaluate the
|
|
|
|
|
- watchpoint expression. The following code does that by
|
|
|
|
|
- removing the watchpoint (actually, all watchpoints and
|
|
|
|
|
- breakpoints), single-stepping the target, re-inserting
|
|
|
|
|
- watchpoints, and then falling through to let normal
|
|
|
|
|
- single-step processing handle proceed. Since this
|
|
|
|
|
- includes evaluating watchpoints, things will come to a
|
|
|
|
|
- stop in the correct manner. */
|
|
|
|
|
+ In order to make watchpoints work `right', we mark the
|
|
|
|
|
+ triggered watchpoints so that after we single step,
|
|
|
|
|
+ we will check for a value change. */
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ target_stopped_data_address (¤t_target, &addr);
|
|
|
|
|
+ mark_triggered_watchpoints (addr);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
if (debug_infrun)
|
|
|
|
|
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
|
|
|
|
|
@@ -1801,6 +1810,41 @@ handle_inferior_event (struct execution_
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ if (stop_signal == TARGET_SIGNAL_TRAP
|
|
|
|
|
+ && trap_expected
|
|
|
|
|
+ && gdbarch_single_step_through_delay_p (current_gdbarch)
|
|
|
|
|
+ && currently_stepping (ecs))
|
|
|
|
|
+ {
|
|
|
|
|
+ /* We're trying to step of a breakpoint. Turns out that we're
|
|
|
|
|
+ also on an instruction that needs to be stepped multiple
|
|
|
|
|
+ times before it's been fully executing. E.g., architectures
|
|
|
|
|
+ with a delay slot. It needs to be stepped twice, once for
|
|
|
|
|
+ the instruction and once for the delay slot. */
|
|
|
|
|
+ int step_through_delay
|
|
|
|
|
+ = gdbarch_single_step_through_delay (current_gdbarch,
|
|
|
|
|
+ get_current_frame ());
|
|
|
|
|
+ if (debug_infrun && step_through_delay)
|
2006-07-11 06:33:02 +00:00
|
|
|
|
+ fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n");
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ if (step_range_end == 0 && step_through_delay)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* The user issued a continue when stopped at a breakpoint.
|
|
|
|
|
+ Set up for another trap and get out of here. */
|
|
|
|
|
+ ecs->another_trap = 1;
|
|
|
|
|
+ keep_going (ecs);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (step_through_delay)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* The user issued a step when stopped at a breakpoint.
|
|
|
|
|
+ Maybe we should stop, maybe we should not - the delay
|
|
|
|
|
+ slot *might* correspond to a line of source. In any
|
|
|
|
|
+ case, don't decide that here, just set ecs->another_trap,
|
|
|
|
|
+ making sure we single-step again before breakpoints are
|
|
|
|
|
+ re-inserted. */
|
|
|
|
|
+ ecs->another_trap = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
/* Look at the cause of the stop, and decide what to do.
|
|
|
|
|
The alternatives are:
|
|
|
|
|
1) break; to really stop and return to the debugger,
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -1852,6 +1896,8 @@ handle_inferior_event (struct execution_
|
|
|
|
|
See more comments in inferior.h. */
|
|
|
|
|
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
+ if (debug_infrun)
|
2006-07-11 06:33:02 +00:00
|
|
|
|
+ fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
|
2004-12-15 21:21:25 +00:00
|
|
|
|
stop_stepping (ecs);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
if (stop_signal == TARGET_SIGNAL_STOP)
|
|
|
|
|
stop_signal = TARGET_SIGNAL_0;
|
|
|
|
|
Index: gdb-6.5/gdb/breakpoint.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/breakpoint.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/breakpoint.c 2006-07-11 02:29:50.000000000 -0300
|
|
|
|
|
@@ -748,6 +748,90 @@ insert_catchpoint (struct ui_out *uo, vo
|
2004-12-15 21:21:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* External function to insert all existing watchpoints on a newly
|
|
|
|
|
+ attached thread. IWPFN is a callback function to perform
|
|
|
|
|
+ the target insert watchpoint. This function is used to support
|
|
|
|
|
+ platforms where a watchpoint must be inserted/removed on each
|
|
|
|
|
+ individual thread (e.g. ia64-linux and s390-linux). For
|
|
|
|
|
+ ia64 and s390 linux, this function is called via a new thread
|
|
|
|
|
+ observer. */
|
|
|
|
|
+int
|
|
|
|
|
+insert_watchpoints_for_new_thread (ptid_t new_thread,
|
|
|
|
|
+ insert_watchpoint_ftype *iwpfn)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bp_location *b;
|
|
|
|
|
+ int val = 0;
|
|
|
|
|
+ int return_val = 0;
|
|
|
|
|
+ struct ui_file *tmp_error_stream = mem_fileopen ();
|
|
|
|
|
+ make_cleanup_ui_file_delete (tmp_error_stream);
|
|
|
|
|
+
|
|
|
|
|
+ /* Explicitly mark the warning -- this will only be printed if
|
|
|
|
|
+ there was an error. */
|
|
|
|
|
+ fprintf_unfiltered (tmp_error_stream, "Warning:\n");
|
|
|
|
|
+
|
|
|
|
|
+ ALL_BP_LOCATIONS (b)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Skip disabled breakpoints. */
|
|
|
|
|
+ if (!breakpoint_enabled (b->owner))
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ /* For every active watchpoint, we need to insert the watchpoint on
|
|
|
|
|
+ the new thread. */
|
|
|
|
|
+ if (b->loc_type == bp_loc_hardware_watchpoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ struct value *v = b->owner->val_chain;
|
|
|
|
|
+
|
|
|
|
|
+ /* Look at each value on the value chain. */
|
|
|
|
|
+ for (; v; 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->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 = (*iwpfn) (new_thread, addr, len, type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (val)
|
|
|
|
|
+ return_val = val;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Failure to insert a watchpoint on any memory value in the
|
|
|
|
|
+ value chain brings us here. */
|
|
|
|
|
+ if (return_val)
|
|
|
|
|
+ {
|
|
|
|
|
+ fprintf_unfiltered (tmp_error_stream,
|
|
|
|
|
+ "%s\n",
|
|
|
|
|
+ "Could not insert hardware watchpoints on new thread.");
|
|
|
|
|
+ target_terminal_ours_for_output ();
|
|
|
|
|
+ error_stream (tmp_error_stream);
|
|
|
|
|
+ }
|
|
|
|
|
+ return return_val;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Helper routine: free the value chain for a breakpoint (watchpoint). */
|
|
|
|
|
|
|
|
|
|
static void free_valchain (struct bp_location *b)
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -1190,6 +1274,7 @@ remove_breakpoints (void)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
struct bp_location *b;
|
|
|
|
|
int val;
|
|
|
|
|
+ int return_val = 0;
|
|
|
|
|
|
|
|
|
|
ALL_BP_LOCATIONS (b)
|
|
|
|
|
{
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -1197,10 +1282,10 @@ remove_breakpoints (void)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
val = remove_breakpoint (b, mark_uninserted);
|
|
|
|
|
if (val != 0)
|
|
|
|
|
- return val;
|
|
|
|
|
+ return_val = val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
- return 0;
|
|
|
|
|
+ return return_val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2126,8 +2211,13 @@ print_it_typical (bpstat bs)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case bp_thread_event:
|
|
|
|
|
- /* Not sure how we will get here.
|
|
|
|
|
- GDB should not stop for these breakpoints. */
|
|
|
|
|
+ /* We can only get here legitimately if something further on the bs
|
|
|
|
|
+ list has caused the stop status to be noisy. A valid example
|
|
|
|
|
+ of this is a new thread event and a software watchpoint have
|
|
|
|
|
+ both occurred. */
|
|
|
|
|
+ if (bs->next)
|
|
|
|
|
+ return PRINT_UNKNOWN;
|
|
|
|
|
+
|
2006-07-11 06:33:02 +00:00
|
|
|
|
printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n"));
|
2004-12-15 21:21:25 +00:00
|
|
|
|
return PRINT_NOTHING;
|
|
|
|
|
break;
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2567,6 +2657,54 @@ which its expression is valid.\n");
|
2004-12-15 21:21:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* Check watchpoints for a match with a stopped data address.
|
|
|
|
|
+
|
|
|
|
|
+ STOPPED_DATA_ADDRESS is the address of a triggered watchpoint.
|
|
|
|
|
+ A match with an existing watchpoint will cause that watchpoint
|
|
|
|
|
+ to be marked as triggered.
|
|
|
|
|
+
|
|
|
|
|
+ This function is only used for platforms where a watchpoint
|
|
|
|
|
+ triggers prior to the data being accessed. */
|
|
|
|
|
+
|
|
|
|
|
+void
|
|
|
|
|
+mark_triggered_watchpoints (CORE_ADDR stopped_data_address)
|
|
|
|
|
+{
|
|
|
|
|
+ struct breakpoint *b, *temp;
|
|
|
|
|
+ CORE_ADDR addr = stopped_data_address;
|
|
|
|
|
+ struct value *v;
|
|
|
|
|
+
|
|
|
|
|
+ ALL_BREAKPOINTS_SAFE (b, temp)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (b->type == bp_hardware_watchpoint
|
|
|
|
|
+ || b->type == bp_read_watchpoint
|
|
|
|
|
+ || b->type == bp_access_watchpoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ for (v = b->val_chain; v; v = v->next)
|
|
|
|
|
+ {
|
|
|
|
|
+ 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 = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Get a bpstat associated with having just stopped at address
|
|
|
|
|
BP_ADDR in thread PTID. STOPPED_BY_WATCHPOINT is 1 if the
|
|
|
|
|
target thinks we stopped due to a hardware watchpoint, 0 if we
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2697,82 +2835,61 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
|
2004-12-15 21:21:25 +00:00
|
|
|
|
bs->stop = 1;
|
|
|
|
|
bs->print = 1;
|
|
|
|
|
|
|
|
|
|
- if (b->type == bp_watchpoint ||
|
|
|
|
|
- b->type == bp_hardware_watchpoint)
|
|
|
|
|
- {
|
|
|
|
|
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
|
|
|
|
|
- b->number);
|
|
|
|
|
- struct cleanup *cleanups = make_cleanup (xfree, message);
|
|
|
|
|
- int e = catch_errors (watchpoint_check, bs, message,
|
|
|
|
|
- RETURN_MASK_ALL);
|
|
|
|
|
- do_cleanups (cleanups);
|
|
|
|
|
- switch (e)
|
|
|
|
|
- {
|
|
|
|
|
- case WP_DELETED:
|
|
|
|
|
- /* We've already printed what needs to be printed. */
|
|
|
|
|
- /* Actually this is superfluous, because by the time we
|
|
|
|
|
- call print_it_typical() the wp will be already deleted,
|
|
|
|
|
- and the function will return immediately. */
|
|
|
|
|
- bs->print_it = print_it_done;
|
|
|
|
|
- /* Stop. */
|
|
|
|
|
- break;
|
|
|
|
|
- case WP_VALUE_CHANGED:
|
|
|
|
|
- /* Stop. */
|
|
|
|
|
- ++(b->hit_count);
|
|
|
|
|
- break;
|
|
|
|
|
- case WP_VALUE_NOT_CHANGED:
|
|
|
|
|
- /* Don't stop. */
|
|
|
|
|
- bs->print_it = print_it_noop;
|
|
|
|
|
- bs->stop = 0;
|
|
|
|
|
- continue;
|
|
|
|
|
- default:
|
|
|
|
|
- /* Can't happen. */
|
|
|
|
|
- /* FALLTHROUGH */
|
|
|
|
|
- case 0:
|
|
|
|
|
- /* Error from catch_errors. */
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- if (b->related_breakpoint)
|
|
|
|
|
- b->related_breakpoint->disposition = disp_del_at_next_stop;
|
|
|
|
|
- b->disposition = disp_del_at_next_stop;
|
|
|
|
|
- /* We've already printed what needs to be printed. */
|
|
|
|
|
- bs->print_it = print_it_done;
|
|
|
|
|
-
|
|
|
|
|
- /* Stop. */
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if (b->type == bp_read_watchpoint ||
|
|
|
|
|
- b->type == bp_access_watchpoint)
|
|
|
|
|
+ if (b->type == bp_watchpoint
|
|
|
|
|
+ || b->type == bp_read_watchpoint
|
|
|
|
|
+ || b->type == bp_access_watchpoint
|
|
|
|
|
+ || b->type == bp_hardware_watchpoint)
|
|
|
|
|
{
|
|
|
|
|
CORE_ADDR addr;
|
|
|
|
|
struct value *v;
|
|
|
|
|
- int found = 0;
|
|
|
|
|
+ int must_check_value = 0;
|
|
|
|
|
|
|
|
|
|
- if (!target_stopped_data_address (¤t_target, &addr))
|
|
|
|
|
- continue;
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- for (v = b->val_chain; v; v = value_next (v))
|
|
|
|
|
+ if (b->type == bp_watchpoint
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ || b->watchpoint_triggered
|
|
|
|
|
+ || (b->type == bp_hardware_watchpoint
|
|
|
|
|
+ && !target_stopped_data_address_p (¤t_target)))
|
|
|
|
|
{
|
|
|
|
|
- if (VALUE_LVAL (v) == lval_memory
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- && ! value_lazy (v))
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ /* We either have a software watchpoint, a triggered watchpoint
|
|
|
|
|
+ which we have stepped over, or we cannot ascertain what data
|
|
|
|
|
+ address causes a write watchpoint. In all these
|
|
|
|
|
+ cases, we must check the watchpoint value. */
|
|
|
|
|
+ b->watchpoint_triggered = 0;
|
|
|
|
|
+ must_check_value = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* At this point, we know target_stopped_data_address () works or
|
|
|
|
|
+ we have a read or access watchpoint and have no alternatives. */
|
|
|
|
|
+ if (!target_stopped_data_address (¤t_target, &addr))
|
|
|
|
|
{
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- struct type *vtype = check_typedef (value_type (v));
|
2004-12-15 21:21:25 +00:00
|
|
|
|
-
|
|
|
|
|
- if (v == b->val_chain
|
|
|
|
|
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
|
|
|
|
|
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
|
|
|
|
|
+ bs->print_it = print_it_noop;
|
|
|
|
|
+ bs->stop = 0;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (v = b->val_chain; v; v = v->next)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (VALUE_LVAL (v) == lval_memory
|
|
|
|
|
+ && ! VALUE_LAZY (v))
|
|
|
|
|
{
|
|
|
|
|
- CORE_ADDR vaddr;
|
|
|
|
|
-
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- vaddr = VALUE_ADDRESS (v) + value_offset (v);
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- /* Exact match not required. Within range is
|
|
|
|
|
- sufficient. */
|
|
|
|
|
- if (addr >= vaddr &&
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- addr < vaddr + TYPE_LENGTH (value_type (v)))
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- found = 1;
|
|
|
|
|
+ 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)))
|
|
|
|
|
+ must_check_value = 1;
|
|
|
|
|
+ }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
- if (found)
|
2006-07-11 06:33:02 +00:00
|
|
|
|
+ if (must_check_value)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
|
|
|
|
|
b->number);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2801,6 +2918,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
|
2004-12-15 21:21:25 +00:00
|
|
|
|
break;
|
|
|
|
|
case WP_VALUE_NOT_CHANGED:
|
|
|
|
|
/* Stop. */
|
|
|
|
|
+ if (b->type == bp_hardware_watchpoint
|
|
|
|
|
+ || b->type == bp_watchpoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Don't stop: write watchpoints shouldn't fire if
|
|
|
|
|
+ the value hasn't changed. */
|
|
|
|
|
+ bs->print_it = print_it_noop;
|
|
|
|
|
+ bs->stop = 0;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
++(b->hit_count);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2816,7 +2942,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
|
2004-12-15 21:21:25 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
- else /* found == 0 */
|
|
|
|
|
+ else /* must_check_value == 0 */
|
|
|
|
|
{
|
|
|
|
|
/* This is a case where some watchpoint(s) triggered,
|
|
|
|
|
but not at the address of this watchpoint (FOUND
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -4112,6 +4238,7 @@ set_raw_breakpoint (struct symtab_and_li
|
2004-12-15 21:21:25 +00:00
|
|
|
|
b->exec_pathname = NULL;
|
|
|
|
|
b->ops = NULL;
|
|
|
|
|
b->pending = 0;
|
|
|
|
|
+ b->watchpoint_triggered = 0;
|
|
|
|
|
|
|
|
|
|
/* Add this breakpoint to the end of the chain
|
|
|
|
|
so that a list of breakpoints will come out in order
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/breakpoint.h
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/breakpoint.h 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/breakpoint.h 2006-07-11 02:29:49.000000000 -0300
|
|
|
|
|
@@ -426,6 +426,11 @@ struct breakpoint
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2005-01-07 22:49:23 +00:00
|
|
|
|
/* Is breakpoint pending on shlib loads? */
|
|
|
|
|
int pending;
|
|
|
|
|
+
|
|
|
|
|
+ /* Has a watchpoint been triggered? This is only used for
|
|
|
|
|
+ non-continuable watchpoints which trigger prior to the data
|
|
|
|
|
+ being modified. */
|
|
|
|
|
+ int watchpoint_triggered;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* The following stuff is an abstract data type "bpstat" ("breakpoint
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -692,6 +697,14 @@ extern void tbreak_command (char *, int)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
|
|
|
|
|
extern int insert_breakpoints (void);
|
|
|
|
|
|
|
|
|
|
+/* The following provides a callback mechanism to insert watchpoints
|
|
|
|
|
+ for a new thread. This is needed, for example, on ia64 linux. */
|
|
|
|
|
+typedef int (insert_watchpoint_ftype) (ptid_t, CORE_ADDR, int, int);
|
|
|
|
|
+extern int insert_watchpoints_for_new_thread (ptid_t ptid,
|
|
|
|
|
+ insert_watchpoint_ftype *fn);
|
|
|
|
|
+
|
|
|
|
|
+extern void mark_triggered_watchpoints (CORE_ADDR);
|
|
|
|
|
+
|
|
|
|
|
extern int remove_breakpoints (void);
|
|
|
|
|
|
|
|
|
|
/* This function can be used to physically insert eventpoints from the
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/linux-nat.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/linux-nat.c 2006-07-07 04:24:57.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/linux-nat.c 2006-07-11 02:29:49.000000000 -0300
|
|
|
|
|
@@ -36,6 +36,7 @@
|
2005-01-07 22:49:23 +00:00
|
|
|
|
#include "gdbthread.h"
|
|
|
|
|
#include "gdbcmd.h"
|
|
|
|
|
#include "regcache.h"
|
|
|
|
|
+#include "observer.h"
|
2006-07-11 06:33:02 +00:00
|
|
|
|
#include "regset.h"
|
|
|
|
|
#include "inf-ptrace.h"
|
|
|
|
|
#include "auxv.h"
|
|
|
|
|
@@ -764,6 +765,9 @@ delete_lwp (ptid_t ptid)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
else
|
|
|
|
|
lwp_list = lp->next;
|
|
|
|
|
|
|
|
|
|
+ if (lp->saved_trap_data)
|
|
|
|
|
+ xfree (lp->saved_trap_data);
|
|
|
|
|
+
|
|
|
|
|
xfree (lp);
|
|
|
|
|
}
|
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -1478,6 +1482,13 @@ stop_wait_callback (struct lwp_info *lp,
|
2005-01-07 22:49:23 +00:00
|
|
|
|
user will delete or disable the breakpoint, but the
|
|
|
|
|
thread will have already tripped on it. */
|
|
|
|
|
|
|
|
|
|
+ /* Notify any observers that we have a SIGTRAP.
|
|
|
|
|
+ This is needed on platforms that must save more state
|
|
|
|
|
+ than just the trap. For example, ia64 linux uses
|
|
|
|
|
+ siginfo to determine if a watchpoint has occurred and
|
|
|
|
|
+ this information gets trashed by a SIGSTOP. */
|
|
|
|
|
+ observer_notify_sigtrap (lp);
|
|
|
|
|
+
|
|
|
|
|
/* Now resume this LWP and get the SIGSTOP event. */
|
|
|
|
|
errno = 0;
|
|
|
|
|
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2054,6 +2065,14 @@ retry:
|
|
|
|
|
target_pid_to_str (lp->ptid));
|
2005-01-07 22:49:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /* For platforms such as ia64, a hardware watchpoint is
|
|
|
|
|
+ determined by looking at special information available
|
|
|
|
|
+ at the time time of the trap (siginfo). This information
|
|
|
|
|
+ is not preserved if we choose to take an event on another
|
|
|
|
|
+ thread and later come back to this event, thus we must
|
|
|
|
|
+ notify an observer so the information can be stored. */
|
|
|
|
|
+ observer_notify_sigtrap (lp);
|
|
|
|
|
+
|
|
|
|
|
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
|
|
|
|
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
|
|
|
|
{
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/linux-nat.h
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/linux-nat.h 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/linux-nat.h 2006-07-07 04:24:57.000000000 -0300
|
|
|
|
|
@@ -63,6 +63,18 @@ struct lwp_info
|
2005-01-07 22:49:23 +00:00
|
|
|
|
|
|
|
|
|
/* Next LWP in list. */
|
|
|
|
|
struct lwp_info *next;
|
|
|
|
|
+
|
|
|
|
|
+ /* Optional saved trap state for when a trap gets pushed back
|
|
|
|
|
+ due to multiple events occurring at the same time. */
|
|
|
|
|
+ void *saved_trap_data;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/* Watchpoint description. */
|
|
|
|
|
+struct linux_watchpoint
|
|
|
|
|
+{
|
|
|
|
|
+ CORE_ADDR addr;
|
|
|
|
|
+ int len;
|
|
|
|
|
+ int type;
|
|
|
|
|
};
|
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
/* Attempt to initialize libthread_db. */
|
|
|
|
|
Index: gdb-6.5/gdb/Makefile.in
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/Makefile.in 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/Makefile.in 2006-07-11 02:29:50.000000000 -0300
|
|
|
|
|
@@ -2113,7 +2113,7 @@ i387-tdep.o: i387-tdep.c $(defs_h) $(dou
|
|
|
|
|
$(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
ia64-linux-nat.o: ia64-linux-nat.c $(defs_h) $(gdb_string_h) $(inferior_h) \
|
2006-07-11 06:33:02 +00:00
|
|
|
|
$(target_h) $(gdbcore_h) $(regcache_h) $(ia64_tdep_h) $(gdb_wait_h) \
|
|
|
|
|
- $(gregset_h) $(linux_nat_h)
|
|
|
|
|
+ $(gregset_h) $(observer_h) $(linux_nat_h)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(ia64_tdep_h) \
|
2006-07-11 06:33:02 +00:00
|
|
|
|
$(arch_utils_h) $(gdbcore_h) $(regcache_h) $(osabi_h) $(solib_svr4_h)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -2518,7 +2518,7 @@ rs6000-tdep.o: rs6000-tdep.c $(defs_h) $
|
|
|
|
|
$(frame_unwind_h) $(frame_base_h) $(rs6000_tdep_h)
|
|
|
|
|
rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(osabi_h) $(rs6000_tdep_h)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
s390-nat.o: s390-nat.c $(defs_h) $(tm_h) $(regcache_h) $(inferior_h) \
|
2006-07-11 06:33:02 +00:00
|
|
|
|
- $(s390_tdep_h) $(target_h) $(linux_nat_h)
|
|
|
|
|
+ $(s390_tdep_h) $(target_h) $(observer_h) $(linux_nat_h)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
s390-tdep.o: s390-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) $(inferior_h) \
|
|
|
|
|
$(symtab_h) $(target_h) $(gdbcore_h) $(gdbcmd_h) $(objfiles_h) \
|
2006-07-11 06:33:02 +00:00
|
|
|
|
$(floatformat_h) $(regcache_h) $(trad_frame_h) $(frame_base_h) \
|
|
|
|
|
Index: gdb-6.5/gdb/linux-thread-db.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/linux-thread-db.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/linux-thread-db.c 2006-07-11 02:29:49.000000000 -0300
|
|
|
|
|
@@ -36,6 +36,7 @@
|
2005-01-07 22:49:23 +00:00
|
|
|
|
#include "target.h"
|
|
|
|
|
#include "regcache.h"
|
|
|
|
|
#include "solib-svr4.h"
|
|
|
|
|
+#include "observer.h"
|
2006-07-11 06:33:02 +00:00
|
|
|
|
#include "gdbcore.h"
|
|
|
|
|
#include "linux-nat.h"
|
2005-01-07 22:49:23 +00:00
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -718,6 +719,7 @@ attach_thread (ptid_t ptid, const td_thr
|
2005-01-07 22:49:23 +00:00
|
|
|
|
{
|
|
|
|
|
struct thread_info *tp;
|
|
|
|
|
td_err_e err;
|
|
|
|
|
+ ptid_t new_ptid;
|
|
|
|
|
|
|
|
|
|
/* If we're being called after a TD_CREATE event, we may already
|
|
|
|
|
know about this thread. There are two ways this can happen. We
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -753,11 +755,18 @@ attach_thread (ptid_t ptid, const td_thr
|
2005-01-07 22:49:23 +00:00
|
|
|
|
if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
|
|
|
|
|
return; /* A zombie thread -- do not attach. */
|
|
|
|
|
|
|
|
|
|
+ new_ptid = BUILD_LWP (ti_p->ti_lid, GET_PID (ptid));
|
|
|
|
|
+
|
|
|
|
|
/* Under GNU/Linux, we have to attach to each and every thread. */
|
|
|
|
|
#ifdef ATTACH_LWP
|
|
|
|
|
- ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
|
|
|
|
|
+ ATTACH_LWP (new_ptid, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
+ /* Notify any observers of a new linux thread. This
|
|
|
|
|
+ would include any linux platforms that have to insert hardware
|
|
|
|
|
+ watchpoints on every thread. */
|
|
|
|
|
+ observer_notify_linux_new_thread (new_ptid);
|
|
|
|
|
+
|
|
|
|
|
/* Enable thread event reporting for this thread. */
|
|
|
|
|
err = td_thr_event_enable_p (th_p, 1);
|
|
|
|
|
if (err != TD_OK)
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -946,7 +955,8 @@ thread_db_wait (ptid_t ptid, struct targ
|
2005-01-07 22:49:23 +00:00
|
|
|
|
return pid_to_ptid (-1);
|
|
|
|
|
|
|
|
|
|
if (ourstatus->kind == TARGET_WAITKIND_STOPPED
|
|
|
|
|
- && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
|
|
|
|
|
+ && (ourstatus->value.sig == TARGET_SIGNAL_TRAP
|
|
|
|
|
+ || ourstatus->value.sig == TARGET_SIGNAL_ILL))
|
|
|
|
|
/* Check for a thread event. */
|
|
|
|
|
check_event (ptid);
|
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/i386-linux-nat.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/i386-linux-nat.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/i386-linux-nat.c 2006-07-11 02:29:47.000000000 -0300
|
|
|
|
|
@@ -619,10 +619,9 @@ i386_linux_dr_get (int regnum)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
int tid;
|
|
|
|
|
unsigned long value;
|
|
|
|
|
|
|
|
|
|
- /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
|
|
|
|
|
- multi-threaded processes here. For now, pretend there is just
|
|
|
|
|
- one thread. */
|
|
|
|
|
- tid = PIDGET (inferior_ptid);
|
|
|
|
|
+ tid = TIDGET (inferior_ptid);
|
|
|
|
|
+ if (tid == 0)
|
|
|
|
|
+ tid = PIDGET (inferior_ptid);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2005-01-07 22:49:23 +00:00
|
|
|
|
/* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
|
|
|
|
|
ptrace call fails breaks debugging remote targets. The correct
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -647,10 +646,9 @@ i386_linux_dr_set (int regnum, unsigned
|
2005-01-07 22:49:23 +00:00
|
|
|
|
{
|
|
|
|
|
int tid;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2005-01-07 22:49:23 +00:00
|
|
|
|
- /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
|
|
|
|
|
- multi-threaded processes here. For now, pretend there is just
|
|
|
|
|
- one thread. */
|
|
|
|
|
- tid = PIDGET (inferior_ptid);
|
|
|
|
|
+ tid = TIDGET (inferior_ptid);
|
|
|
|
|
+ if (tid == 0)
|
|
|
|
|
+ tid = PIDGET (inferior_ptid);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2005-01-07 22:49:23 +00:00
|
|
|
|
errno = 0;
|
|
|
|
|
ptrace (PTRACE_POKEUSER, tid,
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/ia64-linux-nat.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/ia64-linux-nat.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/ia64-linux-nat.c 2006-07-11 02:29:46.000000000 -0300
|
|
|
|
|
@@ -41,6 +41,8 @@
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
#include <asm/ptrace_offsets.h>
|
|
|
|
|
#include <sys/procfs.h>
|
|
|
|
|
+#include "observer.h"
|
|
|
|
|
+#include "linux-nat.h"
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
/* Prototypes for supply_gregset etc. */
|
|
|
|
|
#include "gregset.h"
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -561,8 +563,9 @@ is_power_of_2 (int val)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
return onecount <= 1;
|
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
-int
|
|
|
|
|
-ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
|
|
|
|
|
+/* Internal routine to insert one watchpoint for a specified thread. */
|
|
|
|
|
+static int
|
|
|
|
|
+ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
long dbr_addr, dbr_mask;
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -608,8 +611,38 @@ ia64_linux_insert_watchpoint (ptid_t pti
|
2004-12-15 21:21:25 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* Internal callback routine which can be used via iterate_over_lwps
|
|
|
|
|
+ to insert a specific watchpoint from all active threads. */
|
|
|
|
|
+static int
|
|
|
|
|
+ia64_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data)
|
|
|
|
|
+{
|
|
|
|
|
+ struct linux_watchpoint *args = (struct linux_watchpoint *)data;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ return ia64_linux_insert_one_watchpoint (lwp->ptid, args->addr,
|
|
|
|
|
+ args->len, args->type);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Insert a watchpoint for all threads. */
|
|
|
|
|
int
|
|
|
|
|
-ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
|
|
|
|
|
+ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
|
|
|
|
|
+{
|
|
|
|
|
+ struct linux_watchpoint args;
|
|
|
|
|
+
|
|
|
|
|
+ args.addr = addr;
|
|
|
|
|
+ args.len = len;
|
|
|
|
|
+ args.type = rw;
|
|
|
|
|
+
|
|
|
|
|
+ /* For ia64, watchpoints must be inserted/removed on each thread so
|
|
|
|
|
+ we iterate over the lwp list. */
|
|
|
|
|
+ if (iterate_over_lwps (&ia64_linux_insert_watchpoint_callback, &args))
|
|
|
|
|
+ return -1;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Internal routine to remove one watchpoint for a specified thread. */
|
|
|
|
|
+static int
|
|
|
|
|
+ia64_linux_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
long dbr_addr, dbr_mask;
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -632,23 +665,74 @@ ia64_linux_remove_watchpoint (ptid_t pti
|
2004-12-15 21:21:25 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* Internal callback routine which can be used via iterate_over_lwps
|
|
|
|
|
+ to remove a specific watchpoint from all active threads. */
|
|
|
|
|
+static int
|
|
|
|
|
+ia64_linux_remove_watchpoint_callback (struct lwp_info *lwp, void *data)
|
|
|
|
|
+{
|
|
|
|
|
+ struct linux_watchpoint *args = (struct linux_watchpoint *)data;
|
|
|
|
|
+
|
|
|
|
|
+ return ia64_linux_remove_one_watchpoint (lwp->ptid, args->addr,
|
|
|
|
|
+ args->len);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Remove a watchpoint for all threads. */
|
|
|
|
|
+int
|
|
|
|
|
+ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
|
|
|
|
|
+{
|
|
|
|
|
+ struct linux_watchpoint args;
|
|
|
|
|
+
|
|
|
|
|
+ args.addr = addr;
|
|
|
|
|
+ args.len = len;
|
|
|
|
|
+
|
|
|
|
|
+ /* For ia64, watchpoints must be inserted/removed on each thread so
|
|
|
|
|
+ we iterate over the lwp list. */
|
|
|
|
|
+ if (iterate_over_lwps (&ia64_linux_remove_watchpoint_callback, &args))
|
|
|
|
|
+ return -1;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Callback to find lwp_info struct for a given lwp. */
|
|
|
|
|
+static int
|
|
|
|
|
+find_lwp_info (struct lwp_info *lp, void *data)
|
|
|
|
|
+{
|
|
|
|
|
+ int lwp = *(int *)data;
|
|
|
|
|
+
|
|
|
|
|
+ if (lwp == TIDGET (lp->ptid))
|
|
|
|
|
+ return 1;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
int
|
|
|
|
|
ia64_linux_stopped_data_address (CORE_ADDR *addr_p)
|
|
|
|
|
{
|
|
|
|
|
CORE_ADDR psr;
|
|
|
|
|
int tid;
|
|
|
|
|
struct siginfo siginfo;
|
|
|
|
|
+ struct siginfo *siginfo_p;
|
|
|
|
|
ptid_t ptid = inferior_ptid;
|
|
|
|
|
+ struct lwp_info *lp;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
tid = TIDGET(ptid);
|
|
|
|
|
if (tid == 0)
|
|
|
|
|
tid = PIDGET (ptid);
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
- ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
|
|
|
|
|
+ /* Check to see if we have already cached the siginfo for this
|
|
|
|
|
+ event. */
|
|
|
|
|
+ lp = iterate_over_lwps (find_lwp_info, &tid);
|
|
|
|
|
+ if (lp && lp->saved_trap_data != NULL)
|
|
|
|
|
+ siginfo_p = (struct siginfo *)lp->saved_trap_data;
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ siginfo_p = &siginfo;
|
|
|
|
|
+ ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, siginfo_p);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
- if (errno != 0 || siginfo.si_signo != SIGTRAP ||
|
|
|
|
|
- (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
|
|
|
|
|
+ if (errno != 0 || siginfo_p->si_signo != SIGTRAP ||
|
|
|
|
|
+ (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
psr = read_register_pid (IA64_PSR_REGNUM, ptid);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -656,7 +740,7 @@ ia64_linux_stopped_data_address (CORE_AD
|
2004-12-15 21:21:25 +00:00
|
|
|
|
for the next instruction */
|
|
|
|
|
write_register_pid (IA64_PSR_REGNUM, psr, ptid);
|
|
|
|
|
|
|
|
|
|
- *addr_p = (CORE_ADDR)siginfo.si_addr;
|
|
|
|
|
+ *addr_p = (CORE_ADDR)siginfo_p->si_addr;
|
|
|
|
|
return 1;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -702,3 +786,36 @@ _initialize_ia64_linux_nat (void)
|
|
|
|
|
/* Register the target. */
|
|
|
|
|
linux_nat_add_target (t);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
}
|
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* Observer function for a new thread attach. We need to insert
|
|
|
|
|
+ existing watchpoints on the new thread. */
|
|
|
|
|
+static void
|
|
|
|
|
+ia64_linux_new_thread (ptid_t ptid)
|
|
|
|
|
+{
|
|
|
|
|
+ insert_watchpoints_for_new_thread (ptid,
|
|
|
|
|
+ &ia64_linux_insert_one_watchpoint);
|
|
|
|
|
+}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* For ia64 linux, we must save the siginfo data as part of the state
|
|
|
|
|
+ of a queued SIGTRAP. This is because siginfo is used to determine
|
|
|
|
|
+ if a watchpoint has occurred and the information will be lost if
|
|
|
|
|
+ a SIGSTOP is issued to the thread. */
|
|
|
|
|
+void
|
|
|
|
|
+ia64_linux_save_sigtrap_info (void *queue_data)
|
|
|
|
|
+{
|
|
|
|
|
+ struct lwp_info *lp = (struct lwp_info *)queue_data;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ if (lp->saved_trap_data == NULL)
|
|
|
|
|
+ lp->saved_trap_data = xmalloc (sizeof(struct siginfo));
|
|
|
|
|
+
|
|
|
|
|
+ ptrace (PTRACE_GETSIGINFO, ptid_get_lwp (lp->ptid), (PTRACE_ARG3_TYPE) 0,
|
|
|
|
|
+ lp->saved_trap_data);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void
|
|
|
|
|
+_initialize_ia64_linux_nat (void)
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+{
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ observer_attach_linux_new_thread (ia64_linux_new_thread);
|
|
|
|
|
+ observer_attach_sigtrap (ia64_linux_save_sigtrap_info);
|
|
|
|
|
+}
|
|
|
|
|
+
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/amd64-linux-nat.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/amd64-linux-nat.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/amd64-linux-nat.c 2006-07-11 02:29:47.000000000 -0300
|
|
|
|
|
@@ -234,10 +234,9 @@ amd64_linux_dr_get (int regnum)
|
2005-01-07 22:49:23 +00:00
|
|
|
|
int tid;
|
|
|
|
|
unsigned long value;
|
|
|
|
|
|
|
|
|
|
- /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
|
|
|
|
|
- multi-threaded processes here. For now, pretend there is just
|
|
|
|
|
- one thread. */
|
|
|
|
|
- tid = PIDGET (inferior_ptid);
|
|
|
|
|
+ tid = TIDGET (inferior_ptid);
|
|
|
|
|
+ if (tid == 0)
|
|
|
|
|
+ tid = PIDGET (inferior_ptid);
|
|
|
|
|
|
|
|
|
|
/* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
|
|
|
|
|
ptrace call fails breaks debugging remote targets. The correct
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -262,10 +261,9 @@ amd64_linux_dr_set (int regnum, unsigned
|
2005-01-07 22:49:23 +00:00
|
|
|
|
{
|
|
|
|
|
int tid;
|
|
|
|
|
|
|
|
|
|
- /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
|
|
|
|
|
- multi-threaded processes here. For now, pretend there is just
|
|
|
|
|
- one thread. */
|
|
|
|
|
- tid = PIDGET (inferior_ptid);
|
|
|
|
|
+ tid = TIDGET (inferior_ptid);
|
|
|
|
|
+ if (tid == 0)
|
|
|
|
|
+ tid = PIDGET (inferior_ptid);
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
Index: gdb-6.5/gdb/s390-nat.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- gdb-6.5.orig/gdb/s390-nat.c 2006-07-07 04:24:43.000000000 -0300
|
|
|
|
|
+++ gdb-6.5/gdb/s390-nat.c 2006-07-07 04:24:57.000000000 -0300
|
|
|
|
|
@@ -30,6 +30,8 @@
|
|
|
|
|
#include "linux-nat.h"
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
#include "s390-tdep.h"
|
|
|
|
|
+#include "linux-nat.h"
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+#include "observer.h"
|
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
#include <asm/ptrace.h>
|
|
|
|
|
#include <sys/ptrace.h>
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -114,14 +116,14 @@ fill_fpregset (fpregset_t *regp, int reg
|
2004-12-15 21:21:25 +00:00
|
|
|
|
((char *)regp) + regmap_fpregset[i]);
|
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
-/* Find the TID for the current inferior thread to use with ptrace. */
|
|
|
|
|
+/* Find the TID for use with ptrace. */
|
|
|
|
|
static int
|
|
|
|
|
-s390_inferior_tid (void)
|
|
|
|
|
+s390_tid (ptid_t ptid)
|
|
|
|
|
{
|
|
|
|
|
/* GNU/Linux LWP ID's are process ID's. */
|
|
|
|
|
- int tid = TIDGET (inferior_ptid);
|
|
|
|
|
+ int tid = TIDGET (ptid);
|
|
|
|
|
if (tid == 0)
|
|
|
|
|
- tid = PIDGET (inferior_ptid); /* Not a threaded program. */
|
|
|
|
|
+ tid = PIDGET (ptid); /* Not a threaded program. */
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
return tid;
|
|
|
|
|
}
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -205,7 +207,7 @@ store_fpregs (int tid, int regnum)
|
|
|
|
|
static void
|
|
|
|
|
s390_linux_fetch_inferior_registers (int regnum)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
- int tid = s390_inferior_tid ();
|
|
|
|
|
+ int tid = s390_tid (inferior_ptid);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
if (regnum == -1
|
|
|
|
|
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -221,7 +223,7 @@ s390_linux_fetch_inferior_registers (int
|
|
|
|
|
static void
|
|
|
|
|
s390_linux_store_inferior_registers (int regnum)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
- int tid = s390_inferior_tid ();
|
|
|
|
|
+ int tid = s390_tid (inferior_ptid);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
if (regnum == -1
|
|
|
|
|
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -263,7 +265,7 @@ s390_stopped_by_watchpoint (void)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
parea.len = sizeof (per_lowcore);
|
|
|
|
|
parea.process_addr = (addr_t) & per_lowcore;
|
|
|
|
|
parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
|
|
|
|
|
- if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
|
|
|
|
|
+ if (ptrace (PTRACE_PEEKUSR_AREA, s390_tid (inferior_ptid), &parea) < 0)
|
2006-07-11 06:33:02 +00:00
|
|
|
|
perror_with_name (_("Couldn't retrieve watchpoint status"));
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
return per_lowcore.perc_storage_alteration == 1
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -271,9 +273,9 @@ s390_stopped_by_watchpoint (void)
|
2004-12-13 21:48:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
static void
|
|
|
|
|
-s390_fix_watch_points (void)
|
|
|
|
|
+s390_fix_watch_points (ptid_t ptid)
|
2004-12-13 21:48:04 +00:00
|
|
|
|
{
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- int tid = s390_inferior_tid ();
|
|
|
|
|
+ int tid = s390_tid (ptid);
|
|
|
|
|
|
|
|
|
|
per_struct per_info;
|
|
|
|
|
ptrace_area parea;
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -310,6 +312,16 @@ s390_fix_watch_points (void)
|
|
|
|
|
perror_with_name (_("Couldn't modify watchpoint status"));
|
2004-12-13 21:48:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* Callback routine to use with iterate_over_lwps to insert a specified
|
|
|
|
|
+ watchpoint on all threads. */
|
|
|
|
|
+static int
|
|
|
|
|
+s390_insert_watchpoint_callback (struct lwp_info *lwp, void *data)
|
|
|
|
|
+{
|
|
|
|
|
+ s390_fix_watch_points (lwp->ptid);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Insert a specified watchpoint on all threads. */
|
2006-07-11 06:33:02 +00:00
|
|
|
|
static int
|
|
|
|
|
s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
|
2004-12-13 21:48:04 +00:00
|
|
|
|
{
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -323,10 +335,24 @@ s390_insert_watchpoint (CORE_ADDR addr,
|
2004-12-15 21:21:25 +00:00
|
|
|
|
area->next = watch_base;
|
|
|
|
|
watch_base = area;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- s390_fix_watch_points ();
|
|
|
|
|
+ /* For the S390, a watchpoint must be inserted/removed for each
|
|
|
|
|
+ thread so we iterate over the list of existing lwps. */
|
|
|
|
|
+ if (iterate_over_lwps (&s390_insert_watchpoint_callback, NULL))
|
|
|
|
|
+ return -1;
|
2004-12-13 21:48:04 +00:00
|
|
|
|
+
|
2006-07-11 06:33:02 +00:00
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* Callback routine to use with iterate_over_lwps to remove a specified
|
|
|
|
|
+ watchpoint from all threads. */
|
|
|
|
|
+static int
|
|
|
|
|
+s390_remove_watchpoint_callback (struct lwp_info *lwp, void *data)
|
|
|
|
|
+{
|
|
|
|
|
+ s390_fix_watch_points (lwp->ptid);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* Remove a specified watchpoint from all threads. */
|
2006-07-11 06:33:02 +00:00
|
|
|
|
static int
|
|
|
|
|
s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
|
2004-12-15 21:21:25 +00:00
|
|
|
|
{
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -348,7 +374,11 @@ s390_remove_watchpoint (CORE_ADDR addr,
|
2004-12-15 21:21:25 +00:00
|
|
|
|
*parea = area->next;
|
|
|
|
|
xfree (area);
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
- s390_fix_watch_points ();
|
|
|
|
|
+ /* For the S390, a watchpoint must be inserted/removed for each
|
|
|
|
|
+ thread so we iterate over the list of existing lwps. */
|
|
|
|
|
+ if (iterate_over_lwps (&s390_remove_watchpoint_callback, NULL))
|
|
|
|
|
+ return -1;
|
|
|
|
|
+
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2006-07-11 06:33:02 +00:00
|
|
|
|
@@ -364,6 +394,15 @@ s390_region_ok_for_hw_watchpoint (CORE_A
|
|
|
|
|
return 1;
|
2004-12-15 21:21:25 +00:00
|
|
|
|
}
|
2004-12-13 21:48:04 +00:00
|
|
|
|
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+/* New thread observer that inserts all existing watchpoints on the
|
|
|
|
|
+ new thread. */
|
|
|
|
|
+static void
|
|
|
|
|
+s390_linux_new_thread (ptid_t ptid)
|
|
|
|
|
+{
|
|
|
|
|
+ /* Add existing watchpoints to new thread. */
|
|
|
|
|
+ s390_fix_watch_points (ptid);
|
|
|
|
|
+}
|
|
|
|
|
+
|
2006-07-11 06:33:02 +00:00
|
|
|
|
|
|
|
|
|
void _initialize_s390_nat (void);
|
|
|
|
|
|
|
|
|
|
@@ -389,4 +428,6 @@ _initialize_s390_nat (void)
|
|
|
|
|
|
|
|
|
|
/* Register the target. */
|
|
|
|
|
linux_nat_add_target (t);
|
|
|
|
|
+
|
2004-12-15 21:21:25 +00:00
|
|
|
|
+ observer_attach_linux_new_thread (s390_linux_new_thread);
|
2006-07-11 06:33:02 +00:00
|
|
|
|
}
|