progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / base / regdump.c
1 /* -*-c-*-
2 *
3 * Register dumping and other diagnostic tools for assembler code
4 *
5 * (c) 2016 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
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.
16 *
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.
21 *
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,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <limits.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #include <mLib/bits.h>
38 #include <mLib/macros.h>
39
40 #include "dispatch.h"
41 #include "regdump.h"
42
43 /*----- Low-level printing ------------------------------------------------*/
44
45 /* Currently these are good for all of our targets. */
46 #define STEP_8 1
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"
54
55 #define STEP_16 2
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"
65
66 #define STEP_32 4
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"
79
80 #if ULONG_MAX >> 31 > 0xffffffff
81 # define PL64 "l"
82 #else
83 # define PL64 "ll"
84 #endif
85 #define STEP_64 8
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"
98
99 #if CPUFAM_X86
100 # define STEP_80 12
101 #endif
102 #if CPUFAM_AMD64
103 # define STEP_80 16
104 #endif
105 #define TY_FLT_80 long double
106 #define P_FLT_80 "%29.21Lg"
107 #define PV_FLT_80 P_FLT_80
108
109 #if CPUFAM_X86 || CPUFAM_AMD64
110 # define ARCH_FORMATS(_) \
111 _(80, FLT)
112 #endif
113 #ifndef ARCH_FORMATS
114 # define ARCH_FORMATS(_)
115 #endif
116
117 #define FORMATS(_) \
118 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)
123
124 struct fmtinfo {
125 const unsigned char *p;
126 unsigned wd, f;
127 #define FMTF_VECTOR 1u
128 };
129
130 #define FMTFUNC_STD(w, fmt) \
131 static void dump_##fmt##_##w(struct fmtinfo *fmt) \
132 { \
133 TY_##fmt##_##w x = *(const TY_##fmt##_##w *)fmt->p; \
134 \
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; \
138 }
139
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)
145
146 static void dump_CHR_8(struct fmtinfo *fmt)
147 {
148 unsigned char x = *(const unsigned char *)fmt->p;
149
150 if (x < 32 || x > 126) printf("\\x%02x", x);
151 else printf(" `%c'", x);
152 fmt->p += 1; fmt->wd += 8;
153 }
154
155 #define FMTFUNC(w, fmt) FMTFUNC_##fmt(w)
156 FORMATS(FMTFUNC)
157 #undef FMTFUNC
158
159 static const struct fmttab {
160 uint32 mask;
161 void (*fmt)(struct fmtinfo *);
162 } fmttab[] = {
163 #define FMTTAB(wd, fmt) { REGF_##fmt | REGF_##wd, dump_##fmt##_##wd },
164 FORMATS(FMTTAB)
165 #undef FMTTAB
166 { 0, 0 }
167 };
168
169 /*----- Common subroutines ------------------------------------------------*/
170
171 /* --- @regwd@ --- *
172 *
173 * Arguments: @uint32 f@ = format control word; see @REGF_...@
174 *
175 * Returns: The actual width of the operand, in bits.
176 *
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.
180 */
181
182 static unsigned regwd(uint32 f)
183 {
184 unsigned wd = 1 << ((f&REGF_WDMASK) >> REGF_WDSHIFT);
185
186 if (wd > 1) return (wd);
187 else if (f&REGF_80) return (80);
188 else if (f&REGF_64) return (64);
189 else if (f&REGF_32) return (32);
190 else if (f&REGF_16) return (16);
191 else if (f&REGF_8) return (8);
192 else { assert(0); return (1); }
193 }
194
195 /* --- @regname@ --- *
196 *
197 * Arguments: @char *buf = pointer to output buffer@
198 * @uint32 f@ = format control word; see @REGF_...@
199 *
200 * Returns: Pointer to name string.
201 *
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.
205 */
206
207 static const char *regname(char *buf, uint32 f)
208 {
209 unsigned wd = regwd(f);
210 unsigned src = f&REGF_SRCMASK;
211 unsigned ix = (f&REGF_IXMASK) >> REGF_IXSHIFT;
212 char *p = buf;
213
214 switch (src) {
215
216 case REGSRC_NONE:
217 case REGSRC_ABS:
218 return (0);
219
220 #if CPUFAM_X86 || CPUFAM_AMD64
221 case REGSRC_GP:
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");
227 #if CPUFAM_AMD64
228 } else if (REGIX_R8 <= ix && ix <= REGIX_R15) {
229 p += sprintf(p, "r%u", ix - REGIX_R8 + 8);
230 switch (wd) {
231 case 64: break;
232 case 32: *p++ = 'd'; break;
233 case 16: *p++ = 'w'; break;
234 case 8: *p++ = 'l'; break;
235 default: assert(0);
236 }
237 # endif
238 } else {
239 if (wd == 64) *p++ = 'r';
240 else if (wd == 32) *p++ = 'e';
241 switch (ix) {
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;
251 default: assert(0);
252 }
253 if (0) {
254 shortreg:
255 switch (wd) {
256 case 64:
257 case 32:
258 case 16: *p++ = 'x'; break;
259 case 8: *p++ = 'l'; break;
260 default: assert(0);
261 }
262 } else {
263 longreg:
264 switch (wd) {
265 case 64:
266 case 32:
267 case 16: break;
268 case 8: *p++ = 'l'; break;
269 default: assert(0);
270 }
271 }
272 }
273 *p++ = 0;
274 return (buf);
275
276 case REGSRC_SEG:
277 assert(wd == 16);
278 switch (ix) {
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;
285 default: assert(0);
286 }
287 return (buf);
288
289 case REGSRC_STMMX:
290 if (ix == REGIX_FPFLAGS) return (0);
291 if (f&REGF_80) sprintf(buf, "st(%u)", ix);
292 else sprintf(buf, "mm%u", ix);
293 return (buf);
294
295 case REGSRC_SIMD:
296 if (ix == REGIX_FPFLAGS) return (0);
297 switch (wd) {
298 case 32: case 64: case 128: sprintf(buf, "xmm%u", ix); break;
299 case 256: sprintf(buf, "ymm%u", ix); break;
300 default: assert(0);
301 }
302 return (buf);
303 #endif
304
305 #if CPUFAM_ARMEL
306 case REGSRC_GP:
307 if (ix == REGIX_CPSR) sprintf(buf, "cpsr");
308 else if (ix == 15) sprintf(buf, "pc");
309 else sprintf(buf, "r%u", ix);
310 return (buf);
311 case REGSRC_FP:
312 if (ix == REGIX_FPSCR) sprintf(buf, "fpscr");
313 else {
314 switch (wd) {
315 case 32: *p++ = 's'; break;
316 case 64: *p++ = 'd'; break;
317 case 128: *p++ = 'q'; break;
318 default: assert(0);
319 }
320 p += sprintf(p, "%u", ix);
321 *p++ = 0;
322 }
323 return (buf);
324 #endif
325
326 #if CPUFAM_ARM64
327 case REGSRC_GP:
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");
331 else {
332 switch (wd) {
333 case 32: *p++ = 'w'; break;
334 case 64: *p++ = 'x'; break;
335 default: assert(0);
336 }
337 p += sprintf(p, "%u", ix);
338 *p++ = 0;
339 }
340 return (buf);
341 case REGSRC_FP:
342 if (ix == REGIX_FPFLAGS) sprintf(buf, "fpflags");
343 else {
344 if (f&REGF_WDMASK)
345 *p++ = 'v';
346 else switch (wd) {
347 case 8: *p++ = 'b'; break;
348 case 16: *p++ = 'h'; break;
349 case 32: *p++ = 's'; break;
350 case 64: *p++ = 'd'; break;
351 default: assert(0);
352 }
353 p += sprintf(p, "%u", ix);
354 *p++ = 0;
355 }
356 return (buf);
357 #endif
358
359 default:
360 assert(0);
361 return ("???");
362 }
363 }
364
365 /*----- x86 and AMD64 -----------------------------------------------------*/
366
367 #if CPUFAM_X86 || CPUFAM_AMD64
368
369 #if CPUFAM_X86
370 # define P_HEX_GP "0x%08x"
371 # define GP(gp) (gp).u32
372 #endif
373 #if CPUFAM_AMD64
374 # define P_HEX_GP "0x%016"PL64"x"
375 # define GP(gp) (gp).u64
376 #endif
377
378 #define CF (1 << 0)
379 #define PF (1 << 2)
380 #define AF (1 << 4)
381 #define ZF (1 << 6)
382 #define SF (1 << 7)
383 #define DF (1 << 10)
384 #define OF (1 << 11)
385
386 void regdump_init(void) { ; }
387
388 static void dump_flags(const char *lbl, const char *reg, gpreg f)
389 {
390 printf(";; ");
391 if (lbl) printf("%s: ", lbl);
392 if (reg) printf("%s = ", reg);
393 printf(""P_HEX_GP"\n", GP(f));
394 printf(";;\t\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
395 (GP(f) >> 0)&1u ? '+' : '-',
396 (GP(f) >> 2)&1u ? '+' : '-',
397 (GP(f) >> 4)&1u ? '+' : '-',
398 (GP(f) >> 6)&1u ? '+' : '-',
399 (GP(f) >> 7)&1u ? '+' : '-',
400 (GP(f) >> 10)&1u ? '+' : '-',
401 (GP(f) >> 11)&1u ? '+' : '-');
402 printf(";;\t\tcond:");
403 if (GP(f)&CF) printf(" c/b/nae"); else printf(" nc/ae/nb");
404 if (GP(f)&ZF) printf(" e/z"); else printf(" ne/nz");
405 if (GP(f)&SF) printf(" s"); else printf(" ns");
406 if (GP(f)&OF) printf(" o"); else printf(" no");
407 if (GP(f)&PF) printf(" p"); else printf(" np");
408 if ((GP(f)&CF) || (GP(f)&ZF)) printf(" be/na"); else printf(" a/nbe");
409 if (!(GP(f)&OF) == !(GP(f)&SF)) printf(" ge/nl"); else printf(" l/nge");
410 if (!(GP(f)&OF) == !(GP(f)&SF) && !(GP(f)&ZF))
411 printf(" g/nle"); else printf(" le/ng");
412 putchar('\n');
413 printf(";;\t\tsystem: %ctf %cif iopl=%d %cnt "
414 "%crf %cvm %cac %cvif %cvip %cid\n",
415 (GP(f) >> 8)&1u ? '+' : '-',
416 (GP(f) >> 9)&1u ? '+' : '-',
417 (int)((GP(f) >> 12)&1u),
418 (GP(f) >> 14)&1u ? '+' : '-',
419 (GP(f) >> 16)&1u ? '+' : '-',
420 (GP(f) >> 17)&1u ? '+' : '-',
421 (GP(f) >> 18)&1u ? '+' : '-',
422 (GP(f) >> 19)&1u ? '+' : '-',
423 (GP(f) >> 20)&1u ? '+' : '-',
424 (GP(f) >> 21)&1u ? '+' : '-');
425 }
426
427 static const char
428 *pcmap[] = { "sgl", "???", "dbl", "ext" },
429 *rcmap[] = { "nr", "-∞", "+∞", "0" };
430
431 static void dump_fpflags(const char *lbl, const struct fxsave *fx)
432 {
433 unsigned top = (fx->fsw >> 11)&7u;
434 unsigned tag = fx->ftw;
435 int skip = lbl ? strlen(lbl) + 2 : 0;
436
437 printf(";; ");
438 if (lbl) printf("%s: ", lbl);
439
440 printf(" fcw = 0x%04x: "
441 "%cim %cdm %czm %com %cum %cpm pc=%s rc=%s %cx\n",
442 fx->fcw,
443 (fx->fcw >> 0)&1u ? '+' : '-',
444 (fx->fcw >> 1)&1u ? '+' : '-',
445 (fx->fcw >> 2)&1u ? '+' : '-',
446 (fx->fcw >> 3)&1u ? '+' : '-',
447 (fx->fcw >> 4)&1u ? '+' : '-',
448 (fx->fcw >> 5)&1u ? '+' : '-',
449 pcmap[(fx->fcw >> 8)&3u],
450 rcmap[(fx->fcw >> 10)&3u],
451 (fx->fcw >> 12)&1u ? '+' : '-');
452 printf(";; %*s fsw = 0x%04x: "
453 "%cie %cde %cze %coe %cue %cpe %csf %ces %cc0 %cc1 %cc2 %cc3 "
454 "top=%d %cb\n",
455 skip, "",
456 fx->fsw,
457 (fx->fsw >> 0)&1u ? '+' : '-',
458 (fx->fsw >> 1)&1u ? '+' : '-',
459 (fx->fsw >> 2)&1u ? '+' : '-',
460 (fx->fsw >> 3)&1u ? '+' : '-',
461 (fx->fsw >> 4)&1u ? '+' : '-',
462 (fx->fsw >> 5)&1u ? '+' : '-',
463 (fx->fsw >> 6)&1u ? '+' : '-',
464 (fx->fsw >> 7)&1u ? '+' : '-',
465 (fx->fsw >> 8)&1u ? '+' : '-',
466 (fx->fsw >> 9)&1u ? '+' : '-',
467 (fx->fsw >> 10)&1u ? '+' : '-',
468 (fx->fsw >> 14)&1u ? '+' : '-',
469 top,
470 (fx->fsw >> 15)&1u ? '+' : '-');
471 printf(";; %*s ftw = 0x%02x\n", skip, "", tag);
472 }
473
474 static void dump_mxflags(const char *lbl, const struct fxsave *fx)
475 {
476 printf(";; ");
477 if (lbl) printf("%s: ", lbl);
478
479 printf(" mxcsr = 0x%08x\n"
480 ";;\t\tmask = %cim %cdm %czm %com %cum %cpm\n"
481 ";;\t\t exc = %cie %cde %cze %coe %cue %cpe\n"
482 ";;\t\tmisc = %cdaz %cftz rc=%s\n",
483 fx->mxcsr,
484 (fx->mxcsr >> 7)&1u ? '+' : '-',
485 (fx->mxcsr >> 8)&1u ? '+' : '-',
486 (fx->mxcsr >> 9)&1u ? '+' : '-',
487 (fx->mxcsr >> 10)&1u ? '+' : '-',
488 (fx->mxcsr >> 11)&1u ? '+' : '-',
489 (fx->mxcsr >> 12)&1u ? '+' : '-',
490 (fx->mxcsr >> 0)&1u ? '+' : '-',
491 (fx->mxcsr >> 1)&1u ? '+' : '-',
492 (fx->mxcsr >> 2)&1u ? '+' : '-',
493 (fx->mxcsr >> 3)&1u ? '+' : '-',
494 (fx->mxcsr >> 4)&1u ? '+' : '-',
495 (fx->mxcsr >> 5)&1u ? '+' : '-',
496 (fx->mxcsr >> 6)&1u ? '+' : '-',
497 (fx->mxcsr >> 15)&1u ? '+' : '-',
498 rcmap[(fx->mxcsr >> 13)&3u]);
499 }
500
501 #if CPUFAM_X86
502 # define REGF_GPWD REGF_32
503 #endif
504 #if CPUFAM_AMD64
505 # define REGF_GPWD REGF_64
506 #endif
507
508 void regdump_gp(const struct regmap *map)
509 {
510 unsigned i;
511
512 printf(";; General-purpose registers:\n");
513 for (i = REGIX_AX; i < REGIX_GPLIM; i++)
514 regdump(map, 0,
515 REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_GPWD | REGSRC_GP | i);
516 regdump(map, 0, REGF_HEX | REGF_GPWD | REGSRC_GP | REGIX_IP);
517
518 printf(";; Segment registers:\n");
519 for (i = 0; i < REGIX_SEGLIM; i++)
520 regdump(map, 0, REGF_HEX | REGF_16 | REGSRC_SEG | i);
521
522 printf(";; Flags:\n");
523 regdump(map, 0, REGSRC_GP | REGF_GPWD | REGIX_FLAGS);
524 }
525
526 void regdump_fp(const struct regmap *map)
527 {
528 unsigned top = (map->fx->fsw >> 11)&7u;
529 unsigned tag = map->fx->ftw;
530 unsigned i;
531
532 printf(";; Floating-point/MMX registers:\n");
533 if (!top && tag == 0xff)
534 for (i = 0; i < 8; i++)
535 regdump(map, 0,
536 REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_CHR |
537 REGF_32 | REGF_16 | REGF_8 |
538 REGSRC_STMMX | i | (6 << REGF_WDSHIFT));
539 if (tag)
540 for (i = 0; i < 8; i++)
541 regdump(map, 0, REGF_FLT | REGF_80 | REGSRC_STMMX | i);
542
543 printf(";; Floating-point state:\n");
544 dump_fpflags(0, map->fx);
545 }
546
547 void regdump_simd(const struct regmap *map)
548 {
549 unsigned f = REGF_HEX | REGF_FLT | REGF_UNSGN | REGF_SGN | REGF_CHR |
550 REGF_64 | REGF_32 | REGF_16 | REGF_8 |
551 REGSRC_SIMD;
552 unsigned i;
553
554 if (map->avx) f |= 8 << REGF_WDSHIFT;
555 else f |= 7 << REGF_WDSHIFT;
556
557 printf(";; SSE/AVX registers:\n");
558 for (i = 0; i < N(map->fx->xmm); i++)
559 regdump(map, 0, f | i);
560
561 printf(";; SSE/AVX floating-point state:\n");
562 dump_mxflags(0, map->fx);
563 }
564
565 #endif
566
567 /*----- ARM32 -------------------------------------------------------------*/
568
569 #if CPUFAM_ARMEL
570
571 #define NF (1u << 31)
572 #define ZF (1u << 30)
573 #define CF (1u << 29)
574 #define VF (1u << 28)
575
576 unsigned regdump__flags = 0;
577
578 void regdump_init(void)
579 {
580 if (cpu_feature_p(CPUFEAT_ARM_VFP)) regdump__flags |= REGF_VFP;
581 if (cpu_feature_p(CPUFEAT_ARM_D32)) regdump__flags |= REGF_D32;
582 }
583
584 static void dump_conditions(unsigned f)
585 {
586 if (f&NF) printf(" mi"); else printf(" pl");
587 if (f&ZF) printf(" eq"); else printf(" ne");
588 if (f&CF) printf(" cs/hs"); else printf(" cc/lo");
589 if (f&VF) printf(" vs"); else printf(" vc");
590 if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls");
591 if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt");
592 if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le");
593 }
594
595 static void dump_flags(const char *lbl, unsigned f)
596 {
597 static const char
598 *modetab[] = { "?00", "?01", "?02", "?03", "?04", "?05", "?06", "?07",
599 "?08", "?09", "?10", "?11", "?12", "?13", "?14", "?15",
600 "usr", "fiq", "irq", "svc", "?20", "?21", "mon", "abt",
601 "?24", "?25", "hyp", "und", "?28", "?29", "?30", "sys" },
602 *condtab[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
603 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
604
605 printf(";; ");
606 if (lbl) printf("%s: ", lbl);
607 printf(" cpsr = 0x%08x\n", f);
608 printf(";;\t\tuser: %cn %cz %cc %cv %cq ge=%c%c%c%c;",
609 (f >> 31)&1u ? '+' : '-',
610 (f >> 30)&1u ? '+' : '-',
611 (f >> 29)&1u ? '+' : '-',
612 (f >> 28)&1u ? '+' : '-',
613 (f >> 27)&1u ? '+' : '-',
614 (f >> 19)&1u ? '1' : '0',
615 (f >> 18)&1u ? '1' : '0',
616 (f >> 17)&1u ? '1' : '0',
617 (f >> 16)&1u ? '1' : '0');
618 dump_conditions(f); putchar('\n');
619 printf(";;\t\tsystem: %cj it=%s:%c%c%c%c %ce %ca %ci %cf %ct m=%s\n",
620 (f >> 24)&1u ? '+' : '-',
621 condtab[(f >> 12)&15u],
622 (f >> 11)&1u ? '1' : '0',
623 (f >> 10)&1u ? '1' : '0',
624 (f >> 26)&1u ? '1' : '0',
625 (f >> 25)&1u ? '1' : '0',
626 (f >> 9)&1u ? '+' : '-',
627 (f >> 8)&1u ? '+' : '-',
628 (f >> 7)&1u ? '+' : '-',
629 (f >> 6)&1u ? '+' : '-',
630 (f >> 5)&1u ? '+' : '-',
631 modetab[(f >> 0)&31u]);
632 }
633
634 static void dump_fpflags(const char *lbl, unsigned f)
635 {
636 static const char *rcmap[] = { "nr", "+∞", "-∞", "0" };
637
638 printf(";; ");
639 if (lbl) printf("%s: ", lbl);
640 printf(" fpscr = 0x%08x\n", f);
641 printf(";;\t\tcond: %cn %cz %cc %cv %cqc;",
642 (f >> 31)&1u ? '+' : '-',
643 (f >> 30)&1u ? '+' : '-',
644 (f >> 29)&1u ? '+' : '-',
645 (f >> 28)&1u ? '+' : '-',
646 (f >> 27)&1u ? '+' : '-');
647 dump_conditions(f); putchar('\n');
648 printf(";;\t\ttrap: %cide %cixe %cufe %cofe %cdze %cioe\n",
649 (f >> 15)&1u ? '+' : '-',
650 (f >> 12)&1u ? '+' : '-',
651 (f >> 11)&1u ? '+' : '-',
652 (f >> 10)&1u ? '+' : '-',
653 (f >> 9)&1u ? '+' : '-',
654 (f >> 8)&1u ? '+' : '-');
655 printf(";;\t\terror: %cide %cixe %cufe %cofe %cdze %cioe\n",
656 (f >> 7)&1u ? '+' : '-',
657 (f >> 4)&1u ? '+' : '-',
658 (f >> 3)&1u ? '+' : '-',
659 (f >> 2)&1u ? '+' : '-',
660 (f >> 1)&1u ? '+' : '-',
661 (f >> 0)&1u ? '+' : '-');
662 printf(";;\t\tcontrol: %cahp %cdn %cfz rm=%s str=%d len=%d\n",
663 (f >> 26)&1u ? '+' : '-',
664 (f >> 25)&1u ? '+' : '-',
665 (f >> 24)&1u ? '+' : '-',
666 rcmap[(f >> 22)&3u],
667 (f >> 20)&3u,
668 (f >> 16)&7u);
669 }
670
671 void regdump_gp(const struct regmap *map)
672 {
673 unsigned i;
674
675 printf(";; General-purpose registers:\n");
676 for (i = 0; i < 16; i++)
677 regdump(map, 0,
678 REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_32 | REGSRC_GP | i);
679
680 printf(";; Flags:\n");
681 regdump(map, 0, REGSRC_GP | REGF_32 | REGIX_CPSR);
682 }
683
684 void regdump_fp(const struct regmap *map)
685 {
686 unsigned i, n;
687
688 if (!(regdump__flags&REGF_VFP)) {
689 printf(";; Floating-point and SIMD not available\n");
690 return;
691 }
692
693 printf(";; Floating-point/SIMD registers:\n");
694 if (regdump__flags&REGF_D32) n = 32;
695 else n = 16;
696 for (i = 0; i < n; i++)
697 regdump(map, 0,
698 REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_FLT | REGF_CHR |
699 REGF_64 | REGF_32 | REGF_16 | REGF_8 |
700 REGSRC_FP | i | (6 << REGF_WDSHIFT));
701
702 printf(";; Floating-point state:\n");
703 dump_fpflags(0, map->fp->fpscr);
704 }
705
706 void regdump_simd(const struct regmap *map) { ; }
707
708 #endif
709
710 /*----- ARM64 -------------------------------------------------------------*/
711
712 #if CPUFAM_ARM64
713
714 #define NF (1u << 31)
715 #define ZF (1u << 30)
716 #define CF (1u << 29)
717 #define VF (1u << 28)
718
719 void regdump_init(void) { ; }
720
721 static void dump_conditions(unsigned f)
722 {
723 if (f&NF) printf(" mi"); else printf(" pl");
724 if (f&ZF) printf(" eq"); else printf(" ne");
725 if (f&CF) printf(" cs/hs"); else printf(" cc/lo");
726 if (f&VF) printf(" vs"); else printf(" vc");
727 if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls");
728 if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt");
729 if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le");
730 }
731
732 static void dump_flags(const char *lbl, unsigned f)
733 {
734 printf(";; ");
735 if (lbl) printf("%s: ", lbl);
736 printf(" nzcv = 0x%08x\n", f);
737 printf(";;\t\tuser: %cn %cz %cc %cv;",
738 (f >> 31)&1u ? '+' : '-',
739 (f >> 30)&1u ? '+' : '-',
740 (f >> 29)&1u ? '+' : '-',
741 (f >> 28)&1u ? '+' : '-');
742 dump_conditions(f); putchar('\n');
743 }
744
745 static void dump_fpflags(const char *lbl, const struct fpsave *fp)
746 {
747 static const char *rcmap[] = { "nr", "+∞", "-∞", "0" };
748 int skip = lbl ? strlen(lbl) + 2 : 0;
749
750 printf(";; ");
751 if (lbl) printf("%s: ", lbl);
752 printf(" fpsr = 0x%08x\n", fp->fpsr);
753 printf(";;\t\tcond_a32: %cn %cz %cc %cv %cqc;",
754 (fp->fpsr >> 31)&1u ? '+' : '-',
755 (fp->fpsr >> 30)&1u ? '+' : '-',
756 (fp->fpsr >> 29)&1u ? '+' : '-',
757 (fp->fpsr >> 28)&1u ? '+' : '-',
758 (fp->fpsr >> 27)&1u ? '+' : '-');
759 dump_conditions(fp->fpsr); putchar('\n');
760 printf(";;\t\terror: %cidc %cixc %cufc %cofc %cdzc %cioc\n",
761 (fp->fpsr >> 7)&1u ? '+' : '-',
762 (fp->fpsr >> 4)&1u ? '+' : '-',
763 (fp->fpsr >> 3)&1u ? '+' : '-',
764 (fp->fpsr >> 2)&1u ? '+' : '-',
765 (fp->fpsr >> 1)&1u ? '+' : '-',
766 (fp->fpsr >> 0)&1u ? '+' : '-');
767 printf(";; %*s fpcr = 0x%08x\n", skip, "", fp->fpcr);
768 printf(";;\t\ttrap: %cide %cixe %cufe %cofe %cdze %cioe\n",
769 (fp->fpcr >> 15)&1u ? '+' : '-',
770 (fp->fpcr >> 12)&1u ? '+' : '-',
771 (fp->fpcr >> 11)&1u ? '+' : '-',
772 (fp->fpcr >> 10)&1u ? '+' : '-',
773 (fp->fpcr >> 9)&1u ? '+' : '-',
774 (fp->fpcr >> 8)&1u ? '+' : '-');
775 printf(";;\t\tcontrol: %cahp %cdn %cfz rm=%s str=%d len=%d\n",
776 (fp->fpcr >> 26)&1u ? '+' : '-',
777 (fp->fpcr >> 25)&1u ? '+' : '-',
778 (fp->fpcr >> 24)&1u ? '+' : '-',
779 rcmap[(fp->fpcr >> 22)&3u],
780 (fp->fpcr >> 20)&3u,
781 (fp->fpcr >> 16)&7u);
782 }
783
784 void regdump_gp(const struct regmap *map)
785 {
786 unsigned i;
787
788 printf(";; General-purpose registers:\n");
789 for (i = 0; i < 32; i++)
790 regdump(map, 0,
791 REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_64 | REGSRC_GP | i);
792 regdump(map, 0, REGF_HEX | REGF_64 | REGSRC_GP | REGIX_PC);
793
794 printf(";; Flags:\n");
795 regdump(map, 0, REGSRC_GP | REGF_32 | REGIX_NZCV);
796 }
797
798 void regdump_fp(const struct regmap *map)
799 {
800 unsigned i;
801
802 printf(";; Floating-point/SIMD registers:\n");
803 for (i = 0; i < 32; i++)
804 regdump(map, 0,
805 REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_FLT | REGF_CHR |
806 REGF_64 | REGF_32 | REGF_16 | REGF_8 |
807 REGSRC_SIMD | i | (7 << REGF_WDSHIFT));
808
809 printf(";; Floating-point state:\n");
810 dump_fpflags(0, map->fp);
811 }
812
813 void regdump_simd(const struct regmap *map) { ; }
814
815 #endif
816
817 /*----- The main entry point ----------------------------------------------*/
818
819 /* --- @regdump@ --- *
820 *
821 * Arguments: @const void *base@ = pointer to base structure, corresponding
822 * to the @REGF_SRCMASK@ part of @f@
823 * @const char *lbl@ = label to print
824 * @uint32 f@ = format control word; see @REGF_...@
825 *
826 * Returns: ---
827 *
828 * Use: Dump a register value, or chunk of memory.
829 *
830 * This function is not usually called directly; instead, use
831 * the `reg' or `mem' assembler macros.
832 */
833
834 void regdump(const void *base, const char *lbl, uint32 f)
835 {
836 unsigned ix = (f&REGF_IXMASK) >> REGF_IXSHIFT;
837 unsigned wd = 1 << ((f&REGF_WDMASK) >> REGF_WDSHIFT);
838 unsigned fmt, ty;
839 uint32 fmtbit, tybit;
840 const void *p;
841 char regbuf[8]; const char *reg = regname(regbuf, f);
842 const struct regmap *map;
843 const struct fmttab *tab;
844 struct fmtinfo fi;
845 int firstp = 1;
846 int skip;
847 size_t n;
848
849 #if CPUFAM_X86 || CPUFAM_AMD64
850 union vreg vr;
851 #endif
852
853 if (reg) {
854 n = strlen(reg);
855 if (n < 7) {
856 memmove(regbuf + 7 - n, reg, n + 1);
857 memset(regbuf, ' ', 7 - n);
858 }
859 }
860
861 switch (f&REGF_SRCMASK) {
862
863 case REGSRC_NONE:
864 printf(";; %s\n", lbl);
865 return;
866
867 case REGSRC_ABS:
868 p = base;
869 break;
870
871 #if CPUFAM_X86 || CPUFAM_AMD64
872 case REGSRC_GP:
873 map = (const struct regmap *)base;
874 if (ix == REGIX_FLAGS && !(f&REGF_FMTMASK))
875 { dump_flags(lbl, reg, map->gp->gp[REGIX_FLAGS]); return; }
876 p = &map->gp->gp[ix];
877 break;
878 case REGSRC_SEG:
879 map = (const struct regmap *)base;
880 assert(wd == 1); assert((f&REGF_TYMASK) == REGF_16);
881 p = &map->gp->seg[ix];
882 break;
883 case REGSRC_STMMX:
884 map = (const struct regmap *)base;
885 if (ix == REGIX_FPFLAGS)
886 { assert(!(f&REGF_FMTMASK)); dump_fpflags(lbl, map->fx); return; }
887 if (!((map->fx->ftw << ix)&128u)) {
888 printf(";; ");
889 if (lbl) printf("%s: ", lbl);
890 if (reg) printf("%s = ", reg);
891 printf(" dead\n");
892 return;
893 }
894 p = &map->fx->stmmx[ix];
895 break;
896 case REGSRC_SIMD:
897 map = (const struct regmap *)base;
898 if (ix == REGIX_FPFLAGS)
899 { assert(!(f&REGF_FMTMASK)); dump_mxflags(lbl, map->fx); return; }
900 if (wd <= 128)
901 p = &map->fx->xmm[ix];
902 else {
903 vr.v128[0] = map->fx->xmm[ix];
904 vr.v128[1] = map->avx->ymmh[ix];
905 assert(wd == 256);
906 p = &vr;
907 }
908 break;
909 #endif
910
911 #if CPUFAM_ARMEL
912 case REGSRC_GP:
913 map = (const struct regmap *)base;
914 if (ix == REGIX_CPSR && !(f&REGF_FMTMASK))
915 { dump_flags(lbl, map->gp->r[REGIX_CPSR].u32); return; }
916 p = &map->gp->r[ix];
917 break;
918 case REGSRC_FP:
919 case REGSRC_SIMD:
920 map = (const struct regmap *)base;
921 if (!map->fp) {
922 printf(";;");
923 if (lbl) printf(" %s:", lbl);
924 if (reg) printf(" %s =", reg);
925 printf(" #<not available -- regdump_init?>\n");
926 return;
927 }
928 if (ix == REGIX_FPSCR) {
929 assert(!(f&REGF_FMTMASK));
930 dump_fpflags(lbl, map->fp->fpscr);
931 return;
932 }
933 switch (regwd(f)) {
934 case 32: p = &map->fp->u.s[ix]; break;
935 case 64: p = &map->fp->u.d[ix]; break;
936 case 128: p = &map->fp->u.q[ix]; break;
937 default: assert(0);
938 }
939 break;
940 #endif
941
942 #if CPUFAM_ARM64
943 case REGSRC_GP:
944 map = (const struct regmap *)base;
945 if (ix == REGIX_NZCV && !(f&REGF_FMTMASK))
946 { dump_flags(lbl, map->gp->r[REGIX_NZCV].u64); return; }
947 p = &map->gp->r[ix];
948 break;
949 case REGSRC_FP:
950 case REGSRC_SIMD:
951 map = (const struct regmap *)base;
952 if (ix == REGIX_FPFLAGS)
953 { assert(!(f&REGF_FMTMASK)); dump_fpflags(lbl, map->fp); return; }
954 p = &map->fp->v[ix];
955 break;
956 #endif
957
958 default:
959 assert(0);
960 }
961
962 skip = (lbl ? strlen(lbl) + 2 : 0) + (reg ? strlen(reg) : 0);
963 fi.f = 0; if (wd > 1) fi.f |= FMTF_VECTOR;
964
965 for (ty = (f&REGF_TYMASK) >> REGF_TYSHIFT,
966 tybit = 1 << REGF_TYSHIFT;
967 ty;
968 ty >>= 1, tybit <<= 1) {
969 if (!(ty&1u)) continue;
970
971 for (fmt = (f&REGF_FMTMASK) >> REGF_FMTSHIFT,
972 fmtbit = 1 << REGF_FMTSHIFT;
973 fmt;
974 fmt >>= 1, fmtbit <<= 1) {
975
976 if (!(fmt&1u)) continue;
977
978 for (tab = fmttab; tab->mask; tab++)
979 if (tab->mask == (fmtbit | tybit)) goto found;
980 continue;
981 found:
982
983 if (firstp) {
984 printf(";;");
985 if (lbl) printf(" %s:", lbl);
986 if (reg) printf(" %s =", reg);
987 firstp = 0;
988 } else if (wd > 1)
989 printf("\n;; %*s =", skip, "");
990 else
991 fputs(" =", stdout);
992
993 fi.p = p; fi.wd = 0;
994 while (fi.wd < wd) { putchar(' '); tab->fmt(&fi); }
995 }
996 }
997 putchar('\n');
998 }
999
1000 /*----- Other random utilities --------------------------------------------*/
1001
1002 /* --- @regdump_freshline@ --- *
1003 *
1004 * Arguments: ---
1005 *
1006 * Returns: ---
1007 *
1008 * Use: Begin a fresh line of output.
1009 */
1010
1011 void regdump_freshline(void) { putchar('\n'); }
1012
1013 /*----- That's all, folks -------------------------------------------------*/