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 | |
|
Lei Zhang
2015/06/18 21:45:37
Comments should go in the header. Ditto below.
simonb (inactive)
2015/06/19 12:19:27
Done.
| |
| 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) { | |
|
Lei Zhang
2015/06/18 21:45:37
Just: return (my_memcmp(...) != 0); ?
simonb (inactive)
2015/06/19 12:19:27
Done.
| |
| 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 uintptr_t phdr_addr = start_addr + ehdr->e_phoff; | |
|
Lei Zhang
2015/06/18 21:45:37
Can this or the addition to |phdr_addr| below over
simonb (inactive)
2015/06/19 12:19:27
To somewhat amplify Primiano's comment below... no
| |
| 446 | |
| 447 const uintptr_t max_addr = UINTPTR_MAX; | |
| 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 | |
| 467 *min_vaddr_ptr = min_vaddr; | |
| 468 *dyn_vaddr_ptr = dyn_vaddr; | |
| 469 *dyn_count_ptr = dyn_count; | |
| 470 } | |
| 471 | |
| 472 // Retrieve and check dynamic tags, and return true if tags for Android | |
| 473 // packed relocations as present. Dynamic tags are found at dyn_vaddr past | |
| 474 // the load_bias. | |
| 475 bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias, | |
| 476 uintptr_t dyn_vaddr, | |
| 477 size_t dyn_count) { | |
| 478 uintptr_t dyn_addr = load_bias + dyn_vaddr; | |
|
Lei Zhang
2015/06/18 21:45:37
Can this or the addition to |dyn_addr| below overf
Primiano Tucci (use gerrit)
2015/06/18 21:56:13
but in that case CopyFromProcess will just fill u
| |
| 479 for (size_t i = 0; i < dyn_count; ++i) { | |
| 480 ElfW(Dyn) dyn; | |
| 481 CopyFromProcess(&dyn, pid_, | |
| 482 reinterpret_cast<const void*>(dyn_addr), | |
| 483 sizeof(dyn)); | |
| 484 if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) { | |
| 485 return true; | |
| 486 } | |
| 487 dyn_addr += sizeof(dyn); | |
| 488 } | |
| 489 return false; | |
| 490 } | |
| 491 | |
| 492 // Return the effective load_bias, used by the system linker (or Chromium | |
| 493 // crazy linker) for the ELF shared library mapped at the given start_addr. | |
| 494 // The effective load_bias is start_addr adjusted downwards by the min vaddr | |
| 495 // in the library LOAD segments. | |
| 496 uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, | |
| 497 uintptr_t start_addr) { | |
| 498 uintptr_t min_vaddr = 0; | |
| 499 uintptr_t dyn_vaddr = 0; | |
| 500 size_t dyn_count = 0; | |
| 501 ParseLoadedElfProgramHeaders(ehdr, start_addr, | |
| 502 &min_vaddr, &dyn_vaddr, &dyn_count); | |
| 503 // If min vaddr is non-zero and we find Android packed relocation tags, | |
|
Lei Zhang
2015/06/18 21:45:37
min vaddr -> |min_vaddr|
simonb (inactive)
2015/06/19 12:19:28
Done.
| |
| 504 // return the effective load_bias. | |
| 505 if (min_vaddr != 0) { | |
| 506 const uintptr_t load_bias = start_addr - min_vaddr; | |
|
Lei Zhang
2015/06/18 21:45:37
Is |min_vaddr| guaranteeded to be less than |start
simonb (inactive)
2015/06/19 12:19:27
Done.
Lei Zhang
2015/06/19 18:59:28
Can I get a yes/no answer on this question?
simonb (inactive)
2015/06/22 16:52:42
Sorry, mis-clicked Done here.
What all of this co
| |
| 507 if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) { | |
| 508 return load_bias; | |
| 509 } | |
| 510 } | |
| 511 // Either min vaddr is zero, or it is non-zero but we did not find the | |
| 512 // expected Android packed relocations tags. | |
| 513 return start_addr; | |
| 514 } | |
| 515 | |
| 516 // Iterate mappings_, and adjust any start_addr fields that are for mapped | |
|
Lei Zhang
2015/06/18 21:45:38
|mappings_|
simonb (inactive)
2015/06/19 12:19:27
Done.
| |
| 517 // libraries that contain Android packed relocations. | |
| 518 bool LinuxDumper::LatePostprocessMappings() { | |
| 519 for (size_t i = 0; i < mappings_.size(); ++i) { | |
| 520 // Only consider exec mappings that indicate a file path was mapped, and | |
| 521 // where the ELF header indicates a mapped shared library. | |
| 522 MappingInfo* mapping = mappings_[i]; | |
| 523 if (!(mapping->exec && mapping->name[0] == '/')) { | |
| 524 continue; | |
| 525 } | |
| 526 ElfW(Ehdr) ehdr; | |
| 527 if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) { | |
| 528 continue; | |
| 529 } | |
| 530 if (ehdr.e_type == ET_DYN) { | |
| 531 // Compute the effective load_bias for this mapped library, and update | |
| 532 // the mapping to hold that rather than start_addr. Where the library | |
| 533 // does not contain Android packed relocations, GetEffectiveLoadBias() | |
| 534 // returns start_addr and the mapping entry is not changed. | |
| 535 mapping->start_addr = GetEffectiveLoadBias(&ehdr, mapping->start_addr); | |
| 536 } | |
| 537 } | |
| 538 return true; | |
|
Lei Zhang
2015/06/18 21:45:37
This function can't return anything but true as is
simonb (inactive)
2015/06/19 12:19:27
Done.
I have left LateInit() returning bool for n
| |
| 539 } | |
| 540 | |
| 541 #endif // __ANDROID__ | |
| 542 | |
| 398 // Get information about the stack, given the stack pointer. We don't try to | 543 // 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 | 544 // 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. | 545 // unwind. So we just grab, up to, 32k of stack. |
| 401 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, | 546 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, |
| 402 uintptr_t int_stack_pointer) { | 547 uintptr_t int_stack_pointer) { |
| 403 // Move the stack pointer to the bottom of the page that it's in. | 548 // Move the stack pointer to the bottom of the page that it's in. |
| 404 const uintptr_t page_size = getpagesize(); | 549 const uintptr_t page_size = getpagesize(); |
| 405 | 550 |
| 406 uint8_t* const stack_pointer = | 551 uint8_t* const stack_pointer = |
| 407 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); | 552 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 && | 611 exe_stat.st_dev == new_path_stat.st_dev && |
| 467 exe_stat.st_ino == new_path_stat.st_ino) { | 612 exe_stat.st_ino == new_path_stat.st_ino) { |
| 468 return false; | 613 return false; |
| 469 } | 614 } |
| 470 | 615 |
| 471 my_memcpy(path, exe_link, NAME_MAX); | 616 my_memcpy(path, exe_link, NAME_MAX); |
| 472 return true; | 617 return true; |
| 473 } | 618 } |
| 474 | 619 |
| 475 } // namespace google_breakpad | 620 } // namespace google_breakpad |
| OLD | NEW |