2010-06-22 Roland McGrath <roland@redhat.com>
+ * dwarf_ranges_relocatable.c: New file.
+ * dwarf_getlocation_relocatable.c: New file.
+ * dwarf_haspc_relocatable.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add them.
+ * libdw.map (ELFUTILS_0.149): Add them.
+ * libdw.h: Declare them.
+ * libdwP.h: Add INTDECLs.
+
+ * dwarf_getlocation.c (getlocation): Renamed to ...
+ (__libdw_getlocation): ... this; made global.
+ (dwarf_getlocation, dwarf_getlocation_addr): Update callers.
+ * libdwP.h: Declare it.
+
+ * relocate.h: New file.
+ * relocate.c: Move structs there.
+ (relocatable_datum): Renamed to ...
+ (__libdw_relocatable): ... here, made global.
* libdw.h (Dwarf_Relocatable): New type. Declare three new functions.
* dwarf_relocatable_info.c: New file.
* dwarf_form_relocatable.c: New file.
* dwarf_line_relocatable.c: New file.
* Makefile.am (libdw_a_SOURCES): Add them.
* libdw.map (ELFUTILS_0.149): New set; add those.
+ * libdwP.h: Add an INTDECL.
- * relocate.c (__libdw_relocatable): New function.
- * libdwP.h: Declare it.
+ * memory-access.h (read_8ubyte_unaligned_noncvt): New function/macro.
* dwarf_getlocation.c (check_constant_offset): data[48] are constant.
dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c \
dwarf_aggregate_size.c \
relocate.c dwarf_relocatable_info.c \
- dwarf_form_relocatable.c dwarf_line_relocatable.c
+ dwarf_form_relocatable.c dwarf_line_relocatable.c \
+ dwarf_ranges_relocatable.c dwarf_getlocation_relocatable.c \
+ dwarf_haspc_relocatable.c
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
return 0;
}
+INTDEF (dwarf_form_relocatable)
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_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
+ Dwarf_Op **llbuf, size_t *listlen, int sec_index)
{
+ struct Dwarf_CU *cu = attr->cu;
return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
cu->address_size, (cu->version == 2
? cu->address_size
if (INTUSE(dwarf_formblock) (attr, &block) != 0)
return -1;
- return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
+ return __libdw_getlocation (attr, &block, llbuf, listlen,
+ cu_sec_idx (attr->cu));
}
int
/* If it has a block form, it's a single location expression. */
Dwarf_Block block;
- if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+ if (attr->cu->version < 4 || attr->form == DW_FORM_exprloc)
{
- if (maxlocs == 0)
- return 0;
- if (llbufs != NULL &&
- getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
- cu_sec_idx (attr->cu)) != 0)
- return -1;
- return listlens[0] == 0 ? 0 : 1;
- }
+ if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+ {
+ if (maxlocs == 0)
+ return 0;
+ if (llbufs != NULL &&
+ __libdw_getlocation (attr, &block, &llbufs[0], &listlens[0],
+ cu_sec_idx (attr->cu)) != 0)
+ return -1;
+ return listlens[0] == 0 ? 0 : 1;
+ }
- int error = INTUSE(dwarf_errno) ();
- if (unlikely (error != DWARF_E_NO_BLOCK))
- {
- __libdw_seterrno (error);
- return -1;
+ int error = INTUSE(dwarf_errno) ();
+ if (unlikely (error != DWARF_E_NO_BLOCK))
+ {
+ __libdw_seterrno (error);
+ return -1;
+ }
}
int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
{
/* This one matches the address. */
if (llbufs != NULL
- && unlikely (getlocation (attr->cu, &block,
- &llbufs[got], &listlens[got],
- IDX_debug_loc) != 0))
+ && unlikely (__libdw_getlocation (attr, &block,
+ &llbufs[got], &listlens[got],
+ IDX_debug_loc) != 0))
return -1;
++got;
}
--- /dev/null
+/* Enumerate the PC ranges covered by a location list.
+ Copyright (C) 2010 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 "relocate.h"
+#include <dwarf.h>
+#include <assert.h>
+
+
+ptrdiff_t
+dwarf_getlocation_relocatable (Dwarf_Attribute *attr, ptrdiff_t offset,
+ Dwarf_Relocatable *basep,
+ Dwarf_Relocatable *startp,
+ Dwarf_Relocatable *endp,
+ Dwarf_Op **expr, size_t *exprlen)
+{
+ if (attr == NULL)
+ return -1;
+
+ unsigned int sec_idx = IDX_debug_loc;
+ Dwarf_Block block;
+ if (offset == 0)
+ switch (attr->form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (unlikely (attr->cu->version >= 4))
+ {
+ __libdw_seterrno (DWARF_E_NO_LOCLIST);
+ return -1;
+ }
+
+ case DW_FORM_exprloc:
+ if (unlikely (INTUSE(dwarf_formblock) (attr, &block) < 0))
+ return -1;
+
+ sec_idx = cu_sec_idx (attr->cu);
+ *startp = (Dwarf_Relocatable) { .adjust = 0 };
+ *endp = (Dwarf_Relocatable) { .adjust = (Dwarf_Addr) -1 };
+
+ /* A offset into .debug_loc will never be 1, it must be at least a
+ multiple of 4. So we can return 1 as a special case value to
+ mark there are no ranges to look for on the next call. */
+ offset = 1;
+ break;
+ }
+ else if (offset == 1)
+ return 0;
+
+ if (offset != 1)
+ /* Iterate from last position. */
+ offset = __libdw_ranges_relocatable (attr->cu, attr, offset,
+ basep, startp, endp, &block);
+
+ /* Parse the block into internal form. */
+ if (offset > 0 && expr != NULL
+ && __libdw_getlocation (attr, &block, expr, exprlen, sec_idx) < 0)
+ offset = -1;
+
+ return offset;
+}
--- /dev/null
+/* Determine whether a DIE covers a PC address.
+ Copyright (C) 2010 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 <dwarf.h>
+
+
+int
+dwarf_haspc_relocatable (Dwarf_Die *die, Dwarf_Relocatable *pc)
+{
+ if (die == NULL)
+ return -1;
+
+ GElf_Sym pc_sym;
+ GElf_Sxword pc_addend;
+ int pc_shndx = INTUSE(dwarf_relocatable_info) (pc, &pc_sym, NULL,
+ &pc_addend, NULL);
+ if (pc_shndx < 0)
+ return pc_shndx;
+ pc_sym.st_value += pc_addend;
+
+ Dwarf_Relocatable base;
+ Dwarf_Relocatable begin;
+ Dwarf_Relocatable end;
+ ptrdiff_t offset = 0;
+ while ((offset = INTUSE(dwarf_ranges_relocatable) (die, offset, &base,
+ &begin, &end)) > 0)
+ if (begin.valp == NULL && end.valp == NULL && pc->valp == NULL)
+ {
+ if (pc->adjust >= begin.adjust && pc->adjust < end.adjust)
+ return 1;
+ }
+ else
+ {
+ /* A relocatable address matches if it's in the same section
+ and the section-relative offsets match. */
+
+ GElf_Sym sym;
+ GElf_Sxword addend;
+ int shndx = INTUSE(dwarf_relocatable_info) (&begin, &sym, NULL,
+ &addend, NULL);
+ if (shndx < 0)
+ return -1;
+ if (shndx == pc_shndx && sym.st_shndx == pc_sym.st_shndx
+ && pc_sym.st_value >= sym.st_value + addend)
+ {
+ if (pc_sym.st_value == sym.st_value + addend)
+ return 1;
+ shndx = INTUSE(dwarf_relocatable_info) (&end, &sym, NULL,
+ &addend, NULL);
+ if (shndx < 0)
+ return -1;
+ if (shndx == pc_shndx && sym.st_shndx == pc_sym.st_shndx
+ && pc_sym.st_value < sym.st_value + addend)
+ return 1;
+ }
+ }
+
+ return offset;
+}
+INTDEF (dwarf_haspc_relocatable)
--- /dev/null
+/* Enumerate the PC ranges covered by a DIE.
+ Copyright (C) 2010 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 "relocate.h"
+#include <dwarf.h>
+#include <assert.h>
+
+ptrdiff_t
+internal_function
+__libdw_ranges_relocatable (struct Dwarf_CU *cu, Dwarf_Attribute *attr,
+ ptrdiff_t offset,
+ Dwarf_Relocatable *basep,
+ Dwarf_Relocatable *startp, Dwarf_Relocatable *endp,
+ Dwarf_Block *exprloc)
+{
+ if (offset == 1)
+ return 0;
+
+ const unsigned int sec_idx = (exprloc != NULL ? IDX_debug_loc
+ : IDX_debug_ranges);
+ unsigned char *readp;
+ unsigned char *readendp;
+ if (offset == 0)
+ {
+ Dwarf_Word start_offset;
+ if ((readp = __libdw_formptr (attr, sec_idx,
+ exprloc != NULL ? DWARF_E_NO_LOCLIST
+ : DWARF_E_NO_DEBUG_RANGES,
+ &readendp, &start_offset)) == NULL)
+ return -1;
+
+ offset = start_offset;
+ assert ((Dwarf_Word) offset == start_offset);
+
+ /* This is a marker that we need to fetch the CU base address. */
+ basep->cu = NULL;
+ }
+ else if (__libdw_offset_in_section (cu->dbg,
+ exprloc != NULL ? IDX_debug_loc
+ : IDX_debug_ranges,
+ offset, 1))
+ return -1l;
+ else
+ {
+ const Elf_Data *d = cu->dbg->sectiondata[sec_idx];
+ readp = d->d_buf + offset;
+ readendp = d->d_buf + d->d_size;
+ }
+
+ inline void store (Dwarf_Relocatable *relocp, ptrdiff_t read_adjust)
+ {
+ *relocp = (Dwarf_Relocatable)
+ {
+ .cu = cu, .sec = sec_idx, .form = DW_FORM_addr,
+ .valp = readp
+ };
+ readp += read_adjust;
+ }
+
+ inline bool finalize_reloc (Dwarf_Relocatable *reloc, unsigned int width)
+ {
+ if (basep->cu == NULL)
+ {
+ /* This is the initial default base address and we have not used it
+ yet. Find the base address of the compilation unit. It will
+ normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the
+ base address could be overridden by DW_AT_entry_pc. It's been
+ removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for
+ compilation units with discontinuous ranges. */
+
+ Dwarf_Die cudie = CUDIE (cu);
+ Dwarf_Attribute loattr;
+ if (unlikely (INTUSE(dwarf_form_relocatable)
+ (INTUSE(dwarf_attr) (&cudie, DW_AT_low_pc, &loattr)
+ ?: INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, &loattr),
+ basep) < 0))
+ return true;
+ }
+
+ GElf_Sxword addend;
+ if (__libdw_relocatable (cu->dbg, sec_idx, reloc->valp, width,
+ NULL, &addend) > 0)
+ {
+ /* The address itself has a relocation.
+ The base address entry must not also have a relocation. */
+
+ if (unlikely (__libdw_relocatable (cu->dbg, sec_idx, basep->valp, width,
+ NULL, &addend) > 0))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return true;
+ }
+ }
+ else
+ /* The address is relative to the base address relocation. */
+ reloc->valp = basep->valp;
+
+ reloc->adjust = addend;
+
+ return false;
+ }
+
+ inline ptrdiff_t finalize (unsigned int width)
+ {
+ if (finalize_reloc (startp, width) || finalize_reloc (endp, width))
+ return -1;
+ return readp - (unsigned char *) cu->dbg->sectiondata[sec_idx]->d_buf;
+ }
+
+#define READ_RANGES(AS, Addr, READ) \
+ while (likely (readendp - readp >= 2 * AS)) \
+ { \
+ Addr begin = READ (readp); \
+ \
+ if (begin == (Addr) -1) \
+ { \
+ /* If this is unrelocated, this is a base address entry. */ \
+ int result = __libdw_relocatable (cu->dbg, sec_idx, readp, AS, \
+ NULL, NULL); \
+ if (unlikely (result < 0)) /* Indigestion. */ \
+ return -1; \
+ if (result == 0) /* Not relocatable. */ \
+ { \
+ readp += AS; \
+ store (basep, AS); \
+ continue; \
+ } \
+ } \
+ else if (begin == 0 && READ (readp + AS) == 0) \
+ { \
+ /* If these are both unrelocated, this is the end of list entry. */\
+ int result = __libdw_relocatable (cu->dbg, sec_idx, readp, AS, \
+ NULL, NULL); \
+ if (result == 0) /* Not relocatable. */ \
+ result = __libdw_relocatable (cu->dbg, sec_idx, readp + AS, AS, \
+ NULL, NULL); \
+ if (unlikely (result < 0)) /* Indigestion. */ \
+ return -1; \
+ if (result == 0) /* Not relocatable: end of list entry. */ \
+ return 0; \
+ } \
+ \
+ /* This is a pair of addresses. */ \
+ store (startp, AS); \
+ store (endp, AS); \
+ \
+ if (exprloc != NULL) \
+ { \
+ if (unlikely (readendp - readp < 2)) \
+ break; \
+ exprloc->length = read_2ubyte_unaligned_inc (cu->dbg, readp); \
+ if (unlikely ((size_t) (readendp - readp) < exprloc->length)) \
+ break; \
+ exprloc->data = readp; \
+ } \
+ \
+ return finalize (AS); \
+ }
+
+ if (cu->address_size == 8)
+ READ_RANGES (8, Elf64_Addr, read_8ubyte_unaligned_noncvt)
+ else
+ READ_RANGES (4, Elf32_Addr, read_4ubyte_unaligned_noncvt)
+
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+}
+
+ptrdiff_t
+dwarf_ranges_relocatable (Dwarf_Die *die, ptrdiff_t offset,
+ Dwarf_Relocatable *basep,
+ Dwarf_Relocatable *startp, Dwarf_Relocatable *endp)
+{
+ if (die == NULL)
+ return -1;
+
+ if (offset != 0)
+ /* Iterate from last position. */
+ return __libdw_ranges_relocatable (die->cu, NULL, offset,
+ basep, startp, endp, NULL);
+
+ Dwarf_Attribute attr_mem;
+
+ /* Usually there is a single contiguous range. */
+ if (INTUSE(dwarf_form_relocatable) (INTUSE(dwarf_attr) (die,
+ DW_AT_high_pc,
+ &attr_mem),
+ endp) == 0
+ && INTUSE(dwarf_form_relocatable) (INTUSE(dwarf_attr) (die,
+ DW_AT_low_pc,
+ &attr_mem),
+ startp) == 0)
+ /* A offset into .debug_ranges will never be 1, it must be at least a
+ multiple of 4. So we can return 1 as a special case value to mark
+ there are no ranges to look for on the next call. */
+ return 1;
+
+ Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem);
+ if (attr == NULL)
+ /* No PC attributes in this DIE at all, so an empty range list. */
+ return 0;
+
+ return __libdw_ranges_relocatable (die->cu, attr, 0,
+ basep, startp, endp, NULL);
+}
+INTDEF (dwarf_ranges_relocatable)
# include <config.h>
#endif
-#include "libdwP.h"
+#include "relocate.h"
#include <dwarf.h>
+
static int
relocatable_form (struct Dwarf_CU *cu,
unsigned int sec_idx,
switch (form)
{
default:
- /* This can't be relocatable. We'll let __libdw_relocatable
- fill in the SHN_ABS indicator for the constant 0 base. */
+ /* This can't be relocatable. */
if (addend != NULL)
{
- Dwarf_Attribute attr =
+ if (valp == NULL)
+ *addend = 0;
+ else
{
- .cu = cu,
- .form = form,
- .valp = (unsigned char *) valp
- };
- if (INTUSE(dwarf_formsdata) (&attr, addend))
- return -1;
- *addend += adjust;
- addend = NULL;
+ Dwarf_Attribute attr =
+ {
+ .cu = cu,
+ .form = form,
+ .valp = (unsigned char *) valp
+ };
+ if (INTUSE(dwarf_formsdata) (&attr, addend))
+ return -1;
+ }
}
- width = 0;
- valp = NULL;
- break;
+ noreloc:
+ if (addend != NULL)
+ *addend += adjust;
+ if (sym != NULL)
+ *sym = (GElf_Sym) { .st_shndx = SHN_ABS };
+ if (name != NULL)
+ *name = NULL;
+ if (secname != NULL)
+ *secname = NULL;
+ return 0;
case DW_FORM_addr:
width = cu->address_size;
break;
}
- return __libdw_relocatable (cu->dbg, sec_idx, valp, width,
- sym, name, addend, adjust, secname);
+ int symndx;
+ int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
+ &symndx, addend);
+ if (result == 0)
+ goto noreloc;
+ else if (likely (result > 0))
+ {
+ struct dwarf_section_reloc *r = cu->dbg->relocate->sectionrel[sec_idx];
+ GElf_Sym sym_mem;
+ GElf_Word shndx;
+ if (sym == NULL)
+ sym = &sym_mem;
+
+ if (unlikely (gelf_getsymshndx (r->symdata, r->symxndxdata,
+ symndx, sym, &shndx) == NULL))
+ {
+ __libdw_seterrno (DWARF_E_RELBADSYM);
+ return -1;
+ }
+
+ if (name != NULL)
+ {
+ if (sym->st_name == 0)
+ *name = NULL;
+ else if (unlikely (sym->st_name >= r->symstrdata->d_size))
+ {
+ __libdw_seterrno (DWARF_E_RELBADSYM);
+ return -1;
+ }
+ else
+ *name = (const char *) r->symstrdata->d_buf + sym->st_name;
+ }
+
+ if (addend != NULL)
+ *addend += adjust;
+
+ result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx
+ : sym->st_shndx == SHN_XINDEX ? shndx : SHN_UNDEF);
+
+ if (secname != NULL)
+ {
+ Elf *symelf = ((Elf_Data_Scn *) r->symdata)->s->elf;
+ size_t shstrndx;
+ GElf_Shdr shdr;
+ if (result == 0
+ || elf_getshdrstrndx (symelf, &shstrndx) < 0
+ || gelf_getshdr (elf_getscn (symelf, result), &shdr) == NULL)
+ *secname = NULL;
+ else
+ *secname = elf_strptr (symelf, shstrndx, shdr.sh_name);
+ }
+ }
+
+ return result;
}
+
int
dwarf_relocatable_info (reloc, sym, name, addend, secname)
Dwarf_Relocatable *reloc;
reloc->form, reloc->valp, reloc->adjust,
sym, name, addend, secname);
}
+INTDEF (dwarf_relocatable_info)
#if 0
/* Shorthand for dwarf_relocatable_info(dwarf_form_relocatable). */
0 if not, or -1 for errors. */
extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);
+/* Like dwarf_haspc, but for a relocatable address. */
+extern int dwarf_haspc_relocatable (Dwarf_Die *die, Dwarf_Relocatable *pc);
+
/* Enumerate the PC address ranges covered by this DIE, covering all
addresses where dwarf_haspc returns true. In the first call OFFSET
should be zero and *BASEP need not be initialized. Returns -1 for
*STARTP and *ENDP with a contiguous address range. */
extern ptrdiff_t dwarf_ranges (Dwarf_Die *die,
ptrdiff_t offset, Dwarf_Addr *basep,
- Dwarf_Addr *startp, Dwarf_Addr *endp);
+ Dwarf_Addr *startp, Dwarf_Addr *endp)
+ __nonnull_attribute__ (3, 4, 5);
+
+/* Like dwarf_ranges, but with relocatable addresses. */
+extern ptrdiff_t dwarf_ranges_relocatable (Dwarf_Die *die,
+ ptrdiff_t offset,
+ Dwarf_Relocatable *basep,
+ Dwarf_Relocatable *startp,
+ Dwarf_Relocatable *endp)
+ __nonnull_attribute__ (3, 4, 5);
/* Return byte size attribute of DIE. */
Dwarf_Op **exprs, size_t *exprlens,
size_t nlocs);
+/* Enumerate the locations in a location list.
+ The interface is as for dwarf_ranges_relocatable, above,
+ but also fills in *EXPR and *EXPRLEN as for dwarf_getlocation. */
+extern ptrdiff_t dwarf_getlocation_relocatable (Dwarf_Attribute *attr,
+ ptrdiff_t offset,
+ Dwarf_Relocatable *basep,
+ Dwarf_Relocatable *startp,
+ Dwarf_Relocatable *endp,
+ Dwarf_Op **expr,
+ size_t *exprlen)
+ __nonnull_attribute__ (3, 4, 5, 6, 7);
+
+
/* Return the block associated with a DW_OP_implicit_value operation.
The OP pointer must point into an expression that dwarf_getlocation
or dwarf_getlocation_addr has returned given the same ATTR. */
global:
dwarf_form_relocatable;
dwarf_line_relocatable;
+ dwarf_getlocation_relocatable;
+ dwarf_haspc_relocatable;
+ dwarf_ranges_relocatable;
dwarf_relocatable_info;
} ELFUTILS_0.148;
int sec_index)
__nonnull_attribute__ (5, 6, 9, 10) internal_function;
+extern int __libdw_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
+ Dwarf_Op **llbuf, size_t *listlen, int sec_idx)
+ __nonnull_attribute__ (2, 3, 4) internal_function;
+
/* Return error code of last failing function call. This value is kept
separately for each thread. */
ret, sec_ret, size);
}
-extern int __libdw_relocatable (Dwarf *dbg, int sec_idx,
- const unsigned char *valp, unsigned int width,
- GElf_Sym *sym, const char **name,
- GElf_Sxword *addend, GElf_Sxword offset,
- const char **secname)
- __nonnull_attribute__ (1) internal_function;
-
static inline size_t
cu_sec_idx (struct Dwarf_CU *cu)
INTDECL (dwarf_formsdata)
INTDECL (dwarf_formstring)
INTDECL (dwarf_formudata)
+INTDECL (dwarf_form_relocatable)
INTDECL (dwarf_getarange_addr)
INTDECL (dwarf_getarangeinfo)
INTDECL (dwarf_getaranges)
INTDECL (dwarf_next_unit)
INTDECL (dwarf_offdie)
INTDECL (dwarf_ranges)
+INTDECL (dwarf_ranges_relocatable)
+INTDECL (dwarf_relocatable_info)
INTDECL (dwarf_siblingof)
INTDECL (dwarf_srclang)
INTDECL (dwarf_tag)
? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
: *((const int32_t *) (Addr)))
+# define read_8ubyte_unaligned_noncvt(Addr) \
+ *((const uint64_t *) (Addr))
# define read_8ubyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? bswap_64 (*((const uint64_t *) (Addr))) \
return up->s4;
}
+static inline uint64_t
+read_8ubyte_unaligned_noncvt (const void *p)
+{
+ const union unaligned *up = p;
+ return up->u8;
+}
static inline uint64_t
read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
{
# include <config.h>
#endif
-#include "libdwP.h"
-#include "../libelf/libelfP.h"
+#include "relocate.h"
#include "../libebl/libebl.h"
#include <dwarf.h>
#include <assert.h>
#include <stdlib.h>
-struct dwarf_reloc_table
-{
- size_t n; /* Number of elements in this table. */
- const unsigned char **datum; /* Sorted pointers into section data. */
- int *symndx; /* Corresponding symtab indices. */
- size_t hint; /* Index of last search. */
-};
-
-struct dwarf_section_reloc
-{
- /* This is set only in the laziest state from startup: the reloc
- section needs to be examined, and the rest is uninitialized.
- When this is cleared, the rest is initialized and safe to use. */
- Elf_Scn *scn;
-
- Elf_Data *symdata;
- Elf_Data *symstrdata;
- Elf_Data *symxndxdata;
-
- /* Two tables of predigested relocations, segregated by size. */
- struct dwarf_reloc_table rel4;
- struct dwarf_reloc_table rel8;
-
- /* For SHT_RELA, a parallel table of addends.
- For SHT_REL, these are null. */
- Elf32_Sword *rela4;
- Elf64_Sxword *rela8;
-};
-
static int
internal_function
noresolve_symbol (bool undef,
return -1;
}
-static int
-relocatable_datum (Dwarf *dbg, int sec_index, struct dwarf_section_reloc *r,
- const unsigned char *datum, int width,
- int *symndx, GElf_Sxword *addend)
+int
+internal_function
+__libdw_relocatable (Dwarf *dbg, int sec_index,
+ const unsigned char *datum, int width,
+ int *symndx, GElf_Sxword *addend)
{
+ if (dbg->relocate == NULL)
+ {
+ noreloc:
+ if (addend != NULL)
+ *addend = (width == 8
+ ? read_8ubyte_unaligned (dbg, datum)
+ : read_4ubyte_unaligned (dbg, datum));
+ return 0;
+ }
+
+ struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_index];
if (r == NULL)
- return 0;
+ goto noreloc;
if (r->scn != NULL)
{
if (width == 4)
{
i = find_reloc (&r->rel4, datum);
- *symndx = i < 0 ? STN_UNDEF : r->rel4.symndx[i];
+ if (symndx != NULL)
+ *symndx = i < 0 ? STN_UNDEF : r->rel4.symndx[i];
if (addend != NULL)
*addend = ((i < 0 || r->rela4 == NULL)
? read_4sbyte_unaligned (dbg, datum) : r->rela4[i]);
assert (width == 8);
i = find_reloc (&r->rel8, datum);
- *symndx = i < 0 ? STN_UNDEF : r->rel8.symndx[i];
+ if (symndx != NULL)
+ *symndx = i < 0 ? STN_UNDEF : r->rel8.symndx[i];
if (addend != NULL)
*addend = ((i < 0 || r->rela8 == NULL)
? read_8sbyte_unaligned (dbg, datum) : r->rela8[i]);
__libdw_relocate_address (Dwarf *dbg, int sec_index,
const void *datum, int width, Dwarf_Addr *val)
{
- struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_index];
int symndx;
GElf_Sxword addend;
- int result = relocatable_datum (dbg, sec_index, r, datum, width,
- &symndx, &addend);
+ int result = __libdw_relocatable (dbg, sec_index, datum, width,
+ &symndx, &addend);
if (result > 0 && symndx != STN_UNDEF)
{
GElf_Sym sym;
GElf_Word shndx;
- result = reloc_getsym (r, symndx, &sym, &shndx);
+ result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
+ symndx, &sym, &shndx);
if (result > 0)
{
result = (*dbg->relocate->resolve_symbol)
__libdw_relocate_offset (Dwarf *dbg, int sec_index,
const void *datum, int width, Dwarf_Off *val)
{
- struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_index];
int symndx;
GElf_Sxword addend;
- int result = relocatable_datum (dbg, sec_index, r, datum, width,
- &symndx, &addend);
+ int result = __libdw_relocatable (dbg, sec_index, datum, width,
+ &symndx, &addend);
if (result > 0 && symndx != STN_UNDEF)
{
GElf_Sym sym;
GElf_Word shndx;
- result = reloc_getsym (r, symndx, &sym, &shndx);
+ result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
+ symndx, &sym, &shndx);
if (result > 0)
{
if (unlikely (sym.st_shndx == SHN_UNDEF)
*val = addend;
return result;
}
-\f
-int
-internal_function
-__libdw_relocatable (Dwarf *dbg, int sec_idx,
- const unsigned char *valp, unsigned int width,
- GElf_Sym *sym, const char **name, GElf_Sxword *addend,
- GElf_Sxword offset, const char **secname)
-{
- struct dwarf_section_reloc *const r = ((valp != NULL && dbg->relocate != NULL)
- ? dbg->relocate->sectionrel[sec_idx]
- : NULL);
- int symndx;
- int result = relocatable_datum (dbg, sec_idx, r, valp, width,
- &symndx, addend);
- if (result == 0)
- {
- if (sym != NULL)
- *sym = (GElf_Sym) { .st_shndx = SHN_ABS };
- if (name != NULL)
- *name = NULL;
- if (addend != NULL)
- *addend = offset + (width == 8
- ? read_8ubyte_unaligned (dbg, valp)
- : read_4ubyte_unaligned (dbg, valp));
- if (secname != NULL)
- *secname = NULL;
- }
- else if (likely (result > 0))
- {
- GElf_Sym sym_mem;
- GElf_Word shndx;
- if (sym == NULL)
- sym = &sym_mem;
- result = reloc_getsym (r, symndx, sym, &shndx);
- if (likely (result > 0))
- {
- if (name != NULL)
- {
- if (sym->st_name == 0)
- *name = NULL;
- else if (unlikely (sym->st_name >= r->symstrdata->d_size))
- {
- __libdw_seterrno (DWARF_E_RELBADSYM);
- return -1;
- }
- else
- *name = (const char *) r->symstrdata->d_buf + sym->st_name;
- }
- if (addend != NULL)
- *addend += offset;
- result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx
- : sym->st_shndx == SHN_XINDEX ? shndx : SHN_UNDEF);
- if (secname != NULL)
- {
- Elf *symelf = ((Elf_Data_Scn *) r->symdata)->s->elf;
- size_t shstrndx;
- GElf_Shdr shdr;
- if (result == 0
- || elf_getshdrstrndx (symelf, &shstrndx) < 0
- || gelf_getshdr (elf_getscn (symelf, result), &shdr) == NULL)
- *secname = NULL;
- else
- *secname = elf_strptr (symelf, shstrndx, shdr.sh_name);
- }
- }
- }
-
- return result;
-}
--- /dev/null
+/* Internal definitions for libdw relocation handling.
+ Copyright (C) 2010 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 "libdwP.h"
+#include "libelfP.h"
+
+
+struct dwarf_reloc_table
+{
+ size_t n; /* Number of elements in this table. */
+ const unsigned char **datum; /* Sorted pointers into section data. */
+ int *symndx; /* Corresponding symtab indices. */
+ size_t hint; /* Index of last search. */
+};
+
+struct dwarf_section_reloc
+{
+ /* This is set only in the laziest state from startup: the reloc
+ section needs to be examined, and the rest is uninitialized.
+ When this is cleared, the rest is initialized and safe to use. */
+ Elf_Scn *scn;
+
+ Elf_Data *symdata;
+ Elf_Data *symstrdata;
+ Elf_Data *symxndxdata;
+
+ /* Two tables of predigested relocations, segregated by size. */
+ struct dwarf_reloc_table rel4;
+ struct dwarf_reloc_table rel8;
+
+ /* For SHT_RELA, a parallel table of addends.
+ For SHT_REL, these are null. */
+ Elf32_Sword *rela4;
+ Elf64_Sxword *rela8;
+};
+
+
+extern int __libdw_relocatable (Dwarf *dbg, int sec_index,
+ const unsigned char *datum, int width,
+ int *symndx, GElf_Sxword *addend)
+ __nonnull_attribute__ (1) internal_function;
+
+extern ptrdiff_t __libdw_ranges_relocatable (struct Dwarf_CU *cu,
+ Dwarf_Attribute *attr,
+ ptrdiff_t offset,
+ Dwarf_Relocatable *basep,
+ Dwarf_Relocatable *startp,
+ Dwarf_Relocatable *endp,
+ Dwarf_Block *exprloc)
+ __nonnull_attribute__ (1, 4, 5, 6) internal_function;