Module Name: src Committed By: rin Date: Mon May 31 12:12:24 UTC 2021
Modified Files: src/sys/lib/libunwind: Registers.hpp Log Message: PR toolchain/55837 Bump LAST_REGISTER and LAST_RESTORE_REG to REGNO_ARM32_S31 for arm. There are two numbering schemes for VFPv2 registers: s0-s31 and d0-d15. The former is used by GCC, and the latter is by LLVM. Since libunwind was derived from LLVM, it has never supported the former. This results in crashes for GCC-compiled binaries in exception handler of C++, if it encounters VFPv2 registers when unwinding frames. This commit adds support for s0-s31 numbering to libunwind. I choose an implementation in which VFPv2 registers are ``double-counted'' as s0-s31 AND d0-d15. This does not cause real problems, since the former is only used by GCC, and the later is by LLVM. That is, different numbering schemes cannot appear in a same frame. To make sure, assertions are added in order to check this. I've confirmed that no regression for ATF both for GCC- and LLVM-compiled userlands. To generate a diff of this commit: cvs rdiff -u -r1.26 -r1.27 src/sys/lib/libunwind/Registers.hpp Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/lib/libunwind/Registers.hpp diff -u src/sys/lib/libunwind/Registers.hpp:1.26 src/sys/lib/libunwind/Registers.hpp:1.27 --- src/sys/lib/libunwind/Registers.hpp:1.26 Mon May 31 11:57:28 2021 +++ src/sys/lib/libunwind/Registers.hpp Mon May 31 12:12:24 2021 @@ -335,8 +335,8 @@ enum { class Registers_arm32 { public: enum { - LAST_REGISTER = REGNO_ARM32_D31, - LAST_RESTORE_REG = REGNO_ARM32_D31, + LAST_REGISTER = REGNO_ARM32_S31, + LAST_RESTORE_REG = REGNO_ARM32_S31, RETURN_OFFSET = 0, RETURN_MASK = 0, }; @@ -385,6 +385,14 @@ public: assert(validFloatVectorRegister(num)); const void *addr = reinterpret_cast<const void *>(addr_); if (num >= REGNO_ARM32_S0 && num <= REGNO_ARM32_S31) { + /* + * XXX + * There are two numbering schemes for VFPv2 registers: s0-s31 + * (used by GCC) and d0-d15 (used by LLVM). We won't support both + * schemes simultaneously in a same frame. + */ + assert((flags & FLAGS_EXTENDED_VFPV2_REGNO) == 0); + flags |= FLAGS_LEGACY_VFPV2_REGNO; if ((flags & FLAGS_VFPV2_USED) == 0) { lazyVFPv2(); flags |= FLAGS_VFPV2_USED; @@ -402,6 +410,12 @@ public: addr, sizeof(fpreg[0]) / 2); } else { if (num <= REGNO_ARM32_D15) { + /* + * XXX + * See XXX comment above. + */ + assert((flags & FLAGS_LEGACY_VFPV2_REGNO) == 0); + flags |= FLAGS_EXTENDED_VFPV2_REGNO; if ((flags & FLAGS_VFPV2_USED) == 0) { lazyVFPv2(); flags |= FLAGS_VFPV2_USED; @@ -428,6 +442,8 @@ private: enum { FLAGS_VFPV2_USED = 0x1, FLAGS_VFPV3_USED = 0x2, + FLAGS_LEGACY_VFPV2_REGNO = 0x4, + FLAGS_EXTENDED_VFPV2_REGNO = 0x8, }; };