add symbol lookup

This commit is contained in:
Patrick Lipka 2025-08-18 16:48:33 +02:00
parent b9978801a3
commit f284304dd6
1 changed files with 94 additions and 0 deletions

View File

@ -232,4 +232,98 @@ static int parse_elf_symbols(const char* filepath){
}
return 0;
}
// symbol lookup
const char* rvprof_symbols_lookup(void* addr){
if (!g_rvprof.symbols_loaded || g_rvprof.symbols.size == 0){
snprintf(g_tmp_func_name, sizeof(g_tmp_func_name), "func_%p", addr);
return g_tmp_func_name;
}
uintptr_t target_addr = (uintptr_t)addr;
// try to calculate base address offset using known symbols
if (!g_base_address_calculated && g_rvprof.symbols.size > 0){
// use our own profiling functions as reference points since we know their addresses
for (int i = 0; i < g_rvprof.symbols.size; i++){
symbol_entry_t* sym = &g_rvprof.symbols.data[i];
// use rvprof functions as reference points
if (strcmp(sym->name, "__cyg_profile_func_enter") == 0){
calculate_base_address_offset((void*)__cyg_profile_func_enter, sym->addr);
break;
} else if (strcmp(sym->name, "rvprof_init") == 0){
calculate_base_address_offset((void*)rvprof_init, sym->addr);
break;
}
}
// if we still haven't calculated it, try to infer from the lookup addresses
if (!g_base_address_calculated && g_rvprof.symbols.size > 0){
// find the closest symbol and use it to estimate base offset
uintptr_t highest_elf_addr = 0;
for (int i = 0; i < g_rvprof.symbols.size; i++) {
if (g_rvprof.symbols.data[i].addr > highest_elf_addr) {
highest_elf_addr = g_rvprof.symbols.data[i].addr;
}
}
// if the target address is much higher than any ELF address, calculate offset
if (target_addr > highest_elf_addr && (target_addr - highest_elf_addr) > 0x100000){
// estimate base offset
uintptr_t estimated_offset = target_addr - highest_elf_addr;
// round down to page boundary (typically 4KB)
g_base_address_offset = (estimated_offset & ~0xFFF);
g_base_address_calculated = 1;
}
}
}
// adjust target address by base offset
uintptr_t adjusted_addr = target_addr;
if (g_base_address_calculated && g_base_address_offset > 0){
adjusted_addr = target_addr - g_base_address_offset;
}
// binary search for closest symbol
int left = 0;
int right = g_rvprof.symbols.size - 1;
int best_match = -1;
while (left <= right){
int mid = (left + right) / 2;
if (g_rvprof.symbols.data[mid].addr <= adjusted_addr){
best_match = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
// match?
if (best_match >= 0) {
symbol_entry_t* sym = &g_rvprof.symbols.data[best_match];
// if symbol has size info, check if address is within range
if (sym->size > 0) {
if (adjusted_addr >= sym->addr && adjusted_addr < sym->addr + sym->size){
strncpy(g_temp_func_name, sym->name, sizeof(g_temp_func_name) - 1);
g_temp_func_name[sizeof(g_temp_func_name) - 1] = '\0';
return g_temp_func_name;
}
} else {
// no size info, use 64 KB heuristic: must be within reasonable range
if (adjusted_addr >= sym->addr && (adjusted_addr - sym->addr) < 0x10000){
strncpy(g_temp_func_name, sym->name, sizeof(g_temp_func_name) - 1);
g_temp_func_name[sizeof(g_temp_func_name) - 1] = '\0';
return g_temp_func_name;
}
}
}
// fallback to addresses if we cannot resolve symbols
snprintf(g_temp_func_name, sizeof(g_temp_func_name), "func_%p", addr);
return g_temp_func_name;
}