runtime_symbol_info.hpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
  2. // Copyright 2015-2017 Antony Polukhin.
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_DLL_RUNTIME_SYMBOL_INFO_HPP
  8. #define BOOST_DLL_RUNTIME_SYMBOL_INFO_HPP
  9. #include <boost/config.hpp>
  10. #include <boost/predef/os.h>
  11. #include <boost/predef/compiler/visualc.h>
  12. #include <boost/dll/detail/aggressive_ptr_cast.hpp>
  13. #if BOOST_OS_WINDOWS
  14. # include <boost/winapi/dll.hpp>
  15. # include <boost/dll/detail/windows/path_from_handle.hpp>
  16. #else
  17. # include <dlfcn.h>
  18. # include <boost/dll/detail/posix/program_location_impl.hpp>
  19. #endif
  20. #ifdef BOOST_HAS_PRAGMA_ONCE
  21. # pragma once
  22. #endif
  23. /// \file boost/dll/runtime_symbol_info.hpp
  24. /// \brief Provides methods for getting acceptable by boost::dll::shared_library location of symbol, source line or program.
  25. namespace boost { namespace dll {
  26. #if BOOST_OS_WINDOWS
  27. namespace detail {
  28. inline boost::filesystem::path program_location_impl(boost::system::error_code& ec) {
  29. return boost::dll::detail::path_from_handle(NULL, ec);
  30. }
  31. } // namespace detail
  32. #endif
  33. /*!
  34. * On success returns full path and name to the binary object that holds symbol pointed by ptr_to_symbol.
  35. *
  36. * \param ptr_to_symbol Pointer to symbol which location is to be determined.
  37. * \param ec Variable that will be set to the result of the operation.
  38. * \return Path to the binary object that holds symbol or empty path in case error.
  39. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
  40. *
  41. * \b Examples:
  42. * \code
  43. * int main() {
  44. * dll::symbol_location_ptr(std::set_terminate(0)); // returns "/some/path/libmy_terminate_handler.so"
  45. * dll::symbol_location_ptr(::signal(SIGSEGV, SIG_DFL)); // returns "/some/path/libmy_symbol_handler.so"
  46. * }
  47. * \endcode
  48. */
  49. template <class T>
  50. inline boost::filesystem::path symbol_location_ptr(T ptr_to_symbol, boost::system::error_code& ec) {
  51. 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");
  52. boost::filesystem::path ret;
  53. if (!ptr_to_symbol) {
  54. ec = boost::system::error_code(
  55. boost::system::errc::bad_address,
  56. boost::system::generic_category()
  57. );
  58. return ret;
  59. }
  60. ec.clear();
  61. const void* ptr = boost::dll::detail::aggressive_ptr_cast<const void*>(ptr_to_symbol);
  62. #if BOOST_OS_WINDOWS
  63. boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
  64. if (!boost::winapi::VirtualQuery(ptr, &mbi, sizeof(mbi))) {
  65. ec = boost::dll::detail::last_error_code();
  66. return ret;
  67. }
  68. return boost::dll::detail::path_from_handle(reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase), ec);
  69. #else
  70. Dl_info info;
  71. // Some of the libc headers miss `const` in `dladdr(const void*, Dl_info*)`
  72. const int res = dladdr(const_cast<void*>(ptr), &info);
  73. if (res) {
  74. ret = info.dli_fname;
  75. } else {
  76. boost::dll::detail::reset_dlerror();
  77. ec = boost::system::error_code(
  78. boost::system::errc::bad_address,
  79. boost::system::generic_category()
  80. );
  81. }
  82. return ret;
  83. #endif
  84. }
  85. //! \overload symbol_location_ptr(const void* ptr_to_symbol, boost::system::error_code& ec)
  86. template <class T>
  87. inline boost::filesystem::path symbol_location_ptr(T ptr_to_symbol) {
  88. boost::filesystem::path ret;
  89. boost::system::error_code ec;
  90. ret = boost::dll::symbol_location_ptr(ptr_to_symbol, ec);
  91. if (ec) {
  92. boost::dll::detail::report_error(ec, "boost::dll::symbol_location_ptr(T ptr_to_symbol) failed");
  93. }
  94. return ret;
  95. }
  96. /*!
  97. * On success returns full path and name of the binary object that holds symbol.
  98. *
  99. * \tparam T Type of the symbol, must not be explicitly specified.
  100. * \param symbol Symbol which location is to be determined.
  101. * \param ec Variable that will be set to the result of the operation.
  102. * \return Path to the binary object that holds symbol or empty path in case error.
  103. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
  104. *
  105. * \b Examples:
  106. * \code
  107. * int var;
  108. * void foo() {}
  109. *
  110. * int main() {
  111. * dll::symbol_location(var); // returns program location
  112. * dll::symbol_location(foo); // returns program location
  113. * dll::symbol_location(std::cerr); // returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
  114. * dll::symbol_location(std::placeholders::_1); // returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
  115. * dll::symbol_location(std::puts); // returns location of libc: "/lib/x86_64-linux-gnu/libc.so.6"
  116. * }
  117. * \endcode
  118. */
  119. template <class T>
  120. inline boost::filesystem::path symbol_location(const T& symbol, boost::system::error_code& ec) {
  121. ec.clear();
  122. return boost::dll::symbol_location_ptr(
  123. boost::dll::detail::aggressive_ptr_cast<const void*>(boost::addressof(symbol)),
  124. ec
  125. );
  126. }
  127. #if BOOST_COMP_MSVC < BOOST_VERSION_NUMBER(14,0,0)
  128. // Without this MSVC 7.1 fails with:
  129. // ..\boost\dll\runtime_symbol_info.hpp(133) : error C2780: 'filesystem::path dll::symbol_location(const T &)' : expects 1 arguments - 2 provided
  130. template <class T>
  131. inline boost::filesystem::path symbol_location(const T& symbol, const char* /*workaround*/ = 0)
  132. #else
  133. //! \overload symbol_location(const T& symbol, boost::system::error_code& ec)
  134. template <class T>
  135. inline boost::filesystem::path symbol_location(const T& symbol)
  136. #endif
  137. {
  138. boost::filesystem::path ret;
  139. boost::system::error_code ec;
  140. ret = boost::dll::symbol_location_ptr(
  141. boost::dll::detail::aggressive_ptr_cast<const void*>(boost::addressof(symbol)),
  142. ec
  143. );
  144. if (ec) {
  145. boost::dll::detail::report_error(ec, "boost::dll::symbol_location(const T& symbol) failed");
  146. }
  147. return ret;
  148. }
  149. /// @cond
  150. // We have anonymous namespace here to make sure that `this_line_location()` method is instantiated in
  151. // current translation unit and is not shadowed by instantiations from other units.
  152. namespace {
  153. /// @endcond
  154. /*!
  155. * On success returns full path and name of the binary object that holds the current line of code
  156. * (the line in which the `this_line_location()` method was called).
  157. *
  158. * \param ec Variable that will be set to the result of the operation.
  159. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
  160. */
  161. static inline boost::filesystem::path this_line_location(boost::system::error_code& ec) {
  162. typedef boost::filesystem::path(func_t)(boost::system::error_code& );
  163. func_t& f = this_line_location;
  164. return boost::dll::symbol_location(f, ec);
  165. }
  166. //! \overload this_line_location(boost::system::error_code& ec)
  167. static inline boost::filesystem::path this_line_location() {
  168. boost::filesystem::path ret;
  169. boost::system::error_code ec;
  170. ret = this_line_location(ec);
  171. if (ec) {
  172. boost::dll::detail::report_error(ec, "boost::dll::this_line_location() failed");
  173. }
  174. return ret;
  175. }
  176. /// @cond
  177. } // anonymous namespace
  178. /// @endcond
  179. /*!
  180. * On success returns full path and name of the currently running program (the one which contains the `main()` function).
  181. *
  182. * Return value can be used as a parameter for shared_library. See Tutorial "Linking plugin into the executable"
  183. * for usage example. Flag '-rdynamic' must be used when linking the plugin into the executable
  184. * on Linux OS.
  185. *
  186. * \param ec Variable that will be set to the result of the operation.
  187. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept boost::system::error_code also throws boost::system::system_error.
  188. */
  189. inline boost::filesystem::path program_location(boost::system::error_code& ec) {
  190. ec.clear();
  191. return boost::dll::detail::program_location_impl(ec);
  192. }
  193. //! \overload program_location(boost::system::error_code& ec) {
  194. inline boost::filesystem::path program_location() {
  195. boost::filesystem::path ret;
  196. boost::system::error_code ec;
  197. ret = boost::dll::detail::program_location_impl(ec);
  198. if (ec) {
  199. boost::dll::detail::report_error(ec, "boost::dll::program_location() failed");
  200. }
  201. return ret;
  202. }
  203. }} // namespace boost::dll
  204. #endif // BOOST_DLL_RUNTIME_SYMBOL_INFO_HPP