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