xref: /openbsd-src/gnu/usr.bin/binutils/gdb/bsd-uthread.c (revision b47ceda895a31007022cccbba4bb060f5989b939)
1bb02a7f5Skettenis /* BSD user-level threads support.
2bb02a7f5Skettenis 
3bb02a7f5Skettenis    Copyright 2005 Free Software Foundation, Inc.
4bb02a7f5Skettenis 
5bb02a7f5Skettenis    This file is part of GDB.
6bb02a7f5Skettenis 
7bb02a7f5Skettenis    This program is free software; you can redistribute it and/or modify
8bb02a7f5Skettenis    it under the terms of the GNU General Public License as published by
9bb02a7f5Skettenis    the Free Software Foundation; either version 2 of the License, or
10bb02a7f5Skettenis    (at your option) any later version.
11bb02a7f5Skettenis 
12bb02a7f5Skettenis    This program is distributed in the hope that it will be useful,
13bb02a7f5Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
14bb02a7f5Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15bb02a7f5Skettenis    GNU General Public License for more details.
16bb02a7f5Skettenis 
17bb02a7f5Skettenis    You should have received a copy of the GNU General Public License
18bb02a7f5Skettenis    along with this program; if not, write to the Free Software
19bb02a7f5Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
20bb02a7f5Skettenis    Boston, MA 02111-1307, USA.  */
21bb02a7f5Skettenis 
22bb02a7f5Skettenis #include "defs.h"
23bb02a7f5Skettenis #include "gdbcore.h"
24bb02a7f5Skettenis #include "gdbthread.h"
25bb02a7f5Skettenis #include "inferior.h"
26bb02a7f5Skettenis #include "objfiles.h"
27bb02a7f5Skettenis #include "observer.h"
28bb02a7f5Skettenis #include "regcache.h"
29bb02a7f5Skettenis #include "solib.h"
30bb02a7f5Skettenis #include "solist.h"
31bb02a7f5Skettenis #include "symfile.h"
32bb02a7f5Skettenis #include "target.h"
33bb02a7f5Skettenis 
34bb02a7f5Skettenis #include "gdb_assert.h"
35bb02a7f5Skettenis #include "gdb_obstack.h"
36bb02a7f5Skettenis 
37bb02a7f5Skettenis #include "bsd-uthread.h"
38bb02a7f5Skettenis 
39bb02a7f5Skettenis /* HACK: Save the bsd_uthreads ops returned by bsd_uthread_target.  */
40bb02a7f5Skettenis static struct target_ops *bsd_uthread_ops_hack;
41bb02a7f5Skettenis 
42bb02a7f5Skettenis 
43bb02a7f5Skettenis /* Architecture-specific operations.  */
44bb02a7f5Skettenis 
45bb02a7f5Skettenis /* Per-architecture data key.  */
46bb02a7f5Skettenis static struct gdbarch_data *bsd_uthread_data;
47bb02a7f5Skettenis 
48bb02a7f5Skettenis struct bsd_uthread_ops
49bb02a7f5Skettenis {
50bb02a7f5Skettenis   /* Supply registers for an inactive thread to a register cache.  */
51d9e32885Skurt   void (*supply_uthread)(struct regcache *, int, CORE_ADDR, int);
52bb02a7f5Skettenis 
53bb02a7f5Skettenis   /* Collect registers for an inactive thread from a register cache.  */
54d9e32885Skurt   void (*collect_uthread)(const struct regcache *, int, CORE_ADDR, int);
55bb02a7f5Skettenis };
56bb02a7f5Skettenis 
57bb02a7f5Skettenis static void *
bsd_uthread_init(struct obstack * obstack)58bb02a7f5Skettenis bsd_uthread_init (struct obstack *obstack)
59bb02a7f5Skettenis {
60bb02a7f5Skettenis   struct bsd_uthread_ops *ops;
61bb02a7f5Skettenis 
62bb02a7f5Skettenis   ops = OBSTACK_ZALLOC (obstack, struct bsd_uthread_ops);
63bb02a7f5Skettenis   return ops;
64bb02a7f5Skettenis }
65bb02a7f5Skettenis 
66bb02a7f5Skettenis /* Set the function that supplies registers from an inactive thread
67bb02a7f5Skettenis    for architecture GDBARCH to SUPPLY_UTHREAD.  */
68bb02a7f5Skettenis 
69bb02a7f5Skettenis void
bsd_uthread_set_supply_uthread(struct gdbarch * gdbarch,void (* supply_uthread)(struct regcache *,int,CORE_ADDR,int))70bb02a7f5Skettenis bsd_uthread_set_supply_uthread (struct gdbarch *gdbarch,
71bb02a7f5Skettenis 				void (*supply_uthread) (struct regcache *,
72d9e32885Skurt 							int, CORE_ADDR, int))
73bb02a7f5Skettenis {
74bb02a7f5Skettenis   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
75bb02a7f5Skettenis   ops->supply_uthread = supply_uthread;
76bb02a7f5Skettenis }
77bb02a7f5Skettenis 
78bb02a7f5Skettenis /* Set the function that collects registers for an inactive thread for
79bb02a7f5Skettenis    architecture GDBARCH to SUPPLY_UTHREAD.  */
80bb02a7f5Skettenis 
81bb02a7f5Skettenis void
bsd_uthread_set_collect_uthread(struct gdbarch * gdbarch,void (* collect_uthread)(const struct regcache *,int,CORE_ADDR,int))82bb02a7f5Skettenis bsd_uthread_set_collect_uthread (struct gdbarch *gdbarch,
83bb02a7f5Skettenis 			 void (*collect_uthread) (const struct regcache *,
84d9e32885Skurt 						  int, CORE_ADDR, int))
85bb02a7f5Skettenis {
86bb02a7f5Skettenis   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
87bb02a7f5Skettenis   ops->collect_uthread = collect_uthread;
88bb02a7f5Skettenis }
89bb02a7f5Skettenis 
90bb02a7f5Skettenis /* Magic number to help recognize a valid thread structure.  */
91bb02a7f5Skettenis #define BSD_UTHREAD_PTHREAD_MAGIC	0xd09ba115
92bb02a7f5Skettenis 
93bb02a7f5Skettenis /* Check whether the thread structure at ADDR is valid.  */
94bb02a7f5Skettenis 
95bb02a7f5Skettenis static void
bsd_uthread_check_magic(CORE_ADDR addr)96bb02a7f5Skettenis bsd_uthread_check_magic (CORE_ADDR addr)
97bb02a7f5Skettenis {
98bb02a7f5Skettenis   ULONGEST magic = read_memory_unsigned_integer (addr, 4);
99bb02a7f5Skettenis 
100bb02a7f5Skettenis   if (magic != BSD_UTHREAD_PTHREAD_MAGIC)
101bb02a7f5Skettenis     error (_("Bad magic"));
102bb02a7f5Skettenis }
103bb02a7f5Skettenis 
104bb02a7f5Skettenis /* Thread states.  */
105bb02a7f5Skettenis #define BSD_UTHREAD_PS_RUNNING	0
106bb02a7f5Skettenis #define BSD_UTHREAD_PS_DEAD	18
107bb02a7f5Skettenis 
108bb02a7f5Skettenis /* Address of the pointer to the the thread structure for the running
109bb02a7f5Skettenis    thread.  */
110bb02a7f5Skettenis static CORE_ADDR bsd_uthread_thread_run_addr;
111bb02a7f5Skettenis 
112bb02a7f5Skettenis /* Address of the list of all threads.  */
113bb02a7f5Skettenis static CORE_ADDR bsd_uthread_thread_list_addr;
114bb02a7f5Skettenis 
115bb02a7f5Skettenis /* Offsets of various "interesting" bits in the thread structure.  */
116bb02a7f5Skettenis static int bsd_uthread_thread_state_offset = -1;
117bb02a7f5Skettenis static int bsd_uthread_thread_next_offset = -1;
118bb02a7f5Skettenis static int bsd_uthread_thread_ctx_offset;
119bb02a7f5Skettenis 
120bb02a7f5Skettenis /* Name of shared threads library.  */
121bb02a7f5Skettenis static const char *bsd_uthread_solib_name;
122bb02a7f5Skettenis 
123bb02a7f5Skettenis /* Non-zero if the thread startum implemented by this module is active.  */
124bb02a7f5Skettenis static int bsd_uthread_active;
125bb02a7f5Skettenis 
126bb02a7f5Skettenis static CORE_ADDR
bsd_uthread_lookup_address(const char * name,struct objfile * objfile)127bb02a7f5Skettenis bsd_uthread_lookup_address (const char *name, struct objfile *objfile)
128bb02a7f5Skettenis {
129bb02a7f5Skettenis   struct minimal_symbol *sym;
130bb02a7f5Skettenis 
131bb02a7f5Skettenis   sym = lookup_minimal_symbol (name, NULL, objfile);
132bb02a7f5Skettenis   if (sym)
133bb02a7f5Skettenis     return SYMBOL_VALUE_ADDRESS (sym);
134bb02a7f5Skettenis 
135bb02a7f5Skettenis   return 0;
136bb02a7f5Skettenis }
137bb02a7f5Skettenis 
138bb02a7f5Skettenis static int
bsd_uthread_lookup_offset(const char * name,struct objfile * objfile)139bb02a7f5Skettenis bsd_uthread_lookup_offset (const char *name, struct objfile *objfile)
140bb02a7f5Skettenis {
141bb02a7f5Skettenis   CORE_ADDR addr;
142bb02a7f5Skettenis 
143bb02a7f5Skettenis   addr = bsd_uthread_lookup_address (name, objfile);
144bb02a7f5Skettenis   if (addr == 0)
145bb02a7f5Skettenis     return 0;
146bb02a7f5Skettenis 
147bb02a7f5Skettenis   return read_memory_unsigned_integer (addr, 4);
148bb02a7f5Skettenis }
149bb02a7f5Skettenis 
150bb02a7f5Skettenis /* If OBJFILE contains the symbols corresponding to one of the
151bb02a7f5Skettenis    supported user-level threads libraries, activate the thread stratum
152bb02a7f5Skettenis    implemented by this module.  */
153bb02a7f5Skettenis 
154bb02a7f5Skettenis static int
bsd_uthread_activate(struct objfile * objfile)155bb02a7f5Skettenis bsd_uthread_activate (struct objfile *objfile)
156bb02a7f5Skettenis {
157bb02a7f5Skettenis   struct gdbarch *gdbarch = current_gdbarch;
158bb02a7f5Skettenis   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
159bb02a7f5Skettenis 
160bb02a7f5Skettenis   /* Skip if the thread stratum has already been activated.  */
161bb02a7f5Skettenis   if (bsd_uthread_active)
162bb02a7f5Skettenis     return 0;
163bb02a7f5Skettenis 
164bb02a7f5Skettenis   /* There's no point in enabling this module if no
165bb02a7f5Skettenis      architecture-specific operations are provided.  */
166bb02a7f5Skettenis   if (!ops->supply_uthread)
167bb02a7f5Skettenis     return 0;
168bb02a7f5Skettenis 
169bb02a7f5Skettenis   bsd_uthread_thread_run_addr =
170bb02a7f5Skettenis     bsd_uthread_lookup_address ("_thread_run", objfile);
171bb02a7f5Skettenis   if (bsd_uthread_thread_run_addr == 0)
172bb02a7f5Skettenis     return 0;
173bb02a7f5Skettenis 
174bb02a7f5Skettenis   bsd_uthread_thread_list_addr =
175bb02a7f5Skettenis     bsd_uthread_lookup_address ("_thread_list", objfile);
176bb02a7f5Skettenis   if (bsd_uthread_thread_list_addr == 0)
177bb02a7f5Skettenis     return 0;
178bb02a7f5Skettenis 
179bb02a7f5Skettenis   bsd_uthread_thread_state_offset =
180bb02a7f5Skettenis     bsd_uthread_lookup_offset ("_thread_state_offset", objfile);
181bb02a7f5Skettenis   if (bsd_uthread_thread_state_offset == 0)
182bb02a7f5Skettenis     return 0;
183bb02a7f5Skettenis 
184bb02a7f5Skettenis   bsd_uthread_thread_next_offset =
185bb02a7f5Skettenis     bsd_uthread_lookup_offset ("_thread_next_offset", objfile);
186bb02a7f5Skettenis   if (bsd_uthread_thread_next_offset == 0)
187bb02a7f5Skettenis     return 0;
188bb02a7f5Skettenis 
189bb02a7f5Skettenis   bsd_uthread_thread_ctx_offset =
190bb02a7f5Skettenis     bsd_uthread_lookup_offset ("_thread_ctx_offset", objfile);
191bb02a7f5Skettenis 
192bb02a7f5Skettenis   push_target (bsd_uthread_ops_hack);
193bb02a7f5Skettenis   bsd_uthread_active = 1;
194bb02a7f5Skettenis   return 1;
195bb02a7f5Skettenis }
196bb02a7f5Skettenis 
197bb02a7f5Skettenis /* Deactivate the thread stratum implemented by this module.  */
198bb02a7f5Skettenis 
199bb02a7f5Skettenis static void
bsd_uthread_deactivate(void)200bb02a7f5Skettenis bsd_uthread_deactivate (void)
201bb02a7f5Skettenis {
202bb02a7f5Skettenis   /* Skip if the thread stratum has already been deactivated.  */
203bb02a7f5Skettenis   if (!bsd_uthread_active)
204bb02a7f5Skettenis     return;
205bb02a7f5Skettenis 
206bb02a7f5Skettenis   bsd_uthread_active = 0;
207bb02a7f5Skettenis   unpush_target (bsd_uthread_ops_hack);
208bb02a7f5Skettenis 
209bb02a7f5Skettenis   bsd_uthread_thread_run_addr = 0;
210bb02a7f5Skettenis   bsd_uthread_thread_list_addr = 0;
211bb02a7f5Skettenis   bsd_uthread_thread_state_offset = 0;
212bb02a7f5Skettenis   bsd_uthread_thread_next_offset = 0;
213bb02a7f5Skettenis   bsd_uthread_thread_ctx_offset = 0;
214bb02a7f5Skettenis   bsd_uthread_solib_name = NULL;
215bb02a7f5Skettenis }
216bb02a7f5Skettenis 
217bb02a7f5Skettenis void
bsd_uthread_inferior_created(struct target_ops * ops,int from_tty)218bb02a7f5Skettenis bsd_uthread_inferior_created (struct target_ops *ops, int from_tty)
219bb02a7f5Skettenis {
220bb02a7f5Skettenis   bsd_uthread_activate (NULL);
221bb02a7f5Skettenis }
222bb02a7f5Skettenis 
223bb02a7f5Skettenis /* Likely candidates for the threads library.  */
224bb02a7f5Skettenis static const char *bsd_uthread_solib_names[] =
225bb02a7f5Skettenis {
226bb02a7f5Skettenis   "/usr/lib/libc_r.so",		/* FreeBSD */
227bb02a7f5Skettenis   "/usr/lib/libpthread.so",	/* OpenBSD */
228bb02a7f5Skettenis   NULL
229bb02a7f5Skettenis };
230bb02a7f5Skettenis 
231bb02a7f5Skettenis void
bsd_uthread_solib_loaded(struct so_list * so)232bb02a7f5Skettenis bsd_uthread_solib_loaded (struct so_list *so)
233bb02a7f5Skettenis {
234bb02a7f5Skettenis   const char **names = bsd_uthread_solib_names;
235bb02a7f5Skettenis 
236bb02a7f5Skettenis   for (names = bsd_uthread_solib_names; *names; names++)
237bb02a7f5Skettenis     {
238bb02a7f5Skettenis       if (strncmp (so->so_original_name, *names, strlen (*names)) == 0)
239bb02a7f5Skettenis 	{
240bb02a7f5Skettenis 	  solib_read_symbols (so, so->from_tty);
241bb02a7f5Skettenis 
242bb02a7f5Skettenis 	  if (bsd_uthread_activate (so->objfile))
243bb02a7f5Skettenis 	    {
244*b47ceda8Sjsg 	      bsd_uthread_solib_name = so->so_original_name;
245bb02a7f5Skettenis 	      return;
246bb02a7f5Skettenis 	    }
247bb02a7f5Skettenis 	}
248bb02a7f5Skettenis     }
249bb02a7f5Skettenis }
250bb02a7f5Skettenis 
251bb02a7f5Skettenis void
bsd_uthread_solib_unloaded(struct so_list * so)252bb02a7f5Skettenis bsd_uthread_solib_unloaded (struct so_list *so)
253bb02a7f5Skettenis {
254bb02a7f5Skettenis   if (!bsd_uthread_solib_name)
255bb02a7f5Skettenis     return;
256bb02a7f5Skettenis 
257bb02a7f5Skettenis   if (strcmp (so->so_original_name, bsd_uthread_solib_name) == 0)
258bb02a7f5Skettenis     bsd_uthread_deactivate ();
259bb02a7f5Skettenis }
260bb02a7f5Skettenis 
261bb02a7f5Skettenis static void
bsd_uthread_mourn_inferior(void)262bb02a7f5Skettenis bsd_uthread_mourn_inferior (void)
263bb02a7f5Skettenis {
264bb02a7f5Skettenis   find_target_beneath (bsd_uthread_ops_hack)->to_mourn_inferior ();
265bb02a7f5Skettenis   bsd_uthread_deactivate ();
266bb02a7f5Skettenis }
267bb02a7f5Skettenis 
268bb02a7f5Skettenis static void
bsd_uthread_fetch_registers(int regnum)269bb02a7f5Skettenis bsd_uthread_fetch_registers (int regnum)
270bb02a7f5Skettenis {
271bb02a7f5Skettenis   struct gdbarch *gdbarch = current_gdbarch;
272bb02a7f5Skettenis   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
273bb02a7f5Skettenis   CORE_ADDR addr = ptid_get_tid (inferior_ptid);
274bb02a7f5Skettenis   CORE_ADDR active_addr;
275bb02a7f5Skettenis 
276bb02a7f5Skettenis   /* Always fetch the appropriate registers from the layer beneath.  */
277bb02a7f5Skettenis   find_target_beneath (bsd_uthread_ops_hack)->to_fetch_registers (regnum);
278bb02a7f5Skettenis 
279bb02a7f5Skettenis   /* FIXME: That might have gotten us more than we asked for.  Make
280bb02a7f5Skettenis      sure we overwrite all relevant registers with values from the
281bb02a7f5Skettenis      thread structure.  This can go once we fix the underlying target.  */
282bb02a7f5Skettenis   regnum = -1;
283bb02a7f5Skettenis 
284bb02a7f5Skettenis   active_addr = read_memory_typed_address (bsd_uthread_thread_run_addr,
285bb02a7f5Skettenis 					   builtin_type_void_data_ptr);
286bb02a7f5Skettenis   if (addr != 0 && addr != active_addr)
287bb02a7f5Skettenis     {
288bb02a7f5Skettenis       bsd_uthread_check_magic (addr);
289bb02a7f5Skettenis       ops->supply_uthread (current_regcache, regnum,
290d9e32885Skurt 			   addr, bsd_uthread_thread_ctx_offset);
291bb02a7f5Skettenis     }
292bb02a7f5Skettenis }
293bb02a7f5Skettenis 
294bb02a7f5Skettenis static void
bsd_uthread_store_registers(int regnum)295bb02a7f5Skettenis bsd_uthread_store_registers (int regnum)
296bb02a7f5Skettenis {
297bb02a7f5Skettenis   struct gdbarch *gdbarch = current_gdbarch;
298bb02a7f5Skettenis   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
299bb02a7f5Skettenis   CORE_ADDR addr = ptid_get_tid (inferior_ptid);
300bb02a7f5Skettenis   CORE_ADDR active_addr;
301bb02a7f5Skettenis 
302bb02a7f5Skettenis   active_addr = read_memory_typed_address (bsd_uthread_thread_run_addr,
303bb02a7f5Skettenis 					   builtin_type_void_data_ptr);
304bb02a7f5Skettenis   if (addr != 0 && addr != active_addr)
305bb02a7f5Skettenis     {
306bb02a7f5Skettenis       bsd_uthread_check_magic (addr);
307bb02a7f5Skettenis       ops->collect_uthread (current_regcache, regnum,
308d9e32885Skurt 			    addr, bsd_uthread_thread_ctx_offset);
309bb02a7f5Skettenis     }
310bb02a7f5Skettenis   else
311bb02a7f5Skettenis     {
312bb02a7f5Skettenis       /* Updating the thread that is currently running; pass the
313bb02a7f5Skettenis          request to the layer beneath.  */
314bb02a7f5Skettenis       find_target_beneath (bsd_uthread_ops_hack)->to_store_registers (regnum);
315bb02a7f5Skettenis     }
316bb02a7f5Skettenis }
317bb02a7f5Skettenis 
318bb02a7f5Skettenis /* FIXME: This function is only there because otherwise GDB tries to
319bb02a7f5Skettenis    invoke deprecate_xfer_memory.  */
320bb02a7f5Skettenis 
321bb02a7f5Skettenis static LONGEST
bsd_uthread_xfer_partial(struct target_ops * ops,enum target_object object,const char * annex,void * readbuf,const void * writebuf,ULONGEST offset,LONGEST len)322bb02a7f5Skettenis bsd_uthread_xfer_partial (struct target_ops *ops, enum target_object object,
323bb02a7f5Skettenis 			  const char *annex, void *readbuf,
324bb02a7f5Skettenis 			  const void *writebuf,
325bb02a7f5Skettenis 			  ULONGEST offset, LONGEST len)
326bb02a7f5Skettenis {
327bb02a7f5Skettenis   gdb_assert (ops->beneath->to_xfer_partial);
328bb02a7f5Skettenis   return ops->beneath->to_xfer_partial (ops->beneath, object, annex, readbuf,
329bb02a7f5Skettenis 					writebuf, offset, len);
330bb02a7f5Skettenis }
331bb02a7f5Skettenis 
332bb02a7f5Skettenis static ptid_t
bsd_uthread_wait(ptid_t ptid,struct target_waitstatus * status)333bb02a7f5Skettenis bsd_uthread_wait (ptid_t ptid, struct target_waitstatus *status)
334bb02a7f5Skettenis {
335bb02a7f5Skettenis   CORE_ADDR addr;
336bb02a7f5Skettenis 
337bb02a7f5Skettenis   /* Pass the request to the layer beneath.  */
338bb02a7f5Skettenis   ptid = find_target_beneath (bsd_uthread_ops_hack)->to_wait (ptid, status);
339bb02a7f5Skettenis 
340bb02a7f5Skettenis   /* Fetch the corresponding thread ID, and augment the returned
341bb02a7f5Skettenis      process ID with it.  */
342bb02a7f5Skettenis   addr = read_memory_typed_address (bsd_uthread_thread_run_addr,
343bb02a7f5Skettenis 				    builtin_type_void_data_ptr);
344bb02a7f5Skettenis   if (addr != 0)
345bb02a7f5Skettenis     {
346bb02a7f5Skettenis       char buf[4];
347bb02a7f5Skettenis 
348bb02a7f5Skettenis       /* FIXME: For executables linked statically with the threads
349bb02a7f5Skettenis          library, we end up here before the program has actually been
350bb02a7f5Skettenis          executed.  In that case ADDR will be garbage since it has
351bb02a7f5Skettenis          been read from the wrong virtual memory image.  */
352bb02a7f5Skettenis       if (target_read_memory (addr, buf, 4) == 0)
353bb02a7f5Skettenis 	{
354bb02a7f5Skettenis 	  ULONGEST magic = extract_unsigned_integer (buf, 4);
355bb02a7f5Skettenis 	  if (magic == BSD_UTHREAD_PTHREAD_MAGIC)
356bb02a7f5Skettenis 	    ptid = ptid_build (ptid_get_pid (ptid), 0, addr);
357bb02a7f5Skettenis 	}
358bb02a7f5Skettenis     }
359bb02a7f5Skettenis 
360bb02a7f5Skettenis   /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
361bb02a7f5Skettenis      process isn't recognized as a new thread.  */
362bb02a7f5Skettenis   if (ptid_get_tid (ptid) != 0 && !in_thread_list (ptid)
363bb02a7f5Skettenis       && ptid_get_tid (inferior_ptid) == 0)
364bb02a7f5Skettenis     {
365bb02a7f5Skettenis       add_thread (ptid);
366bb02a7f5Skettenis       inferior_ptid = ptid;
367bb02a7f5Skettenis     }
368bb02a7f5Skettenis 
369bb02a7f5Skettenis   return ptid;
370bb02a7f5Skettenis }
371bb02a7f5Skettenis 
372bb02a7f5Skettenis static void
bsd_uthread_resume(ptid_t ptid,int step,enum target_signal sig)373bb02a7f5Skettenis bsd_uthread_resume (ptid_t ptid, int step, enum target_signal sig)
374bb02a7f5Skettenis {
375bb02a7f5Skettenis   /* Pass the request to the layer beneath.  */
376bb02a7f5Skettenis   find_target_beneath (bsd_uthread_ops_hack)->to_resume (ptid, step, sig);
377bb02a7f5Skettenis }
378bb02a7f5Skettenis 
379bb02a7f5Skettenis static int
bsd_uthread_thread_alive(ptid_t ptid)380bb02a7f5Skettenis bsd_uthread_thread_alive (ptid_t ptid)
381bb02a7f5Skettenis {
382bb02a7f5Skettenis   CORE_ADDR addr = ptid_get_tid (inferior_ptid);
383bb02a7f5Skettenis 
384bb02a7f5Skettenis   if (addr != 0)
385bb02a7f5Skettenis     {
386bb02a7f5Skettenis       int offset = bsd_uthread_thread_state_offset;
387bb02a7f5Skettenis       ULONGEST state;
388bb02a7f5Skettenis 
389bb02a7f5Skettenis       bsd_uthread_check_magic (addr);
390bb02a7f5Skettenis 
391bb02a7f5Skettenis       state = read_memory_unsigned_integer (addr + offset, 4);
392bb02a7f5Skettenis       if (state == BSD_UTHREAD_PS_DEAD)
393bb02a7f5Skettenis 	return 0;
394bb02a7f5Skettenis     }
395bb02a7f5Skettenis 
396bb02a7f5Skettenis   return find_target_beneath (bsd_uthread_ops_hack)->to_thread_alive (ptid);
397bb02a7f5Skettenis }
398bb02a7f5Skettenis 
399bb02a7f5Skettenis static void
bsd_uthread_find_new_threads(void)400bb02a7f5Skettenis bsd_uthread_find_new_threads (void)
401bb02a7f5Skettenis {
402bb02a7f5Skettenis   pid_t pid = ptid_get_pid (inferior_ptid);
403bb02a7f5Skettenis   int offset = bsd_uthread_thread_next_offset;
404bb02a7f5Skettenis   CORE_ADDR addr;
405bb02a7f5Skettenis 
406bb02a7f5Skettenis   addr = read_memory_typed_address (bsd_uthread_thread_list_addr,
407bb02a7f5Skettenis 				    builtin_type_void_data_ptr);
408bb02a7f5Skettenis   while (addr != 0)
409bb02a7f5Skettenis     {
410bb02a7f5Skettenis       ptid_t ptid = ptid_build (pid, 0, addr);
411bb02a7f5Skettenis 
412bb02a7f5Skettenis       if (!in_thread_list (ptid))
413bb02a7f5Skettenis 	add_thread (ptid);
414bb02a7f5Skettenis 
415bb02a7f5Skettenis       addr = read_memory_typed_address (addr + offset,
416bb02a7f5Skettenis 					builtin_type_void_data_ptr);
417bb02a7f5Skettenis     }
418bb02a7f5Skettenis }
419bb02a7f5Skettenis 
420bb02a7f5Skettenis /* Possible states a thread can be in.  */
421bb02a7f5Skettenis static char *bsd_uthread_state[] =
422bb02a7f5Skettenis {
423bb02a7f5Skettenis   "RUNNING",
424bb02a7f5Skettenis   "SIGTHREAD",
425bb02a7f5Skettenis   "MUTEX_WAIT",
426bb02a7f5Skettenis   "COND_WAIT",
427bb02a7f5Skettenis   "FDLR_WAIT",
428bb02a7f5Skettenis   "FDLW_WAIT",
429bb02a7f5Skettenis   "FDR_WAIT",
430bb02a7f5Skettenis   "FDW_WAIT",
431bb02a7f5Skettenis   "FILE_WAIT",
432bb02a7f5Skettenis   "POLL_WAIT",
433bb02a7f5Skettenis   "SELECT_WAIT",
434bb02a7f5Skettenis   "SLEEP_WAIT",
435bb02a7f5Skettenis   "WAIT_WAIT",
436bb02a7f5Skettenis   "SIGSUSPEND",
437bb02a7f5Skettenis   "SIGWAIT",
438bb02a7f5Skettenis   "SPINBLOCK",
439bb02a7f5Skettenis   "JOIN",
440bb02a7f5Skettenis   "SUSPENDED",
441bb02a7f5Skettenis   "DEAD",
442bb02a7f5Skettenis   "DEADLOCK"
443bb02a7f5Skettenis };
444bb02a7f5Skettenis 
445bb02a7f5Skettenis /* Return a string describing th state of the thread specified by
446bb02a7f5Skettenis    INFO.  */
447bb02a7f5Skettenis 
448bb02a7f5Skettenis static char *
bsd_uthread_extra_thread_info(struct thread_info * info)449bb02a7f5Skettenis bsd_uthread_extra_thread_info (struct thread_info *info)
450bb02a7f5Skettenis {
451bb02a7f5Skettenis   CORE_ADDR addr = ptid_get_tid (info->ptid);
452bb02a7f5Skettenis 
453bb02a7f5Skettenis   if (addr != 0)
454bb02a7f5Skettenis     {
455bb02a7f5Skettenis       int offset = bsd_uthread_thread_state_offset;
456bb02a7f5Skettenis       ULONGEST state;
457bb02a7f5Skettenis 
458bb02a7f5Skettenis       state = read_memory_unsigned_integer (addr + offset, 4);
459bb02a7f5Skettenis       if (state < ARRAY_SIZE (bsd_uthread_state))
460bb02a7f5Skettenis 	return bsd_uthread_state[state];
461bb02a7f5Skettenis     }
462bb02a7f5Skettenis 
463bb02a7f5Skettenis   return NULL;
464bb02a7f5Skettenis }
465bb02a7f5Skettenis 
466bb02a7f5Skettenis static char *
bsd_uthread_pid_to_str(ptid_t ptid)467bb02a7f5Skettenis bsd_uthread_pid_to_str (ptid_t ptid)
468bb02a7f5Skettenis {
469bb02a7f5Skettenis   if (ptid_get_tid (ptid) != 0)
470bb02a7f5Skettenis     {
471bb02a7f5Skettenis       static char buf[64];
472bb02a7f5Skettenis 
473bb02a7f5Skettenis       xsnprintf (buf, sizeof buf, "process %d, thread 0x%lx",
474bb02a7f5Skettenis 		 ptid_get_pid (ptid), ptid_get_tid (ptid));
475bb02a7f5Skettenis       return buf;
476bb02a7f5Skettenis     }
477bb02a7f5Skettenis 
478bb02a7f5Skettenis   return normal_pid_to_str (ptid);
479bb02a7f5Skettenis }
480bb02a7f5Skettenis 
481bb02a7f5Skettenis struct target_ops *
bsd_uthread_target(void)482bb02a7f5Skettenis bsd_uthread_target (void)
483bb02a7f5Skettenis {
484bb02a7f5Skettenis   struct target_ops *t = XZALLOC (struct target_ops);
485bb02a7f5Skettenis 
486bb02a7f5Skettenis   t->to_shortname = "bsd-uthreads";
487bb02a7f5Skettenis   t->to_longname = "BSD user-level threads";
488bb02a7f5Skettenis   t->to_doc = "BSD user-level threads";
489bb02a7f5Skettenis   t->to_mourn_inferior = bsd_uthread_mourn_inferior;
490bb02a7f5Skettenis   t->to_fetch_registers = bsd_uthread_fetch_registers;
491bb02a7f5Skettenis   t->to_store_registers = bsd_uthread_store_registers;
492bb02a7f5Skettenis   t->to_xfer_partial = bsd_uthread_xfer_partial;
493bb02a7f5Skettenis   t->to_wait = bsd_uthread_wait;
494bb02a7f5Skettenis   t->to_resume = bsd_uthread_resume;
495bb02a7f5Skettenis   t->to_thread_alive = bsd_uthread_thread_alive;
496bb02a7f5Skettenis   t->to_find_new_threads = bsd_uthread_find_new_threads;
497bb02a7f5Skettenis   t->to_extra_thread_info = bsd_uthread_extra_thread_info;
498bb02a7f5Skettenis   t->to_pid_to_str = bsd_uthread_pid_to_str;
499bb02a7f5Skettenis   t->to_stratum = thread_stratum;
500bb02a7f5Skettenis   t->to_magic = OPS_MAGIC;
501bb02a7f5Skettenis   bsd_uthread_ops_hack = t;
502bb02a7f5Skettenis 
503bb02a7f5Skettenis   return t;
504bb02a7f5Skettenis }
505bb02a7f5Skettenis 
506bb02a7f5Skettenis void
_initialize_bsd_uthread(void)507bb02a7f5Skettenis _initialize_bsd_uthread (void)
508bb02a7f5Skettenis {
509bb02a7f5Skettenis   add_target (bsd_uthread_target ());
510bb02a7f5Skettenis 
511bb02a7f5Skettenis   bsd_uthread_data = gdbarch_data_register_pre_init (bsd_uthread_init);
512bb02a7f5Skettenis 
513bb02a7f5Skettenis   observer_attach_inferior_created (bsd_uthread_inferior_created);
514bb02a7f5Skettenis   observer_attach_solib_loaded (bsd_uthread_solib_loaded);
515bb02a7f5Skettenis   observer_attach_solib_unloaded (bsd_uthread_solib_unloaded);
516bb02a7f5Skettenis }
517