1 // Copyright 2014 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h> // Must come first
31 #endif
32
33 #include "client/linux/dump_writer_common/ucontext_reader.h"
34
35 #include "common/linux/linux_libc_support.h"
36 #include "google_breakpad/common/minidump_format.h"
37
38 namespace google_breakpad {
39
40 // Minidump defines register structures which are different from the raw
41 // structures which we get from the kernel. These are platform specific
42 // functions to juggle the ucontext_t and user structures into minidump format.
43
44 #if defined(__i386__)
45
GetStackPointer(const ucontext_t * uc)46 uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
47 return uc->uc_mcontext.gregs[REG_ESP];
48 }
49
GetInstructionPointer(const ucontext_t * uc)50 uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
51 return uc->uc_mcontext.gregs[REG_EIP];
52 }
53
FillCPUContext(RawContextCPU * out,const ucontext_t * uc,const fpstate_t * fp)54 void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
55 const fpstate_t* fp) {
56 const greg_t* regs = uc->uc_mcontext.gregs;
57
58 out->context_flags = MD_CONTEXT_X86_FULL |
59 MD_CONTEXT_X86_FLOATING_POINT;
60
61 out->gs = regs[REG_GS];
62 out->fs = regs[REG_FS];
63 out->es = regs[REG_ES];
64 out->ds = regs[REG_DS];
65
66 out->edi = regs[REG_EDI];
67 out->esi = regs[REG_ESI];
68 out->ebx = regs[REG_EBX];
69 out->edx = regs[REG_EDX];
70 out->ecx = regs[REG_ECX];
71 out->eax = regs[REG_EAX];
72
73 out->ebp = regs[REG_EBP];
74 out->eip = regs[REG_EIP];
75 out->cs = regs[REG_CS];
76 out->eflags = regs[REG_EFL];
77 out->esp = regs[REG_UESP];
78 out->ss = regs[REG_SS];
79
80 out->float_save.control_word = fp->cw;
81 out->float_save.status_word = fp->sw;
82 out->float_save.tag_word = fp->tag;
83 out->float_save.error_offset = fp->ipoff;
84 out->float_save.error_selector = fp->cssel;
85 out->float_save.data_offset = fp->dataoff;
86 out->float_save.data_selector = fp->datasel;
87
88 // 8 registers * 10 bytes per register.
89 my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
90 }
91
92 #elif defined(__x86_64)
93
94 uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
95 return uc->uc_mcontext.gregs[REG_RSP];
96 }
97
98 uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
99 return uc->uc_mcontext.gregs[REG_RIP];
100 }
101
102 void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
103 const fpstate_t* fpregs) {
104 const greg_t* regs = uc->uc_mcontext.gregs;
105
106 out->context_flags = MD_CONTEXT_AMD64_FULL;
107
108 out->cs = regs[REG_CSGSFS] & 0xffff;
109
110 out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
111 out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
112
113 out->eflags = regs[REG_EFL];
114
115 out->rax = regs[REG_RAX];
116 out->rcx = regs[REG_RCX];
117 out->rdx = regs[REG_RDX];
118 out->rbx = regs[REG_RBX];
119
120 out->rsp = regs[REG_RSP];
121 out->rbp = regs[REG_RBP];
122 out->rsi = regs[REG_RSI];
123 out->rdi = regs[REG_RDI];
124 out->r8 = regs[REG_R8];
125 out->r9 = regs[REG_R9];
126 out->r10 = regs[REG_R10];
127 out->r11 = regs[REG_R11];
128 out->r12 = regs[REG_R12];
129 out->r13 = regs[REG_R13];
130 out->r14 = regs[REG_R14];
131 out->r15 = regs[REG_R15];
132
133 out->rip = regs[REG_RIP];
134
135 out->flt_save.control_word = fpregs->cwd;
136 out->flt_save.status_word = fpregs->swd;
137 out->flt_save.tag_word = fpregs->ftw;
138 out->flt_save.error_opcode = fpregs->fop;
139 out->flt_save.error_offset = fpregs->rip;
140 out->flt_save.data_offset = fpregs->rdp;
141 out->flt_save.error_selector = 0; // We don't have this.
142 out->flt_save.data_selector = 0; // We don't have this.
143 out->flt_save.mx_csr = fpregs->mxcsr;
144 out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
145 my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
146 my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
147 }
148
149 #elif defined(__ARM_EABI__)
150
151 uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
152 return uc->uc_mcontext.arm_sp;
153 }
154
155 uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
156 return uc->uc_mcontext.arm_pc;
157 }
158
159 void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
160 out->context_flags = MD_CONTEXT_ARM_FULL;
161
162 out->iregs[0] = uc->uc_mcontext.arm_r0;
163 out->iregs[1] = uc->uc_mcontext.arm_r1;
164 out->iregs[2] = uc->uc_mcontext.arm_r2;
165 out->iregs[3] = uc->uc_mcontext.arm_r3;
166 out->iregs[4] = uc->uc_mcontext.arm_r4;
167 out->iregs[5] = uc->uc_mcontext.arm_r5;
168 out->iregs[6] = uc->uc_mcontext.arm_r6;
169 out->iregs[7] = uc->uc_mcontext.arm_r7;
170 out->iregs[8] = uc->uc_mcontext.arm_r8;
171 out->iregs[9] = uc->uc_mcontext.arm_r9;
172 out->iregs[10] = uc->uc_mcontext.arm_r10;
173
174 out->iregs[11] = uc->uc_mcontext.arm_fp;
175 out->iregs[12] = uc->uc_mcontext.arm_ip;
176 out->iregs[13] = uc->uc_mcontext.arm_sp;
177 out->iregs[14] = uc->uc_mcontext.arm_lr;
178 out->iregs[15] = uc->uc_mcontext.arm_pc;
179
180 out->cpsr = uc->uc_mcontext.arm_cpsr;
181
182 // TODO: fix this after fixing ExceptionHandler
183 out->float_save.fpscr = 0;
184 my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
185 my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
186 }
187
188 #elif defined(__aarch64__)
189
190 uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
191 return uc->uc_mcontext.sp;
192 }
193
194 uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
195 return uc->uc_mcontext.pc;
196 }
197
198 void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
199 const struct fpsimd_context* fpregs) {
200 out->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
201
202 out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
203 for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
204 out->iregs[i] = uc->uc_mcontext.regs[i];
205 out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp;
206 out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc;
207
208 out->float_save.fpsr = fpregs->fpsr;
209 out->float_save.fpcr = fpregs->fpcr;
210 my_memcpy(&out->float_save.regs, &fpregs->vregs,
211 MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
212 }
213
214 #elif defined(__mips__)
215
216 uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
217 return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
218 }
219
220 uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
221 return uc->uc_mcontext.pc;
222 }
223
224 void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
225 #if _MIPS_SIM == _ABI64
226 out->context_flags = MD_CONTEXT_MIPS64_FULL;
227 #elif _MIPS_SIM == _ABIO32
228 out->context_flags = MD_CONTEXT_MIPS_FULL;
229 #else
230 #error "This mips ABI is currently not supported (n32)"
231 #endif
232
233 for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
234 out->iregs[i] = uc->uc_mcontext.gregs[i];
235
236 out->mdhi = uc->uc_mcontext.mdhi;
237 out->mdlo = uc->uc_mcontext.mdlo;
238
239 out->hi[0] = uc->uc_mcontext.hi1;
240 out->hi[1] = uc->uc_mcontext.hi2;
241 out->hi[2] = uc->uc_mcontext.hi3;
242 out->lo[0] = uc->uc_mcontext.lo1;
243 out->lo[1] = uc->uc_mcontext.lo2;
244 out->lo[2] = uc->uc_mcontext.lo3;
245 out->dsp_control = uc->uc_mcontext.dsp;
246
247 out->epc = uc->uc_mcontext.pc;
248 out->badvaddr = 0; // Not reported in signal context.
249 out->status = 0; // Not reported in signal context.
250 out->cause = 0; // Not reported in signal context.
251
252 for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
253 out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
254
255 out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
256 #if _MIPS_SIM == _ABIO32
257 out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
258 #endif
259 }
260
261 #elif defined(__riscv)
262
263 uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
264 return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP];
265 }
266
267 uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
268 return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_PC];
269 }
270
271 void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
272 # if __riscv__xlen == 32
273 out->context_flags = MD_CONTEXT_RISCV_FULL;
274 # elif __riscv_xlen == 64
275 out->context_flags = MD_CONTEXT_RISCV64_FULL;
276 # else
277 # error "Unexpected __riscv_xlen"
278 # endif
279
280 out->pc = uc->uc_mcontext.__gregs[0];
281 out->ra = uc->uc_mcontext.__gregs[1];
282 out->sp = uc->uc_mcontext.__gregs[2];
283 out->gp = uc->uc_mcontext.__gregs[3];
284 out->tp = uc->uc_mcontext.__gregs[4];
285 out->t0 = uc->uc_mcontext.__gregs[5];
286 out->t1 = uc->uc_mcontext.__gregs[6];
287 out->t2 = uc->uc_mcontext.__gregs[7];
288 out->s0 = uc->uc_mcontext.__gregs[8];
289 out->s1 = uc->uc_mcontext.__gregs[9];
290 out->a0 = uc->uc_mcontext.__gregs[10];
291 out->a1 = uc->uc_mcontext.__gregs[11];
292 out->a2 = uc->uc_mcontext.__gregs[12];
293 out->a3 = uc->uc_mcontext.__gregs[13];
294 out->a4 = uc->uc_mcontext.__gregs[14];
295 out->a5 = uc->uc_mcontext.__gregs[15];
296 out->a6 = uc->uc_mcontext.__gregs[16];
297 out->a7 = uc->uc_mcontext.__gregs[17];
298 out->s2 = uc->uc_mcontext.__gregs[18];
299 out->s3 = uc->uc_mcontext.__gregs[19];
300 out->s4 = uc->uc_mcontext.__gregs[20];
301 out->s5 = uc->uc_mcontext.__gregs[21];
302 out->s6 = uc->uc_mcontext.__gregs[22];
303 out->s7 = uc->uc_mcontext.__gregs[23];
304 out->s8 = uc->uc_mcontext.__gregs[24];
305 out->s9 = uc->uc_mcontext.__gregs[25];
306 out->s10 = uc->uc_mcontext.__gregs[26];
307 out->s11 = uc->uc_mcontext.__gregs[27];
308 out->t3 = uc->uc_mcontext.__gregs[28];
309 out->t4 = uc->uc_mcontext.__gregs[29];
310 out->t5 = uc->uc_mcontext.__gregs[30];
311 out->t6 = uc->uc_mcontext.__gregs[31];
312
313 // Breakpad only supports RISCV32 with 32 bit floating point.
314 // Breakpad only supports RISCV64 with 64 bit floating point.
315 #if __riscv_xlen == 32
316 for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
317 out->fpregs[i] = uc->uc_mcontext.__fpregs.__f.__f[i];
318 out->fcsr = uc->uc_mcontext.__fpregs.__f.__fcsr;
319 #elif __riscv_xlen == 64
320 for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
321 out->fpregs[i] = uc->uc_mcontext.__fpregs.__d.__f[i];
322 out->fcsr = uc->uc_mcontext.__fpregs.__d.__fcsr;
323 #else
324 #error "Unexpected __riscv_xlen"
325 #endif
326 }
327 #endif
328
329 } // namespace google_breakpad
330