runtime_symbol_info.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
  2. // Copyright 2015-2021 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/dll/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::dll::fs::path program_location_impl(boost::dll::fs::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 \forcedlinkfs{error_code} also throws \forcedlinkfs{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::dll::fs::path symbol_location_ptr(T ptr_to_symbol, boost::dll::fs::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::dll::fs::path ret;
  53. if (!ptr_to_symbol) {
  54. ec = boost::dll::fs::make_error_code(
  55. boost::dll::fs::errc::bad_address
  56. );
  57. return ret;
  58. }
  59. ec.clear();
  60. const void* ptr = boost::dll::detail::aggressive_ptr_cast<const void*>(ptr_to_symbol);
  61. #if BOOST_OS_WINDOWS
  62. boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
  63. if (!boost::winapi::VirtualQuery(ptr, &mbi, sizeof(mbi))) {
  64. ec = boost::dll::detail::last_error_code();
  65. return ret;
  66. }
  67. return boost::dll::detail::path_from_handle(reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase), ec);
  68. #else
  69. Dl_info info;
  70. // Some of the libc headers miss `const` in `dladdr(const void*, Dl_info*)`
  71. const int res = dladdr(const_cast<void*>(ptr), &info);
  72. if (res) {
  73. ret = info.dli_fname;
  74. } else {
  75. boost::dll::detail::reset_dlerror();
  76. ec = boost::dll::fs::make_error_code(
  77. boost::dll::fs::errc::bad_address
  78. );
  79. }
  80. return ret;
  81. #endif
  82. }
  83. //! \overload symbol_location_ptr(const void* ptr_to_symbol, boost::dll::fs::error_code& ec)
  84. template <class T>
  85. inline boost::dll::fs::path symbol_location_ptr(T ptr_to_symbol) {
  86. boost::dll::fs::path ret;
  87. boost::dll::fs::error_code ec;
  88. ret = boost::dll::symbol_location_ptr(ptr_to_symbol, ec);
  89. if (ec) {
  90. boost::dll::detail::report_error(ec, "boost::dll::symbol_location_ptr(T ptr_to_symbol) failed");
  91. }
  92. return ret;
  93. }
  94. /*!
  95. * On success returns full path and name of the binary object that holds symbol.
  96. *
  97. * \tparam T Type of the symbol, must not be explicitly specified.
  98. * \param symbol Symbol which location is to be determined.
  99. * \param ec Variable that will be set to the result of the operation.
  100. * \return Path to the binary object that holds symbol or empty path in case error.
  101. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept \forcedlinkfs{error_code} also throws \forcedlinkfs{system_error}.
  102. *
  103. * \b Examples:
  104. * \code
  105. * int var;
  106. * void foo() {}
  107. *
  108. * int main() {
  109. * dll::symbol_location(var); // returns program location
  110. * dll::symbol_location(foo); // returns program location
  111. * dll::symbol_location(std::cerr); // returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
  112. * dll::symbol_location(std::placeholders::_1); // returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
  113. * dll::symbol_location(std::puts); // returns location of libc: "/lib/x86_64-linux-gnu/libc.so.6"
  114. * }
  115. * \endcode
  116. */
  117. template <class T>
  118. inline boost::dll::fs::path symbol_location(const T& symbol, boost::dll::fs::error_code& ec) {
  119. ec.clear();
  120. return boost::dll::symbol_location_ptr(
  121. boost::dll::detail::aggressive_ptr_cast<const void*>(boost::addressof(symbol)),
  122. ec
  123. );
  124. }
  125. #if BOOST_COMP_MSVC < BOOST_VERSION_NUMBER(14,0,0)
  126. // Without this MSVC 7.1 fails with:
  127. // ..\boost\dll\runtime_symbol_info.hpp(133) : error C2780: 'filesystem::path dll::symbol_location(const T &)' : expects 1 arguments - 2 provided
  128. template <class T>
  129. inline boost::dll::fs::path symbol_location(const T& symbol, const char* /*workaround*/ = 0)
  130. #else
  131. //! \overload symbol_location(const T& symbol, boost::dll::fs::error_code& ec)
  132. template <class T>
  133. inline boost::dll::fs::path symbol_location(const T& symbol)
  134. #endif
  135. {
  136. boost::dll::fs::path ret;
  137. boost::dll::fs::error_code ec;
  138. ret = boost::dll::symbol_location_ptr(
  139. boost::dll::detail::aggressive_ptr_cast<const void*>(boost::addressof(symbol)),
  140. ec
  141. );
  142. if (ec) {
  143. boost::dll::detail::report_error(ec, "boost::dll::symbol_location(const T& symbol) failed");
  144. }
  145. return ret;
  146. }
  147. /// @cond
  148. // We have anonymous namespace here to make sure that `this_line_location()` method is instantiated in
  149. // current translation unit and is not shadowed by instantiations from other units.
  150. namespace {
  151. /// @endcond
  152. /*!
  153. * On success returns full path and name of the binary object that holds the current line of code
  154. * (the line in which the `this_line_location()` method was called).
  155. *
  156. * \param ec Variable that will be set to the result of the operation.
  157. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept \forcedlinkfs{error_code} also throws \forcedlinkfs{system_error}.
  158. */
  159. static inline boost::dll::fs::path this_line_location(boost::dll::fs::error_code& ec) {
  160. typedef boost::dll::fs::path(func_t)(boost::dll::fs::error_code& );
  161. func_t& f = this_line_location;
  162. return boost::dll::symbol_location(f, ec);
  163. }
  164. //! \overload this_line_location(boost::dll::fs::error_code& ec)
  165. static inline boost::dll::fs::path this_line_location() {
  166. boost::dll::fs::path ret;
  167. boost::dll::fs::error_code ec;
  168. ret = this_line_location(ec);
  169. if (ec) {
  170. boost::dll::detail::report_error(ec, "boost::dll::this_line_location() failed");
  171. }
  172. return ret;
  173. }
  174. /// @cond
  175. } // anonymous namespace
  176. /// @endcond
  177. /*!
  178. * On success returns full path and name of the currently running program (the one which contains the `main()` function).
  179. *
  180. * Return value can be used as a parameter for shared_library. See Tutorial "Linking plugin into the executable"
  181. * for usage example. Flag '-rdynamic' must be used when linking the plugin into the executable
  182. * on Linux OS.
  183. *
  184. * \param ec Variable that will be set to the result of the operation.
  185. * \throws std::bad_alloc in case of insufficient memory. Overload that does not accept \forcedlinkfs{error_code} also throws \forcedlinkfs{system_error}.
  186. */
  187. inline boost::dll::fs::path program_location(boost::dll::fs::error_code& ec) {
  188. ec.clear();
  189. return boost::dll::detail::program_location_impl(ec);
  190. }
  191. //! \overload program_location(boost::dll::fs::error_code& ec) {
  192. inline boost::dll::fs::path program_location() {
  193. boost::dll::fs::path ret;
  194. boost::dll::fs::error_code ec;
  195. ret = boost::dll::detail::program_location_impl(ec);
  196. if (ec) {
  197. boost::dll::detail::report_error(ec, "boost::dll::program_location() failed");
  198. }
  199. return ret;
  200. }
  201. }} // namespace boost::dll
  202. #endif // BOOST_DLL_RUNTIME_SYMBOL_INFO_HPP