Symbolication.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Array.h>
  7. #include <AK/Checked.h>
  8. #include <AK/JsonArray.h>
  9. #include <AK/JsonObject.h>
  10. #include <AK/JsonValue.h>
  11. #include <AK/LexicalPath.h>
  12. #include <LibCore/File.h>
  13. #include <LibCore/MappedFile.h>
  14. #include <LibDebug/DebugInfo.h>
  15. #include <LibFileSystem/FileSystem.h>
  16. #include <LibSymbolication/Symbolication.h>
  17. namespace Symbolication {
  18. struct CachedELF {
  19. NonnullOwnPtr<Core::MappedFile> mapped_file;
  20. NonnullOwnPtr<Debug::DebugInfo> debug_info;
  21. NonnullOwnPtr<ELF::Image> image;
  22. };
  23. static HashMap<ByteString, OwnPtr<CachedELF>> s_cache;
  24. enum class KernelBaseState {
  25. Uninitialized,
  26. Valid,
  27. Invalid,
  28. };
  29. static FlatPtr s_kernel_base;
  30. static KernelBaseState s_kernel_base_state = KernelBaseState::Uninitialized;
  31. Optional<FlatPtr> kernel_base()
  32. {
  33. if (s_kernel_base_state == KernelBaseState::Uninitialized) {
  34. auto file = Core::File::open("/sys/kernel/load_base"sv, Core::File::OpenMode::Read);
  35. if (file.is_error()) {
  36. s_kernel_base_state = KernelBaseState::Invalid;
  37. return {};
  38. }
  39. auto file_content = file.value()->read_until_eof();
  40. if (file_content.is_error()) {
  41. s_kernel_base_state = KernelBaseState::Invalid;
  42. return {};
  43. }
  44. auto kernel_base_str = ByteString { file_content.value(), NoChomp };
  45. using AddressType = u64;
  46. auto maybe_kernel_base = kernel_base_str.to_number<AddressType>();
  47. if (!maybe_kernel_base.has_value()) {
  48. s_kernel_base_state = KernelBaseState::Invalid;
  49. return {};
  50. }
  51. s_kernel_base = maybe_kernel_base.value();
  52. s_kernel_base_state = KernelBaseState::Valid;
  53. }
  54. if (s_kernel_base_state == KernelBaseState::Invalid)
  55. return {};
  56. return s_kernel_base;
  57. }
  58. Optional<Symbol> symbolicate(ByteString const& path, FlatPtr address, IncludeSourcePosition include_source_positions)
  59. {
  60. ByteString full_path = path;
  61. if (!path.starts_with('/')) {
  62. Array<StringView, 2> search_paths { "/usr/lib"sv, "/usr/local/lib"sv };
  63. bool found = false;
  64. for (auto& search_path : search_paths) {
  65. full_path = LexicalPath::join(search_path, path).string();
  66. if (FileSystem::exists(full_path)) {
  67. found = true;
  68. break;
  69. }
  70. }
  71. if (!found) {
  72. dbgln("Failed to find candidate for {}", path);
  73. s_cache.set(path, {});
  74. return {};
  75. }
  76. }
  77. if (!s_cache.contains(full_path)) {
  78. auto mapped_file = Core::MappedFile::map(full_path);
  79. if (mapped_file.is_error()) {
  80. dbgln("Failed to map {}: {}", full_path, mapped_file.error());
  81. s_cache.set(full_path, {});
  82. return {};
  83. }
  84. auto elf = make<ELF::Image>(mapped_file.value()->bytes());
  85. if (!elf->is_valid()) {
  86. dbgln("ELF not valid: {}", full_path);
  87. s_cache.set(full_path, {});
  88. return {};
  89. }
  90. auto cached_elf = make<CachedELF>(mapped_file.release_value(), make<Debug::DebugInfo>(*elf), move(elf));
  91. s_cache.set(full_path, move(cached_elf));
  92. }
  93. auto it = s_cache.find(full_path);
  94. VERIFY(it != s_cache.end());
  95. auto& cached_elf = it->value;
  96. if (!cached_elf)
  97. return {};
  98. u32 offset = 0;
  99. auto symbol = cached_elf->debug_info->elf().symbolicate(address, &offset);
  100. Vector<Debug::DebugInfo::SourcePosition> positions;
  101. if (include_source_positions == IncludeSourcePosition::Yes) {
  102. auto source_position_with_inlines = cached_elf->debug_info->get_source_position_with_inlines(address).release_value_but_fixme_should_propagate_errors();
  103. for (auto& position : source_position_with_inlines.inline_chain) {
  104. if (!positions.contains_slow(position))
  105. positions.append(position);
  106. }
  107. if (source_position_with_inlines.source_position.has_value() && !positions.contains_slow(source_position_with_inlines.source_position.value())) {
  108. positions.insert(0, source_position_with_inlines.source_position.value());
  109. }
  110. }
  111. return Symbol {
  112. .address = address,
  113. .name = move(symbol),
  114. .object = LexicalPath::basename(path),
  115. .offset = offset,
  116. .source_positions = move(positions),
  117. };
  118. }
  119. Vector<Symbol> symbolicate_thread(pid_t pid, pid_t tid, IncludeSourcePosition include_source_positions)
  120. {
  121. struct RegionWithSymbols {
  122. FlatPtr base { 0 };
  123. size_t size { 0 };
  124. ByteString path;
  125. };
  126. Vector<FlatPtr> stack;
  127. Vector<RegionWithSymbols> regions;
  128. if (auto maybe_kernel_base = kernel_base(); maybe_kernel_base.has_value()) {
  129. regions.append(RegionWithSymbols {
  130. .base = maybe_kernel_base.value(),
  131. .size = 0x3fffffff,
  132. .path = "/boot/Kernel.debug",
  133. });
  134. }
  135. {
  136. auto stack_path = ByteString::formatted("/proc/{}/stacks/{}", pid, tid);
  137. auto file_or_error = Core::File::open(stack_path, Core::File::OpenMode::Read);
  138. if (file_or_error.is_error()) {
  139. warnln("Could not open {}: {}", stack_path, file_or_error.error());
  140. return {};
  141. }
  142. auto file_content = file_or_error.value()->read_until_eof();
  143. if (file_content.is_error()) {
  144. warnln("Could not read {}: {}", stack_path, file_or_error.error());
  145. return {};
  146. }
  147. auto json = JsonValue::from_string(file_content.value());
  148. if (json.is_error() || !json.value().is_array()) {
  149. warnln("Invalid contents in {}", stack_path);
  150. return {};
  151. }
  152. stack.ensure_capacity(json.value().as_array().size());
  153. for (auto& value : json.value().as_array().values()) {
  154. stack.append(value.get_addr().value());
  155. }
  156. }
  157. {
  158. auto vm_path = ByteString::formatted("/proc/{}/vm", pid);
  159. auto file_or_error = Core::File::open(vm_path, Core::File::OpenMode::Read);
  160. if (file_or_error.is_error()) {
  161. warnln("Could not open {}: {}", vm_path, file_or_error.error());
  162. return {};
  163. }
  164. auto file_content = file_or_error.value()->read_until_eof();
  165. if (file_content.is_error()) {
  166. warnln("Could not read {}: {}", vm_path, file_or_error.error());
  167. return {};
  168. }
  169. auto json = JsonValue::from_string(file_content.value());
  170. if (json.is_error() || !json.value().is_array()) {
  171. warnln("Invalid contents in {}", vm_path);
  172. return {};
  173. }
  174. for (auto& region_value : json.value().as_array().values()) {
  175. auto& region = region_value.as_object();
  176. auto name = region.get_byte_string("name"sv).value_or({});
  177. auto address = region.get_addr("address"sv).value_or(0);
  178. auto size = region.get_addr("size"sv).value_or(0);
  179. ByteString path;
  180. if (name == "/usr/lib/Loader.so") {
  181. path = name;
  182. } else if (name.ends_with(": .text"sv) || name.ends_with(": .rodata"sv)) {
  183. auto parts = name.split_view(':');
  184. path = parts[0];
  185. } else {
  186. continue;
  187. }
  188. RegionWithSymbols r;
  189. r.base = address;
  190. r.size = size;
  191. r.path = path;
  192. regions.append(move(r));
  193. }
  194. }
  195. Vector<Symbol> symbols;
  196. bool first_frame = true;
  197. for (auto address : stack) {
  198. RegionWithSymbols const* found_region = nullptr;
  199. for (auto& region : regions) {
  200. FlatPtr region_end;
  201. if (Checked<FlatPtr>::addition_would_overflow(region.base, region.size))
  202. region_end = NumericLimits<FlatPtr>::max();
  203. else
  204. region_end = region.base + region.size;
  205. if (address >= region.base && address < region_end) {
  206. found_region = &region;
  207. break;
  208. }
  209. }
  210. if (!found_region) {
  211. outln("{:p} ??", address);
  212. continue;
  213. }
  214. // We found an address inside of a region, but the base of that region
  215. // may not be the base of the ELF image. For example, there could be an
  216. // .rodata mapping at a lower address than the first .text mapping from
  217. // the same image. look for the lowest address region with the same path.
  218. RegionWithSymbols const* base_region = nullptr;
  219. for (auto& region : regions) {
  220. if (region.path != found_region->path)
  221. continue;
  222. if (!base_region || region.base <= base_region->base)
  223. base_region = &region;
  224. }
  225. FlatPtr adjusted_address = address - base_region->base;
  226. // We're subtracting 1 from the address because this is the return address,
  227. // i.e. it is one instruction past the call instruction.
  228. // However, because the first frame represents the current
  229. // instruction pointer rather than the return address we don't
  230. // subtract 1 for that.
  231. auto result = symbolicate(found_region->path, adjusted_address - (first_frame ? 0 : 1), include_source_positions);
  232. first_frame = false;
  233. if (!result.has_value()) {
  234. symbols.append(Symbol {
  235. .address = address,
  236. .source_positions = {},
  237. });
  238. continue;
  239. }
  240. symbols.append(result.value());
  241. }
  242. return symbols;
  243. }
  244. }