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