Fix `$stacktrace` to decode through internal-c++filt (#6985).

This commit is contained in:
Wilson Snyder 2026-02-02 19:01:24 -05:00
parent 9083b238e5
commit bb979a00c8
5 changed files with 61 additions and 15 deletions

View File

@ -528,6 +528,12 @@ $readmemb, $readmemh
specification do not include support for readmem to multi-dimensional
arrays.
$stacktrace
The `$stacktrace` system call will show the C++ stack, not the Verilog
call stack, though the function names typically correlate. To get
symbolic names, the model must have debug symbols, e.g. compile with
`-CFLAGS -ggdb -LDFLAGS -ggdb -LDFLAGS -rdynamic`.
$test$plusargs, $value$plusargs
Supported, but the instantiating C++/SystemC wrapper must call

View File

@ -1102,6 +1102,7 @@ src
srcdir
srcfile
sscanf
stacktrace
stderr
stdin
stdout

View File

@ -69,6 +69,7 @@
# include <direct.h> // mkdir
#endif
#ifdef __GLIBC__
# include <cxxabi.h>
# include <execinfo.h>
# define _VL_HAVE_STACKTRACE
#endif
@ -1918,6 +1919,40 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
return read_count;
}
#ifdef _VL_HAVE_STACKTRACE
static std::string _vl_stacktrace_demangle(const std::string& input) {
std::string result;
result.reserve(input.size());
std::string word;
for (const char c : input) {
if (std::isalpha(c) || c == '_') {
word += c;
} else if (!word.empty() && std::isdigit(c)) {
word += c;
} else {
if (!word.empty()) {
// abi::__cxa_demangle mallocs demangled_name
int status = 0;
char* const demangled_name
= abi::__cxa_demangle(word.c_str(), NULL, NULL, &status);
if (status == 0) {
result += std::string{demangled_name};
std::free(demangled_name); // Free the allocated memory
} else {
result += word;
}
word.clear();
}
result += c;
}
}
// input requires final newline, so last word can't be symbol
result += word;
return result;
}
#endif
std::string VL_STACKTRACE_N() VL_MT_SAFE {
static VerilatedMutex s_stackTraceMutex;
const VerilatedLockGuard lock{s_stackTraceMutex};
@ -1935,8 +1970,12 @@ std::string VL_STACKTRACE_N() VL_MT_SAFE {
// cppcheck-suppress knownConditionTrueFalse
if (!strings) return "Unable to backtrace\n";
#ifdef _VL_HAVE_STACKTRACE
std::string result = "Backtrace:\n";
for (int j = 0; j < nptrs; ++j) result += std::string{strings[j]} + "\n"s;
for (int j = 0; j < nptrs; ++j)
result += _vl_stacktrace_demangle(std::string{strings[j]} + "\n"s);
#endif
free(strings);
return result;
}

View File

@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.compile(verilator_flags2=['-CFLAGS -ggdb -LDFLAGS -ggdb -LDFLAGS -rdynamic'])
test.execute()

View File

@ -6,22 +6,22 @@
module t;
task automatic t;
// verilator no_inline_task
string trace;
task automatic t;
// verilator no_inline_task
string trace;
$display("== Trace Func");
trace = $stacktrace();
if (trace == "") $stop;
$display("%s", trace);
$display("== Trace Func");
trace = $stacktrace();
if (trace == "") $stop;
$display("%s", trace);
$display("== Trace Task");
$stacktrace;
$display("== Trace Task");
$stacktrace;
$write("*-* All Finished *-*\n");
$finish;
endtask
$write("*-* All Finished *-*\n");
$finish;
endtask
initial t();
initial t();
endmodule