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