// 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; #if _MIPS_SIM == _ABIO32 out->float_save.fir = fpregs.fir; #endif } #endif } // namespace google_breakpad