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

Side by Side Diff: src/client/linux/minidump_writer/linux_dumper.cc

Issue 1761023002: Add an optional root prefix to Linux dumpers (Closed) Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
Patch Set: Remove assertions Created 4 years, 9 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
OLDNEW
1 // Copyright (c) 2010, Google Inc. 1 // Copyright (c) 2010, 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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 return my_strncmp(mapping.name, 81 return my_strncmp(mapping.name,
82 kMappedFileUnsafePrefix, 82 kMappedFileUnsafePrefix,
83 sizeof(kMappedFileUnsafePrefix) - 1) == 0; 83 sizeof(kMappedFileUnsafePrefix) - 1) == 0;
84 } 84 }
85 85
86 namespace google_breakpad { 86 namespace google_breakpad {
87 87
88 // All interesting auvx entry types are below AT_SYSINFO_EHDR 88 // All interesting auvx entry types are below AT_SYSINFO_EHDR
89 #define AT_MAX AT_SYSINFO_EHDR 89 #define AT_MAX AT_SYSINFO_EHDR
90 90
91 LinuxDumper::LinuxDumper(pid_t pid) 91 LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix)
92 : pid_(pid), 92 : pid_(pid),
93 root_prefix_(root_prefix),
93 crash_address_(0), 94 crash_address_(0),
94 crash_signal_(0), 95 crash_signal_(0),
95 crash_thread_(pid), 96 crash_thread_(pid),
96 threads_(&allocator_, 8), 97 threads_(&allocator_, 8),
97 mappings_(&allocator_), 98 mappings_(&allocator_),
98 auxv_(&allocator_, AT_MAX + 1) { 99 auxv_(&allocator_, AT_MAX + 1) {
100 assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX);
99 // The passed-in size to the constructor (above) is only a hint. 101 // The passed-in size to the constructor (above) is only a hint.
100 // Must call .resize() to do actual initialization of the elements. 102 // Must call .resize() to do actual initialization of the elements.
101 auxv_.resize(AT_MAX + 1); 103 auxv_.resize(AT_MAX + 1);
102 } 104 }
103 105
104 LinuxDumper::~LinuxDumper() { 106 LinuxDumper::~LinuxDumper() {
105 } 107 }
106 108
107 bool LinuxDumper::Init() { 109 bool LinuxDumper::Init() {
108 return ReadAuxv() && EnumerateThreads() && EnumerateMappings(); 110 return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
(...skipping 23 matching lines...) Expand all
132 linux_gate = reinterpret_cast<void*>(mapping.start_addr); 134 linux_gate = reinterpret_cast<void*>(mapping.start_addr);
133 } else { 135 } else {
134 linux_gate = allocator_.Alloc(mapping.size); 136 linux_gate = allocator_.Alloc(mapping.size);
135 CopyFromProcess(linux_gate, pid_, 137 CopyFromProcess(linux_gate, pid_,
136 reinterpret_cast<const void*>(mapping.start_addr), 138 reinterpret_cast<const void*>(mapping.start_addr),
137 mapping.size); 139 mapping.size);
138 } 140 }
139 return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier); 141 return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
140 } 142 }
141 143
142 char filename[NAME_MAX]; 144 char filename[PATH_MAX];
143 size_t filename_len = my_strlen(mapping.name); 145 if (!GetMappingAbsolutePath(mapping, filename))
144 if (filename_len >= NAME_MAX) {
145 assert(false);
146 return false; 146 return false;
147 }
148 my_memcpy(filename, mapping.name, filename_len);
149 filename[filename_len] = '\0';
150 bool filename_modified = HandleDeletedFileInMapping(filename); 147 bool filename_modified = HandleDeletedFileInMapping(filename);
151 148
152 MemoryMappedFile mapped_file(filename, mapping.offset); 149 MemoryMappedFile mapped_file(filename, mapping.offset);
153 if (!mapped_file.data() || mapped_file.size() < SELFMAG) 150 if (!mapped_file.data() || mapped_file.size() < SELFMAG)
154 return false; 151 return false;
155 152
156 bool success = 153 bool success =
157 FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); 154 FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
158 if (success && member && filename_modified) { 155 if (success && member && filename_modified) {
159 mappings_[mapping_id]->name[filename_len - 156 mappings_[mapping_id]->name[my_strlen(mapping.name) -
160 sizeof(kDeletedSuffix) + 1] = '\0'; 157 sizeof(kDeletedSuffix) + 1] = '\0';
161 } 158 }
162 159
163 return success; 160 return success;
164 } 161 }
165 162
163 bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
164 char path[PATH_MAX]) const {
165 return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
166 my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX;
167 }
168
166 namespace { 169 namespace {
167 bool ElfFileSoNameFromMappedFile( 170 bool ElfFileSoNameFromMappedFile(
168 const void* elf_base, char* soname, size_t soname_size) { 171 const void* elf_base, char* soname, size_t soname_size) {
169 if (!IsValidElf(elf_base)) { 172 if (!IsValidElf(elf_base)) {
170 // Not ELF 173 // Not ELF
171 return false; 174 return false;
172 } 175 }
173 176
174 const void* segment_start; 177 const void* segment_start;
175 size_t segment_size; 178 size_t segment_size;
(...skipping 29 matching lines...) Expand all
205 } 208 }
206 209
207 // Did not find SONAME 210 // Did not find SONAME
208 return false; 211 return false;
209 } 212 }
210 213
211 // Find the shared object name (SONAME) by examining the ELF information 214 // Find the shared object name (SONAME) by examining the ELF information
212 // for |mapping|. If the SONAME is found copy it into the passed buffer 215 // for |mapping|. If the SONAME is found copy it into the passed buffer
213 // |soname| and return true. The size of the buffer is |soname_size|. 216 // |soname| and return true. The size of the buffer is |soname_size|.
214 // The SONAME will be truncated if it is too long to fit in the buffer. 217 // The SONAME will be truncated if it is too long to fit in the buffer.
215 bool ElfFileSoName( 218 bool ElfFileSoName(const LinuxDumper& dumper,
216 const MappingInfo& mapping, char* soname, size_t soname_size) { 219 const MappingInfo& mapping, char* soname, size_t soname_size) {
217 if (IsMappedFileOpenUnsafe(mapping)) { 220 if (IsMappedFileOpenUnsafe(mapping)) {
218 // Not safe 221 // Not safe
219 return false; 222 return false;
220 } 223 }
221 224
222 char filename[NAME_MAX]; 225 char filename[PATH_MAX];
223 size_t filename_len = my_strlen(mapping.name); 226 if (!dumper.GetMappingAbsolutePath(mapping, filename))
224 if (filename_len >= NAME_MAX) {
225 assert(false);
226 // name too long
227 return false; 227 return false;
228 }
229
230 my_memcpy(filename, mapping.name, filename_len);
231 filename[filename_len] = '\0';
232 228
233 MemoryMappedFile mapped_file(filename, mapping.offset); 229 MemoryMappedFile mapped_file(filename, mapping.offset);
234 if (!mapped_file.data() || mapped_file.size() < SELFMAG) { 230 if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
235 // mmap failed 231 // mmap failed
236 return false; 232 return false;
237 } 233 }
238 234
239 return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); 235 return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
240 } 236 }
241 237
242 } // namespace 238 } // namespace
243 239
244 240
245 // static
246 void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, 241 void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
247 char* file_path, 242 char* file_path,
248 size_t file_path_size, 243 size_t file_path_size,
249 char* file_name, 244 char* file_name,
250 size_t file_name_size) { 245 size_t file_name_size) {
251 my_strlcpy(file_path, mapping.name, file_path_size); 246 my_strlcpy(file_path, mapping.name, file_path_size);
252 247
253 // If an executable is mapped from a non-zero offset, this is likely because 248 // If an executable is mapped from a non-zero offset, this is likely because
254 // the executable was loaded directly from inside an archive file (e.g., an 249 // the executable was loaded directly from inside an archive file (e.g., an
255 // apk on Android). We try to find the name of the shared object (SONAME) by 250 // apk on Android). We try to find the name of the shared object (SONAME) by
256 // looking in the file for ELF sections. 251 // looking in the file for ELF sections.
257 bool mapped_from_archive = false; 252 bool mapped_from_archive = false;
258 if (mapping.exec && mapping.offset != 0) 253 if (mapping.exec && mapping.offset != 0) {
259 mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size); 254 mapped_from_archive =
255 ElfFileSoName(*this, mapping, file_name, file_name_size);
256 }
260 257
261 if (mapped_from_archive) { 258 if (mapped_from_archive) {
262 // Some tools (e.g., stackwalk) extract the basename from the pathname. In 259 // Some tools (e.g., stackwalk) extract the basename from the pathname. In
263 // this case, we append the file_name to the mapped archive path as follows: 260 // this case, we append the file_name to the mapped archive path as follows:
264 // file_name := libname.so 261 // file_name := libname.so
265 // file_path := /path/to/ARCHIVE.APK/libname.so 262 // file_path := /path/to/ARCHIVE.APK/libname.so
266 if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { 263 if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
267 my_strlcat(file_path, "/", file_path_size); 264 my_strlcat(file_path, "/", file_path_size);
268 my_strlcat(file_path, file_name, file_path_size); 265 my_strlcat(file_path, file_name, file_path_size);
269 } 266 }
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 const size_t path_len = my_strlen(path); 570 const size_t path_len = my_strlen(path);
574 if (path_len < kDeletedSuffixLen + 2) 571 if (path_len < kDeletedSuffixLen + 2)
575 return false; 572 return false;
576 if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix, 573 if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
577 kDeletedSuffixLen) != 0) { 574 kDeletedSuffixLen) != 0) {
578 return false; 575 return false;
579 } 576 }
580 577
581 // Check |path| against the /proc/pid/exe 'symlink'. 578 // Check |path| against the /proc/pid/exe 'symlink'.
582 char exe_link[NAME_MAX]; 579 char exe_link[NAME_MAX];
583 char new_path[NAME_MAX];
584 if (!BuildProcPath(exe_link, pid_, "exe")) 580 if (!BuildProcPath(exe_link, pid_, "exe"))
585 return false; 581 return false;
586 if (!SafeReadLink(exe_link, new_path)) 582 MappingInfo new_mapping = {0};
583 if (!SafeReadLink(exe_link, new_mapping.name))
584 return false;
585 char new_path[PATH_MAX];
586 if (!GetMappingAbsolutePath(new_mapping, new_path))
587 return false; 587 return false;
588 if (my_strcmp(path, new_path) != 0) 588 if (my_strcmp(path, new_path) != 0)
589 return false; 589 return false;
590 590
591 // Check to see if someone actually named their executable 'foo (deleted)'. 591 // Check to see if someone actually named their executable 'foo (deleted)'.
592 struct kernel_stat exe_stat; 592 struct kernel_stat exe_stat;
593 struct kernel_stat new_path_stat; 593 struct kernel_stat new_path_stat;
594 if (sys_stat(exe_link, &exe_stat) == 0 && 594 if (sys_stat(exe_link, &exe_stat) == 0 &&
595 sys_stat(new_path, &new_path_stat) == 0 && 595 sys_stat(new_path, &new_path_stat) == 0 &&
596 exe_stat.st_dev == new_path_stat.st_dev && 596 exe_stat.st_dev == new_path_stat.st_dev &&
597 exe_stat.st_ino == new_path_stat.st_ino) { 597 exe_stat.st_ino == new_path_stat.st_ino) {
598 return false; 598 return false;
599 } 599 }
600 600
601 my_memcpy(path, exe_link, NAME_MAX); 601 my_memcpy(path, exe_link, NAME_MAX);
602 return true; 602 return true;
603 } 603 }
604 604
605 } // namespace google_breakpad 605 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « src/client/linux/minidump_writer/linux_dumper.h ('k') | src/client/linux/minidump_writer/minidump_writer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698