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