xref: /dflybsd-src/contrib/gdb-7/gdb/bsd-uthread.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* BSD user-level threads support.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2005-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "gdbcore.h"
225796c8dcSSimon Schubert #include "gdbthread.h"
235796c8dcSSimon Schubert #include "inferior.h"
245796c8dcSSimon Schubert #include "objfiles.h"
255796c8dcSSimon Schubert #include "observer.h"
265796c8dcSSimon Schubert #include "regcache.h"
275796c8dcSSimon Schubert #include "solib.h"
285796c8dcSSimon Schubert #include "solist.h"
295796c8dcSSimon Schubert #include "symfile.h"
305796c8dcSSimon Schubert #include "target.h"
315796c8dcSSimon Schubert 
325796c8dcSSimon Schubert #include "gdb_assert.h"
335796c8dcSSimon Schubert #include "gdb_obstack.h"
345796c8dcSSimon Schubert 
355796c8dcSSimon Schubert #include "bsd-uthread.h"
365796c8dcSSimon Schubert 
375796c8dcSSimon Schubert /* HACK: Save the bsd_uthreads ops returned by bsd_uthread_target.  */
385796c8dcSSimon Schubert static struct target_ops *bsd_uthread_ops_hack;
395796c8dcSSimon Schubert 
405796c8dcSSimon Schubert 
415796c8dcSSimon Schubert /* Architecture-specific operations.  */
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert /* Per-architecture data key.  */
445796c8dcSSimon Schubert static struct gdbarch_data *bsd_uthread_data;
455796c8dcSSimon Schubert 
465796c8dcSSimon Schubert struct bsd_uthread_ops
475796c8dcSSimon Schubert {
485796c8dcSSimon Schubert   /* Supply registers for an inactive thread to a register cache.  */
495796c8dcSSimon Schubert   void (*supply_uthread)(struct regcache *, int, CORE_ADDR);
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert   /* Collect registers for an inactive thread from a register cache.  */
525796c8dcSSimon Schubert   void (*collect_uthread)(const struct regcache *, int, CORE_ADDR);
535796c8dcSSimon Schubert };
545796c8dcSSimon Schubert 
555796c8dcSSimon Schubert static void *
bsd_uthread_init(struct obstack * obstack)565796c8dcSSimon Schubert bsd_uthread_init (struct obstack *obstack)
575796c8dcSSimon Schubert {
585796c8dcSSimon Schubert   struct bsd_uthread_ops *ops;
595796c8dcSSimon Schubert 
605796c8dcSSimon Schubert   ops = OBSTACK_ZALLOC (obstack, struct bsd_uthread_ops);
615796c8dcSSimon Schubert   return ops;
625796c8dcSSimon Schubert }
635796c8dcSSimon Schubert 
645796c8dcSSimon Schubert /* Set the function that supplies registers from an inactive thread
655796c8dcSSimon Schubert    for architecture GDBARCH to SUPPLY_UTHREAD.  */
665796c8dcSSimon Schubert 
675796c8dcSSimon Schubert void
bsd_uthread_set_supply_uthread(struct gdbarch * gdbarch,void (* supply_uthread)(struct regcache *,int,CORE_ADDR))685796c8dcSSimon Schubert bsd_uthread_set_supply_uthread (struct gdbarch *gdbarch,
695796c8dcSSimon Schubert 				void (*supply_uthread) (struct regcache *,
705796c8dcSSimon Schubert 							int, CORE_ADDR))
715796c8dcSSimon Schubert {
725796c8dcSSimon Schubert   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
735796c8dcSSimon Schubert   ops->supply_uthread = supply_uthread;
745796c8dcSSimon Schubert }
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert /* Set the function that collects registers for an inactive thread for
775796c8dcSSimon Schubert    architecture GDBARCH to SUPPLY_UTHREAD.  */
785796c8dcSSimon Schubert 
795796c8dcSSimon Schubert void
bsd_uthread_set_collect_uthread(struct gdbarch * gdbarch,void (* collect_uthread)(const struct regcache *,int,CORE_ADDR))805796c8dcSSimon Schubert bsd_uthread_set_collect_uthread (struct gdbarch *gdbarch,
815796c8dcSSimon Schubert 			 void (*collect_uthread) (const struct regcache *,
825796c8dcSSimon Schubert 						  int, CORE_ADDR))
835796c8dcSSimon Schubert {
845796c8dcSSimon Schubert   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
855796c8dcSSimon Schubert   ops->collect_uthread = collect_uthread;
865796c8dcSSimon Schubert }
875796c8dcSSimon Schubert 
885796c8dcSSimon Schubert /* Magic number to help recognize a valid thread structure.  */
895796c8dcSSimon Schubert #define BSD_UTHREAD_PTHREAD_MAGIC	0xd09ba115
905796c8dcSSimon Schubert 
915796c8dcSSimon Schubert /* Check whether the thread structure at ADDR is valid.  */
925796c8dcSSimon Schubert 
935796c8dcSSimon Schubert static void
bsd_uthread_check_magic(CORE_ADDR addr)945796c8dcSSimon Schubert bsd_uthread_check_magic (CORE_ADDR addr)
955796c8dcSSimon Schubert {
96*ef5ccd6cSJohn Marino   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
975796c8dcSSimon Schubert   ULONGEST magic = read_memory_unsigned_integer (addr, 4, byte_order);
985796c8dcSSimon Schubert 
995796c8dcSSimon Schubert   if (magic != BSD_UTHREAD_PTHREAD_MAGIC)
1005796c8dcSSimon Schubert     error (_("Bad magic"));
1015796c8dcSSimon Schubert }
1025796c8dcSSimon Schubert 
1035796c8dcSSimon Schubert /* Thread states.  */
1045796c8dcSSimon Schubert #define BSD_UTHREAD_PS_RUNNING	0
1055796c8dcSSimon Schubert #define BSD_UTHREAD_PS_DEAD	18
1065796c8dcSSimon Schubert 
107c50c785cSJohn Marino /* Address of the pointer to the thread structure for the running
1085796c8dcSSimon Schubert    thread.  */
1095796c8dcSSimon Schubert static CORE_ADDR bsd_uthread_thread_run_addr;
1105796c8dcSSimon Schubert 
1115796c8dcSSimon Schubert /* Address of the list of all threads.  */
1125796c8dcSSimon Schubert static CORE_ADDR bsd_uthread_thread_list_addr;
1135796c8dcSSimon Schubert 
1145796c8dcSSimon Schubert /* Offsets of various "interesting" bits in the thread structure.  */
1155796c8dcSSimon Schubert static int bsd_uthread_thread_state_offset = -1;
1165796c8dcSSimon Schubert static int bsd_uthread_thread_next_offset = -1;
1175796c8dcSSimon Schubert static int bsd_uthread_thread_ctx_offset;
1185796c8dcSSimon Schubert 
1195796c8dcSSimon Schubert /* Name of shared threads library.  */
1205796c8dcSSimon Schubert static const char *bsd_uthread_solib_name;
1215796c8dcSSimon Schubert 
1225796c8dcSSimon Schubert /* Non-zero if the thread startum implemented by this module is active.  */
1235796c8dcSSimon Schubert static int bsd_uthread_active;
1245796c8dcSSimon Schubert 
1255796c8dcSSimon Schubert static CORE_ADDR
bsd_uthread_lookup_address(const char * name,struct objfile * objfile)1265796c8dcSSimon Schubert bsd_uthread_lookup_address (const char *name, struct objfile *objfile)
1275796c8dcSSimon Schubert {
1285796c8dcSSimon Schubert   struct minimal_symbol *sym;
1295796c8dcSSimon Schubert 
1305796c8dcSSimon Schubert   sym = lookup_minimal_symbol (name, NULL, objfile);
1315796c8dcSSimon Schubert   if (sym)
1325796c8dcSSimon Schubert     return SYMBOL_VALUE_ADDRESS (sym);
1335796c8dcSSimon Schubert 
1345796c8dcSSimon Schubert   return 0;
1355796c8dcSSimon Schubert }
1365796c8dcSSimon Schubert 
1375796c8dcSSimon Schubert static int
bsd_uthread_lookup_offset(const char * name,struct objfile * objfile)1385796c8dcSSimon Schubert bsd_uthread_lookup_offset (const char *name, struct objfile *objfile)
1395796c8dcSSimon Schubert {
140*ef5ccd6cSJohn Marino   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
1415796c8dcSSimon Schubert   CORE_ADDR addr;
1425796c8dcSSimon Schubert 
1435796c8dcSSimon Schubert   addr = bsd_uthread_lookup_address (name, objfile);
1445796c8dcSSimon Schubert   if (addr == 0)
1455796c8dcSSimon Schubert     return 0;
1465796c8dcSSimon Schubert 
1475796c8dcSSimon Schubert   return read_memory_unsigned_integer (addr, 4, byte_order);
1485796c8dcSSimon Schubert }
1495796c8dcSSimon Schubert 
1505796c8dcSSimon Schubert static CORE_ADDR
bsd_uthread_read_memory_address(CORE_ADDR addr)1515796c8dcSSimon Schubert bsd_uthread_read_memory_address (CORE_ADDR addr)
1525796c8dcSSimon Schubert {
153*ef5ccd6cSJohn Marino   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
1545796c8dcSSimon Schubert   return read_memory_typed_address (addr, ptr_type);
1555796c8dcSSimon Schubert }
1565796c8dcSSimon Schubert 
1575796c8dcSSimon Schubert /* If OBJFILE contains the symbols corresponding to one of the
1585796c8dcSSimon Schubert    supported user-level threads libraries, activate the thread stratum
1595796c8dcSSimon Schubert    implemented by this module.  */
1605796c8dcSSimon Schubert 
1615796c8dcSSimon Schubert static int
bsd_uthread_activate(struct objfile * objfile)1625796c8dcSSimon Schubert bsd_uthread_activate (struct objfile *objfile)
1635796c8dcSSimon Schubert {
164*ef5ccd6cSJohn Marino   struct gdbarch *gdbarch = target_gdbarch ();
1655796c8dcSSimon Schubert   struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
1665796c8dcSSimon Schubert 
1675796c8dcSSimon Schubert   /* Skip if the thread stratum has already been activated.  */
1685796c8dcSSimon Schubert   if (bsd_uthread_active)
1695796c8dcSSimon Schubert     return 0;
1705796c8dcSSimon Schubert 
1715796c8dcSSimon Schubert   /* There's no point in enabling this module if no
1725796c8dcSSimon Schubert      architecture-specific operations are provided.  */
1735796c8dcSSimon Schubert   if (!ops->supply_uthread)
1745796c8dcSSimon Schubert     return 0;
1755796c8dcSSimon Schubert 
1765796c8dcSSimon Schubert   bsd_uthread_thread_run_addr =
1775796c8dcSSimon Schubert     bsd_uthread_lookup_address ("_thread_run", objfile);
1785796c8dcSSimon Schubert   if (bsd_uthread_thread_run_addr == 0)
1795796c8dcSSimon Schubert     return 0;
1805796c8dcSSimon Schubert 
1815796c8dcSSimon Schubert   bsd_uthread_thread_list_addr =
1825796c8dcSSimon Schubert     bsd_uthread_lookup_address ("_thread_list", objfile);
1835796c8dcSSimon Schubert   if (bsd_uthread_thread_list_addr == 0)
1845796c8dcSSimon Schubert     return 0;
1855796c8dcSSimon Schubert 
1865796c8dcSSimon Schubert   bsd_uthread_thread_state_offset =
1875796c8dcSSimon Schubert     bsd_uthread_lookup_offset ("_thread_state_offset", objfile);
1885796c8dcSSimon Schubert   if (bsd_uthread_thread_state_offset == 0)
1895796c8dcSSimon Schubert     return 0;
1905796c8dcSSimon Schubert 
1915796c8dcSSimon Schubert   bsd_uthread_thread_next_offset =
1925796c8dcSSimon Schubert     bsd_uthread_lookup_offset ("_thread_next_offset", objfile);
1935796c8dcSSimon Schubert   if (bsd_uthread_thread_next_offset == 0)
1945796c8dcSSimon Schubert     return 0;
1955796c8dcSSimon Schubert 
1965796c8dcSSimon Schubert   bsd_uthread_thread_ctx_offset =
1975796c8dcSSimon Schubert     bsd_uthread_lookup_offset ("_thread_ctx_offset", objfile);
1985796c8dcSSimon Schubert 
1995796c8dcSSimon Schubert   push_target (bsd_uthread_ops_hack);
2005796c8dcSSimon Schubert   bsd_uthread_active = 1;
2015796c8dcSSimon Schubert   return 1;
2025796c8dcSSimon Schubert }
2035796c8dcSSimon Schubert 
2045796c8dcSSimon Schubert /* Cleanup due to deactivation.  */
2055796c8dcSSimon Schubert 
2065796c8dcSSimon Schubert static void
bsd_uthread_close(int quitting)2075796c8dcSSimon Schubert bsd_uthread_close (int quitting)
2085796c8dcSSimon Schubert {
2095796c8dcSSimon Schubert   bsd_uthread_active = 0;
2105796c8dcSSimon Schubert   bsd_uthread_thread_run_addr = 0;
2115796c8dcSSimon Schubert   bsd_uthread_thread_list_addr = 0;
2125796c8dcSSimon Schubert   bsd_uthread_thread_state_offset = 0;
2135796c8dcSSimon Schubert   bsd_uthread_thread_next_offset = 0;
2145796c8dcSSimon Schubert   bsd_uthread_thread_ctx_offset = 0;
2155796c8dcSSimon Schubert   bsd_uthread_solib_name = NULL;
2165796c8dcSSimon Schubert }
2175796c8dcSSimon Schubert 
2185796c8dcSSimon Schubert /* Deactivate the thread stratum implemented by this module.  */
2195796c8dcSSimon Schubert 
2205796c8dcSSimon Schubert static void
bsd_uthread_deactivate(void)2215796c8dcSSimon Schubert bsd_uthread_deactivate (void)
2225796c8dcSSimon Schubert {
2235796c8dcSSimon Schubert   /* Skip if the thread stratum has already been deactivated.  */
2245796c8dcSSimon Schubert   if (!bsd_uthread_active)
2255796c8dcSSimon Schubert     return;
2265796c8dcSSimon Schubert 
2275796c8dcSSimon Schubert   unpush_target (bsd_uthread_ops_hack);
2285796c8dcSSimon Schubert }
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert static void
bsd_uthread_inferior_created(struct target_ops * ops,int from_tty)2315796c8dcSSimon Schubert bsd_uthread_inferior_created (struct target_ops *ops, int from_tty)
2325796c8dcSSimon Schubert {
2335796c8dcSSimon Schubert   bsd_uthread_activate (NULL);
2345796c8dcSSimon Schubert }
2355796c8dcSSimon Schubert 
2365796c8dcSSimon Schubert /* Likely candidates for the threads library.  */
2375796c8dcSSimon Schubert static const char *bsd_uthread_solib_names[] =
2385796c8dcSSimon Schubert {
2395796c8dcSSimon Schubert   "/usr/lib/libc_r.so",		/* FreeBSD */
2405796c8dcSSimon Schubert   "/usr/lib/libpthread.so",	/* OpenBSD */
2415796c8dcSSimon Schubert   NULL
2425796c8dcSSimon Schubert };
2435796c8dcSSimon Schubert 
2445796c8dcSSimon Schubert static void
bsd_uthread_solib_loaded(struct so_list * so)2455796c8dcSSimon Schubert bsd_uthread_solib_loaded (struct so_list *so)
2465796c8dcSSimon Schubert {
2475796c8dcSSimon Schubert   const char **names = bsd_uthread_solib_names;
2485796c8dcSSimon Schubert 
2495796c8dcSSimon Schubert   for (names = bsd_uthread_solib_names; *names; names++)
2505796c8dcSSimon Schubert     {
2515796c8dcSSimon Schubert       if (strncmp (so->so_original_name, *names, strlen (*names)) == 0)
2525796c8dcSSimon Schubert 	{
253cf7f2e2dSJohn Marino 	  solib_read_symbols (so, 0);
2545796c8dcSSimon Schubert 
2555796c8dcSSimon Schubert 	  if (bsd_uthread_activate (so->objfile))
2565796c8dcSSimon Schubert 	    {
2575796c8dcSSimon Schubert 	      bsd_uthread_solib_name = so->so_original_name;
2585796c8dcSSimon Schubert 	      return;
2595796c8dcSSimon Schubert 	    }
2605796c8dcSSimon Schubert 	}
2615796c8dcSSimon Schubert     }
2625796c8dcSSimon Schubert }
2635796c8dcSSimon Schubert 
2645796c8dcSSimon Schubert static void
bsd_uthread_solib_unloaded(struct so_list * so)2655796c8dcSSimon Schubert bsd_uthread_solib_unloaded (struct so_list *so)
2665796c8dcSSimon Schubert {
2675796c8dcSSimon Schubert   if (!bsd_uthread_solib_name)
2685796c8dcSSimon Schubert     return;
2695796c8dcSSimon Schubert 
2705796c8dcSSimon Schubert   if (strcmp (so->so_original_name, bsd_uthread_solib_name) == 0)
2715796c8dcSSimon Schubert     bsd_uthread_deactivate ();
2725796c8dcSSimon Schubert }
2735796c8dcSSimon Schubert 
2745796c8dcSSimon Schubert static void
bsd_uthread_mourn_inferior(struct target_ops * ops)2755796c8dcSSimon Schubert bsd_uthread_mourn_inferior (struct target_ops *ops)
2765796c8dcSSimon Schubert {
2775796c8dcSSimon Schubert   struct target_ops *beneath = find_target_beneath (ops);
2785796c8dcSSimon Schubert   beneath->to_mourn_inferior (beneath);
2795796c8dcSSimon Schubert   bsd_uthread_deactivate ();
2805796c8dcSSimon Schubert }
2815796c8dcSSimon Schubert 
2825796c8dcSSimon Schubert static void
bsd_uthread_fetch_registers(struct target_ops * ops,struct regcache * regcache,int regnum)2835796c8dcSSimon Schubert bsd_uthread_fetch_registers (struct target_ops *ops,
2845796c8dcSSimon Schubert 			     struct regcache *regcache, int regnum)
2855796c8dcSSimon Schubert {
2865796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_regcache_arch (regcache);
2875796c8dcSSimon Schubert   struct bsd_uthread_ops *uthread_ops = gdbarch_data (gdbarch, bsd_uthread_data);
2885796c8dcSSimon Schubert   CORE_ADDR addr = ptid_get_tid (inferior_ptid);
2895796c8dcSSimon Schubert   struct target_ops *beneath = find_target_beneath (ops);
2905796c8dcSSimon Schubert   CORE_ADDR active_addr;
2915796c8dcSSimon Schubert 
2925796c8dcSSimon Schubert   /* Always fetch the appropriate registers from the layer beneath.  */
2935796c8dcSSimon Schubert   beneath->to_fetch_registers (beneath, regcache, regnum);
2945796c8dcSSimon Schubert 
2955796c8dcSSimon Schubert   /* FIXME: That might have gotten us more than we asked for.  Make
2965796c8dcSSimon Schubert      sure we overwrite all relevant registers with values from the
2975796c8dcSSimon Schubert      thread structure.  This can go once we fix the underlying target.  */
2985796c8dcSSimon Schubert   regnum = -1;
2995796c8dcSSimon Schubert 
3005796c8dcSSimon Schubert   active_addr = bsd_uthread_read_memory_address (bsd_uthread_thread_run_addr);
3015796c8dcSSimon Schubert   if (addr != 0 && addr != active_addr)
3025796c8dcSSimon Schubert     {
3035796c8dcSSimon Schubert       bsd_uthread_check_magic (addr);
3045796c8dcSSimon Schubert       uthread_ops->supply_uthread (regcache, regnum,
3055796c8dcSSimon Schubert 				   addr + bsd_uthread_thread_ctx_offset);
3065796c8dcSSimon Schubert     }
3075796c8dcSSimon Schubert }
3085796c8dcSSimon Schubert 
3095796c8dcSSimon Schubert static void
bsd_uthread_store_registers(struct target_ops * ops,struct regcache * regcache,int regnum)3105796c8dcSSimon Schubert bsd_uthread_store_registers (struct target_ops *ops,
3115796c8dcSSimon Schubert 			     struct regcache *regcache, int regnum)
3125796c8dcSSimon Schubert {
3135796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_regcache_arch (regcache);
3145796c8dcSSimon Schubert   struct bsd_uthread_ops *uthread_ops = gdbarch_data (gdbarch, bsd_uthread_data);
3155796c8dcSSimon Schubert   struct target_ops *beneath = find_target_beneath (ops);
3165796c8dcSSimon Schubert   CORE_ADDR addr = ptid_get_tid (inferior_ptid);
3175796c8dcSSimon Schubert   CORE_ADDR active_addr;
3185796c8dcSSimon Schubert 
3195796c8dcSSimon Schubert   active_addr = bsd_uthread_read_memory_address (bsd_uthread_thread_run_addr);
3205796c8dcSSimon Schubert   if (addr != 0 && addr != active_addr)
3215796c8dcSSimon Schubert     {
3225796c8dcSSimon Schubert       bsd_uthread_check_magic (addr);
3235796c8dcSSimon Schubert       uthread_ops->collect_uthread (regcache, regnum,
3245796c8dcSSimon Schubert 				    addr + bsd_uthread_thread_ctx_offset);
3255796c8dcSSimon Schubert     }
3265796c8dcSSimon Schubert   else
3275796c8dcSSimon Schubert     {
3285796c8dcSSimon Schubert       /* Updating the thread that is currently running; pass the
3295796c8dcSSimon Schubert          request to the layer beneath.  */
3305796c8dcSSimon Schubert       beneath->to_store_registers (beneath, regcache, regnum);
3315796c8dcSSimon Schubert     }
3325796c8dcSSimon Schubert }
3335796c8dcSSimon Schubert 
3345796c8dcSSimon Schubert /* FIXME: This function is only there because otherwise GDB tries to
3355796c8dcSSimon Schubert    invoke deprecate_xfer_memory.  */
3365796c8dcSSimon Schubert 
3375796c8dcSSimon Schubert static LONGEST
bsd_uthread_xfer_partial(struct target_ops * ops,enum target_object object,const char * annex,gdb_byte * readbuf,const gdb_byte * writebuf,ULONGEST offset,LONGEST len)3385796c8dcSSimon Schubert bsd_uthread_xfer_partial (struct target_ops *ops, enum target_object object,
3395796c8dcSSimon Schubert 			  const char *annex, gdb_byte *readbuf,
3405796c8dcSSimon Schubert 			  const gdb_byte *writebuf,
3415796c8dcSSimon Schubert 			  ULONGEST offset, LONGEST len)
3425796c8dcSSimon Schubert {
3435796c8dcSSimon Schubert   gdb_assert (ops->beneath->to_xfer_partial);
3445796c8dcSSimon Schubert   return ops->beneath->to_xfer_partial (ops->beneath, object, annex, readbuf,
3455796c8dcSSimon Schubert 					writebuf, offset, len);
3465796c8dcSSimon Schubert }
3475796c8dcSSimon Schubert 
3485796c8dcSSimon Schubert static ptid_t
bsd_uthread_wait(struct target_ops * ops,ptid_t ptid,struct target_waitstatus * status,int options)3495796c8dcSSimon Schubert bsd_uthread_wait (struct target_ops *ops,
3505796c8dcSSimon Schubert 		  ptid_t ptid, struct target_waitstatus *status, int options)
3515796c8dcSSimon Schubert {
352*ef5ccd6cSJohn Marino   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
3535796c8dcSSimon Schubert   CORE_ADDR addr;
3545796c8dcSSimon Schubert   struct target_ops *beneath = find_target_beneath (ops);
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert   /* Pass the request to the layer beneath.  */
3575796c8dcSSimon Schubert   ptid = beneath->to_wait (beneath, ptid, status, options);
3585796c8dcSSimon Schubert 
3595796c8dcSSimon Schubert   /* If the process is no longer alive, there's no point in figuring
3605796c8dcSSimon Schubert      out the thread ID.  It will fail anyway.  */
3615796c8dcSSimon Schubert   if (status->kind == TARGET_WAITKIND_SIGNALLED
3625796c8dcSSimon Schubert       || status->kind == TARGET_WAITKIND_EXITED)
3635796c8dcSSimon Schubert     return ptid;
3645796c8dcSSimon Schubert 
3655796c8dcSSimon Schubert   /* Fetch the corresponding thread ID, and augment the returned
3665796c8dcSSimon Schubert      process ID with it.  */
3675796c8dcSSimon Schubert   addr = bsd_uthread_read_memory_address (bsd_uthread_thread_run_addr);
3685796c8dcSSimon Schubert   if (addr != 0)
3695796c8dcSSimon Schubert     {
3705796c8dcSSimon Schubert       gdb_byte buf[4];
3715796c8dcSSimon Schubert 
3725796c8dcSSimon Schubert       /* FIXME: For executables linked statically with the threads
3735796c8dcSSimon Schubert          library, we end up here before the program has actually been
3745796c8dcSSimon Schubert          executed.  In that case ADDR will be garbage since it has
3755796c8dcSSimon Schubert          been read from the wrong virtual memory image.  */
3765796c8dcSSimon Schubert       if (target_read_memory (addr, buf, 4) == 0)
3775796c8dcSSimon Schubert 	{
3785796c8dcSSimon Schubert 	  ULONGEST magic = extract_unsigned_integer (buf, 4, byte_order);
3795796c8dcSSimon Schubert 	  if (magic == BSD_UTHREAD_PTHREAD_MAGIC)
3805796c8dcSSimon Schubert 	    ptid = ptid_build (ptid_get_pid (ptid), 0, addr);
3815796c8dcSSimon Schubert 	}
3825796c8dcSSimon Schubert     }
3835796c8dcSSimon Schubert 
3845796c8dcSSimon Schubert   /* If INFERIOR_PTID doesn't have a tid member yet, and we now have a
3855796c8dcSSimon Schubert      ptid with tid set, then ptid is still the initial thread of
3865796c8dcSSimon Schubert      the process.  Notify GDB core about it.  */
3875796c8dcSSimon Schubert   if (ptid_get_tid (inferior_ptid) == 0
3885796c8dcSSimon Schubert       && ptid_get_tid (ptid) != 0 && !in_thread_list (ptid))
3895796c8dcSSimon Schubert     thread_change_ptid (inferior_ptid, ptid);
3905796c8dcSSimon Schubert 
3915796c8dcSSimon Schubert   /* Don't let the core see a ptid without a corresponding thread.  */
3925796c8dcSSimon Schubert   if (!in_thread_list (ptid) || is_exited (ptid))
3935796c8dcSSimon Schubert     add_thread (ptid);
3945796c8dcSSimon Schubert 
3955796c8dcSSimon Schubert   return ptid;
3965796c8dcSSimon Schubert }
3975796c8dcSSimon Schubert 
3985796c8dcSSimon Schubert static void
bsd_uthread_resume(struct target_ops * ops,ptid_t ptid,int step,enum gdb_signal sig)3995796c8dcSSimon Schubert bsd_uthread_resume (struct target_ops *ops,
400*ef5ccd6cSJohn Marino 		    ptid_t ptid, int step, enum gdb_signal sig)
4015796c8dcSSimon Schubert {
4025796c8dcSSimon Schubert   /* Pass the request to the layer beneath.  */
4035796c8dcSSimon Schubert   struct target_ops *beneath = find_target_beneath (ops);
4045796c8dcSSimon Schubert   beneath->to_resume (beneath, ptid, step, sig);
4055796c8dcSSimon Schubert }
4065796c8dcSSimon Schubert 
4075796c8dcSSimon Schubert static int
bsd_uthread_thread_alive(struct target_ops * ops,ptid_t ptid)4085796c8dcSSimon Schubert bsd_uthread_thread_alive (struct target_ops *ops, ptid_t ptid)
4095796c8dcSSimon Schubert {
410*ef5ccd6cSJohn Marino   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
4115796c8dcSSimon Schubert   struct target_ops *beneath = find_target_beneath (ops);
4125796c8dcSSimon Schubert   CORE_ADDR addr = ptid_get_tid (inferior_ptid);
4135796c8dcSSimon Schubert 
4145796c8dcSSimon Schubert   if (addr != 0)
4155796c8dcSSimon Schubert     {
4165796c8dcSSimon Schubert       int offset = bsd_uthread_thread_state_offset;
4175796c8dcSSimon Schubert       ULONGEST state;
4185796c8dcSSimon Schubert 
4195796c8dcSSimon Schubert       bsd_uthread_check_magic (addr);
4205796c8dcSSimon Schubert 
4215796c8dcSSimon Schubert       state = read_memory_unsigned_integer (addr + offset, 4, byte_order);
4225796c8dcSSimon Schubert       if (state == BSD_UTHREAD_PS_DEAD)
4235796c8dcSSimon Schubert 	return 0;
4245796c8dcSSimon Schubert     }
4255796c8dcSSimon Schubert 
4265796c8dcSSimon Schubert   return beneath->to_thread_alive (beneath, ptid);
4275796c8dcSSimon Schubert }
4285796c8dcSSimon Schubert 
4295796c8dcSSimon Schubert static void
bsd_uthread_find_new_threads(struct target_ops * ops)4305796c8dcSSimon Schubert bsd_uthread_find_new_threads (struct target_ops *ops)
4315796c8dcSSimon Schubert {
4325796c8dcSSimon Schubert   pid_t pid = ptid_get_pid (inferior_ptid);
4335796c8dcSSimon Schubert   int offset = bsd_uthread_thread_next_offset;
4345796c8dcSSimon Schubert   CORE_ADDR addr;
4355796c8dcSSimon Schubert 
4365796c8dcSSimon Schubert   addr = bsd_uthread_read_memory_address (bsd_uthread_thread_list_addr);
4375796c8dcSSimon Schubert   while (addr != 0)
4385796c8dcSSimon Schubert     {
4395796c8dcSSimon Schubert       ptid_t ptid = ptid_build (pid, 0, addr);
4405796c8dcSSimon Schubert 
4415796c8dcSSimon Schubert       if (!in_thread_list (ptid) || is_exited (ptid))
4425796c8dcSSimon Schubert 	{
4435796c8dcSSimon Schubert 	  /* If INFERIOR_PTID doesn't have a tid member yet, then ptid
4445796c8dcSSimon Schubert 	     is still the initial thread of the process.  Notify GDB
4455796c8dcSSimon Schubert 	     core about it.  */
4465796c8dcSSimon Schubert 	  if (ptid_get_tid (inferior_ptid) == 0)
4475796c8dcSSimon Schubert 	    thread_change_ptid (inferior_ptid, ptid);
4485796c8dcSSimon Schubert 	  else
4495796c8dcSSimon Schubert 	    add_thread (ptid);
4505796c8dcSSimon Schubert 	}
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert       addr = bsd_uthread_read_memory_address (addr + offset);
4535796c8dcSSimon Schubert     }
4545796c8dcSSimon Schubert }
4555796c8dcSSimon Schubert 
4565796c8dcSSimon Schubert /* Possible states a thread can be in.  */
4575796c8dcSSimon Schubert static char *bsd_uthread_state[] =
4585796c8dcSSimon Schubert {
4595796c8dcSSimon Schubert   "RUNNING",
4605796c8dcSSimon Schubert   "SIGTHREAD",
4615796c8dcSSimon Schubert   "MUTEX_WAIT",
4625796c8dcSSimon Schubert   "COND_WAIT",
4635796c8dcSSimon Schubert   "FDLR_WAIT",
4645796c8dcSSimon Schubert   "FDLW_WAIT",
4655796c8dcSSimon Schubert   "FDR_WAIT",
4665796c8dcSSimon Schubert   "FDW_WAIT",
4675796c8dcSSimon Schubert   "FILE_WAIT",
4685796c8dcSSimon Schubert   "POLL_WAIT",
4695796c8dcSSimon Schubert   "SELECT_WAIT",
4705796c8dcSSimon Schubert   "SLEEP_WAIT",
4715796c8dcSSimon Schubert   "WAIT_WAIT",
4725796c8dcSSimon Schubert   "SIGSUSPEND",
4735796c8dcSSimon Schubert   "SIGWAIT",
4745796c8dcSSimon Schubert   "SPINBLOCK",
4755796c8dcSSimon Schubert   "JOIN",
4765796c8dcSSimon Schubert   "SUSPENDED",
4775796c8dcSSimon Schubert   "DEAD",
4785796c8dcSSimon Schubert   "DEADLOCK"
4795796c8dcSSimon Schubert };
4805796c8dcSSimon Schubert 
4815796c8dcSSimon Schubert /* Return a string describing th state of the thread specified by
4825796c8dcSSimon Schubert    INFO.  */
4835796c8dcSSimon Schubert 
4845796c8dcSSimon Schubert static char *
bsd_uthread_extra_thread_info(struct thread_info * info)4855796c8dcSSimon Schubert bsd_uthread_extra_thread_info (struct thread_info *info)
4865796c8dcSSimon Schubert {
487*ef5ccd6cSJohn Marino   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
4885796c8dcSSimon Schubert   CORE_ADDR addr = ptid_get_tid (info->ptid);
4895796c8dcSSimon Schubert 
4905796c8dcSSimon Schubert   if (addr != 0)
4915796c8dcSSimon Schubert     {
4925796c8dcSSimon Schubert       int offset = bsd_uthread_thread_state_offset;
4935796c8dcSSimon Schubert       ULONGEST state;
4945796c8dcSSimon Schubert 
4955796c8dcSSimon Schubert       state = read_memory_unsigned_integer (addr + offset, 4, byte_order);
4965796c8dcSSimon Schubert       if (state < ARRAY_SIZE (bsd_uthread_state))
4975796c8dcSSimon Schubert 	return bsd_uthread_state[state];
4985796c8dcSSimon Schubert     }
4995796c8dcSSimon Schubert 
5005796c8dcSSimon Schubert   return NULL;
5015796c8dcSSimon Schubert }
5025796c8dcSSimon Schubert 
5035796c8dcSSimon Schubert static char *
bsd_uthread_pid_to_str(struct target_ops * ops,ptid_t ptid)5045796c8dcSSimon Schubert bsd_uthread_pid_to_str (struct target_ops *ops, ptid_t ptid)
5055796c8dcSSimon Schubert {
5065796c8dcSSimon Schubert   if (ptid_get_tid (ptid) != 0)
5075796c8dcSSimon Schubert     {
5085796c8dcSSimon Schubert       static char buf[64];
5095796c8dcSSimon Schubert 
5105796c8dcSSimon Schubert       xsnprintf (buf, sizeof buf, "process %d, thread 0x%lx",
5115796c8dcSSimon Schubert 		 ptid_get_pid (ptid), ptid_get_tid (ptid));
5125796c8dcSSimon Schubert       return buf;
5135796c8dcSSimon Schubert     }
5145796c8dcSSimon Schubert 
5155796c8dcSSimon Schubert   return normal_pid_to_str (ptid);
5165796c8dcSSimon Schubert }
5175796c8dcSSimon Schubert 
5185796c8dcSSimon Schubert static struct target_ops *
bsd_uthread_target(void)5195796c8dcSSimon Schubert bsd_uthread_target (void)
5205796c8dcSSimon Schubert {
5215796c8dcSSimon Schubert   struct target_ops *t = XZALLOC (struct target_ops);
5225796c8dcSSimon Schubert 
5235796c8dcSSimon Schubert   t->to_shortname = "bsd-uthreads";
5245796c8dcSSimon Schubert   t->to_longname = "BSD user-level threads";
5255796c8dcSSimon Schubert   t->to_doc = "BSD user-level threads";
5265796c8dcSSimon Schubert   t->to_close = bsd_uthread_close;
5275796c8dcSSimon Schubert   t->to_mourn_inferior = bsd_uthread_mourn_inferior;
5285796c8dcSSimon Schubert   t->to_fetch_registers = bsd_uthread_fetch_registers;
5295796c8dcSSimon Schubert   t->to_store_registers = bsd_uthread_store_registers;
5305796c8dcSSimon Schubert   t->to_xfer_partial = bsd_uthread_xfer_partial;
5315796c8dcSSimon Schubert   t->to_wait = bsd_uthread_wait;
5325796c8dcSSimon Schubert   t->to_resume = bsd_uthread_resume;
5335796c8dcSSimon Schubert   t->to_thread_alive = bsd_uthread_thread_alive;
5345796c8dcSSimon Schubert   t->to_find_new_threads = bsd_uthread_find_new_threads;
5355796c8dcSSimon Schubert   t->to_extra_thread_info = bsd_uthread_extra_thread_info;
5365796c8dcSSimon Schubert   t->to_pid_to_str = bsd_uthread_pid_to_str;
5375796c8dcSSimon Schubert   t->to_stratum = thread_stratum;
5385796c8dcSSimon Schubert   t->to_magic = OPS_MAGIC;
5395796c8dcSSimon Schubert   bsd_uthread_ops_hack = t;
5405796c8dcSSimon Schubert 
5415796c8dcSSimon Schubert   return t;
5425796c8dcSSimon Schubert }
5435796c8dcSSimon Schubert 
5445796c8dcSSimon Schubert /* Provide a prototype to silence -Wmissing-prototypes.  */
5455796c8dcSSimon Schubert extern initialize_file_ftype _initialize_bsd_uthread;
5465796c8dcSSimon Schubert 
5475796c8dcSSimon Schubert void
_initialize_bsd_uthread(void)5485796c8dcSSimon Schubert _initialize_bsd_uthread (void)
5495796c8dcSSimon Schubert {
5505796c8dcSSimon Schubert   add_target (bsd_uthread_target ());
5515796c8dcSSimon Schubert 
5525796c8dcSSimon Schubert   bsd_uthread_data = gdbarch_data_register_pre_init (bsd_uthread_init);
5535796c8dcSSimon Schubert 
5545796c8dcSSimon Schubert   observer_attach_inferior_created (bsd_uthread_inferior_created);
5555796c8dcSSimon Schubert   observer_attach_solib_loaded (bsd_uthread_solib_loaded);
5565796c8dcSSimon Schubert   observer_attach_solib_unloaded (bsd_uthread_solib_unloaded);
5575796c8dcSSimon Schubert }
558