27 #ifndef XERUS_NO_FANCY_CALLSTACK 40 namespace xerus {
namespace misc {
namespace internal {
50 std::unique_ptr<bfd, deleter_t*>
abfd;
55 static std::map<void *, storedBfd>
bfds;
60 if (bfds.count(_info.dli_fbase) == 0) {
61 std::unique_ptr<storedBfd> newBfd(
new storedBfd(bfd_openr(_info.dli_fname,
nullptr), &bfd_close));
65 bfd_check_format(newBfd->abfd.get(),bfd_object);
66 long storageNeeded = bfd_get_symtab_upper_bound(newBfd->abfd.get());
67 if (storageNeeded < 0) {
70 newBfd->symbols.reset(reinterpret_cast<asymbol**>(
new char[static_cast<size_t>(storageNeeded)]));
71 bfd_canonicalize_symtab(newBfd->abfd.get(), newBfd->symbols.get());
73 newBfd->offset =
reinterpret_cast<intptr_t
>(_info.dli_fbase);
75 bfds.insert(std::pair<void *, storedBfd>(_info.dli_fbase, std::move(*newBfd)));
81 if (!bfd_initialized) {
83 bfd_initialized =
true;
89 if (info.dli_fbase ==
nullptr) {
90 return std::pair<uintptr_t, uintptr_t>(0,0);
94 return std::pair<uintptr_t, uintptr_t>(0,0);
96 storedBfd &currBfd = bfds.at(info.dli_fbase);
98 asection *section = bfd_get_section_by_name(currBfd.abfd.get(), _name.c_str());
99 if (section ==
nullptr) {
100 return std::pair<uintptr_t, uintptr_t>(0,0);
102 return std::pair<uintptr_t, uintptr_t>(section->vma, section->vma+section->size);
106 if (!bfd_initialized) {
108 bfd_initialized =
true;
111 std::stringstream res;
112 res <<
"[0x" << std::setw(
int(
sizeof(
void*)*2)) << std::setfill(
'0') << std::hex << reinterpret_cast<uintptr_t>(address);
116 dladdr(address, &info);
117 if (info.dli_fbase ==
nullptr) {
118 return res.str()+
" .?] <object to address not found>";
122 return res.str()+
" .?] <could not open object file>";
124 storedBfd &currBfd = bfds.at(info.dli_fbase);
126 asection *section = currBfd.
abfd->sections;
127 const bool relative = section->vma <
static_cast<uintptr_t
>(currBfd.
offset);
129 while (section !=
nullptr) {
130 const intptr_t
offset =
reinterpret_cast<intptr_t
>(address) - (relative ? currBfd.
offset : 0) -
static_cast<intptr_t
>(section->vma);
134 if (offset < 0 || static_cast<size_t>(offset) > section->size) {
135 section = section->next;
138 res <<
' ' << section->name;
139 if ((section->flags | SEC_CODE) == 0u) {
140 return res.str()+
"] <non executable address>";
146 if (bfd_find_nearest_line(currBfd.
abfd.get(), section, currBfd.
symbols.get(),
offset, &file, &func, &line)) {
147 if (file !=
nullptr) {
150 if (info.dli_saddr !=
nullptr) {
151 return res.str()+
"] ??:? (inside "+
demangle_cxa(func)+
" +0x"+
std::to_string(reinterpret_cast<uintptr_t>(address)-reinterpret_cast<uintptr_t>(info.dli_saddr))+
")";
153 return res.str()+
"] ??:? (inside "+
demangle_cxa(func)+
")";
155 return res.str()+
"] <bfd_error> (inside "+
demangle_cxa((info.dli_sname !=
nullptr?info.dli_sname:
""))+
")";
158 return res.str()+
" .none] <not sectioned address>";
167 const size_t MAX_FRAMES = 1000;
168 std::vector<void *> stack(MAX_FRAMES);
169 int num = backtrace(&stack[0], MAX_FRAMES);
171 return "Callstack could not be built.";
173 while (
size_t(num) == stack.size()) {
174 stack.resize(stack.size()*2);
175 num = backtrace(&stack[0],
int(stack.size()));
177 stack.resize(static_cast<size_t>(num));
180 for (
size_t i = 1; i < static_cast<size_t>(num); ++i) {
193 #else // No fancy callstack 194 #include <execinfo.h> 202 const size_t MAX_FRAMES = 1000;
203 std::vector<void *> stack(MAX_FRAMES);
204 int num = backtrace(&stack[0], MAX_FRAMES);
206 return "Callstack could not be built.";
208 while (
size_t(num) == stack.size()) {
209 stack.resize(stack.size()*2);
210 num = backtrace(&stack[0],
int(stack.size()));
212 stack.resize(
size_t(num));
213 std::stringstream res;
215 for (
size_t i=1; i<size_t(num); ++i) {
216 res <<
"[0x" << std::setw(
int(
sizeof(
void*)*2)) << std::setfill(
'0') << std::hex << uintptr_t(stack[i]) <<
" .?] <bfd not loaded, use addr2line to resolve>\n";
222 return std::pair<uintptr_t, uintptr_t>(0,0);
static std::map< void *, storedBfd > bfds
static std::pair< uintptr_t, uintptr_t > get_range_of_section(void *_addr, std::string _name)
class to load symbols and resolve address pointers
Header file for some elementary string manipulation routines.
The main namespace of xerus.
Header file for the call-stack functionality.
static std::string resolve(void *address)
std::string get_call_stack()
Returns a string representation of the current call-stack (excluding the function itself)...
static bool bfd_initialized
storedBfd(bfd *_abfd, deleter_t *_del)
std::unique_ptr< bfd, deleter_t * > abfd
static bool ensure_bfd_loaded(Dl_info &_info)
Header file for some elementary string manipulation routines.
relevant information belonging to a single bfd
std::string XERUS_warn_unused demangle_cxa(const std::string &_cxa)
Demangles the function and class names created by gcc into a more readable format.
static XERUS_force_inline std::string to_string(const bool obj)
std::unique_ptr< asymbol *[]> symbols
bfd_boolean() deleter_t(bfd *)