Wed Nov 20 16:15:15 1996 Geoffrey Noer <noer@cygnus.com>
[deliverable/binutils-gdb.git] / gdb / sol-thread.c
1 /* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
2 Copyright 1996 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 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
71 extern struct target_ops sol_thread_ops; /* Forward declaration */
72
73 extern int procfs_suppress_run;
74 extern 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
85 extern void supply_gregset PARAMS ((const prgregset_t));
86 extern void fill_gregset PARAMS ((prgregset_t, int));
87 extern void supply_fpregset PARAMS ((const prfpregset_t));
88 extern 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
94 struct ps_prochandle
95 {
96 pid_t pid;
97 };
98
99 struct string_map
100 {
101 int num;
102 char *str;
103 };
104
105 static struct ps_prochandle main_ph;
106 static td_thragent_t *main_ta;
107 static int sol_thread_active = 0;
108
109 static struct cleanup * save_inferior_pid PARAMS ((void));
110 static void restore_inferior_pid PARAMS ((int pid));
111 static char *td_err_string PARAMS ((td_err_e errcode));
112 static char *td_state_string PARAMS ((td_thr_state_e statecode));
113 static int thread_to_lwp PARAMS ((int thread_id, int default_lwp));
114 static void sol_thread_resume PARAMS ((int pid, int step,
115 enum target_signal signo));
116 static 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
128 static void
129 (*p_td_log) (const int on_off);
130 static td_err_e
131 (*p_td_ta_new) (const struct ps_prochandle *ph_p, td_thragent_t **ta_pp);
132 static td_err_e
133 (*p_td_ta_delete) (td_thragent_t *ta_p);
134 static td_err_e
135 (*p_td_init) (void);
136 static td_err_e
137 (*p_td_ta_get_ph) (const td_thragent_t *ta_p, struct ps_prochandle **ph_pp);
138 static td_err_e
139 (*p_td_ta_get_nthreads) (const td_thragent_t *ta_p, int *nthread_p);
140 static td_err_e
141 (*p_td_ta_tsd_iter) (const td_thragent_t *ta_p, td_key_iter_f *cb, void *cbdata_p);
142 static 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);
145 static td_err_e
146 (*p_td_thr_validate) (const td_thrhandle_t *th_p);
147 static td_err_e
148 (*p_td_thr_tsd) (const td_thrhandle_t *th_p, const thread_key_t key, void **data_pp);
149 static td_err_e
150 (*p_td_thr_get_info) (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
151 static td_err_e
152 (*p_td_thr_getfpregs) (const td_thrhandle_t *th_p, prfpregset_t *fpregset);
153 static td_err_e
154 (*p_td_thr_getxregsize) (const td_thrhandle_t *th_p, int *xregsize);
155 static td_err_e
156 (*p_td_thr_getxregs) (const td_thrhandle_t *th_p, const caddr_t xregset);
157 static td_err_e
158 (*p_td_thr_sigsetmask) (const td_thrhandle_t *th_p, const sigset_t ti_sigmask);
159 static td_err_e
160 (*p_td_thr_setprio) (const td_thrhandle_t *th_p, const int ti_pri);
161 static 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);
163 static td_err_e
164 (*p_td_thr_setfpregs) (const td_thrhandle_t *th_p, const prfpregset_t *fpregset);
165 static td_err_e
166 (*p_td_thr_setxregs) (const td_thrhandle_t *th_p, const caddr_t xregset);
167 static td_err_e
168 (*p_td_ta_map_id2thr) (const td_thragent_t *ta_p, thread_t tid, td_thrhandle_t *th_p);
169 static td_err_e
170 (*p_td_ta_map_lwp2thr) (const td_thragent_t *ta_p, lwpid_t lwpid, td_thrhandle_t *th_p);
171 static td_err_e
172 (*p_td_thr_getgregs) (const td_thrhandle_t *th_p, prgregset_t regset);
173 static td_err_e
174 (*p_td_thr_setgregs) (const td_thrhandle_t *th_p, const prgregset_t regset);
175 \f
176 /*
177
178 LOCAL FUNCTION
179
180 td_err_string - Convert a thread_db error code to a string
181
182 SYNOPSIS
183
184 char * td_err_string (errcode)
185
186 DESCRIPTION
187
188 Return the thread_db error string associated with errcode. If errcode
189 is unknown, then return a message.
190
191 */
192
193 static char *
194 td_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
236 LOCAL FUNCTION
237
238 td_state_string - Convert a thread_db state code to a string
239
240 SYNOPSIS
241
242 char * td_state_string (statecode)
243
244 DESCRIPTION
245
246 Return the thread_db state string associated with statecode. If
247 statecode is unknown, then return a message.
248
249 */
250
251 static char *
252 td_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
281 LOCAL FUNCTION
282
283 thread_to_lwp - Convert a Posix or Solaris thread id to a LWP id.
284
285 SYNOPSIS
286
287 int thread_to_lwp (thread_id, default_lwp)
288
289 DESCRIPTION
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
295 NOTES
296
297 This function probably shouldn't call error()...
298
299 */
300
301 static int
302 thread_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
344 LOCAL FUNCTION
345
346 lwp_to_thread - Convert a LWP id to a Posix or Solaris thread id.
347
348 SYNOPSIS
349
350 int lwp_to_thread (lwp_id)
351
352 DESCRIPTION
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
357 NOTES
358
359 This function probably shouldn't call error()...
360
361 */
362
363 static int
364 lwp_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
397 LOCAL 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
402 SYNOPSIS
403
404 struct cleanup *save_inferior_pid ()
405 void restore_inferior_pid (int pid)
406
407 DESCRIPTION
408
409 These two functions act in unison to restore inferior_pid in
410 case of an error.
411
412 NOTES
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
423 static struct cleanup *
424 save_inferior_pid ()
425 {
426 return make_cleanup (restore_inferior_pid, inferior_pid);
427 }
428
429 static void
430 restore_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 */
442 static void
443 sol_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
453 static void
454 sol_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
471 static void
472 sol_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
484 static void
485 sol_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
511 static int
512 sol_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
551 static void
552 sol_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
621 static void
622 sol_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
703 static void
704 sol_thread_prepare_to_store ()
705 {
706 procfs_ops.to_prepare_to_store ();
707 }
708
709 static int
710 sol_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
734 static void
735 sol_thread_files_info (ignore)
736 struct target_ops *ignore;
737 {
738 procfs_ops.to_files_info (ignore);
739 }
740
741 static void
742 sol_thread_kill_inferior ()
743 {
744 procfs_ops.to_kill ();
745 }
746
747 static void
748 sol_thread_notice_signals (pid)
749 int pid;
750 {
751 procfs_ops.to_notice_signals (pid);
752 }
753
754 void target_new_objfile PARAMS ((struct objfile *objfile));
755
756 /* Fork an inferior process, and start debugging it with /proc. */
757
758 static void
759 sol_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
784 void
785 sol_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
816 static void
817 sol_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
824 static int
825 sol_thread_can_run ()
826 {
827 return procfs_suppress_run;
828 }
829
830 static int
831 sol_thread_alive (pid)
832 int pid;
833 {
834 return 1;
835 }
836
837 static void
838 sol_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
851 ps_err_e
852 ps_pstop (const struct ps_prochandle *ph)
853 {
854 return PS_OK;
855 }
856
857 ps_err_e
858 ps_pcontinue (const struct ps_prochandle *ph)
859 {
860 return PS_OK;
861 }
862
863 ps_err_e
864 ps_lstop (const struct ps_prochandle *ph, lwpid_t lwpid)
865 {
866 return PS_OK;
867 }
868
869 ps_err_e
870 ps_lcontinue (const struct ps_prochandle *ph, lwpid_t lwpid)
871 {
872 return PS_OK;
873 }
874
875 ps_err_e
876 ps_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
893 static ps_err_e
894 rw_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
930 ps_err_e
931 ps_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
936 ps_err_e
937 ps_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
942 ps_err_e
943 ps_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
948 ps_err_e
949 ps_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
956 ps_err_e
957 ps_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
976 ps_err_e
977 ps_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
994 void
995 ps_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
1006 ps_err_e
1007 ps_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
1034 ps_err_e
1035 ps_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
1057 ps_err_e
1058 ps_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
1080 ps_err_e
1081 ps_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
1100 ps_err_e
1101 ps_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
1120 char *
1121 solaris_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
1143 struct 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
1186 void
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.124673 seconds and 4 git commands to generate.