diff options
author | Chih-Hung Hsieh <chh@google.com> | 2015-11-16 16:05:01 -0800 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2016-01-02 17:22:36 +0100 |
commit | b1450614fd26d1a9b8ee17fe3f0290d23ddd0748 (patch) | |
tree | 6f7cda73f0608cf6ce7fe2daa3a2cc0daa553cd0 | |
parent | e0b020fd1bdff5c503b31e8de9f5c2b3a50707e5 (diff) | |
download | elfutils-b1450614fd26d1a9b8ee17fe3f0290d23ddd0748.tar.gz |
Move nested functions in dwfl_module_addrsym.c to file scope.
* Move nested functions 'same_section', 'binding_value',
'try_sym_value', and 'search_table'.
Signed-off-by: Chih-Hung Hsieh <chh@google.com>
-rw-r--r-- | libdwfl/ChangeLog | 6 | ||||
-rw-r--r-- | libdwfl/dwfl_module_addrsym.c | 335 |
2 files changed, 193 insertions, 148 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 3c48b5e7..918fb84c 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,9 @@ +2015-11-16 Chih-Hung Hsieh <chh@google.com> + + * dwfl_module_addrsym.c (__libdwfl_addrsym): Move nested functions + 'same_section', 'binding_value', 'try_sym_value', and 'search_table' + to file scope. + 2015-11-19 Mark Wielaard <mjw@redhat.com> * dwfl_module.c (__libdwfl_module_free): Remove Dwfl_Module Ebl from diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c index d205832c..5a7bf714 100644 --- a/libdwfl/dwfl_module_addrsym.c +++ b/libdwfl/dwfl_module_addrsym.c @@ -28,141 +28,144 @@ #include "libdwflP.h" -/* Returns the name of the symbol "closest" to ADDR. - Never returns symbols at addresses above ADDR. */ - -const char * -internal_function -__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, - GElf_Sym *closest_sym, GElf_Word *shndxp, - Elf **elfp, Dwarf_Addr *biasp, bool adjust_st_value) +struct search_state { - int syments = INTUSE(dwfl_module_getsymtab) (mod); - if (syments < 0) - return NULL; + Dwfl_Module *mod; + GElf_Addr addr; - /* Return true iff we consider ADDR to lie in the same section as SYM. */ - GElf_Word addr_shndx = SHN_UNDEF; - Elf *addr_symelf = NULL; - inline bool same_section (GElf_Addr value, Elf *symelf, GElf_Word shndx) - { - /* For absolute symbols and the like, only match exactly. */ - if (shndx >= SHN_LORESERVE) - return value == addr; + GElf_Sym *closest_sym; + bool adjust_st_value; + GElf_Word addr_shndx; + Elf *addr_symelf; - /* If value might not be st_value, the shndx of the symbol might - not match the section of the value. Explicitly look both up. */ - if (! adjust_st_value) - { - Dwarf_Addr v; - if (addr_shndx == SHN_UNDEF) - { - v = addr; - addr_shndx = __libdwfl_find_section_ndx (mod, &v); - } + /* Keep track of the closest symbol we have seen so far. + Here we store only symbols with nonzero st_size. */ + const char *closest_name; + GElf_Addr closest_value; + GElf_Word closest_shndx; + Elf *closest_elf; - v = value; - return addr_shndx == __libdwfl_find_section_ndx (mod, &v); - } + /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ + const char *sizeless_name; + GElf_Sym sizeless_sym; + GElf_Addr sizeless_value; + GElf_Word sizeless_shndx; + Elf *sizeless_elf; - /* Figure out what section ADDR lies in. */ - if (addr_shndx == SHN_UNDEF || addr_symelf != symelf) - { - GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, symelf, addr); - Elf_Scn *scn = NULL; - addr_shndx = SHN_ABS; - addr_symelf = symelf; - while ((scn = elf_nextscn (symelf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (likely (shdr != NULL) - && mod_addr >= shdr->sh_addr - && mod_addr < shdr->sh_addr + shdr->sh_size) - { - addr_shndx = elf_ndxscn (scn); - break; - } - } - } + /* Keep track of the lowest address a relevant sizeless symbol could have. */ + GElf_Addr min_label; +}; - return shndx == addr_shndx && addr_symelf == symelf; +/* Return true iff we consider ADDR to lie in the same section as SYM. */ +static inline bool +same_section (struct search_state *state, + GElf_Addr value, Elf *symelf, GElf_Word shndx) +{ + /* For absolute symbols and the like, only match exactly. */ + if (shndx >= SHN_LORESERVE) + return value == state->addr; + + /* If value might not be st_value, the shndx of the symbol might + not match the section of the value. Explicitly look both up. */ + if (! state->adjust_st_value) + { + Dwarf_Addr v; + if (state->addr_shndx == SHN_UNDEF) + { + v = state->addr; + state->addr_shndx = __libdwfl_find_section_ndx (state->mod, &v); + } + + v = value; + return state->addr_shndx == __libdwfl_find_section_ndx (state->mod, &v); } - /* Keep track of the closest symbol we have seen so far. - Here we store only symbols with nonzero st_size. */ - const char *closest_name = NULL; - GElf_Addr closest_value = 0; - GElf_Word closest_shndx = SHN_UNDEF; - Elf *closest_elf = NULL; + /* Figure out what section ADDR lies in. */ + if (state->addr_shndx == SHN_UNDEF || state->addr_symelf != symelf) + { + GElf_Addr mod_addr = dwfl_deadjust_st_value (state->mod, symelf, + state->addr); + Elf_Scn *scn = NULL; + state->addr_shndx = SHN_ABS; + state->addr_symelf = symelf; + while ((scn = elf_nextscn (symelf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (likely (shdr != NULL) + && mod_addr >= shdr->sh_addr + && mod_addr < shdr->sh_addr + shdr->sh_size) + { + state->addr_shndx = elf_ndxscn (scn); + break; + } + } + } - /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ - const char *sizeless_name = NULL; - GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; - GElf_Addr sizeless_value = 0; - GElf_Word sizeless_shndx = SHN_UNDEF; - Elf *sizeless_elf = NULL; + return shndx == state->addr_shndx && state->addr_symelf == symelf; +} - /* Keep track of the lowest address a relevant sizeless symbol could have. */ - GElf_Addr min_label = 0; +/* Return GELF_ST_BIND as higher-is-better integer. */ +static inline int +binding_value (const GElf_Sym *symp) +{ + switch (GELF_ST_BIND (symp->st_info)) + { + case STB_GLOBAL: + return 3; + case STB_WEAK: + return 2; + case STB_LOCAL: + return 1; + default: + return 0; + } +} - /* Try one symbol and associated value from the search table. */ - inline void try_sym_value (GElf_Addr value, GElf_Sym *sym, - const char *name, GElf_Word shndx, - Elf *elf, bool resolved) - { +/* Try one symbol and associated value from the search table. */ +static inline void +try_sym_value (struct search_state *state, + GElf_Addr value, GElf_Sym *sym, + const char *name, GElf_Word shndx, + Elf *elf, bool resolved) +{ /* Even if we don't choose this symbol, its existence excludes any sizeless symbol (assembly label) that is below its upper bound. */ - if (value + sym->st_size > min_label) - min_label = value + sym->st_size; + if (value + sym->st_size > state->min_label) + state->min_label = value + sym->st_size; - if (sym->st_size == 0 || addr - value < sym->st_size) + if (sym->st_size == 0 || state->addr - value < sym->st_size) { - /* Return GELF_ST_BIND as higher-is-better integer. */ - inline int binding_value (const GElf_Sym *symp) - { - switch (GELF_ST_BIND (symp->st_info)) - { - case STB_GLOBAL: - return 3; - case STB_WEAK: - return 2; - case STB_LOCAL: - return 1; - default: - return 0; - } - } - /* This symbol is a better candidate than the current one if it's closer to ADDR or is global when it was local. */ - if (closest_name == NULL - || closest_value < value - || binding_value (closest_sym) < binding_value (sym)) + if (state->closest_name == NULL + || state->closest_value < value + || binding_value (state->closest_sym) < binding_value (sym)) { if (sym->st_size != 0) { - *closest_sym = *sym; - closest_value = value; - closest_shndx = shndx; - closest_elf = elf; - closest_name = name; + *state->closest_sym = *sym; + state->closest_value = value; + state->closest_shndx = shndx; + state->closest_elf = elf; + state->closest_name = name; } - else if (closest_name == NULL - && value >= min_label - && same_section (value, - resolved ? mod->main.elf : elf, shndx)) + else if (state->closest_name == NULL + && value >= state->min_label + && same_section (state, value, + resolved ? state->mod->main.elf : elf, + shndx)) { /* Handwritten assembly symbols sometimes have no st_size. If no symbol with proper size includes the address, we'll use the closest one that is in the same section as ADDR. */ - sizeless_sym = *sym; - sizeless_value = value; - sizeless_shndx = shndx; - sizeless_elf = elf; - sizeless_name = name; + state->sizeless_sym = *sym; + state->sizeless_value = value; + state->sizeless_shndx = shndx; + state->sizeless_elf = elf; + state->sizeless_name = name; } } /* When the beginning of its range is no closer, @@ -170,26 +173,27 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, GELF_ST_BIND preference. If all are equal prefer the first symbol found. */ else if (sym->st_size != 0 - && closest_value == value - && ((closest_sym->st_size > sym->st_size - && (binding_value (closest_sym) + && state->closest_value == value + && ((state->closest_sym->st_size > sym->st_size + && (binding_value (state->closest_sym) <= binding_value (sym))) - || (closest_sym->st_size >= sym->st_size - && (binding_value (closest_sym) + || (state->closest_sym->st_size >= sym->st_size + && (binding_value (state->closest_sym) < binding_value (sym))))) { - *closest_sym = *sym; - closest_value = value; - closest_shndx = shndx; - closest_elf = elf; - closest_name = name; + *state->closest_sym = *sym; + state->closest_value = value; + state->closest_shndx = shndx; + state->closest_elf = elf; + state->closest_name = name; } } - } +} - /* Look through the symbol table for a matching symbol. */ - inline void search_table (int start, int end) - { +/* Look through the symbol table for a matching symbol. */ +static inline void +search_table (struct search_state *state, int start, int end) +{ for (int i = start; i < end; ++i) { GElf_Sym sym; @@ -197,32 +201,66 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, GElf_Word shndx; Elf *elf; bool resolved; - const char *name = __libdwfl_getsym (mod, i, &sym, &value, + const char *name = __libdwfl_getsym (state->mod, i, &sym, &value, &shndx, &elf, NULL, - &resolved, adjust_st_value); + &resolved, + state->adjust_st_value); if (name != NULL && name[0] != '\0' && sym.st_shndx != SHN_UNDEF - && value <= addr + && value <= state->addr && GELF_ST_TYPE (sym.st_info) != STT_SECTION && GELF_ST_TYPE (sym.st_info) != STT_FILE && GELF_ST_TYPE (sym.st_info) != STT_TLS) { - try_sym_value (value, &sym, name, shndx, elf, resolved); + try_sym_value (state, value, &sym, name, shndx, elf, resolved); /* If this is an addrinfo variant and the value could be resolved then also try matching the (adjusted) st_value. */ - if (resolved && mod->e_type != ET_REL) + if (resolved && state->mod->e_type != ET_REL) { GElf_Addr adjusted_st_value; - adjusted_st_value = dwfl_adjusted_st_value (mod, elf, + adjusted_st_value = dwfl_adjusted_st_value (state->mod, elf, sym.st_value); - if (value != adjusted_st_value && adjusted_st_value <= addr) - try_sym_value (adjusted_st_value, &sym, name, shndx, + if (value != adjusted_st_value + && adjusted_st_value <= state->addr) + try_sym_value (state, adjusted_st_value, &sym, name, shndx, elf, false); } } } - } +} + +/* Returns the name of the symbol "closest" to ADDR. + Never returns symbols at addresses above ADDR. */ +const char * +internal_function +__libdwfl_addrsym (Dwfl_Module *_mod, GElf_Addr _addr, GElf_Off *off, + GElf_Sym *_closest_sym, GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *biasp, bool _adjust_st_value) +{ + int syments = INTUSE(dwfl_module_getsymtab) (_mod); + if (syments < 0) + return NULL; + + struct search_state state = + { + .addr = _addr, + .mod = _mod, + .closest_sym = _closest_sym, + .adjust_st_value = _adjust_st_value, + .addr_shndx = SHN_UNDEF, + .addr_symelf = NULL, + .closest_name = NULL, + .closest_value = 0, + .closest_shndx = SHN_UNDEF, + .closest_elf = NULL, + .sizeless_name = NULL, + .sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }, + .sizeless_value = 0, + .sizeless_shndx = SHN_UNDEF, + .sizeless_elf = NULL, + .min_label = 0 + }; /* First go through global symbols. mod->first_global and mod->aux_first_global are setup by dwfl_module_getsymtab to the @@ -233,38 +271,39 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, come first in the symbol table, then all globals. The zeroth, null entry, in the auxiliary table is skipped if there is a main table. */ - int first_global = INTUSE (dwfl_module_getsymtab_first_global) (mod); + int first_global = INTUSE (dwfl_module_getsymtab_first_global) (state.mod); if (first_global < 0) return NULL; - search_table (first_global == 0 ? 1 : first_global, syments); + search_table (&state, first_global == 0 ? 1 : first_global, syments); /* If we found nothing searching the global symbols, then try the locals. Unless we have a global sizeless symbol that matches exactly. */ - if (closest_name == NULL && first_global > 1 - && (sizeless_name == NULL || sizeless_value != addr)) - search_table (1, first_global); + if (state.closest_name == NULL && first_global > 1 + && (state.sizeless_name == NULL || state.sizeless_value != state.addr)) + search_table (&state, 1, first_global); /* If we found no proper sized symbol to use, fall back to the best candidate sizeless symbol we found, if any. */ - if (closest_name == NULL - && sizeless_name != NULL && sizeless_value >= min_label) + if (state.closest_name == NULL + && state.sizeless_name != NULL + && state.sizeless_value >= state.min_label) { - *closest_sym = sizeless_sym; - closest_value = sizeless_value; - closest_shndx = sizeless_shndx; - closest_elf = sizeless_elf; - closest_name = sizeless_name; + *state.closest_sym = state.sizeless_sym; + state.closest_value = state.sizeless_value; + state.closest_shndx = state.sizeless_shndx; + state.closest_elf = state.sizeless_elf; + state.closest_name = state.sizeless_name; } - *off = addr - closest_value; + *off = state.addr - state.closest_value; if (shndxp != NULL) - *shndxp = closest_shndx; + *shndxp = state.closest_shndx; if (elfp != NULL) - *elfp = closest_elf; + *elfp = state.closest_elf; if (biasp != NULL) - *biasp = dwfl_adjusted_st_value (mod, closest_elf, 0); - return closest_name; + *biasp = dwfl_adjusted_st_value (state.mod, state.closest_elf, 0); + return state.closest_name; } |