Line data Source code
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 "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 0 : uintptr_t ThreadInfo::GetInstructionPointer() const {
126 0 : return regs.rip;
127 : }
128 :
129 0 : void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
130 0 : out->context_flags = MD_CONTEXT_AMD64_FULL |
131 : MD_CONTEXT_AMD64_SEGMENTS;
132 :
133 0 : out->cs = regs.cs;
134 :
135 0 : out->ds = regs.ds;
136 0 : out->es = regs.es;
137 0 : out->fs = regs.fs;
138 0 : out->gs = regs.gs;
139 :
140 0 : out->ss = regs.ss;
141 0 : out->eflags = regs.eflags;
142 :
143 0 : out->dr0 = dregs[0];
144 0 : out->dr1 = dregs[1];
145 0 : out->dr2 = dregs[2];
146 0 : out->dr3 = dregs[3];
147 : // 4 and 5 deliberatly omitted because they aren't included in the minidump
148 : // format.
149 0 : out->dr6 = dregs[6];
150 0 : out->dr7 = dregs[7];
151 :
152 0 : out->rax = regs.rax;
153 0 : out->rcx = regs.rcx;
154 0 : out->rdx = regs.rdx;
155 0 : out->rbx = regs.rbx;
156 :
157 0 : out->rsp = regs.rsp;
158 :
159 0 : out->rbp = regs.rbp;
160 0 : out->rsi = regs.rsi;
161 0 : out->rdi = regs.rdi;
162 0 : out->r8 = regs.r8;
163 0 : out->r9 = regs.r9;
164 0 : out->r10 = regs.r10;
165 0 : out->r11 = regs.r11;
166 0 : out->r12 = regs.r12;
167 0 : out->r13 = regs.r13;
168 0 : out->r14 = regs.r14;
169 0 : out->r15 = regs.r15;
170 :
171 0 : out->rip = regs.rip;
172 :
173 0 : out->flt_save.control_word = fpregs.cwd;
174 0 : out->flt_save.status_word = fpregs.swd;
175 0 : out->flt_save.tag_word = fpregs.ftw;
176 0 : out->flt_save.error_opcode = fpregs.fop;
177 0 : out->flt_save.error_offset = fpregs.rip;
178 0 : out->flt_save.error_selector = 0; // We don't have this.
179 0 : out->flt_save.data_offset = fpregs.rdp;
180 0 : out->flt_save.data_selector = 0; // We don't have this.
181 0 : out->flt_save.mx_csr = fpregs.mxcsr;
182 0 : out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
183 :
184 0 : my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
185 0 : my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
186 0 : }
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;
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 0 : void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
276 0 : 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 0 : if (gp_regs)
284 0 : *gp_regs = ®s;
285 0 : if (size)
286 0 : *size = sizeof(regs);
287 : #endif
288 0 : }
289 :
290 0 : void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
291 0 : 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 0 : if (fp_regs)
299 0 : *fp_regs = &fpregs;
300 0 : if (size)
301 0 : *size = sizeof(fpregs);
302 : #endif
303 0 : }
304 :
305 : } // namespace google_breakpad
|