runtime_symbol_info.hpp 9.2 KB

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