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