diff options
author | eutarass | 2011-06-09 17:49:21 +0000 |
---|---|---|
committer | eutarass | 2011-06-09 17:49:21 +0000 |
commit | bf3f8bdf7996ad67f906b10893bc5f75d155028c (patch) | |
tree | f8643975e67dcd1d003cba36980542623f55bb8b | |
parent | bfd117c4cad39417f5290b304dd3588fad4ba6f1 (diff) | |
download | org.eclipse.tcf.agent-bf3f8bdf7996ad67f906b10893bc5f75d155028c.tar.gz org.eclipse.tcf.agent-bf3f8bdf7996ad67f906b10893bc5f75d155028c.tar.xz org.eclipse.tcf.agent-bf3f8bdf7996ad67f906b10893bc5f75d155028c.zip |
TCF Agent: ELF handling code is changed to better support searching of ELF symbols by address.
-rw-r--r-- | services/dwarfcache.c | 116 | ||||
-rw-r--r-- | services/dwarfcache.h | 36 | ||||
-rw-r--r-- | services/dwarfio.c | 2 | ||||
-rw-r--r-- | services/linenumbers_elf.c | 4 | ||||
-rw-r--r-- | services/symbols_elf.c | 266 | ||||
-rw-r--r-- | services/tcf_elf.c | 213 | ||||
-rw-r--r-- | services/tcf_elf.h | 57 |
7 files changed, 343 insertions, 351 deletions
diff --git a/services/dwarfcache.c b/services/dwarfcache.c index 2c61ee68..c75391f1 100644 --- a/services/dwarfcache.c +++ b/services/dwarfcache.c @@ -43,31 +43,6 @@ static ObjectInfo * sPrevSibling; static int sCloseListenerOK = 0; -unsigned calc_symbol_name_hash(const char * s) { - unsigned h = 0; - while (*s) { - unsigned g; - if (s[0] == '@' && s[1] == '@') break; - h = (h << 4) + (unsigned char)*s++; - g = h & 0xf0000000; - if (g) h ^= g >> 24; - h &= ~g; - } - return h % SYM_HASH_SIZE; -} - -int cmp_symbol_names(const char * x, const char * y) { - while (*x && *x == *y) { - x++; - y++; - } - if (*x == 0 && *y == '@' && y[1] == '@') return 0; - if (*y == 0 && *x == '@' && x[1] == '@') return 0; - if (*x < *y) return -1; - if (*x > *y) return +1; - return 0; -} - unsigned calc_file_name_hash(const char * s) { unsigned l = strlen(s); unsigned h = 0; @@ -84,54 +59,6 @@ unsigned calc_file_name_hash(const char * s) { return h; } -void unpack_elf_symbol_info(SymbolSection * section, U4_T index, SymbolInfo * info) { - memset(info, 0, sizeof(SymbolInfo)); - if (index >= section->mSymCount) str_exception(ERR_INV_FORMAT, "Invalid ELF symbol index"); - info->mSymSection = section; - if (section->mFile->elf64) { - Elf64_Sym s = ((Elf64_Sym *)section->mSymPool)[index]; - if (section->mFile->byte_swap) { - SWAP(s.st_name); - SWAP(s.st_shndx); - SWAP(s.st_size); - SWAP(s.st_value); - } - info->mSectionIndex = s.st_shndx; - if (s.st_shndx > 0 && s.st_shndx < section->mFile->section_cnt) { - info->mSection = section->mFile->sections + s.st_shndx; - } - if (s.st_name > 0) { - if (s.st_name >= section->mStrPoolSize) str_exception(ERR_INV_FORMAT, "Invalid ELF string pool index"); - info->mName = section->mStrPool + s.st_name; - } - info->mBind = ELF64_ST_BIND(s.st_info); - info->mType = ELF64_ST_TYPE(s.st_info); - info->mValue = s.st_value; - info->mSize = s.st_size; - } - else { - Elf32_Sym s = ((Elf32_Sym *)section->mSymPool)[index]; - if (section->mFile->byte_swap) { - SWAP(s.st_name); - SWAP(s.st_shndx); - SWAP(s.st_size); - SWAP(s.st_value); - } - info->mSectionIndex = s.st_shndx; - if (s.st_shndx > 0 && s.st_shndx < section->mFile->section_cnt) { - info->mSection = section->mFile->sections + s.st_shndx; - } - if (s.st_name > 0) { - if (s.st_name >= section->mStrPoolSize) str_exception(ERR_INV_FORMAT, "Invalid ELF string pool index"); - info->mName = section->mStrPool + s.st_name; - } - info->mBind = ELF32_ST_BIND(s.st_info); - info->mType = ELF32_ST_TYPE(s.st_info); - info->mValue = s.st_value; - info->mSize = s.st_size; - } -} - ObjectInfo * find_object(DWARFCache * Cache, U8_T ID) { if (Cache->mObjectHash != NULL) { ObjectInfo * Info = Cache->mObjectHash[OBJ_HASH(Cache, ID)]; @@ -381,37 +308,6 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { } } -static void load_symbol_tables(void) { - unsigned idx; - ELF_File * file = sCache->mFile; - unsigned sym_size = file->elf64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym); - - for (idx = 1; idx < file->section_cnt; idx++) { - ELF_Section * sym_sec = file->sections + idx; - if (sym_sec->size == 0) continue; - if (sym_sec->type == SHT_SYMTAB) { - ELF_Section * str_sec; - SymbolSection * tbl = (SymbolSection *)loc_alloc_zero(sizeof(SymbolSection)); - if (sCache->mSymSectionsCnt >= sCache->mSymSectionsMax) { - sCache->mSymSectionsMax = sCache->mSymSectionsMax == 0 ? 16 : sCache->mSymSectionsMax * 2; - sCache->mSymSections = (SymbolSection **)loc_realloc(sCache->mSymSections, sizeof(SymbolSection *) * sCache->mSymSectionsMax); - } - tbl->mIndex = sCache->mSymSectionsCnt++; - sCache->mSymSections[tbl->mIndex] = tbl; - if (sym_sec->link == 0 || sym_sec->link >= file->section_cnt) exception(EINVAL); - str_sec = file->sections + sym_sec->link; - if (elf_load(sym_sec) < 0) exception(errno); - if (elf_load(str_sec) < 0) exception(errno); - tbl->mFile = file; - tbl->mStrPool = (char *)str_sec->data; - tbl->mStrPoolSize = (size_t)str_sec->size; - tbl->mSymPool = (ElfX_Sym *)sym_sec->data; - tbl->mSymPoolSize = (size_t)sym_sec->size; - tbl->mSymCount = (unsigned)(sym_sec->size / sym_size); - } - } -} - static int cmp_addr_ranges(const void * x, const void * y) { UnitAddressRange * rx = (UnitAddressRange *)x; UnitAddressRange * ry = (UnitAddressRange *)y; @@ -837,7 +733,6 @@ static void free_unit_cache(CompUnit * Unit) { static void free_dwarf_cache(ELF_File * file) { DWARFCache * Cache = (DWARFCache *)file->dwarf_dt_cache; if (Cache != NULL) { - unsigned i; assert(Cache->magic == DWARF_CACHE_MAGIC); Cache->magic = 0; while (Cache->mCompUnits != NULL) { @@ -846,19 +741,12 @@ static void free_dwarf_cache(ELF_File * file) { free_unit_cache(Unit); loc_free(Unit); } - for (i = 0; i < Cache->mSymSectionsCnt; i++) { - SymbolSection * tbl = Cache->mSymSections[i]; - loc_free(tbl->mSymNamesHash); - loc_free(tbl->mSymNamesNext); - loc_free(tbl); - } while (Cache->mObjectList != NULL) { ObjectArray * Buf = Cache->mObjectList; Cache->mObjectList = Buf->mNext; loc_free(Buf); } loc_free(Cache->mObjectHash); - loc_free(Cache->mSymSections); loc_free(Cache->mAddrRanges); loc_free(Cache->mFrameInfoRanges); loc_free(Cache->mPubNames.mHash); @@ -884,7 +772,6 @@ DWARFCache * get_dwarf_cache(ELF_File * file) { sCache->mObjectArrayPos = OBJECT_ARRAY_SIZE; if (set_trap(&trap)) { dio_LoadAbbrevTable(file); - load_symbol_tables(); load_debug_sections(); load_addr_ranges(); clear_trap(&trap); @@ -1130,7 +1017,7 @@ void load_line_numbers(CompUnit * Unit) { DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache; ELF_Section * LineInfoSection = Unit->mDesc.mVersion <= 1 ? Cache->mDebugLineV1 : Cache->mDebugLine; if (LineInfoSection == NULL) return; - if (Unit->mStates != NULL || Unit->mFiles != NULL || Unit->mDirs != NULL) return; + if (Unit->mLineInfoLoaded) return; if (elf_load(LineInfoSection)) exception(errno); dio_EnterSection(&Unit->mDesc, LineInfoSection, Unit->mLineInfoOffs); if (set_trap(&trap)) { @@ -1161,6 +1048,7 @@ void load_line_numbers(CompUnit * Unit) { } dio_ExitSection(); compute_reverse_lookup_indices(Unit); + Unit->mLineInfoLoaded = 1; clear_trap(&trap); } else { diff --git a/services/dwarfcache.h b/services/dwarfcache.h index 3cd89a1d..a5980fed 100644 --- a/services/dwarfcache.h +++ b/services/dwarfcache.h @@ -57,29 +57,6 @@ struct FileInfo { #define SYM_HASH_SIZE (32 * MEM_USAGE_FACTOR - 1) -struct SymbolSection { - ELF_File * mFile; - unsigned mIndex; - char * mStrPool; - size_t mStrPoolSize; - unsigned mSymCount; - ElfX_Sym * mSymPool; /* pointer to ELF section data: array of Elf32_Sym or Elf64_Sym */ - size_t mSymPoolSize; - unsigned * mSymNamesHash; - unsigned * mSymNamesNext; -}; - -struct SymbolInfo { - SymbolSection * mSymSection; - U4_T mSectionIndex; - ELF_Section * mSection; - char * mName; - U1_T mBind; - U1_T mType; - U8_T mValue; - U8_T mSize; -}; - #define TAG_fund_type 0x2000 struct ObjectInfo { @@ -174,6 +151,7 @@ struct CompUnit { U4_T mStatesMax; LineNumbersState * mStates; LineNumbersState ** mStatesIndex; + U1_T mLineInfoLoaded; CompUnit * mBaseTypes; @@ -207,9 +185,6 @@ struct DWARFCache { ELF_Section * mDebugRanges; ELF_Section * mDebugFrame; ELF_Section * mEHFrame; - SymbolSection ** mSymSections; - unsigned mSymSectionsCnt; - unsigned mSymSectionsMax; ObjectInfo ** mObjectHash; unsigned mObjectHashSize; ObjectArray * mObjectList; @@ -227,12 +202,6 @@ struct DWARFCache { /* Return DWARF cache for given file, create and populate the cache if needed, throw an exception if error */ extern DWARFCache * get_dwarf_cache(ELF_File * file); -/* Return symbol name hash. The hash is used to build mSymNamesHash table. */ -extern unsigned calc_symbol_name_hash(const char * s); - -/* Compare symbol names. */ -extern int cmp_symbol_names(const char * x, const char * y); - /* Return file name hash. The hash is used to search FileInfo. */ extern unsigned calc_file_name_hash(const char * s); @@ -245,9 +214,6 @@ extern ObjectInfo * find_object(DWARFCache * cache, U8_T ID); /* Search and return first compilation unit address range in given link-time address range 'addr_min'..'addr_max'. */ extern UnitAddressRange * find_comp_unit_addr_range(DWARFCache * cache, ContextAddress addr_min, ContextAddress addr_max); -/* Get SymbolInfo */ -extern void unpack_elf_symbol_info(SymbolSection * section, U4_T index, SymbolInfo * info); - /* * Read and evaluate a property of a DWARF object, perform ELF relocations if any. * FORM_ADDR values are mapped to run-time address space. diff --git a/services/dwarfio.c b/services/dwarfio.c index 1461f38f..8830b55d 100644 --- a/services/dwarfio.c +++ b/services/dwarfio.c @@ -333,7 +333,7 @@ static U1_T * dio_LoadStringTable(U4_T * StringTableSize) { } static void dio_ReadFormAddr(void) { - dio_gFormData = dio_ReadAddress(&dio_gFormSection); + dio_gFormData = dio_ReadAddressX(&dio_gFormSection, sAddressSize); dio_gFormDataSize = sAddressSize; } diff --git a/services/linenumbers_elf.c b/services/linenumbers_elf.c index 37ac75f6..1deefd87 100644 --- a/services/linenumbers_elf.c +++ b/services/linenumbers_elf.c @@ -228,7 +228,7 @@ int line_to_address(Context * ctx, char * file_name, int line, int column, LineN unsigned j; CompUnit * unit = info->mCompUnit; assert(unit->mFile == file); - load_line_numbers(unit); + if (!unit->mLineInfoLoaded) load_line_numbers(unit); for (j = 0; j < unit->mFilesCnt; j++) { FileInfo * f = unit->mFiles + j; if (f->mNameHash != h) continue; @@ -268,7 +268,7 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L UnitAddressRange * range = elf_find_unit(ctx, addr0, addr1, &range_rt_addr); if (range == NULL) break; assert(range_rt_addr != 0); - load_line_numbers(range->mUnit); + if (!range->mUnit->mLineInfoLoaded) load_line_numbers(range->mUnit); if (range->mUnit->mStatesCnt >= 2) { CompUnit * unit = range->mUnit; unsigned l = 0; diff --git a/services/symbols_elf.c b/services/symbols_elf.c index 81ae587c..614cba8d 100644 --- a/services/symbols_elf.c +++ b/services/symbols_elf.c @@ -49,7 +49,7 @@ struct Symbol { unsigned magic; ObjectInfo * obj; ObjectInfo * var; /* 'this' object if the symbol represents implicit 'this' reference */ - SymbolSection * tbl; + ELF_Section * tbl; ContextAddress address; int sym_class; Context * ctx; @@ -97,28 +97,28 @@ static int get_sym_context(Context * ctx, int frame, ContextAddress addr) { } /* Map ELF symbol table entry value to run-time address in given context address space */ -static int syminfo2address(Context * ctx, SymbolInfo * info, ContextAddress * address) { - switch (info->mType) { +static int syminfo2address(Context * ctx, ELF_SymbolInfo * info, ContextAddress * address) { + switch (info->type) { case STT_OBJECT: case STT_FUNC: { - U8_T value = info->mValue; - ELF_File * file = info->mSymSection->mFile; + U8_T value = info->value; + ELF_File * file = info->section->file; ELF_Section * sec = NULL; - if (info->mSectionIndex == SHN_UNDEF) { + if (info->section_index == SHN_UNDEF) { errno = ERR_INV_ADDRESS; return -1; } - if (info->mSectionIndex == SHN_ABS) { + if (info->section_index == SHN_ABS) { *address = (ContextAddress)value; return 0; } - if (info->mSectionIndex == SHN_COMMON) { + if (info->section_index == SHN_COMMON) { errno = ERR_INV_ADDRESS; return -1; } - if (file->type == ET_REL && info->mSection != NULL) { - sec = info->mSection; + if (file->type == ET_REL && info->section != NULL) { + sec = info->section; value += sec->addr; } *address = elf_map_to_run_time_address(ctx, file, sec, (ContextAddress)value); @@ -390,17 +390,19 @@ static int find_by_name_in_pub_names(DWARFCache * cache, PubNamesTable * tbl, ch return 0; } -static void create_symbol_names_hash(SymbolSection * tbl) { +static void create_symbol_names_hash(ELF_Section * tbl) { unsigned i; - tbl->mSymNamesHash = (unsigned *)loc_alloc_zero(SYM_HASH_SIZE * sizeof(unsigned)); - tbl->mSymNamesNext = (unsigned *)loc_alloc_zero(tbl->mSymCount * sizeof(unsigned)); - for (i = 0; i < tbl->mSymCount; i++) { - SymbolInfo sym; + unsigned sym_size = tbl->file->elf64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym); + unsigned sym_cnt = (unsigned)(tbl->size / sym_size); + tbl->sym_names_hash = (unsigned *)loc_alloc_zero(SYM_HASH_SIZE * sizeof(unsigned)); + tbl->sym_names_next = (unsigned *)loc_alloc_zero(sym_cnt * sizeof(unsigned)); + for (i = 0; i < sym_cnt; i++) { + ELF_SymbolInfo sym; unpack_elf_symbol_info(tbl, i, &sym); - if (sym.mBind == STB_GLOBAL && sym.mName != NULL && sym.mSectionIndex != SHN_UNDEF) { - unsigned h = calc_symbol_name_hash(sym.mName); - tbl->mSymNamesNext[i] = tbl->mSymNamesHash[h]; - tbl->mSymNamesHash[h] = i; + if (sym.bind == STB_GLOBAL && sym.name != NULL && sym.section_index != SHN_UNDEF) { + unsigned h = calc_symbol_name_hash(sym.name); + tbl->sym_names_next[i] = tbl->sym_names_hash[h]; + tbl->sym_names_hash[h] = i; } } } @@ -410,19 +412,20 @@ static int find_by_name_in_sym_table(DWARFCache * cache, char * name, Symbol ** unsigned h = calc_symbol_name_hash(name); unsigned cnt = 0; Context * prs = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS); - while (m < cache->mSymSectionsCnt) { + for (m = 1; m < cache->mFile->section_cnt; m++) { unsigned n; - SymbolSection * tbl = cache->mSymSections[m]; - if (tbl->mSymNamesHash == NULL) create_symbol_names_hash(tbl); - n = tbl->mSymNamesHash[h]; + ELF_Section * tbl = cache->mFile->sections + m; + if (tbl->sym_count == 0) continue; + if (tbl->sym_names_hash == NULL) create_symbol_names_hash(tbl); + n = tbl->sym_names_hash[h]; while (n) { - SymbolInfo sym_info; + ELF_SymbolInfo sym_info; unpack_elf_symbol_info(tbl, n, &sym_info); - if (cmp_symbol_names(name, sym_info.mName) == 0) { + if (cmp_symbol_names(name, sym_info.name) == 0) { ContextAddress addr = 0; if (syminfo2address(prs, &sym_info, &addr) == 0) { int found = 0; - if (sym_info.mSectionIndex != SHN_ABS) { + if (sym_info.section_index != SHN_ABS) { UnitAddressRange * range = elf_find_unit(sym_ctx, addr, addr, NULL); if (range != NULL) { ObjectInfo * obj = range->mUnit->mObject->mChildren; @@ -450,7 +453,7 @@ static int find_by_name_in_sym_table(DWARFCache * cache, char * name, Symbol ** sym->ctx = prs; sym->tbl = tbl; sym->index = n; - switch (sym_info.mType) { + switch (sym_info.type) { case STT_FUNC: sym->sym_class = SYM_CLASS_FUNCTION; break; @@ -463,9 +466,8 @@ static int find_by_name_in_sym_table(DWARFCache * cache, char * name, Symbol ** } } } - n = tbl->mSymNamesNext[n]; + n = tbl->sym_names_next[n]; } - m++; } return cnt == 1; } @@ -656,137 +658,6 @@ int find_symbol_in_scope(Context * ctx, int frame, ContextAddress ip, Symbol * s return 0; } -static int section_symbol_comparator(const void * x, const void * y) { - ELF_SecSymbol * rx = (ELF_SecSymbol *)x; - ELF_SecSymbol * ry = (ELF_SecSymbol *)y; - if (rx->address < ry->address) return -1; - if (rx->address > ry->address) return +1; - return 0; -} - -static void create_symbol_addr_search_index(DWARFCache * cache, ELF_Section * sec) { - int elf64 = cache->mFile->elf64; - int swap = cache->mFile->byte_swap; - int rel = cache->mFile->type == ET_REL; - unsigned m = 0; - - sec->symbols_max = (unsigned)(sec->size / 16) + 16; - sec->symbols = (ELF_SecSymbol *)loc_alloc(sec->symbols_max * sizeof(ELF_SecSymbol)); - - while (m < cache->mSymSectionsCnt) { - SymbolSection * tbl = cache->mSymSections[m]; - unsigned n = 1; - while (n < tbl->mSymCount) { - U8_T addr = 0; - if (elf64) { - Elf64_Sym s = ((Elf64_Sym *)tbl->mSymPool)[n]; - if (swap) SWAP(s.st_shndx); - if (s.st_shndx == sec->index) { - switch (ELF64_ST_TYPE(s.st_info)) { - case STT_OBJECT: - case STT_FUNC: - if (swap) SWAP(s.st_value); - addr = s.st_value; - if (rel) addr += sec->addr; - break; - } - } - } - else { - Elf32_Sym s = ((Elf32_Sym *)tbl->mSymPool)[n]; - if (swap) SWAP(s.st_shndx); - if (s.st_shndx == sec->index) { - switch (ELF32_ST_TYPE(s.st_info)) { - case STT_OBJECT: - case STT_FUNC: - if (swap) SWAP(s.st_value); - addr = s.st_value; - if (rel) addr += sec->addr; - break; - } - } - } - if (addr != 0) { - ELF_SecSymbol * s = NULL; - if (sec->symbols_cnt >= sec->symbols_max) { - sec->symbols_max = sec->symbols_max * 3 / 2; - sec->symbols = (ELF_SecSymbol *)loc_realloc(sec->symbols, sec->symbols_max * sizeof(ELF_SecSymbol)); - } - s = sec->symbols + sec->symbols_cnt++; - s->address = addr; - s->parent = tbl; - s->index = n; - } - n++; - } - m++; - } - - qsort(sec->symbols, sec->symbols_cnt, sizeof(ELF_SecSymbol), section_symbol_comparator); -} - -static int find_by_addr_in_sym_table(DWARFCache * cache, ContextAddress addr, Symbol ** res) { - unsigned m; - unsigned cnt = 0; - Context * prs = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS); - ELF_File * file = cache->mFile; - - for (m = 1; m < file->section_cnt; m++) { - ContextAddress sec_rt_addr; - ContextAddress sym_lt_addr; - ELF_Section * sec = file->sections + m; - if (sec->size == 0) continue; - if ((sec->flags & SHF_ALLOC) == 0) continue; - if (sec->type != SHT_PROGBITS && sec->type != SHT_NOBITS) continue; - sec_rt_addr = elf_map_to_run_time_address(prs, file, file->type == ET_REL ? sec : NULL, sec->addr); - if (addr >= sec_rt_addr && addr < sec_rt_addr + sec->size) { - unsigned l, h; - if (sec->symbols == NULL) create_symbol_addr_search_index(cache, sec); - sym_lt_addr = addr - sec_rt_addr + sec->addr; - l = 0; - h = sec->symbols_cnt; - while (l < h) { - unsigned k = (h + l) / 2; - ELF_SecSymbol * info = sec->symbols + k; - if (info->address > sym_lt_addr) { - h = k; - } - else { - ContextAddress next = k < sec->symbols_cnt - 1 ? - (info + 1)->address : sec->addr + sec->size; - assert(next >= info->address); - if (next <= sym_lt_addr) { - l = k + 1; - } - else { - SymbolInfo sym_info; - Symbol * sym = alloc_symbol(); - SymbolSection * tbl = (SymbolSection *)info->parent; - unpack_elf_symbol_info(tbl, info->index, &sym_info); - sym->frame = STACK_NO_FRAME; - sym->ctx = prs; - sym->tbl = tbl; - sym->index = info->index; - switch (sym_info.mType) { - case STT_FUNC: - sym->sym_class = SYM_CLASS_FUNCTION; - break; - case STT_OBJECT: - sym->sym_class = SYM_CLASS_REFERENCE; - break; - } - *res = sym; - cnt++; - break; - } - } - } - } - } - - return cnt == 1; -} - static int find_by_addr_in_unit(ObjectInfo * obj, int level, ContextAddress addr, Symbol ** res) { while (obj != NULL) { switch (obj->mTag) { @@ -832,28 +703,41 @@ static int find_by_addr_in_unit(ObjectInfo * obj, int level, ContextAddress addr } static int find_by_addr_in_sym_tables(ContextAddress addr, Symbol ** res) { - int error = 0; - int found = 0; - ELF_File * file = elf_list_first(sym_ctx, addr, addr); - if (file == NULL) error = errno; - while (error == 0 && file != NULL) { - Trap trap; - if (set_trap(&trap)) { - DWARFCache * cache = get_dwarf_cache(file); - found = find_by_addr_in_sym_table(cache, addr, res); - clear_trap(&trap); - } - else { - error = trap.error; + ELF_File * file = NULL; + ELF_Section * section = NULL; + ELF_SymbolInfo sym_info; + ContextAddress lt_addr = elf_map_to_link_time_address(sym_ctx, addr, &file, §ion); + elf_find_symbol_by_address(section, lt_addr, &sym_info); + while (sym_info.sym_section != NULL) { + int sym_class = SYM_CLASS_UNKNOWN; + assert(sym_info.section == section); + switch (sym_info.type) { + case STT_FUNC: + sym_class = SYM_CLASS_FUNCTION; + break; + case STT_OBJECT: + sym_class = SYM_CLASS_REFERENCE; break; } - if (found) break; - file = elf_list_next(sym_ctx); - if (file == NULL) error = errno; + if (sym_class != SYM_CLASS_UNKNOWN) { + ContextAddress sym_addr = sym_info.value; + if (file->type == ET_REL) sym_addr += section->addr; + assert(sym_addr <= lt_addr); + if (sym_addr + sym_info.size > lt_addr) { + Symbol * sym = alloc_symbol(); + sym->frame = STACK_NO_FRAME; + sym->ctx = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS); + sym->tbl = sym_info.sym_section; + sym->index = sym_info.sym_index; + sym->sym_class = sym_class; + *res = sym; + return 1; + } + return 0; + } + elf_prev_symbol_by_address(&sym_info); } - elf_list_done(sym_ctx); - if (error) exception(error); - return found; + return 0; } int find_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol ** res) { @@ -935,10 +819,10 @@ const char * symbol2id(const Symbol * sym) { unsigned tbl_index = 0; int frame = sym->frame; if (sym->obj != NULL) file = sym->obj->mCompUnit->mFile; - if (sym->tbl != NULL) file = sym->tbl->mFile; + if (sym->tbl != NULL) file = sym->tbl->file; if (sym->obj != NULL) obj_index = sym->obj->mID; if (sym->var != NULL) var_index = sym->var->mID; - if (sym->tbl != NULL) tbl_index = sym->tbl->mIndex + 1; + if (sym->tbl != NULL) tbl_index = sym->tbl->index; if (frame == STACK_TOP_FRAME) frame = get_top_frame(sym->ctx); assert(sym->var == NULL || sym->var->mCompUnit->mFile == file); snprintf(id, sizeof(id), "@S%X.%lX.%lX.%"PRIX64".%"PRIX64".%"PRIX64".%X.%d.%X.%X.%"PRIX64".%s", @@ -1050,8 +934,8 @@ int id2symbol(const char * id, Symbol ** res) { if (sym->var == NULL) exception(ERR_INV_CONTEXT); } if (tbl_index) { - if (tbl_index > cache->mSymSectionsCnt) exception(ERR_INV_CONTEXT); - sym->tbl = cache->mSymSections[tbl_index - 1]; + if (tbl_index >= file->section_cnt) exception(ERR_INV_CONTEXT); + sym->tbl = file->sections + tbl_index; } clear_trap(&trap); return 0; @@ -1154,10 +1038,10 @@ void ini_symbols_lib(void) { static ELF_File * file; static DWARFCache * cache; static ObjectInfo * obj; -static SymbolSection * tbl; +static ELF_Section * tbl; static unsigned sym_index; static unsigned dimension; -static SymbolInfo * sym_info; +static ELF_SymbolInfo * sym_info; static int unpack(const Symbol * sym) { assert(sym->base == NULL); @@ -1172,7 +1056,7 @@ static int unpack(const Symbol * sym) { dimension = sym->dimension; sym_info = NULL; if (obj != NULL) file = obj->mCompUnit->mFile; - if (tbl != NULL) file = tbl->mFile; + if (tbl != NULL) file = tbl->file; if (file != NULL) { cache = (DWARFCache *)file->dwarf_dt_cache; if (cache == NULL || cache->magic != DWARF_CACHE_MAGIC) { @@ -1180,7 +1064,7 @@ static int unpack(const Symbol * sym) { return -1; } if (tbl != NULL) { - static SymbolInfo info; + static ELF_SymbolInfo info; unpack_elf_symbol_info(tbl, sym_index, &info); sym_info = &info; } @@ -1395,7 +1279,7 @@ int get_symbol_type_class(const Symbol * sym, int * type_class) { break; } } - if (sym_info != NULL && sym_info->mType == STT_FUNC) { + if (sym_info != NULL && sym_info->type == STT_FUNC) { *type_class = TYPE_CLASS_FUNCTION; return 0; } @@ -1419,9 +1303,9 @@ int get_symbol_name(const Symbol * sym, char ** name) { *name = sym->obj->mName; } else if (sym->tbl != NULL) { - static SymbolInfo info; + ELF_SymbolInfo info; unpack_elf_symbol_info(sym->tbl, sym->index, &info); - *name = info.mName; + *name = info.name; } else { *name = NULL; @@ -1509,7 +1393,7 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { clear_trap(&trap); } else if (sym_info != NULL) { - *size = (ContextAddress)sym_info->mSize; + *size = (ContextAddress)sym_info->size; } return 0; } diff --git a/services/tcf_elf.c b/services/tcf_elf.c index e1fed801..dc6b582d 100644 --- a/services/tcf_elf.c +++ b/services/tcf_elf.c @@ -92,7 +92,7 @@ static void elf_dispose(ELF_File * file) { } #endif loc_free(s->data); - loc_free(s->symbols); + loc_free(s->sym_addr_table); } loc_free(file->sections); } @@ -440,6 +440,7 @@ static ELF_File * create_elf_cache(const char * file_name) { sec->link = shdr.sh_link; sec->info = shdr.sh_info; sec->entsize = shdr.sh_entsize; + if (sec->type == SHT_SYMTAB) sec->sym_count = (unsigned)(sec->size / sizeof(Elf32_Sym)); cnt++; } } @@ -551,6 +552,7 @@ static ELF_File * create_elf_cache(const char * file_name) { sec->link = shdr.sh_link; sec->info = shdr.sh_info; sec->entsize = (U4_T)shdr.sh_entsize; + if (sec->type == SHT_SYMTAB) sec->sym_count = (unsigned)(sec->size / sizeof(Elf64_Sym)); cnt++; } } @@ -1104,7 +1106,6 @@ static int get_global_symbol_address(Context * ctx, ELF_File * file, const char for (i = 1; i < file->section_cnt; i++) { ELF_Section * sec = file->sections + i; if (sec->size == 0) continue; - if (sec->name == NULL) continue; if (sec->type == SHT_SYMTAB) { ELF_Section * str = NULL; if (sec->link == 0 || sec->link >= file->section_cnt) { @@ -1153,12 +1154,12 @@ static int get_global_symbol_address(Context * ctx, ELF_File * file, const char } int elf_read_memory_word(Context * ctx, ELF_File * file, ContextAddress addr, ContextAddress * word) { - U1_T buf[8]; size_t size = file->elf64 ? 8 : 4; size_t i = 0; U8_T n = 0; + U1_T buf[8]; - if (ctx->mem_access == 0 && ctx->mem != NULL) ctx = ctx->mem; + if (ctx->mem_access == 0) ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS); if (context_read_mem(ctx, addr, buf, size) < 0) return -1; for (i = 0; i < size; i++) { n = (n << 8) | buf[file->big_endian ? i : size - i - 1]; @@ -1188,6 +1189,210 @@ ContextAddress elf_get_debug_structure_address(Context * ctx, ELF_File ** file_p return addr; } +/************************ ELF symbol tables *****************************************/ + +unsigned calc_symbol_name_hash(const char * s) { + unsigned h = 0; + while (*s) { + unsigned g; + if (s[0] == '@' && s[1] == '@') break; + h = (h << 4) + (unsigned char)*s++; + g = h & 0xf0000000; + if (g) h ^= g >> 24; + h &= ~g; + } + return h % SYM_HASH_SIZE; +} + +int cmp_symbol_names(const char * x, const char * y) { + while (*x && *x == *y) { + x++; + y++; + } + if (*x == 0 && *y == '@' && y[1] == '@') return 0; + if (*y == 0 && *x == '@' && x[1] == '@') return 0; + if (*x < *y) return -1; + if (*x > *y) return +1; + return 0; +} + +void unpack_elf_symbol_info(ELF_Section * sym_sec, U4_T index, ELF_SymbolInfo * info) { + ELF_File * file = sym_sec->file; + ELF_Section * str_sec = NULL; + char * str_pool = NULL; + size_t str_pool_size = 0; + memset(info, 0, sizeof(ELF_SymbolInfo)); + if (index >= sym_sec->sym_count) str_exception(ERR_INV_FORMAT, "Invalid ELF symbol index"); + if (sym_sec->link == 0 || sym_sec->link >= file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid symbol section"); + str_sec = file->sections + sym_sec->link; + if (elf_load(sym_sec) < 0) exception(errno); + if (elf_load(str_sec) < 0) exception(errno); + str_pool = (char *)str_sec->data; + str_pool_size = (size_t)str_sec->size; + info->sym_section = sym_sec; + info->sym_index = index; + if (file->elf64) { + Elf64_Sym s = ((Elf64_Sym *)sym_sec->data)[index]; + if (file->byte_swap) { + SWAP(s.st_name); + SWAP(s.st_shndx); + SWAP(s.st_size); + SWAP(s.st_value); + } + info->section_index = s.st_shndx; + if (s.st_shndx > 0 && s.st_shndx < file->section_cnt) { + info->section = file->sections + s.st_shndx; + } + if (s.st_name > 0) { + if (s.st_name >= str_pool_size) str_exception(ERR_INV_FORMAT, "Invalid ELF string pool index"); + info->name = str_pool + s.st_name; + } + info->bind = ELF64_ST_BIND(s.st_info); + info->type = ELF64_ST_TYPE(s.st_info); + info->value = s.st_value; + info->size = s.st_size; + } + else { + Elf32_Sym s = ((Elf32_Sym *)sym_sec->data)[index]; + if (file->byte_swap) { + SWAP(s.st_name); + SWAP(s.st_shndx); + SWAP(s.st_size); + SWAP(s.st_value); + } + info->section_index = s.st_shndx; + if (s.st_shndx > 0 && s.st_shndx < file->section_cnt) { + info->section = file->sections + s.st_shndx; + } + if (s.st_name > 0) { + if (s.st_name >= str_pool_size) str_exception(ERR_INV_FORMAT, "Invalid ELF string pool index"); + info->name = str_pool + s.st_name; + } + info->bind = ELF32_ST_BIND(s.st_info); + info->type = ELF32_ST_TYPE(s.st_info); + info->value = s.st_value; + info->size = s.st_size; + } +} + +static int section_symbol_comparator(const void * x, const void * y) { + ELF_SecSymbol * rx = (ELF_SecSymbol *)x; + ELF_SecSymbol * ry = (ELF_SecSymbol *)y; + if (rx->address < ry->address) return -1; + if (rx->address > ry->address) return +1; + return 0; +} + +static void create_symbol_addr_search_index(ELF_Section * sec) { + ELF_File * file = sec->file; + int elf64 = file->elf64; + int swap = file->byte_swap; + int rel = file->type == ET_REL; + unsigned m = 0; + + sec->sym_addr_max = (unsigned)(sec->size / 16) + 16; + sec->sym_addr_table = (ELF_SecSymbol *)loc_alloc(sec->sym_addr_max * sizeof(ELF_SecSymbol)); + + for (m = 1; m < file->section_cnt; m++) { + unsigned n = 1; + ELF_Section * tbl = file->sections + m; + if (tbl->sym_count == 0) continue; + if (elf_load(tbl) < 0) exception(errno); + while (n < tbl->sym_count) { + int add = 0; + U8_T addr = 0; + if (elf64) { + Elf64_Sym s = ((Elf64_Sym *)tbl->data)[n]; + if (swap) SWAP(s.st_shndx); + if (s.st_shndx == sec->index) { + if (swap) SWAP(s.st_value); + addr = s.st_value; + if (rel) addr += sec->addr; + add = 1; + } + } + else { + Elf32_Sym s = ((Elf32_Sym *)tbl->data)[n]; + if (swap) SWAP(s.st_shndx); + if (s.st_shndx == sec->index) { + if (swap) SWAP(s.st_value); + addr = s.st_value; + if (rel) addr += sec->addr; + add = 1; + } + } + if (add) { + ELF_SecSymbol * s = NULL; + if (sec->sym_addr_cnt >= sec->sym_addr_max) { + sec->sym_addr_max = sec->sym_addr_max * 3 / 2; + sec->sym_addr_table = (ELF_SecSymbol *)loc_realloc(sec->sym_addr_table, sec->sym_addr_max * sizeof(ELF_SecSymbol)); + } + s = sec->sym_addr_table + sec->sym_addr_cnt++; + s->address = addr; + s->section = tbl; + s->index = n; + } + n++; + } + } + + qsort(sec->sym_addr_table, sec->sym_addr_cnt, sizeof(ELF_SecSymbol), section_symbol_comparator); +} + +void elf_find_symbol_by_address(ELF_Section * sec, ContextAddress addr, ELF_SymbolInfo * sym_info) { + unsigned l = 0; + unsigned h = 0; + memset(sym_info, 0, sizeof(ELF_SymbolInfo)); + if (sec == NULL || addr < sec->addr) return; + if (sec->sym_addr_table == NULL) create_symbol_addr_search_index(sec); + h = sec->sym_addr_cnt; + while (l < h) { + unsigned k = (h + l) / 2; + ELF_SecSymbol * info = sec->sym_addr_table + k; + if (info->address > addr) { + h = k; + } + else { + ContextAddress next = k < sec->sym_addr_cnt - 1 ? + (info + 1)->address : sec->addr + sec->size; + assert(next >= info->address); + if (next <= addr) { + l = k + 1; + } + else { + unpack_elf_symbol_info(info->section, info->index, sym_info); + assert(sym_info->section == sec); + sym_info->addr_index = k; + return; + } + } + } +} + +void elf_prev_symbol_by_address(ELF_SymbolInfo * sym_info) { + if (sym_info->section != NULL && sym_info->addr_index > 0) { + U4_T index = sym_info->addr_index - 1; + ELF_SecSymbol * info = sym_info->section->sym_addr_table + index; + unpack_elf_symbol_info(info->section, info->index, sym_info); + sym_info->addr_index = index; + } + else { + memset(sym_info, 0, sizeof(ELF_SymbolInfo)); + } +} + +void elf_next_symbol_by_address(ELF_SymbolInfo * sym_info) { + if (sym_info->section != NULL && sym_info->addr_index + 1 < sym_info->section->sym_addr_cnt) { + U4_T index = sym_info->addr_index + 1; + ELF_SecSymbol * info = sym_info->section->sym_addr_table + index; + unpack_elf_symbol_info(info->section, info->index, sym_info); + sym_info->addr_index = index; + } + else { + memset(sym_info, 0, sizeof(ELF_SymbolInfo)); + } +} + void ini_elf(void) { } diff --git a/services/tcf_elf.h b/services/tcf_elf.h index 5d5efa25..22ef5405 100644 --- a/services/tcf_elf.h +++ b/services/tcf_elf.h @@ -368,6 +368,7 @@ typedef int64_t I8_T; typedef struct ELF_File ELF_File; typedef struct ELF_Section ELF_Section; typedef struct ELF_SecSymbol ELF_SecSymbol; +typedef struct ELF_SymbolInfo ELF_SymbolInfo; typedef struct ELF_PHeader ELF_PHeader; struct ELF_File { @@ -405,11 +406,24 @@ struct ELF_File { }; struct ELF_SecSymbol { - void * parent; + ELF_Section * section; unsigned index; U8_T address; }; +struct ELF_SymbolInfo { + ELF_Section * sym_section; + U4_T sym_index; + unsigned addr_index; + ELF_Section * section; + U4_T section_index; + char * name; + U1_T bind; + U1_T type; + U8_T value; + U8_T size; +}; + struct ELF_Section { ELF_File * file; U4_T index; @@ -430,9 +444,16 @@ struct ELF_Section { int relocate; - ELF_SecSymbol * symbols; - unsigned symbols_cnt; - unsigned symbols_max; + unsigned sym_count; + + /* Symbol by address search index */ + ELF_SecSymbol * sym_addr_table; + unsigned sym_addr_cnt; + unsigned sym_addr_max; + + /* Symbol by name search index */ + unsigned * sym_names_hash; + unsigned * sym_names_next; }; struct ELF_PHeader { @@ -528,6 +549,34 @@ extern ContextAddress elf_get_debug_structure_address(Context * ctx, ELF_File ** */ extern struct UnitAddressRange * elf_find_unit(Context * ctx, ContextAddress addr_min, ContextAddress addr_max, ContextAddress * range_rt_addr); +/* Return symbol name hash. The hash is used to build sym_names_hash table. */ +extern unsigned calc_symbol_name_hash(const char * s); + +/* Compare symbol names. */ +extern int cmp_symbol_names(const char * x, const char * y); + +/* + * Get ELF_SymbolInfo. + * Call exception() on error. + */ +extern void unpack_elf_symbol_info(ELF_Section * section, U4_T index, ELF_SymbolInfo * info); + +/* + * Find ELF symbol by link-time address in a section. + * Return info for nearest symbol at or before given address. + * If not found, set all 'info' fields to zeros. + * Call exception() on error. + */ +extern void elf_find_symbol_by_address(ELF_Section * section, ContextAddress addr, ELF_SymbolInfo * info); + +/* + * Get prev/next ELF symbol by link-time address in a section. + * If not found, set all 'info' fields to zeros. + * Call exception() on error. + */ +extern void elf_prev_symbol_by_address(ELF_SymbolInfo * info); +extern void elf_next_symbol_by_address(ELF_SymbolInfo * info); + /* * Initialize ELF support module. */ |