1 // Copyright (c) 2010 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 // dump_context.cc: A (mini/micro)dump context.
31 //
32 // See dump_context.h for documentation.
33 
34 #include "google_breakpad/processor/dump_context.h"
35 
36 #include <assert.h>
37 
38 #ifdef _WIN32
39 #include <io.h>
40 #else  // _WIN32
41 #include <unistd.h>
42 #endif  // _WIN32
43 
44 #include "common/stdio_wrapper.h"
45 #include "processor/logging.h"
46 
47 namespace google_breakpad {
48 
DumpContext()49 DumpContext::DumpContext() : context_(),
50                              context_flags_(0) { }
51 
~DumpContext()52 DumpContext::~DumpContext() {
53   FreeContext();
54 }
55 
GetContextCPU() const56 uint32_t DumpContext::GetContextCPU() const {
57   if (!valid_) {
58     // Don't log a message, GetContextCPU can be legitimately called with
59     // valid_ false by FreeContext, which is called by Read.
60     return 0;
61   }
62 
63   return context_flags_ & MD_CONTEXT_CPU_MASK;
64 }
65 
GetContextFlags() const66 uint32_t DumpContext::GetContextFlags() const {
67   return context_flags_;
68 }
69 
GetContextX86() const70 const MDRawContextX86* DumpContext::GetContextX86() const {
71   if (GetContextCPU() != MD_CONTEXT_X86) {
72     BPLOG(ERROR) << "DumpContext cannot get x86 context";
73     return NULL;
74   }
75 
76   return context_.x86;
77 }
78 
GetContextPPC() const79 const MDRawContextPPC* DumpContext::GetContextPPC() const {
80   if (GetContextCPU() != MD_CONTEXT_PPC) {
81     BPLOG(ERROR) << "DumpContext cannot get ppc context";
82     return NULL;
83   }
84 
85   return context_.ppc;
86 }
87 
GetContextPPC64() const88 const MDRawContextPPC64* DumpContext::GetContextPPC64() const {
89   if (GetContextCPU() != MD_CONTEXT_PPC64) {
90     BPLOG(ERROR) << "DumpContext cannot get ppc64 context";
91     return NULL;
92   }
93 
94   return context_.ppc64;
95 }
96 
GetContextAMD64() const97 const MDRawContextAMD64* DumpContext::GetContextAMD64() const {
98   if (GetContextCPU() != MD_CONTEXT_AMD64) {
99     BPLOG(ERROR) << "DumpContext cannot get amd64 context";
100     return NULL;
101   }
102 
103   return context_.amd64;
104 }
105 
GetContextSPARC() const106 const MDRawContextSPARC* DumpContext::GetContextSPARC() const {
107   if (GetContextCPU() != MD_CONTEXT_SPARC) {
108     BPLOG(ERROR) << "DumpContext cannot get sparc context";
109     return NULL;
110   }
111 
112   return context_.ctx_sparc;
113 }
114 
GetContextARM() const115 const MDRawContextARM* DumpContext::GetContextARM() const {
116   if (GetContextCPU() != MD_CONTEXT_ARM) {
117     BPLOG(ERROR) << "DumpContext cannot get arm context";
118     return NULL;
119   }
120 
121   return context_.arm;
122 }
123 
GetContextARM64() const124 const MDRawContextARM64* DumpContext::GetContextARM64() const {
125   if (GetContextCPU() != MD_CONTEXT_ARM64) {
126     BPLOG(ERROR) << "DumpContext cannot get arm64 context";
127     return NULL;
128   }
129 
130   return context_.arm64;
131 }
132 
GetContextMIPS() const133 const MDRawContextMIPS* DumpContext::GetContextMIPS() const {
134   if ((GetContextCPU() != MD_CONTEXT_MIPS) &&
135       (GetContextCPU() != MD_CONTEXT_MIPS64)) {
136     BPLOG(ERROR) << "DumpContext cannot get MIPS context";
137     return NULL;
138   }
139 
140   return context_.ctx_mips;
141 }
142 
GetInstructionPointer(uint64_t * ip) const143 bool DumpContext::GetInstructionPointer(uint64_t* ip) const {
144   BPLOG_IF(ERROR, !ip) << "DumpContext::GetInstructionPointer requires |ip|";
145   assert(ip);
146   *ip = 0;
147 
148   if (!valid_) {
149     BPLOG(ERROR) << "Invalid DumpContext for GetInstructionPointer";
150     return false;
151   }
152 
153   switch (GetContextCPU()) {
154   case MD_CONTEXT_AMD64:
155     *ip = GetContextAMD64()->rip;
156     break;
157   case MD_CONTEXT_ARM:
158     *ip = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_PC];
159     break;
160   case MD_CONTEXT_ARM64:
161     *ip = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_PC];
162     break;
163   case MD_CONTEXT_PPC:
164     *ip = GetContextPPC()->srr0;
165     break;
166   case MD_CONTEXT_PPC64:
167     *ip = GetContextPPC64()->srr0;
168     break;
169   case MD_CONTEXT_SPARC:
170     *ip = GetContextSPARC()->pc;
171     break;
172   case MD_CONTEXT_X86:
173     *ip = GetContextX86()->eip;
174     break;
175   case MD_CONTEXT_MIPS:
176   case MD_CONTEXT_MIPS64:
177     *ip = GetContextMIPS()->epc;
178     break;
179   default:
180     // This should never happen.
181     BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
182     return false;
183   }
184   return true;
185 }
186 
GetStackPointer(uint64_t * sp) const187 bool DumpContext::GetStackPointer(uint64_t* sp) const {
188   BPLOG_IF(ERROR, !sp) << "DumpContext::GetStackPointer requires |sp|";
189   assert(sp);
190   *sp = 0;
191 
192   if (!valid_) {
193     BPLOG(ERROR) << "Invalid DumpContext for GetStackPointer";
194     return false;
195   }
196 
197   switch (GetContextCPU()) {
198   case MD_CONTEXT_AMD64:
199     *sp = GetContextAMD64()->rsp;
200     break;
201   case MD_CONTEXT_ARM:
202     *sp = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_SP];
203     break;
204   case MD_CONTEXT_ARM64:
205     *sp = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_SP];
206     break;
207   case MD_CONTEXT_PPC:
208     *sp = GetContextPPC()->gpr[MD_CONTEXT_PPC_REG_SP];
209     break;
210   case MD_CONTEXT_PPC64:
211     *sp = GetContextPPC64()->gpr[MD_CONTEXT_PPC64_REG_SP];
212     break;
213   case MD_CONTEXT_SPARC:
214     *sp = GetContextSPARC()->g_r[MD_CONTEXT_SPARC_REG_SP];
215     break;
216   case MD_CONTEXT_X86:
217     *sp = GetContextX86()->esp;
218     break;
219   case MD_CONTEXT_MIPS:
220   case MD_CONTEXT_MIPS64:
221     *sp = GetContextMIPS()->iregs[MD_CONTEXT_MIPS_REG_SP];
222     break;
223   default:
224     // This should never happen.
225     BPLOG(ERROR) << "Unknown CPU architecture in GetStackPointer";
226     return false;
227   }
228   return true;
229 }
230 
SetContextFlags(uint32_t context_flags)231 void DumpContext::SetContextFlags(uint32_t context_flags) {
232   context_flags_ = context_flags;
233 }
234 
SetContextX86(MDRawContextX86 * x86)235 void DumpContext::SetContextX86(MDRawContextX86* x86) {
236   context_.x86 = x86;
237 }
238 
SetContextPPC(MDRawContextPPC * ppc)239 void DumpContext::SetContextPPC(MDRawContextPPC* ppc) {
240   context_.ppc = ppc;
241 }
242 
SetContextPPC64(MDRawContextPPC64 * ppc64)243 void DumpContext::SetContextPPC64(MDRawContextPPC64* ppc64) {
244   context_.ppc64 = ppc64;
245 }
246 
SetContextAMD64(MDRawContextAMD64 * amd64)247 void DumpContext::SetContextAMD64(MDRawContextAMD64* amd64) {
248   context_.amd64 = amd64;
249 }
250 
SetContextSPARC(MDRawContextSPARC * ctx_sparc)251 void DumpContext::SetContextSPARC(MDRawContextSPARC* ctx_sparc) {
252   context_.ctx_sparc = ctx_sparc;
253 }
254 
SetContextARM(MDRawContextARM * arm)255 void DumpContext::SetContextARM(MDRawContextARM* arm) {
256   context_.arm = arm;
257 }
258 
SetContextARM64(MDRawContextARM64 * arm64)259 void DumpContext::SetContextARM64(MDRawContextARM64* arm64) {
260   context_.arm64 = arm64;
261 }
262 
SetContextMIPS(MDRawContextMIPS * ctx_mips)263 void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) {
264   context_.ctx_mips = ctx_mips;
265 }
266 
FreeContext()267 void DumpContext::FreeContext() {
268   switch (GetContextCPU()) {
269     case MD_CONTEXT_X86:
270       delete context_.x86;
271       break;
272 
273     case MD_CONTEXT_PPC:
274       delete context_.ppc;
275       break;
276 
277     case MD_CONTEXT_PPC64:
278       delete context_.ppc64;
279       break;
280 
281     case MD_CONTEXT_AMD64:
282       delete context_.amd64;
283       break;
284 
285     case MD_CONTEXT_SPARC:
286       delete context_.ctx_sparc;
287       break;
288 
289     case MD_CONTEXT_ARM:
290       delete context_.arm;
291       break;
292 
293     case MD_CONTEXT_ARM64:
294       delete context_.arm64;
295       break;
296 
297     case MD_CONTEXT_MIPS:
298     case MD_CONTEXT_MIPS64:
299       delete context_.ctx_mips;
300       break;
301 
302     default:
303       // There is no context record (valid_ is false) or there's a
304       // context record for an unknown CPU (shouldn't happen, only known
305       // records are stored by Read).
306       break;
307   }
308 
309   context_flags_ = 0;
310   context_.base = NULL;
311 }
312 
Print()313 void DumpContext::Print() {
314   if (!valid_) {
315     BPLOG(ERROR) << "DumpContext cannot print invalid data";
316     return;
317   }
318 
319   switch (GetContextCPU()) {
320     case MD_CONTEXT_X86: {
321       const MDRawContextX86* context_x86 = GetContextX86();
322       printf("MDRawContextX86\n");
323       printf("  context_flags                = 0x%x\n",
324              context_x86->context_flags);
325       printf("  dr0                          = 0x%x\n", context_x86->dr0);
326       printf("  dr1                          = 0x%x\n", context_x86->dr1);
327       printf("  dr2                          = 0x%x\n", context_x86->dr2);
328       printf("  dr3                          = 0x%x\n", context_x86->dr3);
329       printf("  dr6                          = 0x%x\n", context_x86->dr6);
330       printf("  dr7                          = 0x%x\n", context_x86->dr7);
331       printf("  float_save.control_word      = 0x%x\n",
332              context_x86->float_save.control_word);
333       printf("  float_save.status_word       = 0x%x\n",
334              context_x86->float_save.status_word);
335       printf("  float_save.tag_word          = 0x%x\n",
336              context_x86->float_save.tag_word);
337       printf("  float_save.error_offset      = 0x%x\n",
338              context_x86->float_save.error_offset);
339       printf("  float_save.error_selector    = 0x%x\n",
340              context_x86->float_save.error_selector);
341       printf("  float_save.data_offset       = 0x%x\n",
342              context_x86->float_save.data_offset);
343       printf("  float_save.data_selector     = 0x%x\n",
344              context_x86->float_save.data_selector);
345       printf("  float_save.register_area[%2d] = 0x",
346              MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
347       for (unsigned int register_index = 0;
348            register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
349            ++register_index) {
350         printf("%02x", context_x86->float_save.register_area[register_index]);
351       }
352       printf("\n");
353       printf("  float_save.cr0_npx_state     = 0x%x\n",
354              context_x86->float_save.cr0_npx_state);
355       printf("  gs                           = 0x%x\n", context_x86->gs);
356       printf("  fs                           = 0x%x\n", context_x86->fs);
357       printf("  es                           = 0x%x\n", context_x86->es);
358       printf("  ds                           = 0x%x\n", context_x86->ds);
359       printf("  edi                          = 0x%x\n", context_x86->edi);
360       printf("  esi                          = 0x%x\n", context_x86->esi);
361       printf("  ebx                          = 0x%x\n", context_x86->ebx);
362       printf("  edx                          = 0x%x\n", context_x86->edx);
363       printf("  ecx                          = 0x%x\n", context_x86->ecx);
364       printf("  eax                          = 0x%x\n", context_x86->eax);
365       printf("  ebp                          = 0x%x\n", context_x86->ebp);
366       printf("  eip                          = 0x%x\n", context_x86->eip);
367       printf("  cs                           = 0x%x\n", context_x86->cs);
368       printf("  eflags                       = 0x%x\n", context_x86->eflags);
369       printf("  esp                          = 0x%x\n", context_x86->esp);
370       printf("  ss                           = 0x%x\n", context_x86->ss);
371       printf("  extended_registers[%3d]      = 0x",
372              MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
373       for (unsigned int register_index = 0;
374            register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
375            ++register_index) {
376         printf("%02x", context_x86->extended_registers[register_index]);
377       }
378       printf("\n\n");
379 
380       break;
381     }
382 
383     case MD_CONTEXT_PPC: {
384       const MDRawContextPPC* context_ppc = GetContextPPC();
385       printf("MDRawContextPPC\n");
386       printf("  context_flags            = 0x%x\n",
387              context_ppc->context_flags);
388       printf("  srr0                     = 0x%x\n", context_ppc->srr0);
389       printf("  srr1                     = 0x%x\n", context_ppc->srr1);
390       for (unsigned int gpr_index = 0;
391            gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
392            ++gpr_index) {
393         printf("  gpr[%2d]                  = 0x%x\n",
394                gpr_index, context_ppc->gpr[gpr_index]);
395       }
396       printf("  cr                       = 0x%x\n", context_ppc->cr);
397       printf("  xer                      = 0x%x\n", context_ppc->xer);
398       printf("  lr                       = 0x%x\n", context_ppc->lr);
399       printf("  ctr                      = 0x%x\n", context_ppc->ctr);
400       printf("  mq                       = 0x%x\n", context_ppc->mq);
401       printf("  vrsave                   = 0x%x\n", context_ppc->vrsave);
402       for (unsigned int fpr_index = 0;
403            fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
404            ++fpr_index) {
405         printf("  float_save.fpregs[%2d]    = 0x%" PRIx64 "\n",
406                fpr_index, context_ppc->float_save.fpregs[fpr_index]);
407       }
408       printf("  float_save.fpscr         = 0x%x\n",
409              context_ppc->float_save.fpscr);
410       // TODO(mmentovai): print the 128-bit quantities in
411       // context_ppc->vector_save.  This isn't done yet because printf
412       // doesn't support 128-bit quantities, and printing them using
413       // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
414       // byte ordering.
415       printf("  vector_save.save_vrvalid = 0x%x\n",
416              context_ppc->vector_save.save_vrvalid);
417       printf("\n");
418 
419       break;
420     }
421 
422     case MD_CONTEXT_PPC64: {
423       const MDRawContextPPC64* context_ppc64 = GetContextPPC64();
424       printf("MDRawContextPPC64\n");
425       printf("  context_flags            = 0x%" PRIx64 "\n",
426              context_ppc64->context_flags);
427       printf("  srr0                     = 0x%" PRIx64 "\n",
428              context_ppc64->srr0);
429       printf("  srr1                     = 0x%" PRIx64 "\n",
430              context_ppc64->srr1);
431       for (unsigned int gpr_index = 0;
432            gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
433            ++gpr_index) {
434         printf("  gpr[%2d]                  = 0x%" PRIx64 "\n",
435                gpr_index, context_ppc64->gpr[gpr_index]);
436       }
437       printf("  cr                       = 0x%" PRIx64 "\n", context_ppc64->cr);
438       printf("  xer                      = 0x%" PRIx64 "\n",
439              context_ppc64->xer);
440       printf("  lr                       = 0x%" PRIx64 "\n", context_ppc64->lr);
441       printf("  ctr                      = 0x%" PRIx64 "\n",
442              context_ppc64->ctr);
443       printf("  vrsave                   = 0x%" PRIx64 "\n",
444              context_ppc64->vrsave);
445       for (unsigned int fpr_index = 0;
446            fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
447            ++fpr_index) {
448         printf("  float_save.fpregs[%2d]    = 0x%" PRIx64 "\n",
449                fpr_index, context_ppc64->float_save.fpregs[fpr_index]);
450       }
451       printf("  float_save.fpscr         = 0x%x\n",
452              context_ppc64->float_save.fpscr);
453       // TODO(mmentovai): print the 128-bit quantities in
454       // context_ppc64->vector_save.  This isn't done yet because printf
455       // doesn't support 128-bit quantities, and printing them using
456       // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
457       // byte ordering.
458       printf("  vector_save.save_vrvalid = 0x%x\n",
459              context_ppc64->vector_save.save_vrvalid);
460       printf("\n");
461 
462       break;
463     }
464 
465     case MD_CONTEXT_AMD64: {
466       const MDRawContextAMD64* context_amd64 = GetContextAMD64();
467       printf("MDRawContextAMD64\n");
468       printf("  p1_home       = 0x%" PRIx64 "\n",
469              context_amd64->p1_home);
470       printf("  p2_home       = 0x%" PRIx64 "\n",
471              context_amd64->p2_home);
472       printf("  p3_home       = 0x%" PRIx64 "\n",
473              context_amd64->p3_home);
474       printf("  p4_home       = 0x%" PRIx64 "\n",
475              context_amd64->p4_home);
476       printf("  p5_home       = 0x%" PRIx64 "\n",
477              context_amd64->p5_home);
478       printf("  p6_home       = 0x%" PRIx64 "\n",
479              context_amd64->p6_home);
480       printf("  context_flags = 0x%x\n",
481              context_amd64->context_flags);
482       printf("  mx_csr        = 0x%x\n",
483              context_amd64->mx_csr);
484       printf("  cs            = 0x%x\n", context_amd64->cs);
485       printf("  ds            = 0x%x\n", context_amd64->ds);
486       printf("  es            = 0x%x\n", context_amd64->es);
487       printf("  fs            = 0x%x\n", context_amd64->fs);
488       printf("  gs            = 0x%x\n", context_amd64->gs);
489       printf("  ss            = 0x%x\n", context_amd64->ss);
490       printf("  eflags        = 0x%x\n", context_amd64->eflags);
491       printf("  dr0           = 0x%" PRIx64 "\n", context_amd64->dr0);
492       printf("  dr1           = 0x%" PRIx64 "\n", context_amd64->dr1);
493       printf("  dr2           = 0x%" PRIx64 "\n", context_amd64->dr2);
494       printf("  dr3           = 0x%" PRIx64 "\n", context_amd64->dr3);
495       printf("  dr6           = 0x%" PRIx64 "\n", context_amd64->dr6);
496       printf("  dr7           = 0x%" PRIx64 "\n", context_amd64->dr7);
497       printf("  rax           = 0x%" PRIx64 "\n", context_amd64->rax);
498       printf("  rcx           = 0x%" PRIx64 "\n", context_amd64->rcx);
499       printf("  rdx           = 0x%" PRIx64 "\n", context_amd64->rdx);
500       printf("  rbx           = 0x%" PRIx64 "\n", context_amd64->rbx);
501       printf("  rsp           = 0x%" PRIx64 "\n", context_amd64->rsp);
502       printf("  rbp           = 0x%" PRIx64 "\n", context_amd64->rbp);
503       printf("  rsi           = 0x%" PRIx64 "\n", context_amd64->rsi);
504       printf("  rdi           = 0x%" PRIx64 "\n", context_amd64->rdi);
505       printf("  r8            = 0x%" PRIx64 "\n", context_amd64->r8);
506       printf("  r9            = 0x%" PRIx64 "\n", context_amd64->r9);
507       printf("  r10           = 0x%" PRIx64 "\n", context_amd64->r10);
508       printf("  r11           = 0x%" PRIx64 "\n", context_amd64->r11);
509       printf("  r12           = 0x%" PRIx64 "\n", context_amd64->r12);
510       printf("  r13           = 0x%" PRIx64 "\n", context_amd64->r13);
511       printf("  r14           = 0x%" PRIx64 "\n", context_amd64->r14);
512       printf("  r15           = 0x%" PRIx64 "\n", context_amd64->r15);
513       printf("  rip           = 0x%" PRIx64 "\n", context_amd64->rip);
514       // TODO: print xmm, vector, debug registers
515       printf("\n");
516       break;
517     }
518 
519     case MD_CONTEXT_SPARC: {
520       const MDRawContextSPARC* context_sparc = GetContextSPARC();
521       printf("MDRawContextSPARC\n");
522       printf("  context_flags       = 0x%x\n",
523              context_sparc->context_flags);
524       for (unsigned int g_r_index = 0;
525            g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
526            ++g_r_index) {
527         printf("  g_r[%2d]             = 0x%" PRIx64 "\n",
528                g_r_index, context_sparc->g_r[g_r_index]);
529       }
530       printf("  ccr                 = 0x%" PRIx64 "\n", context_sparc->ccr);
531       printf("  pc                  = 0x%" PRIx64 "\n", context_sparc->pc);
532       printf("  npc                 = 0x%" PRIx64 "\n", context_sparc->npc);
533       printf("  y                   = 0x%" PRIx64 "\n", context_sparc->y);
534       printf("  asi                 = 0x%" PRIx64 "\n", context_sparc->asi);
535       printf("  fprs                = 0x%" PRIx64 "\n", context_sparc->fprs);
536 
537       for (unsigned int fpr_index = 0;
538            fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
539            ++fpr_index) {
540         printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
541                fpr_index, context_sparc->float_save.regs[fpr_index]);
542       }
543       printf("  float_save.filler   = 0x%" PRIx64 "\n",
544              context_sparc->float_save.filler);
545       printf("  float_save.fsr      = 0x%" PRIx64 "\n",
546              context_sparc->float_save.fsr);
547       break;
548     }
549 
550     case MD_CONTEXT_ARM: {
551       const MDRawContextARM* context_arm = GetContextARM();
552       const char * const names[] = {
553         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
554         "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
555       };
556       printf("MDRawContextARM\n");
557       printf("  context_flags        = 0x%x\n",
558              context_arm->context_flags);
559       for (unsigned int ireg_index = 0;
560            ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
561            ++ireg_index) {
562         printf("  %-3s                  = 0x%x\n",
563                names[ireg_index], context_arm->iregs[ireg_index]);
564       }
565       printf("  cpsr                 = 0x%x\n", context_arm->cpsr);
566       printf("  float_save.fpscr     = 0x%" PRIx64 "\n",
567              context_arm->float_save.fpscr);
568       for (unsigned int fpr_index = 0;
569            fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
570            ++fpr_index) {
571         printf("  float_save.regs[%2d]  = 0x%" PRIx64 "\n",
572                fpr_index, context_arm->float_save.regs[fpr_index]);
573       }
574       for (unsigned int fpe_index = 0;
575            fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
576            ++fpe_index) {
577         printf("  float_save.extra[%2d] = 0x%" PRIx32 "\n",
578                fpe_index, context_arm->float_save.extra[fpe_index]);
579       }
580 
581       break;
582     }
583 
584     case MD_CONTEXT_ARM64: {
585       const MDRawContextARM64* context_arm64 = GetContextARM64();
586       printf("MDRawContextARM64\n");
587       printf("  context_flags       = 0x%x\n",
588              context_arm64->context_flags);
589       for (unsigned int ireg_index = 0;
590            ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
591            ++ireg_index) {
592         printf("  iregs[%2d]            = 0x%" PRIx64 "\n",
593                ireg_index, context_arm64->iregs[ireg_index]);
594       }
595       printf("  cpsr                = 0x%x\n", context_arm64->cpsr);
596       printf("  float_save.fpsr     = 0x%x\n", context_arm64->float_save.fpsr);
597       printf("  float_save.fpcr     = 0x%x\n", context_arm64->float_save.fpcr);
598 
599       for (unsigned int freg_index = 0;
600            freg_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
601            ++freg_index) {
602         uint128_struct fp_value = context_arm64->float_save.regs[freg_index];
603         printf("  float_save.regs[%2d]            = 0x%" PRIx64 "%" PRIx64 "\n",
604                freg_index, fp_value.high, fp_value.low);
605       }
606 
607       break;
608     }
609 
610     case MD_CONTEXT_MIPS:
611     case MD_CONTEXT_MIPS64: {
612       const MDRawContextMIPS* context_mips = GetContextMIPS();
613       printf("MDRawContextMIPS\n");
614       printf("  context_flags        = 0x%x\n",
615              context_mips->context_flags);
616       for (int ireg_index = 0;
617            ireg_index < MD_CONTEXT_MIPS_GPR_COUNT;
618            ++ireg_index) {
619         printf("  iregs[%2d]           = 0x%" PRIx64 "\n",
620                ireg_index, context_mips->iregs[ireg_index]);
621       }
622       printf("  mdhi                 = 0x%" PRIx64 "\n",
623              context_mips->mdhi);
624       printf("  mdlo                 = 0x%" PRIx64 "\n",
625              context_mips->mdhi);
626       for (int dsp_index = 0;
627            dsp_index < MD_CONTEXT_MIPS_DSP_COUNT;
628            ++dsp_index) {
629         printf("  hi[%1d]              = 0x%" PRIx32 "\n",
630                dsp_index, context_mips->hi[dsp_index]);
631         printf("  lo[%1d]              = 0x%" PRIx32 "\n",
632                dsp_index, context_mips->lo[dsp_index]);
633       }
634       printf("  dsp_control          = 0x%" PRIx32 "\n",
635              context_mips->dsp_control);
636       printf("  epc                  = 0x%" PRIx64 "\n",
637              context_mips->epc);
638       printf("  badvaddr             = 0x%" PRIx64 "\n",
639              context_mips->badvaddr);
640       printf("  status               = 0x%" PRIx32 "\n",
641              context_mips->status);
642       printf("  cause                = 0x%" PRIx32 "\n",
643              context_mips->cause);
644 
645       for (int fpr_index = 0;
646            fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT;
647            ++fpr_index) {
648         printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
649                fpr_index, context_mips->float_save.regs[fpr_index]);
650       }
651       printf("  float_save.fpcsr     = 0x%" PRIx32 "\n",
652              context_mips->float_save.fpcsr);
653       printf("  float_save.fir       = 0x%" PRIx32 "\n",
654              context_mips->float_save.fir);
655       break;
656     }
657 
658     default: {
659       break;
660     }
661   }
662 }
663 
664 }  // namespace google_breakpad
665