On s390x-linux, adds CFI based unwinding for %f0..%f7, since these are sometimes
used by gcc >= 8.0 to spill integer register values in leaf functions. Hence the
lack of unwinding them was causing unwind failures on this platform.
uregs.ia = ip;
uregs.sp = sp;
uregs.fp = fp;
+ /* JRS FIXME 3 Apr 2019: surely we can do better for f0..f7 */
+ uregs.f0 = 0;
+ uregs.f1 = 0;
+ uregs.f2 = 0;
+ uregs.f3 = 0;
+ uregs.f4 = 0;
+ uregs.f5 = 0;
+ uregs.f6 = 0;
+ uregs.f7 = 0;
return compute_cfa(&uregs,
min_accessible, max_accessible, ce->di, ce->cfsi_m);
}
For arm, the unwound registers are: R7 R11 R12 R13 R14 R15.
For arm64, the unwound registers are: X29(FP) X30(LR) SP PC.
+
+ For s390, the unwound registers are: R11(FP) R14(LR) R15(SP) F0..F7 PC.
*/
Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere,
Addr min_accessible,
/* Now we know the CFA, use it to roll back the registers we're
interested in. */
-#if defined(VGA_mips64) && defined(VGABI_N32)
-#define READ_REGISTER(addr) ML_(read_ULong)((addr))
-#else
-#define READ_REGISTER(addr) ML_(read_Addr)((addr))
-#endif
+# if defined(VGA_mips64) && defined(VGABI_N32)
+# define READ_REGISTER(addr) ML_(read_ULong)((addr))
+# else
+# define READ_REGISTER(addr) ML_(read_Addr)((addr))
+# endif
+
+# if defined(VGA_s390x)
+ const Bool is_s390x = True;
+ const Addr old_S390X_F0 = uregsHere->f0;
+ const Addr old_S390X_F1 = uregsHere->f1;
+ const Addr old_S390X_F2 = uregsHere->f2;
+ const Addr old_S390X_F3 = uregsHere->f3;
+ const Addr old_S390X_F4 = uregsHere->f4;
+ const Addr old_S390X_F5 = uregsHere->f5;
+ const Addr old_S390X_F6 = uregsHere->f6;
+ const Addr old_S390X_F7 = uregsHere->f7;
+# else
+ const Bool is_s390x = False;
+ const Addr old_S390X_F0 = 0;
+ const Addr old_S390X_F1 = 0;
+ const Addr old_S390X_F2 = 0;
+ const Addr old_S390X_F3 = 0;
+ const Addr old_S390X_F4 = 0;
+ const Addr old_S390X_F5 = 0;
+ const Addr old_S390X_F6 = 0;
+ const Addr old_S390X_F7 = 0;
+# endif
# define COMPUTE(_prev, _here, _how, _off) \
do { \
_prev = evalCfiExpr(di->cfsi_exprs, _off, &eec, &ok ); \
if (!ok) return False; \
break; \
+ case CFIR_S390X_F0: \
+ if (is_s390x) { _prev = old_S390X_F0; break; } \
+ vg_assert(0+0-0); \
+ case CFIR_S390X_F1: \
+ if (is_s390x) { _prev = old_S390X_F1; break; } \
+ vg_assert(0+1-1); \
+ case CFIR_S390X_F2: \
+ if (is_s390x) { _prev = old_S390X_F2; break; } \
+ vg_assert(0+2-2); \
+ case CFIR_S390X_F3: \
+ if (is_s390x) { _prev = old_S390X_F3; break; } \
+ vg_assert(0+3-3); \
+ case CFIR_S390X_F4: \
+ if (is_s390x) { _prev = old_S390X_F4; break; } \
+ vg_assert(0+4-4); \
+ case CFIR_S390X_F5: \
+ if (is_s390x) { _prev = old_S390X_F5; break; } \
+ vg_assert(0+5-5); \
+ case CFIR_S390X_F6: \
+ if (is_s390x) { _prev = old_S390X_F6; break; } \
+ vg_assert(0+6-6); \
+ case CFIR_S390X_F7: \
+ if (is_s390x) { _prev = old_S390X_F7; break; } \
+ vg_assert(0+7-7); \
default: \
- vg_assert(0); \
+ vg_assert(0*0); \
} \
} while (0)
COMPUTE(uregsPrev.ia, uregsHere->ia, cfsi_m->ra_how, cfsi_m->ra_off);
COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi_m->sp_how, cfsi_m->sp_off);
COMPUTE(uregsPrev.fp, uregsHere->fp, cfsi_m->fp_how, cfsi_m->fp_off);
+ COMPUTE(uregsPrev.f0, uregsHere->f0, cfsi_m->f0_how, cfsi_m->f0_off);
+ COMPUTE(uregsPrev.f1, uregsHere->f1, cfsi_m->f1_how, cfsi_m->f1_off);
+ COMPUTE(uregsPrev.f2, uregsHere->f2, cfsi_m->f2_how, cfsi_m->f2_off);
+ COMPUTE(uregsPrev.f3, uregsHere->f3, cfsi_m->f3_how, cfsi_m->f3_off);
+ COMPUTE(uregsPrev.f4, uregsHere->f4, cfsi_m->f4_how, cfsi_m->f4_off);
+ COMPUTE(uregsPrev.f5, uregsHere->f5, cfsi_m->f5_how, cfsi_m->f5_off);
+ COMPUTE(uregsPrev.f6, uregsHere->f6, cfsi_m->f6_how, cfsi_m->f6_off);
+ COMPUTE(uregsPrev.f7, uregsHere->f7, cfsi_m->f7_how, cfsi_m->f7_off);
# elif defined(VGA_mips32) || defined(VGA_mips64)
COMPUTE(uregsPrev.pc, uregsHere->pc, cfsi_m->ra_how, cfsi_m->ra_off);
COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi_m->sp_how, cfsi_m->sp_off);
# error "Unknown arch"
# endif
+# undef READ_REGISTER
# undef COMPUTE
*uregsHere = uregsPrev;
CFIR_CFAREL -> cfa + sp/fp/ra_off
CFIR_MEMCFAREL -> *( cfa + sp/fp/ra_off )
CFIR_EXPR -> expr whose index is in sp/fp/ra_off
+ CFIR_S390X_F0 -> old value of %f0
+ CFIR_S390X_F1 -> old value of %f1
+ CFIR_S390X_F2 -> old value of %f2
+ CFIR_S390X_F3 -> old value of %f3
+ CFIR_S390X_F4 -> old value of %f4
+ CFIR_S390X_F5 -> old value of %f5
+ CFIR_S390X_F6 -> old value of %f6
+ CFIR_S390X_F7 -> old value of %f7
*/
#define CFIC_IA_SPREL ((UChar)1)
#define CFIR_CFAREL ((UChar)66)
#define CFIR_MEMCFAREL ((UChar)67)
#define CFIR_EXPR ((UChar)68)
+#define CFIR_S390X_F0 ((UChar)69)
+#define CFIR_S390X_F1 ((UChar)70)
+#define CFIR_S390X_F2 ((UChar)71)
+#define CFIR_S390X_F3 ((UChar)72)
+#define CFIR_S390X_F4 ((UChar)73)
+#define CFIR_S390X_F5 ((UChar)74)
+#define CFIR_S390X_F6 ((UChar)75)
+#define CFIR_S390X_F7 ((UChar)76)
/* Definition of the DiCfSI_m DiCfSI machine dependent part.
These are highly duplicated, and are stored in a pool. */
UChar sp_how; /* a CFIR_ value */
UChar ra_how; /* a CFIR_ value */
UChar fp_how; /* a CFIR_ value */
+ UChar f0_how; /* a CFIR_ value */
+ UChar f1_how; /* a CFIR_ value */
+ UChar f2_how; /* a CFIR_ value */
+ UChar f3_how; /* a CFIR_ value */
+ UChar f4_how; /* a CFIR_ value */
+ UChar f5_how; /* a CFIR_ value */
+ UChar f6_how; /* a CFIR_ value */
+ UChar f7_how; /* a CFIR_ value */
Int cfa_off;
Int sp_off;
Int ra_off;
Int fp_off;
+ Int f0_off;
+ Int f1_off;
+ Int f2_off;
+ Int f3_off;
+ Int f4_off;
+ Int f5_off;
+ Int f6_off;
+ Int f7_off;
}
DiCfSI_m;
#elif defined(VGA_mips32) || defined(VGA_mips64)
# define N_CFI_REGS 320
#elif defined(VGP_arm64_linux)
# define N_CFI_REGS 128
+#elif defined(VGP_s390x_linux)
+# define N_CFI_REGS 66
#else
# define N_CFI_REGS 20
#endif
| RR_Reg arg -- is in register 'arg'
| RR_Expr arg -- is at * [[ arg ]]
| RR_ValExpr arg -- is [[ arg ]]
- | RR_Arch -- dunno
Note that RR_Expr is redundant since the same can be represented
using RR_ValExpr with an explicit dereference (CfiExpr_Deref) at
typedef
struct {
enum { RR_Undef, RR_Same, RR_CFAOff, RR_CFAValOff,
- RR_Reg, /*RR_Expr,*/ RR_ValExpr, RR_Arch } tag;
+ RR_Reg, /*RR_Expr,*/ RR_ValExpr } tag;
/* meaning: int offset for CFAoff/CFAValOff
reg # for Reg
expr index for Expr/ValExpr */
case RR_Same: VG_(printf)("s "); break;
case RR_CFAOff: VG_(printf)("c%d ", rrule->arg); break;
case RR_CFAValOff: VG_(printf)("v%d ", rrule->arg); break;
- case RR_Reg: VG_(printf)("r%d ", rrule->arg); break;
+ case RR_Reg: VG_(printf)("dwReg%d ", rrule->arg); break;
case RR_ValExpr: VG_(printf)("ve{");
ML_(ppCfiExpr)( exprs, rrule->arg );
VG_(printf)("} ");
break;
- case RR_Arch: VG_(printf)("a "); break;
default: VG_(core_panic)("ppRegRule");
}
}
*len = 0;
VG_(bzero_inline)(si_m, sizeof(*si_m));
+ /*const*/ Bool is_s390x_linux = False;
+# if defined(VGP_s390x_linux)
+ is_s390x_linux = True;
+# endif
/* Guard against obviously stupid settings of the reg-rule stack
pointer. */
}
# define SUMMARISE_HOW(_how, _off, _ctxreg) \
+ _how = CFIR_UNKNOWN; /* install safe initial values */ \
+ _off = 0; \
switch (_ctxreg.tag) { \
case RR_Undef: \
_how = CFIR_UNKNOWN; _off = 0; break; \
ML_(ppCfiExpr)(dst, conv); \
break; \
} \
+ case RR_Reg: \
+ if (is_s390x_linux) { \
+ if (_ctxreg.arg == 16/*dwarf reg 16 is %f0*/) { \
+ _how = CFIR_S390X_F0; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 17/*dwarf reg 17 is %f2*/) { \
+ _how = CFIR_S390X_F2; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 18/*dwarf reg 18 is %f4*/) { \
+ _how = CFIR_S390X_F4; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 19/*dwarf reg 19 is %f6*/) { \
+ _how = CFIR_S390X_F6; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 20/*dwarf reg 20 is %f1*/) { \
+ _how = CFIR_S390X_F1; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 21/*dwarf reg 21 is %f3*/) { \
+ _how = CFIR_S390X_F3; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 22/*dwarf reg 22 is %f5*/) { \
+ _how = CFIR_S390X_F5; \
+ _off = 0; \
+ break; \
+ } \
+ else if (_ctxreg.arg == 23/*dwarf reg 23 is %f7*/) { \
+ _how = CFIR_S390X_F7; \
+ _off = 0; \
+ break; \
+ } \
+ } \
+ /* Currently we only support RR_Reg for s390. */ \
+ why = 2; goto failed; \
default: \
why = 2; goto failed; /* otherwise give up */ \
}
ctxs->reg[FP_REG] );
SUMMARISE_HOW(si_m->sp_how, si_m->sp_off,
ctxs->reg[SP_REG] );
+ SUMMARISE_HOW(si_m->f0_how, si_m->f0_off,
+ ctxs->reg[16/*%f0*/]);
+ SUMMARISE_HOW(si_m->f2_how, si_m->f2_off,
+ ctxs->reg[17/*%f2*/]);
+ SUMMARISE_HOW(si_m->f4_how, si_m->f4_off,
+ ctxs->reg[18/*%f4*/]);
+ SUMMARISE_HOW(si_m->f6_how, si_m->f6_off,
+ ctxs->reg[19/*%f6*/]);
+ SUMMARISE_HOW(si_m->f1_how, si_m->f1_off,
+ ctxs->reg[20/*%f1*/]);
+ SUMMARISE_HOW(si_m->f3_how, si_m->f3_off,
+ ctxs->reg[21/*%f3*/]);
+ SUMMARISE_HOW(si_m->f5_how, si_m->f5_off,
+ ctxs->reg[22/*%f5*/]);
+ SUMMARISE_HOW(si_m->f7_how, si_m->f7_off,
+ ctxs->reg[23/*%f7*/]);
/* change some defaults to consumable values */
if (si_m->sp_how == CFIR_UNKNOWN)
si_m->cfa_how = CFIC_IA_SPREL;
si_m->cfa_off = 160;
}
+
if (si_m->ra_how == CFIR_UNKNOWN) {
if (!debuginfo->cfsi_exprs)
debuginfo->cfsi_exprs = VG_(newXA)( ML_(dinfo_zalloc),
Creg_S390_LR);
}
+ if (si_m->f0_how == CFIR_UNKNOWN)
+ si_m->f0_how = CFIR_SAME;
+
+ if (si_m->f1_how == CFIR_UNKNOWN)
+ si_m->f1_how = CFIR_SAME;
+
+ if (si_m->f2_how == CFIR_UNKNOWN)
+ si_m->f2_how = CFIR_SAME;
+
+ if (si_m->f3_how == CFIR_UNKNOWN)
+ si_m->f3_how = CFIR_SAME;
+
+ if (si_m->f4_how == CFIR_UNKNOWN)
+ si_m->f4_how = CFIR_SAME;
+
+ if (si_m->f5_how == CFIR_UNKNOWN)
+ si_m->f5_how = CFIR_SAME;
+
+ if (si_m->f6_how == CFIR_UNKNOWN)
+ si_m->f6_how = CFIR_SAME;
+
+ if (si_m->f7_how == CFIR_UNKNOWN)
+ si_m->f7_how = CFIR_SAME;
+
/* knock out some obviously stupid cases */
if (si_m->ra_how == CFIR_SAME)
{ why = 3; goto failed; }
VG_(printf)("{"); \
ML_(ppCfiExpr)(exprs, _off); \
VG_(printf)("}"); \
+ } else \
+ if (_how == CFIR_S390X_F0) { \
+ VG_(printf)("oldF0"); \
+ } else \
+ if (_how == CFIR_S390X_F1) { \
+ VG_(printf)("oldF1"); \
+ } else \
+ if (_how == CFIR_S390X_F2) { \
+ VG_(printf)("oldF2"); \
+ } else \
+ if (_how == CFIR_S390X_F3) { \
+ VG_(printf)("oldF3"); \
+ } else \
+ if (_how == CFIR_S390X_F4) { \
+ VG_(printf)("oldF4"); \
+ } else \
+ if (_how == CFIR_S390X_F5) { \
+ VG_(printf)("oldF5"); \
+ } else \
+ if (_how == CFIR_S390X_F6) { \
+ VG_(printf)("oldF6"); \
+ } else \
+ if (_how == CFIR_S390X_F7) { \
+ VG_(printf)("oldF7"); \
} else { \
vg_assert(0+0); \
} \
VG_(printf)(" R7=");
SHOW_HOW(si_m->r7_how, si_m->r7_off);
# elif defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le)
-# elif defined(VGA_s390x) || defined(VGA_mips32) || defined(VGA_mips64)
+ /* nothing */
+# elif defined(VGA_s390x)
+ VG_(printf)(" SP=");
+ SHOW_HOW(si_m->sp_how, si_m->sp_off);
+ VG_(printf)(" FP=");
+ SHOW_HOW(si_m->fp_how, si_m->fp_off);
+ VG_(printf)(" F0=");
+ SHOW_HOW(si_m->f0_how, si_m->f0_off);
+ VG_(printf)(" F1=");
+ SHOW_HOW(si_m->f1_how, si_m->f1_off);
+ VG_(printf)(" F2=");
+ SHOW_HOW(si_m->f2_how, si_m->f2_off);
+ VG_(printf)(" F3=");
+ SHOW_HOW(si_m->f3_how, si_m->f3_off);
+ VG_(printf)(" F4=");
+ SHOW_HOW(si_m->f4_how, si_m->f4_off);
+ VG_(printf)(" F5=");
+ SHOW_HOW(si_m->f5_how, si_m->f5_off);
+ VG_(printf)(" F6=");
+ SHOW_HOW(si_m->f6_how, si_m->f6_off);
+ VG_(printf)(" F7=");
+ SHOW_HOW(si_m->f7_how, si_m->f7_off);
+# elif defined(VGA_mips32) || defined(VGA_mips64)
VG_(printf)(" SP=");
SHOW_HOW(si_m->sp_how, si_m->sp_off);
VG_(printf)(" FP=");
}
#elif defined(VGP_s390x_linux)
# define GET_STARTREGS(srP) \
- { ULong ia, sp, fp, lr; \
+ { ULong ia; \
+ ULong block[11]; \
__asm__ __volatile__( \
- "bras %0,0f;" \
- "0: lgr %1,15;" \
- "lgr %2,11;" \
- "lgr %3,14;" \
- : "=r" (ia), "=r" (sp),"=r" (fp),"=r" (lr) \
- /* no read & clobber */ \
+ "bras %0, 0f;" \
+ "0: " \
+ "stg %%r15, 0(%1);" \
+ "stg %%r11, 8(%1);" \
+ "stg %%r14, 16(%1);" \
+ "std %%f0, 24(%1);" \
+ "std %%f1, 32(%1);" \
+ "std %%f2, 40(%1);" \
+ "std %%f3, 48(%1);" \
+ "std %%f4, 56(%1);" \
+ "std %%f5, 64(%1);" \
+ "std %%f6, 72(%1);" \
+ "std %%f7, 80(%1);" \
+ : /* out */ "=r" (ia) \
+ : /* in */ "r" (&block[0]) \
+ : /* trash */ "memory" \
); \
(srP)->r_pc = ia; \
- (srP)->r_sp = sp; \
- (srP)->misc.S390X.r_fp = fp; \
- (srP)->misc.S390X.r_lr = lr; \
+ (srP)->r_sp = block[0]; \
+ (srP)->misc.S390X.r_fp = block[1]; \
+ (srP)->misc.S390X.r_lr = block[2]; \
+ (srP)->misc.S390X.r_f0 = block[3]; \
+ (srP)->misc.S390X.r_f1 = block[4]; \
+ (srP)->misc.S390X.r_f2 = block[5]; \
+ (srP)->misc.S390X.r_f3 = block[6]; \
+ (srP)->misc.S390X.r_f4 = block[7]; \
+ (srP)->misc.S390X.r_f5 = block[8]; \
+ (srP)->misc.S390X.r_f6 = block[9]; \
+ (srP)->misc.S390X.r_f7 = block[10]; \
}
#elif defined(VGP_mips32_linux)
# define GET_STARTREGS(srP) \
= VG_(threads)[tid].arch.vex.guest_FP;
regs->misc.S390X.r_lr
= VG_(threads)[tid].arch.vex.guest_LR;
+ /* ANDREAS 3 Apr 2019 FIXME r_f0..r_f7: is this correct? */
+ regs->misc.S390X.r_f0
+ = VG_(threads)[tid].arch.vex.guest_v0.w64[0];
+ regs->misc.S390X.r_f1
+ = VG_(threads)[tid].arch.vex.guest_v1.w64[0];
+ regs->misc.S390X.r_f2
+ = VG_(threads)[tid].arch.vex.guest_v2.w64[0];
+ regs->misc.S390X.r_f3
+ = VG_(threads)[tid].arch.vex.guest_v3.w64[0];
+ regs->misc.S390X.r_f4
+ = VG_(threads)[tid].arch.vex.guest_v4.w64[0];
+ regs->misc.S390X.r_f5
+ = VG_(threads)[tid].arch.vex.guest_v5.w64[0];
+ regs->misc.S390X.r_f6
+ = VG_(threads)[tid].arch.vex.guest_v6.w64[0];
+ regs->misc.S390X.r_f7
+ = VG_(threads)[tid].arch.vex.guest_v7.w64[0];
# elif defined(VGA_mips32)
regs->r_pc = VG_(threads)[tid].arch.vex.guest_PC;
regs->r_sp = VG_(threads)[tid].arch.vex.guest_r29;
(srP)->r_sp = (ULong)((uc)->uc_mcontext.regs.gprs[15]); \
(srP)->misc.S390X.r_fp = (uc)->uc_mcontext.regs.gprs[11]; \
(srP)->misc.S390X.r_lr = (uc)->uc_mcontext.regs.gprs[14]; \
+ (srP)->misc.S390X.r_f0 = (uc)->uc_mcontext.fpregs.fprs[0]; \
+ (srP)->misc.S390X.r_f1 = (uc)->uc_mcontext.fpregs.fprs[1]; \
+ (srP)->misc.S390X.r_f2 = (uc)->uc_mcontext.fpregs.fprs[2]; \
+ (srP)->misc.S390X.r_f3 = (uc)->uc_mcontext.fpregs.fprs[3]; \
+ (srP)->misc.S390X.r_f4 = (uc)->uc_mcontext.fpregs.fprs[4]; \
+ (srP)->misc.S390X.r_f5 = (uc)->uc_mcontext.fpregs.fprs[5]; \
+ (srP)->misc.S390X.r_f6 = (uc)->uc_mcontext.fpregs.fprs[6]; \
+ (srP)->misc.S390X.r_f7 = (uc)->uc_mcontext.fpregs.fprs[7]; \
}
#elif defined(VGP_mips32_linux)
Addr fp_min = uregs.sp - VG_STACK_REDZONE_SZB;
uregs.fp = startRegs->misc.S390X.r_fp;
uregs.lr = startRegs->misc.S390X.r_lr;
+ uregs.f0 = startRegs->misc.S390X.r_f0;
+ uregs.f1 = startRegs->misc.S390X.r_f1;
+ uregs.f2 = startRegs->misc.S390X.r_f2;
+ uregs.f3 = startRegs->misc.S390X.r_f3;
+ uregs.f4 = startRegs->misc.S390X.r_f4;
+ uregs.f5 = startRegs->misc.S390X.r_f5;
+ uregs.f6 = startRegs->misc.S390X.r_f6;
+ uregs.f7 = startRegs->misc.S390X.r_f7;
fp_max = VG_PGROUNDUP(fp_max_orig);
if (fp_max >= sizeof(Addr))
struct {
ULong r_fp;
ULong r_lr;
+ ULong r_f0;
+ ULong r_f1;
+ ULong r_f2;
+ ULong r_f3;
+ ULong r_f4;
+ ULong r_f5;
+ ULong r_f6;
+ ULong r_f7;
} S390X;
struct {
UInt r30; /* Stack frame pointer or subroutine variable */
D3UnwindRegs;
#elif defined(VGA_s390x)
typedef
- struct { Addr ia; Addr sp; Addr fp; Addr lr;}
+ struct { Addr ia; Addr sp; Addr fp; Addr lr;
+ Addr f0; Addr f1; Addr f2; Addr f3;
+ Addr f4; Addr f5; Addr f6; Addr f7; }
D3UnwindRegs;
#elif defined(VGA_mips32) || defined(VGA_mips64)
typedef