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, ®size)) 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