306 lines
8.6 KiB
C++
306 lines
8.6 KiB
C++
// 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 <assert.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 mcontext.pc;
|
|
}
|
|
|
|
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
|
#if _MIPS_SIM == _ABI64
|
|
out->context_flags = MD_CONTEXT_MIPS64_FULL;
|
|
#elif _MIPS_SIM == _ABIO32
|
|
out->context_flags = MD_CONTEXT_MIPS_FULL;
|
|
#else
|
|
# error "This mips ABI is currently not supported (n32)"
|
|
#endif
|
|
|
|
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
|
|
out->iregs[i] = mcontext.gregs[i];
|
|
|
|
out->mdhi = mcontext.mdhi;
|
|
out->mdlo = mcontext.mdlo;
|
|
out->dsp_control = mcontext.dsp;
|
|
|
|
out->hi[0] = mcontext.hi1;
|
|
out->lo[0] = mcontext.lo1;
|
|
out->hi[1] = mcontext.hi2;
|
|
out->lo[1] = mcontext.lo2;
|
|
out->hi[2] = mcontext.hi3;
|
|
out->lo[2] = mcontext.lo3;
|
|
|
|
out->epc = mcontext.pc;
|
|
out->badvaddr = 0; // Not stored in mcontext
|
|
out->status = 0; // Not stored in mcontext
|
|
out->cause = 0; // Not stored in mcontext
|
|
|
|
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
|
|
out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs;
|
|
|
|
out->float_save.fpcsr = mcontext.fpc_csr;
|
|
#if _MIPS_SIM == _ABIO32
|
|
out->float_save.fir = mcontext.fpc_eir;
|
|
#endif
|
|
}
|
|
#endif // __mips__
|
|
|
|
void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
|
|
assert(gp_regs || size);
|
|
#if defined(__mips__)
|
|
if (gp_regs)
|
|
*gp_regs = mcontext.gregs;
|
|
if (size)
|
|
*size = sizeof(mcontext.gregs);
|
|
#else
|
|
if (gp_regs)
|
|
*gp_regs = ®s;
|
|
if (size)
|
|
*size = sizeof(regs);
|
|
#endif
|
|
}
|
|
|
|
void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
|
|
assert(fp_regs || size);
|
|
#if defined(__mips__)
|
|
if (fp_regs)
|
|
*fp_regs = &mcontext.fpregs;
|
|
if (size)
|
|
*size = sizeof(mcontext.fpregs);
|
|
#else
|
|
if (fp_regs)
|
|
*fp_regs = &fpregs;
|
|
if (size)
|
|
*size = sizeof(fpregs);
|
|
#endif
|
|
}
|
|
|
|
} // namespace google_breakpad
|