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