• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // This code writes out minidump files:
31 //   http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
32 //
33 // Minidumps are a Microsoft format which Breakpad uses for recording crash
34 // dumps. This code has to run in a compromised environment (the address space
35 // may have received SIGSEGV), thus the following rules apply:
36 //   * You may not enter the dynamic linker. This means that we cannot call
37 //     any symbols in a shared library (inc libc). Because of this we replace
38 //     libc functions in linux_libc_support.h.
39 //   * You may not call syscalls via the libc wrappers. This rule is a subset
40 //     of the first rule but it bears repeating. We have direct wrappers
41 //     around the system calls in linux_syscall_support.h.
42 //   * You may not malloc. There's an alternative allocator in memory.h and
43 //     a canonical instance in the LinuxDumper object. We use the placement
44 //     new form to allocate objects and we don't delete them.
45 
46 #include "client/linux/handler/minidump_descriptor.h"
47 #include "client/linux/minidump_writer/minidump_writer.h"
48 #include "client/minidump_file_writer-inl.h"
49 
50 #include <ctype.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <link.h>
54 #include <stdio.h>
55 #if defined(__ANDROID__)
56 #include <sys/system_properties.h>
57 #endif
58 #include <sys/types.h>
59 #include <sys/ucontext.h>
60 #include <sys/user.h>
61 #include <sys/utsname.h>
62 #include <time.h>
63 #include <unistd.h>
64 
65 #include <algorithm>
66 
67 #include "client/linux/dump_writer_common/thread_info.h"
68 #include "client/linux/dump_writer_common/ucontext_reader.h"
69 #include "client/linux/handler/exception_handler.h"
70 #include "client/linux/minidump_writer/cpu_set.h"
71 #include "client/linux/minidump_writer/line_reader.h"
72 #include "client/linux/minidump_writer/linux_dumper.h"
73 #include "client/linux/minidump_writer/linux_ptrace_dumper.h"
74 #include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
75 #include "client/minidump_file_writer.h"
76 #include "common/linux/file_id.h"
77 #include "common/linux/linux_libc_support.h"
78 #include "common/minidump_type_helper.h"
79 #include "google_breakpad/common/minidump_format.h"
80 #include "third_party/lss/linux_syscall_support.h"
81 
82 namespace {
83 
84 using google_breakpad::AppMemoryList;
85 using google_breakpad::auto_wasteful_vector;
86 using google_breakpad::ExceptionHandler;
87 using google_breakpad::CpuSet;
88 using google_breakpad::kDefaultBuildIdSize;
89 using google_breakpad::LineReader;
90 using google_breakpad::LinuxDumper;
91 using google_breakpad::LinuxPtraceDumper;
92 using google_breakpad::MDTypeHelper;
93 using google_breakpad::MappingEntry;
94 using google_breakpad::MappingInfo;
95 using google_breakpad::MappingList;
96 using google_breakpad::MinidumpFileWriter;
97 using google_breakpad::PageAllocator;
98 using google_breakpad::ProcCpuInfoReader;
99 using google_breakpad::RawContextCPU;
100 using google_breakpad::ThreadInfo;
101 using google_breakpad::TypedMDRVA;
102 using google_breakpad::UContextReader;
103 using google_breakpad::UntypedMDRVA;
104 using google_breakpad::wasteful_vector;
105 
106 typedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug;
107 typedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap;
108 
109 class MinidumpWriter {
110  public:
111   // The following kLimit* constants are for when minidump_size_limit_ is set
112   // and the minidump size might exceed it.
113   //
114   // Estimate for how big each thread's stack will be (in bytes).
115   static const unsigned kLimitAverageThreadStackLength = 8 * 1024;
116   // Number of threads whose stack size we don't want to limit.  These base
117   // threads will simply be the first N threads returned by the dumper (although
118   // the crashing thread will never be limited).  Threads beyond this count are
119   // the extra threads.
120   static const unsigned kLimitBaseThreadCount = 20;
121   // Maximum stack size to dump for any extra thread (in bytes).
122   static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024;
123   // Make sure this number of additional bytes can fit in the minidump
124   // (exclude the stack data).
125   static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024;
126 
MinidumpWriter(const char * minidump_path,int minidump_fd,const ExceptionHandler::CrashContext * context,const MappingList & mappings,const AppMemoryList & appmem,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks,LinuxDumper * dumper)127   MinidumpWriter(const char* minidump_path,
128                  int minidump_fd,
129                  const ExceptionHandler::CrashContext* context,
130                  const MappingList& mappings,
131                  const AppMemoryList& appmem,
132                  bool skip_stacks_if_mapping_unreferenced,
133                  uintptr_t principal_mapping_address,
134                  bool sanitize_stacks,
135                  LinuxDumper* dumper)
136       : fd_(minidump_fd),
137         path_(minidump_path),
138         ucontext_(context ? &context->context : NULL),
139 #if !defined(__ARM_EABI__) && !defined(__mips__)
140         float_state_(context ? &context->float_state : NULL),
141 #endif
142         dumper_(dumper),
143         minidump_size_limit_(-1),
144         memory_blocks_(dumper_->allocator()),
145         mapping_list_(mappings),
146         app_memory_list_(appmem),
147         skip_stacks_if_mapping_unreferenced_(
148             skip_stacks_if_mapping_unreferenced),
149         principal_mapping_address_(principal_mapping_address),
150         principal_mapping_(nullptr),
151     sanitize_stacks_(sanitize_stacks) {
152     // Assert there should be either a valid fd or a valid path, not both.
153     assert(fd_ != -1 || minidump_path);
154     assert(fd_ == -1 || !minidump_path);
155   }
156 
Init()157   bool Init() {
158     if (!dumper_->Init())
159       return false;
160 
161     if (!dumper_->ThreadsSuspend() || !dumper_->LateInit())
162       return false;
163 
164     if (skip_stacks_if_mapping_unreferenced_) {
165       principal_mapping_ =
166           dumper_->FindMappingNoBias(principal_mapping_address_);
167       if (!CrashingThreadReferencesPrincipalMapping())
168         return false;
169     }
170 
171     if (fd_ != -1)
172       minidump_writer_.SetFile(fd_);
173     else if (!minidump_writer_.Open(path_))
174       return false;
175 
176     return true;
177   }
178 
~MinidumpWriter()179   ~MinidumpWriter() {
180     // Don't close the file descriptor when it's been provided explicitly.
181     // Callers might still need to use it.
182     if (fd_ == -1)
183       minidump_writer_.Close();
184     dumper_->ThreadsResume();
185   }
186 
CrashingThreadReferencesPrincipalMapping()187   bool CrashingThreadReferencesPrincipalMapping() {
188     if (!ucontext_ || !principal_mapping_)
189       return false;
190 
191     const uintptr_t low_addr =
192         principal_mapping_->system_mapping_info.start_addr;
193     const uintptr_t high_addr =
194         principal_mapping_->system_mapping_info.end_addr;
195 
196     const uintptr_t stack_pointer = UContextReader::GetStackPointer(ucontext_);
197     const uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_);
198 
199     if (pc >= low_addr && pc < high_addr)
200       return true;
201 
202     uint8_t* stack_copy;
203     const void* stack;
204     size_t stack_len;
205 
206     if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer))
207       return false;
208 
209     stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
210     dumper_->CopyFromProcess(stack_copy, GetCrashThread(), stack, stack_len);
211 
212     uintptr_t stack_pointer_offset =
213         stack_pointer - reinterpret_cast<uintptr_t>(stack);
214 
215     return dumper_->StackHasPointerToMapping(
216         stack_copy, stack_len, stack_pointer_offset, *principal_mapping_);
217   }
218 
Dump()219   bool Dump() {
220     // A minidump file contains a number of tagged streams. This is the number
221     // of stream which we write.
222     unsigned kNumWriters = 13;
223 
224     TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
225     {
226       // Ensure the header gets flushed, as that happens in the destructor.
227       // If a crash occurs somewhere below, at least the header will be
228       // intact.
229       TypedMDRVA<MDRawHeader> header(&minidump_writer_);
230       if (!header.Allocate())
231         return false;
232 
233       if (!dir.AllocateArray(kNumWriters))
234         return false;
235 
236       my_memset(header.get(), 0, sizeof(MDRawHeader));
237 
238       header.get()->signature = MD_HEADER_SIGNATURE;
239       header.get()->version = MD_HEADER_VERSION;
240       header.get()->time_date_stamp = time(NULL);
241       header.get()->stream_count = kNumWriters;
242       header.get()->stream_directory_rva = dir.position();
243     }
244 
245     unsigned dir_index = 0;
246     MDRawDirectory dirent;
247 
248     if (!WriteThreadListStream(&dirent))
249       return false;
250     dir.CopyIndex(dir_index++, &dirent);
251 
252     if (!WriteMappings(&dirent))
253       return false;
254     dir.CopyIndex(dir_index++, &dirent);
255 
256     if (!WriteAppMemory())
257       return false;
258 
259     if (!WriteMemoryListStream(&dirent))
260       return false;
261     dir.CopyIndex(dir_index++, &dirent);
262 
263     if (!WriteExceptionStream(&dirent))
264       return false;
265     dir.CopyIndex(dir_index++, &dirent);
266 
267     if (!WriteSystemInfoStream(&dirent))
268       return false;
269     dir.CopyIndex(dir_index++, &dirent);
270 
271     dirent.stream_type = MD_LINUX_CPU_INFO;
272     if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
273       NullifyDirectoryEntry(&dirent);
274     dir.CopyIndex(dir_index++, &dirent);
275 
276     dirent.stream_type = MD_LINUX_PROC_STATUS;
277     if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
278       NullifyDirectoryEntry(&dirent);
279     dir.CopyIndex(dir_index++, &dirent);
280 
281     dirent.stream_type = MD_LINUX_LSB_RELEASE;
282     if (!WriteFile(&dirent.location, "/etc/lsb-release"))
283       NullifyDirectoryEntry(&dirent);
284     dir.CopyIndex(dir_index++, &dirent);
285 
286     dirent.stream_type = MD_LINUX_CMD_LINE;
287     if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
288       NullifyDirectoryEntry(&dirent);
289     dir.CopyIndex(dir_index++, &dirent);
290 
291     dirent.stream_type = MD_LINUX_ENVIRON;
292     if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
293       NullifyDirectoryEntry(&dirent);
294     dir.CopyIndex(dir_index++, &dirent);
295 
296     dirent.stream_type = MD_LINUX_AUXV;
297     if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
298       NullifyDirectoryEntry(&dirent);
299     dir.CopyIndex(dir_index++, &dirent);
300 
301     dirent.stream_type = MD_LINUX_MAPS;
302     if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
303       NullifyDirectoryEntry(&dirent);
304     dir.CopyIndex(dir_index++, &dirent);
305 
306     dirent.stream_type = MD_LINUX_DSO_DEBUG;
307     if (!WriteDSODebugStream(&dirent))
308       NullifyDirectoryEntry(&dirent);
309     dir.CopyIndex(dir_index++, &dirent);
310 
311     // If you add more directory entries, don't forget to update kNumWriters,
312     // above.
313 
314     dumper_->ThreadsResume();
315     return true;
316   }
317 
FillThreadStack(MDRawThread * thread,uintptr_t stack_pointer,uintptr_t pc,int max_stack_len,uint8_t ** stack_copy)318   bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer,
319                        uintptr_t pc, int max_stack_len, uint8_t** stack_copy) {
320     *stack_copy = NULL;
321     const void* stack;
322     size_t stack_len;
323 
324     thread->stack.start_of_memory_range = stack_pointer;
325     thread->stack.memory.data_size = 0;
326     thread->stack.memory.rva = minidump_writer_.position();
327 
328     if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
329       if (max_stack_len >= 0 &&
330           stack_len > static_cast<unsigned int>(max_stack_len)) {
331         stack_len = max_stack_len;
332         // Skip empty chunks of length max_stack_len.
333         uintptr_t int_stack = reinterpret_cast<uintptr_t>(stack);
334         if (max_stack_len > 0) {
335           while (int_stack + max_stack_len < stack_pointer) {
336             int_stack += max_stack_len;
337           }
338         }
339         stack = reinterpret_cast<const void*>(int_stack);
340       }
341       *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
342       dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack,
343                                stack_len);
344 
345       uintptr_t stack_pointer_offset =
346           stack_pointer - reinterpret_cast<uintptr_t>(stack);
347       if (skip_stacks_if_mapping_unreferenced_) {
348         if (!principal_mapping_) {
349           return true;
350         }
351         uintptr_t low_addr = principal_mapping_->system_mapping_info.start_addr;
352         uintptr_t high_addr = principal_mapping_->system_mapping_info.end_addr;
353         if ((pc < low_addr || pc > high_addr) &&
354             !dumper_->StackHasPointerToMapping(*stack_copy, stack_len,
355                                                stack_pointer_offset,
356                                                *principal_mapping_)) {
357           return true;
358         }
359       }
360 
361       if (sanitize_stacks_) {
362         dumper_->SanitizeStackCopy(*stack_copy, stack_len, stack_pointer,
363                                    stack_pointer_offset);
364       }
365 
366       UntypedMDRVA memory(&minidump_writer_);
367       if (!memory.Allocate(stack_len))
368         return false;
369       memory.Copy(*stack_copy, stack_len);
370       thread->stack.start_of_memory_range = reinterpret_cast<uintptr_t>(stack);
371       thread->stack.memory = memory.location();
372       memory_blocks_.push_back(thread->stack);
373     }
374     return true;
375   }
376 
377   // Write information about the threads.
WriteThreadListStream(MDRawDirectory * dirent)378   bool WriteThreadListStream(MDRawDirectory* dirent) {
379     const unsigned num_threads = dumper_->threads().size();
380 
381     TypedMDRVA<uint32_t> list(&minidump_writer_);
382     if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
383       return false;
384 
385     dirent->stream_type = MD_THREAD_LIST_STREAM;
386     dirent->location = list.location();
387 
388     *list.get() = num_threads;
389 
390     // If there's a minidump size limit, check if it might be exceeded.  Since
391     // most of the space is filled with stack data, just check against that.
392     // If this expects to exceed the limit, set extra_thread_stack_len such
393     // that any thread beyond the first kLimitBaseThreadCount threads will
394     // have only kLimitMaxExtraThreadStackLen bytes dumped.
395     int extra_thread_stack_len = -1;  // default to no maximum
396     if (minidump_size_limit_ >= 0) {
397       const unsigned estimated_total_stack_size = num_threads *
398           kLimitAverageThreadStackLength;
399       const off_t estimated_minidump_size = minidump_writer_.position() +
400           estimated_total_stack_size + kLimitMinidumpFudgeFactor;
401       if (estimated_minidump_size > minidump_size_limit_)
402         extra_thread_stack_len = kLimitMaxExtraThreadStackLen;
403     }
404 
405     for (unsigned i = 0; i < num_threads; ++i) {
406       MDRawThread thread;
407       my_memset(&thread, 0, sizeof(thread));
408       thread.thread_id = dumper_->threads()[i];
409 
410       // We have a different source of information for the crashing thread. If
411       // we used the actual state of the thread we would find it running in the
412       // signal handler with the alternative stack, which would be deeply
413       // unhelpful.
414       if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
415           ucontext_ &&
416           !dumper_->IsPostMortem()) {
417         uint8_t* stack_copy;
418         const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
419         if (!FillThreadStack(&thread, stack_ptr,
420                              UContextReader::GetInstructionPointer(ucontext_),
421                              -1, &stack_copy))
422           return false;
423 
424         // Copy 256 bytes around crashing instruction pointer to minidump.
425         const size_t kIPMemorySize = 256;
426         uint64_t ip = UContextReader::GetInstructionPointer(ucontext_);
427         // Bound it to the upper and lower bounds of the memory map
428         // it's contained within. If it's not in mapped memory,
429         // don't bother trying to write it.
430         bool ip_is_mapped = false;
431         MDMemoryDescriptor ip_memory_d;
432         for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
433           const MappingInfo& mapping = *dumper_->mappings()[j];
434           if (ip >= mapping.start_addr &&
435               ip < mapping.start_addr + mapping.size) {
436             ip_is_mapped = true;
437             // Try to get 128 bytes before and after the IP, but
438             // settle for whatever's available.
439             ip_memory_d.start_of_memory_range =
440               std::max(mapping.start_addr,
441                        uintptr_t(ip - (kIPMemorySize / 2)));
442             uintptr_t end_of_range =
443               std::min(uintptr_t(ip + (kIPMemorySize / 2)),
444                        uintptr_t(mapping.start_addr + mapping.size));
445             ip_memory_d.memory.data_size =
446               end_of_range - ip_memory_d.start_of_memory_range;
447             break;
448           }
449         }
450 
451         if (ip_is_mapped) {
452           UntypedMDRVA ip_memory(&minidump_writer_);
453           if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
454             return false;
455           uint8_t* memory_copy =
456               reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
457           dumper_->CopyFromProcess(
458               memory_copy,
459               thread.thread_id,
460               reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
461               ip_memory_d.memory.data_size);
462           ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
463           ip_memory_d.memory = ip_memory.location();
464           memory_blocks_.push_back(ip_memory_d);
465         }
466 
467         TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
468         if (!cpu.Allocate())
469           return false;
470         my_memset(cpu.get(), 0, sizeof(RawContextCPU));
471 #if !defined(__ARM_EABI__) && !defined(__mips__)
472         UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_);
473 #else
474         UContextReader::FillCPUContext(cpu.get(), ucontext_);
475 #endif
476         thread.thread_context = cpu.location();
477         crashing_thread_context_ = cpu.location();
478       } else {
479         ThreadInfo info;
480         if (!dumper_->GetThreadInfoByIndex(i, &info))
481           return false;
482 
483         uint8_t* stack_copy;
484         int max_stack_len = -1;  // default to no maximum for this thread
485         if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount)
486           max_stack_len = extra_thread_stack_len;
487         if (!FillThreadStack(&thread, info.stack_pointer,
488                              info.GetInstructionPointer(), max_stack_len,
489                              &stack_copy))
490           return false;
491 
492         TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
493         if (!cpu.Allocate())
494           return false;
495         my_memset(cpu.get(), 0, sizeof(RawContextCPU));
496         info.FillCPUContext(cpu.get());
497         thread.thread_context = cpu.location();
498         if (dumper_->threads()[i] == GetCrashThread()) {
499           crashing_thread_context_ = cpu.location();
500           if (!dumper_->IsPostMortem()) {
501             // This is the crashing thread of a live process, but
502             // no context was provided, so set the crash address
503             // while the instruction pointer is already here.
504             dumper_->set_crash_address(info.GetInstructionPointer());
505           }
506         }
507       }
508 
509       list.CopyIndexAfterObject(i, &thread, sizeof(thread));
510     }
511 
512     return true;
513   }
514 
515   // Write application-provided memory regions.
WriteAppMemory()516   bool WriteAppMemory() {
517     for (AppMemoryList::const_iterator iter = app_memory_list_.begin();
518          iter != app_memory_list_.end();
519          ++iter) {
520       uint8_t* data_copy =
521         reinterpret_cast<uint8_t*>(dumper_->allocator()->Alloc(iter->length));
522       dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr,
523                                iter->length);
524 
525       UntypedMDRVA memory(&minidump_writer_);
526       if (!memory.Allocate(iter->length)) {
527         return false;
528       }
529       memory.Copy(data_copy, iter->length);
530       MDMemoryDescriptor desc;
531       desc.start_of_memory_range = reinterpret_cast<uintptr_t>(iter->ptr);
532       desc.memory = memory.location();
533       memory_blocks_.push_back(desc);
534     }
535 
536     return true;
537   }
538 
ShouldIncludeMapping(const MappingInfo & mapping)539   static bool ShouldIncludeMapping(const MappingInfo& mapping) {
540     if (mapping.name[0] == 0 ||  // only want modules with filenames.
541         // Only want to include one mapping per shared lib.
542         // Avoid filtering executable mappings.
543         (mapping.offset != 0 && !mapping.exec) ||
544         mapping.size < 4096) {  // too small to get a signature for.
545       return false;
546     }
547 
548     return true;
549   }
550 
551   // If there is caller-provided information about this mapping
552   // in the mapping_list_ list, return true. Otherwise, return false.
HaveMappingInfo(const MappingInfo & mapping)553   bool HaveMappingInfo(const MappingInfo& mapping) {
554     for (MappingList::const_iterator iter = mapping_list_.begin();
555          iter != mapping_list_.end();
556          ++iter) {
557       // Ignore any mappings that are wholly contained within
558       // mappings in the mapping_info_ list.
559       if (mapping.start_addr >= iter->first.start_addr &&
560           (mapping.start_addr + mapping.size) <=
561           (iter->first.start_addr + iter->first.size)) {
562         return true;
563       }
564     }
565     return false;
566   }
567 
568   // Write information about the mappings in effect. Because we are using the
569   // minidump format, the information about the mappings is pretty limited.
570   // Because of this, we also include the full, unparsed, /proc/$x/maps file in
571   // another stream in the file.
WriteMappings(MDRawDirectory * dirent)572   bool WriteMappings(MDRawDirectory* dirent) {
573     const unsigned num_mappings = dumper_->mappings().size();
574     unsigned num_output_mappings = mapping_list_.size();
575 
576     for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
577       const MappingInfo& mapping = *dumper_->mappings()[i];
578       if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
579         num_output_mappings++;
580     }
581 
582     TypedMDRVA<uint32_t> list(&minidump_writer_);
583     if (num_output_mappings) {
584       if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
585         return false;
586     } else {
587       // Still create the module list stream, although it will have zero
588       // modules.
589       if (!list.Allocate())
590         return false;
591     }
592 
593     dirent->stream_type = MD_MODULE_LIST_STREAM;
594     dirent->location = list.location();
595     *list.get() = num_output_mappings;
596 
597     // First write all the mappings from the dumper
598     unsigned int j = 0;
599     for (unsigned i = 0; i < num_mappings; ++i) {
600       const MappingInfo& mapping = *dumper_->mappings()[i];
601       if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
602         continue;
603 
604       MDRawModule mod;
605       if (!FillRawModule(mapping, true, i, &mod, NULL))
606         return false;
607       list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
608     }
609     // Next write all the mappings provided by the caller
610     for (MappingList::const_iterator iter = mapping_list_.begin();
611          iter != mapping_list_.end();
612          ++iter) {
613       MDRawModule mod;
614       if (!FillRawModule(iter->first, false, 0, &mod, iter->second))
615         return false;
616       list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
617     }
618 
619     return true;
620   }
621 
622   // Fill the MDRawModule |mod| with information about the provided
623   // |mapping|. If |identifier| is non-NULL, use it instead of calculating
624   // a file ID from the mapping.
FillRawModule(const MappingInfo & mapping,bool member,unsigned int mapping_id,MDRawModule * mod,const uint8_t * identifier)625   bool FillRawModule(const MappingInfo& mapping,
626                      bool member,
627                      unsigned int mapping_id,
628                      MDRawModule* mod,
629                      const uint8_t* identifier) {
630     my_memset(mod, 0, MD_MODULE_SIZE);
631 
632     mod->base_of_image = mapping.start_addr;
633     mod->size_of_image = mapping.size;
634 
635     auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
636         dumper_->allocator());
637 
638     if (identifier) {
639       // GUID was provided by caller.
640       identifier_bytes.insert(identifier_bytes.end(),
641                               identifier,
642                               identifier + sizeof(MDGUID));
643     } else {
644       // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
645       dumper_->ElfFileIdentifierForMapping(mapping,
646                                            member,
647                                            mapping_id,
648                                            identifier_bytes);
649     }
650 
651     if (!identifier_bytes.empty()) {
652       UntypedMDRVA cv(&minidump_writer_);
653       if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
654         return false;
655 
656       const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
657       cv.Copy(&cv_signature, sizeof(cv_signature));
658       cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
659               identifier_bytes.size());
660 
661       mod->cv_record = cv.location();
662     }
663 
664     char file_name[NAME_MAX];
665     char file_path[NAME_MAX];
666     dumper_->GetMappingEffectiveNameAndPath(
667         mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
668 
669     MDLocationDescriptor ld;
670     if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
671       return false;
672     mod->module_name_rva = ld.rva;
673     return true;
674   }
675 
WriteMemoryListStream(MDRawDirectory * dirent)676   bool WriteMemoryListStream(MDRawDirectory* dirent) {
677     TypedMDRVA<uint32_t> list(&minidump_writer_);
678     if (memory_blocks_.size()) {
679       if (!list.AllocateObjectAndArray(memory_blocks_.size(),
680                                        sizeof(MDMemoryDescriptor)))
681         return false;
682     } else {
683       // Still create the memory list stream, although it will have zero
684       // memory blocks.
685       if (!list.Allocate())
686         return false;
687     }
688 
689     dirent->stream_type = MD_MEMORY_LIST_STREAM;
690     dirent->location = list.location();
691 
692     *list.get() = memory_blocks_.size();
693 
694     for (size_t i = 0; i < memory_blocks_.size(); ++i) {
695       list.CopyIndexAfterObject(i, &memory_blocks_[i],
696                                 sizeof(MDMemoryDescriptor));
697     }
698     return true;
699   }
700 
WriteExceptionStream(MDRawDirectory * dirent)701   bool WriteExceptionStream(MDRawDirectory* dirent) {
702     TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
703     if (!exc.Allocate())
704       return false;
705 
706     MDRawExceptionStream* stream = exc.get();
707     my_memset(stream, 0, sizeof(MDRawExceptionStream));
708 
709     dirent->stream_type = MD_EXCEPTION_STREAM;
710     dirent->location = exc.location();
711 
712     stream->thread_id = GetCrashThread();
713     stream->exception_record.exception_code = dumper_->crash_signal();
714     stream->exception_record.exception_flags = dumper_->crash_signal_code();
715     stream->exception_record.exception_address = dumper_->crash_address();
716     const std::vector<uint64_t> crash_exception_info =
717         dumper_->crash_exception_info();
718     stream->exception_record.number_parameters = crash_exception_info.size();
719     memcpy(stream->exception_record.exception_information,
720            crash_exception_info.data(),
721            sizeof(uint64_t) * crash_exception_info.size());
722     stream->thread_context = crashing_thread_context_;
723 
724     return true;
725   }
726 
WriteSystemInfoStream(MDRawDirectory * dirent)727   bool WriteSystemInfoStream(MDRawDirectory* dirent) {
728     TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
729     if (!si.Allocate())
730       return false;
731     my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
732 
733     dirent->stream_type = MD_SYSTEM_INFO_STREAM;
734     dirent->location = si.location();
735 
736     WriteCPUInformation(si.get());
737     WriteOSInformation(si.get());
738 
739     return true;
740   }
741 
WriteDSODebugStream(MDRawDirectory * dirent)742   bool WriteDSODebugStream(MDRawDirectory* dirent) {
743     ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]);
744     char* base;
745     int phnum = dumper_->auxv()[AT_PHNUM];
746     if (!phnum || !phdr)
747       return false;
748 
749     // Assume the program base is at the beginning of the same page as the PHDR
750     base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
751 
752     // Search for the program PT_DYNAMIC segment
753     ElfW(Addr) dyn_addr = 0;
754     for (; phnum >= 0; phnum--, phdr++) {
755       ElfW(Phdr) ph;
756       if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph)))
757         return false;
758 
759       // Adjust base address with the virtual address of the PT_LOAD segment
760       // corresponding to offset 0
761       if (ph.p_type == PT_LOAD && ph.p_offset == 0) {
762         base -= ph.p_vaddr;
763       }
764       if (ph.p_type == PT_DYNAMIC) {
765         dyn_addr = ph.p_vaddr;
766       }
767     }
768     if (!dyn_addr)
769       return false;
770 
771     ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base);
772 
773     // The dynamic linker makes information available that helps gdb find all
774     // DSOs loaded into the program. If this information is indeed available,
775     // dump it to a MD_LINUX_DSO_DEBUG stream.
776     struct r_debug* r_debug = NULL;
777     uint32_t dynamic_length = 0;
778 
779     for (int i = 0; ; ++i) {
780       ElfW(Dyn) dyn;
781       dynamic_length += sizeof(dyn);
782       if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i,
783                                     sizeof(dyn))) {
784         return false;
785       }
786 
787 #ifdef __mips__
788       const int32_t debug_tag = DT_MIPS_RLD_MAP;
789 #else
790       const int32_t debug_tag = DT_DEBUG;
791 #endif
792       if (dyn.d_tag == debug_tag) {
793         r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
794         continue;
795       } else if (dyn.d_tag == DT_NULL) {
796         break;
797       }
798     }
799 
800     // The "r_map" field of that r_debug struct contains a linked list of all
801     // loaded DSOs.
802     // Our list of DSOs potentially is different from the ones in the crashing
803     // process. So, we have to be careful to never dereference pointers
804     // directly. Instead, we use CopyFromProcess() everywhere.
805     // See <link.h> for a more detailed discussion of the how the dynamic
806     // loader communicates with debuggers.
807 
808     // Count the number of loaded DSOs
809     int dso_count = 0;
810     struct r_debug debug_entry;
811     if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
812                                   sizeof(debug_entry))) {
813       return false;
814     }
815     for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
816       struct link_map map;
817       if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
818         return false;
819 
820       ptr = map.l_next;
821       dso_count++;
822     }
823 
824     MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
825     if (dso_count > 0) {
826       // If we have at least one DSO, create an array of MDRawLinkMap
827       // entries in the minidump file.
828       TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
829       if (!linkmap.AllocateArray(dso_count))
830         return false;
831       linkmap_rva = linkmap.location().rva;
832       int idx = 0;
833 
834       // Iterate over DSOs and write their information to mini dump
835       for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
836         struct link_map map;
837         if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
838           return  false;
839 
840         ptr = map.l_next;
841         char filename[257] = { 0 };
842         if (map.l_name) {
843           dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
844                                    sizeof(filename) - 1);
845         }
846         MDLocationDescriptor location;
847         if (!minidump_writer_.WriteString(filename, 0, &location))
848           return false;
849         MDRawLinkMap entry;
850         entry.name = location.rva;
851         entry.addr = map.l_addr;
852         entry.ld = reinterpret_cast<uintptr_t>(map.l_ld);
853         linkmap.CopyIndex(idx++, &entry);
854       }
855     }
856 
857     // Write MD_LINUX_DSO_DEBUG record
858     TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
859     if (!debug.AllocateObjectAndArray(1, dynamic_length))
860       return false;
861     my_memset(debug.get(), 0, sizeof(MDRawDebug));
862     dirent->stream_type = MD_LINUX_DSO_DEBUG;
863     dirent->location = debug.location();
864 
865     debug.get()->version = debug_entry.r_version;
866     debug.get()->map = linkmap_rva;
867     debug.get()->dso_count = dso_count;
868     debug.get()->brk = debug_entry.r_brk;
869     debug.get()->ldbase = debug_entry.r_ldbase;
870     debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic);
871 
872     wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length);
873     // The passed-in size to the constructor (above) is only a hint.
874     // Must call .resize() to do actual initialization of the elements.
875     dso_debug_data.resize(dynamic_length);
876     dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic,
877                              dynamic_length);
878     debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length);
879 
880     return true;
881   }
882 
set_minidump_size_limit(off_t limit)883   void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; }
884 
885  private:
Alloc(unsigned bytes)886   void* Alloc(unsigned bytes) {
887     return dumper_->allocator()->Alloc(bytes);
888   }
889 
GetCrashThread() const890   pid_t GetCrashThread() const {
891     return dumper_->crash_thread();
892   }
893 
NullifyDirectoryEntry(MDRawDirectory * dirent)894   void NullifyDirectoryEntry(MDRawDirectory* dirent) {
895     dirent->stream_type = 0;
896     dirent->location.data_size = 0;
897     dirent->location.rva = 0;
898   }
899 
900 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
WriteCPUInformation(MDRawSystemInfo * sys_info)901   bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
902     char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
903     static const char vendor_id_name[] = "vendor_id";
904 
905     struct CpuInfoEntry {
906       const char* info_name;
907       int value;
908       bool found;
909     } cpu_info_table[] = {
910       { "processor", -1, false },
911 #if defined(__i386__) || defined(__x86_64__)
912       { "model", 0, false },
913       { "stepping",  0, false },
914       { "cpu family", 0, false },
915 #endif
916     };
917 
918     // processor_architecture should always be set, do this first
919     sys_info->processor_architecture =
920 #if defined(__mips__)
921 # if _MIPS_SIM == _ABIO32
922         MD_CPU_ARCHITECTURE_MIPS;
923 # elif _MIPS_SIM == _ABI64
924         MD_CPU_ARCHITECTURE_MIPS64;
925 # else
926 #  error "This mips ABI is currently not supported (n32)"
927 #endif
928 #elif defined(__i386__)
929         MD_CPU_ARCHITECTURE_X86;
930 #else
931         MD_CPU_ARCHITECTURE_AMD64;
932 #endif
933 
934     const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
935     if (fd < 0)
936       return false;
937 
938     {
939       PageAllocator allocator;
940       ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd);
941       const char* field;
942       while (reader->GetNextField(&field)) {
943         bool is_first_entry = true;
944         for (CpuInfoEntry& entry : cpu_info_table) {
945           if (!is_first_entry && entry.found) {
946             // except for the 'processor' field, ignore repeated values.
947             continue;
948           }
949           is_first_entry = false;
950           if (!my_strcmp(field, entry.info_name)) {
951             size_t value_len;
952             const char* value = reader->GetValueAndLen(&value_len);
953             if (value_len == 0)
954               continue;
955 
956             uintptr_t val;
957             if (my_read_decimal_ptr(&val, value) == value)
958               continue;
959 
960             entry.value = static_cast<int>(val);
961             entry.found = true;
962           }
963         }
964 
965         // special case for vendor_id
966         if (!my_strcmp(field, vendor_id_name)) {
967           size_t value_len;
968           const char* value = reader->GetValueAndLen(&value_len);
969           if (value_len > 0)
970             my_strlcpy(vendor_id, value, sizeof(vendor_id));
971         }
972       }
973       sys_close(fd);
974     }
975 
976     // make sure we got everything we wanted
977     for (const CpuInfoEntry& entry : cpu_info_table) {
978       if (!entry.found) {
979         return false;
980       }
981     }
982     // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo,
983     // assuming this is the highest id, change it to the number of CPUs
984     // by adding one.
985     cpu_info_table[0].value++;
986 
987     sys_info->number_of_processors = cpu_info_table[0].value;
988 #if defined(__i386__) || defined(__x86_64__)
989     sys_info->processor_level      = cpu_info_table[3].value;
990     sys_info->processor_revision   = cpu_info_table[1].value << 8 |
991                                      cpu_info_table[2].value;
992 #endif
993 
994     if (vendor_id[0] != '\0') {
995       my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
996                 sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
997     }
998     return true;
999   }
1000 #elif defined(__arm__) || defined(__aarch64__)
WriteCPUInformation(MDRawSystemInfo * sys_info)1001   bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
1002     // The CPUID value is broken up in several entries in /proc/cpuinfo.
1003     // This table is used to rebuild it from the entries.
1004     const struct CpuIdEntry {
1005       const char* field;
1006       char        format;
1007       char        bit_lshift;
1008       char        bit_length;
1009     } cpu_id_entries[] = {
1010       { "CPU implementer", 'x', 24, 8 },
1011       { "CPU variant", 'x', 20, 4 },
1012       { "CPU part", 'x', 4, 12 },
1013       { "CPU revision", 'd', 0, 4 },
1014     };
1015 
1016     // The ELF hwcaps are listed in the "Features" entry as textual tags.
1017     // This table is used to rebuild them.
1018     const struct CpuFeaturesEntry {
1019       const char* tag;
1020       uint32_t hwcaps;
1021     } cpu_features_entries[] = {
1022 #if defined(__arm__)
1023       { "swp",  MD_CPU_ARM_ELF_HWCAP_SWP },
1024       { "half", MD_CPU_ARM_ELF_HWCAP_HALF },
1025       { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB },
1026       { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT },
1027       { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT },
1028       { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA },
1029       { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP },
1030       { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP },
1031       { "java", MD_CPU_ARM_ELF_HWCAP_JAVA },
1032       { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT },
1033       { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH },
1034       { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE },
1035       { "neon", MD_CPU_ARM_ELF_HWCAP_NEON },
1036       { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 },
1037       { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 },
1038       { "tls", MD_CPU_ARM_ELF_HWCAP_TLS },
1039       { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 },
1040       { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA },
1041       { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT },
1042       { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT },
1043 #elif defined(__aarch64__)
1044       // No hwcaps on aarch64.
1045 #endif
1046     };
1047 
1048     // processor_architecture should always be set, do this first
1049     sys_info->processor_architecture =
1050 #if defined(__aarch64__)
1051         MD_CPU_ARCHITECTURE_ARM64_OLD;
1052 #else
1053         MD_CPU_ARCHITECTURE_ARM;
1054 #endif
1055 
1056     // /proc/cpuinfo is not readable under various sandboxed environments
1057     // (e.g. Android services with the android:isolatedProcess attribute)
1058     // prepare for this by setting default values now, which will be
1059     // returned when this happens.
1060     //
1061     // Note: Bogus values are used to distinguish between failures (to
1062     //       read /sys and /proc files) and really badly configured kernels.
1063     sys_info->number_of_processors = 0;
1064     sys_info->processor_level = 1U;  // There is no ARMv1
1065     sys_info->processor_revision = 42;
1066     sys_info->cpu.arm_cpu_info.cpuid = 0;
1067     sys_info->cpu.arm_cpu_info.elf_hwcaps = 0;
1068 
1069     // Counting the number of CPUs involves parsing two sysfs files,
1070     // because the content of /proc/cpuinfo will only mirror the number
1071     // of 'online' cores, and thus will vary with time.
1072     // See http://www.kernel.org/doc/Documentation/cputopology.txt
1073     {
1074       CpuSet cpus_present;
1075       CpuSet cpus_possible;
1076 
1077       int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0);
1078       if (fd >= 0) {
1079         cpus_present.ParseSysFile(fd);
1080         sys_close(fd);
1081 
1082         fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0);
1083         if (fd >= 0) {
1084           cpus_possible.ParseSysFile(fd);
1085           sys_close(fd);
1086 
1087           cpus_present.IntersectWith(cpus_possible);
1088           int cpu_count = cpus_present.GetCount();
1089           if (cpu_count > 255)
1090             cpu_count = 255;
1091           sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
1092         }
1093       }
1094     }
1095 
1096     // Parse /proc/cpuinfo to reconstruct the CPUID value, as well
1097     // as the ELF hwcaps field. For the latter, it would be easier to
1098     // read /proc/self/auxv but unfortunately, this file is not always
1099     // readable from regular Android applications on later versions
1100     // (>= 4.1) of the Android platform.
1101     const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
1102     if (fd < 0) {
1103       // Do not return false here to allow the minidump generation
1104       // to happen properly.
1105       return true;
1106     }
1107 
1108     {
1109       PageAllocator allocator;
1110       ProcCpuInfoReader* const reader =
1111           new(allocator) ProcCpuInfoReader(fd);
1112       const char* field;
1113       while (reader->GetNextField(&field)) {
1114         for (const CpuIdEntry& entry : cpu_id_entries) {
1115           if (my_strcmp(entry.field, field) != 0)
1116             continue;
1117           uintptr_t result = 0;
1118           const char* value = reader->GetValue();
1119           const char* p = value;
1120           if (value[0] == '0' && value[1] == 'x') {
1121             p = my_read_hex_ptr(&result, value+2);
1122           } else if (entry.format == 'x') {
1123             p = my_read_hex_ptr(&result, value);
1124           } else {
1125             p = my_read_decimal_ptr(&result, value);
1126           }
1127           if (p == value)
1128             continue;
1129 
1130           result &= (1U << entry.bit_length)-1;
1131           result <<= entry.bit_lshift;
1132           sys_info->cpu.arm_cpu_info.cpuid |=
1133               static_cast<uint32_t>(result);
1134         }
1135 #if defined(__arm__)
1136         // Get the architecture version from the "Processor" field.
1137         // Note that it is also available in the "CPU architecture" field,
1138         // however, some existing kernels are misconfigured and will report
1139         // invalid values here (e.g. 6, while the CPU is ARMv7-A based).
1140         // The "Processor" field doesn't have this issue.
1141         if (!my_strcmp(field, "Processor")) {
1142           size_t value_len;
1143           const char* value = reader->GetValueAndLen(&value_len);
1144           // Expected format: <text> (v<level><endian>)
1145           // Where <text> is some text like "ARMv7 Processor rev 2"
1146           // and <level> is a decimal corresponding to the ARM
1147           // architecture number. <endian> is either 'l' or 'b'
1148           // and corresponds to the endianess, it is ignored here.
1149           while (value_len > 0 && my_isspace(value[value_len-1]))
1150             value_len--;
1151 
1152           size_t nn = value_len;
1153           while (nn > 0 && value[nn-1] != '(')
1154             nn--;
1155           if (nn > 0 && value[nn] == 'v') {
1156             uintptr_t arch_level = 5;
1157             my_read_decimal_ptr(&arch_level, value + nn + 1);
1158             sys_info->processor_level = static_cast<uint16_t>(arch_level);
1159           }
1160         }
1161 #elif defined(__aarch64__)
1162         // The aarch64 architecture does not provide the architecture level
1163         // in the Processor field, so we instead check the "CPU architecture"
1164         // field.
1165         if (!my_strcmp(field, "CPU architecture")) {
1166           uintptr_t arch_level = 0;
1167           const char* value = reader->GetValue();
1168           const char* p = value;
1169           p = my_read_decimal_ptr(&arch_level, value);
1170           if (p == value)
1171             continue;
1172           sys_info->processor_level = static_cast<uint16_t>(arch_level);
1173         }
1174 #endif
1175         // Rebuild the ELF hwcaps from the 'Features' field.
1176         if (!my_strcmp(field, "Features")) {
1177           size_t value_len;
1178           const char* value = reader->GetValueAndLen(&value_len);
1179 
1180           // Parse each space-separated tag.
1181           while (value_len > 0) {
1182             const char* tag = value;
1183             size_t tag_len = value_len;
1184             const char* p = my_strchr(tag, ' ');
1185             if (p) {
1186               tag_len = static_cast<size_t>(p - tag);
1187               value += tag_len + 1;
1188               value_len -= tag_len + 1;
1189             } else {
1190               tag_len = strlen(tag);
1191               value_len = 0;
1192             }
1193             for (const CpuFeaturesEntry& entry : cpu_features_entries) {
1194               if (tag_len == strlen(entry.tag) &&
1195                   !memcmp(tag, entry.tag, tag_len)) {
1196                 sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry.hwcaps;
1197                 break;
1198               }
1199             }
1200           }
1201         }
1202       }
1203       sys_close(fd);
1204     }
1205 
1206     return true;
1207   }
1208 #else
1209 #  error "Unsupported CPU"
1210 #endif
1211 
WriteFile(MDLocationDescriptor * result,const char * filename)1212   bool WriteFile(MDLocationDescriptor* result, const char* filename) {
1213     const int fd = sys_open(filename, O_RDONLY, 0);
1214     if (fd < 0)
1215       return false;
1216 
1217     // We can't stat the files because several of the files that we want to
1218     // read are kernel seqfiles, which always have a length of zero. So we have
1219     // to read as much as we can into a buffer.
1220     static const unsigned kBufSize = 1024 - 2*sizeof(void*);
1221     struct Buffers {
1222       Buffers* next;
1223       size_t len;
1224       uint8_t data[kBufSize];
1225     } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1226     buffers->next = NULL;
1227     buffers->len = 0;
1228 
1229     size_t total = 0;
1230     for (Buffers* bufptr = buffers;;) {
1231       ssize_t r;
1232       do {
1233         r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
1234       } while (r == -1 && errno == EINTR);
1235 
1236       if (r < 1)
1237         break;
1238 
1239       total += r;
1240       bufptr->len += r;
1241       if (bufptr->len == kBufSize) {
1242         bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1243         bufptr = bufptr->next;
1244         bufptr->next = NULL;
1245         bufptr->len = 0;
1246       }
1247     }
1248     sys_close(fd);
1249 
1250     if (!total)
1251       return false;
1252 
1253     UntypedMDRVA memory(&minidump_writer_);
1254     if (!memory.Allocate(total))
1255       return false;
1256     for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
1257       // Check for special case of a zero-length buffer.  This should only
1258       // occur if a file's size happens to be a multiple of the buffer's
1259       // size, in which case the final sys_read() will have resulted in
1260       // zero bytes being read after the final buffer was just allocated.
1261       if (buffers->len == 0) {
1262         // This can only occur with final buffer.
1263         assert(buffers->next == NULL);
1264         continue;
1265       }
1266       memory.Copy(pos, &buffers->data, buffers->len);
1267       pos += buffers->len;
1268     }
1269     *result = memory.location();
1270     return true;
1271   }
1272 
WriteOSInformation(MDRawSystemInfo * sys_info)1273   bool WriteOSInformation(MDRawSystemInfo* sys_info) {
1274 #if defined(__ANDROID__)
1275     sys_info->platform_id = MD_OS_ANDROID;
1276 #else
1277     sys_info->platform_id = MD_OS_LINUX;
1278 #endif
1279 
1280     struct utsname uts;
1281     if (uname(&uts))
1282       return false;
1283 
1284     static const size_t buf_len = 512;
1285     char buf[buf_len] = {0};
1286     size_t space_left = buf_len - 1;
1287     const char* info_table[] = {
1288       uts.sysname,
1289       uts.release,
1290       uts.version,
1291       uts.machine,
1292       NULL
1293     };
1294     bool first_item = true;
1295     for (const char** cur_info = info_table; *cur_info; cur_info++) {
1296       static const char separator[] = " ";
1297       size_t separator_len = sizeof(separator) - 1;
1298       size_t info_len = my_strlen(*cur_info);
1299       if (info_len == 0)
1300         continue;
1301 
1302       if (space_left < info_len + (first_item ? 0 : separator_len))
1303         break;
1304 
1305       if (!first_item) {
1306         my_strlcat(buf, separator, sizeof(buf));
1307         space_left -= separator_len;
1308       }
1309 
1310       first_item = false;
1311       my_strlcat(buf, *cur_info, sizeof(buf));
1312       space_left -= info_len;
1313     }
1314 
1315     MDLocationDescriptor location;
1316     if (!minidump_writer_.WriteString(buf, 0, &location))
1317       return false;
1318     sys_info->csd_version_rva = location.rva;
1319 
1320     return true;
1321   }
1322 
WriteProcFile(MDLocationDescriptor * result,pid_t pid,const char * filename)1323   bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
1324                      const char* filename) {
1325     char buf[NAME_MAX];
1326     if (!dumper_->BuildProcPath(buf, pid, filename))
1327       return false;
1328     return WriteFile(result, buf);
1329   }
1330 
1331   // Only one of the 2 member variables below should be set to a valid value.
1332   const int fd_;  // File descriptor where the minidum should be written.
1333   const char* path_;  // Path to the file where the minidum should be written.
1334 
1335   const ucontext_t* const ucontext_;  // also from the signal handler
1336 #if !defined(__ARM_EABI__) && !defined(__mips__)
1337   const google_breakpad::fpstate_t* const float_state_;  // ditto
1338 #endif
1339   LinuxDumper* dumper_;
1340   MinidumpFileWriter minidump_writer_;
1341   off_t minidump_size_limit_;
1342   MDLocationDescriptor crashing_thread_context_;
1343   // Blocks of memory written to the dump. These are all currently
1344   // written while writing the thread list stream, but saved here
1345   // so a memory list stream can be written afterwards.
1346   wasteful_vector<MDMemoryDescriptor> memory_blocks_;
1347   // Additional information about some mappings provided by the caller.
1348   const MappingList& mapping_list_;
1349   // Additional memory regions to be included in the dump,
1350   // provided by the caller.
1351   const AppMemoryList& app_memory_list_;
1352   // If set, skip recording any threads that do not reference the
1353   // mapping containing principal_mapping_address_.
1354   bool skip_stacks_if_mapping_unreferenced_;
1355   uintptr_t principal_mapping_address_;
1356   const MappingInfo* principal_mapping_;
1357   // If true, apply stack sanitization to stored stack data.
1358   bool sanitize_stacks_;
1359 };
1360 
1361 
WriteMinidumpImpl(const char * minidump_path,int minidump_fd,off_t minidump_size_limit,pid_t crashing_process,const void * blob,size_t blob_size,const MappingList & mappings,const AppMemoryList & appmem,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1362 bool WriteMinidumpImpl(const char* minidump_path,
1363                        int minidump_fd,
1364                        off_t minidump_size_limit,
1365                        pid_t crashing_process,
1366                        const void* blob, size_t blob_size,
1367                        const MappingList& mappings,
1368                        const AppMemoryList& appmem,
1369                        bool skip_stacks_if_mapping_unreferenced,
1370                        uintptr_t principal_mapping_address,
1371                        bool sanitize_stacks) {
1372   LinuxPtraceDumper dumper(crashing_process);
1373   const ExceptionHandler::CrashContext* context = NULL;
1374   if (blob) {
1375     if (blob_size != sizeof(ExceptionHandler::CrashContext))
1376       return false;
1377     context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
1378     dumper.SetCrashInfoFromSigInfo(context->siginfo);
1379     dumper.set_crash_thread(context->tid);
1380   }
1381   MinidumpWriter writer(minidump_path, minidump_fd, context, mappings,
1382                         appmem, skip_stacks_if_mapping_unreferenced,
1383                         principal_mapping_address, sanitize_stacks, &dumper);
1384   // Set desired limit for file size of minidump (-1 means no limit).
1385   writer.set_minidump_size_limit(minidump_size_limit);
1386   if (!writer.Init())
1387     return false;
1388   return writer.Dump();
1389 }
1390 
1391 }  // namespace
1392 
1393 namespace google_breakpad {
1394 
WriteMinidump(const char * minidump_path,pid_t crashing_process,const void * blob,size_t blob_size,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1395 bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
1396                    const void* blob, size_t blob_size,
1397                    bool skip_stacks_if_mapping_unreferenced,
1398                    uintptr_t principal_mapping_address,
1399                    bool sanitize_stacks) {
1400   return WriteMinidumpImpl(minidump_path, -1, -1,
1401                            crashing_process, blob, blob_size,
1402                            MappingList(), AppMemoryList(),
1403                            skip_stacks_if_mapping_unreferenced,
1404                            principal_mapping_address,
1405                            sanitize_stacks);
1406 }
1407 
WriteMinidump(int minidump_fd,pid_t crashing_process,const void * blob,size_t blob_size,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1408 bool WriteMinidump(int minidump_fd, pid_t crashing_process,
1409                    const void* blob, size_t blob_size,
1410                    bool skip_stacks_if_mapping_unreferenced,
1411                    uintptr_t principal_mapping_address,
1412                    bool sanitize_stacks) {
1413   return WriteMinidumpImpl(NULL, minidump_fd, -1,
1414                            crashing_process, blob, blob_size,
1415                            MappingList(), AppMemoryList(),
1416                            skip_stacks_if_mapping_unreferenced,
1417                            principal_mapping_address,
1418                            sanitize_stacks);
1419 }
1420 
WriteMinidump(const char * minidump_path,pid_t process,pid_t process_blamed_thread)1421 bool WriteMinidump(const char* minidump_path, pid_t process,
1422                    pid_t process_blamed_thread) {
1423   LinuxPtraceDumper dumper(process);
1424   // MinidumpWriter will set crash address
1425   dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED);
1426   dumper.set_crash_thread(process_blamed_thread);
1427   MappingList mapping_list;
1428   AppMemoryList app_memory_list;
1429   MinidumpWriter writer(minidump_path, -1, NULL, mapping_list,
1430                         app_memory_list, false, 0, false, &dumper);
1431   if (!writer.Init())
1432     return false;
1433   return writer.Dump();
1434 }
1435 
WriteMinidump(const char * minidump_path,pid_t crashing_process,const void * blob,size_t blob_size,const MappingList & mappings,const AppMemoryList & appmem,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1436 bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
1437                    const void* blob, size_t blob_size,
1438                    const MappingList& mappings,
1439                    const AppMemoryList& appmem,
1440                    bool skip_stacks_if_mapping_unreferenced,
1441                    uintptr_t principal_mapping_address,
1442                    bool sanitize_stacks) {
1443   return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process,
1444                            blob, blob_size,
1445                            mappings, appmem,
1446                            skip_stacks_if_mapping_unreferenced,
1447                            principal_mapping_address,
1448                            sanitize_stacks);
1449 }
1450 
WriteMinidump(int minidump_fd,pid_t crashing_process,const void * blob,size_t blob_size,const MappingList & mappings,const AppMemoryList & appmem,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1451 bool WriteMinidump(int minidump_fd, pid_t crashing_process,
1452                    const void* blob, size_t blob_size,
1453                    const MappingList& mappings,
1454                    const AppMemoryList& appmem,
1455                    bool skip_stacks_if_mapping_unreferenced,
1456                    uintptr_t principal_mapping_address,
1457                    bool sanitize_stacks) {
1458   return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process,
1459                            blob, blob_size,
1460                            mappings, appmem,
1461                            skip_stacks_if_mapping_unreferenced,
1462                            principal_mapping_address,
1463                            sanitize_stacks);
1464 }
1465 
WriteMinidump(const char * minidump_path,off_t minidump_size_limit,pid_t crashing_process,const void * blob,size_t blob_size,const MappingList & mappings,const AppMemoryList & appmem,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1466 bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
1467                    pid_t crashing_process,
1468                    const void* blob, size_t blob_size,
1469                    const MappingList& mappings,
1470                    const AppMemoryList& appmem,
1471                    bool skip_stacks_if_mapping_unreferenced,
1472                    uintptr_t principal_mapping_address,
1473                    bool sanitize_stacks) {
1474   return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit,
1475                            crashing_process, blob, blob_size,
1476                            mappings, appmem,
1477                            skip_stacks_if_mapping_unreferenced,
1478                            principal_mapping_address,
1479                            sanitize_stacks);
1480 }
1481 
WriteMinidump(int minidump_fd,off_t minidump_size_limit,pid_t crashing_process,const void * blob,size_t blob_size,const MappingList & mappings,const AppMemoryList & appmem,bool skip_stacks_if_mapping_unreferenced,uintptr_t principal_mapping_address,bool sanitize_stacks)1482 bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
1483                    pid_t crashing_process,
1484                    const void* blob, size_t blob_size,
1485                    const MappingList& mappings,
1486                    const AppMemoryList& appmem,
1487                    bool skip_stacks_if_mapping_unreferenced,
1488                    uintptr_t principal_mapping_address,
1489                    bool sanitize_stacks) {
1490   return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit,
1491                            crashing_process, blob, blob_size,
1492                            mappings, appmem,
1493                            skip_stacks_if_mapping_unreferenced,
1494                            principal_mapping_address,
1495                            sanitize_stacks);
1496 }
1497 
WriteMinidump(const char * filename,const MappingList & mappings,const AppMemoryList & appmem,LinuxDumper * dumper)1498 bool WriteMinidump(const char* filename,
1499                    const MappingList& mappings,
1500                    const AppMemoryList& appmem,
1501                    LinuxDumper* dumper) {
1502   MinidumpWriter writer(filename, -1, NULL, mappings, appmem,
1503                         false, 0, false, dumper);
1504   if (!writer.Init())
1505     return false;
1506   return writer.Dump();
1507 }
1508 
1509 }  // namespace google_breakpad
1510