boost/stacktrace/detail/location_from_symbol.hpp
// 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