base/regdump.h: Pass cooked register index to `REGDEF_GPX86_COMMON'.
[catacomb] / base / regdump.h
CommitLineData
4bc8424a
MW
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. */
69typedef signed char int8;
70typedef short int16;
71typedef int int32;
72#if LONG_MAX >> 31 > 0x7fffffff
73 typedef long int64;
74#else
75 typedef long long int64;
76#endif
77typedef float float32;
78typedef double float64;
79typedef 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
102union gp32 { uint32 u32; int32 i32; PTR32 };
103union 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
189typedef union gp32 gpreg;
190#endif
191#if CPUFAM_AMD64
192typedef union gp64 gpreg;
193#endif
194
195struct gpsave {
196 gpreg gp[REGIX_GPLIM];
197 uint16 seg[REGIX_SEGLIM];
198};
199
200union stmmx {
201 SIMD_COMMON(64);
202#if FLT_RADIX == 2 && LDBL_MANT_DIG == 64
203 long double f80;
204#endif
205unsigned char _pad[16];
206};
207
208union xmm { SIMD_COMMON(128); };
209union ymm { SIMD_COMMON(256); };
210union vreg { union xmm v128[2]; union ymm v256; };
211
212struct 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
246struct 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
256struct 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
e275090f
MW
274#define REGDEF_GPX86_COMMON(rn, ix) \
275 regsrc.e##rn = REGSRC_GP | ix; \
4bc8424a
MW
276 regty.e##rn = REGF_32; \
277 regfmt.e##rn = REGF_HEX; \
e275090f 278 regsrc.r##rn = REGSRC_GP | ix; \
4bc8424a
MW
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; \
e275090f 292 REGDEF_GPX86_COMMON(rn##x, REGIX_##RN##X)
4bc8424a
MW
293REGDEF_GPX86_ABCD(a, A)
294REGDEF_GPX86_ABCD(b, B)
295REGDEF_GPX86_ABCD(c, C)
296REGDEF_GPX86_ABCD(d, D)
297
298 regsrc.eflags = REGSRC_GP | REGIX_FLAGS
299 regty.eflags = REGF_32
82d064a1 300 regfmt.eflags = 0
4bc8424a
MW
301
302#if CPUFAM_AMD64
303 regsrc.rflags = REGSRC_GP | REGIX_FLAGS
304 regty.rflags = REGF_64
82d064a1 305 regfmt.rflags = 0
4bc8424a
MW
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; \
e275090f 315 REGDEF_GPX86_COMMON(rn, REGIX_##RN)
4bc8424a
MW
316REGDEF_GPX86_XP(ip, IP)
317REGDEF_GPX86_XP(si, SI)
318REGDEF_GPX86_XP(di, DI)
319REGDEF_GPX86_XP(bp, BP)
320REGDEF_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
343REGDEF_SEG(ss, SS)
344REGDEF_SEG(cs, CS)
345REGDEF_SEG(ds, DS)
346REGDEF_SEG(es, ES)
347REGDEF_SEG(fs, FS)
348REGDEF_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;
357DO8(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;
366DO8(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 [R_sp(r) - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], R_a(r)
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 R_a(r), \addr
390 mov [R_sp(r) - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], R_a(r)
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 R_sp(r), [R_sp(r) - 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 [esp + 4*REGIX_BX], ebx
404 ldgot
405# endif
a752c20f 406 callext F(regdump_gpsave)
4bc8424a
MW
407
408 // Make space for the extended registers.
409 sub R_sp(r), R_c(r)
a752c20f 410 callext F(regdump_xtsave)
4bc8424a
MW
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 esp, 16
418# elif ABI_WIN
419 sub rsp, 32
420# endif
421 and R_sp(r), ~15
422.endm
423
424.macro _rstrregs
425 // Restore registers.
426
427 // We assume r/ebp still points to the register map.
a752c20f 428 callext F(regdump_xtrstr)
4bc8424a 429 mov R_sp(r), R_bp(r)
a752c20f 430 callext F(regdump_gprstr)
4bc8424a
MW
431 popf
432 lea R_sp(r), [R_sp(r) + REGDUMP_SPADJ]
433.endm
434
435.macro _regbase
436# if CPUFAM_X86
437 mov [esp + 0], ebp
438# elif ABI_SYSV
439 mov rdi, rbp
440# elif ABI_WIN
441 mov rcx, rbp
442# endif
443.endm
444
445.macro _membase
446 mov R_a(r), [R_bp(r) + regmap_gp]
447# if CPUFAM_X86
448 mov eax, [eax + REGIX_ADDR*WORDSZ]
449 mov [esp + 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 [esp + 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 [esp + 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 [esp + 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__
501extern 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
514union neon64 { SIMD_COMMON(64); };
515union neon128 { SIMD_COMMON(128); };
516
517struct gpsave { union gp32 r[REGIX_GPLIM]; };
518
519struct 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
529struct 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;
549DO16(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;
559DO32(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;
565DO32(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;
571DO16(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
19d642aa
MW
646 movw r2, #(\arg)&0xffff
647 movt r2, #((\arg) >> 16)&0xffff
4bc8424a
MW
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
667union v128 { SIMD_COMMON(128); };
668
669struct gpsave { union gp64 r[REGIX_GPLIM]; };
670
671struct fpsave {
672 unsigned fpsr, fpcr;
673 union v128 v[32];
674};
675
676struct 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;
699DO32(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;
729DO32(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
19d642aa
MW
797 movz w2, #(\arg)&0xffff
798 movk w2, #((\arg) >> 16)&0xffff, lsl #16
4bc8424a
MW
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__
821extern 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__
840extern 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__
858extern void regdump_gp(const struct regmap */*map*/);
859extern void regdump_fp(const struct regmap */*map*/);
860extern 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__
877extern 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
a752c20f 888 callext F(regdump_freshline)
4bc8424a
MW
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$\@
a752c20f 900 callext F(regdump)
4bc8424a
MW
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$\@
a752c20f 912 callext F(regdump)
4bc8424a
MW
913 _rstrregs
914.endm
915
916.macro regdump gp=nil, fp=nil, simd=nil
917 _saveregs
918 .ifnes "\gp", "nil"
919 _regbase
a752c20f 920 callext F(regdump_gp)
4bc8424a
MW
921 .endif
922 .ifnes "\fp", "nil"
923 _regbase
a752c20f 924 callext F(regdump_fp)
4bc8424a
MW
925 .endif
926 .ifnes "\simd", "nil"
927 _regbase
a752c20f 928 callext F(regdump_simd)
4bc8424a
MW
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