gdb/gdb-6.3-threaded-watchpoint...

1100 lines
37 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.
2007-10-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Port to GDB-6.7.
2007-11-02 Jan Kratochvil <jan.kratochvil@redhat.com>
Port to post-GDB-6.7.1 multi-PC breakpoints.
Index: gdb-6.7.1/gdb/doc/observer.texi
===================================================================
--- gdb-6.7.1.orig/gdb/doc/observer.texi 2007-05-11 21:55:20.000000000 +0200
+++ gdb-6.7.1/gdb/doc/observer.texi 2007-11-02 15:21:57.000000000 +0100
@@ -129,3 +129,12 @@ Called with @var{objfile} equal to @code
previously loaded symbol table data has now been invalidated.
@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
Index: gdb-6.7.1/gdb/infrun.c
===================================================================
--- gdb-6.7.1.orig/gdb/infrun.c 2007-11-02 15:21:46.000000000 +0100
+++ gdb-6.7.1/gdb/infrun.c 2007-11-02 15:21:57.000000000 +0100
@@ -1781,9 +1781,19 @@ handle_inferior_event (struct execution_
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 (&current_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;
}
@@ -1794,6 +1804,8 @@ handle_inferior_event (struct execution_
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
@@ -1801,15 +1813,12 @@ handle_inferior_event (struct execution_
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 (&current_target, &addr);
+ mark_triggered_watchpoints (addr);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
@@ -1880,6 +1889,41 @@ handle_inferior_event (struct execution_
}
}
+ 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,
@@ -1932,6 +1976,8 @@ handle_inferior_event (struct execution_
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-6.7.1/gdb/breakpoint.c
===================================================================
--- gdb-6.7.1.orig/gdb/breakpoint.c 2007-11-02 15:21:45.000000000 +0100
+++ gdb-6.7.1/gdb/breakpoint.c 2007-11-02 15:23:04.000000000 +0100
@@ -813,6 +813,90 @@ insert_catchpoint (struct ui_out *uo, vo
}
}
+/* External function to insert all existing watchpoints on a newly
+ attached thread. IWPFN is a callback function to perform
+ the target insert watchpoint. This function is used to support
+ platforms where a watchpoint must be inserted/removed on each
+ individual thread (e.g. ia64-linux and s390-linux). For
+ ia64 and s390 linux, this function is called via a new thread
+ observer. */
+int
+insert_watchpoints_for_new_thread (ptid_t new_thread,
+ insert_watchpoint_ftype *iwpfn)
+{
+ struct bp_location *b;
+ int val = 0;
+ int return_val = 0;
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_error_stream);
+
+ /* Explicitly mark the warning -- this will only be printed if
+ there was an error. */
+ fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+ ALL_BP_LOCATIONS (b)
+ {
+ /* Skip disabled breakpoints. */
+ if (!breakpoint_enabled (b->owner))
+ continue;
+
+ /* For every active watchpoint, we need to insert the watchpoint on
+ the new thread. */
+ if (b->loc_type == bp_loc_hardware_watchpoint)
+ {
+ struct value *v = b->owner->val_chain;
+
+ /* Look at each value on the value chain. */
+ for (; v; v = v->next)
+ {
+ /* If it's a memory location, and GDB actually needed
+ its contents to evaluate the expression, then we
+ must watch it. */
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
+ {
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ /* We only watch structs and arrays if user asked
+ for it explicitly, never if they just happen to
+ appear in the middle of some value chain. */
+ if (v == b->owner->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR addr;
+ int len, type;
+
+ addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ len = TYPE_LENGTH (VALUE_TYPE (v));
+ type = hw_write;
+ if (b->owner->type == bp_read_watchpoint)
+ type = hw_read;
+ else if (b->owner->type == bp_access_watchpoint)
+ type = hw_access;
+ val = (*iwpfn) (new_thread, addr, len, type);
+ }
+ }
+ }
+ }
+
+ if (val)
+ return_val = val;
+ }
+
+ /* Failure to insert a watchpoint on any memory value in the
+ value chain brings us here. */
+ if (return_val)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "%s\n",
+ "Could not insert hardware watchpoints on new thread.");
+ target_terminal_ours_for_output ();
+ error_stream (tmp_error_stream);
+ }
+ return return_val;
+}
+
/* Helper routine: free the value chain for a breakpoint (watchpoint). */
static void
@@ -1301,6 +1385,7 @@ remove_breakpoints (void)
{
struct bp_location *b;
int val;
+ int return_val = 0;
ALL_BP_LOCATIONS (b)
{
@@ -1308,10 +1393,10 @@ remove_breakpoints (void)
{
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
- return val;
+ return_val = val;
}
}
- return 0;
+ return return_val;
}
int
@@ -2200,8 +2285,13 @@ print_it_typical (bpstat bs)
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;
@@ -2654,6 +2744,54 @@ which its expression is valid.\n");
}
}
+/* Check watchpoints for a match with a stopped data address.
+
+ STOPPED_DATA_ADDRESS is the address of a triggered watchpoint.
+ A match with an existing watchpoint will cause that watchpoint
+ to be marked as triggered.
+
+ This function is only used for platforms where a watchpoint
+ triggers prior to the data being accessed. */
+
+void
+mark_triggered_watchpoints (CORE_ADDR stopped_data_address)
+{
+ struct breakpoint *b, *temp;
+ CORE_ADDR addr = stopped_data_address;
+ struct value *v;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ {
+ for (v = b->val_chain; v; v = v->next)
+ {
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
+ {
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ if (v == b->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR vaddr;
+
+ vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (addr >= vaddr &&
+ addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
+ b->watchpoint_triggered = 1;
+ }
+ }
+ }
+ }
+ }
+}
+
/* Get a bpstat associated with having just stopped at address
BP_ADDR in thread PTID. STOPPED_BY_WATCHPOINT is 1 if the
target thinks we stopped due to a hardware watchpoint, 0 if we
@@ -2787,82 +2925,61 @@ 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;
+ int must_check_value = 0;
- if (!target_stopped_data_address (&current_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 (&current_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 (&current_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 = v->next)
+ {
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
{
- 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)))
- found = 1;
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ if (v == b->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR vaddr;
+
+ vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (addr >= vaddr &&
+ addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
+ must_check_value = 1;
+ }
}
}
}
- if (found)
+ if (must_check_value)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
@@ -2891,6 +3008,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
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:
@@ -2906,7 +3032,7 @@ 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
@@ -4292,6 +4418,7 @@ set_raw_breakpoint_without_location (enu
b->exec_pathname = NULL;
b->ops = NULL;
b->condition_not_parsed = 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-6.7.1/gdb/breakpoint.h
===================================================================
--- gdb-6.7.1.orig/gdb/breakpoint.h 2007-11-02 15:21:45.000000000 +0100
+++ gdb-6.7.1/gdb/breakpoint.h 2007-11-02 15:22:24.000000000 +0100
@@ -439,6 +439,11 @@ struct breakpoint
no location initially so had no context to parse
the condition in. */
int condition_not_parsed;
+
+ /* Has a watchpoint been triggered? This is only used for
+ non-continuable watchpoints which trigger prior to the data
+ being modified. */
+ int watchpoint_triggered;
};
/* The following stuff is an abstract data type "bpstat" ("breakpoint
@@ -707,6 +712,14 @@ extern void tbreak_command (char *, int)
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-6.7.1/gdb/linux-nat.c
===================================================================
--- gdb-6.7.1.orig/gdb/linux-nat.c 2007-11-02 15:21:46.000000000 +0100
+++ gdb-6.7.1/gdb/linux-nat.c 2007-11-02 15:21:57.000000000 +0100
@@ -34,6 +34,7 @@
#include "gdbthread.h"
#include "gdbcmd.h"
#include "regcache.h"
+#include "observer.h"
#include "regset.h"
#include "inf-ptrace.h"
#include "auxv.h"
@@ -704,6 +705,9 @@ delete_lwp (ptid_t ptid)
else
lwp_list = lp->next;
+ if (lp->saved_trap_data)
+ xfree (lp->saved_trap_data);
+
xfree (lp);
}
@@ -1501,6 +1505,13 @@ stop_wait_callback (struct lwp_info *lp,
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);
@@ -2061,6 +2072,14 @@ retry:
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-6.7.1/gdb/linux-nat.h
===================================================================
--- gdb-6.7.1.orig/gdb/linux-nat.h 2007-11-02 15:21:46.000000000 +0100
+++ gdb-6.7.1/gdb/linux-nat.h 2007-11-02 15:21:57.000000000 +0100
@@ -61,6 +61,18 @@ struct lwp_info
/* 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-6.7.1/gdb/Makefile.in
===================================================================
--- gdb-6.7.1.orig/gdb/Makefile.in 2007-09-05 02:14:02.000000000 +0200
+++ gdb-6.7.1/gdb/Makefile.in 2007-11-02 15:21:57.000000000 +0100
@@ -2160,7 +2160,7 @@ i387-tdep.o: i387-tdep.c $(defs_h) $(dou
$(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)
@@ -2541,7 +2541,7 @@ rs6000-tdep.o: rs6000-tdep.c $(defs_h) $
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) $(linux_nat_h) $(observer_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-6.7.1/gdb/linux-thread-db.c
===================================================================
--- gdb-6.7.1.orig/gdb/linux-thread-db.c 2007-08-23 20:08:35.000000000 +0200
+++ gdb-6.7.1/gdb/linux-thread-db.c 2007-11-02 15:21:57.000000000 +0100
@@ -34,6 +34,7 @@
#include "target.h"
#include "regcache.h"
#include "solib-svr4.h"
+#include "observer.h"
#include "gdbcore.h"
#include "observer.h"
#include "linux-nat.h"
@@ -673,6 +674,7 @@ attach_thread (ptid_t ptid, const td_thr
{
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
@@ -700,8 +702,10 @@ attach_thread (ptid_t ptid, const td_thr
if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
return; /* A zombie thread -- do not attach. */
+ new_ptid = BUILD_LWP (ti_p->ti_lid, GET_PID (ptid));
+
/* Under GNU/Linux, we have to attach to each and every thread. */
- if (lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0) < 0)
+ if (lin_lwp_attach_lwp (new_ptid, 0) < 0)
return;
/* Add the thread to GDB's thread list. */
@@ -712,6 +716,11 @@ attach_thread (ptid_t ptid, const td_thr
if (verbose)
printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
+ /* Notify any observers of a new linux thread. This
+ would include any linux platforms that have to insert hardware
+ watchpoints on every thread. */
+ observer_notify_linux_new_thread (new_ptid);
+
/* Enable thread event reporting for this thread. */
err = td_thr_event_enable_p (th_p, 1);
if (err != TD_OK)
@@ -891,7 +900,8 @@ thread_db_wait (ptid_t ptid, struct targ
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-6.7.1/gdb/i386-linux-nat.c
===================================================================
--- gdb-6.7.1.orig/gdb/i386-linux-nat.c 2007-08-23 20:08:34.000000000 +0200
+++ gdb-6.7.1/gdb/i386-linux-nat.c 2007-11-02 15:21:57.000000000 +0100
@@ -585,10 +585,9 @@ i386_linux_dr_get (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 (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
@@ -613,10 +612,9 @@ i386_linux_dr_set (int regnum, unsigned
{
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-6.7.1/gdb/ia64-linux-nat.c
===================================================================
--- gdb-6.7.1.orig/gdb/ia64-linux-nat.c 2007-08-23 20:08:35.000000000 +0200
+++ gdb-6.7.1/gdb/ia64-linux-nat.c 2007-11-02 15:21:57.000000000 +0100
@@ -27,6 +27,7 @@
#include "regcache.h"
#include "ia64-tdep.h"
#include "linux-nat.h"
+#include "observer.h"
#include <signal.h>
#include <sys/ptrace.h>
@@ -550,10 +551,10 @@ is_power_of_2 (int val)
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;
@@ -598,10 +599,39 @@ ia64_linux_insert_watchpoint (CORE_ADDR
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. */
+static 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, int type)
{
- ptid_t ptid = inferior_ptid;
int idx;
long dbr_addr, dbr_mask;
int max_watchpoints = 4;
@@ -623,13 +653,55 @@ ia64_linux_remove_watchpoint (CORE_ADDR
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. */
+static int
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len)
+{
+ struct linux_watchpoint args;
+
+ args.addr = addr;
+ args.len = len;
+
+ /* For ia64, watchpoints must be inserted/removed on each thread so
+ we iterate over the lwp list. */
+ if (iterate_over_lwps (&ia64_linux_remove_watchpoint_callback, &args))
+ return -1;
+
+ return 0;
+}
+
+/* Callback to find lwp_info struct for a given lwp. */
+static int
+find_lwp_info (struct lwp_info *lp, void *data)
+{
+ int lwp = *(int *)data;
+
+ if (lwp == TIDGET (lp->ptid))
+ return 1;
+
+ 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);
@@ -637,10 +709,19 @@ ia64_linux_stopped_data_address (struct
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);
@@ -648,7 +729,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;
}
@@ -796,6 +877,31 @@ ia64_linux_xfer_partial (struct target_o
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_ARG3_TYPE) 0,
+ lp->saved_trap_data);
+}
+
void _initialize_ia64_linux_nat (void);
void
@@ -834,4 +940,7 @@ _initialize_ia64_linux_nat (void)
/* 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-6.7.1/gdb/amd64-linux-nat.c
===================================================================
--- gdb-6.7.1.orig/gdb/amd64-linux-nat.c 2007-08-23 20:08:26.000000000 +0200
+++ gdb-6.7.1/gdb/amd64-linux-nat.c 2007-11-02 15:21:57.000000000 +0100
@@ -240,10 +240,9 @@ amd64_linux_dr_get (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 (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
@@ -268,10 +267,9 @@ amd64_linux_dr_set (int regnum, unsigned
{
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-6.7.1/gdb/s390-nat.c
===================================================================
--- gdb-6.7.1.orig/gdb/s390-nat.c 2007-08-23 20:08:37.000000000 +0200
+++ gdb-6.7.1/gdb/s390-nat.c 2007-11-02 15:21:57.000000000 +0100
@@ -27,6 +27,7 @@
#include "linux-nat.h"
#include "s390-tdep.h"
+#include "observer.h"
#include <asm/ptrace.h>
#include <sys/ptrace.h>
@@ -111,14 +112,14 @@ fill_fpregset (const struct regcache *re
(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;
}
@@ -202,7 +203,7 @@ store_fpregs (const struct regcache *reg
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))
@@ -218,7 +219,7 @@ s390_linux_fetch_inferior_registers (str
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))
@@ -260,7 +261,7 @@ s390_stopped_by_watchpoint (void)
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
@@ -268,9 +269,9 @@ s390_stopped_by_watchpoint (void)
}
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;
@@ -307,6 +308,16 @@ s390_fix_watch_points (void)
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)
{
@@ -320,10 +331,24 @@ s390_insert_watchpoint (CORE_ADDR addr,
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)
{
@@ -345,7 +370,11 @@ s390_remove_watchpoint (CORE_ADDR addr,
*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;
}
@@ -361,6 +390,15 @@ s390_region_ok_for_hw_watchpoint (CORE_A
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);
@@ -386,4 +424,6 @@ _initialize_s390_nat (void)
/* Register the target. */
linux_nat_add_target (t);
+
+ observer_attach_linux_new_thread (s390_linux_new_thread);
}