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 = ¤t_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