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:
|
private:
|
||||||
LIBCAMERA_DISABLE_COPY(Backtrace)
|
LIBCAMERA_DISABLE_COPY(Backtrace)
|
||||||
|
|
||||||
|
bool backtraceTrace();
|
||||||
|
bool unwindTrace();
|
||||||
|
|
||||||
std::vector<void *> backtrace_;
|
std::vector<void *> backtrace_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,15 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#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 <sstream>
|
||||||
|
|
||||||
#include <libcamera/base/span.h>
|
#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().
|
* It can later be converted to a string with toString().
|
||||||
*/
|
*/
|
||||||
Backtrace::Backtrace()
|
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
|
#if HAVE_BACKTRACE
|
||||||
backtrace_.resize(32);
|
backtrace_.resize(32);
|
||||||
|
@ -153,10 +176,45 @@ Backtrace::Backtrace()
|
||||||
int num_entries = backtrace(backtrace_.data(), backtrace_.size());
|
int num_entries = backtrace(backtrace_.data(), backtrace_.size());
|
||||||
if (num_entries < 0) {
|
if (num_entries < 0) {
|
||||||
backtrace_.clear();
|
backtrace_.clear();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
backtrace_.resize(num_entries);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +239,11 @@ Backtrace::Backtrace()
|
||||||
*/
|
*/
|
||||||
std::string Backtrace::toString(unsigned int skipLevels) const
|
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)
|
if (backtrace_.size() <= skipLevels)
|
||||||
return std::string();
|
return std::string();
|
||||||
|
|
|
@ -20,6 +20,7 @@ libcamera_base_sources = files([
|
||||||
])
|
])
|
||||||
|
|
||||||
libdw = cc.find_library('libdw', required : false)
|
libdw = cc.find_library('libdw', required : false)
|
||||||
|
libunwind = cc.find_library('libunwind', required : false)
|
||||||
|
|
||||||
if cc.has_header_symbol('execinfo.h', 'backtrace')
|
if cc.has_header_symbol('execinfo.h', 'backtrace')
|
||||||
config_h.set('HAVE_BACKTRACE', 1)
|
config_h.set('HAVE_BACKTRACE', 1)
|
||||||
|
@ -29,10 +30,15 @@ if libdw.found()
|
||||||
config_h.set('HAVE_DW', 1)
|
config_h.set('HAVE_DW', 1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if libunwind.found()
|
||||||
|
config_h.set('HAVE_UNWIND', 1)
|
||||||
|
endif
|
||||||
|
|
||||||
libcamera_base_deps = [
|
libcamera_base_deps = [
|
||||||
dependency('threads'),
|
dependency('threads'),
|
||||||
libatomic,
|
libatomic,
|
||||||
libdw,
|
libdw,
|
||||||
|
libunwind,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Internal components must use the libcamera_base_private dependency to enable
|
# Internal components must use the libcamera_base_private dependency to enable
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue