From 040e258b9e9d42ac7861b93148932fffc8c7863b Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 15 Jun 2025 14:25:41 +1200 Subject: [PATCH] 'Generic Commit' --- tests/ipdemo/src/assert.hpp | 85 ++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/tests/ipdemo/src/assert.hpp b/tests/ipdemo/src/assert.hpp index 016dba6..eb421dd 100644 --- a/tests/ipdemo/src/assert.hpp +++ b/tests/ipdemo/src/assert.hpp @@ -109,8 +109,24 @@ std::vector get_source_info_batch(const char* executable, const std: return results; } +// Helper function to get the program counter (return address) in a portable way +inline void* get_pc() { + void* pc; + #if defined(__aarch64__) || defined(__arm__) + // For ARM/AArch64, we can use the link register (x30 on AArch64, r14 on ARM) + #if defined(__aarch64__) + asm volatile ("mov %0, x30" : "=r" (pc)); + #else + asm volatile ("mov %0, lr" : "=r" (pc)); + #endif + #else + // For x86/x86_64, use __builtin_return_address + pc = __builtin_return_address(0); + #endif + return pc; +} + void print_stacktrace() { - // Simple stacktrace implementation that doesn't segfault std::cerr << colors::yellow << "Stack trace:" << colors::reset << "\n"; char exe_path[1024] = {0}; @@ -121,19 +137,29 @@ void print_stacktrace() { exe_path[count] = '\0'; } - // Get just a couple of stack frames safely std::vector addresses; - void* addr1 = __builtin_return_address(1); // assert_failed - void* addr2 = __builtin_return_address(2); // caller of ASSERT + // Get current frame pointer and return address + void* frame_ptr = __builtin_frame_address(0); + void* return_addr = get_pc(); - // Adjust addresses to point to call site instead of return address - // Subtract a small offset to get the call instruction instead of the return address - if (addr1) { - addresses.push_back(static_cast(addr1) - 1); + // Add current return address + if (return_addr) { + addresses.push_back(return_addr); } - if (addr2) { - addresses.push_back(static_cast(addr2) - 1); + + // Try to walk up the stack if we have a valid frame pointer + if (frame_ptr) { + void** frame = static_cast(frame_ptr); + // Limit the number of frames to prevent potential issues + for (int i = 0; i < 5; ++i) { + // The return address is typically at frame[1] + if (frame[1] == nullptr) break; + addresses.push_back(frame[1]); + // Move to the next frame + if (frame[0] == nullptr) break; + frame = static_cast(frame[0]); + } } if (addresses.empty()) { @@ -144,18 +170,55 @@ void print_stacktrace() { // Get source info std::vector results = get_source_info_batch(exe_path, addresses); + // Filter out frames from assert.hpp + results.erase(std::remove_if(results.begin(), results.end(), + [](const SourceInfo& frame) { + if (frame.file.empty()) return false; + std::string_view file(frame.file); + return file.find("assert.hpp") != std::string_view::npos; + }), + results.end() + ); + + if (results.empty()) { + std::cerr << " " << colors::red << "[no user frames available]" << colors::reset << "\n"; + return; + } + + // First pass: find the maximum function name length for alignment + size_t max_func_length = 0; + for (const auto& frame : results) { + size_t length = frame.function.empty() + ? strlen("[unknown function]") + : frame.function.length(); + if (length > max_func_length) { + max_func_length = length; + } + } + + // Second pass: print with aligned output for (size_t i = 0; i < results.size(); ++i) { const auto& frame = results[i]; std::cerr << " "; + // Print function name with alignment + size_t current_length; if (!frame.function.empty()) { std::cerr << colors::green << frame.function << colors::reset; + current_length = frame.function.length(); } else { std::cerr << colors::red << "[unknown function]" << colors::reset; + current_length = strlen("[unknown function]"); } + // Add padding to align the file/line text if (!frame.file.empty() && frame.line > 0) { - std::cerr << " at " << colors::blue << frame.file << colors::reset + // Calculate padding (minimum 1 space) + size_t padding = (max_func_length > current_length) + ? (max_func_length - current_length + 1) + : 1; + std::cerr << std::string(padding, ' ') + << " " << colors::blue << frame.file << colors::reset << ":" << colors::magenta << frame.line << colors::reset; }