]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Unwind branch migrated from Monotone.
authorRoland McGrath <roland@redhat.com>
Wed, 10 Dec 2008 22:41:45 +0000 (14:41 -0800)
committerRoland McGrath <roland@redhat.com>
Wed, 10 Dec 2008 22:41:45 +0000 (14:41 -0800)
48 files changed:
backends/ChangeLog
backends/Makefile.am
backends/i386_cfi.c [new file with mode: 0644]
backends/i386_init.c
backends/x86_64_cfi.c [new file with mode: 0644]
backends/x86_64_init.c
libdw/ChangeLog
libdw/Makefile.am
libdw/cie.c [new file with mode: 0644]
libdw/dwarf.h
libdw/dwarf_cfi_addrframe.c [new file with mode: 0644]
libdw/dwarf_cfi_end.c [new file with mode: 0644]
libdw/dwarf_cfi_setebl.c [new file with mode: 0644]
libdw/dwarf_end.c
libdw/dwarf_error.c
libdw/dwarf_frame_cfa.c [new file with mode: 0644]
libdw/dwarf_frame_register.c [new file with mode: 0644]
libdw/dwarf_frame_return_address_register.c [new file with mode: 0644]
libdw/dwarf_getcfi.c [new file with mode: 0644]
libdw/dwarf_getcfi_elf.c [new file with mode: 0644]
libdw/dwarf_getlocation.c
libdw/dwarf_next_cfi.c [new file with mode: 0644]
libdw/encoded-value.h [new file with mode: 0644]
libdw/fde.c [new file with mode: 0644]
libdw/frame-cache.c [new file with mode: 0644]
libdw/libdw.map
libdw/libdwP.h
libdw/memory-access.h
libdw/unwind.c [new file with mode: 0644]
libdw/unwind.h [new file with mode: 0644]
libdw/unwindP.h [new file with mode: 0644]
libdwfl/ChangeLog
libdwfl/Makefile.am
libdwfl/dwfl_addrframe.c [new file with mode: 0644]
libdwfl/dwfl_module_getcfi.c [new file with mode: 0644]
libdwfl/libdwflP.h
libebl/ChangeLog
libebl/Makefile.am
libebl/ebl-hooks.h
libebl/eblabicfi.c [new file with mode: 0644]
libebl/eblopenbackend.c
libebl/libebl.h
libebl/libeblP.h
src/ChangeLog
src/readelf.c
tests/ChangeLog
tests/Makefile.am
tests/addrcfi.c [new file with mode: 0644]

index 85609b155a123f078d1da39bf775b696899782fa..6ec64df0d810e47a6fc6b7349eab16266bddc18d 100644 (file)
@@ -1,3 +1,13 @@
+2007-01-18  Roland McGrath  <roland@redhat.com>
+
+       * x86_64_cfi.c (x86_64_abi_cfi): New file.
+       * Makefile.am (x86_64_SRCS): Add it.
+       * x86_64_init.c (x86_64_init): Add initializer.
+
+       * i386_cfi.c (i386_abi_cfi): New file.
+       * Makefile.am (i386_SRCS): Add it.
+       * i386_init.c (i386_init): Initialize abi_cfi hook.
+
 2008-10-04  Ulrich Drepper  <drepper@redhat.com>
 
        * i386_reloc.def: Fix entries for TLS_GOTDESC, TLS_DESC_CALL, and
index 5b552946c805f442536c2b02fe9717712e02cc83..a47519f19ebaf72f78ebbfa7ff4dfef32cc8474a 100644 (file)
@@ -60,7 +60,7 @@ endif
 textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi
 
 
-i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c \
+i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c i386_cfi.c \
            i386_retval.c i386_regs.c i386_auxv.c i386_syscall.c
 cpu_i386 = ../libcpu/libcpu_i386.a
 libebl_i386_pic_a_SOURCES = $(i386_SRCS)
@@ -70,7 +70,7 @@ sh_SRCS = sh_init.c sh_symbol.c
 libebl_sh_pic_a_SOURCES = $(sh_SRCS)
 am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os)
 
-x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c \
+x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c x86_64_cfi.c \
              x86_64_retval.c x86_64_regs.c i386_auxv.c x86_64_syscall.c
 cpu_x86_64 = ../libcpu/libcpu_x86_64.a
 libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS)
diff --git a/backends/i386_cfi.c b/backends/i386_cfi.c
new file mode 100644 (file)
index 0000000..3049469
--- /dev/null
@@ -0,0 +1,65 @@
+/* i386 ABI-specified defaults for DWARF CFI.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+
+#define BACKEND i386_
+#include "libebl_CPU.h"
+
+int
+i386_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info)
+{
+  static const uint8_t abi_cfi[] =
+    {
+      /* Call-saved regs.  */
+      DW_CFA_same_value, ULEB128_7 (3), /* %ebx */
+      DW_CFA_same_value, ULEB128_7 (5), /* %ebp */
+      DW_CFA_same_value, ULEB128_7 (6), /* %esi */
+      DW_CFA_same_value, ULEB128_7 (7), /* %edi */
+
+      /* The CFA is the SP.  */
+      DW_CFA_val_offset, ULEB128_7 (4), ULEB128_7 (0),
+
+      /* Segment registers are call-saved if ever used at all.  */
+      DW_CFA_same_value, ULEB128_7 (40), /* %es */
+      DW_CFA_same_value, ULEB128_7 (41), /* %cs */
+      DW_CFA_same_value, ULEB128_7 (42), /* %ss */
+      DW_CFA_same_value, ULEB128_7 (43), /* %ds */
+      DW_CFA_same_value, ULEB128_7 (44), /* %fs */
+      DW_CFA_same_value, ULEB128_7 (45), /* %gs */
+    };
+
+  abi_info->initial_instructions = abi_cfi;
+  abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
+  abi_info->data_alignment_factor = 4;
+
+  abi_info->return_address_register = 8; /* %eip */
+
+  return 0;
+}
index f046dfb69e9de1b05f9594cd78fdaf2a842b1ef3..b468ae5a83638b731a607d7a744603e984c83a03 100644 (file)
@@ -59,6 +59,7 @@ i386_init (elf, machine, eh, ehlen)
   HOOK (eh, syscall_abi);
   HOOK (eh, auxv_info);
   HOOK (eh, disasm);
+  HOOK (eh, abi_cfi);
 
   return MODVERSION;
 }
diff --git a/backends/x86_64_cfi.c b/backends/x86_64_cfi.c
new file mode 100644 (file)
index 0000000..3057700
--- /dev/null
@@ -0,0 +1,60 @@
+/* x86-64 ABI-specified defaults for DWARF CFI.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+
+#define BACKEND x86_64_
+#include "libebl_CPU.h"
+
+int
+x86_64_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info)
+{
+  static const uint8_t abi_cfi[] =
+    {
+      /* Call-saved regs.  */
+      DW_CFA_same_value, ULEB128_7 (0), /* %rbx */
+      DW_CFA_same_value, ULEB128_7 (6), /* %rbp */
+      DW_CFA_same_value, ULEB128_7 (12), /* %r12 */
+      DW_CFA_same_value, ULEB128_7 (13), /* %r13 */
+      DW_CFA_same_value, ULEB128_7 (14), /* %r14 */
+      DW_CFA_same_value, ULEB128_7 (15), /* %r15 */
+      DW_CFA_same_value, ULEB128_7 (16), /* %r16 */
+
+      /* The CFA is the SP.  */
+      DW_CFA_val_offset, ULEB128_7 (7), ULEB128_7 (0),
+    };
+
+  abi_info->initial_instructions = abi_cfi;
+  abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
+  abi_info->data_alignment_factor = 8;
+
+  abi_info->return_address_register = 8; /* %eip */
+
+  return 0;
+}
index a2eaffa5f35b921b6e07fe609d2955f442fadae9..83b9d9dca74eec5007fff49b521c0c9ce283d9ee 100644 (file)
@@ -56,6 +56,7 @@ x86_64_init (elf, machine, eh, ehlen)
   HOOK (eh, syscall_abi);
   HOOK (eh, auxv_info);
   HOOK (eh, disasm);
+  HOOK (eh, abi_cfi);
 
   return MODVERSION;
 }
index 235fac0130e467186d5ead3cd175260d9bef593d..8a0ea159178d597e86da9cb170d703d7418a20e5 100644 (file)
        * libdw.map (ELFUTILS_0.127): New version set, inherits from
        ELFUTILS_0.126.  Add dwfl_module_addrsym.
 
+2007-02-10  Roland McGrath  <roland@redhat.com>
+
+       * libdw.map (ELFUTILS_0.127): Add dwfl_addrframe, dwfl_module_getcfi.
+
+       * dwarf.h: Define DW_EH_PE_* constants.
+
+       * unwindP.h (struct Dwarf_CFI_s): Add `ebl' member.
+       * dwarf_cfi_setebl.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add it.
+       * unwind.h: Declare dwarf_cfi_setebl.
+       * unwindP.h: Add INTDECL.
+
+       * libdwP.h (struct Dwarf): Add member `cfi'.
+       * dwarf_end.c (dwarf_end): Call __libdw_destroy_frame_cache on it.
+       * dwarf_getcfi.c: New file.
+       * dwarf_getcfi_elf.c: New file.
+       * dwarf_cfi_end.c: New file.
+       * dwarf_cfi_addrframe.c: New file.
+       * dwarf_frame_cfa.c: New file.
+       * dwarf_frame_register.c: New file.
+       * dwarf_frame_return_address_register.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add them.
+       * unwind.h: Declare those functions.
+       * libdw.map (ELFUTILS_0.127): Export them.
+
+       * dwarf_getlocation.c (__libdw_intern_expression): New function,
+       broken out of ...
+       (getlocation): ... here, call it.
+       * libdwP.h: Declare it.
+
+       * cie.c: New file.
+       * fde.c: New file.
+       * frame-cache.c: New file.
+       * unwind.c: New file.
+       * unwindP.h: New file.
+       * encoded-value.h: New file.
+       * Makefile.am (libdw_a_SOURCES, noinst_HEADERS): Add them.
+       * libdwP.h: Add DWARF_E_INVALID_CFI to errors enum.
+       * dwarf_error.c (errmsgs): Add element for it.
+
+       * dwarf.h (DW_CFA_low_user, DW_CFA_high_user): Renamed to
+       DW_CFA_lo_user, DW_CFA_hi_user, to match DWARF 3 spec.
+
+       * unwind.h: New file.
+       * dwarf_next_cfi.c: New file.
+       * Makefile.am (euinclude_HEADERS, libdw_a_SOURCES): Add them.
+       * libdw.map (ELFUTILS_0.127): New set inheriting from ELFUTILS_0.126.
+       Add dwarf_next_cfi.
+
+       * memory-access.h [! ALLOW_UNALIGNED]
+       (read_2ubyte_unaligned): Renamed to ...
+       (read_2ubyte_unaligned_1): ... this.  Take bool rather than Dwarf *.
+       (read_2ubyte_unaligned): Define as macro passing dbg->other_byte_order.
+       (read_2sbyte_unaligned): Likewise.
+       (read_4ubyte_unaligned): Likewise.
+       (read_4sbyte_unaligned): Likewise.
+       (read_8ubyte_unaligned): Likewise.
+       (read_8sbyte_unaligned): Likewise.
+
 2007-02-10  Roland McGrath  <roland@redhat.com>
 
        * dwarf.h (DW_OP_fbreg): Comment fix.
index 69ce526c6aeb3d43698dbb414dc31cead7c17180..51b2cd4c39fea8f5d9793461f29e2fa180fd9846 100644 (file)
@@ -47,7 +47,7 @@ noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
 endif
 
 include_HEADERS = dwarf.h
-pkginclude_HEADERS = libdw.h
+pkginclude_HEADERS = libdw.h unwind.h
 
 libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
@@ -83,7 +83,14 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_func_inline.c dwarf_getsrc_file.c \
                  libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c \
                  libdw_visit_scopes.c \
-                 dwarf_entry_breakpoints.c
+                 dwarf_entry_breakpoints.c \
+                 dwarf_next_cfi.c \
+                 cie.c fde.c unwind.c frame-cache.c \
+                 dwarf_frame_cfa.c dwarf_frame_register.c \
+                 dwarf_frame_return_address_register.c \
+                 dwarf_cfi_addrframe.c \
+                 dwarf_getcfi.c dwarf_getcfi_elf.c \
+                 dwarf_cfi_setebl.c dwarf_cfi_end.c
 
 if !MUDFLAP
 libdw_pic_a_SOURCES =
@@ -126,7 +133,8 @@ endif
 
 libdw_a_LIBADD = $(addprefix ../libdwfl/,$(shell $(AR) t ../libdwfl/libdwfl.a))
 
-noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h
+noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \
+                unwindP.h encoded-value.h
 
 EXTRA_DIST = libdw.map
 
diff --git a/libdw/cie.c b/libdw/cie.c
new file mode 100644 (file)
index 0000000..6f86037
--- /dev/null
@@ -0,0 +1,193 @@
+/* CIE reading.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+#include "encoded-value.h"
+#include <search.h>
+#include <stdlib.h>
+
+
+static int
+compare_cie (const void *a, const void *b)
+{
+  const struct dwarf_cie *cie1 = a;
+  const struct dwarf_cie *cie2 = b;
+  if (cie1->offset < cie2->offset)
+    return -1;
+  if (cie1->offset > cie2->offset)
+    return 1;
+  return 0;
+}
+
+/* There is no CIE at OFFSET in the tree.  Add it.  */
+static struct dwarf_cie *
+intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
+{
+  struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie));
+  if (cie == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  cie->offset = offset;
+  cie->code_alignment_factor = info->code_alignment_factor;
+  cie->data_alignment_factor = info->data_alignment_factor;
+  cie->return_address_register = info->return_address_register;
+
+  cie->fde_augmentation_data_size = 0;
+  cie->sized_augmentation_data = false;
+  cie->signal_frame = false;
+
+  cie->fde_encoding = DW_EH_PE_absptr;
+  cie->lsda_encoding = DW_EH_PE_omit;
+
+  /* Grok the augmentation string and its data.  */
+  const uint8_t *data = info->augmentation_data;
+  for (const char *ap = info->augmentation; *ap != '\0'; ++ap)
+    {
+      uint8_t encoding;
+      switch (*ap)
+       {
+       case 'z':
+         cie->sized_augmentation_data = true;
+         continue;
+
+       case 'S':
+         cie->signal_frame = true;
+         continue;
+
+       case 'L':               /* LSDA pointer encoding byte.  */
+         cie->lsda_encoding = *data++;
+         if (!cie->sized_augmentation_data)
+           cie->fde_augmentation_data_size
+             += encoded_value_size (&cache->data, cache->e_ident,
+                                    cie->lsda_encoding, NULL);
+         continue;
+
+       case 'R':               /* FDE address encoding byte.  */
+         cie->fde_encoding = *data++;
+         continue;
+
+       case 'P':               /* Skip personality routine.  */
+         encoding = *data++;
+         data += encoded_value_size (&cache->data, cache->e_ident,
+                                     encoding, data);
+         continue;
+
+       default:
+         /* Unknown augmentation string.  If we have 'z' we can ignore it,
+            otherwise we must bail out.  */
+         if (cie->sized_augmentation_data)
+           continue;
+       }
+      /* We only get here when we need to bail out.  */
+      break;
+    }
+
+  /* Save the initial instructions to be played out into initial state.  */
+  cie->initial_instructions = info->initial_instructions;
+  cie->initial_instructions_end = info->initial_instructions_end;
+  cie->initial_state = NULL;
+
+  /* Add the new entry to the search tree.  */
+  if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL)
+    {
+      free (cie);
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  return cie;
+}
+
+/* Look up a CIE_pointer for random access.  */
+struct dwarf_cie *
+internal_function
+__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
+{
+  const struct dwarf_cie cie_key = { .offset = offset };
+  struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie);
+  if (found != NULL)
+    return *found;
+
+  /* We have not read this CIE yet.  Go find it.  */
+  Dwarf_Off next_offset = offset;
+  Dwarf_CFI_Entry entry;
+  int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
+                                      &cache->data, cache->eh_frame,
+                                      offset, &next_offset, &entry);
+  if (result != 0 || entry.cie.CIE_id != CIE_ID)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  /* If this happened to be what we would have read next, notice it.  */
+  if (cache->next_offset == offset)
+    cache->next_offset = next_offset;
+
+  return intern_new_cie (cache, offset, &entry.cie);
+}
+
+/* Enter a CIE encountered while reading through for FDEs.  */
+void
+internal_function
+__libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
+{
+  const struct dwarf_cie cie_key = { .offset = offset };
+  struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie);
+  if (found == NULL)
+    /* We have not read this CIE yet.  Enter it.  */
+    (void) intern_new_cie (cache, offset, info);
+}
index f1261c3618f1d135bf1aab01e09b71fa19436575..adbb992bed7a078e19aa940986c85315606d3fae 100644 (file)
@@ -661,13 +661,39 @@ enum
     DW_CFA_val_offset_sf = 0x15,
     DW_CFA_val_expression = 0x16,
 
-    DW_CFA_low_user = 0x1c,
+    DW_CFA_lo_user = 0x1c,
     DW_CFA_MIPS_advance_loc8 = 0x1d,
     DW_CFA_GNU_window_save = 0x2d,
     DW_CFA_GNU_args_size = 0x2e,
-    DW_CFA_high_user = 0x3f
+    DW_CFA_hi_user = 0x3f
   };
 
+/* GNU DWARF exception-handling pointer encodings (not part of DWARF 3).
+   These appear in call-frame information that uses 'R' augmentation, and
+   in .eh_frame_hdr (PT_GNU_EH_FRAME) header format.  */
+enum
+  {
+    DW_EH_PE_absptr = 0x00,
+    DW_EH_PE_omit = 0xff,
+
+    DW_EH_PE_uleb128 = 0x01,
+    DW_EH_PE_udata2 = 0x02,
+    DW_EH_PE_udata4 = 0x03,
+    DW_EH_PE_udata8 = 0x04,
+    DW_EH_PE_sleb128 = 0x09,
+    DW_EH_PE_sdata2 = 0x0a,
+    DW_EH_PE_sdata4 = 0x0b,
+    DW_EH_PE_sdata8 = 0x0c,
+    DW_EH_PE_signed = 0x08,
+
+    DW_EH_PE_pcrel = 0x10,
+    DW_EH_PE_textrel = 0x20,
+    DW_EH_PE_datarel = 0x30,
+    DW_EH_PE_funcrel = 0x40,
+    DW_EH_PE_aligned = 0x50,
+
+    DW_EH_PE_indirect = 0x80
+  };
 
 /* DWARF XXX.  */
 #define DW_ADDR_none   0
diff --git a/libdw/dwarf_cfi_addrframe.c b/libdw/dwarf_cfi_addrframe.c
new file mode 100644 (file)
index 0000000..94ff0bf
--- /dev/null
@@ -0,0 +1,78 @@
+/* Compute frame state at PC.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+
+int
+dwarf_cfi_addrframe (cache, address, frame)
+     Dwarf_CFI *cache;
+     Dwarf_Addr address;
+     Dwarf_Frame **frame;
+{
+  /* Maybe there was a previous error.  */
+  if (cache == NULL)
+    return -1;
+
+  struct dwarf_fde *fde = __libdw_find_fde (cache, address);
+  if (fde == NULL)
+    return -1;
+
+  int error = __libdw_frame_at_address (cache, fde, address, frame);
+  if (error != DWARF_E_NOERROR)
+    {
+      __libdw_seterrno (error);
+      return -1;
+    }
+  return 0;
+}
+INTDEF (dwarf_cfi_addrframe)
diff --git a/libdw/dwarf_cfi_end.c b/libdw/dwarf_cfi_end.c
new file mode 100644 (file)
index 0000000..82cd77b
--- /dev/null
@@ -0,0 +1,70 @@
+/* Clean up Dwarf_CFI structure.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "unwindP.h"
+#include <stdlib.h>
+
+int
+dwarf_cfi_end (cache)
+     Dwarf_CFI *cache;
+{
+  if (cache != NULL)
+    {
+      __libdw_destroy_frame_cache (cache);
+      free (cache);
+    }
+
+  return 0;
+}
+INTDEF (dwarf_cfi_end)
diff --git a/libdw/dwarf_cfi_setebl.c b/libdw/dwarf_cfi_setebl.c
new file mode 100644 (file)
index 0000000..10da0c2
--- /dev/null
@@ -0,0 +1,70 @@
+/* Associate Ebl handle with Dwarf_CFI handle.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "unwindP.h"
+#include "../libebl/libebl.h"
+
+int
+dwarf_cfi_setebl (cfi, ebl)
+     Dwarf_CFI *cfi;
+     Ebl *ebl;
+{
+  if (cfi == NULL)
+    return -1;
+
+  cfi->ebl = ebl;
+
+  return 0;
+}
+INTDEF (dwarf_cfi_setebl)
index 60c9716e47df7237890b9f1b27f9cd8ced3dae15..33f863e9846c89c60423fd4930351bb359a58132 100644 (file)
@@ -1,5 +1,5 @@
 /* Release debugging handling context.
-   Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -56,7 +56,7 @@
 #include <stdlib.h>
 
 #include "libdwP.h"
-
+#include "unwindP.h"
 
 
 static void
@@ -82,6 +82,10 @@ dwarf_end (dwarf)
 {
   if (dwarf != NULL)
     {
+      if (dwarf->cfi != NULL)
+       /* Clean up the CFI cache.  */
+       __libdw_destroy_frame_cache (dwarf->cfi);
+
       /* The search tree for the CUs.  NB: the CU data itself is
         allocated separately, but the abbreviation hash tables need
         to be handled.  */
index fe9166414aa30d6282a8c3da4cd94e317383dea0..5f505429e2486f8d50b1477491f4762b272b4a8f 100644 (file)
@@ -1,5 +1,5 @@
 /* Retrieve ELF descriptor used for DWARF access.
-   Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -143,6 +143,7 @@ static const char *errmsgs[] =
     [DWARF_E_NO_FLAG] = N_("no flag value"),
     [DWARF_E_INVALID_OFFSET] = N_("invalid offset"),
     [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"),
+    [DWARF_E_INVALID_CFI] = N_("invalid CFI section"),
   };
 #define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
 
diff --git a/libdw/dwarf_frame_cfa.c b/libdw/dwarf_frame_cfa.c
new file mode 100644 (file)
index 0000000..766f0cf
--- /dev/null
@@ -0,0 +1,100 @@
+/* Get CFA expression for frame.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+#include <dwarf.h>
+#include <stdlib.h>
+
+int
+dwarf_frame_cfa (fs, ops)
+     Dwarf_Frame *fs;
+     Dwarf_Op **ops;
+{
+  /* Maybe there was a previous error.  */
+  if (fs == NULL)
+    return -1;
+
+  switch (fs->cfa_rule)
+    {
+    case cfa_undefined:
+      *ops = NULL;
+      return 0;
+
+    case cfa_offset:
+      /* The Dwarf_Op was already fully initialized by execute_cfi.  */
+      *ops = &fs->cfa_data.offset;
+      return 1;
+
+    case cfa_expr:
+      {
+       unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32
+                                    ? 4 : 8);
+       size_t nops;
+
+       /* Parse the expression into internal form.  */
+       int result = __libdw_intern_expression (NULL,
+                                               fs->cache->other_byte_order,
+                                               address_size,
+                                               &fs->cache->expr_tree,
+                                               &fs->cfa_data.expr,
+                                               ops, &nops);
+       return result ?: (int) nops;
+      }
+
+    default:
+      abort ();
+    }
+
+  /*NOTREACHED*/
+  return -1;
+}
diff --git a/libdw/dwarf_frame_register.c b/libdw/dwarf_frame_register.c
new file mode 100644 (file)
index 0000000..c57c700
--- /dev/null
@@ -0,0 +1,143 @@
+/* Get register location expression for frame.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+#include <dwarf.h>
+
+int
+dwarf_frame_register (fs, regno, ops_mem, ops, nops)
+     Dwarf_Frame *fs;
+     int regno;
+     Dwarf_Op ops_mem[2];
+     Dwarf_Op **ops;
+     size_t *nops;
+{
+  /* Maybe there was a previous error.  */
+  if (fs == NULL)
+    return -1;
+
+  if (unlikely (regno < 0))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ACCESS);
+      return -1;
+    }
+
+  int result = 0;              /* A location, not a value.  */
+
+  if (unlikely ((size_t) regno >= fs->nregs))
+    goto default_rule;
+
+  const struct dwarf_frame_register *reg = &fs->regs[regno];
+
+  switch (reg->rule)
+    {
+    case reg_unspecified:
+    default_rule:
+      /* Use the default rule for registers not yet mentioned in CFI.  */
+      if (fs->cache->default_same_value)
+       goto same_value;
+      /*FALLTHROUGH*/
+    case reg_undefined:
+      /* The value is known to be unavailable.  */
+      result = 1;
+      /*FALLTHROUGH*/
+    case reg_same_value:
+    same_value:
+      /* The location is not known here, but the caller might know it.  */
+      *ops = NULL;
+      *nops = 0;
+      break;
+
+    case reg_val_offset:
+      result = 1;              /* A value, not a location.  */
+      /*FALLTHROUGH*/
+    case reg_offset:
+      ops_mem[0] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa };
+      ops_mem[1] = (Dwarf_Op) { .atom = DW_OP_plus_uconst,
+                               .number = reg->value };
+      *ops = ops_mem;
+      *nops = reg->value == 0 ? 1 : 2;
+      break;
+
+    case reg_register:
+      ops_mem[0] = (Dwarf_Op) { .atom = DW_OP_regx, .number = reg->value };
+      *ops = ops_mem;
+      *nops = 1;
+      break;
+
+    case reg_val_expression:
+      result = 1;              /* A value, not a location.  */
+      /*FALLTHROUGH*/
+    case reg_expression:
+      {
+       unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32
+                                    ? 4 : 8);
+
+       Dwarf_Block block;
+       const uint8_t *p = fs->cache->data.d_buf + reg->value;
+       get_uleb128 (block.length, p);
+       block.data = (void *) p;
+
+       /* Parse the expression into internal form.  */
+       if (__libdw_intern_expression (NULL,
+                                      fs->cache->other_byte_order,
+                                      address_size,
+                                      &fs->cache->expr_tree,
+                                      &block, ops, nops) < 0)
+         result = -1;
+       break;
+      }
+    }
+
+  return result;
+}
diff --git a/libdw/dwarf_frame_return_address_register.c b/libdw/dwarf_frame_return_address_register.c
new file mode 100644 (file)
index 0000000..0ca3884
--- /dev/null
@@ -0,0 +1,63 @@
+/* Get return address register for frame.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+
+int
+dwarf_frame_return_address_register (fs, signalp)
+     Dwarf_Frame *fs;
+     bool *signalp;
+{
+  *signalp = fs->cie->signal_frame;
+  return fs->cie->return_address_register;
+}
diff --git a/libdw/dwarf_getcfi.c b/libdw/dwarf_getcfi.c
new file mode 100644 (file)
index 0000000..16b5d17
--- /dev/null
@@ -0,0 +1,99 @@
+/* Get CFI from DWARF file.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "unwindP.h"
+#include <dwarf.h>
+
+Dwarf_CFI *
+dwarf_getcfi (dbg)
+     Dwarf *dbg;
+{
+  if (dbg == NULL)
+    return NULL;
+
+  if (dbg->cfi == NULL && (dbg->sectiondata[IDX_debug_frame] != NULL
+                          || dbg->sectiondata[IDX_eh_frame] != NULL))
+    {
+      Dwarf_CFI *cfi = libdw_typed_alloc (dbg, Dwarf_CFI);
+
+      cfi->eh_frame = dbg->sectiondata[IDX_debug_frame] == NULL;
+      cfi->data = *dbg->sectiondata[cfi->eh_frame ? IDX_eh_frame
+                                   : IDX_debug_frame];
+      cfi->rawchunk = false;
+      cfi->elf = dbg->elf;
+
+      cfi->search_table = NULL;
+      cfi->search_table_vaddr = 0;
+      cfi->search_table_rawchunk = NULL;
+      cfi->search_table_entries = 0;
+      cfi->search_table_encoding = DW_EH_PE_omit;
+
+      cfi->frame_vaddr = 0;
+      cfi->textrel = 0;
+      cfi->datarel = 0;
+      if (cfi->eh_frame)
+       cfi->frame_vaddr = -1; // XXX .eh_frame sh_addr
+
+      cfi->e_ident = (unsigned char *) elf_getident (dbg->elf, NULL);
+      cfi->other_byte_order = dbg->other_byte_order;
+
+      cfi->next_offset = 0;
+      cfi->cie_tree = cfi->fde_tree = cfi->expr_tree = NULL;
+
+      dbg->cfi = cfi;
+    }
+
+  return dbg->cfi;
+}
+INTDEF (dwarf_getcfi)
diff --git a/libdw/dwarf_getcfi_elf.c b/libdw/dwarf_getcfi_elf.c
new file mode 100644 (file)
index 0000000..94c46ea
--- /dev/null
@@ -0,0 +1,340 @@
+/* Get CFI from ELF file's exception-handling info.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "libdwP.h"
+#include "unwindP.h"
+#include "encoded-value.h"
+#include <dwarf.h>
+
+
+static Dwarf_CFI *
+allocate_cfi (Elf *elf, GElf_Addr vaddr)
+{
+  Dwarf_CFI *cfi = calloc (1, sizeof *cfi);
+  if (cfi == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  cfi->elf = elf;
+  cfi->e_ident = (unsigned char *) elf_getident (elf, NULL);
+  if (cfi->e_ident == NULL)
+    {
+      free (cfi);
+      __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
+      return NULL;
+    }
+
+  cfi->eh_frame = true;
+  if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
+      || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
+    cfi->other_byte_order = true;
+
+  cfi->frame_vaddr = vaddr;
+  cfi->textrel = 0;            /* XXX ? */
+  cfi->datarel = 0;            /* XXX ? */
+
+  return cfi;
+}
+
+static const uint8_t *
+parse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr,
+                   const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr,
+                   size_t *table_entries, uint8_t *table_encoding)
+{
+  const uint8_t *h = hdr;
+
+  if (*h++ != 1)               /* version */
+    return (void *) -1l;
+
+  uint8_t eh_frame_ptr_encoding = *h++;
+  uint8_t fde_count_encoding = *h++;
+  uint8_t fde_table_encoding = *h++;
+
+  if (eh_frame_ptr_encoding == DW_EH_PE_omit)
+    return (void *) -1l;
+
+  /* Dummy used by read_encoded_value.  */
+  Dwarf_CFI dummy_cfi =
+    {
+      .e_ident = ehdr->e_ident,
+      .datarel = hdr_vaddr,
+      .frame_vaddr = hdr_vaddr,
+      .data = { .d_buf = (void *) hdr, .d_size = hdr_size }
+    };
+
+  *eh_frame_vaddr = read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h);
+
+  if (fde_count_encoding != DW_EH_PE_omit)
+    {
+      Dwarf_Word fde_count = read_encoded_value (&dummy_cfi,
+                                                fde_count_encoding, &h);
+      if (fde_count != 0 && (size_t) fde_count == fde_count
+         && fde_table_encoding != DW_EH_PE_omit
+         && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
+       {
+         *table_entries = fde_count;
+         *table_encoding = fde_table_encoding;
+         return h;
+       }
+    }
+
+  return NULL;
+}
+
+static Dwarf_CFI *
+getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
+{
+  if (unlikely (phdr->p_filesz < 4))
+    goto invalid;
+
+  void *const hdr = gelf_rawchunk (elf, phdr->p_offset, phdr->p_filesz);
+  if (hdr == NULL)
+    {
+    invalid_hdr:
+      gelf_freechunk (elf, hdr);
+    invalid:
+      /* XXX might be read error or corrupt phdr */
+      __libdw_seterrno (DWARF_E_INVALID_CFI);
+      return NULL;
+    }
+
+  Dwarf_Addr eh_frame_ptr;
+  size_t search_table_entries;
+  uint8_t search_table_encoding;
+  const uint8_t *search_table = parse_eh_frame_hdr (hdr, phdr->p_filesz,
+                                                   phdr->p_vaddr, ehdr,
+                                                   &eh_frame_ptr,
+                                                   &search_table_entries,
+                                                   &search_table_encoding);
+  if (search_table == (void *) -1l)
+    goto invalid_hdr;
+
+  Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
+  Dwarf_Word eh_frame_size = 0;
+
+  /* XXX we have no way without section headers to know the size
+     of the .eh_frame data.  Calculate the largest it might possibly be.
+     This won't be wasteful if the file is already mmap'd, but if it isn't
+     it might be quite excessive.  */
+  size_t filesize;
+  if (elf_rawfile (elf, &filesize) != NULL)
+    eh_frame_size = filesize - eh_frame_offset;
+
+  Elf_Data data = { .d_version = EV_CURRENT };
+  data.d_buf = gelf_rawchunk (elf, eh_frame_offset, eh_frame_size);
+  data.d_size = eh_frame_size;
+  if (data.d_buf == NULL)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
+      gelf_freechunk (elf, hdr);
+      return NULL;
+    }
+  Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr);
+  if (cfi == NULL)
+    {
+      gelf_freechunk (elf, hdr);
+      gelf_freechunk (elf, data.d_buf);
+    }
+  else
+    {
+      cfi->data = data;
+      cfi->rawchunk = true;
+
+      if (search_table != NULL)
+       {
+         cfi->search_table = search_table;
+         cfi->search_table_vaddr = phdr->p_vaddr;
+         cfi->search_table_encoding = search_table_encoding;
+         cfi->search_table_entries = search_table_entries;
+         cfi->search_table_rawchunk = hdr;
+       }
+      else
+       gelf_freechunk (elf, hdr);
+    }
+  return cfi;
+}
+
+/* Search the phdrs for PT_GNU_EH_FRAME.  */
+static Dwarf_CFI *
+getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
+{
+  const uint_fast16_t phnum = ehdr->e_phnum;
+
+  for (uint_fast16_t i = 0; i < phnum; ++i)
+    {
+      GElf_Phdr phdr_mem;
+      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
+      if (unlikely (phdr == NULL))
+       return NULL;
+      if (phdr->p_type == PT_GNU_EH_FRAME)
+       return getcfi_gnu_eh_frame (elf, ehdr, phdr);
+    }
+
+  __libdw_seterrno (DWARF_E_NO_DWARF);
+  return NULL;
+}
+
+static Dwarf_CFI *
+getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
+                    Elf_Scn *scn, GElf_Shdr *shdr,
+                    Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
+{
+  Elf_Data *data = elf_rawdata (scn, NULL);
+  if (data == NULL)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ELF);
+      return NULL;
+    }
+  Dwarf_CFI *cfi = allocate_cfi (elf, shdr->sh_addr);
+  if (cfi != NULL)
+    {
+      cfi->data = *data;
+      if (hdr_scn != NULL)
+       {
+         Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
+         if (hdr_data != NULL)
+           {
+             GElf_Addr eh_frame_vaddr;
+             cfi->search_table_vaddr = hdr_vaddr;
+             cfi->search_table
+               = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
+                                     hdr_vaddr, ehdr, &eh_frame_vaddr,
+                                     &cfi->search_table_entries,
+                                     &cfi->search_table_encoding);
+             if (cfi->search_table == (void *) -1l)
+               {
+                 free (cfi);
+                 /* XXX might be read error or corrupt phdr */
+                 __libdw_seterrno (DWARF_E_INVALID_CFI);
+                 return NULL;
+               }
+
+             /* Sanity check.  */
+             if (unlikely (eh_frame_vaddr != shdr->sh_addr))
+               cfi->search_table = NULL;
+           }
+       }
+    }
+  return cfi;
+}
+
+/* Search for the section named ".eh_frame".  */
+static Dwarf_CFI *
+getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
+{
+  size_t shstrndx;
+  if (elf_getshstrndx (elf, &shstrndx) != 0)
+    {
+      __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
+      return NULL;
+    }
+
+  if (shstrndx != 0)
+    {
+      Elf_Scn *hdr_scn = NULL;
+      GElf_Addr hdr_vaddr = 0;
+      Elf_Scn *scn = NULL;
+      while ((scn = elf_nextscn (elf, scn)) != NULL)
+       {
+         GElf_Shdr shdr_mem;
+         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+         if (shdr == NULL)
+           continue;
+         const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
+         if (name == NULL)
+           continue;
+         if (!strcmp (name, ".eh_frame_hdr"))
+           {
+             hdr_scn = scn;
+             hdr_vaddr = shdr->sh_addr;
+           }
+         else if (!strcmp (name, ".eh_frame"))
+           return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
+                                       hdr_scn, hdr_vaddr);
+       }
+    }
+
+  return (void *) -1l;
+}
+
+Dwarf_CFI *
+dwarf_getcfi_elf (elf)
+     Elf *elf;
+{
+  if (elf_kind (elf) != ELF_K_ELF)
+    {
+      __libdw_seterrno (DWARF_E_NOELF);
+      return NULL;
+    }
+
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+  if (unlikely (ehdr == NULL))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ELF);
+      return NULL;
+    }
+
+  Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
+  if (result == (void *) -1l)
+    result = getcfi_phdr (elf, ehdr);
+
+  return result;
+}
+INTDEF (dwarf_getcfi_elf)
index f680aa9692e3673c66935c763be0f9186834d226..c3233e293c668837f48e1f47602ca084e29ddf1d 100644 (file)
@@ -1,5 +1,5 @@
 /* Return location expression list.
-   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
@@ -111,15 +111,16 @@ loc_compare (const void *p1, const void *p2)
   return 0;
 }
 
-static int
-getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
-            Dwarf_Op **llbuf, size_t *listlen)
+int
+internal_function
+__libdw_intern_expression (Dwarf *dbg,
+                          bool other_byte_order, unsigned int address_size,
+                          void **cache, const Dwarf_Block *block,
+                          Dwarf_Op **llbuf, size_t *listlen)
 {
-  Dwarf *dbg = cu->dbg;
-
   /* Check whether we already looked at this list.  */
   struct loc_s fake = { .addr = block->data };
-  struct loc_s **found = tfind (&fake, &cu->locs, loc_compare);
+  struct loc_s **found = tfind (&fake, cache, loc_compare);
   if (found != NULL)
     {
       /* We already saw it.  */
@@ -132,6 +133,8 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
   const unsigned char *data = block->data;
   const unsigned char *const end_data = data + block->length;
 
+  const struct { bool other_byte_order; } bo = { other_byte_order };
+
   struct loclist *loclist = NULL;
   unsigned int n = 0;
   /* Decode the opcodes.  It is possible in some situations to have a
@@ -151,7 +154,7 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
        {
        case DW_OP_addr:
          /* Address, depends on address size of CU.  */
-         if (cu->address_size == 4)
+         if (address_size == 4)
            {
              if (unlikely (data + 4 > end_data))
                {
@@ -160,14 +163,14 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
                  return -1;
                }
 
-             newloc->number = read_4ubyte_unaligned_inc (dbg, data);
+             newloc->number = read_4ubyte_unaligned_inc (&bo, data);
            }
          else
            {
              if (unlikely (data + 8 > end_data))
                goto invalid;
 
-             newloc->number = read_8ubyte_unaligned_inc (dbg, data);
+             newloc->number = read_8ubyte_unaligned_inc (&bo, data);
            }
          break;
 
@@ -228,7 +231,7 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
          if (unlikely (data + 2 > end_data))
            goto invalid;
 
-         newloc->number = read_2ubyte_unaligned_inc (dbg, data);
+         newloc->number = read_2ubyte_unaligned_inc (&bo, data);
          break;
 
        case DW_OP_const2s:
@@ -238,14 +241,14 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
          if (unlikely (data + 2 > end_data))
            goto invalid;
 
-         newloc->number = read_2sbyte_unaligned_inc (dbg, data);
+         newloc->number = read_2sbyte_unaligned_inc (&bo, data);
          break;
 
        case DW_OP_const4u:
          if (unlikely (data + 4 > end_data))
            goto invalid;
 
-         newloc->number = read_4ubyte_unaligned_inc (dbg, data);
+         newloc->number = read_4ubyte_unaligned_inc (&bo, data);
          break;
 
        case DW_OP_const4s:
@@ -253,21 +256,21 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
          if (unlikely (data + 4 > end_data))
            goto invalid;
 
-         newloc->number = read_4sbyte_unaligned_inc (dbg, data);
+         newloc->number = read_4sbyte_unaligned_inc (&bo, data);
          break;
 
        case DW_OP_const8u:
          if (unlikely (data + 8 > end_data))
            goto invalid;
 
-         newloc->number = read_8ubyte_unaligned_inc (dbg, data);
+         newloc->number = read_8ubyte_unaligned_inc (&bo, data);
          break;
 
        case DW_OP_const8s:
          if (unlikely (data + 8 > end_data))
            goto invalid;
 
-         newloc->number = read_8sbyte_unaligned_inc (dbg, data);
+         newloc->number = read_8sbyte_unaligned_inc (&bo, data);
          break;
 
        case DW_OP_constu:
@@ -305,7 +308,19 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
     }
 
   /* Allocate the array.  */
-  Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
+  Dwarf_Op *result;
+  if (dbg != NULL)
+    result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
+  else
+    {
+      result = malloc (sizeof *result * n);
+      if (result == NULL)
+       {
+       nomem:
+         __libdw_seterrno (DWARF_E_NOMEM);
+         return -1;
+       }
+    }
 
   /* Store the result.  */
   *llbuf = result;
@@ -327,17 +342,37 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
 
   /* Insert a record in the search tree so that we can find it again
      later.  */
-  struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s),
-                                   1);
+  struct loc_s *newp;
+  if (dbg != NULL)
+    newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
+  else
+    {
+      newp = malloc (sizeof *newp);
+      if (newp == NULL)
+       {
+         free (result);
+         goto nomem;
+       }
+    }
+
   newp->addr = block->data;
   newp->loc = result;
   newp->nloc = *listlen;
-  (void) tsearch (newp, &cu->locs, loc_compare);
+  (void) tsearch (newp, cache, loc_compare);
 
   /* We did it.  */
   return 0;
 }
 
+static int
+getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
+            Dwarf_Op **llbuf, size_t *listlen)
+{
+  return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
+                                   cu->address_size, &cu->locs,
+                                   block, llbuf, listlen);
+}
+
 int
 dwarf_getlocation (attr, llbuf, listlen)
      Dwarf_Attribute *attr;
diff --git a/libdw/dwarf_next_cfi.c b/libdw/dwarf_next_cfi.c
new file mode 100644 (file)
index 0000000..2fe381a
--- /dev/null
@@ -0,0 +1,234 @@
+/* Advance to next CFI entry.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+#include "encoded-value.h"
+
+#include <string.h>
+
+
+int
+dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry)
+     const unsigned char e_ident[];
+     Elf_Data *data;
+     bool eh_frame_p;
+     Dwarf_Off off;
+     Dwarf_Off *next_off;
+     Dwarf_CFI_Entry *entry;
+{
+  /* Dummy struct for memory-access.h macros.  */
+  BYTE_ORDER_DUMMY (dw, e_ident);
+
+  /* If we reached the end before don't do anything.  */
+  if (off == (Dwarf_Off) -1l
+      /* Make sure there is enough space in the .debug_frame section
+        for at least the initial word.  We cannot test the rest since
+        we don't know yet whether this is a 64-bit object or not.  */
+      || unlikely (off + 4 >= data->d_size))
+    {
+      *next_off = (Dwarf_Off) -1l;
+      return 1;
+    }
+
+  /* This points into the .debug_frame section at the start of the entry.  */
+  const uint8_t *bytes = data->d_buf + off;
+  const uint8_t *limit = data->d_buf + data->d_size;
+
+  /* The format of a CFI entry is described in DWARF3 6.4.1:
+   */
+
+  uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes);
+  size_t offset_size = 4;
+  if (length == 0xffffffffu)
+    {
+      /* This is the 64-bit DWARF format.  */
+      offset_size = 8;
+      if (unlikely (limit - bytes < 8))
+       {
+       invalid:
+         __libdw_seterrno (DWARF_E_INVALID_DWARF);
+         return -1;
+       }
+      length = read_8ubyte_unaligned_inc (&dw, bytes);
+    }
+  if (unlikely ((uint64_t) (limit - bytes) < length)
+      || unlikely (length < offset_size + 1))
+    goto invalid;
+
+  /* Now we know how large the entry is.  Note the trick in the
+     computation.  If the offset_size is 4 the '- 4' term undoes the
+     '2 *'.  If offset_size is 8 this term computes the size of the
+     escape value plus the 8 byte offset.  */
+  *next_off = off + (2 * offset_size - 4) + length;
+
+  limit = bytes + length;
+
+  const uint8_t *const cie_pointer_start = bytes;
+  if (offset_size == 8)
+    entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes);
+  else
+    {
+      entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes);
+      /* Canonicalize the 32-bit CIE_ID value to 64 bits.  */
+      if (!eh_frame_p && entry->cie.CIE_id == 0xffffffffu)
+       entry->cie.CIE_id = CIE_ID;
+    }
+  if (eh_frame_p)
+    {
+      /* Canonicalize the .eh_frame CIE pointer to .debug_frame format.  */
+      if (entry->cie.CIE_id == 0)
+       entry->cie.CIE_id = CIE_ID;
+      else
+       {
+         /* In .eh_frame format, a CIE pointer is the distance from where
+            it appears back to the beginning of the CIE.  */
+         ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf;
+         if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos)
+             || unlikely (pos <= (ptrdiff_t) offset_size))
+           goto invalid;
+         entry->cie.CIE_id = pos - entry->cie.CIE_id;
+       }
+    }
+
+  if (entry->cie.CIE_id == CIE_ID)
+    {
+      /* Read the version stamp.  Always an 8-bit value.  */
+      uint8_t version = *bytes++;
+
+      if (version != 1 && version != 3)
+       goto invalid;
+
+      entry->cie.augmentation = (const char *) bytes;
+
+      bytes = memchr (bytes, '\0', limit - bytes);
+      if (bytes == NULL)
+       goto invalid;
+      ++bytes;
+
+      const char *ap = entry->cie.augmentation;
+
+      /* g++ v2 "eh" has pointer immediately following augmentation string,
+        so it must be handled first.  */
+      if (unlikely (ap[0] == 'e' && ap[1] == 'h'))
+       {
+         /* The address size for CFI is implicit in the ELF class.  */
+         unsigned int address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+
+         ap += 2;
+         bytes += address_size;
+       }
+
+      get_uleb128 (entry->cie.code_alignment_factor, bytes);
+      get_sleb128 (entry->cie.data_alignment_factor, bytes);
+
+      if (version == 3)                /* DWARF 3 */
+       get_uleb128 (entry->cie.return_address_register, bytes);
+      else                     /* DWARF 2 */
+       entry->cie.return_address_register = *bytes++;
+
+      /* If we have sized augmentation data,
+        we don't need to grok it all.  */
+      entry->cie.fde_augmentation_data_size = 0;
+      bool sized_augmentation = *ap == 'z';
+      if (sized_augmentation)
+       {
+         get_uleb128 (entry->cie.augmentation_data_size, bytes);
+         if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size)
+           goto invalid;
+         entry->cie.augmentation_data = bytes;
+         bytes += entry->cie.augmentation_data_size;
+       }
+      else
+       {
+         entry->cie.augmentation_data = bytes;
+
+         for (; *ap != '\0'; ++ap)
+           {
+             uint8_t encoding;
+             switch (*ap)
+               {
+               case 'L':               /* Skip LSDA pointer encoding byte.  */
+               case 'R':               /* Skip FDE address encoding byte.  */
+                 encoding = *bytes++;
+                 entry->cie.fde_augmentation_data_size
+                   += encoded_value_size (data, e_ident, encoding, NULL);
+                 continue;
+               case 'P':   /* Skip encoded personality routine pointer. */
+                 encoding = *bytes++;
+                 bytes += encoded_value_size (data, e_ident, encoding, bytes);
+                 continue;
+               case 'S':               /* Skip signal-frame flag.  */
+                 continue;
+               default:
+                 /* Unknown augmentation string.  initial_instructions might
+                    actually start with some augmentation data.  */
+                 break;
+               }
+             break;
+           }
+         entry->cie.augmentation_data_size
+           = bytes - entry->cie.augmentation_data;
+       }
+
+      entry->cie.initial_instructions = bytes;
+      entry->cie.initial_instructions_end = limit;
+    }
+  else
+    {
+      entry->fde.start = bytes;
+      entry->fde.end = limit;
+    }
+
+  return 0;
+}
+INTDEF (dwarf_next_cfi)
diff --git a/libdw/encoded-value.h b/libdw/encoded-value.h
new file mode 100644 (file)
index 0000000..d653dbc
--- /dev/null
@@ -0,0 +1,174 @@
+/* DW_EH_PE_* support for libdw unwinder.
+   Copyright (C) 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifndef _ENCODED_VALUE_H
+#define _ENCODED_VALUE_H 1
+
+#include <dwarf.h>
+#include <stdlib.h>
+#include "unwind.h"            /* XXX */
+
+static size_t __attribute__ ((unused))
+encoded_value_size (const Elf_Data *data, const unsigned char e_ident[],
+                   uint8_t encoding, const uint8_t *p)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+
+  switch (encoding & 0x07)
+    {
+    case DW_EH_PE_udata2:
+      return 2;
+    case DW_EH_PE_udata4:
+      return 4;
+    case DW_EH_PE_udata8:
+      return 8;
+
+    case DW_EH_PE_absptr:
+      return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+
+    case DW_EH_PE_uleb128:
+      if (p != NULL)
+       {
+         const uint8_t *end = p;
+         while (end < (uint8_t *) data->d_buf + data->d_size)
+           if (*end++ & 0x80u)
+             return end - p;
+       }
+
+    default:
+      abort ();
+      return 0;
+    }
+}
+
+static Dwarf_Addr __attribute__ ((unused))
+read_encoded_value (const Dwarf_CFI *cache,
+                   uint8_t encoding, const uint8_t **p)
+{
+  Dwarf_Addr base = 0;
+  switch (encoding & 0x70)
+    {
+    case DW_EH_PE_absptr:
+      break;
+    case DW_EH_PE_pcrel:
+      base = cache->frame_vaddr + (*p - (const uint8_t *) cache->data.d_buf);
+      break;
+    case DW_EH_PE_textrel:
+      // ia64: segrel
+      base = cache->textrel;
+      break;
+    case DW_EH_PE_datarel:
+      // i386: GOTOFF
+      // ia64: gprel
+      base = cache->datarel;
+      break;
+    case DW_EH_PE_funcrel:     /* XXX */
+      break;
+    case DW_EH_PE_aligned:
+      {
+       const size_t address_size
+         = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+       size_t align = ((cache->frame_vaddr
+                        + (*p - (const uint8_t *) cache->data.d_buf))
+                       & (address_size - 1));
+       if (align != 0)
+         *p += address_size - align;
+       break;
+      }
+
+    default:
+      abort ();
+    }
+
+  Dwarf_Addr value;
+  switch (encoding & 0x0f)
+    {
+    case DW_EH_PE_udata2:
+      value = read_2ubyte_unaligned_inc (cache, *p);
+      break;
+    case DW_EH_PE_udata4:
+      value = read_4ubyte_unaligned_inc (cache, *p);
+      break;
+    case DW_EH_PE_udata8:
+      value = read_8ubyte_unaligned_inc (cache, *p);
+      break;
+
+    case DW_EH_PE_sdata2:
+      value = read_2sbyte_unaligned_inc (cache, *p);
+      break;
+    case DW_EH_PE_sdata4:
+      value = read_4sbyte_unaligned_inc (cache, *p);
+      break;
+    case DW_EH_PE_sdata8:
+      value = read_8sbyte_unaligned_inc (cache, *p);
+      break;
+
+    case DW_EH_PE_absptr:
+      if (cache->e_ident[EI_CLASS] == ELFCLASS32)
+       value = read_4ubyte_unaligned_inc (cache, *p);
+      else
+       value = read_8ubyte_unaligned_inc (cache, *p);
+      break;
+
+    case DW_EH_PE_uleb128:
+      get_uleb128 (value, *p);
+      break;
+    case DW_EH_PE_sleb128:
+      get_sleb128 (value, *p);
+      break;
+
+    default:
+      abort ();
+    }
+
+  return base + value;
+}
+
+#endif /* encoded-value.h */
diff --git a/libdw/fde.c b/libdw/fde.c
new file mode 100644 (file)
index 0000000..acfa39d
--- /dev/null
@@ -0,0 +1,298 @@
+/* FDE reading.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+#include <search.h>
+#include <stdlib.h>
+
+#include "encoded-value.h"
+
+static int
+compare_fde (const void *a, const void *b)
+{
+  const struct dwarf_fde *fde1 = a;
+  const struct dwarf_fde *fde2 = b;
+
+  /* Find out which of the two arguments is the search value.
+     It has end offset 0.  */
+  if (fde1->end == 0)
+    {
+      if (fde1->start < fde2->start)
+       return -1;
+      if (fde1->start >= fde2->end)
+       return 1;
+    }
+  else
+    {
+      if (fde2->start < fde1->start)
+       return 1;
+      if (fde2->start >= fde1->end)
+       return -1;
+    }
+
+  return 0;
+}
+
+static struct dwarf_fde *
+intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
+{
+  /* Look up the new entry's CIE.  */
+  struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer);
+  if (cie == NULL)
+    return (void *) -1l;
+
+  struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde));
+  if (fde == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  fde->instructions = entry->start;
+  fde->instructions_end = entry->end;
+  fde->start = read_encoded_value (cache, cie->fde_encoding,
+                                  &fde->instructions);
+  fde->end = fde->start + read_encoded_value (cache, cie->fde_encoding & 0x0f,
+                                             &fde->instructions);
+
+  fde->cie = cie;
+
+  if (cie->sized_augmentation_data)
+    {
+      /* The CIE augmentation says the FDE has a DW_FORM_block
+        before its actual instruction stream.  */
+      Dwarf_Word len;
+      get_uleb128 (len, fde->instructions);
+      if ((Dwarf_Word) (fde->instructions_end < fde->instructions) < len)
+       {
+         free (fde);
+         __libdw_seterrno (DWARF_E_INVALID_DWARF);
+         return NULL;
+       }
+      fde->instructions += len;
+    }
+  else
+    /* We had to understand all of the CIE augmentation string.
+       We've recorded the number of data bytes in FDEs.  */
+    fde->instructions += cie->fde_augmentation_data_size;
+
+  /* Add the new entry to the search tree.  */
+  if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL)
+    {
+      free (fde);
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  return fde;
+}
+
+static struct dwarf_fde *
+fde_by_offset (Dwarf_CFI *cache, Dwarf_Addr address, Dwarf_Off offset)
+{
+  Dwarf_CFI_Entry entry;
+  Dwarf_Off next_offset;
+  int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
+                                      &cache->data, cache->eh_frame,
+                                      offset, &next_offset, &entry);
+  if (result != 0)
+    {
+      if (result > 0)
+      invalid:
+       __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  if (unlikely (dwarf_cfi_cie_p (&entry)))
+    goto invalid;
+
+  /* We have a new FDE to consider.  */
+  struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
+  if (fde == (void *) -1l || fde == NULL)
+    return NULL;
+
+  /* If this happened to be what we would have read next, notice it.  */
+  if (cache->next_offset == offset)
+    cache->next_offset = next_offset;
+
+  /* Sanity check the address range.  */
+  if (address < fde->start || address >= fde->end)
+    goto invalid;
+
+  return fde;
+}
+
+/* Use a binary search table in .eh_frame_hdr format, yield an FDE offset.  */
+static Dwarf_Off
+binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address)
+{
+  const size_t size = 2 * encoded_value_size (&cache->data, cache->e_ident,
+                                             cache->search_table_encoding,
+                                             NULL);
+
+
+  /* Dummy used by read_encoded_value.  */
+  Dwarf_CFI dummy_cfi =
+    {
+      .e_ident = cache->e_ident,
+      .datarel = cache->search_table_vaddr,
+      .frame_vaddr = cache->search_table_vaddr,
+    };
+
+  size_t l = 0, u = cache->search_table_entries;
+  while (l < u)
+    {
+      size_t idx = (l + u) / 2;
+
+      const uint8_t *p = &cache->search_table[idx * size];
+      Dwarf_Addr start = read_encoded_value (&dummy_cfi,
+                                            cache->search_table_encoding, &p);
+      if (address < start)
+       u = idx;
+      else
+       {
+         Dwarf_Addr fde = read_encoded_value (&dummy_cfi,
+                                              cache->search_table_encoding,
+                                              &p);
+         if (address > start)
+           {
+             l = idx + 1;
+
+             /* If this is the last entry, its upper bound is assumed to be
+                the end of the module.
+                XXX really should be end of containing PT_LOAD segment */
+             if (l < cache->search_table_entries)
+               {
+                 /* Look at the start address in the following entry.  */
+                 Dwarf_Addr end
+                   = read_encoded_value (&dummy_cfi,
+                                         cache->search_table_encoding, &p);
+                 if (address >= end)
+                   continue;
+               }
+
+             return fde - cache->frame_vaddr;
+           }
+       }
+    }
+
+  return (Dwarf_Off) -1l;
+}
+
+struct dwarf_fde *
+internal_function
+__libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
+{
+  /* Look for a cached FDE covering this address.  */
+
+  const struct dwarf_fde fde_key = { .start = address, .end = 0 };
+  struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde);
+  if (found != NULL)
+    return *found;
+
+  /* Use .eh_frame_hdr binary search table if possible.  */
+  if (cache->search_table != NULL)
+    {
+      Dwarf_Off offset = binary_search_fde (cache, address);
+      if (offset == (Dwarf_Off) -1l)
+       goto no_match;
+      return fde_by_offset (cache, address, offset);
+    }
+
+  /* It's not there.  Read more CFI entries until we find it.  */
+  while (1)
+    {
+      Dwarf_Off last_offset = cache->next_offset;
+      Dwarf_CFI_Entry entry;
+      int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
+                                          &cache->data, cache->eh_frame,
+                                          last_offset, &cache->next_offset,
+                                          &entry);
+      if (result > 0)
+       break;
+      if (result < 0)
+       {
+         if (cache->next_offset == last_offset)
+           /* We couldn't progress past the bogus FDE.  */
+           break;
+         /* Skip the loser and look at the next entry.  */
+         continue;
+       }
+
+      if (dwarf_cfi_cie_p (&entry))
+       {
+         /* This is a CIE, not an FDE.  We eagerly intern these
+            because the next FDE will usually refer to this CIE.  */
+         __libdw_intern_cie (cache, last_offset, &entry.cie);
+         continue;
+       }
+
+      /* We have a new FDE to consider.  */
+      struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
+
+      if (fde == (void *) -1l) /* Bad FDE, but we can keep looking.  */
+       continue;
+
+      if (fde == NULL)         /* Bad data.  */
+       return NULL;
+
+      /* Is this the one we're looking for?  */
+      if (fde->start <= address && fde->end > address)
+       return fde;
+    }
+
+ no_match:
+  /* We found no FDE covering this address.  */
+  __libdw_seterrno (DWARF_E_NO_MATCH);
+  return NULL;
+}
diff --git a/libdw/frame-cache.c b/libdw/frame-cache.c
new file mode 100644 (file)
index 0000000..2182ad3
--- /dev/null
@@ -0,0 +1,90 @@
+/* Frame cache handling.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unwindP.h"
+#include <search.h>
+#include <stdlib.h>
+
+
+static void
+free_cie (void *arg)
+{
+  struct dwarf_cie *cie = arg;
+
+  free (cie->initial_state);
+  free (cie);
+}
+
+#define free_fde       free
+
+static void
+free_expr (void *arg)
+{
+  struct loc_s *loc = arg;
+
+  free (loc->loc);
+  free (loc);
+}
+
+void
+internal_function
+__libdw_destroy_frame_cache (Dwarf_CFI *cache)
+{
+  /* Most of the data is in our two search trees.  */
+  tdestroy (cache->fde_tree, free_fde);
+  tdestroy (cache->cie_tree, free_cie);
+  tdestroy (cache->expr_tree, free_expr);
+
+  if (cache->rawchunk)
+    gelf_freechunk (cache->elf, cache->data.d_buf);
+}
index 8e2f6441b62cb828e136c29d8f238c5a58bd232b..b53918c616ecf0d17b1f729330c97e161a931af1 100644 (file)
@@ -1,7 +1,6 @@
 ELFUTILS_0 { };
 ELFUTILS_0.122 {
-  global:
-    dwarf_abbrevhaschildren;
+  global:  dwarf_abbrevhaschildren;
     dwarf_addrdie;
     dwarf_arrayorder;
     dwarf_attr;
@@ -185,3 +184,19 @@ ELFUTILS_0.136 {
   local:
     *;
 } ELFUTILS_0.130;
+
+ELFUTILS_0.138_UNWIND {
+  global:
+    # XXX new unwind stuff not decided yet
+    dwarf_next_cfi;
+    dwarf_getcfi;
+    dwarf_getcfi_elf;
+    dwarf_cfi_addrframe;
+    dwarf_cfi_end;
+    dwarf_cfi_setebl;
+    dwarf_frame_cfa;
+    dwarf_frame_register;
+    dwarf_frame_return_address_register;
+    dwfl_addrframe;
+    dwfl_module_getcfi;
+} ELFUTILS_0.136;
index f805295ff26962f1541bc945a901a4a118b1ce08..6937ace87811bad2603dd2014e72502164b7e9b4 100644 (file)
@@ -136,6 +136,7 @@ enum
   DWARF_E_NO_FLAG,
   DWARF_E_INVALID_OFFSET,
   DWARF_E_NO_DEBUG_RANGES,
+  DWARF_E_INVALID_CFI,
 };
 
 
@@ -172,6 +173,9 @@ struct Dwarf
   /* Address ranges.  */
   Dwarf_Aranges *aranges;
 
+  /* Cached info from the CFI section.  */
+  struct Dwarf_CFI_s *cfi;
+
   /* Internal memory handling.  This is basically a simplified
      reimplementation of obstacks.  Unfortunately the standard obstack
      implementation is not usable in libraries.  */
@@ -413,6 +417,16 @@ extern int __libdw_visit_scopes (unsigned int depth,
                                 void *arg)
   __nonnull_attribute__ (2, 3) internal_function;
 
+/* Parse a DWARF Dwarf_Block into an array of Dwarf_Op's,
+   and cache the result (via tsearch).  */
+extern int __libdw_intern_expression (Dwarf *dbg,
+                                     bool other_byte_order,
+                                     unsigned int address_size,
+                                     void **cache, const Dwarf_Block *block,
+                                     Dwarf_Op **llbuf, size_t *listlen)
+  __nonnull_attribute__ (4, 5, 6, 7) internal_function;
+
+
 /* Return error code of last failing function call.  This value is kept
    separately for each thread.  */
 extern int __dwarf_errno_internal (void);
index 52b41b5b020e4c0dc19f137b735d7cd2ff44d94e..ee3efa882345989ca32f87ac9b37e8f93b16e461 100644 (file)
@@ -1,5 +1,5 @@
 /* Unaligned memory access functionality.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2001.
 
@@ -186,19 +186,32 @@ union unaligned
     int64_t s8;
   } __attribute__ ((packed));
 
+# define read_2ubyte_unaligned(Dbg, Addr) \
+  read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
+# define read_2sbyte_unaligned(Dbg, Addr) \
+  read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
+# define read_4ubyte_unaligned(Dbg, Addr) \
+  read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
+# define read_4sbyte_unaligned(Dbg, Addr) \
+  read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
+# define read_8ubyte_unaligned(Dbg, Addr) \
+  read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
+# define read_8sbyte_unaligned(Dbg, Addr) \
+  read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
+
 static inline uint16_t
-read_2ubyte_unaligned (Dwarf *dbg, const void *p)
+read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;
-  if (dbg->other_byte_order)
+  if (unlikely (other_byte_order))
     return bswap_16 (up->u2);
   return up->u2;
 }
 static inline int16_t
-read_2sbyte_unaligned (Dwarf *dbg, const void *p)
+read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;
-  if (dbg->other_byte_order)
+  if (unlikely (other_byte_order))
     return (int16_t) bswap_16 (up->u2);
   return up->s2;
 }
@@ -210,35 +223,35 @@ read_4ubyte_unaligned_noncvt (const void *p)
   return up->u4;
 }
 static inline uint32_t
-read_4ubyte_unaligned (Dwarf *dbg, const void *p)
+read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;
-  if (dbg->other_byte_order)
+  if (unlikely (other_byte_order))
     return bswap_32 (up->u4);
   return up->u4;
 }
 static inline int32_t
-read_4sbyte_unaligned (Dwarf *dbg, const void *p)
+read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;
-  if (dbg->other_byte_order)
+  if (unlikely (other_byte_order))
     return (int32_t) bswap_32 (up->u4);
   return up->s4;
 }
 
 static inline uint64_t
-read_8ubyte_unaligned (Dwarf *dbg, const void *p)
+read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;
-  if (dbg->other_byte_order)
+  if (unlikely (other_byte_order))
     return bswap_64 (up->u8);
   return up->u8;
 }
 static inline int64_t
-read_8sbyte_unaligned (Dwarf *dbg, const void *p)
+read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;
-  if (dbg->other_byte_order)
+  if (unlikely (other_byte_order))
     return (int64_t) bswap_64 (up->u8);
   return up->s8;
 }
diff --git a/libdw/unwind.c b/libdw/unwind.c
new file mode 100644 (file)
index 0000000..1524fe0
--- /dev/null
@@ -0,0 +1,452 @@
+/* CFI program execution.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "../libebl/libebl.h"
+#include "unwindP.h"
+#include "memory-access.h"
+#include "encoded-value.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CFI_PRIMARY_MAX        0x3f
+
+static Dwarf_Frame *
+duplicate_frame_state (Dwarf_Frame *original,
+                      Dwarf_Frame *prev)
+{
+  size_t size = offsetof (Dwarf_Frame, regs[original->nregs]);
+  Dwarf_Frame *copy = malloc (size);
+  if (likely (copy != NULL))
+    {
+      memcpy (copy, original, size);
+      copy->prev = prev;
+    }
+  return copy;
+}
+
+/* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI.  */
+static int
+execute_cfi (Dwarf_CFI *cache,
+            const struct dwarf_cie *cie,
+            Dwarf_Frame **state,
+            const uint8_t *program, const uint8_t *const end, bool abi_cfi,
+            Dwarf_Addr loc, Dwarf_Addr find_pc)
+{
+  /* The caller should not give us anything out of range.  */
+  assert (loc <= find_pc);
+
+  int result = DWARF_E_NOERROR;
+
+#define cfi_assert(ok) do {                                                  \
+    if (likely (ok)) break;                                                  \
+    result = DWARF_E_INVALID_CFI;                                            \
+    goto out;                                                                \
+  } while (0)
+
+  Dwarf_Frame *fs = *state;
+  inline bool enough_registers (Dwarf_Word reg)
+    {
+      if (fs->nregs <= reg)
+       {
+         size_t size = offsetof (Dwarf_Frame, regs[reg + 1]);
+         Dwarf_Frame *bigger = realloc (fs, size);
+         if (unlikely (bigger == NULL))
+           {
+             result = DWARF_E_NOMEM;
+             return false;
+           }
+         else
+           {
+             bigger->nregs = reg + 1;
+             fs = bigger;
+           }
+       }
+      return true;
+    }
+
+
+#define register_rule(regno, r_rule, r_value) do {     \
+    if (unlikely (! enough_registers (regno)))         \
+      goto out;                                                \
+    fs->regs[regno].rule = reg_##r_rule;               \
+    fs->regs[regno].value = (r_value);                 \
+  } while (0)
+
+  while (program < end)
+    {
+      uint8_t opcode = *program++;
+      Dwarf_Word regno;
+      Dwarf_Word offset;
+      Dwarf_Word sf_offset;
+      Dwarf_Word operand = opcode & CFI_PRIMARY_MAX;
+      switch (opcode)
+       {
+       case DW_CFA_advance_loc1:
+         operand = *program++;
+       case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX:
+       advance_loc:
+         loc += operand * cie->code_alignment_factor;
+         break;
+
+       case DW_CFA_advance_loc2:
+         operand = read_2ubyte_unaligned_inc (cache, program);
+         goto advance_loc;
+       case DW_CFA_advance_loc4:
+         operand = read_4ubyte_unaligned_inc (cache, program);
+         goto advance_loc;
+       case DW_CFA_MIPS_advance_loc8:
+         operand = read_8ubyte_unaligned_inc (cache, program);
+         goto advance_loc;
+
+       case DW_CFA_set_loc:
+         loc = read_encoded_value (cache, cie->fde_encoding, &program);
+         break;
+
+       case DW_CFA_def_cfa:
+         get_uleb128 (operand, program);
+         get_uleb128 (offset, program);
+       def_cfa:
+         fs->cfa_rule = cfa_offset;
+         fs->cfa_val_reg = operand;
+         fs->cfa_val_offset = offset;
+         /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it.  */
+         fs->cfa_data.offset.atom = DW_OP_bregx;
+         fs->cfa_data.offset.offset = 0;
+         break;
+
+       case DW_CFA_def_cfa_register:
+         get_uleb128 (regno, program);
+         cfi_assert (fs->cfa_rule == cfa_offset);
+         fs->cfa_val_reg = regno;
+         break;
+
+       case DW_CFA_def_cfa_sf:
+         get_uleb128 (operand, program);
+         get_sleb128 (sf_offset, program);
+         offset = sf_offset * cie->data_alignment_factor;
+         goto def_cfa;
+
+       case DW_CFA_def_cfa_offset:
+         get_uleb128 (offset, program);
+       def_cfa_offset:
+         cfi_assert (fs->cfa_rule == cfa_offset);
+         fs->cfa_val_offset = offset;
+         break;
+
+       case DW_CFA_def_cfa_offset_sf:
+         get_sleb128 (sf_offset, program);
+         offset = sf_offset * cie->data_alignment_factor;
+         goto def_cfa_offset;
+
+       case DW_CFA_def_cfa_expression:
+         /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+         get_uleb128 (operand, program);
+         cfi_assert (operand <= (Dwarf_Word) (end - program));
+         fs->cfa_rule = cfa_expr;
+         fs->cfa_data.expr.data = (unsigned char *) program;
+         fs->cfa_data.expr.length = operand;
+         program += operand;
+         break;
+
+       case DW_CFA_undefined:
+         get_uleb128 (regno, program);
+         register_rule (regno, undefined, 0);
+         break;
+
+       case DW_CFA_same_value:
+         get_uleb128 (regno, program);
+         register_rule (regno, same_value, 0);
+         break;
+
+       case DW_CFA_offset_extended:
+         get_uleb128 (operand, program);
+       case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX:
+         get_uleb128 (offset, program);
+         offset *= cie->data_alignment_factor;
+       offset_extended:
+         register_rule (operand, offset, offset);
+         break;
+
+       case DW_CFA_offset_extended_sf:
+         get_uleb128 (operand, program);
+         get_sleb128 (sf_offset, program);
+         offset = sf_offset * cie->data_alignment_factor;
+         goto offset_extended;
+
+       case DW_CFA_val_offset:
+         get_uleb128 (operand, program);
+         get_uleb128 (offset, program);
+         offset *= cie->data_alignment_factor;
+       val_offset:
+         register_rule (operand, val_offset, offset);
+         break;
+
+       case DW_CFA_val_offset_sf:
+         get_uleb128 (operand, program);
+         get_sleb128 (sf_offset, program);
+         offset = sf_offset * cie->data_alignment_factor;
+         goto val_offset;
+
+       case DW_CFA_register:
+         get_uleb128 (regno, program);
+         get_uleb128 (operand, program);
+         register_rule (regno, register, operand);
+         break;
+
+       case DW_CFA_expression:
+         get_uleb128 (regno, program);
+         offset = program - (const uint8_t *) cache->data.d_buf;
+         /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+         get_uleb128 (operand, program);
+         cfi_assert (operand <= (Dwarf_Word) (end - program));
+         register_rule (regno, expression, offset);
+         program += operand;
+         break;
+
+       case DW_CFA_val_expression:
+         get_uleb128 (regno, program);
+         /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+         offset = program - (const uint8_t *) cache->data.d_buf;
+         get_uleb128 (operand, program);
+         cfi_assert (operand <= (Dwarf_Word) (end - program));
+         register_rule (regno, val_expression, offset);
+         program += operand;
+         break;
+
+       case DW_CFA_restore_extended:
+         get_uleb128 (operand, program);
+       case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX:
+
+         if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore))
+           {
+             /* Special case hack to give backend abi_cfi a shorthand.  */
+             cache->default_same_value = true;
+             break;
+           }
+
+         /* This can't be used in the CIE's own initial instructions.  */
+         cfi_assert (cie->initial_state != NULL);
+
+         /* Restore the CIE's initial rule for this register.  */
+         if (unlikely (! enough_registers (operand)))
+           goto out;
+         if (cie->initial_state->nregs > operand)
+           fs->regs[operand] = cie->initial_state->regs[operand];
+         else
+           fs->regs[operand].rule = reg_unspecified;
+         break;
+
+       case DW_CFA_remember_state:
+         {
+           /* Duplicate the state and chain the copy on.  */
+           Dwarf_Frame *copy = duplicate_frame_state (fs, fs);
+           if (unlikely (copy == NULL))
+             {
+               result = DWARF_E_NOMEM;
+               goto out;
+             }
+           fs = copy;
+           break;
+         }
+
+       case DW_CFA_restore_state:
+         {
+           /* Pop the current state off and use the old one instead.  */
+           Dwarf_Frame *prev = fs->prev;
+           cfi_assert (prev != NULL);
+           free (fs);
+           fs = prev;
+         }
+         break;
+
+       case DW_CFA_nop:
+         break;
+
+       case DW_CFA_GNU_window_save:
+         /* This is magic shorthand used only by SPARC.  It's equivalent
+            to a bunch of DW_CFA_register and DW_CFA_offset operations.  */
+         if (unlikely (! enough_registers (31)))
+           goto out;
+         for (regno = 8; regno < 16; ++regno)
+           {
+             /* Find each %oN in %iN.  */
+             fs->regs[regno].rule = reg_register;
+             fs->regs[regno].value = regno + 16;
+           }
+         unsigned int address_size = (cache->e_ident[EI_CLASS] == ELFCLASS32
+                                      ? 4 : 8);
+         for (; regno < 32; ++regno)
+           {
+             /* Find %l0..%l7 and %i0..%i7 in a block at the CFA.  */
+             fs->regs[regno].rule = reg_offset;
+             fs->regs[regno].value = (regno - 16) * address_size;
+           }
+         break;
+
+       case DW_CFA_GNU_args_size:
+         /* XXX is this useful for anything? */
+         get_uleb128 (operand, program);
+         break;
+
+       default:
+         cfi_assert (false);
+         break;
+       }
+
+      if (find_pc < loc)
+       /* We have just advanced past the address we're looking for.
+          The state currently described is what we want to see.  */
+       break;
+    }
+
+  /* "The end of the instruction stream can be thought of as a
+     DW_CFA_set_loc (initial_location + address_range) instruction."
+     (DWARF 3.0 Section 6.4.3)
+
+     When we fall off the end of the program without an advance_loc/set_loc
+     that put us past FIND_PC, the final state left by the FDE program
+     applies to this address (the caller ensured it was inside the FDE).  */
+
+#undef register_rule
+#undef cfi_assert
+
+ out:
+
+  /* Pop any remembered states left on the stack.  */
+  while (fs->prev != NULL)
+    {
+      Dwarf_Frame *prev = fs->prev;
+      fs->prev = prev->prev;
+      free (prev);
+    }
+
+  if (result == DWARF_E_NOERROR)
+    *state = fs;
+
+  return result;
+}
+
+int
+internal_function
+__libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
+                         Dwarf_Addr address, Dwarf_Frame **frame)
+{
+  if (fde->cie->initial_state == NULL)
+    {
+      /* This CIE has not been used before.  Play out its initial
+        instructions and cache the initial state that results.  */
+
+      Dwarf_Frame *cie_fs = calloc (1, sizeof (Dwarf_Frame));
+      if (unlikely (cie_fs == NULL))
+       return DWARF_E_NOMEM;
+
+      int result = DWARF_E_NOERROR;
+
+      /* First we'll let the backend fill in the default initial
+        state for this machine's ABI.  */
+
+      Dwarf_CIE abi_info = { CIE_ID, 1, 1, -1, "", NULL, 0, 0, NULL, NULL };
+      if (cache->ebl != NULL && ebl_abi_cfi (cache->ebl, &abi_info) < 0)
+       return DWARF_E_UNKNOWN_ERROR;
+
+      /* If the default state of any register is not "undefined"
+        (i.e. call-clobbered), then the backend supplies instructions
+        for the standard initial state.  */
+      if (abi_info.initial_instructions_end > abi_info.initial_instructions)
+       {
+         /* Dummy CIE for backend's instructions.  */
+         struct dwarf_cie abi_cie =
+           {
+             .code_alignment_factor = abi_info.code_alignment_factor,
+             .data_alignment_factor = abi_info.data_alignment_factor,
+           };
+         result = execute_cfi (cache, &abi_cie, &cie_fs,
+                               abi_info.initial_instructions,
+                               abi_info.initial_instructions_end, true,
+                               0, (Dwarf_Addr) -1l);
+       }
+
+      /* Now run the CIE's initial instructions.  */
+      if (fde->cie->initial_instructions_end > fde->cie->initial_instructions
+         && result == DWARF_E_NOERROR)
+       result = execute_cfi (cache, fde->cie, &cie_fs,
+                             fde->cie->initial_instructions,
+                             fde->cie->initial_instructions_end, false,
+                             0, (Dwarf_Addr) -1l);
+
+      if (result != DWARF_E_NOERROR)
+       return result;
+
+      /* Now we have the initial state of things that all
+        FDEs using this CIE will start from.  */
+      cie_fs->cache = cache;
+      cie_fs->cie = fde->cie;
+      fde->cie->initial_state = cie_fs;
+    }
+
+  Dwarf_Frame *fs = duplicate_frame_state (fde->cie->initial_state, NULL);
+  if (unlikely (fs == NULL))
+    return DWARF_E_NOMEM;
+
+  int result = execute_cfi (cache, fde->cie, &fs,
+                           fde->instructions, fde->instructions_end, false,
+                           fde->start, address);
+  if (unlikely (result != DWARF_E_NOERROR))
+    free (fs);
+  else
+    *frame = fs;
+
+  return result;
+}
diff --git a/libdw/unwind.h b/libdw/unwind.h
new file mode 100644 (file)
index 0000000..486822a
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef _libdw_unwind_h                /* XXX */
+#define _libdw_unwind_h 1
+
+#include "libdw.h"
+struct ebl;
+
+/* This describes one Common Information Entry read from a CFI section.
+   Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi.  */
+typedef struct
+{
+  Dwarf_Off CIE_id;    /* Always CIE_ID in Dwarf_CIE structures. */
+#define CIE_ID ((Dwarf_Off) -1l)
+
+  Dwarf_Word code_alignment_factor;
+  Dwarf_Sword data_alignment_factor;
+  Dwarf_Word return_address_register;
+
+  const char *augmentation;    /* Augmentation string.  */
+
+  /* Augmentation data, might be NULL.  The size is correct only if
+     we understood the augmentation string sufficiently.  */
+  const uint8_t *augmentation_data;
+  size_t augmentation_data_size;
+  size_t fde_augmentation_data_size;
+
+  /* Instruction stream describing initial state used by FDEs.  If
+     we did not understand the whole augmentation string and it did
+     not use 'z', then there might be more augmentation data here
+     (and in FDEs) before the actual instructions.  */
+  const uint8_t *initial_instructions;
+  const uint8_t *initial_instructions_end;
+} Dwarf_CIE;
+
+/* This describes one Frame Description Entry read from a CFI section.
+   Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi.  */
+typedef struct
+{
+  /* Section offset of CIE this FDE refers to.  This will never be
+     CIE_ID in an FDE.  If this value is CIE_ID, this is actually a
+     Dwarf_CIE structure.  */
+  Dwarf_Off CIE_pointer;
+
+  /* We can't really decode anything further without looking up the CIE
+     and checking its augmentation string.  Here follows the encoded
+     initial_location and address_range, then any augmentation data,
+     then the instruction stream.  This FDE describes PC locations in
+     the byte range [initial_location, initial_location+address_range).
+     When the CIE augmentation string uses 'z', the augmentation data is
+     a DW_FORM_block (self-sized).  Otherwise, when we understand the
+     augmentation string completely, fde_augmentation_data_size gives
+     the number of bytes of augmentation data before the instructions.  */
+  const uint8_t *start;
+  const uint8_t *end;
+} Dwarf_FDE;
+
+typedef union
+{
+  Dwarf_CIE cie;
+  Dwarf_FDE fde;
+} Dwarf_CFI_Entry;
+
+#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == CIE_ID)
+
+/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
+   The E_IDENT from the originating ELF file indicates the address
+   size and byte order used in the CFI section contained in DATA;
+   EH_FRAME_P should be true for .eh_frame format and false for
+   .debug_frame format.  OFFSET is the byte position in the section
+   to start at; on return *NEXT_OFFSET is filled in with the byte
+   position immediately after this entry.
+
+   On success, returns 0 and fills in *ENTRY; use dwarf_cfi_cie_p to
+   see whether ENTRY->cie or ENTRY->fde is valid.
+
+   On errors, returns -1.  Some format errors will permit safely
+   skipping to the next CFI entry though the current one is unusable.
+   In that case, *NEXT_OFF will be updated before a -1 return.
+
+   If there are no more CFI entries left in the section,
+   returns 1 and sets *NEXT_OFFSET to (Dwarf_Off) -1.  */
+extern int dwarf_next_cfi (const unsigned char e_ident[],
+                          Elf_Data *data, bool eh_frame_p,
+                          Dwarf_Off offset, Dwarf_Off *next_offset,
+                          Dwarf_CFI_Entry *entry)
+  __nonnull_attribute__ (1, 2, 5, 6);
+
+
+/* Opaque type representing a frame state described by CFI.  */
+typedef struct Dwarf_Frame_s Dwarf_Frame;
+
+/* Opaque type representing a CFI section found in a DWARF or ELF file.  */
+typedef struct Dwarf_CFI_s Dwarf_CFI;
+
+/* Use the CFI in the DWARF .debug_frame or .eh_frame section.
+   Returns NULL if there is no such section.
+   The pointer returned can be used until dwarf_end is called on DWARF,
+   and must not be passed to dwarf_cfi_end.
+   Calling this more than once returns the same pointer.  */
+extern Dwarf_CFI *dwarf_getcfi (Dwarf *dwarf);
+
+/* Use the CFI in the ELF file's exception-handling data.
+   Returns NULL if there is no such data.
+   The pointer returned can be used until elf_end is called on ELF,
+   and must be passed to dwarf_cfi_end before then.
+   Calling this more than once allocates independent data structures.  */
+extern Dwarf_CFI *dwarf_getcfi_elf (Elf *elf);
+
+/* Release resources allocated by dwarf_getcfi_elf.  */
+extern int dwarf_cfi_end (Dwarf_CFI *cache);
+
+/* Associate an open backend from <libebl.h> with this Dwarf_CFI handle.
+   The backend may be required to perform CFI unwinding correctly.  */
+extern int dwarf_cfi_setebl (Dwarf_CFI *cache, struct ebl *ebl);
+
+
+/* Compute what's known about a call frame when the PC is at ADDRESS.
+   Returns 0 for success or -1 for errors.
+   On success, *FRAME is a malloc'd pointer.  */
+extern int dwarf_cfi_addrframe (Dwarf_CFI *cache,
+                               Dwarf_Addr address, Dwarf_Frame **frame)
+  __nonnull_attribute__ (3);
+
+/* Deliver a DWARF expression that yields the Canonical Frame Address at
+   this frame state.  Returns -1 for errors, or the number of operations
+   stored at *OPS.  That pointer can be used only as long as FRAME is alive
+   and unchanged.  Returns zero if the CFA cannot be determined here.  */
+extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops)
+  __nonnull_attribute__ (2);
+
+/* Return the DWARF register number used in FRAME to denote
+   the return address in FRAME's caller frame.
+
+   Fill in *SIGNALP to indicate whether this is a signal-handling frame.
+   If true, this is the implicit call frame that calls a signal handler.
+   This frame's "caller" is actually the interrupted state, not a call;
+   its return address is an exact PC, not a PC after a call instruction.  */
+extern int dwarf_frame_return_address_register (Dwarf_Frame *frame,
+                                               bool *signalp)
+  __nonnull_attribute__ (1, 2);
+
+/* Deliver a DWARF expression that yields the location or value of
+   DWARF register number REGNO in the state described by FRAME.
+
+   Returns -1 for errors, 0 if REGNO has an accessible location,
+   or 1 if REGNO has only a computable value.  Stores at *NOPS
+   the number of operations in the array stored at *OPS.
+   With return value 0, this is a DWARF location expression.
+   With return value 1, this is a DWARF expression that computes the value.
+
+   Return value 1 with *NOPS zero means CFI says the caller's REGNO is
+   "undefined" here, i.e. it's call-clobbered and cannot be recovered.
+
+   Return value 0 with *NOPS zero means CFI says the caller's REGNO is
+   "same_value" here, i.e. this frame did not change it; ask the caller
+   frame where to find it.
+
+   For common simple expressions *OPS is OPS_MEM.  For arbitrary DWARF
+   expressions in the CFI, *OPS is an internal pointer that can be used as
+   long as the Dwarf_CFI used to create FRAME remains alive.  */
+extern int dwarf_frame_register (Dwarf_Frame *frame, int regno,
+                                Dwarf_Op ops_mem[2],
+                                Dwarf_Op **ops, size_t *nops)
+  __nonnull_attribute__ (3, 4, 5);
+
+
+// XXX libdwfl front-end
+#include "../libdwfl/libdwfl.h"
+
+
+/* Find the CFI for this module.  Returns NULL if there is no CFI.
+   On success, fills in *BIAS with the difference between addresses
+   within the loaded module and those in the CFI referring to it.
+   This does dwarf_cfi_setebl for you, so another call is not required.
+   The pointer returned can be used until the module is cleaned up.
+   Calling this more than once returns the same pointer.  */
+extern Dwarf_CFI *dwfl_module_getcfi (Dwfl_Module *mod, Dwarf_Addr *bias);
+
+// XXX needs module bias? for DW_OP_addr in exprs?
+/* Compute what's known about a call frame when the PC is at ADDRESS.
+   Returns 0 for success or -1 for errors.
+   On success, *FRAME is a malloc'd pointer.  */
+extern int dwfl_addrframe (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Frame **frame)
+  __nonnull_attribute__ (3);
+
+#endif /* XXX */
diff --git a/libdw/unwindP.h b/libdw/unwindP.h
new file mode 100644 (file)
index 0000000..240388f
--- /dev/null
@@ -0,0 +1,247 @@
+/* Internal definitions for libdw unwinder code.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifndef _UNWINDP_H
+#define _UNWINDP_H 1
+
+#include "libdwP.h"
+#include "unwind.h"            /* XXX */
+struct ebl;
+
+/* Cached CIE representation.  */
+struct dwarf_cie
+{
+  Dwarf_Off offset;     /* Our position, as seen in FDEs' CIE_pointer.  */
+
+  Dwarf_Word code_alignment_factor;
+  Dwarf_Sword data_alignment_factor;
+  Dwarf_Word return_address_register;
+
+  size_t fde_augmentation_data_size;
+
+  // play out to initial state
+  const uint8_t *initial_instructions;
+  const uint8_t *initial_instructions_end;
+
+  Dwarf_Frame *initial_state;
+
+  uint8_t fde_encoding;                /* DW_EH_PE_* for addresses in FDEs.  */
+  uint8_t lsda_encoding;    /* DW_EH_PE_* for LSDA in FDE augmentation.  */
+
+  bool sized_augmentation_data;        /* Saw 'z': FDEs have self-sized data.  */
+  bool signal_frame;           /* Saw 'S': FDE is for a signal frame.  */
+};
+
+/* Cached FDE representation.  */
+struct dwarf_fde
+{
+  struct dwarf_cie *cie;
+
+  /* This FDE describes PC values in [start, end).  */
+  Dwarf_Addr start;
+  Dwarf_Addr end;
+
+  const uint8_t *instructions;
+  const uint8_t *instructions_end;
+};
+
+/* This holds everything we cache about the CFI from each ELF file's
+   .debug_frame or .eh_frame section.  */
+struct Dwarf_CFI_s
+{
+  /* Data of the .debug_frame or .eh_frame section.  */
+  Elf_Data data;
+  const unsigned char *e_ident;        /* For EI_DATA and EI_CLASS.  */
+
+  /* True if the file has a byte order different from the host.  */
+  bool other_byte_order;
+
+  /* True if the section data is in .eh_frame format.  */
+  bool eh_frame;
+
+  /* True if data.d_buf came from gelf_rawchunk.  */
+  bool rawchunk;
+  Elf *elf;                    /* Originating ELF file.  */
+
+  Dwarf_Addr frame_vaddr;  /* DW_EH_PE_pcrel, address of frame section.  */
+  Dwarf_Addr textrel;          /* DW_EH_PE_textrel base address.  */
+  Dwarf_Addr datarel;          /* DW_EH_PE_datarel base address.  */
+
+  /* Default rule for registers not previously mentioned
+     is same_value, not undefined.  */
+  bool default_same_value;
+
+  /* Location of next unread entry in the section.  */
+  Dwarf_Off next_offset;
+
+  /* Search tree for the CIEs, indexed by CIE_pointer (section offset).  */
+  void *cie_tree;
+
+  /* Search tree for the FDEs, indexed by PC address.  */
+  void *fde_tree;
+
+  /* Search tree for parsed DWARF expressions, indexed by raw pointer.  */
+  void *expr_tree;
+
+  /* Backend hook.  */
+  struct ebl *ebl;
+
+  /* Binary search table in .eh_frame_hdr section.  */
+  const uint8_t *search_table;
+  Dwarf_Addr search_table_vaddr;
+  void *search_table_rawchunk;
+  size_t search_table_entries;
+  uint8_t search_table_encoding;
+};
+
+
+enum dwarf_frame_rule
+  {
+    reg_unspecified,           /* Uninitialized state.  */
+    reg_undefined,             /* DW_CFA_undefined */
+    reg_same_value,            /* DW_CFA_same_value */
+    reg_offset,                        /* DW_CFA_offset_extended et al */
+    reg_val_offset,            /* DW_CFA_val_offset et al */
+    reg_register,              /* DW_CFA_register */
+    reg_expression,            /* DW_CFA_expression */
+    reg_val_expression,                /* DW_CFA_val_expression */
+  };
+
+/* This describes what we know about an individual register.  */
+struct dwarf_frame_register
+{
+  enum dwarf_frame_rule rule:3;
+
+  /* The meaning of the value bits depends on the rule:
+
+       Rule                    Value
+       ----                    -----
+       undefined               unused
+       same_value              unused
+       offset(N)               N       (register saved at CFA + value)
+       val_offset(N)           N       (register = CFA + value)
+       register(R)             R       (register = register #value)
+       expression(E)           section offset of DW_FORM_block containing E
+                                       (register saved at address E computes)
+       val_expression(E)       section offset of DW_FORM_block containing E
+                                       (register = value E computes)
+  */
+  Dwarf_Sword value:(sizeof (Dwarf_Sword) * 8 - 3);
+};
+
+/* This holds everything we know about the state of the frame
+   at a particular PC location described by an FDE.  */
+struct Dwarf_Frame_s
+{
+  Dwarf_CFI *cache;
+
+  Dwarf_Frame *prev;
+
+  /* The CIE we got this FDE from.
+     This has the return_address_register and signal_frame flag.  */
+  struct dwarf_cie *cie;
+
+  /* The CFA is unknown, is R+N, or is computed by a DWARF expression.  */
+  enum { cfa_undefined, cfa_offset, cfa_expr } cfa_rule;
+  union
+  {
+    Dwarf_Op offset;
+    Dwarf_Block expr;
+  } cfa_data;
+  /* We store an offset rule as a DW_OP_bregx operation.  */
+#define cfa_val_reg    cfa_data.offset.number
+#define cfa_val_offset cfa_data.offset.number2
+
+  size_t nregs;
+  struct dwarf_frame_register regs[];
+};
+
+
+/* Clean up the data structure and all it points to.  */
+extern void __libdw_destroy_frame_cache (Dwarf_CFI *cache)
+  __nonnull_attribute__ (1) internal_function;
+
+/* Enter a CIE encountered while reading through for FDEs.  */
+extern void __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset,
+                               const Dwarf_CIE *info)
+  __nonnull_attribute__ (1, 3) internal_function;
+
+/* Look up a CIE_pointer for random access.  */
+extern struct dwarf_cie *__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
+  __nonnull_attribute__ (1) internal_function;
+
+
+/* Look for an FDE covering the given PC address.  */
+extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache,
+                                          Dwarf_Addr address)
+  __nonnull_attribute__ (1) internal_function;
+
+/* Process the FDE that contains the given PC address,
+   to yield the frame state when stopped there.
+   The return value is a DWARF_E_* error code.  */
+extern int __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
+                                    Dwarf_Addr address, Dwarf_Frame **frame)
+  __nonnull_attribute__ (1, 2, 4) internal_function;
+
+
+/* Dummy struct for memory-access.h macros.  */
+#define BYTE_ORDER_DUMMY(var, e_ident)                                       \
+  const struct { bool other_byte_order; } var =                                      \
+    { ((BYTE_ORDER == LITTLE_ENDIAN && e_ident[EI_DATA] == ELFDATA2MSB)       \
+       || (BYTE_ORDER == BIG_ENDIAN && e_ident[EI_DATA] == ELFDATA2LSB)) }
+
+
+INTDECL (dwarf_next_cfi)
+INTDECL (dwarf_getcfi)
+INTDECL (dwarf_getcfi_elf)
+INTDECL (dwarf_cfi_end)
+INTDECL (dwarf_cfi_setebl)
+INTDECL (dwarf_cfi_addrframe)
+
+#endif /* unwindP.h */
index 41ff69bca104785035b31dff8cb656f8baf11a9c..16248415ca23dfd556b7ffa93b608bc6e7aa9f79 100644 (file)
@@ -1,3 +1,11 @@
+2007-02-10  Roland McGrath  <roland@redhat.com>
+
+       * libdwflP.h (struct Dwfl_Module): New members `cfi', `cfi_elf'.
+       Add INTDECL for dwfl_module_getcfi.
+       * dwfl_module_getcfi.c: New file.
+       * dwfl_addrframe.c: New file.
+       * Makefile.am (libdwfl_a_SOURCES): Add them.
+
 2008-12-02  Roland McGrath  <roland@redhat.com>
 
        * dwfl_getmodules.c (dwfl_getmodules): Typo fix in last change.
 2006-09-05  Roland McGrath  <roland@redhat.com>
 
        * derelocate.c (cache_sections): Use alloca instead of variable-sized
-       auto array, in function already alloca.
+       auto array, in function already using alloca.
 
 2006-08-14  Roland McGrath  <roland@redhat.com>
 
index db14db2a380f2a36b5c90746502de9604e492b77..45dd0b3a584d7307547bc1447146a1043998666a 100644 (file)
@@ -73,8 +73,8 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
                    dwfl_module_return_value_location.c \
                    dwfl_module_register_names.c \
                    dwfl_segment_report_module.c \
-                   link_map.c core-file.c
-
+                   link_map.c core-file.c \
+                   dwfl_module_getcfi.c dwfl_addrframe.c
 
 if MUDFLAP
 libdwfl = libdwfl.a $(libdw) $(libebl) $(libelf) $(libeu)
diff --git a/libdwfl/dwfl_addrframe.c b/libdwfl/dwfl_addrframe.c
new file mode 100644 (file)
index 0000000..62125fe
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include "libdwflP.h"
+#include "../libdw/unwindP.h"  /* XXX */
+
+int
+dwfl_addrframe (dwfl, address, frame)
+     Dwfl *dwfl;
+     Dwarf_Addr address;
+     Dwarf_Frame **frame;
+{
+  Dwarf_Addr dwbias;
+  Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, address);
+  Dwarf_CFI *cfi = INTUSE(dwfl_module_getcfi) (mod, &dwbias);
+  if (cfi == NULL)
+    return -1;
+
+  int result = INTUSE(dwarf_cfi_addrframe) (cfi, address - dwbias, frame);
+  if (result != 0)
+    __libdwfl_seterrno (DWFL_E_LIBDW);
+  return result;
+}
diff --git a/libdwfl/dwfl_module_getcfi.c b/libdwfl/dwfl_module_getcfi.c
new file mode 100644 (file)
index 0000000..816b493
--- /dev/null
@@ -0,0 +1,92 @@
+/* Find CFI for a module in libdwfl.
+   Copyright (C) 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include "libdwflP.h"
+#include "../libdw/unwindP.h"
+#include "../libdw/unwind.h"   /* XXX */
+
+Dwarf_CFI *
+dwfl_module_getcfi (mod, bias)
+     Dwfl_Module *mod;
+     Dwarf_Addr *bias;
+{
+  if (mod == NULL)
+    return NULL;
+
+  if (mod->cfi == NULL)
+    {
+      Elf *elf = INTUSE(dwfl_module_getelf) (mod, bias);
+      if (elf != NULL)
+       {
+         Dwarf *dw = INTUSE(dwfl_module_getdwarf) (mod, bias);
+         mod->cfi_elf = dw == NULL;
+         mod->cfi = (mod->cfi_elf ? INTUSE(dwarf_getcfi_elf) (elf)
+                     : INTUSE(dwarf_getcfi) (dw));
+         if (mod->cfi == NULL)
+           __libdwfl_seterrno (DWFL_E_LIBDW);
+       }
+
+      if (mod->cfi != NULL && mod->cfi->ebl == NULL)
+       {
+         Dwfl_Error error = __libdwfl_module_getebl (mod);
+         if (error == DWFL_E_NOERROR)
+           mod->cfi->ebl = mod->ebl;
+         else
+           {
+             if (mod->cfi_elf)
+               INTUSE(dwarf_cfi_end) (mod->cfi);
+             mod->cfi = NULL;
+             __libdwfl_seterrno (error);
+           }
+       }
+    }
+
+  return mod->cfi;
+}
+INTDEF (dwfl_module_getcfi)
index 6ba5c96e80c9b9ad511aba4b551180cc79642004..625de0bf5d5e29d3147f66a99caffe2383c1b758 100644 (file)
@@ -62,6 +62,7 @@
 #include <string.h>
 
 #include "../libdw/libdwP.h"   /* We need its INTDECLs.  */
+#include "../libdw/unwind.h"   /* XXX */
 
 /* gettext helper macros.  */
 #define _(Str) dgettext ("elfutils", Str)
@@ -180,6 +181,9 @@ struct Dwfl_Module
   struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs.  */
   unsigned int naranges;
 
+  Dwarf_CFI *cfi;              /* Cached CFI for this module.  */
+  bool cfi_elf;                        /* cfi is from dwarf_getcfi_elf.  */
+
   int segment;                 /* Index of first segment table entry.  */
   bool gc;                     /* Mark/sweep flag.  */
 };
@@ -403,6 +407,7 @@ INTDECL (dwfl_linux_kernel_report_modules)
 INTDECL (dwfl_linux_kernel_report_offline)
 INTDECL (dwfl_offline_section_address)
 INTDECL (dwfl_module_relocate_address)
+INTDECL (dwfl_module_getcfi)
 
 /* Leading arguments standard to callbacks passed a Dwfl_Module.  */
 #define MODCB_ARGS(mod)        (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
index 51b3b705ed866c48c0cbdb767258f513dec3f40d..475fe6bd1e7b002911fd000c76de1173d0bc111e 100644 (file)
@@ -1,3 +1,12 @@
+2007-01-18  Roland McGrath  <roland@redhat.com>
+
+       * ebl-hooks.h: Add abi_cfi hook.
+       * eblopenbackend.c (default_abi_cfi): New function.
+       (fill_defaults): Add initializer.
+       * eblabicfi.c: New file.
+       * Makefile.am (gen_SOURCES): Add it.
+       * libebl.h: Declare ebl_abi_cfi.
+
 2008-08-01  Roland McGrath  <roland@redhat.com>
 
        * eblcorenotetypename.c: Handle NT_386_IOPERM.
index c4e4a076259f1294527082a372a0f002c00835c1..af3ae6a72445cd6e93c74c5d9cf45cc484d1fb88 100644 (file)
@@ -59,7 +59,7 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \
              ebl_check_special_symbol.c eblbsspltp.c eblretval.c \
              eblreginfo.c eblnonerelocp.c eblrelativerelocp.c \
              eblsysvhashentrysize.c eblauxvinfo.c eblcheckobjattr.c \
-             ebl_check_special_section.c ebl_syscall_abi.c
+             ebl_check_special_section.c ebl_syscall_abi.c eblabicfi.c
 
 libebl_a_SOURCES = $(gen_SOURCES)
 
index 2db1e208714b049d89a29b81592dbf65669baf97..fd328aee2c3cf474ffbd8e0506308958a996ba9f 100644 (file)
@@ -167,6 +167,8 @@ int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end,
                     GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb,
                     DisasmGetSymCB_t symcb, void *outcbarg, void *symcbarg);
 
+/* Supply the machine-specific state of CFI before CIE initial programs.  */
+int EBLHOOK(abi_cfi) (Ebl *ebl, Dwarf_CIE *abi_info);
 
 /* Destructor for ELF backend handle.  */
 void EBLHOOK(destr) (struct ebl *);
diff --git a/libebl/eblabicfi.c b/libebl/eblabicfi.c
new file mode 100644 (file)
index 0000000..fe5c7a5
--- /dev/null
@@ -0,0 +1,63 @@
+/* Return ABI-specific DWARF CFI details.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libeblP.h>
+
+
+int
+ebl_abi_cfi (ebl, abi_info)
+     Ebl *ebl;
+     Dwarf_CIE *abi_info;
+{
+  return ebl == NULL ? -1 : ebl->abi_cfi (ebl, abi_info);
+}
index 8cf421893fcd051c67bfe630aabea6b18bacc732..30383ed7eb04d5938df4e776f50451a0ed34d936 100644 (file)
@@ -218,6 +218,7 @@ static bool default_check_object_attribute (Ebl *ebl, const char *vendor,
                                            int tag, uint64_t value,
                                            const char **tag_name,
                                            const char **value_name);
+static int default_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info);
 
 
 static void
@@ -258,6 +259,7 @@ fill_defaults (Ebl *result)
   result->syscall_abi = default_syscall_abi;
   result->check_object_attribute = default_check_object_attribute;
   result->disasm = NULL;
+  result->abi_cfi = default_abi_cfi;
   result->destr = default_destr;
   result->sysvhash_entrysize = sizeof (Elf32_Word);
 }
@@ -746,3 +748,10 @@ default_check_object_attribute (Ebl *ebl __attribute__ ((unused)),
   *value_name = NULL;
   return false;
 }
+
+static int
+default_abi_cfi (Ebl *ebl __attribute__ ((unused)),
+                Dwarf_CIE *abi_info __attribute__ ((unused)))
+{
+  return 0;
+}
index 50258690c5d2f0baaba686b2bd32b8f5f3558e55..11de24aa158be62c7e60582b9836b9333fafba3f 100644 (file)
@@ -52,6 +52,7 @@
 
 #include <gelf.h>
 #include "libdw.h"
+#include "unwind.h"            /* XXX */
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -256,6 +257,38 @@ extern ssize_t ebl_register_info (Ebl *ebl,
 extern int ebl_syscall_abi (Ebl *ebl, int *sp, int *pc,
                            int *callno, int args[6]);
 
+/* Supply the ABI-specified state of DWARF CFI before CIE initial programs.
+
+   The DWARF 3.0 spec says that the default initial states of all registers
+   are "undefined", unless otherwise specified by the machine/compiler ABI.
+
+   This default is wrong for every machine with the CFI generated by GCC.
+   The EH unwinder does not really distinguish "same_value" and "undefined",
+   since it doesn't matter for unwinding (in either case there is no change
+   to make for that register).  GCC generates CFI that says nothing at all
+   about registers it hasn't spilled somewhere.  For our unwinder to give
+   the true story, the backend must supply an initial state that uses
+   "same_value" rules for all the callee-saves registers.
+
+   This can fill in the initial_instructions, initial_instructions_end
+   members of *ABI_INFO to point at a CFI instruction stream to process
+   before each CIE's initial instructions.  It should set the
+   data_alignment_factor member if it affects the initial instructions.
+
+   As a shorthand for some common cases, for this instruction stream
+   we overload some CFI instructions that cannot be used in a CIE:
+
+       DW_CFA_restore          -- Change default rule for all unmentioned
+                                  registers from undefined to same_value.
+
+   This function can also fill in ABI_INFO->return_address_register with the
+   DWARF register number that identifies the actual PC in machine state.
+   If there is no canonical DWARF register number with that meaning, it's
+   left unchanged (callers usually initialize with (Dwarf_Word) -1).
+   This value is not used by CFI per se.  */
+extern int ebl_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info)
+  __nonnull_attribute__ (2);
+
 /* ELF string table handling.  */
 struct Ebl_Strtab;
 struct Ebl_Strent;
index 7bfa650f5c59573180464e32b32970a18d0d3076..9bb886e832349f263d7b430e46e0d36f45e507a4 100644 (file)
@@ -94,4 +94,10 @@ typedef const char *(*ebl_bhinit_t) (Elf *, GElf_Half, Ebl *, size_t);
 #undef _
 #define _(Str) dgettext ("elfutils", Str)
 
+
+/* LEB128 constant helper macros.  */
+#define ULEB128_7(x)   (BUILD_BUG_ON_ZERO ((x) >= (1U << 7)) + (x))
+
+#define BUILD_BUG_ON_ZERO(x) (sizeof (char [(x) ? -1 : 1]) - 1)
+
 #endif /* libeblP.h */
index fb17835fd8588a9da6953b7636d12045ed30ddf4..8ae0274ace1134ffa741dc70849f9a18bbe47a13 100644 (file)
@@ -1,3 +1,18 @@
+2007-02-17  Roland McGrath  <roland@redhat.com>
+
+       * readelf.c (parse_opt): Take "frames" as alias for "frame" in
+       --debug-dump argument, matching bintuils readelf.
+       (print_debug_frame_section): Implemented.
+       (print_debug): Call it on .eh_frame section even dwarf_begin_elf fails.
+
+       * readelf.c (print_debug): Pass section name as new parameter to
+       print_debug_*_section functions.
+       (print_debug_abbrev_section): Take new argument.
+       (print_debug_aranges_section, print_debug_ranges_section)
+       (print_debug_info_section, print_debug_line_section): Likewise.
+       (print_debug_loc_section, print_debug_macinfo_section): Likewise.
+       (print_debug_pubnames_section, print_debug_str_section): Likewise.
+
 2008-12-02  Roland McGrath  <roland@redhat.com>
 
        * readelf.c (count_dwflmod, process_file): Don't presume encoding of
index 2797a8496a4a6a2382d520bc1f95764eb7482b6d..101f7ae33036169faf12db9dd49a26a77928e666 100644 (file)
@@ -57,6 +57,8 @@
 #include "../libdw/libdwP.h"
 #include "../libdwfl/libdwflP.h"
 #include "../libdw/memory-access.h"
+#include "../libdw/unwindP.h"
+#include "../libdw/encoded-value.h"
 
 
 /* Name and version of program.  */
@@ -344,7 +346,7 @@ parse_opt (int key, char *arg,
        print_debug_sections |= section_aranges;
       else if (strcmp (arg, "ranges") == 0)
        print_debug_sections |= section_ranges;
-      else if (strcmp (arg, "frame") == 0)
+      else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0)
        print_debug_sections |= section_frame;
       else if (strcmp (arg, "info") == 0)
        print_debug_sections |= section_info;
@@ -3961,11 +3963,11 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                            Ebl *ebl __attribute__ ((unused)),
                            GElf_Ehdr *ehdr __attribute__ ((unused)),
                            Elf_Scn *scn __attribute__ ((unused)),
-                           GElf_Shdr *shdr, Dwarf *dbg)
+                           GElf_Shdr *shdr, const char *secname, Dwarf *dbg)
 {
   printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"
                   " [ Code]\n"),
-         ".debug_abbrev", (uint64_t) shdr->sh_offset);
+         secname, (uint64_t) shdr->sh_offset);
 
   Dwarf_Off offset = 0;
   while (offset < shdr->sh_size)
@@ -4033,14 +4035,14 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                             Ebl *ebl __attribute__ ((unused)),
                             GElf_Ehdr *ehdr __attribute__ ((unused)),
                             Elf_Scn *scn __attribute__ ((unused)),
-                            GElf_Shdr *shdr, Dwarf *dbg)
+                            GElf_Shdr *shdr, const char *name, Dwarf *dbg)
 {
   Dwarf_Aranges *aranges;
   size_t cnt;
   if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
     {
-      error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
-            dwarf_errmsg (-1));
+      error (0, 0, gettext ("cannot get %s content: %s"),
+            name, dwarf_errmsg (-1));
       return;
     }
 
@@ -4049,7 +4051,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                    "\
 \nDWARF section '%s' at offset %#" PRIx64 " contains %zu entries:\n",
                    cnt),
-         ".debug_aranges", (uint64_t) shdr->sh_offset, cnt);
+         name, (uint64_t) shdr->sh_offset, cnt);
 
   /* Compute floor(log16(cnt)).  */
   size_t tmp = cnt;
@@ -4089,20 +4091,20 @@ static void
 print_debug_ranges_section (Dwfl_Module *dwflmod,
                            Ebl *ebl __attribute__ ((unused)),
                            GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr,
-                           Dwarf *dbg)
+                           const char *name, Dwarf *dbg)
 {
   Elf_Data *data = elf_rawdata (scn, NULL);
 
   if (unlikely (data == NULL))
     {
-      error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
-            elf_errmsg (-1));
+      error (0, 0, gettext ("cannot get %s content: %s"),
+            name, elf_errmsg (-1));
       return;
     }
 
   printf (gettext ("\
 \nDWARF section '%s' at offset %#" PRIx64 ":\n"),
-         ".debug_ranges", (uint64_t) shdr->sh_offset);
+         name, (uint64_t) shdr->sh_offset);
 
   size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
 
@@ -4158,6 +4160,271 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
     }
 }
 
+static void
+print_cfi (unsigned int indent, Dwarf *dbg, Dwarf_CFI *cfi,
+          unsigned int addrsize, uint8_t fde_encoding,
+          const uint8_t *program, const uint8_t *program_end,
+          Dwarf_Addr loc)
+{
+  static const char *cfi_extended[] =
+    {
+      [DW_CFA_nop] = "nop",
+      [DW_CFA_set_loc] = "set_loc",
+      [DW_CFA_advance_loc1] = "advance_loc1",
+      [DW_CFA_advance_loc2] = "advance_loc2",
+      [DW_CFA_advance_loc4] = "advance_loc4",
+      [DW_CFA_offset_extended] = "offset_extended",
+      [DW_CFA_restore_extended] = "restore_extended",
+      [DW_CFA_undefined] = "undefined",
+      [DW_CFA_same_value] = "same_value",
+      [DW_CFA_register] = "register",
+      [DW_CFA_remember_state] = "remember_state",
+      [DW_CFA_restore_state] = "restore_state",
+      [DW_CFA_def_cfa] = "def_cfa",
+      [DW_CFA_def_cfa_register] = "def_cfa_register",
+      [DW_CFA_def_cfa_offset] = "def_cfa_offset",
+      [DW_CFA_def_cfa_expression] = "def_cfa_expression",
+      [DW_CFA_expression] = "expression",
+      [DW_CFA_offset_extended_sf] = "offset_extended_sf",
+      [DW_CFA_def_cfa_sf] = "def_cfa_sf",
+      [DW_CFA_def_cfa_offset_sf] = "def_cfa_offset_sf",
+      [DW_CFA_val_offset] = "val_offset",
+      [DW_CFA_val_offset_sf] = "val_offset_sf",
+      [DW_CFA_val_expression] = "val_expression",
+
+      [DW_CFA_lo_user] = "lo_user",
+      [DW_CFA_MIPS_advance_loc8] = "MIPS_advance_loc8",
+      [DW_CFA_GNU_window_save] = "GNU_window_save",
+      [DW_CFA_GNU_args_size] = "GNU_args_size",
+      [DW_CFA_hi_user] = "hi_user"
+    };
+
+#define REGFMT "r%" PRIu64
+
+  while (program < program_end)
+    {
+      uint8_t opcode = *program++;
+      uint8_t ophi = opcode & 0xc0;
+      uint8_t oplo = opcode & 0x3f;
+      Dwarf_Word operand = oplo;
+
+      switch (ophi)
+       {
+       case DW_CFA_advance_loc:
+         printf ("%*s%s + %#x", indent, "", "advance_loc", oplo);
+         goto advance_loc;
+       case DW_CFA_offset:
+         printf ("%*s%s + %#x", indent, "", "offset", oplo);
+         goto offset;
+       case DW_CFA_restore:
+         printf ("%*s%s + %#x", indent, "", "restore", oplo);
+         goto restore;
+       case DW_CFA_extended:
+         break;
+       }
+
+      if (cfi_extended[oplo] != NULL)
+       printf ("%*s%s", indent, "", cfi_extended[oplo]);
+      else if (oplo >= DW_CFA_lo_user && oplo < DW_CFA_hi_user)
+       printf ("%*s%s + %#x", indent, "", "lo_user", oplo);
+      else
+       printf ("%*s??? %#x", indent, "", oplo);
+
+      Dwarf_Word offset;
+      Dwarf_Sword sf_offset;
+      Dwarf_Word regno;
+      switch (opcode)
+       {
+       case DW_CFA_advance_loc1:
+         operand = *program++;
+       advance_loc:
+         printf (gettext (": advance location %" PRIu64
+                          " * code_alignment_factor\n"),
+                 operand);
+         break;
+
+       case DW_CFA_advance_loc2:
+         operand = read_2ubyte_unaligned_inc (dbg, program);
+         goto advance_loc;
+       case DW_CFA_advance_loc4:
+         operand = read_4ubyte_unaligned_inc (dbg, program);
+         goto advance_loc;
+       case DW_CFA_MIPS_advance_loc8:
+         operand = read_8ubyte_unaligned_inc (dbg, program);
+         goto advance_loc;
+
+       case DW_CFA_set_loc:
+         if (cfi == NULL)
+           {
+             puts (gettext (": invalid in CIE initial instructions"));
+             program += addrsize;
+           }
+         else
+           {
+             loc = read_encoded_value (cfi, fde_encoding, &program);
+             printf (gettext (": set location to %#" PRIx64 "\n"), loc);
+           }
+         break;
+
+       case DW_CFA_def_cfa:
+         get_uleb128 (operand, program);
+         get_uleb128 (offset, program);
+         printf (gettext (": CFA is " REGFMT " + %#" PRIx64 "\n"),
+                 operand, offset);
+         break;
+
+       case DW_CFA_def_cfa_register:
+         get_uleb128 (regno, program);
+         printf (gettext (": CFA is " REGFMT " + old offset\n"), regno);
+         break;
+
+       case DW_CFA_def_cfa_sf:
+         get_uleb128 (operand, program);
+         get_sleb128 (sf_offset, program);
+         printf (gettext (": CFA is " REGFMT
+                          " + %" PRId64 " * data_alignment_factor\n"),
+                 operand, sf_offset);
+         break;
+
+       case DW_CFA_def_cfa_offset:
+         get_uleb128 (offset, program);
+         printf (gettext (": CFA is old register + %#" PRIx64 "\n"), offset);
+         break;
+
+       case DW_CFA_def_cfa_offset_sf:
+         get_sleb128 (sf_offset, program);
+         printf (gettext (": CFA is old register"
+                          " + %" PRId64 " * data_alignment_factor\n"),
+                 sf_offset);
+         break;
+
+       case DW_CFA_def_cfa_expression:
+         /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+         get_uleb128 (operand, program);
+         if ((Dwarf_Word) (program_end - program) < operand)
+           {
+             printf (gettext (": invalid expression length %" PRIu64
+                              " (> %tu)\n"), operand, program_end - program);
+             program = program_end;
+           }
+         else
+           {
+             size_t len = indent + printf (gettext (": CFA computed by:\n"));
+             print_ops (dbg, len, len, addrsize, operand, program);
+             program += operand;
+           }
+         break;
+
+       case DW_CFA_undefined:
+         get_uleb128 (operand, program);
+         printf (gettext (": " REGFMT " is undefined\n"), operand);
+         break;
+
+       case DW_CFA_same_value:
+         get_uleb128 (operand, program);
+         printf (gettext (": " REGFMT " has caller's value\n"), operand);
+         break;
+
+       case DW_CFA_offset_extended:
+         get_uleb128 (operand, program);
+       offset:
+         get_uleb128 (offset, program);
+         printf (gettext (": " REGFMT " at CFA"
+                          " + %" PRId64 " * data_alignment_factor\n"),
+                 operand, offset);
+         break;
+
+       case DW_CFA_offset_extended_sf:
+         get_uleb128 (operand, program);
+         get_sleb128 (sf_offset, program);
+         printf (gettext (": " REGFMT " saved at CFA"
+                          " + %" PRId64 " * data_alignment_factor\n"),
+                 operand, sf_offset);
+         break;
+
+       case DW_CFA_val_offset:
+         get_uleb128 (operand, program);
+         get_uleb128 (offset, program);
+         printf (gettext (": " REGFMT " has value CFA"
+                          " + %" PRIu64 " * data_alignment_factor\n"),
+                 operand, offset);
+         break;
+
+       case DW_CFA_val_offset_sf:
+         get_uleb128 (operand, program);
+         get_sleb128 (sf_offset, program);
+         printf (gettext (": " REGFMT " has value CFA"
+                          " + %" PRId64 " * data_alignment_factor\n"),
+                 operand, sf_offset);
+         break;
+
+       case DW_CFA_register:
+         get_uleb128 (regno, program);
+         get_uleb128 (operand, program);
+         printf (gettext (": " REGFMT " saved in " REGFMT "\n"),
+                 regno, operand);
+         break;
+
+       case DW_CFA_expression:
+         get_uleb128 (regno, program);
+         /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+         get_uleb128 (operand, program);
+         if ((Dwarf_Word) (program_end - program) < operand)
+           {
+             printf (gettext (": invalid expression length %" PRIu64
+                              " (> %tu)\n"), operand, program_end - program);
+             program = program_end;
+           }
+         else
+           {
+             size_t len = indent + printf (gettext (": " REGFMT
+                                                    " saved at:\n"), regno);
+             print_ops (dbg, len, len, addrsize, operand, program);
+             program += operand;
+           }
+         break;
+
+       case DW_CFA_val_expression:
+         get_uleb128 (regno, program);
+         /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+         get_uleb128 (operand, program);
+         if ((Dwarf_Word) (program_end - program) < operand)
+           {
+             printf (gettext (": invalid expression length %" PRIu64
+                              " (> %tu)\n"), operand, program_end - program);
+             program = program_end;
+           }
+         else
+           {
+             size_t len = indent + printf (gettext (": " REGFMT
+                                                    " value is:\n"), regno);
+             print_ops (dbg, len, len, addrsize, operand, program);
+             program += operand;
+           }
+         break;
+
+       case DW_CFA_restore_extended:
+         get_uleb128 (operand, program);
+       restore:
+         printf (gettext ("restore " REGFMT " to CIE initial state\n"),
+                 operand);
+         break;
+
+       case DW_CFA_GNU_args_size:
+         get_uleb128 (operand, program);
+         printf (gettext ("argument size %" PRIu64 "\n"), operand);
+         break;
+
+       case DW_CFA_GNU_window_save:
+       case DW_CFA_remember_state:
+       case DW_CFA_restore_state:
+       case DW_CFA_nop:
+       default:
+         puts ("");
+         break;
+       }
+    }
+}
 
 static void
 print_debug_frame_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
@@ -4165,8 +4432,143 @@ print_debug_frame_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                           GElf_Ehdr *ehdr __attribute__ ((unused)),
                           Elf_Scn *scn __attribute__ ((unused)),
                           GElf_Shdr *shdr __attribute__ ((unused)),
+                          const char *name,
                           Dwarf *dbg __attribute__ ((unused)))
 {
+  Elf_Data *data = elf_rawdata (scn, NULL);
+
+  if (data == NULL)
+    {
+      error (0, 0, gettext ("cannot get %s content: %s"),
+            name, elf_errmsg (-1));
+      return;
+    }
+
+  printf (gettext ("\
+\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
+         name, (uint64_t) shdr->sh_offset);
+
+  bool eh_frame_p = !strcmp (name, ".eh_frame");
+
+  /* Dummy struct for memory-access.h macros.  */
+  Dwarf dw =
+    {
+      .other_byte_order = ((BYTE_ORDER == LITTLE_ENDIAN
+                           && ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+                          || (BYTE_ORDER == BIG_ENDIAN
+                              && ehdr->e_ident[EI_DATA] == ELFDATA2LSB))
+    };
+  if (dbg == NULL)
+    dbg = &dw;
+  else
+    assert (dw.other_byte_order == dbg->other_byte_order);
+
+  unsigned int addrsize = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+
+  Dwarf_Off last_offset;
+  Dwarf_Off offset = 0;
+  uint8_t fde_encoding = DW_EH_PE_omit;
+  size_t fde_augmentation_size = 0;
+  Dwarf_Off last_cie = CIE_ID;
+  do
+    {
+      last_offset = offset;
+      Dwarf_CFI_Entry entry;
+      int result = dwarf_next_cfi (ehdr->e_ident, data, eh_frame_p,
+                                  offset, &offset, &entry);
+      if (result > 0)
+       /* No more entries.  */
+       break;
+      if (result < 0)
+       printf ("cannot read CFI at offset %#" PRIx64 ": %s\n",
+               (uint64_t) last_offset, dwarf_errmsg (-1));
+      else if (dwarf_cfi_cie_p (&entry))
+       {                       /* CIE */
+         printf (gettext (" [%6" PRIx64 "] CIE, augmentation: \"%s\""
+                          " (data bytes: %zu)\n"),
+                 last_offset, entry.cie.augmentation,
+                 entry.cie.augmentation_data_size);
+         printf (gettext ("          code_alignment_factor: %" PRIu64 ", "
+                          "data_alignment_factor: %" PRId64 "\n"),
+                 entry.cie.code_alignment_factor,
+                 entry.cie.data_alignment_factor);
+         printf (gettext ("          return_address_register: %" PRIu64 "\n"),
+                 entry.cie.return_address_register);
+         printf (gettext ("          initial_instructions:\n"));
+         print_cfi (12, dbg, NULL, addrsize, DW_EH_PE_omit,
+                    entry.cie.initial_instructions,
+                    entry.cie.initial_instructions_end,
+                    0);
+       }
+      else
+       {                       /* FDE */
+         printf (gettext (" [%6" PRIx64 "] FDE, "
+                          "CIE_pointer: [%6" PRIx64 "]\n"),
+                 last_offset, entry.fde.CIE_pointer);
+
+         if (entry.fde.CIE_pointer != last_cie
+             || fde_encoding == DW_EH_PE_omit)
+           {
+             /* We have to go find the referenced CIE to be sure of the
+                encodings used in this FDE.  */
+
+             Dwarf_CFI_Entry cie_entry;
+             Dwarf_Off next;
+             result = dwarf_next_cfi (ehdr->e_ident, data, eh_frame_p,
+                                      entry.fde.CIE_pointer,
+                                      &next, &cie_entry);
+             if (result != 0 || !dwarf_cfi_cie_p (&cie_entry))
+               continue;
+
+             last_cie = entry.fde.CIE_pointer;
+             fde_encoding = DW_EH_PE_absptr;
+             const char *p = cie_entry.cie.augmentation;
+             const uint8_t *dp = cie_entry.cie.augmentation_data;
+             while (*p != '\0')
+               {
+                 switch (*p++)
+                   {
+                   case 'R':
+                     fde_encoding = *dp++;
+                     break;
+                   case 'L':   /* Skip LSDA pointer encoding byte.  */
+                     ++dp;
+                     continue;
+                   case 'P':   /* Skip encoded personality routine pointer. */
+                     dp += 1 + encoded_value_size (data, ehdr->e_ident,
+                                                   *dp, dp + 1);
+                     continue;
+                   default:
+                     continue;
+                   }
+                 break;
+               }
+
+             fde_augmentation_size = cie_entry.cie.fde_augmentation_data_size;
+           }
+
+         Dwarf_CFI *cfi = (eh_frame_p ? dwarf_getcfi_elf (ebl->elf)
+                           : dwarf_getcfi (dbg));
+         if (cfi == NULL)
+           continue;
+
+         Dwarf_Addr initial_location = read_encoded_value (cfi,
+                                                           fde_encoding,
+                                                           &entry.fde.start);
+         Dwarf_Addr address_range = read_encoded_value (cfi,
+                                                        fde_encoding & 0x0f,
+                                                        &entry.fde.start);
+         entry.fde.start += fde_augmentation_size;
+
+         printf (gettext ("          initial_location: %#" PRIx64 ", "
+                          "address_range: %#" PRIx64 "\n"),
+                 initial_location, address_range);
+
+         printf (gettext ("          instructions:\n"));
+         print_cfi (12, dbg, cfi, addrsize, fde_encoding,
+                    entry.fde.start, entry.fde.end, initial_location);
+       }
+    } while (offset != last_offset);
 }
 
 
@@ -4390,11 +4792,11 @@ print_debug_info_section (Dwfl_Module *dwflmod,
                          Ebl *ebl __attribute__ ((unused)),
                          GElf_Ehdr *ehdr __attribute__ ((unused)),
                          Elf_Scn *scn __attribute__ ((unused)),
-                         GElf_Shdr *shdr, Dwarf *dbg)
+                         GElf_Shdr *shdr, const char *name, Dwarf *dbg)
 {
   printf (gettext ("\
 \nDWARF section '%s' at offset %#" PRIx64 ":\n [Offset]\n"),
-         ".debug_info", (uint64_t) shdr->sh_offset);
+         name, (uint64_t) shdr->sh_offset);
 
   /* If the section is empty we don't have to do anything.  */
   if (shdr->sh_size == 0)
@@ -4437,7 +4839,7 @@ print_debug_info_section (Dwfl_Module *dwflmod,
     {
       error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
                            " in section '%s': %s"),
-            (uint64_t) offset, ".debug_info", dwarf_errmsg (-1));
+            (uint64_t) offset, name, dwarf_errmsg (-1));
       goto do_return;
     }
 
@@ -4456,7 +4858,7 @@ print_debug_info_section (Dwfl_Module *dwflmod,
        {
          error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
                                " in section '%s': %s"),
-                (uint64_t) offset, ".debug_info", dwarf_errmsg (-1));
+                (uint64_t) offset, name, dwarf_errmsg (-1));
          goto do_return;
        }
 
@@ -4511,11 +4913,12 @@ print_debug_info_section (Dwfl_Module *dwflmod,
 static void
 print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
                          GElf_Ehdr *ehdr __attribute__ ((unused)),
-                         Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
+                         Elf_Scn *scn, GElf_Shdr *shdr, const char *name,
+                         Dwarf *dbg)
 {
   printf (gettext ("\
 \nDWARF section '%s' at offset %#" PRIx64 ":\n"),
-         ".debug_line", (uint64_t) shdr->sh_offset);
+         name, (uint64_t) shdr->sh_offset);
 
   if (shdr->sh_size == 0)
     return;
@@ -4548,7 +4951,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
            {
            invalid_data:
              error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
-                    elf_ndxscn (scn), ".debug_line");
+                    elf_ndxscn (scn), name);
              return;
            }
          unit_length = read_8ubyte_unaligned_inc (dbg, linep);
@@ -4949,21 +5352,21 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
                         Ebl *ebl __attribute__ ((unused)),
                         GElf_Ehdr *ehdr __attribute__ ((unused)),
                         Elf_Scn *scn __attribute__ ((unused)),
-                        GElf_Shdr *shdr,
+                        GElf_Shdr *shdr, const char *name,
                         Dwarf *dbg __attribute__ ((unused)))
 {
   Elf_Data *data = elf_rawdata (scn, NULL);
 
   if (unlikely (data == NULL))
     {
-      error (0, 0, gettext ("cannot get .debug_loc content: %s"),
-            elf_errmsg (-1));
+      error (0, 0, gettext ("cannot get %s content: %s"),
+            name, elf_errmsg (-1));
       return;
     }
 
   printf (gettext ("\
 \nDWARF section '%s' at offset %#" PRIx64 ":\n"),
-         ".debug_loc", (uint64_t) shdr->sh_offset);
+         name, (uint64_t) shdr->sh_offset);
 
   size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
 
@@ -5054,11 +5457,12 @@ static void
 print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                             Ebl *ebl __attribute__ ((unused)),
                             GElf_Ehdr *ehdr __attribute__ ((unused)),
-                            Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
+                            Elf_Scn *scn, GElf_Shdr *shdr, const char *name,
+                            Dwarf *dbg)
 {
   printf (gettext ("\
 \nDWARF section '%s' at offset %#" PRIx64 ":\n"),
-         ".debug_macinfo", (uint64_t) shdr->sh_offset);
+         name, (uint64_t) shdr->sh_offset);
   putc_unlocked ('\n', stdout);
 
   /* There is no function in libdw to iterate over the raw content of
@@ -5227,10 +5631,10 @@ print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                              Ebl *ebl __attribute__ ((unused)),
                              GElf_Ehdr *ehdr __attribute__ ((unused)),
                              Elf_Scn *scn __attribute__ ((unused)),
-                             GElf_Shdr *shdr, Dwarf *dbg)
+                             GElf_Shdr *shdr, const char *name, Dwarf *dbg)
 {
   printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"),
-         ".debug_pubnames", (uint64_t) shdr->sh_offset);
+         name, (uint64_t) shdr->sh_offset);
 
   int n = 0;
   (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0);
@@ -5242,7 +5646,7 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                         Ebl *ebl __attribute__ ((unused)),
                         GElf_Ehdr *ehdr __attribute__ ((unused)),
                         Elf_Scn *scn __attribute__ ((unused)),
-                        GElf_Shdr *shdr, Dwarf *dbg)
+                        GElf_Shdr *shdr, const char *name, Dwarf *dbg)
 {
   /* Compute floor(log16(shdr->sh_size)).  */
   GElf_Addr tmp = shdr->sh_size;
@@ -5256,7 +5660,7 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 
   printf (gettext ("\nDWARF section '%s' at offset %#" PRIx64 ":\n"
                   " %*s  String\n"),
-         ".debug_str", (uint64_t) shdr->sh_offset,
+         name, (uint64_t) shdr->sh_offset,
          /* TRANS: the debugstr| prefix makes the string unique.  */
          digits + 2, sgettext ("debugstr|Offset"));
 
@@ -5281,6 +5685,12 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 static void
 print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
 {
+  /* Find the debug information sections.  For this we have to search
+     through the section table.  */
+  Dwarf *dbg;
+  Elf_Scn *scn;
+  size_t shstrndx;
+
   /* Before we start the real work get a debug context descriptor.  */
   Dwarf_Addr dwbias;
   Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
@@ -5310,8 +5720,8 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
          {
            const char *name;
            enum section_e bitmask;
-           void (*fp) (Dwfl_Module *, Ebl *,
-                       GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
+           void (*fp) (Dwfl_Module *, Ebl *, GElf_Ehdr *,
+                       Elf_Scn *, GElf_Shdr *, const char *, Dwarf *);
          } debug_sections[] =
            {
 #define NEW_SECTION(name) \
@@ -5326,7 +5736,6 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
              NEW_SECTION (str),
              NEW_SECTION (macinfo),
              NEW_SECTION (ranges),
-             { ".eh_frame", section_frame, print_debug_frame_section }
            };
          const int ndebug_sections = (sizeof (debug_sections)
                                       / sizeof (debug_sections[0]));
@@ -5334,11 +5743,19 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
                                         shdr->sh_name);
          int n;
 
+         if (strcmp (name, ".eh_frame") == 0)
+           {
+             if (print_debug_sections & section_frame)
+               print_debug_frame_section (ebl, ehdr, scn, shdr, name, dbg);
+             continue;
+           }
+
          for (n = 0; n < ndebug_sections; ++n)
            if (strcmp (name, debug_sections[n].name) == 0)
              {
                if (print_debug_sections & debug_sections[n].bitmask)
-                 debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
+                 debug_sections[n].fp (dwflmod, ebl, ehdr,
+                                       scn, shdr, name, dbg);
                break;
              }
        }
index b1471c1b08a0fd9b9b38c038830db6704d1f757d..876ae24b6fffecdf82729a4e835e6ce22583b950 100644 (file)
@@ -1,3 +1,9 @@
+2007-02-10  Roland McGrath  <roland@redhat.com>
+
+       * addrcfi.c: New file.
+       * Makefile.am (noinst_PROGRAMS): Add it.
+       (addrcfi_LDADD): New variable.
+
 2008-11-26  Roland McGrath  <roland@redhat.com>
 
        * dwfl-bug-getmodules.c: New file.
index b533521c5988fdbd6aa19e4cb5f43fb62306d083..90b593d39601f717850e079e481a46d406fb671d 100644 (file)
@@ -60,7 +60,7 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  find-prologues funcretval allregs rdwrmmap \
                  dwfl-bug-addr-overflow arls dwfl-bug-fd-leak \
                  dwfl-addr-sect dwfl-bug-report early-offscn \
-                 dwfl-bug-getmodules
+                 dwfl-bug-getmodules addrcfi
 # get-ciefde
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
            asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -233,6 +233,7 @@ dwfl_bug_report_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 dwfl_bug_getmodules_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 dwfl_addr_sect_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 sha1_tst_LDADD = $(libeu) $(libmudflap)
+addrcfi_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 
 CLEANFILES = xxx *.gcno *.gcda *gconv
 
diff --git a/tests/addrcfi.c b/tests/addrcfi.c
new file mode 100644 (file)
index 0000000..79e31e2
--- /dev/null
@@ -0,0 +1,175 @@
+/* Test program for CFI handling.
+   Copyright (C) 2006 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat 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 a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include ELFUTILS_HEADER(dwfl)
+#include <dwarf.h>
+#include <argp.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <error.h>
+#include <string.h>
+
+#include "../libdw/unwind.h"   /* XXX */
+
+static void
+print_detail (int result, const Dwarf_Op *ops, size_t nops)
+{
+  if (result < 0)
+    printf ("indeterminate (%s)\n", dwarf_errmsg (-1));
+  else if (nops == 0)
+    printf ("%s\n", result == 0 ? "same_value" : "undefined");
+  else
+    {
+      printf ("%s expression:", result == 0 ? "location" : "value");
+      for (size_t i = 0; i < nops; ++i)
+       {
+         printf (" %#x", ops[i].atom);
+         if (ops[i].number2 == 0)
+           {
+             if (ops[i].number != 0)
+               printf ("(%" PRId64 ")", ops[i].number);
+           }
+         else
+           printf ("(%" PRId64 ",%" PRId64 ")",
+                   ops[i].number, ops[i].number2);
+       }
+      puts ("");
+    }
+}
+
+static int
+print_register (void *arg,
+               int regno,
+               const char *setname,
+               const char *prefix,
+               const char *regname,
+               int bits __attribute__ ((unused)),
+               int type __attribute__ ((unused)))
+{
+  Dwarf_Frame *frame = arg;
+
+  printf ("\t%s reg%u (%s%s): ", setname, regno, prefix, regname);
+
+  Dwarf_Op ops_mem[2];
+  Dwarf_Op *ops;
+  size_t nops;
+  int result = dwarf_frame_register (frame, regno, ops_mem, &ops, &nops);
+  print_detail (result, ops, nops);
+
+  return DWARF_CB_OK;
+}
+
+static void
+handle_address (GElf_Addr pc, Dwfl *dwfl)
+{
+  Dwarf_Frame *frame;
+  int result = dwfl_addrframe (dwfl, pc, &frame);
+  if (result != 0)
+    error (EXIT_FAILURE, 0, "dwfl_addrframe: %s", dwfl_errmsg (-1));
+
+  printf ("%#" PRIx64 ":\n", pc);
+
+  bool signalp;
+  int ra_regno = dwarf_frame_return_address_register (frame, &signalp);
+  if (ra_regno < 0)
+    printf ("\treturn address register unavailable (%s)\n",
+           dwarf_errmsg (0));
+  else
+    printf ("\treturn address in reg%u%s\n",
+           ra_regno, signalp ? " (signal frame)" : "");
+
+  Dwarf_Op *cfa_ops;
+  int cfa_nops = dwarf_frame_cfa (frame, &cfa_ops);
+  if (cfa_nops < 0)
+    error (EXIT_FAILURE, 0, "dwarf_frame_cfa: %s", dwarf_errmsg (-1));
+
+  printf ("\tCFA ");
+  print_detail (1, cfa_ops, cfa_nops);
+
+  (void) dwfl_module_register_names (dwfl_addrmodule (dwfl, pc),
+                                    &print_register, frame);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int remaining;
+
+  /* Set locale.  */
+  (void) setlocale (LC_ALL, "");
+
+  Dwfl *dwfl = NULL;
+  (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl);
+  assert (dwfl != NULL);
+
+  int result = 0;
+
+  /* Now handle the addresses.  In case none are given on the command
+     line, read from stdin.  */
+  if (remaining == argc)
+    {
+      /* We use no threads here which can interfere with handling a stream.  */
+      (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
+
+      char *buf = NULL;
+      size_t len = 0;
+      while (!feof_unlocked (stdin))
+       {
+         if (getline (&buf, &len, stdin) < 0)
+           break;
+
+         char *endp;
+         uintmax_t addr = strtoumax (buf, &endp, 0);
+         if (endp != buf)
+           handle_address (addr, dwfl);
+         else
+           result = 1;
+       }
+
+      free (buf);
+    }
+  else
+    {
+      do
+       {
+         char *endp;
+         uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
+         if (endp != argv[remaining])
+           handle_address (addr, dwfl);
+         else
+           result = 1;
+       }
+      while (++remaining < argc);
+    }
+
+  dwfl_end (dwfl);
+
+  return result;
+}