* 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:
parent
d983da9c3d
commit
9f0bdab802
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
180
gdb/linux-nat.c
180
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)
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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 (¤t_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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user