xref: /openbsd-src/gnu/usr.bin/binutils/gdb/hpux-thread.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
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