]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/hpux-thread.c
Phase 1 of the ptid_t changes.
[thirdparty/binutils-gdb.git] / gdb / hpux-thread.c
CommitLineData
c906108c 1/* Low level interface for debugging HPUX/DCE threads for GDB, the GNU debugger.
b6ba6518 2 Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
c906108c 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"
4e052eda 42#include "regcache.h"
c906108c 43#include <fcntl.h>
c906108c
SS
44#include <sys/stat.h>
45#include "gdbcore.h"
46
47extern int child_suppress_run;
c5aa993b 48extern struct target_ops child_ops; /* target vector for inftarg.c */
c906108c 49
a14ed312 50extern void _initialize_hpux_thread (void);
c906108c
SS
51
52struct string_map
c5aa993b
JM
53 {
54 int num;
55 char *str;
56 };
c906108c
SS
57
58static int hpux_thread_active = 0;
59
39f77062 60static ptid_t main_ptid; /* Real process ID */
c906108c
SS
61
62static CORE_ADDR P_cma__g_known_threads;
63static CORE_ADDR P_cma__g_current_thread;
64
39f77062 65static struct cleanup *save_inferior_ptid (void);
c906108c 66
39f77062 67static void restore_inferior_ptid (ptid_t pid);
c906108c 68
39f77062
KB
69static void hpux_thread_resume (ptid_t ptid, int step,
70 enum target_signal signo);
c906108c 71
a14ed312 72static void init_hpux_thread_ops (void);
c906108c
SS
73
74static struct target_ops hpux_thread_ops;
75\f
76/*
77
c5aa993b 78 LOCAL FUNCTION
c906108c 79
39f77062
KB
80 save_inferior_ptid - Save inferior_ptid on the cleanup list
81 restore_inferior_ptid - Restore inferior_ptid from the cleanup list
c906108c 82
c5aa993b 83 SYNOPSIS
c906108c 84
39f77062
KB
85 struct cleanup *save_inferior_ptid ()
86 void restore_inferior_ptid (int pid)
c906108c 87
c5aa993b 88 DESCRIPTION
c906108c 89
39f77062 90 These two functions act in unison to restore inferior_ptid in
c5aa993b 91 case of an error.
c906108c 92
c5aa993b 93 NOTES
c906108c 94
39f77062 95 inferior_ptid is a global variable that needs to be changed by many of
c5aa993b 96 these routines before calling functions in procfs.c. In order to
39f77062
KB
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
c5aa993b 99 function, you should invoke do_cleanups to restore it.
c906108c
SS
100
101 */
102
103
104static struct cleanup *
39f77062 105save_inferior_ptid (void)
c906108c 106{
39f77062 107 return make_cleanup (restore_inferior_ptid, inferior_ptid);
c906108c
SS
108}
109
110static void
39f77062 111restore_inferior_ptid (ptid_t ptid)
c906108c 112{
39f77062 113 inferior_ptid = ptid;
c906108c
SS
114}
115\f
a14ed312 116static int find_active_thread (void);
c906108c
SS
117
118static int cached_thread;
119static int cached_active_thread;
120static cma__t_int_tcb cached_tcb;
121
122static int
fba45db2 123find_active_thread (void)
c906108c
SS
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 136
39f77062
KB
137 return (cma_thread_get_unique (&tcb.prolog.client_thread) << 16)
138 | PIDGET (main_ptid);
c906108c
SS
139}
140
a14ed312 141static cma__t_int_tcb *find_tcb (int thread);
c906108c
SS
142
143static cma__t_int_tcb *
fba45db2 144find_tcb (int thread)
c906108c
SS
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
fba45db2 183hpux_thread_open (char *arg, int from_tty)
c906108c
SS
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
191static void
fba45db2 192hpux_thread_attach (char *args, int from_tty)
c906108c
SS
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
207static void
fba45db2 208hpux_thread_detach (char *args, int from_tty)
c906108c
SS
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
39f77062 219hpux_thread_resume (ptid_t ptid, int step, enum target_signal signo)
c906108c
SS
220{
221 struct cleanup *old_chain;
222
39f77062 223 old_chain = save_inferior_ptid ();
c906108c 224
39f77062
KB
225 ptid = main_ptid;
226 inferior_ptid = main_ptid;
c906108c
SS
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
39f77062 237 child_ops.to_resume (ptid, step, signo);
c906108c
SS
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
39f77062
KB
248static ptid_t
249hpux_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
c906108c 250{
39f77062 251 ptid_t rtnval;
c906108c
SS
252 struct cleanup *old_chain;
253
39f77062 254 old_chain = save_inferior_ptid ();
c906108c 255
39f77062 256 inferior_ptid = main_ptid;
c906108c 257
39f77062
KB
258 if (!ptid_equal (ptid, minus_one_ptid))
259 ptid = main_ptid;
c906108c 260
39f77062 261 rtnval = child_ops.to_wait (ptid, ourstatus);
c906108c
SS
262
263 rtnval = find_active_thread ();
264
265 do_cleanups (old_chain);
266
267 return rtnval;
268}
269
270static char regmap[NUM_REGS] =
271{
c5aa993b
JM
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 */
c906108c
SS
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 */
c5aa993b
JM
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 */
c906108c
SS
294};
295
296static void
fba45db2 297hpux_thread_fetch_registers (int regno)
c906108c
SS
298{
299 cma__t_int_tcb tcb, *tcb_ptr;
300 struct cleanup *old_chain;
301 int i;
302 int first_regno, last_regno;
303
39f77062 304 tcb_ptr = find_tcb (PIDGET (inferior_ptid));
c906108c 305
39f77062 306 old_chain = save_inferior_ptid ();
c906108c 307
39f77062 308 inferior_ptid = main_ptid;
c906108c
SS
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
c5aa993b 339 sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
c906108c
SS
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
358static void
fba45db2 359hpux_thread_store_registers (int regno)
c906108c
SS
360{
361 cma__t_int_tcb tcb, *tcb_ptr;
362 struct cleanup *old_chain;
363 int i;
364 int first_regno, last_regno;
365
39f77062 366 tcb_ptr = find_tcb (PIDGET (inferior_ptid));
c906108c 367
39f77062 368 old_chain = save_inferior_ptid ();
c906108c 369
39f77062 370 inferior_ptid = main_ptid;
c906108c
SS
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
c5aa993b 401 sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160;
c906108c
SS
402
403 if (regno == FLAGS_REGNUM)
c5aa993b 404 child_ops.to_store_registers (regno); /* Let lower layer handle this... */
c906108c
SS
405 else if (regno == SP_REGNUM)
406 {
c5aa993b 407 write_memory ((CORE_ADDR) & tcb_ptr->static_ctx.sp,
c906108c
SS
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
433static void
fba45db2 434hpux_thread_prepare_to_store (void)
c906108c
SS
435{
436 child_ops.to_prepare_to_store ();
437}
438
439static int
165a58fe 440hpux_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
971429b4
AC
441 int dowrite, struct mem_attrib *attribs,
442 struct target_ops *target)
c906108c
SS
443{
444 int retval;
445 struct cleanup *old_chain;
446
39f77062 447 old_chain = save_inferior_ptid ();
c906108c 448
39f77062 449 inferior_ptid = main_ptid;
c906108c 450
971429b4
AC
451 retval =
452 child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, attribs, target);
c906108c
SS
453
454 do_cleanups (old_chain);
455
456 return retval;
457}
458
459/* Print status information about what we're accessing. */
460
461static void
fba45db2 462hpux_thread_files_info (struct target_ops *ignore)
c906108c
SS
463{
464 child_ops.to_files_info (ignore);
465}
466
467static void
fba45db2 468hpux_thread_kill_inferior (void)
c906108c
SS
469{
470 child_ops.to_kill ();
471}
472
473static void
39f77062 474hpux_thread_notice_signals (ptid_t ptid)
c906108c 475{
39f77062 476 child_ops.to_notice_signals (ptid);
c906108c
SS
477}
478
479/* Fork an inferior process, and start debugging it with /proc. */
480
481static void
fba45db2 482hpux_thread_create_inferior (char *exec_file, char *allargs, char **env)
c906108c
SS
483{
484 child_ops.to_create_inferior (exec_file, allargs, env);
485
486 if (hpux_thread_active)
487 {
39f77062 488 main_ptid = inferior_ptid;
c906108c
SS
489
490 push_target (&hpux_thread_ops);
491
39f77062 492 inferior_ptid = find_active_thread ();
c906108c 493
39f77062 494 add_thread (inferior_ptid);
c906108c
SS
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
11cf8741
JM
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. */
507f3c78 509static void (*target_new_objfile_chain) (struct objfile *);
11cf8741 510
c906108c 511void
fba45db2 512hpux_thread_new_objfile (struct objfile *objfile)
c906108c
SS
513{
514 struct minimal_symbol *ms;
515
516 if (!objfile)
517 {
518 hpux_thread_active = 0;
11cf8741 519 goto quit;
c906108c
SS
520 }
521
522 ms = lookup_minimal_symbol ("cma__g_known_threads", NULL, objfile);
523
524 if (!ms)
11cf8741 525 goto quit;
c906108c
SS
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)
11cf8741 532 goto quit;
c906108c
SS
533
534 P_cma__g_current_thread = SYMBOL_VALUE_ADDRESS (ms);
535
536 hpux_thread_active = 1;
11cf8741
JM
537quit:
538 /* Call predecessor on chain, if any. */
539 if (target_new_objfile_chain)
540 target_new_objfile_chain (objfile);
c906108c
SS
541}
542
543/* Clean up after the inferior dies. */
544
545static void
fba45db2 546hpux_thread_mourn_inferior (void)
c906108c
SS
547{
548 child_ops.to_mourn_inferior ();
549}
550
551/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
552
553static int
fba45db2 554hpux_thread_can_run (void)
c906108c
SS
555{
556 return child_suppress_run;
557}
558
559static int
39f77062 560hpux_thread_alive (ptid_t ptid)
c906108c
SS
561{
562 return 1;
563}
564
565static void
fba45db2 566hpux_thread_stop (void)
c906108c
SS
567{
568 child_ops.to_stop ();
569}
570\f
571/* Convert a pid to printable form. */
572
573char *
39f77062 574hpux_pid_to_str (ptid_t ptid)
c906108c
SS
575{
576 static char buf[100];
39f77062 577 int pid = PIDGET (ptid);
c906108c
SS
578
579 sprintf (buf, "Thread %d", pid >> 16);
580
581 return buf;
582}
583\f
584static void
fba45db2 585init_hpux_thread_ops (void)
c906108c
SS
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;
b83266a0 612 hpux_thread_ops.to_thread_alive = hpux_thread_alive;
c906108c
SS
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
623void
fba45db2 624_initialize_hpux_thread (void)
c906108c
SS
625{
626 init_hpux_thread_ops ();
627 add_target (&hpux_thread_ops);
628
629 child_suppress_run = 1;
11cf8741
JM
630 /* Hook into new_objfile notification. */
631 target_new_objfile_chain = target_new_objfile_hook;
632 target_new_objfile_hook = hpux_thread_new_objfile;
c906108c 633}