]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
split:
authorJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 12 Nov 2012 17:41:21 +0000 (18:41 +0100)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 12 Nov 2012 17:41:21 +0000 (18:41 +0100)
libdwfl/dwfl_frame_state.c

libdwfl/Makefile.am
libdwfl/dwfl_frame_state.c
libdwfl/dwfl_frame_state_core.c [new file with mode: 0644]
libdwfl/dwfl_frame_state_data.c [new file with mode: 0644]
libdwfl/dwfl_frame_state_pid.c [new file with mode: 0644]
libdwfl/dwfl_frame_thread_next.c [new file with mode: 0644]
libdwfl/dwfl_frame_tid_get.c [new file with mode: 0644]
libdwfl/libdwflP.h

index 399e30601ea3c1c0257b783dea7f6e7aae8aa2a7..641b9ebfd59307642bdb644e7ec550478bf92363 100644 (file)
@@ -69,7 +69,10 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
                    dwfl_module_register_names.c \
                    dwfl_segment_report_module.c \
                    link_map.c core-file.c open.c image-header.c \
-                   dwfl_frame_state.c dwfl_frame_unwind.c dwfl_frame_state_pc.c
+                   dwfl_frame_state.c dwfl_frame_unwind.c \
+                   dwfl_frame_state_pc.c dwfl_frame_state_pid.c \
+                   dwfl_frame_state_core.c dwfl_frame_state_data.c \
+                   dwfl_frame_thread_next.c dwfl_frame_tid_get.c
 
 if ZLIB
 libdwfl_a_SOURCES += gzip.c
index fef8cb63810fa0b3cff323181eabcd35688d12ca..54267324314e07572d6fb705f641fb34af85a31e 100644 (file)
    not, see <http://www.gnu.org/licenses/>.  */
 
 #include "libdwflP.h"
-#include <fcntl.h>
-#include <unistd.h>
 #include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <dirent.h>
-#include "system.h"
+#include <unistd.h>
 
 #ifndef MIN
 # define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
-/* Exact copy from libdwfl/segment.c.  */
-
-static GElf_Addr
-segment_start (Dwfl *dwfl, GElf_Addr start)
-{
-  if (dwfl->segment_align > 1)
-    start &= -dwfl->segment_align;
-  return start;
-}
-
-/* Exact copy from libdwfl/segment.c.  */
-
-static GElf_Addr
-segment_end (Dwfl *dwfl, GElf_Addr end)
-{
-  if (dwfl->segment_align > 1)
-    end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
-  return end;
-}
-
-static bool
-tid_is_attached (Dwfl *dwfl, pid_t tid)
-{
-  for (Dwfl_Frame_State_Process *process = dwfl->framestatelist; process;
-       process = process->next)
-    for (Dwfl_Frame_State_Thread *thread = process->thread; thread;
-         thread = thread->next)
-      if (thread->tid_attached && thread->tid == tid)
-       return true;
-  return false;
-}
-
-static bool
-state_fetch_pc (Dwfl_Frame_State *state)
+bool
+internal_function
+__libdwfl_state_fetch_pc (Dwfl_Frame_State *state)
 {
   switch (state->pc_state)
   {
@@ -137,8 +101,9 @@ state_alloc (Dwfl_Frame_State_Thread *thread)
   return state;
 }
 
-static void
-thread_free (Dwfl_Frame_State_Thread *thread)
+void
+internal_function
+__libdwfl_thread_free (Dwfl_Frame_State_Thread *thread)
 {
   while (thread->unwound)
     state_free (thread->unwound);
@@ -150,10 +115,9 @@ thread_free (Dwfl_Frame_State_Thread *thread)
   free (thread);
 }
 
-/* One state_alloc is called automatically.  */
-
-static Dwfl_Frame_State_Thread *
-thread_alloc (Dwfl_Frame_State_Process *process, pid_t tid)
+Dwfl_Frame_State_Thread *
+internal_function
+__libdwfl_thread_alloc (Dwfl_Frame_State_Process *process, pid_t tid)
 {
   Dwfl_Frame_State_Thread *thread = malloc (sizeof (*thread));
   if (thread == NULL)
@@ -166,17 +130,18 @@ thread_alloc (Dwfl_Frame_State_Process *process, pid_t tid)
   process->thread = thread;
   if (state_alloc (thread) == NULL)
     {
-      thread_free (thread);
+      __libdwfl_thread_free (thread);
       return NULL;
     }
   return thread;
 }
 
-static void
-process_free (Dwfl_Frame_State_Process *process)
+void
+internal_function
+__libdwfl_process_free (Dwfl_Frame_State_Process *process)
 {
   while (process->thread)
-    thread_free (process->thread);
+    __libdwfl_thread_free (process->thread);
   if (process->ebl_close)
     ebl_closebackend (process->ebl);
   elf_end (process->core);
@@ -188,9 +153,10 @@ process_free (Dwfl_Frame_State_Process *process)
   free (process);
 }
 
-static Dwfl_Frame_State_Process *
-process_alloc (Dwfl *dwfl, dwfl_frame_memory_read_t *memory_read,
-              void *memory_read_user_data)
+Dwfl_Frame_State_Process *
+internal_function
+__libdwfl_process_alloc (Dwfl *dwfl, dwfl_frame_memory_read_t *memory_read,
+                        void *memory_read_user_data)
 {
   Dwfl_Frame_State_Process *process = malloc (sizeof (*process));
   if (process == NULL)
@@ -207,498 +173,3 @@ process_alloc (Dwfl *dwfl, dwfl_frame_memory_read_t *memory_read,
   dwfl->framestatelist = process;
   return process;
 }
-
-static bool
-ptrace_attach (pid_t tid)
-{
-  if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
-    return false;
-  /* FIXME: Handle missing SIGSTOP on old Linux kernels.  */
-  for (;;)
-    {
-      int status;
-      if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
-       {
-         ptrace (PTRACE_DETACH, tid, NULL, NULL);
-         return false;
-       }
-      if (WSTOPSIG (status) == SIGSTOP)
-       break;
-      if (ptrace (PTRACE_CONT, tid, NULL,
-                 (void *) (uintptr_t) WSTOPSIG (status)) != 0)
-       {
-         ptrace (PTRACE_DETACH, tid, NULL, NULL);
-         return false;
-       }
-    }
-  return true;
-}
-
-static bool
-dwfl_frame_state_pid_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
-                                 void *user_data)
-{
-  Dwfl_Frame_State_Process *process = user_data;
-  assert (process->core == NULL && process->thread->tid);
-  if (process->ebl->class == ELFCLASS64)
-    {
-      errno = 0;
-      *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
-                       (void *) (uintptr_t) addr, NULL);
-      if (errno != 0)
-       {
-         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-         return false;
-       }
-      return true;
-    }
-#if SIZEOF_LONG == 8
-  /* We do not care about reads unaliged to 4 bytes boundary.
-     But 0x...ffc read of 8 bytes could overrun a page.  */
-  bool lowered = (addr & 4) != 0;
-  if (lowered)
-    addr -= 4;
-#endif /* SIZEOF_LONG == 8 */
-  errno = 0;
-  *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
-                   (void *) (uintptr_t) addr, NULL);
-  if (errno != 0)
-    {
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return false;
-    }
-#if SIZEOF_LONG == 8
-# if BYTE_ORDER == BIG_ENDIAN
-  if (! lowered)
-    *result >>= 32;
-# else
-  if (lowered)
-    *result >>= 32;
-# endif
-#endif /* SIZEOF_LONG == 8 */
-  *result &= 0xffffffff;
-  return true;
-}
-
-Dwfl_Frame_State *
-dwfl_frame_state_pid (Dwfl *dwfl, pid_t pid)
-{
-  char dirname[64];
-  int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid);
-  assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1);
-  Dwfl_Frame_State_Process *process;
-  process = process_alloc (dwfl, dwfl_frame_state_pid_memory_read, NULL);
-  if (process == NULL)
-    return NULL;
-  process->memory_read_user_data = process;
-  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
-    {
-      Dwfl_Error error = __libdwfl_module_getebl (mod);
-      if (error != DWFL_E_NOERROR)
-       continue;
-      process->ebl = mod->ebl;
-    }
-  if (process->ebl == NULL)
-    {
-      /* Not idenified EBL from any of the modules.  */
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return NULL;
-    }
-  DIR *dir = opendir (dirname);
-  if (dir == NULL)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_ERRNO);
-      return NULL;
-    }
-  for (;;)
-    {
-      errno = 0;
-      struct dirent *dirent = readdir (dir);
-      if (dirent == NULL)
-       {
-         if (errno == 0)
-           break;
-         process_free (process);
-         __libdwfl_seterrno (DWFL_E_ERRNO);
-         return NULL;
-       }
-      if (strcmp (dirent->d_name, ".") == 0
-         || strcmp (dirent->d_name, "..") == 0)
-       continue;
-      char *end;
-      errno = 0;
-      long tidl = strtol (dirent->d_name, &end, 10);
-      if (errno != 0)
-       {
-         process_free (process);
-         __libdwfl_seterrno (DWFL_E_ERRNO);
-         return NULL;
-       }
-      pid_t tid = tidl;
-      if (tidl <= 0 || (end && *end) || tid != tidl)
-       {
-         process_free (process);
-         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-         return NULL;
-       }
-      Dwfl_Frame_State_Thread *thread = thread_alloc (process, tid);
-      if (thread == NULL)
-       {
-         process_free (process);
-         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-         return NULL;
-       }
-      if (! tid_is_attached (dwfl, thread->tid))
-       {
-         if (! ptrace_attach (thread->tid))
-           {
-             thread_free (thread);
-             continue;
-           }
-         thread->tid_attached = true;
-       }
-      Dwfl_Frame_State *state = thread->unwound;
-      if (! ebl_frame_state (state) || ! state_fetch_pc (state))
-       {
-         thread_free (thread);
-         continue;
-       }
-    }
-  if (closedir (dir) != 0)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_ERRNO);
-      return NULL;
-    }
-  if (process->thread == NULL)
-    {
-      /* No valid threads recognized.  */
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return NULL;
-    }
-  return process->thread->unwound;
-}
-INTDEF (dwfl_frame_state_pid)
-
-static bool
-dwfl_frame_state_core_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
-                                  void *user_data)
-{
-  Dwfl_Frame_State_Process *process = user_data;
-  Elf *core = process->core;
-  assert (core != NULL);
-  Dwfl *dwfl = process->dwfl;
-  static size_t phnum;
-  if (elf_getphdrnum (core, &phnum) < 0)
-    {
-      __libdwfl_seterrno (DWFL_E_LIBELF);
-      return false;
-    }
-  for (size_t cnt = 0; cnt < phnum; ++cnt)
-    {
-      GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
-      if (phdr == NULL || phdr->p_type != PT_LOAD)
-       continue;
-      /* Bias is zero here, a core file itself has no bias.  */
-      GElf_Addr start = segment_start (dwfl, phdr->p_vaddr);
-      GElf_Addr end = segment_end (dwfl, phdr->p_vaddr + phdr->p_memsz);
-      unsigned bytes = process->ebl->class == ELFCLASS64 ? 8 : 4;
-      if (addr < start || addr + bytes > end)
-       continue;
-      Elf_Data *data;
-      data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
-                                  bytes, ELF_T_ADDR);
-      if (data == NULL)
-       {
-         __libdwfl_seterrno (DWFL_E_LIBELF);
-         return false;
-       }
-      assert (data->d_size == bytes);
-      /* FIXME: Currently any arch supported for unwinding supports
-        unaligned access.  */
-      if (bytes == 8)
-       *result = *(const uint64_t *) data->d_buf;
-      else
-       *result = *(const uint32_t *) data->d_buf;
-      return true;
-    }
-  __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-  return false;
-}
-
-Dwfl_Frame_State *
-dwfl_frame_state_core (Dwfl *dwfl, const char *corefile)
-{
-  Dwfl_Frame_State_Process *process;
-  process = process_alloc (dwfl, dwfl_frame_state_core_memory_read, NULL);
-  if (process == NULL)
-    return NULL;
-  process->memory_read_user_data = process;
-  int core_fd = open64 (corefile, O_RDONLY);
-  if (core_fd < 0)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_BADELF);
-      return NULL;
-    }
-  process->core_fd = core_fd;
-  Elf *core;
-  Dwfl_Error err = __libdw_open_file (&core_fd, &core, true, false);
-  if (err != DWFL_E_NOERROR)
-    {
-      process_free (process);
-      __libdwfl_seterrno (err);
-      return NULL;
-    }
-  process->core = core;
-  Ebl *ebl = ebl_openbackend (core);
-  if (ebl == NULL)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_LIBEBL);
-      return NULL;
-    }
-  process->ebl = ebl;
-  process->ebl_close = true;
-  size_t nregs = ebl_frame_state_nregs (ebl);
-  if (nregs == 0)
-    {
-      /* We do not support unwinding this CORE file EBL.  */
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_LIBEBL);
-      return NULL;
-    }
-  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem);
-  if (ehdr == NULL)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_LIBELF);
-      return NULL;
-    }
-  assert (ehdr->e_type == ET_CORE);
-  size_t phnum;
-  if (elf_getphdrnum (core, &phnum) < 0)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_LIBELF);
-      return NULL;
-    }
-  Dwfl_Frame_State_Thread *thread = NULL;
-  for (size_t cnt = 0; cnt < phnum; ++cnt)
-    {
-      GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
-      if (phdr == NULL || phdr->p_type != PT_NOTE)
-       continue;
-      Elf_Data *data = elf_getdata_rawchunk (core, phdr->p_offset,
-                                            phdr->p_filesz, ELF_T_NHDR);
-      if (data == NULL)
-       {
-         process_free (process);
-         __libdwfl_seterrno (DWFL_E_LIBELF);
-         return NULL;
-       }
-      size_t offset = 0;
-      GElf_Nhdr nhdr;
-      size_t name_offset;
-      size_t desc_offset;
-      while (offset < data->d_size
-            && (offset = gelf_getnote (data, offset,
-                                       &nhdr, &name_offset, &desc_offset)) > 0)
-       {
-         /* Do not check NAME for now, help broken Linux kernels.  */
-         const char *name = data->d_buf + name_offset;
-         const char *desc = data->d_buf + desc_offset;
-         GElf_Word regs_offset;
-         size_t nregloc;
-         const Ebl_Register_Location *reglocs;
-         size_t nitems;
-         const Ebl_Core_Item *items;
-         if (! ebl_core_note (ebl, &nhdr, name,
-                              &regs_offset, &nregloc, &reglocs, &nitems, &items))
-           {
-             /* This note may be just not recognized, skip it.  */
-             continue;
-           }
-         if (nhdr.n_type == NT_PRSTATUS)
-           {
-             const Ebl_Core_Item *item;
-             for (item = items; item < items + nitems; item++)
-               if (strcmp (item->name, "pid") == 0)
-                 break;
-             if (item == items + nitems)
-               {
-                 process_free (process);
-                 __libdwfl_seterrno (DWFL_E_BADELF);
-                 return NULL;
-               }
-             uint32_t val32 = *(const uint32_t *) (desc + item->offset);
-             val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
-                       ? be32toh (val32) : le32toh (val32));
-             pid_t tid = (int32_t) val32;
-             eu_static_assert (sizeof val32 <= sizeof tid);
-             if (thread)
-               {
-                 /* Delay initialization of THREAD till all notes for it have
-                    been read in.  */
-                 Dwfl_Frame_State *state = thread->unwound;
-                 if (! ebl_frame_state (state) || ! state_fetch_pc (state))
-                   {
-                     thread_free (thread);
-                     thread = NULL;
-                     continue;
-                   }
-               }
-             thread = thread_alloc (process, tid);
-             if (thread == NULL)
-               {
-                 process_free (process);
-                 __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-                 return NULL;
-               }
-           }
-         if (thread == NULL)
-           {
-             /* Ignore notes before first PR_NTSTATUS.  */
-             continue;
-           }
-         Dwfl_Frame_State *state = thread->unwound;
-         desc += regs_offset;
-         for (size_t regloci = 0; regloci < nregloc; regloci++)
-           {
-             const Ebl_Register_Location *regloc = reglocs + regloci;
-             if (regloc->regno >= nregs)
-               continue;
-             assert (regloc->bits == 32 || regloc->bits == 64);
-             const char *reg_desc = desc + regloc->offset;
-             for (unsigned regno = regloc->regno;
-                  regno < MIN (regloc->regno + (regloc->count ?: 1U), nregs);
-                  regno++)
-               {
-                 /* PPC provides DWARF register 65 irrelevant for
-                    CFI which clashes with register 108 (LR) we need.
-                    LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
-                    FIXME: It depends now on their order in core notes.  */
-                 if (dwfl_frame_state_reg_get (state, regno, NULL))
-                   continue;
-                 Dwarf_Addr val;
-                 switch (regloc->bits)
-                 {
-                   case 32:;
-                     uint32_t val32 = *(const uint32_t *) reg_desc;
-                     reg_desc += sizeof val32;
-                     val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
-                              ? be32toh (val32) : le32toh (val32));
-                     /* Do a host width conversion.  */
-                     val = val32;
-                     break;
-                   case 64:;
-                     uint64_t val64 = *(const uint64_t *) reg_desc;
-                     reg_desc += sizeof val64;
-                     val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
-                              ? be64toh (val64) : le64toh (val64));
-                     assert (sizeof (*state->regs) == sizeof val64);
-                     val = val64;
-                     break;
-                   default:
-                     abort ();
-                 }
-                 /* Registers not valid for CFI are just ignored.  */
-                 dwfl_frame_state_reg_set (state, regno, val);
-                 reg_desc += regloc->pad;
-               }
-           }
-       }
-    }
-  if (thread)
-    {
-      /* Delay initialization of THREAD till all notes for it have been read
-        in.  */
-      Dwfl_Frame_State *state = thread->unwound;
-      if (! ebl_frame_state (state) || ! state_fetch_pc (state))
-       thread_free (thread);
-    }
-  if (process->thread == NULL)
-    {
-      /* No valid threads recognized in this CORE.  */
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_BADELF);
-      return NULL;
-    }
-  return process->thread->unwound;
-}
-INTDEF (dwfl_frame_state_core)
-
-Dwfl_Frame_State *
-dwfl_frame_state_data (Dwfl *dwfl, bool pc_set, Dwarf_Addr pc, unsigned nregs,
-                      const uint64_t *regs_set, const Dwarf_Addr *regs,
-                      dwfl_frame_memory_read_t *memory_read,
-                      void *memory_read_user_data)
-{
-  Ebl *ebl = NULL;
-  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
-    {
-      Dwfl_Error error = __libdwfl_module_getebl (mod);
-      if (error != DWFL_E_NOERROR)
-       continue;
-      ebl = mod->ebl;
-    }
-  if (ebl == NULL || nregs > ebl_frame_state_nregs (ebl))
-    {
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return NULL;
-    }
-  Dwfl_Frame_State_Process *process;
-  process = process_alloc (dwfl, memory_read, memory_read_user_data);
-  if (process == NULL)
-    return NULL;
-  process->ebl = ebl;
-  Dwfl_Frame_State_Thread *thread = thread_alloc (process, 0);
-  if (thread == NULL)
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return NULL;
-    }
-  Dwfl_Frame_State *state = thread->unwound;
-  state->pc_state = DWFL_FRAME_STATE_ERROR;
-  if (pc_set)
-    {
-      state->pc = pc;
-      state->pc_state = DWFL_FRAME_STATE_PC_SET;
-    }
-  for (unsigned regno = 0; regno < nregs; regno++)
-    if ((regs_set[regno / sizeof (*regs_set) / 8]
-        & (1U << (regno % (sizeof (*regs_set) * 8)))) != 0
-        && ! dwfl_frame_state_reg_set (state, regno, regs[regno]))
-      {
-       process_free (process);
-       __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-       return NULL;
-      }
-  if (! ebl_frame_state (state) || ! state_fetch_pc (state))
-    {
-      process_free (process);
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return NULL;
-    }
-  return process->thread->unwound;
-}
-INTDEF (dwfl_frame_state_data)
-
-Dwfl_Frame_State *
-dwfl_frame_thread_next (Dwfl_Frame_State *state)
-{
-  Dwfl_Frame_State_Thread *thread_next = state->thread->next;
-  return thread_next ? thread_next->unwound : NULL;
-}
-INTDEF (dwfl_frame_thread_next)
-
-pid_t
-dwfl_frame_tid_get (Dwfl_Frame_State *state)
-{
-  return state->thread->tid;
-}
-INTDEF (dwfl_frame_tid_get)
diff --git a/libdwfl/dwfl_frame_state_core.c b/libdwfl/dwfl_frame_state_core.c
new file mode 100644 (file)
index 0000000..ca4eb93
--- /dev/null
@@ -0,0 +1,305 @@
+/* Get Dwarf Frame state for target core file.
+   Copyright (C) 2012 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdwflP.h"
+#include <fcntl.h>
+#include "system.h"
+
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* Exact copy from libdwfl/segment.c.  */
+
+static GElf_Addr
+segment_start (Dwfl *dwfl, GElf_Addr start)
+{
+  if (dwfl->segment_align > 1)
+    start &= -dwfl->segment_align;
+  return start;
+}
+
+/* Exact copy from libdwfl/segment.c.  */
+
+static GElf_Addr
+segment_end (Dwfl *dwfl, GElf_Addr end)
+{
+  if (dwfl->segment_align > 1)
+    end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
+  return end;
+}
+
+static bool
+dwfl_frame_state_core_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
+                                  void *user_data)
+{
+  Dwfl_Frame_State_Process *process = user_data;
+  Elf *core = process->core;
+  assert (core != NULL);
+  Dwfl *dwfl = process->dwfl;
+  static size_t phnum;
+  if (elf_getphdrnum (core, &phnum) < 0)
+    {
+      __libdwfl_seterrno (DWFL_E_LIBELF);
+      return false;
+    }
+  for (size_t cnt = 0; cnt < phnum; ++cnt)
+    {
+      GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
+      if (phdr == NULL || phdr->p_type != PT_LOAD)
+       continue;
+      /* Bias is zero here, a core file itself has no bias.  */
+      GElf_Addr start = segment_start (dwfl, phdr->p_vaddr);
+      GElf_Addr end = segment_end (dwfl, phdr->p_vaddr + phdr->p_memsz);
+      unsigned bytes = process->ebl->class == ELFCLASS64 ? 8 : 4;
+      if (addr < start || addr + bytes > end)
+       continue;
+      Elf_Data *data;
+      data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
+                                  bytes, ELF_T_ADDR);
+      if (data == NULL)
+       {
+         __libdwfl_seterrno (DWFL_E_LIBELF);
+         return false;
+       }
+      assert (data->d_size == bytes);
+      /* FIXME: Currently any arch supported for unwinding supports
+        unaligned access.  */
+      if (bytes == 8)
+       *result = *(const uint64_t *) data->d_buf;
+      else
+       *result = *(const uint32_t *) data->d_buf;
+      return true;
+    }
+  __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+  return false;
+}
+
+Dwfl_Frame_State *
+dwfl_frame_state_core (Dwfl *dwfl, const char *corefile)
+{
+  Dwfl_Frame_State_Process *process;
+  process = __libdwfl_process_alloc (dwfl, dwfl_frame_state_core_memory_read,
+                                    NULL);
+  if (process == NULL)
+    return NULL;
+  process->memory_read_user_data = process;
+  int core_fd = open64 (corefile, O_RDONLY);
+  if (core_fd < 0)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_BADELF);
+      return NULL;
+    }
+  process->core_fd = core_fd;
+  Elf *core;
+  Dwfl_Error err = __libdw_open_file (&core_fd, &core, true, false);
+  if (err != DWFL_E_NOERROR)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (err);
+      return NULL;
+    }
+  process->core = core;
+  Ebl *ebl = ebl_openbackend (core);
+  if (ebl == NULL)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_LIBEBL);
+      return NULL;
+    }
+  process->ebl = ebl;
+  process->ebl_close = true;
+  size_t nregs = ebl_frame_state_nregs (ebl);
+  if (nregs == 0)
+    {
+      /* We do not support unwinding this CORE file EBL.  */
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_LIBEBL);
+      return NULL;
+    }
+  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem);
+  if (ehdr == NULL)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_LIBELF);
+      return NULL;
+    }
+  assert (ehdr->e_type == ET_CORE);
+  size_t phnum;
+  if (elf_getphdrnum (core, &phnum) < 0)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_LIBELF);
+      return NULL;
+    }
+  Dwfl_Frame_State_Thread *thread = NULL;
+  for (size_t cnt = 0; cnt < phnum; ++cnt)
+    {
+      GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
+      if (phdr == NULL || phdr->p_type != PT_NOTE)
+       continue;
+      Elf_Data *data = elf_getdata_rawchunk (core, phdr->p_offset,
+                                            phdr->p_filesz, ELF_T_NHDR);
+      if (data == NULL)
+       {
+         __libdwfl_process_free (process);
+         __libdwfl_seterrno (DWFL_E_LIBELF);
+         return NULL;
+       }
+      size_t offset = 0;
+      GElf_Nhdr nhdr;
+      size_t name_offset;
+      size_t desc_offset;
+      while (offset < data->d_size
+            && (offset = gelf_getnote (data, offset,
+                                       &nhdr, &name_offset, &desc_offset)) > 0)
+       {
+         /* Do not check NAME for now, help broken Linux kernels.  */
+         const char *name = data->d_buf + name_offset;
+         const char *desc = data->d_buf + desc_offset;
+         GElf_Word regs_offset;
+         size_t nregloc;
+         const Ebl_Register_Location *reglocs;
+         size_t nitems;
+         const Ebl_Core_Item *items;
+         if (! ebl_core_note (ebl, &nhdr, name,
+                              &regs_offset, &nregloc, &reglocs, &nitems, &items))
+           {
+             /* This note may be just not recognized, skip it.  */
+             continue;
+           }
+         if (nhdr.n_type == NT_PRSTATUS)
+           {
+             const Ebl_Core_Item *item;
+             for (item = items; item < items + nitems; item++)
+               if (strcmp (item->name, "pid") == 0)
+                 break;
+             if (item == items + nitems)
+               {
+                 __libdwfl_process_free (process);
+                 __libdwfl_seterrno (DWFL_E_BADELF);
+                 return NULL;
+               }
+             uint32_t val32 = *(const uint32_t *) (desc + item->offset);
+             val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
+                       ? be32toh (val32) : le32toh (val32));
+             pid_t tid = (int32_t) val32;
+             eu_static_assert (sizeof val32 <= sizeof tid);
+             if (thread)
+               {
+                 /* Delay initialization of THREAD till all notes for it have
+                    been read in.  */
+                 Dwfl_Frame_State *state = thread->unwound;
+                 if (! ebl_frame_state (state)
+                     || ! __libdwfl_state_fetch_pc (state))
+                   {
+                     __libdwfl_thread_free (thread);
+                     thread = NULL;
+                     continue;
+                   }
+               }
+             thread = __libdwfl_thread_alloc (process, tid);
+             if (thread == NULL)
+               {
+                 __libdwfl_process_free (process);
+                 __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+                 return NULL;
+               }
+           }
+         if (thread == NULL)
+           {
+             /* Ignore notes before first PR_NTSTATUS.  */
+             continue;
+           }
+         Dwfl_Frame_State *state = thread->unwound;
+         desc += regs_offset;
+         for (size_t regloci = 0; regloci < nregloc; regloci++)
+           {
+             const Ebl_Register_Location *regloc = reglocs + regloci;
+             if (regloc->regno >= nregs)
+               continue;
+             assert (regloc->bits == 32 || regloc->bits == 64);
+             const char *reg_desc = desc + regloc->offset;
+             for (unsigned regno = regloc->regno;
+                  regno < MIN (regloc->regno + (regloc->count ?: 1U), nregs);
+                  regno++)
+               {
+                 /* PPC provides DWARF register 65 irrelevant for
+                    CFI which clashes with register 108 (LR) we need.
+                    LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
+                    FIXME: It depends now on their order in core notes.  */
+                 if (dwfl_frame_state_reg_get (state, regno, NULL))
+                   continue;
+                 Dwarf_Addr val;
+                 switch (regloc->bits)
+                 {
+                   case 32:;
+                     uint32_t val32 = *(const uint32_t *) reg_desc;
+                     reg_desc += sizeof val32;
+                     val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
+                              ? be32toh (val32) : le32toh (val32));
+                     /* Do a host width conversion.  */
+                     val = val32;
+                     break;
+                   case 64:;
+                     uint64_t val64 = *(const uint64_t *) reg_desc;
+                     reg_desc += sizeof val64;
+                     val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
+                              ? be64toh (val64) : le64toh (val64));
+                     assert (sizeof (*state->regs) == sizeof val64);
+                     val = val64;
+                     break;
+                   default:
+                     abort ();
+                 }
+                 /* Registers not valid for CFI are just ignored.  */
+                 dwfl_frame_state_reg_set (state, regno, val);
+                 reg_desc += regloc->pad;
+               }
+           }
+       }
+    }
+  if (thread)
+    {
+      /* Delay initialization of THREAD till all notes for it have been read
+        in.  */
+      Dwfl_Frame_State *state = thread->unwound;
+      if (! ebl_frame_state (state) || ! __libdwfl_state_fetch_pc (state))
+       __libdwfl_thread_free (thread);
+    }
+  if (process->thread == NULL)
+    {
+      /* No valid threads recognized in this CORE.  */
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_BADELF);
+      return NULL;
+    }
+  return process->thread->unwound;
+}
+INTDEF (dwfl_frame_state_core)
diff --git a/libdwfl/dwfl_frame_state_data.c b/libdwfl/dwfl_frame_state_data.c
new file mode 100644 (file)
index 0000000..39accb3
--- /dev/null
@@ -0,0 +1,86 @@
+/* Get Dwarf Frame state from modules present in DWFL.
+   Copyright (C) 2012 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdwflP.h"
+
+Dwfl_Frame_State *
+dwfl_frame_state_data (Dwfl *dwfl, bool pc_set, Dwarf_Addr pc, unsigned nregs,
+                      const uint64_t *regs_set, const Dwarf_Addr *regs,
+                      dwfl_frame_memory_read_t *memory_read,
+                      void *memory_read_user_data)
+{
+  Ebl *ebl = NULL;
+  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
+    {
+      Dwfl_Error error = __libdwfl_module_getebl (mod);
+      if (error != DWFL_E_NOERROR)
+       continue;
+      ebl = mod->ebl;
+    }
+  if (ebl == NULL || nregs > ebl_frame_state_nregs (ebl))
+    {
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return NULL;
+    }
+  Dwfl_Frame_State_Process *process;
+  process = __libdwfl_process_alloc (dwfl, memory_read, memory_read_user_data);
+  if (process == NULL)
+    return NULL;
+  process->ebl = ebl;
+  Dwfl_Frame_State_Thread *thread = __libdwfl_thread_alloc (process, 0);
+  if (thread == NULL)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return NULL;
+    }
+  Dwfl_Frame_State *state = thread->unwound;
+  state->pc_state = DWFL_FRAME_STATE_ERROR;
+  if (pc_set)
+    {
+      state->pc = pc;
+      state->pc_state = DWFL_FRAME_STATE_PC_SET;
+    }
+  for (unsigned regno = 0; regno < nregs; regno++)
+    if ((regs_set[regno / sizeof (*regs_set) / 8]
+        & (1U << (regno % (sizeof (*regs_set) * 8)))) != 0
+        && ! dwfl_frame_state_reg_set (state, regno, regs[regno]))
+      {
+       __libdwfl_process_free (process);
+       __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+       return NULL;
+      }
+  if (! ebl_frame_state (state) || ! __libdwfl_state_fetch_pc (state))
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return NULL;
+    }
+  return process->thread->unwound;
+}
+INTDEF (dwfl_frame_state_data)
diff --git a/libdwfl/dwfl_frame_state_pid.c b/libdwfl/dwfl_frame_state_pid.c
new file mode 100644 (file)
index 0000000..9a7e4ff
--- /dev/null
@@ -0,0 +1,220 @@
+/* Get Dwarf Frame state for target live PID process.
+   Copyright (C) 2012 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdwflP.h"
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <dirent.h>
+
+static bool
+tid_is_attached (Dwfl *dwfl, pid_t tid)
+{
+  for (Dwfl_Frame_State_Process *process = dwfl->framestatelist; process;
+       process = process->next)
+    for (Dwfl_Frame_State_Thread *thread = process->thread; thread;
+         thread = thread->next)
+      if (thread->tid_attached && thread->tid == tid)
+       return true;
+  return false;
+}
+
+static bool
+ptrace_attach (pid_t tid)
+{
+  if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
+    return false;
+  /* FIXME: Handle missing SIGSTOP on old Linux kernels.  */
+  for (;;)
+    {
+      int status;
+      if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
+       {
+         ptrace (PTRACE_DETACH, tid, NULL, NULL);
+         return false;
+       }
+      if (WSTOPSIG (status) == SIGSTOP)
+       break;
+      if (ptrace (PTRACE_CONT, tid, NULL,
+                 (void *) (uintptr_t) WSTOPSIG (status)) != 0)
+       {
+         ptrace (PTRACE_DETACH, tid, NULL, NULL);
+         return false;
+       }
+    }
+  return true;
+}
+
+static bool
+dwfl_frame_state_pid_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
+                                 void *user_data)
+{
+  Dwfl_Frame_State_Process *process = user_data;
+  assert (process->core == NULL && process->thread->tid);
+  if (process->ebl->class == ELFCLASS64)
+    {
+      errno = 0;
+      *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
+                       (void *) (uintptr_t) addr, NULL);
+      if (errno != 0)
+       {
+         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+         return false;
+       }
+      return true;
+    }
+#if SIZEOF_LONG == 8
+  /* We do not care about reads unaliged to 4 bytes boundary.
+     But 0x...ffc read of 8 bytes could overrun a page.  */
+  bool lowered = (addr & 4) != 0;
+  if (lowered)
+    addr -= 4;
+#endif /* SIZEOF_LONG == 8 */
+  errno = 0;
+  *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
+                   (void *) (uintptr_t) addr, NULL);
+  if (errno != 0)
+    {
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return false;
+    }
+#if SIZEOF_LONG == 8
+# if BYTE_ORDER == BIG_ENDIAN
+  if (! lowered)
+    *result >>= 32;
+# else
+  if (lowered)
+    *result >>= 32;
+# endif
+#endif /* SIZEOF_LONG == 8 */
+  *result &= 0xffffffff;
+  return true;
+}
+
+Dwfl_Frame_State *
+dwfl_frame_state_pid (Dwfl *dwfl, pid_t pid)
+{
+  char dirname[64];
+  int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid);
+  assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1);
+  Dwfl_Frame_State_Process *process;
+  process = __libdwfl_process_alloc (dwfl, dwfl_frame_state_pid_memory_read,
+                                    NULL);
+  if (process == NULL)
+    return NULL;
+  process->memory_read_user_data = process;
+  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
+    {
+      Dwfl_Error error = __libdwfl_module_getebl (mod);
+      if (error != DWFL_E_NOERROR)
+       continue;
+      process->ebl = mod->ebl;
+    }
+  if (process->ebl == NULL)
+    {
+      /* Not idenified EBL from any of the modules.  */
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return NULL;
+    }
+  DIR *dir = opendir (dirname);
+  if (dir == NULL)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_ERRNO);
+      return NULL;
+    }
+  for (;;)
+    {
+      errno = 0;
+      struct dirent *dirent = readdir (dir);
+      if (dirent == NULL)
+       {
+         if (errno == 0)
+           break;
+         __libdwfl_process_free (process);
+         __libdwfl_seterrno (DWFL_E_ERRNO);
+         return NULL;
+       }
+      if (strcmp (dirent->d_name, ".") == 0
+         || strcmp (dirent->d_name, "..") == 0)
+       continue;
+      char *end;
+      errno = 0;
+      long tidl = strtol (dirent->d_name, &end, 10);
+      if (errno != 0)
+       {
+         __libdwfl_process_free (process);
+         __libdwfl_seterrno (DWFL_E_ERRNO);
+         return NULL;
+       }
+      pid_t tid = tidl;
+      if (tidl <= 0 || (end && *end) || tid != tidl)
+       {
+         __libdwfl_process_free (process);
+         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+         return NULL;
+       }
+      Dwfl_Frame_State_Thread *thread = __libdwfl_thread_alloc (process, tid);
+      if (thread == NULL)
+       {
+         __libdwfl_process_free (process);
+         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+         return NULL;
+       }
+      if (! tid_is_attached (dwfl, thread->tid))
+       {
+         if (! ptrace_attach (thread->tid))
+           {
+             __libdwfl_thread_free (thread);
+             continue;
+           }
+         thread->tid_attached = true;
+       }
+      Dwfl_Frame_State *state = thread->unwound;
+      if (! ebl_frame_state (state) || ! __libdwfl_state_fetch_pc (state))
+       {
+         __libdwfl_thread_free (thread);
+         continue;
+       }
+    }
+  if (closedir (dir) != 0)
+    {
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_ERRNO);
+      return NULL;
+    }
+  if (process->thread == NULL)
+    {
+      /* No valid threads recognized.  */
+      __libdwfl_process_free (process);
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return NULL;
+    }
+  return process->thread->unwound;
+}
+INTDEF (dwfl_frame_state_pid)
diff --git a/libdwfl/dwfl_frame_thread_next.c b/libdwfl/dwfl_frame_thread_next.c
new file mode 100644 (file)
index 0000000..df4aebb
--- /dev/null
@@ -0,0 +1,37 @@
+/* Get innermost frame of the next thread from state.
+   Copyright (C) 2012 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdwflP.h"
+
+Dwfl_Frame_State *
+dwfl_frame_thread_next (Dwfl_Frame_State *state)
+{
+  Dwfl_Frame_State_Thread *thread_next = state->thread->next;
+  return thread_next ? thread_next->unwound : NULL;
+}
+INTDEF (dwfl_frame_thread_next)
diff --git a/libdwfl/dwfl_frame_tid_get.c b/libdwfl/dwfl_frame_tid_get.c
new file mode 100644 (file)
index 0000000..7883b5e
--- /dev/null
@@ -0,0 +1,36 @@
+/* Get Task ID of the thread of state.
+   Copyright (C) 2012 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdwflP.h"
+
+pid_t
+dwfl_frame_tid_get (Dwfl_Frame_State *state)
+{
+  return state->thread->tid;
+}
+INTDEF (dwfl_frame_tid_get)
index 19d5d9cd388e4af5ec5ffaa328b9c083fa9b7ee4..5b24392022ee7b04cc9a38e557175eac8a29e7f6 100644 (file)
@@ -472,6 +472,32 @@ extern Dwfl_Module *__libdwfl_report_offline (Dwfl *dwfl, const char *name,
                                                                const char *))
   internal_function;
 
+/* Set STATE->pc_set from STATE->regs according to the backend.  Return true on
+   success, false on error.  */
+extern bool __libdwfl_state_fetch_pc (Dwfl_Frame_State *state)
+  internal_function;
+
+/* Free and unlink THREAD from the internal lists.  */
+extern void __libdwfl_thread_free (Dwfl_Frame_State_Thread *thread)
+  internal_function;
+
+/* Allocate new Dwfl_Frame_State_Thread for PID and link it to PROCESS.
+   Automatically create and link in also the first Dwfl_Frame_State.  */
+extern Dwfl_Frame_State_Thread *
+  __libdwfl_thread_alloc (Dwfl_Frame_State_Process *process, pid_t tid)
+  internal_function;
+
+/* Free PROCESS.  Unlink and free also any structures it references.  */
+extern void __libdwfl_process_free (Dwfl_Frame_State_Process *process)
+  internal_function;
+
+/* Allocate new Dwfl_Frame_State_Process for DWFL with callback MEMORY_READ
+   (which is passed MEMORY_READ_USER_DATA).  */
+extern Dwfl_Frame_State_Process *
+  __libdwfl_process_alloc (Dwfl *dwfl, dwfl_frame_memory_read_t *memory_read,
+                          void *memory_read_user_data)
+  internal_function;
+
 /* Decompression wrappers: decompress whole file into memory.  */
 extern Dwfl_Error __libdw_gunzip  (int fd, off64_t start_offset,
                                   void *mapped, size_t mapped_size,