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/ucontext_reader.h"
31
32#include "common/linux/linux_libc_support.h"
33#include "google_breakpad/common/minidump_format.h"
34
35namespace google_breakpad {
36
37// Minidump defines register structures which are different from the raw
38// structures which we get from the kernel. These are platform specific
39// functions to juggle the ucontext_t and user structures into minidump format.
40
41#if defined(__i386__)
42
43uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
44 return uc->uc_mcontext.gregs[REG_ESP];
45}
46
47uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
48 return uc->uc_mcontext.gregs[REG_EIP];
49}
50
51void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
52 const fpstate_t* fp) {
53 const greg_t* regs = uc->uc_mcontext.gregs;
54
55 out->context_flags = MD_CONTEXT_X86_FULL |
56 MD_CONTEXT_X86_FLOATING_POINT;
57
58 out->gs = regs[REG_GS];
59 out->fs = regs[REG_FS];
60 out->es = regs[REG_ES];
61 out->ds = regs[REG_DS];
62
63 out->edi = regs[REG_EDI];
64 out->esi = regs[REG_ESI];
65 out->ebx = regs[REG_EBX];
66 out->edx = regs[REG_EDX];
67 out->ecx = regs[REG_ECX];
68 out->eax = regs[REG_EAX];
69
70 out->ebp = regs[REG_EBP];
71 out->eip = regs[REG_EIP];
72 out->cs = regs[REG_CS];
73 out->eflags = regs[REG_EFL];
74 out->esp = regs[REG_UESP];
75 out->ss = regs[REG_SS];
76
77 out->float_save.control_word = fp->cw;
78 out->float_save.status_word = fp->sw;
79 out->float_save.tag_word = fp->tag;
80 out->float_save.error_offset = fp->ipoff;
81 out->float_save.error_selector = fp->cssel;
82 out->float_save.data_offset = fp->dataoff;
83 out->float_save.data_selector = fp->datasel;
84
85 // 8 registers * 10 bytes per register.
86 my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
87}
88
89#elif defined(__x86_64)
90
91uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
92 return uc->uc_mcontext.gregs[REG_RSP];
93}
94
95uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
96 return uc->uc_mcontext.gregs[REG_RIP];
97}
98
99void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
100 const fpstate_t* fpregs) {
101 const greg_t* regs = uc->uc_mcontext.gregs;
102
103 out->context_flags = MD_CONTEXT_AMD64_FULL;
104
105 out->cs = regs[REG_CSGSFS] & 0xffff;
106
107 out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
108 out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
109
110 out->eflags = regs[REG_EFL];
111
112 out->rax = regs[REG_RAX];
113 out->rcx = regs[REG_RCX];
114 out->rdx = regs[REG_RDX];
115 out->rbx = regs[REG_RBX];
116
117 out->rsp = regs[REG_RSP];
118 out->rbp = regs[REG_RBP];
119 out->rsi = regs[REG_RSI];
120 out->rdi = regs[REG_RDI];
121 out->r8 = regs[REG_R8];
122 out->r9 = regs[REG_R9];
123 out->r10 = regs[REG_R10];
124 out->r11 = regs[REG_R11];
125 out->r12 = regs[REG_R12];
126 out->r13 = regs[REG_R13];
127 out->r14 = regs[REG_R14];
128 out->r15 = regs[REG_R15];
129
130 out->rip = regs[REG_RIP];
131
132 out->flt_save.control_word = fpregs->cwd;
133 out->flt_save.status_word = fpregs->swd;
134 out->flt_save.tag_word = fpregs->ftw;
135 out->flt_save.error_opcode = fpregs->fop;
136 out->flt_save.error_offset = fpregs->rip;
137 out->flt_save.data_offset = fpregs->rdp;
138 out->flt_save.error_selector = 0; // We don't have this.
139 out->flt_save.data_selector = 0; // We don't have this.
140 out->flt_save.mx_csr = fpregs->mxcsr;
141 out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
142 my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
143 my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
144}
145
146#elif defined(__ARM_EABI__)
147
148uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
149 return uc->uc_mcontext.arm_sp;
150}
151
152uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
153 return uc->uc_mcontext.arm_pc;
154}
155
156void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
157 out->context_flags = MD_CONTEXT_ARM_FULL;
158
159 out->iregs[0] = uc->uc_mcontext.arm_r0;
160 out->iregs[1] = uc->uc_mcontext.arm_r1;
161 out->iregs[2] = uc->uc_mcontext.arm_r2;
162 out->iregs[3] = uc->uc_mcontext.arm_r3;
163 out->iregs[4] = uc->uc_mcontext.arm_r4;
164 out->iregs[5] = uc->uc_mcontext.arm_r5;
165 out->iregs[6] = uc->uc_mcontext.arm_r6;
166 out->iregs[7] = uc->uc_mcontext.arm_r7;
167 out->iregs[8] = uc->uc_mcontext.arm_r8;
168 out->iregs[9] = uc->uc_mcontext.arm_r9;
169 out->iregs[10] = uc->uc_mcontext.arm_r10;
170
171 out->iregs[11] = uc->uc_mcontext.arm_fp;
172 out->iregs[12] = uc->uc_mcontext.arm_ip;
173 out->iregs[13] = uc->uc_mcontext.arm_sp;
174 out->iregs[14] = uc->uc_mcontext.arm_lr;
175 out->iregs[15] = uc->uc_mcontext.arm_pc;
176
177 out->cpsr = uc->uc_mcontext.arm_cpsr;
178
179 // TODO: fix this after fixing ExceptionHandler
180 out->float_save.fpscr = 0;
181 my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
182 my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
183}
184
185#elif defined(__aarch64__)
186
187uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
188 return uc->uc_mcontext.sp;
189}
190
191uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
192 return uc->uc_mcontext.pc;
193}
194
195void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
196 const struct fpsimd_context* fpregs) {
197 out->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
198
199 out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
200 for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
201 out->iregs[i] = uc->uc_mcontext.regs[i];
202 out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp;
203 out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc;
204
205 out->float_save.fpsr = fpregs->fpsr;
206 out->float_save.fpcr = fpregs->fpcr;
207 my_memcpy(&out->float_save.regs, &fpregs->vregs,
208 MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
209}
210
211#elif defined(__mips__)
212
213uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
214 return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
215}
216
217uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
218 return uc->uc_mcontext.pc;
219}
220
221void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
222#if _MIPS_SIM == _ABI64
223 out->context_flags = MD_CONTEXT_MIPS64_FULL;
224#elif _MIPS_SIM == _ABIO32
225 out->context_flags = MD_CONTEXT_MIPS_FULL;
226#else
227#error "This mips ABI is currently not supported (n32)"
228#endif
229
230 for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
231 out->iregs[i] = uc->uc_mcontext.gregs[i];
232
233 out->mdhi = uc->uc_mcontext.mdhi;
234 out->mdlo = uc->uc_mcontext.mdlo;
235
236 out->hi[0] = uc->uc_mcontext.hi1;
237 out->hi[1] = uc->uc_mcontext.hi2;
238 out->hi[2] = uc->uc_mcontext.hi3;
239 out->lo[0] = uc->uc_mcontext.lo1;
240 out->lo[1] = uc->uc_mcontext.lo2;
241 out->lo[2] = uc->uc_mcontext.lo3;
242 out->dsp_control = uc->uc_mcontext.dsp;
243
244 out->epc = uc->uc_mcontext.pc;
245 out->badvaddr = 0; // Not reported in signal context.
246 out->status = 0; // Not reported in signal context.
247 out->cause = 0; // Not reported in signal context.
248
249 for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
250 out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
251
252 out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
253#if _MIPS_SIM == _ABIO32
254 out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
255#endif
256}
257#endif
258
259} // namespace google_breakpad
260