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