[libunwind] e25cd08 - [libunwind][AIX] Fix up TOC register if unw_getcontext is called from a different module (#66549)

via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 19 07:37:34 PDT 2023


Author: xingxue-ibm
Date: 2023-09-19T10:37:30-04:00
New Revision: e25cd088a642d270c688611b85e22bc83f32f48e

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

LOG: [libunwind][AIX] Fix up TOC register if unw_getcontext is called from a different module (#66549)

`unw_getcontext` saves the caller's registers in the context. However,
if the caller of `unw_getcontext` is in a different module, the glue
code of `unw_getcontext` sets the TOC register (r2) with the new TOC
base and saves the original TOC register value in the stack frame. This
causes the incorrect TOC value is used when the caller steps up frames,
which fails libunwind LIT test case `unw_resume.pass.cpp`. This PR fixes
the problem by using the original TOC register value saved in the stack
if the caller is in a different module and enables `unw_resume.pass.cpp`
on AIX.

Added: 
    

Modified: 
    libunwind/src/UnwindRegistersSave.S
    libunwind/test/unw_resume.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index 58ffd1b9e1fb35a..5534d1734b6ba7b 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -305,9 +305,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   mflr  0
   std   0, PPC64_OFFS_SRR0(3) // store lr as ssr0
   PPC64_STR(1)
+  PPC64_STR(4)        // Save r4 first since it will be used for fixing r2.
+#if defined(_AIX)
+  // The TOC register (r2) was changed by the glue code if unw_getcontext
+  // is called from a 
diff erent module. Save the original TOC register
+  // in the context if this is the case.
+  mflr   4
+  lwz    4, 0(4)      // Get the first instruction at the return address.
+  xoris  0, 4, 0xe841 // Is it reloading the TOC register "ld 2,40(1)"?
+  cmplwi 0, 0x28
+  bne    0, LnoR2Fix  // No need to fix up r2 if it is not.
+  ld     2, 40(1)     // Use the saved TOC register in the stack.
+LnoR2Fix:
+#endif
   PPC64_STR(2)
   PPC64_STR(3)
-  PPC64_STR(4)
   PPC64_STR(5)
   PPC64_STR(6)
   PPC64_STR(7)
@@ -547,9 +559,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   mflr    0
   stw     0,   0(3) // store lr as ssr0
   stw     1,  12(3)
+  stw     4,  24(3) // Save r4 first since it will be used for fixing r2.
+#if defined(_AIX)
+  // The TOC register (r2) was changed by the glue code if unw_getcontext
+  // is called from a 
diff erent module. Save the original TOC register
+  // in the context if this is the case.
+  mflr    4
+  lwz     4,   0(4)     // Get the instruction at the return address.
+  xoris   0,  4, 0x8041 // Is it reloading the TOC register "ld 2,40(1)"?
+  cmplwi  0,  0x14
+  bne     0,  LnoR2Fix  // No need to fix up r2 if it is not.
+  lwz     2,  20(1)     // Use the saved TOC register in the stack.
+LnoR2Fix:
+#endif
   stw     2,  16(3)
   stw     3,  20(3)
-  stw     4,  24(3)
   stw     5,  28(3)
   stw     6,  32(3)
   stw     7,  36(3)

diff  --git a/libunwind/test/unw_resume.pass.cpp b/libunwind/test/unw_resume.pass.cpp
index 76273e4a8ef0a71..08e8d4edeaf2927 100644
--- a/libunwind/test/unw_resume.pass.cpp
+++ b/libunwind/test/unw_resume.pass.cpp
@@ -10,9 +10,6 @@
 // Ensure that unw_resume() resumes execution at the stack frame identified by
 // cursor.
 
-// TODO: Investigate this failure on AIX system.
-// XFAIL: target={{.*}}-aix{{.*}}
-
 // TODO: Figure out why this fails with Memory Sanitizer.
 // XFAIL: msan
 


        


More information about the cfe-commits mailing list