Index: i386-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v retrieving revision 1.55 diff -u -p -r1.55 i386-linux-nat.c --- i386-linux-nat.c 9 Apr 2004 16:31:01 -0000 1.55 +++ i386-linux-nat.c 11 Jun 2004 20:55:28 -0000 @@ -649,10 +649,11 @@ 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); + /* The debug status register is thread-specific and so we should + use the current lwp when fetching the debug registers. */ + tid = target_get_lwp (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the ptrace call fails breaks debugging remote targets. The correct Index: i386-nat.c =================================================================== RCS file: /cvs/src/src/gdb/i386-nat.c,v retrieving revision 1.8 diff -u -p -r1.8 i386-nat.c --- i386-nat.c 5 Mar 2004 20:58:00 -0000 1.8 +++ i386-nat.c 11 Jun 2004 20:55:28 -0000 @@ -166,7 +166,10 @@ #define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) /* Mirror the inferior's DRi registers. We keep the status and - control registers separated because they don't hold addresses. */ + control registers separated because they don't hold addresses. + + Note that the DR_STATUS register is thread-specific and the + mirror value should be refreshed as necessary. */ static CORE_ADDR dr_mirror[DR_NADDR]; static unsigned dr_status_mirror, dr_control_mirror; @@ -567,13 +570,22 @@ i386_region_ok_for_watchpoint (CORE_ADDR /* If the inferior has some watchpoint that triggered, return the address associated with that watchpoint. Otherwise, return zero. */ +extern ptid_t trap_ptid; +extern ptid_t inferior_ptid; + CORE_ADDR i386_stopped_data_address (void) { CORE_ADDR addr = 0; int i; + ptid_t saved_ptid = inferior_ptid; + /* Debug status register is thread-specific. A watchpoint will + cause a trap to occur. Switch to trap ptid to get relevant + status for that thread. */ + inferior_ptid = trap_ptid; dr_status_mirror = I386_DR_LOW_GET_STATUS (); + inferior_ptid = saved_ptid; ALL_DEBUG_REGISTERS(i) { @@ -603,8 +615,16 @@ int i386_stopped_by_hwbp (void) { int i; + ptid_t saved_ptid = inferior_ptid; + + /* Debug status register is thread-specific. A hardware breakpoint + will cause a trap to occur. Switch to trap ptid to get relevant + status for that thread. */ + inferior_ptid = trap_ptid; dr_status_mirror = I386_DR_LOW_GET_STATUS (); + inferior_ptid = saved_ptid; + if (maint_show_dr) i386_show_dr ("stopped_by_hwbp", 0, 0, hw_execute); Index: lin-lwp.c =================================================================== RCS file: /cvs/src/src/gdb/lin-lwp.c,v retrieving revision 1.55 diff -u -p -r1.55 lin-lwp.c --- lin-lwp.c 25 May 2004 14:58:28 -0000 1.55 +++ lin-lwp.c 11 Jun 2004 20:55:28 -0000 @@ -1200,21 +1200,29 @@ child_wait (ptid_t ptid, struct target_w } /* Handle GNU/Linux's extended waitstatus for trace events. */ - if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP - && status >> 16 != 0) + if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) { - linux_handle_extended_wait (pid, status, ourstatus); + /* Set trap_ptid like lin_lwp_wait does. This is needed + for watchpoint support. For example, the x86 linux + watchpoints need to know what thread an event occurred + on so as to read the correct thread-specific status. */ + trap_ptid = pid_to_ptid (pid); - /* If we see a clone event, detach the child, and don't - report the event. It would be nice to offer some way to - switch into a non-thread-db based threaded mode at this - point. */ - if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS) + if (status >> 16 != 0) { - ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0); - ourstatus->kind = TARGET_WAITKIND_IGNORE; - pid = -1; - save_errno = EINTR; + linux_handle_extended_wait (pid, status, ourstatus); + + /* If we see a clone event, detach the child, and don't + report the event. It would be nice to offer some way to + switch into a non-thread-db based threaded mode at this + point. */ + if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS) + { + ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0); + ourstatus->kind = TARGET_WAITKIND_IGNORE; + pid = -1; + save_errno = EINTR; + } } } Index: target.c =================================================================== RCS file: /cvs/src/src/gdb/target.c,v retrieving revision 1.75 diff -u -p -r1.75 target.c --- target.c 9 Jun 2004 20:09:42 -0000 1.75 +++ target.c 11 Jun 2004 20:55:28 -0000 @@ -422,6 +422,7 @@ update_current_target (void) INHERIT (to_notice_signals, t); INHERIT (to_thread_alive, t); INHERIT (to_find_new_threads, t); + INHERIT (to_get_lwp, t); INHERIT (to_pid_to_str, t); INHERIT (to_extra_thread_info, t); INHERIT (to_stop, t); @@ -601,6 +602,9 @@ update_current_target (void) de_fault (to_find_new_threads, (void (*) (void)) target_ignore); + de_fault (to_get_lwp, + (long (*) (ptid_t)) + ptid_get_lwp); de_fault (to_extra_thread_info, (char *(*) (struct thread_info *)) return_zero); @@ -1616,6 +1620,7 @@ init_dummy_target (void) dummy_target.to_find_memory_regions = dummy_find_memory_regions; dummy_target.to_make_corefile_notes = dummy_make_corefile_notes; dummy_target.to_xfer_partial = default_xfer_partial; + dummy_target.to_get_lwp = ptid_get_lwp; dummy_target.to_magic = OPS_MAGIC; } Index: target.h =================================================================== RCS file: /cvs/src/src/gdb/target.h,v retrieving revision 1.60 diff -u -p -r1.60 target.h --- target.h 7 Jun 2004 17:58:32 -0000 1.60 +++ target.h 11 Jun 2004 20:55:29 -0000 @@ -370,6 +370,7 @@ struct target_ops void (*to_notice_signals) (ptid_t ptid); int (*to_thread_alive) (ptid_t ptid); void (*to_find_new_threads) (void); + long (*to_get_lwp) (ptid_t ptid); char *(*to_pid_to_str) (ptid_t); char *(*to_extra_thread_info) (struct thread_info *); void (*to_stop) (void); @@ -815,6 +816,10 @@ extern void target_load (char *arg, int #define target_find_new_threads() \ (*current_target.to_find_new_threads) (); \ +/* Get the lwp for a thread. */ +#define target_get_lwp(ptid) \ + (*current_target.to_get_lwp) (ptid); \ + /* Make target stop in a continuable fashion. (For instance, under Unix, this should act like SIGSTOP). This function is normally used by GUIs to implement a stop button. */ Index: thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/thread-db.c,v retrieving revision 1.42 diff -u -p -r1.42 thread-db.c --- thread-db.c 7 Jun 2004 22:35:55 -0000 1.42 +++ thread-db.c 11 Jun 2004 20:55:29 -0000 @@ -408,6 +408,22 @@ lwp_from_thread (ptid_t ptid) } +static long +thread_db_get_lwp (ptid_t ptid) +{ + if (!is_thread (ptid)) + return ptid.pid; + else + { + struct thread_info *thread_info = find_thread_pid (ptid); + if (!thread_info) + return 0; + + thread_db_get_info (thread_info); + return thread_info->private->ti.ti_lid; + } +} + void thread_db_init (struct target_ops *target) { @@ -1382,6 +1398,7 @@ init_thread_db_ops (void) thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior; thread_db_ops.to_thread_alive = thread_db_thread_alive; thread_db_ops.to_find_new_threads = thread_db_find_new_threads; + thread_db_ops.to_get_lwp = thread_db_get_lwp; thread_db_ops.to_pid_to_str = thread_db_pid_to_str; thread_db_ops.to_stratum = thread_stratum; thread_db_ops.to_has_thread_control = tc_schedlock;