/* Low level interface for debugging AIX 4.3+ pthreads.
- Copyright (C) 1999, 2000, 2002, 2007, 2008, 2009
+ Copyright (C) 1999, 2000, 2002, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Written by Nick Duffek <nsd@redhat.com>.
#include <sched.h>
#include <sys/pthdebug.h>
+#if !HAVE_DECL_GETTHRDS
+extern int getthrds (pid_t, struct thrdsinfo64 *, int, pthdb_tid_t *, int);
+#endif
+
/* Whether to emit debugging output. */
static int debug_aix_thread;
static struct target_ops aix_thread_ops;
-/* Copy of the target over which ops is pushed. This is more
- convenient than a pointer to deprecated_child_ops or core_ops,
- because they lack current_target's default callbacks. */
-
-static struct target_ops base_target;
-
/* Address of the function that libpthread will call when libpthdebug
is ready to be initialized. */
}
/* Write register function should be able to write requested context
- information to specified debuggee's kernel thread id.
+ information to specified debuggee's kernel thread id.
If successful return 0, else non-zero is returned. */
static int
return p1->pthid < p2->pthid ? -1 : p1->pthid > p2->pthid;
}
-/* iterate_over_threads() callback for counting GDB threads. */
+/* iterate_over_threads() callback for counting GDB threads.
+
+ Do not count the main thread (whose tid is zero). This matches
+ the list of threads provided by the pthreaddebug library, which
+ does not include that main thread either, and thus allows us
+ to compare the two lists. */
static int
giter_count (struct thread_info *thread, void *countp)
{
- (*(int *) countp)++;
+ if (PD_TID (thread->ptid))
+ (*(int *) countp)++;
return 0;
}
-/* iterate_over_threads() callback for accumulating GDB thread pids. */
+/* iterate_over_threads() callback for accumulating GDB thread pids.
+
+ Do not include the main thread (whose tid is zero). This matches
+ the list of threads provided by the pthreaddebug library, which
+ does not include that main thread either, and thus allows us
+ to compare the two lists. */
static int
giter_accum (struct thread_info *thread, void *bufp)
{
- **(struct thread_info ***) bufp = thread;
- (*(struct thread_info ***) bufp)++;
+ if (PD_TID (thread->ptid))
+ {
+ **(struct thread_info ***) bufp = thread;
+ (*(struct thread_info ***) bufp)++;
+ }
return 0;
}
pthdb_tid_t ktid = 0;
int result = 0;
- /* getthrds(3) isn't prototyped in any AIX 4.3.3 #include file. */
- extern int getthrds (pid_t, struct thrdsinfo64 *,
- int, pthdb_tid_t *, int);
-
while (1)
{
if (getthrds (PIDGET (inferior_ptid), &thrinf,
return ptid;
}
-/* Try to start debugging threads in the current process.
+/* Try to start debugging threads in the current process.
If successful and SET_INFPID, set inferior_ptid to reflect the
current thread. */
return;
/* Check application word size. */
- arch64 = register_size (current_gdbarch, 0) == 8;
+ arch64 = register_size (target_gdbarch, 0) == 8;
/* Check whether the application is pthreaded. */
stub_name = NULL;
status = pthdb_session_pthreaded (PD_USER, PTHDB_FLAG_REGS,
&pd_callbacks, &stub_name);
- if ((status != PTHDB_SUCCESS &&
- status != PTHDB_NOT_PTHREADED) || !stub_name)
+ if ((status != PTHDB_SUCCESS
+ && status != PTHDB_NOT_PTHREADED) || !stub_name)
return;
/* Set a breakpoint on the returned stub function. */
if (!(ms = lookup_minimal_symbol (stub_name, NULL, NULL)))
return;
pd_brk_addr = SYMBOL_VALUE_ADDRESS (ms);
- if (!create_thread_event_breakpoint (pd_brk_addr))
+ if (!create_thread_event_breakpoint (target_gdbarch, pd_brk_addr))
return;
/* Prepare for thread debugging. */
- base_target = current_target;
push_target (&aix_thread_ops);
pd_able = 1;
static void
aix_thread_attach (struct target_ops *ops, char *args, int from_tty)
{
- base_target.to_attach (&base_target, args, from_tty);
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ beneath->to_attach (beneath, args, from_tty);
pd_activate (1);
}
static void
aix_thread_detach (struct target_ops *ops, char *args, int from_tty)
{
+ struct target_ops *beneath = find_target_beneath (ops);
+
pd_disable ();
- base_target.to_detach (&base_target, args, from_tty);
+ beneath->to_detach (beneath, args, from_tty);
}
/* Tell the inferior process to continue running thread PID if != -1
if (!PD_TID (ptid))
{
struct cleanup *cleanup = save_inferior_ptid ();
+ struct target_ops *beneath = find_target_beneath (ops);
+
inferior_ptid = pid_to_ptid (PIDGET (inferior_ptid));
- base_target.to_resume (ops, ptid, step, sig);
+ beneath->to_resume (beneath, ptid, step, sig);
do_cleanups (cleanup);
}
else
{
- thread = find_thread_pid (ptid);
+ thread = find_thread_ptid (ptid);
if (!thread)
error (_("aix-thread resume: unknown pthread %ld"),
TIDGET (ptid));
static ptid_t
aix_thread_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status)
+ ptid_t ptid, struct target_waitstatus *status, int options)
{
struct cleanup *cleanup = save_inferior_ptid ();
+ struct target_ops *beneath = find_target_beneath (ops);
pid_to_prc (&ptid);
inferior_ptid = pid_to_ptid (PIDGET (inferior_ptid));
- ptid = base_target.to_wait (&base_target, ptid, status);
+ ptid = beneath->to_wait (beneath, ptid, status, options);
do_cleanups (cleanup);
if (PIDGET (ptid) == -1)
{
struct thread_info *thread;
pthdb_tid_t tid;
+ struct target_ops *beneath = find_target_beneath (ops);
if (!PD_TID (inferior_ptid))
- base_target.to_fetch_registers (ops, regcache, regno);
+ beneath->to_fetch_registers (beneath, regcache, regno);
else
{
- thread = find_thread_pid (inferior_ptid);
+ thread = find_thread_ptid (inferior_ptid);
tid = thread->private->tid;
if (tid == PTHDB_INVALID_TID)
int regno;
for (regno = 0; regno < ppc_num_gprs; regno++)
- if (regcache_valid_p (regcache, tdep->ppc_gp0_regnum + regno))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_gp0_regnum + regno))
regcache_raw_collect (regcache, tdep->ppc_gp0_regnum + regno,
vals + regno);
}
int regno;
for (regno = 0; regno < ppc_num_gprs; regno++)
- if (regcache_valid_p (regcache, tdep->ppc_gp0_regnum + regno))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_gp0_regnum + regno))
regcache_raw_collect (regcache, tdep->ppc_gp0_regnum + regno,
vals + regno);
}
for (regno = tdep->ppc_fp0_regnum;
regno < tdep->ppc_fp0_regnum + ppc_num_fprs;
regno++)
- if (regcache_valid_p (regcache, regno))
+ if (REG_VALID == regcache_register_status (regcache, regno))
regcache_raw_collect (regcache, regno, vals + regno);
}
gdb_assert (sizeof (*iar) == register_size
(gdbarch, gdbarch_pc_regnum (gdbarch)));
- if (regcache_valid_p (regcache, gdbarch_pc_regnum (gdbarch)))
+ if (REG_VALID == regcache_register_status (regcache,
+ gdbarch_pc_regnum (gdbarch)))
regcache_raw_collect (regcache, gdbarch_pc_regnum (gdbarch), iar);
- if (regcache_valid_p (regcache, tdep->ppc_ps_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_ps_regnum))
regcache_raw_collect (regcache, tdep->ppc_ps_regnum, msr);
- if (regcache_valid_p (regcache, tdep->ppc_cr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_cr_regnum))
regcache_raw_collect (regcache, tdep->ppc_cr_regnum, cr);
- if (regcache_valid_p (regcache, tdep->ppc_lr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_lr_regnum))
regcache_raw_collect (regcache, tdep->ppc_lr_regnum, lr);
- if (regcache_valid_p (regcache, tdep->ppc_ctr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_ctr_regnum))
regcache_raw_collect (regcache, tdep->ppc_ctr_regnum, ctr);
- if (regcache_valid_p (regcache, tdep->ppc_xer_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_xer_regnum))
regcache_raw_collect (regcache, tdep->ppc_xer_regnum, xer);
if (tdep->ppc_fpscr_regnum >= 0
- && regcache_valid_p (regcache, tdep->ppc_fpscr_regnum))
+ && REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_fpscr_regnum))
regcache_raw_collect (regcache, tdep->ppc_fpscr_regnum, fpscr);
}
gdb_assert (sizeof (*iar) == register_size (gdbarch,
gdbarch_pc_regnum (gdbarch)));
- if (regcache_valid_p (regcache, gdbarch_pc_regnum (gdbarch)))
+ if (REG_VALID == regcache_register_status (regcache,
+ gdbarch_pc_regnum (gdbarch)))
regcache_raw_collect (regcache, gdbarch_pc_regnum (gdbarch), iar);
- if (regcache_valid_p (regcache, tdep->ppc_ps_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_ps_regnum))
regcache_raw_collect (regcache, tdep->ppc_ps_regnum, msr);
- if (regcache_valid_p (regcache, tdep->ppc_cr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_cr_regnum))
regcache_raw_collect (regcache, tdep->ppc_cr_regnum, cr);
- if (regcache_valid_p (regcache, tdep->ppc_lr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_lr_regnum))
regcache_raw_collect (regcache, tdep->ppc_lr_regnum, lr);
- if (regcache_valid_p (regcache, tdep->ppc_ctr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_ctr_regnum))
regcache_raw_collect (regcache, tdep->ppc_ctr_regnum, ctr);
- if (regcache_valid_p (regcache, tdep->ppc_xer_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_xer_regnum))
regcache_raw_collect (regcache, tdep->ppc_xer_regnum, xer);
if (tdep->ppc_fpscr_regnum >= 0
- && regcache_valid_p (regcache, tdep->ppc_fpscr_regnum))
+ && REG_VALID == regcache_register_status (regcache, tdep->ppc_fpscr_regnum))
regcache_raw_collect (regcache, tdep->ppc_fpscr_regnum, fpscr);
}
/* Collect general-purpose register values from the regcache. */
for (i = 0; i < ppc_num_gprs; i++)
- if (regcache_valid_p (regcache, tdep->ppc_gp0_regnum + i))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_gp0_regnum + i))
{
if (arch64)
{
fill_sprs32 (regcache, &tmp_iar, &tmp_msr, &tmp_cr, &tmp_lr, &tmp_ctr,
&tmp_xer, &tmp_fpscr);
- if (regcache_valid_p (regcache, gdbarch_pc_regnum (gdbarch)))
+ if (REG_VALID == regcache_register_status (regcache,
+ gdbarch_pc_regnum (gdbarch)))
ctx.iar = tmp_iar;
- if (regcache_valid_p (regcache, tdep->ppc_ps_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_ps_regnum))
ctx.msr = tmp_msr;
- if (regcache_valid_p (regcache, tdep->ppc_cr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_cr_regnum))
ctx.cr = tmp_cr;
- if (regcache_valid_p (regcache, tdep->ppc_lr_regnum))
+ if (REG_VALID == regcache_register_status (regcache, tdep->ppc_lr_regnum))
ctx.lr = tmp_lr;
- if (regcache_valid_p (regcache, tdep->ppc_ctr_regnum))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_ctr_regnum))
ctx.ctr = tmp_ctr;
- if (regcache_valid_p (regcache, tdep->ppc_xer_regnum))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_xer_regnum))
ctx.xer = tmp_xer;
- if (regcache_valid_p (regcache, tdep->ppc_xer_regnum))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_xer_regnum))
ctx.fpscr = tmp_fpscr;
}
status = pthdb_pthread_setcontext (pd_session, pdtid, &ctx);
if (status != PTHDB_SUCCESS)
- error (_("aix-thread: store_registers: pthdb_pthread_setcontext returned %s"),
+ error (_("aix-thread: store_registers: "
+ "pthdb_pthread_setcontext returned %s"),
pd_status2str (status));
}
sprs32.pt_fpscr = tmp_fpscr;
if (tdep->ppc_mq_regnum >= 0)
- if (regcache_valid_p (regcache, tdep->ppc_mq_regnum))
+ if (REG_VALID == regcache_register_status (regcache,
+ tdep->ppc_mq_regnum))
regcache_raw_collect (regcache, tdep->ppc_mq_regnum,
&sprs32.pt_mq);
{
struct thread_info *thread;
pthdb_tid_t tid;
+ struct target_ops *beneath = find_target_beneath (ops);
if (!PD_TID (inferior_ptid))
- base_target.to_store_registers (ops, regcache, regno);
+ beneath->to_store_registers (beneath, regcache, regno);
else
{
- thread = find_thread_pid (inferior_ptid);
+ thread = find_thread_ptid (inferior_ptid);
tid = thread->private->tid;
if (tid == PTHDB_INVALID_TID)
static LONGEST
aix_thread_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+ const gdb_byte *writebuf,
+ ULONGEST offset, LONGEST len)
{
struct cleanup *old_chain = save_inferior_ptid ();
LONGEST xfer;
+ struct target_ops *beneath = find_target_beneath (ops);
inferior_ptid = pid_to_ptid (PIDGET (inferior_ptid));
- xfer = base_target.to_xfer_partial (ops, object, annex,
- readbuf, writebuf, offset, len);
+ xfer = beneath->to_xfer_partial (beneath, object, annex,
+ readbuf, writebuf, offset, len);
do_cleanups (old_chain);
return xfer;
}
-/* Kill and forget about the inferior process. */
-
-static void
-aix_thread_kill (void)
-{
- struct cleanup *cleanup = save_inferior_ptid ();
-
- inferior_ptid = pid_to_ptid (PIDGET (inferior_ptid));
- base_target.to_kill ();
- do_cleanups (cleanup);
-}
-
/* Clean up after the inferior exits. */
static void
aix_thread_mourn_inferior (struct target_ops *ops)
{
+ struct target_ops *beneath = find_target_beneath (ops);
+
pd_deactivate ();
- base_target.to_mourn_inferior (&base_target);
+ beneath->to_mourn_inferior (beneath);
}
/* Return whether thread PID is still valid. */
static int
aix_thread_thread_alive (struct target_ops *ops, ptid_t ptid)
{
+ struct target_ops *beneath = find_target_beneath (ops);
+
if (!PD_TID (ptid))
- return base_target.to_thread_alive (ops, ptid);
+ return beneath->to_thread_alive (beneath, ptid);
/* We update the thread list every time the child stops, so all
valid threads should be in the thread list. */
aix_thread_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
static char *ret = NULL;
+ struct target_ops *beneath = find_target_beneath (ops);
if (!PD_TID (ptid))
- return base_target.to_pid_to_str (&base_target, ptid);
+ return beneath->to_pid_to_str (beneath, ptid);
/* Free previous return value; a new one will be allocated by
xstrprintf(). */
pthdb_suspendstate_t suspendstate;
pthdb_detachstate_t detachstate;
int cancelpend;
- long length;
static char *ret = NULL;
if (!PD_TID (thread->ptid))
xfree (ret); /* Free old buffer. */
- ret = ui_file_xstrdup (buf, &length);
+ ret = ui_file_xstrdup (buf, NULL);
ui_file_delete (buf);
return ret;
static void
init_aix_thread_ops (void)
{
- aix_thread_ops.to_shortname = "aix-threads";
- aix_thread_ops.to_longname = _("AIX pthread support");
- aix_thread_ops.to_doc = _("AIX pthread support");
-
- aix_thread_ops.to_attach = aix_thread_attach;
- aix_thread_ops.to_detach = aix_thread_detach;
- aix_thread_ops.to_resume = aix_thread_resume;
- aix_thread_ops.to_wait = aix_thread_wait;
- aix_thread_ops.to_fetch_registers = aix_thread_fetch_registers;
- aix_thread_ops.to_store_registers = aix_thread_store_registers;
- aix_thread_ops.to_xfer_partial = aix_thread_xfer_partial;
+ aix_thread_ops.to_shortname = "aix-threads";
+ aix_thread_ops.to_longname = _("AIX pthread support");
+ aix_thread_ops.to_doc = _("AIX pthread support");
+
+ aix_thread_ops.to_attach = aix_thread_attach;
+ aix_thread_ops.to_detach = aix_thread_detach;
+ aix_thread_ops.to_resume = aix_thread_resume;
+ aix_thread_ops.to_wait = aix_thread_wait;
+ aix_thread_ops.to_fetch_registers = aix_thread_fetch_registers;
+ aix_thread_ops.to_store_registers = aix_thread_store_registers;
+ aix_thread_ops.to_xfer_partial = aix_thread_xfer_partial;
/* No need for aix_thread_ops.to_create_inferior, because we activate thread
debugging when the inferior reaches pd_brk_addr. */
- aix_thread_ops.to_kill = aix_thread_kill;
- aix_thread_ops.to_mourn_inferior = aix_thread_mourn_inferior;
- aix_thread_ops.to_thread_alive = aix_thread_thread_alive;
- aix_thread_ops.to_pid_to_str = aix_thread_pid_to_str;
- aix_thread_ops.to_extra_thread_info = aix_thread_extra_thread_info;
- aix_thread_ops.to_get_ada_task_ptid = aix_thread_get_ada_task_ptid;
- aix_thread_ops.to_stratum = thread_stratum;
- aix_thread_ops.to_magic = OPS_MAGIC;
+ aix_thread_ops.to_mourn_inferior = aix_thread_mourn_inferior;
+ aix_thread_ops.to_thread_alive = aix_thread_thread_alive;
+ aix_thread_ops.to_pid_to_str = aix_thread_pid_to_str;
+ aix_thread_ops.to_extra_thread_info = aix_thread_extra_thread_info;
+ aix_thread_ops.to_get_ada_task_ptid = aix_thread_get_ada_task_ptid;
+ aix_thread_ops.to_stratum = thread_stratum;
+ aix_thread_ops.to_magic = OPS_MAGIC;
}
/* Module startup initialization function, automagically called by
observer_attach_new_objfile (new_objfile);
add_setshow_boolean_cmd ("aix-thread", class_maintenance, &debug_aix_thread,
- _("Set debugging of AIX thread module."),
- _("Show debugging of AIX thread module."),
- _("Enables debugging output (used to debug GDB)."),
- NULL, NULL, /* FIXME: i18n: Debugging of AIX thread module is \"%d\". */
- &setdebuglist, &showdebuglist);
+ _("Set debugging of AIX thread module."),
+ _("Show debugging of AIX thread module."),
+ _("Enables debugging output (used to debug GDB)."),
+ NULL, NULL,
+ /* FIXME: i18n: Debugging of AIX thread
+ module is \"%d\". */
+ &setdebuglist, &showdebuglist);
}