stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
// 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_ALIAS_HPP
|
||||
#define BOOST_DLL_ALIAS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/predef/compiler.h>
|
||||
#include <boost/predef/os.h>
|
||||
#include <boost/dll/detail/aggressive_ptr_cast.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
/// \file boost/dll/alias.hpp
|
||||
/// \brief Includes alias methods and macro. You can include this header or
|
||||
/// boost/dll/shared_library.hpp to reduce dependencies
|
||||
/// in case you do not use the refcountable functions.
|
||||
|
||||
namespace boost { namespace dll {
|
||||
|
||||
#ifdef BOOST_DLL_DOXYGEN
|
||||
/// Define this macro to explicitly specify translation unit in which alias must be instantiated.
|
||||
/// See section 'Limitations' for more info. You may find usage examples in source codes of almost each tutorial.
|
||||
/// Must be used in code, when \forcedmacrolink{BOOST_DLL_FORCE_NO_WEAK_EXPORTS} is defined
|
||||
#define BOOST_DLL_FORCE_ALIAS_INSTANTIATION
|
||||
|
||||
/// Define this macro to disable exporting weak symbols and start using the \forcedmacrolink{BOOST_DLL_FORCE_ALIAS_INSTANTIATION}.
|
||||
/// This may be usefull for working around linker problems or to test your program for compatability with linkers that do not support export of weak symbols.
|
||||
#define BOOST_DLL_FORCE_NO_WEAK_EXPORTS
|
||||
#endif
|
||||
|
||||
#if BOOST_COMP_MSVC || (BOOST_COMP_INTEL && BOOST_OS_WINDOWS)
|
||||
|
||||
#define BOOST_DLL_SELECTANY __declspec(selectany)
|
||||
|
||||
#define BOOST_DLL_SECTION(SectionName, Permissions) \
|
||||
BOOST_STATIC_ASSERT_MSG( \
|
||||
sizeof(#SectionName) < 10, \
|
||||
"Some platforms require section names to be at most 8 bytest" \
|
||||
); \
|
||||
__pragma(section(#SectionName, Permissions)) __declspec(allocate(#SectionName)) \
|
||||
/**/
|
||||
|
||||
#else // #if BOOST_COMP_MSVC
|
||||
|
||||
|
||||
#if BOOST_OS_WINDOWS || BOOST_OS_ANDROID || BOOST_COMP_IBM
|
||||
// There are some problems with mixing `__dllexport__` and `weak` using MinGW
|
||||
// See https://sourceware.org/bugzilla/show_bug.cgi?id=17480
|
||||
//
|
||||
// Android had an issue with exporting weak symbols
|
||||
// https://code.google.com/p/android/issues/detail?id=70206
|
||||
#define BOOST_DLL_SELECTANY
|
||||
#else // #if BOOST_OS_WINDOWS
|
||||
/*!
|
||||
* \brief Macro that allows linker to select any occurrence of this symbol instead of
|
||||
* failing with 'multiple definitions' error at linktime.
|
||||
*
|
||||
* This macro does not work on Android, IBM XL C/C++ and MinGW+Windows
|
||||
* because of linker problems with exporting weak symbols
|
||||
* (See https://code.google.com/p/android/issues/detail?id=70206, https://sourceware.org/bugzilla/show_bug.cgi?id=17480)
|
||||
*/
|
||||
#define BOOST_DLL_SELECTANY __attribute__((weak))
|
||||
#endif // #if BOOST_OS_WINDOWS
|
||||
|
||||
// TODO: improve section permissions using following info:
|
||||
// http://stackoverflow.com/questions/6252812/what-does-the-aw-flag-in-the-section-attribute-mean
|
||||
|
||||
#if !BOOST_OS_MACOS && !BOOST_OS_IOS
|
||||
/*!
|
||||
* \brief Macro that puts symbol to a specific section. On MacOS all the sections are put into "__DATA" segment.
|
||||
* \param SectionName Name of the section. Must be a valid C identifier without quotes not longer than 8 bytes.
|
||||
* \param Permissions Can be "read" or "write" (without quotes!).
|
||||
*/
|
||||
#define BOOST_DLL_SECTION(SectionName, Permissions) \
|
||||
BOOST_STATIC_ASSERT_MSG( \
|
||||
sizeof(#SectionName) < 10, \
|
||||
"Some platforms require section names to be at most 8 bytest" \
|
||||
); \
|
||||
__attribute__ ((section (#SectionName))) \
|
||||
/**/
|
||||
#else // #if !BOOST_OS_MACOS && !BOOST_OS_IOS
|
||||
|
||||
#define BOOST_DLL_SECTION(SectionName, Permissions) \
|
||||
BOOST_STATIC_ASSERT_MSG( \
|
||||
sizeof(#SectionName) < 10, \
|
||||
"Some platforms require section names to be at most 8 bytest" \
|
||||
); \
|
||||
__attribute__ ((section ( "__DATA," #SectionName))) \
|
||||
/**/
|
||||
|
||||
#endif // #if #if !BOOST_OS_MACOS && !BOOST_OS_IOS
|
||||
|
||||
#endif // #if BOOST_COMP_MSVC
|
||||
|
||||
|
||||
// Alias - is just a variable that pointers to original data
|
||||
//
|
||||
// A few attempts were made to avoid additional indirection:
|
||||
// 1)
|
||||
// // Does not work on Windows, work on Linux
|
||||
// extern "C" BOOST_SYMBOL_EXPORT void AliasName() {
|
||||
// reinterpret_cast<void (*)()>(Function)();
|
||||
// }
|
||||
//
|
||||
// 2)
|
||||
// // Does not work on Linux (changes permissions of .text section and produces incorrect DSO)
|
||||
// extern "C" BOOST_SYMBOL_EXPORT void* __attribute__ ((section(".text#")))
|
||||
// func_ptr = *reinterpret_cast<std::ptrdiff_t**>(&foo::bar);
|
||||
//
|
||||
// 3) // requires mangled name of `Function`
|
||||
// // AliasName() __attribute__ ((weak, alias ("Function")))
|
||||
//
|
||||
// // hard to use
|
||||
// `#pragma comment(linker, "/alternatename:_pWeakValue=_pDefaultWeakValue")`
|
||||
|
||||
/*!
|
||||
* \brief Makes an alias name for exported function or variable.
|
||||
*
|
||||
* This macro is useful in cases of long mangled C++ names. For example some `void boost::foo(std::sting)`
|
||||
* function name will change to something like `N5boostN3foosE` after mangling.
|
||||
* Importing function by `N5boostN3foosE` name does not looks user friendly, especially assuming the fact
|
||||
* that different compilers have different mangling schemes. AliasName is the name that won't be mangled
|
||||
* and can be used as a portable import name.
|
||||
*
|
||||
*
|
||||
* Can be used in any namespace, including global. FunctionOrVar must be fully qualified,
|
||||
* so that address of it could be taken. Multiple different aliases for a single variable/function
|
||||
* are allowed.
|
||||
*
|
||||
* Make sure that AliasNames are unique per library/executable. Functions or variables
|
||||
* in global namespace must not have names same as AliasNames.
|
||||
*
|
||||
* Same AliasName in different translation units must point to the same FunctionOrVar.
|
||||
*
|
||||
* Puts all the aliases into the \b "boostdll" read only section of the binary. Equal to
|
||||
* \forcedmacrolink{BOOST_DLL_ALIAS_SECTIONED}(FunctionOrVar, AliasName, boostdll).
|
||||
*
|
||||
* \param FunctionOrVar Function or variable for which an alias must be made.
|
||||
* \param AliasName Name of the alias. Must be a valid C identifier.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* namespace foo {
|
||||
* void bar(std::string&);
|
||||
*
|
||||
* BOOST_DLL_ALIAS(foo::bar, foo_bar)
|
||||
* }
|
||||
*
|
||||
* BOOST_DLL_ALIAS(foo::bar, foo_bar_another_alias_name)
|
||||
* \endcode
|
||||
*
|
||||
* \b See: \forcedmacrolink{BOOST_DLL_ALIAS_SECTIONED} for making alias in a specific section.
|
||||
*/
|
||||
#define BOOST_DLL_ALIAS(FunctionOrVar, AliasName) \
|
||||
BOOST_DLL_ALIAS_SECTIONED(FunctionOrVar, AliasName, boostdll) \
|
||||
/**/
|
||||
|
||||
|
||||
#if ((BOOST_COMP_GNUC && BOOST_OS_WINDOWS) || BOOST_OS_ANDROID || BOOST_COMP_IBM || defined(BOOST_DLL_FORCE_NO_WEAK_EXPORTS)) \
|
||||
&& !defined(BOOST_DLL_FORCE_ALIAS_INSTANTIATION) && !defined(BOOST_DLL_DOXYGEN)
|
||||
|
||||
#define BOOST_DLL_ALIAS_SECTIONED(FunctionOrVar, AliasName, SectionName) \
|
||||
namespace _autoaliases { \
|
||||
extern "C" BOOST_SYMBOL_EXPORT const void *AliasName; \
|
||||
} /* namespace _autoaliases */ \
|
||||
/**/
|
||||
|
||||
#define BOOST_DLL_AUTO_ALIAS(FunctionOrVar) \
|
||||
namespace _autoaliases { \
|
||||
extern "C" BOOST_SYMBOL_EXPORT const void *FunctionOrVar; \
|
||||
} /* namespace _autoaliases */ \
|
||||
/**/
|
||||
#else
|
||||
// Note: we can not use `aggressive_ptr_cast` here, because in that case GCC applies
|
||||
// different permissions to the section and it causes Segmentation fault.
|
||||
// Note: we can not use `boost::addressof()` here, because in that case GCC
|
||||
// may optimize away the FunctionOrVar instance and we'll get a pointer to unexisting symbol.
|
||||
/*!
|
||||
* \brief Same as \forcedmacrolink{BOOST_DLL_ALIAS} but puts alias name into the user specified section.
|
||||
*
|
||||
* \param FunctionOrVar Function or variable for which an alias must be made.
|
||||
* \param AliasName Name of the alias. Must be a valid C identifier.
|
||||
* \param SectionName Name of the section. Must be a valid C identifier without quotes not longer than 8 bytes.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* namespace foo {
|
||||
* void bar(std::string&);
|
||||
*
|
||||
* BOOST_DLL_ALIAS_SECTIONED(foo::bar, foo_bar, sect_1) // section "sect_1" now exports "foo_bar"
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
#define BOOST_DLL_ALIAS_SECTIONED(FunctionOrVar, AliasName, SectionName) \
|
||||
namespace _autoaliases { \
|
||||
extern "C" BOOST_SYMBOL_EXPORT const void *AliasName; \
|
||||
BOOST_DLL_SECTION(SectionName, read) BOOST_DLL_SELECTANY \
|
||||
const void * AliasName = reinterpret_cast<const void*>(reinterpret_cast<intptr_t>( \
|
||||
&FunctionOrVar \
|
||||
)); \
|
||||
} /* namespace _autoaliases */ \
|
||||
/**/
|
||||
|
||||
/*!
|
||||
* \brief Exports variable or function with unmangled alias name.
|
||||
*
|
||||
* This macro is useful in cases of long mangled C++ names. For example some `void boost::foo(std::sting)`
|
||||
* function name will change to something like `N5boostN3foosE` after mangling.
|
||||
* Importing function by `N5boostN3foosE` name does not looks user friendly, especially assuming the fact
|
||||
* that different compilers have different mangling schemes.*
|
||||
*
|
||||
* Must be used in scope where FunctionOrVar declared. FunctionOrVar must be a valid C name, which means that
|
||||
* it must not contain `::`.
|
||||
*
|
||||
* Functions or variables
|
||||
* in global namespace must not have names same as FunctionOrVar.
|
||||
*
|
||||
* Puts all the aliases into the \b "boostdll" read only section of the binary. Almost same as
|
||||
* \forcedmacrolink{BOOST_DLL_ALIAS}(FunctionOrVar, FunctionOrVar).
|
||||
*
|
||||
* \param FunctionOrVar Function or variable for which an unmangled alias must be made.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* namespace foo {
|
||||
* void bar(std::string&);
|
||||
* BOOST_DLL_AUTO_ALIAS(bar)
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* \b See: \forcedmacrolink{BOOST_DLL_ALIAS} for making an alias with different names.
|
||||
*/
|
||||
|
||||
#define BOOST_DLL_AUTO_ALIAS(FunctionOrVar) \
|
||||
namespace _autoaliases { \
|
||||
BOOST_DLL_SELECTANY const void * dummy_ ## FunctionOrVar \
|
||||
= reinterpret_cast<const void*>(reinterpret_cast<intptr_t>( \
|
||||
&FunctionOrVar \
|
||||
)); \
|
||||
extern "C" BOOST_SYMBOL_EXPORT const void *FunctionOrVar; \
|
||||
BOOST_DLL_SECTION(boostdll, read) BOOST_DLL_SELECTANY \
|
||||
const void * FunctionOrVar = dummy_ ## FunctionOrVar; \
|
||||
} /* namespace _autoaliases */ \
|
||||
/**/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}} // namespace boost::dll
|
||||
|
||||
|
||||
#endif // BOOST_DLL_ALIAS_HPP
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright 2015-2017 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 <cstring> // std::memcpy
|
||||
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
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>(v);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4172) // "returning address of local variable or temporary" but **v is not local!
|
||||
#endif
|
||||
|
||||
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**>(
|
||||
v
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
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(From));
|
||||
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
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
// 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 BOOST_DLL_DETAIL_CTOR_DTOR_HPP_
|
||||
#define 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; }
|
||||
|
||||
//! True if a standard constructor could be loaded.
|
||||
bool has_standard() const { return standard != 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(_WIN32)
|
||||
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; }
|
||||
|
||||
//! True if a standard destructor could be loaded.
|
||||
bool has_standard() const { return standard != 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;
|
||||
//@apolukhin That does NOT work this way with MSVC-14 x32 via memcpy. The x64 is different.
|
||||
//standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt);
|
||||
void * buf = &lib.template get<int>(dt);
|
||||
standard_t dtor;
|
||||
std::memcpy(&dtor, &buf, sizeof(dtor));
|
||||
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())
|
||||
{
|
||||
//the only way this works on mingw/win.
|
||||
//For some reason there is always an 0xA in the following poniter, which screws with the this pointer.
|
||||
void *buf = &lib.template get<int>(ct.C1);
|
||||
std::memcpy(&s, &buf, sizeof(void*));
|
||||
}
|
||||
if (!ct.C3.empty())
|
||||
{
|
||||
void *buf = &lib.template get<int>(ct.C3);
|
||||
std::memcpy(&a, &buf, sizeof(void*));
|
||||
}
|
||||
|
||||
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 /* BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */
|
||||
@@ -0,0 +1,108 @@
|
||||
// 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)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace dll
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
typedef void * (__cdecl * allocation_function)(std::size_t);
|
||||
typedef void (__cdecl * free_function)(void *);
|
||||
|
||||
extern "C" char* __unDName( char* outputString,
|
||||
const char* name,
|
||||
int maxStringLength, // Note, COMMA is leading following optional arguments
|
||||
allocation_function pAlloc,
|
||||
free_function pFree,
|
||||
unsigned short disableFlags
|
||||
);
|
||||
|
||||
|
||||
inline std::string demangle_symbol(const char *mangled_name)
|
||||
{
|
||||
|
||||
allocation_function alloc = [](std::size_t size){return static_cast<void*>(new char[size]);};
|
||||
free_function free_f = [](void* p){delete [] static_cast<char*>(p);};
|
||||
|
||||
|
||||
|
||||
std::unique_ptr<char> name { __unDName(
|
||||
nullptr,
|
||||
mangled_name,
|
||||
0,
|
||||
alloc,
|
||||
free_f,
|
||||
static_cast<unsigned short>(0))};
|
||||
|
||||
return std::string(name.get());
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
namespace experimental
|
||||
{
|
||||
using ::boost::dll::detail::demangle_symbol;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* BOOST_DEMANGLE_HPP_ */
|
||||
@@ -0,0 +1,326 @@
|
||||
// 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...)>) const
|
||||
{
|
||||
return {get_name<Args>()...};
|
||||
}
|
||||
template<typename Return, typename ...Args>
|
||||
std::string get_return_type(dummy<Return(Args...)>) const
|
||||
{
|
||||
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) const;
|
||||
|
||||
template<typename Func>
|
||||
std::string get_function(const std::string &name) const;
|
||||
|
||||
template<typename Class, typename Func>
|
||||
std::string get_mem_fn(const std::string &name) const;
|
||||
|
||||
template<typename Signature>
|
||||
ctor_sym get_constructor() const;
|
||||
|
||||
template<typename Class>
|
||||
dtor_sym get_destructor() const;
|
||||
|
||||
template<typename T>
|
||||
std::string get_type_info() const;
|
||||
|
||||
template<typename T>
|
||||
std::vector<std::string> get_related() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace parser
|
||||
{
|
||||
|
||||
inline std::string const_rule_impl(true_type ) {return " const";}
|
||||
inline std::string const_rule_impl(false_type) {return "";}
|
||||
template<typename T>
|
||||
std::string 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>
|
||||
std::string 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>
|
||||
std::string reference_rule() {using t_l = is_lvalue_reference<T>; using t_r = is_rvalue_reference<T>; return reference_rule_impl(t_l(), t_r());}
|
||||
|
||||
//it takes a string, because it may be overloaded.
|
||||
template<typename T>
|
||||
std::string type_rule(const std::string & type_name)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
return type_name +
|
||||
const_rule<T>() +
|
||||
volatile_rule<T>() +
|
||||
reference_rule<T>();
|
||||
}
|
||||
|
||||
|
||||
template<typename Return, typename Arg>
|
||||
std::string arg_list(const mangled_storage_impl & ms, Return (*)(Arg))
|
||||
{
|
||||
using namespace std;
|
||||
auto str = ms.get_name<Arg>();
|
||||
return type_rule<Arg>(str);
|
||||
}
|
||||
|
||||
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) const
|
||||
{
|
||||
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) const
|
||||
{
|
||||
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) const
|
||||
{
|
||||
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() const -> 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() const -> 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;
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string mangled_storage_impl::get_type_info() const
|
||||
{
|
||||
std::string id = "typeinfo for " + get_name<T>();
|
||||
|
||||
|
||||
auto predicate = [&](const mangled_storage_base::entry & e)
|
||||
{
|
||||
return e.demangled == id;
|
||||
};
|
||||
|
||||
auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
|
||||
|
||||
|
||||
if (found != storage_.end())
|
||||
return found->mangled;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<std::string> mangled_storage_impl::get_related() const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
auto name = get_name<T>();
|
||||
|
||||
for (auto & c : storage_)
|
||||
{
|
||||
if (c.demangled.find(name) != std::string::npos)
|
||||
ret.push_back(c.demangled);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
#endif /* BOOST_DLL_DETAIL_DEMANGLING_ITANIUM_HPP_ */
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
// 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/ctti_type_index.hpp>
|
||||
#include <boost/type_traits/remove_reference.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::ctti_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();
|
||||
}
|
||||
std::vector<entry> & get_storage() {return storage_;};
|
||||
template<typename T>
|
||||
std::string get_name() const
|
||||
{
|
||||
using boost::typeindex::ctti_type_index;
|
||||
auto tx = ctti_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::ctti_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 /* BOOST_DLL_DETAIL_MANGLE_STORAGE_HPP_ */
|
||||
@@ -0,0 +1,439 @@
|
||||
// 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...)>) const
|
||||
{
|
||||
return {get_name<Args>()...};
|
||||
}
|
||||
template<typename Return, typename ...Args>
|
||||
std::string get_return_type(dummy<Return(Args...)>) const
|
||||
{
|
||||
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) const;
|
||||
|
||||
template<typename Func>
|
||||
std::string get_function(const std::string &name) const;
|
||||
|
||||
template<typename Class, typename Func>
|
||||
std::string get_mem_fn(const std::string &name) const;
|
||||
|
||||
template<typename Signature>
|
||||
ctor_sym get_constructor() const;
|
||||
|
||||
template<typename Class>
|
||||
dtor_sym get_destructor() const;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string get_vtable() const;
|
||||
|
||||
template<typename T>
|
||||
std::vector<std::string> get_related() const;
|
||||
|
||||
};
|
||||
|
||||
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) const
|
||||
{
|
||||
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) const
|
||||
{
|
||||
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) const
|
||||
{
|
||||
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() const -> 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() const -> 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 "";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string mangled_storage_impl::get_vtable() const
|
||||
{
|
||||
std::string id = "const " + get_name<T>() + "::`vftable'";
|
||||
|
||||
auto predicate = [&](const mangled_storage_base::entry & e)
|
||||
{
|
||||
return e.demangled == id;
|
||||
};
|
||||
|
||||
auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
|
||||
|
||||
|
||||
if (found != storage_.end())
|
||||
return found->mangled;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<std::string> mangled_storage_impl::get_related() const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
auto name = get_name<T>();
|
||||
|
||||
for (auto & c : storage_)
|
||||
{
|
||||
if (c.demangled.find(name) != std::string::npos)
|
||||
ret.push_back(c.demangled);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_DLL_DETAIL_DEMANGLING_MSVC_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
|
||||
@@ -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_DETAIL_GET_MEM_FN_TYPE_HPP_
|
||||
#define BOOST_DLL_DETAIL_GET_MEM_FN_TYPE_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 /* BOOST_DLL_SMART_LIBRARY_HPP_ */
|
||||
@@ -0,0 +1,290 @@
|
||||
// Copyright 2015-2016 Klemens D. 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_IMPORT_MANGLED_HELPERS_HPP_
|
||||
#define BOOST_DLL_DETAIL_IMPORT_MANGLED_HELPERS_HPP_
|
||||
|
||||
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost { namespace dll { namespace experimental { namespace detail {
|
||||
|
||||
//the following could be done by fusion, though it's simple enough to just declare it here.
|
||||
template<class ...Args>
|
||||
struct sequence {};
|
||||
|
||||
template<class Value, class Seq> struct push_front;
|
||||
template<class Value, class ...Args>
|
||||
struct push_front<Value, sequence<Args...>>
|
||||
{
|
||||
typedef sequence<Value, Args...> type;
|
||||
};
|
||||
|
||||
template<class Lhs, class Rhs>
|
||||
struct unqalified_is_same :
|
||||
boost::is_same<
|
||||
typename boost::remove_cv<Lhs>::type,
|
||||
typename boost::remove_cv<Rhs>::type
|
||||
>
|
||||
{
|
||||
};
|
||||
|
||||
/* ********************************** function sequence type traits ******************************/
|
||||
|
||||
//determine if it's a sequence of functions.
|
||||
template<class T> struct is_function_seq;
|
||||
|
||||
//type-trait for function overloads
|
||||
template<class Class, class...Args> struct is_function_seq<sequence<Class, Args...>>
|
||||
: boost::conditional<
|
||||
boost::is_function<Class>::value,
|
||||
is_function_seq<sequence<Args...>>,
|
||||
boost::false_type>::type
|
||||
{};
|
||||
|
||||
template<class Class>
|
||||
struct is_function_seq<sequence<Class>> : boost::is_function<Class>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_function_seq<sequence<>> : boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
/* ********************************* Function Tuple *************************** */
|
||||
|
||||
//a tuple of plain functions.
|
||||
template <class ...Ts>
|
||||
struct function_tuple;
|
||||
|
||||
template <class Return, class...Args, class T2, class ...Ts>
|
||||
struct function_tuple<Return(Args...), T2, Ts...>
|
||||
: function_tuple<T2, Ts...>
|
||||
{
|
||||
Return(*f_)(Args...);
|
||||
|
||||
constexpr function_tuple(Return(* t)(Args...), T2* t2, Ts* ... ts)
|
||||
: function_tuple<T2, Ts...>(t2, ts...)
|
||||
, f_(t)
|
||||
{}
|
||||
|
||||
Return operator()(Args...args) const {
|
||||
return (*f_)(static_cast<Args>(args)...);
|
||||
}
|
||||
using function_tuple<T2, Ts...>::operator();
|
||||
};
|
||||
|
||||
template <class Return, class...Args>
|
||||
struct function_tuple<Return(Args...)> {
|
||||
Return(*f_)(Args...);
|
||||
|
||||
constexpr function_tuple(Return(* t)(Args...))
|
||||
: f_(t)
|
||||
{}
|
||||
|
||||
Return operator()(Args...args) const {
|
||||
return (*f_)(static_cast<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* ********************************** MemFn sequence type traits ******************************/
|
||||
|
||||
template<class Class, class Func>
|
||||
struct mem_fn_def
|
||||
{
|
||||
typedef Class class_type;
|
||||
typedef Func func_type;
|
||||
typedef typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn mem_fn;
|
||||
};
|
||||
|
||||
template<class ...Args>
|
||||
struct make_mem_fn_seq;
|
||||
|
||||
// B: is T1 another version of T0?
|
||||
template<bool, class T0, class T1, class T2>
|
||||
struct make_mem_fn_seq_getter;
|
||||
|
||||
template<class T0, class T1, class T2>
|
||||
struct make_mem_fn_seq_getter<true, T0, T1, T2>
|
||||
{
|
||||
typedef mem_fn_def<T1, T2> type;
|
||||
};
|
||||
|
||||
template<class T0, class T1, class T2>
|
||||
struct make_mem_fn_seq_getter<false, T0, T1, T2>
|
||||
{
|
||||
typedef mem_fn_def<T0, T1> type;
|
||||
};
|
||||
|
||||
template<class Class, class Signature>
|
||||
struct make_mem_fn_seq<Class, Signature>
|
||||
{
|
||||
typedef mem_fn_def<Class, Signature> mem_fn;
|
||||
typedef sequence<mem_fn> type;
|
||||
};
|
||||
|
||||
template<class Class>
|
||||
struct make_mem_fn_seq<Class>
|
||||
{
|
||||
typedef sequence<> type;
|
||||
};
|
||||
|
||||
template<class T0, class T1, class T2, class ... Args>
|
||||
struct make_mem_fn_seq<T0, T1, T2, Args...>
|
||||
{
|
||||
/* Since we might have ovls, it might be :
|
||||
* Class, void(int), void(int, int) //--> just us class for both
|
||||
* Class, const Class, void(int)//--> ovl class.
|
||||
*
|
||||
*/
|
||||
static_assert(boost::is_object<T0>::value, "");
|
||||
typedef typename make_mem_fn_seq_getter<
|
||||
unqalified_is_same<T0, T1>::value, T0, T1, T2>::type mem_fn_type;
|
||||
|
||||
typedef typename boost::conditional<
|
||||
unqalified_is_same<T0, T1>::value,
|
||||
make_mem_fn_seq<T1, Args...>,
|
||||
make_mem_fn_seq<T0, T2, Args...>> ::type next;
|
||||
|
||||
typedef typename push_front<mem_fn_type, typename next::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* Ok, this needs to be documented, so here's some pseudo-code:
|
||||
*
|
||||
* @code
|
||||
*
|
||||
* bool unqalified_is_same(lhs, rhs)
|
||||
* {
|
||||
* return remove_cv(lhs) == remove_cv(rhs);
|
||||
* }
|
||||
*
|
||||
* mem_fn make_mem_fn_seq_getter(b, cl, T2, T3)
|
||||
* {
|
||||
* if (b) //b means, that T2 is another version of cl, i.e. qualified
|
||||
* return get_mem_fn_type(T2, T3);
|
||||
* else //means that T2 is a function.
|
||||
* return get_mem_fn_type(cl, T2);
|
||||
* }
|
||||
*
|
||||
* sequence make_mem_fn_seq(type cl, type T2, type T3, types...)
|
||||
* {
|
||||
* mem_fn = make_mem_fn_seq_getter(
|
||||
* unqalified_is_same(cl, T2), cl, T2, T3);
|
||||
*
|
||||
* next = unqalified_is_same(cl, T2) ?
|
||||
* make_mem_fn_seq(T2, types...) //because: T2 is another version of cl, hence i use this. T3 was already consumed.
|
||||
* :
|
||||
* make_mem_fn_seq(Class, T3, types...) //because: T2 was a function, hence it is consumed and class remains unchanged.
|
||||
* ;
|
||||
* return push_front(mem_fn, next) ;
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
|
||||
|
||||
template<class T, class U, class ...Args>
|
||||
struct is_mem_fn_seq_impl
|
||||
{
|
||||
typedef typename boost::conditional<
|
||||
boost::is_function<U>::value || boost::dll::experimental::detail::unqalified_is_same<T, U>::value,
|
||||
typename is_mem_fn_seq_impl<T, Args...>::type,
|
||||
boost::false_type>::type type;
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
struct is_mem_fn_seq_impl<T, U>
|
||||
{
|
||||
typedef typename boost::conditional<
|
||||
boost::is_function<U>::value && boost::is_object<T>::value,
|
||||
boost::true_type, boost::false_type>::type type;
|
||||
};
|
||||
|
||||
template<class T, class U, class Last>
|
||||
struct is_mem_fn_seq_impl<T, U, Last>
|
||||
{
|
||||
typedef typename boost::conditional<
|
||||
(boost::is_function<U>::value || boost::dll::experimental::detail::unqalified_is_same<T, U>::value)
|
||||
&& boost::is_function<Last>::value,
|
||||
boost::true_type, boost::false_type>::type type;
|
||||
};
|
||||
|
||||
template<class T> struct is_mem_fn_seq : boost::false_type {};
|
||||
|
||||
//If only two arguments are provided at all.
|
||||
template<class T, class U>
|
||||
struct is_mem_fn_seq<sequence<T, U>> : boost::conditional<
|
||||
boost::is_object<T>::value && boost::is_function<U>::value,
|
||||
boost::true_type, boost::false_type>::type
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
template<class T, class Func, class ...Args>
|
||||
struct is_mem_fn_seq<sequence<T, Func, Args...>> :
|
||||
boost::conditional<
|
||||
boost::is_class<T>::value && boost::is_function<Func>::value,
|
||||
typename is_mem_fn_seq_impl<T, Args...>::type,
|
||||
boost::false_type>::type {};
|
||||
|
||||
|
||||
/* ********************************** mem fn sequence tuple ******************************/
|
||||
|
||||
/* A tuple of member functions
|
||||
* Unlike for plain functions a sequence here might contain classes as well as functions.
|
||||
*/
|
||||
template <class ...Ts>
|
||||
struct mem_fn_tuple;
|
||||
|
||||
template <class Class, class Return, class...Args, class T2, class ...Ts>
|
||||
struct mem_fn_tuple<mem_fn_def<Class, Return(Args...)>, T2, Ts...>
|
||||
: mem_fn_tuple<T2, Ts...>
|
||||
{
|
||||
typedef typename boost::dll::detail::get_mem_fn_type<Class, Return(Args...)>::mem_fn mem_fn;
|
||||
mem_fn f_;
|
||||
|
||||
constexpr mem_fn_tuple(mem_fn f, typename T2::mem_fn t2, typename Ts::mem_fn ... ts)
|
||||
: mem_fn_tuple<T2, Ts...>(t2, ts...)
|
||||
, f_(f)
|
||||
{}
|
||||
|
||||
Return operator()(Class* const cl, Args...args) const {
|
||||
return (cl->*f_)(static_cast<Args>(args)...);
|
||||
}
|
||||
using mem_fn_tuple<T2, Ts...>::operator();
|
||||
|
||||
};
|
||||
|
||||
template <class Class, class Return, class...Args>
|
||||
struct mem_fn_tuple<mem_fn_def<Class, Return(Args...)>> {
|
||||
typedef typename boost::dll::detail::get_mem_fn_type<Class, Return(Args...)>::mem_fn mem_fn;
|
||||
mem_fn f_;
|
||||
|
||||
constexpr mem_fn_tuple(mem_fn f)
|
||||
: f_(f)
|
||||
{}
|
||||
|
||||
Return operator()(Class * const cl, Args...args) const {
|
||||
return (cl->*f_)(static_cast<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
#endif /* BOOST_DLL_DETAIL_IMPORT_MANGLED_HELPERS_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
|
||||
@@ -0,0 +1,429 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// returning empty result if section was not found
|
||||
if(section_begin_addr == 0 || section_end_addr == 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -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::symbol_location_ptr(si->base, ec);
|
||||
|
||||
if (ec) {
|
||||
ec.clear();
|
||||
si = static_cast<const struct soinfo*>(handle);
|
||||
return boost::dll::symbol_location_ptr(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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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 BOOST_DLL_DETAIL_TYPE_INFO_HPP_
|
||||
#define BOOST_DLL_DETAIL_TYPE_INFO_HPP_
|
||||
|
||||
#include <typeinfo>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost { namespace dll { namespace detail {
|
||||
|
||||
#if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
|
||||
|
||||
#if defined ( _WIN64 )
|
||||
|
||||
template<typename Class, typename Lib, typename Storage>
|
||||
const std::type_info& load_type_info(Lib & lib, Storage & storage)
|
||||
{
|
||||
struct RTTICompleteObjectLocator
|
||||
{
|
||||
boost::detail::winapi::DWORD_ signature; //always zero ?
|
||||
boost::detail::winapi::DWORD_ offset; //offset of this vtable in the complete class
|
||||
boost::detail::winapi::DWORD_ cdOffset; //constructor displacement offset
|
||||
boost::detail::winapi::DWORD_ pTypeDescriptorOffset; //TypeDescriptor of the complete class
|
||||
boost::detail::winapi::DWORD_ pClassDescriptorOffset; //describes inheritance hierarchy (ignored)
|
||||
};
|
||||
|
||||
RTTICompleteObjectLocator** vtable_p = &lib.template get<RTTICompleteObjectLocator*>(storage.template get_vtable<Class>());
|
||||
|
||||
vtable_p--;
|
||||
auto vtable = *vtable_p;
|
||||
|
||||
auto nat = reinterpret_cast<const char*>(lib.native());
|
||||
|
||||
nat += vtable->pTypeDescriptorOffset;
|
||||
|
||||
return *reinterpret_cast<const std::type_info*>(nat);
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<typename Class, typename Lib, typename Storage>
|
||||
const std::type_info& load_type_info(Lib & lib, Storage & storage)
|
||||
{
|
||||
struct RTTICompleteObjectLocator
|
||||
{
|
||||
boost::detail::winapi::DWORD_ signature; //always zero ?
|
||||
boost::detail::winapi::DWORD_ offset; //offset of this vtable in the complete class
|
||||
boost::detail::winapi::DWORD_ cdOffset; //constructor displacement offset
|
||||
const std::type_info* pTypeDescriptor; //TypeDescriptor of the complete class
|
||||
void* pClassDescriptor; //describes inheritance hierarchy (ignored)
|
||||
};
|
||||
|
||||
RTTICompleteObjectLocator** vtable_p = &lib.template get<RTTICompleteObjectLocator*>(storage.template get_vtable<Class>());
|
||||
|
||||
vtable_p--;
|
||||
auto vtable = *vtable_p;
|
||||
return *vtable->pTypeDescriptor;
|
||||
|
||||
}
|
||||
|
||||
#endif //_WIN64
|
||||
|
||||
#else
|
||||
|
||||
template<typename Class, typename Lib, typename Storage>
|
||||
const std::type_info& load_type_info(Lib & lib, Storage & storage)
|
||||
{
|
||||
return lib.template get<const std::type_info>(storage.template get_type_info<Class>());
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}}}
|
||||
#endif /* BOOST_DLL_DETAIL_TYPE_INFO_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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,277 @@
|
||||
// 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_IMPORT_HPP
|
||||
#define BOOST_DLL_IMPORT_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_object.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/dll/shared_library.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
# include <boost/function.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
/// \file boost/dll/import.hpp
|
||||
/// \brief Contains all the boost::dll::import* reference counting
|
||||
/// functions that hold a shared pointer to the instance of
|
||||
/// boost::dll::shared_library.
|
||||
|
||||
namespace boost { namespace dll {
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
class library_function {
|
||||
// Copying of `boost::dll::shared_library` is very expensive, so we use a `shared_ptr` to make it faster.
|
||||
boost::shared_ptr<T> f_;
|
||||
|
||||
public:
|
||||
inline library_function(const boost::shared_ptr<shared_library>& lib, T* func_ptr) BOOST_NOEXCEPT
|
||||
: f_(lib, func_ptr)
|
||||
{}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
operator T*() const BOOST_NOEXCEPT {
|
||||
return f_.get();
|
||||
}
|
||||
#else
|
||||
|
||||
// Compilation error at this point means that imported function
|
||||
// was called with unmatching parameters.
|
||||
//
|
||||
// Example:
|
||||
// auto f = dll::import<void(int)>("function", "lib.so");
|
||||
// f("Hello"); // error: invalid conversion from 'const char*' to 'int'
|
||||
// f(1, 2); // error: too many arguments to function
|
||||
// f(); // error: too few arguments to function
|
||||
template <class... Args>
|
||||
inline auto operator()(Args&&... args) const
|
||||
-> decltype( (*f_)(static_cast<Args&&>(args)...) )
|
||||
{
|
||||
return (*f_)(static_cast<Args&&>(args)...);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T, class = void>
|
||||
struct import_type;
|
||||
|
||||
template <class T>
|
||||
struct import_type<T, typename boost::disable_if<boost::is_object<T> >::type> {
|
||||
typedef boost::dll::detail::library_function<T> base_type;
|
||||
|
||||
#if defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
typedef boost::function<T> type;
|
||||
#else
|
||||
typedef boost::dll::detail::library_function<T> type;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct import_type<T, typename boost::enable_if<boost::is_object<T> >::type> {
|
||||
typedef boost::shared_ptr<T> base_type;
|
||||
typedef boost::shared_ptr<T> type;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
||||
#ifndef BOOST_DLL_DOXYGEN
|
||||
# define BOOST_DLL_IMPORT_RESULT_TYPE inline typename boost::dll::detail::import_type<T>::type
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
* Returns callable object or boost::shared_ptr<T> that holds the symbol imported
|
||||
* from the loaded library. Returned value refcounts usage
|
||||
* of the loaded shared library, so that it won't get unload until all copies of return value
|
||||
* are not destroyed.
|
||||
*
|
||||
* This call will succeed if call to \forcedlink{shared_library}`::has(const char* )`
|
||||
* function with the same symbol name returned `true`.
|
||||
*
|
||||
* For importing symbols by \b alias names use \forcedlink{import_alias} method.
|
||||
*
|
||||
* \b Examples:
|
||||
*
|
||||
* \code
|
||||
* boost::function<int(int)> f = import<int(int)>("test_lib.so", "integer_func_name");
|
||||
*
|
||||
* auto f_cpp11 = import<int(int)>("test_lib.so", "integer_func_name");
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* boost::shared_ptr<int> i = import<int>("test_lib.so", "integer_name");
|
||||
* \endcode
|
||||
*
|
||||
* \b Template \b parameter \b T: Type of the symbol that we are going to import. Must be explicitly specified.
|
||||
*
|
||||
* \param lib Path to shared library or shared library to load function from.
|
||||
* \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
|
||||
* \param mode An mode that will be used on library load.
|
||||
*
|
||||
* \return callable object if T is a function type, or boost::shared_ptr<T> if T is an object type.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
* Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import(const boost::filesystem::path& lib, const char* name,
|
||||
load_mode::type mode = load_mode::default_mode)
|
||||
{
|
||||
typedef typename boost::dll::detail::import_type<T>::base_type type;
|
||||
|
||||
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(lib, mode);
|
||||
return type(p, boost::addressof(p->get<T>(name)));
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import(const boost::filesystem::path& lib, const std::string& name,
|
||||
load_mode::type mode = load_mode::default_mode)
|
||||
{
|
||||
return import<T>(lib, name.c_str(), mode);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import(const shared_library& lib, const char* name) {
|
||||
typedef typename boost::dll::detail::import_type<T>::base_type type;
|
||||
|
||||
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(lib);
|
||||
return type(p, boost::addressof(p->get<T>(name)));
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import(const shared_library& lib, const std::string& name) {
|
||||
return import<T>(lib, name.c_str());
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import(BOOST_RV_REF(shared_library) lib, const char* name) {
|
||||
typedef typename boost::dll::detail::import_type<T>::base_type type;
|
||||
|
||||
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(
|
||||
boost::move(lib)
|
||||
);
|
||||
return type(p, boost::addressof(p->get<T>(name)));
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import(BOOST_RV_REF(shared_library) lib, const std::string& name) {
|
||||
return import<T>(boost::move(lib), name.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* Returns callable object or boost::shared_ptr<T> that holds the symbol imported
|
||||
* from the loaded library. Returned value refcounts usage
|
||||
* of the loaded shared library, so that it won't get unload until all copies of return value
|
||||
* are not destroyed.
|
||||
*
|
||||
* This call will succeed if call to \forcedlink{shared_library}`::has(const char* )`
|
||||
* function with the same symbol name returned `true`.
|
||||
*
|
||||
* For importing symbols by \b non \b alias names use \forcedlink{import} method.
|
||||
*
|
||||
* \b Examples:
|
||||
*
|
||||
* \code
|
||||
* boost::function<int(int)> f = import_alias<int(int)>("test_lib.so", "integer_func_alias_name");
|
||||
*
|
||||
* auto f_cpp11 = import_alias<int(int)>("test_lib.so", "integer_func_alias_name");
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* boost::shared_ptr<int> i = import_alias<int>("test_lib.so", "integer_alias_name");
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* \endcode
|
||||
*
|
||||
* \b Template \b parameter \b T: Type of the symbol alias that we are going to import. Must be explicitly specified.
|
||||
*
|
||||
* \param lib Path to shared library or shared library to load function from.
|
||||
* \param name Null-terminated C or C++ mangled name of the function or variable to import. Can handle std::string, char*, const char*.
|
||||
* \param mode An mode that will be used on library load.
|
||||
*
|
||||
* \return callable object if T is a function type, or boost::shared_ptr<T> if T is an object type.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
* Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(const boost::filesystem::path& lib, const char* name,
|
||||
load_mode::type mode = load_mode::default_mode)
|
||||
{
|
||||
typedef typename boost::dll::detail::import_type<T>::base_type type;
|
||||
|
||||
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(lib, mode);
|
||||
return type(p, p->get<T*>(name));
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_alias(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(const boost::filesystem::path& lib, const std::string& name,
|
||||
load_mode::type mode = load_mode::default_mode)
|
||||
{
|
||||
return import_alias<T>(lib, name.c_str(), mode);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_alias(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(const shared_library& lib, const char* name) {
|
||||
typedef typename boost::dll::detail::import_type<T>::base_type type;
|
||||
|
||||
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(lib);
|
||||
return type(p, p->get<T*>(name));
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_alias(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(const shared_library& lib, const std::string& name) {
|
||||
return import_alias<T>(lib, name.c_str());
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_alias(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(BOOST_RV_REF(shared_library) lib, const char* name) {
|
||||
typedef typename boost::dll::detail::import_type<T>::base_type type;
|
||||
|
||||
boost::shared_ptr<boost::dll::shared_library> p = boost::make_shared<boost::dll::shared_library>(
|
||||
boost::move(lib)
|
||||
);
|
||||
return type(p, p->get<T*>(name));
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_alias(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class T>
|
||||
BOOST_DLL_IMPORT_RESULT_TYPE import_alias(BOOST_RV_REF(shared_library) lib, const std::string& name) {
|
||||
return import_alias<T>(boost::move(lib), name.c_str());
|
||||
}
|
||||
|
||||
#undef BOOST_DLL_IMPORT_RESULT_TYPE
|
||||
|
||||
|
||||
}} // boost::dll
|
||||
|
||||
#endif // BOOST_DLL_IMPORT_HPP
|
||||
|
||||
@@ -0,0 +1,558 @@
|
||||
// Copyright 2015-2016 Klemens D. 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_IMPORT_CLASS_HPP_
|
||||
#define BOOST_DLL_IMPORT_CLASS_HPP_
|
||||
|
||||
#include <boost/dll/smart_library.hpp>
|
||||
#include <boost/dll/import_mangled.hpp>
|
||||
#include <memory>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost { namespace dll { namespace experimental {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct deleter
|
||||
{
|
||||
destructor<T> dtor;
|
||||
bool use_deleting;
|
||||
|
||||
deleter(const destructor<T> & dtor, bool use_deleting = false) :
|
||||
dtor(dtor), use_deleting(use_deleting) {}
|
||||
|
||||
void operator()(T*t)
|
||||
{
|
||||
if (use_deleting)
|
||||
dtor.call_deleting(t);
|
||||
else
|
||||
{
|
||||
dtor.call_standard(t);
|
||||
//the thing is actually an array, so delete[]
|
||||
auto p = reinterpret_cast<char*>(t);
|
||||
delete [] p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, class = void>
|
||||
struct mem_fn_call_proxy;
|
||||
|
||||
template<class Class, class U>
|
||||
struct mem_fn_call_proxy<Class, boost::dll::experimental::detail::mangled_library_mem_fn<Class, U>>
|
||||
{
|
||||
typedef boost::dll::experimental::detail::mangled_library_mem_fn<Class, U> mem_fn_t;
|
||||
Class* t;
|
||||
mem_fn_t & mem_fn;
|
||||
|
||||
mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
|
||||
mem_fn_call_proxy(const mem_fn_call_proxy & ) = delete;
|
||||
mem_fn_call_proxy(Class * t, mem_fn_t & mem_fn)
|
||||
: t(t), mem_fn(mem_fn) {}
|
||||
|
||||
template<typename ...Args>
|
||||
auto operator()(Args&&...args) const
|
||||
{
|
||||
return mem_fn(t, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class T, class Return, class ...Args>
|
||||
struct mem_fn_call_proxy<T, Return(Args...)>
|
||||
{
|
||||
T* t;
|
||||
const std::string &name;
|
||||
smart_library &_lib;
|
||||
|
||||
mem_fn_call_proxy(mem_fn_call_proxy&&) = default;
|
||||
mem_fn_call_proxy(const mem_fn_call_proxy&) = delete;
|
||||
mem_fn_call_proxy(T *t, const std::string &name, smart_library & _lib)
|
||||
: t(t), name(name), _lib(_lib) {};
|
||||
|
||||
Return operator()(Args...args) const
|
||||
{
|
||||
auto f = _lib.get_mem_fn<T, Return(Args...)>(name);
|
||||
return (t->*f)(static_cast<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class imported_class;
|
||||
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib, Args...args);
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib, const std::string & alias_name, Args...args);
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib, std::size_t size, Args...args);
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib, std::size_t size,
|
||||
const std::string & alias_name, Args...args);
|
||||
|
||||
|
||||
/*! This class represents an imported class.
|
||||
*
|
||||
* \note It must be constructed via \ref boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
*
|
||||
* \tparam The type or type-alias of the imported class.
|
||||
*/
|
||||
template<typename T>
|
||||
class imported_class
|
||||
{
|
||||
smart_library _lib;
|
||||
std::unique_ptr<T, detail::deleter<T>> _data;
|
||||
bool _is_allocating;
|
||||
std::size_t _size;
|
||||
const std::type_info& _ti;
|
||||
|
||||
template<typename ... Args>
|
||||
inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, Args ... args);
|
||||
template<typename ... Args>
|
||||
inline std::unique_ptr<T, detail::deleter<T>> make_data(const smart_library& lib, std::size_t size, Args...args);
|
||||
|
||||
template<typename ...Args>
|
||||
imported_class(detail::sequence<Args...> *, const smart_library& lib, Args...args);
|
||||
|
||||
template<typename ...Args>
|
||||
imported_class(detail::sequence<Args...> *, const smart_library& lib, std::size_t size, Args...args);
|
||||
|
||||
template<typename ...Args>
|
||||
imported_class(detail::sequence<Args...> *, smart_library&& lib, Args...args);
|
||||
|
||||
template<typename ...Args>
|
||||
imported_class(detail::sequence<Args...> *, smart_library&& lib, std::size_t size, Args...args);
|
||||
public:
|
||||
//alias to construct with explicit parameter list
|
||||
template<typename ...Args>
|
||||
static imported_class<T> make(smart_library&& lib, Args...args)
|
||||
{
|
||||
typedef detail::sequence<Args...> *seq;
|
||||
return imported_class(seq(), boost::move(lib), static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
static imported_class<T> make(smart_library&& lib, std::size_t size, Args...args)
|
||||
{
|
||||
typedef detail::sequence<Args...> *seq;
|
||||
return imported_class(seq(), boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
template<typename ...Args>
|
||||
static imported_class<T> make(const smart_library& lib, Args...args)
|
||||
{
|
||||
typedef detail::sequence<Args...> *seq;
|
||||
return imported_class(seq(), lib, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
static imported_class<T> make(const smart_library& lib, std::size_t size, Args...args)
|
||||
{
|
||||
typedef detail::sequence<Args...> *seq;
|
||||
return imported_class(seq(), lib, size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
typedef imported_class<T> base_t;
|
||||
///Returns a pointer to the underlying class
|
||||
T* get() {return _data.get();}
|
||||
imported_class() = delete;
|
||||
|
||||
imported_class(imported_class&) = delete;
|
||||
imported_class(imported_class&&) = default; ///<Move constructor
|
||||
imported_class& operator=(imported_class&) = delete;
|
||||
imported_class& operator=(imported_class&&) = default; ///<Move assignmend
|
||||
|
||||
///Check if the imported class is move-constructible
|
||||
bool is_move_constructible() {return !_lib.symbol_storage().template get_constructor<T(T&&)> ().empty();}
|
||||
///Check if the imported class is move-assignable
|
||||
bool is_move_assignable() {return !_lib.symbol_storage().template get_mem_fn<T, T&(T&&)> ("operator=").empty();}
|
||||
///Check if the imported class is copy-constructible
|
||||
bool is_copy_constructible() {return !_lib.symbol_storage().template get_constructor<T(const T&)>().empty();}
|
||||
///Check if the imported class is copy-assignable
|
||||
bool is_copy_assignable() {return !_lib.symbol_storage().template get_mem_fn<T, T&(const T&)>("operator=").empty();}
|
||||
|
||||
imported_class<T> copy() const; ///<Invoke the copy constructor. \attention Undefined behaviour if the imported object is not copy constructible.
|
||||
imported_class<T> move(); ///<Invoke the move constructor. \attention Undefined behaviour if the imported object is not move constructible.
|
||||
|
||||
///Invoke the copy assignment. \attention Undefined behaviour if the imported object is not copy assignable.
|
||||
void copy_assign(const imported_class<T> & lhs) const;
|
||||
///Invoke the move assignment. \attention Undefined behaviour if the imported object is not move assignable.
|
||||
void move_assign( imported_class<T> & lhs);
|
||||
|
||||
///Check if the class is loaded.
|
||||
explicit operator bool() const {return _data;}
|
||||
|
||||
///Get a const reference to the std::type_info.
|
||||
const std::type_info& get_type_info() {return _ti;};
|
||||
|
||||
/*! Call a member function. This returns a proxy to the function.
|
||||
* The proxy mechanic mechanic is necessary, so the signaute can be passed.
|
||||
*
|
||||
* \b Example
|
||||
*
|
||||
* \code
|
||||
* im_class.call<void(const char*)>("function_name")("MyString");
|
||||
* \endcode
|
||||
*/
|
||||
template<class Signature>
|
||||
const detail::mem_fn_call_proxy<T, Signature> call(const std::string& name)
|
||||
{
|
||||
return detail::mem_fn_call_proxy<T, Signature>(_data.get(), name, _lib);
|
||||
}
|
||||
/*! Call a qualified member function, i.e. const and or volatile.
|
||||
*
|
||||
* \b Example
|
||||
*
|
||||
* \code
|
||||
* im_class.call<const type_alias, void(const char*)>("function_name")("MyString");
|
||||
* \endcode
|
||||
*/
|
||||
template<class Tin, class Signature, class = boost::enable_if<detail::unqalified_is_same<T, Tin>>>
|
||||
const detail::mem_fn_call_proxy<Tin, Signature> call(const std::string& name)
|
||||
{
|
||||
return detail::mem_fn_call_proxy<Tin, Signature>(_data.get(), name, _lib);
|
||||
}
|
||||
///Overload of ->* for an imported method.
|
||||
template<class Tin, class T2>
|
||||
const detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>
|
||||
operator->*(detail::mangled_library_mem_fn<Tin, T2>& mn)
|
||||
{
|
||||
return detail::mem_fn_call_proxy<Tin, boost::dll::experimental::detail::mangled_library_mem_fn<Tin, T2>>(_data.get(), mn);
|
||||
}
|
||||
|
||||
///Import a method of the class.
|
||||
template <class ...Args>
|
||||
typename boost::dll::experimental::detail::mangled_import_type<boost::dll::experimental::detail::sequence<T, Args...>>::type
|
||||
import(const std::string & name)
|
||||
{
|
||||
return boost::dll::experimental::import_mangled<T, Args...>(_lib, name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//helper function, uses the allocating
|
||||
template<typename T>
|
||||
template<typename ... Args>
|
||||
inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, Args ... args)
|
||||
{
|
||||
constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
|
||||
destructor<T> dtor = lib.get_destructor <T>();
|
||||
|
||||
if (!ctor.has_allocating() || !dtor.has_deleting())
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_file_descriptor,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
|
||||
// report_error() calls dlsym, do not use it here!
|
||||
boost::throw_exception(
|
||||
boost::system::system_error(
|
||||
ec, "boost::dll::detail::make_data() failed: no allocating ctor or dtor was found"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return std::unique_ptr<T, detail::deleter<T>> (
|
||||
ctor.call_allocating(static_cast<Args>(args)...),
|
||||
detail::deleter<T>(dtor, false /* not deleting dtor*/));
|
||||
}
|
||||
|
||||
//helper function, using the standard
|
||||
template<typename T>
|
||||
template<typename ... Args>
|
||||
inline std::unique_ptr<T, detail::deleter<T>> imported_class<T>::make_data(const smart_library& lib, std::size_t size, Args...args)
|
||||
{
|
||||
constructor<T(Args...)> ctor = lib.get_constructor<T(Args...)>();
|
||||
destructor<T> dtor = lib.get_destructor <T>();
|
||||
|
||||
if (!ctor.has_standard() || !dtor.has_standard())
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_file_descriptor,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
|
||||
// report_error() calls dlsym, do not use it here!
|
||||
boost::throw_exception(
|
||||
boost::system::system_error(
|
||||
ec, "boost::dll::detail::make_data() failed: no regular ctor or dtor was found"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
T *data = reinterpret_cast<T*>(new char[size]);
|
||||
|
||||
ctor.call_standard(data, static_cast<Args>(args)...);
|
||||
|
||||
return std::unique_ptr<T, detail::deleter<T>> (
|
||||
reinterpret_cast<T*>(data),
|
||||
detail::deleter<T>(dtor, false /* not deleting dtor*/));
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
template<typename ...Args>
|
||||
imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, Args...args)
|
||||
: _lib(lib),
|
||||
_data(make_data<Args...>(lib, static_cast<Args>(args)...)),
|
||||
_is_allocating(false),
|
||||
_size(0),
|
||||
_ti(lib.get_type_info<T>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename ...Args>
|
||||
imported_class<T>::imported_class(detail::sequence<Args...> *, const smart_library & lib, std::size_t size, Args...args)
|
||||
: _lib(lib),
|
||||
_data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
|
||||
_is_allocating(true),
|
||||
_size(size),
|
||||
_ti(lib.get_type_info<T>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename ...Args>
|
||||
imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, Args...args)
|
||||
: _lib(boost::move(lib)),
|
||||
_data(make_data<Args...>(lib, static_cast<Args>(args)...)),
|
||||
_is_allocating(false),
|
||||
_size(0),
|
||||
_ti(lib.get_type_info<T>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename ...Args>
|
||||
imported_class<T>::imported_class(detail::sequence<Args...> *, smart_library && lib, std::size_t size, Args...args)
|
||||
: _lib(boost::move(lib)),
|
||||
_data(make_data<Args...>(lib, size, static_cast<Args>(args)...)),
|
||||
_is_allocating(true),
|
||||
_size(size),
|
||||
_ti(lib.get_type_info<T>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline imported_class<T> boost::dll::experimental::imported_class<T>::copy() const
|
||||
{
|
||||
if (this->_is_allocating)
|
||||
return imported_class<T>::template make<const T&>(_lib, *_data);
|
||||
else
|
||||
return imported_class<T>::template make<const T&>(_lib, _size, *_data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline imported_class<T> boost::dll::experimental::imported_class<T>::move()
|
||||
{
|
||||
if (this->_is_allocating)
|
||||
return imported_class<T>::template make<T&&>(_lib, *_data);
|
||||
else
|
||||
return imported_class<T>::template make<T&&>(_lib, _size, *_data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void boost::dll::experimental::imported_class<T>::copy_assign(const imported_class<T>& lhs) const
|
||||
{
|
||||
this->call<T&(const T&)>("operator=")(*lhs._data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void boost::dll::experimental::imported_class<T>::move_assign(imported_class<T>& lhs)
|
||||
{
|
||||
this->call<T&(T&&)>("operator=")(static_cast<T&&>(*lhs._data));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* Returns an instance of \ref imported_class which allows to call or import more functions.
|
||||
* It takes a copy of the smart_libray, so no added type_aliases will be visible,
|
||||
* for the object.
|
||||
*
|
||||
* Few compilers do implement an allocating constructor, which allows the construction
|
||||
* of the class without knowing the size. That is not portable, so the actual size of the class
|
||||
* shall always be provided.
|
||||
*
|
||||
* \b Example:
|
||||
*
|
||||
* \code
|
||||
* auto import_class<class type_alias, const std::string&, std::size_t>(lib, "class_name", 20, "param1", 42);
|
||||
* \endcode
|
||||
*
|
||||
* In this example we construct an instance of the class "class_name" with the size 20, which has "type_alias" as an alias,
|
||||
* through a constructor which takes a const-ref of std::string and an std::size_t parameter.
|
||||
*
|
||||
* \tparam T Class type or alias
|
||||
* \tparam Args Constructor argument list.
|
||||
* \param lib Path to shared library or shared library to load function from.
|
||||
* \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
|
||||
* \param mode An mode that will be used on library load.
|
||||
*
|
||||
* \return class object.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
* Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib_, std::size_t size, Args...args)
|
||||
{
|
||||
smart_library lib(lib_);
|
||||
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib_, Args...args)
|
||||
{
|
||||
smart_library lib(lib_);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib_, const std::string & alias_name, Args...args)
|
||||
{
|
||||
smart_library lib(lib_);
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib_, std::size_t size, const std::string & alias_name, Args...args)
|
||||
{
|
||||
smart_library lib(lib_);
|
||||
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(const smart_library& lib_, const std::string & alias_name, std::size_t size, Args...args)
|
||||
{
|
||||
smart_library lib(lib_);
|
||||
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library && lib, Args...args)
|
||||
{
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library && lib, const std::string & alias_name, Args...args)
|
||||
{
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library && lib, std::size_t size, Args...args)
|
||||
{
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library && lib, std::size_t size, const std::string & alias_name, Args...args)
|
||||
{
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library && lib, const std::string & alias_name, std::size_t size, Args...args)
|
||||
{
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(boost::move(lib), size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
|
||||
*/
|
||||
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library & lib, Args...args)
|
||||
{
|
||||
return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
|
||||
*/
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library & lib, const std::string & alias_name, Args...args)
|
||||
{
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(lib, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
|
||||
*/
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library & lib, std::size_t size, Args...args)
|
||||
{
|
||||
return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
|
||||
*/
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library & lib, std::size_t size, const std::string & alias_name, Args...args)
|
||||
{
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! \overload boost::dll::import_class(const smart_library& lib, std::size_t, Args...)
|
||||
* \note This function does add the type alias to the \ref boost::dll::experimental::smart_library.
|
||||
*/
|
||||
template<typename T, typename ... Args> imported_class<T>
|
||||
import_class(smart_library & lib, const std::string & alias_name, std::size_t size, Args...args)
|
||||
{
|
||||
lib.add_type_alias<T>(alias_name);
|
||||
return imported_class<T>::template make<Args...>(lib, size, static_cast<Args>(args)...);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_DLL_IMPORT_CLASS_HPP_ */
|
||||
@@ -0,0 +1,309 @@
|
||||
// Copyright 2015-2016 Klemens D. 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_IMPORT_MANGLED_HPP_
|
||||
#define BOOST_DLL_IMPORT_MANGLED_HPP_
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/dll/smart_library.hpp>
|
||||
#include <boost/dll/detail/import_mangled_helpers.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/is_object.hpp>
|
||||
|
||||
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost { namespace dll { namespace experimental {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
||||
|
||||
template <class ... Ts>
|
||||
class mangled_library_function {
|
||||
// Copying of `boost::dll::shared_library` is very expensive, so we use a `shared_ptr` to make it faster.
|
||||
boost::shared_ptr<shared_library> lib_;
|
||||
function_tuple<Ts...> f_;
|
||||
public:
|
||||
constexpr mangled_library_function(const boost::shared_ptr<shared_library>& lib, Ts*... func_ptr) BOOST_NOEXCEPT
|
||||
: lib_(lib)
|
||||
, f_(func_ptr...)
|
||||
{}
|
||||
|
||||
|
||||
// Compilation error at this point means that imported function
|
||||
// was called with unmatching parameters.
|
||||
//
|
||||
// Example:
|
||||
// auto f = dll::import_mangled<void(int), void(double)>("function", "lib.so");
|
||||
// f("Hello"); // error: invalid conversion from 'const char*' to 'int'
|
||||
// f(1, 2); // error: too many arguments to function
|
||||
// f(); // error: too few arguments to function
|
||||
template <class... Args>
|
||||
auto operator()(Args&&... args) const
|
||||
-> decltype( f_(static_cast<Args&&>(args)...) )
|
||||
{
|
||||
return f_(static_cast<Args&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Class, class Sequence>
|
||||
class mangled_library_mem_fn;
|
||||
|
||||
template <class Class, class ... Ts>
|
||||
class mangled_library_mem_fn<Class, sequence<Ts...>> {
|
||||
// Copying of `boost::dll::shared_library` is very expensive, so we use a `shared_ptr` to make it faster.
|
||||
typedef mem_fn_tuple<Ts...> call_tuple_t;
|
||||
boost::shared_ptr<shared_library> lib_;
|
||||
call_tuple_t f_;
|
||||
|
||||
public:
|
||||
constexpr mangled_library_mem_fn(const boost::shared_ptr<shared_library>& lib, typename Ts::mem_fn... func_ptr) BOOST_NOEXCEPT
|
||||
: lib_(lib)
|
||||
, f_(func_ptr...)
|
||||
{}
|
||||
|
||||
template <class ClassIn, class... Args>
|
||||
auto operator()(ClassIn *cl, Args&&... args) const
|
||||
-> decltype( f_(cl, static_cast<Args&&>(args)...) )
|
||||
{
|
||||
return f_(cl, static_cast<Args&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// simple enough to be here
|
||||
template<class Seq> struct is_variable : boost::false_type {};
|
||||
template<typename T> struct is_variable<sequence<T>> : boost::is_object<T> {};
|
||||
|
||||
template <class Sequence,
|
||||
bool isFunction = is_function_seq<Sequence>::value,
|
||||
bool isMemFn = is_mem_fn_seq <Sequence>::value,
|
||||
bool isVariable = is_variable <Sequence>::value>
|
||||
struct mangled_import_type;
|
||||
|
||||
template <class ...Args>
|
||||
struct mangled_import_type<sequence<Args...>, true,false,false> //is function
|
||||
{
|
||||
typedef boost::dll::experimental::detail::mangled_library_function<Args...> type;
|
||||
static type make(
|
||||
const boost::dll::experimental::smart_library& p,
|
||||
const std::string& name)
|
||||
{
|
||||
return type(
|
||||
boost::make_shared<shared_library>(p.shared_lib()),
|
||||
boost::addressof(p.get_function<Args>(name))...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Class, class ...Args>
|
||||
struct mangled_import_type<sequence<Class, Args...>, false, true, false> //is member-function
|
||||
{
|
||||
typedef typename boost::dll::experimental::detail::make_mem_fn_seq<Class, Args...>::type actual_sequence;
|
||||
typedef typename boost::dll::experimental::detail::mangled_library_mem_fn<Class, actual_sequence> type;
|
||||
|
||||
|
||||
template<class ... ArgsIn>
|
||||
static type make_impl(
|
||||
const boost::dll::experimental::smart_library& p,
|
||||
const std::string & name,
|
||||
sequence<ArgsIn...> * )
|
||||
{
|
||||
return type(boost::make_shared<shared_library>(p.shared_lib()),
|
||||
p.get_mem_fn<typename ArgsIn::class_type, typename ArgsIn::func_type>(name)...);
|
||||
}
|
||||
|
||||
static type make(
|
||||
const boost::dll::experimental::smart_library& p,
|
||||
const std::string& name)
|
||||
{
|
||||
return make_impl(p, name, static_cast<actual_sequence*>(nullptr));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct mangled_import_type<sequence<T>, false, false, true> //is variable
|
||||
{
|
||||
typedef boost::shared_ptr<T> type;
|
||||
|
||||
static type make(
|
||||
const boost::dll::experimental::smart_library& p,
|
||||
const std::string& name)
|
||||
{
|
||||
return type(
|
||||
boost::make_shared<shared_library>(p.shared_lib()),
|
||||
boost::addressof(p.get_variable<T>(name)));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
#ifndef BOOST_DLL_DOXYGEN
|
||||
# define BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE inline typename \
|
||||
boost::dll::experimental::detail::mangled_import_type<boost::dll::experimental::detail::sequence<Args...>>::type
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Variants:
|
||||
* import_mangled<int>("Stuff");
|
||||
* import_mangled<thingy(xyz)>("Function");
|
||||
* import mangled<thingy, void(int)>("Function");
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Returns callable object or boost::shared_ptr<T> that holds the symbol imported
|
||||
* from the loaded library. Returned value refcounts usage
|
||||
* of the loaded shared library, so that it won't get unload until all copies of return value
|
||||
* are not destroyed.
|
||||
*
|
||||
* For importing symbols by \b alias names use \forcedlink{import_alias} method.
|
||||
*
|
||||
* \b Examples:
|
||||
*
|
||||
* \code
|
||||
* boost::function<int(int)> f = import_mangled<int(int)>("test_lib.so", "integer_func_name");
|
||||
*
|
||||
* auto f_cpp11 = import_mangled<int(int)>("test_lib.so", "integer_func_name");
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* boost::shared_ptr<int> i = import_mangled<int>("test_lib.so", "integer_name");
|
||||
* \endcode
|
||||
*
|
||||
* Additionally you can also import overloaded symbols, including member-functions.
|
||||
*
|
||||
* \code
|
||||
* auto fp = import_mangled<void(int), void(double)>("test_lib.so", "func");
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* auto fp = import_mangled<my_class, void(int), void(double)>("test_lib.so", "func");
|
||||
* \endcode
|
||||
*
|
||||
* If qualified member-functions are needed, this can be set by repeating the class name with const or volatile.
|
||||
* All following signatures after the redifintion will use this, i.e. the latest.
|
||||
*
|
||||
* * * \code
|
||||
* auto fp = import_mangled<my_class, void(int), void(double),
|
||||
* const my_class, void(int), void(double)>("test_lib.so", "func");
|
||||
* \endcode
|
||||
*
|
||||
* \b Template \b parameter \b T: Type of the symbol that we are going to import. Must be explicitly specified.
|
||||
*
|
||||
* \param lib Path to shared library or shared library to load function from.
|
||||
* \param name Null-terminated C or C++ mangled name of the function to import. Can handle std::string, char*, const char*.
|
||||
* \param mode An mode that will be used on library load.
|
||||
*
|
||||
* \return callable object if T is a function type, or boost::shared_ptr<T> if T is an object type.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
* Overload that accepts path also throws std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
|
||||
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(const boost::filesystem::path& lib, const char* name,
|
||||
load_mode::type mode = load_mode::default_mode)
|
||||
{
|
||||
typedef typename boost::dll::experimental::detail::mangled_import_type<
|
||||
boost::dll::experimental::detail::sequence<Args...>> type;
|
||||
|
||||
boost::dll::experimental::smart_library p(lib, mode);
|
||||
//the load
|
||||
return type::make(p, name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(const boost::filesystem::path& lib, const std::string& name,
|
||||
load_mode::type mode = load_mode::default_mode)
|
||||
{
|
||||
return import_mangled<Args...>(lib, name.c_str(), mode);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(const smart_library& lib, const char* name) {
|
||||
typedef typename boost::dll::experimental::detail::mangled_import_type<detail::sequence<Args...>> type;
|
||||
|
||||
return type::make(lib, name);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(const smart_library& lib, const std::string& name) {
|
||||
return import_mangled<Args...>(lib, name.c_str());
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(BOOST_RV_REF(smart_library) lib, const char* name) {
|
||||
typedef typename boost::dll::experimental::detail::mangled_import_type<detail::sequence<Args...>> type;
|
||||
|
||||
return type::make(lib, name);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(BOOST_RV_REF(smart_library) lib, const std::string& name) {
|
||||
return import_mangled<Args...>(boost::move(lib), name.c_str());
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(const shared_library& lib, const char* name) {
|
||||
typedef typename boost::dll::experimental::detail::mangled_import_type<detail::sequence<Args...>> type;
|
||||
|
||||
boost::shared_ptr<boost::dll::experimental::smart_library> p = boost::make_shared<boost::dll::experimental::smart_library>(lib);
|
||||
return type::make(p, name);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(const shared_library& lib, const std::string& name) {
|
||||
return import_mangled<Args...>(lib, name.c_str());
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(BOOST_RV_REF(shared_library) lib, const char* name) {
|
||||
typedef typename boost::dll::experimental::detail::mangled_import_type<detail::sequence<Args...>> type;
|
||||
|
||||
boost::dll::experimental::smart_library p(boost::move(lib));
|
||||
|
||||
return type::make(p, name);
|
||||
}
|
||||
|
||||
//! \overload boost::dll::import(const boost::filesystem::path& lib, const char* name, load_mode::type mode)
|
||||
template <class ...Args>
|
||||
BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE import_mangled(BOOST_RV_REF(shared_library) lib, const std::string& name) {
|
||||
return import_mangled<Args...>(boost::move(lib), name.c_str());
|
||||
}
|
||||
|
||||
#undef BOOST_DLL_MANGLED_IMPORT_RESULT_TYPE
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
#endif /* BOOST_DLL_IMPORT_MANGLED_HPP_ */
|
||||
@@ -0,0 +1,181 @@
|
||||
// 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_LIBRARY_INFO_HPP
|
||||
#define BOOST_DLL_LIBRARY_INFO_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mpl/max_element.hpp>
|
||||
#include <boost/mpl/vector_c.hpp>
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/predef/os.h>
|
||||
#include <boost/predef/architecture.h>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
#include <boost/dll/detail/pe_info.hpp>
|
||||
#include <boost/dll/detail/elf_info.hpp>
|
||||
#include <boost/dll/detail/macho_info.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
/// \file boost/dll/library_info.hpp
|
||||
/// \brief Contains only the boost::dll::library_info class that is capable of
|
||||
/// extracting different information from binaries.
|
||||
|
||||
namespace boost { namespace dll {
|
||||
|
||||
/*!
|
||||
* \brief Class that is capable of extracting different information from a library or binary file.
|
||||
* Currently understands ELF, MACH-O and PE formats on all the platforms.
|
||||
*/
|
||||
class library_info: private boost::noncopyable {
|
||||
private:
|
||||
boost::filesystem::ifstream f_;
|
||||
|
||||
boost::aligned_storage< // making my own std::aligned_union from scratch. TODO: move to TypeTraits
|
||||
boost::mpl::deref<
|
||||
boost::mpl::max_element<
|
||||
boost::mpl::vector_c<std::size_t,
|
||||
sizeof(boost::dll::detail::elf_info32),
|
||||
sizeof(boost::dll::detail::elf_info64),
|
||||
sizeof(boost::dll::detail::pe_info32),
|
||||
sizeof(boost::dll::detail::pe_info64),
|
||||
sizeof(boost::dll::detail::macho_info32),
|
||||
sizeof(boost::dll::detail::macho_info64)
|
||||
>
|
||||
>::type
|
||||
>::type::value
|
||||
>::type impl_;
|
||||
|
||||
/// @cond
|
||||
boost::dll::detail::x_info_interface& impl() BOOST_NOEXCEPT {
|
||||
return *reinterpret_cast<boost::dll::detail::x_info_interface*>(impl_.address());
|
||||
}
|
||||
|
||||
inline static void throw_if_in_32bit_impl(boost::true_type /* is_32bit_platform */) {
|
||||
boost::throw_exception(std::runtime_error("Not native format: 64bit binary"));
|
||||
}
|
||||
|
||||
inline static void throw_if_in_32bit_impl(boost::false_type /* is_32bit_platform */) BOOST_NOEXCEPT {}
|
||||
|
||||
|
||||
inline static void throw_if_in_32bit() {
|
||||
throw_if_in_32bit_impl( boost::integral_constant<bool, (sizeof(void*) == 4)>() );
|
||||
}
|
||||
|
||||
static void throw_if_in_windows() {
|
||||
#if BOOST_OS_WINDOWS
|
||||
boost::throw_exception(std::runtime_error("Not native format: not a PE binary"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void throw_if_in_linux() {
|
||||
#if !BOOST_OS_WINDOWS && !BOOST_OS_MACOS && !BOOST_OS_IOS
|
||||
boost::throw_exception(std::runtime_error("Not native format: not an ELF binary"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void throw_if_in_macos() {
|
||||
#if BOOST_OS_MACOS || BOOST_OS_IOS
|
||||
boost::throw_exception(std::runtime_error("Not native format: not an Mach-O binary"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void init(bool throw_if_not_native) {
|
||||
|
||||
if (boost::dll::detail::elf_info32::parsing_supported(f_)) {
|
||||
if (throw_if_not_native) { throw_if_in_windows(); throw_if_in_macos(); }
|
||||
|
||||
new (impl_.address()) boost::dll::detail::elf_info32(f_);
|
||||
} else if (boost::dll::detail::elf_info64::parsing_supported(f_)) {
|
||||
if (throw_if_not_native) { throw_if_in_windows(); throw_if_in_macos(); throw_if_in_32bit(); }
|
||||
|
||||
new (impl_.address()) boost::dll::detail::elf_info64(f_);
|
||||
} else if (boost::dll::detail::pe_info32::parsing_supported(f_)) {
|
||||
if (throw_if_not_native) { throw_if_in_linux(); throw_if_in_macos(); }
|
||||
|
||||
new (impl_.address()) boost::dll::detail::pe_info32(f_);
|
||||
} else if (boost::dll::detail::pe_info64::parsing_supported(f_)) {
|
||||
if (throw_if_not_native) { throw_if_in_linux(); throw_if_in_macos(); throw_if_in_32bit(); }
|
||||
|
||||
new (impl_.address()) boost::dll::detail::pe_info64(f_);
|
||||
} else if (boost::dll::detail::macho_info32::parsing_supported(f_)) {
|
||||
if (throw_if_not_native) { throw_if_in_linux(); throw_if_in_windows(); }
|
||||
|
||||
new (impl_.address()) boost::dll::detail::macho_info32(f_);
|
||||
} else if (boost::dll::detail::macho_info64::parsing_supported(f_)) {
|
||||
if (throw_if_not_native) { throw_if_in_linux(); throw_if_in_windows(); throw_if_in_32bit(); }
|
||||
|
||||
new (impl_.address()) boost::dll::detail::macho_info64(f_);
|
||||
} else {
|
||||
boost::throw_exception(std::runtime_error("Unsupported binary format"));
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Opens file with specified path and prepares for information extraction.
|
||||
* \param library_path Path to the binary file from which the info must be extracted.
|
||||
* \param throw_if_not_native_format Throw an exception if this file format is not
|
||||
* supported by OS.
|
||||
*/
|
||||
explicit library_info(const boost::filesystem::path& library_path, bool throw_if_not_native_format = true)
|
||||
: f_(library_path, std::ios_base::in | std::ios_base::binary)
|
||||
, impl_()
|
||||
{
|
||||
f_.exceptions(
|
||||
boost::filesystem::ifstream::failbit
|
||||
| boost::filesystem::ifstream::badbit
|
||||
| boost::filesystem::ifstream::eofbit
|
||||
);
|
||||
|
||||
init(throw_if_not_native_format);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \return List of sections that exist in binary file.
|
||||
*/
|
||||
std::vector<std::string> sections() {
|
||||
return impl().sections();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \return List of all the exportable symbols from all the sections that exist in binary file.
|
||||
*/
|
||||
std::vector<std::string> symbols() {
|
||||
return impl().symbols();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \param section_name Name of the section from which symbol names must be returned.
|
||||
* \return List of symbols from the specified section.
|
||||
*/
|
||||
std::vector<std::string> symbols(const char* section_name) {
|
||||
return impl().symbols(section_name);
|
||||
}
|
||||
|
||||
|
||||
//! \overload std::vector<std::string> symbols(const char* section_name)
|
||||
std::vector<std::string> symbols(const std::string& section_name) {
|
||||
return impl().symbols(section_name.c_str());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \throw Nothing.
|
||||
*/
|
||||
~library_info() BOOST_NOEXCEPT {
|
||||
typedef boost::dll::detail::x_info_interface T;
|
||||
impl().~T();
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::dll
|
||||
#endif // BOOST_DLL_LIBRARY_INFO_HPP
|
||||
@@ -0,0 +1,237 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright 2015-2017 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_RUNTIME_SYMBOL_INFO_HPP
|
||||
#define BOOST_DLL_RUNTIME_SYMBOL_INFO_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef/os.h>
|
||||
#include <boost/predef/compiler/visualc.h>
|
||||
#include <boost/dll/detail/aggressive_ptr_cast.hpp>
|
||||
#if BOOST_OS_WINDOWS
|
||||
# include <boost/detail/winapi/dll.hpp>
|
||||
# include <boost/dll/detail/windows/path_from_handle.hpp>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
# include <boost/dll/detail/posix/program_location_impl.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
/// \file boost/dll/runtime_symbol_info.hpp
|
||||
/// \brief Provides methods for getting acceptable by boost::dll::shared_library location of symbol, source line or program.
|
||||
namespace boost { namespace dll {
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
namespace detail {
|
||||
inline boost::filesystem::path program_location_impl(boost::system::error_code& ec) {
|
||||
return boost::dll::detail::path_from_handle(NULL, ec);
|
||||
}
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* On success returns full path and name to the binary object that holds symbol pointed by ptr_to_symbol.
|
||||
*
|
||||
* \param ptr_to_symbol Pointer to symbol which location is to be determined.
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \return Path to the binary object that holds symbol or empty path in case error.
|
||||
* \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
|
||||
*
|
||||
* \b Examples:
|
||||
* \code
|
||||
* int main() {
|
||||
* dll::symbol_location_ptr(std::set_terminate(0)); // returns "/some/path/libmy_terminate_handler.so"
|
||||
* dll::symbol_location_ptr(::signal(SIGSEGV, SIG_DFL)); // returns "/some/path/libmy_symbol_handler.so"
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
template <class T>
|
||||
inline boost::filesystem::path symbol_location_ptr(T ptr_to_symbol, boost::system::error_code& ec) {
|
||||
BOOST_STATIC_ASSERT_MSG(boost::is_pointer<T>::value, "boost::dll::symbol_location_ptr works only with pointers! `ptr_to_symbol` must be a pointer");
|
||||
boost::filesystem::path ret;
|
||||
if (!ptr_to_symbol) {
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_address,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
ec.clear();
|
||||
|
||||
const void* ptr = boost::dll::detail::aggressive_ptr_cast<const void*>(ptr_to_symbol);
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
boost::detail::winapi::MEMORY_BASIC_INFORMATION_ mbi;
|
||||
if (!boost::detail::winapi::VirtualQuery(ptr, &mbi, sizeof(mbi))) {
|
||||
ec = boost::dll::detail::last_error_code();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return boost::dll::detail::path_from_handle(reinterpret_cast<boost::detail::winapi::HMODULE_>(mbi.AllocationBase), ec);
|
||||
#else
|
||||
Dl_info info;
|
||||
|
||||
// Some of the libc headers miss `const` in `dladdr(const void*, Dl_info*)`
|
||||
const int res = dladdr(const_cast<void*>(ptr), &info);
|
||||
|
||||
if (res) {
|
||||
ret = info.dli_fname;
|
||||
} else {
|
||||
boost::dll::detail::reset_dlerror();
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_address,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
//! \overload symbol_location_ptr(const void* ptr_to_symbol, boost::system::error_code& ec)
|
||||
template <class T>
|
||||
inline boost::filesystem::path symbol_location_ptr(T ptr_to_symbol) {
|
||||
boost::filesystem::path ret;
|
||||
boost::system::error_code ec;
|
||||
ret = boost::dll::symbol_location_ptr(ptr_to_symbol, ec);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::symbol_location_ptr(T ptr_to_symbol) failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* On success returns full path and name of the binary object that holds symbol.
|
||||
*
|
||||
* \tparam T Type of the symbol, must not be explicitly specified.
|
||||
* \param symbol Symbol which location is to be determined.
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \return Path to the binary object that holds symbol or empty path in case error.
|
||||
* \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
|
||||
*
|
||||
* \b Examples:
|
||||
* \code
|
||||
* int var;
|
||||
* void foo() {}
|
||||
*
|
||||
* int main() {
|
||||
* dll::symbol_location(var); // returns program location
|
||||
* dll::symbol_location(foo); // returns program location
|
||||
* dll::symbol_location(std::cerr); // returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
|
||||
* dll::symbol_location(std::placeholders::_1); // returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
|
||||
* dll::symbol_location(std::puts); // returns location of libc: "/lib/x86_64-linux-gnu/libc.so.6"
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
template <class T>
|
||||
inline boost::filesystem::path symbol_location(const T& symbol, boost::system::error_code& ec) {
|
||||
ec.clear();
|
||||
return boost::dll::symbol_location_ptr(
|
||||
boost::dll::detail::aggressive_ptr_cast<const void*>(boost::addressof(symbol)),
|
||||
ec
|
||||
);
|
||||
}
|
||||
|
||||
#if BOOST_COMP_MSVC < BOOST_VERSION_NUMBER(14,0,0)
|
||||
// Without this MSVC 7.1 fails with:
|
||||
// ..\boost\dll\runtime_symbol_info.hpp(133) : error C2780: 'filesystem::path dll::symbol_location(const T &)' : expects 1 arguments - 2 provided
|
||||
template <class T>
|
||||
inline boost::filesystem::path symbol_location(const T& symbol, const char* /*workaround*/ = 0)
|
||||
#else
|
||||
//! \overload symbol_location(const T& symbol, boost::system::error_code& ec)
|
||||
template <class T>
|
||||
inline boost::filesystem::path symbol_location(const T& symbol)
|
||||
#endif
|
||||
{
|
||||
boost::filesystem::path ret;
|
||||
boost::system::error_code ec;
|
||||
ret = boost::dll::symbol_location_ptr(
|
||||
boost::dll::detail::aggressive_ptr_cast<const void*>(boost::addressof(symbol)),
|
||||
ec
|
||||
);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::symbol_location(const T& symbol) failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @cond
|
||||
// We have anonymous namespace here to make sure that `this_line_location()` method is instantiated in
|
||||
// current translation unit and is not shadowed by instantiations from other units.
|
||||
namespace {
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
* On success returns full path and name of the binary object that holds the current line of code
|
||||
* (the line in which the `this_line_location()` method was called).
|
||||
*
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
|
||||
*/
|
||||
static inline boost::filesystem::path this_line_location(boost::system::error_code& ec) {
|
||||
typedef boost::filesystem::path(func_t)(boost::system::error_code& );
|
||||
func_t& f = this_line_location;
|
||||
return boost::dll::symbol_location(f, ec);
|
||||
}
|
||||
|
||||
//! \overload this_line_location(boost::system::error_code& ec)
|
||||
static inline boost::filesystem::path this_line_location() {
|
||||
boost::filesystem::path ret;
|
||||
boost::system::error_code ec;
|
||||
ret = this_line_location(ec);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::this_line_location() failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @cond
|
||||
} // anonymous namespace
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
* On success returns full path and name of the currently running program (the one which contains the `main()` function).
|
||||
*
|
||||
* Return value can be used as a parameter for shared_library. See Tutorial "Linking plugin into the executable"
|
||||
* for usage example. Flag '-rdynamic' must be used when linking the plugin into the executable
|
||||
* on Linux OS.
|
||||
*
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
|
||||
*/
|
||||
inline boost::filesystem::path program_location(boost::system::error_code& ec) {
|
||||
ec.clear();
|
||||
return boost::dll::detail::program_location_impl(ec);
|
||||
}
|
||||
|
||||
//! \overload program_location(boost::system::error_code& ec) {
|
||||
inline boost::filesystem::path program_location() {
|
||||
boost::filesystem::path ret;
|
||||
boost::system::error_code ec;
|
||||
ret = boost::dll::detail::program_location_impl(ec);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::program_location() failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}} // namespace boost::dll
|
||||
|
||||
#endif // BOOST_DLL_RUNTIME_SYMBOL_INFO_HPP
|
||||
|
||||
@@ -0,0 +1,550 @@
|
||||
// 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_HPP
|
||||
#define BOOST_DLL_SHARED_LIBRARY_HPP
|
||||
|
||||
/// \file boost/dll/shared_library.hpp
|
||||
/// \brief Contains the boost::dll::shared_library class, core class for all the
|
||||
/// DLL/DSO operations.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef/os.h>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_member_pointer.hpp>
|
||||
#include <boost/utility/explicit_operator_bool.hpp>
|
||||
#include <boost/dll/detail/system_error.hpp>
|
||||
#include <boost/dll/detail/aggressive_ptr_cast.hpp>
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
# include <boost/dll/detail/windows/shared_library_impl.hpp>
|
||||
#else
|
||||
# include <boost/dll/detail/posix/shared_library_impl.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost { namespace dll {
|
||||
|
||||
/*!
|
||||
* \brief This class can be used to load a
|
||||
* Dynamic link libraries (DLL's) or Shared Libraries, also know
|
||||
* as dynamic shared objects (DSO's) and get their exported
|
||||
* symbols (functions and variables).
|
||||
*
|
||||
* shared_library instances share reference count to an actual loaded DLL/DSO, so it
|
||||
* is safe and memory efficient to have multiple instances of shared_library referencing the same DLL/DSO
|
||||
* even if those instances were loaded using different paths (relative + absolute) referencing the same object.
|
||||
*
|
||||
* On Linux/POSIX link with library "dl". "-fvisibility=hidden" flag is also recommended for use on Linux/POSIX.
|
||||
*/
|
||||
class shared_library
|
||||
/// @cond
|
||||
: private boost::dll::detail::shared_library_impl
|
||||
/// @endcond
|
||||
{
|
||||
typedef boost::dll::detail::shared_library_impl base_t;
|
||||
BOOST_COPYABLE_AND_MOVABLE(shared_library)
|
||||
|
||||
public:
|
||||
#ifdef BOOST_DLL_DOXYGEN
|
||||
typedef platform_specific native_handle_t;
|
||||
#else
|
||||
typedef shared_library_impl::native_handle_t native_handle_t;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Creates in anstance that does not reference any DLL/DSO.
|
||||
*
|
||||
* \post this->is_loaded() returns false.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
shared_library() BOOST_NOEXCEPT {}
|
||||
|
||||
/*!
|
||||
* Copy constructor that increments the reference count of an underlying shared library.
|
||||
* Same as calling constructor with `lib.location()` parameter.
|
||||
*
|
||||
* \param lib A library to copy.
|
||||
* \post lib == *this
|
||||
* \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
shared_library(const shared_library& lib)
|
||||
: base_t()
|
||||
{
|
||||
assign(lib);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Copy constructor that increments the reference count of an underlying shared library.
|
||||
* Same as calling constructor with `lib.location(), ec` parameters.
|
||||
*
|
||||
* \param lib A shared library to copy.
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \post lib == *this
|
||||
* \throw std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
shared_library(const shared_library& lib, boost::system::error_code& ec)
|
||||
: base_t()
|
||||
{
|
||||
assign(lib, ec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move constructor. Does not invalidate existing symbols and functions loaded from lib.
|
||||
*
|
||||
* \param lib A shared library to move from.
|
||||
* \post lib.is_loaded() returns false, this->is_loaded() return true.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
shared_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT
|
||||
: base_t(boost::move(static_cast<base_t&>(lib)))
|
||||
{}
|
||||
|
||||
/*!
|
||||
* Loads a library by specified path with a specified mode.
|
||||
*
|
||||
* \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
|
||||
* const wchar_t* or boost::filesystem::path.
|
||||
* \param mode A mode that will be used on library load.
|
||||
* \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
explicit shared_library(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
|
||||
shared_library::load(lib_path, mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Loads a library by specified path with a specified mode.
|
||||
*
|
||||
* \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
|
||||
* const wchar_t* or boost::filesystem::path.
|
||||
* \param mode A mode that will be used on library load.
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \throw std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
|
||||
shared_library::load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
//! \overload shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
|
||||
shared_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) {
|
||||
shared_library::load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
|
||||
*
|
||||
* \param lib A shared library to assign from.
|
||||
* \post lib == *this
|
||||
* \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {
|
||||
boost::system::error_code ec;
|
||||
assign(lib, ec);
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::shared_library::operator= failed");
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
|
||||
*
|
||||
* \param lib A library to move from.
|
||||
* \post lib.is_loaded() returns false.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
shared_library& operator=(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT {
|
||||
if (lib.native() != native()) {
|
||||
swap(lib);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Destroys the object by calling `unload()`. If library was loaded multiple times
|
||||
* by different instances, the actual DLL/DSO won't be unloaded until
|
||||
* there is at least one instance that references the DLL/DSO.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
~shared_library() BOOST_NOEXCEPT {}
|
||||
|
||||
/*!
|
||||
* Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
|
||||
*
|
||||
* \post lib.location() == this->location(), lib == *this
|
||||
* \param lib A library to copy.
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \throw std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
shared_library& assign(const shared_library& lib, boost::system::error_code& ec) {
|
||||
ec.clear();
|
||||
|
||||
if (native() == lib.native()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!lib) {
|
||||
unload();
|
||||
return *this;
|
||||
}
|
||||
|
||||
boost::filesystem::path loc = lib.location(ec);
|
||||
if (ec) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_library copy(loc, ec);
|
||||
if (ec) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
swap(copy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
|
||||
*
|
||||
* \param lib A library instance to assign from.
|
||||
* \post lib.location() == this->location()
|
||||
* \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
shared_library& assign(const shared_library& lib) {
|
||||
boost::system::error_code ec;
|
||||
assign(lib, ec);
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::shared_library::assign() failed");
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Loads a library by specified path with a specified mode.
|
||||
*
|
||||
* Note that if some library is already loaded in this instance, load will
|
||||
* call unload() and then load the new provided library.
|
||||
*
|
||||
* \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
|
||||
* const wchar_t* or boost::filesystem::path.
|
||||
* \param mode A mode that will be used on library load.
|
||||
* \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
|
||||
*
|
||||
*/
|
||||
void load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
|
||||
boost::system::error_code ec;
|
||||
|
||||
base_t::load(lib_path, mode, ec);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::shared_library::load() failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Loads a library by specified path with a specified mode.
|
||||
*
|
||||
* Note that if some library is already loaded in this instance, load will
|
||||
* call unload() and then load the new provided library.
|
||||
*
|
||||
* \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
|
||||
* const wchar_t* or boost::filesystem::path.
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \param mode A mode that will be used on library load.
|
||||
* \throw std::bad_alloc in case of insufficient memory.
|
||||
*/
|
||||
void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
|
||||
ec.clear();
|
||||
base_t::load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
//! \overload void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
|
||||
void load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) {
|
||||
ec.clear();
|
||||
base_t::load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Unloads a shared library. If library was loaded multiple times
|
||||
* by different instances, the actual DLL/DSO won't be unloaded until
|
||||
* there is at least one instance that references the DLL/DSO.
|
||||
*
|
||||
* \post this->is_loaded() returns false.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
void unload() BOOST_NOEXCEPT {
|
||||
base_t::unload();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Check if an library is loaded.
|
||||
*
|
||||
* \return true if a library has been loaded.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
bool is_loaded() const BOOST_NOEXCEPT {
|
||||
return base_t::is_loaded();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Check if an library is not loaded.
|
||||
*
|
||||
* \return true if a library has not been loaded.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
bool operator!() const BOOST_NOEXCEPT {
|
||||
return !is_loaded();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Check if an library is loaded.
|
||||
*
|
||||
* \return true if a library has been loaded.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL()
|
||||
|
||||
/*!
|
||||
* Search for a given symbol on loaded library. Works for all symbols, including alias names.
|
||||
*
|
||||
* \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.
|
||||
* \return `true` if the loaded library contains a symbol with a given name.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
bool has(const char* symbol_name) const BOOST_NOEXCEPT {
|
||||
boost::system::error_code ec;
|
||||
return is_loaded() && !!base_t::symbol_addr(symbol_name, ec) && !ec;
|
||||
}
|
||||
|
||||
//! \overload bool has(const char* symbol_name) const
|
||||
bool has(const std::string& symbol_name) const BOOST_NOEXCEPT {
|
||||
return has(symbol_name.c_str());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns reference to the symbol (function or variable) with the given name from the loaded library.
|
||||
* This call will always succeed and throw nothing if call to `has(const char* )`
|
||||
* member function with the same symbol name returned `true`.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* int& i0 = lib.get<int>("integer_name");
|
||||
* int& i1 = *lib.get<int*>("integer_alias_name");
|
||||
* \endcode
|
||||
*
|
||||
* \tparam T Type of the symbol that we are going to import. Must be explicitly specified.
|
||||
* \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.
|
||||
* \return Reference to the symbol.
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*/
|
||||
template <typename T>
|
||||
inline typename boost::enable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T>::type get(const std::string& symbol_name) const {
|
||||
return get<T>(symbol_name.c_str());
|
||||
}
|
||||
|
||||
//! \overload T& get(const std::string& symbol_name) const
|
||||
template <typename T>
|
||||
inline typename boost::disable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T&>::type get(const std::string& symbol_name) const {
|
||||
return get<T>(symbol_name.c_str());
|
||||
}
|
||||
|
||||
//! \overload T& get(const std::string& symbol_name) const
|
||||
template <typename T>
|
||||
inline typename boost::enable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T>::type get(const char* symbol_name) const {
|
||||
return boost::dll::detail::aggressive_ptr_cast<T>(
|
||||
get_void(symbol_name)
|
||||
);
|
||||
}
|
||||
|
||||
//! \overload T& get(const std::string& symbol_name) const
|
||||
template <typename T>
|
||||
inline typename boost::disable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T&>::type get(const char* symbol_name) const {
|
||||
return *boost::dll::detail::aggressive_ptr_cast<T*>(
|
||||
get_void(symbol_name)
|
||||
);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns a symbol (function or variable) from a shared library by alias name of the symbol.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* int& i = lib.get_alias<int>("integer_alias_name");
|
||||
* \endcode
|
||||
*
|
||||
* \tparam T Type of the symbol that we are going to import. Must be explicitly specified..
|
||||
* \param alias_name Null-terminated alias symbol name. Can handle std::string, char*, const char*.
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*/
|
||||
template <typename T>
|
||||
inline T& get_alias(const char* alias_name) const {
|
||||
return *get<T*>(alias_name);
|
||||
}
|
||||
|
||||
//! \overload T& get_alias(const char* alias_name) const
|
||||
template <typename T>
|
||||
inline T& get_alias(const std::string& alias_name) const {
|
||||
return *get<T*>(alias_name.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
/// @cond
|
||||
// get_void is required to reduce binary size: it does not depend on a template
|
||||
// parameter and will be instantiated only once.
|
||||
void* get_void(const char* sb) const {
|
||||
boost::system::error_code ec;
|
||||
|
||||
if (!is_loaded()) {
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_file_descriptor,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
|
||||
// report_error() calls dlsym, do not use it here!
|
||||
boost::throw_exception(
|
||||
boost::system::system_error(
|
||||
ec, "boost::dll::shared_library::get() failed: no library was loaded"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void* const ret = base_t::symbol_addr(sb, ec);
|
||||
if (ec || !ret) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::shared_library::get() failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Returns the native handler of the loaded library.
|
||||
*
|
||||
* \return Platform-specific handle.
|
||||
*/
|
||||
native_handle_t native() const BOOST_NOEXCEPT {
|
||||
return base_t::native();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns full path and name of this shared object.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* shared_library lib("test_lib.dll");
|
||||
* filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
|
||||
* \endcode
|
||||
*
|
||||
* \return Full path to the shared library.
|
||||
* \throw boost::system::system_error, std::bad_alloc.
|
||||
*/
|
||||
boost::filesystem::path location() const {
|
||||
boost::system::error_code ec;
|
||||
if (!is_loaded()) {
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_file_descriptor,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
|
||||
boost::throw_exception(
|
||||
boost::system::system_error(
|
||||
ec, "boost::dll::shared_library::location() failed (no library was loaded)"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
boost::filesystem::path full_path = base_t::full_module_path(ec);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "boost::dll::shared_library::location() failed");
|
||||
}
|
||||
|
||||
return full_path;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns full path and name of shared module.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* shared_library lib("test_lib.dll");
|
||||
* filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
|
||||
* \endcode
|
||||
*
|
||||
* \param ec Variable that will be set to the result of the operation.
|
||||
* \return Full path to the shared library.
|
||||
* \throw std::bad_alloc.
|
||||
*/
|
||||
boost::filesystem::path location(boost::system::error_code& ec) const {
|
||||
if (!is_loaded()) {
|
||||
ec = boost::system::error_code(
|
||||
boost::system::errc::bad_file_descriptor,
|
||||
boost::system::generic_category()
|
||||
);
|
||||
|
||||
return boost::filesystem::path();
|
||||
}
|
||||
|
||||
ec.clear();
|
||||
return base_t::full_module_path(ec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns suffix of shared module:
|
||||
* in a call to load() or the constructor/load.
|
||||
*
|
||||
* \return The suffix od shared module: ".dll" (Windows), ".so" (Unix/Linux/BSD), ".dylib" (MacOS/IOS)
|
||||
*/
|
||||
static boost::filesystem::path suffix() {
|
||||
return base_t::suffix();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Swaps two libraries. Does not invalidate existing symbols and functions loaded from libraries.
|
||||
*
|
||||
* \param rhs Library to swap with.
|
||||
* \throw Nothing.
|
||||
*/
|
||||
void swap(shared_library& rhs) BOOST_NOEXCEPT {
|
||||
base_t::swap(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.
|
||||
inline bool operator==(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.native() == rhs.native();
|
||||
}
|
||||
|
||||
/// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.
|
||||
inline bool operator!=(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.native() != rhs.native();
|
||||
}
|
||||
|
||||
/// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.
|
||||
inline bool operator<(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.native() < rhs.native();
|
||||
}
|
||||
|
||||
/// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.
|
||||
inline void swap(shared_library& lhs, shared_library& rhs) BOOST_NOEXCEPT {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}} // boost::dll
|
||||
|
||||
#endif // BOOST_DLL_SHARED_LIBRARY_HPP
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
// 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_MODE_HPP
|
||||
#define BOOST_DLL_SHARED_LIBRARY_MODE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef/os.h>
|
||||
#include <boost/predef/library/c.h>
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
//#include <boost/detail/winapi/dll.hpp>
|
||||
#include <boost/detail/winapi/dll.hpp>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
/// \file boost/dll/shared_library_load_mode.hpp
|
||||
/// \brief Contains only the boost::dll::load_mode::type enum and operators related to it.
|
||||
|
||||
namespace boost { namespace dll { namespace load_mode {
|
||||
|
||||
/*! Library load modes.
|
||||
*
|
||||
* Each of system family provides own modes. Flags not supported by a particular platform will be silently ignored.
|
||||
*
|
||||
* For a detailed description of platform specific options see:
|
||||
* <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx">Windows specific options</a>,
|
||||
* <a href="http://pubs.opengroup.org/onlinepubs/000095399/functions/dlopen.html">POSIX specific options</a>.
|
||||
*
|
||||
*/
|
||||
|
||||
enum type {
|
||||
#ifdef BOOST_DLL_DOXYGEN
|
||||
/*!
|
||||
* Default open mode. See the \b Default: comments below to find out the flags that are enabled by default.
|
||||
*/
|
||||
default_mode,
|
||||
|
||||
/*!
|
||||
* \b Platforms: Windows
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* If this value is used, and the executable module is a DLL, the system does
|
||||
* not call DllMain for process and thread initialization and termination.
|
||||
* Also, the system does not load additional executable modules that are
|
||||
* referenced by the specified module.
|
||||
*
|
||||
* Note Do not use this value; it is provided only for backward compatibility.
|
||||
* If you are planning to access only data or resources in the DLL, use
|
||||
* LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE or LOAD_LIBRARY_AS_IMAGE_RESOURCE
|
||||
* or both.
|
||||
*/
|
||||
dont_resolve_dll_references,
|
||||
|
||||
/*!
|
||||
* \b Platforms: Windows
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* If this value is used, the system does not check AppLocker rules or
|
||||
* apply Software Restriction Policies for the DLL.
|
||||
*/
|
||||
load_ignore_code_authz_level,
|
||||
|
||||
/*!
|
||||
* \b Platforms: Windows
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* If this value is used and lpFileName specifies an absolute path,
|
||||
* the system uses the alternate file search strategy.
|
||||
*
|
||||
* This value cannot be combined with any LOAD_LIBRARY_SEARCH flag.
|
||||
*/
|
||||
load_with_altered_search_path,
|
||||
|
||||
/*!
|
||||
* \b Platforms: POSIX
|
||||
*
|
||||
* \b Default: enabled
|
||||
*
|
||||
* Relocations shall be performed at an implementation-defined time, ranging
|
||||
* from the time of the dlopen() call until the first reference to a given
|
||||
* symbol occurs.
|
||||
*
|
||||
* Specifying RTLD_LAZY should improve performance on implementations
|
||||
* supporting dynamic symbol binding as a process may not reference all of
|
||||
* the functions in any given object. And, for systems supporting dynamic
|
||||
* symbol resolution for normal process execution, this behavior mimics
|
||||
* the normal handling of process execution.
|
||||
*/
|
||||
rtld_lazy,
|
||||
|
||||
/*!
|
||||
* \b Platforms: POSIX
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* All necessary relocations shall be performed when the object is first
|
||||
* loaded. This may waste some processing if relocations are performed for
|
||||
* functions that are never referenced. This behavior may be useful for
|
||||
* plugins that need to know as soon as an object is loaded that all
|
||||
* symbols referenced during execution are available.
|
||||
*/
|
||||
rtld_now,
|
||||
|
||||
/*!
|
||||
* \b Platforms: POSIX
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* The object's symbols shall be made available for the relocation
|
||||
* processing of any other object. In addition, symbol lookup using
|
||||
* dlopen(0, mode) and an associated dlsym() allows objects loaded
|
||||
* with this mode to be searched.
|
||||
*/
|
||||
rtld_global,
|
||||
|
||||
/*!
|
||||
* \b Platforms: POSIX
|
||||
*
|
||||
* \b Default: enabled
|
||||
*
|
||||
* The object's symbols shall not be made available for the relocation
|
||||
* processing of any other object.
|
||||
*
|
||||
* This is a default Windows behavior that can not be changed.
|
||||
*/
|
||||
rtld_local,
|
||||
|
||||
/*!
|
||||
* \b Platforms: POSIX (requires glibc >= 2.3.4)
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* The object will use its own symbols in preference to global symbols
|
||||
* with the same name contained in libraries that have already been loaded.
|
||||
* This flag is not specified in POSIX.1-2001.
|
||||
*/
|
||||
rtld_deepbind,
|
||||
|
||||
/*!
|
||||
* \b Platforms: Windows, POSIX
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* Append a platform specific extension and prefix to shared library filename before trying to load it.
|
||||
* If load attempt fails, try to load with exactly specified name.
|
||||
*
|
||||
* \b Example:
|
||||
* \code
|
||||
* // Opens `./my_plugins/plugin1.dll` on Windows, `./my_plugins/libplugin1.so` on Linux, `./my_plugins/libplugin1.dylib` on MacOS.
|
||||
* // If that fails, loads `./my_plugins/plugin1`
|
||||
* boost::dll::shared_library lib("./my_plugins/plugin1", load_mode::append_decorations);
|
||||
* \endcode
|
||||
*/
|
||||
append_decorations,
|
||||
/*!
|
||||
* \b Platforms: Windows, POSIX
|
||||
*
|
||||
* \b Default: disabled
|
||||
*
|
||||
* Allow loading from system folders if path to library contains no parent path.
|
||||
*/
|
||||
search_system_folders
|
||||
#elif BOOST_OS_WINDOWS
|
||||
default_mode = 0,
|
||||
dont_resolve_dll_references = boost::detail::winapi::DONT_RESOLVE_DLL_REFERENCES_,
|
||||
load_ignore_code_authz_level = boost::detail::winapi::LOAD_IGNORE_CODE_AUTHZ_LEVEL_,
|
||||
load_with_altered_search_path = boost::detail::winapi::LOAD_WITH_ALTERED_SEARCH_PATH_,
|
||||
rtld_lazy = 0,
|
||||
rtld_now = 0,
|
||||
rtld_global = 0,
|
||||
rtld_local = 0,
|
||||
rtld_deepbind = 0,
|
||||
append_decorations = 0x00800000,
|
||||
search_system_folders = (append_decorations << 1)
|
||||
#else
|
||||
default_mode = 0,
|
||||
dont_resolve_dll_references = 0,
|
||||
load_ignore_code_authz_level = 0,
|
||||
load_with_altered_search_path = 0,
|
||||
rtld_lazy = RTLD_LAZY,
|
||||
rtld_now = RTLD_NOW,
|
||||
rtld_global = RTLD_GLOBAL,
|
||||
rtld_local = RTLD_LOCAL,
|
||||
|
||||
#if BOOST_LIB_C_GNU < BOOST_VERSION_NUMBER(2,3,4)
|
||||
rtld_deepbind = 0,
|
||||
#else
|
||||
rtld_deepbind = RTLD_DEEPBIND,
|
||||
#endif
|
||||
|
||||
append_decorations = 0x00800000,
|
||||
search_system_folders = (append_decorations << 1)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/// Free operators for load_mode::type flag manipulation.
|
||||
BOOST_CONSTEXPR inline type operator|(type left, type right) BOOST_NOEXCEPT {
|
||||
return static_cast<type>(
|
||||
static_cast<unsigned int>(left) | static_cast<unsigned int>(right)
|
||||
);
|
||||
}
|
||||
BOOST_CXX14_CONSTEXPR inline type& operator|=(type& left, type right) BOOST_NOEXCEPT {
|
||||
left = left | right;
|
||||
return left;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR inline type operator&(type left, type right) BOOST_NOEXCEPT {
|
||||
return static_cast<type>(
|
||||
static_cast<unsigned int>(left) & static_cast<unsigned int>(right)
|
||||
);
|
||||
}
|
||||
BOOST_CXX14_CONSTEXPR inline type& operator&=(type& left, type right) BOOST_NOEXCEPT {
|
||||
left = left & right;
|
||||
return left;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR inline type operator^(type left, type right) BOOST_NOEXCEPT {
|
||||
return static_cast<type>(
|
||||
static_cast<unsigned int>(left) ^ static_cast<unsigned int>(right)
|
||||
);
|
||||
}
|
||||
BOOST_CXX14_CONSTEXPR inline type& operator^=(type& left, type right) BOOST_NOEXCEPT {
|
||||
left = left ^ right;
|
||||
return left;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR inline type operator~(type left) BOOST_NOEXCEPT {
|
||||
return static_cast<type>(
|
||||
~static_cast<unsigned int>(left)
|
||||
);
|
||||
}
|
||||
|
||||
}}} // boost::dll::load_mode
|
||||
|
||||
#endif // BOOST_DLL_SHARED_LIBRARY_MODE_HPP
|
||||
@@ -0,0 +1,462 @@
|
||||
// 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_SMART_LIBRARY_HPP_
|
||||
#define BOOST_DLL_SMART_LIBRARY_HPP_
|
||||
|
||||
/// \file boost/dll/smart_library.hpp
|
||||
/// \warning Extremely experimental! Requires C++14! Will change in next version of Boost! boost/dll/smart_library.hpp is not included in boost/dll.hpp
|
||||
/// \brief Contains the boost::dll::experimental::smart_library class for loading mangled symbols.
|
||||
|
||||
#if BOOST_COMP_GNUC || BOOST_COMP_CLANG || BOOST_COMP_HPACC || BOOST_COMP_IBM
|
||||
#include <boost/dll/detail/demangling/itanium.hpp>
|
||||
#elif BOOST_COMP_MSVC
|
||||
#include <boost/dll/detail/demangling/msvc.hpp>
|
||||
#else
|
||||
#error "Compiler not supported"
|
||||
#endif
|
||||
|
||||
#include <boost/dll/shared_library.hpp>
|
||||
#include <boost/dll/detail/get_mem_fn_type.hpp>
|
||||
#include <boost/dll/detail/ctor_dtor.hpp>
|
||||
#include <boost/dll/detail/type_info.hpp>
|
||||
#include <boost/type_traits/is_object.hpp>
|
||||
#include <boost/type_traits/is_void.hpp>
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#include <boost/predef/compiler.h>
|
||||
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace dll {
|
||||
namespace experimental {
|
||||
|
||||
using boost::dll::detail::constructor;
|
||||
using boost::dll::detail::destructor;
|
||||
|
||||
/*!
|
||||
* \brief This class is an extension of \ref shared_library, which allows to load C++ symbols.
|
||||
*
|
||||
* This class allows type safe loading of overloaded functions, member-functions, constructors and variables.
|
||||
* It also allows to overwrite classes so they can be loaded, while being declared with different names.
|
||||
*
|
||||
* \warning Is still very experimental.
|
||||
*
|
||||
* Currently known limitations:
|
||||
*
|
||||
* Member functions must be defined outside of the class to be exported. That is:
|
||||
* \code
|
||||
* //not exported:
|
||||
* struct BOOST_SYMBOL_EXPORT my_class { void func() {}};
|
||||
* //exported
|
||||
* struct BOOST_SYMBOL_EXPORT my_class { void func();};
|
||||
* void my_class::func() {};
|
||||
* \endcode
|
||||
*
|
||||
* With the current analysis, the first version does get exported in MSVC.
|
||||
* MinGW also does export it, BOOST_SYMBOL_EXPORT is written before it. To allow this on windows one can use
|
||||
* BOOST_DLL_MEMBER_EXPORT for this, so that MinGW and MSVC can provide those functions. This does however not work with gcc on linux.
|
||||
*
|
||||
* Direct initialization of members.
|
||||
* On linux the following member variable i will not be initialized when using the allocating contructor:
|
||||
* \code
|
||||
* struct BOOST_SYMBOL_EXPORT my_class { int i; my_class() : i(42) {} };
|
||||
* \endcode
|
||||
*
|
||||
* This does however not happen when the value is set inside the constructor function.
|
||||
*/
|
||||
class smart_library {
|
||||
shared_library _lib;
|
||||
detail::mangled_storage_impl _storage;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Get the underlying shared_library
|
||||
*/
|
||||
const shared_library &shared_lib() const {return _lib;}
|
||||
|
||||
using mangled_storage = detail::mangled_storage_impl;
|
||||
/*!
|
||||
* Acces to the mangled storage, which is created on construction.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
const mangled_storage &symbol_storage() const {return _storage;}
|
||||
|
||||
///Overload, for current development.
|
||||
mangled_storage &symbol_storage() {return _storage;}
|
||||
|
||||
//! \copydoc shared_library::shared_library()
|
||||
smart_library() BOOST_NOEXCEPT {};
|
||||
|
||||
//! \copydoc shared_library::shared_library(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode)
|
||||
smart_library(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
|
||||
_lib.load(lib_path, mode);
|
||||
_storage.load(lib_path);
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
|
||||
smart_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
|
||||
load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::shared_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec)
|
||||
smart_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) {
|
||||
load(lib_path, mode, ec);
|
||||
}
|
||||
/*!
|
||||
* copy a smart_library object.
|
||||
*
|
||||
* \param lib A smart_library to move from.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
smart_library(const smart_library & lib) BOOST_NOEXCEPT
|
||||
: _lib(lib._lib), _storage(lib._storage)
|
||||
{}
|
||||
/*!
|
||||
* Move a smart_library object.
|
||||
*
|
||||
* \param lib A smart_library to move from.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
smart_library(BOOST_RV_REF(smart_library) lib) BOOST_NOEXCEPT
|
||||
: _lib(boost::move(lib._lib)), _storage(boost::move(lib._storage))
|
||||
{}
|
||||
|
||||
/*!
|
||||
* Construct from a shared_library object.
|
||||
*
|
||||
* \param lib A shared_library to move from.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
explicit smart_library(const shared_library & lib) BOOST_NOEXCEPT
|
||||
: _lib(lib)
|
||||
{
|
||||
_storage.load(lib.location());
|
||||
}
|
||||
/*!
|
||||
* Construct from a shared_library object.
|
||||
*
|
||||
* \param lib A shared_library to move from.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
explicit smart_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT
|
||||
: _lib(boost::move(static_cast<shared_library&>(lib)))
|
||||
{
|
||||
_storage.load(lib.location());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Destroys the smart_library.
|
||||
* `unload()` is called if the DLL/DSO was loaded. If library was loaded multiple times
|
||||
* by different instances of shared_library, the actual DLL/DSO won't be unloaded until
|
||||
* there is at least one instance of shared_library.
|
||||
*
|
||||
* \throw Nothing.
|
||||
*/
|
||||
~smart_library() BOOST_NOEXCEPT {};
|
||||
|
||||
//! \copydoc shared_library::load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode)
|
||||
void load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
|
||||
boost::system::error_code ec;
|
||||
_storage.load(lib_path);
|
||||
_lib.load(lib_path, mode, ec);
|
||||
|
||||
if (ec) {
|
||||
boost::dll::detail::report_error(ec, "load() failed");
|
||||
}
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
|
||||
void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
|
||||
ec.clear();
|
||||
_storage.load(lib_path);
|
||||
_lib.load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec)
|
||||
void load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) {
|
||||
ec.clear();
|
||||
_storage.load(lib_path);
|
||||
_lib.load(lib_path, mode, ec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Load a variable from the referenced library.
|
||||
*
|
||||
* Unlinke shared_library::get this function will also load scoped variables, which also includes static class members.
|
||||
*
|
||||
* \note When mangled, MSVC will also check the type.
|
||||
*
|
||||
* \param name Name of the variable
|
||||
* \tparam T Type of the variable
|
||||
* \return A reference to the variable of type T.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*/
|
||||
template<typename T>
|
||||
T& get_variable(const std::string &name) const {
|
||||
return _lib.get<T>(_storage.get_variable<T>(name));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Load a function from the referenced library.
|
||||
*
|
||||
* \b Example:
|
||||
*
|
||||
* \code
|
||||
* smart_library lib("test_lib.so");
|
||||
* typedef int (&add_ints)(int, int);
|
||||
* typedef double (&add_doubles)(double, double);
|
||||
* add_ints f1 = lib.get_function<int(int, int)> ("func_name");
|
||||
* add_doubles f2 = lib.get_function<double(double, double)>("func_name");
|
||||
* \endcode
|
||||
*
|
||||
* \note When mangled, MSVC will also check the return type.
|
||||
*
|
||||
* \param name Name of the function.
|
||||
* \tparam Func Type of the function, required for determining the overload
|
||||
* \return A reference to the function of type F.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*/
|
||||
template<typename Func>
|
||||
Func& get_function(const std::string &name) const {
|
||||
return _lib.get<Func>(_storage.get_function<Func>(name));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Load a member-function from the referenced library.
|
||||
*
|
||||
* \b Example (import class is MyClass, which is available inside the library and the host):
|
||||
*
|
||||
* \code
|
||||
* smart_library lib("test_lib.so");
|
||||
*
|
||||
* typedef int MyClass(*func)(int);
|
||||
* typedef int MyClass(*func_const)(int) const;
|
||||
*
|
||||
* add_ints f1 = lib.get_mem_fn<MyClass, int(int)> ("MyClass::function");
|
||||
* add_doubles f2 = lib.get_mem_fn<const MyClass, double(double)>("MyClass::function");
|
||||
* \endcode
|
||||
*
|
||||
* \note When mangled, MSVC will also check the return type.
|
||||
*
|
||||
* \param name Name of the function.
|
||||
* \tparam Class The class the function is a member of. If Class is const, the function will be assumed as taking a const this-pointer. The same applies for volatile.
|
||||
* \tparam Func Signature of the function, required for determining the overload
|
||||
* \return A pointer to the member-function with the signature provided
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*/
|
||||
template<typename Class, typename Func>
|
||||
typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn get_mem_fn(const std::string& name) const {
|
||||
return _lib.get<typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn>(
|
||||
_storage.get_mem_fn<Class, Func>(name)
|
||||
);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Load a constructor from the referenced library.
|
||||
*
|
||||
* \b Example (import class is MyClass, which is available inside the library and the host):
|
||||
*
|
||||
* \code
|
||||
* smart_library lib("test_lib.so");
|
||||
*
|
||||
* constructor<MyClass(int) f1 = lib.get_mem_fn<MyClass(int)>();
|
||||
* \endcode
|
||||
*
|
||||
* \tparam Signature Signature of the function, required for determining the overload. The return type is the class which this is the constructor of.
|
||||
* \return A constructor object.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*/
|
||||
template<typename Signature>
|
||||
constructor<Signature> get_constructor() const {
|
||||
return boost::dll::detail::load_ctor<Signature>(_lib, _storage.get_constructor<Signature>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Load a destructor from the referenced library.
|
||||
*
|
||||
* \b Example (import class is MyClass, which is available inside the library and the host):
|
||||
*
|
||||
* \code
|
||||
* smart_library lib("test_lib.so");
|
||||
*
|
||||
* destructor<MyClass> f1 = lib.get_mem_fn<MyClass>();
|
||||
* \endcode
|
||||
*
|
||||
* \tparam Class The class whichs destructor shall be loaded
|
||||
* \return A destructor object.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*
|
||||
*/
|
||||
template<typename Class>
|
||||
destructor<Class> get_destructor() const {
|
||||
return boost::dll::detail::load_dtor<Class>(_lib, _storage.get_destructor<Class>());
|
||||
}
|
||||
/*!
|
||||
* Load the typeinfo of the given type.
|
||||
*
|
||||
* \b Example (import class is MyClass, which is available inside the library and the host):
|
||||
*
|
||||
* \code
|
||||
* smart_library lib("test_lib.so");
|
||||
*
|
||||
* std::type_info &ti = lib.get_Type_info<MyClass>();
|
||||
* \endcode
|
||||
*
|
||||
* \tparam Class The class whichs typeinfo shall be loaded
|
||||
* \return A reference to a type_info object.
|
||||
*
|
||||
* \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
|
||||
*
|
||||
*/
|
||||
template<typename Class>
|
||||
const std::type_info& get_type_info() const
|
||||
{
|
||||
return boost::dll::detail::load_type_info<Class>(_lib, _storage);
|
||||
}
|
||||
/**
|
||||
* This function can be used to add a type alias.
|
||||
*
|
||||
* This is to be used, when a class shall be imported, which is not declared on the host side.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* smart_library lib("test_lib.so");
|
||||
*
|
||||
* lib.add_type_alias<MyAlias>("MyClass"); //when using MyAlias, the library will look for MyClass
|
||||
*
|
||||
* //get the destructor of MyClass
|
||||
* destructor<MyAlias> dtor = lib.get_destructor<MyAlias>();
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* \param name Name of the class the alias is for.
|
||||
*
|
||||
* \attention If the alias-type is not large enough for the imported class, it will result in undefined behaviour.
|
||||
* \warning The alias will only be applied for the type signature, it will not replace the token in the scoped name.
|
||||
*/
|
||||
template<typename Alias> void add_type_alias(const std::string& name) {
|
||||
this->_storage.add_alias<Alias>(name);
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::unload()
|
||||
void unload() BOOST_NOEXCEPT {
|
||||
_storage.clear();
|
||||
_lib.unload();
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::is_loaded() const
|
||||
bool is_loaded() const BOOST_NOEXCEPT {
|
||||
return _lib.is_loaded();
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::operator!() const
|
||||
bool operator!() const BOOST_NOEXCEPT {
|
||||
return !is_loaded();
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::operator bool() const
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL()
|
||||
|
||||
//! \copydoc shared_library::has(const char* symbol_name) const
|
||||
bool has(const char* symbol_name) const BOOST_NOEXCEPT {
|
||||
return _lib.has(symbol_name);
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::has(const std::string& symbol_name) const
|
||||
bool has(const std::string& symbol_name) const BOOST_NOEXCEPT {
|
||||
return _lib.has(symbol_name);
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::assign(const shared_library& lib)
|
||||
smart_library& assign(const smart_library& lib) {
|
||||
_lib.assign(lib._lib);
|
||||
_storage.assign(lib._storage);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \copydoc shared_library::swap(shared_library& rhs)
|
||||
void swap(smart_library& rhs) BOOST_NOEXCEPT {
|
||||
_lib.swap(rhs._lib);
|
||||
_storage.swap(rhs._storage);
|
||||
}
|
||||
};
|
||||
|
||||
/// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.
|
||||
inline bool operator==(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.shared_lib().native() == rhs.shared_lib().native();
|
||||
}
|
||||
|
||||
/// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.
|
||||
inline bool operator!=(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.shared_lib().native() != rhs.shared_lib().native();
|
||||
}
|
||||
|
||||
/// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.
|
||||
inline bool operator<(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.shared_lib().native() < rhs.shared_lib().native();
|
||||
}
|
||||
|
||||
/// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.
|
||||
inline void swap(smart_library& lhs, smart_library& rhs) BOOST_NOEXCEPT {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_DLL_DOXYGEN
|
||||
/** Helper functions for overloads.
|
||||
*
|
||||
* Gets either a variable, function or member-function, depending on the signature.
|
||||
*
|
||||
* @code
|
||||
* smart_library sm("lib.so");
|
||||
* get<int>(sm, "space::value"); //import a variable
|
||||
* get<void(int)>(sm, "space::func"); //import a function
|
||||
* get<some_class, void(int)>(sm, "space::class_::mem_fn"); //import a member function
|
||||
* @endcode
|
||||
*
|
||||
* @param sm A reference to the @ref smart_library
|
||||
* @param name The name of the entity to import
|
||||
*/
|
||||
template<class T, class T2>
|
||||
void get(const smart_library& sm, const std::string &name);
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
T& get(const smart_library& sm, const std::string &name, typename boost::enable_if<boost::is_object<T>,T>::type* = nullptr)
|
||||
|
||||
{
|
||||
return sm.get_variable<T>(name);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto get(const smart_library& sm, const std::string &name, typename boost::enable_if<boost::is_function<T>>::type* = nullptr)
|
||||
{
|
||||
return sm.get_function<T>(name);
|
||||
}
|
||||
|
||||
template<class Class, class Signature>
|
||||
auto get(const smart_library& sm, const std::string &name) -> typename detail::get_mem_fn_type<Class, Signature>::mem_fn
|
||||
{
|
||||
return sm.get_mem_fn<Class, Signature>(name);
|
||||
}
|
||||
|
||||
|
||||
} /* namespace experimental */
|
||||
} /* namespace dll */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif /* BOOST_DLL_SMART_LIBRARY_HPP_ */
|
||||
Reference in New Issue
Block a user