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