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