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 | |
35 | namespace 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 | |
43 | uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
44 | return uc->uc_mcontext.gregs[REG_ESP]; |
45 | } |
46 | |
47 | uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
48 | return uc->uc_mcontext.gregs[REG_EIP]; |
49 | } |
50 | |
51 | void 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 | |
91 | uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
92 | return uc->uc_mcontext.gregs[REG_RSP]; |
93 | } |
94 | |
95 | uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
96 | return uc->uc_mcontext.gregs[REG_RIP]; |
97 | } |
98 | |
99 | void 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 | |
148 | uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
149 | return uc->uc_mcontext.arm_sp; |
150 | } |
151 | |
152 | uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
153 | return uc->uc_mcontext.arm_pc; |
154 | } |
155 | |
156 | void 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 | |
187 | uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
188 | return uc->uc_mcontext.sp; |
189 | } |
190 | |
191 | uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
192 | return uc->uc_mcontext.pc; |
193 | } |
194 | |
195 | void 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 | |
213 | uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
214 | return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; |
215 | } |
216 | |
217 | uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
218 | return uc->uc_mcontext.pc; |
219 | } |
220 | |
221 | void 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 | |