• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
U16(void * out,uint16_t v)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.
U32(void * out,uint32_t v)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 
GetInstructionPointer() const62 uintptr_t ThreadInfo::GetInstructionPointer() const {
63   return regs.eip;
64 }
65 
FillCPUContext(RawContextCPU * out) const66 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 
GetGeneralPurposeRegisters(void ** gp_regs,size_t * size)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 = &regs;
285   if (size)
286     *size = sizeof(regs);
287 #endif
288 }
289 
GetFloatingPointRegisters(void ** fp_regs,size_t * size)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