Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010, Google Inc. | 1 // Copyright (c) 2010, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 #include <string.h> | 45 #include <string.h> |
| 46 | 46 |
| 47 #include "client/linux/minidump_writer/line_reader.h" | 47 #include "client/linux/minidump_writer/line_reader.h" |
| 48 #include "common/linux/elfutils.h" | 48 #include "common/linux/elfutils.h" |
| 49 #include "common/linux/file_id.h" | 49 #include "common/linux/file_id.h" |
| 50 #include "common/linux/linux_libc_support.h" | 50 #include "common/linux/linux_libc_support.h" |
| 51 #include "common/linux/memory_mapped_file.h" | 51 #include "common/linux/memory_mapped_file.h" |
| 52 #include "common/linux/safe_readlink.h" | 52 #include "common/linux/safe_readlink.h" |
| 53 #include "third_party/lss/linux_syscall_support.h" | 53 #include "third_party/lss/linux_syscall_support.h" |
| 54 | 54 |
| 55 #if defined(__ANDROID__) | |
| 56 | |
| 57 // Android packed relocations definitions are not yet available from the | |
| 58 // NDK header files, so we have to provide them manually here. | |
| 59 #ifndef DT_LOOS | |
| 60 #define DT_LOOS 0x6000000d | |
| 61 #endif | |
| 62 #ifndef DT_ANDROID_REL | |
| 63 static const int DT_ANDROID_REL = DT_LOOS + 2; | |
| 64 #endif | |
| 65 #ifndef DT_ANDROID_RELA | |
| 66 static const int DT_ANDROID_RELA = DT_LOOS + 4; | |
| 67 #endif | |
| 68 | |
| 69 #endif // __ANDROID __ | |
| 70 | |
| 55 static const char kMappedFileUnsafePrefix[] = "/dev/"; | 71 static const char kMappedFileUnsafePrefix[] = "/dev/"; |
| 56 static const char kDeletedSuffix[] = " (deleted)"; | 72 static const char kDeletedSuffix[] = " (deleted)"; |
| 57 static const char kReservedFlags[] = " ---p"; | 73 static const char kReservedFlags[] = " ---p"; |
| 58 | 74 |
| 59 inline static bool IsMappedFileOpenUnsafe( | 75 inline static bool IsMappedFileOpenUnsafe( |
| 60 const google_breakpad::MappingInfo& mapping) { | 76 const google_breakpad::MappingInfo& mapping) { |
| 61 // It is unsafe to attempt to open a mapped file that lives under /dev, | 77 // It is unsafe to attempt to open a mapped file that lives under /dev, |
| 62 // because the semantics of the open may be driver-specific so we'd risk | 78 // because the semantics of the open may be driver-specific so we'd risk |
| 63 // hanging the crash dumper. And a file in /dev/ almost certainly has no | 79 // hanging the crash dumper. And a file in /dev/ almost certainly has no |
| 64 // ELF file identifier anyways. | 80 // ELF file identifier anyways. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 85 auxv_.resize(AT_MAX + 1); | 101 auxv_.resize(AT_MAX + 1); |
| 86 } | 102 } |
| 87 | 103 |
| 88 LinuxDumper::~LinuxDumper() { | 104 LinuxDumper::~LinuxDumper() { |
| 89 } | 105 } |
| 90 | 106 |
| 91 bool LinuxDumper::Init() { | 107 bool LinuxDumper::Init() { |
| 92 return ReadAuxv() && EnumerateThreads() && EnumerateMappings(); | 108 return ReadAuxv() && EnumerateThreads() && EnumerateMappings(); |
| 93 } | 109 } |
| 94 | 110 |
| 111 bool LinuxDumper::LateInit() { | |
| 112 #if defined(__ANDROID__) | |
| 113 return LatePostprocessMappings(); | |
| 114 #else | |
| 115 return true; | |
| 116 #endif | |
| 117 } | |
| 118 | |
| 95 bool | 119 bool |
| 96 LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, | 120 LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, |
| 97 bool member, | 121 bool member, |
| 98 unsigned int mapping_id, | 122 unsigned int mapping_id, |
| 99 uint8_t identifier[sizeof(MDGUID)]) { | 123 uint8_t identifier[sizeof(MDGUID)]) { |
| 100 assert(!member || mapping_id < mappings_.size()); | 124 assert(!member || mapping_id < mappings_.size()); |
| 101 my_memset(identifier, 0, sizeof(MDGUID)); | 125 my_memset(identifier, 0, sizeof(MDGUID)); |
| 102 if (IsMappedFileOpenUnsafe(mapping)) | 126 if (IsMappedFileOpenUnsafe(mapping)) |
| 103 return false; | 127 return false; |
| 104 | 128 |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 } | 412 } |
| 389 } | 413 } |
| 390 line_reader->PopLine(line_len); | 414 line_reader->PopLine(line_len); |
| 391 } | 415 } |
| 392 | 416 |
| 393 sys_close(fd); | 417 sys_close(fd); |
| 394 | 418 |
| 395 return !mappings_.empty(); | 419 return !mappings_.empty(); |
| 396 } | 420 } |
| 397 | 421 |
| 422 #if defined(__ANDROID__) | |
| 423 | |
| 424 // Read the memory at start_addr, expecting to find an ELF header. The first | |
| 425 // LOAD segment in an ELF shared library has offset zero, so the ELF file | |
| 426 // header is at the start of this map entry, and in already mapped memory. | |
| 427 bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) { | |
| 428 CopyFromProcess(ehdr, pid_, | |
| 429 reinterpret_cast<const void*>(start_addr), | |
| 430 sizeof(*ehdr)); | |
| 431 if (my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) != 0) { | |
| 432 return false; | |
| 433 } | |
| 434 return true; | |
| 435 } | |
| 436 | |
| 437 // Iterate ELF program headers to find the min vaddr of LOAD segments, and | |
| 438 // the vaddr and count of entries for the DYNAMIC table. The program header | |
| 439 // table is also in already mapped memory. | |
| 440 void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, | |
| 441 uintptr_t start_addr, | |
| 442 uintptr_t* min_vaddr_ptr, | |
| 443 uintptr_t* dyn_vaddr_ptr, | |
| 444 size_t* dyn_count_ptr) { | |
| 445 uint8_t* phdr_addr = reinterpret_cast<uint8_t*>(start_addr) + ehdr->e_phoff; | |
| 446 | |
| 447 const uintptr_t max_addr = ~static_cast<uintptr_t>(0); | |
| 448 uintptr_t min_vaddr = max_addr; | |
| 449 uintptr_t dyn_vaddr = 0; | |
| 450 size_t dyn_count = 0; | |
| 451 | |
| 452 for (size_t i = 0; i < ehdr->e_phnum; ++i) { | |
| 453 ElfW(Phdr) phdr; | |
| 454 CopyFromProcess(&phdr, pid_, | |
| 455 reinterpret_cast<const void*>(phdr_addr), | |
| 456 sizeof(phdr)); | |
| 457 if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) { | |
| 458 min_vaddr = phdr.p_vaddr; | |
| 459 } | |
| 460 if (phdr.p_type == PT_DYNAMIC) { | |
| 461 dyn_vaddr = phdr.p_vaddr; | |
| 462 dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn)); | |
| 463 } | |
| 464 phdr_addr += sizeof(phdr); | |
| 465 } | |
| 466 assert(min_vaddr != max_addr); | |
| 467 | |
| 468 *min_vaddr_ptr = min_vaddr; | |
| 469 *dyn_vaddr_ptr = dyn_vaddr; | |
| 470 *dyn_count_ptr = dyn_count; | |
| 471 } | |
| 472 | |
| 473 // Retrieve and check dynamic tags, and return true if tags for Android | |
| 474 // packed relocations as present. Dynamic tags are found at dyn_vaddr past | |
| 475 // the load_bias. | |
| 476 bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias, | |
| 477 uintptr_t dyn_vaddr, | |
| 478 size_t dyn_count) { | |
| 479 uint8_t* dyn_addr = reinterpret_cast<uint8_t*>(load_bias) + dyn_vaddr; | |
| 480 for (size_t i = 0; i < dyn_count; ++i) { | |
| 481 ElfW(Dyn) dyn; | |
| 482 CopyFromProcess(&dyn, pid_, | |
| 483 reinterpret_cast<const void*>(dyn_addr), | |
| 484 sizeof(dyn)); | |
| 485 if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) { | |
| 486 return true; | |
| 487 } | |
| 488 dyn_addr += sizeof(dyn); | |
| 489 } | |
| 490 return false; | |
| 491 } | |
| 492 | |
| 493 // Return the effective load_bias, used by the system linker (or Chromium | |
| 494 // crazy linker) for the ELF shared library mapped at the given start_addr. | |
| 495 // The effective load_bias is start_addr adjusted downwards by the min vaddr | |
| 496 // in the library LOAD segments. | |
| 497 uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, | |
| 498 uintptr_t start_addr) { | |
| 499 uintptr_t min_vaddr = 0; | |
| 500 uintptr_t dyn_vaddr = 0; | |
| 501 size_t dyn_count = 0; | |
| 502 ParseLoadedElfProgramHeaders(ehdr, start_addr, | |
| 503 &min_vaddr, &dyn_vaddr, &dyn_count); | |
| 504 // If min vaddr is non-zero and we find Android packed relocation tags, | |
| 505 // return the effective load_bias. | |
| 506 if (min_vaddr != 0) { | |
| 507 const uintptr_t load_bias = start_addr - min_vaddr; | |
| 508 if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) { | |
| 509 return load_bias; | |
| 510 } | |
| 511 } | |
| 512 // Either min vaddr is zero, or it is non-zero but we did not find the | |
| 513 // expected Android packed relocations tags. | |
| 514 return start_addr; | |
| 515 } | |
| 516 | |
| 517 // Iterate mappings_, and adjust any start_addr fields that are for mapped | |
| 518 // libraries that contain Android packed relocations. | |
| 519 bool LinuxDumper::LatePostprocessMappings() { | |
| 520 for (size_t i = 0; i < mappings_.size(); ++i) { | |
| 521 // Only consider exec mappings that indicate a file path was mapped, and | |
| 522 // where the ELF header indicates a mapped shared library. | |
| 523 MappingInfo* mapping = mappings_[i]; | |
| 524 if (!(mapping->exec && mapping->name && mapping->name[0] == '/')) { | |
| 525 continue; | |
| 526 } | |
| 527 ElfW(Ehdr) ehdr; | |
| 528 if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) { | |
| 529 return false; | |
|
rmcilroy
2015/06/18 15:08:13
As discussed offline, let's make this a continue i
simonb (inactive)
2015/06/18 16:24:39
Done.
| |
| 530 } | |
| 531 if (ehdr.e_type == ET_DYN) { | |
| 532 // Compute the effective load_bias for this mapped library, and update | |
| 533 // the mapping to hold that rather than start_addr. Where the library | |
| 534 // does not contain Android packed relocations, GetEffectiveLoadBias() | |
| 535 // returns start_addr and the mapping entry is not changed. | |
| 536 mapping->start_addr = GetEffectiveLoadBias(&ehdr, mapping->start_addr); | |
| 537 } | |
| 538 } | |
| 539 return true; | |
| 540 } | |
| 541 | |
| 542 #endif // __ANDROID__ | |
| 543 | |
| 398 // Get information about the stack, given the stack pointer. We don't try to | 544 // Get information about the stack, given the stack pointer. We don't try to |
| 399 // walk the stack since we might not have all the information needed to do | 545 // walk the stack since we might not have all the information needed to do |
| 400 // unwind. So we just grab, up to, 32k of stack. | 546 // unwind. So we just grab, up to, 32k of stack. |
| 401 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, | 547 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, |
| 402 uintptr_t int_stack_pointer) { | 548 uintptr_t int_stack_pointer) { |
| 403 // Move the stack pointer to the bottom of the page that it's in. | 549 // Move the stack pointer to the bottom of the page that it's in. |
| 404 const uintptr_t page_size = getpagesize(); | 550 const uintptr_t page_size = getpagesize(); |
| 405 | 551 |
| 406 uint8_t* const stack_pointer = | 552 uint8_t* const stack_pointer = |
| 407 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); | 553 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 466 exe_stat.st_dev == new_path_stat.st_dev && | 612 exe_stat.st_dev == new_path_stat.st_dev && |
| 467 exe_stat.st_ino == new_path_stat.st_ino) { | 613 exe_stat.st_ino == new_path_stat.st_ino) { |
| 468 return false; | 614 return false; |
| 469 } | 615 } |
| 470 | 616 |
| 471 my_memcpy(path, exe_link, NAME_MAX); | 617 my_memcpy(path, exe_link, NAME_MAX); |
| 472 return true; | 618 return true; |
| 473 } | 619 } |
| 474 | 620 |
| 475 } // namespace google_breakpad | 621 } // namespace google_breakpad |
| OLD | NEW |