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<SourceInfo> 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<void*> 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<char*>(addr1) - 1);
+    // Add current return address
+    if (return_addr) {
+        addresses.push_back(return_addr);
     }
-    if (addr2) {
-        addresses.push_back(static_cast<char*>(addr2) - 1);
+    
+    // Try to walk up the stack if we have a valid frame pointer
+    if (frame_ptr) {
+        void** frame = static_cast<void**>(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<void**>(frame[0]);
+        }
     }
     
     if (addresses.empty()) {
@@ -144,18 +170,55 @@ void print_stacktrace() {
     // Get source info
     std::vector<SourceInfo> 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;
         }