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 |