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