From 5c0095268e19e5a5fcf035c4c591ed03e552f072 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Mon, 29 Feb 2016 17:07:31 +0900 Subject: Fix Stack Unwind for ARM/Linux Make context information compatible with libunwind-arm. In Linux/ARM, seh-unwind.cpp has been updating unw_cursor_t to point another stack by updating the cursor's register entries. However, that does not work in libunwind-arm in Linux, which breaks PAL_VirtualUnwind() functions. Getting the stack information from the cursor had a compatibility issue as well. This patch make both "context->cursor" and "cursor->context" methods compatible with ARM/Linux. Fix #3312 Signed-off-by: MyungJoo Ham --- src/pal/src/exception/seh-unwind.cpp | 38 ++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp index 5d3b353494..ea17cce29e 100644 --- a/src/pal/src/exception/seh-unwind.cpp +++ b/src/pal/src/exception/seh-unwind.cpp @@ -97,17 +97,29 @@ static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor) unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14); unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15); #elif defined(_ARM_) - unw_set_reg(cursor, UNW_ARM_R13, winContext->Sp); - unw_set_reg(cursor, UNW_ARM_R14, winContext->Lr); - unw_set_reg(cursor, UNW_ARM_R15, winContext->Pc); - unw_set_reg(cursor, UNW_ARM_R4, winContext->R4); - unw_set_reg(cursor, UNW_ARM_R5, winContext->R5); - unw_set_reg(cursor, UNW_ARM_R6, winContext->R6); - unw_set_reg(cursor, UNW_ARM_R7, winContext->R7); - unw_set_reg(cursor, UNW_ARM_R8, winContext->R8); - unw_set_reg(cursor, UNW_ARM_R9, winContext->R9); - unw_set_reg(cursor, UNW_ARM_R10, winContext->R10); - unw_set_reg(cursor, UNW_ARM_R11, winContext->R11); + // Assuming that unw_set_reg() on cursor will point the cursor to the + // supposed stack frame is dangerous for libunwind-arm in Linux. + // It is because libunwind's unw_cursor_t has other data structure + // initialized by unw_init_local(), which are not updated by + // unw_set_reg(). + unw_context_t context; + context.regs[0] = 0; + context.regs[1] = 0; + context.regs[2] = 0; + context.regs[3] = 0; + context.regs[4] = winContext->R4; + context.regs[5] = winContext->R5; + context.regs[6] = winContext->R6; + context.regs[7] = winContext->R7; + context.regs[8] = winContext->R8; + context.regs[9] = winContext->R9; + context.regs[10] = winContext->R10; + context.regs[11] = winContext->R11; + context.regs[12] = 0; + context.regs[13] = winContext->Sp; + context.regs[14] = winContext->Lr; + context.regs[15] = winContext->Pc; + unw_init_local(cursor, &context); #endif } #endif @@ -124,9 +136,9 @@ static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext) unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14); unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15); #elif defined(_ARM_) - unw_get_reg(cursor, UNW_ARM_R13, (unw_word_t *) &winContext->Sp); + unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp); + unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc); unw_get_reg(cursor, UNW_ARM_R14, (unw_word_t *) &winContext->Lr); - unw_get_reg(cursor, UNW_ARM_R15, (unw_word_t *) &winContext->Pc); unw_get_reg(cursor, UNW_ARM_R4, (unw_word_t *) &winContext->R4); unw_get_reg(cursor, UNW_ARM_R5, (unw_word_t *) &winContext->R5); unw_get_reg(cursor, UNW_ARM_R6, (unw_word_t *) &winContext->R6); -- cgit v1.2.3 From 3c0d5e85c59107a4710317f445bec0528cbe232b Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Mon, 29 Feb 2016 17:11:10 +0900 Subject: Fix CMake Script for libunwind Feature Check Check the availability correctly for Linux. The cmake configuration script has been trying to find out the availability of functions directly with check_function_exists, which depends on the symbol names in .so files. However, the libunwind implementation uses macros to redefine functions names for each architecture making it impossible to directly look up symbol tables of .so files. In order to allow the script to use the information in header files, check_function_exists should be replaced with check_cxx_source_compiles. Besides config.h.in had missing declarations for the CMAKE variables Fix #3372 Signed-off-by: MyungJoo Ham --- src/pal/src/config.h.in | 2 ++ src/pal/src/configure.cmake | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in index 68cb81ba67..784383f8dd 100644 --- a/src/pal/src/config.h.in +++ b/src/pal/src/config.h.in @@ -53,6 +53,8 @@ #cmakedefine01 HAS_SYSV_SEMAPHORES #cmakedefine01 HAS_PTHREAD_MUTEXES #cmakedefine01 HAVE_TTRACE +#cmakedefine HAVE_UNW_GET_SAVE_LOC +#cmakedefine HAVE_UNW_GET_ACCESSORS #cmakedefine01 HAVE_STAT_TIMESPEC #cmakedefine01 HAVE_STAT_NSEC diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake index be6114d48c..daa99622fe 100644 --- a/src/pal/src/configure.cmake +++ b/src/pal/src/configure.cmake @@ -73,8 +73,28 @@ check_function_exists(directio HAVE_DIRECTIO) check_function_exists(semget HAS_SYSV_SEMAPHORES) check_function_exists(pthread_mutex_init HAS_PTHREAD_MUTEXES) check_function_exists(ttrace HAVE_TTRACE) -check_function_exists(unw_get_save_loc HAVE_UNW_GET_SAVE_LOC) -check_function_exists(unw_get_accessors HAVE_UNW_GET_ACCESSORS) +set(CMAKE_REQUIRED_LIBRARIES unwind unwind-generic) +check_cxx_source_compiles(" +#include + +int main(int argc, char **argv) { + unw_cursor_t cursor; + unw_save_loc_t saveLoc; + int reg = UNW_REG_IP; + unw_get_save_loc(&cursor, reg, &saveLoc); + + return 0; +}" HAVE_UNW_GET_SAVE_LOC) +check_cxx_source_compiles(" +#include + +int main(int argc, char **argv) { + unw_addr_space_t as; + unw_get_accessors(as); + + return 0; +}" HAVE_UNW_GET_ACCESSORS) +set(CMAKE_REQUIRED_LIBRARIES) check_struct_has_member ("struct stat" st_atimespec "sys/types.h;sys/stat.h" HAVE_STAT_TIMESPEC) check_struct_has_member ("struct stat" st_atimensec "sys/types.h;sys/stat.h" HAVE_STAT_NSEC) -- cgit v1.2.3 From b15c9d4f8a2bdad6dc7ecc03df037783e31d7d0c Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Wed, 2 Mar 2016 21:27:00 +0900 Subject: Fix PAL_VirtualUnwind Behavior with Clutters in PC Libunwind-ARM recommends to read LR to get value of PC while unwinding stack, which often causes the caller (PAL_VirtualUnwind) to have LSB of PC set. Such behavior incurs errornous behavior of PAL_VirtualUnwind if the output is fed back to PAL_VirtualUnwind as the input, which is observed with VirtualUnwindToFirstManagedCallFrame(). This commit clears LSB of PC in WinContext to prevent it. Note that this is a partial fix for the issue #3462. (this does not fix assembly stacks) Fix #3462 Signed-off-by: MyungJoo Ham --- src/pal/src/exception/seh-unwind.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp index ea17cce29e..333544379a 100644 --- a/src/pal/src/exception/seh-unwind.cpp +++ b/src/pal/src/exception/seh-unwind.cpp @@ -138,6 +138,7 @@ static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext) #elif defined(_ARM_) unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp); unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc); + winContext->Pc &= ~0x1; unw_get_reg(cursor, UNW_ARM_R14, (unw_word_t *) &winContext->Lr); unw_get_reg(cursor, UNW_ARM_R4, (unw_word_t *) &winContext->R4); unw_get_reg(cursor, UNW_ARM_R5, (unw_word_t *) &winContext->R5); -- cgit v1.2.3 From 35b5df6888f1574e6ef9313c6bc8522d1817573d Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Fri, 4 Mar 2016 13:38:15 +0900 Subject: Fix Stack Unwind Behavior of Libunwind-ARM Disable UNW_ARM_METHOD_DWARF, which gets problematic with assembly-created stacks in ARM systems. Although previous commits have fixed the compatibility issues between cpp stacks and libunwind-arm, the assembly part (asmhelpers.S) had similar problems. Fix #3462 Signed-off-by: MyungJoo Ham --- src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src') diff --git a/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp b/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp index 1125dfb819..8d32a7d390 100644 --- a/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp +++ b/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp @@ -268,6 +268,20 @@ int ExecuteManagedAssembly( // Indicates failure int exitCode = -1; +#ifdef _ARM_ + // LIBUNWIND-ARM has a bug of side effect with DWARF mode + // Ref: https://github.com/dotnet/coreclr/issues/3462 + // This is why Fedora is disabling it by default as well. + // Assuming that we cannot enforce the user to set + // environmental variables for third party packages, + // we set the environmental variable of libunwind locally here. + + // Without this, any exception handling will fail, so let's do this + // as early as possible. + // 0x1: DWARF / 0x2: FRAME / 0x4: EXIDX + putenv("UNW_ARM_UNWIND_METHOD=6"); +#endif // _ARM_ + std::string coreClrDllPath(clrFilesAbsolutePath); coreClrDllPath.append("/"); coreClrDllPath.append(coreClrDll); -- cgit v1.2.3