2004-12-13 Jeff Johnston * linux-nat.c: (stop_wait_callback, linux-nat-wait): Notify observers of a sigtrap. (delete_lwp): Free the saved_trap_data if present. * linux-nat.h (struct lwp_info): Add saved_trap_data field. (struct linux_watchpoint): New struct. * linux-thread-db.c: Add support to always keep lwp info in ptids. (attach_thread): Notify observers of a linux new thread. (thread_db_wait): Call check_event if SIGILL occurs. * infrun.c: (handle_inferior_event): For platforms that hit watchpoints prior to the data write, mark the watchpoints so we know to check them after we step through the write. * breakpoint.c (bpstat_stop_status): Fix up watchpoint code. (insert_watchpoints_for_new_thread): New function. (mark_triggered_watchpoints): Ditto. * breakpoint.h (insert_watchpoints_for_new_thread): New prototype. (mark_triggered_watchpoints): Ditto. * i386-linux-nat.c (i386_linux_dr_get, i386_linux_dr_set): Use TIDGET to get PTRACE lpw, otherwise fall back to PIDGET. * amd64-linux-nat.c (amd64_linux_dr_get, amd64_linux_dr_set): Ditto. * ia64-linux-nat.c: Add support for removing and inserting watchpoints on all threads. * s390-nat.c: Ditto. * Makefile.in: Add observer.h and linux-nat.h to ia64-linux-nat.o and s390-nat.o. * doc/observer.texi: Add two new observers for linux_new_thread and sigtrap. Index: gdb-6.5/gdb/doc/observer.texi =================================================================== --- gdb-6.5.orig/gdb/doc/observer.texi 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/doc/observer.texi 2006-07-11 15:00:15.000000000 -0300 @@ -122,3 +122,13 @@ haven't been loaded yet. @deftypefun void solib_unloaded (struct so_list *@var{solib}) The shared library specified by @var{solib} has been unloaded. @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.5/gdb/infrun.c =================================================================== --- gdb-6.5.orig/gdb/infrun.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/infrun.c 2006-07-11 15:00:17.000000000 -0300 @@ -1703,9 +1703,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 (¤t_target, &addr); + mark_triggered_watchpoints (addr); + registers_changed (); + target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */ + + ecs->waiton_ptid = ecs->ptid; + ecs->wp = &(ecs->ws); + ecs->infwait_state = infwait_nonstep_watch_state; prepare_to_wait (ecs); return; } @@ -1715,6 +1725,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 @@ -1722,15 +1734,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 (¤t_target, &addr); + mark_triggered_watchpoints (addr); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); @@ -1801,6 +1810,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, @@ -1852,6 +1896,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.5/gdb/breakpoint.c =================================================================== --- gdb-6.5.orig/gdb/breakpoint.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/breakpoint.c 2006-07-11 15:00:19.000000000 -0300 @@ -748,6 +748,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 free_valchain (struct bp_location *b) @@ -1190,6 +1274,7 @@ remove_breakpoints (void) { struct bp_location *b; int val; + int return_val = 0; ALL_BP_LOCATIONS (b) { @@ -1197,10 +1282,10 @@ remove_breakpoints (void) { val = remove_breakpoint (b, mark_uninserted); if (val != 0) - return val; + return_val = val; } } - return 0; + return return_val; } int @@ -2126,8 +2211,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; @@ -2567,6 +2657,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 @@ -2697,82 +2835,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 (¤t_target, &addr)) - continue; - for (v = b->val_chain; v; v = value_next (v)) + if (b->type == bp_watchpoint + || b->watchpoint_triggered + || (b->type == bp_hardware_watchpoint + && !target_stopped_data_address_p (¤t_target))) { - if (VALUE_LVAL (v) == lval_memory - && ! value_lazy (v)) + /* We either have a software watchpoint, a triggered watchpoint + which we have stepped over, or we cannot ascertain what data + address causes a write watchpoint. In all these + cases, we must check the watchpoint value. */ + b->watchpoint_triggered = 0; + must_check_value = 1; + } + else + { + /* At this point, we know target_stopped_data_address () works or + we have a read or access watchpoint and have no alternatives. */ + if (!target_stopped_data_address (¤t_target, &addr)) { - struct type *vtype = check_typedef (value_type (v)); - - if (v == b->val_chain - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) + bs->print_it = print_it_noop; + bs->stop = 0; + continue; + } + for (v = b->val_chain; v; v = 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); @@ -2801,6 +2918,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: @@ -2816,7 +2942,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 @@ -4112,6 +4238,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 Index: gdb-6.5/gdb/breakpoint.h =================================================================== --- gdb-6.5.orig/gdb/breakpoint.h 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/breakpoint.h 2006-07-11 15:00:17.000000000 -0300 @@ -426,6 +426,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 @@ -692,6 +697,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.5/gdb/linux-nat.c =================================================================== --- gdb-6.5.orig/gdb/linux-nat.c 2006-07-11 12:32:29.000000000 -0300 +++ gdb-6.5/gdb/linux-nat.c 2006-07-11 15:00:15.000000000 -0300 @@ -36,6 +36,7 @@ #include "gdbthread.h" #include "gdbcmd.h" #include "regcache.h" +#include "observer.h" #include "regset.h" #include "inf-ptrace.h" #include "auxv.h" @@ -764,6 +765,9 @@ delete_lwp (ptid_t ptid) else lwp_list = lp->next; + if (lp->saved_trap_data) + xfree (lp->saved_trap_data); + xfree (lp); } @@ -1478,6 +1482,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); @@ -2054,6 +2065,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.5/gdb/linux-nat.h =================================================================== --- gdb-6.5.orig/gdb/linux-nat.h 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/linux-nat.h 2006-07-11 12:32:29.000000000 -0300 @@ -63,6 +63,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.5/gdb/Makefile.in =================================================================== --- gdb-6.5.orig/gdb/Makefile.in 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/Makefile.in 2006-07-11 15:00:19.000000000 -0300 @@ -2113,7 +2113,7 @@ i387-tdep.o: i387-tdep.c $(defs_h) $(dou $(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h) 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) ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ @@ -2518,7 +2518,7 @@ rs6000-tdep.o: rs6000-tdep.c $(defs_h) $ $(frame_unwind_h) $(frame_base_h) $(rs6000_tdep_h) rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(osabi_h) $(rs6000_tdep_h) s390-nat.o: s390-nat.c $(defs_h) $(tm_h) $(regcache_h) $(inferior_h) \ - $(s390_tdep_h) $(target_h) $(linux_nat_h) + $(s390_tdep_h) $(target_h) $(observer_h) $(linux_nat_h) s390-tdep.o: s390-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) $(inferior_h) \ $(symtab_h) $(target_h) $(gdbcore_h) $(gdbcmd_h) $(objfiles_h) \ $(floatformat_h) $(regcache_h) $(trad_frame_h) $(frame_base_h) \ Index: gdb-6.5/gdb/linux-thread-db.c =================================================================== --- gdb-6.5.orig/gdb/linux-thread-db.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/linux-thread-db.c 2006-07-11 15:00:18.000000000 -0300 @@ -36,6 +36,7 @@ #include "target.h" #include "regcache.h" #include "solib-svr4.h" +#include "observer.h" #include "gdbcore.h" #include "linux-nat.h" @@ -718,6 +719,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 @@ -753,11 +755,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) @@ -946,7 +955,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); Index: gdb-6.5/gdb/i386-linux-nat.c =================================================================== --- gdb-6.5.orig/gdb/i386-linux-nat.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/i386-linux-nat.c 2006-07-11 15:00:09.000000000 -0300 @@ -619,10 +619,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 @@ -647,10 +646,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.5/gdb/ia64-linux-nat.c =================================================================== --- gdb-6.5.orig/gdb/ia64-linux-nat.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/ia64-linux-nat.c 2006-07-11 15:00:00.000000000 -0300 @@ -29,6 +29,7 @@ #include "regcache.h" #include "ia64-tdep.h" #include "linux-nat.h" +#include "observer.h" #include #include @@ -561,8 +562,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; @@ -608,8 +610,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; @@ -632,23 +664,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); @@ -656,7 +739,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; } @@ -685,6 +768,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 @@ -701,4 +809,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.5/gdb/amd64-linux-nat.c =================================================================== --- gdb-6.5.orig/gdb/amd64-linux-nat.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/amd64-linux-nat.c 2006-07-11 15:00:09.000000000 -0300 @@ -234,10 +234,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 @@ -262,10 +261,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.5/gdb/s390-nat.c =================================================================== --- gdb-6.5.orig/gdb/s390-nat.c 2006-07-11 12:30:23.000000000 -0300 +++ gdb-6.5/gdb/s390-nat.c 2006-07-11 15:00:26.000000000 -0300 @@ -30,6 +30,7 @@ #include "linux-nat.h" #include "s390-tdep.h" +#include "observer.h" #include #include @@ -114,14 +115,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; } @@ -205,7 +206,7 @@ store_fpregs (int tid, int regnum) static void s390_linux_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)) @@ -221,7 +222,7 @@ s390_linux_fetch_inferior_registers (int static void s390_linux_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)) @@ -263,7 +264,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 @@ -271,9 +272,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; @@ -310,6 +311,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) { @@ -323,10 +334,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) { @@ -348,7 +373,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; } @@ -364,6 +393,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); @@ -389,4 +427,6 @@ _initialize_s390_nat (void) /* Register the target. */ linux_nat_add_target (t); + + observer_attach_linux_new_thread (s390_linux_new_thread); }