1 : // Copyright (c) 2009, Google Inc.
2 : // All rights reserved.
3 : //
4 : // Redistribution and use in source and binary forms, with or without
5 : // modification, are permitted provided that the following conditions are
6 : // met:
7 : //
8 : // * Redistributions of source code must retain the above copyright
9 : // notice, this list of conditions and the following disclaimer.
10 : // * Redistributions in binary form must reproduce the above
11 : // copyright notice, this list of conditions and the following disclaimer
12 : // in the documentation and/or other materials provided with the
13 : // distribution.
14 : // * Neither the name of Google Inc. nor the names of its
15 : // contributors may be used to endorse or promote products derived from
16 : // this software without specific prior written permission.
17 : //
18 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 :
30 : // This code writes out minidump files:
31 : // http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
32 : //
33 : // Minidumps are a Microsoft format which Breakpad uses for recording crash
34 : // dumps. This code has to run in a compromised environment (the address space
35 : // may have received SIGSEGV), thus the following rules apply:
36 : // * You may not enter the dynamic linker. This means that we cannot call
37 : // any symbols in a shared library (inc libc). Because of this we replace
38 : // libc functions in linux_libc_support.h.
39 : // * You may not call syscalls via the libc wrappers. This rule is a subset
40 : // of the first rule but it bears repeating. We have direct wrappers
41 : // around the system calls in linux_syscall_support.h.
42 : // * You may not malloc. There's an alternative allocator in memory.h and
43 : // a canonical instance in the LinuxDumper object. We use the placement
44 : // new form to allocate objects and we don't delete them.
45 :
46 : #include "client/linux/minidump_writer/minidump_writer.h"
47 : #include "client/minidump_file_writer-inl.h"
48 :
49 : #include <algorithm>
50 :
51 : #include <errno.h>
52 : #include <fcntl.h>
53 : #if defined(__ANDROID__)
54 : #include "client/linux/android_link.h"
55 : #else
56 : #include <link.h>
57 : #endif
58 : #include <stdio.h>
59 : #include <unistd.h>
60 : #include <ctype.h>
61 : #if !defined(__ANDROID__)
62 : #include <sys/ucontext.h>
63 : #include <sys/user.h>
64 : #endif
65 : #include <sys/utsname.h>
66 :
67 : #include "client/minidump_file_writer.h"
68 : #include "google_breakpad/common/minidump_format.h"
69 : #include "google_breakpad/common/minidump_cpu_amd64.h"
70 : #include "google_breakpad/common/minidump_cpu_x86.h"
71 :
72 : #include "client/linux/android_ucontext.h"
73 : #include "client/linux/handler/exception_handler.h"
74 : #include "client/linux/minidump_writer/line_reader.h"
75 : #include "client/linux/minidump_writer/linux_dumper.h"
76 : #include "client/linux/minidump_writer/minidump_extension_linux.h"
77 : #include "common/linux/linux_libc_support.h"
78 : #include "common/linux/linux_syscall_support.h"
79 :
80 : using google_breakpad::ThreadInfo;
81 :
82 : // Minidump defines register structures which are different from the raw
83 : // structures which we get from the kernel. These are platform specific
84 : // functions to juggle the ucontext and user structures into minidump format.
85 : #if defined(__i386)
86 : typedef MDRawContextX86 RawContextCPU;
87 :
88 : // Write a uint16_t to memory
89 : // out: memory location to write to
90 : // v: value to write.
91 0 : static void U16(void* out, uint16_t v) {
92 0 : memcpy(out, &v, sizeof(v));
93 0 : }
94 :
95 : // Write a uint32_t to memory
96 : // out: memory location to write to
97 : // v: value to write.
98 0 : static void U32(void* out, uint32_t v) {
99 0 : memcpy(out, &v, sizeof(v));
100 0 : }
101 :
102 : // Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
103 : // out: the minidump structure
104 : // info: the collection of register structures.
105 0 : static void CPUFillFromThreadInfo(MDRawContextX86 *out,
106 : const ThreadInfo &info) {
107 0 : out->context_flags = MD_CONTEXT_X86_ALL;
108 :
109 0 : out->dr0 = info.dregs[0];
110 0 : out->dr1 = info.dregs[1];
111 0 : out->dr2 = info.dregs[2];
112 0 : out->dr3 = info.dregs[3];
113 : // 4 and 5 deliberatly omitted because they aren't included in the minidump
114 : // format.
115 0 : out->dr6 = info.dregs[6];
116 0 : out->dr7 = info.dregs[7];
117 :
118 0 : out->gs = info.regs.xgs;
119 0 : out->fs = info.regs.xfs;
120 0 : out->es = info.regs.xes;
121 0 : out->ds = info.regs.xds;
122 :
123 0 : out->edi = info.regs.edi;
124 0 : out->esi = info.regs.esi;
125 0 : out->ebx = info.regs.ebx;
126 0 : out->edx = info.regs.edx;
127 0 : out->ecx = info.regs.ecx;
128 0 : out->eax = info.regs.eax;
129 :
130 0 : out->ebp = info.regs.ebp;
131 0 : out->eip = info.regs.eip;
132 0 : out->cs = info.regs.xcs;
133 0 : out->eflags = info.regs.eflags;
134 0 : out->esp = info.regs.esp;
135 0 : out->ss = info.regs.xss;
136 :
137 0 : out->float_save.control_word = info.fpregs.cwd;
138 0 : out->float_save.status_word = info.fpregs.swd;
139 0 : out->float_save.tag_word = info.fpregs.twd;
140 0 : out->float_save.error_offset = info.fpregs.fip;
141 0 : out->float_save.error_selector = info.fpregs.fcs;
142 0 : out->float_save.data_offset = info.fpregs.foo;
143 0 : out->float_save.data_selector = info.fpregs.fos;
144 :
145 : // 8 registers * 10 bytes per register.
146 0 : memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
147 :
148 : // This matches the Intel fpsave format.
149 0 : U16(out->extended_registers + 0, info.fpregs.cwd);
150 0 : U16(out->extended_registers + 2, info.fpregs.swd);
151 0 : U16(out->extended_registers + 4, info.fpregs.twd);
152 0 : U16(out->extended_registers + 6, info.fpxregs.fop);
153 0 : U32(out->extended_registers + 8, info.fpxregs.fip);
154 0 : U16(out->extended_registers + 12, info.fpxregs.fcs);
155 0 : U32(out->extended_registers + 16, info.fpregs.foo);
156 0 : U16(out->extended_registers + 20, info.fpregs.fos);
157 0 : U32(out->extended_registers + 24, info.fpxregs.mxcsr);
158 :
159 0 : memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
160 0 : memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
161 0 : }
162 :
163 : // Juggle an x86 ucontext into minidump format
164 : // out: the minidump structure
165 : // info: the collection of register structures.
166 0 : static void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
167 : const struct _libc_fpstate* fp) {
168 0 : const greg_t* regs = uc->uc_mcontext.gregs;
169 :
170 : out->context_flags = MD_CONTEXT_X86_FULL |
171 0 : MD_CONTEXT_X86_FLOATING_POINT;
172 :
173 0 : out->gs = regs[REG_GS];
174 0 : out->fs = regs[REG_FS];
175 0 : out->es = regs[REG_ES];
176 0 : out->ds = regs[REG_DS];
177 :
178 0 : out->edi = regs[REG_EDI];
179 0 : out->esi = regs[REG_ESI];
180 0 : out->ebx = regs[REG_EBX];
181 0 : out->edx = regs[REG_EDX];
182 0 : out->ecx = regs[REG_ECX];
183 0 : out->eax = regs[REG_EAX];
184 :
185 0 : out->ebp = regs[REG_EBP];
186 0 : out->eip = regs[REG_EIP];
187 0 : out->cs = regs[REG_CS];
188 0 : out->eflags = regs[REG_EFL];
189 0 : out->esp = regs[REG_UESP];
190 0 : out->ss = regs[REG_SS];
191 :
192 0 : out->float_save.control_word = fp->cw;
193 0 : out->float_save.status_word = fp->sw;
194 0 : out->float_save.tag_word = fp->tag;
195 0 : out->float_save.error_offset = fp->ipoff;
196 0 : out->float_save.error_selector = fp->cssel;
197 0 : out->float_save.data_offset = fp->dataoff;
198 0 : out->float_save.data_selector = fp->datasel;
199 :
200 : // 8 registers * 10 bytes per register.
201 0 : memcpy(out->float_save.register_area, fp->_st, 10 * 8);
202 0 : }
203 :
204 0 : static uintptr_t InstructionPointer(const ThreadInfo& info) {
205 0 : return info.regs.eip;
206 : }
207 :
208 0 : static uintptr_t StackPointer(const ThreadInfo& info) {
209 0 : return info.regs.esp;
210 : }
211 :
212 0 : static uintptr_t StackPointer(const ucontext* uc) {
213 0 : return uc->uc_mcontext.gregs[REG_ESP];
214 : }
215 :
216 : #elif defined(__x86_64)
217 : typedef MDRawContextAMD64 RawContextCPU;
218 :
219 : static void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
220 : const ThreadInfo &info) {
221 : out->context_flags = MD_CONTEXT_AMD64_FULL |
222 : MD_CONTEXT_AMD64_SEGMENTS;
223 :
224 : out->cs = info.regs.cs;
225 :
226 : out->ds = info.regs.ds;
227 : out->es = info.regs.es;
228 : out->fs = info.regs.fs;
229 : out->gs = info.regs.gs;
230 :
231 : out->ss = info.regs.ss;
232 : out->eflags = info.regs.eflags;
233 :
234 : out->dr0 = info.dregs[0];
235 : out->dr1 = info.dregs[1];
236 : out->dr2 = info.dregs[2];
237 : out->dr3 = info.dregs[3];
238 : // 4 and 5 deliberatly omitted because they aren't included in the minidump
239 : // format.
240 : out->dr6 = info.dregs[6];
241 : out->dr7 = info.dregs[7];
242 :
243 : out->rax = info.regs.rax;
244 : out->rcx = info.regs.rcx;
245 : out->rdx = info.regs.rdx;
246 : out->rbx = info.regs.rbx;
247 :
248 : out->rsp = info.regs.rsp;
249 :
250 : out->rbp = info.regs.rbp;
251 : out->rsi = info.regs.rsi;
252 : out->rdi = info.regs.rdi;
253 : out->r8 = info.regs.r8;
254 : out->r9 = info.regs.r9;
255 : out->r10 = info.regs.r10;
256 : out->r11 = info.regs.r11;
257 : out->r12 = info.regs.r12;
258 : out->r13 = info.regs.r13;
259 : out->r14 = info.regs.r14;
260 : out->r15 = info.regs.r15;
261 :
262 : out->rip = info.regs.rip;
263 :
264 : out->flt_save.control_word = info.fpregs.cwd;
265 : out->flt_save.status_word = info.fpregs.swd;
266 : out->flt_save.tag_word = info.fpregs.ftw;
267 : out->flt_save.error_opcode = info.fpregs.fop;
268 : out->flt_save.error_offset = info.fpregs.rip;
269 : out->flt_save.error_selector = 0; // We don't have this.
270 : out->flt_save.data_offset = info.fpregs.rdp;
271 : out->flt_save.data_selector = 0; // We don't have this.
272 : out->flt_save.mx_csr = info.fpregs.mxcsr;
273 : out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
274 : memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
275 : memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
276 : }
277 :
278 : static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
279 : const struct _libc_fpstate* fpregs) {
280 : const greg_t* regs = uc->uc_mcontext.gregs;
281 :
282 : out->context_flags = MD_CONTEXT_AMD64_FULL;
283 :
284 : out->cs = regs[REG_CSGSFS] & 0xffff;
285 :
286 : out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
287 : out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
288 :
289 : out->eflags = regs[REG_EFL];
290 :
291 : out->rax = regs[REG_RAX];
292 : out->rcx = regs[REG_RCX];
293 : out->rdx = regs[REG_RDX];
294 : out->rbx = regs[REG_RBX];
295 :
296 : out->rsp = regs[REG_RSP];
297 : out->rbp = regs[REG_RBP];
298 : out->rsi = regs[REG_RSI];
299 : out->rdi = regs[REG_RDI];
300 : out->r8 = regs[REG_R8];
301 : out->r9 = regs[REG_R9];
302 : out->r10 = regs[REG_R10];
303 : out->r11 = regs[REG_R11];
304 : out->r12 = regs[REG_R12];
305 : out->r13 = regs[REG_R13];
306 : out->r14 = regs[REG_R14];
307 : out->r15 = regs[REG_R15];
308 :
309 : out->rip = regs[REG_RIP];
310 :
311 : out->flt_save.control_word = fpregs->cwd;
312 : out->flt_save.status_word = fpregs->swd;
313 : out->flt_save.tag_word = fpregs->ftw;
314 : out->flt_save.error_opcode = fpregs->fop;
315 : out->flt_save.error_offset = fpregs->rip;
316 : out->flt_save.data_offset = fpregs->rdp;
317 : out->flt_save.error_selector = 0; // We don't have this.
318 : out->flt_save.data_selector = 0; // We don't have this.
319 : out->flt_save.mx_csr = fpregs->mxcsr;
320 : out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
321 : memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
322 : memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
323 : }
324 :
325 : static uintptr_t InstructionPointer(const ThreadInfo& info) {
326 : return info.regs.rip;
327 : }
328 :
329 : static uintptr_t StackPointer(const ThreadInfo& info) {
330 : return info.regs.rsp;
331 : }
332 :
333 : static uintptr_t StackPointer(const ucontext* uc) {
334 : return uc->uc_mcontext.gregs[REG_RSP];
335 : }
336 :
337 : #elif defined(__ARMEL__)
338 : typedef MDRawContextARM RawContextCPU;
339 :
340 : static void CPUFillFromThreadInfo(MDRawContextARM *out,
341 : const ThreadInfo &info) {
342 : out->context_flags = MD_CONTEXT_ARM_FULL;
343 :
344 : for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
345 : out->iregs[i] = info.regs.uregs[i];
346 : // No CPSR register in ThreadInfo(it's not accessible via ptrace)
347 : out->cpsr = 0;
348 : #if !defined(__ANDROID__)
349 : out->float_save.fpscr = info.fpregs.fpsr |
350 : (static_cast<u_int64_t>(info.fpregs.fpcr) << 32);
351 : //TODO: sort this out, actually collect floating point registers
352 : memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
353 : memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
354 : #endif
355 : }
356 :
357 : static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
358 : const struct _libc_fpstate* fpregs) {
359 : out->context_flags = MD_CONTEXT_ARM_FULL;
360 :
361 : out->iregs[0] = uc->uc_mcontext.arm_r0;
362 : out->iregs[1] = uc->uc_mcontext.arm_r1;
363 : out->iregs[2] = uc->uc_mcontext.arm_r2;
364 : out->iregs[3] = uc->uc_mcontext.arm_r3;
365 : out->iregs[4] = uc->uc_mcontext.arm_r4;
366 : out->iregs[5] = uc->uc_mcontext.arm_r5;
367 : out->iregs[6] = uc->uc_mcontext.arm_r6;
368 : out->iregs[7] = uc->uc_mcontext.arm_r7;
369 : out->iregs[8] = uc->uc_mcontext.arm_r8;
370 : out->iregs[9] = uc->uc_mcontext.arm_r9;
371 : out->iregs[10] = uc->uc_mcontext.arm_r10;
372 :
373 : out->iregs[11] = uc->uc_mcontext.arm_fp;
374 : out->iregs[12] = uc->uc_mcontext.arm_ip;
375 : out->iregs[13] = uc->uc_mcontext.arm_sp;
376 : out->iregs[14] = uc->uc_mcontext.arm_lr;
377 : out->iregs[15] = uc->uc_mcontext.arm_pc;
378 :
379 : out->cpsr = uc->uc_mcontext.arm_cpsr;
380 :
381 : //TODO: fix this after fixing ExceptionHandler
382 : out->float_save.fpscr = 0;
383 : memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
384 : memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
385 : }
386 :
387 : static uintptr_t InstructionPointer(const ThreadInfo& info) {
388 : return info.regs.ARM_ip;
389 : }
390 :
391 : static uintptr_t StackPointer(const ThreadInfo& info) {
392 : return info.regs.ARM_sp;
393 : }
394 :
395 : static uintptr_t StackPointer(const ucontext* uc) {
396 : return uc->uc_mcontext.arm_sp;
397 : }
398 :
399 : #else
400 : #error "This code has not been ported to your platform yet."
401 : #endif
402 :
403 : namespace google_breakpad {
404 :
405 : // There are two uses of MinidumpWriter:
406 : //
407 : // (1) dumping a process in which a thread has crashed and is blocked
408 : // in a signal handler
409 : // (2) dumping a live process
410 : //
411 : // In case (1), we get the ucontext and fpstate of the crashing_tid_
412 : // from the signal handler. In case (2), we have to extract it using
413 : // ptrace, and we can't assume that crashing_tid_ still exists (or
414 : // ever did).
415 : class MinidumpWriter {
416 : public:
417 : // case (1) above
418 0 : MinidumpWriter(const char* filename,
419 : pid_t crashing_pid,
420 : const ExceptionHandler::CrashContext* context,
421 : const MappingList& mappings,
422 : const AppMemoryList& appmem)
423 : : filename_(filename),
424 : siginfo_(&context->siginfo),
425 : ucontext_(&context->context),
426 : #if !defined(__ARM_EABI__)
427 : float_state_(&context->float_state),
428 : #else
429 : //TODO: fix this after fixing ExceptionHandler
430 : float_state_(NULL),
431 : #endif
432 : crashing_tid_(context->tid),
433 : crashing_tid_pc_(0),
434 : dumper_(crashing_pid),
435 : memory_blocks_(dumper_.allocator()),
436 : mapping_info_(mappings),
437 0 : app_memory_info_(appmem) {
438 0 : }
439 :
440 : // case (2) above
441 0 : MinidumpWriter(const char* filename,
442 : pid_t pid,
443 : pid_t blame_thread,
444 : const MappingList& mappings,
445 : const AppMemoryList& appmem)
446 : : filename_(filename),
447 : siginfo_(NULL), // we fill this in if we find blame_thread
448 : ucontext_(NULL),
449 : float_state_(NULL),
450 : crashing_tid_(blame_thread),
451 : crashing_tid_pc_(0), // set if we find blame_thread
452 : dumper_(pid),
453 : memory_blocks_(dumper_.allocator()),
454 : mapping_info_(mappings),
455 0 : app_memory_info_(appmem) {
456 0 : }
457 :
458 0 : bool Init() {
459 0 : return dumper_.Init() && minidump_writer_.Open(filename_) &&
460 0 : dumper_.ThreadsAttach();
461 : }
462 :
463 0 : ~MinidumpWriter() {
464 0 : minidump_writer_.Close();
465 0 : dumper_.ThreadsDetach();
466 0 : }
467 :
468 0 : bool HaveCrashedThread() const {
469 0 : return ucontext_ != NULL;
470 : }
471 :
472 0 : bool Dump() {
473 : // The dynamic linker makes information available that helps gdb find all
474 : // DSOs loaded into the program. If we can access this information, we dump
475 : // it to a MD_LINUX_DSO_DEBUG stream.
476 0 : struct r_debug* r_debug = NULL;
477 0 : uint32_t dynamic_length = 0;
478 : #if !defined(__ANDROID__)
479 0 : for (int i = 0;;) {
480 : ElfW(Dyn) dyn;
481 0 : dynamic_length += sizeof(dyn);
482 0 : dumper_.CopyFromProcess(&dyn, crashing_tid_, _DYNAMIC+i++, sizeof(dyn));
483 0 : if (dyn.d_tag == DT_DEBUG) {
484 0 : r_debug = (struct r_debug*)dyn.d_un.d_ptr;
485 0 : continue;
486 0 : } else if (dyn.d_tag == DT_NULL)
487 : break;
488 : }
489 : #endif
490 :
491 : // A minidump file contains a number of tagged streams. This is the number
492 : // of stream which we write.
493 0 : unsigned kNumWriters = 12;
494 0 : if (r_debug)
495 0 : ++kNumWriters;
496 :
497 0 : TypedMDRVA<MDRawHeader> header(&minidump_writer_);
498 0 : TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
499 0 : if (!header.Allocate())
500 0 : return false;
501 0 : if (!dir.AllocateArray(kNumWriters))
502 0 : return false;
503 0 : memset(header.get(), 0, sizeof(MDRawHeader));
504 :
505 0 : header.get()->signature = MD_HEADER_SIGNATURE;
506 0 : header.get()->version = MD_HEADER_VERSION;
507 0 : header.get()->time_date_stamp = time(NULL);
508 0 : header.get()->stream_count = kNumWriters;
509 0 : header.get()->stream_directory_rva = dir.position();
510 :
511 0 : unsigned dir_index = 0;
512 : MDRawDirectory dirent;
513 :
514 0 : if (!WriteThreadListStream(&dirent))
515 0 : return false;
516 0 : dir.CopyIndex(dir_index++, &dirent);
517 :
518 0 : if (!WriteMappings(&dirent))
519 0 : return false;
520 0 : dir.CopyIndex(dir_index++, &dirent);
521 :
522 0 : if (!WriteAppMemory())
523 0 : return false;
524 :
525 0 : if (!WriteMemoryListStream(&dirent))
526 0 : return false;
527 0 : dir.CopyIndex(dir_index++, &dirent);
528 :
529 0 : if (siginfo_ || crashing_tid_pc_) {
530 0 : if (!WriteExceptionStream(&dirent))
531 0 : return false;
532 0 : dir.CopyIndex(dir_index++, &dirent);
533 : }
534 :
535 0 : if (!WriteSystemInfoStream(&dirent))
536 0 : return false;
537 0 : dir.CopyIndex(dir_index++, &dirent);
538 :
539 0 : dirent.stream_type = MD_LINUX_CPU_INFO;
540 0 : if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
541 0 : NullifyDirectoryEntry(&dirent);
542 0 : dir.CopyIndex(dir_index++, &dirent);
543 :
544 0 : dirent.stream_type = MD_LINUX_PROC_STATUS;
545 0 : if (!WriteProcFile(&dirent.location, crashing_tid_, "status"))
546 0 : NullifyDirectoryEntry(&dirent);
547 0 : dir.CopyIndex(dir_index++, &dirent);
548 :
549 0 : dirent.stream_type = MD_LINUX_LSB_RELEASE;
550 0 : if (!WriteFile(&dirent.location, "/etc/lsb-release"))
551 0 : NullifyDirectoryEntry(&dirent);
552 0 : dir.CopyIndex(dir_index++, &dirent);
553 :
554 0 : dirent.stream_type = MD_LINUX_CMD_LINE;
555 0 : if (!WriteProcFile(&dirent.location, crashing_tid_, "cmdline"))
556 0 : NullifyDirectoryEntry(&dirent);
557 0 : dir.CopyIndex(dir_index++, &dirent);
558 :
559 0 : dirent.stream_type = MD_LINUX_ENVIRON;
560 0 : if (!WriteProcFile(&dirent.location, crashing_tid_, "environ"))
561 0 : NullifyDirectoryEntry(&dirent);
562 0 : dir.CopyIndex(dir_index++, &dirent);
563 :
564 0 : dirent.stream_type = MD_LINUX_AUXV;
565 0 : if (!WriteProcFile(&dirent.location, crashing_tid_, "auxv"))
566 0 : NullifyDirectoryEntry(&dirent);
567 0 : dir.CopyIndex(dir_index++, &dirent);
568 :
569 0 : dirent.stream_type = MD_LINUX_MAPS;
570 0 : if (!WriteProcFile(&dirent.location, crashing_tid_, "maps"))
571 0 : NullifyDirectoryEntry(&dirent);
572 0 : dir.CopyIndex(dir_index++, &dirent);
573 :
574 0 : if (r_debug) {
575 0 : dirent.stream_type = MD_LINUX_DSO_DEBUG;
576 0 : if (!WriteDSODebugStream(&dirent, r_debug, dynamic_length))
577 0 : NullifyDirectoryEntry(&dirent);
578 0 : dir.CopyIndex(dir_index++, &dirent);
579 : }
580 :
581 : // If you add more directory entries, don't forget to update kNumWriters,
582 : // above.
583 :
584 0 : dumper_.ThreadsDetach();
585 0 : return true;
586 : }
587 :
588 : // Check if the top of the stack is part of a system call that has been
589 : // redirected by the seccomp sandbox. If so, try to pop the stack frames
590 : // all the way back to the point where the interception happened.
591 0 : void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread,
592 : uint8_t* stack_copy) {
593 : #if defined(__x86_64)
594 : u_int64_t bp = cpu->rbp;
595 : u_int64_t top = thread.stack.start_of_memory_range;
596 : for (int i = 4; i--; ) {
597 : if (bp < top ||
598 : bp + sizeof(bp) > thread.stack.start_of_memory_range +
599 : thread.stack.memory.data_size ||
600 : bp & 1) {
601 : break;
602 : }
603 : uint64_t old_top = top;
604 : top = bp;
605 : u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
606 : memcpy(&bp, bp_addr, sizeof(bp));
607 : if (bp == 0xDEADBEEFDEADBEEFull) {
608 : struct {
609 : uint64_t r15;
610 : uint64_t r14;
611 : uint64_t r13;
612 : uint64_t r12;
613 : uint64_t r11;
614 : uint64_t r10;
615 : uint64_t r9;
616 : uint64_t r8;
617 : uint64_t rdi;
618 : uint64_t rsi;
619 : uint64_t rdx;
620 : uint64_t rcx;
621 : uint64_t rbx;
622 : uint64_t deadbeef;
623 : uint64_t rbp;
624 : uint64_t fakeret;
625 : uint64_t ret;
626 : /* char redzone[128]; */
627 : } seccomp_stackframe;
628 : if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
629 : top - offsetof(typeof(seccomp_stackframe), deadbeef) +
630 : sizeof(seccomp_stackframe) >
631 : thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
632 : break;
633 : }
634 : memcpy(&seccomp_stackframe,
635 : bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
636 : sizeof(seccomp_stackframe));
637 : cpu->rbx = seccomp_stackframe.rbx;
638 : cpu->rcx = seccomp_stackframe.rcx;
639 : cpu->rdx = seccomp_stackframe.rdx;
640 : cpu->rsi = seccomp_stackframe.rsi;
641 : cpu->rdi = seccomp_stackframe.rdi;
642 : cpu->rbp = seccomp_stackframe.rbp;
643 : cpu->rsp = top + 4*sizeof(uint64_t) + 128;
644 : cpu->r8 = seccomp_stackframe.r8;
645 : cpu->r9 = seccomp_stackframe.r9;
646 : cpu->r10 = seccomp_stackframe.r10;
647 : cpu->r11 = seccomp_stackframe.r11;
648 : cpu->r12 = seccomp_stackframe.r12;
649 : cpu->r13 = seccomp_stackframe.r13;
650 : cpu->r14 = seccomp_stackframe.r14;
651 : cpu->r15 = seccomp_stackframe.r15;
652 : cpu->rip = seccomp_stackframe.fakeret;
653 : return;
654 : }
655 : }
656 : #elif defined(__i386)
657 0 : u_int32_t bp = cpu->ebp;
658 0 : u_int32_t top = thread.stack.start_of_memory_range;
659 0 : for (int i = 4; i--; ) {
660 0 : if (bp < top ||
661 : bp + sizeof(bp) > thread.stack.start_of_memory_range +
662 : thread.stack.memory.data_size ||
663 : bp & 1) {
664 0 : break;
665 : }
666 0 : uint32_t old_top = top;
667 0 : top = bp;
668 0 : u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
669 0 : memcpy(&bp, bp_addr, sizeof(bp));
670 0 : if (bp == 0xDEADBEEFu) {
671 : struct {
672 : uint32_t edi;
673 : uint32_t esi;
674 : uint32_t edx;
675 : uint32_t ecx;
676 : uint32_t ebx;
677 : uint32_t deadbeef;
678 : uint32_t ebp;
679 : uint32_t fakeret;
680 : uint32_t ret;
681 : } seccomp_stackframe;
682 0 : if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
683 : top - offsetof(typeof(seccomp_stackframe), deadbeef) +
684 : sizeof(seccomp_stackframe) >
685 : thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
686 0 : break;
687 : }
688 : memcpy(&seccomp_stackframe,
689 : bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
690 0 : sizeof(seccomp_stackframe));
691 0 : cpu->ebx = seccomp_stackframe.ebx;
692 0 : cpu->ecx = seccomp_stackframe.ecx;
693 0 : cpu->edx = seccomp_stackframe.edx;
694 0 : cpu->esi = seccomp_stackframe.esi;
695 0 : cpu->edi = seccomp_stackframe.edi;
696 0 : cpu->ebp = seccomp_stackframe.ebp;
697 0 : cpu->esp = top + 4*sizeof(void*);
698 0 : cpu->eip = seccomp_stackframe.fakeret;
699 0 : return;
700 : }
701 : }
702 : #endif
703 : }
704 :
705 : // Write information about the threads.
706 0 : bool WriteThreadListStream(MDRawDirectory* dirent) {
707 0 : const unsigned num_threads = dumper_.threads().size();
708 :
709 0 : TypedMDRVA<uint32_t> list(&minidump_writer_);
710 0 : if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
711 0 : return false;
712 :
713 0 : dirent->stream_type = MD_THREAD_LIST_STREAM;
714 0 : dirent->location = list.location();
715 :
716 0 : *list.get() = num_threads;
717 :
718 0 : for (unsigned i = 0; i < num_threads; ++i) {
719 : MDRawThread thread;
720 0 : my_memset(&thread, 0, sizeof(thread));
721 0 : thread.thread_id = dumper_.threads()[i];
722 : // We have a different source of information for the crashing thread. If
723 : // we used the actual state of the thread we would find it running in the
724 : // signal handler with the alternative stack, which would be deeply
725 : // unhelpful.
726 0 : if (HaveCrashedThread() &&
727 : (pid_t)thread.thread_id == crashing_tid_) {
728 : const void* stack;
729 : size_t stack_len;
730 0 : if (!dumper_.GetStackInfo(&stack, &stack_len, StackPointer(ucontext_)))
731 0 : return false;
732 0 : UntypedMDRVA memory(&minidump_writer_);
733 0 : if (!memory.Allocate(stack_len))
734 0 : return false;
735 0 : uint8_t* stack_copy = (uint8_t*) dumper_.allocator()->Alloc(stack_len);
736 0 : dumper_.CopyFromProcess(stack_copy, thread.thread_id, stack, stack_len);
737 0 : memory.Copy(stack_copy, stack_len);
738 0 : thread.stack.start_of_memory_range = (uintptr_t) (stack);
739 0 : thread.stack.memory = memory.location();
740 0 : memory_blocks_.push_back(thread.stack);
741 :
742 : // Copy 256 bytes around crashing instruction pointer to minidump.
743 0 : const size_t kIPMemorySize = 256;
744 0 : u_int64_t ip = GetInstructionPointer();
745 : // Bound it to the upper and lower bounds of the memory map
746 : // it's contained within. If it's not in mapped memory,
747 : // don't bother trying to write it.
748 0 : bool ip_is_mapped = false;
749 : MDMemoryDescriptor ip_memory_d;
750 0 : for (unsigned i = 0; i < dumper_.mappings().size(); ++i) {
751 0 : const MappingInfo& mapping = *dumper_.mappings()[i];
752 0 : if (ip >= mapping.start_addr &&
753 : ip < mapping.start_addr + mapping.size) {
754 0 : ip_is_mapped = true;
755 : // Try to get 128 bytes before and after the IP, but
756 : // settle for whatever's available.
757 : ip_memory_d.start_of_memory_range =
758 : std::max(mapping.start_addr,
759 0 : uintptr_t(ip - (kIPMemorySize / 2)));
760 : uintptr_t end_of_range =
761 : std::min(uintptr_t(ip + (kIPMemorySize / 2)),
762 0 : uintptr_t(mapping.start_addr + mapping.size));
763 : ip_memory_d.memory.data_size =
764 0 : end_of_range - ip_memory_d.start_of_memory_range;
765 0 : break;
766 : }
767 : }
768 :
769 0 : if (ip_is_mapped) {
770 0 : UntypedMDRVA ip_memory(&minidump_writer_);
771 0 : if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
772 0 : return false;
773 : uint8_t* memory_copy =
774 0 : (uint8_t*) dumper_.allocator()->Alloc(ip_memory_d.memory.data_size);
775 : dumper_.CopyFromProcess(
776 : memory_copy,
777 : thread.thread_id,
778 : reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
779 0 : ip_memory_d.memory.data_size);
780 0 : ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
781 0 : ip_memory_d.memory = ip_memory.location();
782 0 : memory_blocks_.push_back(ip_memory_d);
783 : }
784 :
785 0 : TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
786 0 : if (!cpu.Allocate())
787 0 : return false;
788 0 : my_memset(cpu.get(), 0, sizeof(RawContextCPU));
789 0 : CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
790 0 : PopSeccompStackFrame(cpu.get(), thread, stack_copy);
791 0 : thread.thread_context = cpu.location();
792 0 : crashing_thread_context_ = cpu.location();
793 : } else {
794 : ThreadInfo info;
795 0 : info.tid = dumper_.threads()[i];
796 0 : if (!dumper_.ThreadInfoGet(&info))
797 0 : return false;
798 0 : UntypedMDRVA memory(&minidump_writer_);
799 0 : if (!memory.Allocate(info.stack_len))
800 0 : return false;
801 : uint8_t* stack_copy =
802 0 : (uint8_t*) dumper_.allocator()->Alloc(info.stack_len);
803 : dumper_.CopyFromProcess(stack_copy, thread.thread_id, info.stack,
804 0 : info.stack_len);
805 0 : memory.Copy(stack_copy, info.stack_len);
806 0 : thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
807 0 : thread.stack.memory = memory.location();
808 0 : memory_blocks_.push_back(thread.stack);
809 :
810 0 : TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
811 0 : if (!cpu.Allocate())
812 0 : return false;
813 0 : my_memset(cpu.get(), 0, sizeof(RawContextCPU));
814 0 : CPUFillFromThreadInfo(cpu.get(), info);
815 0 : PopSeccompStackFrame(cpu.get(), thread, stack_copy);
816 0 : thread.thread_context = cpu.location();
817 :
818 0 : if ((pid_t)thread.thread_id == crashing_tid_) {
819 0 : assert(!HaveCrashedThread());
820 : // we're dumping a live process and just found the thread
821 : // that should be "blamed" for the dump. Grab its PC so we
822 : // can write it to the exception stream.
823 0 : crashing_tid_pc_ = InstructionPointer(info);
824 0 : crashing_thread_context_ = cpu.location();
825 : }
826 : }
827 :
828 0 : list.CopyIndexAfterObject(i, &thread, sizeof(thread));
829 : }
830 :
831 0 : return true;
832 : }
833 :
834 0 : bool WriteAppMemory() {
835 0 : for (AppMemoryList::const_iterator iter = app_memory_info_.begin();
836 0 : iter != app_memory_info_.end();
837 : ++iter) {
838 : uint8_t* data_copy =
839 0 : (uint8_t*) dumper_.allocator()->Alloc(iter->length);
840 0 : dumper_.CopyFromProcess(data_copy, crashing_tid_, iter->ptr,
841 0 : iter->length);
842 :
843 0 : UntypedMDRVA memory(&minidump_writer_);
844 0 : if (!memory.Allocate(iter->length))
845 0 : return false;
846 0 : memory.Copy(data_copy, iter->length);
847 : MDMemoryDescriptor desc;
848 0 : desc.start_of_memory_range = (uintptr_t)iter->ptr;
849 0 : desc.memory = memory.location();
850 0 : memory_blocks_.push_back(desc);
851 : }
852 :
853 0 : return true;
854 : }
855 :
856 0 : static bool ShouldIncludeMapping(const MappingInfo& mapping) {
857 0 : if (mapping.name[0] == 0 || // we only want modules with filenames.
858 : mapping.offset || // we only want to include one mapping per shared lib.
859 : mapping.size < 4096) { // too small to get a signature for.
860 0 : return false;
861 : }
862 :
863 0 : return true;
864 : }
865 :
866 : // If there is caller-provided information about this mapping
867 : // in the mapping_info_ list, return true. Otherwise, return false.
868 0 : bool HaveMappingInfo(const MappingInfo& mapping) {
869 0 : for (MappingList::const_iterator iter = mapping_info_.begin();
870 0 : iter != mapping_info_.end();
871 : ++iter) {
872 : // Ignore any mappings that are wholly contained within
873 : // mappings in the mapping_info_ list.
874 0 : if (mapping.start_addr >= iter->first.start_addr &&
875 : (mapping.start_addr + mapping.size) <=
876 0 : (iter->first.start_addr + iter->first.size)) {
877 0 : return true;
878 : }
879 : }
880 0 : return false;
881 : }
882 :
883 : // Write information about the mappings in effect. Because we are using the
884 : // minidump format, the information about the mappings is pretty limited.
885 : // Because of this, we also include the full, unparsed, /proc/$x/maps file in
886 : // another stream in the file.
887 0 : bool WriteMappings(MDRawDirectory* dirent) {
888 0 : const unsigned num_mappings = dumper_.mappings().size();
889 0 : unsigned num_output_mappings = mapping_info_.size();
890 :
891 0 : for (unsigned i = 0; i < dumper_.mappings().size(); ++i) {
892 0 : const MappingInfo& mapping = *dumper_.mappings()[i];
893 0 : if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
894 0 : num_output_mappings++;
895 : }
896 :
897 0 : TypedMDRVA<uint32_t> list(&minidump_writer_);
898 0 : if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
899 0 : return false;
900 :
901 0 : dirent->stream_type = MD_MODULE_LIST_STREAM;
902 0 : dirent->location = list.location();
903 0 : *list.get() = num_output_mappings;
904 :
905 : // First write all the mappings from the dumper
906 0 : unsigned int j = 0;
907 0 : for (unsigned i = 0; i < num_mappings; ++i) {
908 0 : const MappingInfo& mapping = *dumper_.mappings()[i];
909 0 : if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
910 0 : continue;
911 :
912 : MDRawModule mod;
913 0 : if (!FillRawModule(mapping, mod, NULL))
914 0 : return false;
915 0 : list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
916 : }
917 : // Next write all the mappings provided by the caller
918 0 : for (MappingList::const_iterator iter = mapping_info_.begin();
919 0 : iter != mapping_info_.end();
920 : ++iter) {
921 : MDRawModule mod;
922 0 : if (!FillRawModule(iter->first, mod, iter->second))
923 0 : return false;
924 0 : list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
925 : }
926 :
927 0 : return true;
928 : }
929 :
930 : // Fill the MDRawModule mod with information about the provided
931 : // mapping. If identifier is non-NULL, use it instead of calculating
932 : // a file ID from the mapping.
933 0 : bool FillRawModule(const MappingInfo& mapping,
934 : MDRawModule& mod,
935 : const u_int8_t* identifier) {
936 0 : my_memset(&mod, 0, MD_MODULE_SIZE);
937 :
938 0 : mod.base_of_image = mapping.start_addr;
939 0 : mod.size_of_image = mapping.size;
940 0 : const size_t filepath_len = my_strlen(mapping.name);
941 :
942 : // Figure out file name from path
943 0 : const char* filename_ptr = mapping.name + filepath_len - 1;
944 0 : while (filename_ptr >= mapping.name) {
945 0 : if (*filename_ptr == '/')
946 0 : break;
947 0 : filename_ptr--;
948 : }
949 0 : filename_ptr++;
950 :
951 0 : size_t filename_len = mapping.name + filepath_len - filename_ptr;
952 :
953 : uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
954 0 : uint8_t* cv_ptr = cv_buf;
955 0 : UntypedMDRVA cv(&minidump_writer_);
956 0 : if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
957 0 : return false;
958 :
959 0 : const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
960 0 : memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
961 0 : cv_ptr += sizeof(cv_signature);
962 0 : uint8_t* signature = cv_ptr;
963 0 : cv_ptr += sizeof(MDGUID);
964 0 : if (identifier) {
965 : // GUID was provided by caller.
966 0 : memcpy(signature, identifier, sizeof(MDGUID));
967 : } else {
968 0 : dumper_.ElfFileIdentifierForMapping(mapping, signature);
969 : }
970 0 : my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
971 0 : cv_ptr += sizeof(uint32_t);
972 :
973 : // Write pdb_file_name
974 0 : memcpy(cv_ptr, filename_ptr, filename_len + 1);
975 0 : cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
976 :
977 0 : mod.cv_record = cv.location();
978 :
979 : MDLocationDescriptor ld;
980 0 : if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
981 0 : return false;
982 0 : mod.module_name_rva = ld.rva;
983 0 : return true;
984 : }
985 :
986 0 : bool WriteMemoryListStream(MDRawDirectory* dirent) {
987 0 : TypedMDRVA<uint32_t> list(&minidump_writer_);
988 0 : if (!list.AllocateObjectAndArray(memory_blocks_.size(),
989 0 : sizeof(MDMemoryDescriptor)))
990 0 : return false;
991 :
992 0 : dirent->stream_type = MD_MEMORY_LIST_STREAM;
993 0 : dirent->location = list.location();
994 :
995 0 : *list.get() = memory_blocks_.size();
996 :
997 0 : for (size_t i = 0; i < memory_blocks_.size(); ++i) {
998 0 : list.CopyIndexAfterObject(i, &memory_blocks_[i],
999 0 : sizeof(MDMemoryDescriptor));
1000 : }
1001 0 : return true;
1002 : }
1003 :
1004 0 : bool WriteExceptionStream(MDRawDirectory* dirent) {
1005 0 : TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
1006 0 : if (!exc.Allocate())
1007 0 : return false;
1008 0 : my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
1009 :
1010 0 : dirent->stream_type = MD_EXCEPTION_STREAM;
1011 0 : dirent->location = exc.location();
1012 :
1013 0 : int signo = HaveCrashedThread() ? siginfo_->si_signo : SIGSTOP;
1014 0 : uintptr_t crash_addr = HaveCrashedThread() ?
1015 0 : uintptr_t(siginfo_->si_addr) : crashing_tid_pc_;
1016 :
1017 0 : exc.get()->thread_id = crashing_tid_;
1018 0 : exc.get()->exception_record.exception_code = signo;
1019 0 : exc.get()->exception_record.exception_address = crash_addr;
1020 0 : exc.get()->thread_context = crashing_thread_context_;
1021 :
1022 0 : return true;
1023 : }
1024 :
1025 0 : bool WriteSystemInfoStream(MDRawDirectory* dirent) {
1026 0 : TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
1027 0 : if (!si.Allocate())
1028 0 : return false;
1029 0 : my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
1030 :
1031 0 : dirent->stream_type = MD_SYSTEM_INFO_STREAM;
1032 0 : dirent->location = si.location();
1033 :
1034 0 : WriteCPUInformation(si.get());
1035 0 : WriteOSInformation(si.get());
1036 :
1037 0 : return true;
1038 : }
1039 :
1040 0 : bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
1041 : uint32_t dynamic_length) {
1042 : #if defined(__ANDROID__)
1043 : return false;
1044 : #else
1045 : // The caller provided us with a pointer to "struct r_debug". We can
1046 : // look up the "r_map" field to get a linked list of all loaded DSOs.
1047 : // Our list of DSOs potentially is different from the ones in the crashing
1048 : // process. So, we have to be careful to never dereference pointers
1049 : // directly. Instead, we use CopyFromProcess() everywhere.
1050 : // See <link.h> for a more detailed discussion of the how the dynamic
1051 : // loader communicates with debuggers.
1052 :
1053 : // Count the number of loaded DSOs
1054 0 : int dso_count = 0;
1055 : struct r_debug debug_entry;
1056 : dumper_.CopyFromProcess(&debug_entry, crashing_tid_, r_debug,
1057 0 : sizeof(debug_entry));
1058 0 : for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
1059 : struct link_map map;
1060 0 : dumper_.CopyFromProcess(&map, crashing_tid_, ptr, sizeof(map));
1061 0 : ptr = map.l_next;
1062 0 : dso_count++;
1063 : }
1064 :
1065 0 : MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
1066 0 : if (dso_count > 0) {
1067 : // If we have at least one DSO, create an array of MDRawLinkMap
1068 : // entries in the minidump file.
1069 0 : TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
1070 0 : if (!linkmap.AllocateArray(dso_count))
1071 0 : return false;
1072 0 : linkmap_rva = linkmap.location().rva;
1073 0 : int idx = 0;
1074 :
1075 : // Iterate over DSOs and write their information to mini dump
1076 0 : for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
1077 : struct link_map map;
1078 0 : dumper_.CopyFromProcess(&map, crashing_tid_, ptr, sizeof(map));
1079 0 : ptr = map.l_next;
1080 0 : char filename[257] = { 0 };
1081 0 : if (map.l_name) {
1082 : dumper_.CopyFromProcess(filename, crashing_tid_, map.l_name,
1083 0 : sizeof(filename) - 1);
1084 : }
1085 : MDLocationDescriptor location;
1086 0 : if (!minidump_writer_.WriteString(filename, 0, &location))
1087 0 : return false;
1088 : MDRawLinkMap entry;
1089 0 : entry.name = location.rva;
1090 0 : entry.addr = (void*)map.l_addr;
1091 0 : entry.ld = (void*)map.l_ld;
1092 0 : linkmap.CopyIndex(idx++, &entry);
1093 : }
1094 : }
1095 :
1096 : // Write MD_LINUX_DSO_DEBUG record
1097 0 : TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
1098 0 : if (!debug.AllocateObjectAndArray(1, dynamic_length))
1099 0 : return false;
1100 0 : my_memset(debug.get(), 0, sizeof(MDRawDebug));
1101 0 : dirent->stream_type = MD_LINUX_DSO_DEBUG;
1102 0 : dirent->location = debug.location();
1103 :
1104 0 : debug.get()->version = debug_entry.r_version;
1105 0 : debug.get()->map = linkmap_rva;
1106 0 : debug.get()->dso_count = dso_count;
1107 0 : debug.get()->brk = (void*)debug_entry.r_brk;
1108 0 : debug.get()->ldbase = (void*)debug_entry.r_ldbase;
1109 0 : debug.get()->dynamic = (void*)&_DYNAMIC;
1110 :
1111 0 : char *dso_debug_data = new char[dynamic_length];
1112 : dumper_.CopyFromProcess(dso_debug_data, crashing_tid_, &_DYNAMIC,
1113 0 : dynamic_length);
1114 0 : debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
1115 0 : delete[] dso_debug_data;
1116 :
1117 0 : return true;
1118 : #endif // __ANDROID__
1119 : }
1120 :
1121 : private:
1122 : #if defined(__i386)
1123 0 : uintptr_t GetInstructionPointer() {
1124 0 : return ucontext_->uc_mcontext.gregs[REG_EIP];
1125 : }
1126 : #elif defined(__x86_64)
1127 : uintptr_t GetInstructionPointer() {
1128 : return ucontext_->uc_mcontext.gregs[REG_RIP];
1129 : }
1130 : #elif defined(__ARM_EABI__)
1131 : uintptr_t GetInstructionPointer() {
1132 : return ucontext_->uc_mcontext.arm_ip;
1133 : }
1134 : #else
1135 : #error "This code has not been ported to your platform yet."
1136 : #endif
1137 :
1138 0 : void NullifyDirectoryEntry(MDRawDirectory* dirent) {
1139 0 : dirent->stream_type = 0;
1140 0 : dirent->location.data_size = 0;
1141 0 : dirent->location.rva = 0;
1142 0 : }
1143 :
1144 0 : bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
1145 0 : char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
1146 : static const char vendor_id_name[] = "vendor_id";
1147 : static const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
1148 :
1149 : struct CpuInfoEntry {
1150 : const char* info_name;
1151 : int value;
1152 : bool found;
1153 : } cpu_info_table[] = {
1154 : { "processor", -1, false },
1155 : { "model", 0, false },
1156 : { "stepping", 0, false },
1157 : { "cpu family", 0, false },
1158 0 : };
1159 :
1160 : // processor_architecture should always be set, do this first
1161 : sys_info->processor_architecture =
1162 : #if defined(__i386)
1163 0 : MD_CPU_ARCHITECTURE_X86;
1164 : #elif defined(__x86_64)
1165 : MD_CPU_ARCHITECTURE_AMD64;
1166 : #elif defined(__arm__)
1167 : MD_CPU_ARCHITECTURE_ARM;
1168 : #else
1169 : #error "Unknown CPU arch"
1170 : #endif
1171 :
1172 0 : const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
1173 0 : if (fd < 0)
1174 0 : return false;
1175 :
1176 : {
1177 0 : PageAllocator allocator;
1178 0 : LineReader* const line_reader = new(allocator) LineReader(fd);
1179 : const char* line;
1180 : unsigned line_len;
1181 0 : while (line_reader->GetNextLine(&line, &line_len)) {
1182 0 : for (size_t i = 0;
1183 : i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
1184 : i++) {
1185 0 : CpuInfoEntry* entry = &cpu_info_table[i];
1186 0 : if (entry->found && i)
1187 0 : continue;
1188 0 : if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
1189 0 : const char* value = strchr(line, ':');
1190 0 : if (!value)
1191 0 : continue;
1192 :
1193 : // the above strncmp only matches the prefix, it might be the wrong
1194 : // line. i.e. we matched "model name" instead of "model".
1195 : // check and make sure there is only spaces between the prefix and
1196 : // the colon.
1197 0 : const char* space_ptr = line + strlen(entry->info_name);
1198 0 : for (; space_ptr < value; space_ptr++) {
1199 0 : if (!isspace(*space_ptr)) {
1200 0 : break;
1201 : }
1202 : }
1203 0 : if (space_ptr != value)
1204 0 : continue;
1205 :
1206 0 : sscanf(++value, " %d", &(entry->value));
1207 0 : entry->found = true;
1208 : }
1209 : }
1210 :
1211 : // special case for vendor_id
1212 0 : if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
1213 0 : const char* value = strchr(line, ':');
1214 0 : if (!value)
1215 0 : goto popline;
1216 :
1217 : // skip ':" and all the spaces that follows
1218 0 : do {
1219 0 : value++;
1220 0 : } while (isspace(*value));
1221 :
1222 0 : if (*value) {
1223 0 : size_t length = strlen(value);
1224 0 : if (length == 0)
1225 0 : goto popline;
1226 : // we don't want the trailing newline
1227 0 : if (value[length - 1] == '\n')
1228 0 : length--;
1229 : // ensure we have space for the value
1230 0 : if (length < sizeof(vendor_id))
1231 0 : strncpy(vendor_id, value, length);
1232 : }
1233 : }
1234 :
1235 : popline:
1236 0 : line_reader->PopLine(line_len);
1237 : }
1238 0 : sys_close(fd);
1239 : }
1240 :
1241 : // make sure we got everything we wanted
1242 0 : for (size_t i = 0;
1243 : i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
1244 : i++) {
1245 0 : if (!cpu_info_table[i].found) {
1246 0 : return false;
1247 : }
1248 : }
1249 : // /proc/cpuinfo contains cpu id, change it into number by adding one.
1250 0 : cpu_info_table[0].value++;
1251 :
1252 0 : sys_info->number_of_processors = cpu_info_table[0].value;
1253 0 : sys_info->processor_level = cpu_info_table[3].value;
1254 : sys_info->processor_revision = cpu_info_table[1].value << 8 |
1255 0 : cpu_info_table[2].value;
1256 :
1257 0 : if (vendor_id[0] != '\0') {
1258 : memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
1259 0 : sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
1260 : }
1261 0 : return true;
1262 : }
1263 :
1264 0 : bool WriteFile(MDLocationDescriptor* result, const char* filename) {
1265 0 : const int fd = sys_open(filename, O_RDONLY, 0);
1266 0 : if (fd < 0)
1267 0 : return false;
1268 :
1269 : // We can't stat the files because several of the files that we want to
1270 : // read are kernel seqfiles, which always have a length of zero. So we have
1271 : // to read as much as we can into a buffer.
1272 : static const unsigned kBufSize = 1024 - 2*sizeof(void*);
1273 : struct Buffers {
1274 : struct Buffers* next;
1275 : size_t len;
1276 : uint8_t data[kBufSize];
1277 : } *buffers =
1278 0 : (struct Buffers*) dumper_.allocator()->Alloc(sizeof(struct Buffers));
1279 0 : buffers->next = NULL;
1280 0 : buffers->len = 0;
1281 :
1282 0 : size_t total = 0;
1283 0 : for (struct Buffers* bufptr = buffers;;) {
1284 : ssize_t r;
1285 0 : do {
1286 0 : r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
1287 0 : } while (r == -1 && errno == EINTR);
1288 :
1289 0 : if (r < 1)
1290 : break;
1291 :
1292 0 : total += r;
1293 0 : bufptr->len += r;
1294 0 : if (bufptr->len == kBufSize) {
1295 : bufptr->next =
1296 0 : (struct Buffers*) dumper_.allocator()->Alloc(sizeof(struct Buffers));
1297 0 : bufptr = bufptr->next;
1298 0 : bufptr->next = NULL;
1299 0 : bufptr->len = 0;
1300 : }
1301 : }
1302 0 : sys_close(fd);
1303 :
1304 0 : if (!total)
1305 0 : return false;
1306 :
1307 0 : UntypedMDRVA memory(&minidump_writer_);
1308 0 : if (!memory.Allocate(total))
1309 0 : return false;
1310 0 : for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
1311 0 : memory.Copy(pos, &buffers->data, buffers->len);
1312 0 : pos += buffers->len;
1313 : }
1314 0 : *result = memory.location();
1315 0 : return true;
1316 : }
1317 :
1318 0 : bool WriteOSInformation(MDRawSystemInfo* sys_info) {
1319 0 : sys_info->platform_id = MD_OS_LINUX;
1320 :
1321 : struct utsname uts;
1322 0 : if (uname(&uts))
1323 0 : return false;
1324 :
1325 : static const size_t buf_len = 512;
1326 0 : char buf[buf_len] = {0};
1327 0 : size_t space_left = buf_len - 1;
1328 : const char* info_table[] = {
1329 : uts.sysname,
1330 : uts.release,
1331 : uts.version,
1332 : uts.machine,
1333 : NULL
1334 0 : };
1335 0 : bool first_item = true;
1336 0 : for (const char** cur_info = info_table; *cur_info; cur_info++) {
1337 : static const char* separator = " ";
1338 0 : size_t separator_len = strlen(separator);
1339 0 : size_t info_len = strlen(*cur_info);
1340 0 : if (info_len == 0)
1341 0 : continue;
1342 :
1343 0 : if (space_left < info_len + (first_item ? 0 : separator_len))
1344 0 : break;
1345 :
1346 0 : if (!first_item) {
1347 0 : strcat(buf, separator);
1348 0 : space_left -= separator_len;
1349 : }
1350 :
1351 0 : first_item = false;
1352 0 : strcat(buf, *cur_info);
1353 0 : space_left -= info_len;
1354 : }
1355 :
1356 : MDLocationDescriptor location;
1357 0 : if (!minidump_writer_.WriteString(buf, 0, &location))
1358 0 : return false;
1359 0 : sys_info->csd_version_rva = location.rva;
1360 :
1361 0 : return true;
1362 : }
1363 :
1364 0 : bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
1365 : const char* filename) {
1366 : char buf[80];
1367 0 : memcpy(buf, "/proc/", 6);
1368 0 : const unsigned pid_len = my_int_len(pid);
1369 0 : my_itos(buf + 6, pid, pid_len);
1370 0 : buf[6 + pid_len] = '/';
1371 0 : memcpy(buf + 6 + pid_len + 1, filename, my_strlen(filename) + 1);
1372 0 : return WriteFile(result, buf);
1373 : }
1374 :
1375 : const char* const filename_; // output filename
1376 : const siginfo_t* const siginfo_; // from the signal handler (see sigaction)
1377 : const struct ucontext* const ucontext_; // also from the signal handler
1378 : const struct _libc_fpstate* const float_state_; // ditto
1379 : const pid_t crashing_tid_; // the process which actually crashed
1380 : uintptr_t crashing_tid_pc_; // set if we're dumping a live process
1381 : // and find crashing_tid_. used to
1382 : // write exception info. (if we're
1383 : // dumping a crash, this stays 0 and we
1384 : // use siginfo_)
1385 : LinuxDumper dumper_;
1386 : MinidumpFileWriter minidump_writer_;
1387 : MDLocationDescriptor crashing_thread_context_;
1388 : // Blocks of memory written to the dump. These are all currently
1389 : // written while writing the thread list stream, but saved here
1390 : // so a memory list stream can be written afterwards.
1391 : wasteful_vector<MDMemoryDescriptor> memory_blocks_;
1392 : // Additional information about some mappings provided by the caller.
1393 : const MappingList& mapping_info_;
1394 : // Callers can request additional memory regions to be included in
1395 : // the dump.
1396 : const AppMemoryList& app_memory_info_;
1397 : };
1398 :
1399 0 : bool WriteMinidump(const char* filename, pid_t crashing_process,
1400 : const void* blob, size_t blob_size) {
1401 0 : MappingList m;
1402 0 : AppMemoryList a;
1403 0 : return WriteMinidump(filename, crashing_process, blob, blob_size, m, a);
1404 : }
1405 :
1406 0 : bool WriteMinidump(const char* filename, pid_t crashing_process,
1407 : const void* blob, size_t blob_size,
1408 : const MappingList& mappings,
1409 : const AppMemoryList& appmem) {
1410 0 : if (blob_size != sizeof(ExceptionHandler::CrashContext))
1411 0 : return false;
1412 : const ExceptionHandler::CrashContext* context =
1413 0 : reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
1414 0 : MinidumpWriter writer(filename, crashing_process, context, mappings, appmem);
1415 0 : if (!writer.Init())
1416 0 : return false;
1417 0 : return writer.Dump();
1418 : }
1419 :
1420 0 : bool WriteMinidump(const char* filename, pid_t process,
1421 : pid_t process_blamed_thread) {
1422 : //TODO: support mappings here
1423 0 : MappingList m;
1424 0 : AppMemoryList a;
1425 0 : MinidumpWriter writer(filename, process, process_blamed_thread, m, a);
1426 0 : if (!writer.Init())
1427 0 : return false;
1428 0 : return writer.Dump();
1429 : }
1430 :
1431 : } // namespace google_breakpad
|