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,
   };
 };
 

Reply via email to