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 |