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