3 * Register dumping and other diagnostic tools for assembler code
5 * (c) 2016 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
37 #include <mLib/bits.h>
38 #include <mLib/macros.h>
43 /*----- Low-level printing ------------------------------------------------*/
45 /* Currently these are good for all of our targets. */
47 #define TY_HEX_8 uint8
48 #define P_HEX_8 "0x%02x"
49 #define TY_UNSGN_8 uint8
50 #define P_UNSGN_8 "%3u"
51 #define PV_CHR_8 " `%c'"
52 #define PV_HEX_8 " %02x"
53 #define PV_UNSGN_8 "%4u"
56 #define TY_HEX_16 uint16
57 #define P_HEX_16 "0x%04x"
58 #define TY_UNSGN_16 uint16
59 #define P_UNSGN_16 "%5u"
60 #define TY_SGN_16 int16
61 #define P_SGN_16 "%6d"
62 #define PV_HEX_16 " 0x%04x"
63 #define PV_UNSGN_16 "%9u"
64 #define PV_SGN_16 "%9d"
67 #define TY_HEX_32 uint32
68 #define P_HEX_32 "0x%08x"
69 #define TY_UNSGN_32 uint32
70 #define P_UNSGN_32 "%10u"
71 #define TY_SGN_32 int32
72 #define P_SGN_32 "%11d"
73 #define TY_FLT_32 float
74 #define P_FLT_32 "%15.9g"
75 #define PV_HEX_32 " 0x%08x"
76 #define PV_UNSGN_32 "%19u"
77 #define PV_SGN_32 "%19d"
78 #define PV_FLT_32 "%19.9g"
80 #if ULONG_MAX >> 31 > 0xffffffff
86 #define TY_HEX_64 uint64
87 #define P_HEX_64 "0x%016"PL64"x"
88 #define TY_UNSGN_64 uint64
89 #define P_UNSGN_64 "%20"PL64"u"
90 #define TY_SGN_64 int64
91 #define P_SGN_64 "%20"PL64"d"
92 #define TY_FLT_64 double
93 #define P_FLT_64 "%24.17g"
94 #define PV_HEX_64 " 0x%016"PL64"x"
95 #define PV_UNSGN_64 "%39"PL64"u"
96 #define PV_SGN_64 "%39"PL64"d"
97 #define PV_FLT_64 "%39.17g"
105 #define TY_FLT_80 long double
106 #define P_FLT_80 "%29.21Lg"
107 #define PV_FLT_80 P_FLT_80
109 #if CPUFAM_X86 || CPUFAM_AMD64
110 # define ARCH_FORMATS(_) \
114 # define ARCH_FORMATS(_)
119 _(64, HEX) _(64, FLT) _(64, UNSGN) _(64, SGN) \
120 _(32, HEX) _(32, FLT) _(32, UNSGN) _(32, SGN) \
121 _(16, HEX) _(16, UNSGN) _(16, SGN) \
122 _(8, HEX) _(8, CHR) _(8, UNSGN)
125 const unsigned char *p
;
127 #define FMTF_VECTOR 1u
130 #define FMTFUNC_STD(w, fmt) \
131 static void dump_##fmt##_##w(struct fmtinfo *fmt) \
133 TY_##fmt##_##w x = *(const TY_##fmt##_##w *)fmt->p; \
135 if (fmt->f&FMTF_VECTOR) printf(PV_##fmt##_##w, x); \
136 else printf(P_##fmt##_##w, x); \
137 fmt->p += STEP_##w; fmt->wd += 8*STEP_##w; \
140 #define FMTFUNC_HEX(w) FMTFUNC_STD(w, HEX)
141 #define FMTFUNC_UNSGN(w) FMTFUNC_STD(w, UNSGN)
142 #define FMTFUNC_SGN(w) FMTFUNC_STD(w, SGN)
143 #define FMTFUNC_FLT(w) FMTFUNC_STD(w, FLT)
144 #define FMTFUNC_CHR(w)
146 static void dump_CHR_8(struct fmtinfo
*fmt
)
148 unsigned char x
= *(const unsigned char *)fmt
->p
;
150 if (x
< 32 || x
> 126) printf("\\x%02x", x
);
151 else printf(" `%c'", x
);
152 fmt
->p
+= 1; fmt
->wd
+= 8;
155 #define FMTFUNC(w, fmt) FMTFUNC_##fmt(w)
159 static const struct fmttab
{
161 void (*fmt
)(struct fmtinfo
*);
163 #define FMTTAB(wd, fmt) { REGF_##fmt | REGF_##wd, dump_##fmt##_##wd },
169 /*----- Common subroutines ------------------------------------------------*/
173 * Arguments: @uint32 f@ = format control word; see @REGF_...@
175 * Returns: The actual width of the operand, in bits.
177 * Use: If the operand is a vector (the @REGF_WDMASK@ field is
178 * nonzero) then return the width it denotes; otherwise, return
179 * the largest width implied by the @REGF_TYMASK@ field.
182 static unsigned regwd(uint32 f
)
184 unsigned wd
= 1 << ((f
®F_WDMASK
) >> REGF_WDSHIFT
);
186 if (wd
> 1) return (wd
);
187 else if (f
®F_80
) return (80);
188 else if (f
®F_64
) return (64);
189 else if (f
®F_32
) return (32);
190 else if (f
®F_16
) return (16);
191 else if (f
®F_8
) return (8);
192 else { assert(0); return (1); }
195 /* --- @regname@ --- *
197 * Arguments: @char *buf = pointer to output buffer@
198 * @uint32 f@ = format control word; see @REGF_...@
200 * Returns: Pointer to name string.
202 * Use: Return a pointer to the name of the register implied by @f@,
203 * or null if there is no register. Systematic register names
204 * can be built in the provided buffer.
207 static const char *regname(char *buf
, uint32 f
)
209 unsigned wd
= regwd(f
);
210 unsigned src
= f
®F_SRCMASK
;
211 unsigned ix
= (f
®F_IXMASK
) >> REGF_IXSHIFT
;
220 #if CPUFAM_X86 || CPUFAM_AMD64
222 if (ix
== REGIX_FLAGS
) {
223 if (wd
== 64) *p
++ = 'r';
224 else if (wd
== 32) *p
++ = 'e';
225 else if (wd
!= 16) assert(0);
226 p
+= sprintf(p
, "flags");
228 } else if (REGIX_R8
<= ix
&& ix
<= REGIX_R15
) {
229 p
+= sprintf(p
, "r%u", ix
- REGIX_R8
+ 8);
232 case 32: *p
++ = 'd'; break;
233 case 16: *p
++ = 'w'; break;
234 case 8: *p
++ = 'l'; break;
239 if (wd
== 64) *p
++ = 'r';
240 else if (wd
== 32) *p
++ = 'e';
242 case REGIX_IP
: *p
++ = 'i'; *p
++ = 'p'; goto longreg
;
243 case REGIX_AX
: *p
++ = 'a'; goto shortreg
;
244 case REGIX_BX
: *p
++ = 'b'; goto shortreg
;
245 case REGIX_CX
: *p
++ = 'c'; goto shortreg
;
246 case REGIX_DX
: *p
++ = 'd'; goto shortreg
;
247 case REGIX_SI
: *p
++ = 's'; *p
++ = 'i'; goto longreg
;
248 case REGIX_DI
: *p
++ = 'd'; *p
++ = 'i'; goto longreg
;
249 case REGIX_BP
: *p
++ = 'b'; *p
++ = 'p'; goto longreg
;
250 case REGIX_SP
: *p
++ = 's'; *p
++ = 'p'; goto longreg
;
258 case 16: *p
++ = 'x'; break;
259 case 8: *p
++ = 'l'; break;
268 case 8: *p
++ = 'l'; break;
279 case REGIX_CS
: sprintf(buf
, "cs"); break;
280 case REGIX_DS
: sprintf(buf
, "ds"); break;
281 case REGIX_SS
: sprintf(buf
, "ss"); break;
282 case REGIX_ES
: sprintf(buf
, "es"); break;
283 case REGIX_FS
: sprintf(buf
, "fs"); break;
284 case REGIX_GS
: sprintf(buf
, "gs"); break;
290 if (ix
== REGIX_FPFLAGS
) return (0);
291 if (f
®F_80
) sprintf(buf
, "st(%u)", ix
);
292 else sprintf(buf
, "mm%u", ix
);
296 if (ix
== REGIX_FPFLAGS
) return (0);
298 case 32: case 64: case 128: sprintf(buf
, "xmm%u", ix
); break;
299 case 256: sprintf(buf
, "ymm%u", ix
); break;
307 if (ix
== REGIX_CPSR
) sprintf(buf
, "cpsr");
308 else if (ix
== 15) sprintf(buf
, "pc");
309 else sprintf(buf
, "r%u", ix
);
312 if (ix
== REGIX_FPSCR
) sprintf(buf
, "fpscr");
315 case 32: *p
++ = 's'; break;
316 case 64: *p
++ = 'd'; break;
317 case 128: *p
++ = 'q'; break;
320 p
+= sprintf(p
, "%u", ix
);
328 if (ix
== REGIX_PC
) sprintf(buf
, "pc");
329 else if (ix
== REGIX_NZCV
) sprintf(buf
, "nzcv");
330 else if (ix
== 31 && wd
== 64) sprintf(buf
, "sp");
333 case 32: *p
++ = 'w'; break;
334 case 64: *p
++ = 'x'; break;
337 p
+= sprintf(p
, "%u", ix
);
342 if (ix
== REGIX_FPFLAGS
) sprintf(buf
, "fpflags");
347 case 8: *p
++ = 'b'; break;
348 case 16: *p
++ = 'h'; break;
349 case 32: *p
++ = 's'; break;
350 case 64: *p
++ = 'd'; break;
353 p
+= sprintf(p
, "%u", ix
);
365 /*----- x86 and AMD64 -----------------------------------------------------*/
367 #if CPUFAM_X86 || CPUFAM_AMD64
370 # define P_HEX_GP "0x%08x"
371 # define GP(gp) (gp).u32
374 # define P_HEX_GP "0x%016"PL64"x"
375 # define GP(gp) (gp).u64
378 void regdump_init(void) { ; }
380 static void dump_flags(const char *lbl
, const char *reg
, gpreg f
)
383 if (lbl
) printf("%s: ", lbl
);
384 if (reg
) printf("%s = ", reg
);
385 printf(""P_HEX_GP
"\n", GP(f
));
386 printf(";;\t\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
387 (GP(f
) >> 0)&1u ?
'+' : '-',
388 (GP(f
) >> 2)&1u ?
'+' : '-',
389 (GP(f
) >> 4)&1u ?
'+' : '-',
390 (GP(f
) >> 6)&1u ?
'+' : '-',
391 (GP(f
) >> 7)&1u ?
'+' : '-',
392 (GP(f
) >> 10)&1u ?
'+' : '-',
393 (GP(f
) >> 11)&1u ?
'+' : '-');
394 printf(";;\t\tsystem: %ctf %cif iopl=%d %cnt "
395 "%crf %cvm %cac %cvif %cvip %cid\n",
396 (GP(f
) >> 8)&1u ?
'+' : '-',
397 (GP(f
) >> 9)&1u ?
'+' : '-',
398 (int)((GP(f
) >> 12)&1u),
399 (GP(f
) >> 14)&1u ?
'+' : '-',
400 (GP(f
) >> 16)&1u ?
'+' : '-',
401 (GP(f
) >> 17)&1u ?
'+' : '-',
402 (GP(f
) >> 18)&1u ?
'+' : '-',
403 (GP(f
) >> 19)&1u ?
'+' : '-',
404 (GP(f
) >> 20)&1u ?
'+' : '-',
405 (GP(f
) >> 21)&1u ?
'+' : '-');
409 *pcmap
[] = { "sgl", "???", "dbl", "ext" },
410 *rcmap
[] = { "nr", "-∞", "+∞", "0" };
412 static void dump_fpflags(const char *lbl
, const struct fxsave
*fx
)
414 unsigned top
= (fx
->fsw
>> 11)&7u;
415 unsigned tag
= fx
->ftw
;
416 int skip
= lbl ?
strlen(lbl
) + 2 : 0;
419 if (lbl
) printf("%s: ", lbl
);
421 printf(" fcw = 0x%04x: "
422 "%cim %cdm %czm %com %cum %cpm pc=%s rc=%s %cx\n",
424 (fx
->fcw
>> 0)&1u ?
'+' : '-',
425 (fx
->fcw
>> 1)&1u ?
'+' : '-',
426 (fx
->fcw
>> 2)&1u ?
'+' : '-',
427 (fx
->fcw
>> 3)&1u ?
'+' : '-',
428 (fx
->fcw
>> 4)&1u ?
'+' : '-',
429 (fx
->fcw
>> 5)&1u ?
'+' : '-',
430 pcmap
[(fx
->fcw
>> 8)&3u],
431 rcmap
[(fx
->fcw
>> 10)&3u],
432 (fx
->fcw
>> 12)&1u ?
'+' : '-');
433 printf(";; %*s fsw = 0x%04x: "
434 "%cie %cde %cze %coe %cue %cpe %csf %ces %cc0 %cc1 %cc2 %cc3 "
438 (fx
->fsw
>> 0)&1u ?
'+' : '-',
439 (fx
->fsw
>> 1)&1u ?
'+' : '-',
440 (fx
->fsw
>> 2)&1u ?
'+' : '-',
441 (fx
->fsw
>> 3)&1u ?
'+' : '-',
442 (fx
->fsw
>> 4)&1u ?
'+' : '-',
443 (fx
->fsw
>> 5)&1u ?
'+' : '-',
444 (fx
->fsw
>> 6)&1u ?
'+' : '-',
445 (fx
->fsw
>> 7)&1u ?
'+' : '-',
446 (fx
->fsw
>> 8)&1u ?
'+' : '-',
447 (fx
->fsw
>> 9)&1u ?
'+' : '-',
448 (fx
->fsw
>> 10)&1u ?
'+' : '-',
449 (fx
->fsw
>> 14)&1u ?
'+' : '-',
451 (fx
->fsw
>> 15)&1u ?
'+' : '-');
452 printf(";; %*s ftw = 0x%02x\n", skip
, "", tag
);
455 static void dump_mxflags(const char *lbl
, const struct fxsave
*fx
)
458 if (lbl
) printf("%s: ", lbl
);
460 printf(" mxcsr = 0x%08x\n"
461 ";;\t\tmask = %cim %cdm %czm %com %cum %cpm\n"
462 ";;\t\t exc = %cie %cde %cze %coe %cue %cpe\n"
463 ";;\t\tmisc = %cdaz %cftz rc=%s\n",
465 (fx
->mxcsr
>> 7)&1u ?
'+' : '-',
466 (fx
->mxcsr
>> 8)&1u ?
'+' : '-',
467 (fx
->mxcsr
>> 9)&1u ?
'+' : '-',
468 (fx
->mxcsr
>> 10)&1u ?
'+' : '-',
469 (fx
->mxcsr
>> 11)&1u ?
'+' : '-',
470 (fx
->mxcsr
>> 12)&1u ?
'+' : '-',
471 (fx
->mxcsr
>> 0)&1u ?
'+' : '-',
472 (fx
->mxcsr
>> 1)&1u ?
'+' : '-',
473 (fx
->mxcsr
>> 2)&1u ?
'+' : '-',
474 (fx
->mxcsr
>> 3)&1u ?
'+' : '-',
475 (fx
->mxcsr
>> 4)&1u ?
'+' : '-',
476 (fx
->mxcsr
>> 5)&1u ?
'+' : '-',
477 (fx
->mxcsr
>> 6)&1u ?
'+' : '-',
478 (fx
->mxcsr
>> 15)&1u ?
'+' : '-',
479 rcmap
[(fx
->mxcsr
>> 13)&3u]);
483 # define REGF_GPWD REGF_32
486 # define REGF_GPWD REGF_64
489 void regdump_gp(const struct regmap
*map
)
493 printf(";; General-purpose registers:\n");
494 for (i
= REGIX_AX
; i
< REGIX_GPLIM
; i
++)
496 REGF_HEX
| REGF_UNSGN
| REGF_SGN
| REGF_GPWD
| REGSRC_GP
| i
);
497 regdump(map
, 0, REGF_HEX
| REGF_GPWD
| REGSRC_GP
| REGIX_IP
);
499 printf(";; Segment registers:\n");
500 for (i
= 0; i
< REGIX_SEGLIM
; i
++)
501 regdump(map
, 0, REGF_HEX
| REGF_16
| REGSRC_SEG
| i
);
503 printf(";; Flags:\n");
504 regdump(map
, 0, REGSRC_GP
| REGF_GPWD
| REGIX_FLAGS
);
507 void regdump_fp(const struct regmap
*map
)
509 unsigned top
= (map
->fx
->fsw
>> 11)&7u;
510 unsigned tag
= map
->fx
->ftw
;
513 printf(";; Floating-point/MMX registers:\n");
514 if (!top
&& tag
== 0xff)
515 for (i
= 0; i
< 8; i
++)
517 REGF_HEX
| REGF_UNSGN
| REGF_SGN
| REGF_CHR
|
518 REGF_32
| REGF_16
| REGF_8
|
519 REGSRC_STMMX
| i
| (6 << REGF_WDSHIFT
));
521 for (i
= 0; i
< 8; i
++)
522 regdump(map
, 0, REGF_FLT
| REGF_80
| REGSRC_STMMX
| i
);
524 printf(";; Floating-point state:\n");
525 dump_fpflags(0, map
->fx
);
528 void regdump_simd(const struct regmap
*map
)
530 unsigned f
= REGF_HEX
| REGF_FLT
| REGF_UNSGN
| REGF_SGN
| REGF_CHR
|
531 REGF_64
| REGF_32
| REGF_16
| REGF_8
|
535 if (map
->avx
) f
|= 8 << REGF_WDSHIFT
;
536 else f
|= 7 << REGF_WDSHIFT
;
538 printf(";; SSE/AVX registers:\n");
539 for (i
= 0; i
< N(map
->fx
->xmm
); i
++)
540 regdump(map
, 0, f
| i
);
542 printf(";; SSE/AVX floating-point state:\n");
543 dump_mxflags(0, map
->fx
);
548 /*----- ARM32 -------------------------------------------------------------*/
552 unsigned regdump__flags
= 0;
554 void regdump_init(void)
556 if (cpu_feature_p(CPUFEAT_ARM_VFP
)) regdump__flags
|= REGF_VFP
;
557 if (cpu_feature_p(CPUFEAT_ARM_D32
)) regdump__flags
|= REGF_D32
;
560 static void dump_flags(const char *lbl
, unsigned f
)
563 *modetab
[] = { "?00", "?01", "?02", "?03", "?04", "?05", "?06", "?07",
564 "?08", "?09", "?10", "?11", "?12", "?13", "?14", "?15",
565 "usr", "fiq", "irq", "svc", "?20", "?21", "mon", "abt",
566 "?24", "?25", "hyp", "und", "?28", "?29", "?30", "sys" },
567 *condtab
[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
568 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
571 if (lbl
) printf("%s: ", lbl
);
572 printf(" cpsr = 0x%08x\n", f
);
573 printf(";;\t\tuser: %cn %cz %cc %cv %cq ge=%c%c%c%c\n",
574 (f
>> 31)&1u ?
'+' : '-',
575 (f
>> 30)&1u ?
'+' : '-',
576 (f
>> 29)&1u ?
'+' : '-',
577 (f
>> 28)&1u ?
'+' : '-',
578 (f
>> 27)&1u ?
'+' : '-',
579 (f
>> 19)&1u ?
'1' : '0',
580 (f
>> 18)&1u ?
'1' : '0',
581 (f
>> 17)&1u ?
'1' : '0',
582 (f
>> 16)&1u ?
'1' : '0');
583 printf(";;\t\tsystem: %cj it=%s:%c%c%c%c %ce %ca %ci %cf %ct m=%s\n",
584 (f
>> 24)&1u ?
'+' : '-',
585 condtab
[(f
>> 12)&15u],
586 (f
>> 11)&1u ?
'1' : '0',
587 (f
>> 10)&1u ?
'1' : '0',
588 (f
>> 26)&1u ?
'1' : '0',
589 (f
>> 25)&1u ?
'1' : '0',
590 (f
>> 9)&1u ?
'+' : '-',
591 (f
>> 8)&1u ?
'+' : '-',
592 (f
>> 7)&1u ?
'+' : '-',
593 (f
>> 6)&1u ?
'+' : '-',
594 (f
>> 5)&1u ?
'+' : '-',
595 modetab
[(f
>> 0)&31u]);
598 static void dump_fpflags(const char *lbl
, unsigned f
)
600 static const char *rcmap
[] = { "nr", "+∞", "-∞", "0" };
603 if (lbl
) printf("%s: ", lbl
);
604 printf(" fpscr = 0x%08x\n", f
);
605 printf(";;\t\tcond: %cn %cz %cc %cv %cqc\n",
606 (f
>> 31)&1u ?
'+' : '-',
607 (f
>> 30)&1u ?
'+' : '-',
608 (f
>> 29)&1u ?
'+' : '-',
609 (f
>> 28)&1u ?
'+' : '-',
610 (f
>> 27)&1u ?
'+' : '-');
611 printf(";;\t\ttrap: %cide %cixe %cufe %cofe %cdze %cioe\n",
612 (f
>> 15)&1u ?
'+' : '-',
613 (f
>> 12)&1u ?
'+' : '-',
614 (f
>> 11)&1u ?
'+' : '-',
615 (f
>> 10)&1u ?
'+' : '-',
616 (f
>> 9)&1u ?
'+' : '-',
617 (f
>> 8)&1u ?
'+' : '-');
618 printf(";;\t\terror: %cide %cixe %cufe %cofe %cdze %cioe\n",
619 (f
>> 7)&1u ?
'+' : '-',
620 (f
>> 4)&1u ?
'+' : '-',
621 (f
>> 3)&1u ?
'+' : '-',
622 (f
>> 2)&1u ?
'+' : '-',
623 (f
>> 1)&1u ?
'+' : '-',
624 (f
>> 0)&1u ?
'+' : '-');
625 printf(";;\t\tcontrol: %cahp %cdn %cfz rm=%s str=%d len=%d\n",
626 (f
>> 26)&1u ?
'+' : '-',
627 (f
>> 25)&1u ?
'+' : '-',
628 (f
>> 24)&1u ?
'+' : '-',
634 void regdump_gp(const struct regmap
*map
)
638 printf(";; General-purpose registers:\n");
639 for (i
= 0; i
< 16; i
++)
641 REGF_HEX
| REGF_UNSGN
| REGF_SGN
| REGF_32
| REGSRC_GP
| i
);
643 printf(";; Flags:\n");
644 regdump(map
, 0, REGSRC_GP
| REGF_32
| REGIX_CPSR
);
647 void regdump_fp(const struct regmap
*map
)
651 if (!(regdump__flags
®F_VFP
)) {
652 printf(";; Floating-point and SIMD not available\n");
656 printf(";; Floating-point/SIMD registers:\n");
657 if (regdump__flags
®F_D32
) n
= 32;
659 for (i
= 0; i
< n
; i
++)
661 REGF_HEX
| REGF_UNSGN
| REGF_SGN
| REGF_FLT
| REGF_CHR
|
662 REGF_64
| REGF_32
| REGF_16
| REGF_8
|
663 REGSRC_FP
| i
| (6 << REGF_WDSHIFT
));
665 printf(";; Floating-point state:\n");
666 dump_fpflags(0, map
->fp
->fpscr
);
669 void regdump_simd(const struct regmap
*map
) { ; }
673 /*----- ARM64 -------------------------------------------------------------*/
677 void regdump_init(void) { ; }
679 static void dump_flags(const char *lbl
, unsigned f
)
682 if (lbl
) printf("%s: ", lbl
);
683 printf(" nzcv = 0x%08x\n", f
);
684 printf(";;\t\tuser: %cn %cz %cc %cv\n",
685 (f
>> 31)&1u ?
'+' : '-',
686 (f
>> 30)&1u ?
'+' : '-',
687 (f
>> 29)&1u ?
'+' : '-',
688 (f
>> 28)&1u ?
'+' : '-');
691 static void dump_fpflags(const char *lbl
, const struct fpsave
*fp
)
693 static const char *rcmap
[] = { "nr", "+∞", "-∞", "0" };
694 int skip
= lbl ?
strlen(lbl
) + 2 : 0;
697 if (lbl
) printf("%s: ", lbl
);
698 printf(" fpsr = 0x%08x\n", fp
->fpsr
);
699 printf(";;\t\tcond: %cn %cz %cc %cv %cqc\n",
700 (fp
->fpsr
>> 31)&1u ?
'+' : '-',
701 (fp
->fpsr
>> 30)&1u ?
'+' : '-',
702 (fp
->fpsr
>> 29)&1u ?
'+' : '-',
703 (fp
->fpsr
>> 28)&1u ?
'+' : '-',
704 (fp
->fpsr
>> 27)&1u ?
'+' : '-');
705 printf(";;\t\terror: %cidc %cixc %cufc %cofc %cdzc %cioc\n",
706 (fp
->fpsr
>> 7)&1u ?
'+' : '-',
707 (fp
->fpsr
>> 4)&1u ?
'+' : '-',
708 (fp
->fpsr
>> 3)&1u ?
'+' : '-',
709 (fp
->fpsr
>> 2)&1u ?
'+' : '-',
710 (fp
->fpsr
>> 1)&1u ?
'+' : '-',
711 (fp
->fpsr
>> 0)&1u ?
'+' : '-');
712 printf(";; %*s fpcr = 0x%08x\n", skip
, "", fp
->fpcr
);
713 printf(";;\t\ttrap: %cide %cixe %cufe %cofe %cdze %cioe\n",
714 (fp
->fpcr
>> 15)&1u ?
'+' : '-',
715 (fp
->fpcr
>> 12)&1u ?
'+' : '-',
716 (fp
->fpcr
>> 11)&1u ?
'+' : '-',
717 (fp
->fpcr
>> 10)&1u ?
'+' : '-',
718 (fp
->fpcr
>> 9)&1u ?
'+' : '-',
719 (fp
->fpcr
>> 8)&1u ?
'+' : '-');
720 printf(";;\t\tcontrol: %cahp %cdn %cfz rm=%s str=%d len=%d\n",
721 (fp
->fpcr
>> 26)&1u ?
'+' : '-',
722 (fp
->fpcr
>> 25)&1u ?
'+' : '-',
723 (fp
->fpcr
>> 24)&1u ?
'+' : '-',
724 rcmap
[(fp
->fpcr
>> 22)&3u],
726 (fp
->fpcr
>> 16)&7u);
729 void regdump_gp(const struct regmap
*map
)
733 printf(";; General-purpose registers:\n");
734 for (i
= 0; i
< 32; i
++)
736 REGF_HEX
| REGF_UNSGN
| REGF_SGN
| REGF_64
| REGSRC_GP
| i
);
737 regdump(map
, 0, REGF_HEX
| REGF_64
| REGSRC_GP
| REGIX_PC
);
739 printf(";; Flags:\n");
740 regdump(map
, 0, REGSRC_GP
| REGF_32
| REGIX_NZCV
);
743 void regdump_fp(const struct regmap
*map
)
747 printf(";; Floating-point/SIMD registers:\n");
748 for (i
= 0; i
< 32; i
++)
750 REGF_HEX
| REGF_UNSGN
| REGF_SGN
| REGF_FLT
| REGF_CHR
|
751 REGF_64
| REGF_32
| REGF_16
| REGF_8
|
752 REGSRC_SIMD
| i
| (7 << REGF_WDSHIFT
));
754 printf(";; Floating-point state:\n");
755 dump_fpflags(0, map
->fp
);
758 void regdump_simd(const struct regmap
*map
) { ; }
762 /*----- The main entry point ----------------------------------------------*/
764 /* --- @regdump@ --- *
766 * Arguments: @const void *base@ = pointer to base structure, corresponding
767 * to the @REGF_SRCMASK@ part of @f@
768 * @const char *lbl@ = label to print
769 * @uint32 f@ = format control word; see @REGF_...@
773 * Use: Dump a register value, or chunk of memory.
775 * This function is not usually called directly; instead, use
776 * the `reg' or `mem' assembler macros.
779 void regdump(const void *base
, const char *lbl
, uint32 f
)
781 unsigned ix
= (f
®F_IXMASK
) >> REGF_IXSHIFT
;
782 unsigned wd
= 1 << ((f
®F_WDMASK
) >> REGF_WDSHIFT
);
784 uint32 fmtbit
, tybit
;
786 char regbuf
[8]; const char *reg
= regname(regbuf
, f
);
787 const struct regmap
*map
;
788 const struct fmttab
*tab
;
794 #if CPUFAM_X86 || CPUFAM_AMD64
801 memmove(regbuf
+ 7 - n
, reg
, n
+ 1);
802 memset(regbuf
, ' ', 7 - n
);
806 switch (f
®F_SRCMASK
) {
809 printf(";; %s\n", lbl
);
816 #if CPUFAM_X86 || CPUFAM_AMD64
818 map
= (const struct regmap
*)base
;
819 if (ix
== REGIX_FLAGS
&& !(f
®F_FMTMASK
))
820 { dump_flags(lbl
, reg
, map
->gp
->gp
[REGIX_FLAGS
]); return; }
821 p
= &map
->gp
->gp
[ix
];
824 map
= (const struct regmap
*)base
;
825 assert(wd
== 1); assert((f
®F_TYMASK
) == REGF_16
);
826 p
= &map
->gp
->seg
[ix
];
829 map
= (const struct regmap
*)base
;
830 if (ix
== REGIX_FPFLAGS
)
831 { assert(!(f
®F_FMTMASK
)); dump_fpflags(lbl
, map
->fx
); return; }
832 if (!((map
->fx
->ftw
<< ix
)&128u)) {
834 if (lbl
) printf("%s: ", lbl
);
835 if (reg
) printf("%s = ", reg
);
839 p
= &map
->fx
->stmmx
[ix
];
842 map
= (const struct regmap
*)base
;
843 if (ix
== REGIX_FPFLAGS
)
844 { assert(!(f
®F_FMTMASK
)); dump_mxflags(lbl
, map
->fx
); return; }
846 p
= &map
->fx
->xmm
[ix
];
848 vr
.v128
[0] = map
->fx
->xmm
[ix
];
849 vr
.v128
[1] = map
->avx
->ymmh
[ix
];
858 map
= (const struct regmap
*)base
;
859 if (ix
== REGIX_CPSR
&& !(f
®F_FMTMASK
))
860 { dump_flags(lbl
, map
->gp
->r
[REGIX_CPSR
].u32
); return; }
865 map
= (const struct regmap
*)base
;
868 if (lbl
) printf(" %s:", lbl
);
869 if (reg
) printf(" %s =", reg
);
870 printf(" #<not available -- regdump_init?>\n");
873 if (ix
== REGIX_FPSCR
) {
874 assert(!(f
®F_FMTMASK
));
875 dump_fpflags(lbl
, map
->fp
->fpscr
);
879 case 32: p
= &map
->fp
->u
.s
[ix
]; break;
880 case 64: p
= &map
->fp
->u
.d
[ix
]; break;
881 case 128: p
= &map
->fp
->u
.q
[ix
]; break;
889 map
= (const struct regmap
*)base
;
890 if (ix
== REGIX_NZCV
&& !(f
®F_FMTMASK
))
891 { dump_flags(lbl
, map
->gp
->r
[REGIX_NZCV
].u64
); return; }
896 map
= (const struct regmap
*)base
;
897 if (ix
== REGIX_FPFLAGS
)
898 { assert(!(f
®F_FMTMASK
)); dump_fpflags(lbl
, map
->fp
); return; }
907 skip
= (lbl ?
strlen(lbl
) + 2 : 0) + (reg ?
strlen(reg
) : 0);
908 fi
.f
= 0; if (wd
> 1) fi
.f
|= FMTF_VECTOR
;
910 for (ty
= (f
®F_TYMASK
) >> REGF_TYSHIFT
,
911 tybit
= 1 << REGF_TYSHIFT
;
913 ty
>>= 1, tybit
<<= 1) {
914 if (!(ty
&1u)) continue;
916 for (fmt
= (f
®F_FMTMASK
) >> REGF_FMTSHIFT
,
917 fmtbit
= 1 << REGF_FMTSHIFT
;
919 fmt
>>= 1, fmtbit
<<= 1) {
921 if (!(fmt
&1u)) continue;
923 for (tab
= fmttab
; tab
->mask
; tab
++)
924 if (tab
->mask
== (fmtbit
| tybit
)) goto found
;
930 if (lbl
) printf(" %s:", lbl
);
931 if (reg
) printf(" %s =", reg
);
934 printf("\n;; %*s =", skip
, "");
939 while (fi
.wd
< wd
) { putchar(' '); tab
->fmt(&fi
); }
945 /*----- Other random utilities --------------------------------------------*/
947 /* --- @regdump_freshline@ --- *
953 * Use: Begin a fresh line of output.
956 void regdump_freshline(void) { putchar('\n'); }
958 /*----- That's all, folks -------------------------------------------------*/