1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <libdebuggerd/tombstone.h>
18 
19 #include <inttypes.h>
20 
21 #include <functional>
22 #include <set>
23 #include <string>
24 #include <unordered_set>
25 #include <utility>
26 #include <vector>
27 
28 #include <android-base/stringprintf.h>
29 #include <android-base/strings.h>
30 #include <android-base/unique_fd.h>
31 #include <async_safe/log.h>
32 #include <bionic/macros.h>
33 
34 #include "tombstone.pb.h"
35 
36 using android::base::StringAppendF;
37 using android::base::StringPrintf;
38 
39 #define CB(log, ...) callback(StringPrintf(__VA_ARGS__), log)
40 #define CBL(...) CB(true, __VA_ARGS__)
41 #define CBS(...) CB(false, __VA_ARGS__)
42 using CallbackType = std::function<void(const std::string& line, bool should_log)>;
43 
44 static const char* abi_string(const Tombstone& tombstone) {
45   switch (tombstone.arch()) {
46     case Architecture::ARM32:
47       return "arm";
48     case Architecture::ARM64:
49       return "arm64";
50     case Architecture::X86:
51       return "x86";
52     case Architecture::X86_64:
53       return "x86_64";
54     default:
55       return "<unknown>";
56   }
57 }
58 
59 static int pointer_width(const Tombstone& tombstone) {
60   switch (tombstone.arch()) {
61     case Architecture::ARM32:
62       return 4;
63     case Architecture::ARM64:
64       return 8;
65     case Architecture::X86:
66       return 4;
67     case Architecture::X86_64:
68       return 8;
69     default:
70       return 8;
71   }
72 }
73 
74 static void print_thread_header(CallbackType callback, const Tombstone& tombstone,
75                                 const Thread& thread, bool should_log) {
76   const char* process_name = "<unknown>";
77   if (!tombstone.command_line().empty()) {
78     process_name = tombstone.command_line()[0].c_str();
79     CB(should_log, "Cmdline: %s", android::base::Join(tombstone.command_line(), " ").c_str());
80   }
81   CB(should_log, "pid: %d, tid: %d, name: %s  >>> %s <<<", tombstone.pid(), thread.id(),
82      thread.name().c_str(), process_name);
83   CB(should_log, "uid: %d", tombstone.uid());
84   if (thread.tagged_addr_ctrl() != -1) {
85     CB(should_log, "tagged_addr_ctrl: %016" PRIx64, thread.tagged_addr_ctrl());
86   }
87 }
88 
89 static void print_register_row(CallbackType callback, int word_size,
90                                std::vector<std::pair<std::string, uint64_t>> row, bool should_log) {
91   std::string output = "  ";
92   for (const auto& [name, value] : row) {
93     output += android::base::StringPrintf("  %-3s %0*" PRIx64, name.c_str(), 2 * word_size,
94                                           static_cast<uint64_t>(value));
95   }
96   callback(output, should_log);
97 }
98 
99 static void print_thread_registers(CallbackType callback, const Tombstone& tombstone,
100                                    const Thread& thread, bool should_log) {
101   static constexpr size_t column_count = 4;
102   std::vector<std::pair<std::string, uint64_t>> current_row;
103   std::vector<std::pair<std::string, uint64_t>> special_row;
104   std::unordered_set<std::string> special_registers;
105 
106   int word_size = pointer_width(tombstone);
107 
108   switch (tombstone.arch()) {
109     case Architecture::ARM32:
110       special_registers = {"ip", "lr", "sp", "pc", "pst"};
111       break;
112 
113     case Architecture::ARM64:
114       special_registers = {"ip", "lr", "sp", "pc", "pst"};
115       break;
116 
117     case Architecture::X86:
118       special_registers = {"ebp", "esp", "eip"};
119       break;
120 
121     case Architecture::X86_64:
122       special_registers = {"rbp", "rsp", "rip"};
123       break;
124 
125     default:
126       async_safe_fatal("unknown architecture");
127   }
128 
129   for (const auto& reg : thread.registers()) {
130     auto row = &current_row;
131     if (special_registers.count(reg.name()) == 1) {
132       row = &special_row;
133     }
134 
135     row->emplace_back(reg.name(), reg.u64());
136     if (current_row.size() == column_count) {
137       print_register_row(callback, word_size, current_row, should_log);
138       current_row.clear();
139     }
140   }
141 
142   if (!current_row.empty()) {
143     print_register_row(callback, word_size, current_row, should_log);
144   }
145 
146   print_register_row(callback, word_size, special_row, should_log);
147 }
148 
149 static void print_backtrace(CallbackType callback, const Tombstone& tombstone,
150                             const google::protobuf::RepeatedPtrField<BacktraceFrame>& backtrace,
151                             bool should_log) {
152   int index = 0;
153   for (const auto& frame : backtrace) {
154     std::string function;
155 
156     if (!frame.function_name().empty()) {
157       function =
158           StringPrintf(" (%s+%" PRId64 ")", frame.function_name().c_str(), frame.function_offset());
159     }
160 
161     std::string build_id;
162     if (!frame.build_id().empty()) {
163       build_id = StringPrintf(" (BuildId: %s)", frame.build_id().c_str());
164     }
165 
166     CB(should_log, "      #%02d pc %0*" PRIx64 "  %s%s%s", index++, pointer_width(tombstone) * 2,
167        frame.rel_pc(), frame.file_name().c_str(), function.c_str(), build_id.c_str());
168   }
169 }
170 
171 static void print_thread_backtrace(CallbackType callback, const Tombstone& tombstone,
172                                    const Thread& thread, bool should_log) {
173   CBS("");
174   CB(should_log, "backtrace:");
175   if (!thread.backtrace_note().empty()) {
176     CB(should_log, "  NOTE: %s",
177        android::base::Join(thread.backtrace_note(), "\n  NOTE: ").c_str());
178   }
179   print_backtrace(callback, tombstone, thread.current_backtrace(), should_log);
180 }
181 
182 static void print_thread_memory_dump(CallbackType callback, const Tombstone& tombstone,
183                                      const Thread& thread) {
184   static constexpr size_t bytes_per_line = 16;
185   static_assert(bytes_per_line == kTagGranuleSize);
186   int word_size = pointer_width(tombstone);
187   for (const auto& mem : thread.memory_dump()) {
188     CBS("");
189     if (mem.mapping_name().empty()) {
190       CBS("memory near %s:", mem.register_name().c_str());
191     } else {
192       CBS("memory near %s (%s):", mem.register_name().c_str(), mem.mapping_name().c_str());
193     }
194     uint64_t addr = mem.begin_address();
195     for (size_t offset = 0; offset < mem.memory().size(); offset += bytes_per_line) {
196       uint64_t tagged_addr = addr;
197       if (mem.has_arm_mte_metadata() &&
198           mem.arm_mte_metadata().memory_tags().size() > offset / kTagGranuleSize) {
199         tagged_addr |=
200             static_cast<uint64_t>(mem.arm_mte_metadata().memory_tags()[offset / kTagGranuleSize])
201             << 56;
202       }
203       std::string line = StringPrintf("    %0*" PRIx64, word_size * 2, tagged_addr + offset);
204 
205       size_t bytes = std::min(bytes_per_line, mem.memory().size() - offset);
206       for (size_t i = 0; i < bytes; i += word_size) {
207         uint64_t word = 0;
208 
209         // Assumes little-endian, but what doesn't?
210         memcpy(&word, mem.memory().data() + offset + i, word_size);
211 
212         StringAppendF(&line, " %0*" PRIx64, word_size * 2, word);
213       }
214 
215       char ascii[bytes_per_line + 1];
216 
217       memset(ascii, '.', sizeof(ascii));
218       ascii[bytes_per_line] = '\0';
219 
220       for (size_t i = 0; i < bytes; ++i) {
221         uint8_t byte = mem.memory()[offset + i];
222         if (byte >= 0x20 && byte < 0x7f) {
223           ascii[i] = byte;
224         }
225       }
226 
227       CBS("%s  %s", line.c_str(), ascii);
228     }
229   }
230 }
231 
232 static void print_thread(CallbackType callback, const Tombstone& tombstone, const Thread& thread) {
233   print_thread_header(callback, tombstone, thread, false);
234   print_thread_registers(callback, tombstone, thread, false);
235   print_thread_backtrace(callback, tombstone, thread, false);
236   print_thread_memory_dump(callback, tombstone, thread);
237 }
238 
239 static void print_tag_dump(CallbackType callback, const Tombstone& tombstone) {
240   if (!tombstone.has_signal_info()) return;
241 
242   const Signal& signal = tombstone.signal_info();
243 
244   if (!signal.has_fault_address() || !signal.has_fault_adjacent_metadata()) {
245     return;
246   }
247 
248   const MemoryDump& memory_dump = signal.fault_adjacent_metadata();
249 
250   if (!memory_dump.has_arm_mte_metadata() || memory_dump.arm_mte_metadata().memory_tags().empty()) {
251     return;
252   }
253 
254   const std::string& tags = memory_dump.arm_mte_metadata().memory_tags();
255 
256   CBS("");
257   CBS("Memory tags around the fault address (0x%" PRIx64 "), one tag per %zu bytes:",
258       signal.fault_address(), kTagGranuleSize);
259   constexpr uintptr_t kRowStartMask = ~(kNumTagColumns * kTagGranuleSize - 1);
260 
261   size_t tag_index = 0;
262   size_t num_tags = tags.length();
263   uintptr_t fault_granule = untag_address(signal.fault_address()) & ~(kTagGranuleSize - 1);
264   for (size_t row = 0; tag_index < num_tags; ++row) {
265     uintptr_t row_addr =
266         (memory_dump.begin_address() + row * kNumTagColumns * kTagGranuleSize) & kRowStartMask;
267     std::string row_contents;
268     bool row_has_fault = false;
269 
270     for (size_t column = 0; column < kNumTagColumns; ++column) {
271       uintptr_t granule_addr = row_addr + column * kTagGranuleSize;
272       if (granule_addr < memory_dump.begin_address() ||
273           granule_addr >= memory_dump.begin_address() + num_tags * kTagGranuleSize) {
274         row_contents += " . ";
275       } else if (granule_addr == fault_granule) {
276         row_contents += StringPrintf("[%1hhx]", tags[tag_index++]);
277         row_has_fault = true;
278       } else {
279         row_contents += StringPrintf(" %1hhx ", tags[tag_index++]);
280       }
281     }
282 
283     if (row_contents.back() == ' ') row_contents.pop_back();
284 
285     if (row_has_fault) {
286       CBS("    =>0x%" PRIxPTR ":%s", row_addr, row_contents.c_str());
287     } else {
288       CBS("      0x%" PRIxPTR ":%s", row_addr, row_contents.c_str());
289     }
290   }
291 }
292 
293 static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
294                               const Thread& thread) {
295   print_thread_header(callback, tombstone, thread, true);
296 
297   const Signal& signal_info = tombstone.signal_info();
298   std::string sender_desc;
299 
300   if (signal_info.has_sender()) {
301     sender_desc =
302         StringPrintf(" from pid %d, uid %d", signal_info.sender_pid(), signal_info.sender_uid());
303   }
304 
305   if (!tombstone.has_signal_info()) {
306     CBL("signal information missing");
307   } else {
308     std::string fault_addr_desc;
309     if (signal_info.has_fault_address()) {
310       fault_addr_desc = StringPrintf("0x%" PRIx64, signal_info.fault_address());
311     } else {
312       fault_addr_desc = "--------";
313     }
314 
315     CBL("signal %d (%s), code %d (%s%s), fault addr %s", signal_info.number(),
316         signal_info.name().c_str(), signal_info.code(), signal_info.code_name().c_str(),
317         sender_desc.c_str(), fault_addr_desc.c_str());
318   }
319 
320   if (tombstone.causes_size() == 1) {
321     CBL("Cause: %s", tombstone.causes(0).human_readable().c_str());
322   }
323 
324   if (!tombstone.abort_message().empty()) {
325     CBL("Abort message: '%s'", tombstone.abort_message().c_str());
326   }
327 
328   print_thread_registers(callback, tombstone, thread, true);
329   print_thread_backtrace(callback, tombstone, thread, true);
330 
331   if (tombstone.causes_size() > 1) {
332     CBS("");
333     CBL("Note: multiple potential causes for this crash were detected, listing them in decreasing "
334         "order of probability.");
335   }
336 
337   for (const Cause& cause : tombstone.causes()) {
338     if (tombstone.causes_size() > 1) {
339       CBS("");
340       CBL("Cause: %s", cause.human_readable().c_str());
341     }
342 
343     if (cause.has_memory_error() && cause.memory_error().has_heap()) {
344       const HeapObject& heap_object = cause.memory_error().heap();
345 
346       if (heap_object.deallocation_backtrace_size() != 0) {
347         CBS("");
348         CBL("deallocated by thread %" PRIu64 ":", heap_object.deallocation_tid());
349         print_backtrace(callback, tombstone, heap_object.deallocation_backtrace(), true);
350       }
351 
352       if (heap_object.allocation_backtrace_size() != 0) {
353         CBS("");
354         CBL("allocated by thread %" PRIu64 ":", heap_object.allocation_tid());
355         print_backtrace(callback, tombstone, heap_object.allocation_backtrace(), true);
356       }
357     }
358   }
359 
360   print_tag_dump(callback, tombstone);
361 
362   print_thread_memory_dump(callback, tombstone, thread);
363 
364   CBS("");
365   CBS("memory map (%d %s):", tombstone.memory_mappings().size(),
366       tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
367   int word_size = pointer_width(tombstone);
368   const auto format_pointer = [word_size](uint64_t ptr) -> std::string {
369     if (word_size == 8) {
370       uint64_t top = ptr >> 32;
371       uint64_t bottom = ptr & 0xFFFFFFFF;
372       return StringPrintf("%08" PRIx64 "'%08" PRIx64, top, bottom);
373     }
374 
375     return StringPrintf("%0*" PRIx64, word_size * 2, ptr);
376   };
377 
378   for (const auto& map : tombstone.memory_mappings()) {
379     std::string line = "    ";
380     StringAppendF(&line, "%s-%s", format_pointer(map.begin_address()).c_str(),
381                   format_pointer(map.end_address() - 1).c_str());
382     StringAppendF(&line, " %s%s%s", map.read() ? "r" : "-", map.write() ? "w" : "-",
383                   map.execute() ? "x" : "-");
384     StringAppendF(&line, "  %8" PRIx64 "  %8" PRIx64, map.offset(),
385                   map.end_address() - map.begin_address());
386 
387     if (!map.mapping_name().empty()) {
388       StringAppendF(&line, "  %s", map.mapping_name().c_str());
389 
390       if (!map.build_id().empty()) {
391         StringAppendF(&line, " (BuildId: %s)", map.build_id().c_str());
392       }
393 
394       if (map.load_bias() != 0) {
395         StringAppendF(&line, " (load bias 0x%" PRIx64 ")", map.load_bias());
396       }
397     }
398 
399     CBS("%s", line.c_str());
400   }
401 }
402 
403 void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) {
404   for (const auto& buffer : tombstone.log_buffers()) {
405     if (tail) {
406       CBS("--------- tail end of log %s", buffer.name().c_str());
407     } else {
408       CBS("--------- log %s", buffer.name().c_str());
409     }
410 
411     int begin = 0;
412     if (tail != 0) {
413       begin = std::max(0, buffer.logs().size() - tail);
414     }
415 
416     for (int i = begin; i < buffer.logs().size(); ++i) {
417       const LogMessage& msg = buffer.logs(i);
418 
419       static const char* kPrioChars = "!.VDIWEFS";
420       char priority = (msg.priority() < strlen(kPrioChars) ? kPrioChars[msg.priority()] : '?');
421       CBS("%s %5u %5u %c %-8s: %s", msg.timestamp().c_str(), msg.pid(), msg.tid(), priority,
422           msg.tag().c_str(), msg.message().c_str());
423     }
424   }
425 }
426 
427 bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) {
428   CBL("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***");
429   CBL("Build fingerprint: '%s'", tombstone.build_fingerprint().c_str());
430   CBL("Revision: '%s'", tombstone.revision().c_str());
431   CBL("ABI: '%s'", abi_string(tombstone));
432   CBL("Timestamp: %s", tombstone.timestamp().c_str());
433   CBL("Process uptime: %ds", tombstone.process_uptime());
434 
435   // Process header
436   const auto& threads = tombstone.threads();
437   auto main_thread_it = threads.find(tombstone.tid());
438   if (main_thread_it == threads.end()) {
439     CBL("failed to find entry for main thread in tombstone");
440     return false;
441   }
442 
443   const auto& main_thread = main_thread_it->second;
444 
445   print_main_thread(callback, tombstone, main_thread);
446 
447   print_logs(callback, tombstone, 50);
448 
449   // protobuf's map is unordered, so sort the keys first.
450   std::set<int> thread_ids;
451   for (const auto& [tid, _] : threads) {
452     if (tid != tombstone.tid()) {
453       thread_ids.insert(tid);
454     }
455   }
456 
457   for (const auto& tid : thread_ids) {
458     CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
459     print_thread(callback, tombstone, threads.find(tid)->second);
460   }
461 
462   if (tombstone.open_fds().size() > 0) {
463     CBS("");
464     CBS("open files:");
465     for (const auto& fd : tombstone.open_fds()) {
466       std::optional<std::string> owner;
467       if (!fd.owner().empty()) {
468         owner = StringPrintf("owned by %s 0x%" PRIx64, fd.owner().c_str(), fd.tag());
469       }
470 
471       CBS("    fd %d: %s (%s)", fd.fd(), fd.path().c_str(), owner ? owner->c_str() : "unowned");
472     }
473   }
474 
475   print_logs(callback, tombstone, 0);
476 
477   return true;
478 }
479