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