summaryrefslogtreecommitdiffstats
path: root/libunwind/src
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2019-05-16 06:49:13 +0000
committerMartin Storsjo <martin@martin.st>2019-05-16 06:49:13 +0000
commit44266b9e115ad172b1f6a88d15d4e7579812c0fc (patch)
tree9306d2af9f6e8c6bc84980971d635234005e16f3 /libunwind/src
parentec895f11cee1e261289cb5320e366d39b9cf806d (diff)
downloadbcm5719-llvm-44266b9e115ad172b1f6a88d15d4e7579812c0fc.tar.gz
bcm5719-llvm-44266b9e115ad172b1f6a88d15d4e7579812c0fc.zip
[PPC64][libunwind] Fix r2 not properly restored
This change makes each unwind step inspect the instruction at the return address and, if needed, read r2 from its saved location and modify the context appropriately. The unwind logic is able to handle both ELFv1 and ELFv2 stacks. Reported by Bug 41050 Patch by Leandro Lupori! Differential Revision: https://reviews.llvm.org/D59694 llvm-svn: 360861
Diffstat (limited to 'libunwind/src')
-rw-r--r--libunwind/src/DwarfInstructions.hpp25
-rw-r--r--libunwind/src/assembly.h18
2 files changed, 42 insertions, 1 deletions
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index 4f5f821b383..29a070fa3e0 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -232,6 +232,31 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
}
#endif
+#if defined(_LIBUNWIND_TARGET_PPC64)
+#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
+#define PPC64_ELFV1_R2_OFFSET 40
+#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1)
+#define PPC64_ELFV2_R2_OFFSET 24
+ // If the instruction at return address is a TOC (r2) restore,
+ // then r2 was saved and needs to be restored.
+ // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24,
+ // while in ELFv1 ABI it is saved at SP + 40.
+ if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) {
+ pint_t sp = newRegisters.getRegister(UNW_REG_SP);
+ pint_t r2 = 0;
+ switch (addressSpace.get32(returnAddress)) {
+ case PPC64_ELFV1_R2_LOAD_INST_ENCODING:
+ r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET);
+ break;
+ case PPC64_ELFV2_R2_LOAD_INST_ENCODING:
+ r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET);
+ break;
+ }
+ if (r2)
+ newRegisters.setRegister(UNW_PPC64_R2, r2);
+ }
+#endif
+
// Return address is address after call site instruction, so setting IP to
// that does simualates a return.
newRegisters.setIP(returnAddress);
diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h
index 7614b0c3657..7d22aeb1a77 100644
--- a/libunwind/src/assembly.h
+++ b/libunwind/src/assembly.h
@@ -36,6 +36,20 @@
#define SEPARATOR ;
#endif
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
+#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR
+#define PPC64_OPD2 SEPARATOR \
+ .p2align 3 SEPARATOR \
+ .quad .Lfunc_begin0 SEPARATOR \
+ .quad .TOC.@tocbase SEPARATOR \
+ .quad 0 SEPARATOR \
+ .text SEPARATOR \
+.Lfunc_begin0:
+#else
+#define PPC64_OPD1
+#define PPC64_OPD2
+#endif
+
#define GLUE2(a, b) a ## b
#define GLUE(a, b) GLUE2(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
@@ -123,7 +137,9 @@
.globl SYMBOL_NAME(name) SEPARATOR \
HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
- SYMBOL_NAME(name):
+ PPC64_OPD1 \
+ SYMBOL_NAME(name): \
+ PPC64_OPD2
#if defined(__arm__)
#if !defined(__ARM_ARCH)
OpenPOWER on IntegriCloud