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
|