1 | // Copyright (c) 2010, Google Inc. |
2 | // All rights reserved. |
3 | // |
4 | // Redistribution and use in source and binary forms, with or without |
5 | // modification, are permitted provided that the following conditions are |
6 | // met: |
7 | // |
8 | // * Redistributions of source code must retain the above copyright |
9 | // notice, this list of conditions and the following disclaimer. |
10 | // * Redistributions in binary form must reproduce the above |
11 | // copyright notice, this list of conditions and the following disclaimer |
12 | // in the documentation and/or other materials provided with the |
13 | // distribution. |
14 | // * Neither the name of Google Inc. nor the names of its |
15 | // contributors may be used to endorse or promote products derived from |
16 | // this software without specific prior written permission. |
17 | // |
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | |
30 | // linux_dumper.cc: Implement google_breakpad::LinuxDumper. |
31 | // See linux_dumper.h for details. |
32 | |
33 | // This code deals with the mechanics of getting information about a crashed |
34 | // process. Since this code may run in a compromised address space, the same |
35 | // rules apply as detailed at the top of minidump_writer.h: no libc calls and |
36 | // use the alternative allocator. |
37 | |
38 | #include "client/linux/minidump_writer/linux_dumper.h" |
39 | |
40 | #include <assert.h> |
41 | #include <elf.h> |
42 | #include <fcntl.h> |
43 | #include <limits.h> |
44 | #include <stddef.h> |
45 | #include <string.h> |
46 | |
47 | #include "client/linux/minidump_writer/line_reader.h" |
48 | #include "common/linux/elfutils.h" |
49 | #include "common/linux/file_id.h" |
50 | #include "common/linux/linux_libc_support.h" |
51 | #include "common/linux/memory_mapped_file.h" |
52 | #include "common/linux/safe_readlink.h" |
53 | #include "google_breakpad/common/minidump_exception_linux.h" |
54 | #include "third_party/lss/linux_syscall_support.h" |
55 | |
56 | using google_breakpad::elf::FileID; |
57 | |
58 | #if defined(__ANDROID__) |
59 | |
60 | // Android packed relocations definitions are not yet available from the |
61 | // NDK header files, so we have to provide them manually here. |
62 | #ifndef DT_LOOS |
63 | #define DT_LOOS 0x6000000d |
64 | #endif |
65 | #ifndef DT_ANDROID_REL |
66 | static const int DT_ANDROID_REL = DT_LOOS + 2; |
67 | #endif |
68 | #ifndef DT_ANDROID_RELA |
69 | static const int DT_ANDROID_RELA = DT_LOOS + 4; |
70 | #endif |
71 | |
72 | #endif // __ANDROID __ |
73 | |
74 | static const char kMappedFileUnsafePrefix[] = "/dev/" ; |
75 | static const char kDeletedSuffix[] = " (deleted)" ; |
76 | |
77 | inline static bool IsMappedFileOpenUnsafe( |
78 | const google_breakpad::MappingInfo& mapping) { |
79 | // It is unsafe to attempt to open a mapped file that lives under /dev, |
80 | // because the semantics of the open may be driver-specific so we'd risk |
81 | // hanging the crash dumper. And a file in /dev/ almost certainly has no |
82 | // ELF file identifier anyways. |
83 | return my_strncmp(mapping.name, |
84 | kMappedFileUnsafePrefix, |
85 | sizeof(kMappedFileUnsafePrefix) - 1) == 0; |
86 | } |
87 | |
88 | namespace google_breakpad { |
89 | |
90 | namespace { |
91 | |
92 | bool MappingContainsAddress(const MappingInfo& mapping, uintptr_t address) { |
93 | return mapping.system_mapping_info.start_addr <= address && |
94 | address < mapping.system_mapping_info.end_addr; |
95 | } |
96 | |
97 | #if defined(__CHROMEOS__) |
98 | |
99 | // Recover memory mappings before writing dump on ChromeOS |
100 | // |
101 | // On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from |
102 | // addresses. ChromeOS' hugepage implementation replaces some segments with |
103 | // anonymous private pages, which is a restriction of current implementation |
104 | // in Linux kernel at the time of writing. Thus, breakpad can no longer |
105 | // symbolize addresses from those text segments replaced with hugepages. |
106 | // |
107 | // This postprocess tries to recover the mappings. Because hugepages are always |
108 | // inserted in between some .text sections, it tries to infer the names and |
109 | // offsets of the segments, by looking at segments immediately precede and |
110 | // succeed them. |
111 | // |
112 | // For example, a text segment before hugepage optimization |
113 | // 02001000-03002000 r-xp /opt/google/chrome/chrome |
114 | // |
115 | // can be broken into |
116 | // 02001000-02200000 r-xp /opt/google/chrome/chrome |
117 | // 02200000-03000000 r-xp |
118 | // 03000000-03002000 r-xp /opt/google/chrome/chrome |
119 | // |
120 | // For more details, see: |
121 | // crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization |
122 | |
123 | // Copied from CrOS' hugepage implementation, which is unlikely to change. |
124 | // The hugepage size is 2M. |
125 | const unsigned int kHpageShift = 21; |
126 | const size_t kHpageSize = (1 << kHpageShift); |
127 | const size_t kHpageMask = (~(kHpageSize - 1)); |
128 | |
129 | // Find and merge anonymous r-xp segments with surrounding named segments. |
130 | // There are two cases: |
131 | |
132 | // Case 1: curr, next |
133 | // curr is anonymous |
134 | // curr is r-xp |
135 | // curr.size >= 2M |
136 | // curr.size is a multiple of 2M. |
137 | // next is backed by some file. |
138 | // curr and next are contiguous. |
139 | // offset(next) == sizeof(curr) |
140 | void TryRecoverMappings(MappingInfo* curr, MappingInfo* next) { |
141 | // Merged segments are marked with size = 0. |
142 | if (curr->size == 0 || next->size == 0) |
143 | return; |
144 | |
145 | if (curr->size >= kHpageSize && |
146 | curr->exec && |
147 | (curr->size & kHpageMask) == curr->size && |
148 | (curr->start_addr & kHpageMask) == curr->start_addr && |
149 | curr->name[0] == '\0' && |
150 | next->name[0] != '\0' && |
151 | curr->start_addr + curr->size == next->start_addr && |
152 | curr->size == next->offset) { |
153 | |
154 | // matched |
155 | my_strlcpy(curr->name, next->name, NAME_MAX); |
156 | if (next->exec) { |
157 | // (curr, next) |
158 | curr->size += next->size; |
159 | next->size = 0; |
160 | } |
161 | } |
162 | } |
163 | |
164 | // Case 2: prev, curr, next |
165 | // curr is anonymous |
166 | // curr is r-xp |
167 | // curr.size >= 2M |
168 | // curr.size is a multiple of 2M. |
169 | // next and prev are backed by the same file. |
170 | // prev, curr and next are contiguous. |
171 | // offset(next) == offset(prev) + sizeof(prev) + sizeof(curr) |
172 | void TryRecoverMappings(MappingInfo* prev, MappingInfo* curr, |
173 | MappingInfo* next) { |
174 | // Merged segments are marked with size = 0. |
175 | if (prev->size == 0 || curr->size == 0 || next->size == 0) |
176 | return; |
177 | |
178 | if (curr->size >= kHpageSize && |
179 | curr->exec && |
180 | (curr->size & kHpageMask) == curr->size && |
181 | (curr->start_addr & kHpageMask) == curr->start_addr && |
182 | curr->name[0] == '\0' && |
183 | next->name[0] != '\0' && |
184 | curr->start_addr + curr->size == next->start_addr && |
185 | prev->start_addr + prev->size == curr->start_addr && |
186 | my_strncmp(prev->name, next->name, NAME_MAX) == 0 && |
187 | next->offset == prev->offset + prev->size + curr->size) { |
188 | |
189 | // matched |
190 | my_strlcpy(curr->name, prev->name, NAME_MAX); |
191 | if (prev->exec) { |
192 | curr->offset = prev->offset; |
193 | curr->start_addr = prev->start_addr; |
194 | if (next->exec) { |
195 | // (prev, curr, next) |
196 | curr->size += prev->size + next->size; |
197 | prev->size = 0; |
198 | next->size = 0; |
199 | } else { |
200 | // (prev, curr), next |
201 | curr->size += prev->size; |
202 | prev->size = 0; |
203 | } |
204 | } else { |
205 | curr->offset = prev->offset + prev->size; |
206 | if (next->exec) { |
207 | // prev, (curr, next) |
208 | curr->size += next->size; |
209 | next->size = 0; |
210 | } else { |
211 | // prev, curr, next |
212 | } |
213 | } |
214 | } |
215 | } |
216 | |
217 | // mappings_ is sorted excepted for the first entry. |
218 | // This function tries to merge segemnts into the first entry, |
219 | // then check for other sorted entries. |
220 | // See LinuxDumper::EnumerateMappings(). |
221 | void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) { |
222 | // Find the candidate "next" to first segment, which is the only one that |
223 | // could be out-of-order. |
224 | size_t l = 1; |
225 | size_t r = mappings.size(); |
226 | size_t next = mappings.size(); |
227 | while (l < r) { |
228 | int m = (l + r) / 2; |
229 | if (mappings[m]->start_addr > mappings[0]->start_addr) |
230 | r = next = m; |
231 | else |
232 | l = m + 1; |
233 | } |
234 | |
235 | // Shows the range that contains the entry point is |
236 | // [first_start_addr, first_end_addr) |
237 | size_t first_start_addr = mappings[0]->start_addr; |
238 | size_t first_end_addr = mappings[0]->start_addr + mappings[0]->size; |
239 | |
240 | // Put the out-of-order segment in order. |
241 | std::rotate(mappings.begin(), mappings.begin() + 1, mappings.begin() + next); |
242 | |
243 | // Iterate through normal, sorted cases. |
244 | // Normal case 1. |
245 | for (size_t i = 0; i < mappings.size() - 1; i++) |
246 | TryRecoverMappings(mappings[i], mappings[i + 1]); |
247 | |
248 | // Normal case 2. |
249 | for (size_t i = 0; i < mappings.size() - 2; i++) |
250 | TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]); |
251 | |
252 | // Collect merged (size == 0) segments. |
253 | size_t f, e; |
254 | for (f = e = 0; e < mappings.size(); e++) |
255 | if (mappings[e]->size > 0) |
256 | mappings[f++] = mappings[e]; |
257 | mappings.resize(f); |
258 | |
259 | // The entry point is in the first mapping. We want to find the location |
260 | // of the entry point after merging segment. To do this, we want to find |
261 | // the mapping that covers the first mapping from the original mapping list. |
262 | // If the mapping is not in the beginning, we move it to the begining via |
263 | // a right rotate by using reverse iterators. |
264 | for (l = 0; l < mappings.size(); l++) { |
265 | if (mappings[l]->start_addr <= first_start_addr |
266 | && (mappings[l]->start_addr + mappings[l]->size >= first_end_addr)) |
267 | break; |
268 | } |
269 | if (l > 0) { |
270 | r = mappings.size(); |
271 | std::rotate(mappings.rbegin() + r - l - 1, mappings.rbegin() + r - l, |
272 | mappings.rend()); |
273 | } |
274 | } |
275 | |
276 | #endif // __CHROMEOS__ |
277 | |
278 | } // namespace |
279 | |
280 | // All interesting auvx entry types are below AT_SYSINFO_EHDR |
281 | #define AT_MAX AT_SYSINFO_EHDR |
282 | |
283 | LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix) |
284 | : pid_(pid), |
285 | root_prefix_(root_prefix), |
286 | crash_address_(0), |
287 | crash_signal_(0), |
288 | crash_signal_code_(0), |
289 | crash_thread_(pid), |
290 | threads_(&allocator_, 8), |
291 | mappings_(&allocator_), |
292 | auxv_(&allocator_, AT_MAX + 1) { |
293 | assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX); |
294 | // The passed-in size to the constructor (above) is only a hint. |
295 | // Must call .resize() to do actual initialization of the elements. |
296 | auxv_.resize(AT_MAX + 1); |
297 | } |
298 | |
299 | LinuxDumper::~LinuxDumper() { |
300 | } |
301 | |
302 | bool LinuxDumper::Init() { |
303 | return ReadAuxv() && EnumerateThreads() && EnumerateMappings(); |
304 | } |
305 | |
306 | bool LinuxDumper::LateInit() { |
307 | #if defined(__ANDROID__) |
308 | LatePostprocessMappings(); |
309 | #endif |
310 | |
311 | #if defined(__CHROMEOS__) |
312 | CrOSPostProcessMappings(mappings_); |
313 | #endif |
314 | |
315 | return true; |
316 | } |
317 | |
318 | bool |
319 | LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, |
320 | bool member, |
321 | unsigned int mapping_id, |
322 | wasteful_vector<uint8_t>& identifier) { |
323 | assert(!member || mapping_id < mappings_.size()); |
324 | if (IsMappedFileOpenUnsafe(mapping)) |
325 | return false; |
326 | |
327 | // Special-case linux-gate because it's not a real file. |
328 | if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) { |
329 | void* linux_gate = NULL; |
330 | if (pid_ == sys_getpid()) { |
331 | linux_gate = reinterpret_cast<void*>(mapping.start_addr); |
332 | } else { |
333 | linux_gate = allocator_.Alloc(mapping.size); |
334 | CopyFromProcess(linux_gate, pid_, |
335 | reinterpret_cast<const void*>(mapping.start_addr), |
336 | mapping.size); |
337 | } |
338 | return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier); |
339 | } |
340 | |
341 | char filename[PATH_MAX]; |
342 | if (!GetMappingAbsolutePath(mapping, filename)) |
343 | return false; |
344 | bool filename_modified = HandleDeletedFileInMapping(filename); |
345 | |
346 | MemoryMappedFile mapped_file(filename, mapping.offset); |
347 | if (!mapped_file.data() || mapped_file.size() < SELFMAG) |
348 | return false; |
349 | |
350 | bool success = |
351 | FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); |
352 | if (success && member && filename_modified) { |
353 | mappings_[mapping_id]->name[my_strlen(mapping.name) - |
354 | sizeof(kDeletedSuffix) + 1] = '\0'; |
355 | } |
356 | |
357 | return success; |
358 | } |
359 | |
360 | void LinuxDumper::SetCrashInfoFromSigInfo(const siginfo_t& siginfo) { |
361 | set_crash_address(reinterpret_cast<uintptr_t>(siginfo.si_addr)); |
362 | set_crash_signal(siginfo.si_signo); |
363 | set_crash_signal_code(siginfo.si_code); |
364 | } |
365 | |
366 | const char* LinuxDumper::GetCrashSignalString() const { |
367 | switch (static_cast<unsigned int>(crash_signal_)) { |
368 | case MD_EXCEPTION_CODE_LIN_SIGHUP: |
369 | return "SIGHUP" ; |
370 | case MD_EXCEPTION_CODE_LIN_SIGINT: |
371 | return "SIGINT" ; |
372 | case MD_EXCEPTION_CODE_LIN_SIGQUIT: |
373 | return "SIGQUIT" ; |
374 | case MD_EXCEPTION_CODE_LIN_SIGILL: |
375 | return "SIGILL" ; |
376 | case MD_EXCEPTION_CODE_LIN_SIGTRAP: |
377 | return "SIGTRAP" ; |
378 | case MD_EXCEPTION_CODE_LIN_SIGABRT: |
379 | return "SIGABRT" ; |
380 | case MD_EXCEPTION_CODE_LIN_SIGBUS: |
381 | return "SIGBUS" ; |
382 | case MD_EXCEPTION_CODE_LIN_SIGFPE: |
383 | return "SIGFPE" ; |
384 | case MD_EXCEPTION_CODE_LIN_SIGKILL: |
385 | return "SIGKILL" ; |
386 | case MD_EXCEPTION_CODE_LIN_SIGUSR1: |
387 | return "SIGUSR1" ; |
388 | case MD_EXCEPTION_CODE_LIN_SIGSEGV: |
389 | return "SIGSEGV" ; |
390 | case MD_EXCEPTION_CODE_LIN_SIGUSR2: |
391 | return "SIGUSR2" ; |
392 | case MD_EXCEPTION_CODE_LIN_SIGPIPE: |
393 | return "SIGPIPE" ; |
394 | case MD_EXCEPTION_CODE_LIN_SIGALRM: |
395 | return "SIGALRM" ; |
396 | case MD_EXCEPTION_CODE_LIN_SIGTERM: |
397 | return "SIGTERM" ; |
398 | case MD_EXCEPTION_CODE_LIN_SIGSTKFLT: |
399 | return "SIGSTKFLT" ; |
400 | case MD_EXCEPTION_CODE_LIN_SIGCHLD: |
401 | return "SIGCHLD" ; |
402 | case MD_EXCEPTION_CODE_LIN_SIGCONT: |
403 | return "SIGCONT" ; |
404 | case MD_EXCEPTION_CODE_LIN_SIGSTOP: |
405 | return "SIGSTOP" ; |
406 | case MD_EXCEPTION_CODE_LIN_SIGTSTP: |
407 | return "SIGTSTP" ; |
408 | case MD_EXCEPTION_CODE_LIN_SIGTTIN: |
409 | return "SIGTTIN" ; |
410 | case MD_EXCEPTION_CODE_LIN_SIGTTOU: |
411 | return "SIGTTOU" ; |
412 | case MD_EXCEPTION_CODE_LIN_SIGURG: |
413 | return "SIGURG" ; |
414 | case MD_EXCEPTION_CODE_LIN_SIGXCPU: |
415 | return "SIGXCPU" ; |
416 | case MD_EXCEPTION_CODE_LIN_SIGXFSZ: |
417 | return "SIGXFSZ" ; |
418 | case MD_EXCEPTION_CODE_LIN_SIGVTALRM: |
419 | return "SIGVTALRM" ; |
420 | case MD_EXCEPTION_CODE_LIN_SIGPROF: |
421 | return "SIGPROF" ; |
422 | case MD_EXCEPTION_CODE_LIN_SIGWINCH: |
423 | return "SIGWINCH" ; |
424 | case MD_EXCEPTION_CODE_LIN_SIGIO: |
425 | return "SIGIO" ; |
426 | case MD_EXCEPTION_CODE_LIN_SIGPWR: |
427 | return "SIGPWR" ; |
428 | case MD_EXCEPTION_CODE_LIN_SIGSYS: |
429 | return "SIGSYS" ; |
430 | case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: |
431 | return "DUMP_REQUESTED" ; |
432 | default: |
433 | return "UNKNOWN" ; |
434 | } |
435 | } |
436 | |
437 | bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping, |
438 | char path[PATH_MAX]) const { |
439 | return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX && |
440 | my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX; |
441 | } |
442 | |
443 | namespace { |
444 | // Find the shared object name (SONAME) by examining the ELF information |
445 | // for |mapping|. If the SONAME is found copy it into the passed buffer |
446 | // |soname| and return true. The size of the buffer is |soname_size|. |
447 | // The SONAME will be truncated if it is too long to fit in the buffer. |
448 | bool ElfFileSoName(const LinuxDumper& dumper, |
449 | const MappingInfo& mapping, char* soname, size_t soname_size) { |
450 | if (IsMappedFileOpenUnsafe(mapping)) { |
451 | // Not safe |
452 | return false; |
453 | } |
454 | |
455 | char filename[PATH_MAX]; |
456 | if (!dumper.GetMappingAbsolutePath(mapping, filename)) |
457 | return false; |
458 | |
459 | MemoryMappedFile mapped_file(filename, mapping.offset); |
460 | if (!mapped_file.data() || mapped_file.size() < SELFMAG) { |
461 | // mmap failed |
462 | return false; |
463 | } |
464 | |
465 | return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); |
466 | } |
467 | |
468 | } // namespace |
469 | |
470 | |
471 | void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, |
472 | char* file_path, |
473 | size_t file_path_size, |
474 | char* file_name, |
475 | size_t file_name_size) { |
476 | my_strlcpy(file_path, mapping.name, file_path_size); |
477 | |
478 | // Tools such as minidump_stackwalk use the name of the module to look up |
479 | // symbols produced by dump_syms. dump_syms will prefer to use a module's |
480 | // DT_SONAME as the module name, if one exists, and will fall back to the |
481 | // filesystem name of the module. |
482 | |
483 | // Just use the filesystem name if no SONAME is present. |
484 | if (!ElfFileSoName(*this, mapping, file_name, file_name_size)) { |
485 | // file_path := /path/to/libname.so |
486 | // file_name := libname.so |
487 | const char* basename = my_strrchr(file_path, '/'); |
488 | basename = basename == NULL ? file_path : (basename + 1); |
489 | my_strlcpy(file_name, basename, file_name_size); |
490 | return; |
491 | } |
492 | |
493 | if (mapping.exec && mapping.offset != 0) { |
494 | // If an executable is mapped from a non-zero offset, this is likely because |
495 | // the executable was loaded directly from inside an archive file (e.g., an |
496 | // apk on Android). |
497 | // In this case, we append the file_name to the mapped archive path: |
498 | // file_name := libname.so |
499 | // file_path := /path/to/ARCHIVE.APK/libname.so |
500 | if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { |
501 | my_strlcat(file_path, "/" , file_path_size); |
502 | my_strlcat(file_path, file_name, file_path_size); |
503 | } |
504 | } else { |
505 | // Otherwise, replace the basename with the SONAME. |
506 | char* basename = const_cast<char*>(my_strrchr(file_path, '/')); |
507 | if (basename) { |
508 | my_strlcpy(basename + 1, file_name, |
509 | file_path_size - my_strlen(file_path) + |
510 | my_strlen(basename + 1)); |
511 | } else { |
512 | my_strlcpy(file_path, file_name, file_path_size); |
513 | } |
514 | } |
515 | } |
516 | |
517 | bool LinuxDumper::ReadAuxv() { |
518 | char auxv_path[NAME_MAX]; |
519 | if (!BuildProcPath(auxv_path, pid_, "auxv" )) { |
520 | return false; |
521 | } |
522 | |
523 | int fd = sys_open(auxv_path, O_RDONLY, 0); |
524 | if (fd < 0) { |
525 | return false; |
526 | } |
527 | |
528 | elf_aux_entry one_aux_entry; |
529 | bool res = false; |
530 | while (sys_read(fd, |
531 | &one_aux_entry, |
532 | sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) && |
533 | one_aux_entry.a_type != AT_NULL) { |
534 | if (one_aux_entry.a_type <= AT_MAX) { |
535 | auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val; |
536 | res = true; |
537 | } |
538 | } |
539 | sys_close(fd); |
540 | return res; |
541 | } |
542 | |
543 | bool LinuxDumper::EnumerateMappings() { |
544 | char maps_path[NAME_MAX]; |
545 | if (!BuildProcPath(maps_path, pid_, "maps" )) |
546 | return false; |
547 | |
548 | // linux_gate_loc is the beginning of the kernel's mapping of |
549 | // linux-gate.so in the process. It doesn't actually show up in the |
550 | // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR |
551 | // aux vector entry, which gives the information necessary to special |
552 | // case its entry when creating the list of mappings. |
553 | // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more |
554 | // information. |
555 | const void* linux_gate_loc = |
556 | reinterpret_cast<void*>(auxv_[AT_SYSINFO_EHDR]); |
557 | // Although the initial executable is usually the first mapping, it's not |
558 | // guaranteed (see http://crosbug.com/25355); therefore, try to use the |
559 | // actual entry point to find the mapping. |
560 | const void* entry_point_loc = reinterpret_cast<void*>(auxv_[AT_ENTRY]); |
561 | |
562 | const int fd = sys_open(maps_path, O_RDONLY, 0); |
563 | if (fd < 0) |
564 | return false; |
565 | LineReader* const line_reader = new(allocator_) LineReader(fd); |
566 | |
567 | const char* line; |
568 | unsigned line_len; |
569 | while (line_reader->GetNextLine(&line, &line_len)) { |
570 | uintptr_t start_addr, end_addr, offset; |
571 | |
572 | const char* i1 = my_read_hex_ptr(&start_addr, line); |
573 | if (*i1 == '-') { |
574 | const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1); |
575 | if (*i2 == ' ') { |
576 | bool exec = (*(i2 + 3) == 'x'); |
577 | const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); |
578 | if (*i3 == ' ') { |
579 | const char* name = NULL; |
580 | // Only copy name if the name is a valid path name, or if |
581 | // it's the VDSO image. |
582 | if (((name = my_strchr(line, '/')) == NULL) && |
583 | linux_gate_loc && |
584 | reinterpret_cast<void*>(start_addr) == linux_gate_loc) { |
585 | name = kLinuxGateLibraryName; |
586 | offset = 0; |
587 | } |
588 | // Merge adjacent mappings into one module, assuming they're a single |
589 | // library mapped by the dynamic linker. Do this only if their name |
590 | // matches and either they have the same +x protection flag, or if the |
591 | // previous mapping is not executable and the new one is, to handle |
592 | // lld's output (see crbug.com/716484). |
593 | if (name && !mappings_.empty()) { |
594 | MappingInfo* module = mappings_.back(); |
595 | if ((start_addr == module->start_addr + module->size) && |
596 | (my_strlen(name) == my_strlen(module->name)) && |
597 | (my_strncmp(name, module->name, my_strlen(name)) == 0) && |
598 | ((exec == module->exec) || (!module->exec && exec))) { |
599 | module->system_mapping_info.end_addr = end_addr; |
600 | module->size = end_addr - module->start_addr; |
601 | module->exec |= exec; |
602 | line_reader->PopLine(line_len); |
603 | continue; |
604 | } |
605 | } |
606 | MappingInfo* const module = new(allocator_) MappingInfo; |
607 | mappings_.push_back(module); |
608 | my_memset(module, 0, sizeof(MappingInfo)); |
609 | module->system_mapping_info.start_addr = start_addr; |
610 | module->system_mapping_info.end_addr = end_addr; |
611 | module->start_addr = start_addr; |
612 | module->size = end_addr - start_addr; |
613 | module->offset = offset; |
614 | module->exec = exec; |
615 | if (name != NULL) { |
616 | const unsigned l = my_strlen(name); |
617 | if (l < sizeof(module->name)) |
618 | my_memcpy(module->name, name, l); |
619 | } |
620 | } |
621 | } |
622 | } |
623 | line_reader->PopLine(line_len); |
624 | } |
625 | |
626 | if (entry_point_loc) { |
627 | for (size_t i = 0; i < mappings_.size(); ++i) { |
628 | MappingInfo* module = mappings_[i]; |
629 | |
630 | // If this module contains the entry-point, and it's not already the first |
631 | // one, then we need to make it be first. This is because the minidump |
632 | // format assumes the first module is the one that corresponds to the main |
633 | // executable (as codified in |
634 | // processor/minidump.cc:MinidumpModuleList::GetMainModule()). |
635 | if ((entry_point_loc >= reinterpret_cast<void*>(module->start_addr)) && |
636 | (entry_point_loc < |
637 | reinterpret_cast<void*>(module->start_addr + module->size))) { |
638 | for (size_t j = i; j > 0; j--) |
639 | mappings_[j] = mappings_[j - 1]; |
640 | mappings_[0] = module; |
641 | break; |
642 | } |
643 | } |
644 | } |
645 | |
646 | sys_close(fd); |
647 | |
648 | return !mappings_.empty(); |
649 | } |
650 | |
651 | #if defined(__ANDROID__) |
652 | |
653 | bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) { |
654 | CopyFromProcess(ehdr, pid_, |
655 | reinterpret_cast<const void*>(start_addr), |
656 | sizeof(*ehdr)); |
657 | return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0; |
658 | } |
659 | |
660 | void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, |
661 | uintptr_t start_addr, |
662 | uintptr_t* min_vaddr_ptr, |
663 | uintptr_t* dyn_vaddr_ptr, |
664 | size_t* dyn_count_ptr) { |
665 | uintptr_t phdr_addr = start_addr + ehdr->e_phoff; |
666 | |
667 | const uintptr_t max_addr = UINTPTR_MAX; |
668 | uintptr_t min_vaddr = max_addr; |
669 | uintptr_t dyn_vaddr = 0; |
670 | size_t dyn_count = 0; |
671 | |
672 | for (size_t i = 0; i < ehdr->e_phnum; ++i) { |
673 | ElfW(Phdr) phdr; |
674 | CopyFromProcess(&phdr, pid_, |
675 | reinterpret_cast<const void*>(phdr_addr), |
676 | sizeof(phdr)); |
677 | if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) { |
678 | min_vaddr = phdr.p_vaddr; |
679 | } |
680 | if (phdr.p_type == PT_DYNAMIC) { |
681 | dyn_vaddr = phdr.p_vaddr; |
682 | dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn)); |
683 | } |
684 | phdr_addr += sizeof(phdr); |
685 | } |
686 | |
687 | *min_vaddr_ptr = min_vaddr; |
688 | *dyn_vaddr_ptr = dyn_vaddr; |
689 | *dyn_count_ptr = dyn_count; |
690 | } |
691 | |
692 | bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias, |
693 | uintptr_t dyn_vaddr, |
694 | size_t dyn_count) { |
695 | uintptr_t dyn_addr = load_bias + dyn_vaddr; |
696 | for (size_t i = 0; i < dyn_count; ++i) { |
697 | ElfW(Dyn) dyn; |
698 | CopyFromProcess(&dyn, pid_, |
699 | reinterpret_cast<const void*>(dyn_addr), |
700 | sizeof(dyn)); |
701 | if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) { |
702 | return true; |
703 | } |
704 | dyn_addr += sizeof(dyn); |
705 | } |
706 | return false; |
707 | } |
708 | |
709 | uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, |
710 | uintptr_t start_addr) { |
711 | uintptr_t min_vaddr = 0; |
712 | uintptr_t dyn_vaddr = 0; |
713 | size_t dyn_count = 0; |
714 | ParseLoadedElfProgramHeaders(ehdr, start_addr, |
715 | &min_vaddr, &dyn_vaddr, &dyn_count); |
716 | // If |min_vaddr| is non-zero and we find Android packed relocation tags, |
717 | // return the effective load bias. |
718 | if (min_vaddr != 0) { |
719 | const uintptr_t load_bias = start_addr - min_vaddr; |
720 | if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) { |
721 | return load_bias; |
722 | } |
723 | } |
724 | // Either |min_vaddr| is zero, or it is non-zero but we did not find the |
725 | // expected Android packed relocations tags. |
726 | return start_addr; |
727 | } |
728 | |
729 | void LinuxDumper::LatePostprocessMappings() { |
730 | for (size_t i = 0; i < mappings_.size(); ++i) { |
731 | // Only consider exec mappings that indicate a file path was mapped, and |
732 | // where the ELF header indicates a mapped shared library. |
733 | MappingInfo* mapping = mappings_[i]; |
734 | if (!(mapping->exec && mapping->name[0] == '/')) { |
735 | continue; |
736 | } |
737 | ElfW(Ehdr) ehdr; |
738 | if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) { |
739 | continue; |
740 | } |
741 | if (ehdr.e_type == ET_DYN) { |
742 | // Compute the effective load bias for this mapped library, and update |
743 | // the mapping to hold that rather than |start_addr|, at the same time |
744 | // adjusting |size| to account for the change in |start_addr|. Where |
745 | // the library does not contain Android packed relocations, |
746 | // GetEffectiveLoadBias() returns |start_addr| and the mapping entry |
747 | // is not changed. |
748 | const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr, |
749 | mapping->start_addr); |
750 | mapping->size += mapping->start_addr - load_bias; |
751 | mapping->start_addr = load_bias; |
752 | } |
753 | } |
754 | } |
755 | |
756 | #endif // __ANDROID__ |
757 | |
758 | // Get information about the stack, given the stack pointer. We don't try to |
759 | // walk the stack since we might not have all the information needed to do |
760 | // unwind. So we just grab, up to, 32k of stack. |
761 | bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, |
762 | uintptr_t int_stack_pointer) { |
763 | // Move the stack pointer to the bottom of the page that it's in. |
764 | const uintptr_t page_size = getpagesize(); |
765 | |
766 | uint8_t* const stack_pointer = |
767 | reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); |
768 | |
769 | // The number of bytes of stack which we try to capture. |
770 | static const ptrdiff_t kStackToCapture = 32 * 1024; |
771 | |
772 | const MappingInfo* mapping = FindMapping(stack_pointer); |
773 | if (!mapping) |
774 | return false; |
775 | const ptrdiff_t offset = stack_pointer - |
776 | reinterpret_cast<uint8_t*>(mapping->start_addr); |
777 | const ptrdiff_t distance_to_end = |
778 | static_cast<ptrdiff_t>(mapping->size) - offset; |
779 | *stack_len = distance_to_end > kStackToCapture ? |
780 | kStackToCapture : distance_to_end; |
781 | *stack = stack_pointer; |
782 | return true; |
783 | } |
784 | |
785 | void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len, |
786 | uintptr_t stack_pointer, |
787 | uintptr_t sp_offset) { |
788 | // We optimize the search for containing mappings in three ways: |
789 | // 1) We expect that pointers into the stack mapping will be common, so |
790 | // we cache that address range. |
791 | // 2) The last referenced mapping is a reasonable predictor for the next |
792 | // referenced mapping, so we test that first. |
793 | // 3) We precompute a bitfield based upon bits 32:32-n of the start and |
794 | // stop addresses, and use that to short circuit any values that can |
795 | // not be pointers. (n=11) |
796 | const uintptr_t defaced = |
797 | #if defined(__LP64__) |
798 | 0x0defaced0defaced; |
799 | #else |
800 | 0x0defaced; |
801 | #endif |
802 | // the bitfield length is 2^test_bits long. |
803 | const unsigned int test_bits = 11; |
804 | // byte length of the corresponding array. |
805 | const unsigned int array_size = 1 << (test_bits - 3); |
806 | const unsigned int array_mask = array_size - 1; |
807 | // The amount to right shift pointers by. This captures the top bits |
808 | // on 32 bit architectures. On 64 bit architectures this would be |
809 | // uninformative so we take the same range of bits. |
810 | const unsigned int shift = 32 - 11; |
811 | const MappingInfo* last_hit_mapping = nullptr; |
812 | const MappingInfo* hit_mapping = nullptr; |
813 | const MappingInfo* stack_mapping = FindMappingNoBias(stack_pointer); |
814 | // The magnitude below which integers are considered to be to be |
815 | // 'small', and not constitute a PII risk. These are included to |
816 | // avoid eliding useful register values. |
817 | const ssize_t small_int_magnitude = 4096; |
818 | |
819 | char could_hit_mapping[array_size]; |
820 | my_memset(could_hit_mapping, 0, array_size); |
821 | |
822 | // Initialize the bitfield such that if the (pointer >> shift)'th |
823 | // bit, modulo the bitfield size, is not set then there does not |
824 | // exist a mapping in mappings_ that would contain that pointer. |
825 | for (size_t i = 0; i < mappings_.size(); ++i) { |
826 | if (!mappings_[i]->exec) continue; |
827 | // For each mapping, work out the (unmodulo'ed) range of bits to |
828 | // set. |
829 | uintptr_t start = mappings_[i]->start_addr; |
830 | uintptr_t end = start + mappings_[i]->size; |
831 | start >>= shift; |
832 | end >>= shift; |
833 | for (size_t bit = start; bit <= end; ++bit) { |
834 | // Set each bit in the range, applying the modulus. |
835 | could_hit_mapping[(bit >> 3) & array_mask] |= 1 << (bit & 7); |
836 | } |
837 | } |
838 | |
839 | // Zero memory that is below the current stack pointer. |
840 | const uintptr_t offset = |
841 | (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); |
842 | if (offset) { |
843 | my_memset(stack_copy, 0, offset); |
844 | } |
845 | |
846 | // Apply sanitization to each complete pointer-aligned word in the |
847 | // stack. |
848 | uint8_t* sp; |
849 | for (sp = stack_copy + offset; |
850 | sp <= stack_copy + stack_len - sizeof(uintptr_t); |
851 | sp += sizeof(uintptr_t)) { |
852 | uintptr_t addr; |
853 | my_memcpy(&addr, sp, sizeof(uintptr_t)); |
854 | if (static_cast<intptr_t>(addr) <= small_int_magnitude && |
855 | static_cast<intptr_t>(addr) >= -small_int_magnitude) { |
856 | continue; |
857 | } |
858 | if (stack_mapping && MappingContainsAddress(*stack_mapping, addr)) { |
859 | continue; |
860 | } |
861 | if (last_hit_mapping && MappingContainsAddress(*last_hit_mapping, addr)) { |
862 | continue; |
863 | } |
864 | uintptr_t test = addr >> shift; |
865 | if (could_hit_mapping[(test >> 3) & array_mask] & (1 << (test & 7)) && |
866 | (hit_mapping = FindMappingNoBias(addr)) != nullptr && |
867 | hit_mapping->exec) { |
868 | last_hit_mapping = hit_mapping; |
869 | continue; |
870 | } |
871 | my_memcpy(sp, &defaced, sizeof(uintptr_t)); |
872 | } |
873 | // Zero any partial word at the top of the stack, if alignment is |
874 | // such that that is required. |
875 | if (sp < stack_copy + stack_len) { |
876 | my_memset(sp, 0, stack_copy + stack_len - sp); |
877 | } |
878 | } |
879 | |
880 | bool LinuxDumper::StackHasPointerToMapping(const uint8_t* stack_copy, |
881 | size_t stack_len, |
882 | uintptr_t sp_offset, |
883 | const MappingInfo& mapping) { |
884 | // Loop over all stack words that would have been on the stack in |
885 | // the target process (i.e. are word aligned, and at addresses >= |
886 | // the stack pointer). Regardless of the alignment of |stack_copy|, |
887 | // the memory starting at |stack_copy| + |offset| represents an |
888 | // aligned word in the target process. |
889 | const uintptr_t low_addr = mapping.system_mapping_info.start_addr; |
890 | const uintptr_t high_addr = mapping.system_mapping_info.end_addr; |
891 | const uintptr_t offset = |
892 | (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); |
893 | |
894 | for (const uint8_t* sp = stack_copy + offset; |
895 | sp <= stack_copy + stack_len - sizeof(uintptr_t); |
896 | sp += sizeof(uintptr_t)) { |
897 | uintptr_t addr; |
898 | my_memcpy(&addr, sp, sizeof(uintptr_t)); |
899 | if (low_addr <= addr && addr <= high_addr) |
900 | return true; |
901 | } |
902 | return false; |
903 | } |
904 | |
905 | // Find the mapping which the given memory address falls in. |
906 | const MappingInfo* LinuxDumper::FindMapping(const void* address) const { |
907 | const uintptr_t addr = (uintptr_t) address; |
908 | |
909 | for (size_t i = 0; i < mappings_.size(); ++i) { |
910 | const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr); |
911 | if (addr >= start && addr - start < mappings_[i]->size) |
912 | return mappings_[i]; |
913 | } |
914 | |
915 | return NULL; |
916 | } |
917 | |
918 | // Find the mapping which the given memory address falls in. Uses the |
919 | // unadjusted mapping address range from the kernel, rather than the |
920 | // biased range. |
921 | const MappingInfo* LinuxDumper::FindMappingNoBias(uintptr_t address) const { |
922 | for (size_t i = 0; i < mappings_.size(); ++i) { |
923 | if (address >= mappings_[i]->system_mapping_info.start_addr && |
924 | address < mappings_[i]->system_mapping_info.end_addr) { |
925 | return mappings_[i]; |
926 | } |
927 | } |
928 | return NULL; |
929 | } |
930 | |
931 | bool LinuxDumper::HandleDeletedFileInMapping(char* path) const { |
932 | static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1; |
933 | |
934 | // Check for ' (deleted)' in |path|. |
935 | // |path| has to be at least as long as "/x (deleted)". |
936 | const size_t path_len = my_strlen(path); |
937 | if (path_len < kDeletedSuffixLen + 2) |
938 | return false; |
939 | if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix, |
940 | kDeletedSuffixLen) != 0) { |
941 | return false; |
942 | } |
943 | |
944 | // Check |path| against the /proc/pid/exe 'symlink'. |
945 | char exe_link[NAME_MAX]; |
946 | if (!BuildProcPath(exe_link, pid_, "exe" )) |
947 | return false; |
948 | MappingInfo new_mapping = {0}; |
949 | if (!SafeReadLink(exe_link, new_mapping.name)) |
950 | return false; |
951 | char new_path[PATH_MAX]; |
952 | if (!GetMappingAbsolutePath(new_mapping, new_path)) |
953 | return false; |
954 | if (my_strcmp(path, new_path) != 0) |
955 | return false; |
956 | |
957 | // Check to see if someone actually named their executable 'foo (deleted)'. |
958 | struct kernel_stat exe_stat; |
959 | struct kernel_stat new_path_stat; |
960 | if (sys_stat(exe_link, &exe_stat) == 0 && |
961 | sys_stat(new_path, &new_path_stat) == 0 && |
962 | exe_stat.st_dev == new_path_stat.st_dev && |
963 | exe_stat.st_ino == new_path_stat.st_ino) { |
964 | return false; |
965 | } |
966 | |
967 | my_memcpy(path, exe_link, NAME_MAX); |
968 | return true; |
969 | } |
970 | |
971 | } // namespace google_breakpad |
972 | |