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 | |
38 | namespace { |
39 | |
40 | #if defined(__i386__) |
41 | // Write a uint16_t to memory |
42 | // out: memory location to write to |
43 | // v: value to write. |
44 | void 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. |
51 | void U32(void* out, uint32_t v) { |
52 | my_memcpy(out, &v, sizeof(v)); |
53 | } |
54 | #endif |
55 | |
56 | } |
57 | |
58 | namespace google_breakpad { |
59 | |
60 | #if defined(__i386__) |
61 | |
62 | uintptr_t ThreadInfo::GetInstructionPointer() const { |
63 | return regs.eip; |
64 | } |
65 | |
66 | void 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 | |
125 | uintptr_t ThreadInfo::GetInstructionPointer() const { |
126 | return regs.rip; |
127 | } |
128 | |
129 | void 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 | |
190 | uintptr_t ThreadInfo::GetInstructionPointer() const { |
191 | return regs.uregs[15]; |
192 | } |
193 | |
194 | void 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 | |
212 | uintptr_t ThreadInfo::GetInstructionPointer() const { |
213 | return regs.pc; |
214 | } |
215 | |
216 | void 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 | |
233 | uintptr_t ThreadInfo::GetInstructionPointer() const { |
234 | return mcontext.pc; |
235 | } |
236 | |
237 | void 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 | |
275 | void 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 = ®s; |
285 | if (size) |
286 | *size = sizeof(regs); |
287 | #endif |
288 | } |
289 | |
290 | void 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 | |