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

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: Address comments 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 assert(my_strlen(mapping.name) < NAME_MAX);
vapier 2016/03/07 16:32:37 why bother ? why does this matter at all ?
Dominik Laskowski 2016/03/07 18:36:21 It was just to preserve the assert, but I agree it
166 return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
167 my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX &&
168 (assert(my_strlen(path) < PATH_MAX), true);
vapier 2016/03/07 16:32:36 i don't see the point in this assert. we're alrea
Dominik Laskowski 2016/03/07 18:36:21 Removed. No real point other than paranoia about t
169 }
170
166 namespace { 171 namespace {
167 bool ElfFileSoNameFromMappedFile( 172 bool ElfFileSoNameFromMappedFile(
168 const void* elf_base, char* soname, size_t soname_size) { 173 const void* elf_base, char* soname, size_t soname_size) {
169 if (!IsValidElf(elf_base)) { 174 if (!IsValidElf(elf_base)) {
170 // Not ELF 175 // Not ELF
171 return false; 176 return false;
172 } 177 }
173 178
174 const void* segment_start; 179 const void* segment_start;
175 size_t segment_size; 180 size_t segment_size;
(...skipping 29 matching lines...) Expand all
205 } 210 }
206 211
207 // Did not find SONAME 212 // Did not find SONAME
208 return false; 213 return false;
209 } 214 }
210 215
211 // Find the shared object name (SONAME) by examining the ELF information 216 // 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 217 // 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|. 218 // |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. 219 // The SONAME will be truncated if it is too long to fit in the buffer.
215 bool ElfFileSoName( 220 bool ElfFileSoName(const LinuxDumper& dumper,
216 const MappingInfo& mapping, char* soname, size_t soname_size) { 221 const MappingInfo& mapping, char* soname, size_t soname_size) {
217 if (IsMappedFileOpenUnsafe(mapping)) { 222 if (IsMappedFileOpenUnsafe(mapping)) {
218 // Not safe 223 // Not safe
219 return false; 224 return false;
220 } 225 }
221 226
222 char filename[NAME_MAX]; 227 char filename[PATH_MAX];
223 size_t filename_len = my_strlen(mapping.name); 228 if (!dumper.GetMappingAbsolutePath(mapping, filename))
224 if (filename_len >= NAME_MAX) {
225 assert(false);
226 // name too long
227 return false; 229 return false;
228 }
229
230 my_memcpy(filename, mapping.name, filename_len);
231 filename[filename_len] = '\0';
232 230
233 MemoryMappedFile mapped_file(filename, mapping.offset); 231 MemoryMappedFile mapped_file(filename, mapping.offset);
234 if (!mapped_file.data() || mapped_file.size() < SELFMAG) { 232 if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
235 // mmap failed 233 // mmap failed
236 return false; 234 return false;
237 } 235 }
238 236
239 return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); 237 return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
240 } 238 }
241 239
242 } // namespace 240 } // namespace
243 241
244 242
245 // static
246 void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, 243 void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
247 char* file_path, 244 char* file_path,
248 size_t file_path_size, 245 size_t file_path_size,
249 char* file_name, 246 char* file_name,
250 size_t file_name_size) { 247 size_t file_name_size) {
251 my_strlcpy(file_path, mapping.name, file_path_size); 248 my_strlcpy(file_path, mapping.name, file_path_size);
252 249
253 // If an executable is mapped from a non-zero offset, this is likely because 250 // 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 251 // 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 252 // apk on Android). We try to find the name of the shared object (SONAME) by
256 // looking in the file for ELF sections. 253 // looking in the file for ELF sections.
257 bool mapped_from_archive = false; 254 bool mapped_from_archive = false;
258 if (mapping.exec && mapping.offset != 0) 255 if (mapping.exec && mapping.offset != 0) {
vapier 2016/03/07 16:32:37 these braces aren't needed
Dominik Laskowski 2016/03/07 18:36:21 True, but this file uses braces in most cases. See
259 mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size); 256 mapped_from_archive =
257 ElfFileSoName(*this, mapping, file_name, file_name_size);
258 }
260 259
261 if (mapped_from_archive) { 260 if (mapped_from_archive) {
262 // Some tools (e.g., stackwalk) extract the basename from the pathname. In 261 // 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: 262 // this case, we append the file_name to the mapped archive path as follows:
264 // file_name := libname.so 263 // file_name := libname.so
265 // file_path := /path/to/ARCHIVE.APK/libname.so 264 // file_path := /path/to/ARCHIVE.APK/libname.so
266 if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { 265 if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
267 my_strlcat(file_path, "/", file_path_size); 266 my_strlcat(file_path, "/", file_path_size);
268 my_strlcat(file_path, file_name, file_path_size); 267 my_strlcat(file_path, file_name, file_path_size);
269 } 268 }
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 const size_t path_len = my_strlen(path); 572 const size_t path_len = my_strlen(path);
574 if (path_len < kDeletedSuffixLen + 2) 573 if (path_len < kDeletedSuffixLen + 2)
575 return false; 574 return false;
576 if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix, 575 if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
577 kDeletedSuffixLen) != 0) { 576 kDeletedSuffixLen) != 0) {
578 return false; 577 return false;
579 } 578 }
580 579
581 // Check |path| against the /proc/pid/exe 'symlink'. 580 // Check |path| against the /proc/pid/exe 'symlink'.
582 char exe_link[NAME_MAX]; 581 char exe_link[NAME_MAX];
583 char new_path[NAME_MAX];
584 if (!BuildProcPath(exe_link, pid_, "exe")) 582 if (!BuildProcPath(exe_link, pid_, "exe"))
585 return false; 583 return false;
586 if (!SafeReadLink(exe_link, new_path)) 584 MappingInfo new_mapping = {0};
585 if (!SafeReadLink(exe_link, new_mapping.name))
586 return false;
587 char new_path[PATH_MAX];
588 if (!GetMappingAbsolutePath(new_mapping, new_path))
587 return false; 589 return false;
588 if (my_strcmp(path, new_path) != 0) 590 if (my_strcmp(path, new_path) != 0)
589 return false; 591 return false;
590 592
591 // Check to see if someone actually named their executable 'foo (deleted)'. 593 // Check to see if someone actually named their executable 'foo (deleted)'.
592 struct kernel_stat exe_stat; 594 struct kernel_stat exe_stat;
593 struct kernel_stat new_path_stat; 595 struct kernel_stat new_path_stat;
594 if (sys_stat(exe_link, &exe_stat) == 0 && 596 if (sys_stat(exe_link, &exe_stat) == 0 &&
595 sys_stat(new_path, &new_path_stat) == 0 && 597 sys_stat(new_path, &new_path_stat) == 0 &&
596 exe_stat.st_dev == new_path_stat.st_dev && 598 exe_stat.st_dev == new_path_stat.st_dev &&
597 exe_stat.st_ino == new_path_stat.st_ino) { 599 exe_stat.st_ino == new_path_stat.st_ino) {
598 return false; 600 return false;
599 } 601 }
600 602
601 my_memcpy(path, exe_link, NAME_MAX); 603 my_memcpy(path, exe_link, NAME_MAX);
602 return true; 604 return true;
603 } 605 }
604 606
605 } // namespace google_breakpad 607 } // 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