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