chiark / gitweb /
math/mpx-mul4-test.c: Compare and print test outputs by value.
[catacomb] / base / regdump.h
1 /* -*-c-*-
2  *
3  * Register dump and debugging support
4  *
5  * (c) 2019 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 it
13  * under the terms of the GNU Library General Public License as published
14  * by the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * 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 Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 #ifndef CATACOMB_REGDUMP_H
29 #define CATACOMB_REGDUMP_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include "config.h"
38
39 #ifndef ENABLE_ASM_DEBUG
40 #  error "Assembler-level debug disabled by `configure' script."
41 #endif
42
43 #if __ASSEMBLER__
44 #  include "asm-common.h"
45 #else
46 #  include <float.h>
47 #  include <mLib/bits.h>
48 #endif
49
50 /*----- Random utilities --------------------------------------------------*/
51
52 #define DO8(_)                                                          \
53    _(0)  _(1)  _(2)  _(3)  _(4)  _(5)  _(6)  _(7)
54 #define DOHI8(_)                                                        \
55    _(8)  _(9) _(10) _(11) _(12) _(13) _(14) _(15)
56
57 #define DO16(_) DO8(_) DOHI8(_)
58
59 #define DO32(_)                                                         \
60   DO16(_)                                                               \
61   _(16) _(17) _(18) _(19) _(20) _(21) _(22) _(23)                       \
62   _(24) _(25) _(26) _(27) _(28) _(29) _(30) _(31)
63
64 /*----- Common data structures --------------------------------------------*/
65
66 #if !__ASSEMBLER__
67
68 /* The following are good on our assembler targets. */
69 typedef signed char int8;
70 typedef short int16;
71 typedef int int32;
72 #if LONG_MAX >> 31 > 0x7fffffff
73   typedef long int64;
74 #else
75   typedef long long int64;
76 #endif
77 typedef float float32;
78 typedef double float64;
79 typedef long double float80;
80
81 #if CPUFAM_X86 || CPUFAM_ARMEL
82 #  define PTR32 void *p;
83 #  define PTR64
84 #endif
85 #if CPUFAM_AMD64 || CPUFAM_ARM64
86 #  define PTR32
87 #  define PTR64 void *p;
88 #endif
89
90 #define SIMD_COMMON(wd)                                                 \
91   uint8 u8[wd/8];                                                       \
92   int8 i8[wd/8];                                                        \
93   uint16 u16[wd/16];                                                    \
94   int16 i16[wd/16];                                                     \
95   uint32 u32[wd/32];                                                    \
96   int32 i32[wd/32];                                                     \
97   uint64 u64[wd/64];                                                    \
98   int64 i64[wd/64];                                                     \
99   float32 f32[wd/32];                                                   \
100   float64 f64[wd/64]
101
102 union gp32 { uint32 u32; int32 i32; PTR32 };
103 union gp64 { uint64 u64; int64 i64; PTR64 };
104
105 #endif
106
107 /*----- Format word layout ------------------------------------------------*/
108
109 #define REGF_IXMASK     0x000000ff
110 #define REGF_IXSHIFT             0
111 /* The index into the vector indicated by `REGF_SRCMASK', if applicable. */
112
113 #define REGF_FMTMASK    0x0000ff00
114 #define REGF_FMTSHIFT            8
115 #define REGF_HEX        0x00000100
116 #define REGF_CHR        0x00000200
117 #define REGF_FLT        0x00000400
118 #define REGF_UNSGN      0x00000800
119 #define REGF_SGN        0x00001000
120 /* How to format the value(s) found. */
121
122 #define REGF_TYMASK     0x00ff0000
123 #define REGF_TYSHIFT            16
124 #define REGF_80         0x00010000
125 #define REGF_64         0x00020000
126 #define REGF_32         0x00040000
127 #define REGF_16         0x00080000
128 #define REGF_8          0x00100000
129 /* Size of the value(s) to dump. */
130
131 #define REGF_SRCMASK    0x0f000000
132 #define   REGSRC_ABS    0x01000000      /* absolute address */
133 #define   REGSRC_GP     0x02000000      /* general-purpose register */
134 #define   REGSRC_FP     0x03000000      /* floating-point register */
135 #define   REGSRC_SIMD   0x04000000      /* SIMD vector register */
136 #define   REGSRC_STMMX  0x05000000      /* x86-specific: x87/MMX register */
137 #define   REGSRC_SEG    0x06000000      /* x86-specific: segment register */
138 /* Where to find the values. */
139
140 #define REGF_WDMASK     0xf0000000
141 #define REGF_WDSHIFT            28
142 /* If we're to print a scalar, this is zero; otherwise, log_2 of the vector
143  * register width, in bits.
144  */
145
146 /*----- x86 and AMD64 -----------------------------------------------------*/
147
148 #if CPUFAM_X86 || CPUFAM_AMD64
149
150 #define   REGIX_FLAGS    0
151 #define   REGIX_IP       1
152 #define   REGIX_ADDR     2
153 #define   REGIX_AX       3
154 #define   REGIX_BX       4
155 #define   REGIX_CX       5
156 #define   REGIX_DX       6
157 #define   REGIX_SI       7
158 #define   REGIX_DI       8
159 #define   REGIX_BP       9
160 #define   REGIX_SP      10
161 #if CPUFAM_X86
162 #  define REGIX_GPLIM   11
163 #endif
164 #if CPUFAM_AMD64
165 #  define REGIX_R8      11
166 #  define REGIX_R9      12
167 #  define REGIX_R10     13
168 #  define REGIX_R11     14
169 #  define REGIX_R12     15
170 #  define REGIX_R13     16
171 #  define REGIX_R14     17
172 #  define REGIX_R15     18
173 #  define REGIX_GPLIM   19
174 #endif
175
176 #define REGIX_CS         0
177 #define REGIX_DS         1
178 #define REGIX_SS         2
179 #define REGIX_ES         3
180 #define REGIX_FS         4
181 #define REGIX_GS         5
182 #define REGIX_SEGLIM     6
183
184 #define REGIX_FPFLAGS  255
185
186 #if !__ASSEMBLER__
187
188 #if CPUFAM_X86
189 typedef union gp32 gpreg;
190 #endif
191 #if CPUFAM_AMD64
192 typedef union gp64 gpreg;
193 #endif
194
195 struct gpsave {
196   gpreg gp[REGIX_GPLIM];
197   uint16 seg[REGIX_SEGLIM];
198 };
199
200 union stmmx {
201   SIMD_COMMON(64);
202 #if FLT_RADIX == 2 && LDBL_MANT_DIG == 64
203   long double f80;
204 #endif
205 unsigned char _pad[16];
206 };
207
208 union xmm { SIMD_COMMON(128); };
209 union ymm { SIMD_COMMON(256); };
210 union vreg { union xmm v128[2]; union ymm v256; };
211
212 struct fxsave {
213   unsigned short fcw;
214   unsigned short fsw;
215   unsigned char ftw;
216   unsigned char _res0;
217   unsigned short fop;
218 #if CPUFAM_X86
219   unsigned int fpu_ip;
220   unsigned short fpu_cs;
221   unsigned short _res1;
222   unsigned int fpu_dp;
223   unsigned short fpu_ds;
224   unsigned short _res2;
225 #endif
226 #if CPUFAM_AMD64
227   unsigned long long fpu_ip;
228   unsigned long long fpu_dp;
229 #endif
230   unsigned int mxcsr;
231   unsigned int mxcsr_mask;
232
233   union stmmx stmmx[8];
234
235 #if CPUFAM_X86
236   union xmm xmm[8];
237   unsigned char _pad0[8*16];
238 #endif
239 #if CPUFAM_AMD64
240   union xmm xmm[16];
241 #endif
242
243   unsigned char _pad1[96];
244 };
245
246 struct xsave_avx {
247 #if CPUFAM_X86
248   union xmm ymmh[8];
249   unsigned char _pad0[8*16];
250 #endif
251 #if CPUFAM_AMD64
252   union xmm ymmh[16];
253 #endif
254 };
255
256 struct regmap {
257   struct gpsave *gp;
258   struct fxsave *fx;
259   struct xsave_avx *avx;
260 };
261
262 #else
263
264         .extern regdump_gpsave
265         .extern regdump_xtsave
266         .extern regdump_xtrstr
267         .extern regdump_gprstr
268
269         regmap_gp = 0*WORDSZ
270         regmap_fx = 1*WORDSZ
271         regmap_avx = 2*WORDSZ
272         regmap_size = 3*WORDSZ
273
274 #define REGDEF_GPX86_COMMON(rn, ix)                                     \
275         regsrc.e##rn = REGSRC_GP | ix;                                  \
276         regty.e##rn = REGF_32;                                          \
277         regfmt.e##rn = REGF_HEX;                                        \
278         regsrc.r##rn = REGSRC_GP | ix;                                  \
279         regty.r##rn = REGF_64;                                          \
280         regfmt.r##rn = REGF_HEX
281
282 #define REGDEF_GPX86_ABCD(rn, RN)                                       \
283         regsrc.rn##hl = (4 << REGF_WDSHIFT) | REGSRC_GP | REGIX_##RN##X; \
284         regty.rn##hl = REGF_8;                                          \
285         regfmt.rn##hl = REGF_HEX;                                       \
286         regsrc.rn##l = REGSRC_GP | REGIX_##RN##X;                       \
287         regty.rn##l = REGF_8;                                           \
288         regfmt.rn##l = REGF_HEX;                                        \
289         regsrc.rn##x = REGSRC_GP | REGIX_##RN##X;                       \
290         regty.rn##x = REGF_16;                                          \
291         regfmt.rn##x = REGF_HEX;                                        \
292         REGDEF_GPX86_COMMON(rn##x, REGIX_##RN##X)
293 REGDEF_GPX86_ABCD(a, A)
294 REGDEF_GPX86_ABCD(b, B)
295 REGDEF_GPX86_ABCD(c, C)
296 REGDEF_GPX86_ABCD(d, D)
297
298         regsrc.eflags = REGSRC_GP | REGIX_FLAGS
299         regty.eflags = REGF_32
300         regfmt.eflags = 0
301
302 #if CPUFAM_AMD64
303         regsrc.rflags = REGSRC_GP | REGIX_FLAGS
304         regty.rflags = REGF_64
305         regfmt.rflags = 0
306 #endif
307
308 #define REGDEF_GPX86_XP(rn, RN)                                         \
309         regsrc.rn##l = REGSRC_GP | REGIX_##RN;                          \
310         regty.rn##l = REGF_8;                                           \
311         regfmt.rn##l = REGF_HEX;                                        \
312         regsrc.rn = REGSRC_GP | REGIX_##RN;                             \
313         regty.rn = REGF_16;                                             \
314         regfmt.rn = REGF_HEX;                                           \
315         REGDEF_GPX86_COMMON(rn, REGIX_##RN)
316 REGDEF_GPX86_XP(ip, IP)
317 REGDEF_GPX86_XP(si, SI)
318 REGDEF_GPX86_XP(di, DI)
319 REGDEF_GPX86_XP(bp, BP)
320 REGDEF_GPX86_XP(sp, SP)
321
322 #if CPUFAM_AMD64
323 #  define REGDEF_GPAMD64(i)                                             \
324         regsrc.r##i##b = REGSRC_GP | REGIX_R##i;                        \
325         regty.r##i##b = REGF_8;                                         \
326         regfmt.r##i##b = REGF_HEX;                                      \
327         regsrc.r##i##w = REGSRC_GP | REGIX_R##i;                        \
328         regty.r##i##w = REGF_16;                                        \
329         regfmt.r##i##w = REGF_HEX;                                      \
330         regsrc.r##i##d = REGSRC_GP | REGIX_R##i;                        \
331         regty.r##i##d = REGF_32;                                        \
332         regfmt.r##i##d = REGF_HEX;                                      \
333         regsrc.r##i = REGSRC_GP | REGIX_R##i;                           \
334         regty.r##i = REGF_64;                                           \
335         regfmt.r##i = REGF_HEX;
336   DOHI8(REGDEF_GPAMD64)
337 #endif
338
339 #define REGDEF_SEG(rn, RN)                                              \
340         regsrc.rn = REGSRC_SEG | REGIX_##RN;                            \
341         regty.rn = REGF_16;                                             \
342         regfmt.rn = REGF_HEX
343 REGDEF_SEG(ss, SS)
344 REGDEF_SEG(cs, CS)
345 REGDEF_SEG(ds, DS)
346 REGDEF_SEG(es, ES)
347 REGDEF_SEG(fs, FS)
348 REGDEF_SEG(gs, GS)
349
350 #define REGDEF_STMMX(i)                                                 \
351         regsrc.st##i = REGSRC_STMMX | i;                                \
352         regty.st##i = REGF_80;                                          \
353         regfmt.st##i = REGF_FLT;                                        \
354         regsrc.mm##i = (6 << REGF_WDSHIFT) | REGSRC_STMMX | i;          \
355         regty.mm##i = REGF_16;                                          \
356         regfmt.mm##i = REGF_HEX;
357 DO8(REGDEF_STMMX)
358
359 #define REGDEF_SIMD(i)                                                  \
360         regsrc.xmm##i = (7 << REGF_WDSHIFT) | REGSRC_SIMD | i;          \
361         regty.xmm##i = REGF_32;                                         \
362         regfmt.xmm##i = REGF_HEX;                                       \
363         regsrc.ymm##i = (8 << REGF_WDSHIFT) | REGSRC_SIMD | i;          \
364         regty.ymm##i = REGF_32;                                         \
365         regfmt.ymm##i = REGF_HEX;
366 DO8(REGDEF_SIMD)
367 #if CPUFAM_AMD64
368   DOHI8(REGDEF_SIMD)
369 #endif
370
371         REGDUMP_GPSIZE = REGIX_GPLIM*WORDSZ + REGIX_SEGLIM*2
372
373 #  if CPUFAM_AMD64 && ABI_SYSV
374         REGDUMP_SPADJ = REGDUMP_GPSIZE + WORDSZ + 128
375 #  else
376         REGDUMP_SPADJ = REGDUMP_GPSIZE + WORDSZ
377 #  endif
378
379 .macro  _saveregs addr=nil
380         // Save the registers, leaving r/ebp pointing to the register map.
381
382         // Stash r/eax.  This is bletcherous: hope we don't get a signal in
383         // the next few instructions.
384         mov     [SP - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], AX
385
386   .ifnes "\addr", "nil"
387         // Collect the effective address for the following dump, leaving it
388         // in the `addr' slot of the dump.
389         lea     AX, \addr
390         mov     [SP - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], AX
391   .endif
392
393         // Make space for the register save area.  On AMD64 with System/V
394         // ABI, also skip the red zone.  Use `lea' here to preserve the
395         // flags.
396         lea     SP, [SP - REGDUMP_SPADJ]
397
398         // Save flags and general-purpose registers.  On 32-bit x86, we save
399         // ebx here and establish a GOT pointer here for the benefit of the
400         // PLT-indirect calls made later on.
401         pushf
402 #  if CPUFAM_X86
403         mov     [SP + 4*REGIX_BX], ebx
404         ldgot
405 #  endif
406         callext F(regdump_gpsave)
407
408         // Make space for the extended registers.
409         sub     SP, CX
410         callext F(regdump_xtsave)
411
412         // Prepare for calling back into C.  On 32-bit x86, leave space for
413         // the arguments and set up the GOT pointer; on AMD64 Windows, leave
414         // the `shadow space' for the called-function's arguments.  Also,
415         // forcibly align the stack pointer to a 16-byte boundary.
416 #  if CPUFAM_X86
417         sub     SP, 16
418 #  elif ABI_WIN
419         sub     SP, 32
420 #  endif
421         and     SP, ~15
422 .endm
423
424 .macro  _rstrregs
425         // Restore registers.
426
427         // We assume r/ebp still points to the register map.
428         callext F(regdump_xtrstr)
429         mov     SP, BP
430         callext F(regdump_gprstr)
431         popf
432         lea     SP, [SP + REGDUMP_SPADJ]
433 .endm
434
435 .macro  _regbase
436 #  if CPUFAM_X86
437         mov     [SP + 0], BP
438 #  elif ABI_SYSV
439         mov     rdi, BP
440 #  elif ABI_WIN
441         mov     rcx, BP
442 #  endif
443 .endm
444
445 .macro  _membase
446         mov     AX, [BP + regmap_gp]
447 #  if CPUFAM_X86
448         mov     eax, [eax + REGIX_ADDR*WORDSZ]
449         mov     [SP + 0], eax
450 #  elif ABI_SYSV
451         mov     rdi, [rax + REGIX_ADDR*WORDSZ]
452 #  elif ABI_WIN
453         mov     rcx, [rax + REGIX_ADDR*WORDSZ]
454 #  endif
455 .endm
456
457 .macro  _reglbl msg
458   .ifeqs "\msg", ""
459 #  if CPUFAM_X86
460         mov     dword ptr [SP + 4], 0
461 #  elif ABI_SYSV
462         xor     esi, esi
463 #  elif ABI_WIN
464         xor     edx, edx
465 #  endif
466   .else
467 #  if CPUFAM_X86
468         lea     eax, [INTADDR(.L$_reglbl$\@)]
469         mov     [SP + 4], eax
470 #  elif ABI_SYSV
471         lea     rsi, [INTADDR(.L$_reglbl$\@)]
472 #  elif ABI_WIN
473         lea     rdx, [INTADDR(.L$_reglbl$\@)]
474 #  endif
475     _LIT
476 .L$_reglbl$\@:
477         .asciz  "\msg"
478     _ENDLIT
479   .endif
480 .endm
481
482 .macro  _regfmt arg
483 #  if CPUFAM_X86
484         mov     dword ptr [SP + 8], \arg
485 #  elif ABI_SYSV
486         mov     edx, \arg
487 #  elif ABI_WIN
488         mov     r8d, \arg
489 #  endif
490 .endm
491
492 #endif
493
494 #endif
495
496 /*----- ARM32 -------------------------------------------------------------*/
497
498 #if CPUFAM_ARMEL
499
500 #if !__ASSEMBLER__
501 extern unsigned regdump__flags;
502 #endif
503 #define REGF_VFP 1u
504 #define REGF_D32 2u
505
506 #define REGIX_CPSR 16
507 #define REGIX_ADDR 17
508 #define REGIX_GPLIM 18
509
510 #define REGIX_FPSCR 255
511
512 #if !__ASSEMBLER__
513
514 union neon64 { SIMD_COMMON(64); };
515 union neon128 { SIMD_COMMON(128); };
516
517 struct gpsave { union gp32 r[REGIX_GPLIM]; };
518
519 struct fpsave {
520   unsigned fpscr;
521   unsigned _pad0;
522   union {
523     float32 s[32];
524     union neon64 d[32];
525     union neon128 q[16];
526   } u;
527 };
528
529 struct regmap {
530   struct gpsave *gp;
531   struct fpsave *fp;
532 };
533
534 #else
535
536         .extern regdump_gpsave
537         .extern regdump_xtsave
538         .extern regdump_xtrstr
539         .extern regdump_gprstr
540
541         regmap_gp = 0
542         regmap_fp = 4
543         regmap_size = 8
544
545 #define REGDEF_GP(i)                                                    \
546         regsrc.r##i = REGSRC_GP | i;                                    \
547         regty.r##i = REGF_32;                                           \
548         regfmt.r##i = REGF_HEX;
549 DO16(REGDEF_GP)
550
551         regsrc.cpsr = REGSRC_GP | REGIX_CPSR
552         regty.cpsr = REGF_32
553         regfmt.cpsr = 0
554
555 #define REGDEF_NEONS(i)                                                 \
556         regsrc.s##i = REGSRC_FP | i;                                    \
557         regty.s##i = REGF_32;                                           \
558         regfmt.s##i = REGF_FLT;
559 DO32(REGDEF_NEONS)
560
561 #define REGDEF_NEOND(i)                                                 \
562         regsrc.d##i = (6 << REGF_WDSHIFT) | REGSRC_FP | i;              \
563         regty.d##i = REGF_32;                                           \
564         regfmt.d##i = REGF_HEX;
565 DO32(REGDEF_NEOND)
566
567 #define REGDEF_NEONQ(i)                                                 \
568         regsrc.q##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i;              \
569         regty.q##i = REGF_32;                                           \
570         regfmt.q##i = REGF_HEX;
571 DO16(REGDEF_NEONQ)
572
573         regsrc.fpscr = REGSRC_FP | REGIX_FPSCR
574         regty.fpscr = REGF_32
575         regfmt.fpscr = 0
576
577         REGDUMP_GPSIZE = 4*REGIX_GPLIM
578         REGDUMP_FPSIZE_D16 = 8 + 16*8
579         REGDUMP_FPSIZE_D32 = 8 + 32*8
580
581 .macro  _saveregs base=nil, off=#0
582         // Save the registers, leaving r4 pointing to the register map.
583
584         // Stash r14.  This is bletcherous: hope we don't get a signal in
585         // the next few instructions.
586         str     r14, [r13, #-REGDUMP_GPSIZE + 14*4]
587
588   .ifnes "\base,\off", "nil,#0"
589         // Collect the effective address for the following dump, leaving it
590         // in the `addr' slot of the dump.
591     .ifeqs "\base", "nil"
592         adrl    r14, \off
593     .else
594         add     r14, \base, \off
595     .endif
596         str     r14, [r13, #-REGDUMP_GPSIZE + 4*REGIX_ADDR]
597   .endif
598
599         // Make space for the register save area.
600         sub     r13, r13, #REGDUMP_GPSIZE
601
602         // Save flags and general-purpose registers.
603         str     r12, [r13, #4*12]
604         bl      regdump_gpsave
605
606         // Make space for the extended registers.
607         sub     r13, r13, r0
608         bl      regdump_xtsave
609
610         // Prepare for calling back into C.
611         ldgot
612         mov     r0, r13
613         bic     r0, r0, #15
614         mov     r13, r0
615 .endm
616
617 .macro  _rstrregs
618         // Restore registers.
619
620         // We assume r4 still points to the register map.
621         bl      regdump_xtrstr
622         mov     r13, r4
623         bl      regdump_gprstr
624         ldr     r14, [r13, #14*4]
625         add     r13, r13, #REGDUMP_GPSIZE
626 .endm
627
628 .macro  _regbase
629         mov     r0, r5
630 .endm
631
632 .macro  _membase
633         mov     r0, r6
634 .endm
635
636 .macro  _reglbl msg
637         adrl    r1, .L$_reglbl$\@
638     _LIT
639 .L$_reglbl$\@:
640         .asciz  "\msg"
641         .balign 4
642     _ENDLIT
643 .endm
644
645 .macro  _regfmt arg
646         movw    r2, #(\arg)&0xffff
647         movt    r2, #((\arg) >> 16)&0xffff
648 .endm
649
650 #endif
651
652 #endif
653
654 /*----- ARM64 -------------------------------------------------------------*/
655
656 #if CPUFAM_ARM64
657
658 #define REGIX_NZCV 32
659 #define REGIX_PC 33
660 #define REGIX_ADDR 34
661 #define REGIX_GPLIM 36
662
663 #define REGIX_FPFLAGS 255
664
665 #if !__ASSEMBLER__
666
667 union v128 { SIMD_COMMON(128); };
668
669 struct gpsave { union gp64 r[REGIX_GPLIM]; };
670
671 struct fpsave {
672   unsigned fpsr, fpcr;
673   union v128 v[32];
674 };
675
676 struct regmap {
677   struct gpsave *gp;
678   struct fpsave *fp;
679 };
680
681 #else
682
683         .extern regdump_gpsave
684         .extern regdump_xtsave
685         .extern regdump_xtrstr
686         .extern regdump_gprstr
687
688         regmap_gp = 0
689         regmap_fp = 8
690         regmap_size = 16
691
692 #define REGDEF_GP(i)                                                    \
693         regsrc.x##i = REGSRC_GP | i;                                    \
694         regty.x##i = REGF_64;                                           \
695         regfmt.x##i = REGF_HEX;                                         \
696         regsrc.w##i = REGSRC_GP | i;                                    \
697         regty.w##i = REGF_32;                                           \
698         regfmt.w##i = REGF_HEX;
699 DO32(REGDEF_GP)
700
701         regsrc.sp = REGSRC_GP | 31
702         regty.sp = REGF_64
703         regfmt.sp = REGF_HEX
704
705         regsrc.pc = REGSRC_GP | REGIX_PC
706         regty.pc = REGF_64
707         regfmt.pc = REGF_HEX
708
709         regsrc.nzcv = REGSRC_GP | REGIX_NZCV
710         regty.nzcv = REGF_32
711         regfmt.nzcv = 0
712
713 #define REGDEF_FP(i)                                                    \
714         regsrc.b##i = REGSRC_FP | i;                                    \
715         regty.b##i = REGF_8;                                            \
716         regfmt.b##i = REGF_HEX;                                         \
717         regsrc.h##i = REGSRC_FP | i;                                    \
718         regty.h##i = REGF_16;                                           \
719         regfmt.h##i = REGF_HEX;                                         \
720         regsrc.s##i = REGSRC_FP | i;                                    \
721         regty.s##i = REGF_32;                                           \
722         regfmt.s##i = REGF_FLT;                                         \
723         regsrc.d##i = REGSRC_FP | i;                                    \
724         regty.d##i = REGF_64;                                           \
725         regfmt.d##i = REGF_FLT;                                         \
726         regsrc.v##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i;              \
727         regty.v##i = REGF_32;                                           \
728         regfmt.v##i = REGF_HEX;
729 DO32(REGDEF_FP)
730
731         regsrc.fpflags = REGSRC_FP | REGIX_FPFLAGS
732         regty.fpflags = REGF_32
733         regfmt.fpflags = 0
734
735         REGDUMP_GPSIZE = 8*REGIX_GPLIM
736         REGDUMP_FPSIZE = 16 + 16 + 32*16
737
738 .macro  _saveregs base=nil, off=#0
739         // Save the registers, leaving x20 pointing to the register map.
740
741         // Stash x30.  This is bletcherous: hope we don't get a signal in
742         // the next few instructions.
743         str     x30, [sp, #-REGDUMP_GPSIZE + 30*8]
744
745   .ifnes "\base,\off", "nil,#0"
746         // Collect the effective address for the following dump, leaving it
747         // in the `addr' slot of the dump.
748     .ifeqs "\base", "nil"
749         adr     x30, \off
750     .else
751         add     x30, \base, \off
752     .endif
753         str     x30, [sp, #-REGDUMP_GPSIZE + 8*REGIX_ADDR]
754   .endif
755
756         // Make space for the register save area.
757         sub     sp, sp, #REGDUMP_GPSIZE
758
759         // Save flags and general-purpose registers.
760         stp     x16, x17, [sp, #8*16]
761         bl      regdump_gpsave
762
763         // Make space for the extended registers.
764         sub     sp, sp, x0
765         bl      regdump_xtsave
766 .endm
767
768 .macro  _rstrregs
769         // Restore registers.
770
771         // We assume x21 still points to the register map.
772         bl      regdump_xtrstr
773         mov     sp, x20
774         bl      regdump_gprstr
775         ldr     x30, [sp, #30*8]
776         add     sp, sp, #REGDUMP_GPSIZE
777 .endm
778
779 .macro  _regbase
780         mov     x0, x21
781 .endm
782
783 .macro  _membase
784         mov     x0, x22
785 .endm
786
787 .macro  _reglbl msg
788         adr     x1, .L$_reglbl$\@
789     _LIT
790 .L$_reglbl$\@:
791         .asciz  "\msg"
792         .balign 4
793     _ENDLIT
794 .endm
795
796 .macro  _regfmt arg
797         movz    w2, #(\arg)&0xffff
798         movk    w2, #((\arg) >> 16)&0xffff, lsl #16
799 .endm
800
801 #endif
802
803 #endif
804
805 /*----- Functions provided ------------------------------------------------*/
806
807 /* --- @regdump_init@ --- *
808  *
809  * Arguments:   ---
810  *
811  * Returns:     ---
812  *
813  * Use:         Performs one-time initialization for register dumping.  In
814  *              particular, this performs CPU feature detection on platforms
815  *              where that is a difficult task: without it, registers
816  *              corresponding to optional architectural features can be
817  *              neither printed nor preserved by the register-dump machinery.
818  */
819
820 #if !__ASSEMBLER__
821 extern void regdump_init(void);
822 #endif
823
824 /* --- @regdump@ --- *
825  *
826  * Arguments:   @const void *base@ = pointer to base structure, corresponding
827  *                      to the @REGF_SRCMASK@ part of @f@
828  *              @const char *lbl@ = label to print
829  *              @uint32 f@ = format control word; see @REGF_...@
830  *
831  * Returns:     ---
832  *
833  * Use:         Dump a register value, or chunk of memory.
834  *
835  *              This function is not usually called directly; instead, use
836  *              the `reg' or `mem' assembler macros.
837  */
838
839 #if !__ASSEMBLER__
840 extern void regdump(const void *base, const char *lbl, uint32 f);
841 #else
842         .extern regdump
843 #endif
844
845 /* --- @regdump_gp@, @regdump_fp@, @regdump_simd@ --- *
846  *
847  * Arguments:   @const struct regmap *map@ = pointer to register map
848  *
849  * Returns:     ---
850  *
851  * Use:         Dump the general-purpose/floating-point/SIMD registers.
852  *
853  *              This function is not usually called directly; instead, use
854  *              the `regdump' assembler macro.
855  */
856
857 #if !__ASSEMBLER__
858 extern void regdump_gp(const struct regmap */*map*/);
859 extern void regdump_fp(const struct regmap */*map*/);
860 extern void regdump_simd(const struct regmap */*map*/);
861 #else
862         .extern regdump_gp
863         .extern regdump_fp
864         .extern regdump_simd
865 #endif
866
867 /* --- @regdump_freshline@ --- *
868  *
869  * Arguments:   ---
870  *
871  * Returns:     ---
872  *
873  * Use:         Begin a fresh line of output.
874  */
875
876 #if !__ASSEMBLER__
877 extern void regdump_freshline(void);
878 #else
879         .extern regdump_freshline
880 #endif
881
882 /*----- Main user interface macros ----------------------------------------*/
883
884 #if __ASSEMBLER__
885
886 .macro  terpri
887         _saveregs
888         callext F(regdump_freshline)
889         _rstrregs
890 .endm
891
892 .macro  reg     lbl, rn, fmt=0
893         _saveregs
894         _regbase
895         _reglbl "\lbl"
896         .L$reg.fmt$\@ = regsrc.\rn | \fmt | \
897                  (((\fmt&REGF_TYMASK) == 0)&regty.\rn) | \
898                  (((\fmt&REGF_FMTMASK) == 0)&regfmt.\rn)
899         _regfmt .L$reg.fmt$\@
900         callext F(regdump)
901         _rstrregs
902 .endm
903
904 .macro  mem     lbl, addr, fmt=0
905         _saveregs \addr
906         _membase
907         _reglbl "\lbl"
908         .L$mem.fmt$\@ = REGSRC_ABS | \fmt | \
909                  (((\fmt&REGF_TYMASK) == 0)&REGF_32) | \
910                  (((\fmt&REGF_FMTMASK) == 0)&REGF_HEX)
911         _regfmt .L$mem.fmt$\@
912         callext F(regdump)
913         _rstrregs
914 .endm
915
916 .macro  regdump gp=nil, fp=nil, simd=nil
917         _saveregs
918   .ifnes "\gp", "nil"
919         _regbase
920         callext F(regdump_gp)
921   .endif
922   .ifnes "\fp", "nil"
923         _regbase
924         callext F(regdump_fp)
925   .endif
926   .ifnes "\simd", "nil"
927         _regbase
928         callext F(regdump_simd)
929   .endif
930         _rstrregs
931 .endm
932
933 #endif
934
935 /*----- That's all, folks -------------------------------------------------*/
936
937 #ifdef __cplusplus
938   }
939 #endif
940
941 #endif