2004-02-14 Elena Zannoni <ezannoni@redhat.com>
[platform/upstream/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 static void
135 hpux_thread_open (char *arg, int from_tty)
136 {
137   child_ops.to_open (arg, from_tty);
138 }
139
140 /* Attach to process PID, then initialize for debugging it
141    and wait for the trace-trap that results from attaching.  */
142
143 static void
144 hpux_thread_attach (char *args, int from_tty)
145 {
146   child_ops.to_attach (args, from_tty);
147
148   /* XXX - might want to iterate over all the threads and register them. */
149 }
150
151 /* Take a program previously attached to and detaches it.
152    The program resumes execution and will no longer stop
153    on signals, etc.  We'd better not have left any breakpoints
154    in the program or it'll die when it hits one.  For this
155    to work, it may be necessary for the process to have been
156    previously attached.  It *might* work if the program was
157    started via the normal ptrace (PTRACE_TRACEME).  */
158
159 static void
160 hpux_thread_detach (char *args, int from_tty)
161 {
162   child_ops.to_detach (args, from_tty);
163 }
164
165 /* Resume execution of process PID.  If STEP is nozero, then
166    just single step it.  If SIGNAL is nonzero, restart it with that
167    signal activated.  We may have to convert pid from a thread-id to an LWP id
168    for procfs.  */
169
170 static void
171 hpux_thread_resume (ptid_t ptid, int step, enum target_signal signo)
172 {
173   struct cleanup *old_chain;
174
175   old_chain = save_inferior_ptid ();
176
177   ptid = main_ptid;
178   inferior_ptid = main_ptid;
179
180 #if 0
181   if (pid != -1)
182     {
183       pid = thread_to_lwp (pid, -2);
184       if (pid == -2)            /* Inactive thread */
185         error ("This version of Solaris can't start inactive threads.");
186     }
187 #endif
188
189   child_ops.to_resume (ptid, step, signo);
190
191   cached_thread = 0;
192
193   do_cleanups (old_chain);
194 }
195
196 /* Wait for any threads to stop.  We may have to convert PID from a thread id
197    to a LWP id, and vice versa on the way out.  */
198
199 static ptid_t
200 hpux_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
201 {
202   ptid_t rtnval;
203   struct cleanup *old_chain;
204
205   old_chain = save_inferior_ptid ();
206
207   inferior_ptid = main_ptid;
208
209   if (!ptid_equal (ptid, minus_one_ptid))
210     ptid = main_ptid;
211
212   rtnval = child_ops.to_wait (ptid, ourstatus);
213
214   rtnval = find_active_thread ();
215
216   do_cleanups (old_chain);
217
218   return rtnval;
219 }
220
221 static char regmap[NUM_REGS] =
222 {
223   -2, -1, -1, 0, 4, 8, 12, 16, 20, 24,  /* flags, r1 -> r9 */
224   28, 32, 36, 40, 44, 48, 52, 56, 60, -1,       /* r10 -> r19 */
225   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,       /* r20 -> r29 */
226
227   /* r30, r31, sar, pcoqh, pcsqh, pcoqt, pcsqt, eiem, iir, isr */
228   -2, -1, -1, -2, -1, -1, -1, -1, -1, -1,
229
230   /* ior, ipsw, goto, sr4, sr0, sr1, sr2, sr3, sr5, sr6 */
231   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
232
233   /* sr7, cr0, cr8, cr9, ccr, cr12, cr13, cr24, cr25, cr26 */
234   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
235
236   -1, -1, -1, -1,               /* mpsfu_high, mpsfu_low, mpsfu_ovflo, pad */
237   144, -1, -1, -1, -1, -1, -1, -1,      /* fpsr, fpe1 -> fpe7 */
238   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr4 -> fr7 */
239   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr8 -> fr11 */
240   136, -1, 128, -1, 120, -1, 112, -1,   /* fr12 -> fr15 */
241   104, -1, 96, -1, 88, -1, 80, -1,      /* fr16 -> fr19 */
242   72, -1, 64, -1, -1, -1, -1, -1,       /* fr20 -> fr23 */
243   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr24 -> fr27 */
244   -1, -1, -1, -1, -1, -1, -1, -1,       /* fr28 -> fr31 */
245 };
246
247 static void
248 hpux_thread_fetch_registers (int regno)
249 {
250   cma__t_int_tcb tcb, *tcb_ptr;
251   struct cleanup *old_chain;
252   int i;
253   int first_regno, last_regno;
254
255   tcb_ptr = find_tcb (inferior_ptid);
256
257   old_chain = save_inferior_ptid ();
258
259   inferior_ptid = main_ptid;
260
261   if (tcb_ptr->state == cma__c_state_running)
262     {
263       child_ops.to_fetch_registers (regno);
264
265       do_cleanups (old_chain);
266
267       return;
268     }
269
270   if (regno == -1)
271     {
272       first_regno = 0;
273       last_regno = NUM_REGS - 1;
274     }
275   else
276     {
277       first_regno = regno;
278       last_regno = regno;
279     }
280
281   for (regno = first_regno; regno <= last_regno; regno++)
282     {
283       if (regmap[regno] == -1)
284         child_ops.to_fetch_registers (regno);
285       else
286         {
287           unsigned char buf[MAX_REGISTER_SIZE];
288           CORE_ADDR sp;
289
290           sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
291
292           if (regno == FLAGS_REGNUM)
293             /* Flags must be 0 to avoid bogus value for SS_INSYSCALL */
294             memset (buf, '\000', DEPRECATED_REGISTER_RAW_SIZE (regno));
295           else if (regno == SP_REGNUM)
296             store_unsigned_integer (buf, sizeof sp, sp);
297           else if (regno == PC_REGNUM)
298             read_memory (sp - 20, buf, DEPRECATED_REGISTER_RAW_SIZE (regno));
299           else
300             read_memory (sp + regmap[regno], buf, DEPRECATED_REGISTER_RAW_SIZE (regno));
301
302           supply_register (regno, buf);
303         }
304     }
305
306   do_cleanups (old_chain);
307 }
308
309 static void
310 hpux_thread_store_registers (int regno)
311 {
312   cma__t_int_tcb tcb, *tcb_ptr;
313   struct cleanup *old_chain;
314   int i;
315   int first_regno, last_regno;
316
317   tcb_ptr = find_tcb (inferior_ptid);
318
319   old_chain = save_inferior_ptid ();
320
321   inferior_ptid = main_ptid;
322
323   if (tcb_ptr->state == cma__c_state_running)
324     {
325       child_ops.to_store_registers (regno);
326
327       do_cleanups (old_chain);
328
329       return;
330     }
331
332   if (regno == -1)
333     {
334       first_regno = 0;
335       last_regno = NUM_REGS - 1;
336     }
337   else
338     {
339       first_regno = regno;
340       last_regno = regno;
341     }
342
343   for (regno = first_regno; regno <= last_regno; regno++)
344     {
345       if (regmap[regno] == -1)
346         child_ops.to_store_registers (regno);
347       else
348         {
349           unsigned char buf[MAX_REGISTER_SIZE];
350           CORE_ADDR sp;
351
352           sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
353
354           if (regno == FLAGS_REGNUM)
355             child_ops.to_store_registers (regno);       /* Let lower layer handle this... */
356           else if (regno == SP_REGNUM)
357             {
358               write_memory ((CORE_ADDR) & tcb_ptr->static_ctx.sp,
359                             &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)],
360                             DEPRECATED_REGISTER_RAW_SIZE (regno));
361               tcb_ptr->static_ctx.sp = (cma__t_hppa_regs *)
362                 (extract_unsigned_integer (&deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)],
363                                            DEPRECATED_REGISTER_RAW_SIZE (regno)) + 160);
364             }
365           else if (regno == PC_REGNUM)
366             write_memory (sp - 20,
367                           &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)],
368                           DEPRECATED_REGISTER_RAW_SIZE (regno));
369           else
370             write_memory (sp + regmap[regno],
371                           &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)],
372                           DEPRECATED_REGISTER_RAW_SIZE (regno));
373         }
374     }
375
376   do_cleanups (old_chain);
377 }
378
379 /* Get ready to modify the registers array.  On machines which store
380    individual registers, this doesn't need to do anything.  On machines
381    which store all the registers in one fell swoop, this makes sure
382    that registers contains all the registers from the program being
383    debugged.  */
384
385 static void
386 hpux_thread_prepare_to_store (void)
387 {
388   child_ops.to_prepare_to_store ();
389 }
390
391 static int
392 hpux_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
393                          int dowrite, struct mem_attrib *attribs,
394                          struct target_ops *target)
395 {
396   int retval;
397   struct cleanup *old_chain;
398
399   old_chain = save_inferior_ptid ();
400
401   inferior_ptid = main_ptid;
402
403   retval = 
404     child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, attribs, target);
405
406   do_cleanups (old_chain);
407
408   return retval;
409 }
410
411 /* Print status information about what we're accessing.  */
412
413 static void
414 hpux_thread_files_info (struct target_ops *ignore)
415 {
416   child_ops.to_files_info (ignore);
417 }
418
419 static void
420 hpux_thread_kill_inferior (void)
421 {
422   child_ops.to_kill ();
423 }
424
425 static void
426 hpux_thread_notice_signals (ptid_t ptid)
427 {
428   child_ops.to_notice_signals (ptid);
429 }
430
431 /* Fork an inferior process, and start debugging it with /proc.  */
432
433 static void
434 hpux_thread_create_inferior (char *exec_file, char *allargs, char **env)
435 {
436   child_ops.to_create_inferior (exec_file, allargs, env);
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 = target_new_objfile_hook;
585   target_new_objfile_hook  = hpux_thread_new_objfile;
586 }