From 90a17209266597eaf16162d4ff13d72007a25e67 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 24 Sep 2021 05:05:51 +0300 Subject: libcamera: base: backtrace: Fallback to libunwind for symbolic names libunwind has an API to provide symbolic names for functions. It's less optimal than using backtrace_symbols() or libdw, as it doesn't allow deferring the symbolic names lookup, but it can be usefull as a fallback if no other option is available. A sample backtrace when falling back to libunwind looks like libcamera::VimcCameraData::init()+0xbd libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0 libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7 libcamera::CameraManager::Private::init()+0x98 libcamera::CameraManager::Private::run()+0x9f libcamera::Thread::startThread()+0xee decltype(*(std::__1::forward(fp0)).*fp()) std::__1::__invoke(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77 void std::__1::__thread_execute >, void (libcamera::Thread::*)(), libcamera::Thread*, 2ul>(std::__1::tuple >, void (libcamera::Thread::*)(), libcamera::Thread*>&, std::__1::__tuple_indices<2ul>)+0x3e void* std::__1::__thread_proxy >, void (libcamera::Thread::*)(), libcamera::Thread*> >(void*)+0x62 start_thread+0xde ??? Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- include/libcamera/base/backtrace.h | 1 + src/libcamera/base/backtrace.cpp | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/libcamera/base/backtrace.h b/include/libcamera/base/backtrace.h index 58ccc14c..bb77c73b 100644 --- a/include/libcamera/base/backtrace.h +++ b/include/libcamera/base/backtrace.h @@ -30,6 +30,7 @@ private: bool unwindTrace(); std::vector backtrace_; + std::vector backtraceText_; }; } /* namespace libcamera */ diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp index 0aafc6a3..d93e5518 100644 --- a/src/libcamera/base/backtrace.cpp +++ b/src/libcamera/base/backtrace.cpp @@ -202,6 +202,12 @@ bool Backtrace::unwindTrace() return false; do { +#if HAVE_BACKTRACE || HAVE_DW + /* + * If backtrace() or libdw is available, they will be used in + * toString() to provide symbol information for the stack + * frames using the IP register value. + */ unw_word_t ip; ret = unw_get_reg(&cursor, UNW_REG_IP, &ip); if (ret) { @@ -210,6 +216,29 @@ bool Backtrace::unwindTrace() } backtrace_.push_back(reinterpret_cast(ip)); +#else + /* + * Otherwise, use libunwind to get the symbol information. As + * the libunwind API uses cursors, we can't store the IP values + * and delay symbol lookup to toString(). + */ + char symbol[256]; + unw_word_t offset = 0; + ret = unw_get_proc_name(&cursor, symbol, sizeof(symbol), &offset); + if (ret) { + backtraceText_.emplace_back("???\n"); + continue; + } + + std::ostringstream entry; + + char *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr); + entry << (name ? name : symbol); + free(name); + + entry << "+0x" << std::hex << offset << "\n"; + backtraceText_.emplace_back(entry.str()); +#endif } while (unw_step(&cursor) > 0); return true; @@ -245,9 +274,15 @@ std::string Backtrace::toString(unsigned int skipLevels) const */ skipLevels += 2; - if (backtrace_.size() <= skipLevels) + if (backtrace_.size() <= skipLevels && + backtraceText_.size() <= skipLevels) return std::string(); + if (!backtraceText_.empty()) { + Span trace{ backtraceText_ }; + return utils::join(trace.subspan(skipLevels), ""); + } + #if HAVE_DW DwflParser dwfl; -- cgit v1.2.1