2 * i386 CPU dump to FILE
4 * Copyright (c) 2003 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
22 #include "qemu/qemu-print.h"
23 #ifndef CONFIG_USER_ONLY
24 #include "hw/i386/apic_internal.h"
27 /***********************************************************/
30 static const char *cc_op_str
[CC_OP_NB
] = {
97 cpu_x86_dump_seg_cache(CPUX86State
*env
, FILE *f
,
98 const char *name
, struct SegmentCache
*sc
)
101 if (env
->hflags
& HF_CS64_MASK
) {
102 qemu_fprintf(f
, "%-3s=%04x %016" PRIx64
" %08x %08x", name
,
103 sc
->selector
, sc
->base
, sc
->limit
,
104 sc
->flags
& 0x00ffff00);
108 qemu_fprintf(f
, "%-3s=%04x %08x %08x %08x", name
, sc
->selector
,
109 (uint32_t)sc
->base
, sc
->limit
,
110 sc
->flags
& 0x00ffff00);
113 if (!(env
->hflags
& HF_PE_MASK
) || !(sc
->flags
& DESC_P_MASK
))
116 qemu_fprintf(f
, " DPL=%d ",
117 (sc
->flags
& DESC_DPL_MASK
) >> DESC_DPL_SHIFT
);
118 if (sc
->flags
& DESC_S_MASK
) {
119 if (sc
->flags
& DESC_CS_MASK
) {
120 qemu_fprintf(f
, (sc
->flags
& DESC_L_MASK
) ? "CS64" :
121 ((sc
->flags
& DESC_B_MASK
) ? "CS32" : "CS16"));
122 qemu_fprintf(f
, " [%c%c", (sc
->flags
& DESC_C_MASK
) ? 'C' : '-',
123 (sc
->flags
& DESC_R_MASK
) ? 'R' : '-');
125 qemu_fprintf(f
, (sc
->flags
& DESC_B_MASK
126 || env
->hflags
& HF_LMA_MASK
)
128 qemu_fprintf(f
, " [%c%c", (sc
->flags
& DESC_E_MASK
) ? 'E' : '-',
129 (sc
->flags
& DESC_W_MASK
) ? 'W' : '-');
131 qemu_fprintf(f
, "%c]", (sc
->flags
& DESC_A_MASK
) ? 'A' : '-');
133 static const char *sys_type_name
[2][16] = {
135 "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
136 "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
137 "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
138 "CallGate32", "Reserved", "IntGate32", "TrapGate32"
141 "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
142 "Reserved", "Reserved", "Reserved", "Reserved",
143 "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
144 "Reserved", "IntGate64", "TrapGate64"
147 qemu_fprintf(f
, "%s",
148 sys_type_name
[(env
->hflags
& HF_LMA_MASK
) ? 1 : 0]
149 [(sc
->flags
& DESC_TYPE_MASK
) >> DESC_TYPE_SHIFT
]);
152 qemu_fprintf(f
, "\n");
155 #ifndef CONFIG_USER_ONLY
157 /* ARRAY_SIZE check is not required because
158 * DeliveryMode(dm) has a size of 3 bit.
160 static inline const char *dm2str(uint32_t dm
)
162 static const char *str
[] = {
175 static void dump_apic_lvt(const char *name
, uint32_t lvt
, bool is_timer
)
177 uint32_t dm
= (lvt
& APIC_LVT_DELIV_MOD
) >> APIC_LVT_DELIV_MOD_SHIFT
;
178 qemu_printf("%s\t 0x%08x %s %-5s %-6s %-7s %-12s %-6s",
180 lvt
& APIC_LVT_INT_POLARITY
? "active-lo" : "active-hi",
181 lvt
& APIC_LVT_LEVEL_TRIGGER
? "level" : "edge",
182 lvt
& APIC_LVT_MASKED
? "masked" : "",
183 lvt
& APIC_LVT_DELIV_STS
? "pending" : "",
185 "" : lvt
& APIC_LVT_TIMER_PERIODIC
?
186 "periodic" : lvt
& APIC_LVT_TIMER_TSCDEADLINE
?
187 "tsc-deadline" : "one-shot",
189 if (dm
!= APIC_DM_NMI
) {
190 qemu_printf(" (vec %u)\n", lvt
& APIC_VECTOR_MASK
);
196 /* ARRAY_SIZE check is not required because
197 * destination shorthand has a size of 2 bit.
199 static inline const char *shorthand2str(uint32_t shorthand
)
201 const char *str
[] = {
202 "no-shorthand", "self", "all-self", "all"
204 return str
[shorthand
];
207 static inline uint8_t divider_conf(uint32_t divide_conf
)
209 uint8_t divide_val
= ((divide_conf
& 0x8) >> 1) | (divide_conf
& 0x3);
211 return divide_val
== 7 ? 1 : 2 << divide_val
;
214 static inline void mask2str(char *str
, uint32_t val
, uint8_t size
)
217 *str
++ = (val
>> size
) & 1 ? '1' : '0';
222 #define MAX_LOGICAL_APIC_ID_MASK_SIZE 16
224 static void dump_apic_icr(APICCommonState
*s
, CPUX86State
*env
)
226 uint32_t icr
= s
->icr
[0], icr2
= s
->icr
[1];
227 uint8_t dest_shorthand
= \
228 (icr
& APIC_ICR_DEST_SHORT
) >> APIC_ICR_DEST_SHORT_SHIFT
;
229 bool logical_mod
= icr
& APIC_ICR_DEST_MOD
;
230 char apic_id_str
[MAX_LOGICAL_APIC_ID_MASK_SIZE
+ 1];
234 qemu_printf("ICR\t 0x%08x %s %s %s %s\n",
236 logical_mod
? "logical" : "physical",
237 icr
& APIC_ICR_TRIGGER_MOD
? "level" : "edge",
238 icr
& APIC_ICR_LEVEL
? "assert" : "de-assert",
239 shorthand2str(dest_shorthand
));
241 qemu_printf("ICR2\t 0x%08x", icr2
);
242 if (dest_shorthand
!= 0) {
246 x2apic
= env
->features
[FEAT_1_ECX
] & CPUID_EXT_X2APIC
;
247 dest_field
= x2apic
? icr2
: icr2
>> APIC_ICR_DEST_SHIFT
;
251 qemu_printf(" cpu %u (X2APIC ID)\n", dest_field
);
253 qemu_printf(" cpu %u (APIC ID)\n",
254 dest_field
& APIC_LOGDEST_XAPIC_ID
);
259 if (s
->dest_mode
== 0xf) { /* flat mode */
260 mask2str(apic_id_str
, icr2
>> APIC_ICR_DEST_SHIFT
, 8);
261 qemu_printf(" mask %s (APIC ID)\n", apic_id_str
);
262 } else if (s
->dest_mode
== 0) { /* cluster mode */
264 mask2str(apic_id_str
, dest_field
& APIC_LOGDEST_X2APIC_ID
, 16);
265 qemu_printf(" cluster %u mask %s (X2APIC ID)\n",
266 dest_field
>> APIC_LOGDEST_X2APIC_SHIFT
, apic_id_str
);
268 mask2str(apic_id_str
, dest_field
& APIC_LOGDEST_XAPIC_ID
, 4);
269 qemu_printf(" cluster %u mask %s (APIC ID)\n",
270 dest_field
>> APIC_LOGDEST_XAPIC_SHIFT
, apic_id_str
);
275 static void dump_apic_interrupt(const char *name
, uint32_t *ireg_tab
,
280 qemu_printf("%s\t ", name
);
281 for (i
= 0; i
< 256; i
++) {
282 if (apic_get_bit(ireg_tab
, i
)) {
283 qemu_printf("%u%s ", i
,
284 apic_get_bit(tmr_tab
, i
) ? "(level)" : "");
288 qemu_printf("%s\n", empty
? "(none)" : "");
291 void x86_cpu_dump_local_apic_state(CPUState
*cs
, int flags
)
293 X86CPU
*cpu
= X86_CPU(cs
);
294 APICCommonState
*s
= APIC_COMMON(cpu
->apic_state
);
296 qemu_printf("local apic state not available\n");
299 uint32_t *lvt
= s
->lvt
;
301 qemu_printf("dumping local APIC state for CPU %-2u\n\n",
302 CPU(cpu
)->cpu_index
);
303 dump_apic_lvt("LVT0", lvt
[APIC_LVT_LINT0
], false);
304 dump_apic_lvt("LVT1", lvt
[APIC_LVT_LINT1
], false);
305 dump_apic_lvt("LVTPC", lvt
[APIC_LVT_PERFORM
], false);
306 dump_apic_lvt("LVTERR", lvt
[APIC_LVT_ERROR
], false);
307 dump_apic_lvt("LVTTHMR", lvt
[APIC_LVT_THERMAL
], false);
308 dump_apic_lvt("LVTT", lvt
[APIC_LVT_TIMER
], true);
310 qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u"
311 " current_count = %u\n",
312 s
->divide_conf
& APIC_DCR_MASK
,
313 divider_conf(s
->divide_conf
),
314 s
->initial_count
, apic_get_current_count(s
));
316 qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n",
318 s
->spurious_vec
& APIC_SPURIO_ENABLED
? "enabled" : "disabled",
319 s
->spurious_vec
& APIC_SPURIO_FOCUS
? "on" : "off",
320 s
->spurious_vec
& APIC_VECTOR_MASK
);
322 dump_apic_icr(s
, &cpu
->env
);
324 qemu_printf("ESR\t 0x%08x\n", s
->esr
);
326 dump_apic_interrupt("ISR", s
->isr
, s
->tmr
);
327 dump_apic_interrupt("IRR", s
->irr
, s
->tmr
);
329 qemu_printf("\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x",
330 s
->arb_id
, s
->tpr
, s
->dest_mode
, s
->log_dest
);
331 if (s
->dest_mode
== 0) {
332 qemu_printf("(cluster %u: id %u)",
333 s
->log_dest
>> APIC_LOGDEST_XAPIC_SHIFT
,
334 s
->log_dest
& APIC_LOGDEST_XAPIC_ID
);
336 qemu_printf(" PPR 0x%02x\n", apic_get_ppr(s
));
339 void x86_cpu_dump_local_apic_state(CPUState
*cs
, int flags
)
342 #endif /* !CONFIG_USER_ONLY */
344 #define DUMP_CODE_BYTES_TOTAL 50
345 #define DUMP_CODE_BYTES_BACKWARD 20
347 void x86_cpu_dump_state(CPUState
*cs
, FILE *f
, int flags
)
349 X86CPU
*cpu
= X86_CPU(cs
);
350 CPUX86State
*env
= &cpu
->env
;
353 static const char *seg_name
[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
355 eflags
= cpu_compute_eflags(env
);
357 if (env
->hflags
& HF_CS64_MASK
) {
358 qemu_fprintf(f
, "RAX=%016" PRIx64
" RBX=%016" PRIx64
" RCX=%016" PRIx64
" RDX=%016" PRIx64
"\n"
359 "RSI=%016" PRIx64
" RDI=%016" PRIx64
" RBP=%016" PRIx64
" RSP=%016" PRIx64
"\n"
360 "R8 =%016" PRIx64
" R9 =%016" PRIx64
" R10=%016" PRIx64
" R11=%016" PRIx64
"\n"
361 "R12=%016" PRIx64
" R13=%016" PRIx64
" R14=%016" PRIx64
" R15=%016" PRIx64
"\n"
362 "RIP=%016" PRIx64
" RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
380 eflags
& DF_MASK
? 'D' : '-',
381 eflags
& CC_O
? 'O' : '-',
382 eflags
& CC_S
? 'S' : '-',
383 eflags
& CC_Z
? 'Z' : '-',
384 eflags
& CC_A
? 'A' : '-',
385 eflags
& CC_P
? 'P' : '-',
386 eflags
& CC_C
? 'C' : '-',
387 env
->hflags
& HF_CPL_MASK
,
388 (env
->hflags
>> HF_INHIBIT_IRQ_SHIFT
) & 1,
389 (env
->a20_mask
>> 20) & 1,
390 (env
->hflags
>> HF_SMM_SHIFT
) & 1,
395 qemu_fprintf(f
, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
396 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
397 "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
398 (uint32_t)env
->regs
[R_EAX
],
399 (uint32_t)env
->regs
[R_EBX
],
400 (uint32_t)env
->regs
[R_ECX
],
401 (uint32_t)env
->regs
[R_EDX
],
402 (uint32_t)env
->regs
[R_ESI
],
403 (uint32_t)env
->regs
[R_EDI
],
404 (uint32_t)env
->regs
[R_EBP
],
405 (uint32_t)env
->regs
[R_ESP
],
406 (uint32_t)env
->eip
, eflags
,
407 eflags
& DF_MASK
? 'D' : '-',
408 eflags
& CC_O
? 'O' : '-',
409 eflags
& CC_S
? 'S' : '-',
410 eflags
& CC_Z
? 'Z' : '-',
411 eflags
& CC_A
? 'A' : '-',
412 eflags
& CC_P
? 'P' : '-',
413 eflags
& CC_C
? 'C' : '-',
414 env
->hflags
& HF_CPL_MASK
,
415 (env
->hflags
>> HF_INHIBIT_IRQ_SHIFT
) & 1,
416 (env
->a20_mask
>> 20) & 1,
417 (env
->hflags
>> HF_SMM_SHIFT
) & 1,
421 for(i
= 0; i
< 6; i
++) {
422 cpu_x86_dump_seg_cache(env
, f
, seg_name
[i
], &env
->segs
[i
]);
424 cpu_x86_dump_seg_cache(env
, f
, "LDT", &env
->ldt
);
425 cpu_x86_dump_seg_cache(env
, f
, "TR", &env
->tr
);
428 if (env
->hflags
& HF_LMA_MASK
) {
429 qemu_fprintf(f
, "GDT= %016" PRIx64
" %08x\n",
430 env
->gdt
.base
, env
->gdt
.limit
);
431 qemu_fprintf(f
, "IDT= %016" PRIx64
" %08x\n",
432 env
->idt
.base
, env
->idt
.limit
);
433 qemu_fprintf(f
, "CR0=%08x CR2=%016" PRIx64
" CR3=%016" PRIx64
" CR4=%08x\n",
434 (uint32_t)env
->cr
[0],
437 (uint32_t)env
->cr
[4]);
438 for(i
= 0; i
< 4; i
++)
439 qemu_fprintf(f
, "DR%d=%016" PRIx64
" ", i
, env
->dr
[i
]);
440 qemu_fprintf(f
, "\nDR6=%016" PRIx64
" DR7=%016" PRIx64
"\n",
441 env
->dr
[6], env
->dr
[7]);
445 qemu_fprintf(f
, "GDT= %08x %08x\n",
446 (uint32_t)env
->gdt
.base
, env
->gdt
.limit
);
447 qemu_fprintf(f
, "IDT= %08x %08x\n",
448 (uint32_t)env
->idt
.base
, env
->idt
.limit
);
449 qemu_fprintf(f
, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
450 (uint32_t)env
->cr
[0],
451 (uint32_t)env
->cr
[2],
452 (uint32_t)env
->cr
[3],
453 (uint32_t)env
->cr
[4]);
454 for(i
= 0; i
< 4; i
++) {
455 qemu_fprintf(f
, "DR%d=" TARGET_FMT_lx
" ", i
, env
->dr
[i
]);
457 qemu_fprintf(f
, "\nDR6=" TARGET_FMT_lx
" DR7=" TARGET_FMT_lx
"\n",
458 env
->dr
[6], env
->dr
[7]);
460 if (flags
& CPU_DUMP_CCOP
) {
461 if ((unsigned)env
->cc_op
< CC_OP_NB
)
462 snprintf(cc_op_name
, sizeof(cc_op_name
), "%s", cc_op_str
[env
->cc_op
]);
464 snprintf(cc_op_name
, sizeof(cc_op_name
), "[%d]", env
->cc_op
);
466 if (env
->hflags
& HF_CS64_MASK
) {
467 qemu_fprintf(f
, "CCS=%016" PRIx64
" CCD=%016" PRIx64
" CCO=%s\n",
468 env
->cc_src
, env
->cc_dst
,
473 qemu_fprintf(f
, "CCS=%08x CCD=%08x CCO=%s\n",
474 (uint32_t)env
->cc_src
, (uint32_t)env
->cc_dst
,
478 qemu_fprintf(f
, "EFER=%016" PRIx64
"\n", env
->efer
);
479 if (flags
& CPU_DUMP_FPU
) {
481 const uint64_t avx512_mask
= XSTATE_OPMASK_MASK
| \
482 XSTATE_ZMM_Hi256_MASK
| \
483 XSTATE_Hi16_ZMM_MASK
| \
484 XSTATE_YMM_MASK
| XSTATE_SSE_MASK
,
485 avx_mask
= XSTATE_YMM_MASK
| XSTATE_SSE_MASK
;
487 for(i
= 0; i
< 8; i
++) {
488 fptag
|= ((!env
->fptags
[i
]) << i
);
490 update_mxcsr_from_sse_status(env
);
491 qemu_fprintf(f
, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
493 (env
->fpus
& ~0x3800) | (env
->fpstt
& 0x7) << 11,
499 u
.d
= env
->fpregs
[i
].d
;
500 qemu_fprintf(f
, "FPR%d=%016" PRIx64
" %04x",
501 i
, u
.l
.lower
, u
.l
.upper
);
503 qemu_fprintf(f
, "\n");
505 qemu_fprintf(f
, " ");
508 if ((env
->xcr0
& avx512_mask
) == avx512_mask
) {
509 /* XSAVE enabled AVX512 */
510 for (i
= 0; i
< NB_OPMASK_REGS
; i
++) {
511 qemu_fprintf(f
, "Opmask%02d=%016"PRIx64
"%s", i
,
512 env
->opmask_regs
[i
], ((i
& 3) == 3) ? "\n" : " ");
515 nb
= (env
->hflags
& HF_CS64_MASK
) ? 32 : 8;
516 for (i
= 0; i
< nb
; i
++) {
517 qemu_fprintf(f
, "ZMM%02d=%016"PRIx64
" %016"PRIx64
" %016"PRIx64
518 " %016"PRIx64
" %016"PRIx64
" %016"PRIx64
519 " %016"PRIx64
" %016"PRIx64
"\n",
521 env
->xmm_regs
[i
].ZMM_Q(7),
522 env
->xmm_regs
[i
].ZMM_Q(6),
523 env
->xmm_regs
[i
].ZMM_Q(5),
524 env
->xmm_regs
[i
].ZMM_Q(4),
525 env
->xmm_regs
[i
].ZMM_Q(3),
526 env
->xmm_regs
[i
].ZMM_Q(2),
527 env
->xmm_regs
[i
].ZMM_Q(1),
528 env
->xmm_regs
[i
].ZMM_Q(0));
530 } else if ((env
->xcr0
& avx_mask
) == avx_mask
) {
531 /* XSAVE enabled AVX */
532 nb
= env
->hflags
& HF_CS64_MASK
? 16 : 8;
533 for (i
= 0; i
< nb
; i
++) {
534 qemu_fprintf(f
, "YMM%02d=%016"PRIx64
" %016"PRIx64
" %016"PRIx64
535 " %016"PRIx64
"\n", i
,
536 env
->xmm_regs
[i
].ZMM_Q(3),
537 env
->xmm_regs
[i
].ZMM_Q(2),
538 env
->xmm_regs
[i
].ZMM_Q(1),
539 env
->xmm_regs
[i
].ZMM_Q(0));
541 } else { /* SSE and below cases */
542 nb
= env
->hflags
& HF_CS64_MASK
? 16 : 8;
543 for (i
= 0; i
< nb
; i
++) {
544 qemu_fprintf(f
, "XMM%02d=%016"PRIx64
" %016"PRIx64
"%s",
546 env
->xmm_regs
[i
].ZMM_Q(1),
547 env
->xmm_regs
[i
].ZMM_Q(0),
548 (i
& 1) ? "\n" : " ");
552 if (flags
& CPU_DUMP_CODE
) {
553 target_ulong base
= env
->segs
[R_CS
].base
+ env
->eip
;
554 target_ulong offs
= MIN(env
->eip
, DUMP_CODE_BYTES_BACKWARD
);
558 qemu_fprintf(f
, "Code=");
559 for (i
= 0; i
< DUMP_CODE_BYTES_TOTAL
; i
++) {
560 if (cpu_memory_rw_debug(cs
, base
- offs
+ i
, &code
, 1, 0) == 0) {
561 snprintf(codestr
, sizeof(codestr
), "%02x", code
);
563 snprintf(codestr
, sizeof(codestr
), "??");
565 qemu_fprintf(f
, "%s%s%s%s", i
> 0 ? " " : "",
566 i
== offs
? "<" : "", codestr
, i
== offs
? ">" : "");
568 qemu_fprintf(f
, "\n");