xref: /aosp_15_r20/external/google-breakpad/src/client/linux/dump_writer_common/thread_info.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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/thread_info.h"
34 
35 #include <string.h>
36 #include <assert.h>
37 
38 #include "common/linux/linux_libc_support.h"
39 #include "google_breakpad/common/minidump_format.h"
40 
41 namespace {
42 
43 #if defined(__i386__)
44 // Write a uint16_t to memory
45 //   out: memory location to write to
46 //   v: value to write.
U16(void * out,uint16_t v)47 void U16(void* out, uint16_t v) {
48   my_memcpy(out, &v, sizeof(v));
49 }
50 
51 // Write a uint32_t to memory
52 //   out: memory location to write to
53 //   v: value to write.
U32(void * out,uint32_t v)54 void U32(void* out, uint32_t v) {
55   my_memcpy(out, &v, sizeof(v));
56 }
57 #endif
58 
59 }
60 
61 namespace google_breakpad {
62 
63 #if defined(__i386__)
64 
GetInstructionPointer() const65 uintptr_t ThreadInfo::GetInstructionPointer() const {
66   return regs.eip;
67 }
68 
FillCPUContext(RawContextCPU * out) const69 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
70   out->context_flags = MD_CONTEXT_X86_ALL;
71 
72   out->dr0 = dregs[0];
73   out->dr1 = dregs[1];
74   out->dr2 = dregs[2];
75   out->dr3 = dregs[3];
76   // 4 and 5 deliberatly omitted because they aren't included in the minidump
77   // format.
78   out->dr6 = dregs[6];
79   out->dr7 = dregs[7];
80 
81   out->gs = regs.xgs;
82   out->fs = regs.xfs;
83   out->es = regs.xes;
84   out->ds = regs.xds;
85 
86   out->edi = regs.edi;
87   out->esi = regs.esi;
88   out->ebx = regs.ebx;
89   out->edx = regs.edx;
90   out->ecx = regs.ecx;
91   out->eax = regs.eax;
92 
93   out->ebp = regs.ebp;
94   out->eip = regs.eip;
95   out->cs = regs.xcs;
96   out->eflags = regs.eflags;
97   out->esp = regs.esp;
98   out->ss = regs.xss;
99 
100   out->float_save.control_word = fpregs.cwd;
101   out->float_save.status_word = fpregs.swd;
102   out->float_save.tag_word = fpregs.twd;
103   out->float_save.error_offset = fpregs.fip;
104   out->float_save.error_selector = fpregs.fcs;
105   out->float_save.data_offset = fpregs.foo;
106   out->float_save.data_selector = fpregs.fos;
107 
108   // 8 registers * 10 bytes per register.
109   my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8);
110 
111   // This matches the Intel fpsave format.
112   U16(out->extended_registers + 0, fpregs.cwd);
113   U16(out->extended_registers + 2, fpregs.swd);
114   U16(out->extended_registers + 4, fpregs.twd);
115   U16(out->extended_registers + 6, fpxregs.fop);
116   U32(out->extended_registers + 8, fpxregs.fip);
117   U16(out->extended_registers + 12, fpxregs.fcs);
118   U32(out->extended_registers + 16, fpregs.foo);
119   U16(out->extended_registers + 20, fpregs.fos);
120   U32(out->extended_registers + 24, fpxregs.mxcsr);
121 
122   my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128);
123   my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128);
124 }
125 
126 #elif defined(__x86_64)
127 
128 uintptr_t ThreadInfo::GetInstructionPointer() const {
129   return regs.rip;
130 }
131 
132 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
133   out->context_flags = MD_CONTEXT_AMD64_FULL |
134                        MD_CONTEXT_AMD64_SEGMENTS;
135 
136   out->cs = regs.cs;
137 
138   out->ds = regs.ds;
139   out->es = regs.es;
140   out->fs = regs.fs;
141   out->gs = regs.gs;
142 
143   out->ss = regs.ss;
144   out->eflags = regs.eflags;
145 
146   out->dr0 = dregs[0];
147   out->dr1 = dregs[1];
148   out->dr2 = dregs[2];
149   out->dr3 = dregs[3];
150   // 4 and 5 deliberatly omitted because they aren't included in the minidump
151   // format.
152   out->dr6 = dregs[6];
153   out->dr7 = dregs[7];
154 
155   out->rax = regs.rax;
156   out->rcx = regs.rcx;
157   out->rdx = regs.rdx;
158   out->rbx = regs.rbx;
159 
160   out->rsp = regs.rsp;
161 
162   out->rbp = regs.rbp;
163   out->rsi = regs.rsi;
164   out->rdi = regs.rdi;
165   out->r8 = regs.r8;
166   out->r9 = regs.r9;
167   out->r10 = regs.r10;
168   out->r11 = regs.r11;
169   out->r12 = regs.r12;
170   out->r13 = regs.r13;
171   out->r14 = regs.r14;
172   out->r15 = regs.r15;
173 
174   out->rip = regs.rip;
175 
176   out->flt_save.control_word = fpregs.cwd;
177   out->flt_save.status_word = fpregs.swd;
178   out->flt_save.tag_word = fpregs.ftw;
179   out->flt_save.error_opcode = fpregs.fop;
180   out->flt_save.error_offset = fpregs.rip;
181   out->flt_save.error_selector = 0;  // We don't have this.
182   out->flt_save.data_offset = fpregs.rdp;
183   out->flt_save.data_selector = 0;   // We don't have this.
184   out->flt_save.mx_csr = fpregs.mxcsr;
185   out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
186 
187   my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
188   my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
189 }
190 
191 #elif defined(__ARM_EABI__)
192 
193 uintptr_t ThreadInfo::GetInstructionPointer() const {
194   return regs.uregs[15];
195 }
196 
197 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
198   out->context_flags = MD_CONTEXT_ARM_FULL;
199 
200   for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
201     out->iregs[i] = regs.uregs[i];
202   // No CPSR register in ThreadInfo(it's not accessible via ptrace)
203   out->cpsr = 0;
204 #if !defined(__ANDROID__)
205   out->float_save.fpscr = fpregs.fpsr |
206     (static_cast<uint64_t>(fpregs.fpcr) << 32);
207   // TODO: sort this out, actually collect floating point registers
208   my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
209   my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
210 #endif
211 }
212 
213 #elif defined(__aarch64__)
214 
215 uintptr_t ThreadInfo::GetInstructionPointer() const {
216   return regs.pc;
217 }
218 
219 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
220   out->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
221 
222   out->cpsr = static_cast<uint32_t>(regs.pstate);
223   for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
224     out->iregs[i] = regs.regs[i];
225   out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp;
226   out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc;
227 
228   out->float_save.fpsr = fpregs.fpsr;
229   out->float_save.fpcr = fpregs.fpcr;
230   my_memcpy(&out->float_save.regs, &fpregs.vregs,
231       MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
232 }
233 
234 #elif defined(__mips__)
235 
236 uintptr_t ThreadInfo::GetInstructionPointer() const {
237   return mcontext.pc;
238 }
239 
240 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
241 #if _MIPS_SIM == _ABI64
242   out->context_flags = MD_CONTEXT_MIPS64_FULL;
243 #elif _MIPS_SIM == _ABIO32
244   out->context_flags = MD_CONTEXT_MIPS_FULL;
245 #else
246 # error "This mips ABI is currently not supported (n32)"
247 #endif
248 
249   for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
250     out->iregs[i] = mcontext.gregs[i];
251 
252   out->mdhi = mcontext.mdhi;
253   out->mdlo = mcontext.mdlo;
254   out->dsp_control = mcontext.dsp;
255 
256   out->hi[0] = mcontext.hi1;
257   out->lo[0] = mcontext.lo1;
258   out->hi[1] = mcontext.hi2;
259   out->lo[1] = mcontext.lo2;
260   out->hi[2] = mcontext.hi3;
261   out->lo[2] = mcontext.lo3;
262 
263   out->epc = mcontext.pc;
264   out->badvaddr = 0; // Not stored in mcontext
265   out->status = 0; // Not stored in mcontext
266   out->cause = 0; // Not stored in mcontext
267 
268   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
269     out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs;
270 
271   out->float_save.fpcsr = mcontext.fpc_csr;
272 #if _MIPS_SIM == _ABIO32
273   out->float_save.fir = mcontext.fpc_eir;
274 #endif
275 }
276 
277 #elif defined(__riscv)
278 
279 uintptr_t ThreadInfo::GetInstructionPointer() const {
280   return mcontext.__gregs[0];
281 }
282 
283 void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
284 # if __riscv__xlen == 32
285   out->context_flags = MD_CONTEXT_RISCV_FULL;
286 # elif __riscv_xlen == 64
287   out->context_flags = MD_CONTEXT_RISCV64_FULL;
288 # else
289 #  error "Unexpected __riscv_xlen"
290 # endif
291 
292   out->pc  = mcontext.__gregs[0];
293   out->ra  = mcontext.__gregs[1];
294   out->sp  = mcontext.__gregs[2];
295   out->gp  = mcontext.__gregs[3];
296   out->tp  = mcontext.__gregs[4];
297   out->t0  = mcontext.__gregs[5];
298   out->t1  = mcontext.__gregs[6];
299   out->t2  = mcontext.__gregs[7];
300   out->s0  = mcontext.__gregs[8];
301   out->s1  = mcontext.__gregs[9];
302   out->a0  = mcontext.__gregs[10];
303   out->a1  = mcontext.__gregs[11];
304   out->a2  = mcontext.__gregs[12];
305   out->a3  = mcontext.__gregs[13];
306   out->a4  = mcontext.__gregs[14];
307   out->a5  = mcontext.__gregs[15];
308   out->a6  = mcontext.__gregs[16];
309   out->a7  = mcontext.__gregs[17];
310   out->s2  = mcontext.__gregs[18];
311   out->s3  = mcontext.__gregs[19];
312   out->s4  = mcontext.__gregs[20];
313   out->s5  = mcontext.__gregs[21];
314   out->s6  = mcontext.__gregs[22];
315   out->s7  = mcontext.__gregs[23];
316   out->s8  = mcontext.__gregs[24];
317   out->s9  = mcontext.__gregs[25];
318   out->s10 = mcontext.__gregs[26];
319   out->s11 = mcontext.__gregs[27];
320   out->t3  = mcontext.__gregs[28];
321   out->t4  = mcontext.__gregs[29];
322   out->t5  = mcontext.__gregs[30];
323   out->t6  = mcontext.__gregs[31];
324 
325   // Breakpad only supports RISCV32 with 32 bit floating point.
326   // Breakpad only supports RISCV64 with 64 bit floating point.
327 #if __riscv_xlen == 32
328   for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
329     out->fpregs[i] = mcontext.__fpregs.__f.__f[i];
330   out->fcsr = mcontext.__fpregs.__f.__fcsr;
331 #elif __riscv_xlen == 64
332   for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
333     out->fpregs[i] = mcontext.__fpregs.__d.__f[i];
334   out->fcsr = mcontext.__fpregs.__d.__fcsr;
335 #else
336 #error "Unexpected __riscv_xlen"
337 #endif
338 }
339 #endif  // __riscv
340 
GetGeneralPurposeRegisters(void ** gp_regs,size_t * size)341 void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
342   assert(gp_regs || size);
343 #if defined(__mips__)
344   if (gp_regs)
345     *gp_regs = mcontext.gregs;
346   if (size)
347     *size = sizeof(mcontext.gregs);
348 #elif defined(__riscv)
349   if (gp_regs)
350     *gp_regs = mcontext.__gregs;
351   if (size)
352     *size = sizeof(mcontext.__gregs);
353 #else
354   if (gp_regs)
355     *gp_regs = &regs;
356   if (size)
357     *size = sizeof(regs);
358 #endif
359 }
360 
GetFloatingPointRegisters(void ** fp_regs,size_t * size)361 void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
362   assert(fp_regs || size);
363 #if defined(__mips__)
364   if (fp_regs)
365     *fp_regs = &mcontext.fpregs;
366   if (size)
367     *size = sizeof(mcontext.fpregs);
368 #elif defined(__riscv)
369 # if __riscv_flen == 32
370   if (fp_regs)
371     *fp_regs = &mcontext.__fpregs.__f.__f;
372   if (size)
373     *size = sizeof(mcontext.__fpregs.__f.__f);
374 # elif __riscv_flen == 64
375   if (fp_regs)
376     *fp_regs = &mcontext.__fpregs.__d.__f;
377   if (size)
378     *size = sizeof(mcontext.__fpregs.__d.__f);
379 # elif __riscv_flen == 128
380   if (fp_regs)
381     *fp_regs = &mcontext.__fpregs.__q.__f;
382   if (size)
383     *size = sizeof(mcontext.__fpregs.__q.__f);
384 # else
385 #  error "Unexpected __riscv_flen"
386 # endif
387 #else
388   if (fp_regs)
389     *fp_regs = &fpregs;
390   if (size)
391     *size = sizeof(fpregs);
392 #endif
393 }
394 
395 }  // namespace google_breakpad
396