+2009-04-19 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.
+
+ 2009-06-01 Ulrich Drepper <drepper@redhat.com>
+
+ * i386_reloc.def: Add IRELATIVE entry.
+ * x86_64_reloc.def: Likewise.
+
2009-04-16 Roland McGrath <roland@redhat.com>
* arm_regs.c (arm_register_info): Handle VFP registers.
+2009-04-19 Roland McGrath <roland@redhat.com>
+
+ * libdw.map (ELFUTILS_0.141): Add dwfl_addrframe,
+ dwfl_module_dwarf_cfi, dwfl_module_eh_cfi.
+
+ * 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.141): 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.
+ * cfi.c: New file.
+ * cfi.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_next_cfi.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdw.h (Dwarf_CIE, Dwarf_FDE, Dwarf_CIE_Entry): New types.
+ Declare dwarf_next_cfi.
+ * libdw.map (ELFUTILS_0.141): 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.
+
+2009-04-03 Roland McGrath <roland@redhat.com>
+
+ * libdwP.h (IDX_eh_frame): Remove it.
+ * dwarf_begin_elf.c (dwarf_scnnames): Remove its element.
+
+ 2009-05-05 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_formptr): Declare new function.
+ * dwarf_formudata.c: Implement it here.
+ * dwarf_getlocation.c (dwarf_getlocation_addr):
+ Call it instead of hand-rolled offset handling code.
+ * dwarf_getsrclines.c (dwarf_getsrclines): Likewise.
+ * dwarf_ranges.c (dwarf_ranges): Likewise.
+
+ 2009-05-04 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_read_begin_end_pair_inc): Declare new function.
+ * dwarf_ranges.c: Implement it here.
+ (dwarf_ranges): Call it.
+ * dwarf_getlocation.c (dwarf_getlocation_addr): Call it also here.
+
+ 2009-04-23 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formaddr.c (dwarf_formaddr): Call __libdw_read_* instead
+ of read_*ubyte_unaligned.
+ * dwarf_formref_die.c (dwarf_formref_die): Likewise.
+ * dwarf_formstring.c (dwarf_formstring): Likewise.
+ * dwarf_formudate.c (dwarf_formudata): Likewise.
+ * dwarf_getaranges.c (dwarf_getaranges): Likewise.
+ * dwarf_getlocation.c (dwarf_getlocation_addr): Likewise.
+ * dwarf_getpubnames.c (get_offsets): Likewise.
+ * dwarf_nextcu.c (dwarf_nextcu): Likewise.
+
+ 2009-04-23 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_read_addr_inc, __libdw_read_off_inc,
+ __libdw_read_addr, __libdw_read_off): Add four new internal
+ functions.
+
2009-05-07 Roland McGrath <roland@redhat.com>
* dwarf_getmacros.c (dwarf_getmacros): Use absolute section offset in
--- /dev/null
- ops, &nops);
+/* Get CFA expression for frame.
+ Copyright (C) 2006, 2007, 2009 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 "cfi.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,
++ IDX_debug_frame);
+ return result ?: (int) nops;
+ }
+
+ default:
+ abort ();
+ }
+
+ /*NOTREACHED*/
+ return -1;
+}
--- /dev/null
- &block, ops, nops) < 0)
+/* Get register location expression for frame.
+ Copyright (C) 2006, 2007, 2009 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 "cfi.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.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,
++ IDX_debug_frame) < 0)
+ result = -1;
+ break;
+ }
+ }
+
+ return result;
+}
--- /dev/null
- if (elf_getshstrndx (elf, &shstrndx) != 0)
+/* Get CFI from ELF file's exception-handling info.
+ Copyright (C) 2006, 2009 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 "cfi.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->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. */
+ Elf_Data_Scn dummy_cfi_hdr_data =
+ {
+ .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
+ };
+ Dwarf_CFI dummy_cfi =
+ {
+ .e_ident = ehdr->e_ident,
+ .datarel = hdr_vaddr,
+ .frame_vaddr = hdr_vaddr,
+ .data = &dummy_cfi_hdr_data,
+ };
+
+ *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;
+
+ Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
+ ELF_T_BYTE);
+ if (data == NULL)
+ {
+ invalid_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 (data->d_buf, 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;
+
+ data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
+ if (data == NULL)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
+ return NULL;
+ }
+ Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr);
+ if (cfi != NULL)
+ {
+ cfi->data = (Elf_Data_Scn *) data;
+
+ 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;
+ }
+ }
+ 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 = (Elf_Data_Scn *) 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 sections named ".eh_frame" and ".eh_frame_hdr". */
+static Dwarf_CFI *
+getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
+{
+ size_t shstrndx;
++ if (elf_getshdrstrndx (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)
/* Return location expression list.
- Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007 Red Hat, Inc.
- Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
++ Copyright (C) 2000-2009 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
return 0;
}
-static int
-getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
- Dwarf_Op **llbuf, size_t *listlen, int sec_index)
+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_Op **llbuf, size_t *listlen, int sec_index)
{
- 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. */
{
case DW_OP_addr:
/* Address, depends on address size of CU. */
- if (address_size == 4)
- {
- if (unlikely (data + 4 > end_data))
- {
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
- }
-
- newloc->number = read_4ubyte_unaligned_inc (&bo, data);
- }
- else
- {
- if (unlikely (data + 8 > end_data))
- goto invalid;
-
- newloc->number = read_8ubyte_unaligned_inc (&bo, data);
- }
+ if (__libdw_read_address_inc (dbg, sec_index, (unsigned char **)&data,
- cu->address_size, &newloc->number))
++ address_size, &newloc->number))
+ return -1;
break;
case DW_OP_deref:
return 0;
}
- Dwarf_Op **llbuf, size_t *listlen)
+static int
+getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
- block, llbuf, listlen);
++ Dwarf_Op **llbuf, size_t *listlen, int sec_index)
+{
+ return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
+ cu->address_size, &cu->locs,
++ block, llbuf, listlen, sec_index);
+}
+
int
dwarf_getlocation (attr, llbuf, listlen)
Dwarf_Attribute *attr;
void *arg)
__nonnull_attribute__ (2, 3) internal_function;
- Dwarf_Op **llbuf, size_t *listlen)
+/* 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,
++ int sec_index)
+ __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);