From 9f0bdab8028f185719d163f3bfeafd1406ba5a58 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Mon, 1 Oct 2007 00:22:50 +0000 Subject: [PATCH] * linux-nat.c (linux_nat_new_thread): New variable. (linux_child_follow_fork): Set inferior_ptid to include LWP ID. Use linux_nat_switch_fork. (lwp_list): Make public. (add_lwp): Call linux_nat_new_thread. (lin_lwp_attach_lwp, linux_nat_attach): Call add_lwp after stopping the new thread. (resume_callback): Clear lp->siginfo. Remove unused variable. (linux_nat_resume): Assert that the LWP list is already initialized. Clear lp->siginfo. (save_siginfo): New. (stop_wait_callback, linux_nat_wait): Call it. (linux_nat_set_new_thread, linux_nat_get_siginfo): New. * linux-nat.h (struct lwp_info): Add siginfo. (lwp_list, linux_nat_set_new_thread, linux_nat_get_siginfo): Declare. (ALL_LWPS): Define. * amd64-linux-nat.c (amd64_linux_dr): New. (amd64_linux_dr_get): Take a PTID argument. Correct typo. (amd64_linux_dr_set): Take a PTID argument. (amd64_linux_dr_set_control, amd64_linux_dr_set_addr): Use ALL_LWPS. (amd64_linux_dr_reset_addr): Use amd64_linux_dr_set_addr. (amd64_linux_dr_get_status): Pass inferior_ptid to amd64_linux_dr_get. (amd64_linux_new_thread): New. (_initialize_amd64_linux_nat): Call linux_nat_set_new_thread. * i386-linux-nat.c (i386_linux_dr): New. (i386_linux_dr_get, i386_linux_dr_set): Take a PTID argument. (i386_linux_dr_set_control, i386_linux_dr_set_addr): Use ALL_LWPS. (i386_linux_dr_reset_addr): Use i386_linux_dr_set_addr. (i386_linux_dr_get_status): Pass inferior_ptid to i386_linux_dr_get. (i386_linux_new_thread): New. (i386_linux_resume): Remove unnecessary PID check. (_initialize_i386_linux_nat): Call linux_nat_set_new_thread. * ia64-linux-nat.c (enable_watchpoints_in_psr): Take PTID argument. (fetch_debug_register, fetch_debug_register_pair): Delete. (debug_registers): New. (ia64_linux_insert_watchpoint, ia64_linux_remove_watchpoint): Use ALL_LWPS and debug_registers. (ia64_linux_new_thread): New. (ia64_linux_stopped_data_address): Use linux_nat_get_siginfo. (_initialize_ia64_linux_nat): Call linux_nat_set_new_thread. * ppc-linux-nat.c (last_stopped_data_address): Delete. (saved_dabr_value): New. (ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint): Use ALL_LWPS. (ppc_linux_new_thread): New. (ppc_linux_stopped_data_address): Use linux_nat_get_siginfo. (ppc_linux_stopped_by_watchpoint): Call ppc_linux_stopped_data_address. (_initialize_ppc_linux_nat): Call linux_nat_set_new_thread. * s390-nat.c (s390_stopped_by_watchpoint): Clear the watchpoint status after reading it. (s390_fix_watch_points): Take a PTID argument. (s390_insert_watchpoint, s390_remove_watchpoint): Use ALL_LWPS. (_initialize_s390_nat): Call linux_nat_set_new_thread. --- gdb/ChangeLog | 57 ++++++++++++++ gdb/amd64-linux-nat.c | 60 ++++++++++----- gdb/i386-linux-nat.c | 58 ++++++++------ gdb/ia64-linux-nat.c | 90 +++++++++++----------- gdb/linux-nat.c | 170 ++++++++++++++++++++++++++++-------------- gdb/linux-nat.h | 28 ++++++- gdb/ppc-linux-nat.c | 76 +++++++++---------- gdb/s390-nat.c | 35 +++++++-- 8 files changed, 386 insertions(+), 188 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1ecf2e480a..e72f3dada2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,60 @@ +2007-09-30 Daniel Jacobowitz + + * linux-nat.c (linux_nat_new_thread): New variable. + (linux_child_follow_fork): Set inferior_ptid to include LWP ID. Use + linux_nat_switch_fork. + (lwp_list): Make public. + (add_lwp): Call linux_nat_new_thread. + (lin_lwp_attach_lwp, linux_nat_attach): Call add_lwp after stopping + the new thread. + (resume_callback): Clear lp->siginfo. Remove unused variable. + (linux_nat_resume): Assert that the LWP list is already initialized. + Clear lp->siginfo. + (save_siginfo): New. + (stop_wait_callback, linux_nat_wait): Call it. + (linux_nat_set_new_thread, linux_nat_get_siginfo): New. + * linux-nat.h (struct lwp_info): Add siginfo. + (lwp_list, linux_nat_set_new_thread, linux_nat_get_siginfo): Declare. + (ALL_LWPS): Define. + + * amd64-linux-nat.c (amd64_linux_dr): New. + (amd64_linux_dr_get): Take a PTID argument. Correct typo. + (amd64_linux_dr_set): Take a PTID argument. + (amd64_linux_dr_set_control, amd64_linux_dr_set_addr): Use ALL_LWPS. + (amd64_linux_dr_reset_addr): Use amd64_linux_dr_set_addr. + (amd64_linux_dr_get_status): Pass inferior_ptid to amd64_linux_dr_get. + (amd64_linux_new_thread): New. + (_initialize_amd64_linux_nat): Call linux_nat_set_new_thread. + * i386-linux-nat.c (i386_linux_dr): New. + (i386_linux_dr_get, i386_linux_dr_set): Take a PTID argument. + (i386_linux_dr_set_control, i386_linux_dr_set_addr): Use ALL_LWPS. + (i386_linux_dr_reset_addr): Use i386_linux_dr_set_addr. + (i386_linux_dr_get_status): Pass inferior_ptid to i386_linux_dr_get. + (i386_linux_new_thread): New. + (i386_linux_resume): Remove unnecessary PID check. + (_initialize_i386_linux_nat): Call linux_nat_set_new_thread. + * ia64-linux-nat.c (enable_watchpoints_in_psr): Take PTID argument. + (fetch_debug_register, fetch_debug_register_pair): Delete. + (debug_registers): New. + (ia64_linux_insert_watchpoint, ia64_linux_remove_watchpoint): Use + ALL_LWPS and debug_registers. + (ia64_linux_new_thread): New. + (ia64_linux_stopped_data_address): Use linux_nat_get_siginfo. + (_initialize_ia64_linux_nat): Call linux_nat_set_new_thread. + * ppc-linux-nat.c (last_stopped_data_address): Delete. + (saved_dabr_value): New. + (ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint): Use + ALL_LWPS. + (ppc_linux_new_thread): New. + (ppc_linux_stopped_data_address): Use linux_nat_get_siginfo. + (ppc_linux_stopped_by_watchpoint): Call ppc_linux_stopped_data_address. + (_initialize_ppc_linux_nat): Call linux_nat_set_new_thread. + * s390-nat.c (s390_stopped_by_watchpoint): Clear the watchpoint status + after reading it. + (s390_fix_watch_points): Take a PTID argument. + (s390_insert_watchpoint, s390_remove_watchpoint): Use ALL_LWPS. + (_initialize_s390_nat): Call linux_nat_set_new_thread. + 2007-09-30 Daniel Jacobowitz Jeff Johnston diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index 9e9e30f4a9..e7643ac31e 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -233,25 +233,27 @@ amd64_linux_store_inferior_registers (struct regcache *regcache, int regnum) } } +/* Support for debug registers. */ + +static unsigned long amd64_linux_dr[DR_CONTROL + 1]; static unsigned long -amd64_linux_dr_get (int regnum) +amd64_linux_dr_get (ptid_t ptid, int regnum) { int tid; unsigned long value; - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the ptrace call fails breaks debugging remote targets. The correct way to fix this is to add the hardware breakpoint and watchpoint - stuff to the target vectore. For now, just return zero if the + stuff to the target vector. For now, just return zero if the ptrace call fails. */ errno = 0; - value = ptrace (PT_READ_U, tid, + value = ptrace (PTRACE_PEEKUSER, tid, offsetof (struct user, u_debugreg[regnum]), 0); if (errno != 0) #if 0 @@ -264,17 +266,17 @@ amd64_linux_dr_get (int regnum) } static void -amd64_linux_dr_set (int regnum, unsigned long value) +amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) { int tid; - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); errno = 0; - ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value); + ptrace (PTRACE_POKEUSER, tid, + offsetof (struct user, u_debugreg[regnum]), value); if (errno != 0) perror_with_name (_("Couldn't write debug register")); } @@ -282,29 +284,48 @@ amd64_linux_dr_set (int regnum, unsigned long value) void amd64_linux_dr_set_control (unsigned long control) { - amd64_linux_dr_set (DR_CONTROL, control); + struct lwp_info *lp; + ptid_t ptid; + + amd64_linux_dr[DR_CONTROL] = control; + ALL_LWPS (lp, ptid) + amd64_linux_dr_set (ptid, DR_CONTROL, control); } void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr) { + struct lwp_info *lp; + ptid_t ptid; + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr); + amd64_linux_dr[DR_FIRSTADDR + regnum] = addr; + ALL_LWPS (lp, ptid) + amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); } void amd64_linux_dr_reset_addr (int regnum) { - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L); + amd64_linux_dr_set_addr (regnum, 0); } unsigned long amd64_linux_dr_get_status (void) { - return amd64_linux_dr_get (DR_STATUS); + return amd64_linux_dr_get (inferior_ptid, DR_STATUS); +} + +static void +amd64_linux_new_thread (ptid_t ptid) +{ + int i; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]); + + amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]); } @@ -408,4 +429,5 @@ _initialize_amd64_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); + linux_nat_set_new_thread (t, amd64_linux_new_thread); } diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 83484e8a41..2447ecb76a 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -579,16 +579,17 @@ i386_linux_store_inferior_registers (struct regcache *regcache, int regno) /* Support for debug registers. */ +static unsigned long i386_linux_dr[DR_CONTROL + 1]; + static unsigned long -i386_linux_dr_get (int regnum) +i386_linux_dr_get (ptid_t ptid, int regnum) { int tid; unsigned long value; - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the ptrace call fails breaks debugging remote targets. The correct @@ -609,14 +610,13 @@ i386_linux_dr_get (int regnum) } static void -i386_linux_dr_set (int regnum, unsigned long value) +i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) { int tid; - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); errno = 0; ptrace (PTRACE_POKEUSER, tid, @@ -628,29 +628,48 @@ i386_linux_dr_set (int regnum, unsigned long value) void i386_linux_dr_set_control (unsigned long control) { - i386_linux_dr_set (DR_CONTROL, control); + struct lwp_info *lp; + ptid_t ptid; + + i386_linux_dr[DR_CONTROL] = control; + ALL_LWPS (lp, ptid) + i386_linux_dr_set (ptid, DR_CONTROL, control); } void i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) { + struct lwp_info *lp; + ptid_t ptid; + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - i386_linux_dr_set (DR_FIRSTADDR + regnum, addr); + i386_linux_dr[DR_FIRSTADDR + regnum] = addr; + ALL_LWPS (lp, ptid) + i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); } void i386_linux_dr_reset_addr (int regnum) { - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L); + i386_linux_dr_set_addr (regnum, 0); } unsigned long i386_linux_dr_get_status (void) { - return i386_linux_dr_get (DR_STATUS); + return i386_linux_dr_get (inferior_ptid, DR_STATUS); +} + +static void +i386_linux_new_thread (ptid_t ptid) +{ + int i; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + i386_linux_dr_set (ptid, i, i386_linux_dr[i]); + + i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]); } @@ -729,12 +748,6 @@ i386_linux_resume (ptid_t ptid, int step, enum target_signal signal) int request = PTRACE_CONT; - if (pid == -1) - /* Resume all threads. */ - /* I think this only gets used in the non-threaded case, where "resume - all threads" and "resume inferior_ptid" are the same. */ - pid = PIDGET (inferior_ptid); - if (step) { struct regcache *regcache = get_thread_regcache (pid_to_ptid (pid)); @@ -818,4 +831,5 @@ _initialize_i386_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); + linux_nat_set_new_thread (t, i386_linux_new_thread); } diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c index 42555ff72e..fb29d8c837 100644 --- a/gdb/ia64-linux-nat.c +++ b/gdb/ia64-linux-nat.c @@ -479,8 +479,9 @@ fill_fpregset (const struct regcache *regcache, #define IA64_PSR_DD (1UL << 39) static void -enable_watchpoints_in_psr (struct regcache *regcache) +enable_watchpoints_in_psr (ptid_t ptid) { + struct regcache *regcache = get_thread_regcache (ptid); ULONGEST psr; regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); @@ -492,20 +493,7 @@ enable_watchpoints_in_psr (struct regcache *regcache) } } -static long -fetch_debug_register (ptid_t ptid, int idx) -{ - long val; - int tid; - - tid = TIDGET (ptid); - if (tid == 0) - tid = PIDGET (ptid); - - val = ptrace (PT_READ_U, tid, (PTRACE_TYPE_ARG3) (PT_DBR + 8 * idx), 0); - - return val; -} +static long debug_registers[8]; static void store_debug_register (ptid_t ptid, int idx, long val) @@ -519,15 +507,6 @@ store_debug_register (ptid_t ptid, int idx, long val) (void) ptrace (PT_WRITE_U, tid, (PTRACE_TYPE_ARG3) (PT_DBR + 8 * idx), val); } -static void -fetch_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr, long *dbr_mask) -{ - if (dbr_addr) - *dbr_addr = fetch_debug_register (ptid, 2 * idx); - if (dbr_mask) - *dbr_mask = fetch_debug_register (ptid, 2 * idx + 1); -} - static void store_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr, long *dbr_mask) { @@ -553,7 +532,8 @@ is_power_of_2 (int val) static int ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) { - ptid_t ptid = inferior_ptid; + struct lwp_info *lp; + ptid_t ptid; int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; @@ -563,7 +543,7 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) for (idx = 0; idx < max_watchpoints; idx++) { - fetch_debug_register_pair (ptid, idx, NULL, &dbr_mask); + dbr_mask = debug_registers[idx * 2 + 1]; if ((dbr_mask & (0x3UL << 62)) == 0) { /* Exit loop if both r and w bits clear */ @@ -592,8 +572,13 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) return -1; } - store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); - enable_watchpoints_in_psr (get_current_regcache ()); + debug_registers[2 * idx] = dbr_addr; + debug_registers[2 * idx + 1] = dbr_mask; + ALL_LWPS (lp, ptid) + { + store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); + enable_watchpoints_in_psr (ptid); + } return 0; } @@ -601,7 +586,6 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) static int ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) { - ptid_t ptid = inferior_ptid; int idx; long dbr_addr, dbr_mask; int max_watchpoints = 4; @@ -611,36 +595,55 @@ ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type) for (idx = 0; idx < max_watchpoints; idx++) { - fetch_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); + dbr_addr = debug_registers[2 * idx]; + dbr_mask = debug_registers[2 * idx + 1]; if ((dbr_mask & (0x3UL << 62)) && addr == (CORE_ADDR) dbr_addr) { + struct lwp_info *lp; + ptid_t ptid; + + debug_registers[2 * idx] = 0; + debug_registers[2 * idx + 1] = 0; dbr_addr = 0; dbr_mask = 0; - store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); + + ALL_LWPS (lp, ptid) + store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask); + return 0; } } return -1; } +static void +ia64_linux_new_thread (ptid_t ptid) +{ + int i, any; + + any = 0; + for (i = 0; i < 8; i++) + { + if (debug_registers[i] != 0) + any = 1; + store_debug_register (ptid, i, debug_registers[i]); + } + + if (any) + enable_watchpoints_in_psr (ptid); +} + static int ia64_linux_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) { CORE_ADDR psr; - int tid; - struct siginfo siginfo; - ptid_t ptid = inferior_ptid; + struct siginfo *siginfo_p; struct regcache *regcache = get_current_regcache (); - tid = TIDGET(ptid); - if (tid == 0) - tid = PIDGET (ptid); - - errno = 0; - ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo); + siginfo_p = linux_nat_get_siginfo (inferior_ptid); - if (errno != 0 || siginfo.si_signo != SIGTRAP || - (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) + if (siginfo_p->si_signo != SIGTRAP + || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) return 0; regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); @@ -648,7 +651,7 @@ ia64_linux_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) for the next instruction */ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr); - *addr_p = (CORE_ADDR)siginfo.si_addr; + *addr_p = (CORE_ADDR)siginfo_p->si_addr; return 1; } @@ -834,4 +837,5 @@ _initialize_ia64_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); + linux_nat_set_new_thread (t, ia64_linux_new_thread); } diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 90b8a3b845..18c28006b0 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -89,6 +89,9 @@ static struct target_ops *linux_ops; static struct target_ops linux_ops_saved; +/* The method to call, if any, when a new thread is attached. */ +static void (*linux_nat_new_thread) (ptid_t); + /* The saved to_xfer_partial method, inherited from inf-ptrace.c. Called by our to_xfer_partial. */ static LONGEST (*super_xfer_partial) (struct target_ops *, @@ -503,12 +506,13 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child) target_detach (NULL, 0); } - inferior_ptid = pid_to_ptid (child_pid); + inferior_ptid = ptid_build (child_pid, child_pid, 0); /* Reinstall ourselves, since we might have been removed in target_detach (which does other necessary cleanup). */ push_target (ops); + linux_nat_switch_fork (inferior_ptid); /* Reset breakpoints in the child as appropriate. */ follow_inferior_reset_breakpoints (); @@ -573,7 +577,7 @@ linux_child_insert_exec_catchpoint (int pid) because the "zombies" stay around. */ /* List of known LWPs. */ -static struct lwp_info *lwp_list; +struct lwp_info *lwp_list; /* Number of LWPs in the list. */ static int num_lwps; @@ -657,7 +661,8 @@ init_lwp_list (void) } /* Add the LWP specified by PID to the list. Return a pointer to the - structure describing the new LWP. */ + structure describing the new LWP. The LWP should already be stopped + (with an exception for the very first LWP). */ static struct lwp_info * add_lwp (ptid_t ptid) @@ -678,6 +683,9 @@ add_lwp (ptid_t ptid) lwp_list = lp; ++num_lwps; + if (num_lwps > 1 && linux_nat_new_thread != NULL) + linux_nat_new_thread (ptid); + return lp; } @@ -884,6 +892,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose) { pid_t pid; int status; + int cloned = 0; if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) { @@ -897,9 +906,6 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose) return -1; } - if (lp == NULL) - lp = add_lwp (ptid); - if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n", @@ -910,12 +916,16 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose) { /* Try again with __WCLONE to check cloned processes. */ pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE); - lp->cloned = 1; + cloned = 1; } gdb_assert (pid == GET_LWP (ptid) && WIFSTOPPED (status) && WSTOPSIG (status)); + if (lp == NULL) + lp = add_lwp (ptid); + lp->cloned = cloned; + target_post_attach (pid); lp->stopped = 1; @@ -953,15 +963,12 @@ linux_nat_attach (char *args, int from_tty) struct lwp_info *lp; pid_t pid; int status; + int cloned = 0; /* FIXME: We should probably accept a list of process id's, and attach all of them. */ linux_ops->to_attach (args, from_tty); - /* Add the initial process as the first LWP to the list. */ - inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)); - lp = add_lwp (inferior_ptid); - /* Make sure the initial process is stopped. The user-level threads layer might want to poke around in the inferior, and that won't work if things haven't stabilized yet. */ @@ -972,12 +979,17 @@ linux_nat_attach (char *args, int from_tty) /* Try again with __WCLONE to check cloned processes. */ pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE); - lp->cloned = 1; + cloned = 1; } gdb_assert (pid == GET_PID (inferior_ptid) && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP); + /* Add the initial process as the first LWP to the list. */ + inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)); + lp = add_lwp (inferior_ptid); + lp->cloned = cloned; + lp->stopped = 1; /* Fake the SIGSTOP that core GDB expects. */ @@ -1077,8 +1089,6 @@ resume_callback (struct lwp_info *lp, void *data) { if (lp->stopped && lp->status == 0) { - struct thread_info *tp; - linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)), 0, TARGET_SIGNAL_0); if (debug_linux_nat) @@ -1087,6 +1097,7 @@ resume_callback (struct lwp_info *lp, void *data) target_pid_to_str (lp->ptid)); lp->stopped = 0; lp->step = 0; + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); } return 0; @@ -1136,68 +1147,69 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo) ptid = inferior_ptid; lp = find_lwp_pid (ptid); - if (lp) - { - ptid = pid_to_ptid (GET_LWP (lp->ptid)); + gdb_assert (lp != NULL); - /* Remember if we're stepping. */ - lp->step = step; + ptid = pid_to_ptid (GET_LWP (lp->ptid)); - /* Mark this LWP as resumed. */ - lp->resumed = 1; + /* Remember if we're stepping. */ + lp->step = step; - /* If we have a pending wait status for this thread, there is no - point in resuming the process. But first make sure that - linux_nat_wait won't preemptively handle the event - we - should never take this short-circuit if we are going to - leave LP running, since we have skipped resuming all the - other threads. This bit of code needs to be synchronized - with linux_nat_wait. */ + /* Mark this LWP as resumed. */ + lp->resumed = 1; - if (lp->status && WIFSTOPPED (lp->status)) - { - int saved_signo = target_signal_from_host (WSTOPSIG (lp->status)); + /* If we have a pending wait status for this thread, there is no + point in resuming the process. But first make sure that + linux_nat_wait won't preemptively handle the event - we + should never take this short-circuit if we are going to + leave LP running, since we have skipped resuming all the + other threads. This bit of code needs to be synchronized + with linux_nat_wait. */ - if (signal_stop_state (saved_signo) == 0 - && signal_print_state (saved_signo) == 0 - && signal_pass_state (saved_signo) == 1) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLR: Not short circuiting for ignored " - "status 0x%x\n", lp->status); - - /* FIXME: What should we do if we are supposed to continue - this thread with a signal? */ - gdb_assert (signo == TARGET_SIGNAL_0); - signo = saved_signo; - lp->status = 0; - } - } + if (lp->status && WIFSTOPPED (lp->status)) + { + int saved_signo = target_signal_from_host (WSTOPSIG (lp->status)); - if (lp->status) + if (signal_stop_state (saved_signo) == 0 + && signal_print_state (saved_signo) == 0 + && signal_pass_state (saved_signo) == 1) { + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLR: Not short circuiting for ignored " + "status 0x%x\n", lp->status); + /* FIXME: What should we do if we are supposed to continue this thread with a signal? */ gdb_assert (signo == TARGET_SIGNAL_0); + signo = saved_signo; + lp->status = 0; + } + } - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLR: Short circuiting for status 0x%x\n", - lp->status); + if (lp->status) + { + /* FIXME: What should we do if we are supposed to continue + this thread with a signal? */ + gdb_assert (signo == TARGET_SIGNAL_0); - return; - } + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLR: Short circuiting for status 0x%x\n", + lp->status); - /* Mark LWP as not stopped to prevent it from being continued by - resume_callback. */ - lp->stopped = 0; + return; } + /* Mark LWP as not stopped to prevent it from being continued by + resume_callback. */ + lp->stopped = 0; + if (resume_all) iterate_over_lwps (resume_callback, NULL); linux_ops->to_resume (ptid, step, signo); + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLR: %s %s, %s (resume event thread)\n", @@ -1416,6 +1428,22 @@ wait_lwp (struct lwp_info *lp) return status; } +/* Save the most recent siginfo for LP. This is currently only called + for SIGTRAP; some ports use the si_addr field for + target_stopped_data_address. In the future, it may also be used to + restore the siginfo of requeued signals. */ + +static void +save_siginfo (struct lwp_info *lp) +{ + errno = 0; + ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid), + (PTRACE_TYPE_ARG3) 0, &lp->siginfo); + + if (errno != 0) + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); +} + /* Send a SIGSTOP to LP. */ static int @@ -1501,6 +1529,9 @@ stop_wait_callback (struct lwp_info *lp, void *data) user will delete or disable the breakpoint, but the thread will have already tripped on it. */ + /* Save the trap's siginfo in case we need it later. */ + save_siginfo (lp); + /* Now resume this LWP and get the SIGSTOP event. */ errno = 0; ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); @@ -2058,6 +2089,10 @@ retry: target_pid_to_str (lp->ptid)); } + /* Save the trap's siginfo in case we need it later. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) + save_siginfo (lp); + /* Handle GNU/Linux's extended waitstatus for trace events. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) { @@ -3250,6 +3285,27 @@ linux_nat_add_target (struct target_ops *t) thread_db_init (t); } +/* Register a method to call whenever a new thread is attached. */ +void +linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t)) +{ + /* Save the pointer. We only support a single registered instance + of the GNU/Linux native target, so we do not need to map this to + T. */ + linux_nat_new_thread = new_thread; +} + +/* Return the saved siginfo associated with PTID. */ +struct siginfo * +linux_nat_get_siginfo (ptid_t ptid) +{ + struct lwp_info *lp = find_lwp_pid (ptid); + + gdb_assert (lp != NULL); + + return &lp->siginfo; +} + void _initialize_linux_nat (void) { diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index 82cf51b9bf..43686cf9af 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -20,7 +20,11 @@ #include "target.h" -/* Structure describing an LWP. */ +#include + +/* Structure describing an LWP. This is public only for the purposes + of ALL_LWPS; target-specific code should generally not access it + directly. */ struct lwp_info { @@ -54,6 +58,10 @@ struct lwp_info /* Non-zero if we were stepping this LWP. */ int step; + /* Non-zero si_signo if this LWP stopped with a trap. si_addr may + be the address of a hardware watchpoint. */ + struct siginfo siginfo; + /* If WAITSTATUS->KIND != TARGET_WAITKIND_SPURIOUS, the waitstatus for this LWP's last event. This may correspond to STATUS above, or to a local variable in lin_lwp_wait. */ @@ -63,6 +71,18 @@ struct lwp_info struct lwp_info *next; }; +/* The global list of LWPs, for ALL_LWPS. Unlike the threads list, + there is always at least one LWP on the list while the GNU/Linux + native target is active. */ +extern struct lwp_info *lwp_list; + +/* Iterate over the PTID each active thread (light-weight process). There + must be at least one. */ +#define ALL_LWPS(LP, PTID) \ + for ((LP) = lwp_list, (PTID) = (LP)->ptid; \ + (LP) != NULL; \ + (LP) = (LP)->next, (PTID) = (LP) ? (LP)->ptid : (PTID)) + /* Attempt to initialize libthread_db. */ void check_for_thread_db (void); @@ -95,6 +115,12 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int)); instead of calling add_target directly. */ void linux_nat_add_target (struct target_ops *); +/* Register a method to call whenever a new thread is attached. */ +void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t)); + /* Update linux-nat internal state when changing from one fork to another. */ void linux_nat_switch_fork (ptid_t new_ptid); + +/* Return the saved siginfo associated with PTID. */ +struct siginfo *linux_nat_get_siginfo (ptid_t ptid); diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index f0b2abb3e7..ec061b0668 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -142,8 +142,6 @@ struct gdb_evrregset_t error. */ int have_ptrace_getvrregs = 1; -static CORE_ADDR last_stopped_data_address = 0; - /* Non-zero if our kernel may support the PTRACE_GETEVRREGS and PTRACE_SETEVRREGS requests, for reading and writing the SPE registers. Zero if we've tried one of them and gotten an @@ -805,13 +803,16 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) return 1; } +/* The cached DABR value, to install in new threads. */ +static long saved_dabr_value; + /* Set a watchpoint of type TYPE at address ADDR. */ static int ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) { - int tid; + struct lwp_info *lp; + ptid_t ptid; long dabr_value; - ptid_t ptid = inferior_ptid; dabr_value = addr & ~7; switch (rw) @@ -830,61 +831,55 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw) break; } - tid = TIDGET (ptid); - if (tid == 0) - tid = PIDGET (ptid); - - return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value); + ALL_LWPS (lp, ptid) + if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0) + return -1; + saved_dabr_value = dabr_value; + return 0; } static int ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw) { - int tid; - ptid_t ptid = inferior_ptid; - - tid = TIDGET (ptid); - if (tid == 0) - tid = PIDGET (ptid); - - return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0); + struct lwp_info *lp; + ptid_t ptid; + long dabr_value = 0; + + saved_dabr_value = 0; + ALL_LWPS (lp, ptid) + if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0) + return -1; + return 0; } -static int -ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) +static void +ppc_linux_new_thread (ptid_t ptid) { - if (last_stopped_data_address) - { - *addr_p = last_stopped_data_address; - last_stopped_data_address = 0; - return 1; - } - return 0; + ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value); } static int -ppc_linux_stopped_by_watchpoint (void) +ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p) { - int tid; - struct siginfo siginfo; - ptid_t ptid = inferior_ptid; - CORE_ADDR *addr_p; + struct siginfo *siginfo_p; - tid = TIDGET(ptid); - if (tid == 0) - tid = PIDGET (ptid); + siginfo_p = linux_nat_get_siginfo (inferior_ptid); - errno = 0; - ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo); - - if (errno != 0 || siginfo.si_signo != SIGTRAP || - (siginfo.si_code & 0xffff) != 0x0004) + if (siginfo_p->si_signo != SIGTRAP + || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) return 0; - last_stopped_data_address = (uintptr_t) siginfo.si_addr; + *addr_p = (CORE_ADDR) siginfo_p->si_addr; return 1; } +static int +ppc_linux_stopped_by_watchpoint (void) +{ + CORE_ADDR addr; + return ppc_linux_stopped_data_address (¤t_target, &addr); +} + static void ppc_linux_store_inferior_registers (struct regcache *regcache, int regno) { @@ -969,4 +964,5 @@ _initialize_ppc_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); + linux_nat_set_new_thread (t, ppc_linux_new_thread); } diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c index 4c84fcfd18..6fe6939bca 100644 --- a/gdb/s390-nat.c +++ b/gdb/s390-nat.c @@ -252,6 +252,7 @@ s390_stopped_by_watchpoint (void) { per_lowcore_bits per_lowcore; ptrace_area parea; + int result; /* Speed up common case. */ if (!watch_base) @@ -263,14 +264,24 @@ s390_stopped_by_watchpoint (void) if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0) perror_with_name (_("Couldn't retrieve watchpoint status")); - return per_lowcore.perc_storage_alteration == 1 - && per_lowcore.perc_store_real_address == 0; + result = (per_lowcore.perc_storage_alteration == 1 + && per_lowcore.perc_store_real_address == 0); + + if (result) + { + /* Do not report this watchpoint again. */ + memset (&per_lowcore, 0, sizeof (per_lowcore)); + if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0) + perror_with_name (_("Couldn't clear watchpoint status")); + } + + return result; } static void -s390_fix_watch_points (void) +s390_fix_watch_points (ptid_t ptid) { - int tid = s390_inferior_tid (); + int tid; per_struct per_info; ptrace_area parea; @@ -278,6 +289,10 @@ s390_fix_watch_points (void) CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; struct watch_area *area; + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); + for (area = watch_base; area; area = area->next) { watch_lo_addr = min (watch_lo_addr, area->lo_addr); @@ -310,7 +325,10 @@ s390_fix_watch_points (void) static int s390_insert_watchpoint (CORE_ADDR addr, int len, int type) { + struct lwp_info *lp; + ptid_t ptid; struct watch_area *area = xmalloc (sizeof (struct watch_area)); + if (!area) return -1; @@ -320,13 +338,16 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type) area->next = watch_base; watch_base = area; - s390_fix_watch_points (); + ALL_LWPS (lp, ptid) + s390_fix_watch_points (ptid); return 0; } static int s390_remove_watchpoint (CORE_ADDR addr, int len, int type) { + struct lwp_info *lp; + ptid_t ptid; struct watch_area *area, **parea; for (parea = &watch_base; *parea; parea = &(*parea)->next) @@ -345,7 +366,8 @@ s390_remove_watchpoint (CORE_ADDR addr, int len, int type) *parea = area->next; xfree (area); - s390_fix_watch_points (); + ALL_LWPS (lp, ptid) + s390_fix_watch_points (ptid); return 0; } @@ -386,4 +408,5 @@ _initialize_s390_nat (void) /* Register the target. */ linux_nat_add_target (t); + linux_nat_set_new_thread (t, s390_fix_watch_points); } -- 2.34.1