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.
U16(void * out,uint16_t v)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.
U32(void * out,uint32_t v)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
GetInstructionPointer() const61 uintptr_t ThreadInfo::GetInstructionPointer() const {
62 return regs.eip;
63 }
64
FillCPUContext(RawContextCPU * out) const65 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