]> Git Repo - binutils.git/blame_incremental - gdb/sol-thread.c
* config/mips/tm-mips.h (TM_MIPS_H): Enclose file contents in
[binutils.git] / gdb / sol-thread.c
... / ...
CommitLineData
1/* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
2 Copyright 1996 Free Software Foundation, Inc.
3
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20/* This module implements a sort of half target that sits between the
21 machine-independent parts of GDB and the /proc interface (procfs.c) to
22 provide access to the Solaris user-mode thread implementation.
23
24 Solaris threads are true user-mode threads, which are invoked via the thr_*
25 and pthread_* (native and Posix respectivly) interfaces. These are mostly
26 implemented in user-space, with all thread context kept in various
27 structures that live in the user's heap. These should not be confused with
28 lightweight processes (LWPs), which are implemented by the kernel, and
29 scheduled without explicit intervention by the process.
30
31 Just to confuse things a little, Solaris threads (both native and Posix) are
32 actually implemented using LWPs. In general, there are going to be more
33 threads than LWPs. There is no fixed correspondence between a thread and an
34 LWP. When a thread wants to run, it gets scheduled onto the first available
35 LWP and can therefore migrate from one LWP to another as time goes on. A
36 sleeping thread may not be associated with an LWP at all!
37
38 To make it possible to mess with threads, Sun provides a library called
39 libthread_db.so.1 (not to be confused with libthread_db.so.0, which doesn't
40 have a published interface). This interface has an upper part, which it
41 provides, and a lower part which I provide. The upper part consists of the
42 td_* routines, which allow me to find all the threads, query their state,
43 etc... The lower part consists of all of the ps_*, which are used by the
44 td_* routines to read/write memory, manipulate LWPs, lookup symbols, etc...
45 The ps_* routines actually do most of their work by calling functions in
46 procfs.c. */
47
48#include "defs.h"
49
50/* Undefine gregset_t and fpregset_t to avoid conflict with defs in xm file. */
51
52#ifdef gregset_t
53#undef gregset_t
54#endif
55
56#ifdef fpregset_t
57#undef fpregset_t
58#endif
59
60#include <thread.h>
61#include <proc_service.h>
62#include <thread_db.h>
63#include "gdbthread.h"
64#include "target.h"
65#include "inferior.h"
66#include <fcntl.h>
67#include <unistd.h>
68#include <sys/stat.h>
69#include <dlfcn.h>
70
71extern struct target_ops sol_thread_ops; /* Forward declaration */
72
73extern int procfs_suppress_run;
74extern struct target_ops procfs_ops; /* target vector for procfs.c */
75
76/* Note that these prototypes differ slightly from those used in procfs.c
77 for of two reasons. One, we can't use gregset_t, as that's got a whole
78 different meaning under Solaris (also, see above). Two, we can't use the
79 pointer form here as these are actually arrays of ints (for Sparc's at
80 least), and are automatically coerced into pointers to ints when used as
81 parameters. That makes it impossible to avoid a compiler warning when
82 passing pr{g fp}regset_t's from a parameter to an argument of one of
83 these functions. */
84
85extern void supply_gregset PARAMS ((const prgregset_t));
86extern void fill_gregset PARAMS ((prgregset_t, int));
87extern void supply_fpregset PARAMS ((const prfpregset_t));
88extern void fill_fpregset PARAMS ((prfpregset_t, int));
89
90/* This struct is defined by us, but mainly used for the proc_service interface.
91 We don't have much use for it, except as a handy place to get a real pid
92 for memory accesses. */
93
94struct ps_prochandle
95{
96 pid_t pid;
97};
98
99struct string_map
100{
101 int num;
102 char *str;
103};
104
105static struct ps_prochandle main_ph;
106static td_thragent_t *main_ta;
107static int sol_thread_active = 0;
108
109static struct cleanup * save_inferior_pid PARAMS ((void));
110static void restore_inferior_pid PARAMS ((int pid));
111static char *td_err_string PARAMS ((td_err_e errcode));
112static char *td_state_string PARAMS ((td_thr_state_e statecode));
113static int thread_to_lwp PARAMS ((int thread_id, int default_lwp));
114static void sol_thread_resume PARAMS ((int pid, int step,
115 enum target_signal signo));
116static int lwp_to_thread PARAMS ((int lwp));
117
118#define THREAD_FLAG 0x80000000
119#define is_thread(ARG) (((ARG) & THREAD_FLAG) != 0)
120#define is_lwp(ARG) (((ARG) & THREAD_FLAG) == 0)
121#define GET_LWP(LWP_ID) (TIDGET(LWP_ID))
122#define GET_THREAD(THREAD_ID) (((THREAD_ID) >> 16) & 0x7fff)
123#define BUILD_LWP(LWP_ID, PID) ((LWP_ID) << 16 | (PID))
124#define BUILD_THREAD(THREAD_ID, PID) (THREAD_FLAG | BUILD_LWP (THREAD_ID, PID))
125
126/* Pointers to routines from lithread_db resolved by dlopen() */
127
128static void
129 (*p_td_log) (const int on_off);
130static td_err_e
131 (*p_td_ta_new) (const struct ps_prochandle *ph_p, td_thragent_t **ta_pp);
132static td_err_e
133 (*p_td_ta_delete) (td_thragent_t *ta_p);
134static td_err_e
135 (*p_td_init) (void);
136static td_err_e
137 (*p_td_ta_get_ph) (const td_thragent_t *ta_p, struct ps_prochandle **ph_pp);
138static td_err_e
139 (*p_td_ta_get_nthreads) (const td_thragent_t *ta_p, int *nthread_p);
140static td_err_e
141 (*p_td_ta_tsd_iter) (const td_thragent_t *ta_p, td_key_iter_f *cb, void *cbdata_p);
142static td_err_e
143 (*p_td_ta_thr_iter) (const td_thragent_t *ta_p, td_thr_iter_f *cb, void *cbdata_p, td_thr_state_e state,
144 int ti_pri, sigset_t *ti_sigmask_p, unsigned ti_user_flags);
145static td_err_e
146 (*p_td_thr_validate) (const td_thrhandle_t *th_p);
147static td_err_e
148 (*p_td_thr_tsd) (const td_thrhandle_t *th_p, const thread_key_t key, void **data_pp);
149static td_err_e
150 (*p_td_thr_get_info) (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
151static td_err_e
152 (*p_td_thr_getfpregs) (const td_thrhandle_t *th_p, prfpregset_t *fpregset);
153static td_err_e
154 (*p_td_thr_getxregsize) (const td_thrhandle_t *th_p, int *xregsize);
155static td_err_e
156 (*p_td_thr_getxregs) (const td_thrhandle_t *th_p, const caddr_t xregset);
157static td_err_e
158 (*p_td_thr_sigsetmask) (const td_thrhandle_t *th_p, const sigset_t ti_sigmask);
159static td_err_e
160 (*p_td_thr_setprio) (const td_thrhandle_t *th_p, const int ti_pri);
161static td_err_e
162 (*p_td_thr_setsigpending) (const td_thrhandle_t *th_p, const uchar_t ti_pending_flag, const sigset_t ti_pending);
163static td_err_e
164 (*p_td_thr_setfpregs) (const td_thrhandle_t *th_p, const prfpregset_t *fpregset);
165static td_err_e
166 (*p_td_thr_setxregs) (const td_thrhandle_t *th_p, const caddr_t xregset);
167static td_err_e
168 (*p_td_ta_map_id2thr) (const td_thragent_t *ta_p, thread_t tid, td_thrhandle_t *th_p);
169static td_err_e
170 (*p_td_ta_map_lwp2thr) (const td_thragent_t *ta_p, lwpid_t lwpid, td_thrhandle_t *th_p);
171static td_err_e
172 (*p_td_thr_getgregs) (const td_thrhandle_t *th_p, prgregset_t regset);
173static td_err_e
174 (*p_td_thr_setgregs) (const td_thrhandle_t *th_p, const prgregset_t regset);
175\f
176/*
177
178LOCAL FUNCTION
179
180 td_err_string - Convert a thread_db error code to a string
181
182SYNOPSIS
183
184 char * td_err_string (errcode)
185
186DESCRIPTION
187
188 Return the thread_db error string associated with errcode. If errcode
189 is unknown, then return a message.
190
191 */
192
193static char *
194td_err_string (errcode)
195 td_err_e errcode;
196{
197 static struct string_map
198 td_err_table[] = {
199 {TD_OK, "generic \"call succeeded\""},
200 {TD_ERR, "generic error."},
201 {TD_NOTHR, "no thread can be found to satisfy query"},
202 {TD_NOSV, "no synch. variable can be found to satisfy query"},
203 {TD_NOLWP, "no lwp can be found to satisfy query"},
204 {TD_BADPH, "invalid process handle"},
205 {TD_BADTH, "invalid thread handle"},
206 {TD_BADSH, "invalid synchronization handle"},
207 {TD_BADTA, "invalid thread agent"},
208 {TD_BADKEY, "invalid key"},
209 {TD_NOMSG, "td_thr_event_getmsg() called when there was no message"},
210 {TD_NOFPREGS, "FPU register set not available for given thread"},
211 {TD_NOLIBTHREAD, "application not linked with libthread"},
212 {TD_NOEVENT, "requested event is not supported"},
213 {TD_NOCAPAB, "capability not available"},
214 {TD_DBERR, "Debugger service failed"},
215 {TD_NOAPLIC, "Operation not applicable to"},
216 {TD_NOTSD, "No thread specific data for this thread"},
217 {TD_MALLOC, "Malloc failed"},
218 {TD_PARTIALREG, "Only part of register set was writen/read"},
219 {TD_NOXREGS, "X register set not available for given thread"}
220 };
221 const int td_err_size = sizeof td_err_table / sizeof (struct string_map);
222 int i;
223 static char buf[50];
224
225 for (i = 0; i < td_err_size; i++)
226 if (td_err_table[i].num == errcode)
227 return td_err_table[i].str;
228
229 sprintf (buf, "Unknown thread_db error code: %d", errcode);
230
231 return buf;
232}
233\f
234/*
235
236LOCAL FUNCTION
237
238 td_state_string - Convert a thread_db state code to a string
239
240SYNOPSIS
241
242 char * td_state_string (statecode)
243
244DESCRIPTION
245
246 Return the thread_db state string associated with statecode. If
247 statecode is unknown, then return a message.
248
249 */
250
251static char *
252td_state_string (statecode)
253 td_thr_state_e statecode;
254{
255 static struct string_map
256 td_thr_state_table[] = {
257 {TD_THR_ANY_STATE, "any state"},
258 {TD_THR_UNKNOWN, "unknown"},
259 {TD_THR_STOPPED, "stopped"},
260 {TD_THR_RUN, "run"},
261 {TD_THR_ACTIVE, "active"},
262 {TD_THR_ZOMBIE, "zombie"},
263 {TD_THR_SLEEP, "sleep"},
264 {TD_THR_STOPPED_ASLEEP, "stopped asleep"}
265 };
266 const int td_thr_state_table_size = sizeof td_thr_state_table / sizeof (struct string_map);
267 int i;
268 static char buf[50];
269
270 for (i = 0; i < td_thr_state_table_size; i++)
271 if (td_thr_state_table[i].num == statecode)
272 return td_thr_state_table[i].str;
273
274 sprintf (buf, "Unknown thread_db state code: %d", statecode);
275
276 return buf;
277}
278\f
279/*
280
281LOCAL FUNCTION
282
283 thread_to_lwp - Convert a Posix or Solaris thread id to a LWP id.
284
285SYNOPSIS
286
287 int thread_to_lwp (thread_id, default_lwp)
288
289DESCRIPTION
290
291 This function converts a Posix or Solaris thread id to a lightweight
292 process id. If thread_id is non-existent, that's an error. If it's
293 an inactive thread, then we return default_lwp.
294
295NOTES
296
297 This function probably shouldn't call error()...
298
299 */
300
301static int
302thread_to_lwp (thread_id, default_lwp)
303 int thread_id;
304 int default_lwp;
305{
306 td_thrinfo_t ti;
307 td_thrhandle_t th;
308 td_err_e val;
309 int pid;
310 int lwp;
311
312 if (is_lwp (thread_id))
313 return thread_id; /* It's already an LWP id */
314
315 /* It's a thread. Convert to lwp */
316
317 pid = PIDGET (thread_id);
318 thread_id = GET_THREAD(thread_id);
319
320 val = p_td_ta_map_id2thr (main_ta, thread_id, &th);
321 if (val != TD_OK)
322 error ("thread_to_lwp: td_ta_map_id2thr %s", td_err_string (val));
323
324 val = p_td_thr_get_info (&th, &ti);
325
326 if (val != TD_OK)
327 error ("thread_to_lwp: td_thr_get_info: %s", td_err_string (val));
328
329 if (ti.ti_state != TD_THR_ACTIVE)
330 {
331 if (default_lwp != -1)
332 return default_lwp;
333 error ("thread_to_lwp: thread state not active: %s",
334 td_state_string (ti.ti_state));
335 }
336
337 lwp = BUILD_LWP (ti.ti_lid, pid);
338
339 return lwp;
340}
341\f
342/*
343
344LOCAL FUNCTION
345
346 lwp_to_thread - Convert a LWP id to a Posix or Solaris thread id.
347
348SYNOPSIS
349
350 int lwp_to_thread (lwp_id)
351
352DESCRIPTION
353
354 This function converts a lightweight process id to a Posix or Solaris
355 thread id. If thread_id is non-existent, that's an error.
356
357NOTES
358
359 This function probably shouldn't call error()...
360
361 */
362
363static int
364lwp_to_thread (lwp)
365 int lwp;
366{
367 td_thrinfo_t ti;
368 td_thrhandle_t th;
369 td_err_e val;
370 int pid;
371 int thread_id;
372
373 if (is_thread (lwp))
374 return lwp; /* It's already a thread id */
375
376 /* It's an lwp. Convert it to a thread id. */
377
378 pid = PIDGET (lwp);
379 lwp = GET_LWP (lwp);
380
381 val = p_td_ta_map_lwp2thr (main_ta, lwp, &th);
382 if (val != TD_OK)
383 error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
384
385 val = p_td_thr_get_info (&th, &ti);
386
387 if (val != TD_OK)
388 error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
389
390 thread_id = BUILD_THREAD (ti.ti_tid, pid);
391
392 return thread_id;
393}
394\f
395/*
396
397LOCAL FUNCTION
398
399 save_inferior_pid - Save inferior_pid on the cleanup list
400 restore_inferior_pid - Restore inferior_pid from the cleanup list
401
402SYNOPSIS
403
404 struct cleanup *save_inferior_pid ()
405 void restore_inferior_pid (int pid)
406
407DESCRIPTION
408
409 These two functions act in unison to restore inferior_pid in
410 case of an error.
411
412NOTES
413
414 inferior_pid is a global variable that needs to be changed by many of
415 these routines before calling functions in procfs.c. In order to
416 guarantee that inferior_pid gets restored (in case of errors), you
417 need to call save_inferior_pid before changing it. At the end of the
418 function, you should invoke do_cleanups to restore it.
419
420 */
421
422
423static struct cleanup *
424save_inferior_pid ()
425{
426 return make_cleanup (restore_inferior_pid, inferior_pid);
427}
428
429static void
430restore_inferior_pid (pid)
431 int pid;
432{
433 inferior_pid = pid;
434}
435\f
436
437/* Most target vector functions from here on actually just pass through to
438 procfs.c, as they don't need to do anything specific for threads. */
439
440
441/* ARGSUSED */
442static void
443sol_thread_open (arg, from_tty)
444 char *arg;
445 int from_tty;
446{
447 procfs_ops.to_open (arg, from_tty);
448}
449
450/* Attach to process PID, then initialize for debugging it
451 and wait for the trace-trap that results from attaching. */
452
453static void
454sol_thread_attach (args, from_tty)
455 char *args;
456 int from_tty;
457{
458 procfs_ops.to_attach (args, from_tty);
459
460 /* XXX - might want to iterate over all the threads and register them. */
461}
462
463/* Take a program previously attached to and detaches it.
464 The program resumes execution and will no longer stop
465 on signals, etc. We'd better not have left any breakpoints
466 in the program or it'll die when it hits one. For this
467 to work, it may be necessary for the process to have been
468 previously attached. It *might* work if the program was
469 started via the normal ptrace (PTRACE_TRACEME). */
470
471static void
472sol_thread_detach (args, from_tty)
473 char *args;
474 int from_tty;
475{
476 procfs_ops.to_detach (args, from_tty);
477}
478
479/* Resume execution of process PID. If STEP is nozero, then
480 just single step it. If SIGNAL is nonzero, restart it with that
481 signal activated. We may have to convert pid from a thread-id to an LWP id
482 for procfs. */
483
484static void
485sol_thread_resume (pid, step, signo)
486 int pid;
487 int step;
488 enum target_signal signo;
489{
490 struct cleanup *old_chain;
491
492 old_chain = save_inferior_pid ();
493
494 inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid);
495
496 if (pid != -1)
497 {
498 pid = thread_to_lwp (pid, -2);
499 if (pid == -2) /* Inactive thread */
500 error ("This version of Solaris can't start inactive threads.");
501 }
502
503 procfs_ops.to_resume (pid, step, signo);
504
505 do_cleanups (old_chain);
506}
507
508/* Wait for any threads to stop. We may have to convert PID from a thread id
509 to a LWP id, and vice versa on the way out. */
510
511static int
512sol_thread_wait (pid, ourstatus)
513 int pid;
514 struct target_waitstatus *ourstatus;
515{
516 int rtnval;
517 int save_pid;
518 struct cleanup *old_chain;
519
520 save_pid = inferior_pid;
521 old_chain = save_inferior_pid ();
522
523 inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid);
524
525 if (pid != -1)
526 pid = thread_to_lwp (pid, -1);
527
528 rtnval = procfs_ops.to_wait (pid, ourstatus);
529
530 if (rtnval != save_pid
531 && !in_thread_list (rtnval))
532 {
533 fprintf_unfiltered (gdb_stderr, "[New %s]\n",
534 target_pid_to_str (rtnval));
535 add_thread (rtnval);
536 }
537
538 /* During process initialization, we may get here without the thread package
539 being initialized, since that can only happen after we've found the shared
540 libs. */
541
542 /* Map the LWP of interest back to the appropriate thread ID */
543
544 rtnval = lwp_to_thread (rtnval);
545
546 do_cleanups (old_chain);
547
548 return rtnval;
549}
550
551static void
552sol_thread_fetch_registers (regno)
553 int regno;
554{
555 thread_t thread;
556 td_thrhandle_t thandle;
557 td_err_e val;
558 prgregset_t gregset;
559 prfpregset_t fpregset;
560#if 0
561 int xregsize;
562 caddr_t xregset;
563#endif
564
565 /* Convert inferior_pid into a td_thrhandle_t */
566
567 thread = GET_THREAD (inferior_pid);
568
569 if (thread == 0)
570 error ("sol_thread_fetch_registers: thread == 0");
571
572 val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
573 if (val != TD_OK)
574 error ("sol_thread_fetch_registers: td_ta_map_id2thr: %s",
575 td_err_string (val));
576
577 /* Get the integer regs */
578
579 val = p_td_thr_getgregs (&thandle, gregset);
580 if (val != TD_OK
581 && val != TD_PARTIALREG)
582 error ("sol_thread_fetch_registers: td_thr_getgregs %s",
583 td_err_string (val));
584
585 /* For the sparc, TD_PARTIALREG means that only i0->i7, l0->l7, pc and sp
586 are saved (by a thread context switch). */
587
588 /* And, now the fp regs */
589
590 val = p_td_thr_getfpregs (&thandle, &fpregset);
591 if (val != TD_OK
592 && val != TD_NOFPREGS)
593 error ("sol_thread_fetch_registers: td_thr_getfpregs %s",
594 td_err_string (val));
595
596/* Note that we must call supply_{g fp}regset *after* calling the td routines
597 because the td routines call ps_lget* which affect the values stored in the
598 registers array. */
599
600 supply_gregset (gregset);
601 supply_fpregset (fpregset);
602
603#if 0
604/* thread_db doesn't seem to handle this right */
605 val = td_thr_getxregsize (&thandle, &xregsize);
606 if (val != TD_OK && val != TD_NOXREGS)
607 error ("sol_thread_fetch_registers: td_thr_getxregsize %s",
608 td_err_string (val));
609
610 if (val == TD_OK)
611 {
612 xregset = alloca (xregsize);
613 val = td_thr_getxregs (&thandle, xregset);
614 if (val != TD_OK)
615 error ("sol_thread_fetch_registers: td_thr_getxregs %s",
616 td_err_string (val));
617 }
618#endif
619}
620
621static void
622sol_thread_store_registers (regno)
623 int regno;
624{
625 thread_t thread;
626 td_thrhandle_t thandle;
627 td_err_e val;
628 prgregset_t regset;
629 prfpregset_t fpregset;
630#if 0
631 int xregsize;
632 caddr_t xregset;
633#endif
634
635 /* Convert inferior_pid into a td_thrhandle_t */
636
637 thread = GET_THREAD (inferior_pid);
638
639 val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
640 if (val != TD_OK)
641 error ("sol_thread_store_registers: td_ta_map_id2thr %s",
642 td_err_string (val));
643
644 if (regno != -1)
645 { /* Not writing all the regs */
646 val = p_td_thr_getgregs (&thandle, regset);
647 if (val != TD_OK)
648 error ("sol_thread_store_registers: td_thr_getgregs %s",
649 td_err_string (val));
650 val = p_td_thr_getfpregs (&thandle, &fpregset);
651 if (val != TD_OK)
652 error ("sol_thread_store_registers: td_thr_getfpregs %s",
653 td_err_string (val));
654
655#if 0
656/* thread_db doesn't seem to handle this right */
657 val = td_thr_getxregsize (&thandle, &xregsize);
658 if (val != TD_OK && val != TD_NOXREGS)
659 error ("sol_thread_store_registers: td_thr_getxregsize %s",
660 td_err_string (val));
661
662 if (val == TD_OK)
663 {
664 xregset = alloca (xregsize);
665 val = td_thr_getxregs (&thandle, xregset);
666 if (val != TD_OK)
667 error ("sol_thread_store_registers: td_thr_getxregs %s",
668 td_err_string (val));
669 }
670#endif
671 }
672
673 fill_gregset (regset, regno);
674 fill_fpregset (fpregset, regno);
675
676 val = p_td_thr_setgregs (&thandle, regset);
677 if (val != TD_OK)
678 error ("sol_thread_store_registers: td_thr_setgregs %s",
679 td_err_string (val));
680 val = p_td_thr_setfpregs (&thandle, &fpregset);
681 if (val != TD_OK)
682 error ("sol_thread_store_registers: td_thr_setfpregs %s",
683 td_err_string (val));
684
685#if 0
686/* thread_db doesn't seem to handle this right */
687 val = td_thr_getxregsize (&thandle, &xregsize);
688 if (val != TD_OK && val != TD_NOXREGS)
689 error ("sol_thread_store_registers: td_thr_getxregsize %s",
690 td_err_string (val));
691
692 /* Should probably do something about writing the xregs here, but what are
693 they? */
694#endif
695}
696
697/* Get ready to modify the registers array. On machines which store
698 individual registers, this doesn't need to do anything. On machines
699 which store all the registers in one fell swoop, this makes sure
700 that registers contains all the registers from the program being
701 debugged. */
702
703static void
704sol_thread_prepare_to_store ()
705{
706 procfs_ops.to_prepare_to_store ();
707}
708
709static int
710sol_thread_xfer_memory (memaddr, myaddr, len, dowrite, target)
711 CORE_ADDR memaddr;
712 char *myaddr;
713 int len;
714 int dowrite;
715 struct target_ops *target; /* ignored */
716{
717 int retval;
718 struct cleanup *old_chain;
719
720 old_chain = save_inferior_pid ();
721
722 if (is_thread (inferior_pid))
723 inferior_pid = main_ph.pid; /* It's a thread. Convert to lwp */
724
725 retval = procfs_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target);
726
727 do_cleanups (old_chain);
728
729 return retval;
730}
731
732/* Print status information about what we're accessing. */
733
734static void
735sol_thread_files_info (ignore)
736 struct target_ops *ignore;
737{
738 procfs_ops.to_files_info (ignore);
739}
740
741static void
742sol_thread_kill_inferior ()
743{
744 procfs_ops.to_kill ();
745}
746
747static void
748sol_thread_notice_signals (pid)
749 int pid;
750{
751 procfs_ops.to_notice_signals (pid);
752}
753
754void target_new_objfile PARAMS ((struct objfile *objfile));
755
756/* Fork an inferior process, and start debugging it with /proc. */
757
758static void
759sol_thread_create_inferior (exec_file, allargs, env)
760 char *exec_file;
761 char *allargs;
762 char **env;
763{
764 procfs_ops.to_create_inferior (exec_file, allargs, env);
765
766 if (sol_thread_active)
767 {
768 main_ph.pid = inferior_pid; /* Save for xfer_memory */
769
770 push_target (&sol_thread_ops);
771
772 inferior_pid = lwp_to_thread (inferior_pid);
773
774 add_thread (inferior_pid);
775 }
776}
777
778/* This routine is called whenever a new symbol table is read in, or when all
779 symbol tables are removed. libthread_db can only be initialized when it
780 finds the right variables in libthread.so. Since it's a shared library,
781 those variables don't show up until the library gets mapped and the symbol
782 table is read in. */
783
784void
785sol_thread_new_objfile (objfile)
786 struct objfile *objfile;
787{
788 td_err_e val;
789
790 if (!objfile)
791 {
792 sol_thread_active = 0;
793
794 return;
795 }
796
797 /* Now, initialize the thread debugging library. This needs to be done after
798 the shared libraries are located because it needs information from the
799 user's thread library. */
800
801 val = p_td_init ();
802 if (val != TD_OK)
803 error ("target_new_objfile: td_init: %s", td_err_string (val));
804
805 val = p_td_ta_new (&main_ph, &main_ta);
806 if (val == TD_NOLIBTHREAD)
807 return;
808 else if (val != TD_OK)
809 error ("target_new_objfile: td_ta_new: %s", td_err_string (val));
810
811 sol_thread_active = 1;
812}
813
814/* Clean up after the inferior dies. */
815
816static void
817sol_thread_mourn_inferior ()
818{
819 procfs_ops.to_mourn_inferior ();
820}
821
822/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
823
824static int
825sol_thread_can_run ()
826{
827 return procfs_suppress_run;
828}
829
830static int
831sol_thread_alive (pid)
832 int pid;
833{
834 return 1;
835}
836
837static void
838sol_thread_stop ()
839{
840 procfs_ops.to_stop ();
841}
842\f
843/* These routines implement the lower half of the thread_db interface. Ie: the
844 ps_* routines. */
845
846/* The next four routines are called by thread_db to tell us to stop and stop
847 a particular process or lwp. Since GDB ensures that these are all stopped
848 by the time we call anything in thread_db, these routines need to do
849 nothing. */
850
851ps_err_e
852ps_pstop (const struct ps_prochandle *ph)
853{
854 return PS_OK;
855}
856
857ps_err_e
858ps_pcontinue (const struct ps_prochandle *ph)
859{
860 return PS_OK;
861}
862
863ps_err_e
864ps_lstop (const struct ps_prochandle *ph, lwpid_t lwpid)
865{
866 return PS_OK;
867}
868
869ps_err_e
870ps_lcontinue (const struct ps_prochandle *ph, lwpid_t lwpid)
871{
872 return PS_OK;
873}
874
875ps_err_e
876ps_pglobal_lookup (const struct ps_prochandle *ph, const char *ld_object_name,
877 const char *ld_symbol_name, paddr_t *ld_symbol_addr)
878{
879 struct minimal_symbol *ms;
880
881 ms = lookup_minimal_symbol (ld_symbol_name, NULL, NULL);
882
883 if (!ms)
884 return PS_NOSYM;
885
886 *ld_symbol_addr = SYMBOL_VALUE_ADDRESS (ms);
887
888 return PS_OK;
889}
890
891/* Common routine for reading and writing memory. */
892
893static ps_err_e
894rw_common (int dowrite, const struct ps_prochandle *ph, paddr_t addr,
895 char *buf, int size)
896{
897 struct cleanup *old_chain;
898
899 old_chain = save_inferior_pid ();
900
901 if (is_thread (inferior_pid))
902 inferior_pid = main_ph.pid; /* It's a thread. Convert to lwp */
903
904 while (size > 0)
905 {
906 int cc;
907
908 cc = procfs_ops.to_xfer_memory (addr, buf, size, dowrite, &procfs_ops);
909
910 if (cc < 0)
911 {
912 if (dowrite == 0)
913 print_sys_errmsg ("ps_pdread (): read", errno);
914 else
915 print_sys_errmsg ("ps_pdread (): write", errno);
916
917 do_cleanups (old_chain);
918
919 return PS_ERR;
920 }
921 size -= cc;
922 buf += cc;
923 }
924
925 do_cleanups (old_chain);
926
927 return PS_OK;
928}
929
930ps_err_e
931ps_pdread (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size)
932{
933 return rw_common (0, ph, addr, buf, size);
934}
935
936ps_err_e
937ps_pdwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size)
938{
939 return rw_common (1, ph, addr, buf, size);
940}
941
942ps_err_e
943ps_ptread (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size)
944{
945 return rw_common (0, ph, addr, buf, size);
946}
947
948ps_err_e
949ps_ptwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size)
950{
951 return rw_common (1, ph, addr, buf, size);
952}
953
954/* Get integer regs */
955
956ps_err_e
957ps_lgetregs (const struct ps_prochandle *ph, lwpid_t lwpid,
958 prgregset_t gregset)
959{
960 struct cleanup *old_chain;
961
962 old_chain = save_inferior_pid ();
963
964 inferior_pid = BUILD_LWP (lwpid, PIDGET (inferior_pid));
965
966 procfs_ops.to_fetch_registers (-1);
967 fill_gregset (gregset, -1);
968
969 do_cleanups (old_chain);
970
971 return PS_OK;
972}
973
974/* Set integer regs */
975
976ps_err_e
977ps_lsetregs (const struct ps_prochandle *ph, lwpid_t lwpid,
978 const prgregset_t gregset)
979{
980 struct cleanup *old_chain;
981
982 old_chain = save_inferior_pid ();
983
984 inferior_pid = BUILD_LWP (lwpid, PIDGET (inferior_pid));
985
986 supply_gregset (gregset);
987 procfs_ops.to_store_registers (-1);
988
989 do_cleanups (old_chain);
990
991 return PS_OK;
992}
993
994void
995ps_plog (const char *fmt, ...)
996{
997 va_list args;
998
999 va_start (args, fmt);
1000
1001 vfprintf_filtered (gdb_stderr, fmt, args);
1002}
1003
1004/* Get size of extra register set. Currently a noop. */
1005
1006ps_err_e
1007ps_lgetxregsize (const struct ps_prochandle *ph, lwpid_t lwpid, int *xregsize)
1008{
1009#if 0
1010 int lwp_fd;
1011 int regsize;
1012 ps_err_e val;
1013
1014 val = get_lwp_fd (ph, lwpid, &lwp_fd);
1015 if (val != PS_OK)
1016 return val;
1017
1018 if (ioctl (lwp_fd, PIOCGXREGSIZE, &regsize))
1019 {
1020 if (errno == EINVAL)
1021 return PS_NOFREGS; /* XXX Wrong code, but this is the closest
1022 thing in proc_service.h */
1023
1024 print_sys_errmsg ("ps_lgetxregsize (): PIOCGXREGSIZE", errno);
1025 return PS_ERR;
1026 }
1027#endif
1028
1029 return PS_OK;
1030}
1031
1032/* Get extra register set. Currently a noop. */
1033
1034ps_err_e
1035ps_lgetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset)
1036{
1037#if 0
1038 int lwp_fd;
1039 ps_err_e val;
1040
1041 val = get_lwp_fd (ph, lwpid, &lwp_fd);
1042 if (val != PS_OK)
1043 return val;
1044
1045 if (ioctl (lwp_fd, PIOCGXREG, xregset))
1046 {
1047 print_sys_errmsg ("ps_lgetxregs (): PIOCGXREG", errno);
1048 return PS_ERR;
1049 }
1050#endif
1051
1052 return PS_OK;
1053}
1054
1055/* Set extra register set. Currently a noop. */
1056
1057ps_err_e
1058ps_lsetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset)
1059{
1060#if 0
1061 int lwp_fd;
1062 ps_err_e val;
1063
1064 val = get_lwp_fd (ph, lwpid, &lwp_fd);
1065 if (val != PS_OK)
1066 return val;
1067
1068 if (ioctl (lwp_fd, PIOCSXREG, xregset))
1069 {
1070 print_sys_errmsg ("ps_lsetxregs (): PIOCSXREG", errno);
1071 return PS_ERR;
1072 }
1073#endif
1074
1075 return PS_OK;
1076}
1077
1078/* Get floating-point regs. */
1079
1080ps_err_e
1081ps_lgetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid,
1082 prfpregset_t *fpregset)
1083{
1084 struct cleanup *old_chain;
1085
1086 old_chain = save_inferior_pid ();
1087
1088 inferior_pid = BUILD_LWP (lwpid, PIDGET (inferior_pid));
1089
1090 procfs_ops.to_fetch_registers (-1);
1091 fill_fpregset (*fpregset, -1);
1092
1093 do_cleanups (old_chain);
1094
1095 return PS_OK;
1096}
1097
1098/* Set floating-point regs. */
1099
1100ps_err_e
1101ps_lsetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid,
1102 const prfpregset_t *fpregset)
1103{
1104 struct cleanup *old_chain;
1105
1106 old_chain = save_inferior_pid ();
1107
1108 inferior_pid = BUILD_LWP (lwpid, PIDGET (inferior_pid));
1109
1110 supply_fpregset (*fpregset);
1111 procfs_ops.to_store_registers (-1);
1112
1113 do_cleanups (old_chain);
1114
1115 return PS_OK;
1116}
1117\f
1118/* Convert a pid to printable form. */
1119
1120char *
1121solaris_pid_to_str (pid)
1122 int pid;
1123{
1124 static char buf[100];
1125
1126 if (is_thread (pid))
1127 {
1128 int lwp;
1129
1130 lwp = thread_to_lwp (pid, -2);
1131
1132 if (lwp != -2)
1133 sprintf (buf, "Thread %d (LWP %d)", GET_THREAD (pid), GET_LWP (lwp));
1134 else
1135 sprintf (buf, "Thread %d ", GET_THREAD (pid));
1136 }
1137 else
1138 sprintf (buf, "LWP %d ", GET_LWP (pid));
1139
1140 return buf;
1141}
1142\f
1143struct target_ops sol_thread_ops = {
1144 "solaris-threads", /* to_shortname */
1145 "Solaris threads and pthread.", /* to_longname */
1146 "Solaris threads and pthread support.", /* to_doc */
1147 sol_thread_open, /* to_open */
1148 0, /* to_close */
1149 sol_thread_attach, /* to_attach */
1150 sol_thread_detach, /* to_detach */
1151 sol_thread_resume, /* to_resume */
1152 sol_thread_wait, /* to_wait */
1153 sol_thread_fetch_registers, /* to_fetch_registers */
1154 sol_thread_store_registers, /* to_store_registers */
1155 sol_thread_prepare_to_store, /* to_prepare_to_store */
1156 sol_thread_xfer_memory, /* to_xfer_memory */
1157 sol_thread_files_info, /* to_files_info */
1158 memory_insert_breakpoint, /* to_insert_breakpoint */
1159 memory_remove_breakpoint, /* to_remove_breakpoint */
1160 terminal_init_inferior, /* to_terminal_init */
1161 terminal_inferior, /* to_terminal_inferior */
1162 terminal_ours_for_output, /* to_terminal_ours_for_output */
1163 terminal_ours, /* to_terminal_ours */
1164 child_terminal_info, /* to_terminal_info */
1165 sol_thread_kill_inferior, /* to_kill */
1166 0, /* to_load */
1167 0, /* to_lookup_symbol */
1168 sol_thread_create_inferior, /* to_create_inferior */
1169 sol_thread_mourn_inferior, /* to_mourn_inferior */
1170 sol_thread_can_run, /* to_can_run */
1171 sol_thread_notice_signals, /* to_notice_signals */
1172 sol_thread_alive, /* to_thread_alive */
1173 sol_thread_stop, /* to_stop */
1174 process_stratum, /* to_stratum */
1175 0, /* to_next */
1176 1, /* to_has_all_memory */
1177 1, /* to_has_memory */
1178 1, /* to_has_stack */
1179 1, /* to_has_registers */
1180 1, /* to_has_execution */
1181 0, /* sections */
1182 0, /* sections_end */
1183 OPS_MAGIC /* to_magic */
1184};
1185
1186void
1187_initialize_sol_thread ()
1188{
1189 void *dlhandle;
1190
1191 dlhandle = dlopen ("libthread_db.so.1", RTLD_NOW);
1192 if (!dlhandle)
1193 goto die;
1194
1195#define resolve(X) \
1196 if (!(p_##X = dlsym (dlhandle, #X))) \
1197 goto die;
1198
1199 resolve (td_log);
1200 resolve (td_ta_new);
1201 resolve (td_ta_delete);
1202 resolve (td_init);
1203 resolve (td_ta_get_ph);
1204 resolve (td_ta_get_nthreads);
1205 resolve (td_ta_tsd_iter);
1206 resolve (td_ta_thr_iter);
1207 resolve (td_thr_validate);
1208 resolve (td_thr_tsd);
1209 resolve (td_thr_get_info);
1210 resolve (td_thr_getfpregs);
1211 resolve (td_thr_getxregsize);
1212 resolve (td_thr_getxregs);
1213 resolve (td_thr_sigsetmask);
1214 resolve (td_thr_setprio);
1215 resolve (td_thr_setsigpending);
1216 resolve (td_thr_setfpregs);
1217 resolve (td_thr_setxregs);
1218 resolve (td_ta_map_id2thr);
1219 resolve (td_ta_map_lwp2thr);
1220 resolve (td_thr_getgregs);
1221 resolve (td_thr_setgregs);
1222
1223 add_target (&sol_thread_ops);
1224
1225 procfs_suppress_run = 1;
1226
1227 return;
1228
1229 die:
1230
1231 fprintf_unfiltered (gdb_stderr, "[GDB will not be able to debug user-mode threads: %s]\n", dlerror ());
1232
1233 if (dlhandle)
1234 dlclose (dlhandle);
1235
1236 return;
1237}
This page took 0.033667 seconds and 4 git commands to generate.