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 |