Home | History | Annotate | Download | only in dump_writer_common
      1 // Copyright (c) 2014, 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 #include "client/linux/dump_writer_common/thread_info.h"
     31 
     32 #include <string.h>
     33 
     34 #include "common/linux/linux_libc_support.h"
     35 #include "google_breakpad/common/minidump_format.h"
     36 
     37 namespace {
     38 
     39 #if defined(__i386__)
     40 // Write a uint16_t to memory
     41 //   out: memory location to write to
     42 //   v: value to write.
     43 void U16(void* out, uint16_t v) {
     44   my_memcpy(out, &v, sizeof(v));
     45 }
     46 
     47 // Write a uint32_t to memory
     48 //   out: memory location to write to
     49 //   v: value to write.
     50 void U32(void* out, uint32_t v) {
     51   my_memcpy(out, &v, sizeof(v));
     52 }
     53 #endif
     54 
     55 }
     56 
     57 namespace google_breakpad {
     58 
     59 #if defined(__i386__)
     60 
     61 uintptr_t ThreadInfo::GetInstructionPointer() const {
     62   return regs.eip;
     63 }
     64 
     65 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
     66   out->context_flags = MD_CONTEXT_X86_ALL;
     67 
     68   out->dr0 = dregs[0];
     69   out->dr1 = dregs[1];
     70   out->dr2 = dregs[2];
     71   out->dr3 = dregs[3];
     72   // 4 and 5 deliberatly omitted because they aren't included in the minidump
     73   // format.
     74   out->dr6 = dregs[6];
     75   out->dr7 = dregs[7];
     76 
     77   out->gs = regs.xgs;
     78   out->fs = regs.xfs;
     79   out->es = regs.xes;
     80   out->ds = regs.xds;
     81 
     82   out->edi = regs.edi;
     83   out->esi = regs.esi;
     84   out->ebx = regs.ebx;
     85   out->edx = regs.edx;
     86   out->ecx = regs.ecx;
     87   out->eax = regs.eax;
     88 
     89   out->ebp = regs.ebp;
     90   out->eip = regs.eip;
     91   out->cs = regs.xcs;
     92   out->eflags = regs.eflags;
     93   out->esp = regs.esp;
     94   out->ss = regs.xss;
     95 
     96   out->float_save.control_word = fpregs.cwd;
     97   out->float_save.status_word = fpregs.swd;
     98   out->float_save.tag_word = fpregs.twd;
     99   out->float_save.error_offset = fpregs.fip;
    100   out->float_save.error_selector = fpregs.fcs;
    101   out->float_save.data_offset = fpregs.foo;
    102   out->float_save.data_selector = fpregs.fos;
    103 
    104   // 8 registers * 10 bytes per register.
    105   my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8);
    106 
    107   // This matches the Intel fpsave format.
    108   U16(out->extended_registers + 0, fpregs.cwd);
    109   U16(out->extended_registers + 2, fpregs.swd);
    110   U16(out->extended_registers + 4, fpregs.twd);
    111   U16(out->extended_registers + 6, fpxregs.fop);
    112   U32(out->extended_registers + 8, fpxregs.fip);
    113   U16(out->extended_registers + 12, fpxregs.fcs);
    114   U32(out->extended_registers + 16, fpregs.foo);
    115   U16(out->extended_registers + 20, fpregs.fos);
    116   U32(out->extended_registers + 24, fpxregs.mxcsr);
    117 
    118   my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128);
    119   my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128);
    120 }
    121 
    122 #elif defined(__x86_64)
    123 
    124 uintptr_t ThreadInfo::GetInstructionPointer() const {
    125   return regs.rip;
    126 }
    127 
    128 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
    129   out->context_flags = MD_CONTEXT_AMD64_FULL |
    130                        MD_CONTEXT_AMD64_SEGMENTS;
    131 
    132   out->cs = regs.cs;
    133 
    134   out->ds = regs.ds;
    135   out->es = regs.es;
    136   out->fs = regs.fs;
    137   out->gs = regs.gs;
    138 
    139   out->ss = regs.ss;
    140   out->eflags = regs.eflags;
    141 
    142   out->dr0 = dregs[0];
    143   out->dr1 = dregs[1];
    144   out->dr2 = dregs[2];
    145   out->dr3 = dregs[3];
    146   // 4 and 5 deliberatly omitted because they aren't included in the minidump
    147   // format.
    148   out->dr6 = dregs[6];
    149   out->dr7 = dregs[7];
    150 
    151   out->rax = regs.rax;
    152   out->rcx = regs.rcx;
    153   out->rdx = regs.rdx;
    154   out->rbx = regs.rbx;
    155 
    156   out->rsp = regs.rsp;
    157 
    158   out->rbp = regs.rbp;
    159   out->rsi = regs.rsi;
    160   out->rdi = regs.rdi;
    161   out->r8 = regs.r8;
    162   out->r9 = regs.r9;
    163   out->r10 = regs.r10;
    164   out->r11 = regs.r11;
    165   out->r12 = regs.r12;
    166   out->r13 = regs.r13;
    167   out->r14 = regs.r14;
    168   out->r15 = regs.r15;
    169 
    170   out->rip = regs.rip;
    171 
    172   out->flt_save.control_word = fpregs.cwd;
    173   out->flt_save.status_word = fpregs.swd;
    174   out->flt_save.tag_word = fpregs.ftw;
    175   out->flt_save.error_opcode = fpregs.fop;
    176   out->flt_save.error_offset = fpregs.rip;
    177   out->flt_save.error_selector = 0;  // We don't have this.
    178   out->flt_save.data_offset = fpregs.rdp;
    179   out->flt_save.data_selector = 0;   // We don't have this.
    180   out->flt_save.mx_csr = fpregs.mxcsr;
    181   out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
    182 
    183   my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
    184   my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
    185 }
    186 
    187 #elif defined(__ARM_EABI__)
    188 
    189 uintptr_t ThreadInfo::GetInstructionPointer() const {
    190   return regs.uregs[15];
    191 }
    192 
    193 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
    194   out->context_flags = MD_CONTEXT_ARM_FULL;
    195 
    196   for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
    197     out->iregs[i] = regs.uregs[i];
    198   // No CPSR register in ThreadInfo(it's not accessible via ptrace)
    199   out->cpsr = 0;
    200 #if !defined(__ANDROID__)
    201   out->float_save.fpscr = fpregs.fpsr |
    202     (static_cast<uint64_t>(fpregs.fpcr) << 32);
    203   // TODO: sort this out, actually collect floating point registers
    204   my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
    205   my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
    206 #endif
    207 }
    208 
    209 #elif defined(__aarch64__)
    210 
    211 uintptr_t ThreadInfo::GetInstructionPointer() const {
    212   return regs.pc;
    213 }
    214 
    215 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
    216   out->context_flags = MD_CONTEXT_ARM64_FULL;
    217 
    218   out->cpsr = static_cast<uint32_t>(regs.pstate);
    219   for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
    220     out->iregs[i] = regs.regs[i];
    221   out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp;
    222   out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc;
    223 
    224   out->float_save.fpsr = fpregs.fpsr;
    225   out->float_save.fpcr = fpregs.fpcr;
    226   my_memcpy(&out->float_save.regs, &fpregs.vregs,
    227       MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
    228 }
    229 
    230 #elif defined(__mips__)
    231 
    232 uintptr_t ThreadInfo::GetInstructionPointer() const {
    233   return regs.epc;
    234 }
    235 
    236 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
    237   out->context_flags = MD_CONTEXT_MIPS_FULL;
    238 
    239   for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
    240     out->iregs[i] = regs.regs[i];
    241 
    242   out->mdhi = regs.hi;
    243   out->mdlo = regs.lo;
    244 
    245   for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) {
    246     out->hi[i] = hi[i];
    247     out->lo[i] = lo[i];
    248   }
    249   out->dsp_control = dsp_control;
    250 
    251   out->epc = regs.epc;
    252   out->badvaddr = regs.badvaddr;
    253   out->status = regs.status;
    254   out->cause = regs.cause;
    255 
    256   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
    257     out->float_save.regs[i] = fpregs.regs[i];
    258 
    259   out->float_save.fpcsr = fpregs.fpcsr;
    260 #if _MIPS_SIM == _ABIO32
    261   out->float_save.fir = fpregs.fir;
    262 #endif
    263 }
    264 #endif
    265 
    266 }  // namespace google_breakpad
    267