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