addr_base.hpp 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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_ADDR_BASE_HPP
  7. #define BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
  8. #include <boost/config.hpp>
  9. #ifdef BOOST_HAS_PRAGMA_ONCE
  10. # pragma once
  11. #endif
  12. #include <fstream>
  13. #include <sstream>
  14. #include <cstdint>
  15. #include <cstdlib>
  16. namespace boost { namespace stacktrace { namespace detail {
  17. struct mapping_entry_t {
  18. uintptr_t start = 0;
  19. uintptr_t end = 0;
  20. uintptr_t offset_from_base = 0;
  21. inline bool contains_addr(const void* addr) const {
  22. uintptr_t addr_uint = reinterpret_cast<uintptr_t>(addr);
  23. return addr_uint >= start && addr_uint < end;
  24. }
  25. };
  26. inline uintptr_t hex_str_to_int(const std::string& str) {
  27. uintptr_t out;
  28. std::stringstream ss;
  29. ss << std::hex << str;
  30. ss >> out;
  31. if(ss.eof() && !ss.fail()) { // whole stream read, with no errors
  32. return out;
  33. } else {
  34. throw std::invalid_argument(std::string("can't convert '") + str + "' to hex");
  35. }
  36. }
  37. // parse line from /proc/<id>/maps
  38. // format:
  39. // 7fb60d1ea000-7fb60d20c000 r--p 00000000 103:02 120327460 /usr/lib/libc.so.6
  40. // only parts 0 and 2 are interesting, these are:
  41. // 0. mapping address range
  42. // 2. mapping offset from base
  43. inline mapping_entry_t parse_proc_maps_line(const std::string& line) {
  44. std::string mapping_range_str, permissions_str, offset_from_base_str;
  45. std::istringstream line_stream(line);
  46. if(!std::getline(line_stream, mapping_range_str, ' ') ||
  47. !std::getline(line_stream, permissions_str, ' ') ||
  48. !std::getline(line_stream, offset_from_base_str, ' ')) {
  49. return mapping_entry_t{};
  50. }
  51. std::string mapping_start_str, mapping_end_str;
  52. std::istringstream mapping_range_stream(mapping_range_str);
  53. if(!std::getline(mapping_range_stream, mapping_start_str, '-') ||
  54. !std::getline(mapping_range_stream, mapping_end_str)) {
  55. return mapping_entry_t{};
  56. }
  57. mapping_entry_t mapping{};
  58. try {
  59. mapping.start = hex_str_to_int(mapping_start_str);
  60. mapping.end = hex_str_to_int(mapping_end_str);
  61. mapping.offset_from_base = hex_str_to_int(offset_from_base_str);
  62. return mapping;
  63. } catch(std::invalid_argument& e) {
  64. return mapping_entry_t{};
  65. }
  66. }
  67. inline uintptr_t get_own_proc_addr_base(const void* addr) {
  68. std::ifstream maps_file("/proc/self/maps");
  69. for (std::string line; std::getline(maps_file, line); ) {
  70. const mapping_entry_t mapping = parse_proc_maps_line(line);
  71. if (mapping.contains_addr(addr)) {
  72. return mapping.start - mapping.offset_from_base;
  73. }
  74. }
  75. return 0;
  76. }
  77. }}} // namespace boost::stacktrace::detail
  78. #endif // BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP