* [patch 0/1] Threaded Watchpoints
@ 2007-08-13 13:51 Luis Machado
2007-08-20 17:33 ` Luis Machado
0 siblings, 1 reply; 17+ messages in thread
From: Luis Machado @ 2007-08-13 13:51 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 503 bytes --]
Folks,
I took the freedom of refreshing Jeff Johnston's patch for threaded
watchpoints for HEAD in order to keep this feature moving, and
eventually include it for GDB 6.7.
I remember from previous threads that there was some discussion about
the observer implemented by Jeff. Based on comments and suggestions i'll
re-work the patch.
I'm also working on the ppc side of this patch and will submit soon.
Best regards,
--
Luis Machado
IBM Linux Technology Center
e-mail: luisgpm@vnet.linux.ibm.com
[-- Attachment #2: threaded_watchpoints_part1.patch --]
[-- Type: text/x-patch, Size: 46447 bytes --]
2007-08-13 Jeff Johnston <jjohnstn@redhat.com>
* linux-nat.c: (stop_wait_callback, linux-nat-wait): Notify
observers of a sigtrap.
(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.
* linux-thread-db.c: Add support to always keep lwp info in ptids.
(attach_thread): Notify observers of a linux
new thread.
(thread_db_wait): Call check_event if SIGILL occurs.
* infrun.c: (handle_inferior_event): For platforms that
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.
Index: gdb/doc/observer.texi
===================================================================
--- gdb.orig/doc/observer.texi 2007-08-10 14:32:29.000000000 -0700
+++ gdb/doc/observer.texi 2007-08-13 06:21:29.000000000 -0700
@@ -123,6 +123,16 @@
The shared library specified by @var{solib} has been unloaded.
@end deftypefun
+@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
+
@deftypefun void new_objfile (struct objfile *@var{objfile})
The symbol file specified by @var{objfile} has been loaded.
Called with @var{objfile} equal to @code{NULL} to indicate
Index: gdb/infrun.c
===================================================================
--- gdb.orig/infrun.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/infrun.c 2007-08-13 06:21:29.000000000 -0700
@@ -1777,9 +1777,19 @@
single step over a watchpoint without disabling the watchpoint. */
if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
{
+ CORE_ADDR addr = 0;
+
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- resume (1, 0);
+
+ 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;
}
@@ -1790,6 +1800,8 @@
if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch)
&& STOPPED_BY_WATCHPOINT (ecs->ws))
{
+ CORE_ADDR addr = 0;
+
/* 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
@@ -1797,15 +1809,12 @@
now, we would get the old value, and therefore no change
would seem to have occurred.
- 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. */
+
+ target_stopped_data_address (¤t_target, &addr);
+ mark_triggered_watchpoints (addr);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
@@ -1876,6 +1885,41 @@
}
}
+ 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)
+ fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n");
+ 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,
@@ -1928,6 +1972,8 @@
See more comments in inferior.h. */
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP)
{
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
stop_stepping (ecs);
if (stop_signal == TARGET_SIGNAL_STOP)
stop_signal = TARGET_SIGNAL_0;
Index: gdb/breakpoint.c
===================================================================
--- gdb.orig/breakpoint.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/breakpoint.c 2007-08-13 06:21:29.000000000 -0700
@@ -808,6 +808,90 @@
}
}
+/* 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 = 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 == 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
@@ -1296,6 +1380,7 @@
{
struct bp_location *b;
int val;
+ int return_val = 0;
ALL_BP_LOCATIONS (b)
{
@@ -1303,10 +1388,10 @@
{
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
- return val;
+ return_val = val;
}
}
- return 0;
+ return return_val;
}
int
@@ -2209,8 +2294,13 @@
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;
+
printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n"));
return PRINT_NOTHING;
break;
@@ -2658,6 +2748,54 @@
}
}
+/* 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 = 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 = 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
@@ -2788,82 +2926,61 @@
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. */
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- 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;
- for (v = b->val_chain; v; v = value_next (v))
+ if (b->type == bp_watchpoint
+ || b->watchpoint_triggered
+ || (b->type == bp_hardware_watchpoint
+ && !target_stopped_data_address_p (¤t_target)))
{
- if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
+ /* 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))
{
- 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))
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+ for (v = b->val_chain; v; v = value_next(v))
+ {
+ if (VALUE_LVAL (v) == lval_memory
+ && ! value_lazy (v))
{
- CORE_ADDR vaddr;
+ struct type *vtype = check_typedef (value_type (v));
- 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)))
- found = 1;
+ 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)
+ if (must_check_value)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
@@ -2892,6 +3009,15 @@
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:
@@ -2907,7 +3033,7 @@
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
@@ -4208,6 +4334,7 @@
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
Index: gdb/breakpoint.h
===================================================================
--- gdb.orig/breakpoint.h 2007-08-10 14:32:29.000000000 -0700
+++ gdb/breakpoint.h 2007-08-13 06:21:29.000000000 -0700
@@ -422,6 +422,11 @@
/* 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;
};
\f
/* The following stuff is an abstract data type "bpstat" ("breakpoint
@@ -687,6 +692,14 @@
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 *iwpfn);
+
+extern void mark_triggered_watchpoints (CORE_ADDR);
+
extern int remove_breakpoints (void);
/* This function can be used to physically insert eventpoints from the
Index: gdb/linux-nat.c
===================================================================
--- gdb.orig/linux-nat.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/linux-nat.c 2007-08-13 06:21:29.000000000 -0700
@@ -36,6 +36,7 @@
#include "gdbthread.h"
#include "gdbcmd.h"
#include "regcache.h"
+#include "observer.h"
#include "regset.h"
#include "inf-ptrace.h"
#include "auxv.h"
@@ -706,6 +707,9 @@
else
lwp_list = lp->next;
+ if (lp->saved_trap_data)
+ xfree (lp->saved_trap_data);
+
xfree (lp);
}
@@ -1503,6 +1507,13 @@
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);
@@ -2060,6 +2071,14 @@
target_pid_to_str (lp->ptid));
}
+ /* 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)
{
Index: gdb/linux-nat.h
===================================================================
--- gdb.orig/linux-nat.h 2007-08-10 14:32:29.000000000 -0700
+++ gdb/linux-nat.h 2007-08-13 06:21:29.000000000 -0700
@@ -63,6 +63,18 @@
/* 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;
};
/* Attempt to initialize libthread_db. */
Index: gdb/Makefile.in
===================================================================
--- gdb.orig/Makefile.in 2007-08-10 14:32:29.000000000 -0700
+++ gdb/Makefile.in 2007-08-13 06:21:33.000000000 -0700
@@ -555,6 +555,7 @@
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
prologue-value.c \
regcache.c reggroups.c remote.c remote-fileio.c \
+ scm-exp.c scm-lang.c scm-valprint.c \
sentinel-frame.c \
serial.c ser-base.c ser-unix.c \
solib.c solib-null.c source.c \
@@ -787,6 +788,8 @@
remote_h = remote.h
rs6000_tdep_h = rs6000-tdep.h $(defs_h)
s390_tdep_h = s390-tdep.h
+scm_lang_h = scm-lang.h $(scm_tags_h)
+scm_tags_h = scm-tags.h
score_tdep_h = score-tdep.h
sentinel_frame_h = sentinel-frame.h
serial_h = serial.h
@@ -810,7 +813,7 @@
srec_h = srec.h
stabsread_h = stabsread.h
stack_h = stack.h
-symfile_h = symfile.h
+symfile_h = symfile.h $(symtab_h)
symtab_h = symtab.h
target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h) $(vec_h)
target_descriptions_h = target-descriptions.h
@@ -833,6 +836,7 @@
wrapper_h = wrapper.h $(gdb_h)
xcoffsolib_h = xcoffsolib.h
xml_support_h = xml-support.h $(gdb_obstack_h) $(vec_h)
+xml_tdesc_h = xml-tdesc.h
xtensa_tdep_h = xtensa-tdep.h
#
@@ -958,6 +962,7 @@
varobj.o vec.o wrapper.o \
jv-lang.o jv-valprint.o jv-typeprint.o \
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
+ scm-exp.o scm-lang.o scm-valprint.o \
sentinel-frame.o \
complaints.o typeprint.o \
ada-typeprint.o c-typeprint.o f-typeprint.o m2-typeprint.o \
@@ -1702,7 +1707,7 @@
$(gdbcore_h) $(hashtab_h) $(gdb_obstack_h) $(ada_lang_h) \
$(completer_h) $(gdb_stat_h) $(ui_out_h) $(block_h) $(infcall_h) \
$(dictionary_h) $(exceptions_h) $(annotate_h) $(valprint_h) \
- $(source_h)
+ $(source_h) $(observer_h)
ada-typeprint.o: ada-typeprint.c $(defs_h) $(gdb_obstack_h) $(bfd_h) \
$(symtab_h) $(gdbtypes_h) $(expression_h) $(value_h) $(gdbcore_h) \
$(target_h) $(command_h) $(gdbcmd_h) $(language_h) $(demangle_h) \
@@ -1758,7 +1763,7 @@
amd64-linux-nat.o: amd64-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
$(regcache_h) $(linux_nat_h) $(gdb_assert_h) $(gdb_string_h) \
$(gdb_proc_service_h) $(gregset_h) $(amd64_tdep_h) \
- $(i386_linux_tdep_h) $(amd64_nat_h) $(target_h) $(amd64_linux_tdep_h)
+ $(i386_linux_tdep_h) $(amd64_nat_h) $(amd64_linux_tdep_h)
amd64-linux-tdep.o: amd64-linux-tdep.c $(defs_h) $(frame_h) $(gdbcore_h) \
$(regcache_h) $(osabi_h) $(symtab_h) $(gdb_string_h) $(amd64_tdep_h) \
$(solib_svr4_h) $(gdbtypes_h) $(reggroups_h) $(amd64_linux_tdep_h)
@@ -1817,6 +1822,8 @@
$(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \
$(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h) \
$(target_descriptions_h) $(user_regs_h)
+arm-wince-tdep.o: arm-wince-tdep.c $(defs_h) $(osabi_h) $(solib_svr4_h) \
+ $(target_h) $(gdb_string_h) $(arm_tdep_h)
auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \
$(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \
$(elf_common_h)
@@ -1845,8 +1852,8 @@
$(gdb_string_h) $(demangle_h) $(annotate_h) $(symfile_h) \
$(objfiles_h) $(source_h) $(linespec_h) $(completer_h) $(gdb_h) \
$(ui_out_h) $(cli_script_h) $(gdb_assert_h) $(block_h) $(solib_h) \
- $(solist_h) $(observer_h) $(exceptions_h) $(gdb_events_h) $(mi_common_h) \
- $(memattr_h) $(ada_lang_h)
+ $(solist_h) $(observer_h) $(exceptions_h) $(gdb_events_h) \
+ $(mi_common_h) $(memattr_h) $(ada_lang_h) $(top_h)
bsd-kvm.o: bsd-kvm.c $(defs_h) $(cli_cmds_h) $(command_h) $(frame_h) \
$(regcache_h) $(target_h) $(value_h) $(gdbcore_h) $(gdb_assert_h) \
$(readline_h) $(bsd_kvm_h)
@@ -1975,7 +1982,8 @@
$(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h)
event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
$(terminal_h) $(event_loop_h) $(event_top_h) $(interps_h) \
- $(exceptions_h) $(gdbcmd_h) $(readline_h) $(readline_history_h)
+ $(exceptions_h) $(cli_script_h) $(gdbcmd_h) $(readline_h) \
+ $(readline_history_h)
exceptions.o: exceptions.c $(defs_h) $(exceptions_h) $(breakpoint_h) \
$(target_h) $(inferior_h) $(annotate_h) $(ui_out_h) $(gdb_assert_h) \
$(gdb_string_h) $(serial_h)
@@ -2071,7 +2079,7 @@
$(osabi_h) $(frame_h) $(frame_unwind_h) $(trad_frame_h) $(symtab_h) \
$(objfiles_h) $(inferior_h) $(infcall_h) $(observer_h) \
$(hppa_tdep_h) $(solib_som_h) $(solib_pa64_h) $(regset_h) \
- $(regcache_h) $(exceptions_h) $(gdb_string_h)
+ $(regcache_h) $(exceptions_h) $(gdb_string_h) $(hppa_tdep_h)
hppa-linux-nat.o: hppa-linux-nat.c $(defs_h) $(gdbcore_h) $(regcache_h) \
$(gdb_string_h) $(inferior_h) $(hppa_tdep_h) $(gregset_h) \
$(target_h) $(linux_nat_h)
@@ -2114,7 +2122,8 @@
$(i386_linux_tdep_h) $(glibc_tdep_h) $(solib_svr4_h) $(symtab_h)
i386-nat.o: i386-nat.c $(defs_h) $(breakpoint_h) $(command_h) $(gdbcmd_h)
i386nbsd-nat.o: i386nbsd-nat.c $(defs_h) $(gdbcore_h) $(regcache_h) \
- $(target_h) $(i386_tdep_h) $(i386bsd_nat_h) $(bsd_kvm_h)
+ $(target_h) $(i386_tdep_h) $(i386bsd_nat_h) $(nbsd_nat_h) \
+ $(bsd_kvm_h)
i386nbsd-tdep.o: i386nbsd-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) \
$(gdbcore_h) $(regcache_h) $(regset_h) $(osabi_h) $(symtab_h) \
$(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h) \
@@ -2148,7 +2157,7 @@
$(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h)
ia64-linux-nat.o: ia64-linux-nat.c $(defs_h) $(gdb_string_h) $(inferior_h) \
$(target_h) $(gdbcore_h) $(regcache_h) $(ia64_tdep_h) $(gdb_wait_h) \
- $(gregset_h) $(linux_nat_h)
+ $(gregset_h) $(observer_h) $(linux_nat_h)
ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(ia64_tdep_h) \
$(arch_utils_h) $(gdbcore_h) $(regcache_h) $(osabi_h) $(solib_svr4_h) \
$(symtab_h)
@@ -2203,7 +2212,8 @@
jv-lang.o: jv-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
$(parser_defs_h) $(language_h) $(gdbtypes_h) $(symtab_h) \
$(symfile_h) $(objfiles_h) $(gdb_string_h) $(value_h) $(c_lang_h) \
- $(jv_lang_h) $(gdbcore_h) $(block_h) $(demangle_h) $(dictionary_h)
+ $(jv_lang_h) $(gdbcore_h) $(block_h) $(demangle_h) $(dictionary_h) \
+ $(gdb_assert_h)
jv-typeprint.o: jv-typeprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \
$(value_h) $(demangle_h) $(jv_lang_h) $(gdb_string_h) $(typeprint_h) \
$(c_lang_h) $(cp_abi_h)
@@ -2220,7 +2230,7 @@
linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
$(symfile_h) $(objfiles_h) $(source_h) $(demangle_h) $(value_h) \
$(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
- $(objc_lang_h) $(linespec_h) $(exceptions_h)
+ $(objc_lang_h) $(linespec_h) $(exceptions_h) $(language_h)
linux-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
$(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h) \
$(linux_nat_h)
@@ -2239,10 +2249,13 @@
m2-lang.o: m2-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
$(parser_defs_h) $(language_h) $(m2_lang_h) $(c_lang_h) \
$(valprint_h)
-m2-typeprint.o: m2-typeprint.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \
- $(expression_h) $(value_h) $(gdbcore_h) $(target_h) $(m2_lang_h)
+m2-typeprint.o: m2-typeprint.c $(defs_h) $(gdb_obstack_h) $(bfd_h) \
+ $(symtab_h) $(gdbtypes_h) $(expression_h) $(value_h) $(gdbcore_h) \
+ $(m2_lang_h) $(target_h) $(language_h) $(demangle_h) $(c_lang_h) \
+ $(typeprint_h) $(cp_abi_h) $(gdb_string_h)
m2-valprint.o: m2-valprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \
- $(m2_lang_h) $(c_lang_h)
+ $(expression_h) $(value_h) $(valprint_h) $(language_h) \
+ $(typeprint_h) $(c_lang_h) $(m2_lang_h) $(target_h)
m32c-tdep.o: m32c-tdep.c $(defs_h) $(gdb_assert_h) $(elf_bfd_h) \
$(elf_m32c_h) $(gdb_sim_m32c_h) $(dis_asm_h) $(gdbtypes_h) \
$(regcache_h) $(arch_utils_h) $(frame_h) $(frame_unwind_h) \
@@ -2384,7 +2397,7 @@
monitor.o: monitor.c $(defs_h) $(gdbcore_h) $(target_h) $(exceptions_h) \
$(gdb_string_h) $(command_h) $(serial_h) $(monitor_h) $(gdbcmd_h) \
$(inferior_h) $(gdb_regex_h) $(srec_h) $(regcache_h)
-ms1-tdep.o: ms1-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) $(frame_base_h) \
+mt-tdep.o: mt-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) $(frame_base_h) \
$(symtab_h) $(dis_asm_h) $(arch_utils_h) $(gdbtypes_h) \
$(gdb_string_h) $(regcache_h) $(reggroups_h) $(gdbcore_h) \
$(trad_frame_h) $(inferior_h) $(dwarf2_frame_h) $(infcall_h) \
@@ -2498,8 +2511,6 @@
remote-fileio.o: remote-fileio.c $(defs_h) $(gdb_string_h) $(gdbcmd_h) \
$(remote_h) $(gdb_fileio_h) $(gdb_wait_h) $(gdb_stat_h) \
$(exceptions_h) $(remote_fileio_h)
-remote-hms.o: remote-hms.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \
- $(serial_h) $(regcache_h)
remote-m32r-sdi.o: remote-m32r-sdi.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \
$(inferior_h) $(target_h) $(regcache_h) $(gdb_string_h) $(serial_h)
remote-mips.o: remote-mips.c $(defs_h) $(inferior_h) $(bfd_h) $(symfile_h) \
@@ -2527,13 +2538,22 @@
rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(gdb_string_h) $(osabi_h) \
$(regcache_h) $(regset_h) $(rs6000_tdep_h) $(ppc_tdep_h)
s390-nat.o: s390-nat.c $(defs_h) $(regcache_h) $(inferior_h) \
- $(s390_tdep_h) $(target_h) $(linux_nat_h)
+ $(s390_tdep_h) $(target_h) $(observer_h) $(linux_nat_h)
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) \
$(floatformat_h) $(regcache_h) $(trad_frame_h) $(frame_base_h) \
$(frame_unwind_h) $(dwarf2_frame_h) $(reggroups_h) $(regset_h) \
$(value_h) $(gdb_assert_h) $(dis_asm_h) $(solib_svr4_h) \
$(prologue_value_h) $(s390_tdep_h)
+scm-exp.o: scm-exp.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
+ $(parser_defs_h) $(language_h) $(value_h) $(c_lang_h) $(scm_lang_h) \
+ $(scm_tags_h)
+scm-lang.o: scm-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
+ $(parser_defs_h) $(language_h) $(value_h) $(c_lang_h) $(scm_lang_h) \
+ $(scm_tags_h) $(source_h) $(gdb_string_h) $(gdbcore_h) $(infcall_h)
+scm-valprint.o: scm-valprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \
+ $(expression_h) $(parser_defs_h) $(language_h) $(value_h) \
+ $(scm_lang_h) $(valprint_h) $(gdbcore_h) $(c_lang_h)
score-tdep.o: score-tdep.c $(defs_h) $(gdb_assert_h) $(inferior_h) \
$(symtab_h) $(objfiles_h) $(gdbcore_h) $(target_h) \
$(arch_utils_h) $(regcache_h) $(dis_asm_h) $(frame_unwind_h) \
@@ -2626,7 +2646,7 @@
$(gregset_h) $(sparc64_tdep_h) $(sparc_tdep_h) \
$(sparc_nat_h) $(inferior_h) $(target_h) $(linux_nat_h)
sparc64-linux-tdep.o: sparc64-linux-tdep.c $(defs_h) $(frame_h) \
- $(frame_unwind_h) $(dwarf2-frame_h) $(regset_h) $(regcache_h) \
+ $(frame_unwind_h) $(dwarf2_frame_h) $(regset_h) $(regcache_h) \
$(gdbarch_h) $(gdbcore_h) $(osabi_h) $(solib_svr4_h) $(symtab_h) \
$(trad_frame_h) $(tramp_frame_h) $(sparc64_tdep_h)
sparc64-nat.o: sparc64-nat.c $(defs_h) $(gdbarch_h) $(sparc64_tdep_h) \
@@ -2727,7 +2747,7 @@
$(filenames_h) $(objc_lang_h) $(ada_lang_h) $(hashtab_h) \
$(gdb_obstack_h) $(block_h) $(dictionary_h) $(gdb_string_h) \
$(gdb_stat_h) $(cp_abi_h) $(observer_h) $(gdb_assert_h) \
- $(solist_h)
+ $(solist_h) $(ada_lang_h)
target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
$(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
$(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
@@ -2808,7 +2828,7 @@
$(frame_unwind_h) $(osabi_h) $(symtab_h) $(trad_frame_h) \
$(vax_tdep_h) $(gdb_string_h)
vax-tdep.o: vax-tdep.c $(defs_h) $(arch_utils_h) $(dis_asm_h) \
- $(float_format_h) $(frame_h) $(frame_base_h) $(frame_unwind_h) \
+ $(floatformat_h) $(frame_h) $(frame_base_h) $(frame_unwind_h) \
$(gdbcore_h) $(gdbtypes_h) $(osabi_h) $(regcache_h) $(regset_h) \
$(trad_frame_h) $(value_h) $(gdb_string_h) $(vax_tdep_h)
vec.o: vec.c $(defs_h) $(vec_h)
@@ -2817,6 +2837,7 @@
$(regcache_h) $(top_h) $(buildsym_h) $(symfile_h) $(objfiles_h) \
$(gdb_string_h) $(gdbthread_h) $(gdbcmd_h) $(exec_h) $(solist_h) \
$(solib_h) $(i386_tdep_h) $(i387_tdep_h)
+win32-termcap.o: win32-termcap.c
wrapper.o: wrapper.c $(defs_h) $(value_h) $(exceptions_h) $(wrapper_h) \
$(ui_out_h)
xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \
@@ -2836,9 +2857,6 @@
$(gdbcmd_h) $(gdbcore_h) $(value_h) $(dis_asm_h) $(inferior_h) \
$(gdb_string_h) $(gdb_assert_h) $(arch_utils_h) $(floatformat_h) \
$(regcache_h) $(doublest_h) $(osabi_h) $(objfiles_h)
-xtensa-linux-tdep.o: xtensa-linux-tdep.c $(defs_h) $(inferior_h) \
- $(gdbcore_h) $(regcache_h) $(osabi_h) $(gdb_string_h) \
- $(xtensa_tdep_h) $(xtensa_linux_tdep_h)
xtensa-tdep.o: xtensa-tdep.c $(defs_h) $(doublest_h) $(frame_h) \
$(frame_unwind_h) $(frame_base_h) $(inferior_h) $(symtab_h) \
$(value_h) $(gdbcmd_h) $(gdbcore_h) $(dis_asm_h) $(symfile_h) \
@@ -2878,7 +2896,7 @@
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-logging.c
cli-script.o: $(srcdir)/cli/cli-script.c $(defs_h) $(value_h) $(language_h) \
$(ui_out_h) $(gdb_string_h) $(exceptions_h) $(top_h) $(cli_cmds_h) \
- $(cli_decode_h) $(cli_script_h) $(gdb_assert_h)
+ $(cli_decode_h) $(cli_script_h) $(gdb_assert_h) $(breakpoint_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-script.c
cli-setshow.o: $(srcdir)/cli/cli-setshow.c $(defs_h) $(readline_tilde_h) \
$(value_h) $(gdb_string_h) $(ui_out_h) $(cli_decode_h) $(cli_cmds_h) \
Index: gdb/linux-thread-db.c
===================================================================
--- gdb.orig/linux-thread-db.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/linux-thread-db.c 2007-08-13 06:21:29.000000000 -0700
@@ -36,6 +36,7 @@
#include "target.h"
#include "regcache.h"
#include "solib-svr4.h"
+#include "observer.h"
#include "gdbcore.h"
#include "observer.h"
#include "linux-nat.h"
@@ -675,6 +676,7 @@
{
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
@@ -893,7 +895,8 @@
thread_db_find_new_threads ();
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);
Index: gdb/i386-linux-nat.c
===================================================================
--- gdb.orig/i386-linux-nat.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/i386-linux-nat.c 2007-08-13 06:22:11.000000000 -0700
@@ -587,10 +587,9 @@
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
@@ -615,10 +614,9 @@
{
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 (PTRACE_POKEUSER, tid,
Index: gdb/ia64-linux-nat.c
===================================================================
--- gdb.orig/ia64-linux-nat.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/ia64-linux-nat.c 2007-08-13 06:21:29.000000000 -0700
@@ -29,6 +29,7 @@
#include "regcache.h"
#include "ia64-tdep.h"
#include "linux-nat.h"
+#include "observer.h"
#include <signal.h>
#include <sys/ptrace.h>
@@ -552,10 +553,10 @@
return onecount <= 1;
}
+/* Internal routine to insert one watchpoint for a specified thread. */
static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
{
- ptid_t ptid = inferior_ptid;
int idx;
long dbr_addr, dbr_mask;
int max_watchpoints = 4;
@@ -600,10 +601,39 @@
return 0;
}
+/* Internal callback routine which can be used via iterate_over_lwps
+ to insert a specific watchpoint from all active threads. */
static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data)
+{
+ struct linux_watchpoint *args = (struct linux_watchpoint *)data;
+
+ return ia64_linux_insert_one_watchpoint (lwp->ptid, args->addr,
+ args->len, args->type);
+}
+
+/* Insert a watchpoint for all threads. */
+int
+ia64_linux_insert_watchpoint (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)
{
- ptid_t ptid = inferior_ptid;
int idx;
long dbr_addr, dbr_mask;
int max_watchpoints = 4;
@@ -625,13 +655,56 @@
return -1;
}
+/* 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 (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_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;
+
+ return 0;
+}
+
static int
ia64_linux_stopped_data_address (struct target_ops *ops, 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;
struct regcache *regcache = get_current_regcache ();
tid = TIDGET(ptid);
@@ -639,10 +712,19 @@
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;
regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr);
@@ -650,7 +732,7 @@
for the next instruction */
regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr);
- *addr_p = (CORE_ADDR)siginfo.si_addr;
+ *addr_p = (CORE_ADDR)siginfo_p->si_addr;
return 1;
}
@@ -798,6 +880,31 @@
offset, len);
}
+/* 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);
+}
+
+/* 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;
+
+ if (lp->saved_trap_data == NULL)
+ lp->saved_trap_data = xmalloc (sizeof(struct siginfo));
+
+ ptrace (PTRACE_GETSIGINFO, ptid_get_lwp (lp->ptid), (PTRACE_TYPE_ARG3) 0,
+ lp->saved_trap_data);
+}
+
void _initialize_ia64_linux_nat (void);
void
@@ -836,4 +943,7 @@
/* Register the target. */
linux_nat_add_target (t);
+
+ observer_attach_linux_new_thread (ia64_linux_new_thread);
+ observer_attach_sigtrap (ia64_linux_save_sigtrap_info);
}
Index: gdb/amd64-linux-nat.c
===================================================================
--- gdb.orig/amd64-linux-nat.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/amd64-linux-nat.c 2007-08-13 06:22:11.000000000 -0700
@@ -242,10 +242,9 @@
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
@@ -270,10 +269,9 @@
{
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);
Index: gdb/s390-nat.c
===================================================================
--- gdb.orig/s390-nat.c 2007-08-10 14:32:29.000000000 -0700
+++ gdb/s390-nat.c 2007-08-13 06:21:29.000000000 -0700
@@ -29,6 +29,7 @@
#include "linux-nat.h"
#include "s390-tdep.h"
+#include "observer.h"
#include <asm/ptrace.h>
#include <sys/ptrace.h>
@@ -113,14 +114,14 @@
(char *)regp + regmap_fpregset[i]);
}
-/* 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. */
return tid;
}
@@ -204,7 +205,7 @@
static void
s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
{
- int tid = s390_inferior_tid ();
+ int tid = s390_tid (inferior_ptid);
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
@@ -220,7 +221,7 @@
static void
s390_linux_store_inferior_registers (struct regcache *regcache, int regnum)
{
- int tid = s390_inferior_tid ();
+ int tid = s390_tid (inferior_ptid);
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
@@ -262,7 +263,7 @@
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)
perror_with_name (_("Couldn't retrieve watchpoint status"));
return per_lowcore.perc_storage_alteration == 1
@@ -270,9 +271,9 @@
}
static void
-s390_fix_watch_points (void)
+s390_fix_watch_points (ptid_t ptid)
{
- int tid = s390_inferior_tid ();
+ int tid = s390_tid (ptid);
per_struct per_info;
ptrace_area parea;
@@ -309,6 +310,16 @@
perror_with_name (_("Couldn't modify watchpoint status"));
}
+/* 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. */
static int
s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
{
@@ -322,10 +333,24 @@
area->next = watch_base;
watch_base = area;
- 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;
+
return 0;
}
+/* 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);
+ return 0;
+}
+
+/* Remove a specified watchpoint from all threads. */
static int
s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
{
@@ -347,7 +372,11 @@
*parea = area->next;
xfree (area);
- 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;
}
@@ -363,6 +392,15 @@
return 1;
}
+/* 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);
+}
+
void _initialize_s390_nat (void);
@@ -388,4 +426,6 @@
/* Register the target. */
linux_nat_add_target (t);
+
+ observer_attach_linux_new_thread (s390_linux_new_thread);
}
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [patch 0/1] Threaded Watchpoints 2007-08-13 13:51 [patch 0/1] Threaded Watchpoints Luis Machado @ 2007-08-20 17:33 ` Luis Machado 2007-08-20 17:40 ` Luis Machado 0 siblings, 1 reply; 17+ messages in thread From: Luis Machado @ 2007-08-20 17:33 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 661 bytes --] Patch updated with additional ppc code. Best regards, On Mon, 2007-08-13 at 10:51 -0300, Luis Machado wrote: > Folks, > > I took the freedom of refreshing Jeff Johnston's patch for threaded > watchpoints for HEAD in order to keep this feature moving, and > eventually include it for GDB 6.7. > > I remember from previous threads that there was some discussion about > the observer implemented by Jeff. Based on comments and suggestions i'll > re-work the patch. > > I'm also working on the ppc side of this patch and will submit soon. > > Best regards, > -- Luis Machado Software Engineer IBM Linux Technology Center e-mail: luisgpm@linux.vnet.ibm.com [-- Attachment #2: threaded-watchpoints1.diff --] [-- Type: text/x-patch, Size: 34367 bytes --] 2004-12-13 Jeff Johnston <jjohnstn@redhat.com> * linux-nat.c: (stop_wait_callback, linux-nat-wait): Notify observers of a sigtrap. (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. * linux-thread-db.c: Add support to always keep lwp info in ptids. (attach_thread): Notify observers of a linux new thread. (thread_db_wait): Call check_event if SIGILL occurs. * infrun.c: (handle_inferior_event): For platforms that 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. Index: gdb/doc/observer.texi =================================================================== --- gdb.orig/doc/observer.texi 2007-08-09 07:17:19.000000000 -0700 +++ gdb/doc/observer.texi 2007-08-09 09:33:30.000000000 -0700 @@ -123,6 +123,16 @@ The shared library specified by @var{solib} has been unloaded. @end deftypefun +@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 + @deftypefun void new_objfile (struct objfile *@var{objfile}) The symbol file specified by @var{objfile} has been loaded. Called with @var{objfile} equal to @code{NULL} to indicate Index: gdb/infrun.c =================================================================== --- gdb.orig/infrun.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/infrun.c 2007-08-09 09:33:30.000000000 -0700 @@ -1777,9 +1777,19 @@ single step over a watchpoint without disabling the watchpoint. */ if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws)) { + CORE_ADDR addr = 0; + if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); - resume (1, 0); + + 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; } @@ -1790,6 +1800,8 @@ if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch) && STOPPED_BY_WATCHPOINT (ecs->ws)) { + CORE_ADDR addr = 0; + /* 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 @@ -1797,15 +1809,12 @@ now, we would get the old value, and therefore no change would seem to have occurred. - 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. */ + + target_stopped_data_address (¤t_target, &addr); + mark_triggered_watchpoints (addr); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); @@ -1876,6 +1885,41 @@ } } + 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) + fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n"); + 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, @@ -1928,6 +1972,8 @@ See more comments in inferior.h. */ if (stop_soon == STOP_QUIETLY_NO_SIGSTOP) { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n"); stop_stepping (ecs); if (stop_signal == TARGET_SIGNAL_STOP) stop_signal = TARGET_SIGNAL_0; Index: gdb/breakpoint.c =================================================================== --- gdb.orig/breakpoint.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/breakpoint.c 2007-08-09 09:33:30.000000000 -0700 @@ -808,6 +808,90 @@ } } +/* 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 = 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 == 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 @@ -1296,6 +1380,7 @@ { struct bp_location *b; int val; + int return_val = 0; ALL_BP_LOCATIONS (b) { @@ -1303,10 +1388,10 @@ { val = remove_breakpoint (b, mark_uninserted); if (val != 0) - return val; + return_val = val; } } - return 0; + return return_val; } int @@ -2209,8 +2294,13 @@ 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; + printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n")); return PRINT_NOTHING; break; @@ -2658,6 +2748,54 @@ } } +/* 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 = 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 = 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 @@ -2788,82 +2926,61 @@ 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. */ - printf_filtered (_("Watchpoint %d deleted.\n"), b->number); - 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; - for (v = b->val_chain; v; v = value_next (v)) + if (b->type == bp_watchpoint + || b->watchpoint_triggered + || (b->type == bp_hardware_watchpoint + && !target_stopped_data_address_p (¤t_target))) { - if (VALUE_LVAL (v) == lval_memory - && ! value_lazy (v)) + /* 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)) { - 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)) + bs->print_it = print_it_noop; + bs->stop = 0; + continue; + } + for (v = b->val_chain; v; v = value_next(v)) + { + if (VALUE_LVAL (v) == lval_memory + && ! value_lazy (v)) { - CORE_ADDR vaddr; + struct type *vtype = check_typedef (value_type (v)); - 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))) - found = 1; + 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) + if (must_check_value) { char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n", b->number); @@ -2892,6 +3009,15 @@ 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: @@ -2907,7 +3033,7 @@ 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 @@ -4208,6 +4334,7 @@ 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 Index: gdb/breakpoint.h =================================================================== --- gdb.orig/breakpoint.h 2007-08-09 07:17:19.000000000 -0700 +++ gdb/breakpoint.h 2007-08-09 09:33:30.000000000 -0700 @@ -422,6 +422,11 @@ /* 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; }; \f /* The following stuff is an abstract data type "bpstat" ("breakpoint @@ -687,6 +692,14 @@ 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 Index: gdb/linux-nat.c =================================================================== --- gdb.orig/linux-nat.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/linux-nat.c 2007-08-09 09:33:30.000000000 -0700 @@ -36,6 +36,7 @@ #include "gdbthread.h" #include "gdbcmd.h" #include "regcache.h" +#include "observer.h" #include "regset.h" #include "inf-ptrace.h" #include "auxv.h" @@ -706,6 +707,9 @@ else lwp_list = lp->next; + if (lp->saved_trap_data) + xfree (lp->saved_trap_data); + xfree (lp); } @@ -1503,6 +1507,13 @@ 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); @@ -2060,6 +2071,14 @@ target_pid_to_str (lp->ptid)); } + /* 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) { Index: gdb/linux-nat.h =================================================================== --- gdb.orig/linux-nat.h 2007-08-09 07:17:19.000000000 -0700 +++ gdb/linux-nat.h 2007-08-09 09:33:30.000000000 -0700 @@ -63,6 +63,18 @@ /* 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; }; /* Attempt to initialize libthread_db. */ Index: gdb/Makefile.in =================================================================== --- gdb.orig/Makefile.in 2007-08-09 07:17:19.000000000 -0700 +++ gdb/Makefile.in 2007-08-09 09:33:30.000000000 -0700 @@ -2148,7 +2148,7 @@ $(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h) ia64-linux-nat.o: ia64-linux-nat.c $(defs_h) $(gdb_string_h) $(inferior_h) \ $(target_h) $(gdbcore_h) $(regcache_h) $(ia64_tdep_h) $(gdb_wait_h) \ - $(gregset_h) $(linux_nat_h) + $(gregset_h) $(observer_h) $(linux_nat_h) ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(ia64_tdep_h) \ $(arch_utils_h) $(gdbcore_h) $(regcache_h) $(osabi_h) $(solib_svr4_h) \ $(symtab_h) @@ -2527,7 +2527,7 @@ rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(gdb_string_h) $(osabi_h) \ $(regcache_h) $(regset_h) $(rs6000_tdep_h) $(ppc_tdep_h) s390-nat.o: s390-nat.c $(defs_h) $(regcache_h) $(inferior_h) \ - $(s390_tdep_h) $(target_h) $(linux_nat_h) + $(s390_tdep_h) $(target_h) $(observer_h) $(linux_nat_h) 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) \ $(floatformat_h) $(regcache_h) $(trad_frame_h) $(frame_base_h) \ Index: gdb/linux-thread-db.c =================================================================== --- gdb.orig/linux-thread-db.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/linux-thread-db.c 2007-08-09 09:33:30.000000000 -0700 @@ -36,6 +36,7 @@ #include "target.h" #include "regcache.h" #include "solib-svr4.h" +#include "observer.h" #include "gdbcore.h" #include "observer.h" #include "linux-nat.h" @@ -675,6 +676,7 @@ { 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 @@ -893,7 +895,8 @@ thread_db_find_new_threads (); 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); Index: gdb/i386-linux-nat.c =================================================================== --- gdb.orig/i386-linux-nat.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/i386-linux-nat.c 2007-08-09 09:33:30.000000000 -0700 @@ -587,10 +587,9 @@ 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 @@ -615,10 +614,9 @@ { 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 (PTRACE_POKEUSER, tid, Index: gdb/ia64-linux-nat.c =================================================================== --- gdb.orig/ia64-linux-nat.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/ia64-linux-nat.c 2007-08-09 09:53:06.000000000 -0700 @@ -29,6 +29,7 @@ #include "regcache.h" #include "ia64-tdep.h" #include "linux-nat.h" +#include "observer.h" #include <signal.h> #include <sys/ptrace.h> @@ -552,10 +553,10 @@ return onecount <= 1; } +/* Internal routine to insert one watchpoint for a specified thread. */ static int -ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) +ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw) { - ptid_t ptid = inferior_ptid; int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; @@ -600,10 +601,39 @@ return 0; } +/* Internal callback routine which can be used via iterate_over_lwps + to insert a specific watchpoint from all active threads. */ static int -ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) +ia64_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *)data; + + return ia64_linux_insert_one_watchpoint (lwp->ptid, args->addr, + args->len, args->type); +} + +/* Insert a watchpoint for all threads. */ +int +ia64_linux_insert_watchpoint (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) { - ptid_t ptid = inferior_ptid; int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; @@ -625,13 +655,56 @@ return -1; } +/* 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 (CORE_ADDR addr, int len) +{ + 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_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; + + return 0; +} + static int ia64_linux_stopped_data_address (struct target_ops *ops, 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; struct regcache *regcache = get_current_regcache (); tid = TIDGET(ptid); @@ -639,10 +712,19 @@ 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; regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); @@ -650,7 +732,7 @@ for the next instruction */ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr); - *addr_p = (CORE_ADDR)siginfo.si_addr; + *addr_p = (CORE_ADDR)siginfo_p->si_addr; return 1; } @@ -798,6 +880,31 @@ offset, len); } +/* 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); +} + +/* 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; + + if (lp->saved_trap_data == NULL) + lp->saved_trap_data = xmalloc (sizeof(struct siginfo)); + + ptrace (PTRACE_GETSIGINFO, ptid_get_lwp (lp->ptid), (PTRACE_TYPE_ARG3) 0, + lp->saved_trap_data); +} + void _initialize_ia64_linux_nat (void); void @@ -836,4 +943,7 @@ /* Register the target. */ linux_nat_add_target (t); + + observer_attach_linux_new_thread (ia64_linux_new_thread); + observer_attach_sigtrap (ia64_linux_save_sigtrap_info); } Index: gdb/amd64-linux-nat.c =================================================================== --- gdb.orig/amd64-linux-nat.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/amd64-linux-nat.c 2007-08-09 09:33:30.000000000 -0700 @@ -242,10 +242,9 @@ 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 @@ -270,10 +269,9 @@ { 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); Index: gdb/s390-nat.c =================================================================== --- gdb.orig/s390-nat.c 2007-08-09 07:17:19.000000000 -0700 +++ gdb/s390-nat.c 2007-08-09 09:33:30.000000000 -0700 @@ -29,6 +29,7 @@ #include "linux-nat.h" #include "s390-tdep.h" +#include "observer.h" #include <asm/ptrace.h> #include <sys/ptrace.h> @@ -113,14 +114,14 @@ (char *)regp + regmap_fpregset[i]); } -/* 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. */ return tid; } @@ -204,7 +205,7 @@ static void s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum) { - int tid = s390_inferior_tid (); + int tid = s390_tid (inferior_ptid); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) @@ -220,7 +221,7 @@ static void s390_linux_store_inferior_registers (struct regcache *regcache, int regnum) { - int tid = s390_inferior_tid (); + int tid = s390_tid (inferior_ptid); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) @@ -262,7 +263,7 @@ 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) perror_with_name (_("Couldn't retrieve watchpoint status")); return per_lowcore.perc_storage_alteration == 1 @@ -270,9 +271,9 @@ } static void -s390_fix_watch_points (void) +s390_fix_watch_points (ptid_t ptid) { - int tid = s390_inferior_tid (); + int tid = s390_tid (ptid); per_struct per_info; ptrace_area parea; @@ -309,6 +310,16 @@ perror_with_name (_("Couldn't modify watchpoint status")); } +/* 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. */ static int s390_insert_watchpoint (CORE_ADDR addr, int len, int type) { @@ -322,10 +333,24 @@ area->next = watch_base; watch_base = area; - 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; + return 0; } +/* 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); + return 0; +} + +/* Remove a specified watchpoint from all threads. */ static int s390_remove_watchpoint (CORE_ADDR addr, int len, int type) { @@ -347,7 +372,11 @@ *parea = area->next; xfree (area); - 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; } @@ -363,6 +392,15 @@ return 1; } +/* 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); +} + void _initialize_s390_nat (void); @@ -388,4 +426,6 @@ /* Register the target. */ linux_nat_add_target (t); + + observer_attach_linux_new_thread (s390_linux_new_thread); } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-08-20 17:33 ` Luis Machado @ 2007-08-20 17:40 ` Luis Machado 2007-09-05 2:04 ` Daniel Jacobowitz 0 siblings, 1 reply; 17+ messages in thread From: Luis Machado @ 2007-08-20 17:40 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 192 bytes --] OK, i messed up the last patch, it appears to be an older version. Follows the correct one. -- Luis Machado Software Engineer IBM Linux Technology Center e-mail: luisgpm@linux.vnet.ibm.com [-- Attachment #2: threaded-watchpoints1.diff --] [-- Type: text/x-patch, Size: 37731 bytes --] 2007-08-20 Jeff Johnston <jjohnstn@redhat.com> Luis Machado <luisgpm@linux.vnet.ibm.com> * linux-nat.c: (stop_wait_callback, linux-nat-wait): Notify observers of a sigtrap. (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. * linux-thread-db.c: Add support to always keep lwp info in ptids. (attach_thread): Notify observers of a linux new thread. (thread_db_wait): Call check_event if SIGILL occurs. * infrun.c: (handle_inferior_event): For platforms that 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. * ppc-linux-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. Index: gdb/doc/observer.texi =================================================================== --- gdb.orig/doc/observer.texi 2007-08-20 07:14:43.000000000 -0700 +++ gdb/doc/observer.texi 2007-08-20 08:38:51.000000000 -0700 @@ -123,6 +123,16 @@ The shared library specified by @var{solib} has been unloaded. @end deftypefun +@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 + @deftypefun void new_objfile (struct objfile *@var{objfile}) The symbol file specified by @var{objfile} has been loaded. Called with @var{objfile} equal to @code{NULL} to indicate Index: gdb/infrun.c =================================================================== --- gdb.orig/infrun.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/infrun.c 2007-08-20 08:38:51.000000000 -0700 @@ -1777,9 +1777,19 @@ single step over a watchpoint without disabling the watchpoint. */ if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws)) { + CORE_ADDR addr = 0; + if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); - resume (1, 0); + + 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; } @@ -1790,6 +1800,8 @@ if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch) && STOPPED_BY_WATCHPOINT (ecs->ws)) { + CORE_ADDR addr = 0; + /* 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 @@ -1797,15 +1809,12 @@ now, we would get the old value, and therefore no change would seem to have occurred. - 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. */ + + target_stopped_data_address (¤t_target, &addr); + mark_triggered_watchpoints (addr); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); @@ -1876,6 +1885,41 @@ } } + 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) + fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n"); + 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, @@ -1928,6 +1972,8 @@ See more comments in inferior.h. */ if (stop_soon == STOP_QUIETLY_NO_SIGSTOP) { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n"); stop_stepping (ecs); if (stop_signal == TARGET_SIGNAL_STOP) stop_signal = TARGET_SIGNAL_0; Index: gdb/breakpoint.c =================================================================== --- gdb.orig/breakpoint.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/breakpoint.c 2007-08-20 08:38:51.000000000 -0700 @@ -808,6 +808,90 @@ } } +/* 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 = 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 == 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 @@ -1296,6 +1380,7 @@ { struct bp_location *b; int val; + int return_val = 0; ALL_BP_LOCATIONS (b) { @@ -1303,10 +1388,10 @@ { val = remove_breakpoint (b, mark_uninserted); if (val != 0) - return val; + return_val = val; } } - return 0; + return return_val; } int @@ -2189,8 +2274,13 @@ 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; + printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n")); return PRINT_NOTHING; break; @@ -2638,6 +2728,54 @@ } } +/* 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 = 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 = 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 @@ -2768,82 +2906,61 @@ 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. */ - printf_filtered (_("Watchpoint %d deleted.\n"), b->number); - 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; - for (v = b->val_chain; v; v = value_next (v)) + if (b->type == bp_watchpoint + || b->watchpoint_triggered + || (b->type == bp_hardware_watchpoint + && !target_stopped_data_address_p (¤t_target))) { - if (VALUE_LVAL (v) == lval_memory - && ! value_lazy (v)) + /* 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)) { - 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)) + bs->print_it = print_it_noop; + bs->stop = 0; + continue; + } + for (v = b->val_chain; v; v = value_next(v)) + { + if (VALUE_LVAL (v) == lval_memory + && ! value_lazy (v)) { - CORE_ADDR vaddr; + struct type *vtype = check_typedef (value_type (v)); - 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))) - found = 1; + 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) + if (must_check_value) { char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n", b->number); @@ -2872,6 +2989,15 @@ 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: @@ -2887,7 +3013,7 @@ 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 @@ -4188,6 +4314,7 @@ 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 Index: gdb/breakpoint.h =================================================================== --- gdb.orig/breakpoint.h 2007-08-20 07:14:43.000000000 -0700 +++ gdb/breakpoint.h 2007-08-20 08:38:51.000000000 -0700 @@ -422,6 +422,11 @@ /* 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; }; \f /* The following stuff is an abstract data type "bpstat" ("breakpoint @@ -690,6 +695,14 @@ 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 *iwpfn); + +extern void mark_triggered_watchpoints (CORE_ADDR); + extern int remove_breakpoints (void); /* This function can be used to physically insert eventpoints from the Index: gdb/linux-nat.c =================================================================== --- gdb.orig/linux-nat.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/linux-nat.c 2007-08-20 08:38:51.000000000 -0700 @@ -36,6 +36,7 @@ #include "gdbthread.h" #include "gdbcmd.h" #include "regcache.h" +#include "observer.h" #include "regset.h" #include "inf-ptrace.h" #include "auxv.h" @@ -706,6 +707,9 @@ else lwp_list = lp->next; + if (lp->saved_trap_data) + xfree (lp->saved_trap_data); + xfree (lp); } @@ -1503,6 +1507,13 @@ 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); @@ -2060,6 +2071,14 @@ target_pid_to_str (lp->ptid)); } + /* 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) { Index: gdb/linux-nat.h =================================================================== --- gdb.orig/linux-nat.h 2007-08-20 07:14:43.000000000 -0700 +++ gdb/linux-nat.h 2007-08-20 08:38:51.000000000 -0700 @@ -63,6 +63,18 @@ /* 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; }; /* Attempt to initialize libthread_db. */ Index: gdb/Makefile.in =================================================================== --- gdb.orig/Makefile.in 2007-08-20 07:14:43.000000000 -0700 +++ gdb/Makefile.in 2007-08-20 08:38:51.000000000 -0700 @@ -2157,7 +2157,7 @@ $(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h) ia64-linux-nat.o: ia64-linux-nat.c $(defs_h) $(gdb_string_h) $(inferior_h) \ $(target_h) $(gdbcore_h) $(regcache_h) $(ia64_tdep_h) $(gdb_wait_h) \ - $(gregset_h) $(linux_nat_h) + $(gregset_h) $(observer_h) $(linux_nat_h) ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(ia64_tdep_h) \ $(arch_utils_h) $(gdbcore_h) $(regcache_h) $(osabi_h) $(solib_svr4_h) \ $(symtab_h) @@ -2538,7 +2538,7 @@ rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(gdb_string_h) $(osabi_h) \ $(regcache_h) $(regset_h) $(rs6000_tdep_h) $(ppc_tdep_h) s390-nat.o: s390-nat.c $(defs_h) $(regcache_h) $(inferior_h) \ - $(s390_tdep_h) $(target_h) $(linux_nat_h) + $(s390_tdep_h) $(target_h) $(observer_h) $(linux_nat_h) 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) \ $(floatformat_h) $(regcache_h) $(trad_frame_h) $(frame_base_h) \ Index: gdb/linux-thread-db.c =================================================================== --- gdb.orig/linux-thread-db.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/linux-thread-db.c 2007-08-20 08:38:51.000000000 -0700 @@ -36,6 +36,7 @@ #include "target.h" #include "regcache.h" #include "solib-svr4.h" +#include "observer.h" #include "gdbcore.h" #include "observer.h" #include "linux-nat.h" @@ -675,6 +676,7 @@ { 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 @@ -893,7 +895,8 @@ thread_db_find_new_threads (); 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); Index: gdb/i386-linux-nat.c =================================================================== --- gdb.orig/i386-linux-nat.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/i386-linux-nat.c 2007-08-20 08:38:51.000000000 -0700 @@ -587,10 +587,9 @@ 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 @@ -615,10 +614,9 @@ { 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 (PTRACE_POKEUSER, tid, Index: gdb/ia64-linux-nat.c =================================================================== --- gdb.orig/ia64-linux-nat.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/ia64-linux-nat.c 2007-08-20 08:38:51.000000000 -0700 @@ -29,6 +29,7 @@ #include "regcache.h" #include "ia64-tdep.h" #include "linux-nat.h" +#include "observer.h" #include <signal.h> #include <sys/ptrace.h> @@ -552,10 +553,10 @@ return onecount <= 1; } +/* Internal routine to insert one watchpoint for a specified thread. */ static int -ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) +ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw) { - ptid_t ptid = inferior_ptid; int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; @@ -600,10 +601,39 @@ return 0; } +/* Internal callback routine which can be used via iterate_over_lwps + to insert a specific watchpoint from all active threads. */ static int -ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) +ia64_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *)data; + + return ia64_linux_insert_one_watchpoint (lwp->ptid, args->addr, + args->len, args->type); +} + +/* Insert a watchpoint for all threads. */ +int +ia64_linux_insert_watchpoint (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) { - ptid_t ptid = inferior_ptid; int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; @@ -625,13 +655,56 @@ return -1; } +/* 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 (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_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; + + return 0; +} + static int ia64_linux_stopped_data_address (struct target_ops *ops, 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; struct regcache *regcache = get_current_regcache (); tid = TIDGET(ptid); @@ -639,10 +712,19 @@ 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; regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); @@ -650,7 +732,7 @@ for the next instruction */ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr); - *addr_p = (CORE_ADDR)siginfo.si_addr; + *addr_p = (CORE_ADDR)siginfo_p->si_addr; return 1; } @@ -798,6 +880,31 @@ offset, len); } +/* 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); +} + +/* 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; + + if (lp->saved_trap_data == NULL) + lp->saved_trap_data = xmalloc (sizeof(struct siginfo)); + + ptrace (PTRACE_GETSIGINFO, ptid_get_lwp (lp->ptid), (PTRACE_TYPE_ARG3) 0, + lp->saved_trap_data); +} + void _initialize_ia64_linux_nat (void); void @@ -836,4 +943,7 @@ /* Register the target. */ linux_nat_add_target (t); + + observer_attach_linux_new_thread (ia64_linux_new_thread); + observer_attach_sigtrap (ia64_linux_save_sigtrap_info); } Index: gdb/amd64-linux-nat.c =================================================================== --- gdb.orig/amd64-linux-nat.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/amd64-linux-nat.c 2007-08-20 08:38:51.000000000 -0700 @@ -242,10 +242,9 @@ 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 @@ -270,10 +269,9 @@ { 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); Index: gdb/s390-nat.c =================================================================== --- gdb.orig/s390-nat.c 2007-08-20 07:14:43.000000000 -0700 +++ gdb/s390-nat.c 2007-08-20 08:38:51.000000000 -0700 @@ -29,6 +29,7 @@ #include "linux-nat.h" #include "s390-tdep.h" +#include "observer.h" #include <asm/ptrace.h> #include <sys/ptrace.h> @@ -113,14 +114,14 @@ (char *)regp + regmap_fpregset[i]); } -/* 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. */ return tid; } @@ -204,7 +205,7 @@ static void s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum) { - int tid = s390_inferior_tid (); + int tid = s390_tid (inferior_ptid); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) @@ -220,7 +221,7 @@ static void s390_linux_store_inferior_registers (struct regcache *regcache, int regnum) { - int tid = s390_inferior_tid (); + int tid = s390_tid (inferior_ptid); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) @@ -262,7 +263,7 @@ 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) perror_with_name (_("Couldn't retrieve watchpoint status")); return per_lowcore.perc_storage_alteration == 1 @@ -270,9 +271,9 @@ } static void -s390_fix_watch_points (void) +s390_fix_watch_points (ptid_t ptid) { - int tid = s390_inferior_tid (); + int tid = s390_tid (ptid); per_struct per_info; ptrace_area parea; @@ -309,6 +310,16 @@ perror_with_name (_("Couldn't modify watchpoint status")); } +/* 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. */ static int s390_insert_watchpoint (CORE_ADDR addr, int len, int type) { @@ -322,10 +333,24 @@ area->next = watch_base; watch_base = area; - 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; + return 0; } +/* 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); + return 0; +} + +/* Remove a specified watchpoint from all threads. */ static int s390_remove_watchpoint (CORE_ADDR addr, int len, int type) { @@ -347,7 +372,11 @@ *parea = area->next; xfree (area); - 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; } @@ -363,6 +392,15 @@ return 1; } +/* 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); +} + void _initialize_s390_nat (void); @@ -388,4 +426,6 @@ /* Register the target. */ linux_nat_add_target (t); + + observer_attach_linux_new_thread (s390_linux_new_thread); } Index: gdb/ppc-linux-nat.c =================================================================== --- gdb.orig/ppc-linux-nat.c 2007-08-17 13:03:31.000000000 -0700 +++ gdb/ppc-linux-nat.c 2007-08-20 10:24:37.000000000 -0700 @@ -29,6 +29,7 @@ #include "gdb_assert.h" #include "target.h" #include "linux-nat.h" +#include "observer.h" #include <stdint.h> #include <sys/types.h> @@ -807,13 +808,12 @@ return 1; } -/* Set a watchpoint of type TYPE at address ADDR. */ +/* Internal routine to insert one watchpoint for a specified thread. */ static int -ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) +ppc_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw) { int tid; long dabr_value; - ptid_t ptid = inferior_ptid; dabr_value = addr & ~7; switch (rw) @@ -839,11 +839,38 @@ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value); } +/* Internal callback routine which can be used via iterate_over_lwps + to insert a specific watchpoint from all active threads. */ static int -ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw) +ppc_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *) data; + + return ppc_linux_insert_one_watchpoint (lwp->ptid, args->addr, + args->len, args->type); +} + +/* Set a watchpoint of type TYPE at address ADDR for all threads. */ +static int +ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) +{ + struct linux_watchpoint args; + + args.addr = addr; + args.len = len; + args.type = rw; + + if (iterate_over_lwps (&ppc_linux_insert_watchpoint_callback, &args)) + return -1; + + return 0; +} + +/* Internal routine to remove one watchpoint for a specified thread. */ +static int +ppc_linux_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len) { int tid; - ptid_t ptid = inferior_ptid; tid = TIDGET (ptid); if (tid == 0) @@ -852,6 +879,42 @@ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0); } +/* Internal callback routine which can be used via iterate_over_lwps + to remove a specific watchpoint from all active threads. */ +static int +ppc_linux_remove_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *) data; + + return ppc_linux_remove_one_watchpoint (lwp->ptid, args->addr, + args->len); +} + +/* Remove a watchpoint for all threads. */ +static int +ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw) +{ + struct linux_watchpoint args; + + args.addr = addr; + args.len = len; + args.type = rw; + + if (iterate_over_lwps (&ppc_linux_remove_watchpoint_callback, &args)) + return -1; + + return 0; +} + +/* Observer function for a new thread attach. We need to insert + existing watchpoints on the new thread. */ +static void +ppc_linux_new_thread (ptid_t ptid) +{ + insert_watchpoints_for_new_thread (ptid, + &ppc_linux_insert_one_watchpoint); +} + static int ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) { @@ -1024,4 +1087,6 @@ /* Register the target. */ linux_nat_add_target (t); + + observer_attach_linux_new_thread (ppc_linux_new_thread); } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-08-20 17:40 ` Luis Machado @ 2007-09-05 2:04 ` Daniel Jacobowitz 2007-09-05 12:31 ` Luis Machado 0 siblings, 1 reply; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-05 2:04 UTC (permalink / raw) To: Luis Machado; +Cc: gdb-patches On Mon, Aug 20, 2007 at 02:39:28PM -0300, Luis Machado wrote: > OK, i messed up the last patch, it appears to be an older version. > Follows the correct one. Hi Luis, I just wanted to let you know this hasn't been forgotten. There are a couple of problems with this submission, and I'm working on a new version of it. The problem that made me take another try is that when we last discussed the patch we eventually concluded that this was a bad (and avoidable) use of observers. The problem that's giving me a headache is I can't work out what a lot of the independent parts of this patch are supposed to do... I'll be in touch, hopefully in the next few days. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-05 2:04 ` Daniel Jacobowitz @ 2007-09-05 12:31 ` Luis Machado 2007-09-10 0:21 ` Daniel Jacobowitz 0 siblings, 1 reply; 17+ messages in thread From: Luis Machado @ 2007-09-05 12:31 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches > Hi Luis, > > I just wanted to let you know this hasn't been forgotten. There are a > couple of problems with this submission, and I'm working on a new > version of it. The problem that made me take another try is that when > we last discussed the patch we eventually concluded that this was a > bad (and avoidable) use of observers. The problem that's giving me > a headache is I can't work out what a lot of the independent parts > of this patch are supposed to do... > > I'll be in touch, hopefully in the next few days. Hi Daniel, Yes, i remember the observer's problem in that discussion, but as the thread stopped abruptly, i didn't have a clear idea of the way it should've been done. I added the ppc piece together with the s390's, ia64's and amd64's code in the first patch. I believe the second one is a bit more complicated because it works with bits and pieces of the i386 code, which i'm not really familiar with, so it was a plain refresh of Jeff's patch. If i can be of any help on those, feel free to contact me in the available ways, i'm on IRC as well. Looking forward to your comments. Thanks for reviewing it. Regards, -- Luis Machado IBM Linux Technology Center e-mail: luisgpm@linux.vnet.ibm.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-05 12:31 ` Luis Machado @ 2007-09-10 0:21 ` Daniel Jacobowitz 2007-09-10 15:34 ` Luis Machado 2007-09-10 18:23 ` Ulrich Weigand 0 siblings, 2 replies; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-10 0:21 UTC (permalink / raw) To: Luis Machado; +Cc: gdb-patches On Wed, Sep 05, 2007 at 09:31:21AM -0300, Luis Machado wrote: > I added the ppc piece together with the s390's, ia64's and amd64's code > in the first patch. I believe the second one is a bit more complicated > because it works with bits and pieces of the i386 code, which i'm not > really familiar with, so it was a plain refresh of Jeff's patch. If i > can be of any help on those, feel free to contact me in the available > ways, i'm on IRC as well. > > Looking forward to your comments. Thanks for reviewing it. Here is my current patch. The PowerPC bits are totally untested, not even compiled - could you test it for me, please? I don't have a suitable system. Most of this is liberally borrowed from Jeff's (and your's and Jan's) work. There are some bits I'm not happy with yet, but I hope I'll have time to finish it up this week or next weekend, and then I will submit each logical change separately. Some of them deserve more explanation (and comments and gdbint documentation). I've regression tested i386, amd64, and ia64. I tested S/390 by hand and it works, but the extra logic in watchthreads.exp for that platform hasn't been tested (no DejaGNU or expect on my test system). -- Daniel Jacobowitz CodeSourcery Index: amd64-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/amd64-linux-nat.c,v retrieving revision 1.17 diff -u -p -r1.17 amd64-linux-nat.c --- amd64-linux-nat.c 23 Aug 2007 18:08:26 -0000 1.17 +++ amd64-linux-nat.c 10 Sep 2007 00:20:24 -0000 @@ -233,25 +233,33 @@ amd64_linux_store_inferior_registers (st } } \f +/* Support for debug registers. */ + +static unsigned long amd64_linux_dr[DR_CONTROL + 1]; + +struct amd64_linux_dr_set_args +{ + int regnum; + unsigned long value; +}; static unsigned long -amd64_linux_dr_get (int regnum) +amd64_linux_dr_get (ptid_t ptid, int regnum) { 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 (ptid); + if (tid == 0) + tid = PIDGET (ptid); /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the ptrace call fails breaks debugging remote targets. The correct way to fix this is to add the hardware breakpoint and watchpoint - stuff to the target vectore. For now, just return zero if the + stuff to the target vector. For now, just return zero if the ptrace call fails. */ errno = 0; - value = ptrace (PT_READ_U, tid, + value = ptrace (PTRACE_PEEKUSER, tid, offsetof (struct user, u_debugreg[regnum]), 0); if (errno != 0) #if 0 @@ -264,25 +272,49 @@ amd64_linux_dr_get (int regnum) } static void -amd64_linux_dr_set (int regnum, unsigned long value) +amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) { 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 (ptid); + if (tid == 0) + tid = PIDGET (ptid); errno = 0; - ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value); + ptrace (PTRACE_POKEUSER, tid, + offsetof (struct user, u_debugreg[regnum]), value); if (errno != 0) perror_with_name (_("Couldn't write debug register")); } +static int +amd64_linux_dr_set_lwp (struct lwp_info *lp, void *args_p) +{ + struct amd64_linux_dr_set_args *args = args_p; + + /* We do not need to set the debug registers for new threads now; + they'll be done at resume anyway. */ + if (linux_nat_lwp_is_new (lp->ptid)) + return 0; + + amd64_linux_dr[args->regnum] = args->value; + amd64_linux_dr_set (lp->ptid, args->regnum, args->value); + + return 0; +} + void amd64_linux_dr_set_control (unsigned long control) { - amd64_linux_dr_set (DR_CONTROL, control); + if (amd64_linux_dr[DR_CONTROL] != control) + { + struct amd64_linux_dr_set_args args; + + amd64_linux_dr[DR_CONTROL] = control; + args.regnum = DR_CONTROL; + args.value = control; + iterate_over_lwps (amd64_linux_dr_set_lwp, &args); + } } void @@ -290,21 +322,41 @@ amd64_linux_dr_set_addr (int regnum, COR { gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr); + if (amd64_linux_dr[DR_FIRSTADDR + regnum] != addr) + { + struct amd64_linux_dr_set_args args; + + amd64_linux_dr[DR_FIRSTADDR + regnum] = addr; + args.regnum = DR_FIRSTADDR + regnum; + args.value = addr; + iterate_over_lwps (amd64_linux_dr_set_lwp, &args); + } } void amd64_linux_dr_reset_addr (int regnum) { - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L); + amd64_linux_dr_set_addr (regnum, 0); } unsigned long amd64_linux_dr_get_status (void) { - return amd64_linux_dr_get (DR_STATUS); + return amd64_linux_dr_get (inferior_ptid, DR_STATUS); +} + +static void +amd64_linux_dr_update (ptid_t ptid) +{ + int i; + + if (!linux_nat_lwp_is_new (ptid)) + return; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]); + + amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]); } \f @@ -368,6 +420,7 @@ ps_get_thread_area (const struct ps_proc \f static void (*super_post_startup_inferior) (ptid_t ptid); +static void (*super_resume) (ptid_t ptid, int step, enum target_signal signal); static void amd64_linux_child_post_startup_inferior (ptid_t ptid) @@ -375,6 +428,13 @@ amd64_linux_child_post_startup_inferior i386_cleanup_dregs (); super_post_startup_inferior (ptid); } + +static void +amd64_linux_resume (ptid_t ptid, int step, enum target_signal signal) +{ + amd64_linux_dr_update (ptid); + super_resume (ptid, step, signal); +} \f /* Provide a prototype to silence -Wmissing-prototypes. */ @@ -398,6 +458,10 @@ _initialize_amd64_linux_nat (void) /* Fill in the generic GNU/Linux methods. */ t = linux_target (); + /* Override the default ptrace resume method. */ + super_resume = t->to_resume; + t->to_resume = amd64_linux_resume; + /* Override the GNU/Linux inferior startup hook. */ super_post_startup_inferior = t->to_post_startup_inferior; t->to_post_startup_inferior = amd64_linux_child_post_startup_inferior; Index: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.263 diff -u -p -r1.263 breakpoint.c --- breakpoint.c 29 Aug 2007 22:07:47 -0000 1.263 +++ breakpoint.c 10 Sep 2007 00:20:24 -0000 @@ -2519,6 +2519,83 @@ bpstat_alloc (struct breakpoint *b, bpst return bs; } \f +/* The target has stopped with waitstatus WS. Check if any hardware + watchpoints have triggered, according to the target. */ + +int +watchpoints_triggered (struct target_waitstatus *ws) +{ + int stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (*ws); + CORE_ADDR addr; + struct breakpoint *b; + + if (!stopped_by_watchpoint) + { + /* We were not stopped by a watchpoint. Mark all watchpoints + as not triggered. */ + ALL_BREAKPOINTS (b) + if (b->type == bp_hardware_watchpoint + || b->type == bp_read_watchpoint + || b->type == bp_access_watchpoint) + b->watchpoint_triggered = watch_triggered_no; + + return 0; + } + + if (!target_stopped_data_address (¤t_target, &addr)) + { + /* We were stopped by a watchpoint, but we don't know where. + Mark all watchpoints as unknown. */ + ALL_BREAKPOINTS (b) + if (b->type == bp_hardware_watchpoint + || b->type == bp_read_watchpoint + || b->type == bp_access_watchpoint) + b->watchpoint_triggered = watch_triggered_unknown; + + return stopped_by_watchpoint; + } + + /* The target could report the data address. Mark watchpoints + affected by this data address as triggered, and all others as not + triggered. */ + + ALL_BREAKPOINTS (b) + if (b->type == bp_hardware_watchpoint + || b->type == bp_read_watchpoint + || b->type == bp_access_watchpoint) + { + 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; + } + } + } + } + } + + return 1; +} + /* Possible return values for watchpoint_check (this can't be an enum because of check_errors). */ /* The watchpoint has been deleted. */ @@ -2637,11 +2714,9 @@ which its expression is valid.\n"); } /* 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 - know we did not trigger a hardware watchpoint, and -1 if we do not know. */ + BP_ADDR in thread PTID. -/* Determine whether we stopped at a breakpoint, etc, or whether we + Determine whether we stopped at a breakpoint, etc, or whether we don't understand this stop. Result is a chain of bpstat's such that: if we don't understand the stop, the result is a null pointer. @@ -2656,7 +2731,7 @@ which its expression is valid.\n"); commands, FIXME??? fields. */ bpstat -bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid, int stopped_by_watchpoint) +bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) { struct breakpoint *b, *temp; /* True if we've hit a breakpoint (as opposed to a watchpoint). */ @@ -2691,16 +2766,30 @@ bpstat_stop_status (CORE_ADDR bp_addr, p continue; } - /* Continuable hardware watchpoints are treated as non-existent if the - reason we stopped wasn't a hardware watchpoint (we didn't stop on - some data address). Otherwise gdb won't stop on a break instruction - in the code (not from a breakpoint) when a hardware watchpoint has - been defined. */ + /* Pretend that watchpoints are triggered if we have hit their associated + scope breakpoint. */ + if ((b->type == bp_watchpoint + || b->type == bp_hardware_watchpoint + || b->type == bp_read_watchpoint + || b->type == bp_access_watchpoint) + && b->related_breakpoint + && b->related_breakpoint->loc->address == bp_addr + && (!overlay_debugging + || !section_is_overlay (b->related_breakpoint->loc->section) + || section_is_mapped (b->related_breakpoint->loc->section))) + b->watchpoint_triggered = watch_triggered_yes; + + /* Continuable hardware watchpoints are treated as non-existent if the + reason we stopped wasn't a hardware watchpoint (we didn't stop on + some data address). Otherwise gdb won't stop on a break instruction + in the code (not from a breakpoint) when a hardware watchpoint has + been defined. Also skip watchpoints which we know did not trigger + (did not match the data address). */ if ((b->type == bp_hardware_watchpoint || b->type == bp_read_watchpoint || b->type == bp_access_watchpoint) - && !stopped_by_watchpoint) + && b->watchpoint_triggered == watch_triggered_no) continue; if (b->type == bp_hardware_breakpoint) @@ -2766,82 +2855,33 @@ bpstat_stop_status (CORE_ADDR bp_addr, p 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. */ - printf_filtered (_("Watchpoint %d deleted.\n"), b->number); - 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; - - if (!target_stopped_data_address (¤t_target, &addr)) - continue; - 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)); + int must_check_value = 0; - if (v == b->val_chain - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) - { - CORE_ADDR vaddr; + if (b->type == bp_watchpoint) + /* For a software watchpoint, we must always check the + watched value. */ + must_check_value = 1; + else if (b->watchpoint_triggered == watch_triggered_yes) + /* We have a hardware watchpoint (read, write, or access) + and the target earlier reported an address watched by + this watchpoint. */ + must_check_value = 1; + else if (b->watchpoint_triggered == watch_triggered_unknown + && b->type == bp_hardware_watchpoint) + /* We were stopped by a hardware watchpoint, but the target could + not report the data address. We must check the watchpoint's + value. Access and read watchpoints are out of luck; without + a data address, we can't figure it out. */ + must_check_value = 1; - 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))) - found = 1; - } - } - } - if (found) + if (must_check_value) { char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n", b->number); @@ -2869,6 +2909,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, p ++(b->hit_count); break; case WP_VALUE_NOT_CHANGED: + 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; + } /* Stop. */ ++(b->hit_count); break; @@ -2885,12 +2934,12 @@ bpstat_stop_status (CORE_ADDR bp_addr, p 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 - was left zero). So don't print anything for this - watchpoint. */ + /* This is a case where some watchpoint(s) triggered, but + not at the address of this watchpoint, or else no + watchpoint triggered after all. So don't print + anything for this watchpoint. */ bs->print_it = print_it_noop; bs->stop = 0; continue; @@ -2942,6 +2991,9 @@ bpstat_stop_status (CORE_ADDR bp_addr, p annotate_ignore_count_change (); bs->stop = 0; } + else if (b->type == bp_thread_event || b->type == bp_overlay_event) + /* We do not stop for these. */ + bs->stop = 0; else { /* We will stop here */ @@ -2968,17 +3020,27 @@ bpstat_stop_status (CORE_ADDR bp_addr, p bs->next = NULL; /* Terminate the chain */ bs = root_bs->next; /* Re-grab the head of the chain */ - /* The value of a hardware watchpoint hasn't changed, but the - intermediate memory locations we are watching may have. */ - if (bs && !bs->stop && - (bs->breakpoint_at->type == bp_hardware_watchpoint || - bs->breakpoint_at->type == bp_read_watchpoint || - bs->breakpoint_at->type == bp_access_watchpoint)) - { - remove_breakpoints (); - insert_breakpoints (); - } - return bs; + /* If we aren't stopping, the value of some hardware watchpoint may + not have changed, but the intermediate memory locations we are + watching may have. Don't bother if we're stopping; this will get + done later. */ + for (bs = root_bs->next; bs != NULL; bs = bs->next) + if (bs->stop) + break; + + if (bs == NULL) + for (bs = root_bs->next; bs != NULL; bs = bs->next) + if (!bs->stop + && (bs->breakpoint_at->type == bp_hardware_watchpoint + || bs->breakpoint_at->type == bp_read_watchpoint + || bs->breakpoint_at->type == bp_access_watchpoint)) + { + remove_breakpoints (); + insert_breakpoints (); + break; + } + + return root_bs->next; } \f /* Tell what to do about this bpstat. */ @@ -5827,6 +5889,7 @@ watch_command_1 (char *arg, int accessfl /* The scope breakpoint is related to the watchpoint. We will need to act on them together. */ b->related_breakpoint = scope_breakpoint; + scope_breakpoint->related_breakpoint = b; } } value_free_to_mark (mark); Index: breakpoint.h =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.h,v retrieving revision 1.47 diff -u -p -r1.47 breakpoint.h --- breakpoint.h 23 Aug 2007 18:08:26 -0000 1.47 +++ breakpoint.h 10 Sep 2007 00:20:24 -0000 @@ -299,6 +299,19 @@ struct breakpoint_ops void (*print_mention) (struct breakpoint *); }; +enum watchpoint_triggered +{ + /* This watchpoint definitely did not trigger. */ + watch_triggered_no = 0, + + /* Some hardware watchpoint triggered, and it might have been this + one, but we do not know which it was. */ + watch_triggered_unknown, + + /* This hardware watchpoint definitely did trigger. */ + watch_triggered_yes +}; + /* Note that the ->silent field is not currently used by any commands (though the code is in there if it was to be, and set_raw_breakpoint does set it to 0). I implemented it because I thought it would be @@ -378,6 +391,10 @@ struct breakpoint should be evaluated on the outermost frame. */ struct frame_id watchpoint_frame; + /* For hardware watchpoints, the triggered status according to the + hardware. */ + enum watchpoint_triggered watchpoint_triggered; + /* Thread number for thread-specific breakpoint, or -1 if don't care */ int thread; @@ -440,8 +457,7 @@ extern void bpstat_clear (bpstat *); is part of the bpstat is copied as well. */ extern bpstat bpstat_copy (bpstat); -extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid, - int stopped_by_watchpoint); +extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid); \f /* This bpstat_what stuff tells wait_for_inferior what to do with a breakpoint (a challenging task). */ @@ -836,4 +852,8 @@ extern void remove_single_step_breakpoin extern void *deprecated_insert_raw_breakpoint (CORE_ADDR); extern int deprecated_remove_raw_breakpoint (void *); +/* Check if any hardware watchpoints have triggered, according to the + target. */ +int watchpoints_triggered (struct target_waitstatus *); + #endif /* !defined (BREAKPOINT_H) */ Index: i386-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v retrieving revision 1.82 diff -u -p -r1.82 i386-linux-nat.c --- i386-linux-nat.c 23 Aug 2007 18:08:34 -0000 1.82 +++ i386-linux-nat.c 10 Sep 2007 00:20:24 -0000 @@ -579,16 +579,23 @@ i386_linux_store_inferior_registers (str /* Support for debug registers. */ +static unsigned long i386_linux_dr[DR_CONTROL + 1]; + +struct i386_linux_dr_set_args +{ + int regnum; + unsigned long value; +}; + static unsigned long -i386_linux_dr_get (int regnum) +i386_linux_dr_get (ptid_t ptid, int regnum) { 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 (ptid); + if (tid == 0) + tid = PIDGET (ptid); /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the ptrace call fails breaks debugging remote targets. The correct @@ -609,14 +616,13 @@ i386_linux_dr_get (int regnum) } static void -i386_linux_dr_set (int regnum, unsigned long value) +i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) { 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 (ptid); + if (tid == 0) + tid = PIDGET (ptid); errno = 0; ptrace (PTRACE_POKEUSER, tid, @@ -625,10 +631,34 @@ i386_linux_dr_set (int regnum, unsigned perror_with_name (_("Couldn't write debug register")); } +static int +i386_linux_dr_set_lwp (struct lwp_info *lp, void *args_p) +{ + struct i386_linux_dr_set_args *args = args_p; + + /* We do not need to set the debug registers for new threads now; + they'll be done at resume anyway. */ + if (linux_nat_lwp_is_new (lp->ptid)) + return 0; + + i386_linux_dr[args->regnum] = args->value; + i386_linux_dr_set (lp->ptid, args->regnum, args->value); + + return 0; +} + void i386_linux_dr_set_control (unsigned long control) { - i386_linux_dr_set (DR_CONTROL, control); + if (i386_linux_dr[DR_CONTROL] != control) + { + struct i386_linux_dr_set_args args; + + i386_linux_dr[DR_CONTROL] = control; + args.regnum = DR_CONTROL; + args.value = control; + iterate_over_lwps (i386_linux_dr_set_lwp, &args); + } } void @@ -636,21 +666,41 @@ i386_linux_dr_set_addr (int regnum, CORE { gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - i386_linux_dr_set (DR_FIRSTADDR + regnum, addr); + if (i386_linux_dr[DR_FIRSTADDR + regnum] != addr) + { + struct i386_linux_dr_set_args args; + + i386_linux_dr[DR_FIRSTADDR + regnum] = addr; + args.regnum = DR_FIRSTADDR + regnum; + args.value = addr; + iterate_over_lwps (i386_linux_dr_set_lwp, &args); + } } void i386_linux_dr_reset_addr (int regnum) { - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L); + i386_linux_dr_set_addr (regnum, 0); } unsigned long i386_linux_dr_get_status (void) { - return i386_linux_dr_get (DR_STATUS); + return i386_linux_dr_get (inferior_ptid, DR_STATUS); +} + +static void +i386_linux_dr_update (ptid_t ptid) +{ + int i; + + if (!linux_nat_lwp_is_new (ptid)) + return; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + i386_linux_dr_set (ptid, i, i386_linux_dr[i]); + + i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]); } \f @@ -729,12 +779,6 @@ i386_linux_resume (ptid_t ptid, int step int request = PTRACE_CONT; - if (pid == -1) - /* Resume all threads. */ - /* I think this only gets used in the non-threaded case, where "resume - all threads" and "resume inferior_ptid" are the same. */ - pid = PIDGET (inferior_ptid); - if (step) { struct regcache *regcache = get_thread_regcache (pid_to_ptid (pid)); @@ -784,6 +828,8 @@ i386_linux_resume (ptid_t ptid, int step } } + i386_linux_dr_update (ptid); + if (ptrace (request, pid, 0, target_signal_to_host (signal)) == -1) perror_with_name (("ptrace")); } Index: ia64-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v retrieving revision 1.40 diff -u -p -r1.40 ia64-linux-nat.c --- ia64-linux-nat.c 23 Aug 2007 18:08:35 -0000 1.40 +++ ia64-linux-nat.c 10 Sep 2007 00:20:24 -0000 @@ -479,8 +479,9 @@ fill_fpregset (const struct regcache *re #define IA64_PSR_DD (1UL << 39) static void -enable_watchpoints_in_psr (struct regcache *regcache) +enable_watchpoints_in_psr (ptid_t ptid) { + struct regcache *regcache = get_thread_regcache (ptid); ULONGEST psr; regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); @@ -492,20 +493,21 @@ enable_watchpoints_in_psr (struct regcac } } -static long -fetch_debug_register (ptid_t ptid, int idx) +static int +enable_watchpoints_in_psr_lwp (struct lwp_info *lp, void *unused) { - long val; - int tid; - - tid = TIDGET (ptid); - if (tid == 0) - tid = PIDGET (ptid); + enable_watchpoints_in_psr (lp->ptid); + return 0; +} - val = ptrace (PT_READ_U, tid, (PTRACE_TYPE_ARG3) (PT_DBR + 8 * idx), 0); +static long debug_registers[8]; - return val; -} +struct store_debug_register_pair_args +{ + int idx; + long dbr_addr; + long dbr_mask; +}; static void store_debug_register (ptid_t ptid, int idx, long val) @@ -520,15 +522,6 @@ store_debug_register (ptid_t ptid, int i } static void -fetch_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr, long *dbr_mask) -{ - if (dbr_addr) - *dbr_addr = fetch_debug_register (ptid, 2 * idx); - if (dbr_mask) - *dbr_mask = fetch_debug_register (ptid, 2 * idx + 1); -} - -static void store_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr, long *dbr_mask) { if (dbr_addr) @@ -538,6 +531,22 @@ store_debug_register_pair (ptid_t ptid, } static int +store_debug_register_pair_lwp (struct lwp_info *lp, void *args_p) +{ + struct store_debug_register_pair_args *args = args_p; + + /* We do not need to set the debug registers for new threads now; + they'll be done at resume anyway. */ + if (linux_nat_lwp_is_new (lp->ptid)) + return 0; + + store_debug_register_pair (lp->ptid, args->idx, &args->dbr_addr, + &args->dbr_mask); + + return 0; +} + +static int is_power_of_2 (int val) { int i, onecount; @@ -557,13 +566,14 @@ ia64_linux_insert_watchpoint (CORE_ADDR int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; + struct store_debug_register_pair_args args; if (len <= 0 || !is_power_of_2 (len)) return -1; for (idx = 0; idx < max_watchpoints; idx++) { - fetch_debug_register_pair (ptid, idx, NULL, &dbr_mask); + dbr_mask = debug_registers[idx * 2 + 1]; if ((dbr_mask & (0x3UL << 62)) == 0) { /* Exit loop if both r and w bits clear */ @@ -592,8 +602,15 @@ ia64_linux_insert_watchpoint (CORE_ADDR return -1; } + debug_registers[2 * idx] = dbr_addr; + debug_registers[2 * idx + 1] = dbr_mask; + args.idx = idx; + args.dbr_addr = dbr_addr; + args.dbr_mask = dbr_mask; + iterate_over_lwps (store_debug_register_pair_lwp, &args); + store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); - enable_watchpoints_in_psr (get_current_regcache ()); + iterate_over_lwps (enable_watchpoints_in_psr_lwp, NULL); return 0; } @@ -611,36 +628,56 @@ ia64_linux_remove_watchpoint (CORE_ADDR for (idx = 0; idx < max_watchpoints; idx++) { - fetch_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); + dbr_addr = debug_registers[2 * idx]; + dbr_mask = debug_registers[2 * idx + 1]; if ((dbr_mask & (0x3UL << 62)) && addr == (CORE_ADDR) dbr_addr) { - dbr_addr = 0; - dbr_mask = 0; - store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); + struct store_debug_register_pair_args args; + + debug_registers[2 * idx] = 0; + debug_registers[2 * idx + 1] = 0; + args.idx = idx; + args.dbr_addr = 0; + args.dbr_mask = 0; + iterate_over_lwps (store_debug_register_pair_lwp, &args); + return 0; } } return -1; } +static void +ia64_linux_debug_register_update (ptid_t ptid) +{ + int i, any; + + if (!linux_nat_lwp_is_new (ptid)) + return; + + any = 0; + for (i = 0; i < 8; i++) + { + if (debug_registers[i] != 0) + any = 1; + store_debug_register (ptid, i, debug_registers[i]); + } + + if (any) + enable_watchpoints_in_psr (ptid); +} + static int ia64_linux_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) { CORE_ADDR psr; - int tid; - struct siginfo siginfo; - ptid_t ptid = inferior_ptid; + struct siginfo *siginfo_p; struct regcache *regcache = get_current_regcache (); - tid = TIDGET(ptid); - if (tid == 0) - tid = PIDGET (ptid); - - errno = 0; - ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo); + siginfo_p = linux_nat_get_siginfo (inferior_ptid); - if (errno != 0 || siginfo.si_signo != SIGTRAP || - (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) + if (siginfo_p->si_signo != SIGTRAP + || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) return 0; regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); @@ -648,7 +685,7 @@ ia64_linux_stopped_data_address (struct for the next instruction */ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr); - *addr_p = (CORE_ADDR)siginfo.si_addr; + *addr_p = (CORE_ADDR)siginfo_p->si_addr; return 1; } @@ -781,6 +818,7 @@ ia64_linux_store_registers (struct regca static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object, const char *, gdb_byte *, const gdb_byte *, ULONGEST, LONGEST); +static void (*super_resume) (ptid_t ptid, int step, enum target_signal signal); static LONGEST ia64_linux_xfer_partial (struct target_ops *ops, @@ -796,6 +834,13 @@ ia64_linux_xfer_partial (struct target_o offset, len); } +static void +ia64_linux_resume (ptid_t ptid, int step, enum target_signal signal) +{ + ia64_linux_debug_register_update (ptid); + super_resume (ptid, step, signal); +} + void _initialize_ia64_linux_nat (void); void @@ -814,6 +859,10 @@ _initialize_ia64_linux_nat (void) super_xfer_partial = t->to_xfer_partial; t->to_xfer_partial = ia64_linux_xfer_partial; + /* Override the default ptrace resume method. */ + super_resume = t->to_resume; + t->to_resume = ia64_linux_resume; + /* Override watchpoint routines. */ /* The IA-64 architecture can step over a watch point (without triggering Index: infrun.c =================================================================== RCS file: /cvs/src/src/gdb/infrun.c,v retrieving revision 1.245 diff -u -p -r1.245 infrun.c --- infrun.c 23 Aug 2007 18:08:35 -0000 1.245 +++ infrun.c 10 Sep 2007 00:20:25 -0000 @@ -882,6 +882,7 @@ enum infwait_states { infwait_normal_state, infwait_thread_hop_state, + infwait_step_watch_state, infwait_nonstep_watch_state }; @@ -1221,17 +1222,12 @@ adjust_pc_after_break (struct execution_ by an event from the inferior, figure out what it means and take appropriate action. */ -int stepped_after_stopped_by_watchpoint; - void handle_inferior_event (struct execution_control_state *ecs) { - /* NOTE: bje/2005-05-02: If you're looking at this code and thinking - that the variable stepped_after_stopped_by_watchpoint isn't used, - then you're wrong! See remote.c:remote_stopped_data_address. */ - int sw_single_step_trap_p = 0; - int stopped_by_watchpoint = -1; /* Mark as unknown. */ + int stopped_by_watchpoint; + int stepped_after_stopped_by_watchpoint = 0; /* Cache the last pid/waitstatus. */ target_last_wait_ptid = ecs->ptid; @@ -1251,7 +1247,17 @@ handle_inferior_event (struct execution_ case infwait_normal_state: if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n"); - stepped_after_stopped_by_watchpoint = 0; + break; + + case infwait_step_watch_state: + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: infwait_step_watch_state\n"); + + /* FIXME-maybe: is this cleaner than setting a flag? Does it + handle things like signals arriving and other things happening + in combination correctly? */ + stepped_after_stopped_by_watchpoint = 1; break; case infwait_nonstep_watch_state: @@ -1440,7 +1446,7 @@ handle_inferior_event (struct execution_ stop_pc = read_pc (); - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); @@ -1488,7 +1494,7 @@ handle_inferior_event (struct execution_ ecs->saved_inferior_ptid = inferior_ptid; inferior_ptid = ecs->ptid; - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); inferior_ptid = ecs->saved_inferior_ptid; @@ -1770,24 +1776,20 @@ handle_inferior_event (struct execution_ singlestep_breakpoints_inserted_p = 0; } - /* It may not be necessary to disable the watchpoint to stop over - it. For example, the PA can (with some kernel cooperation) - single step over a watchpoint without disabling the watchpoint. */ - if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws)) + if (stepped_after_stopped_by_watchpoint) + stopped_by_watchpoint = 0; + else + stopped_by_watchpoint = watchpoints_triggered (&ecs->ws); + + /* If necessary, step over this watchpoint. We'll be back to display + it in a moment. */ + if (stopped_by_watchpoint + && (HAVE_STEPPABLE_WATCHPOINT + || gdbarch_have_nonsteppable_watchpoint (current_gdbarch))) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); - resume (1, 0); - prepare_to_wait (ecs); - return; - } - /* It is far more common to need to disable a watchpoint to step - the inferior over it. FIXME. What else might a debug - register or page protection watchpoint scheme need here? */ - if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch) - && STOPPED_BY_WATCHPOINT (ecs->ws)) - { /* 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 @@ -1797,31 +1799,31 @@ handle_inferior_event (struct execution_ 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. */ + watchpoint expression. We do this by single-stepping the + target. - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); - remove_breakpoints (); + It may not be necessary to disable the watchpoint to stop over + it. For example, the PA can (with some kernel cooperation) + single step over a watchpoint without disabling the watchpoint. + + It is far more common to need to disable a watchpoint to step + the inferior over it. If we have non-steppable watchpoints, + we must disable the current watchpoint; it's simplest to + disable all watchpoints and breakpoints. */ + + if (!HAVE_STEPPABLE_WATCHPOINT) + remove_breakpoints (); 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; + if (HAVE_STEPPABLE_WATCHPOINT) + ecs->infwait_state = infwait_step_watch_state; + else + ecs->infwait_state = infwait_nonstep_watch_state; prepare_to_wait (ecs); return; } - /* It may be possible to simply continue after a watchpoint. */ - if (HAVE_CONTINUABLE_WATCHPOINT) - stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (ecs->ws); - ecs->stop_func_start = 0; ecs->stop_func_end = 0; ecs->stop_func_name = 0; @@ -1943,8 +1945,7 @@ handle_inferior_event (struct execution_ else { /* See if there is a breakpoint at the current PC. */ - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, - stopped_by_watchpoint); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); /* Following in case break condition called a function. */ Index: linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.c,v retrieving revision 1.67 diff -u -p -r1.67 linux-nat.c --- linux-nat.c 2 Sep 2007 14:04:31 -0000 1.67 +++ linux-nat.c 10 Sep 2007 00:20:25 -0000 @@ -503,12 +503,13 @@ linux_child_follow_fork (struct target_o target_detach (NULL, 0); } - inferior_ptid = pid_to_ptid (child_pid); + inferior_ptid = ptid_build (child_pid, child_pid, 0); /* Reinstall ourselves, since we might have been removed in target_detach (which does other necessary cleanup). */ push_target (ops); + linux_nat_switch_fork (inferior_ptid); /* Reset breakpoints in the child as appropriate. */ follow_inferior_reset_breakpoints (); @@ -673,6 +674,7 @@ add_lwp (ptid_t ptid) lp->waitstatus.kind = TARGET_WAITKIND_IGNORE; lp->ptid = ptid; + lp->new_lwp = 1; lp->next = lwp_list; lwp_list = lp; @@ -1077,8 +1079,6 @@ resume_callback (struct lwp_info *lp, vo { if (lp->stopped && lp->status == 0) { - struct thread_info *tp; - linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)), 0, TARGET_SIGNAL_0); if (debug_linux_nat) @@ -1087,6 +1087,8 @@ resume_callback (struct lwp_info *lp, vo target_pid_to_str (lp->ptid)); lp->stopped = 0; lp->step = 0; + lp->new_lwp = 0; + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); } return 0; @@ -1136,68 +1138,70 @@ linux_nat_resume (ptid_t ptid, int step, ptid = inferior_ptid; lp = find_lwp_pid (ptid); - if (lp) - { - ptid = pid_to_ptid (GET_LWP (lp->ptid)); - - /* Remember if we're stepping. */ - lp->step = step; + gdb_assert (lp != NULL); - /* Mark this LWP as resumed. */ - lp->resumed = 1; + ptid = pid_to_ptid (GET_LWP (lp->ptid)); - /* If we have a pending wait status for this thread, there is no - point in resuming the process. But first make sure that - linux_nat_wait won't preemptively handle the event - we - should never take this short-circuit if we are going to - leave LP running, since we have skipped resuming all the - other threads. This bit of code needs to be synchronized - with linux_nat_wait. */ - - if (lp->status && WIFSTOPPED (lp->status)) - { - int saved_signo = target_signal_from_host (WSTOPSIG (lp->status)); - - if (signal_stop_state (saved_signo) == 0 - && signal_print_state (saved_signo) == 0 - && signal_pass_state (saved_signo) == 1) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLR: Not short circuiting for ignored " - "status 0x%x\n", lp->status); + /* Remember if we're stepping. */ + lp->step = step; - /* FIXME: What should we do if we are supposed to continue - this thread with a signal? */ - gdb_assert (signo == TARGET_SIGNAL_0); - signo = saved_signo; - lp->status = 0; - } - } + /* Mark this LWP as resumed. */ + lp->resumed = 1; - if (lp->status) + /* If we have a pending wait status for this thread, there is no + point in resuming the process. But first make sure that + linux_nat_wait won't preemptively handle the event - we + should never take this short-circuit if we are going to + leave LP running, since we have skipped resuming all the + other threads. This bit of code needs to be synchronized + with linux_nat_wait. */ + + if (lp->status && WIFSTOPPED (lp->status)) + { + int saved_signo = target_signal_from_host (WSTOPSIG (lp->status)); + + if (signal_stop_state (saved_signo) == 0 + && signal_print_state (saved_signo) == 0 + && signal_pass_state (saved_signo) == 1) { + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLR: Not short circuiting for ignored " + "status 0x%x\n", lp->status); + /* FIXME: What should we do if we are supposed to continue this thread with a signal? */ gdb_assert (signo == TARGET_SIGNAL_0); + signo = saved_signo; + lp->status = 0; + } + } - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLR: Short circuiting for status 0x%x\n", - lp->status); + if (lp->status) + { + /* FIXME: What should we do if we are supposed to continue + this thread with a signal? */ + gdb_assert (signo == TARGET_SIGNAL_0); - return; - } + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLR: Short circuiting for status 0x%x\n", + lp->status); - /* Mark LWP as not stopped to prevent it from being continued by - resume_callback. */ - lp->stopped = 0; + return; } + /* Mark LWP as not stopped to prevent it from being continued by + resume_callback. */ + lp->stopped = 0; + if (resume_all) iterate_over_lwps (resume_callback, NULL); linux_ops->to_resume (ptid, step, signo); + lp->new_lwp = 0; + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLR: %s %s, %s (resume event thread)\n", @@ -1416,6 +1420,22 @@ wait_lwp (struct lwp_info *lp) return status; } +/* Save the most recent siginfo for LP. This is currently only called + for SIGTRAP; some ports use the si_addr field for + target_stopped_data_address. In the future, it may also be used to + restore the siginfo of requeued signals. */ + +static void +save_siginfo (struct lwp_info *lp) +{ + errno = 0; + ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid), + (PTRACE_TYPE_ARG3) 0, &lp->siginfo); + + if (errno != 0) + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); +} + /* Send a SIGSTOP to LP. */ static int @@ -1501,6 +1521,9 @@ stop_wait_callback (struct lwp_info *lp, user will delete or disable the breakpoint, but the thread will have already tripped on it. */ + /* Save the trap's siginfo in case we need it later. */ + save_siginfo (lp); + /* Now resume this LWP and get the SIGSTOP event. */ errno = 0; ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); @@ -2058,6 +2081,10 @@ retry: target_pid_to_str (lp->ptid)); } + /* Save the trap's siginfo in case we need it later. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) + save_siginfo (lp); + /* Handle GNU/Linux's extended waitstatus for trace events. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) { @@ -3250,6 +3277,28 @@ linux_nat_add_target (struct target_ops thread_db_init (t); } +/* Return non-zero if the specified LWP is new. */ +int +linux_nat_lwp_is_new (ptid_t ptid) +{ + struct lwp_info *lp = find_lwp_pid (ptid); + + gdb_assert (lp != NULL); + + return lp->new_lwp; +} + +/* Return the saved siginfo associated with PTID. */ +struct siginfo * +linux_nat_get_siginfo (ptid_t ptid) +{ + struct lwp_info *lp = find_lwp_pid (ptid); + + gdb_assert (lp != NULL); + + return &lp->siginfo; +} + void _initialize_linux_nat (void) { Index: linux-nat.h =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.h,v retrieving revision 1.19 diff -u -p -r1.19 linux-nat.h --- linux-nat.h 23 Aug 2007 18:08:35 -0000 1.19 +++ linux-nat.h 10 Sep 2007 00:20:25 -0000 @@ -20,6 +20,8 @@ #include "target.h" +#include <signal.h> + /* Structure describing an LWP. */ struct lwp_info @@ -54,6 +56,14 @@ struct lwp_info /* Non-zero if we were stepping this LWP. */ int step; + /* Non-zero if this LWP is new. An LWP is considered new from the + moment it is attached until just after it has been resumed once. */ + int new_lwp; + + /* Non-zero si_signo if this LWP stopped with a trap. si_addr may + be the address of a hardware watchpoint. */ + struct siginfo siginfo; + /* If WAITSTATUS->KIND != TARGET_WAITKIND_SPURIOUS, the waitstatus for this LWP's last event. This may correspond to STATUS above, or to a local variable in lin_lwp_wait. */ @@ -98,3 +108,9 @@ void linux_nat_add_target (struct target /* Update linux-nat internal state when changing from one fork to another. */ void linux_nat_switch_fork (ptid_t new_ptid); + +/* Return non-zero if the specified LWP is new. */ +int linux_nat_lwp_is_new (ptid_t ptid); + +/* Return the saved siginfo associated with PTID. */ +struct siginfo *linux_nat_get_siginfo (ptid_t ptid); Index: ppc-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/ppc-linux-nat.c,v retrieving revision 1.70 diff -u -p -r1.70 ppc-linux-nat.c --- ppc-linux-nat.c 30 Aug 2007 13:13:59 -0000 1.70 +++ ppc-linux-nat.c 10 Sep 2007 00:20:25 -0000 @@ -142,8 +142,6 @@ struct gdb_evrregset_t error. */ int have_ptrace_getvrregs = 1; -static CORE_ADDR last_stopped_data_address = 0; - /* Non-zero if our kernel may support the PTRACE_GETEVRREGS and PTRACE_SETEVRREGS requests, for reading and writing the SPE registers. Zero if we've tried one of them and gotten an @@ -805,13 +803,29 @@ ppc_linux_region_ok_for_hw_watchpoint (C return 1; } +/* The cached DABR value, to install in new threads. */ +static long saved_dabr_value; + +static int +ppc_linux_set_debugreg_lwp (struct lwp_info *lp, void *arg) +{ + int tid; + long dabr_value = *(long *) arg; + + /* We do not need to set the debug registers for new threads now; + they'll be done at resume anyway. */ + if (linux_nat_lwp_is_new (lp->ptid)) + return 0; + + ptrace (PTRACE_SET_DEBUGREG, TIDGET (lp->ptid), 0, dabr_value); + return 0; +} + /* Set a watchpoint of type TYPE at address ADDR. */ static int ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) { - int tid; long dabr_value; - ptid_t ptid = inferior_ptid; dabr_value = addr & ~7; switch (rw) @@ -830,61 +844,57 @@ ppc_linux_insert_watchpoint (CORE_ADDR a break; } - tid = TIDGET (ptid); - if (tid == 0) - tid = PIDGET (ptid); - - return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value); + saved_dabr_value = dabr_value; + iterate_over_lwps (ppc_linux_set_debugreg_lwp, &dabr_value); + return 0; } static int ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw) { - int tid; - ptid_t ptid = inferior_ptid; - - tid = TIDGET (ptid); - if (tid == 0) - tid = PIDGET (ptid); + long dabr_value = 0; - return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0); + saved_dabr_value = 0; + iterate_over_lwps (ppc_linux_set_debugreg_lwp, &dabr_value); + return 0; } -static int -ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) +static void +ppc_linux_debugreg_update (ptid_t ptid) { - if (last_stopped_data_address) - { - *addr_p = last_stopped_data_address; - last_stopped_data_address = 0; - return 1; - } - return 0; + int tid = TIDGET (inferior_ptid); + + if (!linux_nat_lwp_is_new (ptid)) + return; + + if (tid == 0) + tid = PIDGET (inferior_ptid); + ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); } static int -ppc_linux_stopped_by_watchpoint (void) +ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) { - int tid; - struct siginfo siginfo; - ptid_t ptid = inferior_ptid; + struct siginfo *siginfo_p; CORE_ADDR *addr_p; - tid = TIDGET(ptid); - if (tid == 0) - tid = PIDGET (ptid); - - errno = 0; - ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo); + siginfo_p = linux_nat_get_siginfo (inferior_ptid); - if (errno != 0 || siginfo.si_signo != SIGTRAP || - (siginfo.si_code & 0xffff) != 0x0004) + if (siginfo_p->si_signo != SIGTRAP + || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) return 0; - last_stopped_data_address = (uintptr_t) siginfo.si_addr; + *addr_p = (CORE_ADDR) siginfo_p->si_addr; return 1; } +static int +ppc_linux_stopped_by_watchpoint (void) +{ + CORE_ADDR addr; + return ppc_linux_stopped_data_address (¤t_target, &addr); +} + static void ppc_linux_store_inferior_registers (struct regcache *regcache, int regno) { @@ -945,6 +955,15 @@ fill_fpregset (const struct regcache *re fpregsetp, sizeof (*fpregsetp)); } +static void (*super_resume) (ptid_t ptid, int step, enum target_signal signal); + +static void +ppc_linux_resume (ptid_t ptid, int step, enum target_signal signal) +{ + ppc_linux_debugreg_update (ptid); + super_resume (ptid, step, signal); +} + void _initialize_ppc_linux_nat (void); void @@ -959,6 +978,10 @@ _initialize_ppc_linux_nat (void) t->to_fetch_registers = ppc_linux_fetch_inferior_registers; t->to_store_registers = ppc_linux_store_inferior_registers; + /* Override the default ptrace resume method. */ + super_resume = t->to_resume; + t->to_resume = ppc_linux_resume; + /* Add our watchpoint methods. */ t->to_can_use_hw_breakpoint = ppc_linux_check_watch_resources; t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint; Index: remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.266 diff -u -p -r1.266 remote.c --- remote.c 23 Aug 2007 18:08:36 -0000 1.266 +++ remote.c 10 Sep 2007 00:20:25 -0000 @@ -5410,14 +5410,11 @@ remote_stopped_by_watchpoint (void) return remote_stopped_by_watchpoint_p; } -extern int stepped_after_stopped_by_watchpoint; - static int remote_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) { int rc = 0; - if (remote_stopped_by_watchpoint () - || stepped_after_stopped_by_watchpoint) + if (remote_stopped_by_watchpoint ()) { *addr_p = remote_watch_data_address; rc = 1; Index: s390-nat.c =================================================================== RCS file: /cvs/src/src/gdb/s390-nat.c,v retrieving revision 1.25 diff -u -p -r1.25 s390-nat.c --- s390-nat.c 23 Aug 2007 18:08:37 -0000 1.25 +++ s390-nat.c 10 Sep 2007 00:20:25 -0000 @@ -252,6 +252,7 @@ s390_stopped_by_watchpoint (void) { per_lowcore_bits per_lowcore; ptrace_area parea; + int result; /* Speed up common case. */ if (!watch_base) @@ -263,14 +264,24 @@ s390_stopped_by_watchpoint (void) if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0) perror_with_name (_("Couldn't retrieve watchpoint status")); - return per_lowcore.perc_storage_alteration == 1 - && per_lowcore.perc_store_real_address == 0; + result = (per_lowcore.perc_storage_alteration == 1 + && per_lowcore.perc_store_real_address == 0); + + if (result) + { + /* Do not report this watchpoint again. */ + memset (&per_lowcore, 0, sizeof (per_lowcore)); + if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0) + perror_with_name (_("Couldn't clear watchpoint status")); + } + + return result; } static void -s390_fix_watch_points (void) +s390_fix_watch_points (ptid_t ptid) { - int tid = s390_inferior_tid (); + int tid; per_struct per_info; ptrace_area parea; @@ -278,6 +289,10 @@ s390_fix_watch_points (void) CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; struct watch_area *area; + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); + for (area = watch_base; area; area = area->next) { watch_lo_addr = min (watch_lo_addr, area->lo_addr); @@ -308,6 +323,18 @@ s390_fix_watch_points (void) } static int +s390_fix_watch_points_lwp (struct lwp_info *lp, void *unused) +{ + /* We do not need to set the debug registers for new threads now; + they'll be done at resume anyway. */ + if (linux_nat_lwp_is_new (lp->ptid)) + return 0; + + s390_fix_watch_points (lp->ptid); + return 0; +} + +static int s390_insert_watchpoint (CORE_ADDR addr, int len, int type) { struct watch_area *area = xmalloc (sizeof (struct watch_area)); @@ -320,7 +347,7 @@ s390_insert_watchpoint (CORE_ADDR addr, area->next = watch_base; watch_base = area; - s390_fix_watch_points (); + iterate_over_lwps (s390_fix_watch_points_lwp, NULL); return 0; } @@ -345,7 +372,7 @@ s390_remove_watchpoint (CORE_ADDR addr, *parea = area->next; xfree (area); - s390_fix_watch_points (); + iterate_over_lwps (s390_fix_watch_points_lwp, NULL); return 0; } @@ -361,6 +388,15 @@ s390_region_ok_for_hw_watchpoint (CORE_A return 1; } +static void (*super_resume) (ptid_t ptid, int step, enum target_signal signal); + +static void +s390_resume (ptid_t ptid, int step, enum target_signal signal) +{ + if (linux_nat_lwp_is_new (ptid)) + s390_fix_watch_points (ptid); + super_resume (ptid, step, signal); +} void _initialize_s390_nat (void); @@ -376,6 +412,10 @@ _initialize_s390_nat (void) t->to_fetch_registers = s390_linux_fetch_inferior_registers; t->to_store_registers = s390_linux_store_inferior_registers; + /* Override the default ptrace resume method. */ + super_resume = t->to_resume; + t->to_resume = s390_resume; + /* Add our watchpoint methods. */ t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint; t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint; Index: testsuite/gdb.threads/watchthreads.c =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.threads/watchthreads.c,v retrieving revision 1.3 diff -u -p -r1.3 watchthreads.c --- testsuite/gdb.threads/watchthreads.c 23 Aug 2007 18:08:50 -0000 1.3 +++ testsuite/gdb.threads/watchthreads.c 10 Sep 2007 00:20:26 -0000 @@ -56,7 +56,7 @@ void *thread_function(void *arg) { /* Don't run forever. Run just short of it :) */ while (*myp > 0) { - (*myp) ++; /* Loop increment. */ + (*myp) ++; usleep (1); /* Loop increment. */ } pthread_exit(NULL); Index: testsuite/gdb.threads/watchthreads.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.threads/watchthreads.exp,v retrieving revision 1.4 diff -u -p -r1.4 watchthreads.exp --- testsuite/gdb.threads/watchthreads.exp 23 Aug 2007 18:14:19 -0000 1.4 +++ testsuite/gdb.threads/watchthreads.exp 10 Sep 2007 00:20:26 -0000 @@ -30,6 +30,10 @@ if [target_info exists gdb,no_hardware_w return 0; } +proc target_no_stopped_data { } { + return [istarget s390*-*-*] +} + set testfile "watchthreads" set srcfile ${testfile}.c set binfile ${objdir}/${subdir}/${testfile} @@ -61,20 +65,56 @@ gdb_test "watch args\[1\]" "Hardware wat set init_line [expr [gdb_get_line_number "Init value"]+1] set inc_line [gdb_get_line_number "Loop increment"] +set main_loc "main \\\(\\\) at .*watchthreads.c:$init_line" +set thread0_loc "thread_function \\\(arg=0x0\\\) at .*watchthreads.c:$inc_line" +set thread1_loc "thread_function \\\(arg=0x1\\\) at .*watchthreads.c:$inc_line" # Loop and continue to allow both watchpoints to be triggered. for {set i 0} {$i < 30} {incr i} { + set test_flag_0 0 + set test_flag_1 0 set test_flag 0 gdb_test_multiple "continue" "threaded watch loop" { - -re "Hardware watchpoint 2: args\\\[0\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads.c:$init_line.*$gdb_prompt $" - { set args_0 1; set test_flag 1 } - -re "Hardware watchpoint 3: args\\\[1\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads.c:$init_line.*$gdb_prompt $" - { set args_1 1; set test_flag 1 } - -re "Hardware watchpoint 2: args\\\[0\\\].*Old value = $args_0.*New value = [expr $args_0+1].*in thread_function \\\(arg=0x0\\\) at .*watchthreads.c:$inc_line.*$gdb_prompt $" - { set args_0 [expr $args_0+1]; set test_flag 1 } - -re "Hardware watchpoint 3: args\\\[1\\\].*Old value = $args_1.*New value = [expr $args_1+1].*in thread_function \\\(arg=0x1\\\) at .*watchthreads.c:$inc_line.*$gdb_prompt $" - { set args_1 [expr $args_1+1]; set test_flag 1 } + -re "(.*Hardware watchpoint.*)$gdb_prompt $" { + # At least one hardware watchpoint was hit. Check if both were. + set string $expect_out(1,string) + + if [regexp "Hardware watchpoint 2: args\\\[0\\\]\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $args_0\[^\r\]*\r\[^\r\]*New value = [expr $args_0+1]\r" $string] { + incr args_0 + incr test_flag_0 + } + if [regexp "Hardware watchpoint 3: args\\\[1\\\]\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $args_1\[^\r\]*\r\[^\r\]*New value = [expr $args_1+1]\r" $string] { + incr args_1 + incr test_flag_1 + } + + set expected_loc "bogus location" + if { $test_flag_0 == 1 && $test_flag_1 == 0 && $args_0 == 1 } { + set expected_loc $main_loc + } elseif { $test_flag_0 == 0 && $test_flag_1 == 1 && $args_1 == 1 } { + set expected_loc $main_loc + } elseif { $test_flag_0 == 1 && $test_flag_1 == 0 } { + set expected_loc $thread0_loc + } elseif { $test_flag_0 == 0 && $test_flag_1 == 1 } { + set expected_loc $thread1_loc + } elseif { $test_flag_0 + $test_flag_1 == 2 } { + # On S/390, or any other system which can not report the + # stopped data address, it is OK to report two watchpoints + # at once in this test. Make sure the reported location + # corresponds to at least one of the watchpoints (and not, + # e.g., __nptl_create_event). On other systems, we should + # report the two watchpoints serially. + if { [target_no_stopped_data] } { + set expected_loc "($main_loc|$thread0_loc|$thread1_loc)" + } + } + + if [ regexp "$expected_loc" $string ] { + set test_flag 1 + } + } } + # If we fail above, don't bother continuing loop if { $test_flag == 0 } { set i 30; @@ -84,6 +124,8 @@ for {set i 0} {$i < 30} {incr i} { # Print success message if loop succeeded. if { $test_flag == 1 } { pass "threaded watch loop" +} else { + fail "threaded watch loop" } # Verify that we hit first watchpoint in main thread. @@ -120,7 +162,14 @@ if { $args_1 > 1 } { # Verify that all watchpoint hits are accounted for. set message "combination of threaded watchpoints = 30" -if { [expr $args_0+$args_1] == 30 } { +if { [target_no_stopped_data] } { + # See above. If we allow two watchpoints to be hit at once, we + # may have more than 30 hits total. + set result [expr $args_0 + $args_1 >= 30] +} else { + set result [expr $args_0 + $args_1 == 30] +} +if { $result } { pass $message } else { fail $message ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 0:21 ` Daniel Jacobowitz @ 2007-09-10 15:34 ` Luis Machado 2007-09-10 15:44 ` Daniel Jacobowitz 2007-09-10 18:23 ` Ulrich Weigand 1 sibling, 1 reply; 17+ messages in thread From: Luis Machado @ 2007-09-10 15:34 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches > Here is my current patch. The PowerPC bits are totally untested, > not even compiled - could you test it for me, please? I don't > have a suitable system. Sure, i'll do the tests as soon as i get the code to compile. > I've regression tested i386, amd64, and ia64. I tested S/390 by hand > and it works, but the extra logic in watchthreads.exp for that > platform hasn't been tested (no DejaGNU or expect on my test system). I couldn't build the code for ppc due to a call to the "save_siginfo" function. Why is exactly that function's been moved to "linux-nat.c"? It seems that it's being called only in that file, and with a PPC-specific ptrace request "PTRACE_GETSIGINFO", which is not declared anywhere except for "ppc-linux-nat.c". Could you please clarify this specific point? Thanks! Regards, -- Luis Machado IBM Linux Technology Center e-mail: luisgpm@linux.vnet.ibm.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 15:34 ` Luis Machado @ 2007-09-10 15:44 ` Daniel Jacobowitz 2007-09-10 17:56 ` Luis Machado 0 siblings, 1 reply; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-10 15:44 UTC (permalink / raw) To: Luis Machado; +Cc: gdb-patches On Mon, Sep 10, 2007 at 12:34:14PM -0300, Luis Machado wrote: > > I've regression tested i386, amd64, and ia64. I tested S/390 by hand > > and it works, but the extra logic in watchthreads.exp for that > > platform hasn't been tested (no DejaGNU or expect on my test system). > > I couldn't build the code for ppc due to a call to the "save_siginfo" > function. Why is exactly that function's been moved to "linux-nat.c"? It > seems that it's being called only in that file, and with a PPC-specific > ptrace request "PTRACE_GETSIGINFO", which is not declared anywhere > except for "ppc-linux-nat.c". > > Could you please clarify this specific point? PTRACE_GETSIGINFO is not specific to PowerPC. It's architecture-independent (although somewhat recent); IA-64 uses it for watchpoints just like PowerPC does. If your system headers are not new enough to define it, the definition from ppc-linux-nat.c should probably move to linux-nat.c too. If that doesn't help, could you show me the error message? Thanks. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 15:44 ` Daniel Jacobowitz @ 2007-09-10 17:56 ` Luis Machado 2007-09-10 18:30 ` Daniel Jacobowitz 0 siblings, 1 reply; 17+ messages in thread From: Luis Machado @ 2007-09-10 17:56 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches Hi, > If that doesn't help, could you show me the error message? Thanks. Yes, that does it, though it doesn't look right to have that definition moved to "linux-nat.c". But i might have outdated include files (when were they changed?), so the current code should be fine except for this particular piece: ==== code ==== static int -ppc_linux_stopped_by_watchpoint (void) +ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) { - int tid; - struct siginfo siginfo; - ptid_t ptid = inferior_ptid; + struct siginfo *siginfo_p; CORE_ADDR *addr_p; - tid = TIDGET(ptid); - if (tid == 0) - tid = PIDGET (ptid); === code === We should get rid of the locally-defined "addr_p" since it's already being passed as a parameter by "stopped_data_address". I've built GDB, tried to insert a watchpoint after creating 10 threads and the those threads triggered correctly. As for the testcases, since PPC only supports one hardware watchpoint per process, we should work that test case in a different way or mark it as unsupported for PPC and write a different test case. Regards, -- Luis Machado IBM Linux Technology Center e-mail: luisgpm@linux.vnet.ibm.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 17:56 ` Luis Machado @ 2007-09-10 18:30 ` Daniel Jacobowitz 0 siblings, 0 replies; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-10 18:30 UTC (permalink / raw) To: Luis Machado; +Cc: gdb-patches On Mon, Sep 10, 2007 at 02:56:30PM -0300, Luis Machado wrote: > As for the testcases, since PPC only supports one hardware watchpoint > per process, we should work that test case in a different way or mark it > as unsupported for PPC and write a different test case. Oops, you're correct. This should be easy to check for in the testcase; I don't remember if we'll get an error or a software watchpoint for the second watchpoint. Actually, I think PPC will currently "succeed" and things will go wrong... -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 0:21 ` Daniel Jacobowitz 2007-09-10 15:34 ` Luis Machado @ 2007-09-10 18:23 ` Ulrich Weigand 2007-09-10 18:29 ` Daniel Jacobowitz 1 sibling, 1 reply; 17+ messages in thread From: Ulrich Weigand @ 2007-09-10 18:23 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: Luis Machado, gdb-patches Dan Jacobowitz wrote: > Most of this is liberally borrowed from Jeff's (and your's and Jan's) > work. There are some bits I'm not happy with yet, but I hope I'll > have time to finish it up this week or next weekend, and then I will > submit each logical change separately. Some of them deserve more > explanation (and comments and gdbint documentation). Thanks for working on this! I like the simplification of the infrun logic handling steppable/nonsteppable watchpoints. Was the change to remove use of HAVE_CONTINUABLE_WATCHPOINTS deliberate? It used to be that you had to set one of the three flags in order to activate the watchpoint logic at all, but your new code will always call STOPPED_BY_WATCHPOINT. Another question: +static void +s390_resume (ptid_t ptid, int step, enum target_signal signal) +{ + if (linux_nat_lwp_is_new (ptid)) + s390_fix_watch_points (ptid); + super_resume (ptid, step, signal); +} This assumes that the new thread's ptid will always be passed to the resume. Is this necessarily the case? I would expect ptid to be -1 in most cases ... > I've regression tested i386, amd64, and ia64. I tested S/390 by hand > and it works, but the extra logic in watchthreads.exp for that > platform hasn't been tested (no DejaGNU or expect on my test system). I did a full test on s390-ibm-linux and s390x-ibm-linux, and it works fine. There are no longer any FAILs reported for watchthreads.exp. I did have to define PTRACE_GETSIGINFO in linux-nat.c to get it to compile, however. Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 18:23 ` Ulrich Weigand @ 2007-09-10 18:29 ` Daniel Jacobowitz 2007-09-10 18:44 ` Ulrich Weigand 0 siblings, 1 reply; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-10 18:29 UTC (permalink / raw) To: Ulrich Weigand; +Cc: gdb-patches On Mon, Sep 10, 2007 at 08:22:56PM +0200, Ulrich Weigand wrote: > Was the change to remove use of HAVE_CONTINUABLE_WATCHPOINTS deliberate? > It used to be that you had to set one of the three flags in order to > activate the watchpoint logic at all, but your new code will always > call STOPPED_BY_WATCHPOINT. Yes - do you think I shouldn't? Easy enough to put it back. > +static void > +s390_resume (ptid_t ptid, int step, enum target_signal signal) > +{ > + if (linux_nat_lwp_is_new (ptid)) > + s390_fix_watch_points (ptid); > + super_resume (ptid, step, signal); > +} > > This assumes that the new thread's ptid will always be passed to the > resume. Is this necessarily the case? I would expect ptid to be -1 > in most cases ... It is necessarily the case. This function is never called through target_resume, only through linux_nat_resume. This was one of the big cleanups that made my patch possible. > I did a full test on s390-ibm-linux and s390x-ibm-linux, and it works > fine. There are no longer any FAILs reported for watchthreads.exp. Thanks a lot! -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 18:29 ` Daniel Jacobowitz @ 2007-09-10 18:44 ` Ulrich Weigand 2007-09-10 18:54 ` Daniel Jacobowitz 0 siblings, 1 reply; 17+ messages in thread From: Ulrich Weigand @ 2007-09-10 18:44 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches Daniel Jacobowitz wrote: > On Mon, Sep 10, 2007 at 08:22:56PM +0200, Ulrich Weigand wrote: > > Was the change to remove use of HAVE_CONTINUABLE_WATCHPOINTS deliberate? > > It used to be that you had to set one of the three flags in order to > > activate the watchpoint logic at all, but your new code will always > > call STOPPED_BY_WATCHPOINT. > > Yes - do you think I shouldn't? Easy enough to put it back. I guess your new way makes more sense. This means we can remove HAVE_CONTINUABLE_WATCHPOINTS completely, though. (As a related point, I think it would be good to fix the oddity that nonsteppable watchpoints are reported as a gdbarch property while steppable watchpoints are reported as a target property ...) > > This assumes that the new thread's ptid will always be passed to the > > resume. Is this necessarily the case? I would expect ptid to be -1 > > in most cases ... > > It is necessarily the case. This function is never called through > target_resume, only through linux_nat_resume. This was one of the big > cleanups that made my patch possible. Hmm, I see. This assumes that after every new-thread event, the new thread is selected as inferior_ptid, though. This unfortunately interferes with a patch I'm working on right now: when a new thread event (or shared library event) occurs while we're currently single- stepping another thread, things don't work very well right now. I was proposing to fix this by always selecting the thread being stepped as current thread again after processing the event ... Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 18:44 ` Ulrich Weigand @ 2007-09-10 18:54 ` Daniel Jacobowitz 2007-09-10 19:03 ` Ulrich Weigand 0 siblings, 1 reply; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-10 18:54 UTC (permalink / raw) To: Ulrich Weigand; +Cc: gdb-patches On Mon, Sep 10, 2007 at 08:44:22PM +0200, Ulrich Weigand wrote: > I guess your new way makes more sense. This means we can remove > HAVE_CONTINUABLE_WATCHPOINTS completely, though. (As a related > point, I think it would be good to fix the oddity that nonsteppable > watchpoints are reported as a gdbarch property while steppable > watchpoints are reported as a target property ...) I totally agree. I just don't know which one makes more sense. Probably gdbarch but I'm sure I'll break something if I try to change it. > > > This assumes that the new thread's ptid will always be passed to the > > > resume. Is this necessarily the case? I would expect ptid to be -1 > > > in most cases ... > > > > It is necessarily the case. This function is never called through > > target_resume, only through linux_nat_resume. This was one of the big > > cleanups that made my patch possible. > > Hmm, I see. This assumes that after every new-thread event, the new > thread is selected as inferior_ptid, though. I don't think it assumes that. s390_resume should be called once for each thread, and not depend on inferior_ptid at all; only linux_nat_resume has to check for ptid == -1, schedlocking, et cetera. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 18:54 ` Daniel Jacobowitz @ 2007-09-10 19:03 ` Ulrich Weigand 2007-09-10 19:12 ` Daniel Jacobowitz 2007-09-10 19:31 ` Mark Kettenis 0 siblings, 2 replies; 17+ messages in thread From: Ulrich Weigand @ 2007-09-10 19:03 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches Daniel Jacobowitz wrote: > On Mon, Sep 10, 2007 at 08:44:22PM +0200, Ulrich Weigand wrote: > > I guess your new way makes more sense. This means we can remove > > HAVE_CONTINUABLE_WATCHPOINTS completely, though. (As a related > > point, I think it would be good to fix the oddity that nonsteppable > > watchpoints are reported as a gdbarch property while steppable > > watchpoints are reported as a target property ...) > > I totally agree. I just don't know which one makes more sense. > Probably gdbarch but I'm sure I'll break something if I try to > change it. I'd tend to agree with Andrew's comment in mips-tdep.c: /* FIXME: cagney/2003-08-29: The macros HAVE_STEPPABLE_WATCHPOINT, HAVE_NONSTEPPABLE_WATCHPOINT, and HAVE_CONTINUABLE_WATCHPOINT need to all be folded into the target vector. Since they are being used as guards for STOPPED_BY_WATCHPOINT, why not have STOPPED_BY_WATCHPOINT return the type of watchpoint that the code is sitting on? */ Since all other watchpoint-related callbacks are in the target vector, having nonsteppable_watchpoint as a gdbarch property does look somewhat odd. The only problem with moving HAVE_NONSTEPPABLE_WATCHPOINT into the target vector might be the remote targets. Is this information available via the remote protocol somehow? If not, I guess it has to stay in gdbarch ... > > Hmm, I see. This assumes that after every new-thread event, the new > > thread is selected as inferior_ptid, though. > > I don't think it assumes that. s390_resume should be called once for > each thread, and not depend on inferior_ptid at all; only > linux_nat_resume has to check for ptid == -1, schedlocking, et cetera. Doh! You're right, of course. That should work fine then. Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 19:03 ` Ulrich Weigand @ 2007-09-10 19:12 ` Daniel Jacobowitz 2007-09-10 19:31 ` Mark Kettenis 1 sibling, 0 replies; 17+ messages in thread From: Daniel Jacobowitz @ 2007-09-10 19:12 UTC (permalink / raw) To: Ulrich Weigand; +Cc: gdb-patches On Mon, Sep 10, 2007 at 09:03:26PM +0200, Ulrich Weigand wrote: > The only problem with moving HAVE_NONSTEPPABLE_WATCHPOINT into the > target vector might be the remote targets. Is this information > available via the remote protocol somehow? If not, I guess it has > to stay in gdbarch ... No, it is not. We could add it, but of course existing remote stubs won't tell us which it is. I guess it depends: are there any targets where it varies based on how you're connected? There's room in the world for such a thing: an x86 simulator (like, say, qemu) might offer steppable or non-steppable watchpoints instead of continuable ones. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 0/1] Threaded Watchpoints 2007-09-10 19:03 ` Ulrich Weigand 2007-09-10 19:12 ` Daniel Jacobowitz @ 2007-09-10 19:31 ` Mark Kettenis 1 sibling, 0 replies; 17+ messages in thread From: Mark Kettenis @ 2007-09-10 19:31 UTC (permalink / raw) To: uweigand; +Cc: drow, gdb-patches > Date: Mon, 10 Sep 2007 21:03:26 +0200 (CEST) > From: "Ulrich Weigand" <uweigand@de.ibm.com> > > I'd tend to agree with Andrew's comment in mips-tdep.c: > > /* FIXME: cagney/2003-08-29: The macros HAVE_STEPPABLE_WATCHPOINT, > HAVE_NONSTEPPABLE_WATCHPOINT, and HAVE_CONTINUABLE_WATCHPOINT > need to all be folded into the target vector. Since they are > being used as guards for STOPPED_BY_WATCHPOINT, why not have > STOPPED_BY_WATCHPOINT return the type of watchpoint that the code > is sitting on? */ > > Since all other watchpoint-related callbacks are in the target > vector, having nonsteppable_watchpoint as a gdbarch property > does look somewhat odd. > > The only problem with moving HAVE_NONSTEPPABLE_WATCHPOINT into the > target vector might be the remote targets. Is this information > available via the remote protocol somehow? If not, I guess it has > to stay in gdbarch ... That really is the wrong way to think about this; we shouldn't keep gdb criplled forever, just because some bad decision was made years and years ago. So the real question here is, whether HAVE_NONSTEPPABLE_WATCHPOINT and these other properties mentions above are really a fundamental property of the architecture (ISA or OS ABI). Or if they are properties of a particular debug interface (ptrace, remote, jtag). In some cases it may actually make sense to have something as a property of the architecture but making it possible for the target vector to override it. Mark ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2007-09-10 19:31 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-08-13 13:51 [patch 0/1] Threaded Watchpoints Luis Machado 2007-08-20 17:33 ` Luis Machado 2007-08-20 17:40 ` Luis Machado 2007-09-05 2:04 ` Daniel Jacobowitz 2007-09-05 12:31 ` Luis Machado 2007-09-10 0:21 ` Daniel Jacobowitz 2007-09-10 15:34 ` Luis Machado 2007-09-10 15:44 ` Daniel Jacobowitz 2007-09-10 17:56 ` Luis Machado 2007-09-10 18:30 ` Daniel Jacobowitz 2007-09-10 18:23 ` Ulrich Weigand 2007-09-10 18:29 ` Daniel Jacobowitz 2007-09-10 18:44 ` Ulrich Weigand 2007-09-10 18:54 ` Daniel Jacobowitz 2007-09-10 19:03 ` Ulrich Weigand 2007-09-10 19:12 ` Daniel Jacobowitz 2007-09-10 19:31 ` Mark Kettenis
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox