gdb/gdb-6.3-threaded-watchpoints-20041213.patch
2004-12-13 21:48:04 +00:00

2160 lines
70 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: Add latest vfork fixes.
(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.
* 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: Add debug statement support.
(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.
k
* 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.
--- gdb-6.3/gdb/doc/observer.texi.fix Mon Dec 13 15:01:35 2004
+++ gdb-6.3/gdb/doc/observer.texi Mon Dec 13 16:07:04 2004
@@ -95,3 +95,14 @@ inferior, and before any information on
The specified shared library has been discovered to be 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
+
+
--- gdb-6.3/gdb/ia64-linux-nat.c.fix Mon Dec 13 14:59:45 2004
+++ gdb-6.3/gdb/ia64-linux-nat.c Mon Dec 13 15:10:01 2004
@@ -39,6 +39,8 @@
#include <asm/ptrace_offsets.h>
#include <sys/procfs.h>
+#include "observer.h"
+#include "linux-nat.h"
/* Prototypes for supply_gregset etc. */
#include "gregset.h"
@@ -559,8 +561,9 @@ is_power_of_2 (int val)
return onecount <= 1;
}
-int
-ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+/* Internal routine to insert one watchpoint for a specified thread. */
+static int
+ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
{
int idx;
long dbr_addr, dbr_mask;
@@ -606,8 +609,38 @@ ia64_linux_insert_watchpoint (ptid_t pti
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_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_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
+ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+{
+ struct linux_watchpoint args;
+
+ args.addr = addr;
+ args.len = len;
+ args.type = rw;
+
+ /* For ia64, watchpoints must be inserted/removed on each thread so
+ we iterate over the lwp list. */
+ if (iterate_over_lwps (&ia64_linux_insert_watchpoint_callback, &args))
+ return -1;
+
+ return 0;
+}
+
+/* Internal routine to remove one watchpoint for a specified thread. */
+static int
+ia64_linux_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
{
int idx;
long dbr_addr, dbr_mask;
@@ -630,23 +663,74 @@ ia64_linux_remove_watchpoint (ptid_t pti
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 (ptid_t ptid, CORE_ADDR addr, int len)
+{
+ struct linux_watchpoint args;
+
+ args.addr = addr;
+ args.len = len;
+
+ /* For ia64, watchpoints must be inserted/removed on each thread so
+ we iterate over the lwp list. */
+ if (iterate_over_lwps (&ia64_linux_remove_watchpoint_callback, &args))
+ return -1;
+
+ return 0;
+}
+
+/* Callback to find lwp_info struct for a given lwp. */
+static int
+find_lwp_info (struct lwp_info *lp, void *data)
+{
+ int lwp = *(int *)data;
+
+ if (lwp == TIDGET (lp->ptid))
+ return 1;
+
+ return 0;
+}
+
int
ia64_linux_stopped_data_address (CORE_ADDR *addr_p)
{
CORE_ADDR psr;
int tid;
struct siginfo siginfo;
+ struct siginfo *siginfo_p;
ptid_t ptid = inferior_ptid;
+ struct lwp_info *lp;
tid = TIDGET(ptid);
if (tid == 0)
tid = PIDGET (ptid);
errno = 0;
- ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+ /* Check to see if we have already cached the siginfo for this
+ event. */
+ lp = iterate_over_lwps (find_lwp_info, &tid);
+ if (lp && lp->saved_trap_data != NULL)
+ siginfo_p = (struct siginfo *)lp->saved_trap_data;
+ else
+ {
+ siginfo_p = &siginfo;
+ ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, siginfo_p);
+ }
- if (errno != 0 || siginfo.si_signo != SIGTRAP ||
- (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+ if (errno != 0 || siginfo_p->si_signo != SIGTRAP ||
+ (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
return 0;
psr = read_register_pid (IA64_PSR_REGNUM, ptid);
@@ -654,7 +738,7 @@ ia64_linux_stopped_data_address (CORE_AD
for the next instruction */
write_register_pid (IA64_PSR_REGNUM, psr, ptid);
- *addr_p = (CORE_ADDR)siginfo.si_addr;
+ *addr_p = (CORE_ADDR)siginfo_p->si_addr;
return 1;
}
@@ -674,3 +758,36 @@ ia64_linux_xfer_unwind_table (struct tar
{
return syscall (__NR_getunwind, readbuf, 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)
+{
+ observer_attach_linux_new_thread (ia64_linux_new_thread);
+ observer_attach_sigtrap (ia64_linux_save_sigtrap_info);
+}
+
--- gdb-6.3/gdb/s390-nat.c.fix Mon Dec 13 15:00:02 2004
+++ gdb-6.3/gdb/s390-nat.c Mon Dec 13 15:31:42 2004
@@ -27,6 +27,8 @@
#include "inferior.h"
#include "s390-tdep.h"
+#include "linux-nat.h"
+#include "observer.h"
#include <asm/ptrace.h>
#include <sys/ptrace.h>
@@ -112,14 +114,14 @@ fill_fpregset (fpregset_t *regp, int reg
((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;
}
@@ -203,7 +205,7 @@ store_fpregs (int tid, int regnum)
void
fetch_inferior_registers (int regnum)
{
- int tid = s390_inferior_tid ();
+ int tid = s390_tid (inferior_ptid);
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
@@ -219,7 +221,7 @@ fetch_inferior_registers (int regnum)
void
store_inferior_registers (int regnum)
{
- int tid = s390_inferior_tid ();
+ int tid = s390_tid (inferior_ptid);
if (regnum == -1
|| (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
@@ -261,7 +263,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
@@ -269,9 +271,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;
@@ -308,6 +310,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. */
int
s390_insert_watchpoint (CORE_ADDR addr, int len)
{
@@ -321,10 +333,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. */
int
s390_remove_watchpoint (CORE_ADDR addr, int len)
{
@@ -346,7 +372,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;
}
@@ -357,3 +387,17 @@ kernel_u_size (void)
return sizeof (struct user);
}
+/* 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)
+{
+ observer_attach_linux_new_thread (s390_linux_new_thread);
+}
--- gdb-6.3/gdb/Makefile.in.fix Mon Dec 13 15:01:16 2004
+++ gdb-6.3/gdb/Makefile.in Mon Dec 13 15:06:36 2004
@@ -2083,7 +2083,8 @@ ia64-aix-nat.o: ia64-aix-nat.c $(defs_h)
$(objfiles_h) $(gdb_stat_h)
ia64-aix-tdep.o: ia64-aix-tdep.c $(defs_h)
ia64-linux-nat.o: ia64-linux-nat.c $(defs_h) $(gdb_string_h) $(inferior_h) \
- $(target_h) $(gdbcore_h) $(regcache_h) $(gdb_wait_h) $(gregset_h)
+ $(target_h) $(gdbcore_h) $(regcache_h) $(gdb_wait_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)
ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
@@ -2465,7 +2466,7 @@ rs6000-tdep.o: rs6000-tdep.c $(defs_h) $
$(ppc_tdep_h) $(gdb_assert_h) $(dis_asm_h) $(trad_frame_h) \
$(frame_unwind_h) $(frame_base_h)
s390-nat.o: s390-nat.c $(defs_h) $(tm_h) $(regcache_h) $(inferior_h) \
- $(s390_tdep_h)
+ $(s390_tdep_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) \
$(tm_h) $(__bfd_bfd_h) $(floatformat_h) $(regcache_h) \
--- gdb-6.3/gdb/breakpoint.c.fix Mon Dec 13 15:00:09 2004
+++ gdb-6.3/gdb/breakpoint.c Mon Dec 13 15:22:24 2004
@@ -86,11 +86,6 @@ static void watch_command (char *, int);
static int can_use_hardware_watchpoint (struct value *);
-extern void break_at_finish_command (char *, int);
-extern void break_at_finish_at_depth_command (char *, int);
-
-extern void tbreak_at_finish_command (char *, int);
-
static int break_command_1 (char *, int, int, struct breakpoint *);
static void mention (struct breakpoint *);
@@ -181,11 +176,6 @@ static void create_fork_vfork_event_catc
char *cond_string,
enum bptype bp_kind);
-static void break_at_finish_at_depth_command_1 (char *arg,
- int flag, int from_tty);
-
-static void break_at_finish_command_1 (char *arg, int flag, int from_tty);
-
static void stop_command (char *arg, int from_tty);
static void stopin_command (char *arg, int from_tty);
@@ -748,6 +738,90 @@ insert_catchpoint (struct ui_out *uo, vo
return 0;
}
+/* External function to insert all existing watchpoints on a newly
+ attached thread. IWPFN is a callback function to perform
+ the target insert watchpoint. This function is used to support
+ platforms where a watchpoint must be inserted/removed on each
+ individual thread (e.g. ia64-linux and s390-linux). For
+ ia64 and s390 linux, this function is called via a new thread
+ observer. */
+int
+insert_watchpoints_for_new_thread (ptid_t new_thread,
+ insert_watchpoint_ftype *iwpfn)
+{
+ struct bp_location *b;
+ int val = 0;
+ int return_val = 0;
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_error_stream);
+
+ /* Explicitly mark the warning -- this will only be printed if
+ there was an error. */
+ fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+ ALL_BP_LOCATIONS (b)
+ {
+ /* Skip disabled breakpoints. */
+ if (!breakpoint_enabled (b->owner))
+ continue;
+
+ /* For every active watchpoint, we need to insert the watchpoint on
+ the new thread. */
+ if (b->loc_type == bp_loc_hardware_watchpoint)
+ {
+ struct value *v = b->owner->val_chain;
+
+ /* Look at each value on the value chain. */
+ for (; v; v = v->next)
+ {
+ /* If it's a memory location, and GDB actually needed
+ its contents to evaluate the expression, then we
+ must watch it. */
+ if (VALUE_LVAL (v) == lval_memory
+ && ! VALUE_LAZY (v))
+ {
+ struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+ /* We only watch structs and arrays if user asked
+ for it explicitly, never if they just happen to
+ appear in the middle of some value chain. */
+ if (v == b->owner->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR addr;
+ int len, type;
+
+ addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+ len = TYPE_LENGTH (VALUE_TYPE (v));
+ type = hw_write;
+ if (b->owner->type == bp_read_watchpoint)
+ type = hw_read;
+ else if (b->owner->type == bp_access_watchpoint)
+ type = hw_access;
+ val = (*iwpfn) (new_thread, addr, len, type);
+ }
+ }
+ }
+ }
+
+ if (val)
+ return_val = val;
+ }
+
+ /* Failure to insert a watchpoint on any memory value in the
+ value chain brings us here. */
+ if (return_val)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "%s\n",
+ "Could not insert hardware watchpoints on new thread.");
+ target_terminal_ours_for_output ();
+ error_stream (tmp_error_stream);
+ }
+ return return_val;
+}
+
/* Helper routine: free the value chain for a breakpoint (watchpoint). */
static void free_valchain (struct bp_location *b)
@@ -1179,6 +1253,7 @@ remove_breakpoints (void)
{
struct bp_location *b;
int val;
+ int return_val = 0;
ALL_BP_LOCATIONS (b)
{
@@ -1186,10 +1261,10 @@ remove_breakpoints (void)
{
val = remove_breakpoint (b, mark_uninserted);
if (val != 0)
- return val;
+ return_val = val;
}
}
- return 0;
+ return return_val;
}
int
@@ -2123,8 +2198,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;
@@ -2561,6 +2641,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
@@ -2691,82 +2819,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 = v->next)
+ 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);
@@ -2795,6 +2902,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:
@@ -2810,7 +2926,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
@@ -4092,6 +4208,7 @@ set_raw_breakpoint (struct symtab_and_li
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
@@ -5450,169 +5567,6 @@ gdb_breakpoint (char *address, char *con
}
-static void
-break_at_finish_at_depth_command_1 (char *arg, int flag, int from_tty)
-{
- struct frame_info *frame;
- CORE_ADDR low, high, selected_pc = 0;
- char *extra_args = NULL;
- char *level_arg;
- int extra_args_len = 0, if_arg = 0;
-
- if (!arg ||
- (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
- {
-
- if (default_breakpoint_valid)
- {
- if (deprecated_selected_frame)
- {
- selected_pc = get_frame_pc (deprecated_selected_frame);
- if (arg)
- if_arg = 1;
- }
- else
- error ("No selected frame.");
- }
- else
- error ("No default breakpoint address now.");
- }
- else
- {
- extra_args = strchr (arg, ' ');
- if (extra_args)
- {
- extra_args++;
- extra_args_len = strlen (extra_args);
- level_arg = (char *) xmalloc (extra_args - arg);
- strncpy (level_arg, arg, extra_args - arg - 1);
- level_arg[extra_args - arg - 1] = '\0';
- }
- else
- {
- level_arg = (char *) xmalloc (strlen (arg) + 1);
- strcpy (level_arg, arg);
- }
-
- frame = parse_frame_specification (level_arg);
- if (frame)
- selected_pc = get_frame_pc (frame);
- else
- selected_pc = 0;
- }
- if (if_arg)
- {
- extra_args = arg;
- extra_args_len = strlen (arg);
- }
-
- if (selected_pc)
- {
- if (find_pc_partial_function (selected_pc, (char **) NULL, &low, &high))
- {
- char *addr_string;
- if (extra_args_len)
- addr_string = xstrprintf ("*0x%s %s", paddr_nz (high), extra_args);
- else
- addr_string = xstrprintf ("*0x%s", paddr_nz (high));
- break_command_1 (addr_string, flag, from_tty, NULL);
- xfree (addr_string);
- }
- else
- error ("No function contains the specified address");
- }
- else
- error ("Unable to set breakpoint at procedure exit");
-}
-
-
-static void
-break_at_finish_command_1 (char *arg, int flag, int from_tty)
-{
- char *addr_string, *break_string, *beg_addr_string;
- CORE_ADDR low, high;
- struct symtabs_and_lines sals;
- struct symtab_and_line sal;
- struct cleanup *old_chain;
- char *extra_args = NULL;
- int extra_args_len = 0;
- int i, if_arg = 0;
-
- if (!arg ||
- (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
- {
- if (default_breakpoint_valid)
- {
- if (deprecated_selected_frame)
- {
- addr_string = xstrprintf ("*0x%s",
- paddr_nz (get_frame_pc (deprecated_selected_frame)));
- if (arg)
- if_arg = 1;
- }
- else
- error ("No selected frame.");
- }
- else
- error ("No default breakpoint address now.");
- }
- else
- {
- addr_string = (char *) xmalloc (strlen (arg) + 1);
- strcpy (addr_string, arg);
- }
-
- if (if_arg)
- {
- extra_args = arg;
- extra_args_len = strlen (arg);
- }
- else if (arg)
- {
- /* get the stuff after the function name or address */
- extra_args = strchr (arg, ' ');
- if (extra_args)
- {
- extra_args++;
- extra_args_len = strlen (extra_args);
- }
- }
-
- sals.sals = NULL;
- sals.nelts = 0;
-
- beg_addr_string = addr_string;
- sals = decode_line_1 (&addr_string, 1, (struct symtab *) NULL, 0,
- (char ***) NULL, NULL);
-
- xfree (beg_addr_string);
- old_chain = make_cleanup (xfree, sals.sals);
- for (i = 0; (i < sals.nelts); i++)
- {
- sal = sals.sals[i];
- if (find_pc_partial_function (sal.pc, (char **) NULL, &low, &high))
- {
- break_string;
- if (extra_args_len)
- break_string = xstrprintf ("*0x%s %s", paddr_nz (high),
- extra_args);
- else
- break_string = xstrprintf ("*0x%s", paddr_nz (high));
- break_command_1 (break_string, flag, from_tty, NULL);
- xfree (break_string);
- }
- else
- error ("No function contains the specified address");
- }
- if (sals.nelts > 1)
- {
- warning ("Multiple breakpoints were set.\n");
- warning ("Use the \"delete\" command to delete unwanted breakpoints.");
- }
- do_cleanups (old_chain);
-}
-
-
/* Helper function for break_command_1 and disassemble_command. */
void
@@ -5669,29 +5623,11 @@ break_command (char *arg, int from_tty)
}
void
-break_at_finish_command (char *arg, int from_tty)
-{
- break_at_finish_command_1 (arg, 0, from_tty);
-}
-
-void
-break_at_finish_at_depth_command (char *arg, int from_tty)
-{
- break_at_finish_at_depth_command_1 (arg, 0, from_tty);
-}
-
-void
tbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_TEMPFLAG, from_tty, NULL);
}
-void
-tbreak_at_finish_command (char *arg, int from_tty)
-{
- break_at_finish_command_1 (arg, BP_TEMPFLAG, from_tty);
-}
-
static void
hbreak_command (char *arg, int from_tty)
{
--- gdb-6.3/gdb/amd64-linux-nat.c.fix Mon Dec 13 15:01:58 2004
+++ gdb-6.3/gdb/amd64-linux-nat.c Mon Dec 13 15:10:16 2004
@@ -233,10 +233,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
@@ -261,10 +260,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);
--- gdb-6.3/gdb/breakpoint.h.fix Mon Dec 13 15:02:25 2004
+++ gdb-6.3/gdb/breakpoint.h Mon Dec 13 15:10:24 2004
@@ -397,6 +397,11 @@ struct breakpoint
/* Is breakpoint pending on shlib loads? */
int pending;
+
+ /* Has a watchpoint been triggered? This is only used for
+ non-continuable watchpoints which trigger prior to the data
+ being modified. */
+ int watchpoint_triggered;
};
/* The following stuff is an abstract data type "bpstat" ("breakpoint
@@ -663,6 +668,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
--- gdb-6.3/gdb/i386-linux-nat.c.fix Mon Dec 13 15:02:52 2004
+++ gdb-6.3/gdb/i386-linux-nat.c Mon Dec 13 15:10:06 2004
@@ -617,10 +617,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
@@ -645,10 +644,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,
--- gdb-6.3/gdb/infrun.c.fix Mon Dec 13 15:03:13 2004
+++ gdb-6.3/gdb/infrun.c Mon Dec 13 15:10:27 2004
@@ -106,6 +106,8 @@ static ptid_t previous_inferior_ptid;
static int may_follow_exec = MAY_FOLLOW_EXEC;
+static int debug_infrun = 0;
+
/* If the program uses ELF-style shared libraries, then calls to
functions in shared libraries go through stubs, which live in a
table called the PLT (Procedure Linkage Table). The first time the
@@ -161,16 +163,6 @@ static int may_follow_exec = MAY_FOLLOW_
#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0
#endif
-/* On some systems, the PC may be left pointing at an instruction that won't
- actually be executed. This is usually indicated by a bit in the PSW. If
- we find ourselves in such a state, then we step the target beyond the
- nullified instruction before returning control to the user so as to avoid
- confusion. */
-
-#ifndef INSTRUCTION_NULLIFIED
-#define INSTRUCTION_NULLIFIED 0
-#endif
-
/* We can't step off a permanent breakpoint in the ordinary way, because we
can't remove it. Instead, we have to advance the PC to the next
instruction. This macro should expand to a pointer to a function that
@@ -517,6 +509,9 @@ resume (int step, enum target_signal sig
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
QUIT;
+ if (debug_infrun)
+ printf_unfiltered ("infrun: resume (step=%d, signal=%d)\n", step, sig);
+
/* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
@@ -714,24 +709,17 @@ proceed (CORE_ADDR addr, enum target_sig
if (addr == (CORE_ADDR) -1)
{
- /* If there is a breakpoint at the address we will resume at,
- step one instruction before inserting breakpoints
- so that we do not stop right away (and report a second
- hit at this breakpoint). */
-
if (read_pc () == stop_pc && breakpoint_here_p (read_pc ()))
+ /* There is a breakpoint at the address we will resume at,
+ step one instruction before inserting breakpoints so that
+ we do not stop right away (and report a second hit at this
+ breakpoint). */
oneproc = 1;
-
-#ifndef STEP_SKIPS_DELAY
-#define STEP_SKIPS_DELAY(pc) (0)
-#define STEP_SKIPS_DELAY_P (0)
-#endif
- /* Check breakpoint_here_p first, because breakpoint_here_p is fast
- (it just checks internal GDB data structures) and STEP_SKIPS_DELAY
- is slow (it needs to read memory from the target). */
- if (STEP_SKIPS_DELAY_P
- && breakpoint_here_p (read_pc () + 4)
- && STEP_SKIPS_DELAY (read_pc ()))
+ else if (gdbarch_single_step_through_delay_p (current_gdbarch)
+ && gdbarch_single_step_through_delay (current_gdbarch,
+ get_current_frame ()))
+ /* We stepped onto an instruction that needs to be stepped
+ again before re-inserting the breakpoint, do so. */
oneproc = 1;
}
else
@@ -739,6 +727,10 @@ proceed (CORE_ADDR addr, enum target_sig
write_pc (addr);
}
+ if (debug_infrun)
+ printf_unfiltered ("infrun: proceed (addr=0x%s, signal=%d, step=%d)\n",
+ paddr_nz (addr), siggnal, step);
+
/* In a multi-threaded task we may select another thread
and then continue or step.
@@ -878,7 +870,6 @@ enum infwait_states
{
infwait_normal_state,
infwait_thread_hop_state,
- infwait_nullified_state,
infwait_nonstep_watch_state
};
@@ -957,6 +948,9 @@ wait_for_inferior (void)
struct execution_control_state ecss;
struct execution_control_state *ecs;
+ if (debug_infrun)
+ printf_unfiltered ("infrun: wait_for_inferior\n");
+
old_cleanups = make_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
@@ -1241,6 +1235,8 @@ handle_inferior_event (struct execution_
switch (ecs->infwait_state)
{
case infwait_thread_hop_state:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: infwait_thread_hop_state\n");
/* Cancel the waiton_ptid. */
ecs->waiton_ptid = pid_to_ptid (-1);
/* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event
@@ -1254,6 +1250,8 @@ handle_inferior_event (struct execution_
break;
case infwait_normal_state:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: infwait_normal_state\n");
/* See comments where a TARGET_WAITKIND_SYSCALL_RETURN event
is serviced in this loop, below. */
if (ecs->enable_hw_watchpoints_after_wait)
@@ -1264,11 +1262,9 @@ handle_inferior_event (struct execution_
stepped_after_stopped_by_watchpoint = 0;
break;
- case infwait_nullified_state:
- stepped_after_stopped_by_watchpoint = 0;
- break;
-
case infwait_nonstep_watch_state:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: infwait_nonstep_watch_state\n");
insert_breakpoints ();
/* FIXME-maybe: is this cleaner than setting a flag? Does it
@@ -1303,6 +1299,8 @@ handle_inferior_event (struct execution_
switch (ecs->ws.kind)
{
case TARGET_WAITKIND_LOADED:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_LOADED\n");
/* Ignore gracefully during startup of the inferior, as it
might be the shell which has just loaded some objects,
otherwise add the symbols for the newly loaded objects. */
@@ -1347,11 +1345,15 @@ handle_inferior_event (struct execution_
return;
case TARGET_WAITKIND_SPURIOUS:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_SPURIOUS\n");
resume (0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
case TARGET_WAITKIND_EXITED:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_EXITED\n");
target_terminal_ours (); /* Must do this before mourn anyway */
print_stop_reason (EXITED, ecs->ws.value.integer);
@@ -1368,6 +1370,8 @@ handle_inferior_event (struct execution_
return;
case TARGET_WAITKIND_SIGNALLED:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_SIGNALLED\n");
stop_print_frame = 0;
stop_signal = ecs->ws.value.sig;
target_terminal_ours (); /* Must do this before mourn anyway */
@@ -1388,6 +1392,8 @@ handle_inferior_event (struct execution_
the above cases end in a continue or goto. */
case TARGET_WAITKIND_FORKED:
case TARGET_WAITKIND_VFORKED:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_FORKED\n");
stop_signal = TARGET_SIGNAL_TRAP;
pending_follow.kind = ecs->ws.kind;
@@ -1410,6 +1416,8 @@ handle_inferior_event (struct execution_
goto process_event_stop_test;
case TARGET_WAITKIND_EXECD:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_EXECED\n");
stop_signal = TARGET_SIGNAL_TRAP;
/* NOTE drow/2002-12-05: This code should be pushed down into the
@@ -1477,6 +1485,8 @@ handle_inferior_event (struct execution_
Also, be careful not to try to gather much state about a thread
that's in a syscall. It's frequently a losing proposition. */
case TARGET_WAITKIND_SYSCALL_ENTRY:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
number_of_threads_in_syscalls++;
if (number_of_threads_in_syscalls == 1)
{
@@ -1501,6 +1511,8 @@ handle_inferior_event (struct execution_
here, which will be serviced immediately after the target
is waited on. */
case TARGET_WAITKIND_SYSCALL_RETURN:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
if (number_of_threads_in_syscalls > 0)
@@ -1513,6 +1525,8 @@ handle_inferior_event (struct execution_
return;
case TARGET_WAITKIND_STOPPED:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_STOPPED\n");
stop_signal = ecs->ws.value.sig;
break;
@@ -1526,6 +1540,8 @@ handle_inferior_event (struct execution_
circumstance is any event which the lower level knows will be
reported multiple times without an intervening resume. */
case TARGET_WAITKIND_IGNORE:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: TARGET_WAITKIND_IGNORE\n");
prepare_to_wait (ecs);
return;
}
@@ -1546,6 +1562,9 @@ handle_inferior_event (struct execution_
stop_pc = read_pc_pid (ecs->ptid);
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stop_pc = 0x%s\n", paddr_nz (stop_pc));
+
if (stepping_past_singlestep_breakpoint)
{
gdb_assert (SOFTWARE_SINGLE_STEP_P ()
@@ -1560,6 +1579,8 @@ handle_inferior_event (struct execution_
we could tell, but we can't reliably. */
if (stop_signal == TARGET_SIGNAL_TRAP)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepping_past_singlestep_breakpoint\n");
/* Pull the single step breakpoints out of the target. */
SOFTWARE_SINGLE_STEP (0, 0);
singlestep_breakpoints_inserted_p = 0;
@@ -1616,6 +1637,9 @@ handle_inferior_event (struct execution_
{
int remove_status;
+ if (debug_infrun)
+ printf_unfiltered ("infrun: thread_hop_needed\n");
+
/* Saw a breakpoint, but it was hit by the wrong thread.
Just continue. */
@@ -1681,6 +1705,9 @@ handle_inferior_event (struct execution_
so, then switch to that thread. */
if (!ptid_equal (ecs->ptid, inferior_ptid))
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: context switch\n");
+
context_switch (ecs);
if (deprecated_context_hook)
@@ -1696,33 +1723,24 @@ handle_inferior_event (struct execution_
singlestep_breakpoints_inserted_p = 0;
}
- /* If PC is pointing at a nullified instruction, then step beyond
- it so that the user won't be confused when GDB appears to be ready
- to execute it. */
-
- /* if (INSTRUCTION_NULLIFIED && currently_stepping (ecs)) */
- if (INSTRUCTION_NULLIFIED)
- {
- registers_changed ();
- target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
-
- /* We may have received a signal that we want to pass to
- the inferior; therefore, we must not clobber the waitstatus
- in WS. */
-
- ecs->infwait_state = infwait_nullified_state;
- ecs->waiton_ptid = ecs->ptid;
- ecs->wp = &(ecs->tmpstatus);
- prepare_to_wait (ecs);
- return;
- }
-
/* 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))
{
- resume (1, 0);
+ CORE_ADDR addr = 0;
+
+ if (debug_infrun)
+ printf_unfiltered ("infrun: STOPPED_BY_WATCHPOINT\n");
+
+ 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;
}
@@ -1732,6 +1750,8 @@ handle_inferior_event (struct execution_
register or page protection watchpoint scheme need here? */
if (HAVE_NONSTEPPABLE_WATCHPOINT && 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
@@ -1739,15 +1759,15 @@ 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. */
+
+ if (debug_infrun)
+ printf_unfiltered ("infrun: STOPPED_BY_WATCHPOINT\n");
+
+ target_stopped_data_address (&current_target, &addr);
+ mark_triggered_watchpoints (addr);
remove_breakpoints ();
registers_changed ();
@@ -1781,6 +1801,41 @@ handle_inferior_event (struct execution_
stopped_by_random_signal = 0;
breakpoints_failed = 0;
+ 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)
+ printf_unfiltered ("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,
@@ -1809,6 +1864,8 @@ handle_inferior_event (struct execution_
{
if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stopped\n");
stop_print_frame = 0;
stop_stepping (ecs);
return;
@@ -1818,6 +1875,8 @@ handle_inferior_event (struct execution_
shared libraries hook functions. */
if (stop_soon == STOP_QUIETLY)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: quietly stopped\n");
stop_stepping (ecs);
return;
}
@@ -1837,7 +1896,11 @@ handle_inferior_event (struct execution_
/* Don't even think about breakpoints if just proceeded over a
breakpoint. */
if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected)
- bpstat_clear (&stop_bpstat);
+ {
+ if (debug_infrun)
+ printf_unfiltered ("infrun: trap expected\n");
+ bpstat_clear (&stop_bpstat);
+ }
else
{
/* See if there is a breakpoint at the current PC. */
@@ -1898,6 +1961,9 @@ process_event_stop_test:
/* Signal not for debugging purposes. */
int printed = 0;
+ if (debug_infrun)
+ printf_unfiltered ("infrun: random signal %d\n", stop_signal);
+
stopped_by_random_signal = 1;
if (signal_print[stop_signal])
@@ -1977,6 +2043,8 @@ process_event_stop_test:
/* If we hit the breakpoint at longjmp, disable it for the
duration of this command. Then, install a temporary
breakpoint at the target of the jmp_buf. */
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_SET_LONGJMP_RESUME\n");
disable_longjmp_breakpoint ();
remove_breakpoints ();
breakpoints_inserted = 0;
@@ -2000,6 +2068,8 @@ process_event_stop_test:
case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_CLEAR_LONGJMP_RESUME\n");
remove_breakpoints ();
breakpoints_inserted = 0;
disable_longjmp_breakpoint ();
@@ -2009,6 +2079,8 @@ process_event_stop_test:
/* else fallthrough */
case BPSTAT_WHAT_SINGLE:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_SINGLE\n");
if (breakpoints_inserted)
{
remove_breakpoints ();
@@ -2020,6 +2092,8 @@ process_event_stop_test:
break;
case BPSTAT_WHAT_STOP_NOISY:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_STOP_NOISY\n");
stop_print_frame = 1;
/* We are about to nuke the step_resume_breakpointt via the
@@ -2029,6 +2103,8 @@ process_event_stop_test:
return;
case BPSTAT_WHAT_STOP_SILENT:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_STOP_SILENT\n");
stop_print_frame = 0;
/* We are about to nuke the step_resume_breakpoin via the
@@ -2055,6 +2131,9 @@ process_event_stop_test:
step-resume bp, but it makes no effort to ensure that
the one deleted is the one currently stopped at. MVS */
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_STEP_RESUME\n");
+
if (step_resume_breakpoint == NULL)
{
step_resume_breakpoint =
@@ -2076,6 +2155,8 @@ process_event_stop_test:
break;
case BPSTAT_WHAT_THROUGH_SIGTRAMP:
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_THROUGH_SIGTRAMP\n");
/* If were waiting for a trap, hitting the step_resume_break
doesn't count as getting it. */
if (trap_expected)
@@ -2086,6 +2167,8 @@ process_event_stop_test:
case BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK:
#ifdef SOLIB_ADD
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: BPSTATE_WHAT_CHECK_SHLIBS\n");
/* Remove breakpoints, we eventually want to step over the
shlib event breakpoint, and SOLIB_ADD might adjust
breakpoint addresses via breakpoint_re_set. */
@@ -2198,11 +2281,15 @@ process_event_stop_test:
/* Have we reached our destination? If not, keep going. */
if (SOLIB_IN_DYNAMIC_LINKER (PIDGET (ecs->ptid), stop_pc))
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepping in dynamic linker\n");
ecs->another_trap = 1;
keep_going (ecs);
return;
}
#endif
+ if (debug_infrun)
+ printf_unfiltered ("infrun: step past dynamic linker\n");
/* Else, stop and report the catchpoint(s) whose triggering
caused us to begin stepping. */
ecs->stepping_through_solib_after_catch = 0;
@@ -2216,6 +2303,9 @@ process_event_stop_test:
if (step_resume_breakpoint)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: step-resume breakpoint\n");
+
/* Having a step-resume breakpoint overrides anything
else having to do with stepping commands until
that breakpoint is reached. */
@@ -2225,6 +2315,8 @@ process_event_stop_test:
if (step_range_end == 0)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: no stepping, continue\n");
/* Likewise if we aren't even stepping. */
keep_going (ecs);
return;
@@ -2237,6 +2329,10 @@ process_event_stop_test:
within it! */
if (stop_pc >= step_range_start && stop_pc < step_range_end)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepping inside range [0x%s-0x%s]\n",
+ paddr_nz (step_range_start),
+ paddr_nz (step_range_end));
keep_going (ecs);
return;
}
@@ -2253,6 +2349,9 @@ process_event_stop_test:
CORE_ADDR pc_after_resolver =
gdbarch_skip_solib_resolver (current_gdbarch, stop_pc);
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped into dynsym resolve code\n");
+
if (pc_after_resolver)
{
/* Set up a step-resume breakpoint at the address
@@ -2273,6 +2372,8 @@ process_event_stop_test:
|| step_over_calls == STEP_OVER_ALL)
&& get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped into signal trampoline\n");
/* The inferior, while doing a "step" or "next", has ended up in
a signal trampoline (either by a signal being delivered or by
the signal handler returning). Just single-step until the
@@ -2287,6 +2388,9 @@ process_event_stop_test:
/* It's a subroutine call. */
CORE_ADDR real_stop_pc;
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped into subroutine\n");
+
if ((step_over_calls == STEP_OVER_NONE)
|| ((step_range_end == 1)
&& in_prologue (prev_pc, ecs->stop_func_start)))
@@ -2303,27 +2407,6 @@ process_event_stop_test:
return;
}
-#ifdef DEPRECATED_IGNORE_HELPER_CALL
- /* On MIPS16, a function that returns a floating point value may
- call a library helper function to copy the return value to a
- floating point register. The DEPRECATED_IGNORE_HELPER_CALL
- macro returns non-zero if we should ignore (i.e. step over)
- this function call. */
- /* FIXME: cagney/2004-07-21: These custom ``ignore frame when
- stepping'' function attributes (SIGTRAMP_FRAME,
- DEPRECATED_IGNORE_HELPER_CALL, SKIP_TRAMPOLINE_CODE,
- skip_language_trampoline frame, et.al.) need to be replaced
- with generic attributes bound to the frame's function. */
- if (DEPRECATED_IGNORE_HELPER_CALL (stop_pc))
- {
- /* We're doing a "next", set a breakpoint at callee's return
- address (the address at which the caller will
- resume). */
- insert_step_resume_breakpoint_at_frame (get_prev_frame (get_current_frame ()));
- keep_going (ecs);
- return;
- }
-#endif
if (step_over_calls == STEP_OVER_ALL)
{
/* We're doing a "next", set a breakpoint at callee's return
@@ -2398,6 +2481,9 @@ process_event_stop_test:
/* Determine where this trampoline returns. */
CORE_ADDR real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc);
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped into solib return tramp\n");
+
/* Only proceed through if we know where it's going. */
if (real_stop_pc)
{
@@ -2426,6 +2512,9 @@ process_event_stop_test:
if (step_over_calls == STEP_OVER_UNDEBUGGABLE
&& ecs->stop_func_name == NULL)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped into undebuggable function\n");
+
/* The inferior just stepped into, or returned to, an
undebuggable function (where there is no symbol, not even a
minimal symbol, corresponding to the address where the
@@ -2456,6 +2545,8 @@ process_event_stop_test:
{
/* It is stepi or nexti. We always want to stop stepping after
one instruction. */
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepi/nexti\n");
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
@@ -2470,6 +2561,8 @@ process_event_stop_test:
stepping (does this always happen right after one instruction,
when we do "s" in a function with no line numbers,
or can this happen as a result of a return or longjmp?). */
+ if (debug_infrun)
+ printf_unfiltered ("infrun: no line number info\n");
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
@@ -2484,6 +2577,8 @@ process_event_stop_test:
we don't stop if we step into the middle of a different line.
That is said to make things like for (;;) statements work
better. */
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped to a different line\n");
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
@@ -2504,6 +2599,8 @@ process_event_stop_test:
This is particularly necessary for a one-line function,
in which after skipping the prologue we better stop even though
we will be in mid-line. */
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stepped to a different function\n");
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
@@ -2540,6 +2637,8 @@ process_event_stop_test:
step_frame_id = current_frame;
}
+ if (debug_infrun)
+ printf_unfiltered ("infrun: keep going\n");
keep_going (ecs);
}
@@ -2676,6 +2775,9 @@ insert_step_resume_breakpoint_at_frame (
static void
stop_stepping (struct execution_control_state *ecs)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: stop_stepping\n");
+
/* Let callers know we don't want to wait for the inferior anymore. */
ecs->wait_some_more = 0;
}
@@ -2753,6 +2855,8 @@ keep_going (struct execution_control_sta
static void
prepare_to_wait (struct execution_control_state *ecs)
{
+ if (debug_infrun)
+ printf_unfiltered ("infrun: prepare_to_wait\n");
if (ecs->infwait_state == infwait_normal_state)
{
overlay_cache_invalid = 1;
@@ -3014,7 +3118,7 @@ normal_stop (void)
LOCATION: Print only location
SRC_AND_LOC: Print location and source line */
if (do_frame_printing)
- print_stack_frame (get_selected_frame (), 0, source_flag);
+ print_stack_frame (get_selected_frame (NULL), 0, source_flag);
/* Display the auto-display expressions. */
do_displays ();
@@ -3790,6 +3894,10 @@ Pass and Stop may be combined.", NULL));
This allows you to set a list of commands to be run each time execution\n\
of the program stops.", &cmdlist);
+ add_set_cmd ("infrun", class_maintenance, var_zinteger,
+ &debug_infrun, "Set inferior debugging.\n\
+When non-zero, inferior specific debugging is enabled.", &setdebuglist);
+
numsigs = (int) TARGET_SIGNAL_LAST;
signal_stop = (unsigned char *) xmalloc (sizeof (signal_stop[0]) * numsigs);
signal_print = (unsigned char *)
--- gdb-6.3/gdb/linux-nat.h.fix Mon Dec 13 15:03:36 2004
+++ gdb-6.3/gdb/linux-nat.h Mon Dec 13 15:10:41 2004
@@ -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;
};
/* Read/write to target memory via the Linux kernel's "proc file
--- gdb-6.3/gdb/thread-db.c.fix Mon Dec 13 15:03:48 2004
+++ gdb-6.3/gdb/thread-db.c Mon Dec 13 15:49:44 2004
@@ -34,6 +34,7 @@
#include "target.h"
#include "regcache.h"
#include "solib-svr4.h"
+#include "observer.h"
#ifdef HAVE_GNU_LIBC_VERSION_H
#include <gnu/libc-version.h>
@@ -143,7 +144,6 @@ static void detach_thread (ptid_t ptid,
#define is_thread(ptid) (GET_THREAD (ptid) != 0)
#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
-#define BUILD_THREAD(tid, pid) ptid_build (pid, 0, tid)
/* Use "struct private_thread_info" to cache thread state. This is
@@ -267,7 +267,7 @@ thread_get_info_callback (const td_thrha
thread_db_err_str (err));
/* Fill the cache. */
- thread_ptid = BUILD_THREAD (ti.ti_tid, GET_PID (inferior_ptid));
+ thread_ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, ti.ti_tid);
thread_info = find_thread_pid (thread_ptid);
/* In the case of a zombie thread, don't continue. We don't want to
@@ -385,22 +385,14 @@ thread_from_lwp (ptid_t ptid)
gdb_assert (thread_info && thread_info->private->ti_valid);
- return BUILD_THREAD (thread_info->private->ti.ti_tid, GET_PID (ptid));
+ return ptid_build (GET_PID (ptid), GET_LWP (ptid),
+ thread_info->private->ti.ti_tid);
}
static ptid_t
lwp_from_thread (ptid_t ptid)
{
- struct thread_info *thread_info;
- ptid_t thread_ptid;
-
- if (!is_thread (ptid))
- return ptid;
-
- thread_info = find_thread_pid (ptid);
- thread_db_get_info (thread_info);
-
- return BUILD_LWP (thread_info->private->ti.ti_lid, GET_PID (ptid));
+ return BUILD_LWP (GET_LWP (ptid), GET_PID (ptid));
}
@@ -722,6 +714,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
@@ -757,11 +750,18 @@ 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. */
#ifdef ATTACH_LWP
- ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
+ ATTACH_LWP (new_ptid, 0);
#endif
+ /* Notify any observers of a new linux thread. This
+ would include any linux platforms that have to insert hardware
+ watchpoints on every thread. */
+ observer_notify_linux_new_thread (new_ptid);
+
/* Enable thread event reporting for this thread. */
err = td_thr_event_enable_p (th_p, 1);
if (err != TD_OK)
@@ -887,7 +887,7 @@ check_event (ptid_t ptid)
if (err != TD_OK)
error ("Cannot get thread info: %s", thread_db_err_str (err));
- ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
+ ptid = ptid_build (GET_PID (ptid), ti.ti_lid, ti.ti_tid);
switch (msg.event)
{
@@ -934,7 +934,8 @@ thread_db_wait (ptid_t ptid, struct targ
return pid_to_ptid (-1);
if (ourstatus->kind == TARGET_WAITKIND_STOPPED
- && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
+ && (ourstatus->value.sig == TARGET_SIGNAL_TRAP
+ || ourstatus->value.sig == TARGET_SIGNAL_ILL))
/* Check for a thread event. */
check_event (ptid);
@@ -1159,7 +1160,7 @@ find_new_threads_callback (const td_thrh
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
return 0; /* A zombie -- ignore. */
- ptid = BUILD_THREAD (ti.ti_tid, GET_PID (inferior_ptid));
+ ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, ti.ti_tid);
if (!in_thread_list (ptid))
attach_thread (ptid, th_p, &ti, 1);
--- gdb-6.3/gdb/linux-nat.c.fix Mon Dec 13 15:42:30 2004
+++ gdb-6.3/gdb/linux-nat.c Mon Dec 13 15:43:58 2004
@@ -34,6 +34,7 @@
#include "gdbthread.h"
#include "gdbcmd.h"
#include "regcache.h"
+#include "observer.h"
#include <sys/param.h> /* for MAXPATHLEN */
#include <sys/procfs.h> /* for elf_gregset etc. */
#include "elf-bfd.h" /* for elfcore_write_* */
@@ -69,7 +70,7 @@
#define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4
-#define PTRACE_EVENT_VFORKDONE 5
+#define PTRACE_EVENT_VFORK_DONE 5
#define PTRACE_EVENT_EXIT 6
#endif /* PTRACE_EVENT_FORK */
@@ -147,21 +148,50 @@ linux_tracefork_child (void)
ptrace (PTRACE_TRACEME, 0, 0, 0);
kill (getpid (), SIGSTOP);
fork ();
- exit (0);
+ _exit (0);
}
-/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events. We
+/* Wrapper function for waitpid which handles EINTR. */
+
+static int
+my_waitpid (int pid, int *status, int flags)
+{
+ int ret;
+ do
+ {
+ ret = waitpid (pid, status, flags);
+ }
+ while (ret == -1 && errno == EINTR);
+
+ return ret;
+}
+
+/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.
+
+ First, we try to enable fork tracing on ORIGINAL_PID. If this fails,
+ we know that the feature is not available. This may change the tracing
+ options for ORIGINAL_PID, but we'll be setting them shortly anyway.
+
+ However, if it succeeds, we don't know for sure that the feature is
+ available; old versions of PTRACE_SETOPTIONS ignored unknown options. We
create a child process, attach to it, use PTRACE_SETOPTIONS to enable
- fork tracing, and let it fork. If the process exits, we assume that
- we can't use TRACEFORK; if we get the fork notification, and we can
- extract the new child's PID, then we assume that we can. */
+ fork tracing, and let it fork. If the process exits, we assume that we
+ can't use TRACEFORK; if we get the fork notification, and we can extract
+ the new child's PID, then we assume that we can. */
static void
-linux_test_for_tracefork (void)
+linux_test_for_tracefork (int original_pid)
{
int child_pid, ret, status;
long second_pid;
+ linux_supports_tracefork_flag = 0;
+ linux_supports_tracevforkdone_flag = 0;
+
+ ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACEFORK);
+ if (ret != 0)
+ return;
+
child_pid = fork ();
if (child_pid == -1)
perror_with_name ("linux_test_for_tracefork: fork");
@@ -169,7 +199,7 @@ linux_test_for_tracefork (void)
if (child_pid == 0)
linux_tracefork_child ();
- ret = waitpid (child_pid, &status, 0);
+ ret = my_waitpid (child_pid, &status, 0);
if (ret == -1)
perror_with_name ("linux_test_for_tracefork: waitpid");
else if (ret != child_pid)
@@ -177,13 +207,23 @@ linux_test_for_tracefork (void)
if (! WIFSTOPPED (status))
error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status);
- linux_supports_tracefork_flag = 0;
-
ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
if (ret != 0)
{
- ptrace (PTRACE_KILL, child_pid, 0, 0);
- waitpid (child_pid, &status, 0);
+ ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+ if (ret != 0)
+ {
+ warning ("linux_test_for_tracefork: failed to kill child");
+ return;
+ }
+
+ ret = my_waitpid (child_pid, &status, 0);
+ if (ret != child_pid)
+ warning ("linux_test_for_tracefork: failed to wait for killed child");
+ else if (!WIFSIGNALED (status))
+ warning ("linux_test_for_tracefork: unexpected wait status 0x%x from "
+ "killed child", status);
+
return;
}
@@ -192,8 +232,12 @@ linux_test_for_tracefork (void)
PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
linux_supports_tracevforkdone_flag = (ret == 0);
- ptrace (PTRACE_CONT, child_pid, 0, 0);
- ret = waitpid (child_pid, &status, 0);
+ ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to resume child");
+
+ ret = my_waitpid (child_pid, &status, 0);
+
if (ret == child_pid && WIFSTOPPED (status)
&& status >> 16 == PTRACE_EVENT_FORK)
{
@@ -204,34 +248,38 @@ linux_test_for_tracefork (void)
int second_status;
linux_supports_tracefork_flag = 1;
- waitpid (second_pid, &second_status, 0);
- ptrace (PTRACE_DETACH, second_pid, 0, 0);
+ my_waitpid (second_pid, &second_status, 0);
+ ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to kill second child");
}
}
+ else
+ warning ("linux_test_for_tracefork: unexpected result from waitpid "
+ "(%d, status 0x%x)", ret, status);
- if (WIFSTOPPED (status))
- {
- ptrace (PTRACE_DETACH, child_pid, 0, 0);
- waitpid (child_pid, &status, 0);
- }
+ ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+ if (ret != 0)
+ warning ("linux_test_for_tracefork: failed to kill child");
+ my_waitpid (child_pid, &status, 0);
}
/* Return non-zero iff we have tracefork functionality available.
This function also sets linux_supports_tracefork_flag. */
static int
-linux_supports_tracefork (void)
+linux_supports_tracefork (int pid)
{
if (linux_supports_tracefork_flag == -1)
- linux_test_for_tracefork ();
+ linux_test_for_tracefork (pid);
return linux_supports_tracefork_flag;
}
static int
-linux_supports_tracevforkdone (void)
+linux_supports_tracevforkdone (int pid)
{
if (linux_supports_tracefork_flag == -1)
- linux_test_for_tracefork ();
+ linux_test_for_tracefork (pid);
return linux_supports_tracevforkdone_flag;
}
@@ -242,12 +290,12 @@ linux_enable_event_reporting (ptid_t pti
int pid = ptid_get_pid (ptid);
int options;
- if (! linux_supports_tracefork ())
+ if (! linux_supports_tracefork (pid))
return;
options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
| PTRACE_O_TRACECLONE;
- if (linux_supports_tracevforkdone ())
+ if (linux_supports_tracevforkdone (pid))
options |= PTRACE_O_TRACEVFORKDONE;
/* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
@@ -308,13 +356,14 @@ child_follow_fork (int follow_child)
if (has_vforked)
{
- if (linux_supports_tracevforkdone ())
+ gdb_assert (linux_supports_tracefork_flag >= 0);
+ if (linux_supports_tracevforkdone (0))
{
int status;
ptrace (PTRACE_CONT, parent_pid, 0, 0);
waitpid (parent_pid, &status, __WALL);
- if ((status >> 16) != PTRACE_EVENT_VFORKDONE)
+ if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
warning ("Unexpected waitpid result %06x when waiting for "
"vfork-done", status);
}
@@ -476,7 +525,7 @@ linux_handle_extended_wait (int pid, int
int
child_insert_fork_catchpoint (int pid)
{
- if (! linux_supports_tracefork ())
+ if (! linux_supports_tracefork (pid))
error ("Your system does not support fork catchpoints.");
return 0;
@@ -485,7 +534,7 @@ child_insert_fork_catchpoint (int pid)
int
child_insert_vfork_catchpoint (int pid)
{
- if (!linux_supports_tracefork ())
+ if (!linux_supports_tracefork (pid))
error ("Your system does not support vfork catchpoints.");
return 0;
@@ -494,7 +543,7 @@ child_insert_vfork_catchpoint (int pid)
int
child_insert_exec_catchpoint (int pid)
{
- if (!linux_supports_tracefork ())
+ if (!linux_supports_tracefork (pid))
error ("Your system does not support exec catchpoints.");
return 0;
@@ -1285,6 +1334,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);
@@ -1960,6 +2016,14 @@ retry:
}
}
+ /* 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)
{