diff options
Diffstat (limited to 'boost/dll/detail')
-rw-r--r-- | boost/dll/detail/aggressive_ptr_cast.hpp | 130 | ||||
-rw-r--r-- | boost/dll/detail/ctor_dtor.hpp | 176 | ||||
-rw-r--r-- | boost/dll/detail/demangling/demangle_symbol.hpp | 83 | ||||
-rw-r--r-- | boost/dll/detail/demangling/itanium.hpp | 285 | ||||
-rw-r--r-- | boost/dll/detail/demangling/mangled_storage_base.hpp | 118 | ||||
-rw-r--r-- | boost/dll/detail/demangling/msvc.hpp | 400 | ||||
-rw-r--r-- | boost/dll/detail/elf_info.hpp | 285 | ||||
-rw-r--r-- | boost/dll/detail/get_mem_fn_type.hpp | 40 | ||||
-rw-r--r-- | boost/dll/detail/macho_info.hpp | 321 | ||||
-rw-r--r-- | boost/dll/detail/pe_info.hpp | 427 | ||||
-rw-r--r-- | boost/dll/detail/posix/path_from_handle.hpp | 169 | ||||
-rw-r--r-- | boost/dll/detail/posix/program_location_impl.hpp | 140 | ||||
-rw-r--r-- | boost/dll/detail/posix/shared_library_impl.hpp | 215 | ||||
-rw-r--r-- | boost/dll/detail/system_error.hpp | 56 | ||||
-rw-r--r-- | boost/dll/detail/windows/path_from_handle.hpp | 62 | ||||
-rw-r--r-- | boost/dll/detail/windows/shared_library_impl.hpp | 177 | ||||
-rw-r--r-- | boost/dll/detail/x_info_interface.hpp | 32 |
17 files changed, 3116 insertions, 0 deletions
diff --git a/boost/dll/detail/aggressive_ptr_cast.hpp b/boost/dll/detail/aggressive_ptr_cast.hpp new file mode 100644 index 0000000000..a8887f4382 --- /dev/null +++ b/boost/dll/detail/aggressive_ptr_cast.hpp @@ -0,0 +1,130 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015-2016 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_AGGRESSIVE_PTR_CAST_HPP +#define BOOST_DLL_DETAIL_AGGRESSIVE_PTR_CAST_HPP + +#include <boost/config.hpp> +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include <boost/static_assert.hpp> +#include <boost/type_traits/is_pointer.hpp> +#include <boost/type_traits/is_member_pointer.hpp> +#include <boost/type_traits/is_void.hpp> +#include <boost/type_traits/is_reference.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/cstdint.hpp> // boost::uintptr_t +#include <cstring> // std::memcpy + +namespace boost { namespace dll { namespace detail { + +// GCC warns when reinterpret_cast between function pointer and object pointer occur. +// This method suppress the warnings and ensures that such casts are safe. +template <class To, class From> +BOOST_FORCEINLINE typename boost::disable_if_c<boost::is_member_pointer<To>::value || boost::is_reference<To>::value || boost::is_member_pointer<From>::value, To>::type + aggressive_ptr_cast(From v) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT_MSG( + boost::is_pointer<To>::value && boost::is_pointer<From>::value, + "`agressive_ptr_cast` function must be used only for pointer casting." + ); + + BOOST_STATIC_ASSERT_MSG( + boost::is_void< typename boost::remove_pointer<To>::type >::value + || boost::is_void< typename boost::remove_pointer<From>::type >::value, + "`agressive_ptr_cast` function must be used only for casting to or from void pointers." + ); + + BOOST_STATIC_ASSERT_MSG( + sizeof(v) == sizeof(To), + "Pointer to function and pointer to object differ in size on your platform." + ); + + return reinterpret_cast<To>( + reinterpret_cast<boost::uintptr_t>(v) + ); +} + +template <class To, class From> +BOOST_FORCEINLINE typename boost::disable_if_c<!boost::is_reference<To>::value || boost::is_member_pointer<From>::value, To>::type + aggressive_ptr_cast(From v) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT_MSG( + boost::is_pointer<From>::value, + "`agressive_ptr_cast` function must be used only for pointer casting." + ); + + BOOST_STATIC_ASSERT_MSG( + boost::is_void< typename boost::remove_pointer<From>::type >::value, + "`agressive_ptr_cast` function must be used only for casting to or from void pointers." + ); + + BOOST_STATIC_ASSERT_MSG( + sizeof(v) == sizeof(typename boost::remove_reference<To>::type*), + "Pointer to function and pointer to object differ in size on your platform." + ); + + return static_cast<To>( + *reinterpret_cast<typename boost::remove_reference<To>::type*>( + *reinterpret_cast<boost::uintptr_t*>( + reinterpret_cast<unsigned char*>( + v + ) + ) + ) + ); +} + +template <class To, class From> +BOOST_FORCEINLINE typename boost::disable_if_c<!boost::is_member_pointer<To>::value || boost::is_member_pointer<From>::value, To>::type + aggressive_ptr_cast(From v) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT_MSG( + boost::is_pointer<From>::value, + "`agressive_ptr_cast` function must be used only for pointer casting." + ); + + BOOST_STATIC_ASSERT_MSG( + boost::is_void< typename boost::remove_pointer<From>::type >::value, + "`agressive_ptr_cast` function must be used only for casting to or from void pointers." + ); + + To res = 0; + std::memcpy(&res, &v, sizeof(To)); + return res; +} + +template <class To, class From> +BOOST_FORCEINLINE typename boost::disable_if_c<boost::is_member_pointer<To>::value || !boost::is_member_pointer<From>::value, To>::type + aggressive_ptr_cast(From v) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT_MSG( + boost::is_pointer<To>::value, + "`agressive_ptr_cast` function must be used only for pointer casting." + ); + + BOOST_STATIC_ASSERT_MSG( + boost::is_void< typename boost::remove_pointer<To>::type >::value, + "`agressive_ptr_cast` function must be used only for casting to or from void pointers." + ); + + BOOST_STATIC_ASSERT_MSG( + !sizeof(From), + "Casting from member pointers to void pointer is not implemnted in `agressive_ptr_cast`." + ); + + return 0; +} + +}}} // boost::dll::detail + +#endif // BOOST_DLL_DETAIL_AGGRESSIVE_PTR_CAST_HPP + diff --git a/boost/dll/detail/ctor_dtor.hpp b/boost/dll/detail/ctor_dtor.hpp new file mode 100644 index 0000000000..5950d9e60a --- /dev/null +++ b/boost/dll/detail/ctor_dtor.hpp @@ -0,0 +1,176 @@ +// Copyright 2016 Klemens Morgenstern, 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) + +// For more information, see http://www.boost.org + +#ifndef INCLUDE_BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ +#define INCLUDE_BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ + +#include <boost/config.hpp> +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#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) +# include <boost/dll/detail/demangling/msvc.hpp> +#else +# include <boost/dll/detail/demangling/itanium.hpp> +#endif + +namespace boost { namespace dll { namespace detail { + +/*! + * This class stores a constructor. + * + * In some compilers there are several constructors in code, which may include an allocating one. + * This can be used if the imported class shall be put on the heap, which is why the class provied both types. + */ +template<typename Signature> +struct constructor; + +template<typename Class, typename ...Args> +struct constructor<Class(Args...)> { + typedef typename detail::get_mem_fn_type<Class, void(Args...)>::mem_fn standard_t; + typedef Class*(*allocating_t)(Args...); + + + //! The standard, i.e. not allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_standard instead. + standard_t standard; + //! The allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_allocating instead. + allocating_t allocating; + + //! Call the standard contructor + void call_standard (Class * const ptr, Args...args){ (ptr->*standard)(static_cast<Args>(args)...); } + + //! Call the deleting destructor + Class * call_allocating(Args...args){ return allocating(static_cast<Args>(args)...); } + + + //! True if a allocating constructor could be loaded. + bool has_allocating() const { return allocating != nullptr; } + + //! False if neither the allocating nor the standard constructor is available. + bool is_empty() const { return !((allocating == nullptr) && (standard != nullptr)) ; } + + constructor() = delete; + constructor(const constructor &) = default; + + explicit constructor(standard_t standard, allocating_t allocating = nullptr) + : standard(standard) + , allocating(allocating) + {} +}; + + + +template <typename Class> +struct destructor { +#if !defined(BOOST_MSVC) && !defined(BOOST_MSVC_VER) + typedef void( *type)(Class* const); +#elif !defined(_WIN64) + typedef void(__thiscall * type)(Class* const); +#else + typedef void(__cdecl * type)(Class* const); +#endif + + typedef type standard_t; + typedef type deleting_t; + + //! The standard, i.e. not deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_standard instead. + standard_t standard; + //! The deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_deallocating instead. + deleting_t deleting; + + //! Call the standard contructor + void call_standard(Class * const ptr){ standard(ptr); } + + //! Call the deleting destructor + void call_deleting(Class * const ptr){ deleting(ptr); } + + //! True if a deleting destructor could be loaded. + bool has_deleting() const { return deleting != nullptr; } + + //! False if neither the deleting nor the standard destructor is available. + bool is_empty() const { return !((deleting == nullptr) && (standard != nullptr)) ; } + destructor() = delete; + + //! Copy destructor. + destructor(const destructor &) = default; + + //! Construct it from both the standard destructor and the allocating destructor + explicit destructor(const standard_t &standard, const deleting_t &deleting = nullptr) + : standard(standard) + , deleting(deleting) + {} +}; + +#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER) +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; + standard_t ctor = lib.template get<standard_t>(ct); + return constructor<Signature>(ctor); +} + +template<typename Class, typename Lib> +destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) { + typedef typename destructor<Class>::standard_t standard_t; + standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt); + return destructor<Class>(dtor); +} + +#else + +template<typename Signature, typename Lib> +constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) { + typedef typename constructor<Signature>::standard_t stand; + typedef typename constructor<Signature>::allocating_t alloc; + + stand s = nullptr; + alloc a = nullptr; + + //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor + + if (!ct.C1.empty()) { + s = lib.template get<stand>(ct.C1); + } + + if (!ct.C3.empty()) { + a = lib.template get<alloc>(ct.C3); + } + + return constructor<Signature>(s,a); +} + +template<typename Class, typename Lib> +destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) { + typedef typename destructor<Class>::standard_t stand; + typedef typename destructor<Class>::deleting_t delet; + + stand s = nullptr; + delet d = nullptr; + + //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor + if (!dt.D1.empty()) { + s = &lib.template get< typename boost::remove_pointer<stand>::type >(dt.D1); + } + + if (!dt.D0.empty()) { + d = &lib.template get< typename boost::remove_pointer<delet>::type >(dt.D0); + } + + return destructor<Class>(s,d); + +} + +#endif + +}}} // namespace boost::dll::detail + +#endif /* INCLUDE_BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */ diff --git a/boost/dll/detail/demangling/demangle_symbol.hpp b/boost/dll/detail/demangling/demangle_symbol.hpp new file mode 100644 index 0000000000..e0590b38fa --- /dev/null +++ b/boost/dll/detail/demangling/demangle_symbol.hpp @@ -0,0 +1,83 @@ +// Copyright 2015 Klemens Morgenstern +// +// This file provides a demangling for function names, i.e. entry points of a dll. +// +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DLL_DEMANGLE_SYMBOL_HPP_ +#define BOOST_DLL_DEMANGLE_SYMBOL_HPP_ + +#include <boost/config.hpp> +#include <string> +#include <algorithm> + +#if defined(BOOST_MSVC) || defined(BOOST_MSVC_FULL_VER) +#include <boost/detail/winapi/dbghelp.hpp> + +namespace boost +{ +namespace dll +{ +namespace detail +{ + + +inline std::string demangle_symbol(const char *mangled_name) +{ + char unmangled_name[2048]; + + ::boost::detail::winapi:: + UnDecorateSymbolName(mangled_name, unmangled_name, 2048, 0); + + return std::string(unmangled_name); +} +inline std::string demangle_symbol(const std::string& mangled_name) +{ + return demangle_symbol(mangled_name.c_str()); +} + + +}}} +#else + +#include <boost/core/demangle.hpp> + +namespace boost +{ +namespace dll +{ +namespace detail +{ + +inline std::string demangle_symbol(const char *mangled_name) +{ + + if (*mangled_name == '_') + { + //because it start's with an underline _ + auto dm = boost::core::demangle(mangled_name); + if (!dm.empty()) + return dm; + else + return (mangled_name); + } + + //could not demangled + return ""; + + +} + +//for my personal convinience +inline std::string demangle_symbol(const std::string& mangled_name) +{ + return demangle_symbol(mangled_name.c_str()); +} + + +}}} + +#endif + +#endif /* INCLUDE_BOOST_DEMANGLE_HPP_ */ diff --git a/boost/dll/detail/demangling/itanium.hpp b/boost/dll/detail/demangling/itanium.hpp new file mode 100644 index 0000000000..356a5eca82 --- /dev/null +++ b/boost/dll/detail/demangling/itanium.hpp @@ -0,0 +1,285 @@ +// Copyright 2016 Klemens Morgenstern +// +// 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_DEMANGLING_ITANIUM_HPP_ +#define BOOST_DLL_DETAIL_DEMANGLING_ITANIUM_HPP_ + +#include <boost/dll/detail/demangling/mangled_storage_base.hpp> +#include <iterator> +#include <algorithm> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/is_volatile.hpp> +#include <boost/type_traits/is_rvalue_reference.hpp> +#include <boost/type_traits/is_lvalue_reference.hpp> +#include <boost/type_traits/function_traits.hpp> + + +namespace boost { namespace dll { namespace detail { + + + +class mangled_storage_impl : public mangled_storage_base +{ + template<typename T> + struct dummy {}; + + template<typename Return, typename ...Args> + std::vector<std::string> get_func_params(dummy<Return(Args...)>) + { + return {get_name<Args>()...}; + } + template<typename Return, typename ...Args> + std::string get_return_type(dummy<Return(Args...)>) + { + return get_name<Return>(); + } +public: + using mangled_storage_base::mangled_storage_base; + struct ctor_sym + { + std::string C1; + std::string C2; + std::string C3; + + bool empty() const + { + return C1.empty() && C2.empty() && C3.empty(); + } + }; + + struct dtor_sym + { + std::string D0; + std::string D1; + std::string D2; + bool empty() const + { + return D0.empty() && D1.empty() && D2.empty(); + } + }; + + template<typename T> + std::string get_variable(const std::string &name); + + template<typename Func> + std::string get_function(const std::string &name); + + template<typename Class, typename Func> + std::string get_mem_fn(const std::string &name); + + template<typename Signature> + ctor_sym get_constructor(); + + template<typename Class> + dtor_sym get_destructor(); + +}; + + + +namespace parser +{ + + inline std::string const_rule_impl(true_type ) {return " const";} + inline std::string const_rule_impl(false_type) {return "";} + template<typename T> + auto const_rule() {using t = is_const<typename remove_reference<T>::type>; return const_rule_impl(t());} + + inline std::string volatile_rule_impl(true_type ) {return " volatile";} + inline std::string volatile_rule_impl(false_type) {return "";} + template<typename T> + auto volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return volatile_rule_impl(t());} + + inline std::string reference_rule_impl(false_type, false_type) {return "";} + 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> + auto 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> + auto 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); + } + + 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()); + } + + template<typename Return> + std::string arg_list(const mangled_storage_impl &, Return (*)()) + { + return ""; + } +} + + + +template<typename T> std::string mangled_storage_impl::get_variable(const std::string &name) +{ + auto found = std::find_if(storage_.begin(), storage_.end(), + [&](const entry& e) {return e.demangled == name;}); + + if (found != storage_.end()) + return found->mangled; + else + return ""; +} + +template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) +{ + using func_type = Func*; + + auto matcher = name + '(' + parser::arg_list(*this, func_type()) + ')'; + + auto found = std::find_if(storage_.begin(), storage_.end(), [&](const entry& e) {return e.demangled == matcher;}); + if (found != storage_.end()) + return found->mangled; + else + return ""; + +} + +template<typename Class, typename Func> +std::string mangled_storage_impl::get_mem_fn(const std::string &name) +{ + using namespace parser; + + using func_type = Func*; + + std::string cname = get_name<Class>(); + + 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;}); + + if (found != storage_.end()) + return found->mangled; + else + return ""; + +} + + +template<typename Signature> +auto mangled_storage_impl::get_constructor() -> ctor_sym +{ + using namespace parser; + + using func_type = Signature*; + + std::string ctor_name; // = class_name + "::" + name; + std::string unscoped_cname; //the unscoped class-name + { + auto class_name = get_return_type(dummy<Signature>()); + auto pos = class_name.rfind("::"); + if (pos == std::string::npos) + { + ctor_name = class_name+ "::" +class_name ; + unscoped_cname = class_name; + } + else + { + unscoped_cname = class_name.substr(pos+2) ; + ctor_name = class_name+ "::" + unscoped_cname; + } + } + + auto matcher = + ctor_name + '(' + parser::arg_list(*this, func_type()) + ')'; + + + std::vector<entry> findings; + std::copy_if(storage_.begin(), storage_.end(), + std::back_inserter(findings), [&](const entry& e) {return e.demangled == matcher;}); + + ctor_sym ct; + + for (auto & e : findings) + { + + if (e.mangled.find(unscoped_cname +"C1E") != std::string::npos) + ct.C1 = e.mangled; + else if (e.mangled.find(unscoped_cname +"C2E") != std::string::npos) + ct.C2 = e.mangled; + else if (e.mangled.find(unscoped_cname +"C3E") != std::string::npos) + ct.C3 = e.mangled; + } + return ct; +} + +template<typename Class> +auto mangled_storage_impl::get_destructor() -> dtor_sym +{ + std::string dtor_name; // = class_name + "::" + name; + std::string unscoped_cname; //the unscoped class-name + { + auto class_name = get_name<Class>(); + auto pos = class_name.rfind("::"); + if (pos == std::string::npos) + { + dtor_name = class_name+ "::~" + class_name + "()"; + unscoped_cname = class_name; + } + else + { + unscoped_cname = class_name.substr(pos+2) ; + dtor_name = class_name+ "::~" + unscoped_cname + "()"; + } + } + + auto d0 = unscoped_cname + "D0Ev"; + auto d1 = unscoped_cname + "D1Ev"; + auto d2 = unscoped_cname + "D2Ev"; + + dtor_sym dt; + //this is so simple, i don#t need a predicate + for (auto & s : storage_) + { + //alright, name fits + if (s.demangled == dtor_name) + { + if (s.mangled.find(d0) != std::string::npos) + dt.D0 = s.mangled; + else if (s.mangled.find(d1) != std::string::npos) + dt.D1 = s.mangled; + else if (s.mangled.find(d2) != std::string::npos) + dt.D2 = s.mangled; + + } + } + return dt; + +} + +}}} + + +#endif /* INCLUDE_BOOST_DLL_DETAIL_DEMANGLING_ITANIUM_HPP_ */ diff --git a/boost/dll/detail/demangling/mangled_storage_base.hpp b/boost/dll/detail/demangling/mangled_storage_base.hpp new file mode 100644 index 0000000000..e4bf3753f9 --- /dev/null +++ b/boost/dll/detail/demangling/mangled_storage_base.hpp @@ -0,0 +1,118 @@ +// Copyright 2016 Klemens Morgenstern +// +// 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_MANGLE_STORAGE_BASE_HPP_ +#define BOOST_DLL_DETAIL_MANGLE_STORAGE_BASE_HPP_ + +#include <vector> +#include <string> +#include <map> +#include <boost/dll/detail/demangling/demangle_symbol.hpp> +#include <boost/dll/library_info.hpp> +#include <boost/type_index/stl_type_index.hpp> + +namespace boost { namespace dll { namespace detail { + +///stores the mangled names with the demangled name. +struct mangled_storage_base +{ + struct entry + { + std::string mangled; + std::string demangled; + entry() = default; + entry(const std::string & m, const std::string &d) : mangled(m), demangled(d) {} + entry(const entry&) = default; + entry(entry&&) = default; + entry &operator= (const entry&) = default; + entry &operator= (entry&&) = default; + }; +protected: + std::vector<entry> storage_; + ///if a unknown class is imported it can be overloaded by this type + std::map<boost::typeindex::stl_type_index, std::string> aliases_; +public: + void assign(const mangled_storage_base & storage) + { + aliases_ = storage.aliases_; + storage_ = storage.storage_; + } + void swap( mangled_storage_base & storage) + { + aliases_.swap(storage.aliases_); + storage_.swap(storage.storage_); + } + void clear() + { + storage_.clear(); + aliases_.clear(); + } + const std::vector<entry> & get_storage() const {return storage_;}; + template<typename T> + std::string get_name() const + { + auto tx = boost::typeindex::stl_type_index::type_id<T>(); + auto val = (aliases_.count(tx) > 0) ? aliases_.at(tx) : tx.pretty_name(); + return val; + } + + mangled_storage_base() = default; + mangled_storage_base(mangled_storage_base&&) = default; + mangled_storage_base(const mangled_storage_base&) = default; + + mangled_storage_base(const std::vector<std::string> & symbols) { add_symbols(symbols);} + + explicit mangled_storage_base(library_info & li) : mangled_storage_base(li.symbols()) {} + + explicit mangled_storage_base( + const boost::filesystem::path& library_path, + bool throw_if_not_native_format = true) + : mangled_storage_base(library_info(library_path, throw_if_not_native_format).symbols()) + { + + } + + void load(library_info & li) { storage_.clear(); add_symbols(li.symbols()); }; + void load(const boost::filesystem::path& library_path, + bool throw_if_not_native_format = true) + { + storage_.clear(); + add_symbols(library_info(library_path, throw_if_not_native_format).symbols()); + }; + + /*! Allows do add a class as alias, if the class imported is not known + * in this binary. + * @tparam Alias The Alias type + * @param The name to create the alias for. + * + * @note There can be multiple aliases, this is on purpose. + */ + template<typename Alias> void add_alias(const std::string& name) + { + aliases_.emplace( + boost::typeindex::stl_type_index::type_id<Alias>(), + name + ); + } + void add_symbols(const std::vector<std::string> & symbols) + { + for (auto & sym : symbols) + { + auto dm = demangle_symbol(sym); + if (!dm.empty()) + storage_.emplace_back(sym, dm); + else + storage_.emplace_back(sym, sym); + } + } + + +}; + + +}}} + +#endif /* INCLUDE_BOOST_DLL_DETAIL_MANGLE_STORAGE_HPP_ */ diff --git a/boost/dll/detail/demangling/msvc.hpp b/boost/dll/detail/demangling/msvc.hpp new file mode 100644 index 0000000000..4cab143266 --- /dev/null +++ b/boost/dll/detail/demangling/msvc.hpp @@ -0,0 +1,400 @@ +// Copyright 2016 Klemens Morgenstern +// +// 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_DEMANGLING_MSVC_HPP_ +#define BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ + +#include <boost/dll/detail/demangling/mangled_storage_base.hpp> +#include <iterator> +#include <algorithm> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/is_volatile.hpp> +#include <boost/type_traits/is_lvalue_reference.hpp> +#include <boost/type_traits/is_rvalue_reference.hpp> +#include <boost/type_traits/function_traits.hpp> +#include <boost/type_traits/remove_reference.hpp> + +#include <boost/spirit/home/x3.hpp> + +namespace boost { namespace dll { namespace detail { + +class mangled_storage_impl : public mangled_storage_base +{ + template<typename T> + struct dummy {}; + + template<typename Return, typename ...Args> + std::vector<std::string> get_func_params(dummy<Return(Args...)>) + { + return {get_name<Args>()...}; + } + template<typename Return, typename ...Args> + std::string get_return_type(dummy<Return(Args...)>) + { + return get_name<Return>(); + } + //function to remove preceeding 'class ' or 'struct ' if the are given in this format. + + inline static void trim_typename(std::string & val); +public: + using ctor_sym = std::string; + using dtor_sym = std::string; + + using mangled_storage_base::mangled_storage_base; + + template<typename T> + std::string get_variable(const std::string &name); + + template<typename Func> + std::string get_function(const std::string &name); + + template<typename Class, typename Func> + std::string get_mem_fn(const std::string &name); + + template<typename Signature> + ctor_sym get_constructor(); + + template<typename Class> + dtor_sym get_destructor(); + + template<typename T> //overload, does not need to virtual. + std::string get_name() const + { + auto nm = mangled_storage_base::get_name<T>(); + trim_typename(nm); + return nm; + } +}; + +void mangled_storage_impl::trim_typename(std::string & val) +{ + //remove preceeding class or struct, because you might want to use a struct as class, et vice versa + if (val.size() >= 6) + { + using namespace std; + static constexpr char class_ [7] = "class "; + static constexpr char struct_[8] = "struct "; + + if (equal(begin(class_), end(class_)-1, val.begin())) //aklright, starts with 'class ' + val.erase(0, 6); + else if (val.size() >= 7) + if (equal(begin(struct_), end(struct_)-1, val.begin())) + val.erase(0, 7); + } +} + + +namespace parser +{ + namespace x3 = spirit::x3; + + auto ptr_rule_impl(std::integral_constant<std::size_t, 32>) + { + return -((-x3::space) >> "__ptr32"); + } + auto ptr_rule_impl(std::integral_constant<std::size_t, 64>) + { + return -((-x3::space) >> "__ptr64"); + } + + auto ptr_rule() { return ptr_rule_impl(std::integral_constant<std::size_t, sizeof(std::size_t)*8>());} + + auto const visibility = ("public:" | x3::lit("protected:") | "private:"); + auto const virtual_ = x3::space >> "virtual"; + auto const static_ = x3::space >> x3::lit("static") ; + + auto const_rule_impl(true_type ) {return x3::space >> "const";}; + auto const_rule_impl(false_type) {return x3::eps;}; + template<typename T> + auto const_rule() {using t = is_const<typename remove_reference<T>::type>; return const_rule_impl(t());} + + auto volatile_rule_impl(true_type ) {return x3::space >> "volatile";}; + auto volatile_rule_impl(false_type) {return x3::eps;}; + template<typename T> + auto volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return volatile_rule_impl(t());} + + + auto inv_const_rule_impl(true_type ) {return "const" >> x3::space ;}; + auto inv_const_rule_impl(false_type) {return x3::eps;}; + template<typename T> + auto inv_const_rule() {using t = is_const<typename remove_reference<T>::type>; return inv_const_rule_impl(t());} + + auto inv_volatile_rule_impl(true_type ) {return "volatile" >> x3::space;}; + auto inv_volatile_rule_impl(false_type) {return x3::eps;}; + template<typename T> + auto inv_volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return inv_volatile_rule_impl(t());} + + + auto reference_rule_impl(false_type, false_type) {return x3::eps;} + auto reference_rule_impl(true_type, false_type) {return x3::space >>"&" ;} + auto reference_rule_impl(false_type, true_type ) {return x3::space >>"&&" ;} + + + template<typename T> + auto reference_rule() {using t_l = is_lvalue_reference<T>; using t_r = is_rvalue_reference<T>; return reference_rule_impl(t_l(), t_r());} + + auto const class_ = ("class" | x3::lit("struct")); + + //it takes a string, because it may be overloaded. + template<typename T> + auto type_rule(const std::string & type_name) + { + using namespace std; + + return -(class_ >> x3::space)>> x3::string(type_name) >> + const_rule<T>() >> + volatile_rule<T>() >> + reference_rule<T>() >> + ptr_rule(); + } + template<> + auto type_rule<void>(const std::string &) { return x3::string("void"); }; + + auto const cdecl_ = "__cdecl" >> x3::space; + auto const stdcall = "__stdcall" >> x3::space; +#if defined(_WIN64)//seems to be necessary by msvc 14-x64 + auto const thiscall = "__cdecl" >> x3::space; +#else + auto const thiscall = "__thiscall" >> x3::space; +#endif + + template<typename Return, typename Arg> + auto arg_list(const mangled_storage_impl & ms, Return (*)(Arg)) + { + using namespace std; + + return type_rule<Arg>(ms.get_name<Arg>()); + } + + template<typename Return, typename First, typename Second, typename ...Args> + auto arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...)) + { + + using next_type = Return (*)(Second, Args...); + return type_rule<First>(ms.get_name<First>()) >> x3::char_(',') >> arg_list(ms, next_type()); + } + + template<typename Return> + auto arg_list(const mangled_storage_impl & ms, Return (*)()) + { + return x3::string("void"); + } +} + + +template<typename T> std::string mangled_storage_impl::get_variable(const std::string &name) +{ + using namespace std; + using namespace boost; + + namespace x3 = spirit::x3; + using namespace parser; + + auto type_name = get_name<T>(); + + auto matcher = + -(visibility >> static_ >> x3::space) >> //it may be a static class-member + parser::type_rule<T>(type_name) >> x3::space >> + name; + + auto predicate = [&](const mangled_storage_base::entry & e) + { + if (e.demangled == name)//maybe not mangled, + return true; + + auto itr = e.demangled.begin(); + auto end = e.demangled.end(); + auto res = x3::parse(itr, end, matcher); + return res && (itr == end); + }; + + auto found = std::find_if(storage_.begin(), storage_.end(), predicate); + + if (found != storage_.end()) + return found->mangled; + else + return ""; +} + +template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) +{ + namespace x3 = spirit::x3; + using namespace parser; + using func_type = Func*; + using return_type = typename function_traits<Func>::result_type; + std::string return_type_name = get_name<return_type>(); + + + auto matcher = + -(visibility >> static_ >> x3::space) >> //it may be a static class-member, which does however not have the static attribute. + parser::type_rule<return_type>(return_type_name) >> x3::space >> + cdecl_ >> //cdecl declaration for methods. stdcall cannot be + name >> x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule(); + + + auto predicate = [&](const mangled_storage_base::entry & e) + { + if (e.demangled == name)//maybe not mangled, + return true; + + auto itr = e.demangled.begin(); + auto end = e.demangled.end(); + auto res = x3::parse(itr, end, matcher); + + return res && (itr == end); + }; + + auto found = std::find_if(storage_.begin(), storage_.end(), predicate); + + if (found != storage_.end()) + return found->mangled; + else + return ""; + +} + +template<typename Class, typename Func> +std::string mangled_storage_impl::get_mem_fn(const std::string &name) +{ + namespace x3 = spirit::x3; + using namespace parser; + using func_type = Func*; + using return_type = typename function_traits<Func>::result_type; + auto return_type_name = get_name<return_type>(); + + + auto cname = get_name<Class>(); + + auto matcher = + visibility >> -virtual_ >> x3::space >> + parser::type_rule<return_type>(return_type_name) >> x3::space >> + thiscall >> //cdecl declaration for methods. stdcall cannot be + cname >> "::" >> name >> + x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> + inv_const_rule<Class>() >> inv_volatile_rule<Class>() >> parser::ptr_rule(); + + auto predicate = [&](const mangled_storage_base::entry & e) + { + auto itr = e.demangled.begin(); + auto end = e.demangled.end(); + auto res = x3::parse(itr, end, matcher); + + return res && (itr == end); + }; + + auto found = std::find_if(storage_.begin(), storage_.end(), predicate); + + if (found != storage_.end()) + return found->mangled; + else + return ""; +} + + +template<typename Signature> +auto mangled_storage_impl::get_constructor() -> ctor_sym +{ + namespace x3 = spirit::x3; + using namespace parser; + + using func_type = Signature*; + + + std::string ctor_name; // = class_name + "::" + name; + std::string unscoped_cname; //the unscoped class-name + { + auto class_name = get_return_type(dummy<Signature>()); + auto pos = class_name.rfind("::"); + if (pos == std::string::npos) + { + ctor_name = class_name+ "::" + class_name ; + unscoped_cname = class_name; + } + else + { + unscoped_cname = class_name.substr(pos+2) ; + ctor_name = class_name+ "::" + unscoped_cname; + } + } + + auto matcher = + visibility >> x3::space >> + thiscall >> //cdecl declaration for methods. stdcall cannot be + ctor_name >> + x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule(); + + + auto predicate = [&](const mangled_storage_base::entry & e) + { + auto itr = e.demangled.begin(); + auto end = e.demangled.end(); + auto res = x3::parse(itr, end, matcher); + + return res && (itr == end); + }; + + auto f = std::find_if(storage_.begin(), storage_.end(), predicate); + + if (f != storage_.end()) + return f->mangled; + else + return ""; +} + +template<typename Class> +auto mangled_storage_impl::get_destructor() -> dtor_sym +{ + namespace x3 = spirit::x3; + using namespace parser; + std::string dtor_name; // = class_name + "::" + name; + std::string unscoped_cname; //the unscoped class-name + { + auto class_name = get_name<Class>(); + auto pos = class_name.rfind("::"); + if (pos == std::string::npos) + { + dtor_name = class_name+ "::~" + class_name + "(void)"; + unscoped_cname = class_name; + } + else + { + unscoped_cname = class_name.substr(pos+2) ; + dtor_name = class_name+ "::~" + unscoped_cname + "(void)"; + } + } + + auto matcher = + visibility >> -virtual_ >> x3::space >> + thiscall >> //cdecl declaration for methods. stdcall cannot be + dtor_name >> parser::ptr_rule(); + + + auto predicate = [&](const mangled_storage_base::entry & e) + { + auto itr = e.demangled.begin(); + auto end = e.demangled.end(); + auto res = x3::parse(itr, end, matcher); + + return res && (itr == end); + }; + + auto found = std::find_if(storage_.begin(), storage_.end(), predicate); + + + if (found != storage_.end()) + return found->mangled; + else + return ""; +} + + + + +}}} + + + +#endif /* INCLUDE_BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ */ diff --git a/boost/dll/detail/elf_info.hpp b/boost/dll/detail/elf_info.hpp new file mode 100644 index 0000000000..325df9cb10 --- /dev/null +++ b/boost/dll/detail/elf_info.hpp @@ -0,0 +1,285 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015 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_POSIX_ELF_INFO_HPP +#define BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP + +#include <boost/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include <cstring> +#include <boost/filesystem/fstream.hpp> +#include <boost/dll/detail/x_info_interface.hpp> + +namespace boost { namespace dll { namespace detail { + +template <class AddressOffsetT> +struct Elf_Ehdr_template { + unsigned char e_ident[16]; /* Magic number and other info */ + boost::uint16_t e_type; /* Object file type */ + boost::uint16_t e_machine; /* Architecture */ + boost::uint32_t e_version; /* Object file version */ + AddressOffsetT e_entry; /* Entry point virtual address */ + AddressOffsetT e_phoff; /* Program header table file offset */ + AddressOffsetT e_shoff; /* Section header table file offset */ + boost::uint32_t e_flags; /* Processor-specific flags */ + boost::uint16_t e_ehsize; /* ELF header size in bytes */ + boost::uint16_t e_phentsize; /* Program header table entry size */ + boost::uint16_t e_phnum; /* Program header table entry count */ + boost::uint16_t e_shentsize; /* Section header table entry size */ + boost::uint16_t e_shnum; /* Section header table entry count */ + boost::uint16_t e_shstrndx; /* Section header string table index */ +}; + +typedef Elf_Ehdr_template<boost::uint32_t> Elf32_Ehdr_; +typedef Elf_Ehdr_template<boost::uint64_t> Elf64_Ehdr_; + +template <class AddressOffsetT> +struct Elf_Shdr_template { + boost::uint32_t sh_name; /* Section name (string tbl index) */ + boost::uint32_t sh_type; /* Section type */ + AddressOffsetT sh_flags; /* Section flags */ + AddressOffsetT sh_addr; /* Section virtual addr at execution */ + AddressOffsetT sh_offset; /* Section file offset */ + AddressOffsetT sh_size; /* Section size in bytes */ + boost::uint32_t sh_link; /* Link to another section */ + boost::uint32_t sh_info; /* Additional section information */ + AddressOffsetT sh_addralign; /* Section alignment */ + AddressOffsetT sh_entsize; /* Entry size if section holds table */ +}; + +typedef Elf_Shdr_template<boost::uint32_t> Elf32_Shdr_; +typedef Elf_Shdr_template<boost::uint64_t> Elf64_Shdr_; + +template <class AddressOffsetT> +struct Elf_Sym_template; + +template <> +struct Elf_Sym_template<boost::uint32_t> { + typedef boost::uint32_t AddressOffsetT; + + boost::uint32_t st_name; /* Symbol name (string tbl index) */ + AddressOffsetT st_value; /* Symbol value */ + AddressOffsetT st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + boost::uint16_t st_shndx; /* Section index */ +}; + +template <> +struct Elf_Sym_template<boost::uint64_t> { + typedef boost::uint64_t AddressOffsetT; + + boost::uint32_t st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + boost::uint16_t st_shndx; /* Section index */ + AddressOffsetT st_value; /* Symbol value */ + AddressOffsetT st_size; /* Symbol size */ +}; + + +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 { + boost::filesystem::ifstream& f_; + + 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(unsigned char, STB_LOCAL_ = 0); /* Local symbol */ + BOOST_STATIC_CONSTANT(unsigned char, STB_GLOBAL_ = 1); /* Global symbol */ + BOOST_STATIC_CONSTANT(unsigned char, STB_WEAK_ = 2); /* Weak symbol */ + + /* Symbol visibility specification encoded in the st_other field. */ + BOOST_STATIC_CONSTANT(unsigned char, STV_DEFAULT_ = 0); /* Default symbol visibility rules */ + BOOST_STATIC_CONSTANT(unsigned char, STV_INTERNAL_ = 1); /* Processor specific hidden class */ + BOOST_STATIC_CONSTANT(unsigned char, STV_HIDDEN_ = 2); /* Sym unavailable in other modules */ + BOOST_STATIC_CONSTANT(unsigned char, STV_PROTECTED_ = 3); /* Not preemptible, not exported */ + +public: + static bool parsing_supported(boost::filesystem::ifstream& f) { + const unsigned char magic_bytes[5] = { + 0x7f, 'E', 'L', 'F', sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 1 : 2 + }; + + unsigned char ch; + f.seekg(0); + for (std::size_t i = 0; i < sizeof(magic_bytes); ++i) { + f >> ch; + if (ch != magic_bytes[i]) { + return false; + } + } + + return true; + } + + explicit elf_info(boost::filesystem::ifstream& f) BOOST_NOEXCEPT + : f_(f) + {} + + std::vector<std::string> sections() { + std::vector<std::string> ret; + std::vector<char> names; + sections_names_raw(names); + + const char* name_begin = &names[0]; + const char* const name_end = name_begin + names.size(); + ret.reserve(header().e_shnum); + do { + ret.push_back(name_begin); + name_begin += ret.back().size() + 1; + } 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); + } + + inline header_t header() { + header_t elf; + + f_.seekg(0); + read_raw(elf); + + return elf; + } + + void sections_names_raw(std::vector<char>& sections) { + const header_t elf = header(); + + section_t section_names_section; + f_.seekg(elf.e_shoff + elf.e_shstrndx * sizeof(section_t)); + read_raw(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)); + } + + void symbols_text(std::vector<symbol_t>& symbols, std::vector<char>& text) { + const header_t elf = header(); + f_.seekg(elf.e_shoff); + + for (std::size_t i = 0; i < elf.e_shnum; ++i) { + section_t section; + read_raw(section); + + if (section.sh_type == SHT_SYMTAB_) { + symbols.resize(static_cast<std::size_t>(section.sh_size / sizeof(symbol_t))); + + const boost::filesystem::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); + } else if (section.sh_type == SHT_STRTAB_) { + text.resize(static_cast<std::size_t>(section.sh_size)); + + const boost::filesystem::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); + } + } + } + + static bool is_visible(const symbol_t& sym) BOOST_NOEXCEPT { + // `(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; + } + +public: + std::vector<std::string> symbols() { + std::vector<std::string> ret; + + std::vector<symbol_t> symbols; + std::vector<char> text; + symbols_text(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 (ret.back().empty()) { + ret.pop_back(); // Do not show empty names + } + } + } + + return ret; + } + + std::vector<std::string> symbols(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(); + + 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; + } + } + } + + std::vector<symbol_t> symbols; + std::vector<char> text; + symbols_text(symbols, text); + + if (ptrs_in_section_count < symbols.size()) { + ret.reserve(ptrs_in_section_count); + } else { + ret.reserve(symbols.size()); + } + + 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 (ret.back().empty()) { + ret.pop_back(); // Do not show empty names + } + } + } + + return ret; + } +}; + +typedef elf_info<boost::uint32_t> elf_info32; +typedef elf_info<boost::uint64_t> elf_info64; + +}}} // namespace boost::dll::detail + +#endif // BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP diff --git a/boost/dll/detail/get_mem_fn_type.hpp b/boost/dll/detail/get_mem_fn_type.hpp new file mode 100644 index 0000000000..65cead20bc --- /dev/null +++ b/boost/dll/detail/get_mem_fn_type.hpp @@ -0,0 +1,40 @@ +// Copyright 2016 Klemens Morgenstern +// +// 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) + +// For more information, see http://www.boost.org + +#ifndef BOOST_DLL_SMART_LIBRARY_HPP_ +#define BOOST_DLL_SMART_LIBRARY_HPP_ + +namespace boost { namespace dll { namespace detail { + +template<typename Class, typename Func> +struct get_mem_fn_type; + +template<typename Class, typename Return, typename ...Args> +struct get_mem_fn_type<Class, Return(Args...)> { + typedef Return (Class::*mem_fn)(Args...); +}; + +template<typename Class, typename Return, typename ...Args> +struct get_mem_fn_type<const Class, Return(Args...)> { + typedef Return (Class::*mem_fn)(Args...) const ; +}; + +template<typename Class, typename Return, typename ...Args> +struct get_mem_fn_type<volatile Class, Return(Args...)> { + typedef Return (Class::*mem_fn)(Args...) volatile; +}; + +template<typename Class, typename Return, typename ...Args> +struct get_mem_fn_type<const volatile Class, Return(Args...)> { + typedef Return (Class::*mem_fn)(Args...) const volatile ; +}; + +}}} // namespace boost::dll::detail + + +#endif /* INCLUDE_BOOST_DLL_SMART_LIBRARY_HPP_ */ diff --git a/boost/dll/detail/macho_info.hpp b/boost/dll/detail/macho_info.hpp new file mode 100644 index 0000000000..6911908238 --- /dev/null +++ b/boost/dll/detail/macho_info.hpp @@ -0,0 +1,321 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015 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_MACHO_INFO_HPP +#define BOOST_DLL_DETAIL_MACHO_INFO_HPP + +#include <boost/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include <boost/filesystem/fstream.hpp> +#include <boost/dll/detail/x_info_interface.hpp> + +namespace boost { namespace dll { namespace detail { + +typedef int integer_t; +typedef int vm_prot_t; +typedef integer_t cpu_type_t; +typedef integer_t cpu_subtype_t; + +template <class AddressOffsetT> +struct mach_header_template { + boost::uint32_t magic; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + boost::uint32_t filetype; + boost::uint32_t ncmds; + boost::uint32_t sizeofcmds; + boost::uint32_t flags[sizeof(AddressOffsetT) / sizeof(uint32_t)]; // Flags and reserved +}; + +typedef mach_header_template<boost::uint32_t> mach_header_32_; +typedef mach_header_template<boost::uint64_t> mach_header_64_; + +struct load_command_ { + boost::uint32_t cmd; /* type of command */ + boost::uint32_t cmdsize; +}; + +struct load_command_types { + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_ = 0x1); /* segment of this file to be mapped */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SYMTAB_ = 0x2); /* link-edit stab symbol table info */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SYMSEG_ = 0x3); /* link-edit gdb symbol table info (obsolete) */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_THREAD_ = 0x4); /* thread */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_UNIXTHREAD_ = 0x5); /* unix thread (includes a stack) */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOADFVMLIB_ = 0x6); /* load a specified fixed VM shared library */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_IDFVMLIB_ = 0x7); /* fixed VM shared library identification */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_IDENT_ = 0x8); /* object identification info (obsolete) */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_FVMFILE_ = 0x9); /* fixed VM file inclusion (internal use) */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREPAGE_ = 0xa); /* prepage command (internal use) */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYSYMTAB_ = 0xb); /* dynamic link-edit symbol table info */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_DYLIB_ = 0xc); /* load a dynamically linked shared library */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ID_DYLIB_ = 0xd); /* dynamically linked shared lib ident */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_DYLINKER_ = 0xe); /* load a dynamic linker */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ID_DYLINKER_ = 0xf); /* dynamic linker identification */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREBOUND_DYLIB_ = 0x10); /* modules prebound for a dynamically linked shared library */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ROUTINES_ = 0x11); /* image routines */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_FRAMEWORK_ = 0x12); /* sub framework */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_UMBRELLA_ = 0x13); /* sub umbrella */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_CLIENT_ = 0x14); /* sub client */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_LIBRARY_ = 0x15); /* sub library */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_TWOLEVEL_HINTS_ = 0x16); /* two-level namespace lookup hints */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREBIND_CKSUM_ = 0x17); /* prebind checksum */ +/* + * After MacOS X 10.1 when a new load command is added that is required to be + * understood by the dynamic linker for the image to execute properly the + * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic + * linker sees such a load command it it does not understand will issue a + * "unknown load command required for execution" error and refuse to use the + * image. Other load commands without this bit that are not understood will + * simply be ignored. + */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_REQ_DYLD_ = 0x80000000); + +/* + * load a dynamically linked shared library that is allowed to be missing + * (all symbols are weak imported). + */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_WEAK_DYLIB_ = (0x18 | LC_REQ_DYLD_)); + + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_64_ = 0x19); /* 64-bit segment of this file to be mapped */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ROUTINES_64_ = 0x1a); /* 64-bit image routines */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_UUID_ = 0x1b); /* the uuid */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_RPATH_ = (0x1c | LC_REQ_DYLD_)); /* runpath additions */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_CODE_SIGNATURE_ = 0x1d); /* local of code signature */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_SPLIT_INFO_= 0x1e); /* local of info to split segments */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_REEXPORT_DYLIB_ = (0x1f | LC_REQ_DYLD_)); /* load and re-export dylib */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LAZY_LOAD_DYLIB_ = 0x20); /* delay load of dylib until first use */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ENCRYPTION_INFO_ = 0x21); /* encrypted segment information */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYLD_INFO_ = 0x22); /* compressed dyld information */ + BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYLD_INFO_ONLY_ = (0x22|LC_REQ_DYLD_)); /* compressed dyld information only */ +}; + +template <class AddressOffsetT> +struct segment_command_template { + boost::uint32_t cmd; /* LC_SEGMENT_ */ + boost::uint32_t cmdsize; /* includes sizeof section structs */ + char segname[16]; /* segment name */ + AddressOffsetT vmaddr; /* memory address of this segment */ + AddressOffsetT vmsize; /* memory size of this segment */ + AddressOffsetT fileoff; /* file offset of this segment */ + AddressOffsetT filesize; /* amount to map from the file */ + vm_prot_t maxprot; /* maximum VM protection */ + vm_prot_t initprot; /* initial VM protection */ + boost::uint32_t nsects; /* number of sections in segment */ + boost::uint32_t flags; /* flags */ +}; + +typedef segment_command_template<boost::uint32_t> segment_command_32_; +typedef segment_command_template<boost::uint64_t> segment_command_64_; + +template <class AddressOffsetT> +struct section_template { + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + AddressOffsetT addr; /* memory address of this section */ + AddressOffsetT size; /* size in bytes of this section */ + boost::uint32_t offset; /* file offset of this section */ + boost::uint32_t align; /* section alignment (power of 2) */ + boost::uint32_t reloff; /* file offset of relocation entries */ + boost::uint32_t nreloc; /* number of relocation entries */ + boost::uint32_t flags; /* flags (section type and attributes)*/ + boost::uint32_t reserved[1 + sizeof(AddressOffsetT) / sizeof(uint32_t)]; +}; + +typedef section_template<boost::uint32_t> section_32_; +typedef section_template<boost::uint64_t> section_64_; + +struct symtab_command_ { + boost::uint32_t cmd; /* LC_SYMTAB_ */ + boost::uint32_t cmdsize; /* sizeof(struct symtab_command) */ + boost::uint32_t symoff; /* symbol table offset */ + boost::uint32_t nsyms; /* number of symbol table entries */ + boost::uint32_t stroff; /* string table offset */ + boost::uint32_t strsize; /* string table size in bytes */ +}; + +template <class AddressOffsetT> +struct nlist_template { + boost::uint32_t n_strx; + boost::uint8_t n_type; + boost::uint8_t n_sect; + boost::uint16_t n_desc; + AddressOffsetT n_value; +}; + +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 { + boost::filesystem::ifstream& f_; + + 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; + typedef boost::dll::detail::section_template<AddressOffsetT> section_t; + typedef boost::dll::detail::symtab_command_ symbol_header_t; + typedef boost::dll::detail::nlist_template<AddressOffsetT> nlist_t; + + 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(boost::filesystem::ifstream& f) { + 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)); + return (magic_bytes == magic); + } + + explicit macho_info(boost::filesystem::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); + } + + template <class F> + void command_finder(uint32_t cmd_num, F callback_f) { + const header_t h = header(); + load_command_t command; + f_.seekg(sizeof(header_t)); + for (std::size_t i = 0; i < h.ncmds; ++i) { + const boost::filesystem::ifstream::pos_type pos = f_.tellg(); + read_raw(command); + if (command.cmd != cmd_num) { + f_.seekg(pos + static_cast<boost::filesystem::ifstream::pos_type>(command.cmdsize)); + continue; + } + + f_.seekg(pos); + callback_f(*this); + f_.seekg(pos + static_cast<boost::filesystem::ifstream::pos_type>(command.cmdsize)); + } + } + + struct section_names_gather { + std::vector<std::string>& ret; + + void operator()(const macho_info& f) const { + segment_t segment; + f.read_raw(segment); + + section_t section; + ret.reserve(ret.size() + segment.nsects); + for (std::size_t j = 0; j < segment.nsects; ++j) { + f.read_raw(section); + // `segname` goes right after the `sectname`. + // Forcing `sectname` to end on '\0' + section.segname[0] = '\0'; + ret.push_back(section.sectname); + if (ret.back().empty()) { + ret.pop_back(); // Do not show empty names + } + } + } + }; + + struct symbol_names_gather { + std::vector<std::string>& ret; + std::size_t section_index; + + void operator()(const macho_info& f) const { + symbol_header_t symbh; + f.read_raw(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); + if (!symbol.n_strx) { + continue; // Symbol has no name + } + + if ((symbol.n_type & 0x0e) != 0xe || !symbol.n_sect) { + continue; // Symbol has no section + } + + if (section_index && section_index != symbol.n_sect) { + continue; // Not in the required section + } + + f.f_.seekg(symbh.stroff + symbol.n_strx); + getline(f.f_, symbol_name, '\0'); + if (symbol_name.empty()) { + continue; + } + + if (symbol_name[0] == '_') { + // Linker adds additional '_' symbol. Could not find official docs for that case. + ret.push_back(symbol_name.c_str() + 1); + } else { + ret.push_back(symbol_name); + } + } + } + }; + +public: + std::vector<std::string> sections() { + std::vector<std::string> ret; + section_names_gather f = { ret }; + command_finder(SEGMENT_CMD_NUMBER, f); + return ret; + } + +private: + inline header_t header() { + header_t h; + + f_.seekg(0); + read_raw(h); + + return h; + } + +public: + std::vector<std::string> symbols() { + std::vector<std::string> ret; + symbol_names_gather f = { ret, 0 }; + command_finder(load_command_types::LC_SYMTAB_, f); + return ret; + } + + std::vector<std::string> symbols(const char* section_name) { + // Not very optimal solution + std::vector<std::string> ret = sections(); + std::vector<std::string>::iterator it = std::find(ret.begin(), ret.end(), section_name); + if (it == ret.end()) { + // No section with such name + ret.clear(); + return ret; + } + + // 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); + return ret; + } +}; + +typedef macho_info<boost::uint32_t> macho_info32; +typedef macho_info<boost::uint64_t> macho_info64; + +}}} // namespace boost::dll::detail + +#endif // BOOST_DLL_DETAIL_MACHO_INFO_HPP diff --git a/boost/dll/detail/pe_info.hpp b/boost/dll/detail/pe_info.hpp new file mode 100644 index 0000000000..7f1584a656 --- /dev/null +++ b/boost/dll/detail/pe_info.hpp @@ -0,0 +1,427 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015 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_WINDOWS_PE_INFO_HPP +#define BOOST_DLL_DETAIL_WINDOWS_PE_INFO_HPP + +#include <boost/config.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include <boost/filesystem/fstream.hpp> +#include <boost/dll/detail/x_info_interface.hpp> + +namespace boost { namespace dll { namespace detail { + +// reference: +// http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/ +// http://msdn.microsoft.com/en-us/magazine/ms809762.aspx +// http://msdn.microsoft.com/en-us/magazine/cc301808.aspx +// + +// Basic Windows typedefs. We can not use <boost/detail/winapi/basic_types.hpp> header +// because that header must be included only on Windows platform +typedef unsigned char BYTE_; +typedef unsigned short WORD_; +typedef unsigned long DWORD_; +typedef long LONG_; +typedef unsigned long ULONG_; +typedef boost::int64_t LONGLONG_; +typedef boost::uint64_t ULONGLONG_; + +struct IMAGE_DOS_HEADER_ { // 32/64 independent header + boost::dll::detail::WORD_ e_magic; // Magic number + boost::dll::detail::WORD_ e_cblp; // Bytes on last page of file + boost::dll::detail::WORD_ e_cp; // Pages in file + boost::dll::detail::WORD_ e_crlc; // Relocations + boost::dll::detail::WORD_ e_cparhdr; // Size of header in paragraphs + boost::dll::detail::WORD_ e_minalloc; // Minimum extra paragraphs needed + boost::dll::detail::WORD_ e_maxalloc; // Maximum extra paragraphs needed + boost::dll::detail::WORD_ e_ss; // Initial (relative) SS value + boost::dll::detail::WORD_ e_sp; // Initial SP value + boost::dll::detail::WORD_ e_csum; // Checksum + boost::dll::detail::WORD_ e_ip; // Initial IP value + boost::dll::detail::WORD_ e_cs; // Initial (relative) CS value + boost::dll::detail::WORD_ e_lfarlc; // File address of relocation table + boost::dll::detail::WORD_ e_ovno; // Overlay number + boost::dll::detail::WORD_ e_res[4]; // Reserved words + boost::dll::detail::WORD_ e_oemid; // OEM identifier (for e_oeminfo) + boost::dll::detail::WORD_ e_oeminfo; // OEM information; e_oemid specific + boost::dll::detail::WORD_ e_res2[10]; // Reserved words + boost::dll::detail::LONG_ e_lfanew; // File address of new exe header +}; + +struct IMAGE_FILE_HEADER_ { // 32/64 independent header + boost::dll::detail::WORD_ Machine; + boost::dll::detail::WORD_ NumberOfSections; + boost::dll::detail::DWORD_ TimeDateStamp; + boost::dll::detail::DWORD_ PointerToSymbolTable; + boost::dll::detail::DWORD_ NumberOfSymbols; + boost::dll::detail::WORD_ SizeOfOptionalHeader; + boost::dll::detail::WORD_ Characteristics; +}; + +struct IMAGE_DATA_DIRECTORY_ { // 32/64 independent header + boost::dll::detail::DWORD_ VirtualAddress; + boost::dll::detail::DWORD_ Size; +}; + +struct IMAGE_EXPORT_DIRECTORY_ { // 32/64 independent header + boost::dll::detail::DWORD_ Characteristics; + boost::dll::detail::DWORD_ TimeDateStamp; + boost::dll::detail::WORD_ MajorVersion; + boost::dll::detail::WORD_ MinorVersion; + boost::dll::detail::DWORD_ Name; + boost::dll::detail::DWORD_ Base; + boost::dll::detail::DWORD_ NumberOfFunctions; + boost::dll::detail::DWORD_ NumberOfNames; + boost::dll::detail::DWORD_ AddressOfFunctions; + boost::dll::detail::DWORD_ AddressOfNames; + boost::dll::detail::DWORD_ AddressOfNameOrdinals; +}; + +struct IMAGE_SECTION_HEADER_ { // 32/64 independent header + static const std::size_t IMAGE_SIZEOF_SHORT_NAME_ = 8; + + boost::dll::detail::BYTE_ Name[IMAGE_SIZEOF_SHORT_NAME_]; + union { + boost::dll::detail::DWORD_ PhysicalAddress; + boost::dll::detail::DWORD_ VirtualSize; + } Misc; + boost::dll::detail::DWORD_ VirtualAddress; + boost::dll::detail::DWORD_ SizeOfRawData; + boost::dll::detail::DWORD_ PointerToRawData; + boost::dll::detail::DWORD_ PointerToRelocations; + boost::dll::detail::DWORD_ PointerToLinenumbers; + boost::dll::detail::WORD_ NumberOfRelocations; + boost::dll::detail::WORD_ NumberOfLinenumbers; + boost::dll::detail::DWORD_ Characteristics; +}; + + +template <class AddressOffsetT> +struct IMAGE_OPTIONAL_HEADER_template { + static const std::size_t IMAGE_NUMBEROF_DIRECTORY_ENTRIES_ = 16; + + boost::dll::detail::WORD_ Magic; + boost::dll::detail::BYTE_ MajorLinkerVersion; + boost::dll::detail::BYTE_ MinorLinkerVersion; + boost::dll::detail::DWORD_ SizeOfCode; + boost::dll::detail::DWORD_ SizeOfInitializedData; + boost::dll::detail::DWORD_ SizeOfUninitializedData; + boost::dll::detail::DWORD_ AddressOfEntryPoint; + union { + boost::dll::detail::DWORD_ BaseOfCode; + unsigned char padding_[sizeof(AddressOffsetT) == 8 ? 4 : 8]; // in x64 version BaseOfData does not exist + } BaseOfCode_and_BaseOfData; + + AddressOffsetT ImageBase; + boost::dll::detail::DWORD_ SectionAlignment; + boost::dll::detail::DWORD_ FileAlignment; + boost::dll::detail::WORD_ MajorOperatingSystemVersion; + boost::dll::detail::WORD_ MinorOperatingSystemVersion; + boost::dll::detail::WORD_ MajorImageVersion; + boost::dll::detail::WORD_ MinorImageVersion; + boost::dll::detail::WORD_ MajorSubsystemVersion; + boost::dll::detail::WORD_ MinorSubsystemVersion; + boost::dll::detail::DWORD_ Win32VersionValue; + boost::dll::detail::DWORD_ SizeOfImage; + boost::dll::detail::DWORD_ SizeOfHeaders; + boost::dll::detail::DWORD_ CheckSum; + boost::dll::detail::WORD_ Subsystem; + boost::dll::detail::WORD_ DllCharacteristics; + AddressOffsetT SizeOfStackReserve; + AddressOffsetT SizeOfStackCommit; + AddressOffsetT SizeOfHeapReserve; + AddressOffsetT SizeOfHeapCommit; + boost::dll::detail::DWORD_ LoaderFlags; + boost::dll::detail::DWORD_ NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY_ DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES_]; +}; + +typedef IMAGE_OPTIONAL_HEADER_template<boost::dll::detail::DWORD_> IMAGE_OPTIONAL_HEADER32_; +typedef IMAGE_OPTIONAL_HEADER_template<boost::dll::detail::ULONGLONG_> IMAGE_OPTIONAL_HEADER64_; + +template <class AddressOffsetT> +struct IMAGE_NT_HEADERS_template { + boost::dll::detail::DWORD_ Signature; + IMAGE_FILE_HEADER_ FileHeader; + IMAGE_OPTIONAL_HEADER_template<AddressOffsetT> OptionalHeader; +}; + +typedef IMAGE_NT_HEADERS_template<boost::dll::detail::DWORD_> IMAGE_NT_HEADERS32_; +typedef IMAGE_NT_HEADERS_template<boost::dll::detail::ULONGLONG_> IMAGE_NT_HEADERS64_; + + +template <class AddressOffsetT> +class pe_info: public x_info_interface { + boost::filesystem::ifstream& f_; + + 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); + } + +public: + static bool parsing_supported(boost::filesystem::ifstream& f) { + dos_t dos; + f.seekg(0); + f.read(reinterpret_cast<char*>(&dos), sizeof(dos)); + + // 'MZ' and 'ZM' according to Wikipedia + if (dos.e_magic != 0x4D5A && dos.e_magic != 0x5A4D) { + return false; + } + + header_t h; + f.seekg(dos.e_lfanew); + f.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(boost::filesystem::ifstream& f) BOOST_NOEXCEPT + : f_(f) + {} + +private: + inline header_t header() { + header_t h; + + dos_t dos; + f_.seekg(0); + read_raw(dos); + + f_.seekg(dos.e_lfanew); + read_raw(h); + + return h; + } + + inline exports_t exports(const header_t& h) { + exports_t exports; + + static const unsigned int IMAGE_DIRECTORY_ENTRY_EXPORT_ = 0; + const std::size_t exp_virtual_address = h.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT_].VirtualAddress; + + const std::size_t real_offset = get_file_offset(exp_virtual_address, h); + BOOST_ASSERT(real_offset); + + f_.seekg(real_offset); + read_raw(exports); + + return exports; + } + + std::size_t get_file_offset(std::size_t virtual_address, const header_t& h) { + section_t image_section_header; + + { // f_.seekg to the beginning on section headers + dos_t dos; + f_.seekg(0); + read_raw(dos); + f_.seekg(dos.e_lfanew + sizeof(header_t)); + } + + for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) { + read_raw(image_section_header); + if (virtual_address >= image_section_header.VirtualAddress + && virtual_address < image_section_header.VirtualAddress + image_section_header.SizeOfRawData) + { + return image_section_header.PointerToRawData + virtual_address - image_section_header.VirtualAddress; + } + } + + return 0; + } + +public: + std::vector<std::string> sections() { + std::vector<std::string> ret; + + const header_t h = header(); + ret.reserve(h.FileHeader.NumberOfSections); + + // get names, e.g: .text .rdata .data .rsrc .reloc + section_t image_section_header; + char name_helper[section_t::IMAGE_SIZEOF_SHORT_NAME_ + 1]; + 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); + std::memcpy(name_helper, image_section_header.Name, section_t::IMAGE_SIZEOF_SHORT_NAME_); + + if (name_helper[0] != '/') { + ret.push_back(name_helper); + } else { + // For longer names, image_section_header.Name contains a slash (/) followed by ASCII representation of a decimal number. + // this number is an offset into the string table. + // TODO: fixme + ret.push_back(name_helper); + } + } + + return ret; + } + + std::vector<std::string> symbols() { + std::vector<std::string> ret; + + const header_t h = header(); + const exports_t exprt = exports(h); + const std::size_t exported_symbols = exprt.NumberOfNames; + const std::size_t fixed_names_addr = get_file_offset(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'); + ret.push_back(symbol_name); + } + + return ret; + } + + std::vector<std::string> symbols(const char* section_name) { + std::vector<std::string> ret; + + const header_t h = header(); + + std::size_t section_begin_addr = 0; + std::size_t section_end_addr = 0; + + { // getting address range for the section + section_t image_section_header; + char name_helper[section_t::IMAGE_SIZEOF_SHORT_NAME_ + 1]; + 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); + 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; + section_end_addr = section_begin_addr + image_section_header.SizeOfRawData; + } + } + BOOST_ASSERT(section_begin_addr); + BOOST_ASSERT(section_end_addr); + } + + const exports_t exprt = exports(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); + + ret.reserve(exported_symbols); + boost::dll::detail::DWORD_ ptr; + boost::dll::detail::WORD_ ordinal; + 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); + + // 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) ); + + 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'); + ret.push_back(symbol_name); + } + + return ret; + } + + // a test method to get dependents modules, + // who my plugin imports (1st level only) + /* + e.g. for myself I get: + KERNEL32.dll + MSVCP110D.dll + boost_system-vc-mt-gd-1_56.dll + MSVCR110D.dll + */ + /* + std::vector<std::string> depend_of(boost::system::error_code &ec) BOOST_NOEXCEPT { + std::vector<std::string> ret; + + IMAGE_DOS_HEADER* image_dos_header = (IMAGE_DOS_HEADER*)native(); + if(!image_dos_header) { + // ERROR_BAD_EXE_FORMAT + ec = boost::system::error_code( + boost::system::errc::executable_format_error, + boost::system::generic_category() + ); + + return ret; + } + + IMAGE_OPTIONAL_HEADER* image_optional_header = (IMAGE_OPTIONAL_HEADER*)((boost::dll::detail::BYTE_*)native() + image_dos_header->e_lfanew + 24); + if(!image_optional_header) { + // ERROR_BAD_EXE_FORMAT + ec = boost::system::error_code( + boost::system::errc::executable_format_error, + boost::system::generic_category() + ); + + return ret; + } + + IMAGE_IMPORT_DESCRIPTOR* image_import_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)((boost::dll::detail::BYTE_*)native() + image_optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + if(!image_import_descriptor) { + // ERROR_BAD_EXE_FORMAT + ec = boost::system::error_code( + boost::system::errc::executable_format_error, + boost::system::generic_category() + ); + + return ret; + } + + while(image_import_descriptor->FirstThunk) { + std::string module_name = reinterpret_cast<char*>((boost::dll::detail::BYTE_*)native() + image_import_descriptor->Name); + + if(module_name.size()) { + ret.push_back(module_name); + } + + image_import_descriptor++; + } + + return ret; + } +*/ +}; + +typedef pe_info<boost::dll::detail::DWORD_> pe_info32; +typedef pe_info<boost::dll::detail::ULONGLONG_> pe_info64; + +}}} // namespace boost::dll::detail + +#endif // BOOST_DLL_DETAIL_WINDOWS_PE_INFO_HPP diff --git a/boost/dll/detail/posix/path_from_handle.hpp b/boost/dll/detail/posix/path_from_handle.hpp new file mode 100644 index 0000000000..a2787623d6 --- /dev/null +++ b/boost/dll/detail/posix/path_from_handle.hpp @@ -0,0 +1,169 @@ +// Copyright 2014-2015 Renato Tegon Forti, 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_POSIX_PATH_FROM_HANDLE_HPP +#define BOOST_DLL_DETAIL_POSIX_PATH_FROM_HANDLE_HPP + +#include <boost/config.hpp> +#include <boost/dll/detail/system_error.hpp> +#include <boost/dll/detail/posix/program_location_impl.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/predef/os.h> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#if BOOST_OS_MACOS || BOOST_OS_IOS + +# include <mach-o/dyld.h> +# include <mach-o/nlist.h> +# include <cstddef> // for std::ptrdiff_t + +namespace boost { namespace dll { namespace detail { + inline void* strip_handle(void* handle) BOOST_NOEXCEPT { + return reinterpret_cast<void*>( + (reinterpret_cast<std::ptrdiff_t>(handle) >> 2) << 2 + ); + } + + inline boost::filesystem::path path_from_handle(void* handle, boost::system::error_code &ec) { + handle = strip_handle(handle); + + // 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) { + // 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); + + // dlopen/dlclose must not affect `_dyld_image_count()`, because libraries are already loaded and only the internal counter is affected + void* probe_handle = dlopen(image_name, RTLD_LAZY); + dlclose(probe_handle); + + // If the handle is the same as what was passed in (modulo mode bits), return this image name + if (handle == strip_handle(probe_handle)) { + boost::dll::detail::reset_dlerror(); + return image_name; + } + } + + boost::dll::detail::reset_dlerror(); + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + + return boost::filesystem::path(); + } + +}}} // namespace boost::dll::detail + +#elif BOOST_OS_ANDROID + +#include <boost/dll/runtime_symbol_info.hpp> + +namespace boost { namespace dll { namespace detail { + + struct soinfo { + // if defined(__work_around_b_24465209__), then an array of char[128] goes here. + // Unfortunately, __work_around_b_24465209__ is visible only during compilation of Android's linker + const void* phdr; + size_t phnum; + void* entry; + void* base; + // ... // Ignoring remaning parts of the structure + }; + + inline boost::filesystem::path path_from_handle(const void* handle, boost::system::error_code &ec) { + static const std::size_t work_around_b_24465209__offset = 128; + const struct soinfo* si = reinterpret_cast<const struct soinfo*>( + static_cast<const char*>(handle) + work_around_b_24465209__offset + ); + boost::filesystem::path ret = boost::dll::detail::symbol_location_impl(si->base, ec); + + if (ec) { + ec.clear(); + si = static_cast<const struct soinfo*>(handle); + return boost::dll::detail::symbol_location_impl(si->base, ec); + } + + return ret; + } + +}}} // namespace boost::dll::detail + +#else // #if BOOST_OS_MACOS || BOOST_OS_IOS || BOOST_OS_ANDROID + +// for dlinfo +#include <dlfcn.h> + +#if BOOST_OS_QNX +// QNX's copy of <elf.h> and <link.h> reside in sys folder +# include <sys/link.h> +#else +# include <link.h> // struct link_map +#endif + +namespace boost { namespace dll { namespace detail { + +#if BOOST_OS_QNX + // Android and QNX miss struct link_map. QNX misses ElfW macro, so avoiding it. + struct link_map { + void *l_addr; // Base address shared object is loaded at + char *l_name; // Absolute file name object was found in + // ... // Ignoring remaning parts of the structure + }; +#endif // #if BOOST_OS_QNX + + inline boost::filesystem::path path_from_handle(void* handle, boost::system::error_code &ec) { + // RTLD_DI_LINKMAP (RTLD_DI_ORIGIN returns only folder and is not suitable for this case) + // Obtain the Link_map for the handle that is specified. + // The p argument points to a Link_map pointer (Link_map + // **p). The actual storage for the Link_map structure is + // maintained by ld.so.1. + // + // Unfortunately we can not use `dlinfo(handle, RTLD_DI_LINKMAP, &link_map) < 0` + // because it is not supported on MacOS X 10.3, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, + // HP-UX 11, IRIX 6.5, OSF/1 5.1, Cygwin, mingw, Interix 3.5, BeOS. + // Fortunately investigating the sources of open source projects brought the understanding, that + // `handle` is just a `struct link_map*` that contains full library name. + + const struct link_map* link_map = 0; +#if BOOST_OS_BSD_FREE + // FreeBSD has it's own logic http://code.metager.de/source/xref/freebsd/libexec/rtld-elf/rtld.c + // Fortunately it has the dlinfo call. + if (dlinfo(handle, RTLD_DI_LINKMAP, &link_map) < 0) { + link_map = 0; + } +#else + link_map = static_cast<const struct link_map*>(handle); +#endif + if (!link_map) { + boost::dll::detail::reset_dlerror(); + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + + return boost::filesystem::path(); + } + + if (!link_map->l_name || *link_map->l_name == '\0') { + return program_location_impl(ec); + } + + return boost::filesystem::path(link_map->l_name); + } + +}}} // namespace boost::dll::detail + +#endif // #if BOOST_OS_MACOS || BOOST_OS_IOS + +#endif // BOOST_DLL_DETAIL_POSIX_PATH_FROM_HANDLE_HPP + + diff --git a/boost/dll/detail/posix/program_location_impl.hpp b/boost/dll/detail/posix/program_location_impl.hpp new file mode 100644 index 0000000000..bca9b8caef --- /dev/null +++ b/boost/dll/detail/posix/program_location_impl.hpp @@ -0,0 +1,140 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015 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_POSIX_PROGRAM_LOCATION_IMPL_HPP +#define BOOST_DLL_DETAIL_POSIX_PROGRAM_LOCATION_IMPL_HPP + +#include <boost/config.hpp> +#include <boost/dll/detail/system_error.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/predef/os.h> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#if BOOST_OS_MACOS || BOOST_OS_IOS + +#include <mach-o/dyld.h> + +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code &ec) { + ec.clear(); + + char path[1024]; + uint32_t size = sizeof(path); + if (_NSGetExecutablePath(path, &size) == 0) + return boost::filesystem::path(path); + + char *p = new char[size]; + if (_NSGetExecutablePath(p, &size) != 0) { + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + } + + boost::filesystem::path ret(p); + delete[] p; + return ret; + } +}}} // namespace boost::dll::detail + +#elif BOOST_OS_SOLARIS + +#include <stdlib.h> +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code& ec) { + ec.clear(); + + return boost::filesystem::path(getexecname()); + } +}}} // namespace boost::dll::detail + +#elif BOOST_OS_BSD_FREE + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <stdlib.h> + +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code& ec) { + ec.clear(); + + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char buf[10240]; + size_t cb = sizeof(buf); + sysctl(mib, 4, buf, &cb, NULL, 0); + + return boost::filesystem::path(buf); + } +}}} // namespace boost::dll::detail + + + +#elif BOOST_OS_BSD_NET + +#include <boost/filesystem/operations.hpp> +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code &ec) { + return boost::filesystem::read_symlink("/proc/curproc/exe", ec); + } +}}} // namespace boost::dll::detail + +#elif BOOST_OS_BSD_DRAGONFLY + +#include <boost/filesystem/operations.hpp> +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code &ec) { + return boost::filesystem::read_symlink("/proc/curproc/file", ec); + } +}}} // namespace boost::dll::detail + +#elif BOOST_OS_QNX + +#include <fstream> +#include <string> // for std::getline +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code &ec) { + ec.clear(); + + std::string s; + std::ifstream ifs("/proc/self/exefile"); + std::getline(ifs, s); + + if (ifs.fail() || s.empty()) { + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + } + + return boost::filesystem::path(s); + } +}}} // namespace boost::dll::detail + +#else // BOOST_OS_LINUX || BOOST_OS_UNIX || BOOST_OS_HPUX || BOOST_OS_ANDROID + +#include <boost/filesystem/operations.hpp> +namespace boost { namespace dll { namespace detail { + inline boost::filesystem::path program_location_impl(boost::system::error_code &ec) { + // We can not use + // boost::dll::detail::path_from_handle(dlopen(NULL, RTLD_LAZY | RTLD_LOCAL), ignore); + // because such code returns empty path. + + return boost::filesystem::read_symlink("/proc/self/exe", ec); // Linux specific + } +}}} // namespace boost::dll::detail + +#endif + +#endif // BOOST_DLL_DETAIL_POSIX_PROGRAM_LOCATION_IMPL_HPP + diff --git a/boost/dll/detail/posix/shared_library_impl.hpp b/boost/dll/detail/posix/shared_library_impl.hpp new file mode 100644 index 0000000000..509e6c7487 --- /dev/null +++ b/boost/dll/detail/posix/shared_library_impl.hpp @@ -0,0 +1,215 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015-2016 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_SHARED_LIBRARY_IMPL_HPP +#define BOOST_DLL_SHARED_LIBRARY_IMPL_HPP + +#include <boost/config.hpp> +#include <boost/dll/shared_library_load_mode.hpp> +#include <boost/dll/detail/posix/path_from_handle.hpp> +#include <boost/dll/detail/posix/program_location_impl.hpp> + +#include <boost/move/utility.hpp> +#include <boost/swap.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/predef/os.h> + +#include <dlfcn.h> +#include <cstring> // strncmp +#if !BOOST_OS_MACOS && !BOOST_OS_IOS && !BOOST_OS_QNX +# include <link.h> +#elif BOOST_OS_QNX +// QNX's copy of <elf.h> and <link.h> reside in sys folder +# include <sys/link.h> +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +namespace boost { namespace dll { namespace detail { + +class shared_library_impl { + + BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_library_impl) + +public: + typedef void* native_handle_t; + + shared_library_impl() BOOST_NOEXCEPT + : handle_(NULL) + {} + + ~shared_library_impl() BOOST_NOEXCEPT { + unload(); + } + + shared_library_impl(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT + : handle_(sl.handle_) + { + sl.handle_ = NULL; + } + + shared_library_impl & operator=(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT { + swap(sl); + return *this; + } + + void load(boost::filesystem::path sl, load_mode::type mode, boost::system::error_code &ec) { + typedef int native_mode_t; + unload(); + + // Do not allow opening NULL paths. User must use program_location() instead + if (sl.empty()) { + boost::dll::detail::reset_dlerror(); + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + + return; + } + + // Fixing modes + if (!(mode & load_mode::rtld_now)) { + mode |= load_mode::rtld_lazy; + } + + if (!(mode & load_mode::rtld_global)) { + mode |= load_mode::rtld_local; + } + +#if BOOST_OS_LINUX || BOOST_OS_ANDROID + if (!sl.has_parent_path() && !(mode & load_mode::search_system_folders)) { + sl = "." / sl; + } +#else + if (!sl.is_absolute() && !(mode & load_mode::search_system_folders)) { + boost::system::error_code current_path_ec; + boost::filesystem::path prog_loc = boost::filesystem::current_path(current_path_ec); + if (!current_path_ec) { + prog_loc /= sl; + sl.swap(prog_loc); + } + } +#endif + + mode &= ~load_mode::search_system_folders; + + // Trying to open with appended decorations + if (!!(mode & load_mode::append_decorations)) { + mode &= ~load_mode::append_decorations; + + boost::filesystem::path actual_path = ( + std::strncmp(sl.filename().string().c_str(), "lib", 3) + ? (sl.has_parent_path() ? sl.parent_path() / L"lib" : L"lib").native() + sl.filename().native() + : sl + ); + actual_path += suffix(); + + handle_ = dlopen(actual_path.c_str(), static_cast<native_mode_t>(mode)); + if (handle_) { + boost::dll::detail::reset_dlerror(); + return; + } + } + + // Opening by exactly specified path + handle_ = dlopen(sl.c_str(), static_cast<native_mode_t>(mode)); + if (handle_) { + boost::dll::detail::reset_dlerror(); + return; + } + + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + + // Maybe user wanted to load the executable itself? Checking... + // We assume that usually user wants to load a dynamic library not the executable itself, that's why + // we try this only after traditional load fails. + boost::system::error_code prog_loc_err; + boost::filesystem::path loc = boost::dll::detail::program_location_impl(prog_loc_err); + if (!prog_loc_err && boost::filesystem::equivalent(sl, loc, prog_loc_err) && !prog_loc_err) { + // As is known the function dlopen() loads the dynamic library file + // named by the null-terminated string filename and returns an opaque + // "handle" for the dynamic library. If filename is NULL, then the + // returned handle is for the main program. + ec.clear(); + boost::dll::detail::reset_dlerror(); + handle_ = dlopen(NULL, static_cast<native_mode_t>(mode)); + if (!handle_) { + ec = boost::system::error_code( + boost::system::errc::bad_file_descriptor, + boost::system::generic_category() + ); + } + } + } + + bool is_loaded() const BOOST_NOEXCEPT { + return (handle_ != 0); + } + + void unload() BOOST_NOEXCEPT { + if (!is_loaded()) { + return; + } + + dlclose(handle_); + handle_ = 0; + } + + void swap(shared_library_impl& rhs) BOOST_NOEXCEPT { + boost::swap(handle_, rhs.handle_); + } + + boost::filesystem::path full_module_path(boost::system::error_code &ec) const { + return boost::dll::detail::path_from_handle(handle_, ec); + } + + static boost::filesystem::path suffix() { + // https://sourceforge.net/p/predef/wiki/OperatingSystems/ +#if BOOST_OS_MACOS || BOOST_OS_IOS + return ".dylib"; +#else + return ".so"; +#endif + } + + void* symbol_addr(const char* sb, boost::system::error_code &ec) const BOOST_NOEXCEPT { + // dlsym - obtain the address of a symbol from a dlopen object + void* const symbol = dlsym(handle_, sb); + if (symbol == NULL) { + ec = boost::system::error_code( + boost::system::errc::invalid_seek, + boost::system::generic_category() + ); + } + + // If handle does not refer to a valid object opened by dlopen(), + // or if the named symbol cannot be found within any of the objects + // associated with handle, dlsym() shall return NULL. + // More detailed diagnostic information shall be available through dlerror(). + + return symbol; + } + + native_handle_t native() const BOOST_NOEXCEPT { + return handle_; + } + +private: + native_handle_t handle_; +}; + +}}} // boost::dll::detail + +#endif // BOOST_DLL_SHARED_LIBRARY_IMPL_HPP + diff --git a/boost/dll/detail/system_error.hpp b/boost/dll/detail/system_error.hpp new file mode 100644 index 0000000000..c032633a0b --- /dev/null +++ b/boost/dll/detail/system_error.hpp @@ -0,0 +1,56 @@ +// Copyright 2014 Renato Tegon Forti, 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_SYSTEM_ERROR_HPP +#define BOOST_DLL_SYSTEM_ERROR_HPP + +#include <boost/config.hpp> +#include <boost/predef/os.h> +#include <boost/system/error_code.hpp> +#include <boost/system/system_error.hpp> +#include <boost/throw_exception.hpp> + +#if !BOOST_OS_WINDOWS +# include <dlfcn.h> +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +namespace boost { namespace dll { namespace detail { + + inline void reset_dlerror() BOOST_NOEXCEPT { +#if !BOOST_OS_WINDOWS + const char* const error_txt = dlerror(); + (void)error_txt; +#endif + } + + inline void report_error(const boost::system::error_code& ec, const char* message) { +#if !BOOST_OS_WINDOWS + const char* const error_txt = dlerror(); + if (error_txt) { + boost::throw_exception( + boost::system::system_error( + ec, + message + std::string(" (dlerror system message: ") + error_txt + std::string(")") + ) + ); + } +#endif + + boost::throw_exception( + boost::system::system_error( + ec, message + ) + ); + } + +}}} // boost::dll::detail + +#endif // BOOST_DLL_SYSTEM_ERROR_HPP + diff --git a/boost/dll/detail/windows/path_from_handle.hpp b/boost/dll/detail/windows/path_from_handle.hpp new file mode 100644 index 0000000000..37eee86428 --- /dev/null +++ b/boost/dll/detail/windows/path_from_handle.hpp @@ -0,0 +1,62 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015 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_WINDOWS_PATH_FROM_HANDLE_HPP +#define BOOST_DLL_DETAIL_WINDOWS_PATH_FROM_HANDLE_HPP + +#include <boost/config.hpp> +#include <boost/dll/detail/system_error.hpp> +#include <boost/detail/winapi/dll.hpp> +#include <boost/detail/winapi/get_last_error.hpp> +#include <boost/filesystem/path.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +namespace boost { namespace dll { namespace detail { + + static inline boost::system::error_code last_error_code() BOOST_NOEXCEPT { + boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError(); + return boost::system::error_code( + err, + boost::system::system_category() + ); + } + + inline boost::filesystem::path path_from_handle(boost::detail::winapi::HMODULE_ handle, boost::system::error_code &ec) { + BOOST_STATIC_CONSTANT(boost::detail::winapi::DWORD_, ERROR_INSUFFICIENT_BUFFER_ = 0x7A); + BOOST_STATIC_CONSTANT(boost::detail::winapi::DWORD_, DEFAULT_PATH_SIZE_ = 260); + + // If `handle` parameter is NULL, GetModuleFileName retrieves the path of the + // executable file of the current process. + boost::detail::winapi::WCHAR_ path_hldr[DEFAULT_PATH_SIZE_]; + boost::detail::winapi::GetModuleFileNameW(handle, path_hldr, DEFAULT_PATH_SIZE_); + ec = last_error_code(); + if (!ec) { + return boost::filesystem::path(path_hldr); + } + + for (unsigned i = 2; i < 1025 && static_cast<boost::detail::winapi::DWORD_>(ec.value()) == ERROR_INSUFFICIENT_BUFFER_; i *= 2) { + std::wstring p(DEFAULT_PATH_SIZE_ * i, L'\0'); + const std::size_t size = boost::detail::winapi::GetModuleFileNameW(handle, &p[0], DEFAULT_PATH_SIZE_ * i); + ec = last_error_code(); + + if (!ec) { + p.resize(size); + return boost::filesystem::path(p); + } + } + + // Error other than ERROR_INSUFFICIENT_BUFFER_ occurred or failed to allocate buffer big enough + return boost::filesystem::path(); + } + +}}} // namespace boost::dll::detail + +#endif // BOOST_DLL_DETAIL_WINDOWS_PATH_FROM_HANDLE_HPP + diff --git a/boost/dll/detail/windows/shared_library_impl.hpp b/boost/dll/detail/windows/shared_library_impl.hpp new file mode 100644 index 0000000000..48156505f4 --- /dev/null +++ b/boost/dll/detail/windows/shared_library_impl.hpp @@ -0,0 +1,177 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015-2016 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_SHARED_LIBRARY_IMPL_HPP +#define BOOST_DLL_SHARED_LIBRARY_IMPL_HPP + +#include <boost/config.hpp> +#include <boost/dll/shared_library_load_mode.hpp> +#include <boost/dll/detail/aggressive_ptr_cast.hpp> +#include <boost/dll/detail/system_error.hpp> +#include <boost/dll/detail/windows/path_from_handle.hpp> + +#include <boost/move/utility.hpp> +#include <boost/swap.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> + +#include <boost/detail/winapi/dll.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +namespace boost { namespace dll { namespace detail { + +class shared_library_impl { + BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_library_impl) + +public: + typedef boost::detail::winapi::HMODULE_ native_handle_t; + + shared_library_impl() BOOST_NOEXCEPT + : handle_(NULL) + {} + + ~shared_library_impl() BOOST_NOEXCEPT { + unload(); + } + + shared_library_impl(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT + : handle_(sl.handle_) + { + sl.handle_ = NULL; + } + + shared_library_impl & operator=(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT { + swap(sl); + return *this; + } + + void load(boost::filesystem::path sl, load_mode::type mode, boost::system::error_code &ec) { + typedef boost::detail::winapi::DWORD_ native_mode_t; + unload(); + + if (!sl.is_absolute() && !(mode & load_mode::search_system_folders)) { + + boost::system::error_code current_path_ec; + boost::filesystem::path prog_loc = boost::filesystem::current_path(current_path_ec); + if (!current_path_ec) { + prog_loc /= sl; + sl.swap(prog_loc); + } + } + mode &= ~load_mode::search_system_folders; + + // Trying to open with appended decorations + if (!!(mode & load_mode::append_decorations)) { + mode &= ~load_mode::append_decorations; + + handle_ = boost::detail::winapi::LoadLibraryExW((sl.native() + L".dll").c_str(), 0, static_cast<native_mode_t>(mode)); + if (!handle_) { + // MinGW loves 'lib' prefix and puts it even on Windows platform + const boost::filesystem::path load_path = (sl.has_parent_path() ? sl.parent_path() / L"lib" : L"lib").native() + sl.filename().native() + L".dll"; + handle_ = boost::detail::winapi::LoadLibraryExW( + load_path.c_str(), + 0, + static_cast<native_mode_t>(mode) + ); + } + + if (handle_) { + return; + } + } + + // From MSDN: If the string specifies a module name without a path and the + // file name extension is omitted, the function appends the default library + // extension .dll to the module name. + // + // From experiments: Default library extension appended to the module name even if + // 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::detail::winapi::LoadLibraryExW(sl.c_str(), 0, static_cast<native_mode_t>(mode)); + } else { + handle_ = boost::detail::winapi::LoadLibraryExW((sl.native() + L".").c_str(), 0, static_cast<native_mode_t>(mode)); + } + + // LoadLibraryExW method is capable of self loading from program_location() path. No special actions + // must be taken to allow self loading. + + if (!handle_) { + ec = boost::dll::detail::last_error_code(); + } + } + + bool is_loaded() const BOOST_NOEXCEPT { + return (handle_ != 0); + } + + void unload() BOOST_NOEXCEPT { + if (handle_) { + boost::detail::winapi::FreeLibrary(handle_); + handle_ = 0; + } + } + + void swap(shared_library_impl& rhs) BOOST_NOEXCEPT { + boost::swap(handle_, rhs.handle_); + } + + boost::filesystem::path full_module_path(boost::system::error_code &ec) const { + return boost::dll::detail::path_from_handle(handle_, ec); + } + + static boost::filesystem::path suffix() { + return L".dll"; + } + + void* symbol_addr(const char* sb, boost::system::error_code &ec) const BOOST_NOEXCEPT { + if (is_resource()) { + // `GetProcAddress` could not be called for libraries loaded with + // `LOAD_LIBRARY_AS_DATAFILE`, `LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE` + // or `LOAD_LIBRARY_AS_IMAGE_RESOURCE`. + ec = boost::system::error_code( + boost::system::errc::operation_not_supported, + boost::system::generic_category() + ); + + return NULL; + } + + // Judging by the documentation of GetProcAddress + // there is no version for UNICODE on desktop/server Windows, because + // names of functions are stored in narrow characters. + void* const symbol = boost::dll::detail::aggressive_ptr_cast<void*>( + boost::detail::winapi::get_proc_address(handle_, sb) + ); + if (symbol == NULL) { + ec = boost::dll::detail::last_error_code(); + } + + return symbol; + } + + native_handle_t native() const BOOST_NOEXCEPT { + return handle_; + } + +private: + bool is_resource() const BOOST_NOEXCEPT { + return false; /*!!( + reinterpret_cast<boost::detail::winapi::ULONG_PTR_>(handle_) & static_cast<boost::detail::winapi::ULONG_PTR_>(3) + );*/ + } + + native_handle_t handle_; +}; + +}}} // boost::dll::detail + +#endif // BOOST_DLL_SHARED_LIBRARY_IMPL_HPP + diff --git a/boost/dll/detail/x_info_interface.hpp b/boost/dll/detail/x_info_interface.hpp new file mode 100644 index 0000000000..e53214e1cd --- /dev/null +++ b/boost/dll/detail/x_info_interface.hpp @@ -0,0 +1,32 @@ +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// Copyright 2015 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/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 |