1/* Get Dwarf Frame state for target PID or core file.
2   Copyright (C) 2013, 2014 Red Hat, Inc.
3   This file is part of elfutils.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of either
7
8     * the GNU Lesser General Public License as published by the Free
9       Software Foundation; either version 3 of the License, or (at
10       your option) any later version
11
12   or
13
14     * the GNU General Public License as published by the Free
15       Software Foundation; either version 2 of the License, or (at
16       your option) any later version
17
18   or both in parallel, as here.
19
20   elfutils is distributed in the hope that it will be useful, but
21   WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   General Public License for more details.
24
25   You should have received copies of the GNU General Public License and
26   the GNU Lesser General Public License along with this program.  If
27   not, see <http://www.gnu.org/licenses/>.  */
28
29#include "libdwflP.h"
30#include <sys/ptrace.h>
31#include <unistd.h>
32
33/* Set STATE->pc_set from STATE->regs according to the backend.  Return true on
34   success, false on error.  */
35static bool
36state_fetch_pc (Dwfl_Frame *state)
37{
38  switch (state->pc_state)
39    {
40    case DWFL_FRAME_STATE_PC_SET:
41      return true;
42    case DWFL_FRAME_STATE_PC_UNDEFINED:
43      abort ();
44    case DWFL_FRAME_STATE_ERROR:
45      {
46	Ebl *ebl = state->thread->process->ebl;
47	Dwarf_CIE abi_info;
48	if (ebl_abi_cfi (ebl, &abi_info) != 0)
49	  {
50	    __libdwfl_seterrno (DWFL_E_LIBEBL);
51	    return false;
52	  }
53	unsigned ra = abi_info.return_address_register;
54	/* dwarf_frame_state_reg_is_set is not applied here.  */
55	if (ra >= ebl_frame_nregs (ebl))
56	  {
57	    __libdwfl_seterrno (DWFL_E_LIBEBL_BAD);
58	    return false;
59	  }
60	state->pc = state->regs[ra] + ebl_ra_offset (ebl);
61	state->pc_state = DWFL_FRAME_STATE_PC_SET;
62      }
63      return true;
64    }
65  abort ();
66}
67
68/* Do not call it on your own, to be used by thread_* functions only.  */
69
70static void
71state_free (Dwfl_Frame *state)
72{
73  Dwfl_Thread *thread = state->thread;
74  assert (thread->unwound == state);
75  thread->unwound = state->unwound;
76  free (state);
77}
78
79static void
80thread_free_all_states (Dwfl_Thread *thread)
81{
82  while (thread->unwound)
83    state_free (thread->unwound);
84}
85
86static Dwfl_Frame *
87state_alloc (Dwfl_Thread *thread)
88{
89  assert (thread->unwound == NULL);
90  Ebl *ebl = thread->process->ebl;
91  size_t nregs = ebl_frame_nregs (ebl);
92  if (nregs == 0)
93    return NULL;
94  assert (nregs < sizeof (((Dwfl_Frame *) NULL)->regs_set) * 8);
95  Dwfl_Frame *state = malloc (sizeof (*state) + sizeof (*state->regs) * nregs);
96  if (state == NULL)
97    return NULL;
98  state->thread = thread;
99  state->signal_frame = false;
100  state->initial_frame = true;
101  state->pc_state = DWFL_FRAME_STATE_ERROR;
102  memset (state->regs_set, 0, sizeof (state->regs_set));
103  thread->unwound = state;
104  state->unwound = NULL;
105  return state;
106}
107
108void
109internal_function
110__libdwfl_process_free (Dwfl_Process *process)
111{
112  Dwfl *dwfl = process->dwfl;
113  if (process->callbacks->detach != NULL)
114    process->callbacks->detach (dwfl, process->callbacks_arg);
115  assert (dwfl->process == process);
116  dwfl->process = NULL;
117  if (process->ebl_close)
118    ebl_closebackend (process->ebl);
119  free (process);
120  dwfl->attacherr = DWFL_E_NOERROR;
121}
122
123/* Allocate new Dwfl_Process for DWFL.  */
124static void
125process_alloc (Dwfl *dwfl)
126{
127  Dwfl_Process *process = malloc (sizeof (*process));
128  if (process == NULL)
129    return;
130  process->dwfl = dwfl;
131  dwfl->process = process;
132}
133
134bool
135dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid,
136		   const Dwfl_Thread_Callbacks *thread_callbacks, void *arg)
137{
138  if (dwfl->process != NULL)
139    {
140      __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
141      return false;
142    }
143
144  /* Reset any previous error, we are just going to try again.  */
145  dwfl->attacherr = DWFL_E_NOERROR;
146  /* thread_callbacks is declared NN */
147  if (thread_callbacks->next_thread == NULL
148      || thread_callbacks->set_initial_registers == NULL)
149    {
150      dwfl->attacherr = DWFL_E_INVALID_ARGUMENT;
151    fail:
152      dwfl->attacherr = __libdwfl_canon_error (dwfl->attacherr);
153      __libdwfl_seterrno (dwfl->attacherr);
154      return false;
155    }
156
157  Ebl *ebl;
158  bool ebl_close;
159  if (elf != NULL)
160    {
161      ebl = ebl_openbackend (elf);
162      ebl_close = true;
163    }
164  else
165    {
166      ebl = NULL;
167      for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
168	{
169	  /* Reading of the vDSO or (deleted) modules may fail as
170	     /proc/PID/mem is unreadable without PTRACE_ATTACH and
171	     we may not be PTRACE_ATTACH-ed now.  MOD would not be
172	     re-read later to unwind it when we are already
173	     PTRACE_ATTACH-ed to PID.  This happens when this function
174	     is called from dwfl_linux_proc_attach with elf == NULL.
175	     __libdwfl_module_getebl will call __libdwfl_getelf which
176	     will call the find_elf callback.  */
177	  if (strncmp (mod->name, "[vdso: ", 7) == 0
178	      || strcmp (strrchr (mod->name, ' ') ?: "",
179			 " (deleted)") == 0)
180	    continue;
181	  Dwfl_Error error = __libdwfl_module_getebl (mod);
182	  if (error != DWFL_E_NOERROR)
183	    continue;
184	  ebl = mod->ebl;
185	  break;
186	}
187      ebl_close = false;
188    }
189  if (ebl == NULL)
190    {
191      /* Not identified EBL from any of the modules.  */
192      dwfl->attacherr = DWFL_E_PROCESS_NO_ARCH;
193      goto fail;
194    }
195  process_alloc (dwfl);
196  Dwfl_Process *process = dwfl->process;
197  if (process == NULL)
198    {
199      if (ebl_close)
200	ebl_closebackend (ebl);
201      dwfl->attacherr = DWFL_E_NOMEM;
202      goto fail;
203    }
204  process->ebl = ebl;
205  process->ebl_close = ebl_close;
206  process->pid = pid;
207  process->callbacks = thread_callbacks;
208  process->callbacks_arg = arg;
209  return true;
210}
211INTDEF(dwfl_attach_state)
212
213pid_t
214dwfl_pid (Dwfl *dwfl)
215{
216  if (dwfl->attacherr != DWFL_E_NOERROR)
217    {
218      __libdwfl_seterrno (dwfl->attacherr);
219      return -1;
220    }
221
222  if (dwfl->process == NULL)
223    {
224      __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
225      return -1;
226    }
227  return dwfl->process->pid;
228}
229INTDEF(dwfl_pid)
230
231Dwfl *
232dwfl_thread_dwfl (Dwfl_Thread *thread)
233{
234  return thread->process->dwfl;
235}
236INTDEF(dwfl_thread_dwfl)
237
238pid_t
239dwfl_thread_tid (Dwfl_Thread *thread)
240{
241  return thread->tid;
242}
243INTDEF(dwfl_thread_tid)
244
245Dwfl_Thread *
246dwfl_frame_thread (Dwfl_Frame *state)
247{
248  return state->thread;
249}
250INTDEF(dwfl_frame_thread)
251
252int
253dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg),
254		 void *arg)
255{
256  if (dwfl->attacherr != DWFL_E_NOERROR)
257    {
258      __libdwfl_seterrno (dwfl->attacherr);
259      return -1;
260    }
261
262  Dwfl_Process *process = dwfl->process;
263  if (process == NULL)
264    {
265      __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
266      return -1;
267    }
268
269  Dwfl_Thread thread;
270  thread.process = process;
271  thread.unwound = NULL;
272  thread.callbacks_arg = NULL;
273  for (;;)
274    {
275      thread.tid = process->callbacks->next_thread (dwfl,
276						    process->callbacks_arg,
277						    &thread.callbacks_arg);
278      if (thread.tid < 0)
279	{
280	  Dwfl_Error saved_errno = dwfl_errno ();
281	  thread_free_all_states (&thread);
282	  __libdwfl_seterrno (saved_errno);
283	  return -1;
284	}
285      if (thread.tid == 0)
286	{
287	  thread_free_all_states (&thread);
288	  __libdwfl_seterrno (DWFL_E_NOERROR);
289	  return 0;
290	}
291      int err = callback (&thread, arg);
292      if (err != DWARF_CB_OK)
293	{
294	  thread_free_all_states (&thread);
295	  return err;
296	}
297      assert (thread.unwound == NULL);
298    }
299  /* NOTREACHED */
300}
301INTDEF(dwfl_getthreads)
302
303struct one_arg
304{
305  pid_t tid;
306  bool seen;
307  int (*callback) (Dwfl_Thread *thread, void *arg);
308  void *arg;
309  int ret;
310};
311
312static int
313get_one_thread_cb (Dwfl_Thread *thread, void *arg)
314{
315  struct one_arg *oa = (struct one_arg *) arg;
316  if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid)
317    {
318      oa->seen = true;
319      oa->ret = oa->callback (thread, oa->arg);
320      return DWARF_CB_ABORT;
321    }
322
323  return DWARF_CB_OK;
324}
325
326/* Note not currently exported, will be when there are more Dwfl_Thread
327   properties to query.  Use dwfl_getthread_frames for now directly.  */
328static int
329getthread (Dwfl *dwfl, pid_t tid,
330	   int (*callback) (Dwfl_Thread *thread, void *arg),
331	   void *arg)
332{
333  if (dwfl->attacherr != DWFL_E_NOERROR)
334    {
335      __libdwfl_seterrno (dwfl->attacherr);
336      return -1;
337    }
338
339  Dwfl_Process *process = dwfl->process;
340  if (process == NULL)
341    {
342      __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
343      return -1;
344    }
345
346  if (process->callbacks->get_thread != NULL)
347    {
348      Dwfl_Thread thread;
349      thread.process = process;
350      thread.unwound = NULL;
351      thread.callbacks_arg = NULL;
352
353      if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
354					  &thread.callbacks_arg))
355	{
356	  int err;
357	  thread.tid = tid;
358	  err = callback (&thread, arg);
359	  thread_free_all_states (&thread);
360	  return err;
361	}
362
363      return -1;
364    }
365
366   struct one_arg oa = { .tid = tid, .callback = callback,
367			 .arg = arg, .seen = false };
368   int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa);
369
370   if (err == DWARF_CB_ABORT && oa.seen)
371     return oa.ret;
372
373   if (err == DWARF_CB_OK && ! oa.seen)
374     {
375	errno = ESRCH;
376	__libdwfl_seterrno (DWFL_E_ERRNO);
377	return -1;
378     }
379
380   return err;
381}
382
383struct one_thread
384{
385  int (*callback) (Dwfl_Frame *frame, void *arg);
386  void *arg;
387};
388
389static int
390get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg)
391{
392  struct one_thread *ot = (struct one_thread *) arg;
393  return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg);
394}
395
396int
397dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
398		       int (*callback) (Dwfl_Frame *frame, void *arg),
399		       void *arg)
400{
401  struct one_thread ot = { .callback = callback, .arg = arg };
402  return getthread (dwfl, tid, get_one_thread_frames_cb, &ot);
403}
404INTDEF(dwfl_getthread_frames)
405
406int
407dwfl_thread_getframes (Dwfl_Thread *thread,
408		       int (*callback) (Dwfl_Frame *state, void *arg),
409		       void *arg)
410{
411  if (thread->unwound != NULL)
412    {
413      /* We had to be called from inside CALLBACK.  */
414      __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
415      return -1;
416    }
417  Ebl *ebl = thread->process->ebl;
418  if (ebl_frame_nregs (ebl) == 0)
419    {
420      __libdwfl_seterrno (DWFL_E_NO_UNWIND);
421      return -1;
422    }
423  if (state_alloc (thread) == NULL)
424    {
425      __libdwfl_seterrno (DWFL_E_NOMEM);
426      return -1;
427    }
428  Dwfl_Process *process = thread->process;
429  if (! process->callbacks->set_initial_registers (thread,
430						   thread->callbacks_arg))
431    {
432      thread_free_all_states (thread);
433      return -1;
434    }
435  if (! state_fetch_pc (thread->unwound))
436    {
437      if (process->callbacks->thread_detach)
438	process->callbacks->thread_detach (thread, thread->callbacks_arg);
439      thread_free_all_states (thread);
440      return -1;
441    }
442
443  Dwfl_Frame *state;
444  do
445    {
446      state = thread->unwound;
447      int err = callback (state, arg);
448      if (err != DWARF_CB_OK)
449	{
450	  if (process->callbacks->thread_detach)
451	    process->callbacks->thread_detach (thread, thread->callbacks_arg);
452	  thread_free_all_states (thread);
453	  return err;
454	}
455      __libdwfl_frame_unwind (state);
456      /* The old frame is no longer needed.  */
457      state_free (thread->unwound);
458      state = thread->unwound;
459    }
460  while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
461
462  Dwfl_Error err = dwfl_errno ();
463  if (process->callbacks->thread_detach)
464    process->callbacks->thread_detach (thread, thread->callbacks_arg);
465  if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
466    {
467      thread_free_all_states (thread);
468      __libdwfl_seterrno (err);
469      return -1;
470    }
471  assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
472  thread_free_all_states (thread);
473  return 0;
474}
475INTDEF(dwfl_thread_getframes)
476