Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/lib/libunwind PR toolchain/55837



details:   https://anonhg.NetBSD.org/src/rev/bbf040c88828
branches:  trunk
changeset: 379435:bbf040c88828
user:      rin <rin%NetBSD.org@localhost>
date:      Mon May 31 12:12:24 2021 +0000

description:
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.

diffstat:

 sys/lib/libunwind/Registers.hpp |  20 ++++++++++++++++++--
 1 files changed, 18 insertions(+), 2 deletions(-)

diffs (51 lines):

diff -r 453fc6aeb652 -r bbf040c88828 sys/lib/libunwind/Registers.hpp
--- a/sys/lib/libunwind/Registers.hpp   Mon May 31 11:57:28 2021 +0000
+++ b/sys/lib/libunwind/Registers.hpp   Mon May 31 12:12:24 2021 +0000
@@ -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,
   };
 };
 



Home | Main Index | Thread Index | Old Index