From fdbd1ce205e2bd0c85d92a746499bc529496cfd0 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 28 Jun 2010 23:23:05 -0700 Subject: [PATCH] Rejigger relocatable Dwarf_Line in a sort-friendly way. --- libdw/ChangeLog | 21 +++++++ libdw/dwarf_getsrclines.c | 104 +++++++++++++++++++++++++++++---- libdw/dwarf_line_relocatable.c | 6 +- libdw/dwarf_lineaddr.c | 21 +++---- libdw/dwarf_relocatable_info.c | 100 +++++++++++++++++-------------- libdw/libdw.h | 5 +- libdw/libdwP.h | 4 +- libdw/relocate.c | 91 ++++++++++++++++++----------- libdw/relocate.h | 11 ++++ 9 files changed, 254 insertions(+), 109 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 7223eb7db..70e46a16e 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,24 @@ +2010-06-28 Roland McGrath + + * 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 * encoded-value.h (encoded_value_size): Replace E_IDENT parameter diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index aefa8d32d..f15b4410c 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -52,11 +52,11 @@ # include #endif +#include "relocate.h" +#include #include #include #include -#include "dwarf.h" -#include "libdwP.h" struct filelist @@ -68,7 +68,15 @@ struct filelist struct linelist { Dwarf_Line line; - const unsigned char *reloc; + union + { + const unsigned char *reloc; + struct + { + int symndx; + int shndx; + }; + }; struct linelist *next; }; @@ -77,14 +85,23 @@ struct linelist 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 @@ -726,8 +743,69 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) 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; } @@ -746,11 +824,13 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) && 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; diff --git a/libdw/dwarf_line_relocatable.c b/libdw/dwarf_line_relocatable.c index a57422e96..d53644b70 100644 --- a/libdw/dwarf_line_relocatable.c +++ b/libdw/dwarf_line_relocatable.c @@ -63,12 +63,14 @@ dwarf_line_relocatable (line, reloc) 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 }; diff --git a/libdw/dwarf_lineaddr.c b/libdw/dwarf_lineaddr.c index 7bfefd6cc..1e0b32343 100644 --- a/libdw/dwarf_lineaddr.c +++ b/libdw/dwarf_lineaddr.c @@ -53,6 +53,7 @@ #endif #include "libdwP.h" +#include "relocate.h" int @@ -61,22 +62,18 @@ dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp) 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); } diff --git a/libdw/dwarf_relocatable_info.c b/libdw/dwarf_relocatable_info.c index c1ad30527..f4260e772 100644 --- a/libdw/dwarf_relocatable_info.c +++ b/libdw/dwarf_relocatable_info.c @@ -57,9 +57,10 @@ 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) @@ -109,57 +110,66 @@ relocatable_form (struct Dwarf_CU *cu, 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; @@ -177,8 +187,8 @@ dwarf_relocatable_info (reloc, sym, name, addend, secname) 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) diff --git a/libdw/libdw.h b/libdw/libdw.h index 52962b4a0..c359e10f2 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -151,8 +151,9 @@ typedef struct /* 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; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index c970c9aed..f2886028c 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -280,7 +280,9 @@ struct Dwarf_Line_s 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]; }; diff --git a/libdw/relocate.c b/libdw/relocate.c index 2a38e51c0..03671ce44 100644 --- a/libdw/relocate.c +++ b/libdw/relocate.c @@ -462,29 +462,55 @@ reloc_getsym (struct dwarf_section_reloc *r, int symndx, 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; @@ -497,32 +523,27 @@ __libdw_relocate_offset (Dwarf *dbg, int sec_index, 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; diff --git a/libdw/relocate.h b/libdw/relocate.h index eaf8e6285..6c9751879 100644 --- a/libdw/relocate.h +++ b/libdw/relocate.h @@ -86,6 +86,17 @@ extern int __libdw_relocatable (Dwarf *dbg, int sec_index, 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, -- 2.47.2