Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(798)

Side by Side Diff: src/common/linux/file_id.cc

Issue 1688743002: Switch the Linux minidump writer to use MDCVInfoELF for CV data. (Closed) Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
Patch Set: Rework to handle arbitrary size build ids Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/common/linux/file_id.h ('k') | src/common/linux/file_id_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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**)&note_section, &note_size, &elfclass) || 102 (const void**)&note_section, &note_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**)&note_section, &note_size, &elfclass) || 105 (const void**)&note_section, &note_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
OLDNEW
« no previous file with comments | « src/common/linux/file_id.h ('k') | src/common/linux/file_id_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698