]> Git Repo - binutils.git/blob - gdb/hpux-thread.c
This commit was generated by cvs2svn to track changes on a CVS vendor
[binutils.git] / gdb / hpux-thread.c
1 /* Low level interface for debugging HPUX/DCE threads for GDB, the GNU debugger.
2    Copyright 1996, 1999 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,
19    Boston, MA 02111-1307, USA.  */
20
21 /* This module implements a sort of half target that sits between the
22    machine-independent parts of GDB and the ptrace interface (infptrace.c) to
23    provide access to the HPUX user-mode thread implementation.
24
25    HPUX threads are true user-mode threads, which are invoked via the cma_*
26    and pthread_* (DCE and Posix respectivly) interfaces.  These are mostly
27    implemented in user-space, with all thread context kept in various
28    structures that live in the user's heap.  For the most part, the kernel has
29    no knowlege of these threads.
30
31  */
32
33 #include "defs.h"
34
35 #define _CMA_NOWRAPPERS_
36
37 #include <cma_tcb_defs.h>
38 #include <cma_deb_core.h>
39 #include "gdbthread.h"
40 #include "target.h"
41 #include "inferior.h"
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <sys/stat.h>
45 #include "gdbcore.h"
46
47 extern int child_suppress_run;
48 extern struct target_ops child_ops;     /* target vector for inftarg.c */
49
50 extern void _initialize_hpux_thread PARAMS ((void));
51
52 struct string_map
53   {
54     int num;
55     char *str;
56   };
57
58 static int hpux_thread_active = 0;
59
60 static int main_pid;            /* Real process ID */
61
62 static CORE_ADDR P_cma__g_known_threads;
63 static CORE_ADDR P_cma__g_current_thread;
64
65 static struct cleanup *save_inferior_pid PARAMS ((void));
66
67 static void restore_inferior_pid PARAMS ((int pid));
68
69 static void hpux_thread_resume PARAMS ((int pid, int step,
70                                         enum target_signal signo));
71
72 static void init_hpux_thread_ops PARAMS ((void));
73
74 static struct target_ops hpux_thread_ops;
75 \f
76 /*
77
78    LOCAL FUNCTION
79
80    save_inferior_pid - Save inferior_pid on the cleanup list
81    restore_inferior_pid - Restore inferior_pid from the cleanup list
82
83    SYNOPSIS
84
85    struct cleanup *save_inferior_pid ()
86    void restore_inferior_pid (int pid)
87
88    DESCRIPTION
89
90    These two functions act in unison to restore inferior_pid in
91    case of an error.
92
93    NOTES
94
95    inferior_pid is a global variable that needs to be changed by many of
96    these routines before calling functions in procfs.c.  In order to
97    guarantee that inferior_pid gets restored (in case of errors), you
98    need to call save_inferior_pid before changing it.  At the end of the
99    function, you should invoke do_cleanups to restore it.
100
101  */
102
103
104 static struct cleanup *
105 save_inferior_pid ()
106 {
107   return make_cleanup (restore_inferior_pid, inferior_pid);
108 }
109
110 static void
111 restore_inferior_pid (pid)
112      int pid;
113 {
114   inferior_pid = pid;
115 }
116 \f
117 static int find_active_thread PARAMS ((void));
118
119 static int cached_thread;
120 static int cached_active_thread;
121 static cma__t_int_tcb cached_tcb;
122
123 static int
124 find_active_thread ()
125 {
126   static cma__t_int_tcb tcb;
127   CORE_ADDR tcb_ptr;
128
129   if (cached_active_thread != 0)
130     return cached_active_thread;
131
132   read_memory ((CORE_ADDR) P_cma__g_current_thread,
133                (char *) &tcb_ptr,
134                sizeof tcb_ptr);
135
136   read_memory (tcb_ptr, (char *) &tcb, sizeof tcb);
137
138   return (cma_thread_get_unique (&tcb.prolog.client_thread) << 16) | main_pid;
139 }
140
141 static cma__t_int_tcb *find_tcb PARAMS ((int thread));
142
143 static cma__t_int_tcb *
144 find_tcb (thread)
145      int thread;
146 {
147   cma__t_known_object queue_header;
148   cma__t_queue *queue_ptr;
149
150   if (thread == cached_thread)
151     return &cached_tcb;
152
153   read_memory ((CORE_ADDR) P_cma__g_known_threads,
154                (char *) &queue_header,
155                sizeof queue_header);
156
157   for (queue_ptr = queue_header.queue.flink;
158        queue_ptr != (cma__t_queue *) P_cma__g_known_threads;
159        queue_ptr = cached_tcb.threads.flink)
160     {
161       cma__t_int_tcb *tcb_ptr;
162
163       tcb_ptr = cma__base (queue_ptr, threads, cma__t_int_tcb);
164
165       read_memory ((CORE_ADDR) tcb_ptr, (char *) &cached_tcb, sizeof cached_tcb);
166
167       if (cached_tcb.header.type == cma__c_obj_tcb)
168         if (cma_thread_get_unique (&cached_tcb.prolog.client_thread) == thread >> 16)
169           {
170             cached_thread = thread;
171             return &cached_tcb;
172           }
173     }
174
175   error ("Can't find TCB %d,%d", thread >> 16, thread & 0xffff);
176   return NULL;
177 }
178 \f
179 /* Most target vector functions from here on actually just pass through to
180    inftarg.c, as they don't need to do anything specific for threads.  */
181
182 /* ARGSUSED */
183 static void
184 hpux_thread_open (arg, from_tty)
185      char *arg;
186      int from_tty;
187 {
188   child_ops.to_open (arg, from_tty);
189 }
190
191 /* Attach to process PID, then initialize for debugging it
192    and wait for the trace-trap that results from attaching.  */
193
194 static void
195 hpux_thread_attach (args, from_tty)
196      char *args;
197      int from_tty;
198 {
199   child_ops.to_attach (args, from_tty);
200
201   /* XXX - might want to iterate over all the threads and register them. */
202 }
203
204 /* Take a program previously attached to and detaches it.
205    The program resumes execution and will no longer stop
206    on signals, etc.  We'd better not have left any breakpoints
207    in the program or it'll die when it hits one.  For this
208    to work, it may be necessary for the process to have been
209    previously attached.  It *might* work if the program was
210    started via the normal ptrace (PTRACE_TRACEME).  */
211
212 static void
213 hpux_thread_detach (args, from_tty)
214      char *args;
215      int from_tty;
216 {
217   child_ops.to_detach (args, from_tty);
218 }
219
220 /* Resume execution of process PID.  If STEP is nozero, then
221    just single step it.  If SIGNAL is nonzero, restart it with that
222    signal activated.  We may have to convert pid from a thread-id to an LWP id
223    for procfs.  */
224
225 static void
226 hpux_thread_resume (pid, step, signo)
227      int pid;
228      int step;
229      enum target_signal signo;
230 {
231   struct cleanup *old_chain;
232
233   old_chain = save_inferior_pid ();
234
235   pid = inferior_pid = main_pid;
236
237 #if 0
238   if (pid != -1)
239     {
240       pid = thread_to_lwp (pid, -2);
241       if (pid == -2)            /* Inactive thread */
242         error ("This version of Solaris can't start inactive threads.");
243     }
244 #endif
245
246   child_ops.to_resume (pid, step, signo);
247
248   cached_thread = 0;
249   cached_active_thread = 0;
250
251   do_cleanups (old_chain);
252 }
253
254 /* Wait for any threads to stop.  We may have to convert PID from a thread id
255    to a LWP id, and vice versa on the way out.  */
256
257 static int
258 hpux_thread_wait (pid, ourstatus)
259      int pid;
260      struct target_waitstatus *ourstatus;
261 {
262   int rtnval;
263   struct cleanup *old_chain;
264
265   old_chain = save_inferior_pid ();
266
267   inferior_pid = main_pid;
268
269   if (pid != -1)
270     pid = main_pid;
271
272   rtnval = child_ops.to_wait (pid, ourstatus);
273
274   rtnval = find_active_thread ();
275
276   do_cleanups (old_chain);
277
278   return rtnval;
279 }
280
281 static char regmap[NUM_REGS] =
282 {
283   -2, -1, -1, 0, 4, 8, 12, 16, 20, 24,  /* flags, r1 -> r9 */
284   28, 32, 36, 40, 44, 48, 52, 56, 60, -1,       /* r10 -> r19 */
285   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,       /* r20 -> r29 */
286
287   /* r30, r31, sar, pcoqh, pcsqh, pcoqt, pcsqt, eiem, iir, isr */
288   -2, -1, -1, -2, -1, -1, -1, -1, -1, -1,
289
290   /* ior, ipsw, goto, sr4, sr0, sr1, sr2, sr3, sr5, sr6 */
291   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
292
293   /* sr7, cr0, cr8, cr9, ccr, cr12, cr13, cr24, cr25, cr26 */
294   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
295
296   -1, -1, -1, -1,               /* mpsfu_high, mpsfu_low, mpsfu_ovflo, pad */
297   144, -1, -1, -1, -1, -1, -1, -1,      /* fpsr, fpe1 -> fpe7 */
298   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr4 -> fr7 */
299   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr8 -> fr11 */
300   136, -1, 128, -1, 120, -1, 112, -1,   /* fr12 -> fr15 */
301   104, -1, 96, -1, 88, -1, 80, -1,      /* fr16 -> fr19 */
302   72, -1, 64, -1, -1, -1, -1, -1,       /* fr20 -> fr23 */
303   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr24 -> fr27 */
304   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr28 -> fr31 */
305 };
306
307 static void
308 hpux_thread_fetch_registers (regno)
309      int regno;
310 {
311   cma__t_int_tcb tcb, *tcb_ptr;
312   struct cleanup *old_chain;
313   int i;
314   int first_regno, last_regno;
315
316   tcb_ptr = find_tcb (inferior_pid);
317
318   old_chain = save_inferior_pid ();
319
320   inferior_pid = main_pid;
321
322   if (tcb_ptr->state == cma__c_state_running)
323     {
324       child_ops.to_fetch_registers (regno);
325
326       do_cleanups (old_chain);
327
328       return;
329     }
330
331   if (regno == -1)
332     {
333       first_regno = 0;
334       last_regno = NUM_REGS - 1;
335     }
336   else
337     {
338       first_regno = regno;
339       last_regno = regno;
340     }
341
342   for (regno = first_regno; regno <= last_regno; regno++)
343     {
344       if (regmap[regno] == -1)
345         child_ops.to_fetch_registers (regno);
346       else
347         {
348           unsigned char buf[MAX_REGISTER_RAW_SIZE];
349           CORE_ADDR sp;
350
351           sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
352
353           if (regno == FLAGS_REGNUM)
354             /* Flags must be 0 to avoid bogus value for SS_INSYSCALL */
355             memset (buf, '\000', REGISTER_RAW_SIZE (regno));
356           else if (regno == SP_REGNUM)
357             store_address (buf, sizeof sp, sp);
358           else if (regno == PC_REGNUM)
359             read_memory (sp - 20, buf, REGISTER_RAW_SIZE (regno));
360           else
361             read_memory (sp + regmap[regno], buf, REGISTER_RAW_SIZE (regno));
362
363           supply_register (regno, buf);
364         }
365     }
366
367   do_cleanups (old_chain);
368 }
369
370 static void
371 hpux_thread_store_registers (regno)
372      int regno;
373 {
374   cma__t_int_tcb tcb, *tcb_ptr;
375   struct cleanup *old_chain;
376   int i;
377   int first_regno, last_regno;
378
379   tcb_ptr = find_tcb (inferior_pid);
380
381   old_chain = save_inferior_pid ();
382
383   inferior_pid = main_pid;
384
385   if (tcb_ptr->state == cma__c_state_running)
386     {
387       child_ops.to_store_registers (regno);
388
389       do_cleanups (old_chain);
390
391       return;
392     }
393
394   if (regno == -1)
395     {
396       first_regno = 0;
397       last_regno = NUM_REGS - 1;
398     }
399   else
400     {
401       first_regno = regno;
402       last_regno = regno;
403     }
404
405   for (regno = first_regno; regno <= last_regno; regno++)
406     {
407       if (regmap[regno] == -1)
408         child_ops.to_store_registers (regno);
409       else
410         {
411           unsigned char buf[MAX_REGISTER_RAW_SIZE];
412           CORE_ADDR sp;
413
414           sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
415
416           if (regno == FLAGS_REGNUM)
417             child_ops.to_store_registers (regno);       /* Let lower layer handle this... */
418           else if (regno == SP_REGNUM)
419             {
420               write_memory ((CORE_ADDR) & tcb_ptr->static_ctx.sp,
421                             registers + REGISTER_BYTE (regno),
422                             REGISTER_RAW_SIZE (regno));
423               tcb_ptr->static_ctx.sp = (cma__t_hppa_regs *)
424                 (extract_address (registers + REGISTER_BYTE (regno), REGISTER_RAW_SIZE (regno)) + 160);
425             }
426           else if (regno == PC_REGNUM)
427             write_memory (sp - 20,
428                           registers + REGISTER_BYTE (regno),
429                           REGISTER_RAW_SIZE (regno));
430           else
431             write_memory (sp + regmap[regno],
432                           registers + REGISTER_BYTE (regno),
433                           REGISTER_RAW_SIZE (regno));
434         }
435     }
436
437   do_cleanups (old_chain);
438 }
439
440 /* Get ready to modify the registers array.  On machines which store
441    individual registers, this doesn't need to do anything.  On machines
442    which store all the registers in one fell swoop, this makes sure
443    that registers contains all the registers from the program being
444    debugged.  */
445
446 static void
447 hpux_thread_prepare_to_store ()
448 {
449   child_ops.to_prepare_to_store ();
450 }
451
452 static int
453 hpux_thread_xfer_memory (memaddr, myaddr, len, dowrite, target)
454      CORE_ADDR memaddr;
455      char *myaddr;
456      int len;
457      int dowrite;
458      struct target_ops *target; /* ignored */
459 {
460   int retval;
461   struct cleanup *old_chain;
462
463   old_chain = save_inferior_pid ();
464
465   inferior_pid = main_pid;
466
467   retval = child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target);
468
469   do_cleanups (old_chain);
470
471   return retval;
472 }
473
474 /* Print status information about what we're accessing.  */
475
476 static void
477 hpux_thread_files_info (ignore)
478      struct target_ops *ignore;
479 {
480   child_ops.to_files_info (ignore);
481 }
482
483 static void
484 hpux_thread_kill_inferior ()
485 {
486   child_ops.to_kill ();
487 }
488
489 static void
490 hpux_thread_notice_signals (pid)
491      int pid;
492 {
493   child_ops.to_notice_signals (pid);
494 }
495
496 /* Fork an inferior process, and start debugging it with /proc.  */
497
498 static void
499 hpux_thread_create_inferior (exec_file, allargs, env)
500      char *exec_file;
501      char *allargs;
502      char **env;
503 {
504   child_ops.to_create_inferior (exec_file, allargs, env);
505
506   if (hpux_thread_active)
507     {
508       main_pid = inferior_pid;
509
510       push_target (&hpux_thread_ops);
511
512       inferior_pid = find_active_thread ();
513
514       add_thread (inferior_pid);
515     }
516 }
517
518 /* This routine is called whenever a new symbol table is read in, or when all
519    symbol tables are removed.  libthread_db can only be initialized when it
520    finds the right variables in libthread.so.  Since it's a shared library,
521    those variables don't show up until the library gets mapped and the symbol
522    table is read in.  */
523
524 void
525 hpux_thread_new_objfile (objfile)
526      struct objfile *objfile;
527 {
528   struct minimal_symbol *ms;
529
530   if (!objfile)
531     {
532       hpux_thread_active = 0;
533
534       return;
535     }
536
537   ms = lookup_minimal_symbol ("cma__g_known_threads", NULL, objfile);
538
539   if (!ms)
540     return;
541
542   P_cma__g_known_threads = SYMBOL_VALUE_ADDRESS (ms);
543
544   ms = lookup_minimal_symbol ("cma__g_current_thread", NULL, objfile);
545
546   if (!ms)
547     return;
548
549   P_cma__g_current_thread = SYMBOL_VALUE_ADDRESS (ms);
550
551   hpux_thread_active = 1;
552 }
553
554 /* Clean up after the inferior dies.  */
555
556 static void
557 hpux_thread_mourn_inferior ()
558 {
559   child_ops.to_mourn_inferior ();
560 }
561
562 /* Mark our target-struct as eligible for stray "run" and "attach" commands.  */
563
564 static int
565 hpux_thread_can_run ()
566 {
567   return child_suppress_run;
568 }
569
570 static int
571 hpux_thread_alive (pid)
572      int pid;
573 {
574   return 1;
575 }
576
577 static void
578 hpux_thread_stop ()
579 {
580   child_ops.to_stop ();
581 }
582 \f
583 /* Convert a pid to printable form. */
584
585 char *
586 hpux_pid_to_str (pid)
587      int pid;
588 {
589   static char buf[100];
590
591   sprintf (buf, "Thread %d", pid >> 16);
592
593   return buf;
594 }
595 \f
596 static void
597 init_hpux_thread_ops ()
598 {
599   hpux_thread_ops.to_shortname = "hpux-threads";
600   hpux_thread_ops.to_longname = "HPUX threads and pthread.";
601   hpux_thread_ops.to_doc = "HPUX threads and pthread support.";
602   hpux_thread_ops.to_open = hpux_thread_open;
603   hpux_thread_ops.to_attach = hpux_thread_attach;
604   hpux_thread_ops.to_detach = hpux_thread_detach;
605   hpux_thread_ops.to_resume = hpux_thread_resume;
606   hpux_thread_ops.to_wait = hpux_thread_wait;
607   hpux_thread_ops.to_fetch_registers = hpux_thread_fetch_registers;
608   hpux_thread_ops.to_store_registers = hpux_thread_store_registers;
609   hpux_thread_ops.to_prepare_to_store = hpux_thread_prepare_to_store;
610   hpux_thread_ops.to_xfer_memory = hpux_thread_xfer_memory;
611   hpux_thread_ops.to_files_info = hpux_thread_files_info;
612   hpux_thread_ops.to_insert_breakpoint = memory_insert_breakpoint;
613   hpux_thread_ops.to_remove_breakpoint = memory_remove_breakpoint;
614   hpux_thread_ops.to_terminal_init = terminal_init_inferior;
615   hpux_thread_ops.to_terminal_inferior = terminal_inferior;
616   hpux_thread_ops.to_terminal_ours_for_output = terminal_ours_for_output;
617   hpux_thread_ops.to_terminal_ours = terminal_ours;
618   hpux_thread_ops.to_terminal_info = child_terminal_info;
619   hpux_thread_ops.to_kill = hpux_thread_kill_inferior;
620   hpux_thread_ops.to_create_inferior = hpux_thread_create_inferior;
621   hpux_thread_ops.to_mourn_inferior = hpux_thread_mourn_inferior;
622   hpux_thread_ops.to_can_run = hpux_thread_can_run;
623   hpux_thread_ops.to_notice_signals = hpux_thread_notice_signals;
624   hpux_thread_ops.to_thread_alive = hpux_thread_alive;
625   hpux_thread_ops.to_stop = hpux_thread_stop;
626   hpux_thread_ops.to_stratum = process_stratum;
627   hpux_thread_ops.to_has_all_memory = 1;
628   hpux_thread_ops.to_has_memory = 1;
629   hpux_thread_ops.to_has_stack = 1;
630   hpux_thread_ops.to_has_registers = 1;
631   hpux_thread_ops.to_has_execution = 1;
632   hpux_thread_ops.to_magic = OPS_MAGIC;
633 }
634
635 void
636 _initialize_hpux_thread ()
637 {
638   init_hpux_thread_ops ();
639   add_target (&hpux_thread_ops);
640
641   child_suppress_run = 1;
642 }
This page took 0.060021 seconds and 4 git commands to generate.