aboutsummaryrefslogtreecommitdiff
path: root/gdb/sol-thread.c
diff options
context:
space:
mode:
authorStu Grossman <grossman@cygnus>1996-05-13 23:22:32 +0000
committerStu Grossman <grossman@cygnus>1996-05-13 23:22:32 +0000
commita50cedad0e0e4d8c6fbea30aaa3a5616170ce5ea (patch)
tree58ab0aacefba7a6b3e39e71dece9763586537dde /gdb/sol-thread.c
parent05535e79e9697bdc703d101039f767ea2faa211f (diff)
downloadgdb-a50cedad0e0e4d8c6fbea30aaa3a5616170ce5ea.zip
gdb-a50cedad0e0e4d8c6fbea30aaa3a5616170ce5ea.tar.gz
gdb-a50cedad0e0e4d8c6fbea30aaa3a5616170ce5ea.tar.bz2
* sol-thread.c: More cleanup, add comments.
* (sol_thread_resume): Prevent people from trying to step inactive threads. * (sol_thread_wait sol_thread_fetch_registers sol_thread_store_registers): Remove unnecessary check for sol_thread_active. These routines won't get called unless threads are active.
Diffstat (limited to 'gdb/sol-thread.c')
-rw-r--r--gdb/sol-thread.c168
1 files changed, 135 insertions, 33 deletions
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index 940e1db..96a5d78 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -17,6 +17,34 @@ 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. */
+/* This module implements a sort of half target that sits between the
+ machine-independent parts of GDB and the /proc interface (procfs.c) to
+ provide access to the Solaris user-mode thread implementation.
+
+ Solaris threads are true user-mode threads, which are invoked via the thr_*
+ and pthread_* (native and Posix respectivly) interfaces. These are mostly
+ implemented in user-space, with all thread context kept in various
+ structures that live in the user's heap. These should not be confused with
+ lightweight processes (LWPs), which are implemented by the kernel, and
+ scheduled without explicit intervention by the process.
+
+ Just to confuse things a little, Solaris threads (both native and Posix) are
+ actually implemented using LWPs. In general, there are going to be more
+ threads than LWPs. There is no fixed correspondence between a thread and an
+ LWP. When a thread wants to run, it gets scheduled onto the first available
+ LWP and can therefore migrate from one LWP to another as time goes on. A
+ sleeping thread may not be associated with an LWP at all!
+
+ To make it possible to mess with threads, Sun provides a library called
+ libthread_db.so.1 (not to be confused with libthread_db.so.0, which doesn't
+ have a published interface). This interface has an upper part, which it
+ provides, and a lower part which I provide. The upper part consists of the
+ td_* routines, which allow me to find all the threads, query their state,
+ etc... The lower part consists of all of the ps_*, which are used by the
+ td_* routines to read/write memory, manipulate LWPs, lookup symbols, etc...
+ The ps_* routines actually do most of their work by calling functions in
+ procfs.c. */
+
#include "defs.h"
/* Undefine gregset_t and fpregset_t to avoid conflict with defs in xm file. */
@@ -44,11 +72,24 @@ extern struct target_ops sol_thread_ops; /* Forward declaration */
extern int procfs_suppress_run;
extern struct target_ops procfs_ops; /* target vector for procfs.c */
+/* Note that these prototypes differ slightly from those used in procfs.c
+ for of two reasons. One, we can't use gregset_t, as that's got a whole
+ different meaning under Solaris (also, see above). Two, we can't use the
+ pointer form here as these are actually arrays of ints (for Sparc's at
+ least), and are automatically coerced into pointers to ints when used as
+ parameters. That makes it impossible to avoid a compiler warning when
+ passing pr{g fp}regset_t's from a parameter to an argument of one of
+ these functions. */
+
extern void supply_gregset PARAMS ((const prgregset_t));
extern void fill_gregset PARAMS ((prgregset_t, int));
extern void supply_fpregset PARAMS ((const prfpregset_t));
extern void fill_fpregset PARAMS ((prfpregset_t, int));
+/* This struct is defined by us, but mainly used for the proc_service interface.
+ We don't have much use for it, except as a handy place to get a real pid
+ for memory accesses. */
+
struct ps_prochandle
{
pid_t pid;
@@ -246,8 +287,27 @@ thread_to_lwp (thread_id, default_lwp)
return lwp;
}
+
+/*
+
+LOCAL FUNCTION
+
+ lwp_to_thread - Convert a LWP id to a Posix or Solaris thread id.
+
+SYNOPSIS
+
+ int lwp_to_thread (lwp_id)
-/* Convert an LWP id to a thread. */
+DESCRIPTION
+
+ This function converts a lightweight process id to a Posix or Solaris
+ thread id. If thread_id is non-existent, that's an error.
+
+NOTES
+
+ This function probably shouldn't call error()...
+
+ */
static int
lwp_to_thread (lwp)
@@ -281,6 +341,34 @@ lwp_to_thread (lwp)
return thread_id;
}
+/*
+
+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 ()
{
@@ -294,6 +382,11 @@ restore_inferior_pid (pid)
inferior_pid = pid;
}
+
+/* Most target vector functions from here on actually just pass through to
+ procfs.c, as they don't need to do anything specific for threads. */
+
+
/* ARGSUSED */
static void
sol_thread_open (arg, from_tty)
@@ -334,7 +427,8 @@ sol_thread_detach (args, from_tty)
/* Resume execution of process PID. If STEP is nozero, then
just single step it. If SIGNAL is nonzero, restart it with that
- signal activated. */
+ signal activated. We may have to convert pid from a thread-id to an LWP id
+ for procfs. */
static void
sol_thread_resume (pid, step, signo)
@@ -349,14 +443,19 @@ sol_thread_resume (pid, step, signo)
inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid);
if (pid != -1)
- pid = thread_to_lwp (pid, -1);
+ {
+ pid = thread_to_lwp (pid, -2);
+ if (pid == -2) /* Inactive thread */
+ error ("This version of Solaris can't start inactive threads.");
+ }
procfs_ops.to_resume (pid, step, signo);
do_cleanups (old_chain);
}
-/* Wait for any LWPs to stop */
+/* 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
sol_thread_wait (pid, ourstatus)
@@ -367,9 +466,6 @@ sol_thread_wait (pid, ourstatus)
int save_pid;
struct cleanup *old_chain;
- if (!sol_thread_active)
- return procfs_ops.to_wait (pid, ourstatus);
-
save_pid = inferior_pid;
old_chain = save_inferior_pid ();
@@ -415,13 +511,6 @@ sol_thread_fetch_registers (regno)
caddr_t xregset;
#endif
- if (!sol_thread_active
- || is_lwp (inferior_pid))
- {
- procfs_ops.to_fetch_registers (regno);
- return;
- }
-
/* Convert inferior_pid into a td_thrhandle_t */
thread = GET_THREAD (inferior_pid);
@@ -495,13 +584,6 @@ sol_thread_store_registers (regno)
caddr_t xregset;
#endif
- if (!sol_thread_active
- || is_lwp (inferior_pid))
- {
- procfs_ops.to_store_registers (regno);
- return;
- }
-
/* Convert inferior_pid into a td_thrhandle_t */
thread = GET_THREAD (inferior_pid);
@@ -646,7 +728,10 @@ sol_thread_create_inferior (exec_file, allargs, env)
}
/* This routine is called whenever a new symbol table is read in, or when all
- symbol tables are removed. */
+ symbol tables are removed. libthread_db can only be initialized when it
+ finds the right variables in libthread.so. Since it's a shared library,
+ those variables don't show up until the library gets mapped and the symbol
+ table is read in. */
void
sol_thread_new_objfile (objfile)
@@ -687,34 +772,33 @@ sol_thread_mourn_inferior ()
}
/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
+
static int
sol_thread_can_run ()
{
return procfs_suppress_run;
}
-int
+static int
sol_thread_alive (pid)
int pid;
{
return 1;
}
-void
+static void
sol_thread_stop ()
{
procfs_ops.to_stop ();
}
+
+/* These routines implement the lower half of the thread_db interface. Ie: the
+ ps_* routines. */
-/* Service routines we must supply to libthread_db */
-
-struct lwp_map
-{
- struct lwp_map *next;
- pid_t pid;
- lwpid_t lwp;
- int lwpfd;
-};
+/* The next four routines are called by thread_db to tell us to stop and stop
+ a particular process or lwp. Since GDB ensures that these are all stopped
+ by the time we call anything in thread_db, these routines need to do
+ nothing. */
ps_err_e
ps_pstop (const struct ps_prochandle *ph)
@@ -756,6 +840,8 @@ ps_pglobal_lookup (const struct ps_prochandle *ph, const char *ld_object_name,
return PS_OK;
}
+/* Common routine for reading and writing memory. */
+
static ps_err_e
rw_common (int dowrite, const struct ps_prochandle *ph, paddr_t addr,
char *buf, int size)
@@ -817,6 +903,8 @@ ps_ptwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size)
return rw_common (1, ph, addr, buf, size);
}
+/* Get integer regs */
+
ps_err_e
ps_lgetregs (const struct ps_prochandle *ph, lwpid_t lwpid,
prgregset_t gregset)
@@ -835,6 +923,8 @@ ps_lgetregs (const struct ps_prochandle *ph, lwpid_t lwpid,
return PS_OK;
}
+/* Set integer regs */
+
ps_err_e
ps_lsetregs (const struct ps_prochandle *ph, lwpid_t lwpid,
const prgregset_t gregset)
@@ -863,6 +953,8 @@ ps_plog (const char *fmt, ...)
vfprintf_filtered (gdb_stderr, fmt, args);
}
+/* Get size of extra register set. Currently a noop. */
+
ps_err_e
ps_lgetxregsize (const struct ps_prochandle *ph, lwpid_t lwpid, int *xregsize)
{
@@ -889,6 +981,8 @@ ps_lgetxregsize (const struct ps_prochandle *ph, lwpid_t lwpid, int *xregsize)
return PS_OK;
}
+/* Get extra register set. Currently a noop. */
+
ps_err_e
ps_lgetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset)
{
@@ -910,6 +1004,8 @@ ps_lgetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset)
return PS_OK;
}
+/* Set extra register set. Currently a noop. */
+
ps_err_e
ps_lsetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset)
{
@@ -931,6 +1027,8 @@ ps_lsetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset)
return PS_OK;
}
+/* Get floating-point regs. */
+
ps_err_e
ps_lgetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid,
prfpregset_t *fpregset)
@@ -949,6 +1047,8 @@ ps_lgetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid,
return PS_OK;
}
+/* Set floating-point regs. */
+
ps_err_e
ps_lsetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid,
const prfpregset_t *fpregset)
@@ -967,6 +1067,8 @@ ps_lsetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid,
return PS_OK;
}
+/* Convert a pid to printable form. */
+
char *
solaris_pid_to_str (pid)
int pid;