stack_trace_fuchsia.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/debug/stack_trace.h"
  5. #include <elf.h>
  6. #include <link.h>
  7. #include <stddef.h>
  8. #include <threads.h>
  9. #include <unwind.h>
  10. #include <zircon/process.h>
  11. #include <zircon/syscalls.h>
  12. #include <zircon/syscalls/port.h>
  13. #include <zircon/types.h>
  14. #include <algorithm>
  15. #include <array>
  16. #include <iomanip>
  17. #include <iostream>
  18. #include <type_traits>
  19. #include "base/atomic_sequence_num.h"
  20. #include "base/debug/elf_reader.h"
  21. #include "base/logging.h"
  22. namespace base {
  23. namespace debug {
  24. namespace {
  25. struct BacktraceData {
  26. void** trace_array;
  27. size_t* count;
  28. size_t max;
  29. };
  30. _Unwind_Reason_Code UnwindStore(struct _Unwind_Context* context,
  31. void* user_data) {
  32. BacktraceData* data = reinterpret_cast<BacktraceData*>(user_data);
  33. uintptr_t pc = _Unwind_GetIP(context);
  34. data->trace_array[*data->count] = reinterpret_cast<void*>(pc);
  35. *data->count += 1;
  36. if (*data->count == data->max)
  37. return _URC_END_OF_STACK;
  38. return _URC_NO_REASON;
  39. }
  40. // Build a "rwx" C string-based representation of the permission bits.
  41. // The output buffer is reused across calls, and should not be retained across
  42. // consecutive invocations of this function.
  43. const char* PermissionFlagsToString(int flags, char permission_buf[4]) {
  44. char* permission = permission_buf;
  45. if (flags & PF_R)
  46. (*permission++) = 'r';
  47. if (flags & PF_W)
  48. (*permission++) = 'w';
  49. if (flags & PF_X)
  50. (*permission++) = 'x';
  51. *permission = '\0';
  52. return permission_buf;
  53. }
  54. // Stores and queries debugging symbol map info for the current process.
  55. class SymbolMap {
  56. public:
  57. struct Segment {
  58. const void* addr = nullptr;
  59. size_t relative_addr = 0;
  60. int permission_flags = 0;
  61. size_t size = 0;
  62. };
  63. struct Module {
  64. // Maximum number of PT_LOAD segments to process per ELF binary. Most
  65. // binaries have only 2-3 such segments.
  66. static constexpr size_t kMaxSegmentCount = 8;
  67. const void* addr = nullptr;
  68. std::array<Segment, kMaxSegmentCount> segments;
  69. size_t segment_count = 0;
  70. char name[ZX_MAX_NAME_LEN + 1] = {0};
  71. char build_id[kMaxBuildIdStringLength + 1] = {0};
  72. };
  73. SymbolMap();
  74. SymbolMap(const SymbolMap&) = delete;
  75. SymbolMap& operator=(const SymbolMap&) = delete;
  76. ~SymbolMap() = default;
  77. // Gets all entries for the symbol map.
  78. span<Module> GetModules() { return {modules_.data(), count_}; }
  79. private:
  80. // Component builds of Chrome pull about 250 shared libraries (on Linux), so
  81. // 512 entries should be enough in most cases.
  82. static const size_t kMaxMapEntries = 512;
  83. void Populate();
  84. // Sorted in descending order by address, for lookup purposes.
  85. std::array<Module, kMaxMapEntries> modules_;
  86. size_t count_ = 0;
  87. bool valid_ = false;
  88. };
  89. SymbolMap::SymbolMap() {
  90. Populate();
  91. }
  92. void SymbolMap::Populate() {
  93. zx_handle_t process = zx_process_self();
  94. // Try to fetch the name of the process' main executable, which was set as the
  95. // name of the |process| kernel object.
  96. // TODO(crbug.com/1131250): Object names can only have up to ZX_MAX_NAME_LEN
  97. // characters, so if we keep hitting problems with truncation, find a way to
  98. // plumb argv[0] through to here instead, e.g. using
  99. // CommandLine::GetProgramName().
  100. char app_name[std::extent<decltype(SymbolMap::Module::name)>()];
  101. zx_status_t status =
  102. zx_object_get_property(process, ZX_PROP_NAME, app_name, sizeof(app_name));
  103. if (status == ZX_OK) {
  104. // The process name may have a process type suffix at the end (e.g.
  105. // "context", "renderer", gpu"), which doesn't belong in the module list.
  106. // Trim the suffix from the name.
  107. for (size_t i = 0; i < std::size(app_name) && app_name[i] != '\0'; ++i) {
  108. if (app_name[i] == ':') {
  109. app_name[i] = 0;
  110. break;
  111. }
  112. }
  113. } else {
  114. DPLOG(WARNING)
  115. << "Couldn't get name, falling back to 'app' for program name: "
  116. << status;
  117. strlcat(app_name, "app", sizeof(app_name));
  118. }
  119. // Retrieve the debug info struct.
  120. uintptr_t debug_addr;
  121. status = zx_object_get_property(process, ZX_PROP_PROCESS_DEBUG_ADDR,
  122. &debug_addr, sizeof(debug_addr));
  123. if (status != ZX_OK) {
  124. DPLOG(ERROR) << "Couldn't get symbol map for process: " << status;
  125. return;
  126. }
  127. r_debug* debug_info = reinterpret_cast<r_debug*>(debug_addr);
  128. // Get the link map from the debug info struct.
  129. link_map* lmap = reinterpret_cast<link_map*>(debug_info->r_map);
  130. if (!lmap) {
  131. DPLOG(ERROR) << "Null link_map for process.";
  132. return;
  133. }
  134. // Populate ELF binary metadata into |modules_|.
  135. while (lmap != nullptr) {
  136. if (count_ >= kMaxMapEntries)
  137. break;
  138. SymbolMap::Module& next_entry = modules_[count_];
  139. ++count_;
  140. next_entry.addr = reinterpret_cast<void*>(lmap->l_addr);
  141. // Create Segment sub-entries for all PT_LOAD headers.
  142. // Each Segment corresponds to a "mmap" line in the output.
  143. next_entry.segment_count = 0;
  144. for (const Elf64_Phdr& phdr : GetElfProgramHeaders(next_entry.addr)) {
  145. if (phdr.p_type != PT_LOAD)
  146. continue;
  147. if (next_entry.segment_count > Module::kMaxSegmentCount) {
  148. LOG(WARNING) << "Exceeded the maximum number of segments.";
  149. break;
  150. }
  151. Segment segment;
  152. segment.addr =
  153. reinterpret_cast<const char*>(next_entry.addr) + phdr.p_vaddr;
  154. segment.relative_addr = phdr.p_vaddr;
  155. segment.size = phdr.p_memsz;
  156. segment.permission_flags = static_cast<int>(phdr.p_flags);
  157. next_entry.segments[next_entry.segment_count] = std::move(segment);
  158. ++next_entry.segment_count;
  159. }
  160. // Get the human-readable library name from the ELF header, falling back on
  161. // using names from the link map for binaries that aren't shared libraries.
  162. absl::optional<StringPiece> elf_library_name =
  163. ReadElfLibraryName(next_entry.addr);
  164. if (elf_library_name) {
  165. strlcpy(next_entry.name, elf_library_name->data(),
  166. elf_library_name->size() + 1);
  167. } else {
  168. StringPiece link_map_name(lmap->l_name[0] ? lmap->l_name : app_name);
  169. // The "module" stack trace annotation doesn't allow for strings which
  170. // resemble paths, so extract the filename portion from |link_map_name|.
  171. size_t directory_prefix_idx = link_map_name.find_last_of("/");
  172. if (directory_prefix_idx != StringPiece::npos) {
  173. link_map_name = link_map_name.substr(
  174. directory_prefix_idx + 1,
  175. link_map_name.size() - directory_prefix_idx - 1);
  176. }
  177. strlcpy(next_entry.name, link_map_name.data(), link_map_name.size() + 1);
  178. }
  179. if (!ReadElfBuildId(next_entry.addr, false, next_entry.build_id)) {
  180. LOG(WARNING) << "Couldn't read build ID.";
  181. continue;
  182. }
  183. lmap = lmap->l_next;
  184. }
  185. valid_ = true;
  186. }
  187. } // namespace
  188. // static
  189. bool EnableInProcessStackDumping() {
  190. // StackTrace works to capture the current stack (e.g. for diagnostics added
  191. // to code), but for local capture and print of backtraces, we just let the
  192. // system crashlogger take over. It handles printing out a nicely formatted
  193. // backtrace with dso information, relative offsets, etc. that we can then
  194. // filter with addr2line in the run script to get file/line info.
  195. return true;
  196. }
  197. size_t CollectStackTrace(void** trace, size_t count) {
  198. size_t frame_count = 0;
  199. BacktraceData data = {trace, &frame_count, count};
  200. _Unwind_Backtrace(&UnwindStore, &data);
  201. return frame_count;
  202. }
  203. void StackTrace::PrintWithPrefix(const char* prefix_string) const {
  204. OutputToStreamWithPrefix(&std::cerr, prefix_string);
  205. }
  206. // Emits stack trace data using the symbolizer markup format specified at:
  207. // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md
  208. void StackTrace::OutputToStreamWithPrefix(std::ostream* os,
  209. const char* prefix_string) const {
  210. SymbolMap map;
  211. int module_id = 0;
  212. for (const SymbolMap::Module& entry : map.GetModules()) {
  213. *os << "{{{module:" << module_id << ":" << entry.name
  214. << ":elf:" << entry.build_id << "}}}\n";
  215. for (size_t i = 0; i < entry.segment_count; ++i) {
  216. const SymbolMap::Segment& segment = entry.segments[i];
  217. char permission_string[4] = {};
  218. *os << "{{{mmap:" << segment.addr << ":0x" << std::hex << segment.size
  219. << std::dec << ":load:" << module_id << ":"
  220. << PermissionFlagsToString(segment.permission_flags,
  221. permission_string)
  222. << ":"
  223. << "0x" << std::hex << segment.relative_addr << std::dec << "}}}\n";
  224. }
  225. ++module_id;
  226. }
  227. for (size_t i = 0; i < count_; ++i)
  228. *os << "{{{bt:" << i << ":" << trace_[i] << "}}}\n";
  229. *os << "{{{reset}}}\n";
  230. }
  231. } // namespace debug
  232. } // namespace base