| 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 21 matching lines...) Expand all Loading... |
| 32 // See file_id.h for documentation | 32 // See file_id.h for documentation |
| 33 // | 33 // |
| 34 | 34 |
| 35 #include "common/linux/file_id.h" | 35 #include "common/linux/file_id.h" |
| 36 | 36 |
| 37 #include <arpa/inet.h> | 37 #include <arpa/inet.h> |
| 38 #include <assert.h> | 38 #include <assert.h> |
| 39 #include <string.h> | 39 #include <string.h> |
| 40 | 40 |
| 41 #include <algorithm> | 41 #include <algorithm> |
| 42 #include <string> |
| 42 | 43 |
| 43 #include "common/linux/elf_gnu_compat.h" | 44 #include "common/linux/elf_gnu_compat.h" |
| 44 #include "common/linux/elfutils.h" | 45 #include "common/linux/elfutils.h" |
| 45 #include "common/linux/linux_libc_support.h" | 46 #include "common/linux/linux_libc_support.h" |
| 46 #include "common/linux/memory_mapped_file.h" | 47 #include "common/linux/memory_mapped_file.h" |
| 47 #include "third_party/lss/linux_syscall_support.h" | 48 #include "third_party/lss/linux_syscall_support.h" |
| 48 | 49 |
| 50 using std::string; |
| 51 |
| 49 namespace google_breakpad { | 52 namespace google_breakpad { |
| 50 | 53 |
| 54 // Used in a few places for backwards-compatibility. |
| 55 const size_t kMDGUIDSize = sizeof(MDGUID); |
| 56 |
| 51 FileID::FileID(const char* path) : path_(path) {} | 57 FileID::FileID(const char* path) : path_(path) {} |
| 52 | 58 |
| 53 // ELF note name and desc are 32-bits word padded. | 59 // ELF note name and desc are 32-bits word padded. |
| 54 #define NOTE_PADDING(a) ((a + 3) & ~3) | 60 #define NOTE_PADDING(a) ((a + 3) & ~3) |
| 55 | 61 |
| 56 // These functions are also used inside the crashed process, so be safe | 62 // 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. | 63 // and use the syscall/libc wrappers instead of direct syscalls or libc. |
| 58 | 64 |
| 59 template<typename ElfClass> | 65 template<typename ElfClass> |
| 60 static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, | 66 static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, |
| 61 uint8_t identifier[kMDGUIDSize]) { | 67 wasteful_vector<uint8_t>& identifier)
{ |
| 62 typedef typename ElfClass::Nhdr Nhdr; | 68 typedef typename ElfClass::Nhdr Nhdr; |
| 63 | 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 identifier.insert(identifier.end(), |
| 82 // into the GUID space. | 88 build_id, |
| 83 my_memset(identifier, 0, kMDGUIDSize); | 89 build_id + note_header->n_descsz); |
| 84 memcpy(identifier, build_id, | |
| 85 std::min(kMDGUIDSize, (size_t)note_header->n_descsz)); | |
| 86 | 90 |
| 87 return true; | 91 return true; |
| 88 } | 92 } |
| 89 | 93 |
| 90 // Attempt to locate a .note.gnu.build-id section in an ELF binary | 94 // 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|. | 95 // and copy it into |identifier|. |
| 92 static bool FindElfBuildIDNote(const void *elf_mapped_base, | 96 static bool FindElfBuildIDNote(const void* elf_mapped_base, |
| 93 uint8_t identifier[kMDGUIDSize]) { | 97 wasteful_vector<uint8_t>& identifier) { |
| 94 void* note_section; | 98 void* note_section; |
| 95 size_t note_size; | 99 size_t note_size; |
| 96 int elfclass; | 100 int elfclass; |
| 97 if ((!FindElfSegment(elf_mapped_base, PT_NOTE, | 101 if ((!FindElfSegment(elf_mapped_base, PT_NOTE, |
| 98 (const void**)¬e_section, ¬e_size, &elfclass) || | 102 (const void**)¬e_section, ¬e_size, &elfclass) || |
| 99 note_size == 0) && | 103 note_size == 0) && |
| 100 (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, | 104 (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, |
| 101 (const void**)¬e_section, ¬e_size, &elfclass) || | 105 (const void**)¬e_section, ¬e_size, &elfclass) || |
| 102 note_size == 0)) { | 106 note_size == 0)) { |
| 103 return false; | 107 return false; |
| 104 } | 108 } |
| 105 | 109 |
| 106 if (elfclass == ELFCLASS32) { | 110 if (elfclass == ELFCLASS32) { |
| 107 return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size, | 111 return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size, |
| 108 identifier); | 112 identifier); |
| 109 } else if (elfclass == ELFCLASS64) { | 113 } else if (elfclass == ELFCLASS64) { |
| 110 return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size, | 114 return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size, |
| 111 identifier); | 115 identifier); |
| 112 } | 116 } |
| 113 | 117 |
| 114 return false; | 118 return false; |
| 115 } | 119 } |
| 116 | 120 |
| 117 // Attempt to locate the .text section of an ELF binary and generate | 121 // 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|. | 122 // a simple hash by XORing the first page worth of bytes into |identifier|. |
| 119 static bool HashElfTextSection(const void *elf_mapped_base, | 123 static bool HashElfTextSection(const void* elf_mapped_base, |
| 120 uint8_t identifier[kMDGUIDSize]) { | 124 wasteful_vector<uint8_t>& identifier) { |
| 125 identifier.resize(kMDGUIDSize); |
| 126 |
| 121 void* text_section; | 127 void* text_section; |
| 122 size_t text_size; | 128 size_t text_size; |
| 123 if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, | 129 if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, |
| 124 (const void**)&text_section, &text_size, NULL) || | 130 (const void**)&text_section, &text_size, NULL) || |
| 125 text_size == 0) { | 131 text_size == 0) { |
| 126 return false; | 132 return false; |
| 127 } | 133 } |
| 128 | 134 |
| 129 my_memset(identifier, 0, kMDGUIDSize); | 135 // Only provide |kMDGUIDSize| bytes to keep identifiers produced by this |
| 136 // function backwards-compatible. |
| 137 my_memset(&identifier[0], 0, kMDGUIDSize); |
| 130 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section); | 138 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)); | 139 const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096)); |
| 132 while (ptr < ptr_end) { | 140 while (ptr < ptr_end) { |
| 133 for (unsigned i = 0; i < kMDGUIDSize; i++) | 141 for (unsigned i = 0; i < kMDGUIDSize; i++) |
| 134 identifier[i] ^= ptr[i]; | 142 identifier[i] ^= ptr[i]; |
| 135 ptr += kMDGUIDSize; | 143 ptr += kMDGUIDSize; |
| 136 } | 144 } |
| 137 return true; | 145 return true; |
| 138 } | 146 } |
| 139 | 147 |
| 140 // static | 148 // static |
| 141 bool FileID::ElfFileIdentifierFromMappedFile(const void* base, | 149 bool FileID::ElfFileIdentifierFromMappedFile(const void* base, |
| 142 uint8_t identifier[kMDGUIDSize]) { | 150 wasteful_vector<uint8_t>& identifie
r) { |
| 143 // Look for a build id note first. | 151 // Look for a build id note first. |
| 144 if (FindElfBuildIDNote(base, identifier)) | 152 if (FindElfBuildIDNote(base, identifier)) |
| 145 return true; | 153 return true; |
| 146 | 154 |
| 147 // Fall back on hashing the first page of the text section. | 155 // Fall back on hashing the first page of the text section. |
| 148 return HashElfTextSection(base, identifier); | 156 return HashElfTextSection(base, identifier); |
| 149 } | 157 } |
| 150 | 158 |
| 151 bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) { | 159 bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) { |
| 152 MemoryMappedFile mapped_file(path_.c_str(), 0); | 160 MemoryMappedFile mapped_file(path_.c_str(), 0); |
| 153 if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? | 161 if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? |
| 154 return false; | 162 return false; |
| 155 | 163 |
| 156 return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); | 164 return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); |
| 157 } | 165 } |
| 158 | 166 |
| 167 // This function is not ever called in an unsafe context, so it's OK |
| 168 // to allocate memory and use libc. |
| 159 // static | 169 // static |
| 160 void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize], | 170 string FileID::ConvertIdentifierToUUIDString( |
| 161 char* buffer, int buffer_length) { | 171 const wasteful_vector<uint8_t>& identifier) { |
| 162 uint8_t identifier_swapped[kMDGUIDSize]; | 172 uint8_t identifier_swapped[kMDGUIDSize] = { 0 }; |
| 163 | 173 |
| 164 // Endian-ness swap to match dump processor expectation. | 174 // Endian-ness swap to match dump processor expectation. |
| 165 memcpy(identifier_swapped, identifier, kMDGUIDSize); | 175 memcpy(identifier_swapped, &identifier[0], |
| 176 std::min(kMDGUIDSize, identifier.size())); |
| 166 uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped); | 177 uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped); |
| 167 *data1 = htonl(*data1); | 178 *data1 = htonl(*data1); |
| 168 uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4); | 179 uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4); |
| 169 *data2 = htons(*data2); | 180 *data2 = htons(*data2); |
| 170 uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6); | 181 uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6); |
| 171 *data3 = htons(*data3); | 182 *data3 = htons(*data3); |
| 172 | 183 |
| 173 int buffer_idx = 0; | 184 string result; |
| 174 for (unsigned int idx = 0; | 185 for (unsigned int idx = 0; idx < kMDGUIDSize; ++idx) { |
| 175 (buffer_idx < buffer_length) && (idx < kMDGUIDSize); | 186 char buf[3]; |
| 176 ++idx) { | 187 snprintf(buf, sizeof(buf), "%02X", identifier_swapped[idx]); |
| 177 int hi = (identifier_swapped[idx] >> 4) & 0x0F; | 188 result.append(buf); |
| 178 int lo = (identifier_swapped[idx]) & 0x0F; | |
| 179 | |
| 180 if (idx == 4 || idx == 6 || idx == 8 || idx == 10) | |
| 181 buffer[buffer_idx++] = '-'; | |
| 182 | |
| 183 buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; | |
| 184 buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; | |
| 185 } | 189 } |
| 186 | 190 return result; |
| 187 // NULL terminate | |
| 188 buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; | |
| 189 } | 191 } |
| 190 | 192 |
| 191 } // namespace google_breakpad | 193 } // namespace google_breakpad |
| OLD | NEW |