Skip to content

Commit e25cd08

Browse files
authored
[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.
1 parent a21d4ab commit e25cd08

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

libunwind/src/UnwindRegistersSave.S

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
305305
mflr 0
306306
std 0, PPC64_OFFS_SRR0(3) // store lr as ssr0
307307
PPC64_STR(1)
308+
PPC64_STR(4) // Save r4 first since it will be used for fixing r2.
309+
#if defined(_AIX)
310+
// The TOC register (r2) was changed by the glue code if unw_getcontext
311+
// is called from a different module. Save the original TOC register
312+
// in the context if this is the case.
313+
mflr 4
314+
lwz 4, 0(4) // Get the first instruction at the return address.
315+
xoris 0, 4, 0xe841 // Is it reloading the TOC register "ld 2,40(1)"?
316+
cmplwi 0, 0x28
317+
bne 0, LnoR2Fix // No need to fix up r2 if it is not.
318+
ld 2, 40(1) // Use the saved TOC register in the stack.
319+
LnoR2Fix:
320+
#endif
308321
PPC64_STR(2)
309322
PPC64_STR(3)
310-
PPC64_STR(4)
311323
PPC64_STR(5)
312324
PPC64_STR(6)
313325
PPC64_STR(7)
@@ -547,9 +559,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
547559
mflr 0
548560
stw 0, 0(3) // store lr as ssr0
549561
stw 1, 12(3)
562+
stw 4, 24(3) // Save r4 first since it will be used for fixing r2.
563+
#if defined(_AIX)
564+
// The TOC register (r2) was changed by the glue code if unw_getcontext
565+
// is called from a different module. Save the original TOC register
566+
// in the context if this is the case.
567+
mflr 4
568+
lwz 4, 0(4) // Get the instruction at the return address.
569+
xoris 0, 4, 0x8041 // Is it reloading the TOC register "ld 2,40(1)"?
570+
cmplwi 0, 0x14
571+
bne 0, LnoR2Fix // No need to fix up r2 if it is not.
572+
lwz 2, 20(1) // Use the saved TOC register in the stack.
573+
LnoR2Fix:
574+
#endif
550575
stw 2, 16(3)
551576
stw 3, 20(3)
552-
stw 4, 24(3)
553577
stw 5, 28(3)
554578
stw 6, 32(3)
555579
stw 7, 36(3)

libunwind/test/unw_resume.pass.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
// Ensure that unw_resume() resumes execution at the stack frame identified by
1111
// cursor.
1212

13-
// TODO: Investigate this failure on AIX system.
14-
// XFAIL: target={{.*}}-aix{{.*}}
15-
1613
// TODO: Figure out why this fails with Memory Sanitizer.
1714
// XFAIL: msan
1815

0 commit comments

Comments
 (0)