Blame libdwfl/dwfl_frame.c

Packit Service 97d2fb
/* Get Dwarf Frame state for target PID or core file.
Packit Service 97d2fb
   Copyright (C) 2013, 2014 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include "libdwflP.h"
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
/* Set STATE->pc_set from STATE->regs according to the backend.  Return true on
Packit Service 97d2fb
   success, false on error.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
state_fetch_pc (Dwfl_Frame *state)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (state->pc_state)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case DWFL_FRAME_STATE_PC_SET:
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    case DWFL_FRAME_STATE_PC_UNDEFINED:
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    case DWFL_FRAME_STATE_ERROR:
Packit Service 97d2fb
      {
Packit Service 97d2fb
	Ebl *ebl = state->thread->process->ebl;
Packit Service 97d2fb
	Dwarf_CIE abi_info;
Packit Service 97d2fb
	if (ebl_abi_cfi (ebl, &abi_info) != 0)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    __libdwfl_seterrno (DWFL_E_LIBEBL);
Packit Service 97d2fb
	    return false;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	unsigned ra = abi_info.return_address_register;
Packit Service 97d2fb
	/* dwarf_frame_state_reg_is_set is not applied here.  */
Packit Service 97d2fb
	if (ra >= ebl_frame_nregs (ebl))
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    __libdwfl_seterrno (DWFL_E_LIBEBL_BAD);
Packit Service 97d2fb
	    return false;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	state->pc = state->regs[ra] + ebl_ra_offset (ebl);
Packit Service 97d2fb
	state->pc_state = DWFL_FRAME_STATE_PC_SET;
Packit Service 97d2fb
      }
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  abort ();
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Do not call it on your own, to be used by thread_* functions only.  */
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
free_states (Dwfl_Frame *state)
Packit Service 97d2fb
{
Packit Service 97d2fb
  while (state)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwfl_Frame *next = state->unwound;
Packit Service 97d2fb
      free(state);
Packit Service 97d2fb
      state = next;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static Dwfl_Frame *
Packit Service 97d2fb
state_alloc (Dwfl_Thread *thread)
Packit Service 97d2fb
{
Packit Service 97d2fb
  assert (thread->unwound == NULL);
Packit Service 97d2fb
  Ebl *ebl = thread->process->ebl;
Packit Service 97d2fb
  size_t nregs = ebl_frame_nregs (ebl);
Packit Service 97d2fb
  if (nregs == 0)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
  assert (nregs < sizeof (((Dwfl_Frame *) NULL)->regs_set) * 8);
Packit Service 97d2fb
  Dwfl_Frame *state = malloc (sizeof (*state) + sizeof (*state->regs) * nregs);
Packit Service 97d2fb
  if (state == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
  state->thread = thread;
Packit Service 97d2fb
  state->signal_frame = false;
Packit Service 97d2fb
  state->initial_frame = true;
Packit Service 97d2fb
  state->pc_state = DWFL_FRAME_STATE_ERROR;
Packit Service 97d2fb
  memset (state->regs_set, 0, sizeof (state->regs_set));
Packit Service 97d2fb
  thread->unwound = state;
Packit Service 97d2fb
  state->unwound = NULL;
Packit Service 97d2fb
  return state;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_process_free (Dwfl_Process *process)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl *dwfl = process->dwfl;
Packit Service 97d2fb
  if (process->callbacks->detach != NULL)
Packit Service 97d2fb
    process->callbacks->detach (dwfl, process->callbacks_arg);
Packit Service 97d2fb
  assert (dwfl->process == process);
Packit Service 97d2fb
  dwfl->process = NULL;
Packit Service 97d2fb
  if (process->ebl_close)
Packit Service 97d2fb
    ebl_closebackend (process->ebl);
Packit Service 97d2fb
  free (process);
Packit Service 97d2fb
  dwfl->attacherr = DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Allocate new Dwfl_Process for DWFL.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
process_alloc (Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Process *process = malloc (sizeof (*process));
Packit Service 97d2fb
  if (process == NULL)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
  process->dwfl = dwfl;
Packit Service 97d2fb
  dwfl->process = process;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
bool
Packit Service 97d2fb
dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid,
Packit Service 97d2fb
		   const Dwfl_Thread_Callbacks *thread_callbacks, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dwfl->process != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Reset any previous error, we are just going to try again.  */
Packit Service 97d2fb
  dwfl->attacherr = DWFL_E_NOERROR;
Packit Service 97d2fb
  /* thread_callbacks is declared NN */
Packit Service 97d2fb
  if (thread_callbacks->next_thread == NULL
Packit Service 97d2fb
      || thread_callbacks->set_initial_registers == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      dwfl->attacherr = DWFL_E_INVALID_ARGUMENT;
Packit Service 97d2fb
    fail:
Packit Service 97d2fb
      dwfl->attacherr = __libdwfl_canon_error (dwfl->attacherr);
Packit Service 97d2fb
      __libdwfl_seterrno (dwfl->attacherr);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Ebl *ebl;
Packit Service 97d2fb
  bool ebl_close;
Packit Service 97d2fb
  if (elf != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ebl = ebl_openbackend (elf);
Packit Service 97d2fb
      ebl_close = true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ebl = NULL;
Packit Service 97d2fb
      for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Reading of the vDSO or (deleted) modules may fail as
Packit Service 97d2fb
	     /proc/PID/mem is unreadable without PTRACE_ATTACH and
Packit Service 97d2fb
	     we may not be PTRACE_ATTACH-ed now.  MOD would not be
Packit Service 97d2fb
	     re-read later to unwind it when we are already
Packit Service 97d2fb
	     PTRACE_ATTACH-ed to PID.  This happens when this function
Packit Service 97d2fb
	     is called from dwfl_linux_proc_attach with elf == NULL.
Packit Service 97d2fb
	     __libdwfl_module_getebl will call __libdwfl_getelf which
Packit Service 97d2fb
	     will call the find_elf callback.  */
Packit Service 97d2fb
	  if (strncmp (mod->name, "[vdso: ", 7) == 0
Packit Service 97d2fb
	      || strcmp (strrchr (mod->name, ' ') ?: "",
Packit Service 97d2fb
			 " (deleted)") == 0)
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
	  Dwfl_Error error = __libdwfl_module_getebl (mod);
Packit Service 97d2fb
	  if (error != DWFL_E_NOERROR)
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
	  ebl = mod->ebl;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      ebl_close = false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (ebl == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Not identified EBL from any of the modules.  */
Packit Service 97d2fb
      dwfl->attacherr = DWFL_E_PROCESS_NO_ARCH;
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  process_alloc (dwfl);
Packit Service 97d2fb
  Dwfl_Process *process = dwfl->process;
Packit Service 97d2fb
  if (process == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ebl_close)
Packit Service 97d2fb
	ebl_closebackend (ebl);
Packit Service 97d2fb
      dwfl->attacherr = DWFL_E_NOMEM;
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  process->ebl = ebl;
Packit Service 97d2fb
  process->ebl_close = ebl_close;
Packit Service 97d2fb
  process->pid = pid;
Packit Service 97d2fb
  process->callbacks = thread_callbacks;
Packit Service 97d2fb
  process->callbacks_arg = arg;
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_attach_state)
Packit Service 97d2fb
Packit Service 97d2fb
pid_t
Packit Service 97d2fb
dwfl_pid (Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dwfl->attacherr != DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (dwfl->attacherr);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (dwfl->process == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return dwfl->process->pid;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_pid)
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl *
Packit Service 97d2fb
dwfl_thread_dwfl (Dwfl_Thread *thread)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return thread->process->dwfl;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_thread_dwfl)
Packit Service 97d2fb
Packit Service 97d2fb
pid_t
Packit Service 97d2fb
dwfl_thread_tid (Dwfl_Thread *thread)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return thread->tid;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_thread_tid)
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl_Thread *
Packit Service 97d2fb
dwfl_frame_thread (Dwfl_Frame *state)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return state->thread;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_frame_thread)
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg),
Packit Service 97d2fb
		 void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dwfl->attacherr != DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (dwfl->attacherr);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Process *process = dwfl->process;
Packit Service 97d2fb
  if (process == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Thread thread;
Packit Service 97d2fb
  thread.process = process;
Packit Service 97d2fb
  thread.unwound = NULL;
Packit Service 97d2fb
  thread.callbacks_arg = NULL;
Packit Service 97d2fb
  for (;;)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      thread.tid = process->callbacks->next_thread (dwfl,
Packit Service 97d2fb
						    process->callbacks_arg,
Packit Service 97d2fb
						    &thread.callbacks_arg);
Packit Service 97d2fb
      if (thread.tid < 0)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
      if (thread.tid == 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libdwfl_seterrno (DWFL_E_NOERROR);
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      int err = callback (&thread, arg);
Packit Service 97d2fb
      if (err != DWARF_CB_OK)
Packit Service 97d2fb
	return err;
Packit Service 97d2fb
      assert (thread.unwound == NULL);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  /* NOTREACHED */
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_getthreads)
Packit Service 97d2fb
Packit Service 97d2fb
struct one_arg
Packit Service 97d2fb
{
Packit Service 97d2fb
  pid_t tid;
Packit Service 97d2fb
  bool seen;
Packit Service 97d2fb
  int (*callback) (Dwfl_Thread *thread, void *arg);
Packit Service 97d2fb
  void *arg;
Packit Service 97d2fb
  int ret;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
get_one_thread_cb (Dwfl_Thread *thread, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct one_arg *oa = (struct one_arg *) arg;
Packit Service 97d2fb
  if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      oa->seen = true;
Packit Service 97d2fb
      oa->ret = oa->callback (thread, oa->arg);
Packit Service 97d2fb
      return DWARF_CB_ABORT;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Note not currently exported, will be when there are more Dwfl_Thread
Packit Service 97d2fb
   properties to query.  Use dwfl_getthread_frames for now directly.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
getthread (Dwfl *dwfl, pid_t tid,
Packit Service 97d2fb
	   int (*callback) (Dwfl_Thread *thread, void *arg),
Packit Service 97d2fb
	   void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dwfl->attacherr != DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (dwfl->attacherr);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Process *process = dwfl->process;
Packit Service 97d2fb
  if (process == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (process->callbacks->get_thread != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwfl_Thread thread;
Packit Service 97d2fb
      thread.process = process;
Packit Service 97d2fb
      thread.unwound = NULL;
Packit Service 97d2fb
      thread.callbacks_arg = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
      if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
Packit Service 97d2fb
					  &thread.callbacks_arg))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  thread.tid = tid;
Packit Service 97d2fb
	  return callback (&thread, arg);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
   struct one_arg oa = { .tid = tid, .callback = callback,
Packit Service 97d2fb
			 .arg = arg, .seen = false };
Packit Service 97d2fb
   int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa);
Packit Service 97d2fb
Packit Service 97d2fb
   if (err == DWARF_CB_ABORT && oa.seen)
Packit Service 97d2fb
     return oa.ret;
Packit Service 97d2fb
Packit Service 97d2fb
   if (err == DWARF_CB_OK && ! oa.seen)
Packit Service 97d2fb
     {
Packit Service 97d2fb
	errno = ESRCH;
Packit Service 97d2fb
	__libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
     }
Packit Service 97d2fb
Packit Service 97d2fb
   return err;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
struct one_thread
Packit Service 97d2fb
{
Packit Service 97d2fb
  int (*callback) (Dwfl_Frame *frame, void *arg);
Packit Service 97d2fb
  void *arg;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct one_thread *ot = (struct one_thread *) arg;
Packit Service 97d2fb
  return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
Packit Service 97d2fb
		       int (*callback) (Dwfl_Frame *frame, void *arg),
Packit Service 97d2fb
		       void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct one_thread ot = { .callback = callback, .arg = arg };
Packit Service 97d2fb
  return getthread (dwfl, tid, get_one_thread_frames_cb, &ot);
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_getthread_frames)
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_thread_getframes (Dwfl_Thread *thread,
Packit Service 97d2fb
		       int (*callback) (Dwfl_Frame *state, void *arg),
Packit Service 97d2fb
		       void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Ebl *ebl = thread->process->ebl;
Packit Service 97d2fb
  if (ebl_frame_nregs (ebl) == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_NO_UNWIND);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (state_alloc (thread) == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_NOMEM);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  Dwfl_Process *process = thread->process;
Packit Service 97d2fb
  if (! process->callbacks->set_initial_registers (thread,
Packit Service 97d2fb
						   thread->callbacks_arg))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      free_states (thread->unwound);
Packit Service 97d2fb
      thread->unwound = NULL;
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  Dwfl_Frame *state = thread->unwound;
Packit Service 97d2fb
  thread->unwound = NULL;
Packit Service 97d2fb
  if (! state_fetch_pc (state))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (process->callbacks->thread_detach)
Packit Service 97d2fb
	process->callbacks->thread_detach (thread, thread->callbacks_arg);
Packit Service 97d2fb
      free_states (state);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int err = callback (state, arg);
Packit Service 97d2fb
      if (err != DWARF_CB_OK)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (process->callbacks->thread_detach)
Packit Service 97d2fb
	    process->callbacks->thread_detach (thread, thread->callbacks_arg);
Packit Service 97d2fb
	  free_states (state);
Packit Service 97d2fb
	  return err;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      __libdwfl_frame_unwind (state);
Packit Service 97d2fb
      Dwfl_Frame *next = state->unwound;
Packit Service 97d2fb
      /* The old frame is no longer needed.  */
Packit Service 97d2fb
      free (state);
Packit Service 97d2fb
      state = next;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Error err = dwfl_errno ();
Packit Service 97d2fb
  if (process->callbacks->thread_detach)
Packit Service 97d2fb
    process->callbacks->thread_detach (thread, thread->callbacks_arg);
Packit Service 97d2fb
  if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      free_states (state);
Packit Service 97d2fb
      __libdwfl_seterrno (err);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
Packit Service 97d2fb
  free_states (state);
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwfl_thread_getframes)