+2010-06-21 Roland McGrath <roland@redhat.com>
+
+ * libdwP.h (struct Dwarf_Line_s): Replace files with cu.
+ (struct Dwarf_Lines_s): New member reloc.
+ * dwarf_linesrc.c: Update usage.
+ * dwarf_getsrc_file.c: Likewise.
+ * dwarf_getsrclines.c: Record relocatable address locations in
+ parallel array, with Dwarf_Line.addr becoming a relative offset.
+ * dwarf_lineaddr.c: Use __libdw_read_address on demand for a
+ relocatable line address.
+
2010-06-20 Roland McGrath <roland@redhat.com>
+ * relocate.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdwP.h (struct dwarf_file_reloc): New type.
+ (struct Dwarf): New member relocate.
+ (__libdw_relocate_address, __libdw_relocate_offset): Replace inlines
+ with extern decls.
+ (READ_AND_RELOCATE): Call RELOC_HOOK if DBG->relocate,
+ else read directly.
+ (__libdw_read_address, __libdw_read_offset): Just call *_inc variant.
+ (__libdw_relocate_begin, __libdw_relocate_end): Declare them.
+ * dwarf_begin_elf.c (check_section): Take new args to track reloc
+ sections.
+ (global_read, scngrp_read): Pass new args through to check_section.
+ (dwarf_begin_elf): Track reloc sections in an ET_REL file,
+ call __libdw_relocate_begin.
+
+ * libdwP.h (DWARF_E_RELOC, DWARF_E_RELBADTYPE): New enum constants.
+ (DWARF_E_RELBADADDEND, DWARF_E_RELBADOFF): Likewise.
+ (DWARF_E_RELBADSYM, DWARF_E_RELUNDEF, DWARF_E_RELWRONGSEC): Likewise.
+ * dwarf_error.c (errmsgs): Add them.
+
* cfi.h (BYTE_ORDER_DUMMY): Macro moved ...
* memory-access.h: ... here.
to search TUs instead of CUs.
* libdwP.h: Update decl.
(struct Dwarf): New member tu_tree.
+
* dwarf_end.c (dwarf_end): Clean up tu_tree.
* dwarf_offdie.c (do_offdie): New function, broken out of ...
(dwarf_offdie): ... here.
dwarf_frame_info.c dwarf_frame_cfa.c dwarf_frame_register.c \
dwarf_cfi_addrframe.c \
dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c \
- dwarf_aggregate_size.c
+ dwarf_aggregate_size.c \
+ relocate.c
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
# include <config.h>
#endif
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
static Dwarf *
-check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
+check_section (Dwarf *result, GElf_Ehdr *ehdr,
+ uint8_t scn_debug[], size_t shnum, Elf_Scn *relscn[IDX_last],
+ Elf_Scn *scn, bool inscngrp)
{
GElf_Shdr shdr_mem;
GElf_Shdr *shdr;
}
+ /* This might be a relocation section. */
+ if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+ {
+ if (scn_debug != NULL
+ && likely (shdr->sh_info != 0)
+ && likely (shdr->sh_info < shnum))
+ {
+ if (scn_debug[shdr->sh_info] < IDX_last)
+ {
+ /* This section has relocations for a debug section
+ we have already noticed. */
+ relscn[scn_debug[shdr->sh_info]] = scn;
+ if (scn_debug[0] != IDX_debug_info)
+ scn_debug[0] = IDX_debug_abbrev;
+ }
+ else if (unlikely (shdr->sh_info > elf_ndxscn (scn)))
+ {
+ /* A relocation section usually follows its target section.
+ But there is no guarantee. */
+ GElf_Shdr tshdr_mem;
+ GElf_Shdr *tshdr = gelf_getshdr (elf_getscn (result->elf,
+ shdr->sh_info),
+ &tshdr_mem);
+ if (likely (tshdr != NULL))
+ /* Mark that we need a second pass. */
+ scn_debug[0] = IDX_debug_info;
+ }
+ }
+ return result;
+ }
+
+
/* Recognize the various sections. Most names start with .debug_. */
- size_t cnt;
- for (cnt = 0; cnt < ndwarf_scnnames; ++cnt)
+ for (uint_fast8_t cnt = 0; cnt < ndwarf_scnnames; ++cnt)
if (strcmp (scnname, dwarf_scnnames[cnt]) == 0)
{
/* Found it. Remember where the data is. */
/* Get the section data. */
Elf_Data *data = elf_getdata (scn, NULL);
if (data != NULL && data->d_size != 0)
- /* Yep, there is actually data available. */
- result->sectiondata[cnt] = data;
+ {
+ /* Yep, there is actually data available. */
+ result->sectiondata[cnt] = data;
+ if (scn_debug != NULL)
+ scn_debug[elf_ndxscn (scn)] = cnt;
+ }
break;
}
static Dwarf *
-global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr)
+global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr,
+ uint8_t scn_debug[], size_t shnum, Elf_Scn *relscn[IDX_last])
{
Elf_Scn *scn = NULL;
while (result != NULL && (scn = elf_nextscn (elf, scn)) != NULL)
- result = check_section (result, ehdr, scn, false);
+ result = check_section (result, ehdr, scn_debug, shnum, relscn, scn, false);
return valid_p (result);
}
static Dwarf *
-scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp)
+scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr,
+ uint8_t scn_debug[], size_t shnum, Elf_Scn *relscn[IDX_last],
+ Elf_Scn *scngrp)
{
/* SCNGRP is the section descriptor for a section group which might
contain debug sections. */
return NULL;
}
- result = check_section (result, ehdr, scn, true);
+ result = check_section (result, ehdr, scn_debug, shnum, relscn,
+ scn, true);
if (result == NULL)
break;
}
if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR)
{
- /* If the caller provides a section group we get the DWARF
- sections only from this setion group. Otherwise we search
- for the first section with the required name. Further
- sections with the name are ignored. The DWARF specification
- does not really say this is allowed. */
- if (scngrp == NULL)
- return global_read (result, elf, ehdr);
+ inline void read_it (uint8_t scn_debug[], size_t shnum,
+ Elf_Scn *relscn[IDX_last])
+ {
+ /* If the caller provides a section group we get the DWARF
+ sections only from this setion group. Otherwise we search
+ for the first section with the required name. Further
+ sections with the name are ignored. The DWARF specification
+ does not really say this is allowed. */
+ if (scngrp == NULL)
+ result = global_read (result, elf, ehdr, scn_debug, shnum, relscn);
+ else
+ result = scngrp_read (result, elf, ehdr, scn_debug, shnum, relscn,
+ scngrp);
+ }
+
+ if (ehdr->e_type == ET_REL)
+ {
+ Elf_Scn *relscn[IDX_last] = {};
+ size_t shnum;
+ int ret = elf_getshdrnum (elf, &shnum);
+ assert (ret == 0);
+ uint8_t scn_debug[shnum];
+ memset (scn_debug, IDX_last, shnum);
+ read_it (scn_debug, shnum, relscn);
+ if (result != NULL && scn_debug[0] != IDX_last)
+ /* We saw some relocation sections. */
+ __libdw_relocate_begin (result, relscn,
+ scn_debug[0] == IDX_debug_info);
+ }
else
- return scngrp_read (result, elf, ehdr, scngrp);
+ read_it (NULL, 0, NULL);
+ return result;
}
else if (cmd == DWARF_C_WRITE)
{
tdestroy (dwarf->cu_tree, cu_free);
tdestroy (dwarf->tu_tree, cu_free);
+ if (dwarf->relocate != NULL)
+ /* Clean up relocation tracking. */
+ __libdw_relocate_end (dwarf);
+
struct libdw_memblock *memp = dwarf->mem_tail;
/* The first block is allocated together with the Dwarf object. */
while (memp->prev != NULL)
/* Retrieve ELF descriptor used for DWARF access.
- Copyright (C) 2002, 2003, 2004, 2005, 2009 Red Hat, Inc.
+ Copyright (C) 2002-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
[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"),
+ [DWARF_E_RELOC] = N_("value requires relocation"),
+ [DWARF_E_RELBADTYPE] = N_("unsupported relocation type"),
+ [DWARF_E_RELBADADDEND] = N_("relocation addend overflow"),
+ [DWARF_E_RELBADOFF] = N_("relocation at invalid offset"),
+ [DWARF_E_RELBADSYM] = N_("relocation refers to invalid symbol"),
+ [DWARF_E_RELUNDEF] = N_("relocation refers to undefined symbol"),
+ [DWARF_E_RELWRONGSEC] = N_("relocation refers to wrong DWARF section"),
};
#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
/* Find line information for given file/line/column triple.
- Copyright (C) 2005-2009 Red Hat, Inc.
+ Copyright (C) 2005-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2005.
if (lastfile != line->file)
{
lastfile = line->file;
- if (lastfile >= line->files->nfiles)
+ if (lastfile >= line->cu->files->nfiles)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
/* Match the name with the name the user provided. */
- const char *fname2 = line->files->info[lastfile].name;
+ const char *fname2 = line->cu->files->info[lastfile].name;
if (is_basename)
lastmatch = strcmp (basename (fname2), fname) == 0;
else
/* Determine whether this is the best match so far. */
size_t inner;
for (inner = 0; inner < cur_match; ++inner)
- if (match[inner]->files == line->files
+ if (match[inner]->cu->files == line->cu->files
&& match[inner]->file == line->file)
break;
if (inner < cur_match
struct linelist
{
Dwarf_Line line;
+ const unsigned char *reloc;
struct linelist *next;
};
/* We are about to process the statement program. Initialize the
state machine registers (see 6.2.2 in the v2.1 specification). */
+ const unsigned char *addr_reloc = NULL;
Dwarf_Word addr = 0;
unsigned int op_index = 0;
unsigned int file = 1;
#undef SET
+ new_line->reloc = addr_reloc;
new_line->next = linelist;
linelist = new_line;
++nlinelist;
/* Reset the registers. */
addr = 0;
+ addr_reloc = NULL;
op_index = 0;
file = 1;
line = 1;
op_index = 0;
if (unlikely (lineendp - linep < cu->address_size))
goto invalid_data;
- if (__libdw_read_address_inc (dbg, IDX_debug_line, &linep,
- cu->address_size, &addr))
+ if (dbg->relocate != NULL
+ && dbg->relocate->sectionrel[IDX_debug_line] != NULL)
+ {
+ /* We're just recording a relocatable address
+ and offsets from it. We'll do the relocation
+ only lazily in dwarf_lineaddr. */
+ addr = 0;
+ addr_reloc = linep;
+ linep += cu->address_size;
+ }
+ else if (__libdw_read_address_inc (dbg, IDX_debug_line,
+ &linep, cu->address_size,
+ &addr))
goto out;
break;
We'll write the pointers in the end of the buffer, and then
copy into the buffer from the beginning so the overlap works. */
assert (sizeof (Dwarf_Line) >= sizeof (Dwarf_Line *));
- Dwarf_Line **sortlines = (buf + sizeof (Dwarf_Lines)
- + ((sizeof (Dwarf_Line)
- - sizeof (Dwarf_Line *)) * nlinelist));
+ struct linelist **sortlines = (buf + sizeof (Dwarf_Lines)
+ + ((sizeof (Dwarf_Line)
+ - sizeof (Dwarf_Line *)) * nlinelist));
/* The list is in LIFO order and usually they come in clumps with
ascending addresses. So fill from the back to probably start with
unsigned int i = nlinelist;
while (i-- > 0)
{
- sortlines[i] = &linelist->line;
+ sortlines[i] = linelist;
linelist = linelist->next;
}
assert (linelist == NULL);
of SORTLINES by the time we're reading the later ones. */
cu->lines = buf;
cu->lines->nlines = nlinelist;
+
+ if (cu->dbg->relocate != NULL
+ && cu->dbg->relocate->sectionrel[IDX_debug_line] != NULL)
+ {
+ /* Add a parallel table of relocation pointers. */
+ cu->lines->reloc = libdw_alloc (cu->dbg, const unsigned char *,
+ sizeof (const unsigned char *),
+ nlinelist);
+ for (i = 0; i < nlinelist; ++i)
+ cu->lines->reloc[i] = sortlines[i]->reloc;
+ }
+ else
+ cu->lines->reloc = NULL;
+
for (i = 0; i < nlinelist; ++i)
{
- cu->lines->info[i] = *sortlines[i];
- cu->lines->info[i].files = files;
+ cu->lines->info[i] = sortlines[i]->line;
+ cu->lines->info[i].cu = cu;
}
/* Success. */
/* Return line address.
- Copyright (C) 2004 Red Hat, Inc.
+ Copyright (C) 2004-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2004.
if (line == NULL)
return -1;
- *addrp = line->addr;
+ if (line->cu->lines->reloc == NULL
+ || line->cu->lines->reloc[line - line->cu->lines->info] == NULL)
+ {
+ *addrp = line->addr;
+ return 0;
+ }
- return 0;
+ /* We have to relocate an address and then adjust it for this line record. */
+
+ int result = __libdw_read_address
+ (line->cu->dbg, IDX_debug_line,
+ line->cu->lines->reloc[line - line->cu->lines->info],
+ line->cu->address_size, addrp);
+
+ if (result >= 0)
+ *addrp += line->addr;
+
+ return result;
}
/* Find line information for address.
- Copyright (C) 2004 Red Hat, Inc.
+ Copyright (C) 2004-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2004.
if (line == NULL)
return NULL;
- if (line->file >= line->files->nfiles)
+ if (line->file >= line->cu->files->nfiles)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
}
if (mtime != NULL)
- *mtime = line->files->info[line->file].mtime;
+ *mtime = line->cu->files->info[line->file].mtime;
if (length != NULL)
- *length = line->files->info[line->file].length;
+ *length = line->cu->files->info[line->file].length;
- return line->files->info[line->file].name;
+ return line->cu->files->info[line->file].name;
}
DWARF_E_INVALID_OFFSET,
DWARF_E_NO_DEBUG_RANGES,
DWARF_E_INVALID_CFI,
+ DWARF_E_RELOC,
+ DWARF_E_RELBADTYPE,
+ DWARF_E_RELBADADDEND,
+ DWARF_E_RELBADOFF,
+ DWARF_E_RELBADSYM,
+ DWARF_E_RELUNDEF,
+ DWARF_E_RELWRONGSEC,
};
/* The section data. */
Elf_Data *sectiondata[IDX_last];
+ /* Information for relocating an ET_REL file, or null. */
+ struct dwarf_file_reloc *relocate;
+
/* True if the file has a byte order different from the host. */
bool other_byte_order;
};
+/* Hook for relocation information (handled in relocate.c). */
+struct dwarf_file_reloc
+{
+ struct dwarf_section_reloc *sectionrel[IDX_last];
+
+ struct ebl *ebl;
+
+ int (*resolve_symbol) (bool undef, Dwarf *dbg,
+ GElf_Sym *sym, GElf_Word shndx)
+ internal_function;
+};
+
+
/* Abbreviation representation. */
struct Dwarf_Abbrev
{
struct Dwarf_Line_s
{
- Dwarf_Files *files;
+ struct Dwarf_CU *cu;
Dwarf_Addr addr;
unsigned int file;
struct Dwarf_Lines_s
{
+ const unsigned char **reloc;
size_t nlines;
struct Dwarf_Line_s info[0];
};
/* Reader hooks. */
+extern void __libdw_relocate_begin (Dwarf *dbg, Elf_Scn *relscn[IDX_last],
+ bool incomplete)
+ __nonnull_attribute__ (1, 2) internal_function;
+
+extern void __libdw_relocate_end (Dwarf *dbg)
+ __nonnull_attribute__ (1) internal_function;
+
+
/* Relocation hooks return -1 on error (in that case the error code
must already have been set), 0 if there is no relocation and 1 if a
- relocation was present.*/
+ relocation was present. */
-static inline int
-__libdw_relocate_address (Dwarf *dbg __attribute__ ((unused)),
- int sec_index __attribute__ ((unused)),
- const void *addr __attribute__ ((unused)),
- int width __attribute__ ((unused)),
- Dwarf_Addr *val __attribute__ ((unused)))
-{
- return 0;
-}
+extern int __libdw_relocate_address (Dwarf *dbg, int sec_index,
+ const void *addr, int width,
+ Dwarf_Addr *val)
+ __nonnull_attribute__ (1, 3, 5) internal_function;
-static inline int
-__libdw_relocate_offset (Dwarf *dbg __attribute__ ((unused)),
- int sec_index __attribute__ ((unused)),
- const void *addr __attribute__ ((unused)),
- int width __attribute__ ((unused)),
- Dwarf_Off *val __attribute__ ((unused)))
-{
- return 0;
-}
+extern int __libdw_relocate_offset (Dwarf *dbg, int sec_index,
+ const void *addr, int width,
+ Dwarf_Off *val)
+ __nonnull_attribute__ (1, 3, 5) internal_function;
static inline Elf_Data *
__libdw_checked_get_data (Dwarf *dbg, int sec_index)
if (!__libdw_in_section (dbg, sec_index, addr, width)) \
return -1; \
\
- const unsigned char *orig_addr = addr; \
- if (width == 4) \
+ int status = 0; \
+ if (dbg->relocate != NULL) \
+ { \
+ status = RELOC_HOOK (dbg, sec_index, addr, width, &VAL); \
+ if (status < 0) \
+ return status; \
+ addr += width; \
+ } \
+ else if (width == 4) \
VAL = read_4ubyte_unaligned_inc (dbg, addr); \
else \
VAL = read_8ubyte_unaligned_inc (dbg, addr); \
\
- int status = RELOC_HOOK (dbg, sec_index, orig_addr, width, &VAL); \
- if (status < 0) \
- return status; \
status > 0; \
})
int sec_index, const unsigned char *addr,
int width, Dwarf_Addr *ret)
{
- READ_AND_RELOCATE (__libdw_relocate_address, (*ret));
- return 0;
+ return __libdw_read_address_inc (dbg, sec_index, &addr, width, ret);
}
static inline int
int width, Dwarf_Off *ret, int sec_ret,
size_t size)
{
- READ_AND_RELOCATE (__libdw_relocate_offset, (*ret));
- return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
+ return __libdw_read_offset_inc (dbg, sec_index, &addr, width,
+ ret, sec_ret, size);
}
static inline size_t
--- /dev/null
+/* Relocation handling for DWARF reader.
+ 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 "../libelf/libelfP.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,
+ Dwarf *dbg __attribute__ ((unused)),
+ GElf_Sym *sym __attribute__ ((unused)),
+ GElf_Word shndx __attribute__ ((unused)))
+{
+ __libdw_seterrno (undef ? DWARF_E_RELUNDEF : DWARF_E_RELOC);
+ return -1;
+}
+
+void
+internal_function
+__libdw_relocate_begin (Dwarf *dbg, Elf_Scn *relscn[IDX_last], bool incomplete)
+{
+ if (incomplete)
+ {
+ /* We may need a second pass to identify some relocation sections. */
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (dbg->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr;
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ assert (shdr == &shdr_mem);
+ if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+ for (size_t i = 0; i < IDX_last; ++i)
+ if (relscn[i] == NULL && dbg->sectiondata[i] != NULL
+ && (((Elf_Data_Scn * ) dbg->sectiondata[i])->s->index
+ == shdr->sh_link))
+ relscn[i] = scn;
+ }
+ }
+
+ dbg->relocate = libdw_typed_alloc (dbg, struct dwarf_file_reloc);
+ dbg->relocate->ebl = NULL;
+ dbg->relocate->resolve_symbol = &noresolve_symbol;
+
+ /* All we do to start with is cache the section pointers.
+ We'll do the rest on demand in digest_relocs, below. */
+ for (size_t i = 0; i < IDX_last; ++i)
+ if (relscn[i] == NULL)
+ dbg->relocate->sectionrel[i] = NULL;
+ else
+ (dbg->relocate->sectionrel[i]
+ = libdw_typed_alloc (dbg, struct dwarf_section_reloc))->scn = relscn[i];
+}
+
+void
+internal_function
+__libdw_relocate_end (Dwarf *dbg)
+{
+ // XXX let dwfl preinstall, don't close here
+ ebl_closebackend (dbg->relocate->ebl);
+}
+\f
+struct digested_reloc
+{
+ GElf_Sxword addend;
+ const unsigned char *datum;
+ int symndx;
+ bool rel8;
+};
+
+static bool
+match_r_type (const int *types, int r_type)
+{
+ for (const int *t = types; *t != 0; ++t)
+ if (r_type == *t)
+ return true;
+ return false;
+}
+
+static inline int
+digest_one_reloc (const int *rel8_types, const int *rel4_types,
+ struct dwarf_section_reloc *r, Elf_Data *data,
+ struct digested_reloc **digest,
+ GElf_Addr r_offset, GElf_Xword r_info, GElf_Sxword r_addend)
+{
+ const int r_type = GELF_R_TYPE (r_info);
+ int symndx = GELF_R_SYM (r_info);
+
+ size_t *nrel = &r->rel8.n;
+ if (match_r_type (rel8_types, r_type))
+ (*digest)->rel8 = true;
+ else if (unlikely (!match_r_type (rel4_types, r_type)))
+ return DWARF_E_RELBADTYPE;
+ else if (unlikely ((GElf_Sxword) (GElf_Sword) r_addend != r_addend))
+ return DWARF_E_RELBADADDEND;
+ else
+ {
+ (*digest)->rel8 = false;
+ nrel = &r->rel4.n;
+ }
+
+ if (unlikely (data->d_size - ((*digest)->rel8 ? 8 : 4) < r_offset))
+ return DWARF_E_RELBADOFF;
+
+ /* Fetch the symbol used in the reloc. STN_UNDEF means no symbol,
+ just an addend in some unallocated target DWARF section. If the
+ symbol is defined non-weak in another unallocated section, we can
+ adjust the addend now and not bother to record any symbol. */
+
+ inline bool allocated_scn (GElf_Word shndx)
+ {
+ Elf_Scn *const symscn = ((Elf_Data_Scn *) r->symdata)->s;
+ GElf_Shdr shdr;
+ return (gelf_getshdr (elf_getscn (symscn->elf, shndx), &shdr) == NULL
+ || (shdr.sh_flags & SHF_ALLOC));
+ }
+
+ GElf_Sym sym;
+ Elf32_Word shndx;
+ if (symndx != STN_UNDEF
+ && gelf_getsymshndx (r->symdata, r->symxndxdata, symndx, &sym, &shndx)
+ && GELF_ST_BIND (sym.st_info) < STB_WEAK
+ && (sym.st_shndx == SHN_XINDEX ? !allocated_scn (shndx)
+ : (sym.st_shndx != SHN_UNDEF
+ && sym.st_shndx < SHN_LORESERVE
+ && !allocated_scn (sym.st_shndx))))
+ {
+ r_addend += sym.st_value;
+ symndx = STN_UNDEF;
+ }
+
+#if 0
+ // XXX do in separate pass only for unstrip -R
+ if (modify && symndx == STN_UNDEF)
+ {
+ /* This is fully resolved statically.
+ Modify it in place and record nothing. */
+
+ unsigned char *datum = (unsigned char *) (*digest)->datum;
+ if ((*digest)->rel8)
+ {
+ Elf64_Xword val = read_8ubyte_unaligned (dbg, datum) + r_addend;
+ if (dbg->other_byte_order)
+ val = bswap_64 (val);
+ memcpy (datum, &val, sizeof val);
+ }
+ else
+ {
+ Elf32_Word val = read_4ubyte_unaligned (dbg, datum) + r_addend;
+ if (dbg->other_byte_order)
+ val = bswap_32 (val);
+ memcpy (datum, &val, sizeof val);
+ }
+ return 0;
+ }
+#endif
+
+ if (r_addend != 0 || symndx != STN_UNDEF)
+ {
+ /* This will require relocating the data dynamically. Record it. */
+
+ (*digest)->datum = data->d_buf + r_offset;
+ (*digest)->symndx = symndx;
+ (*digest)->addend = r_addend;
+ ++*digest;
+ ++*nrel;
+ }
+
+ return 0;
+}
+
+static int
+compare_digested_reloc (const void *a, const void *b)
+{
+ const struct digested_reloc *r1 = a;
+ const struct digested_reloc *r2 = b;
+ return r1->datum > r2->datum ? 1 : r1->datum < r2->datum ? -1 : 0;
+}
+
+static int
+digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
+{
+ GElf_Shdr shdr;
+ if (unlikely (gelf_getshdr (r->scn, &shdr) == NULL))
+ assert (!"impossible gelf_getshdr failure");
+
+ /* XXX let dwfl supply defaults from main file for separate debug
+ with relocs pointing to SHT_NOBITS symtab
+ r->symdata = dbg->relocate->symdata;
+ r->symstrdata = dbg->relocate->symstrdata;
+ */
+ {
+ GElf_Shdr symshdr;
+ Elf_Scn *const symscn = elf_getscn (r->scn->elf, shdr.sh_link);
+ if (unlikely (gelf_getshdr (symscn, &symshdr) == NULL))
+ return DWARF_E_RELBADSYM;
+ if (symshdr.sh_type != SHT_NOBITS)
+ {
+ r->symdata = elf_getdata (symscn, NULL);
+ if (unlikely (r->symdata == NULL))
+ return DWARF_E_RELBADSYM;
+ r->symstrdata = elf_getdata (elf_getscn (r->scn->elf, symshdr.sh_link),
+ NULL);
+ if (unlikely (r->symstrdata == NULL))
+ return DWARF_E_RELBADSYM;
+ }
+ }
+
+ if (dbg->relocate->ebl == NULL)
+ {
+ dbg->relocate->ebl = ebl_openbackend (dbg->elf);
+ if (unlikely (dbg->relocate->ebl == NULL))
+ return DWARF_E_NOMEM;
+ }
+
+ const int *rel8_types;
+ const int *rel4_types;
+ ebl_reloc_simple_types (dbg->relocate->ebl, &rel8_types, &rel4_types);
+
+ Elf_Data *const reldata = elf_getdata (r->scn, NULL);
+
+ const size_t nrel = shdr.sh_size / shdr.sh_entsize;
+ struct digested_reloc digest[nrel];
+ struct digested_reloc *d = digest;
+
+ r->rel4.n = r->rel8.n = 0;
+
+ int ret = 0;
+ if (shdr.sh_type == SHT_RELA)
+ for (size_t i = 0; i < nrel && !ret; ++i)
+ {
+ GElf_Rela rela;
+ if (unlikely (gelf_getrela (reldata, i, &rela) == NULL))
+ assert (!"impossible gelf_getrela failure");
+ ret = digest_one_reloc (rel8_types, rel4_types, r, data, &d,
+ rela.r_offset, rela.r_info, rela.r_addend);
+ }
+ else
+ for (size_t i = 0; i < nrel && !ret; ++i)
+ {
+ GElf_Rel rel;
+ if (unlikely (gelf_getrel (reldata, i, &rel) == NULL))
+ assert (!"impossible gelf_getrel failure");
+ ret = digest_one_reloc (rel8_types, rel4_types, r, data, &d,
+ rel.r_offset, rel.r_info, 0);
+ }
+
+ assert (r->rel4.n + r->rel8.n == (size_t) (d - digest));
+
+ if (ret)
+ return ret;
+
+ /* Sort by datum address. */
+ qsort (digest, d - digest, sizeof digest[0], &compare_digested_reloc);
+
+ if (r->rel8.n > 0)
+ {
+ r->rel8.datum = libdw_alloc (dbg, const unsigned char *,
+ sizeof (const unsigned char *),
+ r->rel8.n);
+ r->rel8.symndx = libdw_alloc (dbg, int, sizeof (int), r->rel8.n);
+ if (shdr.sh_type == SHT_RELA)
+ r->rela8 = libdw_alloc (dbg, Elf64_Sxword, sizeof (Elf64_Sxword),
+ r->rel8.n);
+ else
+ r->rela8 = NULL;
+ }
+
+ if (r->rel4.n > 0)
+ {
+ r->rel4.datum = libdw_alloc (dbg, const unsigned char *,
+ sizeof (const unsigned char *),
+ r->rel4.n);
+ r->rel4.symndx = libdw_alloc (dbg, int, sizeof (int), r->rel4.n);
+ if (shdr.sh_type == SHT_RELA)
+ r->rela4 = libdw_alloc (dbg, Elf32_Sword, sizeof (Elf32_Sword),
+ r->rel4.n);
+ else
+ r->rela4 = NULL;
+ }
+
+ size_t n8 = 0;
+ size_t n4 = 0;
+ for (struct digested_reloc *dr = digest; dr < d; ++dr)
+ if (dr->rel8)
+ {
+ r->rel8.datum[n8] = dr->datum;
+ r->rel8.symndx[n8] = dr->symndx;
+ if (shdr.sh_type == SHT_RELA)
+ r->rela8[n8] = dr->addend;
+ ++n8;
+ }
+ else
+ {
+ r->rel4.datum[n4] = dr->datum;
+ r->rel4.symndx[n4] = dr->symndx;
+ if (shdr.sh_type == SHT_RELA)
+ r->rela4[n4] = dr->addend;
+ ++n4;
+ }
+ assert (n8 == r->rel8.n);
+ assert (n4 == r->rel4.n);
+
+ /* Clearing this marks that the digested form is set up now. */
+ r->scn = NULL;
+ return 0;
+}
+\f
+/* Binary search for an exact match on the DATUM address. */
+static ssize_t
+find_reloc (struct dwarf_reloc_table *table, const unsigned char *datum)
+{
+ size_t l = 0, u = table->n;
+
+ if (u == 0)
+ return -1;
+
+ if (table->hint < u && table->datum[table->hint] <= datum)
+ {
+ l = table->hint;
+ if (table->datum[l] == datum)
+ return l;
+ if (table->datum[l] < datum)
+ ++l;
+ }
+
+ while (l < u)
+ {
+ size_t i = (l + u) / 2;
+ if (table->datum[i] < datum)
+ l = i + 1;
+ else if (table->datum[i] > datum)
+ u = i;
+ else
+ return table->hint = i;
+ }
+
+ table->hint = l;
+ 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)
+{
+ if (r == NULL)
+ return 0;
+
+ if (r->scn != NULL)
+ {
+ int result = digest_relocs (dbg, dbg->sectiondata[sec_index], r);
+ if (unlikely (result != 0))
+ {
+ __libdw_seterrno (result);
+ return -1;
+ }
+ }
+
+ ssize_t i;
+ if (width == 4)
+ {
+ i = find_reloc (&r->rel4, datum);
+ *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]);
+ }
+ else
+ {
+ assert (width == 8);
+
+ i = find_reloc (&r->rel8, datum);
+ *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]);
+ }
+
+ return i >= 0;
+}
+
+static int
+reloc_getsym (struct dwarf_section_reloc *r, int symndx,
+ GElf_Sym *sym, GElf_Word *shndx)
+{
+ if (unlikely (gelf_getsymshndx (r->symdata, r->symxndxdata,
+ symndx, sym, shndx) == NULL))
+ {
+ __libdw_seterrno (DWARF_E_RELBADSYM);
+ return -1;
+ }
+ return 1;
+}
+
+int
+internal_function
+__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);
+ if (result > 0 && symndx != STN_UNDEF)
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ result = reloc_getsym (r, symndx, &sym, &shndx);
+ if (result > 0)
+ {
+ result = (*dbg->relocate->resolve_symbol)
+ (sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
+ || GELF_ST_BIND (sym.st_info) > STB_WEAK,
+ dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx);
+ addend += sym.st_value;
+ }
+ }
+ if (result >= 0)
+ *val = addend;
+ return result;
+}
+
+int
+internal_function
+__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);
+ if (result > 0 && symndx != STN_UNDEF)
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ result = reloc_getsym (r, symndx, &sym, &shndx);
+ if (result > 0)
+ {
+ if (unlikely (sym.st_shndx == SHN_UNDEF)
+ || (sym.st_shndx > SHN_LORESERVE
+ && unlikely (sym.st_shndx != SHN_XINDEX)))
+ {
+ __libdw_seterrno (DWARF_E_RELUNDEF);
+ return -1;
+ }
+ if (unlikely (((Elf_Data_Scn *) dbg->sectiondata[sec_index])->s->index
+ != (sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx)))
+ {
+ __libdw_seterrno (DWARF_E_RELWRONGSEC);
+ return -1;
+ }
+ addend += sym.st_value;
+ }
+ }
+ if (result >= 0)
+ *val = addend;
+ return result;
+}
+2010-06-21 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsrc_file.: Update for Dwarf_Line member change.
+ * dwfl_lineinfo.c: Likewise. Use dwarf_lineaddr.
+
2010-06-20 Roland McGrath <roland@redhat.com>
* relocate.c (struct reloc_symtab_cache): New members
/* Get information from a source line record returned by libdwfl.
- Copyright (C) 2005, 2006 Red Hat, Inc.
+ Copyright (C) 2005-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
if (colp != NULL)
*colp = info->column;
- struct Dwarf_Fileinfo_s *file = &info->files->info[info->file];
+ struct Dwarf_Fileinfo_s *file = &info->cu->files->info[info->file];
if (mtime != NULL)
*mtime = file->mtime;
if (length != NULL)
/* Find matching source locations in a module.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005-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
{
inline const char *INTUSE(dwarf_line_file) (const Dwarf_Line *line)
{
- return line->files->info[line->file].name;
+ return line->cu->files->info[line->file].name;
}
inline Dwarf_Line *dwfl_line (const Dwfl_Line *line)
{
{
Dwarf_Line *line = &cu->die.cu->lines->info[cnt];
- if (unlikely (line->file >= line->files->nfiles))
+ if (unlikely (line->file >= line->cu->files->nfiles))
{
__libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
return -1;