2009-01-30 Julian Brown <julian@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / sol-thread.c
CommitLineData
8d027a04
MK
1/* Solaris threads debugging interface.
2
6aba47ca 3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
0fb0cc75 4 2007, 2008, 2009 Free Software Foundation, Inc.
c906108c 5
c5aa993b 6 This file is part of GDB.
c906108c 7
c5aa993b
JM
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
a9762ec7 10 the Free Software Foundation; either version 3 of the License, or
c5aa993b 11 (at your option) any later version.
c906108c 12
c5aa993b
JM
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
c906108c 17
c5aa993b 18 You should have received a copy of the GNU General Public License
a9762ec7 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
20
21/* This module implements a sort of half target that sits between the
8d027a04
MK
22 machine-independent parts of GDB and the /proc interface (procfs.c)
23 to provide access to the Solaris user-mode thread implementation.
24
25 Solaris threads are true user-mode threads, which are invoked via
26 the thr_* and pthread_* (native and POSIX respectivly) interfaces.
27 These are mostly implemented in user-space, with all thread context
28 kept in various structures that live in the user's heap. These
29 should not be confused with lightweight processes (LWPs), which are
30 implemented by the kernel, and scheduled without explicit
31 intervention by the process.
32
33 Just to confuse things a little, Solaris threads (both native and
34 POSIX) are actually implemented using LWPs. In general, there are
35 going to be more threads than LWPs. There is no fixed
36 correspondence between a thread and an LWP. When a thread wants to
37 run, it gets scheduled onto the first available LWP and can
38 therefore migrate from one LWP to another as time goes on. A
c906108c
SS
39 sleeping thread may not be associated with an LWP at all!
40
8d027a04
MK
41 To make it possible to mess with threads, Sun provides a library
42 called libthread_db.so.1 (not to be confused with
43 libthread_db.so.0, which doesn't have a published interface). This
44 interface has an upper part, which it provides, and a lower part
45 which we provide. The upper part consists of the td_* routines,
46 which allow us to find all the threads, query their state, etc...
47 The lower part consists of all of the ps_*, which are used by the
48 td_* routines to read/write memory, manipulate LWPs, lookup
49 symbols, etc... The ps_* routines actually do most of their work
50 by calling functions in procfs.c. */
c906108c
SS
51
52#include "defs.h"
53#include <thread.h>
54#include <proc_service.h>
55#include <thread_db.h>
56#include "gdbthread.h"
57#include "target.h"
58#include "inferior.h"
59#include <fcntl.h>
b8a92b82 60#include "gdb_stat.h"
c906108c
SS
61#include <dlfcn.h>
62#include "gdbcmd.h"
23e04971 63#include "gdbcore.h"
4e052eda 64#include "regcache.h"
d45b6f32 65#include "solib.h"
990f9fe3 66#include "symfile.h"
06d3b283 67#include "observer.h"
c906108c 68
6f4492c8
MK
69#include "gdb_string.h"
70
c5aa993b
JM
71extern struct target_ops sol_thread_ops; /* Forward declaration */
72extern struct target_ops sol_core_ops; /* Forward declaration */
c906108c
SS
73
74/* place to store core_ops before we overwrite it */
75static struct target_ops orig_core_ops;
76
77struct target_ops sol_thread_ops;
78struct target_ops sol_core_ops;
79
80extern int procfs_suppress_run;
c5aa993b
JM
81extern struct target_ops procfs_ops; /* target vector for procfs.c */
82extern struct target_ops core_ops; /* target vector for corelow.c */
39f77062 83extern char *procfs_pid_to_str (ptid_t ptid);
c906108c 84
c60c0f5f
MS
85/* Prototypes for supply_gregset etc. */
86#include "gregset.h"
c906108c 87
8d027a04
MK
88/* This struct is defined by us, but mainly used for the proc_service
89 interface. We don't have much use for it, except as a handy place
90 to get a real PID for memory accesses. */
c906108c
SS
91
92struct ps_prochandle
8d027a04
MK
93{
94 ptid_t ptid;
95};
c906108c
SS
96
97struct string_map
8d027a04
MK
98{
99 int num;
100 char *str;
101};
c906108c
SS
102
103static struct ps_prochandle main_ph;
104static td_thragent_t *main_ta;
105static int sol_thread_active = 0;
106
39f77062 107static void sol_thread_resume (ptid_t ptid, int step, enum target_signal signo);
39f77062 108static int sol_thread_alive (ptid_t ptid);
a14ed312
KB
109static void sol_core_close (int quitting);
110
111static void init_sol_thread_ops (void);
112static void init_sol_core_ops (void);
c906108c 113
8d027a04
MK
114/* Default definitions: These must be defined in tm.h if they are to
115 be shared with a process module such as procfs. */
d4f3574e 116
ca6724c1
KB
117#define GET_PID(ptid) ptid_get_pid (ptid)
118#define GET_LWP(ptid) ptid_get_lwp (ptid)
119#define GET_THREAD(ptid) ptid_get_tid (ptid)
120
121#define is_lwp(ptid) (GET_LWP (ptid) != 0)
122#define is_thread(ptid) (GET_THREAD (ptid) != 0)
123
124#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
125#define BUILD_THREAD(tid, pid) ptid_build (pid, 0, tid)
c906108c 126
8d027a04
MK
127/* Pointers to routines from libthread_db resolved by dlopen(). */
128
129static void (*p_td_log)(const int on_off);
130static td_err_e (*p_td_ta_new)(const struct ps_prochandle *ph_p,
131 td_thragent_t **ta_pp);
132static td_err_e (*p_td_ta_delete)(td_thragent_t *ta_p);
133static td_err_e (*p_td_init)(void);
134static td_err_e (*p_td_ta_get_ph)(const td_thragent_t *ta_p,
135 struct ps_prochandle **ph_pp);
136static td_err_e (*p_td_ta_get_nthreads)(const td_thragent_t *ta_p,
137 int *nthread_p);
138static td_err_e (*p_td_ta_tsd_iter)(const td_thragent_t *ta_p,
139 td_key_iter_f *cb, void *cbdata_p);
140static td_err_e (*p_td_ta_thr_iter)(const td_thragent_t *ta_p,
141 td_thr_iter_f *cb, void *cbdata_p,
142 td_thr_state_e state, int ti_pri,
143 sigset_t *ti_sigmask_p,
144 unsigned ti_user_flags);
145static td_err_e (*p_td_thr_validate)(const td_thrhandle_t *th_p);
146static td_err_e (*p_td_thr_tsd)(const td_thrhandle_t * th_p,
147 const thread_key_t key, void **data_pp);
148static td_err_e (*p_td_thr_get_info)(const td_thrhandle_t *th_p,
149 td_thrinfo_t *ti_p);
150static td_err_e (*p_td_thr_getfpregs)(const td_thrhandle_t *th_p,
151 prfpregset_t *fpregset);
152static td_err_e (*p_td_thr_getxregsize)(const td_thrhandle_t *th_p,
153 int *xregsize);
154static td_err_e (*p_td_thr_getxregs)(const td_thrhandle_t *th_p,
155 const caddr_t xregset);
156static td_err_e (*p_td_thr_sigsetmask)(const td_thrhandle_t *th_p,
157 const sigset_t ti_sigmask);
158static td_err_e (*p_td_thr_setprio)(const td_thrhandle_t *th_p,
159 const int ti_pri);
160static td_err_e (*p_td_thr_setsigpending)(const td_thrhandle_t *th_p,
161 const uchar_t ti_pending_flag,
162 const sigset_t ti_pending);
163static td_err_e (*p_td_thr_setfpregs)(const td_thrhandle_t *th_p,
164 const prfpregset_t *fpregset);
165static td_err_e (*p_td_thr_setxregs)(const td_thrhandle_t *th_p,
166 const caddr_t xregset);
167static td_err_e (*p_td_ta_map_id2thr)(const td_thragent_t *ta_p,
168 thread_t tid,
169 td_thrhandle_t *th_p);
170static td_err_e (*p_td_ta_map_lwp2thr)(const td_thragent_t *ta_p,
171 lwpid_t lwpid,
172 td_thrhandle_t *th_p);
173static td_err_e (*p_td_thr_getgregs)(const td_thrhandle_t *th_p,
174 prgregset_t regset);
175static td_err_e (*p_td_thr_setgregs)(const td_thrhandle_t *th_p,
176 const prgregset_t regset);
177\f
c906108c 178
8d027a04
MK
179/* Return the libthread_db error string associated with ERRCODE. If
180 ERRCODE is unknown, return an appropriate message. */
c906108c
SS
181
182static char *
fba45db2 183td_err_string (td_err_e errcode)
c906108c 184{
8d027a04 185 static struct string_map td_err_table[] =
c5aa993b 186 {
8d027a04
MK
187 { TD_OK, "generic \"call succeeded\"" },
188 { TD_ERR, "generic error." },
189 { TD_NOTHR, "no thread can be found to satisfy query" },
190 { TD_NOSV, "no synch. variable can be found to satisfy query" },
191 { TD_NOLWP, "no lwp can be found to satisfy query" },
192 { TD_BADPH, "invalid process handle" },
193 { TD_BADTH, "invalid thread handle" },
194 { TD_BADSH, "invalid synchronization handle" },
195 { TD_BADTA, "invalid thread agent" },
196 { TD_BADKEY, "invalid key" },
197 { TD_NOMSG, "td_thr_event_getmsg() called when there was no message" },
198 { TD_NOFPREGS, "FPU register set not available for given thread" },
199 { TD_NOLIBTHREAD, "application not linked with libthread" },
200 { TD_NOEVENT, "requested event is not supported" },
201 { TD_NOCAPAB, "capability not available" },
202 { TD_DBERR, "Debugger service failed" },
203 { TD_NOAPLIC, "Operation not applicable to" },
204 { TD_NOTSD, "No thread specific data for this thread" },
205 { TD_MALLOC, "Malloc failed" },
206 { TD_PARTIALREG, "Only part of register set was written/read" },
207 { TD_NOXREGS, "X register set not available for given thread" }
c5aa993b 208 };
c906108c
SS
209 const int td_err_size = sizeof td_err_table / sizeof (struct string_map);
210 int i;
211 static char buf[50];
212
213 for (i = 0; i < td_err_size; i++)
214 if (td_err_table[i].num == errcode)
215 return td_err_table[i].str;
c5aa993b 216
8d027a04 217 sprintf (buf, "Unknown libthread_db error code: %d", errcode);
c906108c
SS
218
219 return buf;
220}
c906108c 221
8d027a04
MK
222/* Return the the libthread_db state string assicoated with STATECODE.
223 If STATECODE is unknown, return an appropriate message. */
c906108c
SS
224
225static char *
fba45db2 226td_state_string (td_thr_state_e statecode)
c906108c 227{
8d027a04 228 static struct string_map td_thr_state_table[] =
c5aa993b 229 {
8d027a04
MK
230 { TD_THR_ANY_STATE, "any state" },
231 { TD_THR_UNKNOWN, "unknown" },
232 { TD_THR_STOPPED, "stopped" },
233 { TD_THR_RUN, "run" },
234 { TD_THR_ACTIVE, "active" },
235 { TD_THR_ZOMBIE, "zombie" },
236 { TD_THR_SLEEP, "sleep" },
237 { TD_THR_STOPPED_ASLEEP, "stopped asleep" }
c5aa993b 238 };
8d027a04
MK
239 const int td_thr_state_table_size =
240 sizeof td_thr_state_table / sizeof (struct string_map);
c906108c
SS
241 int i;
242 static char buf[50];
243
244 for (i = 0; i < td_thr_state_table_size; i++)
245 if (td_thr_state_table[i].num == statecode)
246 return td_thr_state_table[i].str;
c5aa993b 247
8d027a04 248 sprintf (buf, "Unknown libthread_db state code: %d", statecode);
c906108c
SS
249
250 return buf;
251}
252\f
c906108c 253
8d027a04
MK
254/* Convert a POSIX or Solaris thread ID into a LWP ID. If THREAD_ID
255 doesn't exist, that's an error. If it's an inactive thread, return
2689673f 256 DEFAULT_LWP.
c906108c 257
8d027a04 258 NOTE: This function probably shouldn't call error(). */
c906108c 259
39f77062
KB
260static ptid_t
261thread_to_lwp (ptid_t thread_id, int default_lwp)
c906108c
SS
262{
263 td_thrinfo_t ti;
264 td_thrhandle_t th;
265 td_err_e val;
266
267 if (is_lwp (thread_id))
8d027a04 268 return thread_id; /* It's already an LWP ID. */
c906108c 269
8d027a04 270 /* It's a thread. Convert to LWP. */
c906108c
SS
271
272 val = p_td_ta_map_id2thr (main_ta, GET_THREAD (thread_id), &th);
273 if (val == TD_NOTHR)
8d027a04 274 return pid_to_ptid (-1); /* Thread must have terminated. */
c906108c 275 else if (val != TD_OK)
8a3fe4f8 276 error (_("thread_to_lwp: td_ta_map_id2thr %s"), td_err_string (val));
c906108c
SS
277
278 val = p_td_thr_get_info (&th, &ti);
279 if (val == TD_NOTHR)
8d027a04 280 return pid_to_ptid (-1); /* Thread must have terminated. */
c906108c 281 else if (val != TD_OK)
8a3fe4f8 282 error (_("thread_to_lwp: td_thr_get_info: %s"), td_err_string (val));
c906108c
SS
283
284 if (ti.ti_state != TD_THR_ACTIVE)
285 {
286 if (default_lwp != -1)
39f77062 287 return pid_to_ptid (default_lwp);
8a3fe4f8 288 error (_("thread_to_lwp: thread state not active: %s"),
c906108c
SS
289 td_state_string (ti.ti_state));
290 }
291
292 return BUILD_LWP (ti.ti_lid, PIDGET (thread_id));
293}
c906108c 294
8d027a04
MK
295/* Convert an LWP ID into a POSIX or Solaris thread ID. If LWP_ID
296 doesn't exists, that's an error.
c906108c 297
8d027a04 298 NOTE: This function probably shouldn't call error(). */
c906108c 299
39f77062
KB
300static ptid_t
301lwp_to_thread (ptid_t lwp)
c906108c
SS
302{
303 td_thrinfo_t ti;
304 td_thrhandle_t th;
305 td_err_e val;
306
307 if (is_thread (lwp))
8d027a04 308 return lwp; /* It's already a thread ID. */
c906108c 309
8d027a04 310 /* It's an LWP. Convert it to a thread ID. */
c906108c
SS
311
312 if (!sol_thread_alive (lwp))
8d027a04 313 return pid_to_ptid (-1); /* Must be a defunct LPW. */
c906108c
SS
314
315 val = p_td_ta_map_lwp2thr (main_ta, GET_LWP (lwp), &th);
316 if (val == TD_NOTHR)
8d027a04 317 return pid_to_ptid (-1); /* Thread must have terminated. */
c906108c 318 else if (val != TD_OK)
8a3fe4f8 319 error (_("lwp_to_thread: td_ta_map_lwp2thr: %s."), td_err_string (val));
c906108c
SS
320
321 val = p_td_thr_validate (&th);
322 if (val == TD_NOTHR)
8d027a04 323 return lwp; /* Unknown to libthread; just return LPW, */
c906108c 324 else if (val != TD_OK)
8a3fe4f8 325 error (_("lwp_to_thread: td_thr_validate: %s."), td_err_string (val));
c906108c
SS
326
327 val = p_td_thr_get_info (&th, &ti);
328 if (val == TD_NOTHR)
8d027a04 329 return pid_to_ptid (-1); /* Thread must have terminated. */
c906108c 330 else if (val != TD_OK)
8a3fe4f8 331 error (_("lwp_to_thread: td_thr_get_info: %s."), td_err_string (val));
c906108c
SS
332
333 return BUILD_THREAD (ti.ti_tid, PIDGET (lwp));
334}
335\f
c906108c 336
8d027a04
MK
337/* Most target vector functions from here on actually just pass
338 through to procfs.c, as they don't need to do anything specific for
339 threads. */
c906108c 340
c906108c 341static void
fba45db2 342sol_thread_open (char *arg, int from_tty)
c906108c
SS
343{
344 procfs_ops.to_open (arg, from_tty);
345}
346
8d027a04
MK
347/* Attach to process PID, then initialize for debugging it and wait
348 for the trace-trap that results from attaching. */
c906108c
SS
349
350static void
136d6dae 351sol_thread_attach (struct target_ops *ops, char *args, int from_tty)
c906108c 352{
2689673f 353 sol_thread_active = 0;
136d6dae 354 procfs_ops.to_attach (&procfs_ops, args, from_tty);
23715f29 355
8d027a04 356 /* Must get symbols from shared libraries before libthread_db can run! */
d45b6f32 357 solib_add (NULL, from_tty, (struct target_ops *) 0, auto_solib_add);
71150974 358
c906108c
SS
359 if (sol_thread_active)
360 {
2689673f 361 ptid_t ptid;
c906108c 362 printf_filtered ("sol-thread active.\n");
8d027a04 363 main_ph.ptid = inferior_ptid; /* Save for xfer_memory. */
c906108c 364 push_target (&sol_thread_ops);
2689673f
PA
365 ptid = lwp_to_thread (inferior_ptid);
366 if (PIDGET (ptid) != -1)
367 thread_change_ptid (inferior_ptid, ptid);
c906108c 368 }
8d027a04
MK
369
370 /* FIXME: Might want to iterate over all the threads and register
371 them. */
c906108c
SS
372}
373
8d027a04
MK
374/* Take a program previously attached to and detaches it. The program
375 resumes execution and will no longer stop on signals, etc. We'd
376 better not have left any breakpoints in the program or it'll die
377 when it hits one. For this to work, it may be necessary for the
378 process to have been previously attached. It *might* work if the
379 program was started via the normal ptrace (PTRACE_TRACEME). */
c906108c
SS
380
381static void
136d6dae 382sol_thread_detach (struct target_ops *ops, char *args, int from_tty)
c906108c 383{
2689673f 384 sol_thread_active = 0;
39f77062 385 inferior_ptid = pid_to_ptid (PIDGET (main_ph.ptid));
c906108c 386 unpush_target (&sol_thread_ops);
136d6dae 387 procfs_ops.to_detach (&procfs_ops, args, from_tty);
c906108c
SS
388}
389
8d027a04
MK
390/* Resume execution of process PTID. If STEP is nozero, then just
391 single step it. If SIGNAL is nonzero, restart it with that signal
392 activated. We may have to convert PTID from a thread ID to an LWP
393 ID for procfs. */
c906108c
SS
394
395static void
39f77062 396sol_thread_resume (ptid_t ptid, int step, enum target_signal signo)
c906108c
SS
397{
398 struct cleanup *old_chain;
399
39f77062 400 old_chain = save_inferior_ptid ();
c906108c 401
39f77062
KB
402 inferior_ptid = thread_to_lwp (inferior_ptid, PIDGET (main_ph.ptid));
403 if (PIDGET (inferior_ptid) == -1)
404 inferior_ptid = procfs_first_available ();
c906108c 405
39f77062 406 if (PIDGET (ptid) != -1)
c906108c 407 {
39f77062 408 ptid_t save_ptid = ptid;
c906108c 409
39f77062 410 ptid = thread_to_lwp (ptid, -2);
8d027a04 411 if (PIDGET (ptid) == -2) /* Inactive thread. */
8a3fe4f8 412 error (_("This version of Solaris can't start inactive threads."));
39f77062 413 if (info_verbose && PIDGET (ptid) == -1)
8a3fe4f8 414 warning (_("Specified thread %ld seems to have terminated"),
39f77062 415 GET_THREAD (save_ptid));
c906108c
SS
416 }
417
39f77062 418 procfs_ops.to_resume (ptid, step, signo);
c906108c
SS
419
420 do_cleanups (old_chain);
421}
422
2689673f 423/* Wait for any threads to stop. We may have to convert PTID from a
8d027a04 424 thread ID to an LWP ID, and vice versa on the way out. */
c906108c 425
39f77062
KB
426static ptid_t
427sol_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
c906108c 428{
39f77062
KB
429 ptid_t rtnval;
430 ptid_t save_ptid;
c906108c
SS
431 struct cleanup *old_chain;
432
39f77062
KB
433 save_ptid = inferior_ptid;
434 old_chain = save_inferior_ptid ();
c906108c 435
39f77062
KB
436 inferior_ptid = thread_to_lwp (inferior_ptid, PIDGET (main_ph.ptid));
437 if (PIDGET (inferior_ptid) == -1)
438 inferior_ptid = procfs_first_available ();
c906108c 439
39f77062 440 if (PIDGET (ptid) != -1)
c906108c 441 {
39f77062 442 ptid_t save_ptid = ptid;
c906108c 443
39f77062 444 ptid = thread_to_lwp (ptid, -2);
8d027a04 445 if (PIDGET (ptid) == -2) /* Inactive thread. */
8a3fe4f8 446 error (_("This version of Solaris can't start inactive threads."));
39f77062 447 if (info_verbose && PIDGET (ptid) == -1)
8a3fe4f8 448 warning (_("Specified thread %ld seems to have terminated"),
39f77062 449 GET_THREAD (save_ptid));
c906108c
SS
450 }
451
39f77062 452 rtnval = procfs_ops.to_wait (ptid, ourstatus);
c906108c
SS
453
454 if (ourstatus->kind != TARGET_WAITKIND_EXITED)
455 {
8d027a04 456 /* Map the LWP of interest back to the appropriate thread ID. */
c906108c 457 rtnval = lwp_to_thread (rtnval);
39f77062
KB
458 if (PIDGET (rtnval) == -1)
459 rtnval = save_ptid;
c906108c 460
8d027a04 461 /* See if we have a new thread. */
c906108c 462 if (is_thread (rtnval)
39f77062 463 && !ptid_equal (rtnval, save_ptid)
2689673f
PA
464 && (!in_thread_list (rtnval)
465 || is_exited (rtnval)))
93815fbf 466 add_thread (rtnval);
c906108c
SS
467 }
468
8d027a04
MK
469 /* During process initialization, we may get here without the thread
470 package being initialized, since that can only happen after we've
471 found the shared libs. */
c906108c
SS
472
473 do_cleanups (old_chain);
474
475 return rtnval;
476}
477
478static void
56be3814 479sol_thread_fetch_registers (struct regcache *regcache, int regnum)
c906108c
SS
480{
481 thread_t thread;
482 td_thrhandle_t thandle;
483 td_err_e val;
484 prgregset_t gregset;
485 prfpregset_t fpregset;
e71c308d
DJ
486 gdb_gregset_t *gregset_p = &gregset;
487 gdb_fpregset_t *fpregset_p = &fpregset;
488
c906108c
SS
489#if 0
490 int xregsize;
491 caddr_t xregset;
492#endif
493
39f77062 494 if (!is_thread (inferior_ptid))
8d027a04
MK
495 {
496 /* It's an LWP; pass the request on to procfs. */
c906108c 497 if (target_has_execution)
56be3814 498 procfs_ops.to_fetch_registers (regcache, regnum);
c906108c 499 else
56be3814 500 orig_core_ops.to_fetch_registers (regcache, regnum);
c906108c
SS
501 return;
502 }
503
8d027a04 504 /* Solaris thread: convert INFERIOR_PTID into a td_thrhandle_t. */
39f77062 505 thread = GET_THREAD (inferior_ptid);
c906108c 506 if (thread == 0)
8a3fe4f8 507 error (_("sol_thread_fetch_registers: thread == 0"));
c906108c
SS
508
509 val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
510 if (val != TD_OK)
8a3fe4f8 511 error (_("sol_thread_fetch_registers: td_ta_map_id2thr: %s"),
c906108c
SS
512 td_err_string (val));
513
8d027a04 514 /* Get the general-purpose registers. */
c906108c
SS
515
516 val = p_td_thr_getgregs (&thandle, gregset);
8d027a04 517 if (val != TD_OK && val != TD_PARTIALREG)
8a3fe4f8 518 error (_("sol_thread_fetch_registers: td_thr_getgregs %s"),
c906108c
SS
519 td_err_string (val));
520
8d027a04
MK
521 /* For SPARC, TD_PARTIALREG means that only %i0...%i7, %l0..%l7, %pc
522 and %sp are saved (by a thread context switch). */
c906108c 523
8d027a04 524 /* And, now the floating-point registers. */
c906108c
SS
525
526 val = p_td_thr_getfpregs (&thandle, &fpregset);
8d027a04 527 if (val != TD_OK && val != TD_NOFPREGS)
8a3fe4f8 528 error (_("sol_thread_fetch_registers: td_thr_getfpregs %s"),
c906108c
SS
529 td_err_string (val));
530
8d027a04
MK
531 /* Note that we must call supply_gregset and supply_fpregset *after*
532 calling the td routines because the td routines call ps_lget*
533 which affect the values stored in the registers array. */
c906108c 534
e71c308d
DJ
535 supply_gregset (regcache, (const gdb_gregset_t *) gregset_p);
536 supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset_p);
c906108c
SS
537
538#if 0
8d027a04 539 /* FIXME: libthread_db doesn't seem to handle this right. */
c906108c
SS
540 val = td_thr_getxregsize (&thandle, &xregsize);
541 if (val != TD_OK && val != TD_NOXREGS)
8a3fe4f8 542 error (_("sol_thread_fetch_registers: td_thr_getxregsize %s"),
c906108c
SS
543 td_err_string (val));
544
545 if (val == TD_OK)
546 {
547 xregset = alloca (xregsize);
548 val = td_thr_getxregs (&thandle, xregset);
549 if (val != TD_OK)
8a3fe4f8 550 error (_("sol_thread_fetch_registers: td_thr_getxregs %s"),
c906108c
SS
551 td_err_string (val));
552 }
553#endif
554}
555
556static void
56be3814 557sol_thread_store_registers (struct regcache *regcache, int regnum)
c906108c
SS
558{
559 thread_t thread;
560 td_thrhandle_t thandle;
561 td_err_e val;
8d027a04 562 prgregset_t gregset;
c906108c
SS
563 prfpregset_t fpregset;
564#if 0
565 int xregsize;
566 caddr_t xregset;
567#endif
568
39f77062 569 if (!is_thread (inferior_ptid))
8d027a04
MK
570 {
571 /* It's an LWP; pass the request on to procfs.c. */
56be3814 572 procfs_ops.to_store_registers (regcache, regnum);
c906108c
SS
573 return;
574 }
575
8d027a04 576 /* Solaris thread: convert INFERIOR_PTID into a td_thrhandle_t. */
39f77062 577 thread = GET_THREAD (inferior_ptid);
c906108c
SS
578
579 val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
580 if (val != TD_OK)
8a3fe4f8 581 error (_("sol_thread_store_registers: td_ta_map_id2thr %s"),
c906108c
SS
582 td_err_string (val));
583
8d027a04
MK
584 if (regnum != -1)
585 {
586 /* Not writing all the registers. */
87232496 587 char old_value[MAX_REGISTER_SIZE];
6034ae49 588
87232496 589 /* Save new register value. */
56be3814 590 regcache_raw_collect (regcache, regnum, old_value);
c906108c 591
c60c0f5f 592 val = p_td_thr_getgregs (&thandle, gregset);
c906108c 593 if (val != TD_OK)
8a3fe4f8 594 error (_("sol_thread_store_registers: td_thr_getgregs %s"),
c906108c
SS
595 td_err_string (val));
596 val = p_td_thr_getfpregs (&thandle, &fpregset);
597 if (val != TD_OK)
8a3fe4f8 598 error (_("sol_thread_store_registers: td_thr_getfpregs %s"),
c906108c
SS
599 td_err_string (val));
600
87232496 601 /* Restore new register value. */
56be3814 602 regcache_raw_supply (regcache, regnum, old_value);
c906108c
SS
603
604#if 0
8d027a04 605 /* FIXME: libthread_db doesn't seem to handle this right. */
c906108c
SS
606 val = td_thr_getxregsize (&thandle, &xregsize);
607 if (val != TD_OK && val != TD_NOXREGS)
8a3fe4f8 608 error (_("sol_thread_store_registers: td_thr_getxregsize %s"),
c906108c
SS
609 td_err_string (val));
610
611 if (val == TD_OK)
612 {
613 xregset = alloca (xregsize);
614 val = td_thr_getxregs (&thandle, xregset);
615 if (val != TD_OK)
8a3fe4f8 616 error (_("sol_thread_store_registers: td_thr_getxregs %s"),
c906108c
SS
617 td_err_string (val));
618 }
619#endif
620 }
621
56be3814
UW
622 fill_gregset (regcache, (gdb_gregset_t *) &gregset, regnum);
623 fill_fpregset (regcache, (gdb_fpregset_t *) &fpregset, regnum);
c906108c 624
c60c0f5f 625 val = p_td_thr_setgregs (&thandle, gregset);
c906108c 626 if (val != TD_OK)
8a3fe4f8 627 error (_("sol_thread_store_registers: td_thr_setgregs %s"),
c906108c
SS
628 td_err_string (val));
629 val = p_td_thr_setfpregs (&thandle, &fpregset);
630 if (val != TD_OK)
8a3fe4f8 631 error (_("sol_thread_store_registers: td_thr_setfpregs %s"),
c906108c
SS
632 td_err_string (val));
633
634#if 0
8d027a04 635 /* FIXME: libthread_db doesn't seem to handle this right. */
c906108c
SS
636 val = td_thr_getxregsize (&thandle, &xregsize);
637 if (val != TD_OK && val != TD_NOXREGS)
8a3fe4f8 638 error (_("sol_thread_store_registers: td_thr_getxregsize %s"),
c906108c
SS
639 td_err_string (val));
640
8d027a04
MK
641 /* ??? Should probably do something about writing the xregs here,
642 but what are they? */
c906108c
SS
643#endif
644}
645
646/* Get ready to modify the registers array. On machines which store
8d027a04
MK
647 individual registers, this doesn't need to do anything. On
648 machines which store all the registers in one fell swoop, this
649 makes sure that registers contains all the registers from the
650 program being debugged. */
c906108c
SS
651
652static void
316f2060 653sol_thread_prepare_to_store (struct regcache *regcache)
c906108c 654{
316f2060 655 procfs_ops.to_prepare_to_store (regcache);
c906108c
SS
656}
657
c338868a
KB
658/* Transfer LEN bytes between GDB address MYADDR and target address
659 MEMADDR. If DOWRITE is non-zero, transfer them to the target,
660 otherwise transfer them from the target. TARGET is unused.
661
8d027a04 662 Returns the number of bytes transferred. */
c338868a 663
c906108c 664static int
b6958cfb
MK
665sol_thread_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
666 int dowrite, struct mem_attrib *attrib,
c338868a 667 struct target_ops *target)
c906108c
SS
668{
669 int retval;
670 struct cleanup *old_chain;
671
39f77062 672 old_chain = save_inferior_ptid ();
c906108c 673
8d027a04
MK
674 if (is_thread (inferior_ptid) || !target_thread_alive (inferior_ptid))
675 {
676 /* It's either a thread or an LWP that isn't alive. Any live
677 LWP will do so use the first available.
678
679 NOTE: We don't need to call switch_to_thread; we're just
680 reading memory. */
681 inferior_ptid = procfs_first_available ();
682 }
c906108c
SS
683
684 if (target_has_execution)
c8e73a31
AC
685 retval = procfs_ops.deprecated_xfer_memory (memaddr, myaddr, len,
686 dowrite, attrib, target);
c906108c 687 else
c8e73a31
AC
688 retval = orig_core_ops.deprecated_xfer_memory (memaddr, myaddr, len,
689 dowrite, attrib, target);
c906108c
SS
690
691 do_cleanups (old_chain);
692
693 return retval;
694}
695
8d027a04
MK
696/* Perform partial transfers on OBJECT. See target_read_partial and
697 target_write_partial for details of each variant. One, and only
698 one, of readbuf or writebuf must be non-NULL. */
6034ae49
RM
699
700static LONGEST
701sol_thread_xfer_partial (struct target_ops *ops, enum target_object object,
b6958cfb
MK
702 const char *annex, gdb_byte *readbuf,
703 const gdb_byte *writebuf,
704 ULONGEST offset, LONGEST len)
6034ae49
RM
705{
706 int retval;
707 struct cleanup *old_chain;
708
709 old_chain = save_inferior_ptid ();
710
8d027a04
MK
711 if (is_thread (inferior_ptid) || !target_thread_alive (inferior_ptid))
712 {
713 /* It's either a thread or an LWP that isn't alive. Any live
714 LWP will do so use the first available.
715
716 NOTE: We don't need to call switch_to_thread; we're just
717 reading memory. */
718 inferior_ptid = procfs_first_available ();
719 }
6034ae49
RM
720
721 if (target_has_execution)
722 retval = procfs_ops.to_xfer_partial (ops, object, annex,
723 readbuf, writebuf, offset, len);
724 else
725 retval = orig_core_ops.to_xfer_partial (ops, object, annex,
726 readbuf, writebuf, offset, len);
727
728 do_cleanups (old_chain);
729
730 return retval;
731}
732
c906108c
SS
733/* Print status information about what we're accessing. */
734
735static void
fba45db2 736sol_thread_files_info (struct target_ops *ignore)
c906108c
SS
737{
738 procfs_ops.to_files_info (ignore);
739}
740
741static void
fba45db2 742sol_thread_kill_inferior (void)
c906108c
SS
743{
744 procfs_ops.to_kill ();
745}
746
747static void
39f77062 748sol_thread_notice_signals (ptid_t ptid)
c906108c 749{
39f77062 750 procfs_ops.to_notice_signals (pid_to_ptid (PIDGET (ptid)));
c906108c
SS
751}
752
753/* Fork an inferior process, and start debugging it with /proc. */
754
755static void
136d6dae
VP
756sol_thread_create_inferior (struct target_ops *ops, char *exec_file,
757 char *allargs, char **env, int from_tty)
c906108c 758{
2689673f 759 sol_thread_active = 0;
136d6dae 760 procfs_ops.to_create_inferior (&procfs_ops, exec_file, allargs, env, from_tty);
c906108c 761
39f77062 762 if (sol_thread_active && !ptid_equal (inferior_ptid, null_ptid))
c906108c 763 {
2689673f
PA
764 ptid_t ptid;
765
8d027a04
MK
766 /* Save for xfer_memory. */
767 main_ph.ptid = inferior_ptid;
c906108c
SS
768
769 push_target (&sol_thread_ops);
770
2689673f
PA
771 ptid = lwp_to_thread (inferior_ptid);
772 if (PIDGET (ptid) != -1)
773 thread_change_ptid (inferior_ptid, ptid);
c906108c
SS
774 }
775}
776
8d027a04
MK
777/* This routine is called whenever a new symbol table is read in, or
778 when all symbol tables are removed. libthread_db can only be
779 initialized when it finds the right variables in libthread.so.
780 Since it's a shared library, those variables don't show up until
06d3b283 781 the library gets mapped and the symbol table is read in. */
c906108c 782
06d3b283 783static void
fba45db2 784sol_thread_new_objfile (struct objfile *objfile)
c906108c
SS
785{
786 td_err_e val;
787
788 if (!objfile)
789 {
790 sol_thread_active = 0;
06d3b283 791 return;
c906108c
SS
792 }
793
8d027a04
MK
794 /* Don't do anything if init failed to resolve the libthread_db
795 library. */
c906108c 796 if (!procfs_suppress_run)
06d3b283 797 return;
c906108c 798
8d027a04
MK
799 /* Now, initialize libthread_db. This needs to be done after the
800 shared libraries are located because it needs information from
801 the user's thread library. */
c906108c
SS
802
803 val = p_td_init ();
804 if (val != TD_OK)
11cf8741 805 {
8a3fe4f8 806 warning (_("sol_thread_new_objfile: td_init: %s"), td_err_string (val));
06d3b283 807 return;
11cf8741 808 }
c906108c
SS
809
810 val = p_td_ta_new (&main_ph, &main_ta);
811 if (val == TD_NOLIBTHREAD)
06d3b283 812 return;
c906108c 813 else if (val != TD_OK)
11cf8741 814 {
8a3fe4f8 815 warning (_("sol_thread_new_objfile: td_ta_new: %s"), td_err_string (val));
06d3b283 816 return;
11cf8741 817 }
c906108c
SS
818
819 sol_thread_active = 1;
820}
821
822/* Clean up after the inferior dies. */
823
824static void
136d6dae 825sol_thread_mourn_inferior (struct target_ops *ops)
c906108c 826{
2689673f 827 sol_thread_active = 0;
c906108c 828 unpush_target (&sol_thread_ops);
136d6dae 829 procfs_ops.to_mourn_inferior (&procfs_ops);
c906108c
SS
830}
831
8d027a04
MK
832/* Mark our target-struct as eligible for stray "run" and "attach"
833 commands. */
c906108c
SS
834
835static int
fba45db2 836sol_thread_can_run (void)
c906108c
SS
837{
838 return procfs_suppress_run;
839}
840
6034ae49 841/*
c906108c 842
c5aa993b 843 LOCAL FUNCTION
c906108c 844
c5aa993b 845 sol_thread_alive - test thread for "aliveness"
c906108c 846
c5aa993b 847 SYNOPSIS
c906108c 848
39f77062 849 static bool sol_thread_alive (ptid_t ptid);
c906108c 850
c5aa993b 851 DESCRIPTION
c906108c 852
c5aa993b 853 returns true if thread still active in inferior.
c906108c
SS
854
855 */
856
8d027a04
MK
857/* Return true if PTID is still active in the inferior. */
858
c906108c 859static int
39f77062 860sol_thread_alive (ptid_t ptid)
c906108c 861{
8d027a04 862 if (is_thread (ptid))
c906108c 863 {
8d027a04 864 /* It's a (user-level) thread. */
c906108c
SS
865 td_err_e val;
866 td_thrhandle_t th;
39f77062 867 int pid;
c906108c 868
39f77062 869 pid = GET_THREAD (ptid);
c906108c 870 if ((val = p_td_ta_map_id2thr (main_ta, pid, &th)) != TD_OK)
8d027a04 871 return 0; /* Thread not found. */
c906108c 872 if ((val = p_td_thr_validate (&th)) != TD_OK)
8d027a04
MK
873 return 0; /* Thread not valid. */
874 return 1; /* Known thread. */
c906108c 875 }
c5aa993b 876 else
c906108c 877 {
8d027a04 878 /* It's an LPW; pass the request on to procfs. */
c906108c 879 if (target_has_execution)
39f77062 880 return procfs_ops.to_thread_alive (ptid);
c906108c 881 else
39f77062 882 return orig_core_ops.to_thread_alive (ptid);
c906108c
SS
883 }
884}
885
886static void
f9c72d52 887sol_thread_stop (ptid_t ptid)
c906108c 888{
f9c72d52 889 procfs_ops.to_stop (ptid);
c906108c
SS
890}
891\f
8d027a04
MK
892/* These routines implement the lower half of the thread_db interface,
893 i.e. the ps_* routines. */
c906108c 894
8d027a04
MK
895/* Various versions of <proc_service.h> have slightly different
896 function prototypes. In particular, we have
c906108c 897
c5aa993b
JM
898 NEWER OLDER
899 struct ps_prochandle * const struct ps_prochandle *
900 void* char*
8d027a04
MK
901 const void* char*
902 int size_t
c906108c 903
8d027a04
MK
904 Which one you have depends on the Solaris version and what patches
905 you've applied. On the theory that there are only two major
906 variants, we have configure check the prototype of ps_pdwrite (),
907 and use that info to make appropriate typedefs here. */
c906108c
SS
908
909#ifdef PROC_SERVICE_IS_OLD
c5aa993b
JM
910typedef const struct ps_prochandle *gdb_ps_prochandle_t;
911typedef char *gdb_ps_read_buf_t;
912typedef char *gdb_ps_write_buf_t;
c906108c 913typedef int gdb_ps_size_t;
76e1ee85 914typedef psaddr_t gdb_ps_addr_t;
c906108c 915#else
c5aa993b
JM
916typedef struct ps_prochandle *gdb_ps_prochandle_t;
917typedef void *gdb_ps_read_buf_t;
918typedef const void *gdb_ps_write_buf_t;
c906108c 919typedef size_t gdb_ps_size_t;
291dcb3e 920typedef psaddr_t gdb_ps_addr_t;
c906108c
SS
921#endif
922
8d027a04
MK
923/* The next four routines are called by libthread_db to tell us to
924 stop and stop a particular process or lwp. Since GDB ensures that
925 these are all stopped by the time we call anything in thread_db,
926 these routines need to do nothing. */
c906108c 927
8d027a04 928/* Process stop. */
d4f3574e 929
c906108c
SS
930ps_err_e
931ps_pstop (gdb_ps_prochandle_t ph)
932{
933 return PS_OK;
934}
935
8d027a04 936/* Process continue. */
d4f3574e 937
c906108c
SS
938ps_err_e
939ps_pcontinue (gdb_ps_prochandle_t ph)
940{
941 return PS_OK;
942}
943
8d027a04 944/* LWP stop. */
d4f3574e 945
c906108c
SS
946ps_err_e
947ps_lstop (gdb_ps_prochandle_t ph, lwpid_t lwpid)
948{
949 return PS_OK;
950}
951
8d027a04 952/* LWP continue. */
d4f3574e 953
c906108c
SS
954ps_err_e
955ps_lcontinue (gdb_ps_prochandle_t ph, lwpid_t lwpid)
956{
957 return PS_OK;
958}
959
d4f3574e
SS
960/* Looks up the symbol LD_SYMBOL_NAME in the debugger's symbol table. */
961
c906108c
SS
962ps_err_e
963ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *ld_object_name,
8d027a04 964 const char *ld_symbol_name, gdb_ps_addr_t *ld_symbol_addr)
c906108c
SS
965{
966 struct minimal_symbol *ms;
967
968 ms = lookup_minimal_symbol (ld_symbol_name, NULL, NULL);
c906108c
SS
969 if (!ms)
970 return PS_NOSYM;
971
972 *ld_symbol_addr = SYMBOL_VALUE_ADDRESS (ms);
c906108c
SS
973 return PS_OK;
974}
975
976/* Common routine for reading and writing memory. */
977
978static ps_err_e
291dcb3e 979rw_common (int dowrite, const struct ps_prochandle *ph, gdb_ps_addr_t addr,
c906108c
SS
980 char *buf, int size)
981{
982 struct cleanup *old_chain;
983
39f77062 984 old_chain = save_inferior_ptid ();
c906108c 985
8d027a04
MK
986 if (is_thread (inferior_ptid) || !target_thread_alive (inferior_ptid))
987 {
988 /* It's either a thread or an LWP that isn't alive. Any live
989 LWP will do so use the first available.
990
991 NOTE: We don't need to call switch_to_thread; we're just
992 reading memory. */
993 inferior_ptid = procfs_first_available ();
994 }
c906108c 995
23e04971
MS
996#if defined (__sparcv9)
997 /* For Sparc64 cross Sparc32, make sure the address has not been
998 accidentally sign-extended (or whatever) to beyond 32 bits. */
359431fb 999 if (bfd_get_arch_size (exec_bfd) == 32)
23e04971
MS
1000 addr &= 0xffffffff;
1001#endif
1002
c906108c
SS
1003 while (size > 0)
1004 {
1005 int cc;
1006
f4d650ec 1007 /* FIXME: passing 0 as attrib argument. */
c906108c 1008 if (target_has_execution)
c8e73a31
AC
1009 cc = procfs_ops.deprecated_xfer_memory (addr, buf, size,
1010 dowrite, 0, &procfs_ops);
c906108c 1011 else
c8e73a31
AC
1012 cc = orig_core_ops.deprecated_xfer_memory (addr, buf, size,
1013 dowrite, 0, &core_ops);
c906108c
SS
1014
1015 if (cc < 0)
1016 {
1017 if (dowrite == 0)
1018 print_sys_errmsg ("rw_common (): read", errno);
1019 else
1020 print_sys_errmsg ("rw_common (): write", errno);
1021
1022 do_cleanups (old_chain);
1023
1024 return PS_ERR;
1025 }
d5cb3e0e
MS
1026 else if (cc == 0)
1027 {
1028 if (dowrite == 0)
8a3fe4f8 1029 warning (_("rw_common (): unable to read at addr 0x%lx"),
d5cb3e0e
MS
1030 (long) addr);
1031 else
8a3fe4f8 1032 warning (_("rw_common (): unable to write at addr 0x%lx"),
d5cb3e0e
MS
1033 (long) addr);
1034
1035 do_cleanups (old_chain);
1036
1037 return PS_ERR;
1038 }
1039
c906108c
SS
1040 size -= cc;
1041 buf += cc;
1042 }
1043
1044 do_cleanups (old_chain);
1045
1046 return PS_OK;
1047}
1048
d4f3574e
SS
1049/* Copies SIZE bytes from target process .data segment to debugger memory. */
1050
c906108c 1051ps_err_e
291dcb3e 1052ps_pdread (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
c906108c
SS
1053 gdb_ps_read_buf_t buf, gdb_ps_size_t size)
1054{
1055 return rw_common (0, ph, addr, buf, size);
1056}
1057
d4f3574e
SS
1058/* Copies SIZE bytes from debugger memory .data segment to target process. */
1059
c906108c 1060ps_err_e
291dcb3e 1061ps_pdwrite (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
c906108c
SS
1062 gdb_ps_write_buf_t buf, gdb_ps_size_t size)
1063{
c5aa993b 1064 return rw_common (1, ph, addr, (char *) buf, size);
c906108c
SS
1065}
1066
d4f3574e
SS
1067/* Copies SIZE bytes from target process .text segment to debugger memory. */
1068
c906108c 1069ps_err_e
291dcb3e 1070ps_ptread (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
c906108c
SS
1071 gdb_ps_read_buf_t buf, gdb_ps_size_t size)
1072{
1073 return rw_common (0, ph, addr, buf, size);
1074}
1075
d4f3574e
SS
1076/* Copies SIZE bytes from debugger memory .text segment to target process. */
1077
c906108c 1078ps_err_e
291dcb3e 1079ps_ptwrite (gdb_ps_prochandle_t ph, gdb_ps_addr_t addr,
c906108c
SS
1080 gdb_ps_write_buf_t buf, gdb_ps_size_t size)
1081{
c5aa993b 1082 return rw_common (1, ph, addr, (char *) buf, size);
c906108c
SS
1083}
1084
8d027a04 1085/* Get general-purpose registers for LWP. */
c906108c
SS
1086
1087ps_err_e
8d027a04 1088ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
c906108c
SS
1089{
1090 struct cleanup *old_chain;
594f7785 1091 struct regcache *regcache;
c906108c 1092
39f77062 1093 old_chain = save_inferior_ptid ();
c906108c 1094
39f77062 1095 inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
594f7785 1096 regcache = get_thread_regcache (inferior_ptid);
c5aa993b 1097
c906108c 1098 if (target_has_execution)
594f7785 1099 procfs_ops.to_fetch_registers (regcache, -1);
c906108c 1100 else
594f7785
UW
1101 orig_core_ops.to_fetch_registers (regcache, -1);
1102 fill_gregset (regcache, (gdb_gregset_t *) gregset, -1);
c906108c
SS
1103
1104 do_cleanups (old_chain);
1105
1106 return PS_OK;
1107}
1108
8d027a04 1109/* Set general-purpose registers for LWP. */
c906108c
SS
1110
1111ps_err_e
1112ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
1113 const prgregset_t gregset)
1114{
1115 struct cleanup *old_chain;
594f7785 1116 struct regcache *regcache;
c906108c 1117
39f77062 1118 old_chain = save_inferior_ptid ();
c906108c 1119
39f77062 1120 inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
594f7785 1121 regcache = get_thread_regcache (inferior_ptid);
c5aa993b 1122
594f7785 1123 supply_gregset (regcache, (const gdb_gregset_t *) gregset);
c906108c 1124 if (target_has_execution)
594f7785 1125 procfs_ops.to_store_registers (regcache, -1);
c906108c 1126 else
594f7785 1127 orig_core_ops.to_store_registers (regcache, -1);
c906108c
SS
1128
1129 do_cleanups (old_chain);
1130
1131 return PS_OK;
1132}
1133
d4f3574e
SS
1134/* Log a message (sends to gdb_stderr). */
1135
c906108c 1136void
8d027a04 1137ps_plog (const char *fmt, ...)
c906108c
SS
1138{
1139 va_list args;
1140
1141 va_start (args, fmt);
1142
1143 vfprintf_filtered (gdb_stderr, fmt, args);
1144}
1145
1146/* Get size of extra register set. Currently a noop. */
1147
1148ps_err_e
1149ps_lgetxregsize (gdb_ps_prochandle_t ph, lwpid_t lwpid, int *xregsize)
1150{
1151#if 0
1152 int lwp_fd;
1153 int regsize;
1154 ps_err_e val;
1155
1156 val = get_lwp_fd (ph, lwpid, &lwp_fd);
1157 if (val != PS_OK)
1158 return val;
1159
1160 if (ioctl (lwp_fd, PIOCGXREGSIZE, &regsize))
1161 {
1162 if (errno == EINVAL)
1163 return PS_NOFREGS; /* XXX Wrong code, but this is the closest
1164 thing in proc_service.h */
1165
1166 print_sys_errmsg ("ps_lgetxregsize (): PIOCGXREGSIZE", errno);
1167 return PS_ERR;
1168 }
1169#endif
1170
1171 return PS_OK;
1172}
1173
1174/* Get extra register set. Currently a noop. */
1175
1176ps_err_e
1177ps_lgetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
1178{
1179#if 0
1180 int lwp_fd;
1181 ps_err_e val;
1182
1183 val = get_lwp_fd (ph, lwpid, &lwp_fd);
1184 if (val != PS_OK)
1185 return val;
1186
1187 if (ioctl (lwp_fd, PIOCGXREG, xregset))
1188 {
1189 print_sys_errmsg ("ps_lgetxregs (): PIOCGXREG", errno);
1190 return PS_ERR;
1191 }
1192#endif
1193
1194 return PS_OK;
1195}
1196
1197/* Set extra register set. Currently a noop. */
1198
1199ps_err_e
1200ps_lsetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
1201{
1202#if 0
1203 int lwp_fd;
1204 ps_err_e val;
1205
1206 val = get_lwp_fd (ph, lwpid, &lwp_fd);
1207 if (val != PS_OK)
1208 return val;
1209
1210 if (ioctl (lwp_fd, PIOCSXREG, xregset))
1211 {
1212 print_sys_errmsg ("ps_lsetxregs (): PIOCSXREG", errno);
1213 return PS_ERR;
1214 }
1215#endif
1216
1217 return PS_OK;
1218}
1219
8d027a04 1220/* Get floating-point registers for LWP. */
c906108c
SS
1221
1222ps_err_e
1223ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
8d027a04 1224 prfpregset_t *fpregset)
c906108c
SS
1225{
1226 struct cleanup *old_chain;
594f7785 1227 struct regcache *regcache;
c906108c 1228
39f77062 1229 old_chain = save_inferior_ptid ();
c906108c 1230
39f77062 1231 inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
594f7785 1232 regcache = get_thread_regcache (inferior_ptid);
c906108c
SS
1233
1234 if (target_has_execution)
594f7785 1235 procfs_ops.to_fetch_registers (regcache, -1);
c906108c 1236 else
594f7785
UW
1237 orig_core_ops.to_fetch_registers (regcache, -1);
1238 fill_fpregset (regcache, (gdb_fpregset_t *) fpregset, -1);
c906108c
SS
1239
1240 do_cleanups (old_chain);
1241
1242 return PS_OK;
1243}
1244
d4f3574e 1245/* Set floating-point regs for LWP */
c906108c
SS
1246
1247ps_err_e
1248ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
c5aa993b 1249 const prfpregset_t * fpregset)
c906108c
SS
1250{
1251 struct cleanup *old_chain;
594f7785 1252 struct regcache *regcache;
c906108c 1253
39f77062 1254 old_chain = save_inferior_ptid ();
c906108c 1255
39f77062 1256 inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
594f7785 1257 regcache = get_thread_regcache (inferior_ptid);
c5aa993b 1258
594f7785 1259 supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset);
c906108c 1260 if (target_has_execution)
594f7785 1261 procfs_ops.to_store_registers (regcache, -1);
c906108c 1262 else
594f7785 1263 orig_core_ops.to_store_registers (regcache, -1);
c906108c
SS
1264
1265 do_cleanups (old_chain);
1266
1267 return PS_OK;
1268}
1269
23715f29 1270#ifdef PR_MODEL_LP64
8d027a04
MK
1271/* Identify process as 32-bit or 64-bit. At the moment we're using
1272 BFD to do this. There might be a more Solaris-specific
1273 (e.g. procfs) method, but this ought to work. */
23e04971
MS
1274
1275ps_err_e
1276ps_pdmodel (gdb_ps_prochandle_t ph, int *data_model)
1277{
1278 if (exec_bfd == 0)
a95ac8b6
PS
1279 *data_model = PR_MODEL_UNKNOWN;
1280 else if (bfd_get_arch_size (exec_bfd) == 32)
23e04971
MS
1281 *data_model = PR_MODEL_ILP32;
1282 else
1283 *data_model = PR_MODEL_LP64;
1284
1285 return PS_OK;
1286}
23715f29 1287#endif /* PR_MODEL_LP64 */
23e04971 1288
965b60ee 1289#if (defined(__i386__) || defined(__x86_64__)) && defined (sun)
c906108c 1290
965b60ee
JB
1291/* Reads the local descriptor table of a LWP.
1292
1293 This function is necessary on x86-solaris only. Without it, the loading
1294 of libthread_db would fail because of ps_lgetLDT being undefined. */
d4f3574e 1295
c906108c
SS
1296ps_err_e
1297ps_lgetLDT (gdb_ps_prochandle_t ph, lwpid_t lwpid,
1298 struct ssd *pldt)
1299{
8d027a04 1300 /* NOTE: only used on Solaris, therefore OK to refer to procfs.c. */
39f77062 1301 extern struct ssd *procfs_find_LDT_entry (ptid_t);
05e28a7b 1302 struct ssd *ret;
c906108c 1303
8d027a04
MK
1304 /* FIXME: can't I get the process ID from the prochandle or
1305 something? */
2f09097b 1306
39f77062 1307 if (PIDGET (inferior_ptid) <= 0 || lwpid <= 0)
2f09097b
ND
1308 return PS_BADLID;
1309
39f77062 1310 ret = procfs_find_LDT_entry (BUILD_LWP (lwpid, PIDGET (inferior_ptid)));
05e28a7b 1311 if (ret)
c906108c 1312 {
05e28a7b
AC
1313 memcpy (pldt, ret, sizeof (struct ssd));
1314 return PS_OK;
c906108c 1315 }
8d027a04
MK
1316 else
1317 /* LDT not found. */
c906108c 1318 return PS_ERR;
c5aa993b 1319}
965b60ee 1320#endif
c906108c 1321\f
8d027a04
MK
1322
1323/* Convert PTID to printable form. */
c906108c
SS
1324
1325char *
39f77062 1326solaris_pid_to_str (ptid_t ptid)
c906108c
SS
1327{
1328 static char buf[100];
1329
8d027a04 1330 /* In case init failed to resolve the libthread_db library. */
c906108c 1331 if (!procfs_suppress_run)
39f77062 1332 return procfs_pid_to_str (ptid);
c906108c 1333
39f77062 1334 if (is_thread (ptid))
c906108c 1335 {
39f77062 1336 ptid_t lwp;
c906108c 1337
39f77062 1338 lwp = thread_to_lwp (ptid, -2);
c906108c 1339
39f77062
KB
1340 if (PIDGET (lwp) == -1)
1341 sprintf (buf, "Thread %ld (defunct)", GET_THREAD (ptid));
1342 else if (PIDGET (lwp) != -2)
8d027a04
MK
1343 sprintf (buf, "Thread %ld (LWP %ld)",
1344 GET_THREAD (ptid), GET_LWP (lwp));
c906108c 1345 else
39f77062 1346 sprintf (buf, "Thread %ld ", GET_THREAD (ptid));
c906108c 1347 }
39f77062
KB
1348 else if (GET_LWP (ptid) != 0)
1349 sprintf (buf, "LWP %ld ", GET_LWP (ptid));
c906108c 1350 else
39f77062 1351 sprintf (buf, "process %d ", PIDGET (ptid));
c906108c
SS
1352
1353 return buf;
1354}
1355\f
1356
8d027a04
MK
1357/* Worker bee for find_new_threads. Callback function that gets
1358 called once per user-level thread (i.e. not for LWP's). */
c906108c
SS
1359
1360static int
fba45db2 1361sol_find_new_threads_callback (const td_thrhandle_t *th, void *ignored)
c906108c
SS
1362{
1363 td_err_e retval;
1364 td_thrinfo_t ti;
39f77062 1365 ptid_t ptid;
c906108c 1366
8d027a04
MK
1367 retval = p_td_thr_get_info (th, &ti);
1368 if (retval != TD_OK)
1369 return -1;
1370
39f77062 1371 ptid = BUILD_THREAD (ti.ti_tid, PIDGET (inferior_ptid));
2689673f 1372 if (!in_thread_list (ptid) || is_exited (ptid))
39f77062 1373 add_thread (ptid);
c906108c
SS
1374
1375 return 0;
1376}
1377
d4f3574e 1378static void
fba45db2 1379sol_find_new_threads (void)
c906108c 1380{
8d027a04
MK
1381 /* Don't do anything if init failed to resolve the libthread_db
1382 library. */
c906108c
SS
1383 if (!procfs_suppress_run)
1384 return;
1385
39f77062 1386 if (PIDGET (inferior_ptid) == -1)
c906108c 1387 {
c5aa993b 1388 printf_filtered ("No process.\n");
c906108c
SS
1389 return;
1390 }
8d027a04
MK
1391
1392 /* First Find any new LWP's. */
1393 procfs_ops.to_find_new_threads ();
1394
1395 /* Then find any new user-level threads. */
c5aa993b 1396 p_td_ta_thr_iter (main_ta, sol_find_new_threads_callback, (void *) 0,
c906108c
SS
1397 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
1398 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
1399}
1400
1401static void
fba45db2 1402sol_core_open (char *filename, int from_tty)
c906108c
SS
1403{
1404 orig_core_ops.to_open (filename, from_tty);
1405}
1406
1407static void
fba45db2 1408sol_core_close (int quitting)
c906108c
SS
1409{
1410 orig_core_ops.to_close (quitting);
1411}
1412
1413static void
136d6dae 1414sol_core_detach (struct target_ops *ops, char *args, int from_tty)
c906108c
SS
1415{
1416 unpush_target (&core_ops);
136d6dae 1417 orig_core_ops.to_detach (&orig_core_ops, args, from_tty);
c906108c
SS
1418}
1419
1420static void
fba45db2 1421sol_core_files_info (struct target_ops *t)
c906108c
SS
1422{
1423 orig_core_ops.to_files_info (t);
1424}
1425
8d027a04
MK
1426/* Worker bee for the "info sol-thread" command. This is a callback
1427 function that gets called once for each Solaris user-level thread
1428 (i.e. not for LWPs) in the inferior. Print anything interesting
1429 that we can think of. */
c906108c 1430
c5aa993b 1431static int
fba45db2 1432info_cb (const td_thrhandle_t *th, void *s)
c906108c
SS
1433{
1434 td_err_e ret;
1435 td_thrinfo_t ti;
c906108c 1436
8d027a04
MK
1437 ret = p_td_thr_get_info (th, &ti);
1438 if (ret == TD_OK)
c906108c 1439 {
c5aa993b
JM
1440 printf_filtered ("%s thread #%d, lwp %d, ",
1441 ti.ti_type == TD_THR_SYSTEM ? "system" : "user ",
c906108c 1442 ti.ti_tid, ti.ti_lid);
c5aa993b
JM
1443 switch (ti.ti_state)
1444 {
c906108c 1445 default:
c5aa993b
JM
1446 case TD_THR_UNKNOWN:
1447 printf_filtered ("<unknown state>");
1448 break;
1449 case TD_THR_STOPPED:
1450 printf_filtered ("(stopped)");
1451 break;
1452 case TD_THR_RUN:
1453 printf_filtered ("(run) ");
1454 break;
1455 case TD_THR_ACTIVE:
1456 printf_filtered ("(active) ");
1457 break;
1458 case TD_THR_ZOMBIE:
1459 printf_filtered ("(zombie) ");
1460 break;
1461 case TD_THR_SLEEP:
1462 printf_filtered ("(asleep) ");
1463 break;
1464 case TD_THR_STOPPED_ASLEEP:
1465 printf_filtered ("(stopped asleep)");
1466 break;
1467 }
8d027a04 1468 /* Print thr_create start function. */
c906108c 1469 if (ti.ti_startfunc != 0)
4ce44c66
JM
1470 {
1471 struct minimal_symbol *msym;
1472 msym = lookup_minimal_symbol_by_pc (ti.ti_startfunc);
1473 if (msym)
8d027a04 1474 printf_filtered (" startfunc: %s\n",
3567439c 1475 SYMBOL_PRINT_NAME (msym));
4ce44c66
JM
1476 else
1477 printf_filtered (" startfunc: 0x%s\n", paddr (ti.ti_startfunc));
1478 }
c906108c 1479
8d027a04 1480 /* If thread is asleep, print function that went to sleep. */
c906108c 1481 if (ti.ti_state == TD_THR_SLEEP)
4ce44c66
JM
1482 {
1483 struct minimal_symbol *msym;
1484 msym = lookup_minimal_symbol_by_pc (ti.ti_pc);
1485 if (msym)
8d027a04 1486 printf_filtered (" - Sleep func: %s\n",
3567439c 1487 SYMBOL_PRINT_NAME (msym));
4ce44c66
JM
1488 else
1489 printf_filtered (" - Sleep func: 0x%s\n", paddr (ti.ti_startfunc));
1490 }
c906108c 1491
8d027a04 1492 /* Wrap up line, if necessary. */
c906108c
SS
1493 if (ti.ti_state != TD_THR_SLEEP && ti.ti_startfunc == 0)
1494 printf_filtered ("\n"); /* don't you hate counting newlines? */
1495 }
1496 else
8a3fe4f8 1497 warning (_("info sol-thread: failed to get info for thread."));
c906108c 1498
c5aa993b 1499 return 0;
c906108c
SS
1500}
1501
8d027a04
MK
1502/* List some state about each Solaris user-level thread in the
1503 inferior. */
c906108c
SS
1504
1505static void
fba45db2 1506info_solthreads (char *args, int from_tty)
c906108c 1507{
c5aa993b 1508 p_td_ta_thr_iter (main_ta, info_cb, args,
c906108c
SS
1509 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
1510 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
1511}
c906108c 1512
be4d1333 1513static int
8d027a04
MK
1514sol_find_memory_regions (int (*func) (CORE_ADDR, unsigned long,
1515 int, int, int, void *),
be4d1333
MS
1516 void *data)
1517{
1518 return procfs_ops.to_find_memory_regions (func, data);
1519}
1520
1521static char *
1522sol_make_note_section (bfd *obfd, int *note_size)
1523{
1524 return procfs_ops.to_make_corefile_notes (obfd, note_size);
1525}
1526
c906108c 1527static int
8181d85f 1528ignore (struct bp_target_info *bp_tgt)
c906108c
SS
1529{
1530 return 0;
1531}
1532
c906108c 1533static void
fba45db2 1534init_sol_thread_ops (void)
c906108c
SS
1535{
1536 sol_thread_ops.to_shortname = "solaris-threads";
1537 sol_thread_ops.to_longname = "Solaris threads and pthread.";
1538 sol_thread_ops.to_doc = "Solaris threads and pthread support.";
1539 sol_thread_ops.to_open = sol_thread_open;
c906108c
SS
1540 sol_thread_ops.to_attach = sol_thread_attach;
1541 sol_thread_ops.to_detach = sol_thread_detach;
1542 sol_thread_ops.to_resume = sol_thread_resume;
1543 sol_thread_ops.to_wait = sol_thread_wait;
1544 sol_thread_ops.to_fetch_registers = sol_thread_fetch_registers;
1545 sol_thread_ops.to_store_registers = sol_thread_store_registers;
1546 sol_thread_ops.to_prepare_to_store = sol_thread_prepare_to_store;
c8e73a31 1547 sol_thread_ops.deprecated_xfer_memory = sol_thread_xfer_memory;
6034ae49 1548 sol_thread_ops.to_xfer_partial = sol_thread_xfer_partial;
c906108c
SS
1549 sol_thread_ops.to_files_info = sol_thread_files_info;
1550 sol_thread_ops.to_insert_breakpoint = memory_insert_breakpoint;
1551 sol_thread_ops.to_remove_breakpoint = memory_remove_breakpoint;
1552 sol_thread_ops.to_terminal_init = terminal_init_inferior;
1553 sol_thread_ops.to_terminal_inferior = terminal_inferior;
1554 sol_thread_ops.to_terminal_ours_for_output = terminal_ours_for_output;
1555 sol_thread_ops.to_terminal_ours = terminal_ours;
a790ad35 1556 sol_thread_ops.to_terminal_save_ours = terminal_save_ours;
c906108c
SS
1557 sol_thread_ops.to_terminal_info = child_terminal_info;
1558 sol_thread_ops.to_kill = sol_thread_kill_inferior;
c906108c
SS
1559 sol_thread_ops.to_create_inferior = sol_thread_create_inferior;
1560 sol_thread_ops.to_mourn_inferior = sol_thread_mourn_inferior;
1561 sol_thread_ops.to_can_run = sol_thread_can_run;
1562 sol_thread_ops.to_notice_signals = sol_thread_notice_signals;
1563 sol_thread_ops.to_thread_alive = sol_thread_alive;
ed9a39eb 1564 sol_thread_ops.to_pid_to_str = solaris_pid_to_str;
b83266a0 1565 sol_thread_ops.to_find_new_threads = sol_find_new_threads;
c906108c
SS
1566 sol_thread_ops.to_stop = sol_thread_stop;
1567 sol_thread_ops.to_stratum = process_stratum;
1568 sol_thread_ops.to_has_all_memory = 1;
1569 sol_thread_ops.to_has_memory = 1;
1570 sol_thread_ops.to_has_stack = 1;
1571 sol_thread_ops.to_has_registers = 1;
1572 sol_thread_ops.to_has_execution = 1;
1573 sol_thread_ops.to_has_thread_control = tc_none;
be4d1333
MS
1574 sol_thread_ops.to_find_memory_regions = sol_find_memory_regions;
1575 sol_thread_ops.to_make_corefile_notes = sol_make_note_section;
c906108c
SS
1576 sol_thread_ops.to_magic = OPS_MAGIC;
1577}
1578
c906108c 1579static void
fba45db2 1580init_sol_core_ops (void)
c906108c 1581{
c5aa993b
JM
1582 sol_core_ops.to_shortname = "solaris-core";
1583 sol_core_ops.to_longname = "Solaris core threads and pthread.";
1584 sol_core_ops.to_doc = "Solaris threads and pthread support for core files.";
1585 sol_core_ops.to_open = sol_core_open;
1586 sol_core_ops.to_close = sol_core_close;
1587 sol_core_ops.to_attach = sol_thread_attach;
1588 sol_core_ops.to_detach = sol_core_detach;
c5aa993b 1589 sol_core_ops.to_fetch_registers = sol_thread_fetch_registers;
c8e73a31 1590 sol_core_ops.deprecated_xfer_memory = sol_thread_xfer_memory;
6034ae49 1591 sol_core_ops.to_xfer_partial = sol_thread_xfer_partial;
c5aa993b
JM
1592 sol_core_ops.to_files_info = sol_core_files_info;
1593 sol_core_ops.to_insert_breakpoint = ignore;
1594 sol_core_ops.to_remove_breakpoint = ignore;
c5aa993b
JM
1595 sol_core_ops.to_create_inferior = sol_thread_create_inferior;
1596 sol_core_ops.to_stratum = core_stratum;
c5aa993b
JM
1597 sol_core_ops.to_has_memory = 1;
1598 sol_core_ops.to_has_stack = 1;
1599 sol_core_ops.to_has_registers = 1;
c5aa993b 1600 sol_core_ops.to_has_thread_control = tc_none;
db348f27 1601 sol_core_ops.to_thread_alive = sol_thread_alive;
ed9a39eb 1602 sol_core_ops.to_pid_to_str = solaris_pid_to_str;
8d027a04
MK
1603 /* On Solaris/x86, when debugging a threaded core file from process
1604 <n>, the following causes "info threads" to produce "procfs:
1605 couldn't find pid <n> in procinfo list" where <n> is the pid of
1606 the process that produced the core file. Disable it for now. */
1607#if 0
1608 sol_core_ops.to_find_new_threads = sol_find_new_threads;
1609#endif
c5aa993b 1610 sol_core_ops.to_magic = OPS_MAGIC;
c906108c
SS
1611}
1612
8d027a04
MK
1613/* We suppress the call to add_target of core_ops in corelow because
1614 if there are two targets in the stratum core_stratum,
1615 find_core_target won't know which one to return. See corelow.c for
1616 an additonal comment on coreops_suppress_target. */
c906108c
SS
1617int coreops_suppress_target = 1;
1618
1619void
fba45db2 1620_initialize_sol_thread (void)
c906108c
SS
1621{
1622 void *dlhandle;
1623
1624 init_sol_thread_ops ();
1625 init_sol_core_ops ();
1626
1627 dlhandle = dlopen ("libthread_db.so.1", RTLD_NOW);
1628 if (!dlhandle)
1629 goto die;
1630
1631#define resolve(X) \
1632 if (!(p_##X = dlsym (dlhandle, #X))) \
1633 goto die;
1634
1635 resolve (td_log);
1636 resolve (td_ta_new);
1637 resolve (td_ta_delete);
1638 resolve (td_init);
1639 resolve (td_ta_get_ph);
1640 resolve (td_ta_get_nthreads);
1641 resolve (td_ta_tsd_iter);
1642 resolve (td_ta_thr_iter);
1643 resolve (td_thr_validate);
1644 resolve (td_thr_tsd);
1645 resolve (td_thr_get_info);
1646 resolve (td_thr_getfpregs);
1647 resolve (td_thr_getxregsize);
1648 resolve (td_thr_getxregs);
1649 resolve (td_thr_sigsetmask);
1650 resolve (td_thr_setprio);
1651 resolve (td_thr_setsigpending);
1652 resolve (td_thr_setfpregs);
1653 resolve (td_thr_setxregs);
1654 resolve (td_ta_map_id2thr);
1655 resolve (td_ta_map_lwp2thr);
1656 resolve (td_thr_getgregs);
1657 resolve (td_thr_setgregs);
1658
1659 add_target (&sol_thread_ops);
1660
1661 procfs_suppress_run = 1;
1662
c5aa993b 1663 add_cmd ("sol-threads", class_maintenance, info_solthreads,
1a966eab 1664 _("Show info on Solaris user threads."), &maintenanceinfolist);
c906108c 1665
5d6fa950
DE
1666 /* FIXME: This code takes errant advantage of the order in which
1667 initialization routines are run. _initialize_corelow must run before
1668 this one otherwise orig_core_ops will still contain zeros and the work
1669 of init_sol_core_ops will be undone. */
c5aa993b
JM
1670 memcpy (&orig_core_ops, &core_ops, sizeof (struct target_ops));
1671 memcpy (&core_ops, &sol_core_ops, sizeof (struct target_ops));
c906108c
SS
1672 add_target (&core_ops);
1673
8d027a04 1674 /* Hook into new_objfile notification. */
06d3b283 1675 observer_attach_new_objfile (sol_thread_new_objfile);
c906108c
SS
1676 return;
1677
8d027a04
MK
1678 die:
1679 fprintf_unfiltered (gdb_stderr, "\
1680[GDB will not be able to debug user-mode threads: %s]\n", dlerror ());
c906108c
SS
1681
1682 if (dlhandle)
1683 dlclose (dlhandle);
1684
8d027a04 1685 /* Allow the user to debug non-threaded core files. */
c5aa993b 1686 add_target (&core_ops);
c906108c
SS
1687
1688 return;
1689}
This page took 0.914984 seconds and 4 git commands to generate.