+2010-06-28 Roland McGrath <roland@redhat.com>
+
+ * libdwP.h (struct Dwarf_Lines_s): Change reloc member to int pointer.
+ * dwarf_getsrclines.c (struct linelist): Add reloc/symndx/shndx members.
+ (compare_lines): Sort by shndx before line.addr.
+ (dwarf_getsrclines): Resolve relocatable addresses to a symndx and
+ section-relative address.
+ * dwarf_line_relocatable.c: Initialize symndx instead of valp.
+ * dwarf_lineaddr.c: Use __libdw_relocate_shndx
+
+ * relocate.c (__libdw_relocatable_getsym): New function.
+ (__libdw_relocate_address, __libdw_relocate_offset): Call it.
+ (__libdw_relocate_shndx): New function.
+ * relocate.h: Declare them.
+
+ * libdw.h (Dwarf_Relocatable): Use uint8_t for sec and form members.
+ Add symndx member.
+ * dwarf_relocatable_info.c (relocatable_form): Take new arg SYMNDX.
+ If VALP is null, use SYMNDX instead of looking for a reloc.
+ (dwarf_relocatable_info): Update caller.
+
2010-06-24 Roland McGrath <roland@redhat.com>
* encoded-value.h (encoded_value_size): Replace E_IDENT parameter
# include <config.h>
#endif
+#include "relocate.h"
+#include <dwarf.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "dwarf.h"
-#include "libdwP.h"
struct filelist
struct linelist
{
Dwarf_Line line;
- const unsigned char *reloc;
+ union
+ {
+ const unsigned char *reloc;
+ struct
+ {
+ int symndx;
+ int shndx;
+ };
+ };
struct linelist *next;
};
static int
compare_lines (const void *a, const void *b)
{
- Dwarf_Line *const *p1 = a;
- Dwarf_Line *const *p2 = b;
+ struct linelist *const *p1 = a;
+ struct linelist *const *p2 = b;
+
+ int result = (*p1)->shndx - (*p2)->shndx;
+ if (result != 0)
+ return result;
- if ((*p1)->addr == (*p2)->addr)
+ if ((*p1)->line.addr == (*p2)->line.addr)
/* An end_sequence marker precedes a normal record at the same address. */
- return (*p2)->end_sequence - (*p1)->end_sequence;
+ return (*p2)->line.end_sequence - (*p1)->line.end_sequence;
- return (*p1)->addr - (*p2)->addr;
+ if ((*p1)->line.addr > (*p2)->line.addr)
+ return 1;
+ if ((*p1)->line.addr < (*p2)->line.addr)
+ return -1;
+
+ return 0;
}
int
ascending addresses. So fill from the back to probably start with
runs already in order before we sort. */
unsigned int i = nlinelist;
+ addr_reloc = NULL;
+ int reloc_symndx = STN_UNDEF;
+ int reloc_shndx = 0;
+ GElf_Sxword reloc_value = 0;
while (i-- > 0)
{
+ if (linelist->reloc == NULL)
+ {
+ assert (linelist->symndx == STN_UNDEF);
+ assert (linelist->shndx == 0);
+ }
+ else
+ {
+ /* A relocatable address in line information must be
+ a defined symbol. So we can reduce it immediately
+ to a section index. */
+
+ if (linelist->reloc != addr_reloc)
+ {
+ addr_reloc = linelist->reloc;
+
+ GElf_Sym sym;
+ GElf_Word shndx;
+ int result = __libdw_relocatable_getsym (cu->dbg,
+ IDX_debug_line,
+ addr_reloc,
+ cu->address_size,
+ &reloc_symndx,
+ &sym, &shndx,
+ &reloc_value);
+ if (unlikely (result < 0))
+ {
+ res = -1;
+ goto out;
+ }
+ if (result == 0)
+ reloc_symndx = STN_UNDEF;
+ if (reloc_symndx == STN_UNDEF)
+ reloc_shndx = 0;
+ else
+ {
+ reloc_value += sym.st_value;
+ if (likely (sym.st_shndx < SHN_LORESERVE)
+ && likely (sym.st_shndx != SHN_UNDEF))
+ reloc_shndx = sym.st_shndx;
+ else if (sym.st_shndx == SHN_ABS)
+ reloc_shndx = 0;
+ else if (sym.st_shndx == SHN_XINDEX)
+ reloc_shndx = shndx;
+ else
+ {
+ __libdw_seterrno (DWARF_E_RELOC);
+ res = -1;
+ goto out;
+ }
+ }
+ }
+
+ linelist->symndx = reloc_symndx;
+ linelist->shndx = reloc_shndx;
+ linelist->line.addr += reloc_value;
+ }
+
sortlines[i] = linelist;
linelist = linelist->next;
}
&& 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);
+ cu->lines->reloc = libdw_alloc (cu->dbg, int, sizeof (int),
+ 2 * nlinelist);
for (i = 0; i < nlinelist; ++i)
- cu->lines->reloc[i] = sortlines[i]->reloc;
+ {
+ cu->lines->reloc[i * 2] = sortlines[i]->symndx;
+ cu->lines->reloc[i * 2 + 1] = sortlines[i]->shndx;
+ }
}
else
cu->lines->reloc = NULL;
if (line == NULL)
return -1;
+ const int *const linerel = line->cu->lines->reloc;
+ const size_t idx = line - line->cu->lines->info;
+
*reloc = (Dwarf_Relocatable)
{
.sec = IDX_debug_line, .form = DW_FORM_addr,
.cu = line->cu,
- .valp = (line->cu->lines->reloc == NULL ? NULL
- : line->cu->lines->reloc[line - line->cu->lines->info]),
+ .symndx = linerel == NULL ? STN_UNDEF : linerel[idx * 2],
.adjust = line->addr
};
#endif
#include "libdwP.h"
+#include "relocate.h"
int
if (line == NULL)
return -1;
- if (line->cu->lines->reloc == NULL
- || line->cu->lines->reloc[line - line->cu->lines->info] == NULL)
+ const int *const reloc = line->cu->lines->reloc;
+ const size_t idx = line - line->cu->lines->info;
+
+ if (reloc == NULL || reloc[idx * 2] == STN_UNDEF)
{
*addrp = line->addr;
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;
+ /* We have already reduced this relocatable address to a section offset.
+ We just have to resolve the section address. */
- return result;
+ return __libdw_relocate_shndx (line->cu->dbg,
+ reloc[idx * 2 + 1], line->addr, addrp);
}
static int
relocatable_form (struct Dwarf_CU *cu,
- unsigned int sec_idx,
- unsigned int form,
+ uint_fast8_t sec_idx,
+ uint_fast8_t form,
const unsigned char *valp,
+ int symndx,
Dwarf_Addr adjust,
GElf_Sym *sym, const char **name,
GElf_Sxword *addend, const char **secname)
break;
}
- int symndx;
- int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
- &symndx, addend);
- if (result == 0)
- goto noreloc;
- else if (likely (result > 0))
+ if (valp != NULL)
{
- 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))
+ int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
+ &symndx, addend);
+ if (unlikely (result < 0))
+ return result;
+ if (result == 0)
+ goto noreloc;
+ }
+
+ 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 (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)
+ if (addend != NULL)
+ {
+ if (valp == NULL)
+ /* The ADJUST value was already section-relative, so we have to
+ remove the st_value portion of it. */
+ *addend = adjust - sym->st_value;
+ else
*addend += adjust;
+ }
- result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx
+ int 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);
- }
+ 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;
if (reloc == NULL)
return -1;
- return relocatable_form (reloc->cu, reloc->sec,
- reloc->form, reloc->valp, reloc->adjust,
+ return relocatable_form (reloc->cu, reloc->sec, reloc->form,
+ reloc->valp, reloc->symndx, reloc->adjust,
sym, name, addend, secname);
}
INTDEF (dwarf_relocatable_info)
/* Relocatable address representation. */
typedef struct
{
- unsigned int sec;
- unsigned int form;
+ int symndx;
+ uint8_t sec;
+ uint8_t form;
const unsigned char *valp;
struct Dwarf_CU *cu;
Dwarf_Addr adjust;
struct Dwarf_Lines_s
{
- const unsigned char **reloc;
+ /* If non-null, reloc[i * 2], reloc[i * 2 + 1] are symndx, shndx
+ corresponding to info[i], and info[i].addr is section-relative. */
+ int *reloc;
size_t nlines;
struct Dwarf_Line_s info[0];
};
return 1;
}
+int
+internal_function
+__libdw_relocatable_getsym (Dwarf *dbg, int sec_index,
+ const unsigned char *datum, int width,
+ int *symndx, GElf_Sym *sym, GElf_Word *shndx,
+ GElf_Sxword *addend)
+{
+ int result = __libdw_relocatable (dbg, sec_index, datum, width,
+ symndx, addend);
+ if (result > 0 && *symndx != STN_UNDEF)
+ result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
+ *symndx, sym, shndx);
+ return result;
+}
+
+int
+internal_function
+__libdw_relocate_shndx (Dwarf *dbg, GElf_Word shndx, GElf_Sxword addend,
+ Dwarf_Addr *val)
+{
+ GElf_Sym sym =
+ {
+ .st_shndx = shndx < SHN_LORESERVE ? shndx : SHN_XINDEX,
+ .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
+ };
+ int result = (*dbg->relocate->resolve_symbol) (false, dbg, &sym, shndx);
+ if (result == 0)
+ *val = sym.st_value + addend;
+ return result;
+}
+
int
internal_function
__libdw_relocate_address (Dwarf *dbg, int sec_index,
const void *datum, int width, Dwarf_Addr *val)
{
int symndx;
+ GElf_Sym sym;
+ GElf_Word shndx;
GElf_Sxword addend;
- int result = __libdw_relocatable (dbg, sec_index, datum, width,
- &symndx, &addend);
+ int result = __libdw_relocatable_getsym (dbg, sec_index, datum, width,
+ &symndx, &sym, &shndx, &addend);
if (result > 0 && symndx != STN_UNDEF)
{
- GElf_Sym sym;
- GElf_Word shndx;
- result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
- 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;
- }
+ 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;
const void *datum, int width, Dwarf_Off *val)
{
int symndx;
+ GElf_Sym sym;
+ GElf_Word shndx;
GElf_Sxword addend;
- int result = __libdw_relocatable (dbg, sec_index, datum, width,
- &symndx, &addend);
+ int result = __libdw_relocatable_getsym (dbg, sec_index, datum, width,
+ &symndx, &sym, &shndx, &addend);
if (result > 0 && symndx != STN_UNDEF)
{
- GElf_Sym sym;
- GElf_Word shndx;
- result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
- 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)))
{
- 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;
+ __libdw_seterrno (DWARF_E_RELWRONGSEC);
+ return -1;
}
+ addend += sym.st_value;
}
if (result >= 0)
*val = addend;
int *symndx, GElf_Sxword *addend)
__nonnull_attribute__ (1) internal_function;
+extern int __libdw_relocatable_getsym (Dwarf *dbg, int sec_index,
+ const unsigned char *datum, int width,
+ int *symndx, GElf_Sym *sym,
+ GElf_Word *shndx, GElf_Sxword *addend)
+ __nonnull_attribute__ (1, 3, 5, 6, 7, 8) internal_function;
+
+extern int __libdw_relocate_shndx (Dwarf *dbg,
+ GElf_Word shndx, GElf_Sxword addend,
+ Dwarf_Addr *val)
+ __nonnull_attribute__ (1, 4) internal_function;
+
extern ptrdiff_t __libdw_ranges_relocatable (struct Dwarf_CU *cu,
Dwarf_Attribute *attr,
ptrdiff_t offset,