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
37namespace {
38
39#if defined(__i386__)
40// Write a uint16_t to memory
41//   out: memory location to write to
42//   v: value to write.
43void 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.
50void U32(void* out, uint32_t v) {
51  my_memcpy(out, &v, sizeof(v));
52}
53#endif
54
55}
56
57namespace google_breakpad {
58
59#if defined(__i386__)
60
61uintptr_t ThreadInfo::GetInstructionPointer() const {
62  return regs.eip;
63}
64
65void 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
124uintptr_t ThreadInfo::GetInstructionPointer() const {
125  return regs.rip;
126}
127
128void 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
189uintptr_t ThreadInfo::GetInstructionPointer() const {
190  return regs.uregs[15];
191}
192
193void 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
211uintptr_t ThreadInfo::GetInstructionPointer() const {
212  return regs.pc;
213}
214
215void 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
232uintptr_t ThreadInfo::GetInstructionPointer() const {
233  return regs.epc;
234}
235
236void 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  out->float_save.fir = fpregs.fir;
261}
262#endif
263
264}  // namespace google_breakpad
265