[libunwind] a085c23 - [libunwind] Allow restoring SP while unwinding.

Marco Vanotti via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 23 12:40:00 PDT 2021


Author: Marco Vanotti
Date: 2021-07-23T12:39:49-07:00
New Revision: a085c23aa3c8f91866d7f4588d4f683407dc775d

URL: https://github.com/llvm/llvm-project/commit/a085c23aa3c8f91866d7f4588d4f683407dc775d
DIFF: https://github.com/llvm/llvm-project/commit/a085c23aa3c8f91866d7f4588d4f683407dc775d.diff

LOG: [libunwind] Allow restoring SP while unwinding.

This commit modifies stepWithDwarf allowing for CFI directives to
specify the value of the stack pointer.

Previously, the SP would be unconditionally set to the CFA, because it
(wrongly) stated that the CFA is the stack pointer at the call site of a
function, but that is not always true.

One situation in which that is false, is for example if you have
switched stacks. In that case if you set the CFA to the SP before
switching the stack, the CFA would be far away from where the current
call frame is located.

The CFA always points to the current call frame, and that call frame
could have a CFI directive that specifies how to restore the stack
pointer. If not, it is OK to fallback and set the SP = CFA.

This change sets SP = CFA before restoring the registers during
unwinding, allowing the stack frame to be restored with a value
different than the CFA.

Reviewed By: #libunwind, phosek

Differential Revision: https://reviews.llvm.org/D106626

Added: 
    

Modified: 
    libunwind/src/DwarfInstructions.hpp

Removed: 
    


################################################################################
diff  --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index bd13d16231536..686c6be0d8fde 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -167,6 +167,16 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
 
        // restore registers that DWARF says were saved
       R newRegisters = registers;
+
+      // Typically, the CFA is the stack pointer at the call site in
+      // the previous frame. However, there are scenarios in which this is not
+      // true. For example, if we switched to a new stack. In that case, the
+      // value of the previous SP might be indicated by a CFI directive.
+      //
+      // We set the SP here to the CFA, allowing for it to be overridden
+      // by a CFI directive later on.
+      newRegisters.setSP(cfa);
+
       pint_t returnAddress = 0;
       const int lastReg = R::lastDwarfRegNum();
       assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
@@ -200,10 +210,6 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
         }
       }
 
-      // By definition, the CFA is the stack pointer at the call site, so
-      // restoring SP means setting it to CFA.
-      newRegisters.setSP(cfa);
-
       isSignalFrame = cieInfo.isSignalFrame;
 
 #if defined(_LIBUNWIND_TARGET_AARCH64)


        


More information about the cfe-commits mailing list