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 LatePostprocessMappings(); |
| 114 #endif |
| 115 return true; |
| 116 } |
| 117 |
95 bool | 118 bool |
96 LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, | 119 LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, |
97 bool member, | 120 bool member, |
98 unsigned int mapping_id, | 121 unsigned int mapping_id, |
99 uint8_t identifier[sizeof(MDGUID)]) { | 122 uint8_t identifier[sizeof(MDGUID)]) { |
100 assert(!member || mapping_id < mappings_.size()); | 123 assert(!member || mapping_id < mappings_.size()); |
101 my_memset(identifier, 0, sizeof(MDGUID)); | 124 my_memset(identifier, 0, sizeof(MDGUID)); |
102 if (IsMappedFileOpenUnsafe(mapping)) | 125 if (IsMappedFileOpenUnsafe(mapping)) |
103 return false; | 126 return false; |
104 | 127 |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 } | 411 } |
389 } | 412 } |
390 line_reader->PopLine(line_len); | 413 line_reader->PopLine(line_len); |
391 } | 414 } |
392 | 415 |
393 sys_close(fd); | 416 sys_close(fd); |
394 | 417 |
395 return !mappings_.empty(); | 418 return !mappings_.empty(); |
396 } | 419 } |
397 | 420 |
| 421 #if defined(__ANDROID__) |
| 422 |
| 423 bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) { |
| 424 CopyFromProcess(ehdr, pid_, |
| 425 reinterpret_cast<const void*>(start_addr), |
| 426 sizeof(*ehdr)); |
| 427 return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0; |
| 428 } |
| 429 |
| 430 void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, |
| 431 uintptr_t start_addr, |
| 432 uintptr_t* min_vaddr_ptr, |
| 433 uintptr_t* dyn_vaddr_ptr, |
| 434 size_t* dyn_count_ptr) { |
| 435 uintptr_t phdr_addr = start_addr + ehdr->e_phoff; |
| 436 |
| 437 const uintptr_t max_addr = UINTPTR_MAX; |
| 438 uintptr_t min_vaddr = max_addr; |
| 439 uintptr_t dyn_vaddr = 0; |
| 440 size_t dyn_count = 0; |
| 441 |
| 442 for (size_t i = 0; i < ehdr->e_phnum; ++i) { |
| 443 ElfW(Phdr) phdr; |
| 444 CopyFromProcess(&phdr, pid_, |
| 445 reinterpret_cast<const void*>(phdr_addr), |
| 446 sizeof(phdr)); |
| 447 if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) { |
| 448 min_vaddr = phdr.p_vaddr; |
| 449 } |
| 450 if (phdr.p_type == PT_DYNAMIC) { |
| 451 dyn_vaddr = phdr.p_vaddr; |
| 452 dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn)); |
| 453 } |
| 454 phdr_addr += sizeof(phdr); |
| 455 } |
| 456 |
| 457 *min_vaddr_ptr = min_vaddr; |
| 458 *dyn_vaddr_ptr = dyn_vaddr; |
| 459 *dyn_count_ptr = dyn_count; |
| 460 } |
| 461 |
| 462 bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias, |
| 463 uintptr_t dyn_vaddr, |
| 464 size_t dyn_count) { |
| 465 uintptr_t dyn_addr = load_bias + dyn_vaddr; |
| 466 for (size_t i = 0; i < dyn_count; ++i) { |
| 467 ElfW(Dyn) dyn; |
| 468 CopyFromProcess(&dyn, pid_, |
| 469 reinterpret_cast<const void*>(dyn_addr), |
| 470 sizeof(dyn)); |
| 471 if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) { |
| 472 return true; |
| 473 } |
| 474 dyn_addr += sizeof(dyn); |
| 475 } |
| 476 return false; |
| 477 } |
| 478 |
| 479 uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, |
| 480 uintptr_t start_addr) { |
| 481 uintptr_t min_vaddr = 0; |
| 482 uintptr_t dyn_vaddr = 0; |
| 483 size_t dyn_count = 0; |
| 484 ParseLoadedElfProgramHeaders(ehdr, start_addr, |
| 485 &min_vaddr, &dyn_vaddr, &dyn_count); |
| 486 // If |min_vaddr| is non-zero and we find Android packed relocation tags, |
| 487 // return the effective load bias. |
| 488 if (min_vaddr != 0) { |
| 489 const uintptr_t load_bias = start_addr - min_vaddr; |
| 490 if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) { |
| 491 return load_bias; |
| 492 } |
| 493 } |
| 494 // Either |min_vaddr| is zero, or it is non-zero but we did not find the |
| 495 // expected Android packed relocations tags. |
| 496 return start_addr; |
| 497 } |
| 498 |
| 499 void LinuxDumper::LatePostprocessMappings() { |
| 500 for (size_t i = 0; i < mappings_.size(); ++i) { |
| 501 // Only consider exec mappings that indicate a file path was mapped, and |
| 502 // where the ELF header indicates a mapped shared library. |
| 503 MappingInfo* mapping = mappings_[i]; |
| 504 if (!(mapping->exec && mapping->name[0] == '/')) { |
| 505 continue; |
| 506 } |
| 507 ElfW(Ehdr) ehdr; |
| 508 if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) { |
| 509 continue; |
| 510 } |
| 511 if (ehdr.e_type == ET_DYN) { |
| 512 // Compute the effective load bias for this mapped library, and update |
| 513 // the mapping to hold that rather than |start_addr|. Where the library |
| 514 // does not contain Android packed relocations, GetEffectiveLoadBias() |
| 515 // returns |start_addr| and the mapping entry is not changed. |
| 516 mapping->start_addr = GetEffectiveLoadBias(&ehdr, mapping->start_addr); |
| 517 } |
| 518 } |
| 519 } |
| 520 |
| 521 #endif // __ANDROID__ |
| 522 |
398 // Get information about the stack, given the stack pointer. We don't try to | 523 // 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 | 524 // 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. | 525 // unwind. So we just grab, up to, 32k of stack. |
401 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, | 526 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, |
402 uintptr_t int_stack_pointer) { | 527 uintptr_t int_stack_pointer) { |
403 // Move the stack pointer to the bottom of the page that it's in. | 528 // Move the stack pointer to the bottom of the page that it's in. |
404 const uintptr_t page_size = getpagesize(); | 529 const uintptr_t page_size = getpagesize(); |
405 | 530 |
406 uint8_t* const stack_pointer = | 531 uint8_t* const stack_pointer = |
407 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); | 532 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 && | 591 exe_stat.st_dev == new_path_stat.st_dev && |
467 exe_stat.st_ino == new_path_stat.st_ino) { | 592 exe_stat.st_ino == new_path_stat.st_ino) { |
468 return false; | 593 return false; |
469 } | 594 } |
470 | 595 |
471 my_memcpy(path, exe_link, NAME_MAX); | 596 my_memcpy(path, exe_link, NAME_MAX); |
472 return true; | 597 return true; |
473 } | 598 } |
474 | 599 |
475 } // namespace google_breakpad | 600 } // namespace google_breakpad |
OLD | NEW |