~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to thirdparty/breakpad/client/linux/minidump_writer/minidump_writer.cc

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2010, Google Inc.
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are
 
6
// met:
 
7
//
 
8
//     * Redistributions of source code must retain the above copyright
 
9
// notice, this list of conditions and the following disclaimer.
 
10
//     * Redistributions in binary form must reproduce the above
 
11
// copyright notice, this list of conditions and the following disclaimer
 
12
// in the documentation and/or other materials provided with the
 
13
// distribution.
 
14
//     * Neither the name of Google Inc. nor the names of its
 
15
// contributors may be used to endorse or promote products derived from
 
16
// this software without specific prior written permission.
 
17
//
 
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 
 
30
// This code writes out minidump files:
 
31
//   http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
 
32
//
 
33
// Minidumps are a Microsoft format which Breakpad uses for recording crash
 
34
// dumps. This code has to run in a compromised environment (the address space
 
35
// may have received SIGSEGV), thus the following rules apply:
 
36
//   * You may not enter the dynamic linker. This means that we cannot call
 
37
//     any symbols in a shared library (inc libc). Because of this we replace
 
38
//     libc functions in linux_libc_support.h.
 
39
//   * You may not call syscalls via the libc wrappers. This rule is a subset
 
40
//     of the first rule but it bears repeating. We have direct wrappers
 
41
//     around the system calls in linux_syscall_support.h.
 
42
//   * You may not malloc. There's an alternative allocator in memory.h and
 
43
//     a canonical instance in the LinuxDumper object. We use the placement
 
44
//     new form to allocate objects and we don't delete them.
 
45
 
 
46
#include "client/linux/minidump_writer/minidump_writer.h"
 
47
#include "client/minidump_file_writer-inl.h"
 
48
 
 
49
#include <ctype.h>
 
50
#include <errno.h>
 
51
#include <fcntl.h>
 
52
#if !defined(__ANDROID__)
 
53
#include <link.h>
 
54
#endif
 
55
#include <stdio.h>
 
56
#if !defined(__ANDROID__)
 
57
#include <sys/ucontext.h>
 
58
#include <sys/user.h>
 
59
#endif
 
60
#include <sys/utsname.h>
 
61
#include <unistd.h>
 
62
 
 
63
#include <algorithm>
 
64
 
 
65
#include "client/minidump_file_writer.h"
 
66
#include "google_breakpad/common/minidump_format.h"
 
67
 
 
68
#if defined(__ANDROID__)
 
69
#include "client/linux/android_link.h"
 
70
#include "client/linux/android_ucontext.h"
 
71
#endif
 
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"
 
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
static void U16(void* out, uint16_t v) {
 
92
  memcpy(out, &v, sizeof(v));
 
93
}
 
94
 
 
95
// Write a uint32_t to memory
 
96
//   out: memory location to write to
 
97
//   v: value to write.
 
98
static void U32(void* out, uint32_t v) {
 
99
  memcpy(out, &v, sizeof(v));
 
100
}
 
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
static void CPUFillFromThreadInfo(MDRawContextX86 *out,
 
106
                                  const google_breakpad::ThreadInfo &info) {
 
107
  out->context_flags = MD_CONTEXT_X86_ALL;
 
108
 
 
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
 
114
  // format.
 
115
  out->dr6 = info.dregs[6];
 
116
  out->dr7 = info.dregs[7];
 
117
 
 
118
  out->gs = info.regs.xgs;
 
119
  out->fs = info.regs.xfs;
 
120
  out->es = info.regs.xes;
 
121
  out->ds = info.regs.xds;
 
122
 
 
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;
 
129
 
 
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;
 
136
 
 
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;
 
144
 
 
145
  // 8 registers * 10 bytes per register.
 
146
  memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
 
147
 
 
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);
 
158
 
 
159
  memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
 
160
  memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
 
161
}
 
162
 
 
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;
 
169
 
 
170
  out->context_flags = MD_CONTEXT_X86_FULL |
 
171
                       MD_CONTEXT_X86_FLOATING_POINT;
 
172
 
 
173
  out->gs = regs[REG_GS];
 
174
  out->fs = regs[REG_FS];
 
175
  out->es = regs[REG_ES];
 
176
  out->ds = regs[REG_DS];
 
177
 
 
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];
 
184
 
 
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];
 
191
 
 
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;
 
199
 
 
200
  // 8 registers * 10 bytes per register.
 
201
  memcpy(out->float_save.register_area, fp->_st, 10 * 8);
 
202
}
 
203
 
 
204
#elif defined(__x86_64)
 
205
typedef MDRawContextAMD64 RawContextCPU;
 
206
 
 
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;
 
211
 
 
212
  out->cs = info.regs.cs;
 
213
 
 
214
  out->ds = info.regs.ds;
 
215
  out->es = info.regs.es;
 
216
  out->fs = info.regs.fs;
 
217
  out->gs = info.regs.gs;
 
218
 
 
219
  out->ss = info.regs.ss;
 
220
  out->eflags = info.regs.eflags;
 
221
 
 
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
 
227
  // format.
 
228
  out->dr6 = info.dregs[6];
 
229
  out->dr7 = info.dregs[7];
 
230
 
 
231
  out->rax = info.regs.rax;
 
232
  out->rcx = info.regs.rcx;
 
233
  out->rdx = info.regs.rdx;
 
234
  out->rbx = info.regs.rbx;
 
235
 
 
236
  out->rsp = info.regs.rsp;
 
237
 
 
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;
 
249
 
 
250
  out->rip = info.regs.rip;
 
251
 
 
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);
 
264
}
 
265
 
 
266
static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
 
267
                                const struct _libc_fpstate* fpregs) {
 
268
  const greg_t* regs = uc->uc_mcontext.gregs;
 
269
 
 
270
  out->context_flags = MD_CONTEXT_AMD64_FULL;
 
271
 
 
272
  out->cs = regs[REG_CSGSFS] & 0xffff;
 
273
 
 
274
  out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
 
275
  out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
 
276
 
 
277
  out->eflags = regs[REG_EFL];
 
278
 
 
279
  out->rax = regs[REG_RAX];
 
280
  out->rcx = regs[REG_RCX];
 
281
  out->rdx = regs[REG_RDX];
 
282
  out->rbx = regs[REG_RBX];
 
283
 
 
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];
 
296
 
 
297
  out->rip = regs[REG_RIP];
 
298
 
 
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);
 
311
}
 
312
 
 
313
#elif defined(__ARMEL__)
 
314
typedef MDRawContextARM RawContextCPU;
 
315
 
 
316
static void CPUFillFromThreadInfo(MDRawContextARM *out,
 
317
                                  const google_breakpad::ThreadInfo &info) {
 
318
  out->context_flags = MD_CONTEXT_ARM_FULL;
 
319
 
 
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)
 
323
  out->cpsr = 0;
 
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));
 
330
#endif
 
331
}
 
332
 
 
333
static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
 
334
                                const struct _libc_fpstate* fpregs) {
 
335
  out->context_flags = MD_CONTEXT_ARM_FULL;
 
336
 
 
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;
 
348
 
 
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;
 
354
 
 
355
  out->cpsr = uc->uc_mcontext.arm_cpsr;
 
356
 
 
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));
 
361
}
 
362
 
 
363
#else
 
364
#error "This code has not been ported to your platform yet."
 
365
#endif
 
366
 
 
367
namespace google_breakpad {
 
368
 
 
369
class MinidumpWriter {
 
370
 public:
 
371
  MinidumpWriter(const char* filename,
 
372
                 const ExceptionHandler::CrashContext* context,
 
373
                 const MappingList& mappings,
 
374
                 LinuxDumper* dumper)
 
375
      : filename_(filename),
 
376
        ucontext_(context ? &context->context : NULL),
 
377
#if !defined(__ARM_EABI__)
 
378
        float_state_(context ? &context->float_state : NULL),
 
379
#else
 
380
        // TODO: fix this after fixing ExceptionHandler
 
381
        float_state_(NULL),
 
382
#endif
 
383
        dumper_(dumper),
 
384
        memory_blocks_(dumper_->allocator()),
 
385
        mapping_list_(mappings) {
 
386
  }
 
387
 
 
388
  bool Init() {
 
389
    return dumper_->Init() && minidump_writer_.Open(filename_) &&
 
390
           dumper_->ThreadsSuspend();
 
391
  }
 
392
 
 
393
  ~MinidumpWriter() {
 
394
    minidump_writer_.Close();
 
395
    dumper_->ThreadsResume();
 
396
  }
 
397
 
 
398
  bool Dump() {
 
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.
 
411
      for (int i = 0;;) {
 
412
        ElfW(Dyn) dyn;
 
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++,
 
417
                                 sizeof(dyn));
 
418
        if (dyn.d_tag == DT_DEBUG) {
 
419
          r_debug = (struct r_debug*)dyn.d_un.d_ptr;
 
420
          continue;
 
421
        } else if (dyn.d_tag == DT_NULL) {
 
422
          break;
 
423
        }
 
424
      }
 
425
    }
 
426
#endif
 
427
 
 
428
    // A minidump file contains a number of tagged streams. This is the number
 
429
    // of stream which we write.
 
430
    unsigned kNumWriters = 12;
 
431
    if (r_debug)
 
432
      ++kNumWriters;
 
433
 
 
434
    TypedMDRVA<MDRawHeader> header(&minidump_writer_);
 
435
    TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
 
436
    if (!header.Allocate())
 
437
      return false;
 
438
    if (!dir.AllocateArray(kNumWriters))
 
439
      return false;
 
440
    memset(header.get(), 0, sizeof(MDRawHeader));
 
441
 
 
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();
 
447
 
 
448
    unsigned dir_index = 0;
 
449
    MDRawDirectory dirent;
 
450
 
 
451
    if (!WriteThreadListStream(&dirent))
 
452
      return false;
 
453
    dir.CopyIndex(dir_index++, &dirent);
 
454
 
 
455
    if (!WriteMappings(&dirent))
 
456
      return false;
 
457
    dir.CopyIndex(dir_index++, &dirent);
 
458
 
 
459
    if (!WriteMemoryListStream(&dirent))
 
460
      return false;
 
461
    dir.CopyIndex(dir_index++, &dirent);
 
462
 
 
463
    if (!WriteExceptionStream(&dirent))
 
464
      return false;
 
465
    dir.CopyIndex(dir_index++, &dirent);
 
466
 
 
467
    if (!WriteSystemInfoStream(&dirent))
 
468
      return false;
 
469
    dir.CopyIndex(dir_index++, &dirent);
 
470
 
 
471
    dirent.stream_type = MD_LINUX_CPU_INFO;
 
472
    if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
 
473
      NullifyDirectoryEntry(&dirent);
 
474
    dir.CopyIndex(dir_index++, &dirent);
 
475
 
 
476
    dirent.stream_type = MD_LINUX_PROC_STATUS;
 
477
    if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
 
478
      NullifyDirectoryEntry(&dirent);
 
479
    dir.CopyIndex(dir_index++, &dirent);
 
480
 
 
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);
 
485
 
 
486
    dirent.stream_type = MD_LINUX_CMD_LINE;
 
487
    if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
 
488
      NullifyDirectoryEntry(&dirent);
 
489
    dir.CopyIndex(dir_index++, &dirent);
 
490
 
 
491
    dirent.stream_type = MD_LINUX_ENVIRON;
 
492
    if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
 
493
      NullifyDirectoryEntry(&dirent);
 
494
    dir.CopyIndex(dir_index++, &dirent);
 
495
 
 
496
    dirent.stream_type = MD_LINUX_AUXV;
 
497
    if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
 
498
      NullifyDirectoryEntry(&dirent);
 
499
    dir.CopyIndex(dir_index++, &dirent);
 
500
 
 
501
    dirent.stream_type = MD_LINUX_MAPS;
 
502
    if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
 
503
      NullifyDirectoryEntry(&dirent);
 
504
    dir.CopyIndex(dir_index++, &dirent);
 
505
 
 
506
    if (r_debug) {
 
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);
 
511
    }
 
512
 
 
513
    // If you add more directory entries, don't forget to update kNumWriters,
 
514
    // above.
 
515
 
 
516
    dumper_->ThreadsResume();
 
517
    return true;
 
518
  }
 
519
 
 
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--; ) {
 
529
      if (bp < top ||
 
530
          bp + sizeof(bp) > thread.stack.start_of_memory_range +
 
531
          thread.stack.memory.data_size ||
 
532
          bp & 1) {
 
533
        break;
 
534
      }
 
535
      uint64_t old_top = top;
 
536
      top = bp;
 
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) {
 
540
        struct {
 
541
          uint64_t r15;
 
542
          uint64_t r14;
 
543
          uint64_t r13;
 
544
          uint64_t r12;
 
545
          uint64_t r11;
 
546
          uint64_t r10;
 
547
          uint64_t r9;
 
548
          uint64_t r8;
 
549
          uint64_t rdi;
 
550
          uint64_t rsi;
 
551
          uint64_t rdx;
 
552
          uint64_t rcx;
 
553
          uint64_t rbx;
 
554
          uint64_t deadbeef;
 
555
          uint64_t rbp;
 
556
          uint64_t fakeret;
 
557
          uint64_t ret;
 
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) {
 
564
          break;
 
565
        }
 
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;
 
585
        return;
 
586
      }
 
587
    }
 
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--; ) {
 
592
      if (bp < top ||
 
593
          bp + sizeof(bp) > thread.stack.start_of_memory_range +
 
594
          thread.stack.memory.data_size ||
 
595
          bp & 1) {
 
596
        break;
 
597
      }
 
598
      uint32_t old_top = top;
 
599
      top = bp;
 
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) {
 
603
        struct {
 
604
          uint32_t edi;
 
605
          uint32_t esi;
 
606
          uint32_t edx;
 
607
          uint32_t ecx;
 
608
          uint32_t ebx;
 
609
          uint32_t deadbeef;
 
610
          uint32_t ebp;
 
611
          uint32_t fakeret;
 
612
          uint32_t ret;
 
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) {
 
618
          break;
 
619
        }
 
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;
 
631
        return;
 
632
      }
 
633
    }
 
634
#endif
 
635
  }
 
636
 
 
637
  // Write information about the threads.
 
638
  bool WriteThreadListStream(MDRawDirectory* dirent) {
 
639
    const unsigned num_threads = dumper_->threads().size();
 
640
 
 
641
    TypedMDRVA<uint32_t> list(&minidump_writer_);
 
642
    if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
 
643
      return false;
 
644
 
 
645
    dirent->stream_type = MD_THREAD_LIST_STREAM;
 
646
    dirent->location = list.location();
 
647
 
 
648
    *list.get() = num_threads;
 
649
 
 
650
    for (unsigned i = 0; i < num_threads; ++i) {
 
651
      MDRawThread thread;
 
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
 
657
      // unhelpful.
 
658
      if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
 
659
          !dumper_->IsPostMortem()) {
 
660
        const void* stack;
 
661
        size_t stack_len;
 
662
        if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
 
663
          return false;
 
664
        UntypedMDRVA memory(&minidump_writer_);
 
665
        if (!memory.Allocate(stack_len))
 
666
          return false;
 
667
        uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
 
668
        dumper_->CopyFromProcess(stack_copy, thread.thread_id, stack,
 
669
                                 stack_len);
 
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);
 
674
 
 
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) {
 
687
            ip_is_mapped = true;
 
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;
 
698
            break;
 
699
          }
 
700
        }
 
701
 
 
702
        if (ip_is_mapped) {
 
703
          UntypedMDRVA ip_memory(&minidump_writer_);
 
704
          if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
 
705
            return false;
 
706
          uint8_t* memory_copy =
 
707
              reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
 
708
          dumper_->CopyFromProcess(
 
709
              memory_copy,
 
710
              thread.thread_id,
 
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);
 
716
        }
 
717
 
 
718
        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
 
719
        if (!cpu.Allocate())
 
720
          return false;
 
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();
 
726
      } else {
 
727
        ThreadInfo info;
 
728
        if (!dumper_->GetThreadInfoByIndex(i, &info))
 
729
          return false;
 
730
        UntypedMDRVA memory(&minidump_writer_);
 
731
        if (!memory.Allocate(info.stack_len))
 
732
          return false;
 
733
        uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(info.stack_len));
 
734
        dumper_->CopyFromProcess(stack_copy, thread.thread_id, info.stack,
 
735
                                 info.stack_len);
 
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);
 
740
 
 
741
        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
 
742
        if (!cpu.Allocate())
 
743
          return false;
 
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();
 
751
        }
 
752
      }
 
753
 
 
754
      list.CopyIndexAfterObject(i, &thread, sizeof(thread));
 
755
    }
 
756
 
 
757
    return true;
 
758
  }
 
759
 
 
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.
 
764
      return false;
 
765
    }
 
766
 
 
767
    return true;
 
768
  }
 
769
 
 
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();
 
775
         ++iter) {
 
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)) {
 
781
        return true;
 
782
      }
 
783
    }
 
784
    return false;
 
785
  }
 
786
 
 
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();
 
794
 
 
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++;
 
799
    }
 
800
 
 
801
    TypedMDRVA<uint32_t> list(&minidump_writer_);
 
802
    if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
 
803
      return false;
 
804
 
 
805
    dirent->stream_type = MD_MODULE_LIST_STREAM;
 
806
    dirent->location = list.location();
 
807
    *list.get() = num_output_mappings;
 
808
 
 
809
    // First write all the mappings from the dumper
 
810
    unsigned int j = 0;
 
811
    for (unsigned i = 0; i < num_mappings; ++i) {
 
812
      const MappingInfo& mapping = *dumper_->mappings()[i];
 
813
      if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
 
814
        continue;
 
815
 
 
816
      MDRawModule mod;
 
817
      if (!FillRawModule(mapping, true, i, mod, NULL))
 
818
        return false;
 
819
      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
 
820
    }
 
821
    // Next write all the mappings provided by the caller
 
822
    for (MappingList::const_iterator iter = mapping_list_.begin();
 
823
         iter != mapping_list_.end();
 
824
         ++iter) {
 
825
      MDRawModule mod;
 
826
      if (!FillRawModule(iter->first, false, 0, mod, iter->second))
 
827
        return false;
 
828
      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
 
829
    }
 
830
 
 
831
    return true;
 
832
  }
 
833
 
 
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,
 
838
                     bool member,
 
839
                     unsigned int mapping_id,
 
840
                     MDRawModule& mod,
 
841
                     const u_int8_t* identifier) {
 
842
    my_memset(&mod, 0, MD_MODULE_SIZE);
 
843
 
 
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);
 
847
 
 
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 == '/')
 
852
        break;
 
853
      filename_ptr--;
 
854
    }
 
855
    filename_ptr++;
 
856
 
 
857
    const size_t filename_len = mapping.name + filepath_len - filename_ptr;
 
858
 
 
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))
 
863
      return false;
 
864
 
 
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);
 
870
    if (identifier) {
 
871
      // GUID was provided by caller.
 
872
      memcpy(signature, identifier, sizeof(MDGUID));
 
873
    } else {
 
874
      dumper_->ElfFileIdentifierForMapping(mapping, member,
 
875
                                           mapping_id, signature);
 
876
    }
 
877
    my_memset(cv_ptr, 0, sizeof(uint32_t));  // Set age to 0 on Linux.
 
878
    cv_ptr += sizeof(uint32_t);
 
879
 
 
880
    // Write pdb_file_name
 
881
    memcpy(cv_ptr, filename_ptr, filename_len + 1);
 
882
    cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
 
883
 
 
884
    mod.cv_record = cv.location();
 
885
 
 
886
    MDLocationDescriptor ld;
 
887
    if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
 
888
      return false;
 
889
    mod.module_name_rva = ld.rva;
 
890
    return true;
 
891
  }
 
892
 
 
893
  bool WriteMemoryListStream(MDRawDirectory* dirent) {
 
894
    TypedMDRVA<uint32_t> list(&minidump_writer_);
 
895
    if (!list.AllocateObjectAndArray(memory_blocks_.size(),
 
896
                                     sizeof(MDMemoryDescriptor)))
 
897
      return false;
 
898
 
 
899
    dirent->stream_type = MD_MEMORY_LIST_STREAM;
 
900
    dirent->location = list.location();
 
901
 
 
902
    *list.get() = memory_blocks_.size();
 
903
 
 
904
    for (size_t i = 0; i < memory_blocks_.size(); ++i) {
 
905
      list.CopyIndexAfterObject(i, &memory_blocks_[i],
 
906
                                sizeof(MDMemoryDescriptor));
 
907
    }
 
908
    return true;
 
909
  }
 
910
 
 
911
  bool WriteExceptionStream(MDRawDirectory* dirent) {
 
912
    TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
 
913
    if (!exc.Allocate())
 
914
      return false;
 
915
    my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
 
916
 
 
917
    dirent->stream_type = MD_EXCEPTION_STREAM;
 
918
    dirent->location = exc.location();
 
919
 
 
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_;
 
924
 
 
925
    return true;
 
926
  }
 
927
 
 
928
  bool WriteSystemInfoStream(MDRawDirectory* dirent) {
 
929
    TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
 
930
    if (!si.Allocate())
 
931
      return false;
 
932
    my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
 
933
 
 
934
    dirent->stream_type = MD_SYSTEM_INFO_STREAM;
 
935
    dirent->location = si.location();
 
936
 
 
937
    WriteCPUInformation(si.get());
 
938
    WriteOSInformation(si.get());
 
939
 
 
940
    return true;
 
941
  }
 
942
 
 
943
  bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
 
944
                           uint32_t dynamic_length) {
 
945
#if defined(__ANDROID__)
 
946
    return false;
 
947
#else
 
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.
 
955
 
 
956
    // Count the number of loaded DSOs
 
957
    int dso_count = 0;
 
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; ) {
 
962
      struct link_map map;
 
963
      dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
 
964
      ptr = map.l_next;
 
965
      dso_count++;
 
966
    }
 
967
 
 
968
    MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
 
969
    if (dso_count > 0) {
 
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))
 
974
        return false;
 
975
      linkmap_rva = linkmap.location().rva;
 
976
      int idx = 0;
 
977
 
 
978
      // Iterate over DSOs and write their information to mini dump
 
979
      for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
 
980
        struct link_map map;
 
981
        dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
 
982
        ptr = map.l_next;
 
983
        char filename[257] = { 0 };
 
984
        if (map.l_name) {
 
985
          dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
 
986
                                   sizeof(filename) - 1);
 
987
        }
 
988
        MDLocationDescriptor location;
 
989
        if (!minidump_writer_.WriteString(filename, 0, &location))
 
990
          return false;
 
991
        MDRawLinkMap entry;
 
992
        entry.name = location.rva;
 
993
        entry.addr = (void*)map.l_addr;
 
994
        entry.ld = (void*)map.l_ld;
 
995
        linkmap.CopyIndex(idx++, &entry);
 
996
      }
 
997
    }
 
998
 
 
999
    // Write MD_LINUX_DSO_DEBUG record
 
1000
    TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
 
1001
    if (!debug.AllocateObjectAndArray(1, dynamic_length))
 
1002
      return false;
 
1003
    my_memset(debug.get(), 0, sizeof(MDRawDebug));
 
1004
    dirent->stream_type = MD_LINUX_DSO_DEBUG;
 
1005
    dirent->location = debug.location();
 
1006
 
 
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;
 
1013
 
 
1014
    char *dso_debug_data = new char[dynamic_length];
 
1015
    dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), &_DYNAMIC,
 
1016
                             dynamic_length);
 
1017
    debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
 
1018
    delete[] dso_debug_data;
 
1019
 
 
1020
    return true;
 
1021
#endif
 
1022
  }
 
1023
 
 
1024
 private:
 
1025
  void* Alloc(unsigned bytes) {
 
1026
    return dumper_->allocator()->Alloc(bytes);
 
1027
  }
 
1028
 
 
1029
  pid_t GetCrashThread() const {
 
1030
    return dumper_->crash_thread();
 
1031
  }
 
1032
 
 
1033
#if defined(__i386)
 
1034
  uintptr_t GetStackPointer() {
 
1035
    return ucontext_->uc_mcontext.gregs[REG_ESP];
 
1036
  }
 
1037
 
 
1038
  uintptr_t GetInstructionPointer() {
 
1039
    return ucontext_->uc_mcontext.gregs[REG_EIP];
 
1040
  }
 
1041
#elif defined(__x86_64)
 
1042
  uintptr_t GetStackPointer() {
 
1043
    return ucontext_->uc_mcontext.gregs[REG_RSP];
 
1044
  }
 
1045
 
 
1046
  uintptr_t GetInstructionPointer() {
 
1047
    return ucontext_->uc_mcontext.gregs[REG_RIP];
 
1048
  }
 
1049
#elif defined(__ARM_EABI__)
 
1050
  uintptr_t GetStackPointer() {
 
1051
    return ucontext_->uc_mcontext.arm_sp;
 
1052
  }
 
1053
 
 
1054
  uintptr_t GetInstructionPointer() {
 
1055
    return ucontext_->uc_mcontext.arm_ip;
 
1056
  }
 
1057
#else
 
1058
#error "This code has not been ported to your platform yet."
 
1059
#endif
 
1060
 
 
1061
  void NullifyDirectoryEntry(MDRawDirectory* dirent) {
 
1062
    dirent->stream_type = 0;
 
1063
    dirent->location.data_size = 0;
 
1064
    dirent->location.rva = 0;
 
1065
  }
 
1066
 
 
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;
 
1071
 
 
1072
    struct CpuInfoEntry {
 
1073
      const char* info_name;
 
1074
      int value;
 
1075
      bool found;
 
1076
    } cpu_info_table[] = {
 
1077
      { "processor", -1, false },
 
1078
      { "model", 0, false },
 
1079
      { "stepping",  0, false },
 
1080
      { "cpu family", 0, false },
 
1081
    };
 
1082
 
 
1083
    // processor_architecture should always be set, do this first
 
1084
    sys_info->processor_architecture =
 
1085
#if defined(__i386)
 
1086
        MD_CPU_ARCHITECTURE_X86;
 
1087
#elif defined(__x86_64)
 
1088
        MD_CPU_ARCHITECTURE_AMD64;
 
1089
#elif defined(__arm__)
 
1090
        MD_CPU_ARCHITECTURE_ARM;
 
1091
#else
 
1092
#error "Unknown CPU arch"
 
1093
#endif
 
1094
 
 
1095
    const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
 
1096
    if (fd < 0)
 
1097
      return false;
 
1098
 
 
1099
    {
 
1100
      PageAllocator allocator;
 
1101
      LineReader* const line_reader = new(allocator) LineReader(fd);
 
1102
      const char* line;
 
1103
      unsigned line_len;
 
1104
      while (line_reader->GetNextLine(&line, &line_len)) {
 
1105
        for (size_t i = 0;
 
1106
             i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
 
1107
             i++) {
 
1108
          CpuInfoEntry* entry = &cpu_info_table[i];
 
1109
          if (entry->found && i)
 
1110
            continue;
 
1111
          if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
 
1112
            const char* value = strchr(line, ':');
 
1113
            if (!value)
 
1114
              continue;
 
1115
 
 
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
 
1119
            // the colon.
 
1120
            const char* space_ptr = line + strlen(entry->info_name);
 
1121
            for (; space_ptr < value; space_ptr++) {
 
1122
              if (!isspace(*space_ptr)) {
 
1123
                break;
 
1124
              }
 
1125
            }
 
1126
            if (space_ptr != value)
 
1127
              continue;
 
1128
 
 
1129
            sscanf(++value, " %d", &(entry->value));
 
1130
            entry->found = true;
 
1131
          }
 
1132
        }
 
1133
 
 
1134
        // special case for vendor_id
 
1135
        if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
 
1136
          const char* value = strchr(line, ':');
 
1137
          if (!value)
 
1138
            goto popline;
 
1139
 
 
1140
          // skip ':" and all the spaces that follows
 
1141
          do {
 
1142
            value++;
 
1143
          } while (isspace(*value));
 
1144
 
 
1145
          if (*value) {
 
1146
            size_t length = strlen(value);
 
1147
            if (length == 0)
 
1148
              goto popline;
 
1149
            // we don't want the trailing newline
 
1150
            if (value[length - 1] == '\n')
 
1151
              length--;
 
1152
            // ensure we have space for the value
 
1153
            if (length < sizeof(vendor_id))
 
1154
              strncpy(vendor_id, value, length);
 
1155
          }
 
1156
        }
 
1157
 
 
1158
 popline:
 
1159
        line_reader->PopLine(line_len);
 
1160
      }
 
1161
      sys_close(fd);
 
1162
    }
 
1163
 
 
1164
    // make sure we got everything we wanted
 
1165
    for (size_t i = 0;
 
1166
         i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
 
1167
         i++) {
 
1168
      if (!cpu_info_table[i].found) {
 
1169
        return false;
 
1170
      }
 
1171
    }
 
1172
    // /proc/cpuinfo contains cpu id, change it into number by adding one.
 
1173
    cpu_info_table[0].value++;
 
1174
 
 
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;
 
1179
 
 
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));
 
1183
    }
 
1184
    return true;
 
1185
  }
 
1186
 
 
1187
  bool WriteFile(MDLocationDescriptor* result, const char* filename) {
 
1188
    const int fd = sys_open(filename, O_RDONLY, 0);
 
1189
    if (fd < 0)
 
1190
      return false;
 
1191
 
 
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*);
 
1196
    struct Buffers {
 
1197
      Buffers* next;
 
1198
      size_t len;
 
1199
      uint8_t data[kBufSize];
 
1200
    } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
 
1201
    buffers->next = NULL;
 
1202
    buffers->len = 0;
 
1203
 
 
1204
    size_t total = 0;
 
1205
    for (Buffers* bufptr = buffers;;) {
 
1206
      ssize_t r;
 
1207
      do {
 
1208
        r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
 
1209
      } while (r == -1 && errno == EINTR);
 
1210
 
 
1211
      if (r < 1)
 
1212
        break;
 
1213
 
 
1214
      total += r;
 
1215
      bufptr->len += r;
 
1216
      if (bufptr->len == kBufSize) {
 
1217
        bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
 
1218
        bufptr = bufptr->next;
 
1219
        bufptr->next = NULL;
 
1220
        bufptr->len = 0;
 
1221
      }
 
1222
    }
 
1223
    sys_close(fd);
 
1224
 
 
1225
    if (!total)
 
1226
      return false;
 
1227
 
 
1228
    UntypedMDRVA memory(&minidump_writer_);
 
1229
    if (!memory.Allocate(total))
 
1230
      return false;
 
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);
 
1239
        continue;
 
1240
      }
 
1241
      memory.Copy(pos, &buffers->data, buffers->len);
 
1242
      pos += buffers->len;
 
1243
    }
 
1244
    *result = memory.location();
 
1245
    return true;
 
1246
  }
 
1247
 
 
1248
  bool WriteOSInformation(MDRawSystemInfo* sys_info) {
 
1249
    sys_info->platform_id = MD_OS_LINUX;
 
1250
 
 
1251
    struct utsname uts;
 
1252
    if (uname(&uts))
 
1253
      return false;
 
1254
 
 
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[] = {
 
1259
      uts.sysname,
 
1260
      uts.release,
 
1261
      uts.version,
 
1262
      uts.machine,
 
1263
      NULL
 
1264
    };
 
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);
 
1270
      if (info_len == 0)
 
1271
        continue;
 
1272
 
 
1273
      if (space_left < info_len + (first_item ? 0 : separator_len))
 
1274
        break;
 
1275
 
 
1276
      if (!first_item) {
 
1277
        strcat(buf, separator);
 
1278
        space_left -= separator_len;
 
1279
      }
 
1280
 
 
1281
      first_item = false;
 
1282
      strcat(buf, *cur_info);
 
1283
      space_left -= info_len;
 
1284
    }
 
1285
 
 
1286
    MDLocationDescriptor location;
 
1287
    if (!minidump_writer_.WriteString(buf, 0, &location))
 
1288
      return false;
 
1289
    sys_info->csd_version_rva = location.rva;
 
1290
 
 
1291
    return true;
 
1292
  }
 
1293
 
 
1294
  bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
 
1295
                     const char* filename) {
 
1296
    char buf[NAME_MAX];
 
1297
    if (!dumper_->BuildProcPath(buf, pid, filename))
 
1298
      return false;
 
1299
    return WriteFile(result, buf);
 
1300
  }
 
1301
 
 
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_;
 
1314
};
 
1315
 
 
1316
bool WriteMinidump(const char* filename, pid_t crashing_process,
 
1317
                   const void* blob, size_t blob_size) {
 
1318
  MappingList m;
 
1319
  return WriteMinidump(filename, crashing_process, blob, blob_size, m);
 
1320
}
 
1321
 
 
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))
 
1326
    return false;
 
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);
 
1335
  if (!writer.Init())
 
1336
    return false;
 
1337
  return writer.Dump();
 
1338
}
 
1339
 
 
1340
bool WriteMinidump(const char* filename,
 
1341
                   const MappingList& mappings,
 
1342
                   LinuxDumper* dumper) {
 
1343
  MinidumpWriter writer(filename, NULL, mappings, dumper);
 
1344
  if (!writer.Init())
 
1345
    return false;
 
1346
  return writer.Dump();
 
1347
}
 
1348
 
 
1349
}  // namespace google_breakpad