aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/linux/dump_writer_common/mapping_info.h49
-rw-r--r--src/client/linux/dump_writer_common/raw_context_cpu.h53
-rw-r--r--src/client/linux/dump_writer_common/seccomp_unwinder.cc154
-rw-r--r--src/client/linux/dump_writer_common/seccomp_unwinder.h50
-rw-r--r--src/client/linux/dump_writer_common/thread_info.cc263
-rw-r--r--src/client/linux/dump_writer_common/thread_info.h88
-rw-r--r--src/client/linux/dump_writer_common/ucontext_reader.cc255
-rw-r--r--src/client/linux/dump_writer_common/ucontext_reader.h64
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h50
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc586
10 files changed, 993 insertions, 619 deletions
diff --git a/src/client/linux/dump_writer_common/mapping_info.h b/src/client/linux/dump_writer_common/mapping_info.h
new file mode 100644
index 00000000..c206b504
--- /dev/null
+++ b/src/client/linux/dump_writer_common/mapping_info.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
+#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
+
+#include <stdint.h>
+
+namespace google_breakpad {
+
+// One of these is produced for each mapping in the process (i.e. line in
+// /proc/$x/maps).
+struct MappingInfo {
+ uintptr_t start_addr;
+ size_t size;
+ size_t offset; // offset into the backed file.
+ bool exec; // true if the mapping has the execute bit set.
+ char name[NAME_MAX];
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
diff --git a/src/client/linux/dump_writer_common/raw_context_cpu.h b/src/client/linux/dump_writer_common/raw_context_cpu.h
new file mode 100644
index 00000000..e2ef45df
--- /dev/null
+++ b/src/client/linux/dump_writer_common/raw_context_cpu.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
+#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
+
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+#if defined(__i386__)
+typedef MDRawContextX86 RawContextCPU;
+#elif defined(__x86_64)
+typedef MDRawContextAMD64 RawContextCPU;
+#elif defined(__ARM_EABI__)
+typedef MDRawContextARM RawContextCPU;
+#elif defined(__aarch64__)
+typedef MDRawContextARM64 RawContextCPU;
+#elif defined(__mips__)
+typedef MDRawContextMIPS RawContextCPU;
+#else
+#error "This code has not been ported to your platform yet."
+#endif
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
diff --git a/src/client/linux/dump_writer_common/seccomp_unwinder.cc b/src/client/linux/dump_writer_common/seccomp_unwinder.cc
new file mode 100644
index 00000000..49971557
--- /dev/null
+++ b/src/client/linux/dump_writer_common/seccomp_unwinder.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/linux/dump_writer_common/seccomp_unwinder.h"
+
+#include <string.h>
+
+#include "google_breakpad/common/minidump_format.h"
+#include "common/linux/linux_libc_support.h"
+
+namespace google_breakpad {
+
+void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu,
+ const MDRawThread& thread,
+ uint8_t* stack_copy) {
+#if defined(__x86_64)
+ uint64_t bp = cpu->rbp;
+ uint64_t top = thread.stack.start_of_memory_range;
+ for (int i = 4; i--; ) {
+ if (bp < top ||
+ bp + sizeof(bp) > thread.stack.start_of_memory_range +
+ thread.stack.memory.data_size ||
+ bp & 1) {
+ break;
+ }
+ uint64_t old_top = top;
+ top = bp;
+ uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
+ my_memcpy(&bp, bp_addr, sizeof(bp));
+ if (bp == 0xDEADBEEFDEADBEEFull) {
+ struct {
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t rbx;
+ uint64_t deadbeef;
+ uint64_t rbp;
+ uint64_t fakeret;
+ uint64_t ret;
+ /* char redzone[128]; */
+ } seccomp_stackframe;
+ if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
+ top - offsetof(typeof(seccomp_stackframe), deadbeef) +
+ sizeof(seccomp_stackframe) >
+ thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
+ break;
+ }
+ my_memcpy(&seccomp_stackframe,
+ bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
+ sizeof(seccomp_stackframe));
+ cpu->rbx = seccomp_stackframe.rbx;
+ cpu->rcx = seccomp_stackframe.rcx;
+ cpu->rdx = seccomp_stackframe.rdx;
+ cpu->rsi = seccomp_stackframe.rsi;
+ cpu->rdi = seccomp_stackframe.rdi;
+ cpu->rbp = seccomp_stackframe.rbp;
+ cpu->rsp = top + 4*sizeof(uint64_t) + 128;
+ cpu->r8 = seccomp_stackframe.r8;
+ cpu->r9 = seccomp_stackframe.r9;
+ cpu->r10 = seccomp_stackframe.r10;
+ cpu->r11 = seccomp_stackframe.r11;
+ cpu->r12 = seccomp_stackframe.r12;
+ cpu->r13 = seccomp_stackframe.r13;
+ cpu->r14 = seccomp_stackframe.r14;
+ cpu->r15 = seccomp_stackframe.r15;
+ cpu->rip = seccomp_stackframe.fakeret;
+ return;
+ }
+ }
+#elif defined(__i386__)
+ uint32_t bp = cpu->ebp;
+ uint32_t top = thread.stack.start_of_memory_range;
+ for (int i = 4; i--; ) {
+ if (bp < top ||
+ bp + sizeof(bp) > thread.stack.start_of_memory_range +
+ thread.stack.memory.data_size ||
+ bp & 1) {
+ break;
+ }
+ uint32_t old_top = top;
+ top = bp;
+ uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
+ my_memcpy(&bp, bp_addr, sizeof(bp));
+ if (bp == 0xDEADBEEFu) {
+ struct {
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t ebx;
+ uint32_t deadbeef;
+ uint32_t ebp;
+ uint32_t fakeret;
+ uint32_t ret;
+ } seccomp_stackframe;
+ if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
+ top - offsetof(typeof(seccomp_stackframe), deadbeef) +
+ sizeof(seccomp_stackframe) >
+ thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
+ break;
+ }
+ my_memcpy(&seccomp_stackframe,
+ bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
+ sizeof(seccomp_stackframe));
+ cpu->ebx = seccomp_stackframe.ebx;
+ cpu->ecx = seccomp_stackframe.ecx;
+ cpu->edx = seccomp_stackframe.edx;
+ cpu->esi = seccomp_stackframe.esi;
+ cpu->edi = seccomp_stackframe.edi;
+ cpu->ebp = seccomp_stackframe.ebp;
+ cpu->esp = top + 4*sizeof(void*);
+ cpu->eip = seccomp_stackframe.fakeret;
+ return;
+ }
+ }
+#endif
+}
+
+} // namespace google_breakpad
diff --git a/src/client/linux/dump_writer_common/seccomp_unwinder.h b/src/client/linux/dump_writer_common/seccomp_unwinder.h
new file mode 100644
index 00000000..0f5637b6
--- /dev/null
+++ b/src/client/linux/dump_writer_common/seccomp_unwinder.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
+#define CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
+
+#include "client/linux/dump_writer_common/raw_context_cpu.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+struct SeccompUnwinder {
+
+ // Check if the top of the stack is part of a system call that has been
+ // redirected by the seccomp sandbox. If so, try to pop the stack frames
+ // all the way back to the point where the interception happened.
+ static void PopSeccompStackFrame(RawContextCPU* cpu,
+ const MDRawThread& thread,
+ uint8_t* stack_copy);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc
new file mode 100644
index 00000000..905941ee
--- /dev/null
+++ b/src/client/linux/dump_writer_common/thread_info.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/linux/dump_writer_common/thread_info.h"
+
+#include <string.h>
+
+#include "common/linux/linux_libc_support.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace {
+
+#if defined(__i386__)
+// Write a uint16_t to memory
+// out: memory location to write to
+// v: value to write.
+void U16(void* out, uint16_t v) {
+ my_memcpy(out, &v, sizeof(v));
+}
+
+// Write a uint32_t to memory
+// out: memory location to write to
+// v: value to write.
+void U32(void* out, uint32_t v) {
+ my_memcpy(out, &v, sizeof(v));
+}
+#endif
+
+}
+
+namespace google_breakpad {
+
+#if defined(__i386__)
+
+uintptr_t ThreadInfo::GetInstructionPointer() const {
+ return regs.eip;
+}
+
+void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
+ out->context_flags = MD_CONTEXT_X86_ALL;
+
+ out->dr0 = dregs[0];
+ out->dr1 = dregs[1];
+ out->dr2 = dregs[2];
+ out->dr3 = dregs[3];
+ // 4 and 5 deliberatly omitted because they aren't included in the minidump
+ // format.
+ out->dr6 = dregs[6];
+ out->dr7 = dregs[7];
+
+ out->gs = regs.xgs;
+ out->fs = regs.xfs;
+ out->es = regs.xes;
+ out->ds = regs.xds;
+
+ out->edi = regs.edi;
+ out->esi = regs.esi;
+ out->ebx = regs.ebx;
+ out->edx = regs.edx;
+ out->ecx = regs.ecx;
+ out->eax = regs.eax;
+
+ out->ebp = regs.ebp;
+ out->eip = regs.eip;
+ out->cs = regs.xcs;
+ out->eflags = regs.eflags;
+ out->esp = regs.esp;
+ out->ss = regs.xss;
+
+ out->float_save.control_word = fpregs.cwd;
+ out->float_save.status_word = fpregs.swd;
+ out->float_save.tag_word = fpregs.twd;
+ out->float_save.error_offset = fpregs.fip;
+ out->float_save.error_selector = fpregs.fcs;
+ out->float_save.data_offset = fpregs.foo;
+ out->float_save.data_selector = fpregs.fos;
+
+ // 8 registers * 10 bytes per register.
+ my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8);
+
+ // This matches the Intel fpsave format.
+ U16(out->extended_registers + 0, fpregs.cwd);
+ U16(out->extended_registers + 2, fpregs.swd);
+ U16(out->extended_registers + 4, fpregs.twd);
+ U16(out->extended_registers + 6, fpxregs.fop);
+ U32(out->extended_registers + 8, fpxregs.fip);
+ U16(out->extended_registers + 12, fpxregs.fcs);
+ U32(out->extended_registers + 16, fpregs.foo);
+ U16(out->extended_registers + 20, fpregs.fos);
+ U32(out->extended_registers + 24, fpxregs.mxcsr);
+
+ my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128);
+ my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128);
+}
+
+#elif defined(__x86_64)
+
+uintptr_t ThreadInfo::GetInstructionPointer() const {
+ return regs.rip;
+}
+
+void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
+ out->context_flags = MD_CONTEXT_AMD64_FULL |
+ MD_CONTEXT_AMD64_SEGMENTS;
+
+ out->cs = regs.cs;
+
+ out->ds = regs.ds;
+ out->es = regs.es;
+ out->fs = regs.fs;
+ out->gs = regs.gs;
+
+ out->ss = regs.ss;
+ out->eflags = regs.eflags;
+
+ out->dr0 = dregs[0];
+ out->dr1 = dregs[1];
+ out->dr2 = dregs[2];
+ out->dr3 = dregs[3];
+ // 4 and 5 deliberatly omitted because they aren't included in the minidump
+ // format.
+ out->dr6 = dregs[6];
+ out->dr7 = dregs[7];
+
+ out->rax = regs.rax;
+ out->rcx = regs.rcx;
+ out->rdx = regs.rdx;
+ out->rbx = regs.rbx;
+
+ out->rsp = regs.rsp;
+
+ out->rbp = regs.rbp;
+ out->rsi = regs.rsi;
+ out->rdi = regs.rdi;
+ out->r8 = regs.r8;
+ out->r9 = regs.r9;
+ out->r10 = regs.r10;
+ out->r11 = regs.r11;
+ out->r12 = regs.r12;
+ out->r13 = regs.r13;
+ out->r14 = regs.r14;
+ out->r15 = regs.r15;
+
+ out->rip = regs.rip;
+
+ out->flt_save.control_word = fpregs.cwd;
+ out->flt_save.status_word = fpregs.swd;
+ out->flt_save.tag_word = fpregs.ftw;
+ out->flt_save.error_opcode = fpregs.fop;
+ out->flt_save.error_offset = fpregs.rip;
+ out->flt_save.error_selector = 0; // We don't have this.
+ out->flt_save.data_offset = fpregs.rdp;
+ out->flt_save.data_selector = 0; // We don't have this.
+ out->flt_save.mx_csr = fpregs.mxcsr;
+ out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
+ my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
+ my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
+}
+
+#elif defined(__ARM_EABI__)
+
+uintptr_t ThreadInfo::GetInstructionPointer() const {
+ return regs.uregs[15];
+}
+
+void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
+ out->context_flags = MD_CONTEXT_ARM_FULL;
+
+ for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
+ out->iregs[i] = regs.uregs[i];
+ // No CPSR register in ThreadInfo(it's not accessible via ptrace)
+ out->cpsr = 0;
+#if !defined(__ANDROID__)
+ out->float_save.fpscr = fpregs.fpsr |
+ (static_cast<uint64_t>(fpregs.fpcr) << 32);
+ // TODO: sort this out, actually collect floating point registers
+ my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
+ my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
+#endif
+}
+
+#elif defined(__aarch64__)
+
+uintptr_t ThreadInfo::GetInstructionPointer() const {
+ return regs.pc;
+}
+
+void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
+ out->context_flags = MD_CONTEXT_ARM64_FULL;
+
+ out->cpsr = static_cast<uint32_t>(regs.pstate);
+ for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
+ out->iregs[i] = regs.regs[i];
+ out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp;
+ out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc;
+
+ out->float_save.fpsr = fpregs.fpsr;
+ out->float_save.fpcr = fpregs.fpcr;
+ my_memcpy(&out->float_save.regs, &fpregs.vregs,
+ MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
+}
+
+#elif defined(__mips__)
+
+uintptr_t ThreadInfo::GetInstructionPointer() const {
+ return regs.epc;
+}
+
+void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
+ out->context_flags = MD_CONTEXT_MIPS_FULL;
+
+ for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
+ out->iregs[i] = regs.regs[i];
+
+ out->mdhi = regs.hi;
+ out->mdlo = regs.lo;
+
+ for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) {
+ out->hi[i] = hi[i];
+ out->lo[i] = lo[i];
+ }
+ out->dsp_control = dsp_control;
+
+ out->epc = regs.epc;
+ out->badvaddr = regs.badvaddr;
+ out->status = regs.status;
+ out->cause = regs.cause;
+
+ for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
+ out->float_save.regs[i] = fpregs.regs[i];
+
+ out->float_save.fpcsr = fpregs.fpcsr;
+ out->float_save.fir = fpregs.fir;
+}
+#endif
+
+} // namespace google_breakpad
diff --git a/src/client/linux/dump_writer_common/thread_info.h b/src/client/linux/dump_writer_common/thread_info.h
new file mode 100644
index 00000000..5f24fd6b
--- /dev/null
+++ b/src/client/linux/dump_writer_common/thread_info.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
+#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
+
+#include <sys/ucontext.h>
+#include <sys/user.h>
+
+#include "client/linux/dump_writer_common/raw_context_cpu.h"
+#include "common/memory.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+#if defined(__i386) || defined(__x86_64)
+typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
+#endif
+
+// We produce one of these structures for each thread in the crashed process.
+struct ThreadInfo {
+ pid_t tgid; // thread group id
+ pid_t ppid; // parent process
+
+ uintptr_t stack_pointer; // thread stack pointer
+
+
+#if defined(__i386) || defined(__x86_64)
+ user_regs_struct regs;
+ user_fpregs_struct fpregs;
+ static const unsigned kNumDebugRegisters = 8;
+ debugreg_t dregs[8];
+#if defined(__i386)
+ user_fpxregs_struct fpxregs;
+#endif // defined(__i386)
+
+#elif defined(__ARM_EABI__)
+ // Mimicking how strace does this(see syscall.c, search for GETREGS)
+ struct user_regs regs;
+ struct user_fpregs fpregs;
+#elif defined(__aarch64__)
+ // Use the structures defined in <asm/ptrace.h>
+ struct user_pt_regs regs;
+ struct user_fpsimd_state fpregs;
+#elif defined(__mips__)
+ user_regs_struct regs;
+ user_fpregs_struct fpregs;
+ uint32_t hi[3];
+ uint32_t lo[3];
+ uint32_t dsp_control;
+#endif
+
+ // Returns the instruction pointer (platform-dependent impl.).
+ uintptr_t GetInstructionPointer() const;
+
+ // Fills a RawContextCPU using the context in the ThreadInfo object.
+ void FillCPUContext(RawContextCPU* out) const;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc
new file mode 100644
index 00000000..f497ac2f
--- /dev/null
+++ b/src/client/linux/dump_writer_common/ucontext_reader.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/linux/dump_writer_common/ucontext_reader.h"
+
+#include "common/linux/linux_libc_support.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Minidump defines register structures which are different from the raw
+// structures which we get from the kernel. These are platform specific
+// functions to juggle the ucontext and user structures into minidump format.
+
+#if defined(__i386__)
+
+uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.gregs[REG_ESP];
+}
+
+uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.gregs[REG_EIP];
+}
+
+void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
+ const struct _libc_fpstate* fp) {
+ const greg_t* regs = uc->uc_mcontext.gregs;
+
+ out->context_flags = MD_CONTEXT_X86_FULL |
+ MD_CONTEXT_X86_FLOATING_POINT;
+
+ out->gs = regs[REG_GS];
+ out->fs = regs[REG_FS];
+ out->es = regs[REG_ES];
+ out->ds = regs[REG_DS];
+
+ out->edi = regs[REG_EDI];
+ out->esi = regs[REG_ESI];
+ out->ebx = regs[REG_EBX];
+ out->edx = regs[REG_EDX];
+ out->ecx = regs[REG_ECX];
+ out->eax = regs[REG_EAX];
+
+ out->ebp = regs[REG_EBP];
+ out->eip = regs[REG_EIP];
+ out->cs = regs[REG_CS];
+ out->eflags = regs[REG_EFL];
+ out->esp = regs[REG_UESP];
+ out->ss = regs[REG_SS];
+
+ out->float_save.control_word = fp->cw;
+ out->float_save.status_word = fp->sw;
+ out->float_save.tag_word = fp->tag;
+ out->float_save.error_offset = fp->ipoff;
+ out->float_save.error_selector = fp->cssel;
+ out->float_save.data_offset = fp->dataoff;
+ out->float_save.data_selector = fp->datasel;
+
+ // 8 registers * 10 bytes per register.
+ my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
+}
+
+#elif defined(__x86_64)
+
+uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.gregs[REG_RSP];
+}
+
+uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.gregs[REG_RIP];
+}
+
+void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
+ const struct _libc_fpstate* fpregs) {
+ const greg_t* regs = uc->uc_mcontext.gregs;
+
+ out->context_flags = MD_CONTEXT_AMD64_FULL;
+
+ out->cs = regs[REG_CSGSFS] & 0xffff;
+
+ out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
+ out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
+
+ out->eflags = regs[REG_EFL];
+
+ out->rax = regs[REG_RAX];
+ out->rcx = regs[REG_RCX];
+ out->rdx = regs[REG_RDX];
+ out->rbx = regs[REG_RBX];
+
+ out->rsp = regs[REG_RSP];
+ out->rbp = regs[REG_RBP];
+ out->rsi = regs[REG_RSI];
+ out->rdi = regs[REG_RDI];
+ out->r8 = regs[REG_R8];
+ out->r9 = regs[REG_R9];
+ out->r10 = regs[REG_R10];
+ out->r11 = regs[REG_R11];
+ out->r12 = regs[REG_R12];
+ out->r13 = regs[REG_R13];
+ out->r14 = regs[REG_R14];
+ out->r15 = regs[REG_R15];
+
+ out->rip = regs[REG_RIP];
+
+ out->flt_save.control_word = fpregs->cwd;
+ out->flt_save.status_word = fpregs->swd;
+ out->flt_save.tag_word = fpregs->ftw;
+ out->flt_save.error_opcode = fpregs->fop;
+ out->flt_save.error_offset = fpregs->rip;
+ out->flt_save.data_offset = fpregs->rdp;
+ out->flt_save.error_selector = 0; // We don't have this.
+ out->flt_save.data_selector = 0; // We don't have this.
+ out->flt_save.mx_csr = fpregs->mxcsr;
+ out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
+ my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
+ my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
+}
+
+#elif defined(__ARM_EABI__)
+
+uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.arm_sp;
+}
+
+uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.arm_pc;
+}
+
+void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
+ out->context_flags = MD_CONTEXT_ARM_FULL;
+
+ out->iregs[0] = uc->uc_mcontext.arm_r0;
+ out->iregs[1] = uc->uc_mcontext.arm_r1;
+ out->iregs[2] = uc->uc_mcontext.arm_r2;
+ out->iregs[3] = uc->uc_mcontext.arm_r3;
+ out->iregs[4] = uc->uc_mcontext.arm_r4;
+ out->iregs[5] = uc->uc_mcontext.arm_r5;
+ out->iregs[6] = uc->uc_mcontext.arm_r6;
+ out->iregs[7] = uc->uc_mcontext.arm_r7;
+ out->iregs[8] = uc->uc_mcontext.arm_r8;
+ out->iregs[9] = uc->uc_mcontext.arm_r9;
+ out->iregs[10] = uc->uc_mcontext.arm_r10;
+
+ out->iregs[11] = uc->uc_mcontext.arm_fp;
+ out->iregs[12] = uc->uc_mcontext.arm_ip;
+ out->iregs[13] = uc->uc_mcontext.arm_sp;
+ out->iregs[14] = uc->uc_mcontext.arm_lr;
+ out->iregs[15] = uc->uc_mcontext.arm_pc;
+
+ out->cpsr = uc->uc_mcontext.arm_cpsr;
+
+ // TODO: fix this after fixing ExceptionHandler
+ out->float_save.fpscr = 0;
+ my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
+ my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
+}
+
+#elif defined(__aarch64__)
+
+uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.sp;
+}
+
+uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.pc;
+}
+
+void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
+ const struct fpsimd_context* fpregs) {
+ out->context_flags = MD_CONTEXT_ARM64_FULL;
+
+ out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
+ for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
+ out->iregs[i] = uc->uc_mcontext.regs[i];
+ out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp;
+ out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc;
+
+ out->float_save.fpsr = fpregs->fpsr;
+ out->float_save.fpcr = fpregs->fpcr;
+ my_memcpy(&out->float_save.regs, &fpregs->vregs,
+ MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
+}
+
+#elif defined(__mips__)
+
+uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
+}
+
+uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
+ return uc->uc_mcontext.pc;
+}
+
+void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
+ out->context_flags = MD_CONTEXT_MIPS_FULL;
+
+ for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
+ out->iregs[i] = uc->uc_mcontext.gregs[i];
+
+ out->mdhi = uc->uc_mcontext.mdhi;
+ out->mdlo = uc->uc_mcontext.mdlo;
+
+ out->hi[0] = uc->uc_mcontext.hi1;
+ out->hi[1] = uc->uc_mcontext.hi2;
+ out->hi[2] = uc->uc_mcontext.hi3;
+ out->lo[0] = uc->uc_mcontext.lo1;
+ out->lo[1] = uc->uc_mcontext.lo2;
+ out->lo[2] = uc->uc_mcontext.lo3;
+ out->dsp_control = uc->uc_mcontext.dsp;
+
+ out->epc = uc->uc_mcontext.pc;
+ out->badvaddr = 0; // Not reported in signal context.
+ out->status = 0; // Not reported in signal context.
+ out->cause = 0; // Not reported in signal context.
+
+ for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
+#if defined (__ANDROID__)
+ out->float_save.regs[i] = uc->uc_mcontext.fpregs[i];
+#else
+ out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
+#endif
+
+ out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
+ out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
+}
+#endif
+
+} // namespace google_breakpad
diff --git a/src/client/linux/dump_writer_common/ucontext_reader.h b/src/client/linux/dump_writer_common/ucontext_reader.h
new file mode 100644
index 00000000..b6e77b4b
--- /dev/null
+++ b/src/client/linux/dump_writer_common/ucontext_reader.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
+#define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
+
+#include <sys/ucontext.h>
+#include <sys/user.h>
+
+#include "client/linux/dump_writer_common/raw_context_cpu.h"
+#include "common/memory.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Wraps platform-dependent implementations of accessors to ucontext structs.
+struct UContextReader {
+ static uintptr_t GetStackPointer(const struct ucontext* uc);
+
+ static uintptr_t GetInstructionPointer(const struct ucontext* uc);
+
+ // Juggle a arch-specific ucontext into a minidump format
+ // out: the minidump structure
+ // info: the collection of register structures.
+#if defined(__i386__) || defined(__x86_64)
+ static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
+ const struct _libc_fpstate* fp);
+#elif defined(__aarch64__)
+ static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
+ const struct fpsimd_context* fpregs);
+#else
+ static void FillCPUContext(RawContextCPU *out, const ucontext *uc);
+#endif
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h
index ad2af018..e37ed179 100644
--- a/src/client/linux/minidump_writer/linux_dumper.h
+++ b/src/client/linux/minidump_writer/linux_dumper.h
@@ -44,15 +44,13 @@
#include <sys/types.h>
#include <sys/user.h>
+#include "client/linux/dump_writer_common/mapping_info.h"
+#include "client/linux/dump_writer_common/thread_info.h"
#include "common/memory.h"
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
-#if defined(__i386) || defined(__x86_64)
-typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
-#endif
-
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
#if defined(__i386) || defined(__ARM_EABI__) || defined(__mips__)
typedef Elf32_auxv_t elf_aux_entry;
@@ -67,50 +65,6 @@ typedef typeof(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t;
// This should always be less than NAME_MAX!
const char kLinuxGateLibraryName[] = "linux-gate.so";
-// We produce one of these structures for each thread in the crashed process.
-struct ThreadInfo {
- pid_t tgid; // thread group id
- pid_t ppid; // parent process
-
- uintptr_t stack_pointer; // thread stack pointer
-
-
-#if defined(__i386) || defined(__x86_64)
- user_regs_struct regs;
- user_fpregs_struct fpregs;
- static const unsigned kNumDebugRegisters = 8;
- debugreg_t dregs[8];
-#if defined(__i386)
- user_fpxregs_struct fpxregs;
-#endif // defined(__i386)
-
-#elif defined(__ARM_EABI__)
- // Mimicking how strace does this(see syscall.c, search for GETREGS)
- struct user_regs regs;
- struct user_fpregs fpregs;
-#elif defined(__aarch64__)
- // Use the structures defined in <asm/ptrace.h>
- struct user_pt_regs regs;
- struct user_fpsimd_state fpregs;
-#elif defined(__mips__)
- user_regs_struct regs;
- user_fpregs_struct fpregs;
- uint32_t hi[3];
- uint32_t lo[3];
- uint32_t dsp_control;
-#endif
-};
-
-// One of these is produced for each mapping in the process (i.e. line in
-// /proc/$x/maps).
-struct MappingInfo {
- uintptr_t start_addr;
- size_t size;
- size_t offset; // offset into the backed file.
- bool exec; // true if the mapping has the execute bit set.
- char name[NAME_MAX];
-};
-
class LinuxDumper {
public:
explicit LinuxDumper(pid_t pid);
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index 41b4864b..c65fa9c9 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -64,6 +64,9 @@
#include <algorithm>
+#include "client/linux/dump_writer_common/seccomp_unwinder.h"
+#include "client/linux/dump_writer_common/thread_info.h"
+#include "client/linux/dump_writer_common/ucontext_reader.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/cpu_set.h"
#include "client/linux/minidump_writer/line_reader.h"
@@ -89,393 +92,14 @@ using google_breakpad::MappingList;
using google_breakpad::MinidumpFileWriter;
using google_breakpad::PageAllocator;
using google_breakpad::ProcCpuInfoReader;
+using google_breakpad::RawContextCPU;
+using google_breakpad::SeccompUnwinder;
using google_breakpad::ThreadInfo;
using google_breakpad::TypedMDRVA;
+using google_breakpad::UContextReader;
using google_breakpad::UntypedMDRVA;
using google_breakpad::wasteful_vector;
-// Minidump defines register structures which are different from the raw
-// structures which we get from the kernel. These are platform specific
-// functions to juggle the ucontext and user structures into minidump format.
-#if defined(__i386__)
-typedef MDRawContextX86 RawContextCPU;
-
-// Write a uint16_t to memory
-// out: memory location to write to
-// v: value to write.
-void U16(void* out, uint16_t v) {
- my_memcpy(out, &v, sizeof(v));
-}
-
-// Write a uint32_t to memory
-// out: memory location to write to
-// v: value to write.
-void U32(void* out, uint32_t v) {
- my_memcpy(out, &v, sizeof(v));
-}
-
-// Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
-// out: the minidump structure
-// info: the collection of register structures.
-void CPUFillFromThreadInfo(MDRawContextX86 *out,
- const google_breakpad::ThreadInfo &info) {
- out->context_flags = MD_CONTEXT_X86_ALL;
-
- out->dr0 = info.dregs[0];
- out->dr1 = info.dregs[1];
- out->dr2 = info.dregs[2];
- out->dr3 = info.dregs[3];
- // 4 and 5 deliberatly omitted because they aren't included in the minidump
- // format.
- out->dr6 = info.dregs[6];
- out->dr7 = info.dregs[7];
-
- out->gs = info.regs.xgs;
- out->fs = info.regs.xfs;
- out->es = info.regs.xes;
- out->ds = info.regs.xds;
-
- out->edi = info.regs.edi;
- out->esi = info.regs.esi;
- out->ebx = info.regs.ebx;
- out->edx = info.regs.edx;
- out->ecx = info.regs.ecx;
- out->eax = info.regs.eax;
-
- out->ebp = info.regs.ebp;
- out->eip = info.regs.eip;
- out->cs = info.regs.xcs;
- out->eflags = info.regs.eflags;
- out->esp = info.regs.esp;
- out->ss = info.regs.xss;
-
- out->float_save.control_word = info.fpregs.cwd;
- out->float_save.status_word = info.fpregs.swd;
- out->float_save.tag_word = info.fpregs.twd;
- out->float_save.error_offset = info.fpregs.fip;
- out->float_save.error_selector = info.fpregs.fcs;
- out->float_save.data_offset = info.fpregs.foo;
- out->float_save.data_selector = info.fpregs.fos;
-
- // 8 registers * 10 bytes per register.
- my_memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
-
- // This matches the Intel fpsave format.
- U16(out->extended_registers + 0, info.fpregs.cwd);
- U16(out->extended_registers + 2, info.fpregs.swd);
- U16(out->extended_registers + 4, info.fpregs.twd);
- U16(out->extended_registers + 6, info.fpxregs.fop);
- U32(out->extended_registers + 8, info.fpxregs.fip);
- U16(out->extended_registers + 12, info.fpxregs.fcs);
- U32(out->extended_registers + 16, info.fpregs.foo);
- U16(out->extended_registers + 20, info.fpregs.fos);
- U32(out->extended_registers + 24, info.fpxregs.mxcsr);
-
- my_memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
- my_memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
-}
-
-// Juggle an x86 ucontext into minidump format
-// out: the minidump structure
-// info: the collection of register structures.
-void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
- const struct _libc_fpstate* fp) {
- const greg_t* regs = uc->uc_mcontext.gregs;
-
- out->context_flags = MD_CONTEXT_X86_FULL |
- MD_CONTEXT_X86_FLOATING_POINT;
-
- out->gs = regs[REG_GS];
- out->fs = regs[REG_FS];
- out->es = regs[REG_ES];
- out->ds = regs[REG_DS];
-
- out->edi = regs[REG_EDI];
- out->esi = regs[REG_ESI];
- out->ebx = regs[REG_EBX];
- out->edx = regs[REG_EDX];
- out->ecx = regs[REG_ECX];
- out->eax = regs[REG_EAX];
-
- out->ebp = regs[REG_EBP];
- out->eip = regs[REG_EIP];
- out->cs = regs[REG_CS];
- out->eflags = regs[REG_EFL];
- out->esp = regs[REG_UESP];
- out->ss = regs[REG_SS];
-
- out->float_save.control_word = fp->cw;
- out->float_save.status_word = fp->sw;
- out->float_save.tag_word = fp->tag;
- out->float_save.error_offset = fp->ipoff;
- out->float_save.error_selector = fp->cssel;
- out->float_save.data_offset = fp->dataoff;
- out->float_save.data_selector = fp->datasel;
-
- // 8 registers * 10 bytes per register.
- my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
-}
-
-#elif defined(__x86_64)
-typedef MDRawContextAMD64 RawContextCPU;
-
-void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
- const google_breakpad::ThreadInfo &info) {
- out->context_flags = MD_CONTEXT_AMD64_FULL |
- MD_CONTEXT_AMD64_SEGMENTS;
-
- out->cs = info.regs.cs;
-
- out->ds = info.regs.ds;
- out->es = info.regs.es;
- out->fs = info.regs.fs;
- out->gs = info.regs.gs;
-
- out->ss = info.regs.ss;
- out->eflags = info.regs.eflags;
-
- out->dr0 = info.dregs[0];
- out->dr1 = info.dregs[1];
- out->dr2 = info.dregs[2];
- out->dr3 = info.dregs[3];
- // 4 and 5 deliberatly omitted because they aren't included in the minidump
- // format.
- out->dr6 = info.dregs[6];
- out->dr7 = info.dregs[7];
-
- out->rax = info.regs.rax;
- out->rcx = info.regs.rcx;
- out->rdx = info.regs.rdx;
- out->rbx = info.regs.rbx;
-
- out->rsp = info.regs.rsp;
-
- out->rbp = info.regs.rbp;
- out->rsi = info.regs.rsi;
- out->rdi = info.regs.rdi;
- out->r8 = info.regs.r8;
- out->r9 = info.regs.r9;
- out->r10 = info.regs.r10;
- out->r11 = info.regs.r11;
- out->r12 = info.regs.r12;
- out->r13 = info.regs.r13;
- out->r14 = info.regs.r14;
- out->r15 = info.regs.r15;
-
- out->rip = info.regs.rip;
-
- out->flt_save.control_word = info.fpregs.cwd;
- out->flt_save.status_word = info.fpregs.swd;
- out->flt_save.tag_word = info.fpregs.ftw;
- out->flt_save.error_opcode = info.fpregs.fop;
- out->flt_save.error_offset = info.fpregs.rip;
- out->flt_save.error_selector = 0; // We don't have this.
- out->flt_save.data_offset = info.fpregs.rdp;
- out->flt_save.data_selector = 0; // We don't have this.
- out->flt_save.mx_csr = info.fpregs.mxcsr;
- out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
- my_memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
- my_memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
-}
-
-void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
- const struct _libc_fpstate* fpregs) {
- const greg_t* regs = uc->uc_mcontext.gregs;
-
- out->context_flags = MD_CONTEXT_AMD64_FULL;
-
- out->cs = regs[REG_CSGSFS] & 0xffff;
-
- out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
- out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
-
- out->eflags = regs[REG_EFL];
-
- out->rax = regs[REG_RAX];
- out->rcx = regs[REG_RCX];
- out->rdx = regs[REG_RDX];
- out->rbx = regs[REG_RBX];
-
- out->rsp = regs[REG_RSP];
- out->rbp = regs[REG_RBP];
- out->rsi = regs[REG_RSI];
- out->rdi = regs[REG_RDI];
- out->r8 = regs[REG_R8];
- out->r9 = regs[REG_R9];
- out->r10 = regs[REG_R10];
- out->r11 = regs[REG_R11];
- out->r12 = regs[REG_R12];
- out->r13 = regs[REG_R13];
- out->r14 = regs[REG_R14];
- out->r15 = regs[REG_R15];
-
- out->rip = regs[REG_RIP];
-
- out->flt_save.control_word = fpregs->cwd;
- out->flt_save.status_word = fpregs->swd;
- out->flt_save.tag_word = fpregs->ftw;
- out->flt_save.error_opcode = fpregs->fop;
- out->flt_save.error_offset = fpregs->rip;
- out->flt_save.data_offset = fpregs->rdp;
- out->flt_save.error_selector = 0; // We don't have this.
- out->flt_save.data_selector = 0; // We don't have this.
- out->flt_save.mx_csr = fpregs->mxcsr;
- out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
- my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
- my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
-}
-
-#elif defined(__ARMEL__)
-typedef MDRawContextARM RawContextCPU;
-
-void CPUFillFromThreadInfo(MDRawContextARM* out,
- const google_breakpad::ThreadInfo& info) {
- out->context_flags = MD_CONTEXT_ARM_FULL;
-
- for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
- out->iregs[i] = info.regs.uregs[i];
- // No CPSR register in ThreadInfo(it's not accessible via ptrace)
- out->cpsr = 0;
-#if !defined(__ANDROID__)
- out->float_save.fpscr = info.fpregs.fpsr |
- (static_cast<uint64_t>(info.fpregs.fpcr) << 32);
- // TODO: sort this out, actually collect floating point registers
- my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
- my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
-#endif
-}
-
-void CPUFillFromUContext(MDRawContextARM* out, const ucontext* uc) {
- out->context_flags = MD_CONTEXT_ARM_FULL;
-
- out->iregs[0] = uc->uc_mcontext.arm_r0;
- out->iregs[1] = uc->uc_mcontext.arm_r1;
- out->iregs[2] = uc->uc_mcontext.arm_r2;
- out->iregs[3] = uc->uc_mcontext.arm_r3;
- out->iregs[4] = uc->uc_mcontext.arm_r4;
- out->iregs[5] = uc->uc_mcontext.arm_r5;
- out->iregs[6] = uc->uc_mcontext.arm_r6;
- out->iregs[7] = uc->uc_mcontext.arm_r7;
- out->iregs[8] = uc->uc_mcontext.arm_r8;
- out->iregs[9] = uc->uc_mcontext.arm_r9;
- out->iregs[10] = uc->uc_mcontext.arm_r10;
-
- out->iregs[11] = uc->uc_mcontext.arm_fp;
- out->iregs[12] = uc->uc_mcontext.arm_ip;
- out->iregs[13] = uc->uc_mcontext.arm_sp;
- out->iregs[14] = uc->uc_mcontext.arm_lr;
- out->iregs[15] = uc->uc_mcontext.arm_pc;
-
- out->cpsr = uc->uc_mcontext.arm_cpsr;
-
- // TODO: fix this after fixing ExceptionHandler
- out->float_save.fpscr = 0;
- my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
- my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
-}
-
-#elif defined(__aarch64__)
-typedef MDRawContextARM64 RawContextCPU;
-
-void CPUFillFromThreadInfo(MDRawContextARM64* out,
- const google_breakpad::ThreadInfo& info) {
- out->context_flags = MD_CONTEXT_ARM64_FULL;
-
- out->cpsr = static_cast<uint32_t>(info.regs.pstate);
- for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
- out->iregs[i] = info.regs.regs[i];
- out->iregs[MD_CONTEXT_ARM64_REG_SP] = info.regs.sp;
- out->iregs[MD_CONTEXT_ARM64_REG_PC] = info.regs.pc;
-
- out->float_save.fpsr = info.fpregs.fpsr;
- out->float_save.fpcr = info.fpregs.fpcr;
- my_memcpy(&out->float_save.regs, &info.fpregs.vregs,
- MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
-}
-
-void CPUFillFromUContext(MDRawContextARM64* out, const ucontext* uc,
- const struct fpsimd_context* fpregs) {
- out->context_flags = MD_CONTEXT_ARM64_FULL;
-
- out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
- for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
- out->iregs[i] = uc->uc_mcontext.regs[i];
- out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp;
- out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc;
-
- out->float_save.fpsr = fpregs->fpsr;
- out->float_save.fpcr = fpregs->fpcr;
- my_memcpy(&out->float_save.regs, &fpregs->vregs,
- MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
-}
-
-#elif defined(__mips__)
-typedef MDRawContextMIPS RawContextCPU;
-
-static void CPUFillFromThreadInfo(MDRawContextMIPS* out,
- const google_breakpad::ThreadInfo& info) {
- out->context_flags = MD_CONTEXT_MIPS_FULL;
-
- for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
- out->iregs[i] = info.regs.regs[i];
-
- out->mdhi = info.regs.hi;
- out->mdlo = info.regs.lo;
-
- for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) {
- out->hi[i] = info.hi[i];
- out->lo[i] = info.lo[i];
- }
- out->dsp_control = info.dsp_control;
-
- out->epc = info.regs.epc;
- out->badvaddr = info.regs.badvaddr;
- out->status = info.regs.status;
- out->cause = info.regs.cause;
-
- for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
- out->float_save.regs[i] = info.fpregs.regs[i];
-
- out->float_save.fpcsr = info.fpregs.fpcsr;
- out->float_save.fir = info.fpregs.fir;
-}
-
-static void CPUFillFromUContext(MDRawContextMIPS* out, const ucontext* uc) {
- out->context_flags = MD_CONTEXT_MIPS_FULL;
-
- for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
- out->iregs[i] = uc->uc_mcontext.gregs[i];
-
- out->mdhi = uc->uc_mcontext.mdhi;
- out->mdlo = uc->uc_mcontext.mdlo;
-
- out->hi[0] = uc->uc_mcontext.hi1;
- out->hi[1] = uc->uc_mcontext.hi2;
- out->hi[2] = uc->uc_mcontext.hi3;
- out->lo[0] = uc->uc_mcontext.lo1;
- out->lo[1] = uc->uc_mcontext.lo2;
- out->lo[2] = uc->uc_mcontext.lo3;
- out->dsp_control = uc->uc_mcontext.dsp;
-
- out->epc = uc->uc_mcontext.pc;
- out->badvaddr = 0; // Not reported in signal context.
- out->status = 0; // Not reported in signal context.
- out->cause = 0; // Not reported in signal context.
-
- for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
-#if defined (__ANDROID__)
- out->float_save.regs[i] = uc->uc_mcontext.fpregs[i];
-#else
- out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
-#endif
-
- out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
- out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
-}
-
-#else
-#error "This code has not been ported to your platform yet."
-#endif
class MinidumpWriter {
public:
@@ -629,123 +253,6 @@ class MinidumpWriter {
return true;
}
- // Check if the top of the stack is part of a system call that has been
- // redirected by the seccomp sandbox. If so, try to pop the stack frames
- // all the way back to the point where the interception happened.
- void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread,
- uint8_t* stack_copy) {
-#if defined(__x86_64)
- uint64_t bp = cpu->rbp;
- uint64_t top = thread.stack.start_of_memory_range;
- for (int i = 4; i--; ) {
- if (bp < top ||
- bp + sizeof(bp) > thread.stack.start_of_memory_range +
- thread.stack.memory.data_size ||
- bp & 1) {
- break;
- }
- uint64_t old_top = top;
- top = bp;
- uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
- my_memcpy(&bp, bp_addr, sizeof(bp));
- if (bp == 0xDEADBEEFDEADBEEFull) {
- struct {
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t r11;
- uint64_t r10;
- uint64_t r9;
- uint64_t r8;
- uint64_t rdi;
- uint64_t rsi;
- uint64_t rdx;
- uint64_t rcx;
- uint64_t rbx;
- uint64_t deadbeef;
- uint64_t rbp;
- uint64_t fakeret;
- uint64_t ret;
- /* char redzone[128]; */
- } seccomp_stackframe;
- if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
- top - offsetof(typeof(seccomp_stackframe), deadbeef) +
- sizeof(seccomp_stackframe) >
- thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
- break;
- }
- my_memcpy(&seccomp_stackframe,
- bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
- sizeof(seccomp_stackframe));
- cpu->rbx = seccomp_stackframe.rbx;
- cpu->rcx = seccomp_stackframe.rcx;
- cpu->rdx = seccomp_stackframe.rdx;
- cpu->rsi = seccomp_stackframe.rsi;
- cpu->rdi = seccomp_stackframe.rdi;
- cpu->rbp = seccomp_stackframe.rbp;
- cpu->rsp = top + 4*sizeof(uint64_t) + 128;
- cpu->r8 = seccomp_stackframe.r8;
- cpu->r9 = seccomp_stackframe.r9;
- cpu->r10 = seccomp_stackframe.r10;
- cpu->r11 = seccomp_stackframe.r11;
- cpu->r12 = seccomp_stackframe.r12;
- cpu->r13 = seccomp_stackframe.r13;
- cpu->r14 = seccomp_stackframe.r14;
- cpu->r15 = seccomp_stackframe.r15;
- cpu->rip = seccomp_stackframe.fakeret;
- return;
- }
- }
-#elif defined(__i386__)
- uint32_t bp = cpu->ebp;
- uint32_t top = thread.stack.start_of_memory_range;
- for (int i = 4; i--; ) {
- if (bp < top ||
- bp + sizeof(bp) > thread.stack.start_of_memory_range +
- thread.stack.memory.data_size ||
- bp & 1) {
- break;
- }
- uint32_t old_top = top;
- top = bp;
- uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
- my_memcpy(&bp, bp_addr, sizeof(bp));
- if (bp == 0xDEADBEEFu) {
- struct {
- uint32_t edi;
- uint32_t esi;
- uint32_t edx;
- uint32_t ecx;
- uint32_t ebx;
- uint32_t deadbeef;
- uint32_t ebp;
- uint32_t fakeret;
- uint32_t ret;
- } seccomp_stackframe;
- if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
- top - offsetof(typeof(seccomp_stackframe), deadbeef) +
- sizeof(seccomp_stackframe) >
- thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
- break;
- }
- my_memcpy(&seccomp_stackframe,
- bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
- sizeof(seccomp_stackframe));
- cpu->ebx = seccomp_stackframe.ebx;
- cpu->ecx = seccomp_stackframe.ecx;
- cpu->edx = seccomp_stackframe.edx;
- cpu->esi = seccomp_stackframe.esi;
- cpu->edi = seccomp_stackframe.edi;
- cpu->ebp = seccomp_stackframe.ebp;
- cpu->esp = top + 4*sizeof(void*);
- cpu->eip = seccomp_stackframe.fakeret;
- return;
- }
- }
-#endif
- }
-
bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer,
int max_stack_len, uint8_t** stack_copy) {
*stack_copy = NULL;
@@ -816,12 +323,13 @@ class MinidumpWriter {
ucontext_ &&
!dumper_->IsPostMortem()) {
uint8_t* stack_copy;
- if (!FillThreadStack(&thread, GetStackPointer(), -1, &stack_copy))
+ const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
+ if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy))
return false;
// Copy 256 bytes around crashing instruction pointer to minidump.
const size_t kIPMemorySize = 256;
- uint64_t ip = GetInstructionPointer();
+ uint64_t ip = UContextReader::GetInstructionPointer(ucontext_);
// Bound it to the upper and lower bounds of the memory map
// it's contained within. If it's not in mapped memory,
// don't bother trying to write it.
@@ -867,12 +375,12 @@ class MinidumpWriter {
return false;
my_memset(cpu.get(), 0, sizeof(RawContextCPU));
#if !defined(__ARM_EABI__) && !defined(__mips__)
- CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
+ UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_);
#else
- CPUFillFromUContext(cpu.get(), ucontext_);
+ UContextReader::FillCPUContext(cpu.get(), ucontext_);
#endif
if (stack_copy)
- PopSeccompStackFrame(cpu.get(), thread, stack_copy);
+ SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy);
thread.thread_context = cpu.location();
crashing_thread_context_ = cpu.location();
} else {
@@ -892,9 +400,9 @@ class MinidumpWriter {
if (!cpu.Allocate())
return false;
my_memset(cpu.get(), 0, sizeof(RawContextCPU));
- CPUFillFromThreadInfo(cpu.get(), info);
+ info.FillCPUContext(cpu.get());
if (stack_copy)
- PopSeccompStackFrame(cpu.get(), thread, stack_copy);
+ SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy);
thread.thread_context = cpu.location();
if (dumper_->threads()[i] == GetCrashThread()) {
crashing_thread_context_ = cpu.location();
@@ -902,7 +410,7 @@ class MinidumpWriter {
// This is the crashing thread of a live process, but
// no context was provided, so set the crash address
// while the instruction pointer is already here.
- dumper_->set_crash_address(GetInstructionPointer(info));
+ dumper_->set_crash_address(info.GetInstructionPointer());
}
}
}
@@ -1297,70 +805,6 @@ class MinidumpWriter {
return dumper_->crash_thread();
}
-#if defined(__i386__)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.gregs[REG_ESP];
- }
-
- uintptr_t GetInstructionPointer() {
- return ucontext_->uc_mcontext.gregs[REG_EIP];
- }
-
- uintptr_t GetInstructionPointer(const ThreadInfo& info) {
- return info.regs.eip;
- }
-#elif defined(__x86_64)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.gregs[REG_RSP];
- }
-
- uintptr_t GetInstructionPointer() {
- return ucontext_->uc_mcontext.gregs[REG_RIP];
- }
-
- uintptr_t GetInstructionPointer(const ThreadInfo& info) {
- return info.regs.rip;
- }
-#elif defined(__ARM_EABI__)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.arm_sp;
- }
-
- uintptr_t GetInstructionPointer() {
- return ucontext_->uc_mcontext.arm_pc;
- }
-
- uintptr_t GetInstructionPointer(const ThreadInfo& info) {
- return info.regs.uregs[15];
- }
-#elif defined(__aarch64__)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.sp;
- }
-
- uintptr_t GetInstructionPointer() {
- return ucontext_->uc_mcontext.pc;
- }
-
- uintptr_t GetInstructionPointer(const ThreadInfo& info) {
- return info.regs.pc;
- }
-#elif defined(__mips__)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
- }
-
- uintptr_t GetInstructionPointer() {
- return ucontext_->uc_mcontext.pc;
- }
-
- uintptr_t GetInstructionPointer(const ThreadInfo& info) {
- return info.regs.epc;
- }
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
void NullifyDirectoryEntry(MDRawDirectory* dirent) {
dirent->stream_type = 0;
dirent->location.data_size = 0;