Symbolication.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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, u32 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 = cached_elf->debug_info->get_source_position(address);
  45. String filename;
  46. u32 line_number = 0;
  47. if (source_position.has_value()) {
  48. filename = source_position.value().file_path;
  49. line_number = source_position.value().line_number;
  50. }
  51. return Symbol {
  52. .address = address,
  53. .name = move(symbol),
  54. .offset = offset,
  55. .filename = move(filename),
  56. .line_number = line_number
  57. };
  58. }
  59. Vector<Symbol> symbolicate_thread(pid_t pid, pid_t tid)
  60. {
  61. struct RegionWithSymbols {
  62. FlatPtr base { 0 };
  63. size_t size { 0 };
  64. String path;
  65. bool is_relative { true };
  66. };
  67. Vector<FlatPtr> stack;
  68. Vector<RegionWithSymbols> regions;
  69. regions.append(RegionWithSymbols {
  70. .base = 0xc0000000,
  71. .size = 0x3fffffff,
  72. .path = "/boot/Kernel",
  73. .is_relative = false });
  74. {
  75. auto stack_path = String::formatted("/proc/{}/stacks/{}", pid, tid);
  76. auto file_or_error = Core::File::open(stack_path, Core::OpenMode::ReadOnly);
  77. if (file_or_error.is_error()) {
  78. warnln("Could not open {}: {}", stack_path, file_or_error.error());
  79. return {};
  80. }
  81. auto json = JsonValue::from_string(file_or_error.value()->read_all());
  82. if (!json.has_value() || !json.value().is_array()) {
  83. warnln("Invalid contents in {}", stack_path);
  84. return {};
  85. }
  86. stack.ensure_capacity(json.value().as_array().size());
  87. for (auto& value : json.value().as_array().values()) {
  88. stack.append(value.to_u32());
  89. }
  90. }
  91. {
  92. auto vm_path = String::formatted("/proc/{}/vm", pid);
  93. auto file_or_error = Core::File::open(vm_path, Core::OpenMode::ReadOnly);
  94. if (file_or_error.is_error()) {
  95. warnln("Could not open {}: {}", vm_path, file_or_error.error());
  96. return {};
  97. }
  98. auto json = JsonValue::from_string(file_or_error.value()->read_all());
  99. if (!json.has_value() || !json.value().is_array()) {
  100. warnln("Invalid contents in {}", vm_path);
  101. return {};
  102. }
  103. for (auto& region_value : json.value().as_array().values()) {
  104. auto& region = region_value.as_object();
  105. auto name = region.get("name").to_string();
  106. auto address = region.get("address").to_u32();
  107. auto size = region.get("size").to_u32();
  108. String path;
  109. if (name == "/usr/lib/Loader.so") {
  110. path = name;
  111. } else if (name.ends_with(": .text")) {
  112. auto parts = name.split_view(':');
  113. path = parts[0];
  114. if (!path.starts_with('/'))
  115. path = String::formatted("/usr/lib/{}", path);
  116. } else {
  117. continue;
  118. }
  119. RegionWithSymbols r;
  120. r.base = address;
  121. r.size = size;
  122. r.path = path;
  123. regions.append(move(r));
  124. }
  125. }
  126. Vector<Symbol> symbols;
  127. for (auto address : stack) {
  128. const RegionWithSymbols* found_region = nullptr;
  129. for (auto& region : regions) {
  130. if (address >= region.base && address < (region.base + region.size)) {
  131. found_region = &region;
  132. break;
  133. }
  134. }
  135. if (!found_region) {
  136. outln("{:p} ??", address);
  137. continue;
  138. }
  139. FlatPtr adjusted_address;
  140. if (found_region->is_relative)
  141. adjusted_address = address - found_region->base;
  142. else
  143. adjusted_address = address;
  144. auto result = symbolicate(found_region->path, adjusted_address);
  145. if (!result.has_value()) {
  146. symbols.append(Symbol {
  147. .address = address,
  148. });
  149. continue;
  150. }
  151. symbols.append(result.value());
  152. }
  153. return symbols;
  154. }
  155. }