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