From f284304dd62aadea65deb3ca5aaf1f16a03e8931 Mon Sep 17 00:00:00 2001 From: Patrick Lipka Date: Mon, 18 Aug 2025 16:48:33 +0200 Subject: [PATCH] add symbol lookup --- src/rvprof_symbols.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/rvprof_symbols.c b/src/rvprof_symbols.c index d130a4d..d166897 100644 --- a/src/rvprof_symbols.c +++ b/src/rvprof_symbols.c @@ -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; } \ No newline at end of file