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