146283Sdfr/* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
2130803Smarcel   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
398944Sobrien   Free Software Foundation, Inc.
446283Sdfr
598944Sobrien   This file is part of GDB.
646283Sdfr
798944Sobrien   This program is free software; you can redistribute it and/or modify
898944Sobrien   it under the terms of the GNU General Public License as published by
998944Sobrien   the Free Software Foundation; either version 2 of the License, or
1098944Sobrien   (at your option) any later version.
1146283Sdfr
1298944Sobrien   This program is distributed in the hope that it will be useful,
1398944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1498944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598944Sobrien   GNU General Public License for more details.
1646283Sdfr
1798944Sobrien   You should have received a copy of the GNU General Public License
1898944Sobrien   along with this program; if not, write to the Free Software
1998944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2098944Sobrien   Boston, MA 02111-1307, USA.  */
2146283Sdfr
2246283Sdfr/* This module implements a sort of half target that sits between the
2346283Sdfr   machine-independent parts of GDB and the /proc interface (procfs.c) to
2446283Sdfr   provide access to the Solaris user-mode thread implementation.
2546283Sdfr
2646283Sdfr   Solaris threads are true user-mode threads, which are invoked via the thr_*
2746283Sdfr   and pthread_* (native and Posix respectivly) interfaces.  These are mostly
2846283Sdfr   implemented in user-space, with all thread context kept in various
2946283Sdfr   structures that live in the user's heap.  These should not be confused with
3046283Sdfr   lightweight processes (LWPs), which are implemented by the kernel, and
3146283Sdfr   scheduled without explicit intervention by the process.
3246283Sdfr
3346283Sdfr   Just to confuse things a little, Solaris threads (both native and Posix) are
3446283Sdfr   actually implemented using LWPs.  In general, there are going to be more
3546283Sdfr   threads than LWPs.  There is no fixed correspondence between a thread and an
3646283Sdfr   LWP.  When a thread wants to run, it gets scheduled onto the first available
3746283Sdfr   LWP and can therefore migrate from one LWP to another as time goes on.  A
3846283Sdfr   sleeping thread may not be associated with an LWP at all!
3946283Sdfr
4046283Sdfr   To make it possible to mess with threads, Sun provides a library called
4146283Sdfr   libthread_db.so.1 (not to be confused with libthread_db.so.0, which doesn't
4246283Sdfr   have a published interface).  This interface has an upper part, which it
4346283Sdfr   provides, and a lower part which I provide.  The upper part consists of the
4446283Sdfr   td_* routines, which allow me to find all the threads, query their state,
4546283Sdfr   etc...  The lower part consists of all of the ps_*, which are used by the
4646283Sdfr   td_* routines to read/write memory, manipulate LWPs, lookup symbols, etc...
4746283Sdfr   The ps_* routines actually do most of their work by calling functions in
4846283Sdfr   procfs.c.  */
4946283Sdfr
5046283Sdfr#include "defs.h"
5146283Sdfr#include <thread.h>
5246283Sdfr#include <proc_service.h>
5346283Sdfr#include <thread_db.h>
5446283Sdfr#include "gdbthread.h"
5546283Sdfr#include "target.h"
5646283Sdfr#include "inferior.h"
5746283Sdfr#include <fcntl.h>
58130803Smarcel#include "gdb_stat.h"
5946283Sdfr#include <dlfcn.h>
6046283Sdfr#include "gdbcmd.h"
6198944Sobrien#include "gdbcore.h"
6298944Sobrien#include "regcache.h"
6398944Sobrien#include "symfile.h"
6446283Sdfr
65130803Smarcel#include "gdb_string.h"
66130803Smarcel
6798944Sobrienextern struct target_ops sol_thread_ops;	/* Forward declaration */
6898944Sobrienextern struct target_ops sol_core_ops;	/* Forward declaration */
6946283Sdfr
7046283Sdfr/* place to store core_ops before we overwrite it */
7146283Sdfrstatic struct target_ops orig_core_ops;
7246283Sdfr
7346283Sdfrstruct target_ops sol_thread_ops;
7446283Sdfrstruct target_ops sol_core_ops;
7546283Sdfr
7646283Sdfrextern int procfs_suppress_run;
7798944Sobrienextern struct target_ops procfs_ops;	/* target vector for procfs.c */
7898944Sobrienextern struct target_ops core_ops;	/* target vector for corelow.c */
7998944Sobrienextern char *procfs_pid_to_str (ptid_t ptid);
8046283Sdfr
8198944Sobrien/* Prototypes for supply_gregset etc. */
8298944Sobrien#include "gregset.h"
8346283Sdfr
8446283Sdfr/* This struct is defined by us, but mainly used for the proc_service interface.
8546283Sdfr   We don't have much use for it, except as a handy place to get a real pid
8646283Sdfr   for memory accesses.  */
8746283Sdfr
8846283Sdfrstruct ps_prochandle
8998944Sobrien  {
9098944Sobrien    ptid_t ptid;
9198944Sobrien  };
9246283Sdfr
9346283Sdfrstruct string_map
9498944Sobrien  {
9598944Sobrien    int num;
9698944Sobrien    char *str;
9798944Sobrien  };
9846283Sdfr
9946283Sdfrstatic struct ps_prochandle main_ph;
10046283Sdfrstatic td_thragent_t *main_ta;
10146283Sdfrstatic int sol_thread_active = 0;
10246283Sdfr
10398944Sobrienstatic char *td_err_string (td_err_e errcode);
10498944Sobrienstatic char *td_state_string (td_thr_state_e statecode);
10598944Sobrienstatic ptid_t thread_to_lwp (ptid_t thread_id, int default_lwp);
10698944Sobrienstatic void sol_thread_resume (ptid_t ptid, int step, enum target_signal signo);
10798944Sobrienstatic ptid_t lwp_to_thread (ptid_t lwp);
10898944Sobrienstatic int sol_thread_alive (ptid_t ptid);
10998944Sobrienstatic void sol_core_close (int quitting);
11046283Sdfr
11198944Sobrienstatic void init_sol_thread_ops (void);
11298944Sobrienstatic void init_sol_core_ops (void);
11346283Sdfr
114130803Smarcel/* Default definitions: These must be defined in tm.h
11598944Sobrien   if they are to be shared with a process module such as procfs.  */
11646283Sdfr
11798944Sobrien#define GET_PID(ptid)		ptid_get_pid (ptid)
11898944Sobrien#define GET_LWP(ptid)		ptid_get_lwp (ptid)
11998944Sobrien#define GET_THREAD(ptid)	ptid_get_tid (ptid)
12098944Sobrien
12198944Sobrien#define is_lwp(ptid)		(GET_LWP (ptid) != 0)
12298944Sobrien#define is_thread(ptid)		(GET_THREAD (ptid) != 0)
12398944Sobrien
12498944Sobrien#define BUILD_LWP(lwp, pid)	ptid_build (pid, lwp, 0)
12598944Sobrien#define BUILD_THREAD(tid, pid)	ptid_build (pid, 0, tid)
12698944Sobrien
12746283Sdfr/* Pointers to routines from lithread_db resolved by dlopen() */
12846283Sdfr
12998944Sobrienstatic void     (*p_td_log)               (const int on_off);
130130803Smarcelstatic td_err_e (*p_td_ta_new)            (const struct ps_prochandle * ph_p,
13198944Sobrien					   td_thragent_t ** ta_pp);
13298944Sobrienstatic td_err_e (*p_td_ta_delete)         (td_thragent_t * ta_p);
13398944Sobrienstatic td_err_e (*p_td_init)              (void);
134130803Smarcelstatic td_err_e (*p_td_ta_get_ph)         (const td_thragent_t * ta_p,
13598944Sobrien					   struct ps_prochandle ** ph_pp);
136130803Smarcelstatic td_err_e (*p_td_ta_get_nthreads)   (const td_thragent_t * ta_p,
13798944Sobrien					   int *nthread_p);
138130803Smarcelstatic td_err_e (*p_td_ta_tsd_iter)       (const td_thragent_t * ta_p,
139130803Smarcel					   td_key_iter_f * cb,
14098944Sobrien					   void *cbdata_p);
141130803Smarcelstatic td_err_e (*p_td_ta_thr_iter)       (const td_thragent_t * ta_p,
142130803Smarcel					   td_thr_iter_f * cb,
143130803Smarcel					   void *cbdata_p,
14498944Sobrien					   td_thr_state_e state,
145130803Smarcel					   int ti_pri,
146130803Smarcel					   sigset_t * ti_sigmask_p,
14798944Sobrien					   unsigned ti_user_flags);
14898944Sobrienstatic td_err_e (*p_td_thr_validate)      (const td_thrhandle_t * th_p);
149130803Smarcelstatic td_err_e (*p_td_thr_tsd)           (const td_thrhandle_t * th_p,
150130803Smarcel					   const thread_key_t key,
15198944Sobrien					   void **data_pp);
152130803Smarcelstatic td_err_e (*p_td_thr_get_info)      (const td_thrhandle_t * th_p,
15398944Sobrien					   td_thrinfo_t * ti_p);
154130803Smarcelstatic td_err_e (*p_td_thr_getfpregs)     (const td_thrhandle_t * th_p,
15598944Sobrien					   prfpregset_t * fpregset);
156130803Smarcelstatic td_err_e (*p_td_thr_getxregsize)   (const td_thrhandle_t * th_p,
15798944Sobrien					   int *xregsize);
158130803Smarcelstatic td_err_e (*p_td_thr_getxregs)      (const td_thrhandle_t * th_p,
15998944Sobrien					   const caddr_t xregset);
160130803Smarcelstatic td_err_e (*p_td_thr_sigsetmask)    (const td_thrhandle_t * th_p,
16198944Sobrien					   const sigset_t ti_sigmask);
162130803Smarcelstatic td_err_e (*p_td_thr_setprio)       (const td_thrhandle_t * th_p,
16398944Sobrien					   const int ti_pri);
164130803Smarcelstatic td_err_e (*p_td_thr_setsigpending) (const td_thrhandle_t * th_p,
165130803Smarcel					   const uchar_t ti_pending_flag,
16698944Sobrien					   const sigset_t ti_pending);
167130803Smarcelstatic td_err_e (*p_td_thr_setfpregs)     (const td_thrhandle_t * th_p,
16898944Sobrien					   const prfpregset_t * fpregset);
169130803Smarcelstatic td_err_e (*p_td_thr_setxregs)      (const td_thrhandle_t * th_p,
17098944Sobrien					   const caddr_t xregset);
171130803Smarcelstatic td_err_e (*p_td_ta_map_id2thr)     (const td_thragent_t * ta_p,
172130803Smarcel					   thread_t tid,
17398944Sobrien					   td_thrhandle_t * th_p);
174130803Smarcelstatic td_err_e (*p_td_ta_map_lwp2thr)    (const td_thragent_t * ta_p,
175130803Smarcel					   lwpid_t lwpid,
17698944Sobrien					   td_thrhandle_t * th_p);
177130803Smarcelstatic td_err_e (*p_td_thr_getgregs)      (const td_thrhandle_t * th_p,
17898944Sobrien					   prgregset_t regset);
179130803Smarcelstatic td_err_e (*p_td_thr_setgregs)      (const td_thrhandle_t * th_p,
18098944Sobrien					   const prgregset_t regset);
18198944Sobrien
18246283Sdfr/*
18346283Sdfr
18498944Sobrien   LOCAL FUNCTION
18546283Sdfr
18698944Sobrien   td_err_string - Convert a thread_db error code to a string
18746283Sdfr
18898944Sobrien   SYNOPSIS
18946283Sdfr
19098944Sobrien   char * td_err_string (errcode)
19146283Sdfr
19298944Sobrien   DESCRIPTION
19346283Sdfr
19498944Sobrien   Return the thread_db error string associated with errcode.  If errcode
19598944Sobrien   is unknown, then return a message.
19646283Sdfr
19746283Sdfr */
19846283Sdfr
19946283Sdfrstatic char *
20098944Sobrientd_err_string (td_err_e errcode)
20146283Sdfr{
20246283Sdfr  static struct string_map
20398944Sobrien    td_err_table[] =
20498944Sobrien  {
20598944Sobrien    {TD_OK, "generic \"call succeeded\""},
20698944Sobrien    {TD_ERR, "generic error."},
20798944Sobrien    {TD_NOTHR, "no thread can be found to satisfy query"},
20898944Sobrien    {TD_NOSV, "no synch. variable can be found to satisfy query"},
20998944Sobrien    {TD_NOLWP, "no lwp can be found to satisfy query"},
21098944Sobrien    {TD_BADPH, "invalid process handle"},
21198944Sobrien    {TD_BADTH, "invalid thread handle"},
21298944Sobrien    {TD_BADSH, "invalid synchronization handle"},
21398944Sobrien    {TD_BADTA, "invalid thread agent"},
21498944Sobrien    {TD_BADKEY, "invalid key"},
21598944Sobrien    {TD_NOMSG, "td_thr_event_getmsg() called when there was no message"},
21698944Sobrien    {TD_NOFPREGS, "FPU register set not available for given thread"},
21798944Sobrien    {TD_NOLIBTHREAD, "application not linked with libthread"},
21898944Sobrien    {TD_NOEVENT, "requested event is not supported"},
21998944Sobrien    {TD_NOCAPAB, "capability not available"},
22098944Sobrien    {TD_DBERR, "Debugger service failed"},
22198944Sobrien    {TD_NOAPLIC, "Operation not applicable to"},
22298944Sobrien    {TD_NOTSD, "No thread specific data for this thread"},
22398944Sobrien    {TD_MALLOC, "Malloc failed"},
22498944Sobrien    {TD_PARTIALREG, "Only part of register set was written/read"},
22598944Sobrien    {TD_NOXREGS, "X register set not available for given thread"}
22698944Sobrien  };
22746283Sdfr  const int td_err_size = sizeof td_err_table / sizeof (struct string_map);
22846283Sdfr  int i;
22946283Sdfr  static char buf[50];
23046283Sdfr
23146283Sdfr  for (i = 0; i < td_err_size; i++)
23246283Sdfr    if (td_err_table[i].num == errcode)
23346283Sdfr      return td_err_table[i].str;
23498944Sobrien
23546283Sdfr  sprintf (buf, "Unknown thread_db error code: %d", errcode);
23646283Sdfr
23746283Sdfr  return buf;
23846283Sdfr}
23946283Sdfr
24046283Sdfr/*
24146283Sdfr
24298944Sobrien   LOCAL FUNCTION
24346283Sdfr
24498944Sobrien   td_state_string - Convert a thread_db state code to a string
24546283Sdfr
24698944Sobrien   SYNOPSIS
24746283Sdfr
24898944Sobrien   char * td_state_string (statecode)
24946283Sdfr
25098944Sobrien   DESCRIPTION
25146283Sdfr
25298944Sobrien   Return the thread_db state string associated with statecode.  If
25398944Sobrien   statecode is unknown, then return a message.
25446283Sdfr
25546283Sdfr */
25646283Sdfr
25746283Sdfrstatic char *
25898944Sobrientd_state_string (td_thr_state_e statecode)
25946283Sdfr{
26046283Sdfr  static struct string_map
26198944Sobrien    td_thr_state_table[] =
26298944Sobrien  {
26398944Sobrien    {TD_THR_ANY_STATE, "any state"},
26498944Sobrien    {TD_THR_UNKNOWN, "unknown"},
26598944Sobrien    {TD_THR_STOPPED, "stopped"},
26698944Sobrien    {TD_THR_RUN, "run"},
26798944Sobrien    {TD_THR_ACTIVE, "active"},
26898944Sobrien    {TD_THR_ZOMBIE, "zombie"},
26998944Sobrien    {TD_THR_SLEEP, "sleep"},
27098944Sobrien    {TD_THR_STOPPED_ASLEEP, "stopped asleep"}
27198944Sobrien  };
27246283Sdfr  const int td_thr_state_table_size = sizeof td_thr_state_table / sizeof (struct string_map);
27346283Sdfr  int i;
27446283Sdfr  static char buf[50];
27546283Sdfr
27646283Sdfr  for (i = 0; i < td_thr_state_table_size; i++)
27746283Sdfr    if (td_thr_state_table[i].num == statecode)
27846283Sdfr      return td_thr_state_table[i].str;
27998944Sobrien
28046283Sdfr  sprintf (buf, "Unknown thread_db state code: %d", statecode);
28146283Sdfr
28246283Sdfr  return buf;
28346283Sdfr}
28446283Sdfr
28546283Sdfr/*
28646283Sdfr
28798944Sobrien   LOCAL FUNCTION
28846283Sdfr
28998944Sobrien   thread_to_lwp - Convert a Posix or Solaris thread id to a LWP id.
29046283Sdfr
29198944Sobrien   SYNOPSIS
29246283Sdfr
29398944Sobrien   tpid_t thread_to_lwp (thread_id, default_lwp)
29446283Sdfr
29598944Sobrien   DESCRIPTION
29646283Sdfr
29798944Sobrien   This function converts a Posix or Solaris thread id to a lightweight
29898944Sobrien   process id.  If thread_id is non-existent, that's an error.  If it's
29998944Sobrien   an inactive thread, then we return default_lwp.
30046283Sdfr
30198944Sobrien   NOTES
30246283Sdfr
30398944Sobrien   This function probably shouldn't call error()...
30446283Sdfr
30546283Sdfr */
30646283Sdfr
30798944Sobrienstatic ptid_t
30898944Sobrienthread_to_lwp (ptid_t thread_id, int default_lwp)
30946283Sdfr{
31046283Sdfr  td_thrinfo_t ti;
31146283Sdfr  td_thrhandle_t th;
31246283Sdfr  td_err_e val;
31346283Sdfr
31446283Sdfr  if (is_lwp (thread_id))
31598944Sobrien    return thread_id;		/* It's already an LWP id */
31646283Sdfr
31746283Sdfr  /* It's a thread.  Convert to lwp */
31846283Sdfr
31946283Sdfr  val = p_td_ta_map_id2thr (main_ta, GET_THREAD (thread_id), &th);
32046283Sdfr  if (val == TD_NOTHR)
32198944Sobrien    return pid_to_ptid (-1);		/* thread must have terminated */
32246283Sdfr  else if (val != TD_OK)
32346283Sdfr    error ("thread_to_lwp: td_ta_map_id2thr %s", td_err_string (val));
32446283Sdfr
32546283Sdfr  val = p_td_thr_get_info (&th, &ti);
32646283Sdfr  if (val == TD_NOTHR)
32798944Sobrien    return pid_to_ptid (-1);		/* thread must have terminated */
32846283Sdfr  else if (val != TD_OK)
32946283Sdfr    error ("thread_to_lwp: td_thr_get_info: %s", td_err_string (val));
33046283Sdfr
33146283Sdfr  if (ti.ti_state != TD_THR_ACTIVE)
33246283Sdfr    {
33346283Sdfr      if (default_lwp != -1)
33498944Sobrien	return pid_to_ptid (default_lwp);
33546283Sdfr      error ("thread_to_lwp: thread state not active: %s",
33646283Sdfr	     td_state_string (ti.ti_state));
33746283Sdfr    }
33846283Sdfr
33946283Sdfr  return BUILD_LWP (ti.ti_lid, PIDGET (thread_id));
34046283Sdfr}
34146283Sdfr
34246283Sdfr/*
34346283Sdfr
34498944Sobrien   LOCAL FUNCTION
34546283Sdfr
34698944Sobrien   lwp_to_thread - Convert a LWP id to a Posix or Solaris thread id.
34746283Sdfr
34898944Sobrien   SYNOPSIS
34946283Sdfr
35098944Sobrien   int lwp_to_thread (lwp_id)
35146283Sdfr
35298944Sobrien   DESCRIPTION
35346283Sdfr
35498944Sobrien   This function converts a lightweight process id to a Posix or Solaris
35598944Sobrien   thread id.  If thread_id is non-existent, that's an error.
35646283Sdfr
35798944Sobrien   NOTES
35846283Sdfr
35998944Sobrien   This function probably shouldn't call error()...
36046283Sdfr
36146283Sdfr */
36246283Sdfr
36398944Sobrienstatic ptid_t
36498944Sobrienlwp_to_thread (ptid_t lwp)
36546283Sdfr{
36646283Sdfr  td_thrinfo_t ti;
36746283Sdfr  td_thrhandle_t th;
36846283Sdfr  td_err_e val;
36946283Sdfr
37046283Sdfr  if (is_thread (lwp))
37146283Sdfr    return lwp;			/* It's already a thread id */
37246283Sdfr
37346283Sdfr  /* It's an lwp.  Convert it to a thread id.  */
37446283Sdfr
37546283Sdfr  if (!sol_thread_alive (lwp))
37698944Sobrien    return pid_to_ptid (-1);	/* defunct lwp */
37746283Sdfr
37846283Sdfr  val = p_td_ta_map_lwp2thr (main_ta, GET_LWP (lwp), &th);
37946283Sdfr  if (val == TD_NOTHR)
38098944Sobrien    return pid_to_ptid (-1);	/* thread must have terminated */
38146283Sdfr  else if (val != TD_OK)
38246283Sdfr    error ("lwp_to_thread: td_ta_map_lwp2thr: %s.", td_err_string (val));
38346283Sdfr
38446283Sdfr  val = p_td_thr_validate (&th);
38546283Sdfr  if (val == TD_NOTHR)
38698944Sobrien    return lwp;			/* libthread doesn't know about it;
38798944Sobrien				   just return lwp */
38846283Sdfr  else if (val != TD_OK)
38946283Sdfr    error ("lwp_to_thread: td_thr_validate: %s.", td_err_string (val));
39046283Sdfr
39146283Sdfr  val = p_td_thr_get_info (&th, &ti);
39246283Sdfr  if (val == TD_NOTHR)
39398944Sobrien    return pid_to_ptid (-1);	/* thread must have terminated */
39446283Sdfr  else if (val != TD_OK)
39546283Sdfr    error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
39646283Sdfr
39746283Sdfr  return BUILD_THREAD (ti.ti_tid, PIDGET (lwp));
39846283Sdfr}
39946283Sdfr
40046283Sdfr
40146283Sdfr/* Most target vector functions from here on actually just pass through to
40246283Sdfr   procfs.c, as they don't need to do anything specific for threads.  */
40346283Sdfr
40446283Sdfrstatic void
40598944Sobriensol_thread_open (char *arg, int from_tty)
40646283Sdfr{
40746283Sdfr  procfs_ops.to_open (arg, from_tty);
40846283Sdfr}
40946283Sdfr
41046283Sdfr/* Attach to process PID, then initialize for debugging it
41146283Sdfr   and wait for the trace-trap that results from attaching.  */
41246283Sdfr
41346283Sdfrstatic void
41498944Sobriensol_thread_attach (char *args, int from_tty)
41546283Sdfr{
41646283Sdfr  procfs_ops.to_attach (args, from_tty);
41798944Sobrien
41846283Sdfr  /* Must get symbols from solibs before libthread_db can run! */
41998944Sobrien  SOLIB_ADD ((char *) 0, from_tty, (struct target_ops *) 0, auto_solib_add);
42098944Sobrien
42146283Sdfr  if (sol_thread_active)
42246283Sdfr    {
42346283Sdfr      printf_filtered ("sol-thread active.\n");
42498944Sobrien      main_ph.ptid = inferior_ptid;		/* Save for xfer_memory */
42546283Sdfr      push_target (&sol_thread_ops);
42698944Sobrien      inferior_ptid = lwp_to_thread (inferior_ptid);
42798944Sobrien      if (PIDGET (inferior_ptid) == -1)
42898944Sobrien	inferior_ptid = main_ph.ptid;
42946283Sdfr      else
43098944Sobrien	add_thread (inferior_ptid);
43146283Sdfr    }
43246283Sdfr  /* XXX - might want to iterate over all the threads and register them. */
43346283Sdfr}
43446283Sdfr
43546283Sdfr/* Take a program previously attached to and detaches it.
43646283Sdfr   The program resumes execution and will no longer stop
43746283Sdfr   on signals, etc.  We'd better not have left any breakpoints
43846283Sdfr   in the program or it'll die when it hits one.  For this
43946283Sdfr   to work, it may be necessary for the process to have been
44046283Sdfr   previously attached.  It *might* work if the program was
44146283Sdfr   started via the normal ptrace (PTRACE_TRACEME).  */
44246283Sdfr
44346283Sdfrstatic void
44498944Sobriensol_thread_detach (char *args, int from_tty)
44546283Sdfr{
44698944Sobrien  inferior_ptid = pid_to_ptid (PIDGET (main_ph.ptid));
44746283Sdfr  unpush_target (&sol_thread_ops);
44846283Sdfr  procfs_ops.to_detach (args, from_tty);
44946283Sdfr}
45046283Sdfr
45146283Sdfr/* Resume execution of process PID.  If STEP is nozero, then
45246283Sdfr   just single step it.  If SIGNAL is nonzero, restart it with that
45346283Sdfr   signal activated.  We may have to convert pid from a thread-id to an LWP id
45446283Sdfr   for procfs.  */
45546283Sdfr
45646283Sdfrstatic void
45798944Sobriensol_thread_resume (ptid_t ptid, int step, enum target_signal signo)
45846283Sdfr{
45946283Sdfr  struct cleanup *old_chain;
46046283Sdfr
46198944Sobrien  old_chain = save_inferior_ptid ();
46246283Sdfr
46398944Sobrien  inferior_ptid = thread_to_lwp (inferior_ptid, PIDGET (main_ph.ptid));
46498944Sobrien  if (PIDGET (inferior_ptid) == -1)
46598944Sobrien    inferior_ptid = procfs_first_available ();
46646283Sdfr
46798944Sobrien  if (PIDGET (ptid) != -1)
46846283Sdfr    {
46998944Sobrien      ptid_t save_ptid = ptid;
47046283Sdfr
47198944Sobrien      ptid = thread_to_lwp (ptid, -2);
47298944Sobrien      if (PIDGET (ptid) == -2)		/* Inactive thread */
47346283Sdfr	error ("This version of Solaris can't start inactive threads.");
47498944Sobrien      if (info_verbose && PIDGET (ptid) == -1)
47598944Sobrien	warning ("Specified thread %ld seems to have terminated",
47698944Sobrien		 GET_THREAD (save_ptid));
47746283Sdfr    }
47846283Sdfr
47998944Sobrien  procfs_ops.to_resume (ptid, step, signo);
48046283Sdfr
48146283Sdfr  do_cleanups (old_chain);
48246283Sdfr}
48346283Sdfr
48446283Sdfr/* Wait for any threads to stop.  We may have to convert PID from a thread id
48546283Sdfr   to a LWP id, and vice versa on the way out.  */
48646283Sdfr
48798944Sobrienstatic ptid_t
48898944Sobriensol_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
48946283Sdfr{
49098944Sobrien  ptid_t rtnval;
49198944Sobrien  ptid_t save_ptid;
49246283Sdfr  struct cleanup *old_chain;
49346283Sdfr
49498944Sobrien  save_ptid = inferior_ptid;
49598944Sobrien  old_chain = save_inferior_ptid ();
49646283Sdfr
49798944Sobrien  inferior_ptid = thread_to_lwp (inferior_ptid, PIDGET (main_ph.ptid));
49898944Sobrien  if (PIDGET (inferior_ptid) == -1)
49998944Sobrien    inferior_ptid = procfs_first_available ();
50046283Sdfr
50198944Sobrien  if (PIDGET (ptid) != -1)
50246283Sdfr    {
50398944Sobrien      ptid_t save_ptid = ptid;
50446283Sdfr
50598944Sobrien      ptid = thread_to_lwp (ptid, -2);
50698944Sobrien      if (PIDGET (ptid) == -2)		/* Inactive thread */
50746283Sdfr	error ("This version of Solaris can't start inactive threads.");
50898944Sobrien      if (info_verbose && PIDGET (ptid) == -1)
50998944Sobrien	warning ("Specified thread %ld seems to have terminated",
51098944Sobrien		 GET_THREAD (save_ptid));
51146283Sdfr    }
51246283Sdfr
51398944Sobrien  rtnval = procfs_ops.to_wait (ptid, ourstatus);
51446283Sdfr
51546283Sdfr  if (ourstatus->kind != TARGET_WAITKIND_EXITED)
51646283Sdfr    {
51746283Sdfr      /* Map the LWP of interest back to the appropriate thread ID */
51846283Sdfr      rtnval = lwp_to_thread (rtnval);
51998944Sobrien      if (PIDGET (rtnval) == -1)
52098944Sobrien	rtnval = save_ptid;
52146283Sdfr
52246283Sdfr      /* See if we have a new thread */
52346283Sdfr      if (is_thread (rtnval)
52498944Sobrien	  && !ptid_equal (rtnval, save_ptid)
52546283Sdfr	  && !in_thread_list (rtnval))
52646283Sdfr	{
52746283Sdfr	  printf_filtered ("[New %s]\n", target_pid_to_str (rtnval));
52846283Sdfr	  add_thread (rtnval);
52946283Sdfr	}
53046283Sdfr    }
53146283Sdfr
53246283Sdfr  /* During process initialization, we may get here without the thread package
53346283Sdfr     being initialized, since that can only happen after we've found the shared
53446283Sdfr     libs.  */
53546283Sdfr
53646283Sdfr  do_cleanups (old_chain);
53746283Sdfr
53846283Sdfr  return rtnval;
53946283Sdfr}
54046283Sdfr
54146283Sdfrstatic void
54298944Sobriensol_thread_fetch_registers (int regno)
54346283Sdfr{
54446283Sdfr  thread_t thread;
54546283Sdfr  td_thrhandle_t thandle;
54646283Sdfr  td_err_e val;
54746283Sdfr  prgregset_t gregset;
54846283Sdfr  prfpregset_t fpregset;
54946283Sdfr#if 0
55046283Sdfr  int xregsize;
55146283Sdfr  caddr_t xregset;
55246283Sdfr#endif
55346283Sdfr
55498944Sobrien  if (!is_thread (inferior_ptid))
55598944Sobrien    {				/* LWP: pass the request on to procfs.c */
55646283Sdfr      if (target_has_execution)
55746283Sdfr	procfs_ops.to_fetch_registers (regno);
55846283Sdfr      else
55946283Sdfr	orig_core_ops.to_fetch_registers (regno);
56046283Sdfr      return;
56146283Sdfr    }
56246283Sdfr
56398944Sobrien  /* Solaris thread: convert inferior_ptid into a td_thrhandle_t */
56446283Sdfr
56598944Sobrien  thread = GET_THREAD (inferior_ptid);
56646283Sdfr
56746283Sdfr  if (thread == 0)
56846283Sdfr    error ("sol_thread_fetch_registers:  thread == 0");
56946283Sdfr
57046283Sdfr  val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
57146283Sdfr  if (val != TD_OK)
57246283Sdfr    error ("sol_thread_fetch_registers: td_ta_map_id2thr: %s",
57346283Sdfr	   td_err_string (val));
57446283Sdfr
57546283Sdfr  /* Get the integer regs */
57646283Sdfr
57746283Sdfr  val = p_td_thr_getgregs (&thandle, gregset);
57846283Sdfr  if (val != TD_OK
57946283Sdfr      && val != TD_PARTIALREG)
58046283Sdfr    error ("sol_thread_fetch_registers: td_thr_getgregs %s",
58146283Sdfr	   td_err_string (val));
58246283Sdfr
58346283Sdfr  /* For the sparc, TD_PARTIALREG means that only i0->i7, l0->l7, pc and sp
58446283Sdfr     are saved (by a thread context switch).  */
58546283Sdfr
58646283Sdfr  /* And, now the fp regs */
58746283Sdfr
58846283Sdfr  val = p_td_thr_getfpregs (&thandle, &fpregset);
58946283Sdfr  if (val != TD_OK
59046283Sdfr      && val != TD_NOFPREGS)
59146283Sdfr    error ("sol_thread_fetch_registers: td_thr_getfpregs %s",
59246283Sdfr	   td_err_string (val));
59346283Sdfr
59446283Sdfr/* Note that we must call supply_{g fp}regset *after* calling the td routines
59546283Sdfr   because the td routines call ps_lget* which affect the values stored in the
59646283Sdfr   registers array.  */
59746283Sdfr
59898944Sobrien  supply_gregset  ((gdb_gregset_t *)  &gregset);
59998944Sobrien  supply_fpregset ((gdb_fpregset_t *) &fpregset);
60046283Sdfr
60146283Sdfr#if 0
60246283Sdfr/* thread_db doesn't seem to handle this right */
60346283Sdfr  val = td_thr_getxregsize (&thandle, &xregsize);
60446283Sdfr  if (val != TD_OK && val != TD_NOXREGS)
60546283Sdfr    error ("sol_thread_fetch_registers: td_thr_getxregsize %s",
60646283Sdfr	   td_err_string (val));
60746283Sdfr
60846283Sdfr  if (val == TD_OK)
60946283Sdfr    {
61046283Sdfr      xregset = alloca (xregsize);
61146283Sdfr      val = td_thr_getxregs (&thandle, xregset);
61246283Sdfr      if (val != TD_OK)
61346283Sdfr	error ("sol_thread_fetch_registers: td_thr_getxregs %s",
61446283Sdfr	       td_err_string (val));
61546283Sdfr    }
61646283Sdfr#endif
61746283Sdfr}
61846283Sdfr
61946283Sdfrstatic void
62098944Sobriensol_thread_store_registers (int regno)
62146283Sdfr{
62246283Sdfr  thread_t thread;
62346283Sdfr  td_thrhandle_t thandle;
62446283Sdfr  td_err_e val;
62598944Sobrien  prgregset_t  gregset;
62646283Sdfr  prfpregset_t fpregset;
62746283Sdfr#if 0
62846283Sdfr  int xregsize;
62946283Sdfr  caddr_t xregset;
63046283Sdfr#endif
63146283Sdfr
63298944Sobrien  if (!is_thread (inferior_ptid))
63398944Sobrien    {				/* LWP: pass the request on to procfs.c */
63446283Sdfr      procfs_ops.to_store_registers (regno);
63546283Sdfr      return;
63646283Sdfr    }
63746283Sdfr
63898944Sobrien  /* Solaris thread: convert inferior_ptid into a td_thrhandle_t */
63946283Sdfr
64098944Sobrien  thread = GET_THREAD (inferior_ptid);
64146283Sdfr
64246283Sdfr  val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
64346283Sdfr  if (val != TD_OK)
64446283Sdfr    error ("sol_thread_store_registers: td_ta_map_id2thr %s",
64546283Sdfr	   td_err_string (val));
64646283Sdfr
64746283Sdfr  if (regno != -1)
64846283Sdfr    {				/* Not writing all the regs */
649130803Smarcel      char old_value[MAX_REGISTER_SIZE];
65046283Sdfr
651130803Smarcel      /* Save new register value.  */
652130803Smarcel      regcache_collect (regno, old_value);
653130803Smarcel
65498944Sobrien      val = p_td_thr_getgregs (&thandle, gregset);
65546283Sdfr      if (val != TD_OK)
65646283Sdfr	error ("sol_thread_store_registers: td_thr_getgregs %s",
65746283Sdfr	       td_err_string (val));
65846283Sdfr      val = p_td_thr_getfpregs (&thandle, &fpregset);
65946283Sdfr      if (val != TD_OK)
66046283Sdfr	error ("sol_thread_store_registers: td_thr_getfpregs %s",
66146283Sdfr	       td_err_string (val));
66246283Sdfr
663130803Smarcel      /* Restore new register value.  */
664130803Smarcel      supply_register (regno, old_value);
66546283Sdfr
66646283Sdfr#if 0
66746283Sdfr/* thread_db doesn't seem to handle this right */
66846283Sdfr      val = td_thr_getxregsize (&thandle, &xregsize);
66946283Sdfr      if (val != TD_OK && val != TD_NOXREGS)
67046283Sdfr	error ("sol_thread_store_registers: td_thr_getxregsize %s",
67146283Sdfr	       td_err_string (val));
67246283Sdfr
67346283Sdfr      if (val == TD_OK)
67446283Sdfr	{
67546283Sdfr	  xregset = alloca (xregsize);
67646283Sdfr	  val = td_thr_getxregs (&thandle, xregset);
67746283Sdfr	  if (val != TD_OK)
67846283Sdfr	    error ("sol_thread_store_registers: td_thr_getxregs %s",
67946283Sdfr		   td_err_string (val));
68046283Sdfr	}
68146283Sdfr#endif
68246283Sdfr    }
68346283Sdfr
68498944Sobrien  fill_gregset  ((gdb_gregset_t *)  &gregset,  regno);
68598944Sobrien  fill_fpregset ((gdb_fpregset_t *) &fpregset, regno);
68646283Sdfr
68798944Sobrien  val = p_td_thr_setgregs (&thandle, gregset);
68846283Sdfr  if (val != TD_OK)
68946283Sdfr    error ("sol_thread_store_registers: td_thr_setgregs %s",
69046283Sdfr	   td_err_string (val));
69146283Sdfr  val = p_td_thr_setfpregs (&thandle, &fpregset);
69246283Sdfr  if (val != TD_OK)
69346283Sdfr    error ("sol_thread_store_registers: td_thr_setfpregs %s",
69446283Sdfr	   td_err_string (val));
69546283Sdfr
69646283Sdfr#if 0
69746283Sdfr/* thread_db doesn't seem to handle this right */
69846283Sdfr  val = td_thr_getxregsize (&thandle, &xregsize);
69946283Sdfr  if (val != TD_OK && val != TD_NOXREGS)
70046283Sdfr    error ("sol_thread_store_registers: td_thr_getxregsize %s",
70146283Sdfr	   td_err_string (val));
70246283Sdfr
70346283Sdfr  /* Should probably do something about writing the xregs here, but what are
70446283Sdfr     they? */
70546283Sdfr#endif
70646283Sdfr}
70746283Sdfr
70846283Sdfr/* Get ready to modify the registers array.  On machines which store
70946283Sdfr   individual registers, this doesn't need to do anything.  On machines
71046283Sdfr   which store all the registers in one fell swoop, this makes sure
71146283Sdfr   that registers contains all the registers from the program being
71246283Sdfr   debugged.  */
71346283Sdfr
71446283Sdfrstatic void
71598944Sobriensol_thread_prepare_to_store (void)
71646283Sdfr{
71746283Sdfr  procfs_ops.to_prepare_to_store ();
71846283Sdfr}
71946283Sdfr
72098944Sobrien/* Transfer LEN bytes between GDB address MYADDR and target address
72198944Sobrien   MEMADDR.  If DOWRITE is non-zero, transfer them to the target,
72298944Sobrien   otherwise transfer them from the target.  TARGET is unused.
72398944Sobrien
72498944Sobrien   Returns the number of bytes transferred. */
72598944Sobrien
72646283Sdfrstatic int
72798944Sobriensol_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
72898944Sobrien			struct mem_attrib *attrib,
72998944Sobrien			struct target_ops *target)
73046283Sdfr{
73146283Sdfr  int retval;
73246283Sdfr  struct cleanup *old_chain;
73346283Sdfr
73498944Sobrien  old_chain = save_inferior_ptid ();
73546283Sdfr
73698944Sobrien  if (is_thread (inferior_ptid) ||	/* A thread */
73798944Sobrien      !target_thread_alive (inferior_ptid))	/* An lwp, but not alive */
73898944Sobrien    inferior_ptid = procfs_first_available ();	/* Find any live lwp.  */
73946283Sdfr  /* Note: don't need to call switch_to_thread; we're just reading memory.  */
74046283Sdfr
74146283Sdfr  if (target_has_execution)
742130803Smarcel    retval = procfs_ops.to_xfer_memory (memaddr, myaddr, len,
74398944Sobrien					dowrite, attrib, target);
74446283Sdfr  else
74546283Sdfr    retval = orig_core_ops.to_xfer_memory (memaddr, myaddr, len,
74698944Sobrien					   dowrite, attrib, target);
74746283Sdfr
74846283Sdfr  do_cleanups (old_chain);
74946283Sdfr
75046283Sdfr  return retval;
75146283Sdfr}
75246283Sdfr
753130803Smarcel/* Perform partial transfers on OBJECT.  See target_read_partial
754130803Smarcel   and target_write_partial for details of each variant.  One, and
755130803Smarcel   only one, of readbuf or writebuf must be non-NULL.  */
756130803Smarcel
757130803Smarcelstatic LONGEST
758130803Smarcelsol_thread_xfer_partial (struct target_ops *ops, enum target_object object,
759130803Smarcel			  const char *annex, void *readbuf,
760130803Smarcel			  const void *writebuf, ULONGEST offset, LONGEST len)
761130803Smarcel{
762130803Smarcel  int retval;
763130803Smarcel  struct cleanup *old_chain;
764130803Smarcel
765130803Smarcel  old_chain = save_inferior_ptid ();
766130803Smarcel
767130803Smarcel  if (is_thread (inferior_ptid) ||	/* A thread */
768130803Smarcel      !target_thread_alive (inferior_ptid))	/* An lwp, but not alive */
769130803Smarcel    inferior_ptid = procfs_first_available ();	/* Find any live lwp.  */
770130803Smarcel  /* Note: don't need to call switch_to_thread; we're just reading memory.  */
771130803Smarcel
772130803Smarcel  if (target_has_execution)
773130803Smarcel    retval = procfs_ops.to_xfer_partial (ops, object, annex,
774130803Smarcel					 readbuf, writebuf, offset, len);
775130803Smarcel  else
776130803Smarcel    retval = orig_core_ops.to_xfer_partial (ops, object, annex,
777130803Smarcel					    readbuf, writebuf, offset, len);
778130803Smarcel
779130803Smarcel  do_cleanups (old_chain);
780130803Smarcel
781130803Smarcel  return retval;
782130803Smarcel}
783130803Smarcel
78446283Sdfr/* Print status information about what we're accessing.  */
78546283Sdfr
78646283Sdfrstatic void
78798944Sobriensol_thread_files_info (struct target_ops *ignore)
78846283Sdfr{
78946283Sdfr  procfs_ops.to_files_info (ignore);
79046283Sdfr}
79146283Sdfr
79246283Sdfrstatic void
79398944Sobriensol_thread_kill_inferior (void)
79446283Sdfr{
79546283Sdfr  procfs_ops.to_kill ();
79646283Sdfr}
79746283Sdfr
79846283Sdfrstatic void
79998944Sobriensol_thread_notice_signals (ptid_t ptid)
80046283Sdfr{
80198944Sobrien  procfs_ops.to_notice_signals (pid_to_ptid (PIDGET (ptid)));
80246283Sdfr}
80346283Sdfr
80446283Sdfr/* Fork an inferior process, and start debugging it with /proc.  */
80546283Sdfr
80646283Sdfrstatic void
80798944Sobriensol_thread_create_inferior (char *exec_file, char *allargs, char **env)
80846283Sdfr{
80946283Sdfr  procfs_ops.to_create_inferior (exec_file, allargs, env);
81046283Sdfr
81198944Sobrien  if (sol_thread_active && !ptid_equal (inferior_ptid, null_ptid))
81246283Sdfr    {
81398944Sobrien      main_ph.ptid = inferior_ptid;	/* Save for xfer_memory */
81446283Sdfr
81546283Sdfr      push_target (&sol_thread_ops);
81646283Sdfr
81798944Sobrien      inferior_ptid = lwp_to_thread (inferior_ptid);
81898944Sobrien      if (PIDGET (inferior_ptid) == -1)
81998944Sobrien	inferior_ptid = main_ph.ptid;
82046283Sdfr
82198944Sobrien      if (!in_thread_list (inferior_ptid))
82298944Sobrien	add_thread (inferior_ptid);
82346283Sdfr    }
82446283Sdfr}
82546283Sdfr
82646283Sdfr/* This routine is called whenever a new symbol table is read in, or when all
82746283Sdfr   symbol tables are removed.  libthread_db can only be initialized when it
82846283Sdfr   finds the right variables in libthread.so.  Since it's a shared library,
82946283Sdfr   those variables don't show up until the library gets mapped and the symbol
83046283Sdfr   table is read in.  */
83146283Sdfr
832130803Smarcel/* This new_objfile event is now managed by a chained function pointer.
83398944Sobrien * It is the callee's responsability to call the next client on the chain.
83498944Sobrien */
83598944Sobrien
83698944Sobrien/* Saved pointer to previous owner of the new_objfile event. */
83798944Sobrienstatic void (*target_new_objfile_chain) (struct objfile *);
83898944Sobrien
83946283Sdfrvoid
84098944Sobriensol_thread_new_objfile (struct objfile *objfile)
84146283Sdfr{
84246283Sdfr  td_err_e val;
84346283Sdfr
84446283Sdfr  if (!objfile)
84546283Sdfr    {
84646283Sdfr      sol_thread_active = 0;
84798944Sobrien      goto quit;
84846283Sdfr    }
84946283Sdfr
85046283Sdfr  /* don't do anything if init failed to resolve the libthread_db library */
85146283Sdfr  if (!procfs_suppress_run)
85298944Sobrien    goto quit;
85346283Sdfr
85446283Sdfr  /* Now, initialize the thread debugging library.  This needs to be done after
85546283Sdfr     the shared libraries are located because it needs information from the
85646283Sdfr     user's thread library.  */
85746283Sdfr
85846283Sdfr  val = p_td_init ();
85946283Sdfr  if (val != TD_OK)
86098944Sobrien    {
86198944Sobrien      warning ("sol_thread_new_objfile: td_init: %s", td_err_string (val));
86298944Sobrien      goto quit;
86398944Sobrien    }
86446283Sdfr
86546283Sdfr  val = p_td_ta_new (&main_ph, &main_ta);
86646283Sdfr  if (val == TD_NOLIBTHREAD)
86798944Sobrien    goto quit;
86846283Sdfr  else if (val != TD_OK)
86998944Sobrien    {
87098944Sobrien      warning ("sol_thread_new_objfile: td_ta_new: %s", td_err_string (val));
87198944Sobrien      goto quit;
87298944Sobrien    }
87346283Sdfr
87446283Sdfr  sol_thread_active = 1;
87598944Sobrienquit:
87698944Sobrien  /* Call predecessor on chain, if any. */
87798944Sobrien  if (target_new_objfile_chain)
87898944Sobrien    target_new_objfile_chain (objfile);
87946283Sdfr}
88046283Sdfr
88146283Sdfr/* Clean up after the inferior dies.  */
88246283Sdfr
88346283Sdfrstatic void
88498944Sobriensol_thread_mourn_inferior (void)
88546283Sdfr{
88646283Sdfr  unpush_target (&sol_thread_ops);
88746283Sdfr  procfs_ops.to_mourn_inferior ();
88846283Sdfr}
88946283Sdfr
89046283Sdfr/* Mark our target-struct as eligible for stray "run" and "attach" commands.  */
89146283Sdfr
89246283Sdfrstatic int
89398944Sobriensol_thread_can_run (void)
89446283Sdfr{
89546283Sdfr  return procfs_suppress_run;
89646283Sdfr}
89746283Sdfr
898130803Smarcel/*
89946283Sdfr
90098944Sobrien   LOCAL FUNCTION
90146283Sdfr
90298944Sobrien   sol_thread_alive     - test thread for "aliveness"
90346283Sdfr
90498944Sobrien   SYNOPSIS
90546283Sdfr
90698944Sobrien   static bool sol_thread_alive (ptid_t ptid);
90746283Sdfr
90898944Sobrien   DESCRIPTION
90946283Sdfr
91098944Sobrien   returns true if thread still active in inferior.
91146283Sdfr
91246283Sdfr */
91346283Sdfr
91446283Sdfrstatic int
91598944Sobriensol_thread_alive (ptid_t ptid)
91646283Sdfr{
91798944Sobrien  if (is_thread (ptid))		/* non-kernel thread */
91846283Sdfr    {
91946283Sdfr      td_err_e val;
92046283Sdfr      td_thrhandle_t th;
92198944Sobrien      int pid;
92246283Sdfr
92398944Sobrien      pid = GET_THREAD (ptid);
92446283Sdfr      if ((val = p_td_ta_map_id2thr (main_ta, pid, &th)) != TD_OK)
92598944Sobrien	return 0;		/* thread not found */
92646283Sdfr      if ((val = p_td_thr_validate (&th)) != TD_OK)
92798944Sobrien	return 0;		/* thread not valid */
92898944Sobrien      return 1;			/* known thread: return true */
92946283Sdfr    }
93098944Sobrien  else
93198944Sobrien    /* kernel thread (LWP): let procfs test it */
93246283Sdfr    {
93346283Sdfr      if (target_has_execution)
93498944Sobrien	return procfs_ops.to_thread_alive (ptid);
93546283Sdfr      else
93698944Sobrien	return orig_core_ops.to_thread_alive (ptid);
93746283Sdfr    }
93846283Sdfr}
93946283Sdfr
94046283Sdfrstatic void
94198944Sobriensol_thread_stop (void)
94246283Sdfr{
94346283Sdfr  procfs_ops.to_stop ();
94446283Sdfr}
94546283Sdfr
94646283Sdfr/* These routines implement the lower half of the thread_db interface.  Ie: the
94746283Sdfr   ps_* routines.  */
94846283Sdfr
94946283Sdfr/* Various versions of <proc_service.h> have slightly
95046283Sdfr   different function prototypes.  In particular, we have
95146283Sdfr
95298944Sobrien   NEWER                        OLDER
95398944Sobrien   struct ps_prochandle *       const struct ps_prochandle *
95498944Sobrien   void*                        char*
95598944Sobrien   const void*          char*
95698944Sobrien   int                  size_t
95746283Sdfr
95846283Sdfr   Which one you have depends on solaris version and what
95946283Sdfr   patches you've applied.  On the theory that there are
96046283Sdfr   only two major variants, we have configure check the
96146283Sdfr   prototype of ps_pdwrite (), and use that info to make
96246283Sdfr   appropriate typedefs here. */
96346283Sdfr
96446283Sdfr#ifdef PROC_SERVICE_IS_OLD
96598944Sobrientypedef const struct ps_prochandle *gdb_ps_prochandle_t;
96698944Sobrientypedef char *gdb_ps_read_buf_t;
96798944Sobrientypedef char *gdb_ps_write_buf_t;
96846283Sdfrtypedef int gdb_ps_size_t;
96998944Sobrientypedef paddr_t gdb_ps_addr_t;
97046283Sdfr#else
97198944Sobrientypedef struct ps_prochandle *gdb_ps_prochandle_t;
97298944Sobrientypedef void *gdb_ps_read_buf_t;
97398944Sobrientypedef const void *gdb_ps_write_buf_t;
97446283Sdfrtypedef size_t gdb_ps_size_t;
97598944Sobrientypedef psaddr_t gdb_ps_addr_t;
97646283Sdfr#endif
97746283Sdfr
97846283Sdfr
97946283Sdfr/* The next four routines are called by thread_db to tell us to stop and stop
98046283Sdfr   a particular process or lwp.  Since GDB ensures that these are all stopped
98146283Sdfr   by the time we call anything in thread_db, these routines need to do
98246283Sdfr   nothing.  */
98346283Sdfr
98498944Sobrien/* Process stop */
98598944Sobrien
98646283Sdfrps_err_e
98746283Sdfrps_pstop (gdb_ps_prochandle_t ph)
98846283Sdfr{
98946283Sdfr  return PS_OK;
99046283Sdfr}
99146283Sdfr
99298944Sobrien/* Process continue */
99398944Sobrien
99446283Sdfrps_err_e
99546283Sdfrps_pcontinue (gdb_ps_prochandle_t ph)
99646283Sdfr{
99746283Sdfr  return PS_OK;
99846283Sdfr}
99946283Sdfr
100098944Sobrien/* LWP stop */
100198944Sobrien
100246283Sdfrps_err_e
100346283Sdfrps_lstop (gdb_ps_prochandle_t ph, lwpid_t lwpid)
100446283Sdfr{
100546283Sdfr  return PS_OK;
100646283Sdfr}
100746283Sdfr
100898944Sobrien/* LWP continue */
100998944Sobrien
101046283Sdfrps_err_e
101146283Sdfrps_lcontinue (gdb_ps_prochandle_t ph, lwpid_t lwpid)
101246283Sdfr{
101346283Sdfr  return PS_OK;
101446283Sdfr}
101546283Sdfr
101698944Sobrien/* Looks up the symbol LD_SYMBOL_NAME in the debugger's symbol table.  */
101798944Sobrien
101846283Sdfrps_err_e
101946283Sdfrps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *ld_object_name,
102098944Sobrien		   const char *ld_symbol_name, gdb_ps_addr_t * ld_symbol_addr)
102146283Sdfr{
102246283Sdfr  struct minimal_symbol *ms;
102346283Sdfr
102446283Sdfr  ms = lookup_minimal_symbol (ld_symbol_name, NULL, NULL);
102546283Sdfr
102646283Sdfr  if (!ms)
102746283Sdfr    return PS_NOSYM;
102846283Sdfr
102946283Sdfr  *ld_symbol_addr = SYMBOL_VALUE_ADDRESS (ms);
103046283Sdfr
103146283Sdfr  return PS_OK;
103246283Sdfr}
103346283Sdfr
103446283Sdfr/* Common routine for reading and writing memory.  */
103546283Sdfr
103646283Sdfrstatic ps_err_e
103798944Sobrienrw_common (int dowrite, const struct ps_prochandle *ph, gdb_ps_addr_t addr,
103846283Sdfr	   char *buf, int size)
103946283Sdfr{
104046283Sdfr  struct cleanup *old_chain;
104146283Sdfr
104298944Sobrien  old_chain = save_inferior_ptid ();
104346283Sdfr
104498944Sobrien  if (is_thread (inferior_ptid) ||	/* A thread */
104598944Sobrien      !target_thread_alive (inferior_ptid))	/* An lwp, but not alive */
104698944Sobrien    inferior_ptid = procfs_first_available ();	/* Find any live lwp.  */
104746283Sdfr  /* Note: don't need to call switch_to_thread; we're just reading memory.  */
104846283Sdfr
104998944Sobrien#if defined (__sparcv9)
105098944Sobrien  /* For Sparc64 cross Sparc32, make sure the address has not been
105198944Sobrien     accidentally sign-extended (or whatever) to beyond 32 bits.  */
105298944Sobrien  if (bfd_get_arch_size (exec_bfd) == 32)
105398944Sobrien    addr &= 0xffffffff;
105498944Sobrien#endif
105598944Sobrien
105646283Sdfr  while (size > 0)
105746283Sdfr    {
105846283Sdfr      int cc;
105946283Sdfr
106098944Sobrien      /* FIXME: passing 0 as attrib argument.  */
106146283Sdfr      if (target_has_execution)
1062130803Smarcel	cc = procfs_ops.to_xfer_memory (addr, buf, size,
106398944Sobrien					dowrite, 0, &procfs_ops);
106446283Sdfr      else
1065130803Smarcel	cc = orig_core_ops.to_xfer_memory (addr, buf, size,
106698944Sobrien					   dowrite, 0, &core_ops);
106746283Sdfr
106846283Sdfr      if (cc < 0)
106946283Sdfr	{
107046283Sdfr	  if (dowrite == 0)
107146283Sdfr	    print_sys_errmsg ("rw_common (): read", errno);
107246283Sdfr	  else
107346283Sdfr	    print_sys_errmsg ("rw_common (): write", errno);
107446283Sdfr
107546283Sdfr	  do_cleanups (old_chain);
107646283Sdfr
107746283Sdfr	  return PS_ERR;
107846283Sdfr	}
107998944Sobrien      else if (cc == 0)
108098944Sobrien	{
108198944Sobrien	  if (dowrite == 0)
1082130803Smarcel	    warning ("rw_common (): unable to read at addr 0x%lx",
108398944Sobrien		     (long) addr);
108498944Sobrien	  else
1085130803Smarcel	    warning ("rw_common (): unable to write at addr 0x%lx",
108698944Sobrien		     (long) addr);
108798944Sobrien
108898944Sobrien	  do_cleanups (old_chain);
108998944Sobrien
109098944Sobrien	  return PS_ERR;
109198944Sobrien	}
109298944Sobrien
109346283Sdfr      size -= cc;
109446283Sdfr      buf += cc;
109546283Sdfr    }
109646283Sdfr
109746283Sdfr  do_cleanups (old_chain);
109846283Sdfr
109946283Sdfr  return PS_OK;
110046283Sdfr}
110146283Sdfr
110298944Sobrien/* Copies SIZE bytes from target process .data segment to debugger memory.  */
110398944Sobrien
110446283Sdfrps_err_e
110598944Sobrienps_pdread (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
110646283Sdfr	   gdb_ps_read_buf_t buf, gdb_ps_size_t size)
110746283Sdfr{
110846283Sdfr  return rw_common (0, ph, addr, buf, size);
110946283Sdfr}
111046283Sdfr
111198944Sobrien/* Copies SIZE bytes from debugger memory .data segment to target process.  */
111298944Sobrien
111346283Sdfrps_err_e
111498944Sobrienps_pdwrite (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
111546283Sdfr	    gdb_ps_write_buf_t buf, gdb_ps_size_t size)
111646283Sdfr{
111798944Sobrien  return rw_common (1, ph, addr, (char *) buf, size);
111846283Sdfr}
111946283Sdfr
112098944Sobrien/* Copies SIZE bytes from target process .text segment to debugger memory.  */
112198944Sobrien
112246283Sdfrps_err_e
112398944Sobrienps_ptread (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
112446283Sdfr	   gdb_ps_read_buf_t buf, gdb_ps_size_t size)
112546283Sdfr{
112646283Sdfr  return rw_common (0, ph, addr, buf, size);
112746283Sdfr}
112846283Sdfr
112998944Sobrien/* Copies SIZE bytes from debugger memory .text segment to target process.  */
113098944Sobrien
113146283Sdfrps_err_e
113298944Sobrienps_ptwrite (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
113346283Sdfr	    gdb_ps_write_buf_t buf, gdb_ps_size_t size)
113446283Sdfr{
113598944Sobrien  return rw_common (1, ph, addr, (char *) buf, size);
113646283Sdfr}
113746283Sdfr
113898944Sobrien/* Get integer regs for LWP */
113946283Sdfr
114046283Sdfrps_err_e
114146283Sdfrps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
114246283Sdfr	     prgregset_t gregset)
114346283Sdfr{
114446283Sdfr  struct cleanup *old_chain;
114546283Sdfr
114698944Sobrien  old_chain = save_inferior_ptid ();
114746283Sdfr
114898944Sobrien  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
114998944Sobrien
115046283Sdfr  if (target_has_execution)
115146283Sdfr    procfs_ops.to_fetch_registers (-1);
115246283Sdfr  else
115346283Sdfr    orig_core_ops.to_fetch_registers (-1);
115498944Sobrien  fill_gregset ((gdb_gregset_t *) gregset, -1);
115546283Sdfr
115646283Sdfr  do_cleanups (old_chain);
115746283Sdfr
115846283Sdfr  return PS_OK;
115946283Sdfr}
116046283Sdfr
116198944Sobrien/* Set integer regs for LWP */
116246283Sdfr
116346283Sdfrps_err_e
116446283Sdfrps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
116546283Sdfr	     const prgregset_t gregset)
116646283Sdfr{
116746283Sdfr  struct cleanup *old_chain;
116846283Sdfr
116998944Sobrien  old_chain = save_inferior_ptid ();
117046283Sdfr
117198944Sobrien  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
117298944Sobrien
117398944Sobrien  supply_gregset ((gdb_gregset_t *) gregset);
117446283Sdfr  if (target_has_execution)
117546283Sdfr    procfs_ops.to_store_registers (-1);
117646283Sdfr  else
117746283Sdfr    orig_core_ops.to_store_registers (-1);
117846283Sdfr
117946283Sdfr  do_cleanups (old_chain);
118046283Sdfr
118146283Sdfr  return PS_OK;
118246283Sdfr}
118346283Sdfr
118498944Sobrien/* Log a message (sends to gdb_stderr).  */
118598944Sobrien
118646283Sdfrvoid
118798944Sobrienps_plog (const char *fmt,...)
118846283Sdfr{
118946283Sdfr  va_list args;
119046283Sdfr
119146283Sdfr  va_start (args, fmt);
119246283Sdfr
119346283Sdfr  vfprintf_filtered (gdb_stderr, fmt, args);
119446283Sdfr}
119546283Sdfr
119646283Sdfr/* Get size of extra register set.  Currently a noop.  */
119746283Sdfr
119846283Sdfrps_err_e
119946283Sdfrps_lgetxregsize (gdb_ps_prochandle_t ph, lwpid_t lwpid, int *xregsize)
120046283Sdfr{
120146283Sdfr#if 0
120246283Sdfr  int lwp_fd;
120346283Sdfr  int regsize;
120446283Sdfr  ps_err_e val;
120546283Sdfr
120646283Sdfr  val = get_lwp_fd (ph, lwpid, &lwp_fd);
120746283Sdfr  if (val != PS_OK)
120846283Sdfr    return val;
120946283Sdfr
121046283Sdfr  if (ioctl (lwp_fd, PIOCGXREGSIZE, &regsize))
121146283Sdfr    {
121246283Sdfr      if (errno == EINVAL)
121346283Sdfr	return PS_NOFREGS;	/* XXX Wrong code, but this is the closest
121446283Sdfr				   thing in proc_service.h  */
121546283Sdfr
121646283Sdfr      print_sys_errmsg ("ps_lgetxregsize (): PIOCGXREGSIZE", errno);
121746283Sdfr      return PS_ERR;
121846283Sdfr    }
121946283Sdfr#endif
122046283Sdfr
122146283Sdfr  return PS_OK;
122246283Sdfr}
122346283Sdfr
122446283Sdfr/* Get extra register set.  Currently a noop.  */
122546283Sdfr
122646283Sdfrps_err_e
122746283Sdfrps_lgetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
122846283Sdfr{
122946283Sdfr#if 0
123046283Sdfr  int lwp_fd;
123146283Sdfr  ps_err_e val;
123246283Sdfr
123346283Sdfr  val = get_lwp_fd (ph, lwpid, &lwp_fd);
123446283Sdfr  if (val != PS_OK)
123546283Sdfr    return val;
123646283Sdfr
123746283Sdfr  if (ioctl (lwp_fd, PIOCGXREG, xregset))
123846283Sdfr    {
123946283Sdfr      print_sys_errmsg ("ps_lgetxregs (): PIOCGXREG", errno);
124046283Sdfr      return PS_ERR;
124146283Sdfr    }
124246283Sdfr#endif
124346283Sdfr
124446283Sdfr  return PS_OK;
124546283Sdfr}
124646283Sdfr
124746283Sdfr/* Set extra register set.  Currently a noop.  */
124846283Sdfr
124946283Sdfrps_err_e
125046283Sdfrps_lsetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
125146283Sdfr{
125246283Sdfr#if 0
125346283Sdfr  int lwp_fd;
125446283Sdfr  ps_err_e val;
125546283Sdfr
125646283Sdfr  val = get_lwp_fd (ph, lwpid, &lwp_fd);
125746283Sdfr  if (val != PS_OK)
125846283Sdfr    return val;
125946283Sdfr
126046283Sdfr  if (ioctl (lwp_fd, PIOCSXREG, xregset))
126146283Sdfr    {
126246283Sdfr      print_sys_errmsg ("ps_lsetxregs (): PIOCSXREG", errno);
126346283Sdfr      return PS_ERR;
126446283Sdfr    }
126546283Sdfr#endif
126646283Sdfr
126746283Sdfr  return PS_OK;
126846283Sdfr}
126946283Sdfr
127098944Sobrien/* Get floating-point regs for LWP */
127146283Sdfr
127246283Sdfrps_err_e
127346283Sdfrps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
127498944Sobrien	       prfpregset_t * fpregset)
127546283Sdfr{
127646283Sdfr  struct cleanup *old_chain;
127746283Sdfr
127898944Sobrien  old_chain = save_inferior_ptid ();
127946283Sdfr
128098944Sobrien  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
128146283Sdfr
128246283Sdfr  if (target_has_execution)
128346283Sdfr    procfs_ops.to_fetch_registers (-1);
128446283Sdfr  else
128546283Sdfr    orig_core_ops.to_fetch_registers (-1);
128698944Sobrien  fill_fpregset ((gdb_fpregset_t *) fpregset, -1);
128746283Sdfr
128846283Sdfr  do_cleanups (old_chain);
128946283Sdfr
129046283Sdfr  return PS_OK;
129146283Sdfr}
129246283Sdfr
129398944Sobrien/* Set floating-point regs for LWP */
129446283Sdfr
129546283Sdfrps_err_e
129646283Sdfrps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
129798944Sobrien	       const prfpregset_t * fpregset)
129846283Sdfr{
129946283Sdfr  struct cleanup *old_chain;
130046283Sdfr
130198944Sobrien  old_chain = save_inferior_ptid ();
130246283Sdfr
130398944Sobrien  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
130498944Sobrien
130598944Sobrien  supply_fpregset ((gdb_fpregset_t *) fpregset);
130646283Sdfr  if (target_has_execution)
130746283Sdfr    procfs_ops.to_store_registers (-1);
130846283Sdfr  else
130946283Sdfr    orig_core_ops.to_store_registers (-1);
131046283Sdfr
131146283Sdfr  do_cleanups (old_chain);
131246283Sdfr
131346283Sdfr  return PS_OK;
131446283Sdfr}
131546283Sdfr
131698944Sobrien#ifdef PR_MODEL_LP64
131798944Sobrien/* Identify process as 32-bit or 64-bit.
131898944Sobrien   At the moment I'm using bfd to do this.
131998944Sobrien   There might be a more solaris-specific (eg. procfs) method,
132098944Sobrien   but this ought to work.  */
132146283Sdfr
132298944Sobrienps_err_e
132398944Sobrienps_pdmodel (gdb_ps_prochandle_t ph, int *data_model)
132498944Sobrien{
132598944Sobrien  if (exec_bfd == 0)
132698944Sobrien    *data_model = PR_MODEL_UNKNOWN;
132798944Sobrien  else if (bfd_get_arch_size (exec_bfd) == 32)
132898944Sobrien    *data_model = PR_MODEL_ILP32;
132998944Sobrien  else
133098944Sobrien    *data_model = PR_MODEL_LP64;
133146283Sdfr
133298944Sobrien  return PS_OK;
133398944Sobrien}
133498944Sobrien#endif /* PR_MODEL_LP64 */
133546283Sdfr
133698944Sobrien#ifdef TM_I386SOL2_H
133746283Sdfr
133898944Sobrien/* Reads the local descriptor table of a LWP.  */
133998944Sobrien
134046283Sdfrps_err_e
134146283Sdfrps_lgetLDT (gdb_ps_prochandle_t ph, lwpid_t lwpid,
134246283Sdfr	    struct ssd *pldt)
134346283Sdfr{
134498944Sobrien  /* NOTE: only used on Solaris, therefore OK to refer to procfs.c */
134598944Sobrien  extern struct ssd *procfs_find_LDT_entry (ptid_t);
134698944Sobrien  struct ssd *ret;
134746283Sdfr
134898944Sobrien  /* FIXME: can't I get the process ID from the prochandle or something?
134998944Sobrien   */
135098944Sobrien
135198944Sobrien  if (PIDGET (inferior_ptid) <= 0 || lwpid <= 0)
135246283Sdfr    return PS_BADLID;
135346283Sdfr
135498944Sobrien  ret = procfs_find_LDT_entry (BUILD_LWP (lwpid, PIDGET (inferior_ptid)));
135598944Sobrien  if (ret)
135646283Sdfr    {
135798944Sobrien      memcpy (pldt, ret, sizeof (struct ssd));
135898944Sobrien      return PS_OK;
135946283Sdfr    }
136098944Sobrien  else	/* LDT not found. */
136146283Sdfr    return PS_ERR;
136298944Sobrien}
136346283Sdfr#endif /* TM_I386SOL2_H */
136446283Sdfr
136546283Sdfr/* Convert a pid to printable form. */
136646283Sdfr
136746283Sdfrchar *
136898944Sobriensolaris_pid_to_str (ptid_t ptid)
136946283Sdfr{
137046283Sdfr  static char buf[100];
137146283Sdfr
137246283Sdfr  /* in case init failed to resolve the libthread_db library */
137346283Sdfr  if (!procfs_suppress_run)
137498944Sobrien    return procfs_pid_to_str (ptid);
137546283Sdfr
137698944Sobrien  if (is_thread (ptid))
137746283Sdfr    {
137898944Sobrien      ptid_t lwp;
137946283Sdfr
138098944Sobrien      lwp = thread_to_lwp (ptid, -2);
138146283Sdfr
138298944Sobrien      if (PIDGET (lwp) == -1)
138398944Sobrien	sprintf (buf, "Thread %ld (defunct)", GET_THREAD (ptid));
138498944Sobrien      else if (PIDGET (lwp) != -2)
138598944Sobrien	sprintf (buf, "Thread %ld (LWP %ld)", GET_THREAD (ptid), GET_LWP (lwp));
138646283Sdfr      else
138798944Sobrien	sprintf (buf, "Thread %ld        ", GET_THREAD (ptid));
138846283Sdfr    }
138998944Sobrien  else if (GET_LWP (ptid) != 0)
139098944Sobrien    sprintf (buf, "LWP    %ld        ", GET_LWP (ptid));
139146283Sdfr  else
139298944Sobrien    sprintf (buf, "process %d    ", PIDGET (ptid));
139346283Sdfr
139446283Sdfr  return buf;
139546283Sdfr}
139646283Sdfr
139746283Sdfr
139846283Sdfr/* Worker bee for find_new_threads
139946283Sdfr   Callback function that gets called once per USER thread (i.e., not
140046283Sdfr   kernel) thread. */
140146283Sdfr
140246283Sdfrstatic int
140398944Sobriensol_find_new_threads_callback (const td_thrhandle_t *th, void *ignored)
140446283Sdfr{
140546283Sdfr  td_err_e retval;
140646283Sdfr  td_thrinfo_t ti;
140798944Sobrien  ptid_t ptid;
140846283Sdfr
140998944Sobrien  if ((retval = p_td_thr_get_info (th, &ti)) != TD_OK)
141046283Sdfr    {
141146283Sdfr      return -1;
141246283Sdfr    }
141398944Sobrien  ptid = BUILD_THREAD (ti.ti_tid, PIDGET (inferior_ptid));
141498944Sobrien  if (!in_thread_list (ptid))
141598944Sobrien    add_thread (ptid);
141646283Sdfr
141746283Sdfr  return 0;
141846283Sdfr}
141946283Sdfr
142098944Sobrienstatic void
142198944Sobriensol_find_new_threads (void)
142246283Sdfr{
142346283Sdfr  /* don't do anything if init failed to resolve the libthread_db library */
142446283Sdfr  if (!procfs_suppress_run)
142546283Sdfr    return;
142646283Sdfr
142798944Sobrien  if (PIDGET (inferior_ptid) == -1)
142846283Sdfr    {
142998944Sobrien      printf_filtered ("No process.\n");
143046283Sdfr      return;
143146283Sdfr    }
143298944Sobrien  procfs_ops.to_find_new_threads ();	/* first find new kernel threads */
143398944Sobrien  p_td_ta_thr_iter (main_ta, sol_find_new_threads_callback, (void *) 0,
143446283Sdfr		    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
143546283Sdfr		    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
143646283Sdfr}
143746283Sdfr
143846283Sdfrstatic void
143998944Sobriensol_core_open (char *filename, int from_tty)
144046283Sdfr{
144146283Sdfr  orig_core_ops.to_open (filename, from_tty);
144246283Sdfr}
144346283Sdfr
144446283Sdfrstatic void
144598944Sobriensol_core_close (int quitting)
144646283Sdfr{
144746283Sdfr  orig_core_ops.to_close (quitting);
144846283Sdfr}
144946283Sdfr
145046283Sdfrstatic void
145198944Sobriensol_core_detach (char *args, int from_tty)
145246283Sdfr{
145346283Sdfr  unpush_target (&core_ops);
145446283Sdfr  orig_core_ops.to_detach (args, from_tty);
145546283Sdfr}
145646283Sdfr
145746283Sdfrstatic void
145898944Sobriensol_core_files_info (struct target_ops *t)
145946283Sdfr{
146046283Sdfr  orig_core_ops.to_files_info (t);
146146283Sdfr}
146246283Sdfr
146346283Sdfr/* Worker bee for info sol-thread command.  This is a callback function that
1464130803Smarcel   gets called once for each Solaris thread (ie. not kernel thread) in the
146546283Sdfr   inferior.  Print anything interesting that we can think of.  */
146646283Sdfr
146798944Sobrienstatic int
146898944Sobrieninfo_cb (const td_thrhandle_t *th, void *s)
146946283Sdfr{
147046283Sdfr  td_err_e ret;
147146283Sdfr  td_thrinfo_t ti;
147246283Sdfr
147346283Sdfr  if ((ret = p_td_thr_get_info (th, &ti)) == TD_OK)
147446283Sdfr    {
147598944Sobrien      printf_filtered ("%s thread #%d, lwp %d, ",
147698944Sobrien		       ti.ti_type == TD_THR_SYSTEM ? "system" : "user  ",
147746283Sdfr		       ti.ti_tid, ti.ti_lid);
147898944Sobrien      switch (ti.ti_state)
147998944Sobrien	{
148046283Sdfr	default:
148198944Sobrien	case TD_THR_UNKNOWN:
148298944Sobrien	  printf_filtered ("<unknown state>");
148398944Sobrien	  break;
148498944Sobrien	case TD_THR_STOPPED:
148598944Sobrien	  printf_filtered ("(stopped)");
148698944Sobrien	  break;
148798944Sobrien	case TD_THR_RUN:
148898944Sobrien	  printf_filtered ("(run)    ");
148998944Sobrien	  break;
149098944Sobrien	case TD_THR_ACTIVE:
149198944Sobrien	  printf_filtered ("(active) ");
149298944Sobrien	  break;
149398944Sobrien	case TD_THR_ZOMBIE:
149498944Sobrien	  printf_filtered ("(zombie) ");
149598944Sobrien	  break;
149698944Sobrien	case TD_THR_SLEEP:
149798944Sobrien	  printf_filtered ("(asleep) ");
149898944Sobrien	  break;
149998944Sobrien	case TD_THR_STOPPED_ASLEEP:
150098944Sobrien	  printf_filtered ("(stopped asleep)");
150198944Sobrien	  break;
150298944Sobrien	}
150346283Sdfr      /* Print thr_create start function: */
150446283Sdfr      if (ti.ti_startfunc != 0)
150598944Sobrien	{
150698944Sobrien	  struct minimal_symbol *msym;
150798944Sobrien	  msym = lookup_minimal_symbol_by_pc (ti.ti_startfunc);
150898944Sobrien	  if (msym)
1509130803Smarcel	    printf_filtered ("   startfunc: %s\n", DEPRECATED_SYMBOL_NAME (msym));
151098944Sobrien	  else
151198944Sobrien	    printf_filtered ("   startfunc: 0x%s\n", paddr (ti.ti_startfunc));
151298944Sobrien	}
151346283Sdfr
151446283Sdfr      /* If thread is asleep, print function that went to sleep: */
151546283Sdfr      if (ti.ti_state == TD_THR_SLEEP)
151698944Sobrien	{
151798944Sobrien	  struct minimal_symbol *msym;
151898944Sobrien	  msym = lookup_minimal_symbol_by_pc (ti.ti_pc);
151998944Sobrien	  if (msym)
1520130803Smarcel	    printf_filtered (" - Sleep func: %s\n", DEPRECATED_SYMBOL_NAME (msym));
152198944Sobrien	  else
152298944Sobrien	    printf_filtered (" - Sleep func: 0x%s\n", paddr (ti.ti_startfunc));
152398944Sobrien	}
152446283Sdfr
152546283Sdfr      /* Wrap up line, if necessary */
152646283Sdfr      if (ti.ti_state != TD_THR_SLEEP && ti.ti_startfunc == 0)
152746283Sdfr	printf_filtered ("\n");	/* don't you hate counting newlines? */
152846283Sdfr    }
152946283Sdfr  else
153046283Sdfr    warning ("info sol-thread: failed to get info for thread.");
153146283Sdfr
153298944Sobrien  return 0;
153346283Sdfr}
153446283Sdfr
153546283Sdfr/* List some state about each Solaris user thread in the inferior.  */
153646283Sdfr
153746283Sdfrstatic void
153898944Sobrieninfo_solthreads (char *args, int from_tty)
153946283Sdfr{
154098944Sobrien  p_td_ta_thr_iter (main_ta, info_cb, args,
154146283Sdfr		    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
154246283Sdfr		    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
154346283Sdfr}
154446283Sdfr
154546283Sdfrstatic int
1546130803Smarcelsol_find_memory_regions (int (*func) (CORE_ADDR,
1547130803Smarcel				      unsigned long,
1548130803Smarcel				      int, int, int,
1549130803Smarcel				      void *),
155098944Sobrien			 void *data)
155146283Sdfr{
155298944Sobrien  return procfs_ops.to_find_memory_regions (func, data);
155398944Sobrien}
155498944Sobrien
155598944Sobrienstatic char *
155698944Sobriensol_make_note_section (bfd *obfd, int *note_size)
155798944Sobrien{
155898944Sobrien  return procfs_ops.to_make_corefile_notes (obfd, note_size);
155998944Sobrien}
156098944Sobrien
156198944Sobrienstatic int
156298944Sobrienignore (CORE_ADDR addr, char *contents)
156398944Sobrien{
156446283Sdfr  return 0;
156546283Sdfr}
156646283Sdfr
156746283Sdfr
156846283Sdfrstatic void
156998944Sobrieninit_sol_thread_ops (void)
157046283Sdfr{
157146283Sdfr  sol_thread_ops.to_shortname = "solaris-threads";
157246283Sdfr  sol_thread_ops.to_longname = "Solaris threads and pthread.";
157346283Sdfr  sol_thread_ops.to_doc = "Solaris threads and pthread support.";
157446283Sdfr  sol_thread_ops.to_open = sol_thread_open;
157546283Sdfr  sol_thread_ops.to_attach = sol_thread_attach;
157646283Sdfr  sol_thread_ops.to_detach = sol_thread_detach;
157746283Sdfr  sol_thread_ops.to_resume = sol_thread_resume;
157846283Sdfr  sol_thread_ops.to_wait = sol_thread_wait;
157946283Sdfr  sol_thread_ops.to_fetch_registers = sol_thread_fetch_registers;
158046283Sdfr  sol_thread_ops.to_store_registers = sol_thread_store_registers;
158146283Sdfr  sol_thread_ops.to_prepare_to_store = sol_thread_prepare_to_store;
158246283Sdfr  sol_thread_ops.to_xfer_memory = sol_thread_xfer_memory;
1583130803Smarcel  sol_thread_ops.to_xfer_partial = sol_thread_xfer_partial;
158446283Sdfr  sol_thread_ops.to_files_info = sol_thread_files_info;
158546283Sdfr  sol_thread_ops.to_insert_breakpoint = memory_insert_breakpoint;
158646283Sdfr  sol_thread_ops.to_remove_breakpoint = memory_remove_breakpoint;
158746283Sdfr  sol_thread_ops.to_terminal_init = terminal_init_inferior;
158846283Sdfr  sol_thread_ops.to_terminal_inferior = terminal_inferior;
158946283Sdfr  sol_thread_ops.to_terminal_ours_for_output = terminal_ours_for_output;
159046283Sdfr  sol_thread_ops.to_terminal_ours = terminal_ours;
1591130803Smarcel  sol_thread_ops.to_terminal_save_ours = terminal_save_ours;
159246283Sdfr  sol_thread_ops.to_terminal_info = child_terminal_info;
159346283Sdfr  sol_thread_ops.to_kill = sol_thread_kill_inferior;
159446283Sdfr  sol_thread_ops.to_create_inferior = sol_thread_create_inferior;
159546283Sdfr  sol_thread_ops.to_mourn_inferior = sol_thread_mourn_inferior;
159646283Sdfr  sol_thread_ops.to_can_run = sol_thread_can_run;
159746283Sdfr  sol_thread_ops.to_notice_signals = sol_thread_notice_signals;
159846283Sdfr  sol_thread_ops.to_thread_alive = sol_thread_alive;
159998944Sobrien  sol_thread_ops.to_pid_to_str = solaris_pid_to_str;
160098944Sobrien  sol_thread_ops.to_find_new_threads = sol_find_new_threads;
160146283Sdfr  sol_thread_ops.to_stop = sol_thread_stop;
160246283Sdfr  sol_thread_ops.to_stratum = process_stratum;
160346283Sdfr  sol_thread_ops.to_has_all_memory = 1;
160446283Sdfr  sol_thread_ops.to_has_memory = 1;
160546283Sdfr  sol_thread_ops.to_has_stack = 1;
160646283Sdfr  sol_thread_ops.to_has_registers = 1;
160746283Sdfr  sol_thread_ops.to_has_execution = 1;
160846283Sdfr  sol_thread_ops.to_has_thread_control = tc_none;
160998944Sobrien  sol_thread_ops.to_find_memory_regions = sol_find_memory_regions;
161098944Sobrien  sol_thread_ops.to_make_corefile_notes = sol_make_note_section;
161146283Sdfr  sol_thread_ops.to_magic = OPS_MAGIC;
161246283Sdfr}
161346283Sdfr
161446283Sdfr
161546283Sdfrstatic void
161698944Sobrieninit_sol_core_ops (void)
161746283Sdfr{
161898944Sobrien  sol_core_ops.to_shortname = "solaris-core";
161998944Sobrien  sol_core_ops.to_longname = "Solaris core threads and pthread.";
162098944Sobrien  sol_core_ops.to_doc = "Solaris threads and pthread support for core files.";
162198944Sobrien  sol_core_ops.to_open = sol_core_open;
162298944Sobrien  sol_core_ops.to_close = sol_core_close;
162398944Sobrien  sol_core_ops.to_attach = sol_thread_attach;
162498944Sobrien  sol_core_ops.to_detach = sol_core_detach;
162598944Sobrien  sol_core_ops.to_fetch_registers = sol_thread_fetch_registers;
162698944Sobrien  sol_core_ops.to_xfer_memory = sol_thread_xfer_memory;
1627130803Smarcel  sol_core_ops.to_xfer_partial = sol_thread_xfer_partial;
162898944Sobrien  sol_core_ops.to_files_info = sol_core_files_info;
162998944Sobrien  sol_core_ops.to_insert_breakpoint = ignore;
163098944Sobrien  sol_core_ops.to_remove_breakpoint = ignore;
163198944Sobrien  sol_core_ops.to_create_inferior = sol_thread_create_inferior;
163298944Sobrien  sol_core_ops.to_stratum = core_stratum;
163398944Sobrien  sol_core_ops.to_has_memory = 1;
163498944Sobrien  sol_core_ops.to_has_stack = 1;
163598944Sobrien  sol_core_ops.to_has_registers = 1;
163698944Sobrien  sol_core_ops.to_has_thread_control = tc_none;
163798944Sobrien  sol_core_ops.to_thread_alive = sol_thread_alive;
163898944Sobrien  sol_core_ops.to_pid_to_str = solaris_pid_to_str;
163998944Sobrien  /* On Solaris/x86, when debugging a threaded core file from process <n>,
164098944Sobrien     the following causes "info threads" to produce "procfs: couldn't find pid
164198944Sobrien     <n> in procinfo list" where <n> is the pid of the process that produced
164298944Sobrien     the core file.  Disable it for now. */
164398944Sobrien  /* sol_core_ops.to_find_new_threads = sol_find_new_threads; */
164498944Sobrien  sol_core_ops.to_magic = OPS_MAGIC;
164546283Sdfr}
164646283Sdfr
164746283Sdfr/* we suppress the call to add_target of core_ops in corelow because
164846283Sdfr   if there are two targets in the stratum core_stratum, find_core_target
164946283Sdfr   won't know which one to return.  see corelow.c for an additonal
165046283Sdfr   comment on coreops_suppress_target. */
165146283Sdfrint coreops_suppress_target = 1;
165246283Sdfr
165346283Sdfrvoid
165498944Sobrien_initialize_sol_thread (void)
165546283Sdfr{
165646283Sdfr  void *dlhandle;
165746283Sdfr
165846283Sdfr  init_sol_thread_ops ();
165946283Sdfr  init_sol_core_ops ();
166046283Sdfr
166146283Sdfr  dlhandle = dlopen ("libthread_db.so.1", RTLD_NOW);
166246283Sdfr  if (!dlhandle)
166346283Sdfr    goto die;
166446283Sdfr
166546283Sdfr#define resolve(X) \
166646283Sdfr  if (!(p_##X = dlsym (dlhandle, #X))) \
166746283Sdfr    goto die;
166846283Sdfr
166946283Sdfr  resolve (td_log);
167046283Sdfr  resolve (td_ta_new);
167146283Sdfr  resolve (td_ta_delete);
167246283Sdfr  resolve (td_init);
167346283Sdfr  resolve (td_ta_get_ph);
167446283Sdfr  resolve (td_ta_get_nthreads);
167546283Sdfr  resolve (td_ta_tsd_iter);
167646283Sdfr  resolve (td_ta_thr_iter);
167746283Sdfr  resolve (td_thr_validate);
167846283Sdfr  resolve (td_thr_tsd);
167946283Sdfr  resolve (td_thr_get_info);
168046283Sdfr  resolve (td_thr_getfpregs);
168146283Sdfr  resolve (td_thr_getxregsize);
168246283Sdfr  resolve (td_thr_getxregs);
168346283Sdfr  resolve (td_thr_sigsetmask);
168446283Sdfr  resolve (td_thr_setprio);
168546283Sdfr  resolve (td_thr_setsigpending);
168646283Sdfr  resolve (td_thr_setfpregs);
168746283Sdfr  resolve (td_thr_setxregs);
168846283Sdfr  resolve (td_ta_map_id2thr);
168946283Sdfr  resolve (td_ta_map_lwp2thr);
169046283Sdfr  resolve (td_thr_getgregs);
169146283Sdfr  resolve (td_thr_setgregs);
169246283Sdfr
169346283Sdfr  add_target (&sol_thread_ops);
169446283Sdfr
169546283Sdfr  procfs_suppress_run = 1;
169646283Sdfr
169798944Sobrien  add_cmd ("sol-threads", class_maintenance, info_solthreads,
169898944Sobrien	   "Show info on Solaris user threads.\n", &maintenanceinfolist);
169946283Sdfr
170098944Sobrien  memcpy (&orig_core_ops, &core_ops, sizeof (struct target_ops));
170198944Sobrien  memcpy (&core_ops, &sol_core_ops, sizeof (struct target_ops));
170246283Sdfr  add_target (&core_ops);
170346283Sdfr
170498944Sobrien  /* Hook into new_objfile notification. */
170598944Sobrien  target_new_objfile_chain = target_new_objfile_hook;
170698944Sobrien  target_new_objfile_hook  = sol_thread_new_objfile;
170746283Sdfr  return;
170846283Sdfr
170998944Sobriendie:
171046283Sdfr
171146283Sdfr  fprintf_unfiltered (gdb_stderr, "[GDB will not be able to debug user-mode threads: %s]\n", dlerror ());
171246283Sdfr
171346283Sdfr  if (dlhandle)
171446283Sdfr    dlclose (dlhandle);
171546283Sdfr
171646283Sdfr  /* allow the user to debug non-threaded core files */
171798944Sobrien  add_target (&core_ops);
171846283Sdfr
171946283Sdfr  return;
172046283Sdfr}
1721