From: Roland McGrath Date: Tue, 16 Jun 2009 04:50:08 +0000 (-0700) Subject: Merge commit 'origin/master' into roland/unwind X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3d42835e009576f3283c9fb20370688483660a1f;p=thirdparty%2Felfutils.git Merge commit 'origin/master' into roland/unwind Conflicts: backends/ChangeLog libdw/ChangeLog libdw/dwarf_getlocation.c --- 3d42835e009576f3283c9fb20370688483660a1f diff --cc backends/ChangeLog index 30c0c4c1e,a1aa351fc..3793519b2 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@@ -1,13 -1,8 +1,18 @@@ +2009-04-19 Roland McGrath + + * 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 + + * i386_reloc.def: Add IRELATIVE entry. + * x86_64_reloc.def: Likewise. + 2009-04-16 Roland McGrath * arm_regs.c (arm_register_info): Handle VFP registers. diff --cc libdw/ChangeLog index a5c8548a0,525bb329b..40b1c61b5 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@@ -1,57 -1,37 +1,91 @@@ +2009-04-19 Roland McGrath + + * 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 + + * libdwP.h (IDX_eh_frame): Remove it. + * dwarf_begin_elf.c (dwarf_scnnames): Remove its element. + + 2009-05-05 Petr Machata + + * 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 + + * 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 + + * 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 + + * 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 * dwarf_getmacros.c (dwarf_getmacros): Use absolute section offset in diff --cc libdw/dwarf_frame_cfa.c index a491fa32b,000000000..331b934d8 mode 100644,000000..100644 --- a/libdw/dwarf_frame_cfa.c +++ b/libdw/dwarf_frame_cfa.c @@@ -1,100 -1,0 +1,101 @@@ +/* 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "cfi.h" +#include +#include + +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); ++ ops, &nops, ++ IDX_debug_frame); + return result ?: (int) nops; + } + + default: + abort (); + } + + /*NOTREACHED*/ + return -1; +} diff --cc libdw/dwarf_frame_register.c index dc414d0f8,000000000..61e6ee2fa mode 100644,000000..100644 --- a/libdw/dwarf_frame_register.c +++ b/libdw/dwarf_frame_register.c @@@ -1,143 -1,0 +1,144 @@@ +/* 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "cfi.h" +#include + +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) < 0) ++ &block, ops, nops, ++ IDX_debug_frame) < 0) + result = -1; + break; + } + } + + return result; +} diff --cc libdw/dwarf_getcfi_elf.c index ae6c1baa3,000000000..dc711eda9 mode 100644,000000..100644 --- a/libdw/dwarf_getcfi_elf.c +++ b/libdw/dwarf_getcfi_elf.c @@@ -1,331 -1,0 +1,331 @@@ +/* 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libdwP.h" +#include "cfi.h" +#include "encoded-value.h" +#include + + +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_getshstrndx (elf, &shstrndx) != 0) ++ 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) diff --cc libdw/dwarf_getlocation.c index c3233e293,f829e72b1..be8a33308 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@@ -1,5 -1,5 +1,5 @@@ /* 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 , 2000. @@@ -111,16 -111,15 +111,16 @@@ loc_compare (const void *p1, const voi 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. */ @@@ -154,24 -151,9 +154,9 @@@ { 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: @@@ -364,15 -327,6 +353,15 @@@ return 0; } +static int +getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, - Dwarf_Op **llbuf, size_t *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); ++ block, llbuf, listlen, sec_index); +} + int dwarf_getlocation (attr, llbuf, listlen) Dwarf_Attribute *attr; diff --cc libdw/libdwP.h index 4cccb56cf,97a2e042f..28c49e53a --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@@ -417,16 -414,6 +417,17 @@@ extern int __libdw_visit_scopes (unsign 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) ++ 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);