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 | |
49 | DumpContext::DumpContext() : context_(), |
50 | context_flags_(0) { } |
51 | |
52 | DumpContext::~DumpContext() { |
53 | FreeContext(); |
54 | } |
55 | |
56 | 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 | |
66 | uint32_t DumpContext::GetContextFlags() const { |
67 | return context_flags_; |
68 | } |
69 | |
70 | 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 | |
79 | 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 | |
88 | 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 | |
97 | 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 | |
106 | 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 | |
115 | 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 | |
124 | 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 | |
133 | 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 | |
143 | 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 | |
187 | 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 | |
231 | void DumpContext::SetContextFlags(uint32_t context_flags) { |
232 | context_flags_ = context_flags; |
233 | } |
234 | |
235 | void DumpContext::SetContextX86(MDRawContextX86* x86) { |
236 | context_.x86 = x86; |
237 | } |
238 | |
239 | void DumpContext::SetContextPPC(MDRawContextPPC* ppc) { |
240 | context_.ppc = ppc; |
241 | } |
242 | |
243 | void DumpContext::SetContextPPC64(MDRawContextPPC64* ppc64) { |
244 | context_.ppc64 = ppc64; |
245 | } |
246 | |
247 | void DumpContext::SetContextAMD64(MDRawContextAMD64* amd64) { |
248 | context_.amd64 = amd64; |
249 | } |
250 | |
251 | void DumpContext::SetContextSPARC(MDRawContextSPARC* ctx_sparc) { |
252 | context_.ctx_sparc = ctx_sparc; |
253 | } |
254 | |
255 | void DumpContext::SetContextARM(MDRawContextARM* arm) { |
256 | context_.arm = arm; |
257 | } |
258 | |
259 | void DumpContext::SetContextARM64(MDRawContextARM64* arm64) { |
260 | context_.arm64 = arm64; |
261 | } |
262 | |
263 | void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) { |
264 | context_.ctx_mips = ctx_mips; |
265 | } |
266 | |
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 | |
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 | |