Skip to content

Commit 5f0e423

Browse files
committed
Add libdwfl based implementation
This commit adds an implementation based on libdwfl from elfutils. Implements #176
1 parent 22982db commit 5f0e423

File tree

11 files changed

+209
-2
lines changed

11 files changed

+209
-2
lines changed

CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ function(stacktrace_check var source incs libs defs)
6262
endfunction()
6363

6464
stacktrace_check(BOOST_STACKTRACE_HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "")
65+
stacktrace_check(BOOST_STACKTRACE_HAS_DWFL has_dwfl.cpp "" "dw" "")
6566

6667
set(_default_addr2line ON)
6768
if(WIN32 AND NOT CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
@@ -78,6 +79,7 @@ endif()
7879

7980
option(BOOST_STACKTRACE_ENABLE_NOOP "Boost.Stacktrace: build boost_stacktrace_noop" ON)
8081
option(BOOST_STACKTRACE_ENABLE_BACKTRACE "Boost.Stacktrace: build boost_stacktrace_backtrace" ${BOOST_STACKTRACE_HAS_BACKTRACE})
82+
option(BOOST_STACKTRACE_ENABLE_DWFL "Boost.Stacktrace: build boost_stacktrace_dwfl" ${BOOST_STACKTRACE_HAS_DWFL})
8183
option(BOOST_STACKTRACE_ENABLE_ADDR2LINE "Boost.Stacktrace: build boost_stacktrace_addr2line" ${_default_addr2line})
8284
option(BOOST_STACKTRACE_ENABLE_BASIC "Boost.Stacktrace: build boost_stacktrace_basic" ON)
8385
option(BOOST_STACKTRACE_ENABLE_WINDBG "Boost.Stacktrace: build boost_stacktrace_windbg" ${BOOST_STACKTRACE_HAS_WINDBG})
@@ -90,6 +92,7 @@ unset(_default_from_exception)
9092
message(STATUS "Boost.Stacktrace: "
9193
"noop ${BOOST_STACKTRACE_ENABLE_NOOP}, "
9294
"backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE}, "
95+
"dwfl ${BOOST_STACKTRACE_ENABLE_DWFL}, "
9396
"addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE}, "
9497
"basic ${BOOST_STACKTRACE_ENABLE_BASIC}, "
9598
"windbg ${BOOST_STACKTRACE_ENABLE_WINDBG}, "
@@ -99,6 +102,7 @@ message(STATUS "Boost.Stacktrace: "
99102

100103
stacktrace_add_library(noop ${BOOST_STACKTRACE_ENABLE_NOOP} "" "")
101104
stacktrace_add_library(backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE} "backtrace;${CMAKE_DL_LIBS}" "")
105+
stacktrace_add_library(dwfl ${BOOST_STACKTRACE_ENABLE_DWFL} "dw;${CMAKE_DL_LIBS}" "")
102106
stacktrace_add_library(addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE} "${CMAKE_DL_LIBS}" "")
103107
stacktrace_add_library(basic ${BOOST_STACKTRACE_ENABLE_BASIC} "${CMAKE_DL_LIBS}" "")
104108
stacktrace_add_library(windbg ${BOOST_STACKTRACE_ENABLE_WINDBG} "dbgeng;ole32" "_GNU_SOURCE=1")
@@ -119,6 +123,10 @@ elseif(BOOST_STACKTRACE_ENABLE_BACKTRACE)
119123

120124
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_backtrace)
121125

126+
elseif(BOOST_STACKTRACE_ENABLE_DWFL)
127+
128+
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_dwfl)
129+
122130
elseif(BOOST_STACKTRACE_ENABLE_ADDR2LINE)
123131

124132
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_addr2line)

build.jam

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ project /boost/stacktrace
2222
explicit
2323
[ alias boost_stacktrace_addr2line : build//boost_stacktrace_addr2line ]
2424
[ alias boost_stacktrace_backtrace : build//boost_stacktrace_backtrace ]
25+
[ alias boost_stacktrace_dwfl : build//boost_stacktrace_dwfl ]
2526
[ alias boost_stacktrace_basic : build//boost_stacktrace_basic ]
2627
[ alias boost_stacktrace_from_exception : build//boost_stacktrace_from_exception ]
2728
[ alias boost_stacktrace_noop : build//boost_stacktrace_noop ]
@@ -31,6 +32,7 @@ explicit
3132
[ alias all :
3233
boost_stacktrace_addr2line
3334
boost_stacktrace_backtrace
35+
boost_stacktrace_dwfl
3436
boost_stacktrace_basic
3537
boost_stacktrace_from_exception
3638
boost_stacktrace_noop
@@ -44,6 +46,7 @@ call-if : boost-library stacktrace
4446
: install
4547
boost_stacktrace_addr2line
4648
boost_stacktrace_backtrace
49+
boost_stacktrace_dwfl
4750
boost_stacktrace_basic
4851
boost_stacktrace_from_exception
4952
boost_stacktrace_noop

build/Jamfile.v2

+19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ lib dl ;
2828
lib gcc_s ;
2929
lib Dbgeng ;
3030
lib ole32 ;
31+
lib dw ;
3132

3233
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
3334
lib backtrace
@@ -54,6 +55,9 @@ rule mp-run-simple ( sources + : args * : input-files * : requirements * : targe
5455
mp-run-simple has_backtrace.cpp : : : <library>backtrace : libbacktrace ;
5556
explicit libbacktrace ;
5657

58+
mp-run-simple has_dwfl.cpp : : : <library>dw : libdw ;
59+
explicit libdw ;
60+
5761
mp-run-simple has_addr2line.cpp : : : : addr2line ;
5862
explicit addr2line ;
5963

@@ -90,6 +94,21 @@ lib boost_stacktrace_backtrace
9094
<define>BOOST_STACKTRACE_NO_LIB=1
9195
;
9296

97+
lib boost_stacktrace_dwfl
98+
: # sources
99+
../src/dwfl.cpp
100+
: # requirements
101+
<warnings>all
102+
<target-os>linux:<library>dl
103+
<library>dw
104+
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
105+
[ check-target-builds libdw : : <build>no ]
106+
: # default build
107+
: # usage-requirements
108+
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
109+
<define>BOOST_STACKTRACE_NO_LIB=1
110+
;
111+
93112
lib boost_stacktrace_addr2line
94113
: # sources
95114
../src/addr2line.cpp

build/has_dwfl.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Distributed under the Boost Software License, Version 1.0. (See
2+
// accompanying file LICENSE_1_0.txt or copy at
3+
// http://www.boost.org/LICENSE_1_0.txt)
4+
5+
#include <elfutils/libdwfl.h>
6+
7+
int main() {
8+
Dwfl_Callbacks callbacks{nullptr, nullptr, nullptr, nullptr};
9+
Dwfl* dwfl_ = dwfl_begin(&callbacks);
10+
}

doc/stacktrace.qbk

+1
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ In header only mode library could be tuned by macro. If one of the link macro fr
321321
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries[footnote Some *libbacktrace* packages SEGFAULT if there's a concurrent work with the same `backtrace_state` instance. To avoid that issue the Boost.Stacktrace library uses `thread_local` states, unfortunately this may consume a lot of memory if you often create and destroy execution threads in your application. Define *BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC* to force single instance, but make sure that [@https://github.com/boostorg/stacktrace/blob/develop/test/thread_safety_checking.cpp thread_safety_checking.cpp] works well in your setup. ]. *libbacktrace* is probably already installed in your system[footnote If you are using Clang with libstdc++ you could get into troubles of including `<backtrace.h>`, because on some platforms Clang does not search for headers in the GCC's include paths and any attempt to add GCC's include path leads to linker errors. To explicitly specify a path to the `<backtrace.h>` header you could define the *BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE* to a full path to the header. For example on Ubuntu Xenial use the command line option *-DBOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE=</usr/lib/gcc/x86_64-linux-gnu/5/include/backtrace.h>* while building with Clang. ], or built into your compiler.
322322

323323
Otherwise (if you are a *MinGW*/*MinGW-w64* user for example) it can be downloaded [@https://github.com/ianlancetaylor/libbacktrace from here] or [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here]. ] [Any compiler on POSIX, or MinGW, or MinGW-w64] [yes] [yes]]
324+
[[*BOOST_STACKTRACE_USE_DWFL*] [*boost_stacktrace_dwfl*] [Use *libdwfl* from *elfutils*.] [POSIX] [yes] [yes]]
324325
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and `::fork` system call. Macro *BOOST_STACKTRACE_ADDR2LINE_LOCATION* must be defined to the absolute path to the addr2line executable if it is not located in /usr/bin/addr2line. ] [Any compiler on POSIX] [yes] [yes]]
325326
[[*BOOST_STACKTRACE_USE_NOOP*] [*boost_stacktrace_noop*] [Use this if you wish to disable backtracing. `stacktrace::size()` with that macro always returns 0. ] [All] [no] [no]]
326327
]

include/boost/stacktrace/detail/frame_unwind.ipp

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#ifdef BOOST_STACKTRACE_USE_BACKTRACE
2525
# include <boost/stacktrace/detail/libbacktrace_impls.hpp>
26+
#elif defined(BOOST_STACKTRACE_USE_DWFL)
27+
# include <boost/stacktrace/detail/libdwfl_impls.hpp>
2628
#elif defined(BOOST_STACKTRACE_USE_ADDR2LINE)
2729
# include <boost/stacktrace/detail/addr2line_impls.hpp>
2830
#else
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Distributed under the Boost Software License, Version 1.0. (See
2+
// accompanying file LICENSE_1_0.txt or copy at
3+
// http://www.boost.org/LICENSE_1_0.txt)
4+
5+
#ifndef BOOST_STACKTRACE_DETAIL_LIBDWFL_IMPLS_HPP
6+
#define BOOST_STACKTRACE_DETAIL_LIBDWFL_IMPLS_HPP
7+
8+
#include <elfutils/libdwfl.h>
9+
10+
#include <boost/stacktrace/detail/to_dec_array.hpp>
11+
#include <boost/stacktrace/frame.hpp>
12+
13+
namespace boost { namespace stacktrace { namespace detail {
14+
15+
class dwfl_handle {
16+
public:
17+
dwfl_handle() noexcept
18+
: dwfl_(dwfl_begin(&callbacks_))
19+
{
20+
if (dwfl_) {
21+
dwfl_linux_proc_report(dwfl_, getpid());
22+
dwfl_report_end(dwfl_, nullptr, nullptr);
23+
}
24+
}
25+
26+
~dwfl_handle() {
27+
if (dwfl_) {
28+
dwfl_end(dwfl_);
29+
}
30+
}
31+
32+
const char* function(Dwarf_Addr addr) const noexcept {
33+
if (!dwfl_ || !addr) {
34+
return nullptr;
35+
}
36+
37+
Dwfl_Module* dwfl_module = dwfl_addrmodule (dwfl_, addr);
38+
return dwfl_module ? dwfl_module_addrname(dwfl_module, addr) : nullptr;
39+
}
40+
41+
std::pair<const char*, std::size_t> source(Dwarf_Addr addr) const noexcept {
42+
if (!dwfl_ || !addr) {
43+
return {nullptr, 0};
44+
}
45+
46+
Dwfl_Line* dwfl_line = dwfl_getsrc(dwfl_, addr);
47+
if (!dwfl_line) {
48+
return {nullptr, 0};
49+
}
50+
51+
int line{0};
52+
const char* filename = dwfl_lineinfo(dwfl_line, nullptr, &line, nullptr, nullptr, nullptr);
53+
return {filename, static_cast<std::size_t>(line)};
54+
}
55+
56+
private:
57+
Dwfl_Callbacks callbacks_{
58+
.find_elf = dwfl_linux_proc_find_elf,
59+
.find_debuginfo = dwfl_build_id_find_debuginfo,
60+
.section_address = dwfl_offline_section_address,
61+
.debuginfo_path = nullptr,
62+
};
63+
Dwfl* dwfl_;
64+
};
65+
66+
struct to_string_using_dwfl {
67+
std::string res;
68+
dwfl_handle dwfl;
69+
70+
void prepare_function_name(const void* addr) noexcept {
71+
const char* function = dwfl.function(reinterpret_cast<Dwarf_Addr>(addr));
72+
if (function) {
73+
res = function;
74+
}
75+
}
76+
77+
bool prepare_source_location(const void* addr) noexcept {
78+
auto [filename, line] = dwfl.source(reinterpret_cast<Dwarf_Addr>(addr));
79+
if (!filename) {
80+
return false;
81+
}
82+
83+
res += " at ";
84+
res += filename;
85+
res += ':';
86+
res += boost::stacktrace::detail::to_dec_array(line).data();
87+
88+
return true;
89+
}
90+
};
91+
92+
template <class Base> class to_string_impl_base;
93+
typedef to_string_impl_base<to_string_using_dwfl> to_string_impl;
94+
95+
inline std::string name_impl(const void* addr) {
96+
dwfl_handle dwfl;
97+
const char* function = dwfl.function(reinterpret_cast<Dwarf_Addr>(addr));
98+
return function ? std::string{function} : std::string{};
99+
}
100+
101+
} // namespace detail
102+
103+
std::string frame::source_file() const {
104+
detail::dwfl_handle dwfl;
105+
auto [filename, _] = dwfl.source(reinterpret_cast<Dwarf_Addr>(addr_));
106+
return filename ? std::string{filename} : std::string{};
107+
}
108+
109+
std::size_t frame::source_line() const {
110+
detail::dwfl_handle dwfl;
111+
return dwfl.source(reinterpret_cast<Dwarf_Addr>(addr_)).second;
112+
}
113+
114+
}} // namespace boost::stacktrace
115+
116+
#endif // BOOST_STACKTRACE_DETAIL_LIBDWFL_IMPLS_HPP

src/dwfl.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Distributed under the Boost Software License, Version 1.0. (See
2+
// accompanying file LICENSE_1_0.txt or copy at
3+
// http://www.boost.org/LICENSE_1_0.txt)
4+
5+
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
6+
#define BOOST_STACKTRACE_USE_DWFL
7+
#define BOOST_STACKTRACE_LINK
8+
9+
#ifndef _GNU_SOURCE
10+
# define _GNU_SOURCE
11+
#endif
12+
13+
#include <boost/stacktrace/detail/frame_unwind.ipp>
14+
#include <boost/stacktrace/safe_dump_to.hpp>

test/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ boost_test(TYPE run SOURCES test.cpp test_impl.cpp LINK_LIBRARIES Boost::stacktr
1212
boost_test(TYPE run SOURCES test_noop.cpp test_impl.cpp LINK_LIBRARIES Boost::stacktrace_noop Boost::core)
1313

1414
boost_test(TYPE run SOURCES test_trivial.cpp LINK_LIBRARIES Boost::stacktrace Boost::core)
15+
16+
if(BOOST_STACKTRACE_ENABLE_DWFL)
17+
boost_test(TYPE run NAME test_dwfl SOURCES test.cpp test_impl.cpp COMPILE_DEFINITIONS BOOST_STACKTRACE_USE_DWFL LINK_LIBRARIES Boost::stacktrace_dwfl Boost::core)
18+
endif()

0 commit comments

Comments
 (0)