1132179Sdavidxu/* $FreeBSD$ */
2132179Sdavidxu/* FreeBSD libthread_db assisted debugging support.
3132179Sdavidxu   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
4132179Sdavidxu
5132179Sdavidxu   This file is part of GDB.
6132179Sdavidxu
7132179Sdavidxu   This program is free software; you can redistribute it and/or modify
8132179Sdavidxu   it under the terms of the GNU General Public License as published by
9132179Sdavidxu   the Free Software Foundation; either version 2 of the License, or
10132179Sdavidxu   (at your option) any later version.
11132179Sdavidxu
12132179Sdavidxu   This program is distributed in the hope that it will be useful,
13132179Sdavidxu   but WITHOUT ANY WARRANTY; without even the implied warranty of
14132179Sdavidxu   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15132179Sdavidxu   GNU General Public License for more details.
16132179Sdavidxu
17132179Sdavidxu   You should have received a copy of the GNU General Public License
18132179Sdavidxu   along with this program; if not, write to the Free Software
19132179Sdavidxu   Foundation, Inc., 59 Temple Place - Suite 330,
20132179Sdavidxu   Boston, MA 02111-1307, USA.  */
21132179Sdavidxu
22134147Sdavidxu#include <dlfcn.h>
23134147Sdavidxu#include <sys/types.h>
24134147Sdavidxu#include <sys/ptrace.h>
25155379Sdavidxu#include <signal.h>
26132179Sdavidxu
27132179Sdavidxu#include "proc_service.h"
28132179Sdavidxu#include "thread_db.h"
29132179Sdavidxu
30134147Sdavidxu#include "defs.h"
31132179Sdavidxu#include "bfd.h"
32134147Sdavidxu#include "elf-bfd.h"
33134147Sdavidxu#include "gdb_assert.h"
34134147Sdavidxu#include "gdbcore.h"
35132179Sdavidxu#include "gdbthread.h"
36132179Sdavidxu#include "inferior.h"
37134147Sdavidxu#include "objfiles.h"
38134147Sdavidxu#include "regcache.h"
39132179Sdavidxu#include "symfile.h"
40132179Sdavidxu#include "symtab.h"
41132179Sdavidxu#include "target.h"
42132179Sdavidxu#include "gdbcmd.h"
43133345Sdavidxu#include "solib-svr4.h"
44132179Sdavidxu
45218822Sdim#include "gregset.h"
46218822Sdim#ifdef PT_GETXMMREGS
47218822Sdim#include "i387-tdep.h"
48218822Sdim#endif
49132179Sdavidxu
50132179Sdavidxu#define LIBTHREAD_DB_SO "libthread_db.so"
51132179Sdavidxu
52132179Sdavidxustruct ps_prochandle
53132179Sdavidxu{
54132179Sdavidxu  pid_t pid;
55132179Sdavidxu};
56132179Sdavidxu
57134147Sdavidxuextern int child_suppress_run;
58134147Sdavidxu
59132179Sdavidxuextern struct target_ops child_ops;
60132179Sdavidxu
61134152Sdavidxu/* This module's target vectors.  */
62134147Sdavidxustatic struct target_ops fbsd_thread_ops;
63134147Sdavidxustatic struct target_ops fbsd_core_ops;
64132179Sdavidxu
65134147Sdavidxu/* Saved copy of orignal core_ops. */
66134147Sdavidxustatic struct target_ops orig_core_ops;
67134147Sdavidxuextern struct target_ops core_ops;
68134147Sdavidxu
69132179Sdavidxu/* Pointer to the next function on the objfile event chain.  */
70132179Sdavidxustatic void (*target_new_objfile_chain) (struct objfile *objfile);
71132179Sdavidxu
72134147Sdavidxu/* Non-zero if there is a thread module */
73134147Sdavidxustatic int fbsd_thread_present;
74134147Sdavidxu
75132179Sdavidxu/* Non-zero if we're using this module's target vector.  */
76134147Sdavidxustatic int fbsd_thread_active;
77132179Sdavidxu
78134147Sdavidxu/* Non-zero if core_open is called */
79134147Sdavidxustatic int fbsd_thread_core = 0;
80134147Sdavidxu
81132179Sdavidxu/* Non-zero if we have to keep this module's target vector active
82132179Sdavidxu   across re-runs.  */
83132179Sdavidxustatic int keep_thread_db;
84132179Sdavidxu
85132179Sdavidxu/* Structure that identifies the child process for the
86132179Sdavidxu   <proc_service.h> interface.  */
87132179Sdavidxustatic struct ps_prochandle proc_handle;
88132179Sdavidxu
89132179Sdavidxu/* Connection to the libthread_db library.  */
90132179Sdavidxustatic td_thragent_t *thread_agent;
91132179Sdavidxu
92132179Sdavidxu/* The last thread we are single stepping */
93132179Sdavidxustatic ptid_t last_single_step_thread;
94132179Sdavidxu
95132179Sdavidxu/* Pointers to the libthread_db functions.  */
96132179Sdavidxu
97132179Sdavidxustatic td_err_e (*td_init_p) (void);
98132179Sdavidxu
99132179Sdavidxustatic td_err_e (*td_ta_new_p) (struct ps_prochandle *ps, td_thragent_t **ta);
100134147Sdavidxustatic td_err_e (*td_ta_delete_p) (td_thragent_t *);
101132179Sdavidxustatic td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
102132179Sdavidxu				       td_thrhandle_t *__th);
103132179Sdavidxustatic td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
104132179Sdavidxu					td_thrhandle_t *th);
105132179Sdavidxustatic td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta,
106132179Sdavidxu				     td_thr_iter_f *callback,
107132179Sdavidxu				     void *cbdata_p, td_thr_state_e state,
108132179Sdavidxu				     int ti_pri, sigset_t *ti_sigmask_p,
109132179Sdavidxu				     unsigned int ti_user_flags);
110132179Sdavidxustatic td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
111132179Sdavidxu				       td_event_e event, td_notify_t *ptr);
112132179Sdavidxustatic td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
113132179Sdavidxu				      td_thr_events_t *event);
114132179Sdavidxustatic td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
115132179Sdavidxu					 td_event_msg_t *msg);
116132179Sdavidxustatic td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
117132179Sdavidxu				      td_thrinfo_t *infop);
118146818Sdfr#ifdef PT_GETXMMREGS
119146818Sdfrstatic td_err_e (*td_thr_getxmmregs_p) (const td_thrhandle_t *th,
120146818Sdfr					char *regset);
121146818Sdfr#endif
122132179Sdavidxustatic td_err_e (*td_thr_getfpregs_p) (const td_thrhandle_t *th,
123132179Sdavidxu				       prfpregset_t *regset);
124132179Sdavidxustatic td_err_e (*td_thr_getgregs_p) (const td_thrhandle_t *th,
125132179Sdavidxu				      prgregset_t gregs);
126146818Sdfr#ifdef PT_GETXMMREGS
127146818Sdfrstatic td_err_e (*td_thr_setxmmregs_p) (const td_thrhandle_t *th,
128146818Sdfr					const char *fpregs);
129146818Sdfr#endif
130132179Sdavidxustatic td_err_e (*td_thr_setfpregs_p) (const td_thrhandle_t *th,
131132179Sdavidxu				       const prfpregset_t *fpregs);
132132179Sdavidxustatic td_err_e (*td_thr_setgregs_p) (const td_thrhandle_t *th,
133132179Sdavidxu				      prgregset_t gregs);
134132179Sdavidxustatic td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
135132179Sdavidxu
136132179Sdavidxustatic td_err_e (*td_thr_sstep_p) (td_thrhandle_t *th, int step);
137132179Sdavidxu
138132179Sdavidxustatic td_err_e (*td_ta_tsd_iter_p) (const td_thragent_t *ta,
139132179Sdavidxu				 td_key_iter_f *func, void *data);
140133345Sdavidxustatic td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
141133345Sdavidxu                                          void *map_address,
142133345Sdavidxu                                          size_t offset, void **address);
143132179Sdavidxustatic td_err_e (*td_thr_dbsuspend_p) (const td_thrhandle_t *);
144132179Sdavidxustatic td_err_e (*td_thr_dbresume_p) (const td_thrhandle_t *);
145132179Sdavidxu
146144923Sdavidxustatic CORE_ADDR td_create_bp_addr;
147144923Sdavidxu
148144923Sdavidxu/* Location of the thread death event breakpoint.  */
149144923Sdavidxustatic CORE_ADDR td_death_bp_addr;
150144923Sdavidxu
151132179Sdavidxu/* Prototypes for local functions.  */
152132179Sdavidxustatic void fbsd_thread_find_new_threads (void);
153133345Sdavidxustatic int fbsd_thread_alive (ptid_t ptid);
154144923Sdavidxustatic void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
155144923Sdavidxu               const td_thrinfo_t *ti_p, int verbose);
156144923Sdavidxustatic void fbsd_thread_detach (char *args, int from_tty);
157132179Sdavidxu
158132179Sdavidxu/* Building process ids.  */
159132179Sdavidxu
160132179Sdavidxu#define GET_PID(ptid)		ptid_get_pid (ptid)
161132179Sdavidxu#define GET_LWP(ptid)		ptid_get_lwp (ptid)
162132179Sdavidxu#define GET_THREAD(ptid)	ptid_get_tid (ptid)
163132179Sdavidxu
164132179Sdavidxu#define IS_LWP(ptid)		(GET_LWP (ptid) != 0)
165132179Sdavidxu#define IS_THREAD(ptid)		(GET_THREAD (ptid) != 0)
166132179Sdavidxu
167132179Sdavidxu#define BUILD_LWP(lwp, pid)	ptid_build (pid, lwp, 0)
168132179Sdavidxu#define BUILD_THREAD(tid, pid)	ptid_build (pid, 0, tid)
169132179Sdavidxu
170132179Sdavidxustatic char *
171132179Sdavidxuthread_db_err_str (td_err_e err)
172132179Sdavidxu{
173132179Sdavidxu  static char buf[64];
174132179Sdavidxu
175132179Sdavidxu  switch (err)
176132179Sdavidxu    {
177132179Sdavidxu    case TD_OK:
178132179Sdavidxu      return "generic 'call succeeded'";
179132179Sdavidxu    case TD_ERR:
180132179Sdavidxu      return "generic error";
181132179Sdavidxu    case TD_NOTHR:
182132179Sdavidxu      return "no thread to satisfy query";
183132179Sdavidxu    case TD_NOSV:
184132179Sdavidxu      return "no sync handle to satisfy query";
185132179Sdavidxu    case TD_NOLWP:
186132179Sdavidxu      return "no LWP to satisfy query";
187132179Sdavidxu    case TD_BADPH:
188132179Sdavidxu      return "invalid process handle";
189132179Sdavidxu    case TD_BADTH:
190132179Sdavidxu      return "invalid thread handle";
191132179Sdavidxu    case TD_BADSH:
192132179Sdavidxu      return "invalid synchronization handle";
193132179Sdavidxu    case TD_BADTA:
194132179Sdavidxu      return "invalid thread agent";
195132179Sdavidxu    case TD_BADKEY:
196132179Sdavidxu      return "invalid key";
197132179Sdavidxu    case TD_NOMSG:
198132179Sdavidxu      return "no event message for getmsg";
199132179Sdavidxu    case TD_NOFPREGS:
200132179Sdavidxu      return "FPU register set not available";
201132179Sdavidxu    case TD_NOLIBTHREAD:
202132179Sdavidxu      return "application not linked with libthread";
203132179Sdavidxu    case TD_NOEVENT:
204132179Sdavidxu      return "requested event is not supported";
205132179Sdavidxu    case TD_NOCAPAB:
206132179Sdavidxu      return "capability not available";
207132179Sdavidxu    case TD_DBERR:
208132179Sdavidxu      return "debugger service failed";
209132179Sdavidxu    case TD_NOAPLIC:
210132179Sdavidxu      return "operation not applicable to";
211132179Sdavidxu    case TD_NOTSD:
212132179Sdavidxu      return "no thread-specific data for this thread";
213132179Sdavidxu    case TD_MALLOC:
214132179Sdavidxu      return "malloc failed";
215132179Sdavidxu    case TD_PARTIALREG:
216132179Sdavidxu      return "only part of register set was written/read";
217132179Sdavidxu    case TD_NOXREGS:
218132179Sdavidxu      return "X register set not available for this thread";
219132179Sdavidxu    default:
220132179Sdavidxu      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
221132179Sdavidxu      return buf;
222132179Sdavidxu    }
223132179Sdavidxu}
224132179Sdavidxu
225132179Sdavidxustatic char *
226132179Sdavidxuthread_db_state_str (td_thr_state_e state)
227132179Sdavidxu{
228132179Sdavidxu  static char buf[64];
229132179Sdavidxu
230132179Sdavidxu  switch (state)
231132179Sdavidxu    {
232132179Sdavidxu    case TD_THR_STOPPED:
233132179Sdavidxu      return "stopped by debugger";
234132179Sdavidxu    case TD_THR_RUN:
235132179Sdavidxu      return "runnable";
236132179Sdavidxu    case TD_THR_ACTIVE:
237132179Sdavidxu      return "active";
238132179Sdavidxu    case TD_THR_ZOMBIE:
239132179Sdavidxu      return "zombie";
240132179Sdavidxu    case TD_THR_SLEEP:
241132179Sdavidxu      return "sleeping";
242132179Sdavidxu    case TD_THR_STOPPED_ASLEEP:
243132179Sdavidxu      return "stopped by debugger AND blocked";
244132179Sdavidxu    default:
245132179Sdavidxu      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
246132179Sdavidxu      return buf;
247132179Sdavidxu    }
248132179Sdavidxu}
249132179Sdavidxu
250132179Sdavidxu/* Convert LWP to user-level thread id. */
251132179Sdavidxustatic ptid_t
252144923Sdavidxuthread_from_lwp (ptid_t ptid, td_thrhandle_t *th, td_thrinfo_t *ti)
253132179Sdavidxu{
254132179Sdavidxu  td_err_e err;
255132179Sdavidxu
256132179Sdavidxu  gdb_assert (IS_LWP (ptid));
257132179Sdavidxu
258134147Sdavidxu  if (fbsd_thread_active)
259132179Sdavidxu    {
260144923Sdavidxu      err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), th);
261134147Sdavidxu      if (err == TD_OK)
262134147Sdavidxu        {
263144923Sdavidxu          err = td_thr_get_info_p (th, ti);
264134147Sdavidxu          if (err != TD_OK)
265134147Sdavidxu            error ("Cannot get thread info: %s", thread_db_err_str (err));
266144923Sdavidxu          return BUILD_THREAD (ti->ti_tid, GET_PID (ptid));
267134147Sdavidxu        }
268132179Sdavidxu    }
269132179Sdavidxu
270132179Sdavidxu  /* the LWP is not mapped to user thread */
271132179Sdavidxu  return BUILD_LWP (GET_LWP (ptid), GET_PID (ptid));
272132179Sdavidxu}
273132179Sdavidxu
274134147Sdavidxustatic void
275134147Sdavidxufbsd_core_get_first_lwp (bfd *abfd, asection *asect, void *obj)
276134147Sdavidxu{
277134147Sdavidxu  if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0)
278134147Sdavidxu    return;
279134147Sdavidxu
280134147Sdavidxu  if (*(lwpid_t *)obj != 0)
281134147Sdavidxu    return;
282134147Sdavidxu
283134147Sdavidxu  *(lwpid_t *)obj = atoi (bfd_section_name (abfd, asect) + 5);
284134147Sdavidxu}
285134147Sdavidxu
286132179Sdavidxustatic long
287132179Sdavidxuget_current_lwp (int pid)
288132179Sdavidxu{
289132179Sdavidxu  struct ptrace_lwpinfo pl;
290134147Sdavidxu  lwpid_t lwpid;
291132179Sdavidxu
292134147Sdavidxu  if (!target_has_execution)
293134147Sdavidxu    {
294134147Sdavidxu      lwpid = 0;
295134147Sdavidxu      bfd_map_over_sections (core_bfd, fbsd_core_get_first_lwp, &lwpid);
296134147Sdavidxu      return lwpid;
297134147Sdavidxu    }
298132179Sdavidxu  if (ptrace (PT_LWPINFO, pid, (caddr_t)&pl, sizeof(pl)))
299132179Sdavidxu    perror_with_name("PT_LWPINFO");
300132179Sdavidxu
301132179Sdavidxu  return (long)pl.pl_lwpid;
302132179Sdavidxu}
303132179Sdavidxu
304132179Sdavidxustatic void
305132179Sdavidxuget_current_thread ()
306132179Sdavidxu{
307144923Sdavidxu  td_thrhandle_t th;
308144923Sdavidxu  td_thrinfo_t ti;
309132179Sdavidxu  long lwp;
310132179Sdavidxu  ptid_t tmp, ptid;
311132179Sdavidxu
312132179Sdavidxu  lwp = get_current_lwp (proc_handle.pid);
313132179Sdavidxu  tmp = BUILD_LWP (lwp, proc_handle.pid);
314144923Sdavidxu  ptid = thread_from_lwp (tmp, &th, &ti);
315132179Sdavidxu  if (!in_thread_list (ptid))
316132179Sdavidxu    {
317144923Sdavidxu      attach_thread (ptid, &th, &ti, 1);
318132179Sdavidxu    }
319137731Sdavidxu  inferior_ptid = ptid;
320132179Sdavidxu}
321132179Sdavidxu
322144923Sdavidxustatic td_err_e
323144923Sdavidxuenable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
324144923Sdavidxu{
325144923Sdavidxu  td_notify_t notify;
326144923Sdavidxu  td_err_e err;
327144923Sdavidxu
328144923Sdavidxu  /* Get the breakpoint address for thread EVENT.  */
329144923Sdavidxu  err = td_ta_event_addr_p (thread_agent, event, &notify);
330144923Sdavidxu  if (err != TD_OK)
331144923Sdavidxu    return err;
332144923Sdavidxu
333144923Sdavidxu  /* Set up the breakpoint.  */
334144923Sdavidxu  (*bp) = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
335155379Sdavidxu            extract_typed_address(&notify.u.bptaddr, builtin_type_void_func_ptr),
336155379Sdavidxu            &current_target);
337144923Sdavidxu  create_thread_event_breakpoint ((*bp));
338144923Sdavidxu
339144923Sdavidxu  return TD_OK;
340144923Sdavidxu}
341144923Sdavidxu
342132179Sdavidxustatic void
343144923Sdavidxuenable_thread_event_reporting (void)
344144923Sdavidxu{
345144923Sdavidxu  td_thr_events_t events;
346144923Sdavidxu  td_notify_t notify;
347144923Sdavidxu  td_err_e err;
348144923Sdavidxu
349144923Sdavidxu  /* We cannot use the thread event reporting facility if these
350144923Sdavidxu     functions aren't available.  */
351144923Sdavidxu  if (td_ta_event_addr_p == NULL || td_ta_set_event_p == NULL
352144923Sdavidxu      || td_ta_event_getmsg_p == NULL || td_thr_event_enable_p == NULL)
353144923Sdavidxu    return;
354144923Sdavidxu
355144923Sdavidxu  /* Set the process wide mask saying which events we're interested in.  */
356144923Sdavidxu  td_event_emptyset (&events);
357144923Sdavidxu  td_event_addset (&events, TD_CREATE);
358144923Sdavidxu  td_event_addset (&events, TD_DEATH);
359144923Sdavidxu
360144923Sdavidxu  err = td_ta_set_event_p (thread_agent, &events);
361144923Sdavidxu  if (err != TD_OK)
362144923Sdavidxu    {
363144923Sdavidxu      warning ("Unable to set global thread event mask: %s",
364144923Sdavidxu	       thread_db_err_str (err));
365144923Sdavidxu      return;
366144923Sdavidxu    }
367144923Sdavidxu
368144923Sdavidxu  /* Delete previous thread event breakpoints, if any.  */
369144923Sdavidxu  remove_thread_event_breakpoints ();
370144923Sdavidxu  td_create_bp_addr = 0;
371144923Sdavidxu  td_death_bp_addr = 0;
372144923Sdavidxu
373144923Sdavidxu  /* Set up the thread creation event.  */
374144923Sdavidxu  err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr);
375144923Sdavidxu  if (err != TD_OK)
376144923Sdavidxu    {
377144923Sdavidxu      warning ("Unable to get location for thread creation breakpoint: %s",
378144923Sdavidxu	       thread_db_err_str (err));
379144923Sdavidxu      return;
380144923Sdavidxu    }
381144923Sdavidxu
382144923Sdavidxu  /* Set up the thread death event.  */
383144923Sdavidxu  err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr);
384144923Sdavidxu  if (err != TD_OK)
385144923Sdavidxu    {
386144923Sdavidxu      warning ("Unable to get location for thread death breakpoint: %s",
387144923Sdavidxu	       thread_db_err_str (err));
388144923Sdavidxu      return;
389144923Sdavidxu    }
390144923Sdavidxu}
391144923Sdavidxu
392144923Sdavidxustatic void
393144923Sdavidxudisable_thread_event_reporting (void)
394144923Sdavidxu{
395144923Sdavidxu  td_thr_events_t events;
396144923Sdavidxu
397144923Sdavidxu  /* Set the process wide mask saying we aren't interested in any
398144923Sdavidxu     events anymore.  */
399144923Sdavidxu  td_event_emptyset (&events);
400144923Sdavidxu  td_ta_set_event_p (thread_agent, &events);
401144923Sdavidxu
402144923Sdavidxu  /* Delete thread event breakpoints, if any.  */
403144923Sdavidxu  remove_thread_event_breakpoints ();
404144923Sdavidxu  td_create_bp_addr = 0;
405144923Sdavidxu  td_death_bp_addr = 0;
406144923Sdavidxu}
407144923Sdavidxu
408144923Sdavidxustatic void
409134147Sdavidxufbsd_thread_activate (void)
410134147Sdavidxu{
411134147Sdavidxu  fbsd_thread_active = 1;
412134147Sdavidxu  init_thread_list();
413144923Sdavidxu  if (fbsd_thread_core == 0)
414144923Sdavidxu    enable_thread_event_reporting ();
415134147Sdavidxu  fbsd_thread_find_new_threads ();
416134147Sdavidxu  get_current_thread ();
417134147Sdavidxu}
418134147Sdavidxu
419134147Sdavidxustatic void
420134147Sdavidxufbsd_thread_deactivate (void)
421134147Sdavidxu{
422144923Sdavidxu  if (fbsd_thread_core == 0)
423144923Sdavidxu    disable_thread_event_reporting();
424134147Sdavidxu  td_ta_delete_p (thread_agent);
425134147Sdavidxu
426134147Sdavidxu  inferior_ptid = pid_to_ptid (proc_handle.pid);
427134147Sdavidxu  proc_handle.pid = 0;
428134147Sdavidxu  fbsd_thread_active = 0;
429134147Sdavidxu  fbsd_thread_present = 0;
430134147Sdavidxu  init_thread_list ();
431134147Sdavidxu}
432134147Sdavidxu
433215679Sattiliostatic char *
434215679Sattiliofbsd_thread_get_name (lwpid_t lwpid)
435215679Sattilio{
436215679Sattilio  static char last_thr_name[MAXCOMLEN + 1];
437215679Sattilio  char section_name[32];
438215679Sattilio  struct ptrace_lwpinfo lwpinfo;
439215679Sattilio  bfd_size_type size;
440215679Sattilio  struct bfd_section *section;
441215679Sattilio
442215679Sattilio  if (target_has_execution)
443215679Sattilio    {
444215679Sattilio      if (ptrace (PT_LWPINFO, lwpid, (caddr_t)&lwpinfo, sizeof (lwpinfo)) == -1)
445215679Sattilio        goto fail;
446215679Sattilio      strncpy (last_thr_name, lwpinfo.pl_tdname, sizeof (last_thr_name) - 1);
447215679Sattilio    }
448215679Sattilio  else
449215679Sattilio    {
450215679Sattilio      snprintf (section_name, sizeof (section_name), ".tname/%u", lwpid);
451215679Sattilio      section = bfd_get_section_by_name (core_bfd, section_name);
452215679Sattilio      if (! section)
453215679Sattilio        goto fail;
454215679Sattilio
455215679Sattilio      /* Section size fix-up. */
456215679Sattilio      size = bfd_section_size (core_bfd, section);
457215679Sattilio      if (size > sizeof (last_thr_name))
458215679Sattilio        size = sizeof (last_thr_name);
459215679Sattilio
460215679Sattilio      if (! bfd_get_section_contents (core_bfd, section, last_thr_name,
461215679Sattilio	       (file_ptr)0, size))
462215679Sattilio        goto fail;
463215679Sattilio      if (last_thr_name[0] == '\0')
464215679Sattilio        goto fail;
465215679Sattilio    }
466215679Sattilio    last_thr_name[sizeof (last_thr_name) - 1] = '\0';
467215679Sattilio    return last_thr_name;
468215679Sattiliofail:
469215679Sattilio     strcpy (last_thr_name, "<unknown>");
470215679Sattilio     return last_thr_name;
471215679Sattilio}
472215679Sattilio
473134147Sdavidxustatic void
474132179Sdavidxufbsd_thread_new_objfile (struct objfile *objfile)
475132179Sdavidxu{
476132179Sdavidxu  td_err_e err;
477132179Sdavidxu
478134147Sdavidxu  if (objfile == NULL)
479132179Sdavidxu    {
480132179Sdavidxu      /* All symbols have been discarded.  If the thread_db target is
481132179Sdavidxu         active, deactivate it now.  */
482134147Sdavidxu      if (fbsd_thread_active)
483132179Sdavidxu        {
484132179Sdavidxu          gdb_assert (proc_handle.pid == 0);
485134147Sdavidxu          fbsd_thread_active = 0;
486132179Sdavidxu        }
487132179Sdavidxu
488132179Sdavidxu      goto quit;
489132179Sdavidxu    }
490132179Sdavidxu
491134147Sdavidxu  if (!child_suppress_run)
492134147Sdavidxu    goto quit;
493134147Sdavidxu
494134152Sdavidxu  /* Nothing to do.  The thread library was already detected and the
495134152Sdavidxu     target vector was already activated.  */
496134147Sdavidxu  if (fbsd_thread_active)
497132179Sdavidxu    goto quit;
498132179Sdavidxu
499132179Sdavidxu  /* Initialize the structure that identifies the child process.  Note
500132179Sdavidxu     that at this point there is no guarantee that we actually have a
501132179Sdavidxu     child process.  */
502132179Sdavidxu  proc_handle.pid = GET_PID (inferior_ptid);
503132179Sdavidxu
504132179Sdavidxu  /* Now attempt to open a connection to the thread library.  */
505132179Sdavidxu  err = td_ta_new_p (&proc_handle, &thread_agent);
506132179Sdavidxu  switch (err)
507132179Sdavidxu    {
508132179Sdavidxu    case TD_NOLIBTHREAD:
509132179Sdavidxu      /* No thread library was detected.  */
510132179Sdavidxu      break;
511132179Sdavidxu
512132179Sdavidxu    case TD_OK:
513132179Sdavidxu      /* The thread library was detected.  Activate the thread_db target.  */
514134147Sdavidxu      fbsd_thread_present = 1;
515132179Sdavidxu
516132179Sdavidxu      /* We can only poke around if there actually is a child process.
517132179Sdavidxu         If there is no child process alive, postpone the steps below
518132179Sdavidxu         until one has been created.  */
519134147Sdavidxu      if (fbsd_thread_core == 0 && proc_handle.pid != 0)
520132179Sdavidxu        {
521134147Sdavidxu          push_target(&fbsd_thread_ops);
522134147Sdavidxu          fbsd_thread_activate();
523132179Sdavidxu        }
524132179Sdavidxu      else
525134147Sdavidxu        {
526134147Sdavidxu          td_ta_delete_p(thread_agent);
527134147Sdavidxu          thread_agent = NULL;
528134147Sdavidxu        }
529132179Sdavidxu      break;
530132179Sdavidxu
531132179Sdavidxu    default:
532132179Sdavidxu      warning ("Cannot initialize thread debugging library: %s",
533132179Sdavidxu               thread_db_err_str (err));
534132179Sdavidxu      break;
535132179Sdavidxu    }
536132179Sdavidxu
537132179Sdavidxu quit:
538132179Sdavidxu  if (target_new_objfile_chain)
539132179Sdavidxu    target_new_objfile_chain (objfile);
540132179Sdavidxu}
541132179Sdavidxu
542132179Sdavidxustatic void
543132179Sdavidxufbsd_thread_attach (char *args, int from_tty)
544132179Sdavidxu{
545134147Sdavidxu  fbsd_thread_core = 0;
546134147Sdavidxu
547132179Sdavidxu  child_ops.to_attach (args, from_tty);
548132179Sdavidxu
549134147Sdavidxu  /* Must get symbols from solibs before libthread_db can run! */
550134147Sdavidxu  SOLIB_ADD ((char *) 0, from_tty, (struct target_ops *) 0, auto_solib_add);
551132179Sdavidxu
552134147Sdavidxu  if (fbsd_thread_present && !fbsd_thread_active)
553134147Sdavidxu    push_target(&fbsd_thread_ops);
554134147Sdavidxu}
555132179Sdavidxu
556134147Sdavidxustatic void
557134147Sdavidxufbsd_thread_post_attach (int pid)
558134147Sdavidxu{
559134147Sdavidxu  child_ops.to_post_attach (pid);
560134147Sdavidxu
561134147Sdavidxu  if (fbsd_thread_present && !fbsd_thread_active)
562134147Sdavidxu    {
563134147Sdavidxu      proc_handle.pid = GET_PID (inferior_ptid);
564134147Sdavidxu      fbsd_thread_activate ();
565134147Sdavidxu    }
566132179Sdavidxu}
567132179Sdavidxu
568132179Sdavidxustatic void
569132179Sdavidxufbsd_thread_detach (char *args, int from_tty)
570132179Sdavidxu{
571134147Sdavidxu  fbsd_thread_deactivate ();
572134147Sdavidxu  unpush_target (&fbsd_thread_ops);
573134147Sdavidxu
574134147Sdavidxu  /* Clear gdb solib information and symbol file
575134147Sdavidxu     cache, so that after detach and re-attach, new_objfile
576134147Sdavidxu     hook will be called */
577134147Sdavidxu
578134147Sdavidxu  clear_solib();
579134147Sdavidxu  symbol_file_clear(0);
580132179Sdavidxu  proc_handle.pid = 0;
581132179Sdavidxu  child_ops.to_detach (args, from_tty);
582132179Sdavidxu}
583132179Sdavidxu
584132179Sdavidxustatic int
585132179Sdavidxususpend_thread_callback (const td_thrhandle_t *th_p, void *data)
586132179Sdavidxu{
587133345Sdavidxu  int err = td_thr_dbsuspend_p (th_p);
588133345Sdavidxu  if (err != 0)
589134147Sdavidxu	fprintf_filtered(gdb_stderr, "%s %s\n", __func__, thread_db_err_str (err));
590133345Sdavidxu  return (err);
591132179Sdavidxu}
592132179Sdavidxu
593132179Sdavidxustatic int
594132179Sdavidxuresume_thread_callback (const td_thrhandle_t *th_p, void *data)
595132179Sdavidxu{
596133345Sdavidxu  int err = td_thr_dbresume_p (th_p);
597133345Sdavidxu  if (err != 0)
598134147Sdavidxu	fprintf_filtered(gdb_stderr, "%s %s\n", __func__, thread_db_err_str (err));
599133345Sdavidxu  return (err);
600132179Sdavidxu}
601132179Sdavidxu
602132179Sdavidxustatic void
603132179Sdavidxufbsd_thread_resume (ptid_t ptid, int step, enum target_signal signo)
604132179Sdavidxu{
605132179Sdavidxu  td_thrhandle_t th;
606132179Sdavidxu  td_thrinfo_t ti;
607132179Sdavidxu  ptid_t work_ptid;
608132179Sdavidxu  int resume_all, ret;
609132179Sdavidxu  long lwp, thvalid = 0;
610132179Sdavidxu
611134147Sdavidxu  if (!fbsd_thread_active)
612132179Sdavidxu    {
613134147Sdavidxu      child_ops.to_resume (ptid, step, signo);
614132179Sdavidxu      return;
615132179Sdavidxu    }
616132179Sdavidxu
617132179Sdavidxu  if (GET_PID(ptid) != -1 && step != 0)
618132179Sdavidxu    {
619132179Sdavidxu      resume_all = 0;
620132179Sdavidxu      work_ptid = ptid;
621132179Sdavidxu    }
622132179Sdavidxu  else
623132179Sdavidxu    {
624132179Sdavidxu      resume_all = 1;
625132179Sdavidxu      work_ptid = inferior_ptid;
626132179Sdavidxu    }
627132179Sdavidxu
628132179Sdavidxu  lwp = GET_LWP (work_ptid);
629132179Sdavidxu  if (lwp == 0)
630132179Sdavidxu    {
631132179Sdavidxu      /* check user thread */
632132179Sdavidxu      ret = td_ta_map_id2thr_p (thread_agent, GET_THREAD(work_ptid), &th);
633132179Sdavidxu      if (ret)
634132179Sdavidxu        error (thread_db_err_str (ret));
635132179Sdavidxu
636134152Sdavidxu      /* For M:N thread, we need to tell UTS to set/unset single step
637134152Sdavidxu         flag at context switch time, the flag will be written into
638134152Sdavidxu         thread mailbox. This becauses some architecture may not have
639134152Sdavidxu         machine single step flag in ucontext, so we put the flag in mailbox,
640134152Sdavidxu         when the thread switches back, kse_switchin restores the single step
641134152Sdavidxu         state.  */
642132179Sdavidxu      ret = td_thr_sstep_p (&th, step);
643132179Sdavidxu      if (ret)
644132179Sdavidxu        error (thread_db_err_str (ret));
645132179Sdavidxu      ret = td_thr_get_info_p (&th, &ti);
646132179Sdavidxu      if (ret)
647132179Sdavidxu        error (thread_db_err_str (ret));
648132179Sdavidxu      thvalid = 1;
649132179Sdavidxu      lwp = ti.ti_lid;
650132179Sdavidxu    }
651132179Sdavidxu
652132179Sdavidxu  if (lwp)
653132179Sdavidxu    {
654132179Sdavidxu      int req = step ? PT_SETSTEP : PT_CLEARSTEP;
655132179Sdavidxu      if (ptrace (req, (pid_t) lwp, (caddr_t) 1, target_signal_to_host(signo)))
656132179Sdavidxu        perror_with_name ("PT_SETSTEP/PT_CLEARSTEP");
657132179Sdavidxu    }
658132179Sdavidxu
659132179Sdavidxu  if (!ptid_equal (last_single_step_thread, null_ptid))
660132179Sdavidxu    {
661132179Sdavidxu       ret = td_ta_thr_iter_p (thread_agent, resume_thread_callback, NULL,
662132179Sdavidxu          TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
663132179Sdavidxu          TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
664132179Sdavidxu      if (ret != TD_OK)
665132179Sdavidxu        error ("resume error: %s", thread_db_err_str (ret));
666132179Sdavidxu    }
667132179Sdavidxu
668132179Sdavidxu  if (!resume_all)
669132179Sdavidxu    {
670132179Sdavidxu      ret = td_ta_thr_iter_p (thread_agent, suspend_thread_callback, NULL,
671132179Sdavidxu          TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
672132179Sdavidxu          TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
673132179Sdavidxu      if (ret != TD_OK)
674132179Sdavidxu        error ("suspend error: %s", thread_db_err_str (ret));
675132179Sdavidxu      last_single_step_thread = work_ptid;
676132179Sdavidxu    }
677132179Sdavidxu  else
678132179Sdavidxu    last_single_step_thread = null_ptid;
679132179Sdavidxu
680132179Sdavidxu  if (thvalid)
681132179Sdavidxu    {
682132179Sdavidxu      ret = td_thr_dbresume_p (&th);
683132179Sdavidxu      if (ret != TD_OK)
684132179Sdavidxu        error ("resume error: %s", thread_db_err_str (ret));
685132179Sdavidxu    }
686132179Sdavidxu  else
687132179Sdavidxu    {
688132179Sdavidxu      /* it is not necessary, put it here for completness */
689132179Sdavidxu      ret = ptrace(PT_RESUME, lwp, 0, 0);
690132179Sdavidxu    }
691132179Sdavidxu
692132179Sdavidxu  /* now continue the process, suspended thread wont run */
693132179Sdavidxu  if (ptrace (PT_CONTINUE, proc_handle.pid , (caddr_t)1,
694132179Sdavidxu	      target_signal_to_host(signo)))
695132179Sdavidxu    perror_with_name ("PT_CONTINUE");
696132179Sdavidxu}
697132179Sdavidxu
698144923Sdavidxustatic void
699144923Sdavidxuattach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
700144923Sdavidxu               const td_thrinfo_t *ti_p, int verbose)
701144923Sdavidxu{
702144923Sdavidxu  td_err_e err;
703144923Sdavidxu
704144923Sdavidxu  /* Add the thread to GDB's thread list.  */
705144923Sdavidxu  if (!in_thread_list (ptid)) {
706144923Sdavidxu    add_thread (ptid);
707144923Sdavidxu    if (verbose)
708144923Sdavidxu      printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid));
709144923Sdavidxu  }
710144923Sdavidxu
711144923Sdavidxu  if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
712144923Sdavidxu    return;                     /* A zombie thread -- do not attach.  */
713144923Sdavidxu
714144923Sdavidxu  if (! IS_THREAD(ptid))
715144923Sdavidxu    return;
716145960Sdavidxu  if (fbsd_thread_core != 0)
717145960Sdavidxu    return;
718144923Sdavidxu  /* Enable thread event reporting for this thread. */
719144923Sdavidxu  err = td_thr_event_enable_p (th_p, 1);
720144923Sdavidxu  if (err != TD_OK)
721144923Sdavidxu    error ("Cannot enable thread event reporting for %s: %s",
722144923Sdavidxu           target_pid_to_str (ptid), thread_db_err_str (err));
723144923Sdavidxu}
724144923Sdavidxu
725144923Sdavidxustatic void
726144923Sdavidxudetach_thread (ptid_t ptid, int verbose)
727144923Sdavidxu{
728144923Sdavidxu  if (verbose)
729144923Sdavidxu    printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid));
730144923Sdavidxu}
731144923Sdavidxu
732144923Sdavidxustatic void
733144923Sdavidxucheck_event (ptid_t ptid)
734144923Sdavidxu{
735144923Sdavidxu  td_event_msg_t msg;
736144923Sdavidxu  td_thrinfo_t ti;
737144923Sdavidxu  td_err_e err;
738144923Sdavidxu  CORE_ADDR stop_pc;
739144923Sdavidxu  int loop = 0;
740144923Sdavidxu
741144923Sdavidxu  /* Bail out early if we're not at a thread event breakpoint.  */
742144923Sdavidxu  stop_pc = read_pc_pid (ptid) - DECR_PC_AFTER_BREAK;
743144923Sdavidxu  if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
744144923Sdavidxu    return;
745144923Sdavidxu  loop = 1;
746144923Sdavidxu
747144923Sdavidxu  do
748144923Sdavidxu    {
749144923Sdavidxu      err = td_ta_event_getmsg_p (thread_agent, &msg);
750144923Sdavidxu      if (err != TD_OK)
751144923Sdavidxu        {
752144923Sdavidxu	  if (err == TD_NOMSG)
753144923Sdavidxu	    return;
754144923Sdavidxu          error ("Cannot get thread event message: %s",
755144923Sdavidxu		 thread_db_err_str (err));
756144923Sdavidxu        }
757183023Smarcel      err = td_thr_get_info_p ((void *)(uintptr_t)msg.th_p, &ti);
758144923Sdavidxu      if (err != TD_OK)
759144923Sdavidxu        error ("Cannot get thread info: %s", thread_db_err_str (err));
760144923Sdavidxu      ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
761144923Sdavidxu      switch (msg.event)
762144923Sdavidxu        {
763144923Sdavidxu        case TD_CREATE:
764144923Sdavidxu          /* We may already know about this thread, for instance when the
765144923Sdavidxu             user has issued the `info threads' command before the SIGTRAP
766144923Sdavidxu             for hitting the thread creation breakpoint was reported.  */
767183023Smarcel          attach_thread (ptid, (void *)(uintptr_t)msg.th_p, &ti, 1);
768144923Sdavidxu          break;
769144923Sdavidxu       case TD_DEATH:
770144923Sdavidxu         if (!in_thread_list (ptid))
771144923Sdavidxu           error ("Spurious thread death event.");
772144923Sdavidxu         detach_thread (ptid, 1);
773144923Sdavidxu         break;
774144923Sdavidxu       default:
775144923Sdavidxu          error ("Spurious thread event.");
776144923Sdavidxu       }
777144923Sdavidxu    }
778144923Sdavidxu  while (loop);
779144923Sdavidxu}
780144923Sdavidxu
781132179Sdavidxustatic ptid_t
782132179Sdavidxufbsd_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
783132179Sdavidxu{
784132179Sdavidxu  ptid_t ret;
785132179Sdavidxu  long lwp;
786132179Sdavidxu  CORE_ADDR stop_pc;
787144923Sdavidxu  td_thrhandle_t th;
788144923Sdavidxu  td_thrinfo_t ti;
789132179Sdavidxu
790132179Sdavidxu  ret = child_ops.to_wait (ptid, ourstatus);
791132179Sdavidxu  if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED)
792132179Sdavidxu    {
793134147Sdavidxu      lwp = get_current_lwp (GET_PID(ret));
794144923Sdavidxu      ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)),
795144923Sdavidxu         &th, &ti);
796144923Sdavidxu      if (!in_thread_list(ret)) {
797144923Sdavidxu        /*
798144923Sdavidxu         * We have to enable event reporting for initial thread
799144923Sdavidxu         * which was not mapped before.
800144923Sdavidxu	 */
801144923Sdavidxu        attach_thread(ret, &th, &ti, 1);
802144923Sdavidxu      }
803144923Sdavidxu      if (ourstatus->value.sig == TARGET_SIGNAL_TRAP)
804144923Sdavidxu        check_event(ret);
805133345Sdavidxu      /* this is a hack, if an event won't cause gdb to stop, for example,
806133345Sdavidxu         SIGARLM, gdb resumes the process immediatly without setting
807133345Sdavidxu         inferior_ptid to the new thread returned here, this is a bug
808133345Sdavidxu         because inferior_ptid may already not exist there, and passing
809133345Sdavidxu         a none existing thread to fbsd_thread_resume causes error. */
810133345Sdavidxu      if (!fbsd_thread_alive (inferior_ptid))
811133345Sdavidxu        {
812133345Sdavidxu          delete_thread (inferior_ptid);
813133345Sdavidxu          inferior_ptid = ret;
814144923Sdavidxu        }
815132179Sdavidxu    }
816132179Sdavidxu
817132179Sdavidxu  return (ret);
818132179Sdavidxu}
819132179Sdavidxu
820132179Sdavidxustatic int
821132179Sdavidxufbsd_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
822132179Sdavidxu                        struct mem_attrib *attrib, struct target_ops *target)
823132179Sdavidxu{
824134147Sdavidxu  int err;
825134147Sdavidxu
826134147Sdavidxu  if (target_has_execution)
827134147Sdavidxu    err = child_ops.to_xfer_memory (memaddr, myaddr, len, write, attrib,
828134147Sdavidxu	target);
829134147Sdavidxu  else
830134147Sdavidxu    err = orig_core_ops.to_xfer_memory (memaddr, myaddr, len, write, attrib,
831134147Sdavidxu	target);
832134147Sdavidxu
833134147Sdavidxu  return (err);
834132179Sdavidxu}
835132179Sdavidxu
836132179Sdavidxustatic void
837132179Sdavidxufbsd_lwp_fetch_registers (int regno)
838132179Sdavidxu{
839132179Sdavidxu  gregset_t gregs;
840132179Sdavidxu  fpregset_t fpregs;
841132179Sdavidxu  lwpid_t lwp;
842146818Sdfr#ifdef PT_GETXMMREGS
843146818Sdfr  char xmmregs[512];
844146818Sdfr#endif
845132179Sdavidxu
846134147Sdavidxu  if (!target_has_execution)
847134147Sdavidxu    {
848134147Sdavidxu      orig_core_ops.to_fetch_registers (-1);
849134147Sdavidxu      return;
850134147Sdavidxu    }
851134147Sdavidxu
852140071Speadar  /* XXX: We've replaced the pid with the lwpid for GDB's benefit. */
853140071Speadar  lwp = GET_PID (inferior_ptid);
854132179Sdavidxu
855132179Sdavidxu  if (ptrace (PT_GETREGS, lwp, (caddr_t) &gregs, 0) == -1)
856132179Sdavidxu    error ("Cannot get lwp %d registers: %s\n", lwp, safe_strerror (errno));
857132179Sdavidxu  supply_gregset (&gregs);
858132179Sdavidxu
859146818Sdfr#ifdef PT_GETXMMREGS
860146818Sdfr  if (ptrace (PT_GETXMMREGS, lwp, xmmregs, 0) == 0)
861146818Sdfr    {
862146818Sdfr      i387_supply_fxsave (current_regcache, -1, xmmregs);
863146818Sdfr    }
864146818Sdfr  else
865146818Sdfr    {
866146818Sdfr#endif
867146818Sdfr      if (ptrace (PT_GETFPREGS, lwp, (caddr_t) &fpregs, 0) == -1)
868146818Sdfr	error ("Cannot get lwp %d registers: %s\n ", lwp, safe_strerror (errno));
869146818Sdfr      supply_fpregset (&fpregs);
870146818Sdfr#ifdef PT_GETXMMREGS
871146818Sdfr    }
872146818Sdfr#endif
873132179Sdavidxu}
874132179Sdavidxu
875132179Sdavidxustatic void
876132179Sdavidxufbsd_thread_fetch_registers (int regno)
877132179Sdavidxu{
878132179Sdavidxu  prgregset_t gregset;
879132179Sdavidxu  prfpregset_t fpregset;
880132179Sdavidxu  td_thrhandle_t th;
881132179Sdavidxu  td_err_e err;
882146818Sdfr#ifdef PT_GETXMMREGS
883146818Sdfr  char xmmregs[512];
884146818Sdfr#endif
885132179Sdavidxu
886132179Sdavidxu  if (!IS_THREAD (inferior_ptid))
887132179Sdavidxu    {
888132179Sdavidxu      fbsd_lwp_fetch_registers (regno);
889132179Sdavidxu      return;
890132179Sdavidxu    }
891132179Sdavidxu
892132179Sdavidxu  err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (inferior_ptid), &th);
893132179Sdavidxu  if (err != TD_OK)
894132179Sdavidxu    error ("Cannot find thread %d: Thread ID=%ld, %s",
895132179Sdavidxu           pid_to_thread_id (inferior_ptid),
896132179Sdavidxu           GET_THREAD (inferior_ptid), thread_db_err_str (err));
897132179Sdavidxu
898132179Sdavidxu  err = td_thr_getgregs_p (&th, gregset);
899132179Sdavidxu  if (err != TD_OK)
900132179Sdavidxu    error ("Cannot fetch general-purpose registers for thread %d: Thread ID=%ld, %s",
901132179Sdavidxu           pid_to_thread_id (inferior_ptid),
902132179Sdavidxu           GET_THREAD (inferior_ptid), thread_db_err_str (err));
903146818Sdfr#ifdef PT_GETXMMREGS
904146818Sdfr  err = td_thr_getxmmregs_p (&th, xmmregs);
905146818Sdfr  if (err == TD_OK)
906146818Sdfr    {
907146818Sdfr      i387_supply_fxsave (current_regcache, -1, xmmregs);
908146818Sdfr    }
909146818Sdfr  else
910146818Sdfr    {
911146818Sdfr#endif
912146818Sdfr      err = td_thr_getfpregs_p (&th, &fpregset);
913146818Sdfr      if (err != TD_OK)
914146818Sdfr	error ("Cannot get floating-point registers for thread %d: Thread ID=%ld, %s",
915146818Sdfr	       pid_to_thread_id (inferior_ptid),
916146818Sdfr	       GET_THREAD (inferior_ptid), thread_db_err_str (err));
917146818Sdfr      supply_fpregset (&fpregset);
918146818Sdfr#ifdef PT_GETXMMREGS
919146818Sdfr    }
920146818Sdfr#endif
921132179Sdavidxu
922132179Sdavidxu  supply_gregset (gregset);
923132179Sdavidxu}
924132179Sdavidxu
925132179Sdavidxustatic void
926132179Sdavidxufbsd_lwp_store_registers (int regno)
927132179Sdavidxu{
928132179Sdavidxu  gregset_t gregs;
929132179Sdavidxu  fpregset_t fpregs;
930132179Sdavidxu  lwpid_t lwp;
931146818Sdfr#ifdef PT_GETXMMREGS
932146818Sdfr  char xmmregs[512];
933146818Sdfr#endif
934132179Sdavidxu
935132179Sdavidxu  /* FIXME, is it possible ? */
936132179Sdavidxu  if (!IS_LWP (inferior_ptid))
937132179Sdavidxu    {
938132179Sdavidxu      child_ops.to_store_registers (regno);
939132179Sdavidxu      return ;
940132179Sdavidxu    }
941132179Sdavidxu
942132179Sdavidxu  lwp = GET_LWP (inferior_ptid);
943132179Sdavidxu  if (regno != -1)
944132179Sdavidxu    if (ptrace (PT_GETREGS, lwp, (caddr_t) &gregs, 0) == -1)
945132179Sdavidxu      error ("Cannot get lwp %d registers: %s\n", lwp, safe_strerror (errno));
946132179Sdavidxu
947132179Sdavidxu  fill_gregset (&gregs, regno);
948132179Sdavidxu  if (ptrace (PT_SETREGS, lwp, (caddr_t) &gregs, 0) == -1)
949132179Sdavidxu      error ("Cannot set lwp %d registers: %s\n", lwp, safe_strerror (errno));
950132179Sdavidxu
951146818Sdfr#ifdef PT_GETXMMREGS
952132179Sdavidxu  if (regno != -1)
953146818Sdfr    if (ptrace (PT_GETXMMREGS, lwp, xmmregs, 0) == -1)
954146818Sdfr      goto noxmm;
955146818Sdfr
956146818Sdfr  i387_fill_fxsave (xmmregs, regno);
957146818Sdfr  if (ptrace (PT_SETXMMREGS, lwp, xmmregs, 0) == -1)
958146818Sdfr    goto noxmm;
959146818Sdfr
960146818Sdfr  return;
961146818Sdfr
962146818Sdfrnoxmm:
963146818Sdfr#endif
964146818Sdfr
965146818Sdfr  if (regno != -1)
966132179Sdavidxu    if (ptrace (PT_GETFPREGS, lwp, (caddr_t) &fpregs, 0) == -1)
967132179Sdavidxu      error ("Cannot get lwp %d float registers: %s\n", lwp,
968132179Sdavidxu             safe_strerror (errno));
969132179Sdavidxu
970132179Sdavidxu  fill_fpregset (&fpregs, regno);
971132179Sdavidxu  if (ptrace (PT_SETFPREGS, lwp, (caddr_t) &fpregs, 0) == -1)
972132179Sdavidxu     error ("Cannot set lwp %d float registers: %s\n", lwp,
973132179Sdavidxu            safe_strerror (errno));
974132179Sdavidxu}
975132179Sdavidxu
976132179Sdavidxustatic void
977132179Sdavidxufbsd_thread_store_registers (int regno)
978132179Sdavidxu{
979132179Sdavidxu  prgregset_t gregset;
980132179Sdavidxu  prfpregset_t fpregset;
981132179Sdavidxu  td_thrhandle_t th;
982132179Sdavidxu  td_err_e err;
983146818Sdfr#ifdef PT_GETXMMREGS
984146818Sdfr  char xmmregs[512];
985146818Sdfr#endif
986132179Sdavidxu
987132179Sdavidxu  if (!IS_THREAD (inferior_ptid))
988132179Sdavidxu    {
989132179Sdavidxu      fbsd_lwp_store_registers (regno);
990132179Sdavidxu      return;
991132179Sdavidxu    }
992132179Sdavidxu
993132179Sdavidxu  err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (inferior_ptid), &th);
994132179Sdavidxu  if (err != TD_OK)
995132179Sdavidxu    error ("Cannot find thread %d: Thread ID=%ld, %s",
996132179Sdavidxu           pid_to_thread_id (inferior_ptid),
997132179Sdavidxu           GET_THREAD (inferior_ptid),
998132179Sdavidxu           thread_db_err_str (err));
999132179Sdavidxu
1000132179Sdavidxu  if (regno != -1)
1001132179Sdavidxu    {
1002132179Sdavidxu      char old_value[MAX_REGISTER_SIZE];
1003132179Sdavidxu
1004132179Sdavidxu      regcache_collect (regno, old_value);
1005132179Sdavidxu      err = td_thr_getgregs_p (&th, gregset);
1006132179Sdavidxu      if (err != TD_OK)
1007132179Sdavidxu        error ("%s: td_thr_getgregs %s", __func__, thread_db_err_str (err));
1008166851Semaste#ifdef PT_GETXMMREGS
1009166851Semaste      err = td_thr_getxmmregs_p (&th, xmmregs);
1010132179Sdavidxu      if (err != TD_OK)
1011166851Semaste        {
1012166851Semaste#endif
1013166851Semaste          err = td_thr_getfpregs_p (&th, &fpregset);
1014166851Semaste          if (err != TD_OK)
1015166851Semaste            error ("%s: td_thr_getfpgregs %s", __func__, thread_db_err_str (err));
1016166851Semaste#ifdef PT_GETXMMREGS
1017166851Semaste        }
1018166851Semaste#endif
1019132179Sdavidxu      supply_register (regno, old_value);
1020132179Sdavidxu    }
1021132179Sdavidxu
1022132179Sdavidxu  fill_gregset (gregset, regno);
1023132179Sdavidxu  err = td_thr_setgregs_p (&th, gregset);
1024132179Sdavidxu  if (err != TD_OK)
1025132179Sdavidxu    error ("Cannot store general-purpose registers for thread %d: Thread ID=%d, %s",
1026132179Sdavidxu           pid_to_thread_id (inferior_ptid), GET_THREAD (inferior_ptid),
1027132179Sdavidxu           thread_db_err_str (err));
1028146818Sdfr
1029146818Sdfr#ifdef PT_GETXMMREGS
1030166851Semaste  i387_fill_fxsave (xmmregs, regno);
1031146818Sdfr  err = td_thr_setxmmregs_p (&th, xmmregs);
1032146818Sdfr  if (err == TD_OK)
1033146818Sdfr    return;
1034146818Sdfr#endif
1035146818Sdfr
1036166851Semaste  fill_fpregset (&fpregset, regno);
1037132179Sdavidxu  err = td_thr_setfpregs_p (&th, &fpregset);
1038132179Sdavidxu  if (err != TD_OK)
1039132179Sdavidxu    error ("Cannot store floating-point registers for thread %d: Thread ID=%d, %s",
1040132179Sdavidxu           pid_to_thread_id (inferior_ptid), GET_THREAD (inferior_ptid),
1041132179Sdavidxu           thread_db_err_str (err));
1042132179Sdavidxu}
1043132179Sdavidxu
1044132179Sdavidxustatic void
1045132179Sdavidxufbsd_thread_kill (void)
1046132179Sdavidxu{
1047132179Sdavidxu  child_ops.to_kill();
1048132179Sdavidxu}
1049132179Sdavidxu
1050134147Sdavidxustatic int
1051134147Sdavidxufbsd_thread_can_run (void)
1052134147Sdavidxu{
1053134147Sdavidxu  return child_suppress_run;
1054134147Sdavidxu}
1055134147Sdavidxu
1056132179Sdavidxustatic void
1057132179Sdavidxufbsd_thread_create_inferior (char *exec_file, char *allargs, char **env)
1058132179Sdavidxu{
1059134147Sdavidxu  if (fbsd_thread_present && !fbsd_thread_active)
1060134147Sdavidxu    push_target(&fbsd_thread_ops);
1061132179Sdavidxu
1062132179Sdavidxu  child_ops.to_create_inferior (exec_file, allargs, env);
1063132179Sdavidxu}
1064132179Sdavidxu
1065132179Sdavidxustatic void
1066132179Sdavidxufbsd_thread_post_startup_inferior (ptid_t ptid)
1067132179Sdavidxu{
1068134147Sdavidxu  if (fbsd_thread_present && !fbsd_thread_active)
1069132179Sdavidxu    {
1070134152Sdavidxu      /* The child process is now the actual multi-threaded
1071134152Sdavidxu         program.  Snatch its process ID... */
1072132179Sdavidxu      proc_handle.pid = GET_PID (ptid);
1073134147Sdavidxu      td_ta_new_p (&proc_handle, &thread_agent);
1074134147Sdavidxu      fbsd_thread_activate();
1075132179Sdavidxu    }
1076132179Sdavidxu}
1077132179Sdavidxu
1078132179Sdavidxustatic void
1079132179Sdavidxufbsd_thread_mourn_inferior (void)
1080132179Sdavidxu{
1081134147Sdavidxu  if (fbsd_thread_active)
1082134147Sdavidxu    fbsd_thread_deactivate ();
1083132179Sdavidxu
1084134147Sdavidxu  unpush_target (&fbsd_thread_ops);
1085134147Sdavidxu
1086132179Sdavidxu  child_ops.to_mourn_inferior ();
1087132179Sdavidxu}
1088132179Sdavidxu
1089134147Sdavidxustatic void
1090134147Sdavidxufbsd_core_check_lwp (bfd *abfd, asection *asect, void *obj)
1091134147Sdavidxu{
1092134147Sdavidxu  lwpid_t lwp;
1093134147Sdavidxu
1094134147Sdavidxu  if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0)
1095134147Sdavidxu    return;
1096134147Sdavidxu
1097134147Sdavidxu  /* already found */
1098134147Sdavidxu  if (*(lwpid_t *)obj == 0)
1099134147Sdavidxu    return;
1100134147Sdavidxu
1101134147Sdavidxu  lwp = atoi (bfd_section_name (abfd, asect) + 5);
1102134147Sdavidxu  if (*(lwpid_t *)obj == lwp)
1103134147Sdavidxu    *(lwpid_t *)obj = 0;
1104134147Sdavidxu}
1105134147Sdavidxu
1106132179Sdavidxustatic int
1107132179Sdavidxufbsd_thread_alive (ptid_t ptid)
1108132179Sdavidxu{
1109132179Sdavidxu  td_thrhandle_t th;
1110132179Sdavidxu  td_thrinfo_t ti;
1111132179Sdavidxu  td_err_e err;
1112132179Sdavidxu  gregset_t gregs;
1113134147Sdavidxu  lwpid_t lwp;
1114132179Sdavidxu
1115132179Sdavidxu  if (IS_THREAD (ptid))
1116132179Sdavidxu    {
1117132179Sdavidxu      err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (ptid), &th);
1118132179Sdavidxu      if (err != TD_OK)
1119132179Sdavidxu        return 0;
1120132179Sdavidxu
1121132179Sdavidxu      err = td_thr_get_info_p (&th, &ti);
1122132179Sdavidxu      if (err != TD_OK)
1123132179Sdavidxu        return 0;
1124132179Sdavidxu
1125132179Sdavidxu      /* A zombie thread. */
1126132179Sdavidxu      if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
1127132179Sdavidxu        return 0;
1128132179Sdavidxu
1129132179Sdavidxu      return 1;
1130132179Sdavidxu    }
1131132179Sdavidxu  else if (GET_LWP (ptid) == 0)
1132132179Sdavidxu    {
1133132179Sdavidxu      /* we sometimes are called with lwp == 0 */
1134132179Sdavidxu      return 1;
1135132179Sdavidxu    }
1136132179Sdavidxu
1137134147Sdavidxu  if (fbsd_thread_active)
1138134147Sdavidxu    {
1139134147Sdavidxu      err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
1140132179Sdavidxu
1141134147Sdavidxu      /*
1142134147Sdavidxu       * if the lwp was already mapped to user thread, don't use it
1143134147Sdavidxu       * directly, please use user thread id instead.
1144134147Sdavidxu       */
1145134147Sdavidxu      if (err == TD_OK)
1146134147Sdavidxu        return 0;
1147134147Sdavidxu    }
1148132179Sdavidxu
1149134147Sdavidxu  if (!target_has_execution)
1150134147Sdavidxu    {
1151134147Sdavidxu      lwp = GET_LWP (ptid);
1152134147Sdavidxu      bfd_map_over_sections (core_bfd, fbsd_core_check_lwp, &lwp);
1153134147Sdavidxu      return (lwp == 0);
1154134147Sdavidxu    }
1155134147Sdavidxu
1156132179Sdavidxu  /* check lwp in kernel */
1157132179Sdavidxu  return ptrace (PT_GETREGS, GET_LWP (ptid), (caddr_t)&gregs, 0) == 0;
1158132179Sdavidxu}
1159132179Sdavidxu
1160134147Sdavidxustatic void
1161134147Sdavidxufbsd_thread_files_info (struct target_ops *ignore)
1162134147Sdavidxu{
1163134147Sdavidxu  child_ops.to_files_info (ignore);
1164134147Sdavidxu}
1165134147Sdavidxu
1166132179Sdavidxustatic int
1167132179Sdavidxufind_new_threads_callback (const td_thrhandle_t *th_p, void *data)
1168132179Sdavidxu{
1169132179Sdavidxu  td_thrinfo_t ti;
1170132179Sdavidxu  td_err_e err;
1171132179Sdavidxu  ptid_t ptid;
1172132179Sdavidxu
1173132179Sdavidxu  err = td_thr_get_info_p (th_p, &ti);
1174132179Sdavidxu  if (err != TD_OK)
1175132179Sdavidxu    error ("Cannot get thread info: %s", thread_db_err_str (err));
1176132179Sdavidxu
1177132179Sdavidxu  /* Ignore zombie */
1178132179Sdavidxu  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
1179132179Sdavidxu    return 0;
1180132179Sdavidxu
1181134147Sdavidxu  ptid = BUILD_THREAD (ti.ti_tid, proc_handle.pid);
1182144923Sdavidxu  attach_thread (ptid, th_p, &ti, 1);
1183132179Sdavidxu  return 0;
1184132179Sdavidxu}
1185132179Sdavidxu
1186132179Sdavidxustatic void
1187132179Sdavidxufbsd_thread_find_new_threads (void)
1188132179Sdavidxu{
1189132179Sdavidxu  td_err_e err;
1190132179Sdavidxu
1191134147Sdavidxu  if (!fbsd_thread_active)
1192134147Sdavidxu    return;
1193134147Sdavidxu
1194132179Sdavidxu  /* Iterate over all user-space threads to discover new threads. */
1195132179Sdavidxu  err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL,
1196132179Sdavidxu          TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
1197132179Sdavidxu          TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
1198132179Sdavidxu  if (err != TD_OK)
1199132179Sdavidxu    error ("Cannot find new threads: %s", thread_db_err_str (err));
1200132179Sdavidxu}
1201132179Sdavidxu
1202132179Sdavidxustatic char *
1203132179Sdavidxufbsd_thread_pid_to_str (ptid_t ptid)
1204132179Sdavidxu{
1205215679Sattilio  static char buf[64 + MAXCOMLEN];
1206132179Sdavidxu
1207132179Sdavidxu  if (IS_THREAD (ptid))
1208132179Sdavidxu    {
1209132179Sdavidxu      td_thrhandle_t th;
1210132179Sdavidxu      td_thrinfo_t ti;
1211132179Sdavidxu      td_err_e err;
1212132179Sdavidxu
1213132179Sdavidxu      err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (ptid), &th);
1214132179Sdavidxu      if (err != TD_OK)
1215132179Sdavidxu        error ("Cannot find thread, Thread ID=%ld, %s",
1216132179Sdavidxu                GET_THREAD (ptid), thread_db_err_str (err));
1217132179Sdavidxu
1218132179Sdavidxu      err = td_thr_get_info_p (&th, &ti);
1219132179Sdavidxu      if (err != TD_OK)
1220132179Sdavidxu        error ("Cannot get thread info, Thread ID=%ld, %s",
1221132179Sdavidxu               GET_THREAD (ptid), thread_db_err_str (err));
1222132179Sdavidxu
1223132179Sdavidxu      if (ti.ti_lid != 0)
1224132179Sdavidxu        {
1225215679Sattilio          snprintf (buf, sizeof (buf), "Thread %llx (LWP %d/%s)",
1226215679Sattilio                    (unsigned long long)th.th_thread, ti.ti_lid,
1227215679Sattilio                    fbsd_thread_get_name (ti.ti_lid));
1228132179Sdavidxu        }
1229132179Sdavidxu      else
1230132179Sdavidxu        {
1231183023Smarcel          snprintf (buf, sizeof (buf), "Thread %llx (%s)",
1232183023Smarcel		    (unsigned long long)th.th_thread,
1233183023Smarcel		    thread_db_state_str (ti.ti_state));
1234132179Sdavidxu        }
1235132179Sdavidxu
1236132179Sdavidxu      return buf;
1237132179Sdavidxu    }
1238132179Sdavidxu  else if (IS_LWP (ptid))
1239132179Sdavidxu    {
1240132179Sdavidxu      snprintf (buf, sizeof (buf), "LWP %d", (int) GET_LWP (ptid));
1241132179Sdavidxu      return buf;
1242132179Sdavidxu    }
1243132179Sdavidxu  return normal_pid_to_str (ptid);
1244132179Sdavidxu}
1245132179Sdavidxu
1246133345SdavidxuCORE_ADDR
1247133345Sdavidxufbsd_thread_get_local_address(ptid_t ptid, struct objfile *objfile,
1248133345Sdavidxu                              CORE_ADDR offset)
1249133345Sdavidxu{
1250133345Sdavidxu  td_thrhandle_t th;
1251133345Sdavidxu  void *address;
1252133345Sdavidxu  CORE_ADDR lm;
1253155379Sdavidxu  void *lm2;
1254133345Sdavidxu  int ret, is_library = (objfile->flags & OBJF_SHARED);
1255133345Sdavidxu
1256133345Sdavidxu  if (IS_THREAD (ptid))
1257133345Sdavidxu    {
1258133345Sdavidxu      if (!td_thr_tls_get_addr_p)
1259133345Sdavidxu        error ("Cannot find thread-local interface in thread_db library.");
1260133345Sdavidxu
1261133345Sdavidxu      /* Get the address of the link map for this objfile. */
1262133345Sdavidxu      lm = svr4_fetch_objfile_link_map (objfile);
1263133345Sdavidxu
1264133345Sdavidxu      /* Couldn't find link map. Bail out. */
1265133345Sdavidxu      if (!lm)
1266133345Sdavidxu        {
1267133345Sdavidxu          if (is_library)
1268133345Sdavidxu            error ("Cannot find shared library `%s' link_map in dynamic"
1269133345Sdavidxu                   " linker's module list", objfile->name);
1270133345Sdavidxu          else
1271133345Sdavidxu            error ("Cannot find executable file `%s' link_map in dynamic"
1272133345Sdavidxu                   " linker's module list", objfile->name);
1273133345Sdavidxu        }
1274133345Sdavidxu
1275133345Sdavidxu      ret = td_ta_map_id2thr_p (thread_agent, GET_THREAD(ptid), &th);
1276133345Sdavidxu
1277133345Sdavidxu      /* get the address of the variable. */
1278155379Sdavidxu      store_typed_address(&lm2, builtin_type_void_data_ptr, lm);
1279155379Sdavidxu      ret = td_thr_tls_get_addr_p (&th, lm2, offset, &address);
1280133345Sdavidxu
1281133345Sdavidxu      if (ret != TD_OK)
1282133345Sdavidxu        {
1283133345Sdavidxu          if (is_library)
1284133345Sdavidxu            error ("Cannot find thread-local storage for thread %ld, "
1285133345Sdavidxu                   "shared library %s:\n%s",
1286133345Sdavidxu                   (long) GET_THREAD (ptid),
1287133345Sdavidxu                   objfile->name, thread_db_err_str (ret));
1288133345Sdavidxu          else
1289133345Sdavidxu            error ("Cannot find thread-local storage for thread %ld, "
1290133345Sdavidxu                   "executable file %s:\n%s",
1291133345Sdavidxu                   (long) GET_THREAD (ptid),
1292133345Sdavidxu                   objfile->name, thread_db_err_str (ret));
1293133345Sdavidxu        }
1294133345Sdavidxu
1295133345Sdavidxu      /* Cast assuming host == target. */
1296155379Sdavidxu      return extract_typed_address(&address, builtin_type_void_data_ptr);
1297133345Sdavidxu    }
1298133345Sdavidxu  return (0);
1299133345Sdavidxu}
1300133345Sdavidxu
1301132179Sdavidxustatic int
1302132179Sdavidxutsd_cb (thread_key_t key, void (*destructor)(void *), void *ignore)
1303132179Sdavidxu{
1304132179Sdavidxu  struct minimal_symbol *ms;
1305132179Sdavidxu  char *name;
1306132179Sdavidxu
1307155379Sdavidxu  ms = lookup_minimal_symbol_by_pc (
1308155379Sdavidxu	extract_typed_address(&destructor, builtin_type_void_func_ptr));
1309132179Sdavidxu  if (!ms)
1310132179Sdavidxu    name = "???";
1311132179Sdavidxu  else
1312132179Sdavidxu    name = DEPRECATED_SYMBOL_NAME (ms);
1313132179Sdavidxu
1314235714Sdavidxu  printf_filtered ("Key %d, destructor %p <%s>\n", key, destructor, name);
1315132179Sdavidxu  return 0;
1316132179Sdavidxu}
1317132179Sdavidxu
1318132179Sdavidxustatic void
1319132179Sdavidxufbsd_thread_tsd_cmd (char *exp, int from_tty)
1320132179Sdavidxu{
1321134147Sdavidxu  if (fbsd_thread_active)
1322134147Sdavidxu    td_ta_tsd_iter_p (thread_agent, tsd_cb, NULL);
1323132179Sdavidxu}
1324132179Sdavidxu
1325155379Sdavidxustatic void
1326155379Sdavidxufbsd_print_sigset (sigset_t *set)
1327155379Sdavidxu{
1328155379Sdavidxu  int i;
1329155379Sdavidxu
1330155379Sdavidxu  for (i = 1; i <= _SIG_MAXSIG; ++i) {
1331155379Sdavidxu     if (sigismember(set, i)) {
1332155379Sdavidxu       if (i < sizeof(sys_signame)/sizeof(sys_signame[0]))
1333155379Sdavidxu         printf_filtered("%s ", sys_signame[i]);
1334155379Sdavidxu       else
1335155379Sdavidxu         printf_filtered("sig%d ", i);
1336155379Sdavidxu     }
1337155379Sdavidxu  }
1338155379Sdavidxu  printf_filtered("\n");
1339155379Sdavidxu}
1340155379Sdavidxu
1341155379Sdavidxustatic void
1342155379Sdavidxufbsd_thread_signal_cmd (char *exp, int from_tty)
1343155379Sdavidxu{
1344155379Sdavidxu  td_thrhandle_t th;
1345155379Sdavidxu  td_thrinfo_t ti;
1346155379Sdavidxu  td_err_e err;
1347209690Skib  const char *code;
1348155379Sdavidxu
1349155379Sdavidxu  if (!fbsd_thread_active || !IS_THREAD(inferior_ptid))
1350155379Sdavidxu    return;
1351155379Sdavidxu
1352155379Sdavidxu  err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (inferior_ptid), &th);
1353155379Sdavidxu  if (err != TD_OK)
1354155379Sdavidxu    return;
1355155379Sdavidxu
1356155379Sdavidxu  err = td_thr_get_info_p (&th, &ti);
1357155379Sdavidxu  if (err != TD_OK)
1358155379Sdavidxu    return;
1359155379Sdavidxu
1360155379Sdavidxu  printf_filtered("signal mask:\n");
1361155379Sdavidxu  fbsd_print_sigset(&ti.ti_sigmask);
1362155379Sdavidxu  printf_filtered("signal pending:\n");
1363155379Sdavidxu  fbsd_print_sigset(&ti.ti_pending);
1364209690Skib  if (ti.ti_siginfo.si_signo != 0) {
1365209690Skib   printf_filtered("si_signo %d si_errno %d", ti.ti_siginfo.si_signo,
1366209690Skib     ti.ti_siginfo.si_errno);
1367209690Skib   if (ti.ti_siginfo.si_errno != 0)
1368209690Skib    printf_filtered(" (%s)", strerror(ti.ti_siginfo.si_errno));
1369209690Skib   printf_filtered("\n");
1370209690Skib   switch (ti.ti_siginfo.si_code) {
1371209690Skib   case SI_NOINFO:
1372209690Skib	code = "NOINFO";
1373209690Skib	break;
1374209690Skib    case SI_USER:
1375209690Skib	code = "USER";
1376209690Skib	break;
1377209690Skib    case SI_QUEUE:
1378209690Skib	code = "QUEUE";
1379209690Skib	break;
1380209690Skib    case SI_TIMER:
1381209690Skib	code = "TIMER";
1382209690Skib	break;
1383209690Skib    case SI_ASYNCIO:
1384209690Skib	code = "ASYNCIO";
1385209690Skib	break;
1386209690Skib    case SI_MESGQ:
1387209690Skib	code = "MESGQ";
1388209690Skib	break;
1389209690Skib    case SI_KERNEL:
1390209690Skib	code = "KERNEL";
1391209690Skib	break;
1392209690Skib    default:
1393209690Skib	code = "UNKNOWN";
1394209690Skib	break;
1395209690Skib    }
1396220043Skib    printf_filtered("si_code %s (%d) si_pid %d si_uid %d si_status %x "
1397220043Skib      "si_addr %p\n",
1398220043Skib      code, ti.ti_siginfo.si_code, ti.ti_siginfo.si_pid, ti.ti_siginfo.si_uid,
1399220043Skib      ti.ti_siginfo.si_status, ti.ti_siginfo.si_addr);
1400209690Skib  }
1401155379Sdavidxu}
1402155379Sdavidxu
1403134147Sdavidxustatic int
1404134147Sdavidxuignore (CORE_ADDR addr, char *contents)
1405132179Sdavidxu{
1406134147Sdavidxu  return 0;
1407132179Sdavidxu}
1408132179Sdavidxu
1409134147Sdavidxustatic void
1410134147Sdavidxufbsd_core_open (char *filename, int from_tty)
1411132179Sdavidxu{
1412134147Sdavidxu  int err;
1413132179Sdavidxu
1414134147Sdavidxu  fbsd_thread_core = 1;
1415132179Sdavidxu
1416134147Sdavidxu  orig_core_ops.to_open (filename, from_tty);
1417132179Sdavidxu
1418134147Sdavidxu  if (fbsd_thread_present)
1419134147Sdavidxu    {
1420134147Sdavidxu      err = td_ta_new_p (&proc_handle, &thread_agent);
1421134147Sdavidxu      if (err == TD_OK)
1422134147Sdavidxu        {
1423134147Sdavidxu          proc_handle.pid = elf_tdata (core_bfd)->core_pid;
1424134147Sdavidxu          fbsd_thread_activate ();
1425134147Sdavidxu        }
1426134147Sdavidxu      else
1427134149Sdavidxu        error ("fbsd_core_open: td_ta_new: %s", thread_db_err_str (err));
1428134147Sdavidxu    }
1429134147Sdavidxu}
1430132179Sdavidxu
1431134147Sdavidxustatic void
1432134147Sdavidxufbsd_core_close (int quitting)
1433134147Sdavidxu{
1434134147Sdavidxu  orig_core_ops.to_close (quitting);
1435134147Sdavidxu}
1436132179Sdavidxu
1437134147Sdavidxustatic void
1438134147Sdavidxufbsd_core_detach (char *args, int from_tty)
1439134147Sdavidxu{
1440134147Sdavidxu  if (fbsd_thread_active)
1441134147Sdavidxu    fbsd_thread_deactivate ();
1442134147Sdavidxu  unpush_target (&fbsd_thread_ops);
1443134147Sdavidxu  orig_core_ops.to_detach (args, from_tty);
1444134147Sdavidxu
1445134147Sdavidxu  /* Clear gdb solib information and symbol file
1446134147Sdavidxu     cache, so that after detach and re-attach, new_objfile
1447134147Sdavidxu     hook will be called */
1448134147Sdavidxu  clear_solib();
1449134147Sdavidxu  symbol_file_clear(0);
1450134147Sdavidxu}
1451132179Sdavidxu
1452134147Sdavidxustatic void
1453134147Sdavidxufbsd_core_files_info (struct target_ops *ignore)
1454134147Sdavidxu{
1455134147Sdavidxu  orig_core_ops.to_files_info (ignore);
1456134147Sdavidxu}
1457132179Sdavidxu
1458134147Sdavidxustatic void
1459134147Sdavidxuinit_fbsd_core_ops (void)
1460134147Sdavidxu{
1461134147Sdavidxu  fbsd_core_ops.to_shortname = "FreeBSD-core";
1462178666Sjhb  fbsd_core_ops.to_longname = "FreeBSD multithreaded core dump file";
1463178666Sjhb  fbsd_core_ops.to_doc =
1464178666Sjhb    "Use a core file as a target.  Specify the filename of the core file.";
1465134147Sdavidxu  fbsd_core_ops.to_open = fbsd_core_open;
1466134147Sdavidxu  fbsd_core_ops.to_close = fbsd_core_close;
1467134147Sdavidxu  fbsd_core_ops.to_attach = 0;
1468134147Sdavidxu  fbsd_core_ops.to_post_attach = 0;
1469134147Sdavidxu  fbsd_core_ops.to_detach = fbsd_core_detach;
1470134147Sdavidxu  /* fbsd_core_ops.to_resume  = 0; */
1471134147Sdavidxu  /* fbsd_core_ops.to_wait  = 0;  */
1472134147Sdavidxu  fbsd_core_ops.to_fetch_registers = fbsd_thread_fetch_registers;
1473134147Sdavidxu  /* fbsd_core_ops.to_store_registers  = 0; */
1474134147Sdavidxu  /* fbsd_core_ops.to_prepare_to_store  = 0; */
1475134147Sdavidxu  fbsd_core_ops.to_xfer_memory = fbsd_thread_xfer_memory;
1476134147Sdavidxu  fbsd_core_ops.to_files_info = fbsd_core_files_info;
1477134147Sdavidxu  fbsd_core_ops.to_insert_breakpoint = ignore;
1478134147Sdavidxu  fbsd_core_ops.to_remove_breakpoint = ignore;
1479134147Sdavidxu  /* fbsd_core_ops.to_lookup_symbol  = 0; */
1480134147Sdavidxu  fbsd_core_ops.to_create_inferior = fbsd_thread_create_inferior;
1481134147Sdavidxu  fbsd_core_ops.to_stratum = core_stratum;
1482134147Sdavidxu  fbsd_core_ops.to_has_all_memory = 0;
1483134147Sdavidxu  fbsd_core_ops.to_has_memory = 1;
1484134147Sdavidxu  fbsd_core_ops.to_has_stack = 1;
1485134147Sdavidxu  fbsd_core_ops.to_has_registers = 1;
1486134147Sdavidxu  fbsd_core_ops.to_has_execution = 0;
1487134147Sdavidxu  fbsd_core_ops.to_has_thread_control = tc_none;
1488134147Sdavidxu  fbsd_core_ops.to_thread_alive = fbsd_thread_alive;
1489134147Sdavidxu  fbsd_core_ops.to_pid_to_str = fbsd_thread_pid_to_str;
1490134147Sdavidxu  fbsd_core_ops.to_find_new_threads = fbsd_thread_find_new_threads;
1491134147Sdavidxu  fbsd_core_ops.to_sections = 0;
1492134147Sdavidxu  fbsd_core_ops.to_sections_end = 0;
1493134147Sdavidxu  fbsd_core_ops.to_magic = OPS_MAGIC;
1494134147Sdavidxu}
1495132179Sdavidxu
1496134147Sdavidxustatic void
1497134147Sdavidxuinit_fbsd_thread_ops (void)
1498134147Sdavidxu{
1499134147Sdavidxu  fbsd_thread_ops.to_shortname = "freebsd-threads";
1500134147Sdavidxu  fbsd_thread_ops.to_longname = "FreeBSD multithreaded child process.";
1501134147Sdavidxu  fbsd_thread_ops.to_doc = "FreeBSD threads support.";
1502134147Sdavidxu  fbsd_thread_ops.to_attach = fbsd_thread_attach;
1503134147Sdavidxu  fbsd_thread_ops.to_detach = fbsd_thread_detach;
1504134147Sdavidxu  fbsd_thread_ops.to_post_attach = fbsd_thread_post_attach;
1505134147Sdavidxu  fbsd_thread_ops.to_resume = fbsd_thread_resume;
1506134147Sdavidxu  fbsd_thread_ops.to_wait = fbsd_thread_wait;
1507134147Sdavidxu  fbsd_thread_ops.to_fetch_registers = fbsd_thread_fetch_registers;
1508134147Sdavidxu  fbsd_thread_ops.to_store_registers = fbsd_thread_store_registers;
1509134147Sdavidxu  fbsd_thread_ops.to_xfer_memory = fbsd_thread_xfer_memory;
1510134147Sdavidxu  fbsd_thread_ops.to_files_info = fbsd_thread_files_info;
1511134147Sdavidxu  fbsd_thread_ops.to_kill = fbsd_thread_kill;
1512134147Sdavidxu  fbsd_thread_ops.to_create_inferior = fbsd_thread_create_inferior;
1513134147Sdavidxu  fbsd_thread_ops.to_post_startup_inferior = fbsd_thread_post_startup_inferior;
1514134147Sdavidxu  fbsd_thread_ops.to_mourn_inferior = fbsd_thread_mourn_inferior;
1515134147Sdavidxu  fbsd_thread_ops.to_can_run = fbsd_thread_can_run;
1516134147Sdavidxu  fbsd_thread_ops.to_thread_alive = fbsd_thread_alive;
1517134147Sdavidxu  fbsd_thread_ops.to_find_new_threads = fbsd_thread_find_new_threads;
1518134147Sdavidxu  fbsd_thread_ops.to_pid_to_str = fbsd_thread_pid_to_str;
1519134147Sdavidxu  fbsd_thread_ops.to_stratum = thread_stratum;
1520134147Sdavidxu  fbsd_thread_ops.to_has_thread_control = tc_none;
1521134147Sdavidxu  fbsd_thread_ops.to_has_all_memory = 1;
1522134147Sdavidxu  fbsd_thread_ops.to_has_memory = 1;
1523134147Sdavidxu  fbsd_thread_ops.to_has_stack = 1;
1524134147Sdavidxu  fbsd_thread_ops.to_has_registers = 1;
1525134147Sdavidxu  fbsd_thread_ops.to_has_execution = 1;
1526134147Sdavidxu  fbsd_thread_ops.to_insert_breakpoint = memory_insert_breakpoint;
1527134147Sdavidxu  fbsd_thread_ops.to_remove_breakpoint = memory_remove_breakpoint;
1528134147Sdavidxu  fbsd_thread_ops.to_get_thread_local_address = fbsd_thread_get_local_address;
1529134147Sdavidxu  fbsd_thread_ops.to_magic = OPS_MAGIC;
1530134147Sdavidxu}
1531132179Sdavidxu
1532134147Sdavidxustatic int
1533134147Sdavidxuthread_db_load (void)
1534134147Sdavidxu{
1535134147Sdavidxu  void *handle;
1536134147Sdavidxu  td_err_e err;
1537132179Sdavidxu
1538134147Sdavidxu  handle = dlopen (LIBTHREAD_DB_SO, RTLD_NOW);
1539134147Sdavidxu  if (handle == NULL)
1540134147Sdavidxu      return 0;
1541132179Sdavidxu
1542134147Sdavidxu#define resolve(X)			\
1543134147Sdavidxu if (!(X##_p = dlsym (handle, #X)))	\
1544134147Sdavidxu   return 0;
1545132179Sdavidxu
1546134147Sdavidxu  resolve(td_init);
1547134147Sdavidxu  resolve(td_ta_new);
1548134147Sdavidxu  resolve(td_ta_delete);
1549134147Sdavidxu  resolve(td_ta_map_id2thr);
1550134147Sdavidxu  resolve(td_ta_map_lwp2thr);
1551134147Sdavidxu  resolve(td_ta_thr_iter);
1552134147Sdavidxu  resolve(td_thr_get_info);
1553146818Sdfr#ifdef PT_GETXMMREGS
1554146818Sdfr  resolve(td_thr_getxmmregs);
1555146818Sdfr#endif
1556134147Sdavidxu  resolve(td_thr_getfpregs);
1557134147Sdavidxu  resolve(td_thr_getgregs);
1558146818Sdfr#ifdef PT_GETXMMREGS
1559146818Sdfr  resolve(td_thr_setxmmregs);
1560146818Sdfr#endif
1561134147Sdavidxu  resolve(td_thr_setfpregs);
1562134147Sdavidxu  resolve(td_thr_setgregs);
1563134147Sdavidxu  resolve(td_thr_sstep);
1564134147Sdavidxu  resolve(td_ta_tsd_iter);
1565134147Sdavidxu  resolve(td_thr_dbsuspend);
1566134147Sdavidxu  resolve(td_thr_dbresume);
1567134147Sdavidxu  resolve(td_thr_tls_get_addr);
1568132179Sdavidxu
1569132179Sdavidxu  /* Initialize the library.  */
1570132179Sdavidxu  err = td_init_p ();
1571132179Sdavidxu  if (err != TD_OK)
1572132179Sdavidxu    {
1573132179Sdavidxu      warning ("Cannot initialize libthread_db: %s", thread_db_err_str (err));
1574132179Sdavidxu      return 0;
1575132179Sdavidxu    }
1576132179Sdavidxu
1577144923Sdavidxu  /* These are not essential.  */
1578144923Sdavidxu  td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
1579144923Sdavidxu  td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
1580144923Sdavidxu  td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
1581144923Sdavidxu  td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
1582144923Sdavidxu  td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
1583144923Sdavidxu
1584132179Sdavidxu  return 1;
1585132179Sdavidxu}
1586132179Sdavidxu
1587134147Sdavidxu/* we suppress the call to add_target of core_ops in corelow because
1588134147Sdavidxu   if there are two targets in the stratum core_stratum, find_core_target
1589134147Sdavidxu   won't know which one to return.  see corelow.c for an additonal
1590134147Sdavidxu   comment on coreops_suppress_target. */
1591134147Sdavidxu
1592134147Sdavidxuint coreops_suppress_target = 1;
1593134147Sdavidxu
1594178666Sjhb/* similarly we allow this target to be completely skipped.  This is used
1595178666Sjhb   by kgdb which uses its own core target. */
1596178666Sjhb
1597178666Sjhbint fbsdcoreops_suppress_target;
1598178666Sjhb
1599132179Sdavidxuvoid
1600132179Sdavidxu_initialize_thread_db (void)
1601132179Sdavidxu{
1602178666Sjhb
1603178666Sjhb  if (fbsdcoreops_suppress_target)
1604178666Sjhb    return;
1605134147Sdavidxu  init_fbsd_thread_ops ();
1606134147Sdavidxu  init_fbsd_core_ops ();
1607134147Sdavidxu
1608132179Sdavidxu  if (thread_db_load ())
1609132179Sdavidxu    {
1610134147Sdavidxu      add_target (&fbsd_thread_ops);
1611132179Sdavidxu
1612132179Sdavidxu      /* "thread tsd" command */
1613132179Sdavidxu      add_cmd ("tsd", class_run, fbsd_thread_tsd_cmd,
1614132179Sdavidxu            "Show the thread-specific data keys and destructors "
1615132179Sdavidxu            "for the process.\n",
1616132179Sdavidxu           &thread_cmd_list);
1617132179Sdavidxu
1618155379Sdavidxu      add_cmd ("signal", class_run, fbsd_thread_signal_cmd,
1619155379Sdavidxu            "Show the thread signal info.\n",
1620155379Sdavidxu           &thread_cmd_list);
1621155379Sdavidxu
1622134147Sdavidxu      memcpy (&orig_core_ops, &core_ops, sizeof (struct target_ops));
1623134147Sdavidxu      memcpy (&core_ops, &fbsd_core_ops, sizeof (struct target_ops));
1624134147Sdavidxu      add_target (&core_ops);
1625134147Sdavidxu
1626132179Sdavidxu      /* Add ourselves to objfile event chain. */
1627132179Sdavidxu      target_new_objfile_chain = target_new_objfile_hook;
1628132179Sdavidxu      target_new_objfile_hook = fbsd_thread_new_objfile;
1629134147Sdavidxu
1630134147Sdavidxu      child_suppress_run = 1;
1631132179Sdavidxu    }
1632132179Sdavidxu  else
1633132179Sdavidxu    {
1634134147Sdavidxu      fprintf_unfiltered (gdb_stderr,
1635134147Sdavidxu        "[GDB will not be able to debug user-mode threads: %s]\n", dlerror());
1636134147Sdavidxu
1637134147Sdavidxu      /* allow the user to debug non-threaded core files */
1638134147Sdavidxu      add_target (&core_ops);
1639132179Sdavidxu    }
1640132179Sdavidxu}
1641132179Sdavidxu
1642132179Sdavidxu/* proc service functions */
1643132179Sdavidxuvoid
1644132179Sdavidxups_plog (const char *fmt, ...)
1645132179Sdavidxu{
1646132179Sdavidxu  va_list args;
1647132179Sdavidxu
1648132179Sdavidxu  va_start (args, fmt);
1649132179Sdavidxu  vfprintf_filtered (gdb_stderr, fmt, args);
1650132179Sdavidxu  va_end (args);
1651132179Sdavidxu}
1652132179Sdavidxu
1653132179Sdavidxups_err_e
1654132179Sdavidxups_pglobal_lookup (struct ps_prochandle *ph, const char *obj,
1655132179Sdavidxu   const char *name, psaddr_t *sym_addr)
1656132179Sdavidxu{
1657132179Sdavidxu  struct minimal_symbol *ms;
1658155379Sdavidxu  CORE_ADDR addr;
1659132179Sdavidxu
1660132179Sdavidxu  ms = lookup_minimal_symbol (name, NULL, NULL);
1661132179Sdavidxu  if (ms == NULL)
1662132179Sdavidxu    return PS_NOSYM;
1663132179Sdavidxu
1664155379Sdavidxu  addr = SYMBOL_VALUE_ADDRESS (ms);
1665155379Sdavidxu  store_typed_address(sym_addr, builtin_type_void_data_ptr, addr);
1666132179Sdavidxu  return PS_OK;
1667132179Sdavidxu}
1668132179Sdavidxu
1669132179Sdavidxups_err_e
1670132300Smarcelps_pread (struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t len)
1671132179Sdavidxu{
1672155379Sdavidxu  int err = target_read_memory (
1673155379Sdavidxu    extract_typed_address(&addr, builtin_type_void_data_ptr), buf, len);
1674134147Sdavidxu  return (err == 0 ? PS_OK : PS_ERR);
1675132179Sdavidxu}
1676132179Sdavidxu
1677132179Sdavidxups_err_e
1678132300Smarcelps_pwrite (struct ps_prochandle *ph, psaddr_t addr, const void *buf,
1679132179Sdavidxu            size_t len)
1680132179Sdavidxu{
1681155379Sdavidxu  int err = target_write_memory (
1682155379Sdavidxu    extract_typed_address(&addr, builtin_type_void_data_ptr), (void *)buf, len);
1683134147Sdavidxu  return (err == 0 ? PS_OK : PS_ERR);
1684132179Sdavidxu}
1685132179Sdavidxu
1686132179Sdavidxups_err_e
1687132179Sdavidxups_lgetregs (struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset)
1688132179Sdavidxu{
1689132179Sdavidxu  struct cleanup *old_chain;
1690132179Sdavidxu
1691132179Sdavidxu  old_chain = save_inferior_ptid ();
1692140071Speadar
1693140071Speadar  /* XXX: Target operation isn't lwp aware: replace pid with lwp */
1694140071Speadar  inferior_ptid = BUILD_LWP (0, lwpid);
1695140071Speadar
1696132179Sdavidxu  target_fetch_registers (-1);
1697132179Sdavidxu  fill_gregset (gregset, -1);
1698132179Sdavidxu  do_cleanups (old_chain);
1699132179Sdavidxu  return PS_OK;
1700132179Sdavidxu}
1701132179Sdavidxu
1702132179Sdavidxups_err_e
1703132179Sdavidxups_lsetregs (struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t gregset)
1704132179Sdavidxu{
1705132179Sdavidxu  struct cleanup *old_chain;
1706132179Sdavidxu
1707132179Sdavidxu  old_chain = save_inferior_ptid ();
1708132179Sdavidxu  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
1709218822Sdim  supply_gregset ((gdb_gregset_t *) gregset);
1710132179Sdavidxu  target_store_registers (-1);
1711132179Sdavidxu  do_cleanups (old_chain);
1712132179Sdavidxu  return PS_OK;
1713132179Sdavidxu}
1714132179Sdavidxu
1715132179Sdavidxups_err_e
1716132179Sdavidxups_lgetfpregs (struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *fpregset)
1717132179Sdavidxu{
1718132179Sdavidxu  struct cleanup *old_chain;
1719132179Sdavidxu
1720132179Sdavidxu  old_chain = save_inferior_ptid ();
1721132179Sdavidxu  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
1722132179Sdavidxu  target_fetch_registers (-1);
1723132179Sdavidxu  fill_fpregset (fpregset, -1);
1724132179Sdavidxu  do_cleanups (old_chain);
1725132179Sdavidxu  return PS_OK;
1726132179Sdavidxu}
1727132179Sdavidxu
1728132179Sdavidxups_err_e
1729132179Sdavidxups_lsetfpregs (struct ps_prochandle *ph, lwpid_t lwpid,
1730132179Sdavidxu               const prfpregset_t *fpregset)
1731132179Sdavidxu{
1732132179Sdavidxu  struct cleanup *old_chain;
1733132179Sdavidxu
1734132179Sdavidxu  old_chain = save_inferior_ptid ();
1735132179Sdavidxu  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
1736218822Sdim  supply_fpregset ((gdb_fpregset_t *) fpregset);
1737132179Sdavidxu  target_store_registers (-1);
1738132179Sdavidxu  do_cleanups (old_chain);
1739132179Sdavidxu  return PS_OK;
1740132179Sdavidxu}
1741132179Sdavidxu
1742146818Sdfr#ifdef PT_GETXMMREGS
1743132179Sdavidxups_err_e
1744146818Sdfrps_lgetxmmregs (struct ps_prochandle *ph, lwpid_t lwpid, char *xmmregs)
1745146818Sdfr{
1746146818Sdfr  struct cleanup *old_chain;
1747146818Sdfr
1748146818Sdfr  old_chain = save_inferior_ptid ();
1749146818Sdfr  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
1750146818Sdfr  target_fetch_registers (-1);
1751146818Sdfr  i387_fill_fxsave (xmmregs, -1);
1752146818Sdfr  do_cleanups (old_chain);
1753146818Sdfr  return PS_OK;
1754146818Sdfr}
1755146818Sdfr
1756146818Sdfrps_err_e
1757146818Sdfrps_lsetxmmregs (struct ps_prochandle *ph, lwpid_t lwpid,
1758146818Sdfr		const char *xmmregs)
1759146818Sdfr{
1760146818Sdfr  struct cleanup *old_chain;
1761146818Sdfr
1762146818Sdfr  old_chain = save_inferior_ptid ();
1763146818Sdfr  inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
1764146818Sdfr  i387_supply_fxsave (current_regcache, -1, xmmregs);
1765146818Sdfr  target_store_registers (-1);
1766146818Sdfr  do_cleanups (old_chain);
1767146818Sdfr  return PS_OK;
1768146818Sdfr}
1769146818Sdfr#endif
1770146818Sdfr
1771146818Sdfrps_err_e
1772132179Sdavidxups_lstop(struct ps_prochandle *ph, lwpid_t lwpid)
1773132179Sdavidxu{
1774132244Sdavidxu  if (ptrace (PT_SUSPEND, lwpid, 0, 0) == -1)
1775132244Sdavidxu    return PS_ERR;
1776132244Sdavidxu  return PS_OK;
1777132179Sdavidxu}
1778132179Sdavidxu
1779132179Sdavidxups_err_e
1780132179Sdavidxups_lcontinue(struct ps_prochandle *ph, lwpid_t lwpid)
1781132179Sdavidxu{
1782132244Sdavidxu  if (ptrace (PT_RESUME, lwpid, 0, 0) == -1)
1783132244Sdavidxu    return PS_ERR;
1784132244Sdavidxu  return PS_OK;
1785132179Sdavidxu}
1786155412Sdavidxu
1787155412Sdavidxups_err_e
1788155412Sdavidxups_linfo(struct ps_prochandle *ph, lwpid_t lwpid, void *info)
1789155412Sdavidxu{
1790155412Sdavidxu  if (fbsd_thread_core) {
1791155412Sdavidxu    /* XXX should verify lwpid and make a pseudo lwp info */
1792155412Sdavidxu    memset(info, 0, sizeof(struct ptrace_lwpinfo));
1793155412Sdavidxu    return PS_OK;
1794155412Sdavidxu  }
1795155412Sdavidxu
1796155412Sdavidxu  if (ptrace (PT_LWPINFO, lwpid, info, sizeof(struct ptrace_lwpinfo)) == -1)
1797155412Sdavidxu    return PS_ERR;
1798155412Sdavidxu  return PS_OK;
1799155412Sdavidxu}
1800