summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-09-24 05:05:51 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-10-15 05:05:23 +0300
commitf8d76fe79b6137d3996f951568b29a615bb3c415 (patch)
treedb0e7c4319514f4d188a8809fa321224f745bce7
parentbae9d2bdb32ee8cdc717537ae498eee03a25543b (diff)
libcamera: base: backtrace: Use libdw to provide symbolic names
libdw provides access to debugging information. This allows creating better stack trace entries, with file names and line numbers, but also with demangled symbols as the symbol name is available and can be passed to abi::__cxa_demangle(). With libdw, the backtrace previously generated by backtrace_symbols() src/cam/../libcamera/libcamera.so(_ZN9libcamera14VimcCameraData4initEv+0xbd) [0x7f7dbb73222d] src/cam/../libcamera/libcamera.so(_ZN9libcamera19PipelineHandlerVimc5matchEPNS_16DeviceEnumeratorE+0x3e0) [0x7f7dbb731c40] src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private22createPipelineHandlersEv+0x1a7) [0x7f7dbb5ea027] src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private4initEv+0x98) [0x7f7dbb5e9dc8] src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private3runEv+0x9f) [0x7f7dbb5e9c5f] src/cam/../libcamera/base/libcamera-base.so(_ZN9libcamera6Thread11startThreadEv+0xee) [0x7f7dbb3e95be] src/cam/../libcamera/base/libcamera-base.so(+0x4f9d7) [0x7f7dbb3ec9d7] src/cam/../libcamera/base/libcamera-base.so(+0x4f90e) [0x7f7dbb3ec90e] src/cam/../libcamera/base/libcamera-base.so(+0x4f2c2) [0x7f7dbb3ec2c2] /lib64/libpthread.so.0(+0x7e8e) [0x7f7dbab65e8e] /lib64/libc.so.6(clone+0x3f) [0x7f7dbb10b26f] becomes libcamera::VimcCameraData::init()+0xbd (src/libcamera/libcamera.so [0x00007f9de605b22d]) libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0 (src/libcamera/libcamera.so [0x00007f9de605ac40]) libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7 (src/libcamera/libcamera.so [0x00007f9de5f13027]) libcamera::CameraManager::Private::init()+0x98 (src/libcamera/libcamera.so [0x00007f9de5f12dc8]) libcamera::CameraManager::Private::run()+0x9f (src/libcamera/libcamera.so [0x00007f9de5f12c5f]) libcamera::Thread::startThread()+0xee (src/libcamera/base/libcamera-base.so [0x00007f9de5d125be]) decltype(*(std::__1::forward<libcamera::Thread*>(fp0)).*fp()) std::__1::__invoke<void (libcamera::Thread::*)(), libcamera::Thread*, void>(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77 (src/libcamera/base/libcamera-base.so [0x00007f9de5d159d7]) void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*, 2ul>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*>&, std::__1::__tuple_indices<2ul>)+0x3e (src/libcamera/base/libcamera-base.so [0x00007f9de5d1590e]) void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*> >(void*)+0x62 (src/libcamera/base/libcamera-base.so [0x00007f9de5d152c2]) start_thread+0xde (/var/tmp/portage/sys-libs/glibc-2.33-r1/work/glibc-2.33/nptl/pthread_create.c:482) __clone+0x3f (../sysdeps/unix/sysv/linux/x86_64/clone.S:97) The stack entries related to libcamera are missing source file name and line information, which will be investigated separately, but this is still an improvement. Use libdw when available, falling back to backtrace_symbols() otherwise, or if libdw fails for any reason. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-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