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