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