summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dimitry@andric.com>2019-07-09 19:22:59 +0000
committerDimitry Andric <dimitry@andric.com>2019-07-09 19:22:59 +0000
commit1d1c85a8445baea8457e56b25f4f2d4945aaf6f7 (patch)
treeaaa9d6f88f826d0694002d56b75453f8dfcb9f36
parent69257bfb8a5b872c0ea885fb7944e1253a398af6 (diff)
Merging r360861, with an additional change to also add the PPC64_OPD1release_80
and PPC64_OPD2 lines to the DEFINE_LIBUNWIND_PRIVATE_FUNCTION() macro, which was removed in r357640: ------------------------------------------------------------------------ r360861 | mstorsjo | 2019-05-15 23:49:13 -0700 (Wed, 15 May 2019) | 13 lines [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 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/libunwind/branches/release_80@365542 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--src/DwarfInstructions.hpp25
-rw-r--r--src/assembly.h22
-rw-r--r--test/lit.cfg3
3 files changed, 48 insertions, 2 deletions
diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp
index ec70c0a..4109549 100644
--- a/src/DwarfInstructions.hpp
+++ b/src/DwarfInstructions.hpp
@@ -234,6 +234,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/src/assembly.h b/src/assembly.h
index 7806892..0b7d243 100644
--- a/src/assembly.h
+++ b/src/assembly.h
@@ -35,6 +35,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)
@@ -95,13 +109,17 @@
.globl SYMBOL_NAME(name) SEPARATOR \
EXPORT_SYMBOL(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
- SYMBOL_NAME(name):
+ PPC64_OPD1 \
+ SYMBOL_NAME(name): \
+ PPC64_OPD2
#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \
.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)
diff --git a/test/lit.cfg b/test/lit.cfg
index 272bc16..1d284bd 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -23,6 +23,9 @@ config.suffixes = ['.cpp', '.s']
# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)
+# needed to test libunwind with code that throws exceptions
+config.enable_exceptions = True
+
# Infer the libcxx_test_source_root for configuration import.
# If libcxx_source_root isn't specified in the config, assume that the libcxx
# and libunwind source directories are sibling directories.