diff --git a/ipdemo/src/assert.hpp b/ipdemo/src/assert.hpp index 2a8342a..19dba04 100644 --- a/ipdemo/src/assert.hpp +++ b/ipdemo/src/assert.hpp @@ -42,51 +42,61 @@ struct SourceInfo { int line = 0; }; -SourceInfo get_source_info(const char* executable, void* addr) { - char cmd[512]; - snprintf(cmd, sizeof(cmd), "addr2line -f -e %s %p 2>/dev/null", executable, addr); - - FILE* pipe = popen(cmd, "r"); - if (!pipe) return {}; - - SourceInfo info; - char func_buf[1024] = {0}; - char file_buf[1024] = {0}; - int line = 0; - - // Read function name - if (fgets(func_buf, sizeof(func_buf), pipe)) { +std::vector get_source_info_batch(const char* executable, const std::vector& addresses) { + if (addresses.empty()) return {}; + + // Build command with all addresses + std::string cmd = std::string("addr2line -f -e ") + executable; + for (void* addr : addresses) { + char addr_buf[32]; + snprintf(addr_buf, sizeof(addr_buf), " %p", addr); + cmd += addr_buf; + } + cmd += " 2>/dev/null"; + + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) return std::vector(addresses.size()); + + std::vector results(addresses.size()); + char buffer[1024] = {0}; + size_t current_frame = 0; + + // Read function names and file/line info for each address + while (current_frame < addresses.size() && fgets(buffer, sizeof(buffer), pipe)) { // Remove trailing newline - size_t len = strlen(func_buf); - if (len > 0 && func_buf[len-1] == '\n') { - func_buf[len-1] = '\0'; + size_t len = strlen(buffer); + if (len > 0 && buffer[len-1] == '\n') { + buffer[len-1] = '\0'; } - info.function = func_buf; - // Demangle the function name + // Demangle function name int status = 0; - char* demangled = abi::__cxa_demangle(func_buf, nullptr, nullptr, &status); + char* demangled = abi::__cxa_demangle(buffer, nullptr, nullptr, &status); if (demangled) { - info.function = demangled; + results[current_frame].function = demangled; free(demangled); + } else { + results[current_frame].function = buffer; } - } - - // Read file and line number - if (fgets(file_buf, sizeof(file_buf), pipe)) { - char* colon = strchr(file_buf, ':'); - if (colon) { - *colon = '\0'; - info.line = atoi(colon + 1); - - // Extract just the filename - const char* slash = strrchr(file_buf, '/'); - info.file = (slash ? slash + 1 : file_buf); + + // Read file and line number + if (fgets(buffer, sizeof(buffer), pipe)) { + char* colon = strchr(buffer, ':'); + if (colon) { + *colon = '\0'; + results[current_frame].line = atoi(colon + 1); + + // Extract just the filename + const char* slash = strrchr(buffer, '/'); + results[current_frame].file = (slash ? slash + 1 : buffer); + } } + + current_frame++; } - + pclose(pipe); - return info; + return results; } void print_stacktrace() { @@ -110,13 +120,19 @@ void print_stacktrace() { unw_init_local(&cursor, &context); // First pass: collect frames until we find main + std::vector addresses; while (unw_step(&cursor) > 0) { if (unw_get_reg(&cursor, UNW_REG_IP, &pc) != 0 || pc == 0) { break; } + addresses.push_back(reinterpret_cast(pc)); + } - SourceInfo info = get_source_info(exe_path, reinterpret_cast(pc)); - + // Get source info for all addresses in batch + std::vector results = get_source_info_batch(exe_path, addresses); + + // Process results and check for main + for (auto& info : results) { // Stop collecting after main() if (!info.function.empty() && (info.function.find("main") != std::string::npos || @@ -125,7 +141,6 @@ void print_stacktrace() { frames.push_back(info); break; } - frames.push_back(info); }