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