Symbolication.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/JsonArray.h>
  7. #include <AK/JsonObject.h>
  8. #include <AK/JsonValue.h>
  9. #include <AK/MappedFile.h>
  10. #include <LibCore/File.h>
  11. #include <LibDebug/DebugInfo.h>
  12. #include <LibSymbolication/Symbolication.h>
  13. namespace Symbolication {
  14. struct CachedELF {
  15. NonnullRefPtr<MappedFile> mapped_file;
  16. NonnullOwnPtr<Debug::DebugInfo> debug_info;
  17. };
  18. static HashMap<String, OwnPtr<CachedELF>> s_cache;
  19. Optional<Symbol> symbolicate(String const& path, FlatPtr address)
  20. {
  21. if (!s_cache.contains(path)) {
  22. auto mapped_file = MappedFile::map(path);
  23. if (mapped_file.is_error()) {
  24. dbgln("Failed to map {}: {}", path, mapped_file.error().string());
  25. s_cache.set(path, {});
  26. return {};
  27. }
  28. auto elf = make<ELF::Image>(mapped_file.value()->bytes());
  29. if (!elf->is_valid()) {
  30. dbgln("ELF not valid: {}", path);
  31. s_cache.set(path, {});
  32. {};
  33. }
  34. auto cached_elf = make<CachedELF>(mapped_file.release_value(), make<Debug::DebugInfo>(move(elf)));
  35. s_cache.set(path, move(cached_elf));
  36. }
  37. auto it = s_cache.find(path);
  38. VERIFY(it != s_cache.end());
  39. auto& cached_elf = it->value;
  40. if (!cached_elf)
  41. return {};
  42. u32 offset = 0;
  43. auto symbol = cached_elf->debug_info->elf().symbolicate(address, &offset);
  44. auto source_position_with_inlines = cached_elf->debug_info->get_source_position_with_inlines(address);
  45. Vector<Debug::DebugInfo::SourcePosition> positions;
  46. for (auto& position : source_position_with_inlines.inline_chain) {
  47. if (!positions.contains_slow(position))
  48. positions.append(position);
  49. }
  50. if (source_position_with_inlines.source_position.has_value() && !positions.contains_slow(source_position_with_inlines.source_position.value())) {
  51. positions.insert(0, source_position_with_inlines.source_position.value());
  52. }
  53. return Symbol {
  54. .address = address,
  55. .name = move(symbol),
  56. .offset = offset,
  57. .source_positions = move(positions),
  58. };
  59. }
  60. Vector<Symbol> symbolicate_thread(pid_t pid, pid_t tid)
  61. {
  62. struct RegionWithSymbols {
  63. FlatPtr base { 0 };
  64. size_t size { 0 };
  65. String path;
  66. bool is_relative { true };
  67. };
  68. Vector<FlatPtr> stack;
  69. Vector<RegionWithSymbols> regions;
  70. regions.append(RegionWithSymbols {
  71. .base = 0xc0000000,
  72. .size = 0x3fffffff,
  73. .path = "/boot/Kernel",
  74. .is_relative = false });
  75. {
  76. auto stack_path = String::formatted("/proc/{}/stacks/{}", pid, tid);
  77. auto file_or_error = Core::File::open(stack_path, Core::OpenMode::ReadOnly);
  78. if (file_or_error.is_error()) {
  79. warnln("Could not open {}: {}", stack_path, file_or_error.error());
  80. return {};
  81. }
  82. auto json = JsonValue::from_string(file_or_error.value()->read_all());
  83. if (!json.has_value() || !json.value().is_array()) {
  84. warnln("Invalid contents in {}", stack_path);
  85. return {};
  86. }
  87. stack.ensure_capacity(json.value().as_array().size());
  88. for (auto& value : json.value().as_array().values()) {
  89. stack.append(value.to_u32());
  90. }
  91. }
  92. {
  93. auto vm_path = String::formatted("/proc/{}/vm", pid);
  94. auto file_or_error = Core::File::open(vm_path, Core::OpenMode::ReadOnly);
  95. if (file_or_error.is_error()) {
  96. warnln("Could not open {}: {}", vm_path, file_or_error.error());
  97. return {};
  98. }
  99. auto json = JsonValue::from_string(file_or_error.value()->read_all());
  100. if (!json.has_value() || !json.value().is_array()) {
  101. warnln("Invalid contents in {}", vm_path);
  102. return {};
  103. }
  104. for (auto& region_value : json.value().as_array().values()) {
  105. auto& region = region_value.as_object();
  106. auto name = region.get("name").to_string();
  107. auto address = region.get("address").to_u32();
  108. auto size = region.get("size").to_u32();
  109. String path;
  110. if (name == "/usr/lib/Loader.so") {
  111. path = name;
  112. } else if (name.ends_with(": .text")) {
  113. auto parts = name.split_view(':');
  114. path = parts[0];
  115. if (!path.starts_with('/'))
  116. path = String::formatted("/usr/lib/{}", path);
  117. } else {
  118. continue;
  119. }
  120. RegionWithSymbols r;
  121. r.base = address;
  122. r.size = size;
  123. r.path = path;
  124. regions.append(move(r));
  125. }
  126. }
  127. Vector<Symbol> symbols;
  128. bool first_frame = true;
  129. for (auto address : stack) {
  130. const RegionWithSymbols* found_region = nullptr;
  131. for (auto& region : regions) {
  132. if (address >= region.base && address < (region.base + region.size)) {
  133. found_region = &region;
  134. break;
  135. }
  136. }
  137. if (!found_region) {
  138. outln("{:p} ??", address);
  139. continue;
  140. }
  141. FlatPtr adjusted_address;
  142. if (found_region->is_relative)
  143. adjusted_address = address - found_region->base;
  144. else
  145. adjusted_address = address;
  146. // We're subtracting 1 from the address because this is the return address,
  147. // i.e. it is one instruction past the call instruction.
  148. // However, because the first frame represents the current
  149. // instruction pointer rather than the return address we don't
  150. // subtract 1 for that.
  151. auto result = symbolicate(found_region->path, adjusted_address - (first_frame ? 0 : 1));
  152. first_frame = false;
  153. if (!result.has_value()) {
  154. symbols.append(Symbol {
  155. .address = address,
  156. .source_positions = {},
  157. });
  158. continue;
  159. }
  160. symbols.append(result.value());
  161. }
  162. return symbols;
  163. }
  164. }