base/regdump-arm64.S, base/regdump.h: Save NZCV and x8--x15 early.
[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 */
cd303963 138#define REGSRC_NONE 0x0f000000 /* just a message */
4bc8424a
MW
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
190typedef union gp32 gpreg;
191#endif
192#if CPUFAM_AMD64
193typedef union gp64 gpreg;
194#endif
195
196struct gpsave {
197 gpreg gp[REGIX_GPLIM];
198 uint16 seg[REGIX_SEGLIM];
199};
200
201union stmmx {
202 SIMD_COMMON(64);
203#if FLT_RADIX == 2 && LDBL_MANT_DIG == 64
204 long double f80;
205#endif
206unsigned char _pad[16];
207};
208
209union xmm { SIMD_COMMON(128); };
210union ymm { SIMD_COMMON(256); };
211union vreg { union xmm v128[2]; union ymm v256; };
212
213struct 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
247struct 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
257struct 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
e275090f
MW
275#define REGDEF_GPX86_COMMON(rn, ix) \
276 regsrc.e##rn = REGSRC_GP | ix; \
4bc8424a
MW
277 regty.e##rn = REGF_32; \
278 regfmt.e##rn = REGF_HEX; \
e275090f 279 regsrc.r##rn = REGSRC_GP | ix; \
4bc8424a
MW
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; \
e275090f 293 REGDEF_GPX86_COMMON(rn##x, REGIX_##RN##X)
4bc8424a
MW
294REGDEF_GPX86_ABCD(a, A)
295REGDEF_GPX86_ABCD(b, B)
296REGDEF_GPX86_ABCD(c, C)
297REGDEF_GPX86_ABCD(d, D)
298
299 regsrc.eflags = REGSRC_GP | REGIX_FLAGS
300 regty.eflags = REGF_32
82d064a1 301 regfmt.eflags = 0
4bc8424a
MW
302
303#if CPUFAM_AMD64
304 regsrc.rflags = REGSRC_GP | REGIX_FLAGS
305 regty.rflags = REGF_64
82d064a1 306 regfmt.rflags = 0
4bc8424a
MW
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; \
e275090f 316 REGDEF_GPX86_COMMON(rn, REGIX_##RN)
4bc8424a
MW
317REGDEF_GPX86_XP(ip, IP)
318REGDEF_GPX86_XP(si, SI)
319REGDEF_GPX86_XP(di, DI)
320REGDEF_GPX86_XP(bp, BP)
321REGDEF_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
344REGDEF_SEG(ss, SS)
345REGDEF_SEG(cs, CS)
346REGDEF_SEG(ds, DS)
347REGDEF_SEG(es, ES)
348REGDEF_SEG(fs, FS)
349REGDEF_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;
358DO8(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;
367DO8(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.
a90d420c 385 mov [SP - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], AX
4bc8424a
MW
386
387 .ifnes "\addr", "nil"
388 // Collect the effective address for the following dump, leaving it
389 // in the `addr' slot of the dump.
a90d420c
MW
390 lea AX, \addr
391 mov [SP - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], AX
4bc8424a
MW
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.
a90d420c 397 lea SP, [SP - REGDUMP_SPADJ]
4bc8424a
MW
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
a90d420c 404 mov [SP + 4*REGIX_BX], ebx
4bc8424a
MW
405 ldgot
406# endif
a752c20f 407 callext F(regdump_gpsave)
4bc8424a
MW
408
409 // Make space for the extended registers.
a90d420c 410 sub SP, CX
a752c20f 411 callext F(regdump_xtsave)
4bc8424a
MW
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
a90d420c 418 sub SP, 16
4bc8424a 419# elif ABI_WIN
a90d420c 420 sub SP, 32
4bc8424a 421# endif
a90d420c 422 and SP, ~15
4bc8424a
MW
423.endm
424
425.macro _rstrregs
426 // Restore registers.
427
428 // We assume r/ebp still points to the register map.
a752c20f 429 callext F(regdump_xtrstr)
a90d420c 430 mov SP, BP
a752c20f 431 callext F(regdump_gprstr)
4bc8424a 432 popf
a90d420c 433 lea SP, [SP + REGDUMP_SPADJ]
4bc8424a
MW
434.endm
435
cd303963
MW
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
4bc8424a
MW
447.macro _regbase
448# if CPUFAM_X86
a90d420c 449 mov [SP + 0], BP
4bc8424a 450# elif ABI_SYSV
a90d420c 451 mov rdi, BP
4bc8424a 452# elif ABI_WIN
a90d420c 453 mov rcx, BP
4bc8424a
MW
454# endif
455.endm
456
457.macro _membase
a90d420c 458 mov AX, [BP + regmap_gp]
4bc8424a
MW
459# if CPUFAM_X86
460 mov eax, [eax + REGIX_ADDR*WORDSZ]
a90d420c 461 mov [SP + 0], eax
4bc8424a
MW
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
a90d420c 472 mov dword ptr [SP + 4], 0
4bc8424a
MW
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$\@)]
a90d420c 481 mov [SP + 4], eax
4bc8424a
MW
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
a90d420c 496 mov dword ptr [SP + 8], \arg
4bc8424a
MW
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__
513extern 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
526union neon64 { SIMD_COMMON(64); };
527union neon128 { SIMD_COMMON(128); };
528
529struct gpsave { union gp32 r[REGIX_GPLIM]; };
530
531struct 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
541struct 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;
561DO16(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;
571DO32(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;
577DO32(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;
583DO16(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.
6a3d653c
MW
615 mrs r14, cpsr
616 str r14, [r13, #4*REGIX_CPSR]
4bc8424a
MW
617 str r12, [r13, #4*12]
618 bl regdump_gpsave
619
620 // Make space for the extended registers.
621 sub r13, r13, r0
622 bl regdump_xtsave
623
624 // Prepare for calling back into C.
625 ldgot
626 mov r0, r13
627 bic r0, r0, #15
628 mov r13, r0
629.endm
630
631.macro _rstrregs
632 // Restore registers.
633
634 // We assume r4 still points to the register map.
635 bl regdump_xtrstr
636 mov r13, r4
637 bl regdump_gprstr
638 ldr r14, [r13, #14*4]
639 add r13, r13, #REGDUMP_GPSIZE
640.endm
641
cd303963
MW
642.macro _nilbase
643 mov r0, #0
644.endm
645
4bc8424a
MW
646.macro _regbase
647 mov r0, r5
648.endm
649
650.macro _membase
651 mov r0, r6
652.endm
653
654.macro _reglbl msg
655 adrl r1, .L$_reglbl$\@
656 _LIT
657.L$_reglbl$\@:
658 .asciz "\msg"
659 .balign 4
660 _ENDLIT
661.endm
662
663.macro _regfmt arg
19d642aa
MW
664 movw r2, #(\arg)&0xffff
665 movt r2, #((\arg) >> 16)&0xffff
4bc8424a
MW
666.endm
667
668#endif
669
670#endif
671
672/*----- ARM64 -------------------------------------------------------------*/
673
674#if CPUFAM_ARM64
675
676#define REGIX_NZCV 32
677#define REGIX_PC 33
678#define REGIX_ADDR 34
679#define REGIX_GPLIM 36
680
681#define REGIX_FPFLAGS 255
682
683#if !__ASSEMBLER__
684
685union v128 { SIMD_COMMON(128); };
686
687struct gpsave { union gp64 r[REGIX_GPLIM]; };
688
689struct fpsave {
690 unsigned fpsr, fpcr;
691 union v128 v[32];
692};
693
694struct regmap {
695 struct gpsave *gp;
696 struct fpsave *fp;
697};
698
699#else
700
701 .extern regdump_gpsave
702 .extern regdump_xtsave
703 .extern regdump_xtrstr
704 .extern regdump_gprstr
705
706 regmap_gp = 0
707 regmap_fp = 8
708 regmap_size = 16
709
710#define REGDEF_GP(i) \
711 regsrc.x##i = REGSRC_GP | i; \
712 regty.x##i = REGF_64; \
713 regfmt.x##i = REGF_HEX; \
714 regsrc.w##i = REGSRC_GP | i; \
715 regty.w##i = REGF_32; \
716 regfmt.w##i = REGF_HEX;
717DO32(REGDEF_GP)
718
719 regsrc.sp = REGSRC_GP | 31
720 regty.sp = REGF_64
721 regfmt.sp = REGF_HEX
722
723 regsrc.pc = REGSRC_GP | REGIX_PC
724 regty.pc = REGF_64
725 regfmt.pc = REGF_HEX
726
727 regsrc.nzcv = REGSRC_GP | REGIX_NZCV
728 regty.nzcv = REGF_32
729 regfmt.nzcv = 0
730
731#define REGDEF_FP(i) \
732 regsrc.b##i = REGSRC_FP | i; \
733 regty.b##i = REGF_8; \
734 regfmt.b##i = REGF_HEX; \
735 regsrc.h##i = REGSRC_FP | i; \
736 regty.h##i = REGF_16; \
737 regfmt.h##i = REGF_HEX; \
738 regsrc.s##i = REGSRC_FP | i; \
739 regty.s##i = REGF_32; \
740 regfmt.s##i = REGF_FLT; \
741 regsrc.d##i = REGSRC_FP | i; \
742 regty.d##i = REGF_64; \
743 regfmt.d##i = REGF_FLT; \
744 regsrc.v##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i; \
745 regty.v##i = REGF_32; \
746 regfmt.v##i = REGF_HEX;
747DO32(REGDEF_FP)
748
749 regsrc.fpflags = REGSRC_FP | REGIX_FPFLAGS
750 regty.fpflags = REGF_32
751 regfmt.fpflags = 0
752
753 REGDUMP_GPSIZE = 8*REGIX_GPLIM
754 REGDUMP_FPSIZE = 16 + 16 + 32*16
755
756.macro _saveregs base=nil, off=#0
757 // Save the registers, leaving x20 pointing to the register map.
758
759 // Stash x30. This is bletcherous: hope we don't get a signal in
760 // the next few instructions.
761 str x30, [sp, #-REGDUMP_GPSIZE + 30*8]
762
763 .ifnes "\base,\off", "nil,#0"
764 // Collect the effective address for the following dump, leaving it
765 // in the `addr' slot of the dump.
766 .ifeqs "\base", "nil"
767 adr x30, \off
768 .else
769 add x30, \base, \off
770 .endif
771 str x30, [sp, #-REGDUMP_GPSIZE + 8*REGIX_ADDR]
772 .endif
773
774 // Make space for the register save area.
775 sub sp, sp, #REGDUMP_GPSIZE
776
818bad9b
MW
777 // Save flags and general-purpose registers. The PLT linkage code
778 // makes free with x8--x17, so we must save those here.
779 mrs x30, nzcv
780 str x30, [sp, #8*REGIX_NZCV]
781 stp x8, x9, [sp, #64]
782 stp x10, x11, [sp, #80]
783 stp x12, x13, [sp, #96]
784 stp x14, x15, [sp, #112]
785 stp x16, x17, [sp, #128]
4bc8424a
MW
786 bl regdump_gpsave
787
788 // Make space for the extended registers.
789 sub sp, sp, x0
790 bl regdump_xtsave
791.endm
792
793.macro _rstrregs
794 // Restore registers.
795
796 // We assume x21 still points to the register map.
797 bl regdump_xtrstr
798 mov sp, x20
799 bl regdump_gprstr
800 ldr x30, [sp, #30*8]
801 add sp, sp, #REGDUMP_GPSIZE
802.endm
803
cd303963
MW
804.macro _nilbase
805 mov x0, #0
806.endm
807
4bc8424a
MW
808.macro _regbase
809 mov x0, x21
810.endm
811
812.macro _membase
813 mov x0, x22
814.endm
815
816.macro _reglbl msg
817 adr x1, .L$_reglbl$\@
818 _LIT
819.L$_reglbl$\@:
820 .asciz "\msg"
821 .balign 4
822 _ENDLIT
823.endm
824
825.macro _regfmt arg
19d642aa
MW
826 movz w2, #(\arg)&0xffff
827 movk w2, #((\arg) >> 16)&0xffff, lsl #16
4bc8424a
MW
828.endm
829
830#endif
831
832#endif
833
834/*----- Functions provided ------------------------------------------------*/
835
836/* --- @regdump_init@ --- *
837 *
838 * Arguments: ---
839 *
840 * Returns: ---
841 *
842 * Use: Performs one-time initialization for register dumping. In
843 * particular, this performs CPU feature detection on platforms
844 * where that is a difficult task: without it, registers
845 * corresponding to optional architectural features can be
846 * neither printed nor preserved by the register-dump machinery.
847 */
848
849#if !__ASSEMBLER__
850extern void regdump_init(void);
851#endif
852
853/* --- @regdump@ --- *
854 *
855 * Arguments: @const void *base@ = pointer to base structure, corresponding
856 * to the @REGF_SRCMASK@ part of @f@
857 * @const char *lbl@ = label to print
858 * @uint32 f@ = format control word; see @REGF_...@
859 *
860 * Returns: ---
861 *
862 * Use: Dump a register value, or chunk of memory.
863 *
864 * This function is not usually called directly; instead, use
865 * the `reg' or `mem' assembler macros.
866 */
867
868#if !__ASSEMBLER__
869extern void regdump(const void *base, const char *lbl, uint32 f);
870#else
871 .extern regdump
872#endif
873
874/* --- @regdump_gp@, @regdump_fp@, @regdump_simd@ --- *
875 *
876 * Arguments: @const struct regmap *map@ = pointer to register map
877 *
878 * Returns: ---
879 *
880 * Use: Dump the general-purpose/floating-point/SIMD registers.
881 *
882 * This function is not usually called directly; instead, use
883 * the `regdump' assembler macro.
884 */
885
886#if !__ASSEMBLER__
887extern void regdump_gp(const struct regmap */*map*/);
888extern void regdump_fp(const struct regmap */*map*/);
889extern void regdump_simd(const struct regmap */*map*/);
890#else
891 .extern regdump_gp
892 .extern regdump_fp
893 .extern regdump_simd
894#endif
895
896/* --- @regdump_freshline@ --- *
897 *
898 * Arguments: ---
899 *
900 * Returns: ---
901 *
902 * Use: Begin a fresh line of output.
903 */
904
905#if !__ASSEMBLER__
906extern void regdump_freshline(void);
907#else
908 .extern regdump_freshline
909#endif
910
911/*----- Main user interface macros ----------------------------------------*/
912
913#if __ASSEMBLER__
914
915.macro terpri
916 _saveregs
a752c20f 917 callext F(regdump_freshline)
4bc8424a
MW
918 _rstrregs
919.endm
920
cd303963
MW
921.macro msg lbl
922 _saveregs
923 _nilbase
924 _reglbl "\lbl"
925 _regfmt REGSRC_NONE | (1 << REGF_WDSHIFT)
926 callext F(regdump)
927 _rstrregs
928.endm
929
4bc8424a
MW
930.macro reg lbl, rn, fmt=0
931 _saveregs
932 _regbase
933 _reglbl "\lbl"
934 .L$reg.fmt$\@ = regsrc.\rn | \fmt | \
935 (((\fmt&REGF_TYMASK) == 0)&regty.\rn) | \
936 (((\fmt&REGF_FMTMASK) == 0)&regfmt.\rn)
937 _regfmt .L$reg.fmt$\@
a752c20f 938 callext F(regdump)
4bc8424a
MW
939 _rstrregs
940.endm
941
942.macro mem lbl, addr, fmt=0
943 _saveregs \addr
944 _membase
945 _reglbl "\lbl"
946 .L$mem.fmt$\@ = REGSRC_ABS | \fmt | \
947 (((\fmt&REGF_TYMASK) == 0)&REGF_32) | \
948 (((\fmt&REGF_FMTMASK) == 0)&REGF_HEX)
949 _regfmt .L$mem.fmt$\@
a752c20f 950 callext F(regdump)
4bc8424a
MW
951 _rstrregs
952.endm
953
954.macro regdump gp=nil, fp=nil, simd=nil
955 _saveregs
956 .ifnes "\gp", "nil"
957 _regbase
a752c20f 958 callext F(regdump_gp)
4bc8424a
MW
959 .endif
960 .ifnes "\fp", "nil"
961 _regbase
a752c20f 962 callext F(regdump_fp)
4bc8424a
MW
963 .endif
964 .ifnes "\simd", "nil"
965 _regbase
a752c20f 966 callext F(regdump_simd)
4bc8424a
MW
967 .endif
968 _rstrregs
969.endm
970
971#endif
972
973/*----- That's all, folks -------------------------------------------------*/
974
975#ifdef __cplusplus
976 }
977#endif
978
979#endif