* 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.
This commit is contained in:
Daniel Jacobowitz 2007-10-01 00:22:50 +00:00
parent d983da9c3d
commit 9f0bdab802
8 changed files with 391 additions and 193 deletions

View File

@ -1,3 +1,60 @@
2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
* 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 <dan@codesourcery.com>
Jeff Johnston <jjohnstn@redhat.com>

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)
gdb_assert (lp != NULL);
ptid = pid_to_ptid (GET_LWP (lp->ptid));
/* Remember if we're stepping. */
lp->step = step;
/* Mark this LWP as resumed. */
lp->resumed = 1;
/* 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 (lp->status && WIFSTOPPED (lp->status))
{
ptid = pid_to_ptid (GET_LWP (lp->ptid));
int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
/* Remember if we're stepping. */
lp->step = step;
/* Mark this LWP as resumed. */
lp->resumed = 1;
/* 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 (lp->status && WIFSTOPPED (lp->status))
if (signal_stop_state (saved_signo) == 0
&& signal_print_state (saved_signo) == 0
&& signal_pass_state (saved_signo) == 1)
{
int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLR: Not short circuiting for ignored "
"status 0x%x\n", 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 (lp->status)
{
/* FIXME: What should we do if we are supposed to continue
this thread with a signal? */
gdb_assert (signo == TARGET_SIGNAL_0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLR: Short circuiting for status 0x%x\n",
lp->status);
return;
signo = saved_signo;
lp->status = 0;
}
/* Mark LWP as not stopped to prevent it from being continued by
resume_callback. */
lp->stopped = 0;
}
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);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLR: Short circuiting for status 0x%x\n",
lp->status);
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)
{

View File

@ -20,7 +20,11 @@
#include "target.h"
/* Structure describing an LWP. */
#include <signal.h>
/* 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);

View File

@ -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,59 +831,53 @@ 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;
struct lwp_info *lp;
ptid_t ptid;
long dabr_value = 0;
tid = TIDGET (ptid);
if (tid == 0)
tid = PIDGET (ptid);
saved_dabr_value = 0;
ALL_LWPS (lp, ptid)
if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
return -1;
return 0;
}
return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0);
static void
ppc_linux_new_thread (ptid_t ptid)
{
ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value);
}
static int
ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
if (last_stopped_data_address)
{
*addr_p = last_stopped_data_address;
last_stopped_data_address = 0;
return 1;
}
return 0;
struct siginfo *siginfo_p;
siginfo_p = linux_nat_get_siginfo (inferior_ptid);
if (siginfo_p->si_signo != SIGTRAP
|| (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
return 0;
*addr_p = (CORE_ADDR) siginfo_p->si_addr;
return 1;
}
static int
ppc_linux_stopped_by_watchpoint (void)
{
int tid;
struct siginfo siginfo;
ptid_t ptid = inferior_ptid;
CORE_ADDR *addr_p;
tid = TIDGET(ptid);
if (tid == 0)
tid = PIDGET (ptid);
errno = 0;
ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
if (errno != 0 || siginfo.si_signo != SIGTRAP ||
(siginfo.si_code & 0xffff) != 0x0004)
return 0;
last_stopped_data_address = (uintptr_t) siginfo.si_addr;
return 1;
CORE_ADDR addr;
return ppc_linux_stopped_data_address (&current_target, &addr);
}
static void
@ -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);
}

View File

@ -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);
}