199 lines
5.4 KiB
C++
199 lines
5.4 KiB
C++
|
// Copyright Antony Polukhin, 2016-2024.
|
||
|
//
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||
|
// accompanying file LICENSE_1_0.txt or copy at
|
||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||
|
|
||
|
#ifndef BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|
||
|
#define BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|
||
|
|
||
|
#include <boost/config.hpp>
|
||
|
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||
|
# pragma once
|
||
|
#endif
|
||
|
|
||
|
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||
|
# include <dlfcn.h>
|
||
|
#else
|
||
|
# include <boost/winapi/dll.hpp>
|
||
|
#endif
|
||
|
|
||
|
#ifdef _AIX
|
||
|
/* AIX doesn't provide dladdr syscall.
|
||
|
This provides a minimal implementation of dladdr which retrieves
|
||
|
only files information.
|
||
|
TODO: Implement the symbol name. */
|
||
|
|
||
|
#include <sys/ldr.h>
|
||
|
#include <sys/debug.h>
|
||
|
#include <cstring>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
namespace boost { namespace stacktrace { namespace detail {
|
||
|
|
||
|
struct Dl_info {
|
||
|
std::string fname_storage{};
|
||
|
const char *dli_fname = nullptr;
|
||
|
const char *dli_sname = nullptr;
|
||
|
};
|
||
|
|
||
|
int dladdr(const void* address_raw, Dl_info* info) noexcept {
|
||
|
static constexpr std::size_t dl_buff_size = 0x1000;
|
||
|
|
||
|
try {
|
||
|
std::vector<struct ld_info> pld_info_storage;
|
||
|
pld_info_storage.resize(
|
||
|
(dl_buff_size + sizeof(struct ld_info) - 1) / sizeof(struct ld_info)
|
||
|
);
|
||
|
|
||
|
if (loadquery(L_GETINFO, pld_info_storage.data(), dl_buff_size) == -1) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const auto* pld_info = pld_info_storage.data();
|
||
|
const char* const address = static_cast<const char*>(address_raw);
|
||
|
while (true) {
|
||
|
const auto* const dataorg = static_cast<char*>(pld_info->ldinfo_dataorg);
|
||
|
const auto* const textorg = static_cast<char*>(pld_info->ldinfo_textorg);
|
||
|
if ((address >= dataorg && address < dataorg + pld_info->ldinfo_datasize )
|
||
|
|| (address >= textorg && address < textorg + pld_info->ldinfo_textsize )) {
|
||
|
|
||
|
/* ldinfo_filename is the null-terminated path name followed
|
||
|
by null-terminated member name.
|
||
|
If the file is not an archive, then member name is null. */
|
||
|
const auto size_filename = std::strlen(pld_info->ldinfo_filename);
|
||
|
const auto size_member = std::strlen(pld_info->ldinfo_filename + size_filename + 1);
|
||
|
|
||
|
/* If member is not null, '(' and ')' must be added to create a
|
||
|
fname looking like "filename(membername)". */
|
||
|
info->fname_storage.reserve(size_filename + (size_member ? size_member + 3 : 1));
|
||
|
info->fname_storage = pld_info->ldinfo_filename;
|
||
|
if (size_member) {
|
||
|
info->fname_storage += "(";
|
||
|
info->fname_storage += pld_info->ldinfo_filename + size_filename + 1;
|
||
|
info->fname_storage += ")";
|
||
|
}
|
||
|
|
||
|
info->dli_fname = info->fname_storage.c_str();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (!pld_info->ldinfo_next) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pld_info = reinterpret_cast<const struct ld_info *>(
|
||
|
reinterpret_cast<const char*>(pld_info) + pld_info->ldinfo_next
|
||
|
);
|
||
|
};
|
||
|
} catch (...) {
|
||
|
// ignore
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
}}} // namespace boost::stacktrace::detail
|
||
|
|
||
|
#elif !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||
|
|
||
|
namespace boost { namespace stacktrace { namespace detail {
|
||
|
|
||
|
using Dl_info = ::Dl_info;
|
||
|
|
||
|
inline int dladdr(const void* addr, Dl_info& dli) noexcept {
|
||
|
// `dladdr` on Solaris accepts nonconst addresses
|
||
|
return ::dladdr(const_cast<void*>(addr), &dli);
|
||
|
}
|
||
|
|
||
|
}}} // namespace boost::stacktrace::detail
|
||
|
|
||
|
#endif
|
||
|
|
||
|
namespace boost { namespace stacktrace { namespace detail {
|
||
|
|
||
|
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||
|
class location_from_symbol {
|
||
|
boost::stacktrace::detail::Dl_info dli_;
|
||
|
|
||
|
public:
|
||
|
explicit location_from_symbol(const void* addr) noexcept
|
||
|
: dli_()
|
||
|
{
|
||
|
if (!boost::stacktrace::detail::dladdr(addr, dli_)) {
|
||
|
dli_.dli_fname = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool empty() const noexcept {
|
||
|
return !dli_.dli_fname;
|
||
|
}
|
||
|
|
||
|
const char* name() const noexcept {
|
||
|
return dli_.dli_fname;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class program_location {
|
||
|
public:
|
||
|
const char* name() const noexcept {
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#else
|
||
|
|
||
|
class location_from_symbol {
|
||
|
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||
|
char file_name_[DEFAULT_PATH_SIZE_];
|
||
|
|
||
|
public:
|
||
|
explicit location_from_symbol(const void* addr) noexcept {
|
||
|
file_name_[0] = '\0';
|
||
|
|
||
|
boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
|
||
|
if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
boost::winapi::HMODULE_ handle = reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase);
|
||
|
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||
|
file_name_[0] = '\0';
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool empty() const noexcept {
|
||
|
return file_name_[0] == '\0';
|
||
|
}
|
||
|
|
||
|
const char* name() const noexcept {
|
||
|
return file_name_;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class program_location {
|
||
|
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||
|
char file_name_[DEFAULT_PATH_SIZE_];
|
||
|
|
||
|
public:
|
||
|
program_location() noexcept {
|
||
|
file_name_[0] = '\0';
|
||
|
|
||
|
const boost::winapi::HMODULE_ handle = 0;
|
||
|
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||
|
file_name_[0] = '\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* name() const noexcept {
|
||
|
return file_name_[0] ? file_name_ : 0;
|
||
|
}
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
}}} // namespace boost::stacktrace::detail
|
||
|
|
||
|
#endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|