update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt

View File

@@ -17,7 +17,7 @@
#include <boost/dll/detail/aggressive_ptr_cast.hpp>
#include <boost/dll/detail/get_mem_fn_type.hpp>
#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
#if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows
# include <boost/dll/detail/demangling/msvc.hpp>
#else
# include <boost/dll/detail/demangling/itanium.hpp>
@@ -117,7 +117,8 @@ struct destructor {
{}
};
#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
#if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows
template<typename Signature, typename Lib>
constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
typedef typename constructor<Signature>::standard_t standard_t;

View File

@@ -13,7 +13,7 @@
#include <algorithm>
#include <memory>
#if defined(BOOST_MSVC) || defined(BOOST_MSVC_FULL_VER)
#if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows
namespace boost
{

View File

@@ -88,6 +88,102 @@ public:
namespace parser
{
//! declare
template <typename... T>
struct dummy;
template <typename T>
std::string parse_type_helper(const mangled_storage_impl & ms, dummy<T>*);
template <typename... T, template <typename...> class Tn>
std::string parse_type_helper(const mangled_storage_impl & ms, dummy<Tn<T...>>*);
template <typename... T, template <typename...> class Tn>
std::string parse_type(const mangled_storage_impl & ms, dummy<Tn<T...>>*);
template <typename T>
std::string parse_type(const mangled_storage_impl & ms, dummy<T>*);
template <typename T1, typename T2, typename... T3>
std::string parse_type(const mangled_storage_impl & ms, dummy<T1, T2, T3...>*);
template <typename R, typename... Args>
std::string parse_type(const mangled_storage_impl & ms, dummy<R(Args...)>*);
std::string parse_type(const mangled_storage_impl & ms, dummy<>*);
template<typename T>
std::string
type_name(const mangled_storage_impl &);
//The purpose of this class template is to separate the pure type from the rule name from the target type
template<typename T>
struct pure_type
{
typedef T type;
inline static std::string type_rule() { return ""; }
};
template<typename T>
struct pure_type<T*>
{
typedef typename pure_type<T>::type type;
inline static std::string type_rule()
{
return pure_type<T>::type_rule() + "*";
}
};
template<typename T>
struct pure_type<T const>
{
typedef typename pure_type<T>::type type;
inline static std::string type_rule()
{
return pure_type<T>::type_rule() + " const";
}
};
template<typename T>
struct pure_type<T volatile>
{
typedef typename pure_type<T>::type type;
inline static std::string type_rule()
{
return pure_type<T>::type_rule() + " volatile";
}
};
template<typename T>
struct pure_type<T const volatile>
{
typedef typename pure_type<T>::type type;
inline static std::string type_rule()
{
return pure_type<T>::type_rule() + " const volatile";
}
};
template<typename T>
struct pure_type<T&>
{
typedef typename pure_type<T>::type type;
inline static std::string type_rule()
{
return pure_type<T>::type_rule() + "&";
}
};
template<typename T>
struct pure_type<T&&>
{
typedef typename pure_type<T>::type type;
inline static std::string type_rule()
{
return pure_type<T>::type_rule() + "&&";
}
};
inline std::string const_rule_impl(true_type ) {return " const";}
inline std::string const_rule_impl(false_type) {return "";}
@@ -103,38 +199,22 @@ namespace parser
inline std::string reference_rule_impl(true_type, false_type) {return "&" ;}
inline std::string reference_rule_impl(false_type, true_type ) {return "&&";}
template<typename T>
std::string reference_rule() {using t_l = is_lvalue_reference<T>; using t_r = is_rvalue_reference<T>; return reference_rule_impl(t_l(), t_r());}
//it takes a string, because it may be overloaded.
template<typename T>
std::string type_rule(const std::string & type_name)
{
using namespace std;
return type_name +
const_rule<T>() +
volatile_rule<T>() +
reference_rule<T>();
}
template<typename Return, typename Arg>
std::string arg_list(const mangled_storage_impl & ms, Return (*)(Arg))
{
using namespace std;
auto str = ms.get_name<Arg>();
return type_rule<Arg>(str);
return type_name<Arg>(ms);
}
template<typename Return, typename First, typename Second, typename ...Args>
std::string arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...))
{
auto st = ms.get_name<First>();
using next_type = Return (*)(Second, Args...);
return type_rule<First>(st) + ", " + arg_list(ms, next_type());
return type_name<First>(ms) + ", " + arg_list(ms, next_type());
}
template<typename Return>
@@ -142,6 +222,70 @@ namespace parser
{
return "";
}
//! implement
template <typename T>
inline std::string parse_type_helper(const mangled_storage_impl & ms, dummy<T>*) {
return ms.get_name<T>();
}
template <typename... T, template <typename...> class Tn>
inline std::string parse_type_helper(const mangled_storage_impl & ms, dummy<Tn<T...>>*) {
using type = dummy<Tn<T...>>*;
return parse_type(ms, type());
}
template <typename R, typename... Args>
inline std::string parse_type(const mangled_storage_impl & ms, dummy<R(*)(Args...)>*) {
using args_type = dummy<Args...>*;
using return_type = dummy<R>*;
return parse_type(ms, return_type()) + " (*)(" + parse_type(ms, args_type()) + ")";
}
template <typename R, typename... Args>
inline std::string parse_type(const mangled_storage_impl & ms, dummy<R(Args...)>*) {
using args_type = dummy<Args...>*;
using return_type = dummy<R>*;
return parse_type(ms, return_type()) + " (" + parse_type(ms, args_type()) + ")";
}
template <typename T>
inline std::string parse_type(const mangled_storage_impl & ms, dummy<T>*) {
using type = dummy<typename pure_type<T>::type>*;
auto str = parse_type_helper(ms, type());
return str + pure_type<T>::type_rule();
}
template <typename T1, typename T2, typename... T3>
inline std::string parse_type(const mangled_storage_impl & ms, dummy<T1, T2, T3...>*) {
using first_type = dummy<T1>*;
using next_type = dummy<T2, T3...>*;
return parse_type(ms, first_type()) + ", " + parse_type(ms, next_type());
}
template <typename... T, template <typename...> class Tn>
inline std::string parse_type(const mangled_storage_impl & ms, dummy<Tn<T...>>*) {
using next_type = dummy<T...>*;
std::string str = ms.get_name<Tn<T...>>();
auto frist = str.find_first_of("<");
std::string template_name = str.substr(0, frist);
std::string args_name = parse_type(ms, next_type());
char last_ch = args_name[args_name.size() - 1];
return template_name + "<" + args_name + (last_ch == '>' ? " >" : ">");
}
inline std::string parse_type(const mangled_storage_impl &, dummy<>*) {
return "";
}
template<typename T>
inline std::string
type_name(const mangled_storage_impl &ms)
{
using namespace parser;
using type = dummy<T>*;
return parse_type(ms, type());
}
}
@@ -180,11 +324,30 @@ std::string mangled_storage_impl::get_mem_fn(const std::string &name) const
std::string cname = get_name<Class>();
auto matcher = cname + "::" + name +
const auto matcher = cname + "::" + name +
'(' + parser::arg_list(*this, func_type()) + ')'
+ const_rule<Class>() + volatile_rule<Class>();
auto found = std::find_if(storage_.begin(), storage_.end(), [&](const entry& e) {return e.demangled == matcher;});
// Linux export table contains int MyClass::Func<float>(), but expected in import_mangled MyClass::Func<float>() without returned type.
auto found = std::find_if(storage_.begin(), storage_.end(), [&matcher](const entry& e) {
if (e.demangled == matcher) {
return true;
}
const auto pos = e.demangled.rfind(matcher);
if (pos == std::string::npos) {
// Not found.
return false;
}
if (pos + matcher.size() != e.demangled.size()) {
// There are some characters after the `matcher` string.
return false;
}
// Double checking that we matched a full function name
return e.demangled[pos - 1] == ' '; // `if (e.demangled == matcher)` makes sure that `pos > 0`
});
if (found != storage_.end())
return found->mangled;

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -16,9 +16,11 @@
#include <cstring>
#include <fstream>
#include <limits>
#include <vector>
#include <boost/cstdint.hpp>
#include <boost/dll/detail/x_info_interface.hpp>
#include <boost/throw_exception.hpp>
namespace boost { namespace dll { namespace detail {
@@ -92,15 +94,14 @@ typedef Elf_Sym_template<boost::uint32_t> Elf32_Sym_;
typedef Elf_Sym_template<boost::uint64_t> Elf64_Sym_;
template <class AddressOffsetT>
class elf_info: public x_info_interface {
std::ifstream& f_;
class elf_info {
typedef boost::dll::detail::Elf_Ehdr_template<AddressOffsetT> header_t;
typedef boost::dll::detail::Elf_Shdr_template<AddressOffsetT> section_t;
typedef boost::dll::detail::Elf_Sym_template<AddressOffsetT> symbol_t;
BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_SYMTAB_ = 2);
BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_STRTAB_ = 3);
BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_DYNSYM_ = 11);
BOOST_STATIC_CONSTANT(unsigned char, STB_LOCAL_ = 0); /* Local symbol */
BOOST_STATIC_CONSTANT(unsigned char, STB_GLOBAL_ = 1); /* Global symbol */
@@ -113,15 +114,15 @@ class elf_info: public x_info_interface {
BOOST_STATIC_CONSTANT(unsigned char, STV_PROTECTED_ = 3); /* Not preemptible, not exported */
public:
static bool parsing_supported(std::ifstream& f) {
static bool parsing_supported(std::ifstream& fs) {
const unsigned char magic_bytes[5] = {
0x7f, 'E', 'L', 'F', sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 1 : 2
};
unsigned char ch;
f.seekg(0);
fs.seekg(0);
for (std::size_t i = 0; i < sizeof(magic_bytes); ++i) {
f >> ch;
fs >> ch;
if (ch != magic_bytes[i]) {
return false;
}
@@ -130,97 +131,154 @@ public:
return true;
}
explicit elf_info(std::ifstream& f) BOOST_NOEXCEPT
: f_(f)
{}
std::vector<std::string> sections() {
static std::vector<std::string> sections(std::ifstream& fs) {
std::vector<std::string> ret;
std::vector<char> names;
sections_names_raw(names);
sections_names_raw(fs, names);
const char* name_begin = &names[0];
const char* const name_end = name_begin + names.size();
ret.reserve(header().e_shnum);
ret.reserve(header(fs).e_shnum);
do {
ret.push_back(name_begin);
name_begin += ret.back().size() + 1;
if (*name_begin) {
ret.push_back(name_begin);
name_begin += ret.back().size() + 1;
} else {
++name_begin;
}
} while (name_begin != name_end);
return ret;
}
private:
template <class T>
inline void read_raw(T& value, std::size_t size = sizeof(T)) const {
f_.read(reinterpret_cast<char*>(&value), size);
template <class Integer>
static void checked_seekg(std::ifstream& fs, Integer pos) {
/* TODO: use cmp_less, cmp_greater
if ((std::numeric_limits<std::streamoff>::max)() < pos) {
boost::throw_exception(std::runtime_error("Integral overflow while getting info from ELF file"));
}
if ((std::numeric_limits<std::streamoff>::min)() > pos){
boost::throw_exception(std::runtime_error("Integral underflow while getting info from ELF file"));
}
*/
fs.seekg(static_cast<std::streamoff>(pos));
}
inline header_t header() {
template <class T>
static void read_raw(std::ifstream& fs, T& value, std::size_t size = sizeof(T)) {
fs.read(reinterpret_cast<char*>(&value), size);
}
static header_t header(std::ifstream& fs) {
header_t elf;
f_.seekg(0);
read_raw(elf);
fs.seekg(0);
read_raw(fs, elf);
return elf;
}
void sections_names_raw(std::vector<char>& sections) {
const header_t elf = header();
static void sections_names_raw(std::ifstream& fs, std::vector<char>& sections) {
const header_t elf = header(fs);
section_t section_names_section;
f_.seekg(elf.e_shoff + elf.e_shstrndx * sizeof(section_t));
read_raw(section_names_section);
checked_seekg(fs, elf.e_shoff + elf.e_shstrndx * sizeof(section_t));
read_raw(fs, section_names_section);
sections.resize(static_cast<std::size_t>(section_names_section.sh_size));
f_.seekg(section_names_section.sh_offset);
read_raw(sections[0], static_cast<std::size_t>(section_names_section.sh_size));
sections.resize(static_cast<std::size_t>(section_names_section.sh_size) + 1, '\0');
checked_seekg(fs, section_names_section.sh_offset);
read_raw(fs, sections[0], static_cast<std::size_t>(section_names_section.sh_size));
}
void symbols_text(std::vector<symbol_t>& symbols, std::vector<char>& text) {
const header_t elf = header();
f_.seekg(elf.e_shoff);
static void symbols_text(std::ifstream& fs, std::vector<symbol_t>& symbols, std::vector<char>& text) {
std::vector<char> names;
sections_names_raw(fs, names);
symbols_text(fs, symbols, text, names);
}
static void symbols_text(std::ifstream& fs, std::vector<symbol_t>& symbols, std::vector<char>& text, const std::vector<char>& names) {
const header_t elf = header(fs);
checked_seekg(fs, elf.e_shoff);
// ".dynsym" section may not have info on symbols that could be used while self loading an executable,
// so we prefer ".symtab" section.
AddressOffsetT symtab_size = 0;
AddressOffsetT symtab_offset = 0;
AddressOffsetT strtab_size = 0;
AddressOffsetT strtab_offset = 0;
AddressOffsetT dynsym_size = 0;
AddressOffsetT dynsym_offset = 0;
AddressOffsetT dynstr_size = 0;
AddressOffsetT dynstr_offset = 0;
for (std::size_t i = 0; i < elf.e_shnum; ++i) {
section_t section;
read_raw(section);
read_raw(fs, section);
if (section.sh_name >= names.size()) {
continue;
}
const char* name = &names[section.sh_name];
if (section.sh_type == SHT_SYMTAB_) {
symbols.resize(static_cast<std::size_t>(section.sh_size / sizeof(symbol_t)));
const std::ifstream::pos_type pos = f_.tellg();
f_.seekg(section.sh_offset);
read_raw(symbols[0], static_cast<std::size_t>(section.sh_size - (section.sh_size % sizeof(symbol_t))) );
f_.seekg(pos);
if (section.sh_type == SHT_SYMTAB_ && !std::strcmp(name, ".symtab")) {
symtab_size = section.sh_size;
symtab_offset = section.sh_offset;
} else if (section.sh_type == SHT_STRTAB_) {
text.resize(static_cast<std::size_t>(section.sh_size));
const std::ifstream::pos_type pos = f_.tellg();
f_.seekg(section.sh_offset);
read_raw(text[0], static_cast<std::size_t>(section.sh_size));
f_.seekg(pos);
if (!std::strcmp(name, ".dynstr")) {
dynstr_size = section.sh_size;
dynstr_offset = section.sh_offset;
} else if (!std::strcmp(name, ".strtab")) {
strtab_size = section.sh_size;
strtab_offset = section.sh_offset;
}
} else if (section.sh_type == SHT_DYNSYM_ && !std::strcmp(name, ".dynsym")) {
dynsym_size = section.sh_size;
dynsym_offset = section.sh_offset;
}
}
if (!symtab_size || !strtab_size) {
// ".symtab" stripped from the binary and we have to fallback to ".dynsym"
symtab_size = dynsym_size;
symtab_offset = dynsym_offset;
strtab_size = dynstr_size;
strtab_offset = dynstr_offset;
}
if (!symtab_size || !strtab_size) {
return;
}
text.resize(static_cast<std::size_t>(strtab_size) + 1, '\0');
checked_seekg(fs, strtab_offset);
read_raw(fs, text[0], static_cast<std::size_t>(strtab_size));
symbols.resize(static_cast<std::size_t>(symtab_size / sizeof(symbol_t)));
checked_seekg(fs, symtab_offset);
read_raw(fs, symbols[0], static_cast<std::size_t>(symtab_size - (symtab_size % sizeof(symbol_t))) );
}
static bool is_visible(const symbol_t& sym) BOOST_NOEXCEPT {
const unsigned char visibility = (sym.st_other & 0x03);
// `(sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size` check also workarounds the
// GCC's issue https://sourceware.org/bugzilla/show_bug.cgi?id=13621
return (sym.st_other & 0x03) == STV_DEFAULT_ && (sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size;
return (visibility == STV_DEFAULT_ || visibility == STV_PROTECTED_)
&& (sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size;
}
public:
std::vector<std::string> symbols() {
static std::vector<std::string> symbols(std::ifstream& fs) {
std::vector<std::string> ret;
std::vector<symbol_t> symbols;
std::vector<char> text;
symbols_text(symbols, text);
symbols_text(fs, symbols, text);
ret.reserve(symbols.size());
for (std::size_t i = 0; i < symbols.size(); ++i) {
if (is_visible(symbols[i])) {
ret.push_back(&text[0] + symbols[i].st_name);
if (is_visible(symbols[i]) && symbols[i].st_name < text.size()) {
ret.push_back(&text[symbols[i].st_name]);
if (ret.back().empty()) {
ret.pop_back(); // Do not show empty names
}
@@ -230,35 +288,34 @@ public:
return ret;
}
std::vector<std::string> symbols(const char* section_name) {
static std::vector<std::string> symbols(std::ifstream& fs, const char* section_name) {
std::vector<std::string> ret;
std::size_t index = 0;
std::size_t ptrs_in_section_count = 0;
{
std::vector<char> names;
sections_names_raw(names);
const header_t elf = header();
std::vector<char> names;
sections_names_raw(fs, names);
for (; index < elf.e_shnum; ++index) {
section_t section;
f_.seekg(elf.e_shoff + index * sizeof(section_t));
read_raw(section);
if (!std::strcmp(&names[0] + section.sh_name, section_name)) {
if (!section.sh_entsize) {
section.sh_entsize = 1;
}
ptrs_in_section_count = static_cast<std::size_t>(section.sh_size / section.sh_entsize);
break;
const header_t elf = header(fs);
for (; index < elf.e_shnum; ++index) {
section_t section;
checked_seekg(fs, elf.e_shoff + index * sizeof(section_t));
read_raw(fs, section);
if (!std::strcmp(&names.at(section.sh_name), section_name)) {
if (!section.sh_entsize) {
section.sh_entsize = 1;
}
}
ptrs_in_section_count = static_cast<std::size_t>(section.sh_size / section.sh_entsize);
break;
}
}
std::vector<symbol_t> symbols;
std::vector<char> text;
symbols_text(symbols, text);
std::vector<char> text;
symbols_text(fs, symbols, text, names);
if (ptrs_in_section_count < symbols.size()) {
ret.reserve(ptrs_in_section_count);
@@ -267,8 +324,8 @@ public:
}
for (std::size_t i = 0; i < symbols.size(); ++i) {
if (symbols[i].st_shndx == index && is_visible(symbols[i])) {
ret.push_back(&text[0] + symbols[i].st_name);
if (symbols[i].st_shndx == index && is_visible(symbols[i]) && symbols[i].st_name < text.size()) {
ret.push_back(&text[symbols[i].st_name]);
if (ret.back().empty()) {
ret.pop_back(); // Do not show empty names
}

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -16,9 +16,10 @@
#include <algorithm>
#include <fstream>
#include <string> // for std::getline
#include <vector>
#include <boost/cstdint.hpp>
#include <boost/dll/detail/x_info_interface.hpp>
namespace boost { namespace dll { namespace detail {
@@ -157,9 +158,7 @@ typedef nlist_template<boost::uint32_t> nlist_32_;
typedef nlist_template<boost::uint64_t> nlist_64_;
template <class AddressOffsetT>
class macho_info: public x_info_interface {
std::ifstream& f_;
class macho_info {
typedef boost::dll::detail::mach_header_template<AddressOffsetT> header_t;
typedef boost::dll::detail::load_command_ load_command_t;
typedef boost::dll::detail::segment_command_template<AddressOffsetT> segment_t;
@@ -170,55 +169,51 @@ class macho_info: public x_info_interface {
BOOST_STATIC_CONSTANT(boost::uint32_t, SEGMENT_CMD_NUMBER = (sizeof(AddressOffsetT) > 4 ? load_command_types::LC_SEGMENT_64_ : load_command_types::LC_SEGMENT_));
public:
static bool parsing_supported(std::ifstream& f) {
static bool parsing_supported(std::ifstream& fs) {
static const uint32_t magic_bytes = (sizeof(AddressOffsetT) <= sizeof(uint32_t) ? 0xfeedface : 0xfeedfacf);
uint32_t magic;
f.seekg(0);
f.read(reinterpret_cast<char*>(&magic), sizeof(magic));
fs.seekg(0);
fs.read(reinterpret_cast<char*>(&magic), sizeof(magic));
return (magic_bytes == magic);
}
explicit macho_info(std::ifstream& f) BOOST_NOEXCEPT
: f_(f)
{}
private:
template <class T>
inline void read_raw(T& value, std::size_t size = sizeof(T)) const {
f_.read(reinterpret_cast<char*>(&value), size);
static void read_raw(std::ifstream& fs, T& value, std::size_t size = sizeof(T)) {
fs.read(reinterpret_cast<char*>(&value), size);
}
template <class F>
void command_finder(uint32_t cmd_num, F callback_f) {
const header_t h = header();
static void command_finder(std::ifstream& fs, uint32_t cmd_num, F callback_f) {
const header_t h = header(fs);
load_command_t command;
f_.seekg(sizeof(header_t));
fs.seekg(sizeof(header_t));
for (std::size_t i = 0; i < h.ncmds; ++i) {
const std::ifstream::pos_type pos = f_.tellg();
read_raw(command);
const std::ifstream::pos_type pos = fs.tellg();
read_raw(fs, command);
if (command.cmd != cmd_num) {
f_.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
fs.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
continue;
}
f_.seekg(pos);
callback_f(*this);
f_.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
fs.seekg(pos);
callback_f(fs);
fs.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
}
}
struct section_names_gather {
std::vector<std::string>& ret;
void operator()(const macho_info& f) const {
void operator()(std::ifstream& fs) const {
segment_t segment;
f.read_raw(segment);
read_raw(fs, segment);
section_t section;
ret.reserve(ret.size() + segment.nsects);
for (std::size_t j = 0; j < segment.nsects; ++j) {
f.read_raw(section);
read_raw(fs, section);
// `segname` goes right after the `sectname`.
// Forcing `sectname` to end on '\0'
section.segname[0] = '\0';
@@ -234,16 +229,16 @@ private:
std::vector<std::string>& ret;
std::size_t section_index;
void operator()(const macho_info& f) const {
void operator()(std::ifstream& fs) const {
symbol_header_t symbh;
f.read_raw(symbh);
read_raw(fs, symbh);
ret.reserve(ret.size() + symbh.nsyms);
nlist_t symbol;
std::string symbol_name;
for (std::size_t j = 0; j < symbh.nsyms; ++j) {
f.f_.seekg(symbh.symoff + j * sizeof(nlist_t));
f.read_raw(symbol);
fs.seekg(symbh.symoff + j * sizeof(nlist_t));
read_raw(fs, symbol);
if (!symbol.n_strx) {
continue; // Symbol has no name
}
@@ -256,8 +251,8 @@ private:
continue; // Not in the required section
}
f.f_.seekg(symbh.stroff + symbol.n_strx);
getline(f.f_, symbol_name, '\0');
fs.seekg(symbh.stroff + symbol.n_strx);
std::getline(fs, symbol_name, '\0');
if (symbol_name.empty()) {
continue;
}
@@ -273,34 +268,34 @@ private:
};
public:
std::vector<std::string> sections() {
static std::vector<std::string> sections(std::ifstream& fs) {
std::vector<std::string> ret;
section_names_gather f = { ret };
command_finder(SEGMENT_CMD_NUMBER, f);
command_finder(fs, SEGMENT_CMD_NUMBER, f);
return ret;
}
private:
inline header_t header() {
static header_t header(std::ifstream& fs) {
header_t h;
f_.seekg(0);
read_raw(h);
fs.seekg(0);
read_raw(fs, h);
return h;
}
public:
std::vector<std::string> symbols() {
static std::vector<std::string> symbols(std::ifstream& fs) {
std::vector<std::string> ret;
symbol_names_gather f = { ret, 0 };
command_finder(load_command_types::LC_SYMTAB_, f);
command_finder(fs, load_command_types::LC_SYMTAB_, f);
return ret;
}
std::vector<std::string> symbols(const char* section_name) {
static std::vector<std::string> symbols(std::ifstream& fs, const char* section_name) {
// Not very optimal solution
std::vector<std::string> ret = sections();
std::vector<std::string> ret = sections(fs);
std::vector<std::string>::iterator it = std::find(ret.begin(), ret.end(), section_name);
if (it == ret.end()) {
// No section with such name
@@ -311,7 +306,7 @@ public:
// section indexes start from 1
symbol_names_gather f = { ret, static_cast<std::size_t>(1 + (it - ret.begin())) };
ret.clear();
command_finder(load_command_types::LC_SYMTAB_, f);
command_finder(fs, load_command_types::LC_SYMTAB_, f);
return ret;
}
};

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -16,10 +16,11 @@
#include <cstring>
#include <fstream>
#include <string> // for std::getline
#include <vector>
#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/dll/detail/x_info_interface.hpp>
namespace boost { namespace dll { namespace detail {
@@ -164,24 +165,22 @@ typedef IMAGE_NT_HEADERS_template<boost::dll::detail::ULONGLONG_> IMAGE_NT_HEAD
template <class AddressOffsetT>
class pe_info: public x_info_interface {
std::ifstream& f_;
class pe_info {
typedef IMAGE_NT_HEADERS_template<AddressOffsetT> header_t;
typedef IMAGE_EXPORT_DIRECTORY_ exports_t;
typedef IMAGE_SECTION_HEADER_ section_t;
typedef IMAGE_DOS_HEADER_ dos_t;
template <class T>
inline void read_raw(T& value, std::size_t size = sizeof(T)) const {
f_.read(reinterpret_cast<char*>(&value), size);
static void read_raw(std::ifstream& fs, T& value, std::size_t size = sizeof(T)) {
fs.read(reinterpret_cast<char*>(&value), size);
}
public:
static bool parsing_supported(std::ifstream& f) {
static bool parsing_supported(std::ifstream& fs) {
dos_t dos;
f.seekg(0);
f.read(reinterpret_cast<char*>(&dos), sizeof(dos));
fs.seekg(0);
fs.read(reinterpret_cast<char*>(&dos), sizeof(dos));
// 'MZ' and 'ZM' according to Wikipedia
if (dos.e_magic != 0x4D5A && dos.e_magic != 0x5A4D) {
@@ -189,59 +188,61 @@ public:
}
header_t h;
f.seekg(dos.e_lfanew);
f.read(reinterpret_cast<char*>(&h), sizeof(h));
fs.seekg(dos.e_lfanew);
fs.read(reinterpret_cast<char*>(&h), sizeof(h));
return h.Signature == 0x00004550 // 'PE00'
&& h.OptionalHeader.Magic == (sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 0x10B : 0x20B);
}
explicit pe_info(std::ifstream& f) BOOST_NOEXCEPT
: f_(f)
{}
private:
inline header_t header() {
static header_t header(std::ifstream& fs) {
header_t h;
dos_t dos;
f_.seekg(0);
read_raw(dos);
fs.seekg(0);
read_raw(fs, dos);
f_.seekg(dos.e_lfanew);
read_raw(h);
fs.seekg(dos.e_lfanew);
read_raw(fs, h);
return h;
}
inline exports_t exports(const header_t& h) {
exports_t exports;
static exports_t exports(std::ifstream& fs, const header_t& h) {
static const unsigned int IMAGE_DIRECTORY_ENTRY_EXPORT_ = 0;
const std::size_t exp_virtual_address = h.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT_].VirtualAddress;
exports_t exports;
const std::size_t real_offset = get_file_offset(exp_virtual_address, h);
if (exp_virtual_address == 0) {
// The virtual address can be 0 in case there are no exported symbols
std::memset(&exports, 0, sizeof(exports));
return exports;
}
const std::size_t real_offset = get_file_offset(fs, exp_virtual_address, h);
BOOST_ASSERT(real_offset);
f_.seekg(real_offset);
read_raw(exports);
fs.seekg(real_offset);
read_raw(fs, exports);
return exports;
}
std::size_t get_file_offset(std::size_t virtual_address, const header_t& h) {
static std::size_t get_file_offset(std::ifstream& fs, std::size_t virtual_address, const header_t& h) {
BOOST_ASSERT(virtual_address);
section_t image_section_header;
{ // f_.seekg to the beginning on section headers
{ // fs.seekg to the beginning on section headers
dos_t dos;
f_.seekg(0);
read_raw(dos);
f_.seekg(dos.e_lfanew + sizeof(header_t));
fs.seekg(0);
read_raw(fs, dos);
fs.seekg(dos.e_lfanew + sizeof(header_t));
}
for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) {
read_raw(image_section_header);
read_raw(fs, image_section_header);
if (virtual_address >= image_section_header.VirtualAddress
&& virtual_address < image_section_header.VirtualAddress + image_section_header.SizeOfRawData)
{
@@ -253,10 +254,10 @@ private:
}
public:
std::vector<std::string> sections() {
static std::vector<std::string> sections(std::ifstream& fs) {
std::vector<std::string> ret;
const header_t h = header();
const header_t h = header(fs);
ret.reserve(h.FileHeader.NumberOfSections);
// get names, e.g: .text .rdata .data .rsrc .reloc
@@ -265,7 +266,7 @@ public:
std::memset(name_helper, 0, sizeof(name_helper));
for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) {
// There is no terminating null character if the string is exactly eight characters long
read_raw(image_section_header);
read_raw(fs, image_section_header);
std::memcpy(name_helper, image_section_header.Name, section_t::IMAGE_SIZEOF_SHORT_NAME_);
if (name_helper[0] != '/') {
@@ -281,32 +282,37 @@ public:
return ret;
}
std::vector<std::string> symbols() {
static std::vector<std::string> symbols(std::ifstream& fs) {
std::vector<std::string> ret;
const header_t h = header();
const exports_t exprt = exports(h);
const header_t h = header(fs);
const exports_t exprt = exports(fs, h);
const std::size_t exported_symbols = exprt.NumberOfNames;
const std::size_t fixed_names_addr = get_file_offset(exprt.AddressOfNames, h);
if (exported_symbols == 0) {
return ret;
}
const std::size_t fixed_names_addr = get_file_offset(fs, exprt.AddressOfNames, h);
ret.reserve(exported_symbols);
boost::dll::detail::DWORD_ name_offset;
std::string symbol_name;
for (std::size_t i = 0;i < exported_symbols;++i) {
f_.seekg(fixed_names_addr + i * sizeof(name_offset));
read_raw(name_offset);
f_.seekg(get_file_offset(name_offset, h));
getline(f_, symbol_name, '\0');
fs.seekg(fixed_names_addr + i * sizeof(name_offset));
read_raw(fs, name_offset);
fs.seekg(get_file_offset(fs, name_offset, h));
std::getline(fs, symbol_name, '\0');
ret.push_back(symbol_name);
}
return ret;
}
std::vector<std::string> symbols(const char* section_name) {
static std::vector<std::string> symbols(std::ifstream& fs, const char* section_name) {
std::vector<std::string> ret;
const header_t h = header();
const header_t h = header(fs);
std::size_t section_begin_addr = 0;
std::size_t section_end_addr = 0;
@@ -317,7 +323,7 @@ public:
std::memset(name_helper, 0, sizeof(name_helper));
for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) {
// There is no terminating null character if the string is exactly eight characters long
read_raw(image_section_header);
read_raw(fs, image_section_header);
std::memcpy(name_helper, image_section_header.Name, section_t::IMAGE_SIZEOF_SHORT_NAME_);
if (!std::strcmp(section_name, name_helper)) {
section_begin_addr = image_section_header.PointerToRawData;
@@ -330,11 +336,11 @@ public:
return ret;
}
const exports_t exprt = exports(h);
const exports_t exprt = exports(fs, h);
const std::size_t exported_symbols = exprt.NumberOfFunctions;
const std::size_t fixed_names_addr = get_file_offset(exprt.AddressOfNames, h);
const std::size_t fixed_ordinals_addr = get_file_offset(exprt.AddressOfNameOrdinals, h);
const std::size_t fixed_functions_addr = get_file_offset(exprt.AddressOfFunctions, h);
const std::size_t fixed_names_addr = get_file_offset(fs, exprt.AddressOfNames, h);
const std::size_t fixed_ordinals_addr = get_file_offset(fs, exprt.AddressOfNameOrdinals, h);
const std::size_t fixed_functions_addr = get_file_offset(fs, exprt.AddressOfFunctions, h);
ret.reserve(exported_symbols);
boost::dll::detail::DWORD_ ptr;
@@ -342,22 +348,22 @@ public:
std::string symbol_name;
for (std::size_t i = 0;i < exported_symbols;++i) {
// getting ordinal
f_.seekg(fixed_ordinals_addr + i * sizeof(ordinal));
read_raw(ordinal);
fs.seekg(fixed_ordinals_addr + i * sizeof(ordinal));
read_raw(fs, ordinal);
// getting function addr
f_.seekg(fixed_functions_addr + ordinal * sizeof(ptr));
read_raw(ptr);
ptr = static_cast<boost::dll::detail::DWORD_>( get_file_offset(ptr, h) );
fs.seekg(fixed_functions_addr + ordinal * sizeof(ptr));
read_raw(fs, ptr);
ptr = static_cast<boost::dll::detail::DWORD_>( get_file_offset(fs, ptr, h) );
if (ptr >= section_end_addr || ptr < section_begin_addr) {
continue;
}
f_.seekg(fixed_names_addr + i * sizeof(ptr));
read_raw(ptr);
f_.seekg(get_file_offset(ptr, h));
getline(f_, symbol_name, '\0');
fs.seekg(fixed_names_addr + i * sizeof(ptr));
read_raw(fs, ptr);
fs.seekg(get_file_offset(fs, ptr, h));
std::getline(fs, symbol_name, '\0');
ret.push_back(symbol_name);
}
@@ -374,7 +380,7 @@ public:
MSVCR110D.dll
*/
/*
std::vector<std::string> depend_of(boost::dll::fs::error_code &ec) BOOST_NOEXCEPT {
static std::vector<std::string> depend_of(boost::dll::fs::error_code &ec) BOOST_NOEXCEPT {
std::vector<std::string> ret;
IMAGE_DOS_HEADER* image_dos_header = (IMAGE_DOS_HEADER*)native();

View File

@@ -1,5 +1,5 @@
// Copyright 2014-2015 Renato Tegon Forti, Antony Polukhin.
// Copyright 2016-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2016-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -35,8 +35,8 @@ namespace boost { namespace dll { namespace detail {
// Iterate through all images currently in memory
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/dyld.3.html
const std::size_t count = _dyld_image_count(); // not thread safe: other thread my [un]load images
for (std::size_t i = 0; i <= count; ++i) {
const uint32_t count = _dyld_image_count(); // not thread safe: other thread my [un]load images
for (uint32_t i = 0; i <= count; ++i) {
// on last iteration `i` is equal to `count` which is out of range, so `_dyld_get_image_name`
// will return NULL. `dlopen(NULL, RTLD_LAZY)` call will open the current executable.
const char* image_name = _dyld_get_image_name(i);

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -62,15 +62,16 @@ public:
static boost::dll::fs::path decorate(const boost::dll::fs::path & sl) {
boost::dll::fs::path actual_path = (
std::strncmp(sl.filename().string().c_str(), "lib", 3)
? boost::dll::fs::path((sl.has_parent_path() ? sl.parent_path() / L"lib" : L"lib").native() + sl.filename().native())
? boost::dll::fs::path((sl.has_parent_path() ? sl.parent_path() / "lib" : "lib").native() + sl.filename().native())
: sl
);
actual_path += suffix();
return actual_path;
}
void load(boost::dll::fs::path sl, load_mode::type mode, boost::dll::fs::error_code &ec) {
void load(boost::dll::fs::path sl, load_mode::type portable_mode, boost::dll::fs::error_code &ec) {
typedef int native_mode_t;
native_mode_t native_mode = static_cast<native_mode_t>(portable_mode);
unload();
// Do not allow opening NULL paths. User must use program_location() instead
@@ -84,20 +85,20 @@ public:
}
// Fixing modes
if (!(mode & load_mode::rtld_now)) {
mode |= load_mode::rtld_lazy;
if (!(native_mode & load_mode::rtld_now)) {
native_mode |= load_mode::rtld_lazy;
}
if (!(mode & load_mode::rtld_global)) {
mode |= load_mode::rtld_local;
if (!(native_mode & load_mode::rtld_global)) {
native_mode |= load_mode::rtld_local;
}
#if BOOST_OS_LINUX || BOOST_OS_ANDROID
if (!sl.has_parent_path() && !(mode & load_mode::search_system_folders)) {
if (!sl.has_parent_path() && !(native_mode & load_mode::search_system_folders)) {
sl = "." / sl;
}
#else
if (!sl.is_absolute() && !(mode & load_mode::search_system_folders)) {
if (!sl.is_absolute() && !(native_mode & load_mode::search_system_folders)) {
boost::dll::fs::error_code current_path_ec;
boost::dll::fs::path prog_loc = boost::dll::fs::current_path(current_path_ec);
if (!current_path_ec) {
@@ -107,14 +108,14 @@ public:
}
#endif
mode &= ~load_mode::search_system_folders;
native_mode = static_cast<unsigned>(native_mode) & ~static_cast<unsigned>(load_mode::search_system_folders);
// Trying to open with appended decorations
if (!!(mode & load_mode::append_decorations)) {
mode &= ~load_mode::append_decorations;
if (!!(native_mode & load_mode::append_decorations)) {
native_mode = static_cast<unsigned>(native_mode) & ~static_cast<unsigned>(load_mode::append_decorations);
boost::dll::fs::path actual_path = decorate(sl);
handle_ = dlopen(actual_path.c_str(), static_cast<native_mode_t>(mode));
handle_ = dlopen(actual_path.c_str(), native_mode);
if (handle_) {
boost::dll::detail::reset_dlerror();
return;
@@ -131,7 +132,7 @@ public:
}
// Opening by exactly specified path
handle_ = dlopen(sl.c_str(), static_cast<native_mode_t>(mode));
handle_ = dlopen(sl.c_str(), native_mode);
if (handle_) {
boost::dll::detail::reset_dlerror();
return;
@@ -153,7 +154,7 @@ public:
// returned handle is for the main program.
ec.clear();
boost::dll::detail::reset_dlerror();
handle_ = dlopen(NULL, static_cast<native_mode_t>(mode));
handle_ = dlopen(NULL, native_mode);
if (!handle_) {
ec = boost::dll::fs::make_error_code(
boost::dll::fs::errc::bad_file_descriptor

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt

View File

@@ -12,13 +12,13 @@
#include <typeinfo>
#include <cstring>
#include <boost/dll/config.hpp>
#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
#if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows
#include <boost/winapi/basic_types.hpp>
#endif
namespace boost { namespace dll { namespace detail {
#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
#if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows
#if defined ( _WIN64 )

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -31,27 +31,28 @@ namespace boost { namespace dll { namespace detail {
BOOST_STATIC_CONSTANT(boost::winapi::DWORD_, ERROR_INSUFFICIENT_BUFFER_ = 0x7A);
BOOST_STATIC_CONSTANT(boost::winapi::DWORD_, DEFAULT_PATH_SIZE_ = 260);
// On success, GetModuleFileNameW() doesn't reset last error to ERROR_SUCCESS. Resetting it manually.
boost::winapi::GetLastError();
// If `handle` parameter is NULL, GetModuleFileName retrieves the path of the
// executable file of the current process.
boost::winapi::WCHAR_ path_hldr[DEFAULT_PATH_SIZE_];
boost::winapi::GetModuleFileNameW(handle, path_hldr, DEFAULT_PATH_SIZE_);
ec = boost::dll::detail::last_error_code();
if (!ec) {
const boost::winapi::DWORD_ ret = boost::winapi::GetModuleFileNameW(handle, path_hldr, DEFAULT_PATH_SIZE_);
if (ret) {
// On success, GetModuleFileNameW() doesn't reset last error to ERROR_SUCCESS. Resetting it manually.
ec.clear();
return boost::dll::fs::path(path_hldr);
}
ec = boost::dll::detail::last_error_code();
for (unsigned i = 2; i < 1025 && static_cast<boost::winapi::DWORD_>(ec.value()) == ERROR_INSUFFICIENT_BUFFER_; i *= 2) {
std::wstring p(DEFAULT_PATH_SIZE_ * i, L'\0');
const std::size_t size = boost::winapi::GetModuleFileNameW(handle, &p[0], DEFAULT_PATH_SIZE_ * i);
ec = boost::dll::detail::last_error_code();
if (!ec) {
if (size) {
// On success, GetModuleFileNameW() doesn't reset last error to ERROR_SUCCESS. Resetting it manually.
ec.clear();
p.resize(size);
return boost::dll::fs::path(p);
}
ec = boost::dll::detail::last_error_code();
}
// Error other than ERROR_INSUFFICIENT_BUFFER_ occurred or failed to allocate buffer big enough.

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2023.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -56,11 +56,12 @@ public:
return actual_path;
}
void load(boost::dll::fs::path sl, load_mode::type mode, boost::dll::fs::error_code &ec) {
void load(boost::dll::fs::path sl, load_mode::type portable_mode, boost::dll::fs::error_code &ec) {
typedef boost::winapi::DWORD_ native_mode_t;
native_mode_t native_mode = static_cast<native_mode_t>(portable_mode);
unload();
if (!sl.is_absolute() && !(mode & load_mode::search_system_folders)) {
if (!sl.is_absolute() && !(native_mode & load_mode::search_system_folders)) {
boost::dll::fs::error_code current_path_ec;
boost::dll::fs::path prog_loc = boost::dll::fs::current_path(current_path_ec);
@@ -69,13 +70,13 @@ public:
sl.swap(prog_loc);
}
}
mode &= ~load_mode::search_system_folders;
native_mode = static_cast<unsigned>(native_mode) & ~static_cast<unsigned>(load_mode::search_system_folders);
// Trying to open with appended decorations
if (!!(mode & load_mode::append_decorations)) {
mode &= ~load_mode::append_decorations;
if (!!(native_mode & load_mode::append_decorations)) {
native_mode = static_cast<unsigned>(native_mode) & ~static_cast<unsigned>(load_mode::append_decorations);
if (load_impl(decorate(sl), static_cast<native_mode_t>(mode), ec)) {
if (load_impl(decorate(sl), native_mode, ec)) {
return;
}
@@ -85,7 +86,7 @@ public:
? sl.parent_path() / L"lib"
: L"lib"
).native() + sl.filename().native() + suffix().native();
if (load_impl(mingw_load_path, static_cast<native_mode_t>(mode), ec)) {
if (load_impl(mingw_load_path, native_mode, ec)) {
return;
}
}
@@ -98,9 +99,9 @@ public:
// we have some path. So we do not check for path, only for extension. We can not be sure that
// such behavior remain across all platforms, so we add L"." by hand.
if (sl.has_extension()) {
handle_ = boost::winapi::LoadLibraryExW(sl.c_str(), 0, static_cast<native_mode_t>(mode));
handle_ = boost::winapi::LoadLibraryExW(sl.c_str(), 0, native_mode);
} else {
handle_ = boost::winapi::LoadLibraryExW((sl.native() + L".").c_str(), 0, static_cast<native_mode_t>(mode));
handle_ = boost::winapi::LoadLibraryExW((sl.native() + L".").c_str(), 0, native_mode);
}
// LoadLibraryExW method is capable of self loading from program_location() path. No special actions

View File

@@ -1,32 +0,0 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2019 Antony Polukhin.
//
// 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_DLL_DETAIL_X_INFO_INTERFACE_HPP
#define BOOST_DLL_DETAIL_X_INFO_INTERFACE_HPP
#include <boost/dll/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <string>
#include <vector>
namespace boost { namespace dll { namespace detail {
class x_info_interface {
public:
virtual std::vector<std::string> sections() = 0;
virtual std::vector<std::string> symbols() = 0;
virtual std::vector<std::string> symbols(const char* section_name) = 0;
virtual ~x_info_interface() BOOST_NOEXCEPT {}
};
}}} // namespace boost::dll::detail
#endif // BOOST_DLL_DETAIL_X_INFO_INTERFACE_HPP