location_from_symbol.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright Antony Polukhin, 2016-2024.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
  7. #define BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
  8. #include <boost/config.hpp>
  9. #ifdef BOOST_HAS_PRAGMA_ONCE
  10. # pragma once
  11. #endif
  12. #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  13. # include <dlfcn.h>
  14. #else
  15. # include <boost/winapi/dll.hpp>
  16. #endif
  17. #ifdef _AIX
  18. /* AIX doesn't provide dladdr syscall.
  19. This provides a minimal implementation of dladdr which retrieves
  20. only files information.
  21. TODO: Implement the symbol name. */
  22. #include <sys/ldr.h>
  23. #include <sys/debug.h>
  24. #include <cstring>
  25. #include <string>
  26. #include <vector>
  27. namespace boost { namespace stacktrace { namespace detail {
  28. struct Dl_info {
  29. std::string fname_storage{};
  30. const char *dli_fname = nullptr;
  31. const char *dli_sname = nullptr;
  32. };
  33. int dladdr(const void* address_raw, Dl_info* info) noexcept {
  34. static constexpr std::size_t dl_buff_size = 0x1000;
  35. try {
  36. std::vector<struct ld_info> pld_info_storage;
  37. pld_info_storage.resize(
  38. (dl_buff_size + sizeof(struct ld_info) - 1) / sizeof(struct ld_info)
  39. );
  40. if (loadquery(L_GETINFO, pld_info_storage.data(), dl_buff_size) == -1) {
  41. return 0;
  42. }
  43. const auto* pld_info = pld_info_storage.data();
  44. const char* const address = static_cast<const char*>(address_raw);
  45. while (true) {
  46. const auto* const dataorg = static_cast<char*>(pld_info->ldinfo_dataorg);
  47. const auto* const textorg = static_cast<char*>(pld_info->ldinfo_textorg);
  48. if ((address >= dataorg && address < dataorg + pld_info->ldinfo_datasize )
  49. || (address >= textorg && address < textorg + pld_info->ldinfo_textsize )) {
  50. /* ldinfo_filename is the null-terminated path name followed
  51. by null-terminated member name.
  52. If the file is not an archive, then member name is null. */
  53. const auto size_filename = std::strlen(pld_info->ldinfo_filename);
  54. const auto size_member = std::strlen(pld_info->ldinfo_filename + size_filename + 1);
  55. /* If member is not null, '(' and ')' must be added to create a
  56. fname looking like "filename(membername)". */
  57. info->fname_storage.reserve(size_filename + (size_member ? size_member + 3 : 1));
  58. info->fname_storage = pld_info->ldinfo_filename;
  59. if (size_member) {
  60. info->fname_storage += "(";
  61. info->fname_storage += pld_info->ldinfo_filename + size_filename + 1;
  62. info->fname_storage += ")";
  63. }
  64. info->dli_fname = info->fname_storage.c_str();
  65. return 1;
  66. }
  67. if (!pld_info->ldinfo_next) {
  68. break;
  69. }
  70. pld_info = reinterpret_cast<const struct ld_info *>(
  71. reinterpret_cast<const char*>(pld_info) + pld_info->ldinfo_next
  72. );
  73. };
  74. } catch (...) {
  75. // ignore
  76. }
  77. return 0;
  78. }
  79. }}} // namespace boost::stacktrace::detail
  80. #elif !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  81. namespace boost { namespace stacktrace { namespace detail {
  82. using Dl_info = ::Dl_info;
  83. inline int dladdr(const void* addr, Dl_info& dli) noexcept {
  84. // `dladdr` on Solaris accepts nonconst addresses
  85. return ::dladdr(const_cast<void*>(addr), &dli);
  86. }
  87. }}} // namespace boost::stacktrace::detail
  88. #endif
  89. namespace boost { namespace stacktrace { namespace detail {
  90. #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  91. class location_from_symbol {
  92. boost::stacktrace::detail::Dl_info dli_;
  93. public:
  94. explicit location_from_symbol(const void* addr) noexcept
  95. : dli_()
  96. {
  97. if (!boost::stacktrace::detail::dladdr(addr, dli_)) {
  98. dli_.dli_fname = 0;
  99. }
  100. }
  101. bool empty() const noexcept {
  102. return !dli_.dli_fname;
  103. }
  104. const char* name() const noexcept {
  105. return dli_.dli_fname;
  106. }
  107. };
  108. class program_location {
  109. public:
  110. const char* name() const noexcept {
  111. return 0;
  112. }
  113. };
  114. #else
  115. class location_from_symbol {
  116. BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
  117. char file_name_[DEFAULT_PATH_SIZE_];
  118. public:
  119. explicit location_from_symbol(const void* addr) noexcept {
  120. file_name_[0] = '\0';
  121. boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
  122. if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
  123. return;
  124. }
  125. boost::winapi::HMODULE_ handle = reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase);
  126. if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
  127. file_name_[0] = '\0';
  128. return;
  129. }
  130. }
  131. bool empty() const noexcept {
  132. return file_name_[0] == '\0';
  133. }
  134. const char* name() const noexcept {
  135. return file_name_;
  136. }
  137. };
  138. class program_location {
  139. BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
  140. char file_name_[DEFAULT_PATH_SIZE_];
  141. public:
  142. program_location() noexcept {
  143. file_name_[0] = '\0';
  144. const boost::winapi::HMODULE_ handle = 0;
  145. if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
  146. file_name_[0] = '\0';
  147. }
  148. }
  149. const char* name() const noexcept {
  150. return file_name_[0] ? file_name_ : 0;
  151. }
  152. };
  153. #endif
  154. }}} // namespace boost::stacktrace::detail
  155. #endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP