Index: frysk-imports/elfutils/libdwfl/dwfl_module_addrsym.c =================================================================== RCS file: /cvs/frysk/frysk-imports/elfutils/libdwfl/dwfl_module_addrsym.c,v retrieving revision 1.6.2.2 retrieving revision 1.6.2.3 diff -p -r1.6.2.2 -r1.6.2.3 *** frysk-imports/elfutils/libdwfl/dwfl_module_addrsym.c 28 Aug 2007 20:40:47 -0000 1.6.2.2 --- frysk-imports/elfutils/libdwfl/dwfl_module_addrsym.c 30 Aug 2007 19:07:03 -0000 1.6.2.3 *************** dwfl_module_addrsym (Dwfl_Module *mod, G *** 97,170 **** return shndx == addr_shndx; } ! /* 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_Word closest_shndx = SHN_UNDEF; - - /* 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_Word sizeless_shndx = SHN_UNDEF; - - /* Keep track of the lowest address a relevant sizeless symbol could have. */ - GElf_Addr min_label = addr; - - /* Look through the symbol table for a matching symbol. */ for (int i = 1; i < syments; ++i) { GElf_Sym sym; GElf_Word shndx; const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx); ! if (name != NULL ! && sym.st_value <= addr ! && (sym.st_size == 0 || addr - sym.st_value < sym.st_size)) { ! /* Even if we don't choose this symbol, its existence ! excludes any sizeless symbol (assembly label) that ! is inside its bounds. */ ! if (sym.st_value + sym.st_size > addr) ! min_label = sym.st_value + sym.st_size; ! ! /* This symbol is a better candidate than the current one ! if it's a named symbol, not a section or file symbol, ! and is closer to ADDR or is global when it was local. */ ! if (name[0] != '\0' ! && GELF_ST_TYPE (sym.st_info) != STT_SECTION ! && GELF_ST_TYPE (sym.st_info) != STT_FILE ! && (closest_name == NULL ! || closest_sym->st_value < sym.st_value ! || (GELF_ST_BIND (closest_sym->st_info) ! < GELF_ST_BIND (sym.st_info)))) { ! if (sym.st_size != 0) { ! *closest_sym = sym; ! closest_shndx = shndx; ! closest_name = name; } ! else if (same_section (&sym, 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_shndx = shndx; ! sizeless_name = name; } } } } ! /* 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_sym.st_value >= min_label) { ! *closest_sym = sizeless_sym; ! closest_shndx = sizeless_shndx; ! closest_name = sizeless_name; } if (shndxp != NULL) --- 97,176 ---- return shndx == addr_shndx; } ! /* Look through the symbol table for a matching symbol. */ const char *closest_name = NULL; + memset(closest_sym, 0, sizeof(*closest_sym)); GElf_Word closest_shndx = SHN_UNDEF; for (int i = 1; i < syments; ++i) { GElf_Sym sym; GElf_Word shndx; const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx); ! if (name != NULL && sym.st_value <= addr) { ! inline void closest (void) { ! *closest_sym = sym; ! closest_shndx = shndx; ! closest_name = name; ! } ! ! /* This symbol contains ADDR; but is it better than the ! previous candidate? */ ! if (addr < sym.st_value + sym.st_size) ! { ! if (addr >= closest_sym->st_value + closest_sym->st_size) ! { ! /* Ha! The previous candidate doesn't even contain ! ADDR; replace it. */ ! closest(); ! continue; ! } ! if (sym.st_value > closest_sym->st_value) { ! /* This candidate is closer to ADDR. */ ! closest (); ! continue; } ! if (sym.st_value == closest_sym->st_value ! && sym.st_size < closest_sym->st_size) { ! /* This candidate, while having an identical value, ! is at least smaller. */ ! closest (); ! continue; } + /* Discard this candidate, no better than the previous + sized symbol that contained ADDR. */ + continue; + } + + /* The current closest symbol contains ADDR, can't do better + than that. */ + if (addr < closest_sym->st_value + closest_sym->st_size) + continue; + + /* Save the symbol which is "closer". Use the end-address + so that a sized symbol that ends closer to an unsized + symbol wins (unsized symbols are typically created using + hand-written assembler). */ + if (sym.st_value + sym.st_size + >= closest_sym->st_value + closest_sym->st_size + && same_section (&sym, shndx)) + { + closest (); + continue; } } } ! /* If the closest symbol has a size doesn't contain ADDR, discard ! it. There must be a hole in the symbol table. */ ! if (closest_sym->st_size > 0 ! && addr >= closest_sym->st_value + closest_sym->st_size) { ! memset(closest_sym, 0, sizeof(*closest_sym)); ! return NULL; } if (shndxp != NULL)