-/* Low level interface for debugging HPUX/DCE threads for GDB, the GNU debugger.
- Copyright 1996, 1999 Free Software Foundation, Inc.
+/* Low level interface for debugging HPUX/DCE threads for GDB, the GNU
+ debugger.
+
+ Copyright (C) 1996, 1998, 1999, 2000, 2001, 2004, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* This module implements a sort of half target that sits between the
machine-independent parts of GDB and the ptrace interface (infptrace.c) to
#include "gdbthread.h"
#include "target.h"
#include "inferior.h"
+#include "regcache.h"
#include <fcntl.h>
-#include <sys/stat.h>
+#include <string.h>
+#include "gdb_stat.h"
#include "gdbcore.h"
+#include "hppa-tdep.h"
+#include "observer.h"
extern int child_suppress_run;
-extern struct target_ops child_ops; /* target vector for inftarg.c */
extern void _initialize_hpux_thread (void);
static int hpux_thread_active = 0;
-static int main_pid; /* Real process ID */
+static ptid_t main_ptid; /* Real process ID */
static CORE_ADDR P_cma__g_known_threads;
static CORE_ADDR P_cma__g_current_thread;
-static struct cleanup *save_inferior_pid (void);
-
-static void restore_inferior_pid (int pid);
-
-static void hpux_thread_resume (int pid, int step, enum target_signal signo);
-
static void init_hpux_thread_ops (void);
static struct target_ops hpux_thread_ops;
\f
-/*
-
- LOCAL FUNCTION
-
- save_inferior_pid - Save inferior_pid on the cleanup list
- restore_inferior_pid - Restore inferior_pid from the cleanup list
-
- SYNOPSIS
-
- struct cleanup *save_inferior_pid ()
- void restore_inferior_pid (int pid)
-
- DESCRIPTION
-
- These two functions act in unison to restore inferior_pid in
- case of an error.
-
- NOTES
-
- inferior_pid is a global variable that needs to be changed by many of
- these routines before calling functions in procfs.c. In order to
- guarantee that inferior_pid gets restored (in case of errors), you
- need to call save_inferior_pid before changing it. At the end of the
- function, you should invoke do_cleanups to restore it.
-
- */
-
-
-static struct cleanup *
-save_inferior_pid ()
-{
- return make_cleanup (restore_inferior_pid, inferior_pid);
-}
-
-static void
-restore_inferior_pid (pid)
- int pid;
-{
- inferior_pid = pid;
-}
-\f
-static int find_active_thread (void);
+static ptid_t find_active_thread (void);
static int cached_thread;
-static int cached_active_thread;
static cma__t_int_tcb cached_tcb;
-static int
-find_active_thread ()
+static ptid_t
+find_active_thread (void)
{
static cma__t_int_tcb tcb;
CORE_ADDR tcb_ptr;
- if (cached_active_thread != 0)
- return cached_active_thread;
-
read_memory ((CORE_ADDR) P_cma__g_current_thread,
(char *) &tcb_ptr,
sizeof tcb_ptr);
read_memory (tcb_ptr, (char *) &tcb, sizeof tcb);
- return (cma_thread_get_unique (&tcb.prolog.client_thread) << 16) | main_pid;
+ return (ptid_build (PIDGET (main_ptid), 0,
+ cma_thread_get_unique (&tcb.prolog.client_thread)));
}
-static cma__t_int_tcb *find_tcb (int thread);
+static cma__t_int_tcb *find_tcb (ptid_t ptid);
static cma__t_int_tcb *
-find_tcb (thread)
- int thread;
+find_tcb (ptid_t ptid)
{
cma__t_known_object queue_header;
cma__t_queue *queue_ptr;
+ int thread = ptid_get_tid (ptid);
if (thread == cached_thread)
return &cached_tcb;
read_memory ((CORE_ADDR) tcb_ptr, (char *) &cached_tcb, sizeof cached_tcb);
if (cached_tcb.header.type == cma__c_obj_tcb)
- if (cma_thread_get_unique (&cached_tcb.prolog.client_thread) == thread >> 16)
+ if (cma_thread_get_unique (&cached_tcb.prolog.client_thread) == thread)
{
cached_thread = thread;
return &cached_tcb;
}
}
- error ("Can't find TCB %d,%d", thread >> 16, thread & 0xffff);
+ error (_("Can't find TCB %d"), thread);
return NULL;
}
\f
/* Most target vector functions from here on actually just pass through to
inftarg.c, as they don't need to do anything specific for threads. */
-/* ARGSUSED */
static void
-hpux_thread_open (arg, from_tty)
- char *arg;
- int from_tty;
+hpux_thread_open (char *arg, int from_tty)
{
- child_ops.to_open (arg, from_tty);
+ deprecated_child_ops.to_open (arg, from_tty);
}
/* Attach to process PID, then initialize for debugging it
and wait for the trace-trap that results from attaching. */
static void
-hpux_thread_attach (args, from_tty)
- char *args;
- int from_tty;
+hpux_thread_attach (struct target_ops *ops, char *args, int from_tty)
{
- child_ops.to_attach (args, from_tty);
+ deprecated_child_ops.to_attach (&deprecated_child_ops, args, from_tty);
/* XXX - might want to iterate over all the threads and register them. */
}
started via the normal ptrace (PTRACE_TRACEME). */
static void
-hpux_thread_detach (args, from_tty)
- char *args;
- int from_tty;
+hpux_thread_detach (struct target_ops *ops, char *args, int from_tty)
{
- child_ops.to_detach (args, from_tty);
+ deprecated_child_ops.to_detach (&deprecated_child_ops, args, from_tty);
}
/* Resume execution of process PID. If STEP is nozero, then
for procfs. */
static void
-hpux_thread_resume (pid, step, signo)
- int pid;
- int step;
- enum target_signal signo;
+hpux_thread_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum target_signal signo)
{
struct cleanup *old_chain;
- old_chain = save_inferior_pid ();
-
- pid = inferior_pid = main_pid;
+ old_chain = save_inferior_ptid ();
-#if 0
- if (pid != -1)
- {
- pid = thread_to_lwp (pid, -2);
- if (pid == -2) /* Inactive thread */
- error ("This version of Solaris can't start inactive threads.");
- }
-#endif
+ ptid = main_ptid;
+ inferior_ptid = main_ptid;
- child_ops.to_resume (pid, step, signo);
+ deprecated_child_ops.to_resume (&deprecated_child_ops, ptid, step, signo);
cached_thread = 0;
- cached_active_thread = 0;
do_cleanups (old_chain);
}
/* Wait for any threads to stop. We may have to convert PID from a thread id
to a LWP id, and vice versa on the way out. */
-static int
-hpux_thread_wait (pid, ourstatus)
- int pid;
- struct target_waitstatus *ourstatus;
+static ptid_t
+hpux_thread_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
- int rtnval;
+ ptid_t rtnval;
struct cleanup *old_chain;
- old_chain = save_inferior_pid ();
+ old_chain = save_inferior_ptid ();
- inferior_pid = main_pid;
+ inferior_ptid = main_ptid;
- if (pid != -1)
- pid = main_pid;
+ if (!ptid_equal (ptid, minus_one_ptid))
+ ptid = main_ptid;
- rtnval = child_ops.to_wait (pid, ourstatus);
+ rtnval = deprecated_child_ops.to_wait (&deprecated_child_ops,
+ ptid, ourstatus, options);
rtnval = find_active_thread ();
return rtnval;
}
-static char regmap[NUM_REGS] =
+static char regmap[] =
{
-2, -1, -1, 0, 4, 8, 12, 16, 20, 24, /* flags, r1 -> r9 */
28, 32, 36, 40, 44, 48, 52, 56, 60, -1, /* r10 -> r19 */
};
static void
-hpux_thread_fetch_registers (regno)
- int regno;
+hpux_thread_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
cma__t_int_tcb tcb, *tcb_ptr;
struct cleanup *old_chain;
int i;
int first_regno, last_regno;
- tcb_ptr = find_tcb (inferior_pid);
+ tcb_ptr = find_tcb (inferior_ptid);
- old_chain = save_inferior_pid ();
+ old_chain = save_inferior_ptid ();
- inferior_pid = main_pid;
+ inferior_ptid = main_ptid;
if (tcb_ptr->state == cma__c_state_running)
{
- child_ops.to_fetch_registers (regno);
+ deprecated_child_ops.to_fetch_registers (&deprecated_child_ops,
+ regcache, regno);
do_cleanups (old_chain);
if (regno == -1)
{
first_regno = 0;
- last_regno = NUM_REGS - 1;
+ last_regno = gdbarch_num_regs (gdbarch) - 1;
}
else
{
for (regno = first_regno; regno <= last_regno; regno++)
{
if (regmap[regno] == -1)
- child_ops.to_fetch_registers (regno);
+ deprecated_child_ops.to_fetch_registers (&deprecated_child_ops,
+ regcache, regno);
else
{
- unsigned char buf[MAX_REGISTER_RAW_SIZE];
+ unsigned char buf[MAX_REGISTER_SIZE];
CORE_ADDR sp;
sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
- if (regno == FLAGS_REGNUM)
+ if (regno == HPPA_FLAGS_REGNUM)
/* Flags must be 0 to avoid bogus value for SS_INSYSCALL */
- memset (buf, '\000', REGISTER_RAW_SIZE (regno));
- else if (regno == SP_REGNUM)
- store_address (buf, sizeof sp, sp);
- else if (regno == PC_REGNUM)
- read_memory (sp - 20, buf, REGISTER_RAW_SIZE (regno));
+ memset (buf, '\000', register_size (gdbarch, regno));
+ else if (regno == HPPA_SP_REGNUM)
+ store_unsigned_integer (buf, sizeof sp, byte_order, sp);
+ else if (regno == HPPA_PCOQ_HEAD_REGNUM)
+ read_memory (sp - 20, buf, register_size (gdbarch, regno));
else
- read_memory (sp + regmap[regno], buf, REGISTER_RAW_SIZE (regno));
+ read_memory (sp + regmap[regno], buf,
+ register_size (gdbarch, regno));
- supply_register (regno, buf);
+ regcache_raw_supply (regcache, regno, buf);
}
}
}
static void
-hpux_thread_store_registers (regno)
- int regno;
+hpux_thread_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
cma__t_int_tcb tcb, *tcb_ptr;
struct cleanup *old_chain;
int i;
int first_regno, last_regno;
- tcb_ptr = find_tcb (inferior_pid);
+ tcb_ptr = find_tcb (inferior_ptid);
- old_chain = save_inferior_pid ();
+ old_chain = save_inferior_ptid ();
- inferior_pid = main_pid;
+ inferior_ptid = main_ptid;
if (tcb_ptr->state == cma__c_state_running)
{
- child_ops.to_store_registers (regno);
+ deprecated_child_ops.to_store_registers (&deprecated_child_ops,
+ regcache, regno);
do_cleanups (old_chain);
if (regno == -1)
{
first_regno = 0;
- last_regno = NUM_REGS - 1;
+ last_regno = gdbarch_num_regs (gdbarch) - 1;
}
else
{
for (regno = first_regno; regno <= last_regno; regno++)
{
if (regmap[regno] == -1)
- child_ops.to_store_registers (regno);
+ deprecated_child_ops.to_store_registers (regcache, regno);
else
{
- unsigned char buf[MAX_REGISTER_RAW_SIZE];
+ unsigned char buf[MAX_REGISTER_SIZE];
CORE_ADDR sp;
sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
- if (regno == FLAGS_REGNUM)
- child_ops.to_store_registers (regno); /* Let lower layer handle this... */
- else if (regno == SP_REGNUM)
+ if (regno == HPPA_FLAGS_REGNUM)
+ {
+ /* Let lower layer handle this... */
+ deprecated_child_ops.to_store_registers
+ (&deprecated_child_ops, regcache, regno);
+ }
+ else if (regno == HPPA_SP_REGNUM)
{
- write_memory ((CORE_ADDR) & tcb_ptr->static_ctx.sp,
- registers + REGISTER_BYTE (regno),
- REGISTER_RAW_SIZE (regno));
- tcb_ptr->static_ctx.sp = (cma__t_hppa_regs *)
- (extract_address (registers + REGISTER_BYTE (regno), REGISTER_RAW_SIZE (regno)) + 160);
+ regcache_raw_collect (regcache, regno, buf);
+ write_memory ((CORE_ADDR) &tcb_ptr->static_ctx.sp, buf,
+ register_size (gdbarch, regno));
+ tcb_ptr->static_ctx.sp
+ = (cma__t_hppa_regs *) ((CORE_ADDR) buf + 160);
+ }
+ else if (regno == HPPA_PCOQ_HEAD_REGNUM)
+ {
+ regcache_raw_collect (regcache, regno, buf);
+ write_memory (sp - 20, buf,
+ register_size (gdbarch, regno));
}
- else if (regno == PC_REGNUM)
- write_memory (sp - 20,
- registers + REGISTER_BYTE (regno),
- REGISTER_RAW_SIZE (regno));
else
- write_memory (sp + regmap[regno],
- registers + REGISTER_BYTE (regno),
- REGISTER_RAW_SIZE (regno));
+ {
+ regcache_raw_collect (regcache, regno, buf);
+ write_memory (sp + regmap[regno], buf,
+ register_size (gdbarch, regno));
+ }
}
}
debugged. */
static void
-hpux_thread_prepare_to_store ()
+hpux_thread_prepare_to_store (struct regcache *regcache)
{
- child_ops.to_prepare_to_store ();
+ deprecated_child_ops.to_prepare_to_store (regcache);
}
static int
-hpux_thread_xfer_memory (memaddr, myaddr, len, dowrite, target)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
- int dowrite;
- struct target_ops *target; /* ignored */
+hpux_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int dowrite, struct mem_attrib *attribs,
+ struct target_ops *target)
{
int retval;
struct cleanup *old_chain;
- old_chain = save_inferior_pid ();
+ old_chain = save_inferior_ptid ();
- inferior_pid = main_pid;
+ inferior_ptid = main_ptid;
- retval = child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target);
+ retval =
+ deprecated_child_ops.deprecated_xfer_memory (memaddr, myaddr, len, dowrite, attribs, target);
do_cleanups (old_chain);
/* Print status information about what we're accessing. */
static void
-hpux_thread_files_info (ignore)
- struct target_ops *ignore;
+hpux_thread_files_info (struct target_ops *ignore)
{
- child_ops.to_files_info (ignore);
+ deprecated_child_ops.to_files_info (ignore);
}
static void
-hpux_thread_kill_inferior ()
+hpux_thread_kill_inferior (struct target_ops *ops)
{
- child_ops.to_kill ();
+ deprecated_child_ops.to_kill (&deprecated_child_ops);
}
static void
-hpux_thread_notice_signals (pid)
- int pid;
+hpux_thread_notice_signals (ptid_t ptid)
{
- child_ops.to_notice_signals (pid);
+ deprecated_child_ops.to_notice_signals (ptid);
}
/* Fork an inferior process, and start debugging it with /proc. */
static void
-hpux_thread_create_inferior (exec_file, allargs, env)
- char *exec_file;
- char *allargs;
- char **env;
+hpux_thread_create_inferior (struct target_ops *ops, char *exec_file,
+ char *allargs, char **env, int from_tty)
{
- child_ops.to_create_inferior (exec_file, allargs, env);
+ deprecated_child_ops.to_create_inferior (&deprecated_child_ops,
+ exec_file, allargs, env, from_tty);
if (hpux_thread_active)
{
- main_pid = inferior_pid;
+ main_ptid = inferior_ptid;
push_target (&hpux_thread_ops);
- inferior_pid = find_active_thread ();
+ inferior_ptid = find_active_thread ();
- add_thread (inferior_pid);
+ add_thread (inferior_ptid);
}
}
those variables don't show up until the library gets mapped and the symbol
table is read in. */
-/* This new_objfile event is now managed by a chained function pointer.
- * It is the callee's responsability to call the next client on the chain.
- */
-
-/* Saved pointer to previous owner of the new_objfile event. */
-static void (*target_new_objfile_chain) PARAMS ((struct objfile *));
-
-void
-hpux_thread_new_objfile (objfile)
- struct objfile *objfile;
+static void
+hpux_thread_new_objfile (struct objfile *objfile)
{
struct minimal_symbol *ms;
if (!objfile)
{
hpux_thread_active = 0;
- goto quit;
+ return;
}
ms = lookup_minimal_symbol ("cma__g_known_threads", NULL, objfile);
if (!ms)
- goto quit;
+ return;
P_cma__g_known_threads = SYMBOL_VALUE_ADDRESS (ms);
ms = lookup_minimal_symbol ("cma__g_current_thread", NULL, objfile);
if (!ms)
- goto quit;
+ return;
P_cma__g_current_thread = SYMBOL_VALUE_ADDRESS (ms);
hpux_thread_active = 1;
-quit:
- /* Call predecessor on chain, if any. */
- if (target_new_objfile_chain)
- target_new_objfile_chain (objfile);
}
/* Clean up after the inferior dies. */
static void
-hpux_thread_mourn_inferior ()
+hpux_thread_mourn_inferior (void)
{
- child_ops.to_mourn_inferior ();
+ deprecated_child_ops.to_mourn_inferior (&deprecated_child_ops);
}
/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
static int
-hpux_thread_can_run ()
+hpux_thread_can_run (void)
{
return child_suppress_run;
}
static int
-hpux_thread_alive (pid)
- int pid;
+hpux_thread_alive (struct target_ops *ops, ptid_t ptid)
{
return 1;
}
static void
-hpux_thread_stop ()
+hpux_thread_stop (ptid_t ptid)
{
- child_ops.to_stop ();
+ deprecated_child_ops.to_stop (ptid);
}
\f
/* Convert a pid to printable form. */
char *
-hpux_pid_to_str (pid)
- int pid;
+hpux_pid_to_str (ptid_t ptid)
{
static char buf[100];
+ int pid = PIDGET (ptid);
- sprintf (buf, "Thread %d", pid >> 16);
+ sprintf (buf, "Thread %ld", ptid_get_tid (ptid));
return buf;
}
\f
static void
-init_hpux_thread_ops ()
+init_hpux_thread_ops (void)
{
hpux_thread_ops.to_shortname = "hpux-threads";
hpux_thread_ops.to_longname = "HPUX threads and pthread.";
hpux_thread_ops.to_fetch_registers = hpux_thread_fetch_registers;
hpux_thread_ops.to_store_registers = hpux_thread_store_registers;
hpux_thread_ops.to_prepare_to_store = hpux_thread_prepare_to_store;
- hpux_thread_ops.to_xfer_memory = hpux_thread_xfer_memory;
+ hpux_thread_ops.deprecated_xfer_memory = hpux_thread_xfer_memory;
hpux_thread_ops.to_files_info = hpux_thread_files_info;
hpux_thread_ops.to_insert_breakpoint = memory_insert_breakpoint;
hpux_thread_ops.to_remove_breakpoint = memory_remove_breakpoint;
hpux_thread_ops.to_terminal_init = terminal_init_inferior;
hpux_thread_ops.to_terminal_inferior = terminal_inferior;
hpux_thread_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ hpux_thread_ops.to_terminal_save_ours = terminal_save_ours;
hpux_thread_ops.to_terminal_ours = terminal_ours;
hpux_thread_ops.to_terminal_info = child_terminal_info;
hpux_thread_ops.to_kill = hpux_thread_kill_inferior;
hpux_thread_ops.to_thread_alive = hpux_thread_alive;
hpux_thread_ops.to_stop = hpux_thread_stop;
hpux_thread_ops.to_stratum = process_stratum;
- hpux_thread_ops.to_has_all_memory = 1;
- hpux_thread_ops.to_has_memory = 1;
- hpux_thread_ops.to_has_stack = 1;
- hpux_thread_ops.to_has_registers = 1;
- hpux_thread_ops.to_has_execution = 1;
+ hpux_thread_ops.to_has_all_memory = default_child_has_all_memory;
+ hpux_thread_ops.to_has_memory = default_child_has_memory;
+ hpux_thread_ops.to_has_stack = default_child_has_stack;
+ hpux_thread_ops.to_has_registers = default_child_has_registers;
+ hpux_thread_ops.to_has_execution = default_child_has_execution;
hpux_thread_ops.to_magic = OPS_MAGIC;
}
void
-_initialize_hpux_thread ()
+_initialize_hpux_thread (void)
{
init_hpux_thread_ops ();
add_target (&hpux_thread_ops);
child_suppress_run = 1;
- /* Hook into new_objfile notification. */
- target_new_objfile_chain = target_new_objfile_hook;
- target_new_objfile_hook = hpux_thread_new_objfile;
+ /* Hook into new_objfile notification. */
+ observer_attach_new_objfile (hpux_thread_new_objfile);
}