mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-24 00:55:07 +03:00
libcamera: base: backtrace: Use libunwind when available
libunwind is an alternative to glibc's backtrace() to extract a backtrace. Use it when available to extend backtrace support to more platforms. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
f8d76fe79b
commit
a7c7f58d59
3 changed files with 73 additions and 3 deletions
|
@ -26,6 +26,9 @@ public:
|
|||
private:
|
||||
LIBCAMERA_DISABLE_COPY(Backtrace)
|
||||
|
||||
bool backtraceTrace();
|
||||
bool unwindTrace();
|
||||
|
||||
std::vector<void *> backtrace_;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_UNWIND
|
||||
/*
|
||||
* Disable support for remote unwinding to enable a more optimized
|
||||
* implementation.
|
||||
*/
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#endif
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <libcamera/base/span.h>
|
||||
|
@ -146,6 +155,20 @@ std::string DwflParser::stackEntry(const void *ip)
|
|||
* It can later be converted to a string with toString().
|
||||
*/
|
||||
Backtrace::Backtrace()
|
||||
{
|
||||
/* Try libunwind first and fall back to backtrace() if it fails. */
|
||||
if (unwindTrace())
|
||||
return;
|
||||
|
||||
backtraceTrace();
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid inlining to make sure that the Backtrace constructor adds exactly two
|
||||
* calls to the stack, which are later skipped in toString().
|
||||
*/
|
||||
__attribute__((__noinline__))
|
||||
bool Backtrace::backtraceTrace()
|
||||
{
|
||||
#if HAVE_BACKTRACE
|
||||
backtrace_.resize(32);
|
||||
|
@ -153,10 +176,45 @@ Backtrace::Backtrace()
|
|||
int num_entries = backtrace(backtrace_.data(), backtrace_.size());
|
||||
if (num_entries < 0) {
|
||||
backtrace_.clear();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
backtrace_.resize(num_entries);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((__noinline__))
|
||||
bool Backtrace::unwindTrace()
|
||||
{
|
||||
#if HAVE_UNWIND
|
||||
unw_context_t uc;
|
||||
int ret = unw_getcontext(&uc);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
unw_cursor_t cursor;
|
||||
ret = unw_init_local(&cursor, &uc);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
do {
|
||||
unw_word_t ip;
|
||||
ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);
|
||||
if (ret) {
|
||||
backtrace_.push_back(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
backtrace_.push_back(reinterpret_cast<void *>(ip));
|
||||
} while (unw_step(&cursor) > 0);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -181,8 +239,11 @@ Backtrace::Backtrace()
|
|||
*/
|
||||
std::string Backtrace::toString(unsigned int skipLevels) const
|
||||
{
|
||||
/* Skip the first entry, corresponding to the Backtrace construction. */
|
||||
skipLevels += 1;
|
||||
/*
|
||||
* Skip the first two entries, corresponding to the Backtrace
|
||||
* construction.
|
||||
*/
|
||||
skipLevels += 2;
|
||||
|
||||
if (backtrace_.size() <= skipLevels)
|
||||
return std::string();
|
||||
|
|
|
@ -20,6 +20,7 @@ libcamera_base_sources = files([
|
|||
])
|
||||
|
||||
libdw = cc.find_library('libdw', required : false)
|
||||
libunwind = cc.find_library('libunwind', required : false)
|
||||
|
||||
if cc.has_header_symbol('execinfo.h', 'backtrace')
|
||||
config_h.set('HAVE_BACKTRACE', 1)
|
||||
|
@ -29,10 +30,15 @@ if libdw.found()
|
|||
config_h.set('HAVE_DW', 1)
|
||||
endif
|
||||
|
||||
if libunwind.found()
|
||||
config_h.set('HAVE_UNWIND', 1)
|
||||
endif
|
||||
|
||||
libcamera_base_deps = [
|
||||
dependency('threads'),
|
||||
libatomic,
|
||||
libdw,
|
||||
libunwind,
|
||||
]
|
||||
|
||||
# Internal components must use the libcamera_base_private dependency to enable
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue