1
// Copyright (c) 2010, Google Inc.
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
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
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.
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.
30
// This code writes out minidump files:
31
// http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
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.
46
#include "client/linux/minidump_writer/minidump_writer.h"
47
#include "client/minidump_file_writer-inl.h"
52
#if !defined(__ANDROID__)
56
#if !defined(__ANDROID__)
57
#include <sys/ucontext.h>
60
#include <sys/utsname.h>
65
#include "client/minidump_file_writer.h"
66
#include "google_breakpad/common/minidump_format.h"
68
#if defined(__ANDROID__)
69
#include "client/linux/android_link.h"
70
#include "client/linux/android_ucontext.h"
72
#include "client/linux/handler/exception_handler.h"
73
#include "client/linux/minidump_writer/line_reader.h"
74
#include "client/linux/minidump_writer/linux_dumper.h"
75
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
76
#include "client/linux/minidump_writer/minidump_extension_linux.h"
77
#include "client/minidump_file_writer.h"
78
#include "common/linux/linux_libc_support.h"
79
#include "google_breakpad/common/minidump_format.h"
80
#include "third_party/lss/linux_syscall_support.h"
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.
86
typedef MDRawContextX86 RawContextCPU;
88
// Write a uint16_t to memory
89
// out: memory location to write to
91
static void U16(void* out, uint16_t v) {
92
memcpy(out, &v, sizeof(v));
95
// Write a uint32_t to memory
96
// out: memory location to write to
98
static void U32(void* out, uint32_t v) {
99
memcpy(out, &v, sizeof(v));
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
static void CPUFillFromThreadInfo(MDRawContextX86 *out,
106
const google_breakpad::ThreadInfo &info) {
107
out->context_flags = MD_CONTEXT_X86_ALL;
109
out->dr0 = info.dregs[0];
110
out->dr1 = info.dregs[1];
111
out->dr2 = info.dregs[2];
112
out->dr3 = info.dregs[3];
113
// 4 and 5 deliberatly omitted because they aren't included in the minidump
115
out->dr6 = info.dregs[6];
116
out->dr7 = info.dregs[7];
118
out->gs = info.regs.xgs;
119
out->fs = info.regs.xfs;
120
out->es = info.regs.xes;
121
out->ds = info.regs.xds;
123
out->edi = info.regs.edi;
124
out->esi = info.regs.esi;
125
out->ebx = info.regs.ebx;
126
out->edx = info.regs.edx;
127
out->ecx = info.regs.ecx;
128
out->eax = info.regs.eax;
130
out->ebp = info.regs.ebp;
131
out->eip = info.regs.eip;
132
out->cs = info.regs.xcs;
133
out->eflags = info.regs.eflags;
134
out->esp = info.regs.esp;
135
out->ss = info.regs.xss;
137
out->float_save.control_word = info.fpregs.cwd;
138
out->float_save.status_word = info.fpregs.swd;
139
out->float_save.tag_word = info.fpregs.twd;
140
out->float_save.error_offset = info.fpregs.fip;
141
out->float_save.error_selector = info.fpregs.fcs;
142
out->float_save.data_offset = info.fpregs.foo;
143
out->float_save.data_selector = info.fpregs.fos;
145
// 8 registers * 10 bytes per register.
146
memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
148
// This matches the Intel fpsave format.
149
U16(out->extended_registers + 0, info.fpregs.cwd);
150
U16(out->extended_registers + 2, info.fpregs.swd);
151
U16(out->extended_registers + 4, info.fpregs.twd);
152
U16(out->extended_registers + 6, info.fpxregs.fop);
153
U32(out->extended_registers + 8, info.fpxregs.fip);
154
U16(out->extended_registers + 12, info.fpxregs.fcs);
155
U32(out->extended_registers + 16, info.fpregs.foo);
156
U16(out->extended_registers + 20, info.fpregs.fos);
157
U32(out->extended_registers + 24, info.fpxregs.mxcsr);
159
memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
160
memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
163
// Juggle an x86 ucontext into minidump format
164
// out: the minidump structure
165
// info: the collection of register structures.
166
static void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
167
const struct _libc_fpstate* fp) {
168
const greg_t* regs = uc->uc_mcontext.gregs;
170
out->context_flags = MD_CONTEXT_X86_FULL |
171
MD_CONTEXT_X86_FLOATING_POINT;
173
out->gs = regs[REG_GS];
174
out->fs = regs[REG_FS];
175
out->es = regs[REG_ES];
176
out->ds = regs[REG_DS];
178
out->edi = regs[REG_EDI];
179
out->esi = regs[REG_ESI];
180
out->ebx = regs[REG_EBX];
181
out->edx = regs[REG_EDX];
182
out->ecx = regs[REG_ECX];
183
out->eax = regs[REG_EAX];
185
out->ebp = regs[REG_EBP];
186
out->eip = regs[REG_EIP];
187
out->cs = regs[REG_CS];
188
out->eflags = regs[REG_EFL];
189
out->esp = regs[REG_UESP];
190
out->ss = regs[REG_SS];
192
out->float_save.control_word = fp->cw;
193
out->float_save.status_word = fp->sw;
194
out->float_save.tag_word = fp->tag;
195
out->float_save.error_offset = fp->ipoff;
196
out->float_save.error_selector = fp->cssel;
197
out->float_save.data_offset = fp->dataoff;
198
out->float_save.data_selector = fp->datasel;
200
// 8 registers * 10 bytes per register.
201
memcpy(out->float_save.register_area, fp->_st, 10 * 8);
204
#elif defined(__x86_64)
205
typedef MDRawContextAMD64 RawContextCPU;
207
static void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
208
const google_breakpad::ThreadInfo &info) {
209
out->context_flags = MD_CONTEXT_AMD64_FULL |
210
MD_CONTEXT_AMD64_SEGMENTS;
212
out->cs = info.regs.cs;
214
out->ds = info.regs.ds;
215
out->es = info.regs.es;
216
out->fs = info.regs.fs;
217
out->gs = info.regs.gs;
219
out->ss = info.regs.ss;
220
out->eflags = info.regs.eflags;
222
out->dr0 = info.dregs[0];
223
out->dr1 = info.dregs[1];
224
out->dr2 = info.dregs[2];
225
out->dr3 = info.dregs[3];
226
// 4 and 5 deliberatly omitted because they aren't included in the minidump
228
out->dr6 = info.dregs[6];
229
out->dr7 = info.dregs[7];
231
out->rax = info.regs.rax;
232
out->rcx = info.regs.rcx;
233
out->rdx = info.regs.rdx;
234
out->rbx = info.regs.rbx;
236
out->rsp = info.regs.rsp;
238
out->rbp = info.regs.rbp;
239
out->rsi = info.regs.rsi;
240
out->rdi = info.regs.rdi;
241
out->r8 = info.regs.r8;
242
out->r9 = info.regs.r9;
243
out->r10 = info.regs.r10;
244
out->r11 = info.regs.r11;
245
out->r12 = info.regs.r12;
246
out->r13 = info.regs.r13;
247
out->r14 = info.regs.r14;
248
out->r15 = info.regs.r15;
250
out->rip = info.regs.rip;
252
out->flt_save.control_word = info.fpregs.cwd;
253
out->flt_save.status_word = info.fpregs.swd;
254
out->flt_save.tag_word = info.fpregs.ftw;
255
out->flt_save.error_opcode = info.fpregs.fop;
256
out->flt_save.error_offset = info.fpregs.rip;
257
out->flt_save.error_selector = 0; // We don't have this.
258
out->flt_save.data_offset = info.fpregs.rdp;
259
out->flt_save.data_selector = 0; // We don't have this.
260
out->flt_save.mx_csr = info.fpregs.mxcsr;
261
out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
262
memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
263
memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
266
static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
267
const struct _libc_fpstate* fpregs) {
268
const greg_t* regs = uc->uc_mcontext.gregs;
270
out->context_flags = MD_CONTEXT_AMD64_FULL;
272
out->cs = regs[REG_CSGSFS] & 0xffff;
274
out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
275
out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
277
out->eflags = regs[REG_EFL];
279
out->rax = regs[REG_RAX];
280
out->rcx = regs[REG_RCX];
281
out->rdx = regs[REG_RDX];
282
out->rbx = regs[REG_RBX];
284
out->rsp = regs[REG_RSP];
285
out->rbp = regs[REG_RBP];
286
out->rsi = regs[REG_RSI];
287
out->rdi = regs[REG_RDI];
288
out->r8 = regs[REG_R8];
289
out->r9 = regs[REG_R9];
290
out->r10 = regs[REG_R10];
291
out->r11 = regs[REG_R11];
292
out->r12 = regs[REG_R12];
293
out->r13 = regs[REG_R13];
294
out->r14 = regs[REG_R14];
295
out->r15 = regs[REG_R15];
297
out->rip = regs[REG_RIP];
299
out->flt_save.control_word = fpregs->cwd;
300
out->flt_save.status_word = fpregs->swd;
301
out->flt_save.tag_word = fpregs->ftw;
302
out->flt_save.error_opcode = fpregs->fop;
303
out->flt_save.error_offset = fpregs->rip;
304
out->flt_save.data_offset = fpregs->rdp;
305
out->flt_save.error_selector = 0; // We don't have this.
306
out->flt_save.data_selector = 0; // We don't have this.
307
out->flt_save.mx_csr = fpregs->mxcsr;
308
out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
309
memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
310
memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
313
#elif defined(__ARMEL__)
314
typedef MDRawContextARM RawContextCPU;
316
static void CPUFillFromThreadInfo(MDRawContextARM *out,
317
const google_breakpad::ThreadInfo &info) {
318
out->context_flags = MD_CONTEXT_ARM_FULL;
320
for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
321
out->iregs[i] = info.regs.uregs[i];
322
// No CPSR register in ThreadInfo(it's not accessible via ptrace)
324
#if !defined(__ANDROID__)
325
out->float_save.fpscr = info.fpregs.fpsr |
326
(static_cast<u_int64_t>(info.fpregs.fpcr) << 32);
327
// TODO: sort this out, actually collect floating point registers
328
memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
329
memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
333
static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
334
const struct _libc_fpstate* fpregs) {
335
out->context_flags = MD_CONTEXT_ARM_FULL;
337
out->iregs[0] = uc->uc_mcontext.arm_r0;
338
out->iregs[1] = uc->uc_mcontext.arm_r1;
339
out->iregs[2] = uc->uc_mcontext.arm_r2;
340
out->iregs[3] = uc->uc_mcontext.arm_r3;
341
out->iregs[4] = uc->uc_mcontext.arm_r4;
342
out->iregs[5] = uc->uc_mcontext.arm_r5;
343
out->iregs[6] = uc->uc_mcontext.arm_r6;
344
out->iregs[7] = uc->uc_mcontext.arm_r7;
345
out->iregs[8] = uc->uc_mcontext.arm_r8;
346
out->iregs[9] = uc->uc_mcontext.arm_r9;
347
out->iregs[10] = uc->uc_mcontext.arm_r10;
349
out->iregs[11] = uc->uc_mcontext.arm_fp;
350
out->iregs[12] = uc->uc_mcontext.arm_ip;
351
out->iregs[13] = uc->uc_mcontext.arm_sp;
352
out->iregs[14] = uc->uc_mcontext.arm_lr;
353
out->iregs[15] = uc->uc_mcontext.arm_pc;
355
out->cpsr = uc->uc_mcontext.arm_cpsr;
357
// TODO: fix this after fixing ExceptionHandler
358
out->float_save.fpscr = 0;
359
memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
360
memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
364
#error "This code has not been ported to your platform yet."
367
namespace google_breakpad {
369
class MinidumpWriter {
371
MinidumpWriter(const char* filename,
372
const ExceptionHandler::CrashContext* context,
373
const MappingList& mappings,
375
: filename_(filename),
376
ucontext_(context ? &context->context : NULL),
377
#if !defined(__ARM_EABI__)
378
float_state_(context ? &context->float_state : NULL),
380
// TODO: fix this after fixing ExceptionHandler
384
memory_blocks_(dumper_->allocator()),
385
mapping_list_(mappings) {
389
return dumper_->Init() && minidump_writer_.Open(filename_) &&
390
dumper_->ThreadsSuspend();
394
minidump_writer_.Close();
395
dumper_->ThreadsResume();
399
// The dynamic linker makes information available that helps gdb find all
400
// DSOs loaded into the program. If we can access this information, we dump
401
// it to a MD_LINUX_DSO_DEBUG stream.
402
struct r_debug* r_debug = NULL;
403
uint32_t dynamic_length = 0;
404
#if !defined(__ANDROID__)
405
// This code assumes the crashing process is the same as this process and
406
// may hang or take a long time to complete if not so.
407
// Thus, we skip this code for a post-mortem based dump.
408
if (!dumper_->IsPostMortem()) {
409
// The Android NDK is missing structure definitions for most of this.
410
// For now, it's simpler just to skip it.
413
dynamic_length += sizeof(dyn);
414
// NOTE: Use of _DYNAMIC assumes this is the same process as the
415
// crashing process. This loop will go forever if it's out of bounds.
416
dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
418
if (dyn.d_tag == DT_DEBUG) {
419
r_debug = (struct r_debug*)dyn.d_un.d_ptr;
421
} else if (dyn.d_tag == DT_NULL) {
428
// A minidump file contains a number of tagged streams. This is the number
429
// of stream which we write.
430
unsigned kNumWriters = 12;
434
TypedMDRVA<MDRawHeader> header(&minidump_writer_);
435
TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
436
if (!header.Allocate())
438
if (!dir.AllocateArray(kNumWriters))
440
memset(header.get(), 0, sizeof(MDRawHeader));
442
header.get()->signature = MD_HEADER_SIGNATURE;
443
header.get()->version = MD_HEADER_VERSION;
444
header.get()->time_date_stamp = time(NULL);
445
header.get()->stream_count = kNumWriters;
446
header.get()->stream_directory_rva = dir.position();
448
unsigned dir_index = 0;
449
MDRawDirectory dirent;
451
if (!WriteThreadListStream(&dirent))
453
dir.CopyIndex(dir_index++, &dirent);
455
if (!WriteMappings(&dirent))
457
dir.CopyIndex(dir_index++, &dirent);
459
if (!WriteMemoryListStream(&dirent))
461
dir.CopyIndex(dir_index++, &dirent);
463
if (!WriteExceptionStream(&dirent))
465
dir.CopyIndex(dir_index++, &dirent);
467
if (!WriteSystemInfoStream(&dirent))
469
dir.CopyIndex(dir_index++, &dirent);
471
dirent.stream_type = MD_LINUX_CPU_INFO;
472
if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
473
NullifyDirectoryEntry(&dirent);
474
dir.CopyIndex(dir_index++, &dirent);
476
dirent.stream_type = MD_LINUX_PROC_STATUS;
477
if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
478
NullifyDirectoryEntry(&dirent);
479
dir.CopyIndex(dir_index++, &dirent);
481
dirent.stream_type = MD_LINUX_LSB_RELEASE;
482
if (!WriteFile(&dirent.location, "/etc/lsb-release"))
483
NullifyDirectoryEntry(&dirent);
484
dir.CopyIndex(dir_index++, &dirent);
486
dirent.stream_type = MD_LINUX_CMD_LINE;
487
if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
488
NullifyDirectoryEntry(&dirent);
489
dir.CopyIndex(dir_index++, &dirent);
491
dirent.stream_type = MD_LINUX_ENVIRON;
492
if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
493
NullifyDirectoryEntry(&dirent);
494
dir.CopyIndex(dir_index++, &dirent);
496
dirent.stream_type = MD_LINUX_AUXV;
497
if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
498
NullifyDirectoryEntry(&dirent);
499
dir.CopyIndex(dir_index++, &dirent);
501
dirent.stream_type = MD_LINUX_MAPS;
502
if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
503
NullifyDirectoryEntry(&dirent);
504
dir.CopyIndex(dir_index++, &dirent);
507
dirent.stream_type = MD_LINUX_DSO_DEBUG;
508
if (!WriteDSODebugStream(&dirent, r_debug, dynamic_length))
509
NullifyDirectoryEntry(&dirent);
510
dir.CopyIndex(dir_index++, &dirent);
513
// If you add more directory entries, don't forget to update kNumWriters,
516
dumper_->ThreadsResume();
520
// Check if the top of the stack is part of a system call that has been
521
// redirected by the seccomp sandbox. If so, try to pop the stack frames
522
// all the way back to the point where the interception happened.
523
void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread,
524
uint8_t* stack_copy) {
525
#if defined(__x86_64)
526
u_int64_t bp = cpu->rbp;
527
u_int64_t top = thread.stack.start_of_memory_range;
528
for (int i = 4; i--; ) {
530
bp + sizeof(bp) > thread.stack.start_of_memory_range +
531
thread.stack.memory.data_size ||
535
uint64_t old_top = top;
537
u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
538
memcpy(&bp, bp_addr, sizeof(bp));
539
if (bp == 0xDEADBEEFDEADBEEFull) {
558
/* char redzone[128]; */
559
} seccomp_stackframe;
560
if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
561
top - offsetof(typeof(seccomp_stackframe), deadbeef) +
562
sizeof(seccomp_stackframe) >
563
thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
566
memcpy(&seccomp_stackframe,
567
bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
568
sizeof(seccomp_stackframe));
569
cpu->rbx = seccomp_stackframe.rbx;
570
cpu->rcx = seccomp_stackframe.rcx;
571
cpu->rdx = seccomp_stackframe.rdx;
572
cpu->rsi = seccomp_stackframe.rsi;
573
cpu->rdi = seccomp_stackframe.rdi;
574
cpu->rbp = seccomp_stackframe.rbp;
575
cpu->rsp = top + 4*sizeof(uint64_t) + 128;
576
cpu->r8 = seccomp_stackframe.r8;
577
cpu->r9 = seccomp_stackframe.r9;
578
cpu->r10 = seccomp_stackframe.r10;
579
cpu->r11 = seccomp_stackframe.r11;
580
cpu->r12 = seccomp_stackframe.r12;
581
cpu->r13 = seccomp_stackframe.r13;
582
cpu->r14 = seccomp_stackframe.r14;
583
cpu->r15 = seccomp_stackframe.r15;
584
cpu->rip = seccomp_stackframe.fakeret;
588
#elif defined(__i386)
589
u_int32_t bp = cpu->ebp;
590
u_int32_t top = thread.stack.start_of_memory_range;
591
for (int i = 4; i--; ) {
593
bp + sizeof(bp) > thread.stack.start_of_memory_range +
594
thread.stack.memory.data_size ||
598
uint32_t old_top = top;
600
u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
601
memcpy(&bp, bp_addr, sizeof(bp));
602
if (bp == 0xDEADBEEFu) {
613
} seccomp_stackframe;
614
if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
615
top - offsetof(typeof(seccomp_stackframe), deadbeef) +
616
sizeof(seccomp_stackframe) >
617
thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
620
memcpy(&seccomp_stackframe,
621
bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
622
sizeof(seccomp_stackframe));
623
cpu->ebx = seccomp_stackframe.ebx;
624
cpu->ecx = seccomp_stackframe.ecx;
625
cpu->edx = seccomp_stackframe.edx;
626
cpu->esi = seccomp_stackframe.esi;
627
cpu->edi = seccomp_stackframe.edi;
628
cpu->ebp = seccomp_stackframe.ebp;
629
cpu->esp = top + 4*sizeof(void*);
630
cpu->eip = seccomp_stackframe.fakeret;
637
// Write information about the threads.
638
bool WriteThreadListStream(MDRawDirectory* dirent) {
639
const unsigned num_threads = dumper_->threads().size();
641
TypedMDRVA<uint32_t> list(&minidump_writer_);
642
if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
645
dirent->stream_type = MD_THREAD_LIST_STREAM;
646
dirent->location = list.location();
648
*list.get() = num_threads;
650
for (unsigned i = 0; i < num_threads; ++i) {
652
my_memset(&thread, 0, sizeof(thread));
653
thread.thread_id = dumper_->threads()[i];
654
// We have a different source of information for the crashing thread. If
655
// we used the actual state of the thread we would find it running in the
656
// signal handler with the alternative stack, which would be deeply
658
if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
659
!dumper_->IsPostMortem()) {
662
if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
664
UntypedMDRVA memory(&minidump_writer_);
665
if (!memory.Allocate(stack_len))
667
uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
668
dumper_->CopyFromProcess(stack_copy, thread.thread_id, stack,
670
memory.Copy(stack_copy, stack_len);
671
thread.stack.start_of_memory_range = (uintptr_t) (stack);
672
thread.stack.memory = memory.location();
673
memory_blocks_.push_back(thread.stack);
675
// Copy 256 bytes around crashing instruction pointer to minidump.
676
const size_t kIPMemorySize = 256;
677
u_int64_t ip = GetInstructionPointer();
678
// Bound it to the upper and lower bounds of the memory map
679
// it's contained within. If it's not in mapped memory,
680
// don't bother trying to write it.
681
bool ip_is_mapped = false;
682
MDMemoryDescriptor ip_memory_d;
683
for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
684
const MappingInfo& mapping = *dumper_->mappings()[j];
685
if (ip >= mapping.start_addr &&
686
ip < mapping.start_addr + mapping.size) {
688
// Try to get 128 bytes before and after the IP, but
689
// settle for whatever's available.
690
ip_memory_d.start_of_memory_range =
691
std::max(mapping.start_addr,
692
uintptr_t(ip - (kIPMemorySize / 2)));
693
uintptr_t end_of_range =
694
std::min(uintptr_t(ip + (kIPMemorySize / 2)),
695
uintptr_t(mapping.start_addr + mapping.size));
696
ip_memory_d.memory.data_size =
697
end_of_range - ip_memory_d.start_of_memory_range;
703
UntypedMDRVA ip_memory(&minidump_writer_);
704
if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
706
uint8_t* memory_copy =
707
reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
708
dumper_->CopyFromProcess(
711
reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
712
ip_memory_d.memory.data_size);
713
ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
714
ip_memory_d.memory = ip_memory.location();
715
memory_blocks_.push_back(ip_memory_d);
718
TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
721
my_memset(cpu.get(), 0, sizeof(RawContextCPU));
722
CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
723
PopSeccompStackFrame(cpu.get(), thread, stack_copy);
724
thread.thread_context = cpu.location();
725
crashing_thread_context_ = cpu.location();
728
if (!dumper_->GetThreadInfoByIndex(i, &info))
730
UntypedMDRVA memory(&minidump_writer_);
731
if (!memory.Allocate(info.stack_len))
733
uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(info.stack_len));
734
dumper_->CopyFromProcess(stack_copy, thread.thread_id, info.stack,
736
memory.Copy(stack_copy, info.stack_len);
737
thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
738
thread.stack.memory = memory.location();
739
memory_blocks_.push_back(thread.stack);
741
TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
744
my_memset(cpu.get(), 0, sizeof(RawContextCPU));
745
CPUFillFromThreadInfo(cpu.get(), info);
746
PopSeccompStackFrame(cpu.get(), thread, stack_copy);
747
thread.thread_context = cpu.location();
748
if (dumper_->threads()[i] == GetCrashThread()) {
749
assert(dumper_->IsPostMortem());
750
crashing_thread_context_ = cpu.location();
754
list.CopyIndexAfterObject(i, &thread, sizeof(thread));
760
static bool ShouldIncludeMapping(const MappingInfo& mapping) {
761
if (mapping.name[0] == 0 || // only want modules with filenames.
762
mapping.offset || // only want to include one mapping per shared lib.
763
mapping.size < 4096) { // too small to get a signature for.
770
// If there is caller-provided information about this mapping
771
// in the mapping_list_ list, return true. Otherwise, return false.
772
bool HaveMappingInfo(const MappingInfo& mapping) {
773
for (MappingList::const_iterator iter = mapping_list_.begin();
774
iter != mapping_list_.end();
776
// Ignore any mappings that are wholly contained within
777
// mappings in the mapping_info_ list.
778
if (mapping.start_addr >= iter->first.start_addr &&
779
(mapping.start_addr + mapping.size) <=
780
(iter->first.start_addr + iter->first.size)) {
787
// Write information about the mappings in effect. Because we are using the
788
// minidump format, the information about the mappings is pretty limited.
789
// Because of this, we also include the full, unparsed, /proc/$x/maps file in
790
// another stream in the file.
791
bool WriteMappings(MDRawDirectory* dirent) {
792
const unsigned num_mappings = dumper_->mappings().size();
793
unsigned num_output_mappings = mapping_list_.size();
795
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
796
const MappingInfo& mapping = *dumper_->mappings()[i];
797
if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
798
num_output_mappings++;
801
TypedMDRVA<uint32_t> list(&minidump_writer_);
802
if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
805
dirent->stream_type = MD_MODULE_LIST_STREAM;
806
dirent->location = list.location();
807
*list.get() = num_output_mappings;
809
// First write all the mappings from the dumper
811
for (unsigned i = 0; i < num_mappings; ++i) {
812
const MappingInfo& mapping = *dumper_->mappings()[i];
813
if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
817
if (!FillRawModule(mapping, true, i, mod, NULL))
819
list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
821
// Next write all the mappings provided by the caller
822
for (MappingList::const_iterator iter = mapping_list_.begin();
823
iter != mapping_list_.end();
826
if (!FillRawModule(iter->first, false, 0, mod, iter->second))
828
list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
834
// Fill the MDRawModule |mod| with information about the provided
835
// |mapping|. If |identifier| is non-NULL, use it instead of calculating
836
// a file ID from the mapping.
837
bool FillRawModule(const MappingInfo& mapping,
839
unsigned int mapping_id,
841
const u_int8_t* identifier) {
842
my_memset(&mod, 0, MD_MODULE_SIZE);
844
mod.base_of_image = mapping.start_addr;
845
mod.size_of_image = mapping.size;
846
const size_t filepath_len = my_strlen(mapping.name);
848
// Figure out file name from path
849
const char* filename_ptr = mapping.name + filepath_len - 1;
850
while (filename_ptr >= mapping.name) {
851
if (*filename_ptr == '/')
857
const size_t filename_len = mapping.name + filepath_len - filename_ptr;
859
uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
860
uint8_t* cv_ptr = cv_buf;
861
UntypedMDRVA cv(&minidump_writer_);
862
if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
865
const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
866
memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
867
cv_ptr += sizeof(cv_signature);
868
uint8_t* signature = cv_ptr;
869
cv_ptr += sizeof(MDGUID);
871
// GUID was provided by caller.
872
memcpy(signature, identifier, sizeof(MDGUID));
874
dumper_->ElfFileIdentifierForMapping(mapping, member,
875
mapping_id, signature);
877
my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
878
cv_ptr += sizeof(uint32_t);
880
// Write pdb_file_name
881
memcpy(cv_ptr, filename_ptr, filename_len + 1);
882
cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
884
mod.cv_record = cv.location();
886
MDLocationDescriptor ld;
887
if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
889
mod.module_name_rva = ld.rva;
893
bool WriteMemoryListStream(MDRawDirectory* dirent) {
894
TypedMDRVA<uint32_t> list(&minidump_writer_);
895
if (!list.AllocateObjectAndArray(memory_blocks_.size(),
896
sizeof(MDMemoryDescriptor)))
899
dirent->stream_type = MD_MEMORY_LIST_STREAM;
900
dirent->location = list.location();
902
*list.get() = memory_blocks_.size();
904
for (size_t i = 0; i < memory_blocks_.size(); ++i) {
905
list.CopyIndexAfterObject(i, &memory_blocks_[i],
906
sizeof(MDMemoryDescriptor));
911
bool WriteExceptionStream(MDRawDirectory* dirent) {
912
TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
915
my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
917
dirent->stream_type = MD_EXCEPTION_STREAM;
918
dirent->location = exc.location();
920
exc.get()->thread_id = GetCrashThread();
921
exc.get()->exception_record.exception_code = dumper_->crash_signal();
922
exc.get()->exception_record.exception_address = dumper_->crash_address();
923
exc.get()->thread_context = crashing_thread_context_;
928
bool WriteSystemInfoStream(MDRawDirectory* dirent) {
929
TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
932
my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
934
dirent->stream_type = MD_SYSTEM_INFO_STREAM;
935
dirent->location = si.location();
937
WriteCPUInformation(si.get());
938
WriteOSInformation(si.get());
943
bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
944
uint32_t dynamic_length) {
945
#if defined(__ANDROID__)
948
// The caller provided us with a pointer to "struct r_debug". We can
949
// look up the "r_map" field to get a linked list of all loaded DSOs.
950
// Our list of DSOs potentially is different from the ones in the crashing
951
// process. So, we have to be careful to never dereference pointers
952
// directly. Instead, we use CopyFromProcess() everywhere.
953
// See <link.h> for a more detailed discussion of the how the dynamic
954
// loader communicates with debuggers.
956
// Count the number of loaded DSOs
958
struct r_debug debug_entry;
959
dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
960
sizeof(debug_entry));
961
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
963
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
968
MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
970
// If we have at least one DSO, create an array of MDRawLinkMap
971
// entries in the minidump file.
972
TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
973
if (!linkmap.AllocateArray(dso_count))
975
linkmap_rva = linkmap.location().rva;
978
// Iterate over DSOs and write their information to mini dump
979
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
981
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
983
char filename[257] = { 0 };
985
dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
986
sizeof(filename) - 1);
988
MDLocationDescriptor location;
989
if (!minidump_writer_.WriteString(filename, 0, &location))
992
entry.name = location.rva;
993
entry.addr = (void*)map.l_addr;
994
entry.ld = (void*)map.l_ld;
995
linkmap.CopyIndex(idx++, &entry);
999
// Write MD_LINUX_DSO_DEBUG record
1000
TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
1001
if (!debug.AllocateObjectAndArray(1, dynamic_length))
1003
my_memset(debug.get(), 0, sizeof(MDRawDebug));
1004
dirent->stream_type = MD_LINUX_DSO_DEBUG;
1005
dirent->location = debug.location();
1007
debug.get()->version = debug_entry.r_version;
1008
debug.get()->map = linkmap_rva;
1009
debug.get()->dso_count = dso_count;
1010
debug.get()->brk = (void*)debug_entry.r_brk;
1011
debug.get()->ldbase = (void*)debug_entry.r_ldbase;
1012
debug.get()->dynamic = (void*)&_DYNAMIC;
1014
char *dso_debug_data = new char[dynamic_length];
1015
dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), &_DYNAMIC,
1017
debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
1018
delete[] dso_debug_data;
1025
void* Alloc(unsigned bytes) {
1026
return dumper_->allocator()->Alloc(bytes);
1029
pid_t GetCrashThread() const {
1030
return dumper_->crash_thread();
1034
uintptr_t GetStackPointer() {
1035
return ucontext_->uc_mcontext.gregs[REG_ESP];
1038
uintptr_t GetInstructionPointer() {
1039
return ucontext_->uc_mcontext.gregs[REG_EIP];
1041
#elif defined(__x86_64)
1042
uintptr_t GetStackPointer() {
1043
return ucontext_->uc_mcontext.gregs[REG_RSP];
1046
uintptr_t GetInstructionPointer() {
1047
return ucontext_->uc_mcontext.gregs[REG_RIP];
1049
#elif defined(__ARM_EABI__)
1050
uintptr_t GetStackPointer() {
1051
return ucontext_->uc_mcontext.arm_sp;
1054
uintptr_t GetInstructionPointer() {
1055
return ucontext_->uc_mcontext.arm_ip;
1058
#error "This code has not been ported to your platform yet."
1061
void NullifyDirectoryEntry(MDRawDirectory* dirent) {
1062
dirent->stream_type = 0;
1063
dirent->location.data_size = 0;
1064
dirent->location.rva = 0;
1067
bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
1068
char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
1069
static const char vendor_id_name[] = "vendor_id";
1070
static const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
1072
struct CpuInfoEntry {
1073
const char* info_name;
1076
} cpu_info_table[] = {
1077
{ "processor", -1, false },
1078
{ "model", 0, false },
1079
{ "stepping", 0, false },
1080
{ "cpu family", 0, false },
1083
// processor_architecture should always be set, do this first
1084
sys_info->processor_architecture =
1086
MD_CPU_ARCHITECTURE_X86;
1087
#elif defined(__x86_64)
1088
MD_CPU_ARCHITECTURE_AMD64;
1089
#elif defined(__arm__)
1090
MD_CPU_ARCHITECTURE_ARM;
1092
#error "Unknown CPU arch"
1095
const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
1100
PageAllocator allocator;
1101
LineReader* const line_reader = new(allocator) LineReader(fd);
1104
while (line_reader->GetNextLine(&line, &line_len)) {
1106
i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
1108
CpuInfoEntry* entry = &cpu_info_table[i];
1109
if (entry->found && i)
1111
if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
1112
const char* value = strchr(line, ':');
1116
// the above strncmp only matches the prefix, it might be the wrong
1117
// line. i.e. we matched "model name" instead of "model".
1118
// check and make sure there is only spaces between the prefix and
1120
const char* space_ptr = line + strlen(entry->info_name);
1121
for (; space_ptr < value; space_ptr++) {
1122
if (!isspace(*space_ptr)) {
1126
if (space_ptr != value)
1129
sscanf(++value, " %d", &(entry->value));
1130
entry->found = true;
1134
// special case for vendor_id
1135
if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
1136
const char* value = strchr(line, ':');
1140
// skip ':" and all the spaces that follows
1143
} while (isspace(*value));
1146
size_t length = strlen(value);
1149
// we don't want the trailing newline
1150
if (value[length - 1] == '\n')
1152
// ensure we have space for the value
1153
if (length < sizeof(vendor_id))
1154
strncpy(vendor_id, value, length);
1159
line_reader->PopLine(line_len);
1164
// make sure we got everything we wanted
1166
i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
1168
if (!cpu_info_table[i].found) {
1172
// /proc/cpuinfo contains cpu id, change it into number by adding one.
1173
cpu_info_table[0].value++;
1175
sys_info->number_of_processors = cpu_info_table[0].value;
1176
sys_info->processor_level = cpu_info_table[3].value;
1177
sys_info->processor_revision = cpu_info_table[1].value << 8 |
1178
cpu_info_table[2].value;
1180
if (vendor_id[0] != '\0') {
1181
memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
1182
sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
1187
bool WriteFile(MDLocationDescriptor* result, const char* filename) {
1188
const int fd = sys_open(filename, O_RDONLY, 0);
1192
// We can't stat the files because several of the files that we want to
1193
// read are kernel seqfiles, which always have a length of zero. So we have
1194
// to read as much as we can into a buffer.
1195
static const unsigned kBufSize = 1024 - 2*sizeof(void*);
1199
uint8_t data[kBufSize];
1200
} *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1201
buffers->next = NULL;
1205
for (Buffers* bufptr = buffers;;) {
1208
r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
1209
} while (r == -1 && errno == EINTR);
1216
if (bufptr->len == kBufSize) {
1217
bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1218
bufptr = bufptr->next;
1219
bufptr->next = NULL;
1228
UntypedMDRVA memory(&minidump_writer_);
1229
if (!memory.Allocate(total))
1231
for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
1232
// Check for special case of a zero-length buffer. This should only
1233
// occur if a file's size happens to be a multiple of the buffer's
1234
// size, in which case the final sys_read() will have resulted in
1235
// zero bytes being read after the final buffer was just allocated.
1236
if (buffers->len == 0) {
1237
// This can only occur with final buffer.
1238
assert(buffers->next == NULL);
1241
memory.Copy(pos, &buffers->data, buffers->len);
1242
pos += buffers->len;
1244
*result = memory.location();
1248
bool WriteOSInformation(MDRawSystemInfo* sys_info) {
1249
sys_info->platform_id = MD_OS_LINUX;
1255
static const size_t buf_len = 512;
1256
char buf[buf_len] = {0};
1257
size_t space_left = buf_len - 1;
1258
const char* info_table[] = {
1265
bool first_item = true;
1266
for (const char** cur_info = info_table; *cur_info; cur_info++) {
1267
static const char* separator = " ";
1268
size_t separator_len = strlen(separator);
1269
size_t info_len = strlen(*cur_info);
1273
if (space_left < info_len + (first_item ? 0 : separator_len))
1277
strcat(buf, separator);
1278
space_left -= separator_len;
1282
strcat(buf, *cur_info);
1283
space_left -= info_len;
1286
MDLocationDescriptor location;
1287
if (!minidump_writer_.WriteString(buf, 0, &location))
1289
sys_info->csd_version_rva = location.rva;
1294
bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
1295
const char* filename) {
1297
if (!dumper_->BuildProcPath(buf, pid, filename))
1299
return WriteFile(result, buf);
1302
const char* const filename_; // output filename
1303
const struct ucontext* const ucontext_; // also from the signal handler
1304
const struct _libc_fpstate* const float_state_; // ditto
1305
LinuxDumper* dumper_;
1306
MinidumpFileWriter minidump_writer_;
1307
MDLocationDescriptor crashing_thread_context_;
1308
// Blocks of memory written to the dump. These are all currently
1309
// written while writing the thread list stream, but saved here
1310
// so a memory list stream can be written afterwards.
1311
wasteful_vector<MDMemoryDescriptor> memory_blocks_;
1312
// Additional information about some mappings provided by the caller.
1313
const MappingList& mapping_list_;
1316
bool WriteMinidump(const char* filename, pid_t crashing_process,
1317
const void* blob, size_t blob_size) {
1319
return WriteMinidump(filename, crashing_process, blob, blob_size, m);
1322
bool WriteMinidump(const char* filename, pid_t crashing_process,
1323
const void* blob, size_t blob_size,
1324
const MappingList& mappings) {
1325
if (blob_size != sizeof(ExceptionHandler::CrashContext))
1327
const ExceptionHandler::CrashContext* context =
1328
reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
1329
LinuxPtraceDumper dumper(crashing_process);
1330
dumper.set_crash_address(
1331
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
1332
dumper.set_crash_signal(context->siginfo.si_signo);
1333
dumper.set_crash_thread(context->tid);
1334
MinidumpWriter writer(filename, context, mappings, &dumper);
1337
return writer.Dump();
1340
bool WriteMinidump(const char* filename,
1341
const MappingList& mappings,
1342
LinuxDumper* dumper) {
1343
MinidumpWriter writer(filename, NULL, mappings, dumper);
1346
return writer.Dump();
1349
} // namespace google_breakpad