diff --git a/gcc/ginclude/unwind-arm-common.h b/gcc/ginclude/unwind-arm-common.h index a2ef868d0934d21f832fadda08d3097939fa9aac..3ee0a6b1f27dbb4ee893c0d545db9d4120a587d4 100644 --- a/gcc/ginclude/unwind-arm-common.h +++ b/gcc/ginclude/unwind-arm-common.h @@ -127,7 +127,8 @@ extern "C" { _UVRSC_VFP = 1, /* vfp */ _UVRSC_FPA = 2, /* fpa */ _UVRSC_WMMXD = 3, /* Intel WMMX data register */ - _UVRSC_WMMXC = 4 /* Intel WMMX control register */ + _UVRSC_WMMXC = 4, /* Intel WMMX control register */ + _UVRSC_PAC = 5 /* Armv8.1-M Mainline PAC/AUTH pseudo-register */ } _Unwind_VRS_RegClass; diff --git a/libgcc/config/arm/pr-support.c b/libgcc/config/arm/pr-support.c index 76ba0ad4ab88b0e9b8c84eef497ab44bb54e59e8..abacfb62212c2aa0020a71654d3dd248cbea9dcd 100644 --- a/libgcc/config/arm/pr-support.c +++ b/libgcc/config/arm/pr-support.c @@ -106,6 +106,7 @@ __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws) { _uw op; int set_pc; + int set_pac = 0; _uw reg; set_pc = 0; @@ -114,6 +115,27 @@ __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws) op = next_unwind_byte (uws); if (op == CODE_FINISH) { + /* When we reach end, we have to authenticate R12 we just popped + earlier. + + Note: while the check provides additional security against a + corrupted unwind chain, it isn't essential for correct unwinding + of an uncorrupted chain. */ +#if defined(TARGET_HAVE_PACBTI) + if (set_pac) + { + _uw sp; + _uw lr; + _uw pac; + _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &sp); + _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr); + _Unwind_VRS_Get (context, _UVRSC_PAC, R_IP, + _UVRSD_UINT32, &pac); + __asm__ __volatile__ + ("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :); + } +#endif + /* If we haven't already set pc then copy it from lr. */ if (!set_pc) { @@ -227,6 +249,16 @@ __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws) return _URC_FAILURE; continue; } + /* Pop PAC off the stack into VRS pseudo.pac. */ + if (op == 0xb4) + { + if (_Unwind_VRS_Pop (context, _UVRSC_PAC, 0, _UVRSD_UINT32) + != _UVRSR_OK) + return _URC_FAILURE; + set_pac = 1; + continue; + } + if ((op & 0xfc) == 0xb4) /* Obsolete FPA. */ return _URC_FAILURE; diff --git a/libgcc/config/arm/unwind-arm.c b/libgcc/config/arm/unwind-arm.c index 41082b6ede6d61c4d6407bea133ebb1efe1f1a3a..b91821ce8361de3d8f50873e49d83d19d1a961dd 100644 --- a/libgcc/config/arm/unwind-arm.c +++ b/libgcc/config/arm/unwind-arm.c @@ -64,6 +64,12 @@ struct wmmxc_regs _uw wc[4]; }; +/* Holds value of pseudo registers eg. PAC. */ +struct pseudo_regs +{ + _uw pac; +}; + /* The ABI specifies that the unwind routines may only use core registers, except when actually manipulating coprocessor state. This allows us to write one implementation that works on all platforms by @@ -78,6 +84,9 @@ typedef struct /* The first fields must be the same as a phase2_vrs. */ _uw demand_save_flags; struct core_regs core; + /* Armv8.1-M Mainline PAC/AUTH values. This field should be in the same field + order as phase2_vrs. */ + struct pseudo_regs pseudo; _uw prev_sp; /* Only valid during forced unwinding. */ struct vfp_regs vfp; struct vfpv3_regs vfp_regs_16_to_31; @@ -99,6 +108,7 @@ typedef struct { _uw demand_save_flags; struct core_regs core; + struct pseudo_regs pac; } phase2_vrs; /* Coprocessor register state manipulation functions. */ @@ -175,6 +185,10 @@ _Unwind_VRS_Result _Unwind_VRS_Get (_Unwind_Context *context, case _UVRSC_WMMXC: return _UVRSR_NOT_IMPLEMENTED; + case _UVRSC_PAC: + *(_uw *) valuep = vrs->pseudo.pac; + return _UVRSR_OK; + default: return _UVRSR_FAILED; } @@ -206,6 +220,10 @@ _Unwind_VRS_Result _Unwind_VRS_Set (_Unwind_Context *context, case _UVRSC_WMMXC: return _UVRSR_NOT_IMPLEMENTED; + case _UVRSC_PAC: + vrs->pseudo.pac = *(_uw *) valuep; + return _UVRSR_OK; + default: return _UVRSR_FAILED; } @@ -246,6 +264,16 @@ _Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context, } return _UVRSR_OK; + case _UVRSC_PAC: + { + _uw *ptr = (_uw *) vrs->core.r[R_SP]; + if (discriminator != 0) + return _UVRSR_FAILED; + vrs->pseudo.pac = *(ptr++); + vrs->core.r[R_SP] = (_uw) ptr; + return _UVRSR_OK; + } + case _UVRSC_VFP: { _uw start = discriminator >> 16;