sparc64 exception handling fix

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

sparc64 exception handling fix

Mark Kettenis
On SPARC the address of the call instruction is placed in %o7 and a
normal function return will jump to %o7 + 8, skipping the delay slot.
The diff below changes the low-level libunwind code to take this into
account.  This way the addresses seen by the unwinder are as expected
and the unwinder can find the correct information in the various
tables.

ok?


Index: lib/libunwind/src/Registers.hpp
===================================================================
RCS file: /cvs/src/lib/libunwind/src/Registers.hpp,v
retrieving revision 1.4
diff -u -p -r1.4 Registers.hpp
--- lib/libunwind/src/Registers.hpp 21 Oct 2018 05:08:35 -0000 1.4
+++ lib/libunwind/src/Registers.hpp 2 Feb 2019 16:11:16 -0000
@@ -2648,8 +2648,8 @@ public:
 
   uint64_t  getSP() const         { return _registers.__o[6] + 2047; }
   void      setSP(uint64_t value) { _registers.__o[6] = value - 2047; }
-  uint64_t  getIP() const         { return _registers.__o[7]; }
-  void      setIP(uint64_t value) { _registers.__o[7] = value; }
+  uint64_t  getIP() const         { return _registers.__o[7] + 8; }
+  void      setIP(uint64_t value) { _registers.__o[7] = value - 8; }
   uint64_t  getWCookie() const    { return _wcookie; }
 
 private:
@@ -2702,7 +2702,7 @@ inline uint64_t Registers_sparc64::getRe
 
   switch (regNum) {
   case UNW_REG_IP:
-    return _registers.__o[7];
+    return _registers.__o[7] + 8;
   case UNW_REG_SP:
     return _registers.__o[6] + 2047;
   }
@@ -2729,7 +2729,7 @@ inline void Registers_sparc64::setRegist
 
   switch (regNum) {
   case UNW_REG_IP:
-    _registers.__o[7] = value;
+    _registers.__o[7] = value - 8;
     return;
   case UNW_REG_SP:
     _registers.__o[6] = value - 2047;
Index: lib/libunwind/src/UnwindRegistersRestore.S
===================================================================
RCS file: /cvs/src/lib/libunwind/src/UnwindRegistersRestore.S,v
retrieving revision 1.4
diff -u -p -r1.4 UnwindRegistersRestore.S
--- lib/libunwind/src/UnwindRegistersRestore.S 21 Oct 2018 05:08:35 -0000 1.4
+++ lib/libunwind/src/UnwindRegistersRestore.S 2 Feb 2019 16:11:16 -0000
@@ -669,7 +669,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9li
   ldx  [%o0 + 0xe8], %i5
   ldx  [%o0 + 0xf0], %i6
   ldx  [%o0 + 0xf8], %i7
-  jmpl %o7, %g0
+  jmpl %o7 + 8, %g0
    ldx [%o0 + 0x40], %o0
 
 #elif defined(__mips__) && defined(_ABIO32)

Reply | Threaded
Open this post in threaded view
|

Re: sparc64 exception handling fix

Mark Kettenis
> Date: Sat, 2 Feb 2019 17:19:07 +0100 (CET)
> From: Mark Kettenis <[hidden email]>
>
> On SPARC the address of the call instruction is placed in %o7 and a
> normal function return will jump to %o7 + 8, skipping the delay slot.
> The diff below changes the low-level libunwind code to take this into
> account.  This way the addresses seen by the unwinder are as expected
> and the unwinder can find the correct information in the various
> tables.
>
> ok?

Ugh, I botched that one at the last minute.  And didn't notice because
I ran the regression tests without CXX=clang++ :(.

So the situation is a bit more complicated.  On SPARC, DWARF2 uses
register 15 (which maps to %o7) as the return address "column".  This
means that what DWARF2 calls the return address is actually what is
stored in %o7 and therefore off by two instructions.  When the
unwinders processes DWARF2 "instructions" to update the register state
we must therefore set %o7 directly and not substract 8 from the passed
value.

The higher-level unwinding code needs to see the true return address
though.  Luckily the DWARF2 parsing code uses a different interface,
se we can achieve this.

The DWARF2 parsing code uses setIP(), so the diff below changes that
function to remove the minus 8 I added in the previous diff.  I also
changed getIP() back to what it was, even though that interface isn't
actually used in the code.

ok?


Index: lib/libunwind/src/Registers.hpp
===================================================================
RCS file: /cvs/src/lib/libunwind/src/Registers.hpp,v
retrieving revision 1.5
diff -u -p -r1.5 Registers.hpp
--- lib/libunwind/src/Registers.hpp 3 Feb 2019 12:30:02 -0000 1.5
+++ lib/libunwind/src/Registers.hpp 3 Feb 2019 13:42:15 -0000
@@ -2648,8 +2648,8 @@ public:
 
   uint64_t  getSP() const         { return _registers.__o[6] + 2047; }
   void      setSP(uint64_t value) { _registers.__o[6] = value - 2047; }
-  uint64_t  getIP() const         { return _registers.__o[7] + 8; }
-  void      setIP(uint64_t value) { _registers.__o[7] = value - 8; }
+  uint64_t  getIP() const         { return _registers.__o[7]; }
+  void      setIP(uint64_t value) { _registers.__o[7] = value; }
   uint64_t  getWCookie() const    { return _wcookie; }
 
 private: