chiark / gitweb /
progs/perftest.c: Use from Glibc syscall numbers.
[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           // Save general-purpose registers at r/esp; flags, r/eax, and, on
267           // x86, ebx, should have been filled in already, together with the
268           // focus address, in `REGIX_ADDR', if relevant.  Return required
269           // extended save area size in ecx, and leave r/ebp pointing to the
270           // save area.
271
272         .extern regdump_xtsave
273           // Save extended registers at r/esp, leaving r/ebp pointing to the
274           // register map.
275
276         .extern regdump_xtrstr
277           // Restore extended registers from register map in r/ebp, leaving
278           // r/ebp pointing to general-purpose save area.
279
280         .extern regdump_gprstr
281           // Restore general-purpose registers, except r/esp, from save area
282           // at r/ebp.
283
284         regmap_gp = 0*WORDSZ
285         regmap_fx = 1*WORDSZ
286         regmap_avx = 2*WORDSZ
287         regmap_size = 3*WORDSZ
288
289 #define REGDEF_GPX86_COMMON(rn, ix)                                     \
290         regsrc.e##rn = REGSRC_GP | ix;                                  \
291         regty.e##rn = REGF_32;                                          \
292         regfmt.e##rn = REGF_HEX;                                        \
293         regsrc.r##rn = REGSRC_GP | ix;                                  \
294         regty.r##rn = REGF_64;                                          \
295         regfmt.r##rn = REGF_HEX
296
297 #define REGDEF_GPX86_ABCD(rn, RN)                                       \
298         regsrc.rn##hl = (4 << REGF_WDSHIFT) | REGSRC_GP | REGIX_##RN##X; \
299         regty.rn##hl = REGF_8;                                          \
300         regfmt.rn##hl = REGF_HEX;                                       \
301         regsrc.rn##l = REGSRC_GP | REGIX_##RN##X;                       \
302         regty.rn##l = REGF_8;                                           \
303         regfmt.rn##l = REGF_HEX;                                        \
304         regsrc.rn##x = REGSRC_GP | REGIX_##RN##X;                       \
305         regty.rn##x = REGF_16;                                          \
306         regfmt.rn##x = REGF_HEX;                                        \
307         REGDEF_GPX86_COMMON(rn##x, REGIX_##RN##X)
308 REGDEF_GPX86_ABCD(a, A)
309 REGDEF_GPX86_ABCD(b, B)
310 REGDEF_GPX86_ABCD(c, C)
311 REGDEF_GPX86_ABCD(d, D)
312
313         regsrc.eflags = REGSRC_GP | REGIX_FLAGS
314         regty.eflags = REGF_32
315         regfmt.eflags = 0
316
317 #if CPUFAM_AMD64
318         regsrc.rflags = REGSRC_GP | REGIX_FLAGS
319         regty.rflags = REGF_64
320         regfmt.rflags = 0
321 #endif
322
323 #define REGDEF_GPX86_XP(rn, RN)                                         \
324         regsrc.rn##l = REGSRC_GP | REGIX_##RN;                          \
325         regty.rn##l = REGF_8;                                           \
326         regfmt.rn##l = REGF_HEX;                                        \
327         regsrc.rn = REGSRC_GP | REGIX_##RN;                             \
328         regty.rn = REGF_16;                                             \
329         regfmt.rn = REGF_HEX;                                           \
330         REGDEF_GPX86_COMMON(rn, REGIX_##RN)
331 REGDEF_GPX86_XP(ip, IP)
332 REGDEF_GPX86_XP(si, SI)
333 REGDEF_GPX86_XP(di, DI)
334 REGDEF_GPX86_XP(bp, BP)
335 REGDEF_GPX86_XP(sp, SP)
336
337 #if CPUFAM_AMD64
338 #  define REGDEF_GPAMD64(i)                                             \
339         regsrc.r##i##b = REGSRC_GP | REGIX_R##i;                        \
340         regty.r##i##b = REGF_8;                                         \
341         regfmt.r##i##b = REGF_HEX;                                      \
342         regsrc.r##i##w = REGSRC_GP | REGIX_R##i;                        \
343         regty.r##i##w = REGF_16;                                        \
344         regfmt.r##i##w = REGF_HEX;                                      \
345         regsrc.r##i##d = REGSRC_GP | REGIX_R##i;                        \
346         regty.r##i##d = REGF_32;                                        \
347         regfmt.r##i##d = REGF_HEX;                                      \
348         regsrc.r##i = REGSRC_GP | REGIX_R##i;                           \
349         regty.r##i = REGF_64;                                           \
350         regfmt.r##i = REGF_HEX;
351   DOHI8(REGDEF_GPAMD64)
352 #endif
353
354 #define REGDEF_SEG(rn, RN)                                              \
355         regsrc.rn = REGSRC_SEG | REGIX_##RN;                            \
356         regty.rn = REGF_16;                                             \
357         regfmt.rn = REGF_HEX
358 REGDEF_SEG(ss, SS)
359 REGDEF_SEG(cs, CS)
360 REGDEF_SEG(ds, DS)
361 REGDEF_SEG(es, ES)
362 REGDEF_SEG(fs, FS)
363 REGDEF_SEG(gs, GS)
364
365 #define REGDEF_STMMX(i)                                                 \
366         regsrc.st##i = REGSRC_STMMX | i;                                \
367         regty.st##i = REGF_80;                                          \
368         regfmt.st##i = REGF_FLT;                                        \
369         regsrc.mm##i = (6 << REGF_WDSHIFT) | REGSRC_STMMX | i;          \
370         regty.mm##i = REGF_16;                                          \
371         regfmt.mm##i = REGF_HEX;
372 DO8(REGDEF_STMMX)
373
374 #define REGDEF_SIMD(i)                                                  \
375         regsrc.xmm##i = (7 << REGF_WDSHIFT) | REGSRC_SIMD | i;          \
376         regty.xmm##i = REGF_32;                                         \
377         regfmt.xmm##i = REGF_HEX;                                       \
378         regsrc.ymm##i = (8 << REGF_WDSHIFT) | REGSRC_SIMD | i;          \
379         regty.ymm##i = REGF_32;                                         \
380         regfmt.ymm##i = REGF_HEX;
381 DO8(REGDEF_SIMD)
382 #if CPUFAM_AMD64
383   DOHI8(REGDEF_SIMD)
384 #endif
385
386         REGDUMP_GPSIZE = REGIX_GPLIM*WORDSZ + REGIX_SEGLIM*2
387
388 #  if CPUFAM_AMD64 && ABI_SYSV
389         REGDUMP_SPADJ = REGDUMP_GPSIZE + WORDSZ + 128
390 #  else
391         REGDUMP_SPADJ = REGDUMP_GPSIZE + WORDSZ
392 #  endif
393
394 .macro  _saveregs addr=nil
395         // Save the registers, leaving r/ebp pointing to the register map.
396
397         // Stash r/eax.  This is bletcherous: hope we don't get a signal in
398         // the next few instructions.
399         mov     [SP - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], AX
400
401   .ifnes "\addr", "nil"
402         // Collect the focus address for the following dump, leaving it in
403         // the `addr' slot of the dump.
404         lea     AX, \addr
405         mov     [SP - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], AX
406   .endif
407
408         // Make space for the register save area.  On AMD64 with System/V
409         // ABI, also skip the red zone.  Use `lea' here to preserve the
410         // flags.
411         lea     SP, [SP - REGDUMP_SPADJ]
412
413         // Save flags and general-purpose registers.  On 32-bit x86, we save
414         // ebx here and establish a GOT pointer here for the benefit of the
415         // PLT-indirect calls made later on.
416         pushf
417 #  if CPUFAM_X86
418         mov     [SP + 4*REGIX_BX], ebx
419         ldgot
420 #  endif
421         callext F(regdump_gpsave)
422
423         // Make space for the extended registers.
424         sub     SP, CX
425         callext F(regdump_xtsave)
426
427         // Prepare for calling back into C.  On 32-bit x86, leave space for
428         // the arguments and set up the GOT pointer; on AMD64 Windows, leave
429         // the `shadow space' for the called-function's arguments.  Also,
430         // forcibly align the stack pointer to a 16-byte boundary.
431 #  if CPUFAM_X86
432         sub     SP, 16
433 #  elif ABI_WIN
434         sub     SP, 32
435 #  endif
436         and     SP, ~15
437 .endm
438
439 .macro  _rstrregs
440         // Restore registers.
441
442         // We assume r/ebp still points to the register map.
443         callext F(regdump_xtrstr)
444         mov     SP, BP
445         callext F(regdump_gprstr)
446         popf
447         lea     SP, [SP + REGDUMP_SPADJ]
448 .endm
449
450 .macro  _nilbase
451 #  if CPUFAM_X86
452         xor     eax, eax
453         mov     [SP + 0], eax
454 #  elif ABI_SYSV
455         xor     edi, edi
456 #  elif ABI_WIN
457         xor     ecx, ecx
458 #  endif
459 .endm
460
461 .macro  _regbase
462 #  if CPUFAM_X86
463         mov     [SP + 0], BP
464 #  elif ABI_SYSV
465         mov     rdi, BP
466 #  elif ABI_WIN
467         mov     rcx, BP
468 #  endif
469 .endm
470
471 .macro  _membase
472         mov     AX, [BP + regmap_gp]
473 #  if CPUFAM_X86
474         mov     eax, [eax + REGIX_ADDR*WORDSZ]
475         mov     [SP + 0], eax
476 #  elif ABI_SYSV
477         mov     rdi, [rax + REGIX_ADDR*WORDSZ]
478 #  elif ABI_WIN
479         mov     rcx, [rax + REGIX_ADDR*WORDSZ]
480 #  endif
481 .endm
482
483 .macro  _reglbl msg
484   .ifeqs "\msg", ""
485 #  if CPUFAM_X86
486         mov     dword ptr [SP + 4], 0
487 #  elif ABI_SYSV
488         xor     esi, esi
489 #  elif ABI_WIN
490         xor     edx, edx
491 #  endif
492   .else
493 #  if CPUFAM_X86
494         lea     eax, [INTADDR(.L$_reglbl$\@)]
495         mov     [SP + 4], eax
496 #  elif ABI_SYSV
497         lea     rsi, [INTADDR(.L$_reglbl$\@)]
498 #  elif ABI_WIN
499         lea     rdx, [INTADDR(.L$_reglbl$\@)]
500 #  endif
501     _LIT
502 .L$_reglbl$\@:
503         .asciz  "\msg"
504     _ENDLIT
505   .endif
506 .endm
507
508 .macro  _regfmt arg
509 #  if CPUFAM_X86
510         mov     dword ptr [SP + 8], \arg
511 #  elif ABI_SYSV
512         mov     edx, \arg
513 #  elif ABI_WIN
514         mov     r8d, \arg
515 #  endif
516 .endm
517
518 #endif
519
520 #endif
521
522 /*----- ARM32 -------------------------------------------------------------*/
523
524 #if CPUFAM_ARMEL
525
526 #if !__ASSEMBLER__
527 extern unsigned regdump__flags;
528 #endif
529 #define REGF_VFP 1u
530 #define REGF_D32 2u
531
532 #define REGIX_CPSR 16
533 #define REGIX_ADDR 17
534 #define REGIX_GPLIM 18
535
536 #define REGIX_FPSCR 255
537
538 #if !__ASSEMBLER__
539
540 union neon64 { SIMD_COMMON(64); };
541 union neon128 { SIMD_COMMON(128); };
542
543 struct gpsave { union gp32 r[REGIX_GPLIM]; };
544
545 struct fpsave {
546   unsigned fpscr;
547   unsigned _pad0;
548   union {
549     float32 s[32];
550     union neon64 d[32];
551     union neon128 q[16];
552   } u;
553 };
554
555 struct regmap {
556   struct gpsave *gp;
557   struct fpsave *fp;
558 };
559
560 #else
561
562         .extern regdump_gpsave
563           // Save general-purpose registers at r13; r12 and r14 should have
564           // been filled in already, along with the focus address in
565           // `REGIX_ADDR', if relevant.  Return required extended save area
566           // size in r0, leave r4 pointing to the save area, and set r6 to
567           // the focus address.
568
569         .extern regdump_xtsave
570           // Save extended registers at r13, leaving r5 pointing to the
571           // register map.
572
573         .extern regdump_xtrstr
574           // Restore extended registers from register map at r5.
575
576         .extern regdump_gprstr
577           // Restore general-purpose registers, except r13 and r14, from save
578           // area at r4.
579
580         regmap_gp = 0
581         regmap_fp = 4
582         regmap_size = 8
583
584 #define REGDEF_GP(i)                                                    \
585         regsrc.r##i = REGSRC_GP | i;                                    \
586         regty.r##i = REGF_32;                                           \
587         regfmt.r##i = REGF_HEX;
588 DO16(REGDEF_GP)
589
590         regsrc.cpsr = REGSRC_GP | REGIX_CPSR
591         regty.cpsr = REGF_32
592         regfmt.cpsr = 0
593
594 #define REGDEF_NEONS(i)                                                 \
595         regsrc.s##i = REGSRC_FP | i;                                    \
596         regty.s##i = REGF_32;                                           \
597         regfmt.s##i = REGF_FLT;
598 DO32(REGDEF_NEONS)
599
600 #define REGDEF_NEOND(i)                                                 \
601         regsrc.d##i = (6 << REGF_WDSHIFT) | REGSRC_FP | i;              \
602         regty.d##i = REGF_32;                                           \
603         regfmt.d##i = REGF_HEX;
604 DO32(REGDEF_NEOND)
605
606 #define REGDEF_NEONQ(i)                                                 \
607         regsrc.q##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i;              \
608         regty.q##i = REGF_32;                                           \
609         regfmt.q##i = REGF_HEX;
610 DO16(REGDEF_NEONQ)
611
612         regsrc.fpscr = REGSRC_FP | REGIX_FPSCR
613         regty.fpscr = REGF_32
614         regfmt.fpscr = 0
615
616         REGDUMP_GPSIZE = 4*REGIX_GPLIM
617         REGDUMP_FPSIZE_D16 = 8 + 16*8
618         REGDUMP_FPSIZE_D32 = 8 + 32*8
619
620 .macro  _saveregs base=nil, off=#0
621         // Save the registers, leaving r4 pointing to the register map.
622
623         // Stash r14.  This is bletcherous: hope we don't get a signal in
624         // the next few instructions.
625         str     r14, [r13, #-REGDUMP_GPSIZE + 14*4]
626
627   .ifnes "\base,\off", "nil,#0"
628         // Collect the focus address for the following dump, leaving it in
629         // the `addr' slot of the dump.
630     .ifeqs "\base", "nil"
631         adrl    r14, \off
632     .else
633         add     r14, \base, \off
634     .endif
635         str     r14, [r13, #-REGDUMP_GPSIZE + 4*REGIX_ADDR]
636   .endif
637
638         // Make space for the register save area.
639         sub     r13, r13, #REGDUMP_GPSIZE
640
641         // Save flags and general-purpose registers.
642         mrs     r14, cpsr
643         str     r14, [r13, #4*REGIX_CPSR]
644         str     r12, [r13, #4*12]
645         bl      regdump_gpsave
646
647         // Make space for the extended registers.
648         sub     r13, r13, r0
649         bl      regdump_xtsave
650
651         // Prepare for calling back into C.
652         ldgot
653         mov     r0, r13
654         bic     r0, r0, #15
655         mov     r13, r0
656 .endm
657
658 .macro  _rstrregs
659         // Restore registers.
660
661         // We assume r4 still points to the register map.
662         bl      regdump_xtrstr
663         mov     r13, r4
664         bl      regdump_gprstr
665         ldr     r14, [r13, #14*4]
666         add     r13, r13, #REGDUMP_GPSIZE
667 .endm
668
669 .macro  _nilbase
670         mov     r0, #0
671 .endm
672
673 .macro  _regbase
674         mov     r0, r5
675 .endm
676
677 .macro  _membase
678         mov     r0, r6
679 .endm
680
681 .macro  _reglbl msg
682         adrl    r1, .L$_reglbl$\@
683     _LIT
684 .L$_reglbl$\@:
685         .asciz  "\msg"
686         .balign 4
687     _ENDLIT
688 .endm
689
690 .macro  _regfmt arg
691         movw    r2, #(\arg)&0xffff
692         movt    r2, #((\arg) >> 16)&0xffff
693 .endm
694
695 #endif
696
697 #endif
698
699 /*----- ARM64 -------------------------------------------------------------*/
700
701 #if CPUFAM_ARM64
702
703 #define REGIX_NZCV 32
704 #define REGIX_PC 33
705 #define REGIX_ADDR 34
706 #define REGIX_GPLIM 36
707
708 #define REGIX_FPFLAGS 255
709
710 #if !__ASSEMBLER__
711
712 union v128 { SIMD_COMMON(128); };
713
714 struct gpsave { union gp64 r[REGIX_GPLIM]; };
715
716 struct fpsave {
717   unsigned fpsr, fpcr;
718   union v128 v[32];
719 };
720
721 struct regmap {
722   struct gpsave *gp;
723   struct fpsave *fp;
724 };
725
726 #else
727
728         .extern regdump_gpsave
729           // Save general-purpose registers at sp; x16, x17, and x30, should
730           // have been filled in already, along with the focus address in
731           // `REGIX_ADDR', if relevant.  Return required extended save area
732           // size in x0, leave x20 pointing to the save area, and set x22 to
733           // the focus address.
734
735         .extern regdump_xtsave
736           // Save extended registers at sp, leaving x21 pointing to the
737           // register map.
738
739         .extern regdump_xtrstr
740           // Restore extended registers from register map at x21.
741
742         .extern regdump_gprstr
743           // Restore general-purpose registers, except sp and x30, from save
744           // area at x20.
745
746         regmap_gp = 0
747         regmap_fp = 8
748         regmap_size = 16
749
750 #define REGDEF_GP(i)                                                    \
751         regsrc.x##i = REGSRC_GP | i;                                    \
752         regty.x##i = REGF_64;                                           \
753         regfmt.x##i = REGF_HEX;                                         \
754         regsrc.w##i = REGSRC_GP | i;                                    \
755         regty.w##i = REGF_32;                                           \
756         regfmt.w##i = REGF_HEX;
757 DO32(REGDEF_GP)
758
759         regsrc.sp = REGSRC_GP | 31
760         regty.sp = REGF_64
761         regfmt.sp = REGF_HEX
762
763         regsrc.pc = REGSRC_GP | REGIX_PC
764         regty.pc = REGF_64
765         regfmt.pc = REGF_HEX
766
767         regsrc.nzcv = REGSRC_GP | REGIX_NZCV
768         regty.nzcv = REGF_32
769         regfmt.nzcv = 0
770
771 #define REGDEF_FP(i)                                                    \
772         regsrc.b##i = REGSRC_FP | i;                                    \
773         regty.b##i = REGF_8;                                            \
774         regfmt.b##i = REGF_HEX;                                         \
775         regsrc.h##i = REGSRC_FP | i;                                    \
776         regty.h##i = REGF_16;                                           \
777         regfmt.h##i = REGF_HEX;                                         \
778         regsrc.s##i = REGSRC_FP | i;                                    \
779         regty.s##i = REGF_32;                                           \
780         regfmt.s##i = REGF_FLT;                                         \
781         regsrc.d##i = REGSRC_FP | i;                                    \
782         regty.d##i = REGF_64;                                           \
783         regfmt.d##i = REGF_FLT;                                         \
784         regsrc.v##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i;              \
785         regty.v##i = REGF_32;                                           \
786         regfmt.v##i = REGF_HEX;
787 DO32(REGDEF_FP)
788
789         regsrc.fpflags = REGSRC_FP | REGIX_FPFLAGS
790         regty.fpflags = REGF_32
791         regfmt.fpflags = 0
792
793         REGDUMP_GPSIZE = 8*REGIX_GPLIM
794         REGDUMP_FPSIZE = 16 + 16 + 32*16
795
796 .macro  _saveregs base=nil, off=#0
797         // Save the registers, leaving x20 pointing to the register map.
798
799         // Stash x30.  This is bletcherous: hope we don't get a signal in
800         // the next few instructions.
801         str     x30, [sp, #-REGDUMP_GPSIZE + 30*8]
802
803   .ifnes "\base,\off", "nil,#0"
804         // Collect the focus address for the following dump, leaving it in
805         // the `addr' slot of the dump.
806     .ifeqs "\base", "nil"
807         adr     x30, \off
808     .else
809         add     x30, \base, \off
810     .endif
811         str     x30, [sp, #-REGDUMP_GPSIZE + 8*REGIX_ADDR]
812   .endif
813
814         // Make space for the register save area.
815         sub     sp, sp, #REGDUMP_GPSIZE
816
817         // Save flags and general-purpose registers.  The PLT linkage code
818         // makes free with x8--x17, so we must save those here.
819         mrs     x30, nzcv
820         str     x30, [sp, #8*REGIX_NZCV]
821         stp     x8, x9, [sp, #64]
822         stp     x10, x11, [sp, #80]
823         stp     x12, x13, [sp, #96]
824         stp     x14, x15, [sp, #112]
825         stp     x16, x17, [sp, #128]
826         bl      regdump_gpsave
827
828         // Make space for the extended registers.
829         sub     sp, sp, x0
830         bl      regdump_xtsave
831 .endm
832
833 .macro  _rstrregs
834         // Restore registers.
835
836         // We assume x21 still points to the register map.
837         bl      regdump_xtrstr
838         mov     sp, x20
839         bl      regdump_gprstr
840         ldr     x30, [sp, #30*8]
841         add     sp, sp, #REGDUMP_GPSIZE
842 .endm
843
844 .macro  _nilbase
845         mov     x0, #0
846 .endm
847
848 .macro  _regbase
849         mov     x0, x21
850 .endm
851
852 .macro  _membase
853         mov     x0, x22
854 .endm
855
856 .macro  _reglbl msg
857         adr     x1, .L$_reglbl$\@
858     _LIT
859 .L$_reglbl$\@:
860         .asciz  "\msg"
861         .balign 4
862     _ENDLIT
863 .endm
864
865 .macro  _regfmt arg
866         movz    w2, #(\arg)&0xffff
867         movk    w2, #((\arg) >> 16)&0xffff, lsl #16
868 .endm
869
870 #endif
871
872 #endif
873
874 /*----- Functions provided ------------------------------------------------*/
875
876 /* --- @regdump_init@ --- *
877  *
878  * Arguments:   ---
879  *
880  * Returns:     ---
881  *
882  * Use:         Performs one-time initialization for register dumping.  In
883  *              particular, this performs CPU feature detection on platforms
884  *              where that is a difficult task: without it, registers
885  *              corresponding to optional architectural features can be
886  *              neither printed nor preserved by the register-dump machinery.
887  */
888
889 #if !__ASSEMBLER__
890 extern void regdump_init(void);
891 #endif
892
893 /* --- @regdump@ --- *
894  *
895  * Arguments:   @const void *base@ = pointer to base structure, corresponding
896  *                      to the @REGF_SRCMASK@ part of @f@
897  *              @const char *lbl@ = label to print
898  *              @uint32 f@ = format control word; see @REGF_...@
899  *
900  * Returns:     ---
901  *
902  * Use:         Dump a register value, or chunk of memory.
903  *
904  *              This function is not usually called directly; instead, use
905  *              the `reg' or `mem' assembler macros.
906  */
907
908 #if !__ASSEMBLER__
909 extern void regdump(const void *base, const char *lbl, uint32 f);
910 #else
911         .extern regdump
912 #endif
913
914 /* --- @regdump_gp@, @regdump_fp@, @regdump_simd@ --- *
915  *
916  * Arguments:   @const struct regmap *map@ = pointer to register map
917  *
918  * Returns:     ---
919  *
920  * Use:         Dump the general-purpose/floating-point/SIMD registers.
921  *
922  *              This function is not usually called directly; instead, use
923  *              the `regdump' assembler macro.
924  */
925
926 #if !__ASSEMBLER__
927 extern void regdump_gp(const struct regmap */*map*/);
928 extern void regdump_fp(const struct regmap */*map*/);
929 extern void regdump_simd(const struct regmap */*map*/);
930 #else
931         .extern regdump_gp
932         .extern regdump_fp
933         .extern regdump_simd
934 #endif
935
936 /* --- @regdump_freshline@ --- *
937  *
938  * Arguments:   ---
939  *
940  * Returns:     ---
941  *
942  * Use:         Begin a fresh line of output.
943  */
944
945 #if !__ASSEMBLER__
946 extern void regdump_freshline(void);
947 #else
948         .extern regdump_freshline
949 #endif
950
951 /*----- Main user interface macros ----------------------------------------*/
952
953 #if __ASSEMBLER__
954
955 .macro  terpri
956         _saveregs
957         callext F(regdump_freshline)
958         _rstrregs
959 .endm
960
961 .macro  msg     lbl
962         _saveregs
963         _nilbase
964         _reglbl "\lbl"
965         _regfmt REGSRC_NONE | (1 << REGF_WDSHIFT)
966         callext F(regdump)
967         _rstrregs
968 .endm
969
970 .macro  reg     lbl, rn, fmt=0
971         _saveregs
972         _regbase
973         _reglbl "\lbl"
974         .L$reg.fmt$\@ = regsrc.\rn | \fmt | \
975                  (((\fmt&REGF_TYMASK) == 0)&regty.\rn) | \
976                  (((\fmt&REGF_FMTMASK) == 0)&regfmt.\rn)
977         _regfmt .L$reg.fmt$\@
978         callext F(regdump)
979         _rstrregs
980 .endm
981
982 .macro  mem     lbl, addr, fmt=0
983         _saveregs \addr
984         _membase
985         _reglbl "\lbl"
986         .L$mem.fmt$\@ = REGSRC_ABS | \fmt | \
987                  (((\fmt&REGF_TYMASK) == 0)&REGF_32) | \
988                  (((\fmt&REGF_FMTMASK) == 0)&REGF_HEX)
989         _regfmt .L$mem.fmt$\@
990         callext F(regdump)
991         _rstrregs
992 .endm
993
994 .macro  regdump gp=nil, fp=nil, simd=nil
995         _saveregs
996   .ifnes "\gp", "nil"
997         _regbase
998         callext F(regdump_gp)
999   .endif
1000   .ifnes "\fp", "nil"
1001         _regbase
1002         callext F(regdump_fp)
1003   .endif
1004   .ifnes "\simd", "nil"
1005         _regbase
1006         callext F(regdump_simd)
1007   .endif
1008         _rstrregs
1009 .endm
1010
1011 #endif
1012
1013 /*----- That's all, folks -------------------------------------------------*/
1014
1015 #ifdef __cplusplus
1016   }
1017 #endif
1018
1019 #endif