Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2011-06-09 17:49:21 +0000
committereutarass2011-06-09 17:49:21 +0000
commitbf3f8bdf7996ad67f906b10893bc5f75d155028c (patch)
treef8643975e67dcd1d003cba36980542623f55bb8b
parentbfd117c4cad39417f5290b304dd3588fad4ba6f1 (diff)
downloadorg.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.c116
-rw-r--r--services/dwarfcache.h36
-rw-r--r--services/dwarfio.c2
-rw-r--r--services/linenumbers_elf.c4
-rw-r--r--services/symbols_elf.c266
-rw-r--r--services/tcf_elf.c213
-rw-r--r--services/tcf_elf.h57
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, &section);
+ 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.
*/

Back to the top