#define REGSRC_SIMD 0x04000000 /* SIMD vector register */
#define REGSRC_STMMX 0x05000000 /* x86-specific: x87/MMX register */
#define REGSRC_SEG 0x06000000 /* x86-specific: segment register */
+#define REGSRC_NONE 0x0f000000 /* just a message */
/* Where to find the values. */
#define REGF_WDMASK 0xf0000000
#if !__ASSEMBLER__
#if CPUFAM_X86
-typedef union gp32 gpreg;
+ typedef union gp32 gpreg;
#endif
#if CPUFAM_AMD64
-typedef union gp64 gpreg;
+ typedef union gp64 gpreg;
#endif
struct gpsave {
#if FLT_RADIX == 2 && LDBL_MANT_DIG == 64
long double f80;
#endif
-unsigned char _pad[16];
+ unsigned char _pad[16];
};
union xmm { SIMD_COMMON(128); };
#else
.extern regdump_gpsave
+ // Save general-purpose registers at r/esp; flags, r/eax, and, on
+ // x86, ebx, should have been filled in already, together with the
+ // focus address, in `REGIX_ADDR', if relevant. Return required
+ // extended save area size in ecx, and leave r/ebp pointing to the
+ // save area.
+
.extern regdump_xtsave
+ // Save extended registers at r/esp, leaving r/ebp pointing to the
+ // register map.
+
.extern regdump_xtrstr
+ // Restore extended registers from register map in r/ebp, leaving
+ // r/ebp pointing to general-purpose save area.
+
.extern regdump_gprstr
+ // Restore general-purpose registers, except r/esp, from save area
+ // at r/ebp.
regmap_gp = 0*WORDSZ
regmap_fx = 1*WORDSZ
regmap_avx = 2*WORDSZ
regmap_size = 3*WORDSZ
-#define REGDEF_GPX86_COMMON(rn, RN) \
- regsrc.e##rn = REGSRC_GP | REGIX_##RN; \
+#define REGDEF_GPX86_COMMON(rn, ix) \
+ regsrc.e##rn = REGSRC_GP | ix; \
regty.e##rn = REGF_32; \
regfmt.e##rn = REGF_HEX; \
- regsrc.r##rn = REGSRC_GP | REGIX_##RN; \
+ regsrc.r##rn = REGSRC_GP | ix; \
regty.r##rn = REGF_64; \
regfmt.r##rn = REGF_HEX
regsrc.rn##x = REGSRC_GP | REGIX_##RN##X; \
regty.rn##x = REGF_16; \
regfmt.rn##x = REGF_HEX; \
- REGDEF_GPX86_COMMON(rn##x, RN##X)
+ REGDEF_GPX86_COMMON(rn##x, REGIX_##RN##X)
REGDEF_GPX86_ABCD(a, A)
REGDEF_GPX86_ABCD(b, B)
REGDEF_GPX86_ABCD(c, C)
regsrc.rn = REGSRC_GP | REGIX_##RN; \
regty.rn = REGF_16; \
regfmt.rn = REGF_HEX; \
- REGDEF_GPX86_COMMON(rn, RN)
+ REGDEF_GPX86_COMMON(rn, REGIX_##RN)
REGDEF_GPX86_XP(ip, IP)
REGDEF_GPX86_XP(si, SI)
REGDEF_GPX86_XP(di, DI)
// Stash r/eax. This is bletcherous: hope we don't get a signal in
// the next few instructions.
- mov [R_sp(r) - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], R_a(r)
+ mov [SP - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], AX
.ifnes "\addr", "nil"
- // Collect the effective address for the following dump, leaving it
- // in the `addr' slot of the dump.
- lea R_a(r), \addr
- mov [R_sp(r) - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], R_a(r)
+ // Collect the focus address for the following dump, leaving it in
+ // the `addr' slot of the dump.
+ lea AX, \addr
+ mov [SP - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], AX
.endif
// Make space for the register save area. On AMD64 with System/V
// ABI, also skip the red zone. Use `lea' here to preserve the
// flags.
- lea R_sp(r), [R_sp(r) - REGDUMP_SPADJ]
+ lea SP, [SP - REGDUMP_SPADJ]
// Save flags and general-purpose registers. On 32-bit x86, we save
// ebx here and establish a GOT pointer here for the benefit of the
// PLT-indirect calls made later on.
pushf
# if CPUFAM_X86
- mov [esp + 4*REGIX_BX], ebx
+ mov [SP + 4*REGIX_BX], ebx
ldgot
# endif
callext F(regdump_gpsave)
// Make space for the extended registers.
- sub R_sp(r), R_c(r)
+ sub SP, CX
callext F(regdump_xtsave)
// Prepare for calling back into C. On 32-bit x86, leave space for
// the `shadow space' for the called-function's arguments. Also,
// forcibly align the stack pointer to a 16-byte boundary.
# if CPUFAM_X86
- sub esp, 16
+ sub SP, 16
# elif ABI_WIN
- sub rsp, 32
+ sub SP, 32
# endif
- and R_sp(r), ~15
+ and SP, ~15
.endm
.macro _rstrregs
// We assume r/ebp still points to the register map.
callext F(regdump_xtrstr)
- mov R_sp(r), R_bp(r)
+ mov SP, BP
callext F(regdump_gprstr)
popf
- lea R_sp(r), [R_sp(r) + REGDUMP_SPADJ]
+ lea SP, [SP + REGDUMP_SPADJ]
+.endm
+
+.macro _nilbase
+# if CPUFAM_X86
+ xor eax, eax
+ mov [SP + 0], eax
+# elif ABI_SYSV
+ xor edi, edi
+# elif ABI_WIN
+ xor ecx, ecx
+# endif
.endm
.macro _regbase
# if CPUFAM_X86
- mov [esp + 0], ebp
+ mov [SP + 0], BP
# elif ABI_SYSV
- mov rdi, rbp
+ mov rdi, BP
# elif ABI_WIN
- mov rcx, rbp
+ mov rcx, BP
# endif
.endm
.macro _membase
- mov R_a(r), [R_bp(r) + regmap_gp]
+ mov AX, [BP + regmap_gp]
# if CPUFAM_X86
mov eax, [eax + REGIX_ADDR*WORDSZ]
- mov [esp + 0], eax
+ mov [SP + 0], eax
# elif ABI_SYSV
mov rdi, [rax + REGIX_ADDR*WORDSZ]
# elif ABI_WIN
.macro _reglbl msg
.ifeqs "\msg", ""
# if CPUFAM_X86
- mov dword ptr [esp + 4], 0
+ mov dword ptr [SP + 4], 0
# elif ABI_SYSV
xor esi, esi
# elif ABI_WIN
.else
# if CPUFAM_X86
lea eax, [INTADDR(.L$_reglbl$\@)]
- mov [esp + 4], eax
+ mov [SP + 4], eax
# elif ABI_SYSV
lea rsi, [INTADDR(.L$_reglbl$\@)]
# elif ABI_WIN
.macro _regfmt arg
# if CPUFAM_X86
- mov dword ptr [esp + 8], \arg
+ mov dword ptr [SP + 8], \arg
# elif ABI_SYSV
mov edx, \arg
# elif ABI_WIN
#else
.extern regdump_gpsave
+ // Save general-purpose registers at r13; r12 and r14 should have
+ // been filled in already, along with the focus address in
+ // `REGIX_ADDR', if relevant. Return required extended save area
+ // size in r0, leave r4 pointing to the save area, and set r6 to
+ // the focus address.
+
.extern regdump_xtsave
+ // Save extended registers at r13, leaving r5 pointing to the
+ // register map.
+
.extern regdump_xtrstr
+ // Restore extended registers from register map at r5.
+
.extern regdump_gprstr
+ // Restore general-purpose registers, except r13 and r14, from save
+ // area at r4.
regmap_gp = 0
regmap_fp = 4
str r14, [r13, #-REGDUMP_GPSIZE + 14*4]
.ifnes "\base,\off", "nil,#0"
- // Collect the effective address for the following dump, leaving it
- // in the `addr' slot of the dump.
+ // Collect the focus address for the following dump, leaving it in
+ // the `addr' slot of the dump.
.ifeqs "\base", "nil"
adrl r14, \off
.else
sub r13, r13, #REGDUMP_GPSIZE
// Save flags and general-purpose registers.
+ mrs r14, cpsr
+ str r14, [r13, #4*REGIX_CPSR]
str r12, [r13, #4*12]
bl regdump_gpsave
add r13, r13, #REGDUMP_GPSIZE
.endm
+.macro _nilbase
+ mov r0, #0
+.endm
+
.macro _regbase
mov r0, r5
.endm
#else
.extern regdump_gpsave
+ // Save general-purpose registers at sp; x16, x17, and x30, should
+ // have been filled in already, along with the focus address in
+ // `REGIX_ADDR', if relevant. Return required extended save area
+ // size in x0, leave x20 pointing to the save area, and set x22 to
+ // the focus address.
+
.extern regdump_xtsave
+ // Save extended registers at sp, leaving x21 pointing to the
+ // register map.
+
.extern regdump_xtrstr
+ // Restore extended registers from register map at x21.
+
.extern regdump_gprstr
+ // Restore general-purpose registers, except sp and x30, from save
+ // area at x20.
regmap_gp = 0
regmap_fp = 8
str x30, [sp, #-REGDUMP_GPSIZE + 30*8]
.ifnes "\base,\off", "nil,#0"
- // Collect the effective address for the following dump, leaving it
- // in the `addr' slot of the dump.
+ // Collect the focus address for the following dump, leaving it in
+ // the `addr' slot of the dump.
.ifeqs "\base", "nil"
adr x30, \off
.else
// Make space for the register save area.
sub sp, sp, #REGDUMP_GPSIZE
- // Save flags and general-purpose registers.
- stp x16, x17, [sp, #8*16]
+ // Save flags and general-purpose registers. The PLT linkage code
+ // makes free with x8--x17, so we must save those here.
+ mrs x30, nzcv
+ str x30, [sp, #8*REGIX_NZCV]
+ stp x8, x9, [sp, #64]
+ stp x10, x11, [sp, #80]
+ stp x12, x13, [sp, #96]
+ stp x14, x15, [sp, #112]
+ stp x16, x17, [sp, #128]
bl regdump_gpsave
// Make space for the extended registers.
add sp, sp, #REGDUMP_GPSIZE
.endm
+.macro _nilbase
+ mov x0, #0
+.endm
+
.macro _regbase
mov x0, x21
.endm
_rstrregs
.endm
+.macro msg lbl
+ _saveregs
+ _nilbase
+ _reglbl "\lbl"
+ _regfmt REGSRC_NONE | (1 << REGF_WDSHIFT)
+ callext F(regdump)
+ _rstrregs
+.endm
+
.macro reg lbl, rn, fmt=0
_saveregs
_regbase