| OLD | NEW |
| 1 // Copyright (c) 2006, Google Inc. | 1 // Copyright (c) 2006, 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 30 matching lines...) Expand all Loading... |
| 41 #include <algorithm> | 41 #include <algorithm> |
| 42 | 42 |
| 43 #include "common/linux/elf_gnu_compat.h" | 43 #include "common/linux/elf_gnu_compat.h" |
| 44 #include "common/linux/elfutils.h" | 44 #include "common/linux/elfutils.h" |
| 45 #include "common/linux/linux_libc_support.h" | 45 #include "common/linux/linux_libc_support.h" |
| 46 #include "common/linux/memory_mapped_file.h" | 46 #include "common/linux/memory_mapped_file.h" |
| 47 #include "third_party/lss/linux_syscall_support.h" | 47 #include "third_party/lss/linux_syscall_support.h" |
| 48 | 48 |
| 49 namespace google_breakpad { | 49 namespace google_breakpad { |
| 50 | 50 |
| 51 // Used in a few places for backwards-compatibility. |
| 52 const size_t kMDGUIDSize = sizeof(MDGUID); |
| 53 |
| 51 FileID::FileID(const char* path) : path_(path) {} | 54 FileID::FileID(const char* path) : path_(path) {} |
| 52 | 55 |
| 53 // ELF note name and desc are 32-bits word padded. | 56 // ELF note name and desc are 32-bits word padded. |
| 54 #define NOTE_PADDING(a) ((a + 3) & ~3) | 57 #define NOTE_PADDING(a) ((a + 3) & ~3) |
| 55 | 58 |
| 56 // These functions are also used inside the crashed process, so be safe | 59 // These functions are also used inside the crashed process, so be safe |
| 57 // and use the syscall/libc wrappers instead of direct syscalls or libc. | 60 // and use the syscall/libc wrappers instead of direct syscalls or libc. |
| 58 | 61 |
| 59 template<typename ElfClass> | 62 template<typename ElfClass> |
| 60 static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, | 63 static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, |
| 61 uint8_t identifier[kMDGUIDSize]) { | 64 uint8_t identifier[kMaxBuildID], |
| 65 size_t* identifier_length) { |
| 62 typedef typename ElfClass::Nhdr Nhdr; | 66 typedef typename ElfClass::Nhdr Nhdr; |
| 63 | 67 |
| 68 assert(identifier_length); |
| 69 |
| 64 const void* section_end = reinterpret_cast<const char*>(section) + length; | 70 const void* section_end = reinterpret_cast<const char*>(section) + length; |
| 65 const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section); | 71 const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section); |
| 66 while (reinterpret_cast<const void *>(note_header) < section_end) { | 72 while (reinterpret_cast<const void *>(note_header) < section_end) { |
| 67 if (note_header->n_type == NT_GNU_BUILD_ID) | 73 if (note_header->n_type == NT_GNU_BUILD_ID) |
| 68 break; | 74 break; |
| 69 note_header = reinterpret_cast<const Nhdr*>( | 75 note_header = reinterpret_cast<const Nhdr*>( |
| 70 reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) + | 76 reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) + |
| 71 NOTE_PADDING(note_header->n_namesz) + | 77 NOTE_PADDING(note_header->n_namesz) + |
| 72 NOTE_PADDING(note_header->n_descsz)); | 78 NOTE_PADDING(note_header->n_descsz)); |
| 73 } | 79 } |
| 74 if (reinterpret_cast<const void *>(note_header) >= section_end || | 80 if (reinterpret_cast<const void *>(note_header) >= section_end || |
| 75 note_header->n_descsz == 0) { | 81 note_header->n_descsz == 0) { |
| 76 return false; | 82 return false; |
| 77 } | 83 } |
| 78 | 84 |
| 79 const char* build_id = reinterpret_cast<const char*>(note_header) + | 85 const uint8_t* build_id = reinterpret_cast<const uint8_t*>(note_header) + |
| 80 sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz); | 86 sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz); |
| 81 // Copy as many bits of the build ID as will fit | 87 // Copy as many bits of the build ID as will fit |
| 82 // into the GUID space. | 88 // into |identifier|. This should always fit unless someone has |
| 83 my_memset(identifier, 0, kMDGUIDSize); | 89 // passed --build-id=0x... to the linker with a longer-than-standard |
| 84 memcpy(identifier, build_id, | 90 // hex string. |
| 85 std::min(kMDGUIDSize, (size_t)note_header->n_descsz)); | 91 my_memset(identifier, 0, kMaxBuildID); |
| 92 *identifier_length = std::min(kMaxBuildID, (size_t)note_header->n_descsz); |
| 93 memcpy(identifier, build_id, *identifier_length); |
| 86 | 94 |
| 87 return true; | 95 return true; |
| 88 } | 96 } |
| 89 | 97 |
| 90 // Attempt to locate a .note.gnu.build-id section in an ELF binary | 98 // Attempt to locate a .note.gnu.build-id section in an ELF binary |
| 91 // and copy as many bytes of it as will fit into |identifier|. | 99 // and copy as many bytes of it as will fit into |identifier|. |
| 100 // Set |*identifier_length| to the number of bytes copied. |
| 92 static bool FindElfBuildIDNote(const void *elf_mapped_base, | 101 static bool FindElfBuildIDNote(const void *elf_mapped_base, |
| 93 uint8_t identifier[kMDGUIDSize]) { | 102 uint8_t identifier[kMaxBuildID], |
| 103 size_t* identifier_length) { |
| 104 assert(identifier_length); |
| 94 void* note_section; | 105 void* note_section; |
| 95 size_t note_size; | 106 size_t note_size; |
| 96 int elfclass; | 107 int elfclass; |
| 97 if ((!FindElfSegment(elf_mapped_base, PT_NOTE, | 108 if ((!FindElfSegment(elf_mapped_base, PT_NOTE, |
| 98 (const void**)¬e_section, ¬e_size, &elfclass) || | 109 (const void**)¬e_section, ¬e_size, &elfclass) || |
| 99 note_size == 0) && | 110 note_size == 0) && |
| 100 (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, | 111 (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, |
| 101 (const void**)¬e_section, ¬e_size, &elfclass) || | 112 (const void**)¬e_section, ¬e_size, &elfclass) || |
| 102 note_size == 0)) { | 113 note_size == 0)) { |
| 103 return false; | 114 return false; |
| 104 } | 115 } |
| 105 | 116 |
| 106 if (elfclass == ELFCLASS32) { | 117 if (elfclass == ELFCLASS32) { |
| 107 return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size, | 118 return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size, |
| 108 identifier); | 119 identifier, |
| 120 identifier_length); |
| 109 } else if (elfclass == ELFCLASS64) { | 121 } else if (elfclass == ELFCLASS64) { |
| 110 return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size, | 122 return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size, |
| 111 identifier); | 123 identifier, |
| 124 identifier_length); |
| 112 } | 125 } |
| 113 | 126 |
| 114 return false; | 127 return false; |
| 115 } | 128 } |
| 116 | 129 |
| 117 // Attempt to locate the .text section of an ELF binary and generate | 130 // Attempt to locate the .text section of an ELF binary and generate |
| 118 // a simple hash by XORing the first page worth of bytes into |identifier|. | 131 // a simple hash by XORing the first page worth of bytes into |identifier|. |
| 119 static bool HashElfTextSection(const void *elf_mapped_base, | 132 static bool HashElfTextSection(const void *elf_mapped_base, |
| 120 uint8_t identifier[kMDGUIDSize]) { | 133 uint8_t identifier[kMaxBuildID], |
| 134 size_t* identifier_length) { |
| 135 assert(identifier_length); |
| 121 void* text_section; | 136 void* text_section; |
| 122 size_t text_size; | 137 size_t text_size; |
| 123 if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, | 138 if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, |
| 124 (const void**)&text_section, &text_size, NULL) || | 139 (const void**)&text_section, &text_size, NULL) || |
| 125 text_size == 0) { | 140 text_size == 0) { |
| 126 return false; | 141 return false; |
| 127 } | 142 } |
| 128 | 143 |
| 144 // Only provide |kMDGUIDSize| bytes to keep identifiers produced by this |
| 145 // function backwards-compatible. |
| 129 my_memset(identifier, 0, kMDGUIDSize); | 146 my_memset(identifier, 0, kMDGUIDSize); |
| 130 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section); | 147 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section); |
| 131 const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096)); | 148 const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096)); |
| 132 while (ptr < ptr_end) { | 149 while (ptr < ptr_end) { |
| 133 for (unsigned i = 0; i < kMDGUIDSize; i++) | 150 for (unsigned i = 0; i < kMDGUIDSize; i++) |
| 134 identifier[i] ^= ptr[i]; | 151 identifier[i] ^= ptr[i]; |
| 135 ptr += kMDGUIDSize; | 152 ptr += kMDGUIDSize; |
| 136 } | 153 } |
| 154 *identifier_length = kMDGUIDSize; |
| 137 return true; | 155 return true; |
| 138 } | 156 } |
| 139 | 157 |
| 140 // static | 158 // static |
| 141 bool FileID::ElfFileIdentifierFromMappedFile(const void* base, | 159 bool FileID::ElfFileIdentifierFromMappedFile(const void* base, |
| 142 uint8_t identifier[kMDGUIDSize]) { | 160 uint8_t identifier[kMaxBuildID], |
| 161 size_t* identifier_length) { |
| 143 // Look for a build id note first. | 162 // Look for a build id note first. |
| 144 if (FindElfBuildIDNote(base, identifier)) | 163 if (FindElfBuildIDNote(base, identifier, identifier_length)) |
| 145 return true; | 164 return true; |
| 146 | 165 |
| 147 // Fall back on hashing the first page of the text section. | 166 // Fall back on hashing the first page of the text section. |
| 148 return HashElfTextSection(base, identifier); | 167 return HashElfTextSection(base, identifier, identifier_length); |
| 149 } | 168 } |
| 150 | 169 |
| 151 bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) { | 170 bool FileID::ElfFileIdentifier(uint8_t identifier[kMaxBuildID], |
| 171 size_t* identifier_length) { |
| 152 MemoryMappedFile mapped_file(path_.c_str(), 0); | 172 MemoryMappedFile mapped_file(path_.c_str(), 0); |
| 153 if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? | 173 if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? |
| 154 return false; | 174 return false; |
| 155 | 175 |
| 156 return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); | 176 return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier, |
| 177 identifier_length); |
| 157 } | 178 } |
| 158 | 179 |
| 159 // static | 180 // static |
| 160 void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize], | 181 void FileID::ConvertIdentifierToString(const uint8_t identifier[kMaxBuildID], |
| 161 char* buffer, int buffer_length) { | 182 char* buffer, int buffer_length) { |
| 162 uint8_t identifier_swapped[kMDGUIDSize]; | 183 uint8_t identifier_swapped[kMDGUIDSize]; |
| 163 | 184 |
| 164 // Endian-ness swap to match dump processor expectation. | 185 // Endian-ness swap to match dump processor expectation. |
| 165 memcpy(identifier_swapped, identifier, kMDGUIDSize); | 186 memcpy(identifier_swapped, identifier, kMDGUIDSize); |
| 166 uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped); | 187 uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped); |
| 167 *data1 = htonl(*data1); | 188 *data1 = htonl(*data1); |
| 168 uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4); | 189 uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4); |
| 169 *data2 = htons(*data2); | 190 *data2 = htons(*data2); |
| 170 uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6); | 191 uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 182 | 203 |
| 183 buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; | 204 buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; |
| 184 buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; | 205 buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; |
| 185 } | 206 } |
| 186 | 207 |
| 187 // NULL terminate | 208 // NULL terminate |
| 188 buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; | 209 buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; |
| 189 } | 210 } |
| 190 | 211 |
| 191 } // namespace google_breakpad | 212 } // namespace google_breakpad |
| OLD | NEW |