xref: /openbmc/qemu/target/i386/cpu-dump.c (revision e36b976d)
1 /*
2  *  i386 CPU dump to FILE
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "qemu/qemu-print.h"
23 #ifndef CONFIG_USER_ONLY
24 #include "hw/i386/apic_internal.h"
25 #endif
26 
27 /***********************************************************/
28 /* x86 debug */
29 
30 static const char *cc_op_str[CC_OP_NB] = {
31     [CC_OP_DYNAMIC] = "DYNAMIC",
32 
33     [CC_OP_EFLAGS] = "EFLAGS",
34     [CC_OP_ADCX] = "ADCX",
35     [CC_OP_ADOX] = "ADOX",
36     [CC_OP_ADCOX] = "ADCOX",
37 
38     [CC_OP_MULB] = "MULB",
39     [CC_OP_MULW] = "MULW",
40     [CC_OP_MULL] = "MULL",
41     [CC_OP_MULQ] = "MULQ",
42 
43     [CC_OP_ADDB] = "ADDB",
44     [CC_OP_ADDW] = "ADDW",
45     [CC_OP_ADDL] = "ADDL",
46     [CC_OP_ADDQ] = "ADDQ",
47 
48     [CC_OP_ADCB] = "ADCB",
49     [CC_OP_ADCW] = "ADCW",
50     [CC_OP_ADCL] = "ADCL",
51     [CC_OP_ADCQ] = "ADCQ",
52 
53     [CC_OP_SUBB] = "SUBB",
54     [CC_OP_SUBW] = "SUBW",
55     [CC_OP_SUBL] = "SUBL",
56     [CC_OP_SUBQ] = "SUBQ",
57 
58     [CC_OP_SBBB] = "SBBB",
59     [CC_OP_SBBW] = "SBBW",
60     [CC_OP_SBBL] = "SBBL",
61     [CC_OP_SBBQ] = "SBBQ",
62 
63     [CC_OP_LOGICB] = "LOGICB",
64     [CC_OP_LOGICW] = "LOGICW",
65     [CC_OP_LOGICL] = "LOGICL",
66     [CC_OP_LOGICQ] = "LOGICQ",
67 
68     [CC_OP_INCB] = "INCB",
69     [CC_OP_INCW] = "INCW",
70     [CC_OP_INCL] = "INCL",
71     [CC_OP_INCQ] = "INCQ",
72 
73     [CC_OP_DECB] = "DECB",
74     [CC_OP_DECW] = "DECW",
75     [CC_OP_DECL] = "DECL",
76     [CC_OP_DECQ] = "DECQ",
77 
78     [CC_OP_SHLB] = "SHLB",
79     [CC_OP_SHLW] = "SHLW",
80     [CC_OP_SHLL] = "SHLL",
81     [CC_OP_SHLQ] = "SHLQ",
82 
83     [CC_OP_SARB] = "SARB",
84     [CC_OP_SARW] = "SARW",
85     [CC_OP_SARL] = "SARL",
86     [CC_OP_SARQ] = "SARQ",
87 
88     [CC_OP_BMILGB] = "BMILGB",
89     [CC_OP_BMILGW] = "BMILGW",
90     [CC_OP_BMILGL] = "BMILGL",
91     [CC_OP_BMILGQ] = "BMILGQ",
92 
93     [CC_OP_POPCNT] = "POPCNT",
94     [CC_OP_CLR] = "CLR",
95 };
96 
97 static void
cpu_x86_dump_seg_cache(CPUX86State * env,FILE * f,const char * name,struct SegmentCache * sc)98 cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f,
99                        const char *name, struct SegmentCache *sc)
100 {
101 #ifdef TARGET_X86_64
102     if (env->hflags & HF_CS64_MASK) {
103         qemu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
104                      sc->selector, sc->base, sc->limit,
105                      sc->flags & 0x00ffff00);
106     } else
107 #endif
108     {
109         qemu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
110                      (uint32_t)sc->base, sc->limit,
111                      sc->flags & 0x00ffff00);
112     }
113 
114     if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
115         goto done;
116 
117     qemu_fprintf(f, " DPL=%d ",
118                  (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT);
119     if (sc->flags & DESC_S_MASK) {
120         if (sc->flags & DESC_CS_MASK) {
121             qemu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" :
122                          ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16"));
123             qemu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
124                          (sc->flags & DESC_R_MASK) ? 'R' : '-');
125         } else {
126             qemu_fprintf(f, (sc->flags & DESC_B_MASK
127                              || env->hflags & HF_LMA_MASK)
128                          ? "DS  " : "DS16");
129             qemu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
130                          (sc->flags & DESC_W_MASK) ? 'W' : '-');
131         }
132         qemu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-');
133     } else {
134         static const char *sys_type_name[2][16] = {
135             { /* 32 bit mode */
136                 "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
137                 "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
138                 "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
139                 "CallGate32", "Reserved", "IntGate32", "TrapGate32"
140             },
141             { /* 64 bit mode */
142                 "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
143                 "Reserved", "Reserved", "Reserved", "Reserved",
144                 "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
145                 "Reserved", "IntGate64", "TrapGate64"
146             }
147         };
148         qemu_fprintf(f, "%s",
149                      sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0]
150                      [(sc->flags & DESC_TYPE_MASK) >> DESC_TYPE_SHIFT]);
151     }
152 done:
153     qemu_fprintf(f, "\n");
154 }
155 
156 #ifndef CONFIG_USER_ONLY
157 
158 /* ARRAY_SIZE check is not required because
159  * DeliveryMode(dm) has a size of 3 bit.
160  */
dm2str(uint32_t dm)161 static inline const char *dm2str(uint32_t dm)
162 {
163     static const char *str[] = {
164         "Fixed",
165         "...",
166         "SMI",
167         "...",
168         "NMI",
169         "INIT",
170         "...",
171         "ExtINT"
172     };
173     return str[dm];
174 }
175 
dump_apic_lvt(const char * name,uint32_t lvt,bool is_timer)176 static void dump_apic_lvt(const char *name, uint32_t lvt, bool is_timer)
177 {
178     uint32_t dm = (lvt & APIC_LVT_DELIV_MOD) >> APIC_LVT_DELIV_MOD_SHIFT;
179     qemu_printf("%s\t 0x%08x %s %-5s %-6s %-7s %-12s %-6s",
180                 name, lvt,
181                 lvt & APIC_LVT_INT_POLARITY ? "active-lo" : "active-hi",
182                 lvt & APIC_LVT_LEVEL_TRIGGER ? "level" : "edge",
183                 lvt & APIC_LVT_MASKED ? "masked" : "",
184                 lvt & APIC_LVT_DELIV_STS ? "pending" : "",
185                 !is_timer ?
186                     "" : lvt & APIC_LVT_TIMER_PERIODIC ?
187                             "periodic" : lvt & APIC_LVT_TIMER_TSCDEADLINE ?
188                                             "tsc-deadline" : "one-shot",
189                 dm2str(dm));
190     if (dm != APIC_DM_NMI) {
191         qemu_printf(" (vec %u)\n", lvt & APIC_VECTOR_MASK);
192     } else {
193         qemu_printf("\n");
194     }
195 }
196 
197 /* ARRAY_SIZE check is not required because
198  * destination shorthand has a size of 2 bit.
199  */
shorthand2str(uint32_t shorthand)200 static inline const char *shorthand2str(uint32_t shorthand)
201 {
202     const char *str[] = {
203         "no-shorthand", "self", "all-self", "all"
204     };
205     return str[shorthand];
206 }
207 
divider_conf(uint32_t divide_conf)208 static inline uint8_t divider_conf(uint32_t divide_conf)
209 {
210     uint8_t divide_val = ((divide_conf & 0x8) >> 1) | (divide_conf & 0x3);
211 
212     return divide_val == 7 ? 1 : 2 << divide_val;
213 }
214 
mask2str(char * str,uint32_t val,uint8_t size)215 static inline void mask2str(char *str, uint32_t val, uint8_t size)
216 {
217     while (size--) {
218         *str++ = (val >> size) & 1 ? '1' : '0';
219     }
220     *str = 0;
221 }
222 
223 #define MAX_LOGICAL_APIC_ID_MASK_SIZE 16
224 
dump_apic_icr(APICCommonState * s,CPUX86State * env)225 static void dump_apic_icr(APICCommonState *s, CPUX86State *env)
226 {
227     uint32_t icr = s->icr[0], icr2 = s->icr[1];
228     uint8_t dest_shorthand = \
229         (icr & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT;
230     bool logical_mod = icr & APIC_ICR_DEST_MOD;
231     char apic_id_str[MAX_LOGICAL_APIC_ID_MASK_SIZE + 1];
232     uint32_t dest_field;
233     bool x2apic;
234 
235     qemu_printf("ICR\t 0x%08x %s %s %s %s\n",
236                 icr,
237                 logical_mod ? "logical" : "physical",
238                 icr & APIC_ICR_TRIGGER_MOD ? "level" : "edge",
239                 icr & APIC_ICR_LEVEL ? "assert" : "de-assert",
240                 shorthand2str(dest_shorthand));
241 
242     qemu_printf("ICR2\t 0x%08x", icr2);
243     if (dest_shorthand != 0) {
244         qemu_printf("\n");
245         return;
246     }
247     x2apic = env->features[FEAT_1_ECX] & CPUID_EXT_X2APIC;
248     dest_field = x2apic ? icr2 : icr2 >> APIC_ICR_DEST_SHIFT;
249 
250     if (!logical_mod) {
251         if (x2apic) {
252             qemu_printf(" cpu %u (X2APIC ID)\n", dest_field);
253         } else {
254             qemu_printf(" cpu %u (APIC ID)\n",
255                         dest_field & APIC_LOGDEST_XAPIC_ID);
256         }
257         return;
258     }
259 
260     if (s->dest_mode == 0xf) { /* flat mode */
261         mask2str(apic_id_str, icr2 >> APIC_ICR_DEST_SHIFT, 8);
262         qemu_printf(" mask %s (APIC ID)\n", apic_id_str);
263     } else if (s->dest_mode == 0) { /* cluster mode */
264         if (x2apic) {
265             mask2str(apic_id_str, dest_field & APIC_LOGDEST_X2APIC_ID, 16);
266             qemu_printf(" cluster %u mask %s (X2APIC ID)\n",
267                         dest_field >> APIC_LOGDEST_X2APIC_SHIFT, apic_id_str);
268         } else {
269             mask2str(apic_id_str, dest_field & APIC_LOGDEST_XAPIC_ID, 4);
270             qemu_printf(" cluster %u mask %s (APIC ID)\n",
271                         dest_field >> APIC_LOGDEST_XAPIC_SHIFT, apic_id_str);
272         }
273     }
274 }
275 
dump_apic_interrupt(const char * name,uint32_t * ireg_tab,uint32_t * tmr_tab)276 static void dump_apic_interrupt(const char *name, uint32_t *ireg_tab,
277                                 uint32_t *tmr_tab)
278 {
279     int i, empty = true;
280 
281     qemu_printf("%s\t ", name);
282     for (i = 0; i < 256; i++) {
283         if (apic_get_bit(ireg_tab, i)) {
284             qemu_printf("%u%s ", i,
285                         apic_get_bit(tmr_tab, i) ? "(level)" : "");
286             empty = false;
287         }
288     }
289     qemu_printf("%s\n", empty ? "(none)" : "");
290 }
291 
x86_cpu_dump_local_apic_state(CPUState * cs,int flags)292 void x86_cpu_dump_local_apic_state(CPUState *cs, int flags)
293 {
294     X86CPU *cpu = X86_CPU(cs);
295     APICCommonState *s = APIC_COMMON(cpu->apic_state);
296     if (!s) {
297         qemu_printf("local apic state not available\n");
298         return;
299     }
300     uint32_t *lvt = s->lvt;
301 
302     qemu_printf("dumping local APIC state for CPU %-2u\n\n",
303                 CPU(cpu)->cpu_index);
304     dump_apic_lvt("LVT0", lvt[APIC_LVT_LINT0], false);
305     dump_apic_lvt("LVT1", lvt[APIC_LVT_LINT1], false);
306     dump_apic_lvt("LVTPC", lvt[APIC_LVT_PERFORM], false);
307     dump_apic_lvt("LVTERR", lvt[APIC_LVT_ERROR], false);
308     dump_apic_lvt("LVTTHMR", lvt[APIC_LVT_THERMAL], false);
309     dump_apic_lvt("LVTT", lvt[APIC_LVT_TIMER], true);
310 
311     qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u"
312                 " current_count = %u\n",
313                 s->divide_conf & APIC_DCR_MASK,
314                 divider_conf(s->divide_conf),
315                 s->initial_count, apic_get_current_count(s));
316 
317     qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n",
318                 s->spurious_vec,
319                 s->spurious_vec & APIC_SPURIO_ENABLED ? "enabled" : "disabled",
320                 s->spurious_vec & APIC_SPURIO_FOCUS ? "on" : "off",
321                 s->spurious_vec & APIC_VECTOR_MASK);
322 
323     dump_apic_icr(s, &cpu->env);
324 
325     qemu_printf("ESR\t 0x%08x\n", s->esr);
326 
327     dump_apic_interrupt("ISR", s->isr, s->tmr);
328     dump_apic_interrupt("IRR", s->irr, s->tmr);
329 
330     qemu_printf("\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x",
331                 s->arb_id, s->tpr, s->dest_mode, s->log_dest);
332     if (s->dest_mode == 0) {
333         qemu_printf("(cluster %u: id %u)",
334                     s->log_dest >> APIC_LOGDEST_XAPIC_SHIFT,
335                     s->log_dest & APIC_LOGDEST_XAPIC_ID);
336     }
337     qemu_printf(" PPR 0x%02x\n", apic_get_ppr(s));
338 }
339 
340 #endif /* !CONFIG_USER_ONLY */
341 
342 #define DUMP_CODE_BYTES_TOTAL    50
343 #define DUMP_CODE_BYTES_BACKWARD 20
344 
x86_cpu_dump_state(CPUState * cs,FILE * f,int flags)345 void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
346 {
347     X86CPU *cpu = X86_CPU(cs);
348     CPUX86State *env = &cpu->env;
349     int eflags, i, nb;
350     char cc_op_name[32];
351     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
352 
353     eflags = cpu_compute_eflags(env);
354 #ifdef TARGET_X86_64
355     if (env->hflags & HF_CS64_MASK) {
356         qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
357                      "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
358                      "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
359                      "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
360                      "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
361                      env->regs[R_EAX],
362                      env->regs[R_EBX],
363                      env->regs[R_ECX],
364                      env->regs[R_EDX],
365                      env->regs[R_ESI],
366                      env->regs[R_EDI],
367                      env->regs[R_EBP],
368                      env->regs[R_ESP],
369                      env->regs[8],
370                      env->regs[9],
371                      env->regs[10],
372                      env->regs[11],
373                      env->regs[12],
374                      env->regs[13],
375                      env->regs[14],
376                      env->regs[15],
377                      env->eip, eflags,
378                      eflags & DF_MASK ? 'D' : '-',
379                      eflags & CC_O ? 'O' : '-',
380                      eflags & CC_S ? 'S' : '-',
381                      eflags & CC_Z ? 'Z' : '-',
382                      eflags & CC_A ? 'A' : '-',
383                      eflags & CC_P ? 'P' : '-',
384                      eflags & CC_C ? 'C' : '-',
385                      env->hflags & HF_CPL_MASK,
386                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
387                      (env->a20_mask >> 20) & 1,
388                      (env->hflags >> HF_SMM_SHIFT) & 1,
389                      cs->halted);
390     } else
391 #endif
392     {
393         qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
394                      "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
395                      "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
396                      (uint32_t)env->regs[R_EAX],
397                      (uint32_t)env->regs[R_EBX],
398                      (uint32_t)env->regs[R_ECX],
399                      (uint32_t)env->regs[R_EDX],
400                      (uint32_t)env->regs[R_ESI],
401                      (uint32_t)env->regs[R_EDI],
402                      (uint32_t)env->regs[R_EBP],
403                      (uint32_t)env->regs[R_ESP],
404                      (uint32_t)env->eip, eflags,
405                      eflags & DF_MASK ? 'D' : '-',
406                      eflags & CC_O ? 'O' : '-',
407                      eflags & CC_S ? 'S' : '-',
408                      eflags & CC_Z ? 'Z' : '-',
409                      eflags & CC_A ? 'A' : '-',
410                      eflags & CC_P ? 'P' : '-',
411                      eflags & CC_C ? 'C' : '-',
412                      env->hflags & HF_CPL_MASK,
413                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
414                      (env->a20_mask >> 20) & 1,
415                      (env->hflags >> HF_SMM_SHIFT) & 1,
416                      cs->halted);
417     }
418 
419     for(i = 0; i < 6; i++) {
420         cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]);
421     }
422     cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt);
423     cpu_x86_dump_seg_cache(env, f, "TR", &env->tr);
424 
425 #ifdef TARGET_X86_64
426     if (env->hflags & HF_LMA_MASK) {
427         qemu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
428                      env->gdt.base, env->gdt.limit);
429         qemu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
430                      env->idt.base, env->idt.limit);
431         qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
432                      (uint32_t)env->cr[0],
433                      env->cr[2],
434                      env->cr[3],
435                      (uint32_t)env->cr[4]);
436         for(i = 0; i < 4; i++)
437             qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
438         qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
439                      env->dr[6], env->dr[7]);
440     } else
441 #endif
442     {
443         qemu_fprintf(f, "GDT=     %08x %08x\n",
444                      (uint32_t)env->gdt.base, env->gdt.limit);
445         qemu_fprintf(f, "IDT=     %08x %08x\n",
446                      (uint32_t)env->idt.base, env->idt.limit);
447         qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
448                      (uint32_t)env->cr[0],
449                      (uint32_t)env->cr[2],
450                      (uint32_t)env->cr[3],
451                      (uint32_t)env->cr[4]);
452         for(i = 0; i < 4; i++) {
453             qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
454         }
455         qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
456                      env->dr[6], env->dr[7]);
457     }
458     if (flags & CPU_DUMP_CCOP) {
459         if ((unsigned)env->cc_op < CC_OP_NB)
460             snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
461         else
462             snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
463 #ifdef TARGET_X86_64
464         if (env->hflags & HF_CS64_MASK) {
465             qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
466                          env->cc_src, env->cc_dst,
467                          cc_op_name);
468         } else
469 #endif
470         {
471             qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%s\n",
472                          (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
473                          cc_op_name);
474         }
475     }
476     qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
477     if (flags & CPU_DUMP_FPU) {
478         int fptag;
479         const uint64_t avx512_mask = XSTATE_OPMASK_MASK | \
480                                      XSTATE_ZMM_Hi256_MASK | \
481                                      XSTATE_Hi16_ZMM_MASK | \
482                                      XSTATE_YMM_MASK | XSTATE_SSE_MASK,
483                        avx_mask = XSTATE_YMM_MASK | XSTATE_SSE_MASK;
484         fptag = 0;
485         for(i = 0; i < 8; i++) {
486             fptag |= ((!env->fptags[i]) << i);
487         }
488         update_mxcsr_from_sse_status(env);
489         qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
490                      env->fpuc,
491                      (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
492                      env->fpstt,
493                      fptag,
494                      env->mxcsr);
495         for(i=0;i<8;i++) {
496             CPU_LDoubleU u;
497             u.d = env->fpregs[i].d;
498             qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
499                          i, u.l.lower, u.l.upper);
500             if ((i & 1) == 1)
501                 qemu_fprintf(f, "\n");
502             else
503                 qemu_fprintf(f, " ");
504         }
505 
506         if ((env->xcr0 & avx512_mask) == avx512_mask) {
507             /* XSAVE enabled AVX512 */
508             for (i = 0; i < NB_OPMASK_REGS; i++) {
509                 qemu_fprintf(f, "Opmask%02d=%016"PRIx64"%s", i,
510                              env->opmask_regs[i], ((i & 3) == 3) ? "\n" : " ");
511             }
512 
513             nb = (env->hflags & HF_CS64_MASK) ? 32 : 8;
514             for (i = 0; i < nb; i++) {
515                 qemu_fprintf(f, "ZMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
516                              " %016"PRIx64" %016"PRIx64" %016"PRIx64
517                              " %016"PRIx64" %016"PRIx64"\n",
518                              i,
519                              env->xmm_regs[i].ZMM_Q(7),
520                              env->xmm_regs[i].ZMM_Q(6),
521                              env->xmm_regs[i].ZMM_Q(5),
522                              env->xmm_regs[i].ZMM_Q(4),
523                              env->xmm_regs[i].ZMM_Q(3),
524                              env->xmm_regs[i].ZMM_Q(2),
525                              env->xmm_regs[i].ZMM_Q(1),
526                              env->xmm_regs[i].ZMM_Q(0));
527             }
528         } else if ((env->xcr0 & avx_mask)  == avx_mask) {
529             /* XSAVE enabled AVX */
530             nb = env->hflags & HF_CS64_MASK ? 16 : 8;
531             for (i = 0; i < nb; i++) {
532                 qemu_fprintf(f, "YMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
533                              " %016"PRIx64"\n", i,
534                              env->xmm_regs[i].ZMM_Q(3),
535                              env->xmm_regs[i].ZMM_Q(2),
536                              env->xmm_regs[i].ZMM_Q(1),
537                              env->xmm_regs[i].ZMM_Q(0));
538             }
539         } else { /* SSE and below cases */
540             nb = env->hflags & HF_CS64_MASK ? 16 : 8;
541             for (i = 0; i < nb; i++) {
542                 qemu_fprintf(f, "XMM%02d=%016"PRIx64" %016"PRIx64"%s",
543                              i,
544                              env->xmm_regs[i].ZMM_Q(1),
545                              env->xmm_regs[i].ZMM_Q(0),
546                              (i & 1) ? "\n" : " ");
547             }
548         }
549     }
550     if (flags & CPU_DUMP_CODE) {
551         target_ulong base = env->segs[R_CS].base + env->eip;
552         target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
553         uint8_t code;
554         char codestr[3];
555 
556         qemu_fprintf(f, "Code=");
557         for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
558             if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
559                 snprintf(codestr, sizeof(codestr), "%02x", code);
560             } else {
561                 snprintf(codestr, sizeof(codestr), "??");
562             }
563             qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
564                          i == offs ? "<" : "", codestr, i == offs ? ">" : "");
565         }
566         qemu_fprintf(f, "\n");
567     }
568 }
569