Line data Source code
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 "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 "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 "third_party/lss/linux_syscall_support.h"
54 :
55 : #if defined(__ANDROID__)
56 :
57 : // Android packed relocations definitions are not yet available from the
58 : // NDK header files, so we have to provide them manually here.
59 : #ifndef DT_LOOS
60 : #define DT_LOOS 0x6000000d
61 : #endif
62 : #ifndef DT_ANDROID_REL
63 : static const int DT_ANDROID_REL = DT_LOOS + 2;
64 : #endif
65 : #ifndef DT_ANDROID_RELA
66 : static const int DT_ANDROID_RELA = DT_LOOS + 4;
67 : #endif
68 :
69 : #endif // __ANDROID __
70 :
71 : static const char kMappedFileUnsafePrefix[] = "/dev/";
72 : static const char kDeletedSuffix[] = " (deleted)";
73 : static const char kReservedFlags[] = " ---p";
74 :
75 0 : inline static bool IsMappedFileOpenUnsafe(
76 : const google_breakpad::MappingInfo& mapping) {
77 : // It is unsafe to attempt to open a mapped file that lives under /dev,
78 : // because the semantics of the open may be driver-specific so we'd risk
79 : // hanging the crash dumper. And a file in /dev/ almost certainly has no
80 : // ELF file identifier anyways.
81 0 : return my_strncmp(mapping.name,
82 : kMappedFileUnsafePrefix,
83 0 : sizeof(kMappedFileUnsafePrefix) - 1) == 0;
84 : }
85 :
86 : namespace google_breakpad {
87 :
88 : #if defined(__CHROMEOS__)
89 :
90 : namespace {
91 :
92 : // Recover memory mappings before writing dump on ChromeOS
93 : //
94 : // On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from
95 : // addresses. ChromeOS' hugepage implementation replaces some segments with
96 : // anonymous private pages, which is a restriction of current implementation
97 : // in Linux kernel at the time of writing. Thus, breakpad can no longer
98 : // symbolize addresses from those text segments replaced with hugepages.
99 : //
100 : // This postprocess tries to recover the mappings. Because hugepages are always
101 : // inserted in between some .text sections, it tries to infer the names and
102 : // offsets of the segments, by looking at segments immediately precede and
103 : // succeed them.
104 : //
105 : // For example, a text segment before hugepage optimization
106 : // 02001000-03002000 r-xp /opt/google/chrome/chrome
107 : //
108 : // can be broken into
109 : // 02001000-02200000 r-xp /opt/google/chrome/chrome
110 : // 02200000-03000000 r-xp
111 : // 03000000-03002000 r-xp /opt/google/chrome/chrome
112 : //
113 : // For more details, see:
114 : // crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization
115 :
116 : // Copied from CrOS' hugepage implementation, which is unlikely to change.
117 : // The hugepage size is 2M.
118 : const unsigned int kHpageShift = 21;
119 : const size_t kHpageSize = (1 << kHpageShift);
120 : const size_t kHpageMask = (~(kHpageSize - 1));
121 :
122 : // Find and merge anonymous r-xp segments with surrounding named segments.
123 : // There are two cases:
124 :
125 : // Case 1: curr, next
126 : // curr is anonymous
127 : // curr is r-xp
128 : // curr.size >= 2M
129 : // curr.size is a multiple of 2M.
130 : // next is backed by some file.
131 : // curr and next are contiguous.
132 : // offset(next) == sizeof(curr)
133 : void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) {
134 : // Merged segments are marked with size = 0.
135 : if (curr->size == 0 || next->size == 0)
136 : return;
137 :
138 : if (curr->size >= kHpageSize &&
139 : curr->exec &&
140 : (curr->size & kHpageMask) == curr->size &&
141 : (curr->start_addr & kHpageMask) == curr->start_addr &&
142 : curr->name[0] == '\0' &&
143 : next->name[0] != '\0' &&
144 : curr->start_addr + curr->size == next->start_addr &&
145 : curr->size == next->offset) {
146 :
147 : // matched
148 : my_strlcpy(curr->name, next->name, NAME_MAX);
149 : if (next->exec) {
150 : // (curr, next)
151 : curr->size += next->size;
152 : next->size = 0;
153 : }
154 : }
155 : }
156 :
157 : // Case 2: prev, curr, next
158 : // curr is anonymous
159 : // curr is r-xp
160 : // curr.size >= 2M
161 : // curr.size is a multiple of 2M.
162 : // next and prev are backed by the same file.
163 : // prev, curr and next are contiguous.
164 : // offset(next) == offset(prev) + sizeof(prev) + sizeof(curr)
165 : void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr,
166 : MappingInfo *next) {
167 : // Merged segments are marked with size = 0.
168 : if (prev->size == 0 || curr->size == 0 || next->size == 0)
169 : return;
170 :
171 : if (curr->size >= kHpageSize &&
172 : curr->exec &&
173 : (curr->size & kHpageMask) == curr->size &&
174 : (curr->start_addr & kHpageMask) == curr->start_addr &&
175 : curr->name[0] == '\0' &&
176 : next->name[0] != '\0' &&
177 : curr->start_addr + curr->size == next->start_addr &&
178 : prev->start_addr + prev->size == curr->start_addr &&
179 : my_strncmp(prev->name, next->name, NAME_MAX) == 0 &&
180 : next->offset == prev->offset + prev->size + curr->size) {
181 :
182 : // matched
183 : my_strlcpy(curr->name, prev->name, NAME_MAX);
184 : if (prev->exec) {
185 : curr->offset = prev->offset;
186 : curr->start_addr = prev->start_addr;
187 : if (next->exec) {
188 : // (prev, curr, next)
189 : curr->size += prev->size + next->size;
190 : prev->size = 0;
191 : next->size = 0;
192 : } else {
193 : // (prev, curr), next
194 : curr->size += prev->size;
195 : prev->size = 0;
196 : }
197 : } else {
198 : curr->offset = prev->offset + prev->size;
199 : if (next->exec) {
200 : // prev, (curr, next)
201 : curr->size += next->size;
202 : next->size = 0;
203 : } else {
204 : // prev, curr, next
205 : }
206 : }
207 : }
208 : }
209 :
210 : // mappings_ is sorted excepted for the first entry.
211 : // This function tries to merge segemnts into the first entry,
212 : // then check for other sorted entries.
213 : // See LinuxDumper::EnumerateMappings().
214 : void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
215 : // Find the candidate "next" to first segment, which is the only one that
216 : // could be out-of-order.
217 : size_t l = 1;
218 : size_t r = mappings.size();
219 : size_t next = mappings.size();
220 : while (l < r) {
221 : int m = (l + r) / 2;
222 : if (mappings[m]->start_addr > mappings[0]->start_addr)
223 : r = next = m;
224 : else
225 : l = m + 1;
226 : }
227 :
228 : // Try to merge segments into the first.
229 : if (next < mappings.size()) {
230 : TryRecoverMappings(mappings[0], mappings[next]);
231 : if (next - 1 > 0)
232 : TryRecoverMappings(mappings[next - 1], mappings[0], mappings[next]);
233 : }
234 :
235 : // Iterate through normal, sorted cases.
236 : // Normal case 1.
237 : for (size_t i = 1; i < mappings.size() - 1; i++)
238 : TryRecoverMappings(mappings[i], mappings[i + 1]);
239 :
240 : // Normal case 2.
241 : for (size_t i = 1; i < mappings.size() - 2; i++)
242 : TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]);
243 :
244 : // Collect merged (size == 0) segments.
245 : size_t f, e;
246 : for (f = e = 0; e < mappings.size(); e++)
247 : if (mappings[e]->size > 0)
248 : mappings[f++] = mappings[e];
249 : mappings.resize(f);
250 : }
251 :
252 : } // namespace
253 : #endif // __CHROMEOS__
254 :
255 : // All interesting auvx entry types are below AT_SYSINFO_EHDR
256 : #define AT_MAX AT_SYSINFO_EHDR
257 :
258 0 : LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix)
259 : : pid_(pid),
260 : root_prefix_(root_prefix),
261 : crash_address_(0),
262 : crash_signal_(0),
263 : crash_thread_(pid),
264 : threads_(&allocator_, 8),
265 : mappings_(&allocator_),
266 0 : auxv_(&allocator_, AT_MAX + 1) {
267 0 : assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX);
268 : // The passed-in size to the constructor (above) is only a hint.
269 : // Must call .resize() to do actual initialization of the elements.
270 0 : auxv_.resize(AT_MAX + 1);
271 0 : }
272 :
273 0 : LinuxDumper::~LinuxDumper() {
274 0 : }
275 :
276 0 : bool LinuxDumper::Init() {
277 0 : return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
278 : }
279 :
280 0 : bool LinuxDumper::LateInit() {
281 : #if defined(__ANDROID__)
282 : LatePostprocessMappings();
283 : #endif
284 :
285 : #if defined(__CHROMEOS__)
286 : CrOSPostProcessMappings(mappings_);
287 : #endif
288 :
289 0 : return true;
290 : }
291 :
292 : bool
293 0 : LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
294 : bool member,
295 : unsigned int mapping_id,
296 : wasteful_vector<uint8_t>& identifier) {
297 0 : assert(!member || mapping_id < mappings_.size());
298 0 : if (IsMappedFileOpenUnsafe(mapping))
299 0 : return false;
300 :
301 : // Special-case linux-gate because it's not a real file.
302 0 : if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
303 0 : void* linux_gate = NULL;
304 0 : if (pid_ == sys_getpid()) {
305 0 : linux_gate = reinterpret_cast<void*>(mapping.start_addr);
306 : } else {
307 0 : linux_gate = allocator_.Alloc(mapping.size);
308 0 : CopyFromProcess(linux_gate, pid_,
309 0 : reinterpret_cast<const void*>(mapping.start_addr),
310 0 : mapping.size);
311 : }
312 0 : return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
313 : }
314 :
315 : char filename[PATH_MAX];
316 0 : if (!GetMappingAbsolutePath(mapping, filename))
317 0 : return false;
318 0 : bool filename_modified = HandleDeletedFileInMapping(filename);
319 :
320 0 : MemoryMappedFile mapped_file(filename, mapping.offset);
321 0 : if (!mapped_file.data() || mapped_file.size() < SELFMAG)
322 0 : return false;
323 :
324 : bool success =
325 0 : FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
326 0 : if (success && member && filename_modified) {
327 0 : mappings_[mapping_id]->name[my_strlen(mapping.name) -
328 0 : sizeof(kDeletedSuffix) + 1] = '\0';
329 : }
330 :
331 0 : return success;
332 : }
333 :
334 0 : bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
335 : char path[PATH_MAX]) const {
336 0 : return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
337 0 : my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX;
338 : }
339 :
340 : namespace {
341 0 : bool ElfFileSoNameFromMappedFile(
342 : const void* elf_base, char* soname, size_t soname_size) {
343 0 : if (!IsValidElf(elf_base)) {
344 : // Not ELF
345 0 : return false;
346 : }
347 :
348 : const void* segment_start;
349 : size_t segment_size;
350 : int elf_class;
351 0 : if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC,
352 : &segment_start, &segment_size, &elf_class)) {
353 : // No dynamic section
354 0 : return false;
355 : }
356 :
357 : const void* dynstr_start;
358 : size_t dynstr_size;
359 0 : if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB,
360 : &dynstr_start, &dynstr_size, &elf_class)) {
361 : // No dynstr section
362 0 : return false;
363 : }
364 :
365 0 : const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start);
366 0 : size_t dcount = segment_size / sizeof(ElfW(Dyn));
367 0 : for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
368 0 : if (dyn->d_tag == DT_SONAME) {
369 0 : const char* dynstr = static_cast<const char*>(dynstr_start);
370 0 : if (dyn->d_un.d_val >= dynstr_size) {
371 : // Beyond the end of the dynstr section
372 0 : return false;
373 : }
374 0 : const char* str = dynstr + dyn->d_un.d_val;
375 0 : const size_t maxsize = dynstr_size - dyn->d_un.d_val;
376 0 : my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
377 0 : return true;
378 : }
379 : }
380 :
381 : // Did not find SONAME
382 0 : return false;
383 : }
384 :
385 : // Find the shared object name (SONAME) by examining the ELF information
386 : // for |mapping|. If the SONAME is found copy it into the passed buffer
387 : // |soname| and return true. The size of the buffer is |soname_size|.
388 : // The SONAME will be truncated if it is too long to fit in the buffer.
389 0 : bool ElfFileSoName(const LinuxDumper& dumper,
390 : const MappingInfo& mapping, char* soname, size_t soname_size) {
391 0 : if (IsMappedFileOpenUnsafe(mapping)) {
392 : // Not safe
393 0 : return false;
394 : }
395 :
396 : char filename[PATH_MAX];
397 0 : if (!dumper.GetMappingAbsolutePath(mapping, filename))
398 0 : return false;
399 :
400 0 : MemoryMappedFile mapped_file(filename, mapping.offset);
401 0 : if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
402 : // mmap failed
403 0 : return false;
404 : }
405 :
406 0 : return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
407 : }
408 :
409 : } // namespace
410 :
411 :
412 0 : void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
413 : char* file_path,
414 : size_t file_path_size,
415 : char* file_name,
416 : size_t file_name_size) {
417 0 : my_strlcpy(file_path, mapping.name, file_path_size);
418 :
419 : // If an executable is mapped from a non-zero offset, this is likely because
420 : // the executable was loaded directly from inside an archive file (e.g., an
421 : // apk on Android). We try to find the name of the shared object (SONAME) by
422 : // looking in the file for ELF sections.
423 0 : bool mapped_from_archive = false;
424 0 : if (mapping.exec && mapping.offset != 0) {
425 : mapped_from_archive =
426 0 : ElfFileSoName(*this, mapping, file_name, file_name_size);
427 : }
428 :
429 0 : if (mapped_from_archive) {
430 : // Some tools (e.g., stackwalk) extract the basename from the pathname. In
431 : // this case, we append the file_name to the mapped archive path as follows:
432 : // file_name := libname.so
433 : // file_path := /path/to/ARCHIVE.APK/libname.so
434 0 : if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
435 0 : my_strlcat(file_path, "/", file_path_size);
436 0 : my_strlcat(file_path, file_name, file_path_size);
437 : }
438 : } else {
439 : // Common case:
440 : // file_path := /path/to/libname.so
441 : // file_name := libname.so
442 0 : const char* basename = my_strrchr(file_path, '/');
443 0 : basename = basename == NULL ? file_path : (basename + 1);
444 0 : my_strlcpy(file_name, basename, file_name_size);
445 : }
446 0 : }
447 :
448 0 : bool LinuxDumper::ReadAuxv() {
449 : char auxv_path[NAME_MAX];
450 0 : if (!BuildProcPath(auxv_path, pid_, "auxv")) {
451 0 : return false;
452 : }
453 :
454 0 : int fd = sys_open(auxv_path, O_RDONLY, 0);
455 0 : if (fd < 0) {
456 0 : return false;
457 : }
458 :
459 : elf_aux_entry one_aux_entry;
460 0 : bool res = false;
461 0 : while (sys_read(fd,
462 : &one_aux_entry,
463 0 : sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
464 0 : one_aux_entry.a_type != AT_NULL) {
465 0 : if (one_aux_entry.a_type <= AT_MAX) {
466 0 : auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val;
467 0 : res = true;
468 : }
469 : }
470 0 : sys_close(fd);
471 0 : return res;
472 : }
473 :
474 0 : bool LinuxDumper::EnumerateMappings() {
475 : char maps_path[NAME_MAX];
476 0 : if (!BuildProcPath(maps_path, pid_, "maps"))
477 0 : return false;
478 :
479 : // linux_gate_loc is the beginning of the kernel's mapping of
480 : // linux-gate.so in the process. It doesn't actually show up in the
481 : // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR
482 : // aux vector entry, which gives the information necessary to special
483 : // case its entry when creating the list of mappings.
484 : // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
485 : // information.
486 : const void* linux_gate_loc =
487 0 : reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]);
488 : // Although the initial executable is usually the first mapping, it's not
489 : // guaranteed (see http://crosbug.com/25355); therefore, try to use the
490 : // actual entry point to find the mapping.
491 0 : const void* entry_point_loc = reinterpret_cast<void *>(auxv_[AT_ENTRY]);
492 :
493 0 : const int fd = sys_open(maps_path, O_RDONLY, 0);
494 0 : if (fd < 0)
495 0 : return false;
496 0 : LineReader* const line_reader = new(allocator_) LineReader(fd);
497 :
498 : const char* line;
499 : unsigned line_len;
500 0 : while (line_reader->GetNextLine(&line, &line_len)) {
501 : uintptr_t start_addr, end_addr, offset;
502 :
503 0 : const char* i1 = my_read_hex_ptr(&start_addr, line);
504 0 : if (*i1 == '-') {
505 0 : const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
506 0 : if (*i2 == ' ') {
507 0 : bool exec = (*(i2 + 3) == 'x');
508 0 : const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
509 0 : if (*i3 == ' ') {
510 0 : const char* name = NULL;
511 : // Only copy name if the name is a valid path name, or if
512 : // it's the VDSO image.
513 0 : if (((name = my_strchr(line, '/')) == NULL) &&
514 0 : linux_gate_loc &&
515 0 : reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
516 0 : name = kLinuxGateLibraryName;
517 0 : offset = 0;
518 : }
519 : // Merge adjacent mappings with the same name into one module,
520 : // assuming they're a single library mapped by the dynamic linker
521 0 : if (name && !mappings_.empty()) {
522 0 : MappingInfo* module = mappings_.back();
523 0 : if ((start_addr == module->start_addr + module->size) &&
524 0 : (my_strlen(name) == my_strlen(module->name)) &&
525 0 : (my_strncmp(name, module->name, my_strlen(name)) == 0)) {
526 0 : module->size = end_addr - module->start_addr;
527 0 : line_reader->PopLine(line_len);
528 0 : continue;
529 : }
530 : }
531 : // Also merge mappings that result from address ranges that the
532 : // linker reserved but which a loaded library did not use. These
533 : // appear as an anonymous private mapping with no access flags set
534 : // and which directly follow an executable mapping.
535 0 : if (!name && !mappings_.empty()) {
536 0 : MappingInfo* module = mappings_.back();
537 0 : if ((start_addr == module->start_addr + module->size) &&
538 0 : module->exec &&
539 0 : module->name[0] == '/' &&
540 0 : offset == 0 && my_strncmp(i2,
541 : kReservedFlags,
542 : sizeof(kReservedFlags) - 1) == 0) {
543 0 : module->size = end_addr - module->start_addr;
544 0 : line_reader->PopLine(line_len);
545 0 : continue;
546 : }
547 : }
548 0 : MappingInfo* const module = new(allocator_) MappingInfo;
549 0 : my_memset(module, 0, sizeof(MappingInfo));
550 0 : module->start_addr = start_addr;
551 0 : module->size = end_addr - start_addr;
552 0 : module->offset = offset;
553 0 : module->exec = exec;
554 0 : if (name != NULL) {
555 0 : const unsigned l = my_strlen(name);
556 0 : if (l < sizeof(module->name))
557 0 : my_memcpy(module->name, name, l);
558 : }
559 : // If this is the entry-point mapping, and it's not already the
560 : // first one, then we need to make it be first. This is because
561 : // the minidump format assumes the first module is the one that
562 : // corresponds to the main executable (as codified in
563 : // processor/minidump.cc:MinidumpModuleList::GetMainModule()).
564 0 : if (entry_point_loc &&
565 : (entry_point_loc >=
566 0 : reinterpret_cast<void*>(module->start_addr)) &&
567 : (entry_point_loc <
568 0 : reinterpret_cast<void*>(module->start_addr+module->size)) &&
569 0 : !mappings_.empty()) {
570 : // push the module onto the front of the list.
571 0 : mappings_.resize(mappings_.size() + 1);
572 0 : for (size_t idx = mappings_.size() - 1; idx > 0; idx--)
573 0 : mappings_[idx] = mappings_[idx - 1];
574 0 : mappings_[0] = module;
575 : } else {
576 0 : mappings_.push_back(module);
577 : }
578 : }
579 : }
580 : }
581 0 : line_reader->PopLine(line_len);
582 : }
583 :
584 0 : sys_close(fd);
585 :
586 0 : return !mappings_.empty();
587 : }
588 :
589 : #if defined(__ANDROID__)
590 :
591 : bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) {
592 : CopyFromProcess(ehdr, pid_,
593 : reinterpret_cast<const void*>(start_addr),
594 : sizeof(*ehdr));
595 : return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0;
596 : }
597 :
598 : void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
599 : uintptr_t start_addr,
600 : uintptr_t* min_vaddr_ptr,
601 : uintptr_t* dyn_vaddr_ptr,
602 : size_t* dyn_count_ptr) {
603 : uintptr_t phdr_addr = start_addr + ehdr->e_phoff;
604 :
605 : const uintptr_t max_addr = UINTPTR_MAX;
606 : uintptr_t min_vaddr = max_addr;
607 : uintptr_t dyn_vaddr = 0;
608 : size_t dyn_count = 0;
609 :
610 : for (size_t i = 0; i < ehdr->e_phnum; ++i) {
611 : ElfW(Phdr) phdr;
612 : CopyFromProcess(&phdr, pid_,
613 : reinterpret_cast<const void*>(phdr_addr),
614 : sizeof(phdr));
615 : if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) {
616 : min_vaddr = phdr.p_vaddr;
617 : }
618 : if (phdr.p_type == PT_DYNAMIC) {
619 : dyn_vaddr = phdr.p_vaddr;
620 : dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn));
621 : }
622 : phdr_addr += sizeof(phdr);
623 : }
624 :
625 : *min_vaddr_ptr = min_vaddr;
626 : *dyn_vaddr_ptr = dyn_vaddr;
627 : *dyn_count_ptr = dyn_count;
628 : }
629 :
630 : bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias,
631 : uintptr_t dyn_vaddr,
632 : size_t dyn_count) {
633 : uintptr_t dyn_addr = load_bias + dyn_vaddr;
634 : for (size_t i = 0; i < dyn_count; ++i) {
635 : ElfW(Dyn) dyn;
636 : CopyFromProcess(&dyn, pid_,
637 : reinterpret_cast<const void*>(dyn_addr),
638 : sizeof(dyn));
639 : if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) {
640 : return true;
641 : }
642 : dyn_addr += sizeof(dyn);
643 : }
644 : return false;
645 : }
646 :
647 : uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr,
648 : uintptr_t start_addr) {
649 : uintptr_t min_vaddr = 0;
650 : uintptr_t dyn_vaddr = 0;
651 : size_t dyn_count = 0;
652 : ParseLoadedElfProgramHeaders(ehdr, start_addr,
653 : &min_vaddr, &dyn_vaddr, &dyn_count);
654 : // If |min_vaddr| is non-zero and we find Android packed relocation tags,
655 : // return the effective load bias.
656 : if (min_vaddr != 0) {
657 : const uintptr_t load_bias = start_addr - min_vaddr;
658 : if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) {
659 : return load_bias;
660 : }
661 : }
662 : // Either |min_vaddr| is zero, or it is non-zero but we did not find the
663 : // expected Android packed relocations tags.
664 : return start_addr;
665 : }
666 :
667 : void LinuxDumper::LatePostprocessMappings() {
668 : for (size_t i = 0; i < mappings_.size(); ++i) {
669 : // Only consider exec mappings that indicate a file path was mapped, and
670 : // where the ELF header indicates a mapped shared library.
671 : MappingInfo* mapping = mappings_[i];
672 : if (!(mapping->exec && mapping->name[0] == '/')) {
673 : continue;
674 : }
675 : ElfW(Ehdr) ehdr;
676 : if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) {
677 : continue;
678 : }
679 : if (ehdr.e_type == ET_DYN) {
680 : // Compute the effective load bias for this mapped library, and update
681 : // the mapping to hold that rather than |start_addr|, at the same time
682 : // adjusting |size| to account for the change in |start_addr|. Where
683 : // the library does not contain Android packed relocations,
684 : // GetEffectiveLoadBias() returns |start_addr| and the mapping entry
685 : // is not changed.
686 : const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr,
687 : mapping->start_addr);
688 : mapping->size += mapping->start_addr - load_bias;
689 : mapping->start_addr = load_bias;
690 : }
691 : }
692 : }
693 :
694 : #endif // __ANDROID__
695 :
696 : // Get information about the stack, given the stack pointer. We don't try to
697 : // walk the stack since we might not have all the information needed to do
698 : // unwind. So we just grab, up to, 32k of stack.
699 0 : bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
700 : uintptr_t int_stack_pointer) {
701 : // Move the stack pointer to the bottom of the page that it's in.
702 0 : const uintptr_t page_size = getpagesize();
703 :
704 : uint8_t* const stack_pointer =
705 0 : reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
706 :
707 : // The number of bytes of stack which we try to capture.
708 : static const ptrdiff_t kStackToCapture = 32 * 1024;
709 :
710 0 : const MappingInfo* mapping = FindMapping(stack_pointer);
711 0 : if (!mapping)
712 0 : return false;
713 : const ptrdiff_t offset = stack_pointer -
714 0 : reinterpret_cast<uint8_t*>(mapping->start_addr);
715 : const ptrdiff_t distance_to_end =
716 0 : static_cast<ptrdiff_t>(mapping->size) - offset;
717 0 : *stack_len = distance_to_end > kStackToCapture ?
718 : kStackToCapture : distance_to_end;
719 0 : *stack = stack_pointer;
720 0 : return true;
721 : }
722 :
723 : // Find the mapping which the given memory address falls in.
724 0 : const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
725 0 : const uintptr_t addr = (uintptr_t) address;
726 :
727 0 : for (size_t i = 0; i < mappings_.size(); ++i) {
728 0 : const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
729 0 : if (addr >= start && addr - start < mappings_[i]->size)
730 0 : return mappings_[i];
731 : }
732 :
733 0 : return NULL;
734 : }
735 :
736 0 : bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
737 : static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
738 :
739 : // Check for ' (deleted)' in |path|.
740 : // |path| has to be at least as long as "/x (deleted)".
741 0 : const size_t path_len = my_strlen(path);
742 0 : if (path_len < kDeletedSuffixLen + 2)
743 0 : return false;
744 0 : if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
745 : kDeletedSuffixLen) != 0) {
746 0 : return false;
747 : }
748 :
749 : // Check |path| against the /proc/pid/exe 'symlink'.
750 : char exe_link[NAME_MAX];
751 0 : if (!BuildProcPath(exe_link, pid_, "exe"))
752 0 : return false;
753 0 : MappingInfo new_mapping = {0};
754 0 : if (!SafeReadLink(exe_link, new_mapping.name))
755 0 : return false;
756 : char new_path[PATH_MAX];
757 0 : if (!GetMappingAbsolutePath(new_mapping, new_path))
758 0 : return false;
759 0 : if (my_strcmp(path, new_path) != 0)
760 0 : return false;
761 :
762 : // Check to see if someone actually named their executable 'foo (deleted)'.
763 : struct kernel_stat exe_stat;
764 : struct kernel_stat new_path_stat;
765 0 : if (sys_stat(exe_link, &exe_stat) == 0 &&
766 0 : sys_stat(new_path, &new_path_stat) == 0 &&
767 0 : exe_stat.st_dev == new_path_stat.st_dev &&
768 0 : exe_stat.st_ino == new_path_stat.st_ino) {
769 0 : return false;
770 : }
771 :
772 0 : my_memcpy(path, exe_link, NAME_MAX);
773 0 : return true;
774 : }
775 :
776 : } // namespace google_breakpad
|