summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libcamera/base/backtrace.cpp120
-rw-r--r--src/libcamera/base/meson.build7
2 files changed, 127 insertions, 0 deletions
diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp
index c010a7e4..79e4a31f 100644
--- a/src/libcamera/base/backtrace.cpp
+++ b/src/libcamera/base/backtrace.cpp
@@ -12,9 +12,16 @@
#include <stdlib.h>
#endif
+#ifdef HAVE_DW
+#include <cxxabi.h>
+#include <elfutils/libdwfl.h>
+#include <unistd.h>
+#endif
+
#include <sstream>
#include <libcamera/base/span.h>
+#include <libcamera/base/utils.h>
/**
* \file backtrace.h
@@ -23,6 +30,101 @@
namespace libcamera {
+namespace {
+
+#if HAVE_DW
+class DwflParser
+{
+public:
+ DwflParser();
+ ~DwflParser();
+
+ bool isValid() const { return valid_; }
+ std::string stackEntry(const void *ip);
+
+private:
+ Dwfl_Callbacks callbacks_;
+ Dwfl *dwfl_;
+ bool valid_;
+};
+
+DwflParser::DwflParser()
+ : callbacks_({}), dwfl_(nullptr), valid_(false)
+{
+ callbacks_.find_elf = dwfl_linux_proc_find_elf;
+ callbacks_.find_debuginfo = dwfl_standard_find_debuginfo;
+
+ dwfl_ = dwfl_begin(&callbacks_);
+ if (!dwfl_)
+ return;
+
+ int ret = dwfl_linux_proc_report(dwfl_, getpid());
+ if (ret)
+ return;
+
+ ret = dwfl_report_end(dwfl_, nullptr, nullptr);
+ if (ret)
+ return;
+
+ valid_ = true;
+}
+
+DwflParser::~DwflParser()
+{
+ if (dwfl_)
+ dwfl_end(dwfl_);
+}
+
+std::string DwflParser::stackEntry(const void *ip)
+{
+ Dwarf_Addr addr = reinterpret_cast<Dwarf_Addr>(ip);
+
+ Dwfl_Module *module = dwfl_addrmodule(dwfl_, addr);
+ if (!module)
+ return std::string();
+
+ std::ostringstream entry;
+
+ GElf_Off offset;
+ GElf_Sym sym;
+ const char *symbol = dwfl_module_addrinfo(module, addr, &offset, &sym,
+ nullptr, nullptr, nullptr);
+ if (symbol) {
+ char *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr);
+ entry << (name ? name : symbol) << "+0x" << std::hex << offset
+ << std::dec;
+ free(name);
+ } else {
+ entry << "??? [" << utils::hex(addr) << "]";
+ }
+
+ entry << " (";
+
+ Dwfl_Line *line = dwfl_module_getsrc(module, addr);
+ if (line) {
+ const char *filename;
+ int lineNumber = 0;
+
+ filename = dwfl_lineinfo(line, &addr, &lineNumber, nullptr,
+ nullptr, nullptr);
+
+ entry << (filename ? filename : "???") << ":" << lineNumber;
+ } else {
+ const char *filename = nullptr;
+
+ dwfl_module_info(module, nullptr, nullptr, nullptr, nullptr,
+ nullptr, &filename, nullptr);
+
+ entry << (filename ? filename : "???") << " [" << utils::hex(addr) << "]";
+ }
+
+ entry << ")";
+ return entry.str();
+}
+#endif /* HAVE_DW */
+
+} /* namespace */
+
/**
* \class Backtrace
* \brief Representation of a call stack backtrace
@@ -85,6 +187,24 @@ std::string Backtrace::toString(unsigned int skipLevels) const
if (backtrace_.size() <= skipLevels)
return std::string();
+#if HAVE_DW
+ DwflParser dwfl;
+
+ if (dwfl.isValid()) {
+ std::ostringstream msg;
+
+ Span<void *const> trace{ backtrace_ };
+ for (const void *ip : trace.subspan(skipLevels)) {
+ if (ip)
+ msg << dwfl.stackEntry(ip) << std::endl;
+ else
+ msg << "???" << std::endl;
+ }
+
+ return msg.str();
+ }
+#endif
+
#if HAVE_BACKTRACE
Span<void *const> trace{ backtrace_ };
trace = trace.subspan(skipLevels);
diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build
index fc00296d..4c44b9f5 100644
--- a/src/libcamera/base/meson.build
+++ b/src/libcamera/base/meson.build
@@ -19,13 +19,20 @@ libcamera_base_sources = files([
'utils.cpp',
])
+libdw = cc.find_library('libdw', required : false)
+
if cc.has_header_symbol('execinfo.h', 'backtrace')
config_h.set('HAVE_BACKTRACE', 1)
endif
+if libdw.found()
+ config_h.set('HAVE_DW', 1)
+endif
+
libcamera_base_deps = [
dependency('threads'),
libatomic,
+ libdw,
]
# Internal components must use the libcamera_base_private dependency to enable