Libunwind 1.5rc2 again (#36988)
authorSteve MacLean <Steve.MacLean@microsoft.com>
Mon, 1 Jun 2020 20:06:25 +0000 (16:06 -0400)
committerGitHub <noreply@github.com>
Mon, 1 Jun 2020 20:06:25 +0000 (20:06 +0000)
* Add arm64 support for UNWIND_CONTEXT_IS_UCONTEXT_T==0

* Reapply libunwind 1.5rc2

* Fix Linux Alpine libunwind1.5rc2

125 files changed:
src/coreclr/src/pal/src/exception/seh-unwind.cpp
src/coreclr/src/pal/src/libunwind/.gitignore
src/coreclr/src/pal/src/libunwind/.travis.yml
src/coreclr/src/pal/src/libunwind/CMakeLists.txt
src/coreclr/src/pal/src/libunwind/Makefile.am
src/coreclr/src/pal/src/libunwind/README
src/coreclr/src/pal/src/libunwind/autogen.sh
src/coreclr/src/pal/src/libunwind/configure.ac
src/coreclr/src/pal/src/libunwind/include/dwarf-eh.h
src/coreclr/src/pal/src/libunwind/include/dwarf.h
src/coreclr/src/pal/src/libunwind/include/libunwind-aarch64.h
src/coreclr/src/pal/src/libunwind/include/libunwind-common.h.in
src/coreclr/src/pal/src/libunwind/include/libunwind-mips.h
src/coreclr/src/pal/src/libunwind/include/libunwind-s390x.h [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/include/libunwind.h.in
src/coreclr/src/pal/src/libunwind/include/libunwind_i.h
src/coreclr/src/pal/src/libunwind/include/tdep-mips/dwarf-config.h
src/coreclr/src/pal/src/libunwind/include/tdep-mips/libunwind_i.h
src/coreclr/src/pal/src/libunwind/include/tdep-s390x/dwarf-config.h [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/include/tdep-s390x/jmpbuf.h [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/include/tdep-s390x/libunwind_i.h [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/include/tdep-x86_64/jmpbuf.h
src/coreclr/src/pal/src/libunwind/include/tdep-x86_64/libunwind_i.h
src/coreclr/src/pal/src/libunwind/include/tdep/libunwind_i.h.in
src/coreclr/src/pal/src/libunwind/libunwind-version.txt [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/CMakeLists.txt
src/coreclr/src/pal/src/libunwind/src/Makefile.am
src/coreclr/src/pal/src/libunwind/src/aarch64/Ginit.c
src/coreclr/src/pal/src/libunwind/src/aarch64/Ginit_local.c
src/coreclr/src/pal/src/libunwind/src/aarch64/Gresume.c
src/coreclr/src/pal/src/libunwind/src/aarch64/unwind_i.h
src/coreclr/src/pal/src/libunwind/src/arm/Gex_tables.c
src/coreclr/src/pal/src/libunwind/src/arm/Ginit.c
src/coreclr/src/pal/src/libunwind/src/arm/Gresume.c
src/coreclr/src/pal/src/libunwind/src/arm/Gstep.c
src/coreclr/src/pal/src/libunwind/src/coredump/_UCD_access_reg_freebsd.c
src/coreclr/src/pal/src/libunwind/src/coredump/_UCD_access_reg_linux.c
src/coreclr/src/pal/src/libunwind/src/coredump/_UCD_create.c
src/coreclr/src/pal/src/libunwind/src/coredump/_UCD_get_proc_name.c
src/coreclr/src/pal/src/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c
src/coreclr/src/pal/src/libunwind/src/dwarf/Gexpr.c
src/coreclr/src/pal/src/libunwind/src/dwarf/Gfind_proc_info-lsb.c
src/coreclr/src/pal/src/libunwind/src/dwarf/Gfind_unwind_table.c
src/coreclr/src/pal/src/libunwind/src/dwarf/Gparser.c
src/coreclr/src/pal/src/libunwind/src/elfxx.c
src/coreclr/src/pal/src/libunwind/src/hppa/Ginit.c
src/coreclr/src/pal/src/libunwind/src/ia64/Ginit.c
src/coreclr/src/pal/src/libunwind/src/mi/Gfind_dynamic_proc_info.c
src/coreclr/src/pal/src/libunwind/src/mi/Gget_proc_name.c
src/coreclr/src/pal/src/libunwind/src/mi/backtrace.c
src/coreclr/src/pal/src/libunwind/src/mi/flush_cache.c
src/coreclr/src/pal/src/libunwind/src/mips/Gcreate_addr_space.c
src/coreclr/src/pal/src/libunwind/src/mips/Gget_proc_info.c
src/coreclr/src/pal/src/libunwind/src/mips/Ginit.c
src/coreclr/src/pal/src/libunwind/src/mips/Gregs.c
src/coreclr/src/pal/src/libunwind/src/mips/Gstep.c
src/coreclr/src/pal/src/libunwind/src/os-solaris.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/ppc32/Ginit.c
src/coreclr/src/pal/src/libunwind/src/ppc64/Ginit.c
src/coreclr/src/pal/src/libunwind/src/ptrace/_UPT_access_fpreg.c
src/coreclr/src/pal/src/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c
src/coreclr/src/pal/src/libunwind/src/ptrace/_UPT_reg_offset.c
src/coreclr/src/pal/src/libunwind/src/s390x/Gapply_reg_state.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gcreate_addr_space.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gget_proc_info.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gget_save_loc.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gglobal.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Ginit.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Ginit_local.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Ginit_remote.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gis_signal_frame.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Greg_states_iterate.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gregs.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gresume.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Gstep.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lapply_reg_state.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lcreate_addr_space.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lget_proc_info.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lget_save_loc.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lglobal.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Linit.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Linit_local.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Linit_remote.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lis_signal_frame.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lreg_states_iterate.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lregs.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lresume.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/Lstep.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/getcontext.S [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/init.h [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/is_fpreg.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/regname.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/setcontext.S [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/s390x/unwind_i.h [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/setjmp/siglongjmp.c
src/coreclr/src/pal/src/libunwind/src/sh/Ginit.c
src/coreclr/src/pal/src/libunwind/src/sh/Ginit_local.c
src/coreclr/src/pal/src/libunwind/src/sh/Gresume.c
src/coreclr/src/pal/src/libunwind/src/tilegx/Ginit.c
src/coreclr/src/pal/src/libunwind/src/unwind/libunwind.pc.in
src/coreclr/src/pal/src/libunwind/src/x86/Ginit.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Gget_save_loc.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Gglobal.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Ginit.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Ginit_local.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Ginit_remote.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Gos-solaris.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/x86_64/Gstash_frame.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Gstep.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Gtrace.c
src/coreclr/src/pal/src/libunwind/src/x86_64/Los-solaris.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/src/x86_64/getcontext.S
src/coreclr/src/pal/src/libunwind/src/x86_64/setcontext.S
src/coreclr/src/pal/src/libunwind/src/x86_64/ucontext_i.h
src/coreclr/src/pal/src/libunwind/tests/Gtest-bt.c
src/coreclr/src/pal/src/libunwind/tests/Gtest-trace.c
src/coreclr/src/pal/src/libunwind/tests/Gx64-test-dwarf-expressions.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/tests/Ltest-mem-validate.c
src/coreclr/src/pal/src/libunwind/tests/Lx64-test-dwarf-expressions.c [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/tests/Makefile.am
src/coreclr/src/pal/src/libunwind/tests/check-namespace.sh.in
src/coreclr/src/pal/src/libunwind/tests/crasher.c
src/coreclr/src/pal/src/libunwind/tests/test-coredump-unwind.c
src/coreclr/src/pal/src/libunwind/tests/x64-test-dwarf-expressions.S [new file with mode: 0644]
src/coreclr/src/pal/src/libunwind/tests/x64-unwind-badjmp-signal-frame.c [new file with mode: 0644]

index 53c86a0..654e385 100644 (file)
@@ -111,6 +111,22 @@ static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwCon
     unwContext->regs[13] = winContext->Sp;
     unwContext->regs[14] = winContext->Lr;
     unwContext->regs[15] = winContext->Pc;
+#elif defined(HOST_ARM64)
+    unwContext->uc_mcontext.pc       = winContext->Pc;
+    unwContext->uc_mcontext.sp       = winContext->Sp;
+    unwContext->uc_mcontext.regs[29] = winContext->Fp;
+    unwContext->uc_mcontext.regs[30] = winContext->Lr;
+
+    unwContext->uc_mcontext.regs[19] = winContext->X19;
+    unwContext->uc_mcontext.regs[20] = winContext->X20;
+    unwContext->uc_mcontext.regs[21] = winContext->X21;
+    unwContext->uc_mcontext.regs[22] = winContext->X22;
+    unwContext->uc_mcontext.regs[23] = winContext->X23;
+    unwContext->uc_mcontext.regs[24] = winContext->X24;
+    unwContext->uc_mcontext.regs[25] = winContext->X25;
+    unwContext->uc_mcontext.regs[26] = winContext->X26;
+    unwContext->uc_mcontext.regs[27] = winContext->X27;
+    unwContext->uc_mcontext.regs[28] = winContext->X28;
 #endif
 }
 
index 7b7905f..724a1f4 100644 (file)
@@ -75,5 +75,7 @@ tests/[GL]ia64-test-readonly
 tests/[GL]ia64-test-stack
 tests/ia64-test-dyn1
 tests/ia64-test-sig
+tests/[GL]x64-test-dwarf-expressions
+tests/x64-unwind-badjmp-signal-frame
 tests/*.log
 tests/*.trs
index 4a74b4a..7bf0f8d 100644 (file)
@@ -9,6 +9,18 @@ env:
 - TARGET=mipsel-unknown-linux-gnu
 # Currently experiencing build failures here
 #- TARGET=powerpc64-linux-gnu
+
+linux-s390x: &linux-s390x
+  os: linux
+  arch: s390x
+  env: TARGET=s390x-linux-gnu
+  script:
+    - ./autogen.sh
+    - ./configure
+    - make -j32
+    - ulimit -c unlimited
+    - make check -j32
+
 script:
 - ./autogen.sh
 - ./configure --target=$TARGET --host=$HOST
@@ -16,3 +28,7 @@ script:
 - sudo bash -c 'echo core.%p.%p > /proc/sys/kernel/core_pattern'
 - ulimit -c unlimited
 - if [ $TARGET == 'x86_64-linux-gnu' ]; then make check -j32; fi
+
+jobs:
+  include:
+    - <<: *linux-s390x
index 5c66b90..fc47c89 100644 (file)
@@ -13,10 +13,9 @@ elseif(CLR_CMAKE_HOST_ARCH_I386)
 endif()
 
 set(PKG_MAJOR "1")
-set(PKG_MINOR "3")
-set(PKG_EXTRA "-rc1")
+set(PKG_MINOR "5")
+set(PKG_EXTRA "-rc2")
 
 configure_file(include/libunwind-common.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind-common.h)
 configure_file(include/libunwind.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind.h)
 configure_file(include/tdep/libunwind_i.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/tdep/libunwind_i.h)
-
index 711d910..8132fa4 100644 (file)
@@ -41,6 +41,9 @@ endif
 if ARCH_SH
 include_HEADERS += include/libunwind-sh.h
 endif
+if ARCH_S390X
+include_HEADERS += include/libunwind-s390x.h
+endif
 
 if !REMOTE_ONLY
 include_HEADERS += include/libunwind.h include/unwind.h
@@ -84,6 +87,8 @@ noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \
        include/tdep-ppc64/jmpbuf.h include/tdep-ppc64/libunwind_i.h    \
        include/tdep-sh/dwarf-config.h                                  \
        include/tdep-sh/jmpbuf.h include/tdep-sh/libunwind_i.h          \
+       include/tdep-s390x/dwarf-config.h                               \
+       include/tdep-s390x/jmpbuf.h include/tdep-s390x/libunwind_i.h    \
        include/tdep/libunwind_i.h                                      \
        include/tdep/jmpbuf.h include/tdep/dwarf-config.h
 
index 694f600..b6d93ae 100644 (file)
@@ -1,53 +1,83 @@
--*- mode: Outline -*-
+# libunwind
 
 [![Build Status](https://travis-ci.org/libunwind/libunwind.svg?branch=master)](https://travis-ci.org/libunwind/libunwind)
 
-This is version 1.3 of the unwind library.  This library supports
+This is version 1.5 of the unwind library.  This library supports
 several architecture/operating-system combinations:
 
- Linux/x86-64: Works well.
- Linux/x86:    Works well.
- Linux/ARM:    Works well.
- Linux/IA-64:  Works well.
- Linux/PARISC: Works well, but C library missing unwind-info.
- HP-UX/IA-64:  Mostly works but known to have some serious limitations.
- MIPS:          Newly added.
- Linux/AArch64:        Works well.
- Linux/PPC64:  Newly added.
- Linux/SuperH: Newly added.
- FreeBSD/i386: Works well.
- FreeBSD/x86-64: Newly added (FreeBSD architecture is known as amd64).
- Linux/Tilegx:  Newly added (64-bit mode only).
-
-* General Build Instructions
+| System  | Architecture | Status |
+| :------ | :----------- | :----- |
+| Linux   | x86-64       | âœ“      |
+| Linux   | x86          | âœ“      |
+| Linux   | ARM          | âœ“      |
+| Linux   | AArch64      | âœ“      |
+| Linux   | PPC64        | âœ“      |
+| Linux   | SuperH       | âœ“      |
+| Linux   | IA-64        | âœ“      |
+| Linux   | PARISC       | Works well, but C library missing unwind-info |
+| Linux   | Tilegx       | 64-bit mode only |
+| Linux   | MIPS         | Newly added |
+| HP-UX   | IA-64        | Mostly works, but known to have serious limitations |
+| FreeBSD | x86-64       | âœ“      |
+| FreeBSD | x86          | âœ“      |
+| FreeBSD | AArch64      | âœ“      |
+| Solaris | x86-64       | âœ“      |
+
+## Libc Requirements
+
+libunwind depends on getcontext(), setcontext() functions which are missing
+from C libraries like musl-libc because they are considered to be "obsolescent"
+API by POSIX document.  The following table tries to track current status of
+such dependencies
+
+ - r, requires
+ - p, provides its own implementation
+ - empty, no requirement
+
+| Archtecture  | getcontext | setcontext |
+|--------------|------------|------------|
+|    aarch64   |     p      |            |
+|    arm       |     p      |            |
+|    hppa      |     p      |      p     |
+|    ia64      |     p      |      r     |
+|    mips      |     p      |            |
+|    ppc32     |     r      |            |
+|    ppc64     |     r      |      r     |
+|    s390x     |     p      |      p     |
+|    sh        |     r      |            |
+|    tilegx    |     r      |      r     |
+|    x86       |     p      |      r     |
+|    x86_64    |     p      |      p     |
+
+## General Build Instructions
 
 In general, this library can be built and installed with the following
 commands:
 
-       $ ./autogen.sh # Needed only for building from git. Depends on libtool.
-       $ ./configure
-       $ make
-       $ make install prefix=PREFIX
+    $ ./autogen.sh # Needed only for building from git. Depends on libtool.
+    $ ./configure
+    $ make
+    $ make install prefix=PREFIX
 
-where PREFIX is the installation prefix.  By default, a prefix of
-/usr/local is used, such that libunwind.a is installed in
-/usr/local/lib and unwind.h is installed in /usr/local/include.  For
-testing, you may want to use a prefix of /usr/local instead.
+where `PREFIX` is the installation prefix.  By default, a prefix of
+`/usr/local` is used, such that `libunwind.a` is installed in
+`/usr/local/lib` and `unwind.h` is installed in `/usr/local/include`.  For
+testing, you may want to use a prefix of `/usr/local` instead.
 
 
-* Building with Intel compiler
+### Building with Intel compiler
 
-** Version 8 and later
+#### Version 8 and later
 
 Starting with version 8, the preferred name for the IA-64 Intel
-compiler is "icc" (same name as on x86).  Thus, the configure-line
+compiler is `icc` (same name as on x86).  Thus, the configure-line
 should look like this:
 
     $ ./configure CC=icc CFLAGS="-g -O3 -ip" CXX=icc CCAS=gcc CCASFLAGS=-g \
-               LDFLAGS="-L$PWD/src/.libs"
+        LDFLAGS="-L$PWD/src/.libs"
 
 
-* Building on HP-UX
+### Building on HP-UX
 
 For the time being, libunwind must be built with GCC on HP-UX.
 
@@ -55,14 +85,13 @@ libunwind should be configured and installed on HP-UX like this:
 
     $ ./configure CFLAGS="-g -O2 -mlp64" CXXFLAGS="-g -O2 -mlp64"
 
-Caveat: Unwinding of 32-bit (ILP32) binaries is not supported
-       at the moment.
+Caveat: Unwinding of 32-bit (ILP32) binaries is not supported at the moment.
 
-** Workaround for older versions of GCC
+### Workaround for older versions of GCC
 
-GCC v3.0 and GCC v3.2 ship with a bad version of sys/types.h.  The
+GCC v3.0 and GCC v3.2 ship with a bad version of `sys/types.h`.  The
 workaround is to issue the following commands before running
-"configure":
+`configure`:
 
     $ mkdir $top_dir/include/sys
     $ cp /usr/include/sys/types.h $top_dir/include/sys
@@ -70,138 +99,141 @@ workaround is to issue the following commands before running
 GCC v3.3.2 or later have been fixed and do not require this
 workaround.
 
-* Building for PowerPC64 / Linux
+### Building for PowerPC64 / Linux
 
 For building for power64 you should use:
 
-  $ ./configure CFLAGS="-g -O2 -m64" CXXFLAGS="-g -O2 -m64"
+    $ ./configure CFLAGS="-g -O2 -m64" CXXFLAGS="-g -O2 -m64"
 
 If your power support altivec registers:
-  $ ./configure CFLAGS="-g -O2 -m64 -maltivec" CXXFLAGS="-g -O2 -m64 -maltivec"
+
+    $ ./configure CFLAGS="-g -O2 -m64 -maltivec" CXXFLAGS="-g -O2 -m64 -maltivec"
 
 To check if your processor has support for vector registers (altivec):
+
     cat /proc/cpuinfo | grep altivec
+
 and should have something like this:
+
     cpu             : PPC970, altivec supported
 
 If libunwind seems to not work (backtracing failing), try to compile
-it with -O0, without optimizations. There are some compiler problems
+it with `-O0`, without optimizations. There are some compiler problems
 depending on the version of your gcc.
 
-* Building on FreeBSD
-
-General building instructions apply. To build and execute several tests,
-you need libexecinfo library available in ports as devel/libexecinfo.
+### Building on FreeBSD
 
-Development of the port was done of FreeBSD 8.0-STABLE. The library
-was build with the system compiler that is modified version of gcc 4.2.1,
-as well as the gcc 4.4.3.
+General building instructions apply. To build and execute several tests
+on older versions of FreeBSD, you need libexecinfo library available in
+ports as devel/libexecinfo. This port has been removed as of 2017 and is
+indeed no longer needed.
 
-* Regression Testing
+## Regression Testing
 
 After building the library, you can run a set of regression tests with:
 
-       $ make check
+    $ make check
 
-** Expected results on IA-64 Linux
+### Expected results on IA-64 Linux
 
 Unless you have a very recent C library and compiler installed, it is
 currently expected to have the following tests fail on IA-64 Linux:
 
-       Gtest-init              (should pass starting with glibc-2.3.x/gcc-3.4)
-       Ltest-init              (should pass starting with glibc-2.3.x/gcc-3.4)
-       test-ptrace             (should pass starting with glibc-2.3.x/gcc-3.4)
-       run-ia64-test-dyn1      (should pass starting with glibc-2.3.x)
+* `Gtest-init` (should pass starting with glibc-2.3.x/gcc-3.4)
+* `Ltest-init` (should pass starting with glibc-2.3.x/gcc-3.4)
+* `test-ptrace` (should pass starting with glibc-2.3.x/gcc-3.4)
+* `run-ia64-test-dyn1` (should pass starting with glibc-2.3.x)
 
 This does not mean that libunwind cannot be used with older compilers
 or C libraries, it just means that for certain corner cases, unwinding
 will fail.  Since they're corner cases, it is not likely for
 applications to trigger them.
 
-Note: If you get lots of errors in Gia64-test-nat and Lia64-test-nat, it's
-      almost certainly a sign of an old assembler.  The GNU assembler used
-      to encode previous-stack-pointer-relative offsets incorrectly.
-      This bug was fixed on 21-Sep-2004 so any later assembler will be
-      fine.
+Note: If you get lots of errors in `Gia64-test-nat` and `Lia64-test-nat`, it's
+almost certainly a sign of an old assembler.  The GNU assembler used
+to encode previous-stack-pointer-relative offsets incorrectly.
+This bug was fixed on 21-Sep-2004 so any later assembler will be
+fine.
 
-** Expected results on x86 Linux
+### Expected results on x86 Linux
 
 The following tests are expected to fail on x86 Linux:
 
-       test-ptrace
+* `test-ptrace`
 
-** Expected results on x86-64 Linux
+### Expected results on x86-64 Linux
 
 The following tests are expected to fail on x86-64 Linux:
 
-       run-ptrace-misc (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18748
-                        and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18749)
+* `run-ptrace-misc` (see <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18748>
+  and <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18749>)
 
-** Expected results on PARISC Linux
+### Expected results on PARISC Linux
 
 Caveat: GCC v3.4 or newer is needed on PA-RISC Linux.  Earlier
 versions of the compiler failed to generate the exception-handling
-program header (GNU_EH_FRAME) needed for unwinding.
+program header (`GNU_EH_FRAME`) needed for unwinding.
 
 The following tests are expected to fail on x86-64 Linux:
 
-       Gtest-bt   (backtrace truncated at kill() due to lack of unwind-info)
-       Ltest-bt   (likewise)
-       Gtest-resume-sig  (Gresume.c:my_rt_sigreturn() is wrong somehow)
-       Ltest-resume-sig  (likewise)
-       Gtest-init (likewise)
-       Ltest-init (likewise)
-       Gtest-dyn1 (no dynamic unwind info support yet)
-       Ltest-dyn1 (no dynamic unwind info support yet)
-       test-setjmp             (longjmp() not implemented yet)
-       run-check-namespace     (toolchain doesn't support HIDDEN yet)
+* `Gtest-bt` (backtrace truncated at `kill()` due to lack of unwind-info)
+* `Ltest-bt` (likewise)
+* `Gtest-resume-sig` (`Gresume.c:my_rt_sigreturn()` is wrong somehow)
+* `Ltest-resume-sig` (likewise)
+* `Gtest-init` (likewise)
+* `Ltest-init` (likewise)
+* `Gtest-dyn1` (no dynamic unwind info support yet)
+* `Ltest-dyn1` (no dynamic unwind info support yet)
+* `test-setjmp` (`longjmp()` not implemented yet)
+* `run-check-namespace` (toolchain doesn't support `HIDDEN` yet)
 
-** Expected results on HP-UX
+### Expected results on HP-UX
 
-"make check" is currently unsupported for HP-UX.  You can try to run
+`make check` is currently unsupported for HP-UX.  You can try to run
 it, but most tests will fail (and some may fail to terminate).  The
 only test programs that are known to work at this time are:
 
-     tests/bt
-     tests/Gperf-simple
-     tests/test-proc-info
-     tests/test-static-link
-     tests/Gtest-init
-     tests/Ltest-init
-     tests/Gtest-resume-sig
-     tests/Ltest-resume-sig
+* `tests/bt`
+* `tests/Gperf-simple`
+* `tests/test-proc-info`
+* `tests/test-static-link`
+* `tests/Gtest-init`
+* `tests/Ltest-init`
+* `tests/Gtest-resume-sig`
+* `tests/Ltest-resume-sig`
+
+### Expected results on PPC64 Linux
 
-** Expected results on PPC64 Linux
+`make check` should run with no more than 10 out of 24 tests failed.
 
-"make check" should run with no more than 10 out of 24 tests failed.
+### Expected results on Solaris x86-64
 
+`make check` is passing 27 out of 33 tests. The following six tests are consistently
+failing:
 
-* Performance Testing
+* `Gtest-concurrent`
+* `Ltest-concurrent`
+* `Ltest-init-local-signal`
+* `Lrs-race`
+* `test-setjmp`
+* `x64-unwind-badjmp-signal-frame`
+
+## Performance Testing
 
 This distribution includes a few simple performance tests which give
 some idea of the basic cost of various libunwind operations.  After
 building the library, you can run these tests with the following
 commands:
 
- $ cd tests
- $ make perf
-
-* Contacting the Developers
-
-Please direct all questions regarding this library to:
-
-       libunwind-devel@nongnu.org
-
-You can do this by sending a mail to libunwind-request@nongnu.org with
-a body of:
-
-       subscribe libunwind-devel
+    $ cd tests
+    $ make perf
 
-or you can subscribe and manage your subscription via the
-web-interface at:
+## Contacting the Developers
 
-       https://savannah.nongnu.org/mail/?group=libunwind
+Please direct all questions regarding this library to <libunwind-devel@nongnu.org>.
 
-Or interact at the gihub page:
+You can do this by sending an email to <libunwind-request@nongnu.org> with
+a body of "subscribe libunwind-devel", or you can subscribe and manage your
+subscription via the web-interface at <https://savannah.nongnu.org/mail/?group=libunwind>.
 
-       https://github.com/libunwind/libunwind
+You can also interact on our GitHub page: <https://github.com/libunwind/libunwind>.
index aad9de6..b08bc83 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test -n "$srcdir" || srcdir=`dirname "${BASH_SOURCE[0]}"`
+test -n "$srcdir" || srcdir=`dirname "$0"`
 test -n "$srcdir" || srcdir=.
 (
   cd "$srcdir" &&
index 0c51259..226a10f 100644 (file)
@@ -1,5 +1,5 @@
 define(pkg_major, 1)
-define(pkg_minor, 3)
+define(pkg_minor, 5)
 define(pkg_extra, -rc1)
 define(pkg_maintainer, libunwind-devel@nongnu.org)
 define(mkvers, $1.$2$3)
@@ -70,7 +70,7 @@ PT_STEP, PT_SYSCALL], [], [],
 
 dnl Checks for library functions.
 AC_CHECK_FUNCS(dl_iterate_phdr dl_phdr_removals_counter dlmodinfo getunwind \
-               ttrace mincore)
+               ttrace mincore pipe2)
 
 AC_MSG_CHECKING([if building with AltiVec])
 AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
@@ -147,6 +147,10 @@ AC_ARG_ENABLE(tests,
  AS_HELP_STRING([--disable-tests],[Disable tests build]),,
  [enable_tests=yes])
 
+AC_ARG_ENABLE(weak-backtrace,
+ AS_HELP_STRING([--disable-weak-backtrace],[Do not provide the weak 'backtrace' symbol.]),,
+ [enable_weak_backtrace=yes])
+
 AC_MSG_CHECKING([if we should build libunwind-setjmp])
 AC_MSG_RESULT([$enable_setjmp])
 
@@ -175,15 +179,17 @@ AM_CONDITIONAL(ARCH_PPC32, test x$target_arch = xppc32)
 AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64)
 AM_CONDITIONAL(ARCH_SH, test x$target_arch = xsh)
 AM_CONDITIONAL(ARCH_TILEGX, test x$target_arch = xtilegx)
+AM_CONDITIONAL(ARCH_S390X, test x$target_arch = xs390x)
 AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null)
 AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null)
 AM_CONDITIONAL(OS_FREEBSD, expr x$target_os : xfreebsd >/dev/null)
 AM_CONDITIONAL(OS_QNX, expr x$target_os : xnto-qnx >/dev/null)
+AM_CONDITIONAL(OS_SOLARIS, expr x$target_os : xsolaris >/dev/null)
 
 AC_MSG_CHECKING([for ELF helper width])
 case "${target_arch}" in
 (arm|hppa|ppc32|x86|sh) use_elf32=yes; AC_MSG_RESULT([32]);;
-(aarch64|ia64|ppc64|x86_64|tilegx)  use_elf64=yes; AC_MSG_RESULT([64]);;
+(aarch64|ia64|ppc64|x86_64|s390x|tilegx)  use_elf64=yes; AC_MSG_RESULT([64]);;
 (mips)                 use_elfxx=yes; AC_MSG_RESULT([xx]);;
 *)                     AC_MSG_ERROR([Unknown ELF target: ${target_arch}])
 esac
@@ -300,6 +306,23 @@ fi
 AC_SUBST([LIBLZMA])
 AM_CONDITIONAL(HAVE_LZMA, test x$enable_minidebuginfo = xyes)
 
+LIBZ=
+AC_MSG_CHECKING([whether to support ZLIB-compressed symbol tables])
+AC_ARG_ENABLE(zlibdebuginfo,
+AS_HELP_STRING([--enable-zlibdebuginfo], [Enables support for ZLIB-compressed symbol tables]),, [enable_zlibdebuginfo=auto])
+AC_MSG_RESULT([$enable_zlibdebuginfo])
+if test x$enable_zlibdebuginfo != xno; then
+   AC_CHECK_LIB([z], [uncompress],
+   [LIBZ=-lz
+    AC_DEFINE([HAVE_ZLIB], [1], [Define if you have libz])
+    enable_zlibdebuginfo=yes],
+   [if test x$enable_zlibdebuginfo = xyes; then
+      AC_MSG_FAILURE([libz not found])
+    fi])
+fi
+AC_SUBST([LIBZ])
+AM_CONDITIONAL(HAVE_ZLIB, test x$enable_zlibdebuginfo = xyes)
+
 AC_MSG_CHECKING([whether to support UNW_CACHE_PER_THREAD])
 AC_ARG_ENABLE([per-thread-cache],
 AS_HELP_STRING([--enable-per-thread-cache], [build with support for UNW_CACHE_PER_THREAD (which imposes a hight TLS memory usage) (default: disabled)]))
@@ -321,6 +344,14 @@ if test x$GCC = xyes -a x$intel_compiler != xyes; then
 fi
 AC_MSG_RESULT([$intel_compiler])
 
+AC_MSG_CHECKING([if building on Solaris then define __EXTENSIONS__ macro])
+if $OS_SOLARIS; then
+  CFLAGS="${CFLAGS} -D__EXTENSIONS__"
+  AC_MSG_RESULT([yes])
+else
+  AC_MSG_RESULT([no])
+fi
+
 AC_MSG_CHECKING([for QCC compiler])
 AS_CASE([$CC], [qcc*|QCC*], [qcc_compiler=yes], [qcc_compiler=no])
 AC_MSG_RESULT([$qcc_compiler])
@@ -436,6 +467,11 @@ if test "x$enable_tests" = "xyes"; then
   AC_CONFIG_FILES(tests/Makefile tests/check-namespace.sh)
 fi
 
+AM_CONDITIONAL([CONFIG_WEAK_BACKTRACE], [test "x$enable_weak_backtrace" = xyes])
+AM_COND_IF([CONFIG_WEAK_BACKTRACE], [
+  AC_DEFINE([CONFIG_WEAK_BACKTRACE], [1], [Define if the weak 'backtrace' symbol is provided.])
+])
+
 AC_CONFIG_FILES(Makefile src/Makefile
                 include/libunwind-common.h
                 include/libunwind.h include/tdep/libunwind_i.h)
index e037507..96002a1 100644 (file)
@@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #define dwarf_eh_h
 
 #include "dwarf.h"
+#include "libunwind_i.h"
 
 /* This header file defines the format of a DWARF exception-header
    section (.eh_frame_hdr, pointed to by program-header
index fab93c6..764f6f2 100644 (file)
@@ -419,7 +419,7 @@ extern int dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t a
                                     unw_word_t ip);
 extern void dwarf_put_unwind_info (unw_addr_space_t as,
                                    unw_proc_info_t *pi, void *arg);
-extern int dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr,
+extern int dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_word_t *addr,
                             unw_word_t len, unw_word_t *valp,
                             int *is_register);
 extern int
index 85812e1..21cdb54 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #include <inttypes.h>
 #include <stddef.h>
 #include <ucontext.h>
+#include <signal.h>
 
 #define UNW_TARGET      aarch64
 #define UNW_TARGET_AARCH64      1
@@ -44,9 +45,13 @@ extern "C" {
    leaving some slack for future expansion.  Changing this value will
    require recompiling all users of this library.  Stack allocation is
    relatively cheap and unwind-state copying is relatively rare, so we
-   want to err on making it rather too big than too small.  */
+   want to err on making it rather too big than too small.
 
-#define UNW_TDEP_CURSOR_LEN     512
+   Calculation is regs used (64 + 34) * 2 + 40 (bytes of rest of
+   cursor) + padding
+*/
+
+#define UNW_TDEP_CURSOR_LEN     250
 
 typedef uint64_t unw_word_t;
 typedef int64_t unw_sword_t;
@@ -169,15 +174,46 @@ typedef struct unw_tdep_save_loc
 unw_tdep_save_loc_t;
 
 
-/* On AArch64, we can directly use ucontext_t as the unwind context.  */
-typedef ucontext_t unw_tdep_context_t;
+/* On AArch64, we can directly use ucontext_t as the unwind context,
+ * however, the __reserved struct is quite large: tune it down to only
+ * the necessary used fields.  */
+
+struct unw_sigcontext
+  {
+       uint64_t fault_address;
+       uint64_t regs[31];
+       uint64_t sp;
+       uint64_t pc;
+       uint64_t pstate;
+       uint8_t __reserved[(66 * 8)] __attribute__((__aligned__(16)));
+};
+
+typedef struct
+  {
+       unsigned long uc_flags;
+       struct ucontext *uc_link;
+       stack_t uc_stack;
+       sigset_t uc_sigmask;
+       struct unw_sigcontext uc_mcontext;
+  } unw_tdep_context_t;
+
+typedef struct
+  {
+       uint32_t _ctx_magic;
+       uint32_t _ctx_size;
+       uint32_t fpsr;
+       uint32_t fpcr;
+       uint64_t vregs[64];
+  } unw_fpsimd_context_t;
+
+
 
 #include "libunwind-common.h"
 #include "libunwind-dynamic.h"
 
 #define unw_tdep_getcontext(uc) (({                                    \
   unw_tdep_context_t *unw_ctx = (uc);                                  \
-  register uint64_t *unw_base asm ("x0") = (uint64_t*) unw_ctx->uc_mcontext.regs;              \
+  register uint64_t *unw_base __asm__ ("x0") = (uint64_t*) unw_ctx->uc_mcontext.regs;          \
   __asm__ __volatile__ (                                               \
      "stp x0, x1, [%[base], #0]\n" \
      "stp x2, x3, [%[base], #16]\n" \
index 8d96ddc..9dbb415 100644 (file)
@@ -30,6 +30,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #define UNW_VERSION_CODE(maj,min)      (((maj) << 16) | (min))
 #define UNW_VERSION    UNW_VERSION_CODE(UNW_VERSION_MAJOR, UNW_VERSION_MINOR)
 
+#ifdef __sun
+// On SmartOS, gcc fails with the following error:
+//
+// ../include/libunwind-common.h:43:41: error: expected identifier or '(' before numeric constant
+// # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_)
+//                                         ^
+//
+// workaround is to undefine _U explicitly.
+// see https://github.com/libunwind/libunwind/issues/118 for more details.
+//
+#undef _U
+#endif
+
 #define UNW_PASTE2(x,y)        x##y
 #define UNW_PASTE(x,y) UNW_PASTE2(x,y)
 #define UNW_OBJ(fn)    UNW_PASTE(UNW_PREFIX, fn)
@@ -240,7 +253,6 @@ unw_save_loc_t;
 #define unw_set_fpreg          UNW_OBJ(set_fpreg)
 #define unw_get_save_loc       UNW_OBJ(get_save_loc)
 #define unw_is_signal_frame    UNW_OBJ(is_signal_frame)
-#define unw_handle_signal_frame        UNW_OBJ(handle_signal_frame)
 #define unw_get_proc_name      UNW_OBJ(get_proc_name)
 #define unw_set_caching_policy UNW_OBJ(set_caching_policy)
 #define unw_set_cache_size     UNW_OBJ(set_cache_size)
@@ -273,7 +285,6 @@ extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *);
 extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t);
 extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *);
 extern int unw_is_signal_frame (unw_cursor_t *);
-extern int unw_handle_signal_frame (unw_cursor_t *);
 extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *);
 extern const char *unw_strerror (int);
 extern int unw_backtrace (void **, int);
index 97c95e2..ced34b2 100644 (file)
@@ -98,7 +98,7 @@ typedef enum
     UNW_MIPS_R30,
     UNW_MIPS_R31,
 
-    UNW_MIPS_PC = 34,
+    UNW_MIPS_PC = 64,
 
     /* FIXME: Other registers!  */
 
diff --git a/src/coreclr/src/pal/src/libunwind/include/libunwind-s390x.h b/src/coreclr/src/pal/src/libunwind/include/libunwind-s390x.h
new file mode 100644 (file)
index 0000000..ebda40d
--- /dev/null
@@ -0,0 +1,144 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002-2004 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#ifndef LIBUNWIND_H
+#define LIBUNWIND_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <ucontext.h>
+
+#define UNW_TARGET              s390x
+#define UNW_TARGET_S390X        1
+
+#define _U_TDEP_QP_TRUE 0       /* see libunwind-dynamic.h  */
+
+/* This needs to be big enough to accommodate "struct cursor", while
+   leaving some slack for future expansion.  Changing this value will
+   require recompiling all users of this library.  Stack allocation is
+   relatively cheap and unwind-state copying is relatively rare, so we
+   want to err on making it rather too big than too small.  */
+#define UNW_TDEP_CURSOR_LEN     384
+
+typedef uint64_t unw_word_t;
+typedef int64_t unw_sword_t;
+
+typedef double unw_tdep_fpreg_t;
+
+typedef enum
+  {
+    /* general purpose registers */
+    UNW_S390X_R0,
+    UNW_S390X_R1,
+    UNW_S390X_R2,
+    UNW_S390X_R3,
+    UNW_S390X_R4,
+    UNW_S390X_R5,
+    UNW_S390X_R6,
+    UNW_S390X_R7,
+    UNW_S390X_R8,
+    UNW_S390X_R9,
+    UNW_S390X_R10,
+    UNW_S390X_R11,
+    UNW_S390X_R12,
+    UNW_S390X_R13,
+    UNW_S390X_R14,
+    UNW_S390X_R15,
+
+    /* floating point registers */
+    UNW_S390X_F0,
+    UNW_S390X_F1,
+    UNW_S390X_F2,
+    UNW_S390X_F3,
+    UNW_S390X_F4,
+    UNW_S390X_F5,
+    UNW_S390X_F6,
+    UNW_S390X_F7,
+    UNW_S390X_F8,
+    UNW_S390X_F9,
+    UNW_S390X_F10,
+    UNW_S390X_F11,
+    UNW_S390X_F12,
+    UNW_S390X_F13,
+    UNW_S390X_F14,
+    UNW_S390X_F15,
+
+    /* PSW */
+    UNW_S390X_IP,
+
+    UNW_TDEP_LAST_REG = UNW_S390X_IP,
+
+    /* TODO: access, vector registers */
+
+    /* frame info (read-only) */
+    UNW_S390X_CFA,
+
+    UNW_TDEP_IP = UNW_S390X_IP,
+    UNW_TDEP_SP = UNW_S390X_R15,
+
+    /* TODO: placeholders */
+    UNW_TDEP_EH = UNW_S390X_R0,
+  }
+s390x_regnum_t;
+
+#define UNW_TDEP_NUM_EH_REGS    2       /* XXX Not sure what this means */
+
+typedef struct unw_tdep_save_loc
+  {
+    /* Additional target-dependent info on a save location.  */
+    char unused;
+  }
+unw_tdep_save_loc_t;
+
+/* On s390x, we can directly use ucontext_t as the unwind context.  */
+typedef ucontext_t unw_tdep_context_t;
+
+typedef struct
+  {
+    /* no s390x-specific auxiliary proc-info */
+    char unused;
+  }
+unw_tdep_proc_info_t;
+
+#include "libunwind-dynamic.h"
+#include "libunwind-common.h"
+
+#define unw_tdep_getcontext             UNW_ARCH_OBJ(getcontext)
+#define unw_tdep_is_fpreg               UNW_ARCH_OBJ(is_fpreg)
+
+extern int unw_tdep_getcontext (unw_tdep_context_t *);
+extern int unw_tdep_is_fpreg (int);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* LIBUNWIND_H */
index 7a56168..a13e776 100644 (file)
@@ -25,6 +25,8 @@
 # include "libunwind-x86_64.h"
 #elif defined __tilegx__
 # include "libunwind-tilegx.h"
+#elif defined __s390x__
+# include "libunwind-s390x.h"
 #else
 # error "Unsupported arch"
 #endif
index 0fcf326..e0f4540 100644 (file)
@@ -140,6 +140,7 @@ cmpxchg_ptr (void *addr, void *old, void *new)
 }
 # define fetch_and_add1(_ptr)           AO_fetch_and_add1(_ptr)
 # define fetch_and_add(_ptr, value)     AO_fetch_and_add(_ptr, value)
+# define atomic_read(ptr) (AO_load(ptr))
    /* GCC 3.2.0 on HP-UX crashes on cmpxchg_ptr() */
 #  if !(defined(__hpux) && __GNUC__ == 3 && __GNUC_MINOR__ == 2)
 #   define HAVE_CMPXCHG
@@ -164,10 +165,14 @@ cmpxchg_ptr (void *addr, void *old, void *new)
 }
 # define fetch_and_add1(_ptr)           __sync_fetch_and_add(_ptr, 1)
 # define fetch_and_add(_ptr, value)     __sync_fetch_and_add(_ptr, value)
+# define atomic_read(ptr) (__atomic_load_n(ptr,__ATOMIC_RELAXED))
 # define HAVE_CMPXCHG
 # define HAVE_FETCH_AND_ADD
 #endif
+
+#ifndef atomic_read
 #define atomic_read(ptr)        (*(ptr))
+#endif
 
 #define UNWI_OBJ(fn)      UNW_PASTE(UNW_PREFIX,UNW_PASTE(I,fn))
 #define UNWI_ARCH_OBJ(fn) UNW_PASTE(UNW_PASTE(UNW_PASTE(_UI,UNW_TARGET),_), fn)
@@ -363,4 +368,3 @@ static inline void invalidate_edi (struct elf_dyn_info *edi)
 #define UNW_ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
 
 #endif /* libunwind_i_h */
-
index 8006d0b..74b821f 100644 (file)
@@ -35,9 +35,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 /* Return TRUE if the ADDR_SPACE uses big-endian byte-order.  */
 #define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian)
 
-/* Return the size of an address, for DWARF purposes.  */
-#define dwarf_addr_size(addr_space) ((addr_space)->addr_size)
-
 /* Convert a pointer to a dwarf_cursor structure to a pointer to
    unw_cursor_t.  */
 #define dwarf_to_cursor(c)      ((unw_cursor_t *) (c))
index 3fe40c0..0c0fd3c 100644 (file)
@@ -247,6 +247,14 @@ dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
                                      0, c->as_arg);
   else if (c->as->abi == UNW_MIPS_ABI_O32)
     return read_s32 (c, DWARF_GET_LOC (loc), val);
+  else if (c->as->abi == UNW_MIPS_ABI_N32) {
+    if (tdep_big_endian(c->as))
+      return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc) + 4, val,
+                                       0, c->as_arg);
+    else
+      return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
+                                       0, c->as_arg);
+  }
   else
     return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
                                      0, c->as_arg);
diff --git a/src/coreclr/src/pal/src/libunwind/include/tdep-s390x/dwarf-config.h b/src/coreclr/src/pal/src/libunwind/include/tdep-s390x/dwarf-config.h
new file mode 100644 (file)
index 0000000..ca419bd
--- /dev/null
@@ -0,0 +1,52 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+/* copy of include/tdep-x86/dwarf-config.h, modified slightly for x86-64
+   some consolidation is possible here */
+
+#ifndef dwarf_config_h
+#define dwarf_config_h
+
+/* derived from DWARF register mappings in Z ELF ABI */
+#define DWARF_NUM_PRESERVED_REGS        66
+#define DWARF_REGNUM_MAP_LENGTH         DWARF_NUM_PRESERVED_REGS
+
+/* Return TRUE if the ADDR_SPACE uses big-endian byte-order.  */
+#define dwarf_is_big_endian(addr_space) 1
+
+/* Convert a pointer to a dwarf_cursor structure to a pointer to
+   unw_cursor_t.  */
+#define dwarf_to_cursor(c)      ((unw_cursor_t *) (c))
+
+typedef struct dwarf_loc
+  {
+    unw_word_t val;
+    unw_word_t type;            /* see S390X_LOC_TYPE_* macros.  */
+  }
+dwarf_loc_t;
+
+#endif /* dwarf_config_h */
diff --git a/src/coreclr/src/pal/src/libunwind/include/tdep-s390x/jmpbuf.h b/src/coreclr/src/pal/src/libunwind/include/tdep-s390x/jmpbuf.h
new file mode 100644 (file)
index 0000000..5092375
--- /dev/null
@@ -0,0 +1,35 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2004 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#if defined __linux__
+
+/* Use glibc's jump-buffer indices; NPTL peeks at SP: */
+
+#define JB_SP           9  // __gregs[9]
+#define JB_RP           8  // __gregs[8]
+#define JB_MASK_SAVED   18 // __mask_was_saved
+#define JB_MASK         19 // __saved_mask
+
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/include/tdep-s390x/libunwind_i.h b/src/coreclr/src/pal/src/libunwind/include/tdep-s390x/libunwind_i.h
new file mode 100644 (file)
index 0000000..137a0b8
--- /dev/null
@@ -0,0 +1,262 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002-2005 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#ifndef S390X_LIBUNWIND_I_H
+#define S390X_LIBUNWIND_I_H
+
+/* Target-dependent definitions that are internal to libunwind but need
+   to be shared with target-independent code.  */
+
+#include <stdlib.h>
+#include <libunwind.h>
+
+#include "elf64.h"
+#include "mempool.h"
+#include "dwarf.h"
+
+struct unw_addr_space
+  {
+    struct unw_accessors acc;
+    unw_caching_policy_t caching_policy;
+#ifdef HAVE_ATOMIC_OPS_H
+    AO_t cache_generation;
+#else
+    uint32_t cache_generation;
+#endif
+    unw_word_t dyn_generation;          /* see dyn-common.h */
+    unw_word_t dyn_info_list_addr;      /* (cached) dyn_info_list_addr */
+    struct dwarf_rs_cache global_cache;
+    struct unw_debug_frame_list *debug_frames;
+   };
+
+struct cursor
+  {
+    struct dwarf_cursor dwarf;          /* must be first */
+
+    /* Format of sigcontext structure and address at which it is
+       stored: */
+    enum
+      {
+        S390X_SCF_NONE              = 0, /* no signal frame encountered */
+        S390X_SCF_LINUX_SIGFRAME    = 1, /* Linux struct sigcontext */
+        S390X_SCF_LINUX_RT_SIGFRAME = 2, /* Linux ucontext_t */
+      }
+    sigcontext_format;
+    unw_word_t sigcontext_addr;
+    unw_word_t sigcontext_sp;
+    unw_word_t sigcontext_pc;
+    int validate;
+    ucontext_t *uc;
+  };
+
+static inline ucontext_t *
+dwarf_get_uc(const struct dwarf_cursor *cursor)
+{
+  const struct cursor *c = (struct cursor *) cursor->as_arg;
+  return c->uc;
+}
+
+#define DWARF_GET_LOC(l)        ((l).val)
+# define DWARF_LOC_TYPE_MEM     (0 << 0)
+# define DWARF_LOC_TYPE_FP      (1 << 0)
+# define DWARF_LOC_TYPE_REG     (1 << 1)
+# define DWARF_LOC_TYPE_VAL     (1 << 2)
+
+# define DWARF_IS_REG_LOC(l)    (((l).type & DWARF_LOC_TYPE_REG) != 0)
+# define DWARF_IS_FP_LOC(l)     (((l).type & DWARF_LOC_TYPE_FP) != 0)
+# define DWARF_IS_MEM_LOC(l)    ((l).type == DWARF_LOC_TYPE_MEM)
+# define DWARF_IS_VAL_LOC(l)    (((l).type & DWARF_LOC_TYPE_VAL) != 0)
+
+# define DWARF_LOC(r, t)        ((dwarf_loc_t) { .val = (r), .type = (t) })
+# define DWARF_VAL_LOC(c,v)     DWARF_LOC ((v), DWARF_LOC_TYPE_VAL)
+# define DWARF_MEM_LOC(c,m)     DWARF_LOC ((m), DWARF_LOC_TYPE_MEM)
+
+#ifdef UNW_LOCAL_ONLY
+# define DWARF_NULL_LOC         DWARF_LOC (0, 0)
+# define DWARF_IS_NULL_LOC(l)   (DWARF_GET_LOC (l) == 0)
+# define DWARF_REG_LOC(c,r)     (DWARF_LOC((unw_word_t)                      \
+                                 tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
+# define DWARF_FPREG_LOC(c,r)   (DWARF_LOC((unw_word_t)                      \
+                                 tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
+
+#else /* !UNW_LOCAL_ONLY */
+
+# define DWARF_NULL_LOC         DWARF_LOC (0, 0)
+# define DWARF_IS_NULL_LOC(l)                                           \
+                ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; })
+# define DWARF_REG_LOC(c,r)     DWARF_LOC((r), DWARF_LOC_TYPE_REG)
+# define DWARF_FPREG_LOC(c,r)   DWARF_LOC((r), (DWARF_LOC_TYPE_REG      \
+                                                | DWARF_LOC_TYPE_FP))
+
+#endif /* !UNW_LOCAL_ONLY */
+
+static inline int
+dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
+{
+  assert(sizeof(unw_fpreg_t) == sizeof(unw_word_t));
+
+  if (DWARF_IS_NULL_LOC (loc))
+    return -UNW_EBADREG;
+
+  if (DWARF_IS_FP_LOC (loc))
+    return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), val,
+                                       0, c->as_arg);
+  /* FPRs may be saved in GPRs */
+  if (DWARF_IS_REG_LOC (loc))
+    return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), (unw_word_t*)val,
+                                     0, c->as_arg);
+  if (DWARF_IS_MEM_LOC (loc))
+    return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), (unw_word_t*)val,
+                                     0, c->as_arg);
+  assert(DWARF_IS_VAL_LOC (loc));
+  *val = *(unw_fpreg_t*) DWARF_GET_LOC (loc);
+  return 0;
+}
+
+static inline int
+dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
+{
+  assert(sizeof(unw_fpreg_t) == sizeof(unw_word_t));
+  assert(!DWARF_IS_VAL_LOC (loc));
+
+  if (DWARF_IS_NULL_LOC (loc))
+    return -UNW_EBADREG;
+
+  if (DWARF_IS_FP_LOC (loc))
+    return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), &val,
+                                       1, c->as_arg);
+  /* FPRs may be saved in GPRs */
+  if (DWARF_IS_REG_LOC (loc))
+    return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), (unw_word_t*) &val,
+                                     1, c->as_arg);
+
+  assert(DWARF_IS_MEM_LOC (loc));
+  return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), (unw_word_t*) &val,
+                                   1, c->as_arg);
+}
+
+static inline int
+dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
+{
+  assert(sizeof(unw_fpreg_t) == sizeof(unw_word_t));
+
+  if (DWARF_IS_NULL_LOC (loc))
+    return -UNW_EBADREG;
+
+  if (DWARF_IS_REG_LOC (loc))
+    return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val,
+                                     0, c->as_arg);
+  if (DWARF_IS_MEM_LOC (loc))
+    return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
+                                     0, c->as_arg);
+  /* GPRs may be saved in FPRs */
+  if (DWARF_IS_FP_LOC (loc))
+    return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), (unw_fpreg_t*)val,
+                                       0, c->as_arg);
+  assert(DWARF_IS_VAL_LOC (loc));
+  *val = DWARF_GET_LOC (loc);
+  return 0;
+}
+
+static inline int
+dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
+{
+  assert(sizeof(unw_fpreg_t) == sizeof(unw_word_t));
+  assert(!DWARF_IS_VAL_LOC (loc));
+
+  if (DWARF_IS_NULL_LOC (loc))
+    return -UNW_EBADREG;
+
+  if (DWARF_IS_REG_LOC (loc))
+    return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val,
+                                     1, c->as_arg);
+  /* GPRs may be saved in FPRs */
+  if (DWARF_IS_FP_LOC (loc))
+    return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), (unw_fpreg_t*) &val,
+                                       1, c->as_arg);
+
+  assert(DWARF_IS_MEM_LOC (loc));
+  return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
+                                   1, c->as_arg);
+}
+
+#define tdep_getcontext_trace           unw_getcontext
+#define tdep_init_done                  UNW_OBJ(init_done)
+#define tdep_init_mem_validate          UNW_OBJ(init_mem_validate)
+#define tdep_init                       UNW_OBJ(init)
+/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
+   tdep_search_unwind_table.  */
+#define tdep_search_unwind_table        dwarf_search_unwind_table
+#define tdep_find_unwind_table          dwarf_find_unwind_table
+#define tdep_get_elf_image              UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path         UNW_ARCH_OBJ(get_exe_image_path)
+#define tdep_access_reg                 UNW_OBJ(access_reg)
+#define tdep_access_fpreg               UNW_OBJ(access_fpreg)
+#define tdep_fetch_frame(c,ip,n)        do {} while(0)
+#define tdep_cache_frame(c)             0
+#define tdep_reuse_frame(c,rs)          do {} while(0)
+#define tdep_stash_frame(cs,rs)         do {} while(0)
+#define tdep_trace(cur,addr,n)          (-UNW_ENOINFO)
+#define tdep_uc_addr                    UNW_OBJ(uc_addr)
+
+#ifdef UNW_LOCAL_ONLY
+# define tdep_find_proc_info(c,ip,n)                            \
+        dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n),      \
+                                       (c)->as_arg)
+# define tdep_put_unwind_info(as,pi,arg)                \
+        dwarf_put_unwind_info((as), (pi), (arg))
+#else
+# define tdep_find_proc_info(c,ip,n)                                    \
+        (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n),    \
+                                       (c)->as_arg)
+# define tdep_put_unwind_info(as,pi,arg)                        \
+        (*(as)->acc.put_unwind_info)((as), (pi), (arg))
+#endif
+
+#define tdep_get_as(c)                  ((c)->dwarf.as)
+#define tdep_get_as_arg(c)              ((c)->dwarf.as_arg)
+#define tdep_get_ip(c)                  ((c)->dwarf.ip)
+#define tdep_big_endian(as)             1
+
+extern int tdep_init_done;
+
+extern void tdep_init (void);
+extern void tdep_init_mem_validate (void);
+extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
+                                     unw_dyn_info_t *di, unw_proc_info_t *pi,
+                                     int need_unwind_info, void *arg);
+extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
+extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
+                               unsigned long *segbase, unsigned long *mapoff,
+                               char *path, size_t pathlen);
+extern void tdep_get_exe_image_path (char *path);
+extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
+                            unw_word_t *valp, int write);
+extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
+                              unw_fpreg_t *valp, int write);
+
+#endif /* S390X_LIBUNWIND_I_H */
index d571966..b2e5332 100644 (file)
@@ -23,9 +23,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
-#if defined __linux__
+#if defined __linux__ || defined __sun
 
-/* Use glibc's jump-buffer indices; NPTL peeks at SP: */
+/* Use glibc's jump-buffer indices; NPTL peeks at SP:
+   https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=sysdeps/x86_64/jmpbuf-offsets.h;h=ea94a1f90554deecceaf995ca5ee485ae8bffab7;hb=HEAD */
 
 #define JB_SP           6
 #define JB_RP           7
index 283525c..6b798c7 100644 (file)
@@ -89,6 +89,7 @@ struct cursor
         X86_64_SCF_LINUX_RT_SIGFRAME,   /* Linux ucontext_t */
         X86_64_SCF_FREEBSD_SIGFRAME,    /* FreeBSD signal frame */
         X86_64_SCF_FREEBSD_SYSCALL,     /* FreeBSD syscall */
+        X86_64_SCF_SOLARIS_SIGFRAME,    /* illumos/Solaris signal frame */
       }
     sigcontext_format;
     unw_word_t sigcontext_addr;
@@ -232,7 +233,11 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 #define tdep_get_ip(c)                  ((c)->dwarf.ip)
 #define tdep_big_endian(as)             0
 
+#ifdef HAVE_ATOMIC_OPS_H
+extern AO_t tdep_init_done;
+#else
 extern int tdep_init_done;
+#endif
 
 extern void tdep_init (void);
 extern void tdep_init_mem_validate (void);
index af05a7f..c472996 100644 (file)
@@ -25,6 +25,8 @@
 # include "tdep-x86_64/libunwind_i.h"
 #elif defined __tilegx__
 # include "tdep-tilegx/libunwind_i.h"
+#elif defined __s390x__
+# include "tdep-s390x/libunwind_i.h"
 #else
 # error "Unsupported arch"
 #endif
diff --git a/src/coreclr/src/pal/src/libunwind/libunwind-version.txt b/src/coreclr/src/pal/src/libunwind/libunwind-version.txt
new file mode 100644 (file)
index 0000000..500204b
--- /dev/null
@@ -0,0 +1,4 @@
+v1.5-rc2
+https://github.com/libunwind/libunwind/releases/tag/v1.5-rc2
++https://git.alpinelinux.org/aports/tree/main/libunwind/fix-aarch64-sigset_t.patch
++https://github.com/libunwind/libunwind/pull/179
index 891eadd..6014e9d 100644 (file)
@@ -14,8 +14,6 @@ add_definitions(-DPACKAGE_STRING="")
 add_definitions(-DPACKAGE_BUGREPORT="")
 
 add_definitions(-D_GNU_SOURCE)
-# Ensure that the remote and local unwind code can reside in the same binary without name clashing
-add_definitions("-Ddwarf_search_unwind_table_int=UNW_OBJ(dwarf_search_unwind_table_int)")
 
 # Disable warning due to incorrect format specifier in debugging printf via the Debug macro
 add_compile_options(-Wno-format -Wno-format-security)
@@ -25,6 +23,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
 else()
   add_compile_options(-Wno-unused-value)
   add_compile_options(-Wno-unused-result)
+  add_compile_options(-Wno-implicit-function-declaration)
+  add_compile_options(-Wno-incompatible-pointer-types)
 endif()
 
 if(CLR_CMAKE_HOST_ARCH_ARM)
@@ -115,6 +115,14 @@ SET(libunwind_la_SOURCES_os_freebsd_local
 # Nothing
 )
 
+SET(libunwind_la_SOURCES_os_solaris
+    os-solaris.c
+)
+
+SET(libunwind_la_SOURCES_os_solaris_local
+# Nothing
+)
+
 if(CLR_CMAKE_HOST_LINUX)
     SET(libunwind_la_SOURCES_os                 ${libunwind_la_SOURCES_os_linux})
     SET(libunwind_la_SOURCES_os_local           ${libunwind_la_SOURCES_os_linux_local})
@@ -137,6 +145,11 @@ elseif(CLR_CMAKE_HOST_FREEBSD)
     SET(libunwind_la_SOURCES_arm_os             arm/Gos-freebsd.c)
     SET(libunwind_la_SOURCES_arm_os_local       arm/Los-freebsd.c)
     list(APPEND libunwind_coredump_la_SOURCES   coredump/_UCD_access_reg_freebsd.c)
+elseif(CLR_CMAKE_HOST_SUNOS)
+    SET(libunwind_la_SOURCES_os                 ${libunwind_la_SOURCES_os_solaris})
+    SET(libunwind_la_SOURCES_os_local           ${libunwind_la_SOURCES_os_solaris_local})
+    SET(libunwind_la_SOURCES_x86_64_os          x86_64/Gos-solaris.c)
+    SET(libunwind_la_SOURCES_x86_64_os_local    x86_64/Los-solaris.c)
 endif()
 
 # List of arch-independent files needed by both local-only and generic
index a557d8d..ff97744 100644 (file)
@@ -68,7 +68,7 @@ libunwind_coredump_la_SOURCES = \
        coredump/_UPT_resume.c
 libunwind_coredump_la_LDFLAGS = $(COMMON_SO_LDFLAGS) \
                                -version-info $(COREDUMP_SO_VERSION)
-libunwind_coredump_la_LIBADD = $(LIBLZMA)
+libunwind_coredump_la_LIBADD = $(LIBLZMA) $(LIBZ)
 noinst_HEADERS += coredump/_UCD_internal.h coredump/_UCD_lib.h
 
 ### libunwind-setjmp:
@@ -154,6 +154,8 @@ libunwind_la_SOURCES_os_freebsd = os-freebsd.c
 
 libunwind_la_SOURCES_os_qnx = os-qnx.c
 
+libunwind_la_SOURCES_os_solaris = os-solaris.c
+
 libunwind_dwarf_common_la_SOURCES = dwarf/global.c
 
 libunwind_dwarf_local_la_SOURCES = \
@@ -181,9 +183,9 @@ noinst_HEADERS += elf32.h elf64.h elfxx.h
 libunwind_elf32_la_SOURCES = elf32.c
 libunwind_elf64_la_SOURCES = elf64.c
 libunwind_elfxx_la_SOURCES = elfxx.c
-libunwind_elf32_la_LIBADD  = $(LIBLZMA)
-libunwind_elf64_la_LIBADD  = $(LIBLZMA)
-libunwind_elfxx_la_LIBADD  = $(LIBLZMA)
+libunwind_elf32_la_LIBADD  = $(LIBLZMA) $(LIBZ)
+libunwind_elf64_la_LIBADD  = $(LIBLZMA) $(LIBZ)
+libunwind_elfxx_la_LIBADD  = $(LIBLZMA) $(LIBZ)
 
 noinst_LTLIBRARIES += $(LIBUNWIND_ELF)
 libunwind_la_LIBADD += $(LIBUNWIND_ELF)
@@ -463,6 +465,30 @@ libunwind_sh_la_SOURCES_sh = $(libunwind_la_SOURCES_sh_common)             \
        sh/Gglobal.c sh/Ginit.c sh/Ginit_local.c sh/Ginit_remote.c      \
        sh/Gis_signal_frame.c sh/Gregs.c sh/Gresume.c sh/Gstep.c
 
+# The list of files that go both into libunwind and libunwind-s390x:
+noinst_HEADERS += s390x/init.h s390x/unwind_i.h
+libunwind_la_SOURCES_s390x_common = $(libunwind_la_SOURCES_common)     \
+       s390x/is_fpreg.c s390x/regname.c
+
+# The list of files that go into libunwind:
+libunwind_la_SOURCES_s390x = $(libunwind_la_SOURCES_s390x_common)          \
+       $(libunwind_la_SOURCES_local)                                       \
+       s390x/Lapply_reg_state.c s390x/Lreg_states_iterate.c                \
+       s390x/Lcreate_addr_space.c s390x/Lget_save_loc.c s390x/Lglobal.c    \
+       s390x/Linit.c s390x/Linit_local.c s390x/Linit_remote.c              \
+       s390x/Lget_proc_info.c s390x/Lregs.c s390x/Lresume.c                \
+       s390x/Lis_signal_frame.c s390x/Lstep.c                              \
+       s390x/getcontext.S s390x/setcontext.S
+
+# The list of files that go into libunwind-s390x:
+libunwind_s390x_la_SOURCES_s390x = $(libunwind_la_SOURCES_s390x_common)     \
+       $(libunwind_la_SOURCES_generic)                                     \
+       s390x/Gapply_reg_state.c s390x/Greg_states_iterate.c                \
+       s390x/Gcreate_addr_space.c s390x/Gget_save_loc.c s390x/Gglobal.c    \
+       s390x/Ginit.c s390x/Ginit_local.c s390x/Ginit_remote.c              \
+       s390x/Gget_proc_info.c s390x/Gregs.c s390x/Gresume.c                \
+       s390x/Gis_signal_frame.c s390x/Gstep.c
+
 if REMOTE_ONLY
 install-exec-hook:
 #      Nothing to do here....
@@ -514,6 +540,12 @@ if OS_FREEBSD
  libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_freebsd.c
 endif
 
+if OS_SOLARIS
+ libunwind_la_SOURCES_os              = $(libunwind_la_SOURCES_os_solaris)
+ libunwind_la_SOURCES_x86_64_os       = x86_64/Gos-solaris.c
+ libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-solaris.c
+endif
+
 if OS_QNX
  libunwind_la_SOURCES_os       = $(libunwind_la_SOURCES_os_qnx)
  libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_qnx_local)
@@ -662,7 +694,19 @@ if !REMOTE_ONLY
  libunwind_sh_la_LIBADD += libunwind.la -lc
 endif
  libunwind_setjmp_la_SOURCES += sh/siglongjmp.S
+else
+if ARCH_S390X
+ lib_LTLIBRARIES += libunwind-s390x.la
+ libunwind_la_SOURCES = $(libunwind_la_SOURCES_s390x)
+ libunwind_s390x_la_SOURCES = $(libunwind_s390x_la_SOURCES_s390x)
+ libunwind_s390x_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION)
+ libunwind_s390x_la_LIBADD = libunwind-dwarf-generic.la
+ libunwind_s390x_la_LIBADD += libunwind-elf64.la
+if !REMOTE_ONLY
+ libunwind_s390x_la_LIBADD += libunwind.la -lc
+endif
 
+endif # ARCH_S390X
 endif # ARCH_SH
 endif # ARCH_PPC64
 endif # ARCH_PPC32
@@ -688,7 +732,7 @@ endif
 libunwind_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -XCClinker -nostdlib \
                        $(LDFLAGS_STATIC_LIBCXA) -version-info $(SOVERSION)
 libunwind_la_LIBADD  += -lc $(LIBCRTS)
-libunwind_la_LIBADD += $(LIBLZMA)
+libunwind_la_LIBADD += $(LIBLZMA) $(LIBZ)
 
 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/tdep-$(arch) -I.
 AM_CCASFLAGS = $(AM_CPPFLAGS)
@@ -705,6 +749,7 @@ EXTRA_DIST =        $(libunwind_la_SOURCES_aarch64)                 \
                $(libunwind_la_SOURCES_os_linux)                \
                $(libunwind_la_SOURCES_os_hpux)                 \
                $(libunwind_la_SOURCES_os_qnx)                  \
+               $(libunwind_la_SOURCES_os_solaris)              \
                $(libunwind_la_SOURCES_common)                  \
                $(libunwind_la_SOURCES_local)                   \
                $(libunwind_la_SOURCES_generic)                 \
index 9c4eae8..3538976 100644 (file)
@@ -41,7 +41,7 @@ static struct unw_addr_space local_addr_space;
 unw_addr_space_t unw_local_addr_space = &local_addr_space;
 
 static inline void *
-uc_addr (ucontext_t *uc, int reg)
+uc_addr (unw_tdep_context_t *uc, int reg)
 {
   if (reg >= UNW_AARCH64_X0 && reg < UNW_AARCH64_V0)
     return &uc->uc_mcontext.regs[reg];
@@ -54,20 +54,13 @@ uc_addr (ucontext_t *uc, int reg)
 # ifdef UNW_LOCAL_ONLY
 
 HIDDEN void *
-tdep_uc_addr (ucontext_t *uc, int reg)
+tdep_uc_addr (unw_tdep_context_t *uc, int reg)
 {
   return uc_addr (uc, reg);
 }
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -78,7 +71,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
@@ -104,7 +103,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
             void *arg)
 {
   unw_word_t *addr;
-  ucontext_t *uc = arg;
+  unw_tdep_context_t *uc = arg;
 
   if (unw_is_fpreg (reg))
     goto badreg;
@@ -133,7 +132,7 @@ static int
 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
               int write, void *arg)
 {
-  ucontext_t *uc = arg;
+  unw_tdep_context_t *uc = arg;
   unw_fpreg_t *addr;
 
   if (!unw_is_fpreg (reg))
index cd60ca8..69d4ed3 100644 (file)
@@ -59,7 +59,7 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
 }
 
 int
-unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+unw_init_local2 (unw_cursor_t *cursor, unw_tdep_context_t *uc, int flag)
 {
   if (!flag)
     {
index 3d82739..2cc1613 100644 (file)
@@ -71,7 +71,7 @@ aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
         char x[sizeof(regs)];
       };
 
-      asm volatile (
+      __asm__ __volatile__ (
         "mov x4, %0\n"
         "mov x5, %1\n"
         "ldp x0,  x1,  [x4]\n"
@@ -134,7 +134,7 @@ aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
       sc->pc = uc->uc_mcontext.pc;
       sc->pstate = uc->uc_mcontext.pstate;
 
-      asm volatile (
+      __asm__ __volatile__ (
         "mov sp, %0\n"
         "ret %1\n"
         : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc)
index 3d324c2..db7e29d 100644 (file)
@@ -59,6 +59,6 @@ extern int aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
   } while (0)
 #endif
 
-#define GET_FPCTX(uc) ((struct fpsimd_context *)(&uc->uc_mcontext.__reserved))
+#define GET_FPCTX(uc) ((unw_fpsimd_context_t *)(&uc->uc_mcontext.__reserved))
 
 #endif /* unwind_i_h */
index e79903c..d6573a6 100644 (file)
@@ -152,12 +152,13 @@ HIDDEN int
 arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c)
 {
 #define READ_OP() *buf++
-  assert(buf != NULL);
-  assert(len > 0);
   const uint8_t *end = buf + len;
   int ret;
   struct arm_exbuf_data edata;
 
+  assert(buf != NULL);
+  assert(len > 0);
+
   while (buf < end)
     {
       uint8_t op = READ_OP ();
index 2720d06..0bac0d7 100644 (file)
@@ -57,18 +57,17 @@ tdep_uc_addr (unw_tdep_context_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index a828862..3b9dfb3 100644 (file)
@@ -56,7 +56,7 @@ arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
               char x[sizeof(regs)];
       };
 
-      asm __volatile__ (
+      __asm__ __volatile__ (
         "ldmia %0, {r4-r12, lr}\n"
         "mov sp, r12\n"
         "bx lr\n"
@@ -90,7 +90,7 @@ arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
 
       /* Set the SP and the PC in order to continue execution at the modified
          trampoline which restores the signal mask and the registers.  */
-      asm __volatile__ (
+      __asm__ __volatile__ (
         "mov sp, %0\n"
         "bx %1\n"
         : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc)
index 516c9f4..895e8a8 100644 (file)
@@ -46,7 +46,8 @@ arm_exidx_step (struct cursor *c)
   c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
   unw_word_t ip = c->dwarf.ip;
   if (c->dwarf.use_prev_instr)
-    --ip;
+    /* The least bit denotes thumb/arm mode, clear it. */
+    ip = (ip & ~(unw_word_t)0x1) - 1;
 
   /* check dynamic info first --- it overrides everything else */
   ret = unwi_find_dynamic_proc_info (c->dwarf.as, ip, &c->dwarf.pi, 1,
@@ -106,17 +107,20 @@ unw_step (unw_cursor_t *cursor)
       else if (unlikely (ret == -UNW_ESTOPUNWIND))
         return ret;
 
-    if (ret < 0 && ret != -UNW_ENOINFO)
-      {
-        Debug (2, "returning %d\n", ret);
-        return ret;
-      }
+      if (ret < 0 && ret != -UNW_ENOINFO)
+        {
+          Debug (2, "returning %d\n", ret);
+          return ret;
+        }
     }
 #endif /* CONFIG_DEBUG_FRAME */
 
   /* Next, try extbl-based unwinding. */
   if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
     {
+      Debug (13, "%s(ret=%d), trying extbl\n",
+             UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() failed " : "",
+             ret);
       ret = arm_exidx_step (c);
       if (ret > 0)
         return 1;
@@ -134,7 +138,12 @@ unw_step (unw_cursor_t *cursor)
     {
       if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
         {
-          Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
+          Debug (13, "%s%s%s%s(ret=%d), trying frame-chain\n",
+                 UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() " : "",
+                 (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) && UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX)) ? "and " : "",
+                 UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX) ? "arm_exidx_step() " : "",
+                 (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) || UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX)) ? "failed " : "",
+                 ret);
           ret = UNW_ESUCCESS;
           /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
           unw_word_t instr, i;
index 0e3a83b..930a114 100644 (file)
@@ -129,6 +129,26 @@ _UCD_access_reg (unw_addr_space_t as,
        return -UNW_EINVAL;
      }
   }
+#elif defined(UNW_TARGET_AARCH64)
+  if (regnum >= UNW_AARCH64_X0 && regnum < UNW_AARCH64_X30) {
+     *valp = ui->prstatus->pr_reg.x[regnum];
+  } else {
+     switch (regnum) {
+     case UNW_AARCH64_SP:
+       *valp = ui->prstatus->pr_reg.sp;
+       break;
+     case UNW_AARCH64_X30:
+       *valp = ui->prstatus->pr_reg.lr;
+       break;
+     case UNW_AARCH64_PC:
+       *valp = ui->prstatus->pr_reg.elr;
+       break;
+     default:
+       Debug(0, "bad regnum:%d\n", regnum);
+       return -UNW_EINVAL;
+     }
+  }
+
 #else
 #error Port me
 #endif
index 208d8d2..43792f8 100644 (file)
@@ -54,6 +54,9 @@ _UCD_access_reg (unw_addr_space_t as,
 #elif defined(UNW_TARGET_TILEGX)
   if (regnum > UNW_TILEGX_CFA)
     goto badreg;
+#elif defined(UNW_TARGET_S390X)
+  if (regnum > UNW_S390X_R15)
+    goto badreg;
 #else
 #if defined(UNW_TARGET_MIPS)
   static const uint8_t remap_regs[] =
index 62f6ee0..4c430ef 100644 (file)
@@ -259,9 +259,13 @@ _UCD_create(const char *filename)
                                 cur->p_flags
             );
             if (cur->p_filesz < cur->p_memsz)
-              Debug(2, " partial");
+              {
+                Debug(2, " partial");
+              }
             if (cur->p_flags & PF_X)
-              Debug(2, " executable");
+              {
+                Debug(2, " executable");
+              }
           }
         Debug(2, "\n");
         i++;
@@ -338,7 +342,10 @@ int _UCD_add_backing_file_at_segment(struct UCD_info *ui, int phdr_no, const cha
   phdr->backing_filesize = (uoff_t)statbuf.st_size;
 
   if (phdr->p_flags != (PF_X | PF_R))
-    Debug(1, "Note: phdr[%u] is not r-x: flags are 0x%x\n", phdr_no, phdr->p_flags);
+    {
+      Debug(1, "Note: phdr[%u] is not r-x: flags are 0x%x\n",
+                        phdr_no, phdr->p_flags);
+    }
 
   if (phdr->backing_filesize > phdr->p_memsz)
     {
index 00096c4..3a4c9b8 100644 (file)
@@ -36,6 +36,10 @@ elf_w (CD_get_proc_name) (struct UCD_info *ui, unw_addr_space_t as, unw_word_t i
   unsigned long segbase, mapoff;
   int ret;
 
+  /* We're about to map an elf image. If there is an elf image currently mapped,
+     then make sure to unmap it. */
+  invalidate_edi(&ui->edi);
+
   /* Used to be tdep_get_elf_image() in ptrace unwinding code */
   coredump_phdr_t *cphdr = _UCD_get_elf_image(ui, ip);
   if (!cphdr)
index 0d11905..739ed05 100644 (file)
@@ -74,6 +74,11 @@ get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
 
 #else
 
+/* XXX fix me: there is currently no way to locate the dyn-info list
+       by a remote unwinder.  On ia64, this is done via a special
+       unwind-table entry.  Perhaps something similar can be done with
+       DWARF2 unwind info.  */
+
 static inline int
 get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
                int *countp)
index f63c3d2..2af4543 100644 (file)
@@ -60,6 +60,8 @@ static const uint8_t operands[256] =
     [DW_OP_const4s] =           OPND1 (VAL32),
     [DW_OP_const8u] =           OPND1 (VAL64),
     [DW_OP_const8s] =           OPND1 (VAL64),
+    [DW_OP_constu]  =           OPND1 (ULEB128),
+    [DW_OP_consts]  =           OPND1 (SLEB128),
     [DW_OP_pick] =              OPND1 (VAL8),
     [DW_OP_plus_uconst] =       OPND1 (ULEB128),
     [DW_OP_skip] =              OPND1 (VAL16),
@@ -235,8 +237,8 @@ dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr,
 }
 
 HIDDEN int
-dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len,
-                 unw_word_t *valp, int *is_register)
+dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_word_t *addr,
+                 unw_word_t len, unw_word_t *valp, int *is_register)
 {
   unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2 = 0, tmp3, end_addr;
   uint8_t opcode, operands_signature, u8;
@@ -285,10 +287,14 @@ do {                                            \
   end_addr = *addr + len;
   *is_register = 0;
 
-  Debug (14, "len=%lu, pushing cfa=0x%lx\n",
-         (unsigned long) len, (unsigned long) c->cfa);
+  Debug (14, "len=%lu, pushing initial value=0x%lx\n",
+         (unsigned long) len, (unsigned long) stack_val);
 
-  push (c->cfa);        /* push current CFA as required by DWARF spec */
+  /* The DWARF standard requires the current CFA to be pushed onto the stack */
+  /* before evaluating DW_CFA_expression and DW_CFA_val_expression programs. */
+  /* DW_CFA_def_cfa_expressions do not take an initial value, but we push on */
+  /* a dummy value to keep this logic consistent. */
+  push (stack_val);
 
   while (*addr < end_addr)
     {
index 509ceff..0cfb4d4 100644 (file)
@@ -34,6 +34,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #include "dwarf-eh.h"
 #include "libunwind_i.h"
 
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
 struct table_entry
   {
     int32_t start_ip_offset;
@@ -46,12 +50,17 @@ struct table_entry
 #include "os-linux.h"
 #endif
 
+#ifndef __clang__
 static ALIAS(dwarf_search_unwind_table) int
 dwarf_search_unwind_table_int (unw_addr_space_t as,
                                unw_word_t ip,
                                unw_dyn_info_t *di,
                                unw_proc_info_t *pi,
                                int need_unwind_info, void *arg);
+#else
+#define dwarf_search_unwind_table_int dwarf_search_unwind_table
+#endif
+
 static int
 linear_search (unw_addr_space_t as, unw_word_t ip,
                unw_word_t eh_frame_start, unw_word_t eh_frame_end,
@@ -118,14 +127,48 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
       return 1;
     }
 
-  *bufsize = shdr->sh_size;
-  *buf = malloc (*bufsize);
-
-  memcpy(*buf, shdr->sh_offset + ei.image, *bufsize);
+  if (shdr->sh_flags & SHF_COMPRESSED)
+    {
+      unsigned long destSize;
+      Elf_W (Chdr) *chdr = (shdr->sh_offset + ei.image);
+#ifdef HAVE_ZLIB
+      if (chdr->ch_type == ELFCOMPRESS_ZLIB)
+       {
+         *bufsize = destSize = chdr->ch_size;
+         GET_MEMORY(*buf, *bufsize);
+         ret = uncompress((unsigned char *)*buf, &destSize,
+                          shdr->sh_offset + ei.image + sizeof(*chdr),
+                          shdr->sh_size - sizeof(*chdr));
+         if (ret != Z_OK)
+           {
+             Debug (2, "failed to decompress zlib .debug_frame, skipping\n");
+             munmap(*buf, *bufsize);
+             munmap(ei.image, ei.size);
+             return 1;
+           }
+
+         Debug (4, "read %zd->%zd bytes of .debug_frame from offset %zd\n",
+                shdr->sh_size, *bufsize, shdr->sh_offset);
+       }
+      else
+#endif /* HAVE_ZLIB */
+       {
+         Debug (2, "unknown compression type %d, skipping\n",
+                chdr->ch_type);
+          munmap(ei.image, ei.size);
+         return 1;
+        }
+    }
+  else
+    {
+      *bufsize = shdr->sh_size;
+      GET_MEMORY(*buf, *bufsize);
 
-  Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
-        *bufsize, shdr->sh_offset);
+      memcpy(*buf, shdr->sh_offset + ei.image, *bufsize);
 
+      Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
+            *bufsize, shdr->sh_offset);
+    }
   munmap(ei.image, ei.size);
   return 0;
 }
@@ -208,7 +251,7 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
 
   if (!err)
     {
-      fdesc = malloc (sizeof (struct unw_debug_frame_list));
+      GET_MEMORY(fdesc, sizeof (struct unw_debug_frame_list));
 
       fdesc->start = start;
       fdesc->end = end;
@@ -223,66 +266,131 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
   return fdesc;
 }
 
-struct debug_frame_tab
-  {
-    struct table_entry *tab;
-    uint32_t length;
-    uint32_t size;
-  };
-
-static void
-debug_frame_tab_append (struct debug_frame_tab *tab,
-                        unw_word_t fde_offset, unw_word_t start_ip)
+static size_t
+debug_frame_index_make (struct unw_debug_frame_list *fdesc)
 {
-  unsigned int length = tab->length;
+  unw_accessors_t *a = unw_get_accessors_int (unw_local_addr_space);
+  char *buf = fdesc->debug_frame;
+  size_t bufsize = fdesc->debug_frame_size;
+  unw_word_t addr = (unw_word_t) (uintptr_t) buf;
+  size_t count = 0;
 
-  if (length == tab->size)
+  while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
     {
-      tab->size *= 2;
-      tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
-    }
+      unw_word_t item_start = addr, item_end = 0;
+      uint32_t u32val = 0;
+      uint64_t cie_id = 0;
+      uint64_t id_for_cie;
+
+      dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
+
+      if (u32val == 0)
+        break;
+
+      if (u32val != 0xffffffff)
+        {
+          uint32_t cie_id32 = 0;
+
+          item_end = addr + u32val;
+          dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32, NULL);
+          cie_id = cie_id32;
+          id_for_cie = 0xffffffff;
+        }
+      else
+        {
+          uint64_t u64val = 0;
+
+          /* Extended length.  */
+          dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
+          item_end = addr + u64val;
+
+          dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
+          id_for_cie = 0xffffffffffffffffull;
+        }
+
+      /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
+
+      if (cie_id == id_for_cie)
+        {
+          ;
+          /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
+        }
+      else
+        {
+          unw_word_t fde_addr = item_start;
+          unw_proc_info_t this_pi;
+          int err;
+
+          /*Debug (1, "Found FDE at %.8x\n", item_start);*/
+
+          err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
+                                                  a, &fde_addr,
+                                                  &this_pi,
+                                                  (uintptr_t) buf, 0, 1,
+                                                  NULL);
+
+          if (!err)
+            {
+              Debug (15, "start_ip = %lx, end_ip = %lx\n",
+                     (long) this_pi.start_ip, (long) this_pi.end_ip);
+
+              if (fdesc->index)
+                {
+                  struct table_entry *e = &fdesc->index[count];
+
+                  e->fde_offset = item_start - (unw_word_t) (uintptr_t) buf;
+                  e->start_ip_offset = this_pi.start_ip;
+                }
 
-  tab->tab[length].fde_offset = fde_offset;
-  tab->tab[length].start_ip_offset = start_ip;
+              count++;
+            }
+        /*else
+            Debug (1, "FDE parse failed\n");*/
+        }
 
-  tab->length = length + 1;
+      addr = item_end;
+    }
+  return count;
 }
 
 static void
-debug_frame_tab_shrink (struct debug_frame_tab *tab)
+debug_frame_index_sort (struct unw_debug_frame_list *fdesc)
 {
-  if (tab->size > tab->length)
+  size_t i, j, k, n = fdesc->index_size / sizeof (*fdesc->index);
+  struct table_entry *a = fdesc->index;
+  struct table_entry t;
+
+  /* Use a simple Shell sort as it relatively fast and
+   * does not require additional memory. */
+
+  for (k = n / 2; k > 0; k /= 2)
     {
-      tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length);
-      tab->size = tab->length;
-    }
-}
+      for (i = k; i < n; i++)
+        {
+          t = a[i];
 
-static int
-debug_frame_tab_compare (const void *a, const void *b)
-{
-  const struct table_entry *fa = a, *fb = b;
+          for (j = i; j >= k; j -= k)
+            {
+              if (t.start_ip_offset >= a[j - k].start_ip_offset)
+                break;
 
-  if (fa->start_ip_offset > fb->start_ip_offset)
-    return 1;
-  else if (fa->start_ip_offset < fb->start_ip_offset)
-    return -1;
-  else
-    return 0;
+              a[j] = a[j - k];
+            }
+
+          a[j] = t;
+        }
+    }
 }
 
-HIDDEN int
+int
 dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
                         unw_word_t segbase, const char* obj_name,
                         unw_word_t start, unw_word_t end)
 {
-  unw_dyn_info_t *di;
-  struct unw_debug_frame_list *fdesc = 0;
-  unw_accessors_t *a;
-  unw_word_t addr;
+  unw_dyn_info_t *di = di_debug;
+  struct unw_debug_frame_list *fdesc;
 
   Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
-  di = di_debug;
 
   fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
 
@@ -291,130 +399,69 @@ dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
       Debug (15, "couldn't load .debug_frame\n");
       return found;
     }
-  else
+
+  Debug (15, "loaded .debug_frame\n");
+
+  if (fdesc->debug_frame_size == 0)
     {
-      char *buf;
-      size_t bufsize;
-      unw_word_t item_start, item_end = 0;
-      uint32_t u32val = 0;
-      uint64_t cie_id = 0;
-      struct debug_frame_tab tab;
+      Debug (15, "zero-length .debug_frame\n");
+      return found;
+    }
+
+  /* Now create a binary-search table, if it does not already exist. */
+
+  if (!fdesc->index)
+    {
+      /* Find all FDE entries in debug_frame, and make into a sorted
+         index. First determine an index element count. */
 
-      Debug (15, "loaded .debug_frame\n");
+      size_t count = debug_frame_index_make (fdesc);
 
-      buf = fdesc->debug_frame;
-      bufsize = fdesc->debug_frame_size;
+      if (!count)
+        {
+          Debug (15, "no CIE/FDE found in .debug_frame\n");
+          return found;
+        }
 
-      if (bufsize == 0)
-       {
-         Debug (15, "zero-length .debug_frame\n");
-         return found;
-       }
+      fdesc->index_size = count * sizeof (*fdesc->index);
+      GET_MEMORY (fdesc->index, fdesc->index_size);
 
-      /* Now create a binary-search table, if it does not already exist.  */
       if (!fdesc->index)
-       {
-         addr = (unw_word_t) (uintptr_t) buf;
-
-         a = unw_get_accessors_int (unw_local_addr_space);
-
-         /* Find all FDE entries in debug_frame, and make into a sorted
-            index.  */
-
-         tab.length = 0;
-         tab.size = 16;
-         tab.tab = calloc (tab.size, sizeof (struct table_entry));
-
-         while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
-           {
-             uint64_t id_for_cie;
-             item_start = addr;
-
-             dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
-
-             if (u32val == 0)
-               break;
-             else if (u32val != 0xffffffff)
-               {
-                 uint32_t cie_id32 = 0;
-                 item_end = addr + u32val;
-                 dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
-                                NULL);
-                 cie_id = cie_id32;
-                 id_for_cie = 0xffffffff;
-               }
-             else
-               {
-                 uint64_t u64val = 0;
-                 /* Extended length.  */
-                 dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
-                 item_end = addr + u64val;
-
-                 dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
-                 id_for_cie = 0xffffffffffffffffull;
-               }
-
-             /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
-
-             if (cie_id == id_for_cie)
-               ;
-             /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
-             else
-               {
-                 unw_word_t fde_addr = item_start;
-                 unw_proc_info_t this_pi;
-                 int err;
-
-                 /*Debug (1, "Found FDE at %.8x\n", item_start);*/
-
-                 err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
-                                                         a, &fde_addr,
-                                                         &this_pi,
-                                                         (uintptr_t) buf, 0, 1,
-                                                         NULL);
-                 if (err == 0)
-                   {
-                     Debug (15, "start_ip = %lx, end_ip = %lx\n",
-                            (long) this_pi.start_ip, (long) this_pi.end_ip);
-                     debug_frame_tab_append (&tab,
-                                             item_start - (unw_word_t) (uintptr_t) buf,
-                                             this_pi.start_ip);
-                   }
-                 /*else
-                   Debug (1, "FDE parse failed\n");*/
-               }
-
-             addr = item_end;
-           }
-
-         debug_frame_tab_shrink (&tab);
-         qsort (tab.tab, tab.length, sizeof (struct table_entry),
-                debug_frame_tab_compare);
-         /* for (i = 0; i < tab.length; i++)
-            {
-            fprintf (stderr, "ip %x, fde offset %x\n",
-            (int) tab.tab[i].start_ip_offset,
-            (int) tab.tab[i].fde_offset);
-            }*/
-         fdesc->index = tab.tab;
-         fdesc->index_size = tab.length;
-       }
-
-      di->format = UNW_INFO_FORMAT_TABLE;
-      di->start_ip = fdesc->start;
-      di->end_ip = fdesc->end;
-      di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
-      di->u.ti.table_data = (unw_word_t *) fdesc;
-      di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
-      di->u.ti.segbase = segbase;
-
-      found = 1;
-      Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
-            "gp=0x%lx, table_data=0x%lx\n",
-            (char *) (uintptr_t) di->u.ti.name_ptr,
-            (long) di->u.ti.segbase, (long) di->u.ti.table_len,
-            (long) di->gp, (long) di->u.ti.table_data);
+        {
+          Debug (15, "couldn't allocate a frame index table\n");
+          fdesc->index_size = 0;
+          return found;
+        }
+
+      /* Then fill and sort the index. */
+
+      debug_frame_index_make (fdesc);
+      debug_frame_index_sort (fdesc);
+
+    /*for (i = 0; i < count; i++)
+        {
+          const struct table_entry *e = &fdesc->index[i];
+
+          Debug (15, "ip %x, FDE offset %x\n",
+                 e->start_ip_offset, e->fde_offset);
+        }*/
     }
+
+  di->format = UNW_INFO_FORMAT_TABLE;
+  di->start_ip = fdesc->start;
+  di->end_ip = fdesc->end;
+  di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
+  di->u.ti.table_data = (unw_word_t *) fdesc;
+  di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
+  di->u.ti.segbase = segbase;
+
+  found = 1;
+  Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
+         "gp=0x%lx, table_data=0x%lx\n",
+         (char *) (uintptr_t) di->u.ti.name_ptr,
+         (long) di->u.ti.segbase, (long) di->u.ti.table_len,
+         (long) di->gp, (long) di->u.ti.table_data);
+
   return found;
 }
 
@@ -525,6 +572,10 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
         }
       else if (phdr->p_type == PT_GNU_EH_FRAME)
         p_eh_hdr = phdr;
+#if defined __sun
+      else if (phdr->p_type == PT_SUNW_UNWIND)
+        p_eh_hdr = phdr;
+#endif
       else if (phdr->p_type == PT_DYNAMIC)
         p_dynamic = phdr;
     }
@@ -606,11 +657,15 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
           /* If there is no search table or it has an unsupported
              encoding, fall back on linear search.  */
           if (hdr->table_enc == DW_EH_PE_omit)
-            Debug (4, "table `%s' lacks search table; doing linear search\n",
-                   info->dlpi_name);
+            {
+              Debug (4, "table `%s' lacks search table; doing linear search\n",
+                     info->dlpi_name);
+            }
           else
-            Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
-                   info->dlpi_name, hdr->table_enc);
+            {
+              Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
+                     info->dlpi_name, hdr->table_enc);
+            }
 
           eh_frame_end = max_load_addr; /* XXX can we do better? */
 
@@ -843,7 +898,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
          endianness is the target one.  */
       as = unw_local_addr_space;
       table = fdesc->index;
-      table_len = fdesc->index_size * sizeof (struct table_entry);
+      table_len = fdesc->index_size;
       debug_frame_base = (uintptr_t) fdesc->debug_frame;
 #endif
     }
index 6a2ad50..f5f7ad0 100644 (file)
@@ -80,6 +80,9 @@ dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as,
           break;
 
         case PT_GNU_EH_FRAME:
+#if defined __sun
+        case PT_SUNW_UNWIND:
+#endif
           peh_hdr = phdr + i;
           break;
 
index 7d255ae..28fd73c 100644 (file)
@@ -440,8 +440,15 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip)
      continue, and it's important we get this right, as 'ip' could be
      right at the function entry and hence FDE edge, or at instruction
      that manipulates CFA (push/pop). */
+
   if (c->use_prev_instr)
-    --ip;
+    {
+#if defined(__arm__)
+      /* On arm, the least bit denotes thumb/arm mode, clear it. */
+      ip &= ~(unw_word_t)0x1;
+#endif
+      --ip;
+    }
 
   memset (&c->pi, 0, sizeof (c->pi));
 
@@ -734,7 +741,7 @@ create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
 }
 
 static inline int
-eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
+eval_location_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_addr_space_t as,
                     unw_accessors_t *a, unw_word_t addr,
                     dwarf_loc_t *locp, void *arg)
 {
@@ -746,7 +753,7 @@ eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
     return ret;
 
   /* evaluate the expression: */
-  if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
+  if ((ret = dwarf_eval_expr (c, stack_val, &addr, len, &val, &is_register)) < 0)
     return ret;
 
   if (is_register)
@@ -804,7 +811,10 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
       assert (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR);
 
       addr = rs->reg.val[DWARF_CFA_REG_COLUMN];
-      if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
+      /* The dwarf standard doesn't specify an initial value to be pushed on */
+      /* the stack before DW_CFA_def_cfa_expression evaluation. We push on a */
+      /* dummy value (0) to keep the eval_location_expr function consistent. */
+      if ((ret = eval_location_expr (c, 0, as, a, addr, &cfa_loc, arg)) < 0)
         return ret;
       /* the returned location better be a memory location... */
       if (DWARF_IS_REG_LOC (cfa_loc))
@@ -831,18 +841,30 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
           break;
 
         case DWARF_WHERE_REG:
-          new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
+#ifdef __s390x__
+          /* GPRs can be saved in FPRs on s390x */
+          if (unw_is_fpreg (dwarf_to_unw_regnum (rs->reg.val[i])))
+            {
+              new_loc[i] = DWARF_FPREG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
+              break;
+            }
+#endif
+          new_loc[i] = new_loc[rs->reg.val[i]];
           break;
 
         case DWARF_WHERE_EXPR:
           addr = rs->reg.val[i];
-          if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
+          /* The dwarf standard requires the current CFA to be pushed on the */
+          /* stack before DW_CFA_expression evaluation. */
+          if ((ret = eval_location_expr (c, cfa, as, a, addr, new_loc + i, arg)) < 0)
             return ret;
           break;
 
         case DWARF_WHERE_VAL_EXPR:
           addr = rs->reg.val[i];
-          if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
+          /* The dwarf standard requires the current CFA to be pushed on the */
+          /* stack before DW_CFA_val_expression evaluation. */
+          if ((ret = eval_location_expr (c, cfa, as, a, addr, new_loc + i, arg)) < 0)
             return ret;
           new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i]));
           break;
@@ -924,7 +946,6 @@ find_reg_state (struct dwarf_cursor *c, dwarf_state_record_t *sr)
   unsigned short index = -1;
   if (cache)
     {
-      put_rs_cache (c->as, cache, &saved_mask);
       if (rs)
        {
          index = rs - cache->buckets;
@@ -932,6 +953,7 @@ find_reg_state (struct dwarf_cursor *c, dwarf_state_record_t *sr)
          cache->links[c->prev_rs].hint = index + 1;
          c->prev_rs = index;
        }
+      put_rs_cache (c->as, cache, &saved_mask);
     }
   if (ret < 0)
       return ret;
index b03dfcb..2589a3d 100644 (file)
@@ -28,6 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
 #include <stdio.h>
 #include <sys/param.h>
+#include <limits.h>
 
 #ifdef HAVE_LZMA
 #include <lzma.h>
index 461e4b9..265455a 100644 (file)
@@ -64,13 +64,6 @@ _Uhppa_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -81,7 +74,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index b09a2ad..8601bb3 100644 (file)
@@ -68,6 +68,7 @@ get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
   if (!_U_dyn_info_list_addr)
     return -UNW_ENOINFO;
 #endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
   *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
index 98d3501..2e7c62e 100644 (file)
@@ -49,6 +49,7 @@ local_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
     return -UNW_ENOINFO;
 #endif
 
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
   list = (unw_dyn_info_list_t *) (uintptr_t) _U_dyn_info_list_addr ();
   for (di = list->first; di; di = di->next)
     if (ip >= di->start_ip && ip < di->end_ip)
index 840d900..0b77fa5 100644 (file)
@@ -106,7 +106,15 @@ unw_get_proc_name (unw_cursor_t *cursor, char *buf, size_t buf_len,
   ip = tdep_get_ip (c);
 #if !defined(__ia64__)
   if (c->dwarf.use_prev_instr)
-    --ip;
+    {
+#if defined(__arm__)
+      /* On arm, the least bit denotes thumb/arm mode, clear it. */
+      ip &= ~(unw_word_t)0x1;
+#endif
+      --ip;
+    }
+
+
 #endif
   error = get_proc_name (tdep_get_as (c), ip, buf, buf_len, offp,
                          tdep_get_as_arg (c));
index c7aa2bd..b281513 100644 (file)
@@ -23,9 +23,9 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
-#ifndef UNW_REMOTE_ONLY
-
+#if !defined(UNW_REMOTE_ONLY) && !defined(UNW_LOCAL_ONLY)
 #define UNW_LOCAL_ONLY
+
 #include <libunwind.h>
 #include <libunwind_i.h>
 #include <string.h>
@@ -75,7 +75,9 @@ unw_backtrace (void **buffer, int size)
   return n;
 }
 
+#ifdef CONFIG_WEAK_BACKTRACE
 extern int backtrace (void **buffer, int size)
   WEAK ALIAS(unw_backtrace);
+#endif
 
 #endif /* !UNW_REMOTE_ONLY */
index cbd93e1..f2b0115 100644 (file)
@@ -30,21 +30,24 @@ unw_flush_cache (unw_addr_space_t as, unw_word_t lo, unw_word_t hi)
 {
 #if !UNW_TARGET_IA64
   struct unw_debug_frame_list *w = as->debug_frames;
-#endif
 
-  /* clear dyn_info_list_addr cache: */
-  as->dyn_info_list_addr = 0;
-
-#if !UNW_TARGET_IA64
-  for (; w; w = w->next)
+  while (w)
     {
+      struct unw_debug_frame_list *n = w->next;
+
       if (w->index)
-        free (w->index);
-      free (w->debug_frame);
+        munmap (w->index, w->index_size);
+
+      munmap (w->debug_frame, w->debug_frame_size);
+      munmap (w, sizeof (*w));
+      w = n;
     }
   as->debug_frames = NULL;
 #endif
 
+  /* clear dyn_info_list_addr cache: */
+  as->dyn_info_list_addr = 0;
+
   /* This lets us flush caches lazily.  The implementation currently
      ignores the flush range arguments (lo-hi).  This is OK because
      unw_flush_cache() is allowed to flush more than the requested
index 493d03d..24e0d3b 100644 (file)
@@ -58,8 +58,15 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order)
     as->big_endian = (byte_order == __BIG_ENDIAN);
 
   /* FIXME!  There is no way to specify the ABI.  */
+#if _MIPS_SIM == _ABIO32
   as->abi = UNW_MIPS_ABI_O32;
-  as->addr_size = 4;
+#elif _MIPS_SIM == _ABIN32
+  as->abi = UNW_MIPS_ABI_N32;
+#elif _MIPS_SIM == _ABI64
+  as->abi = UNW_MIPS_ABI_N64;
+#else
+# error Unsupported ABI
+#endif
 
   return as;
 #endif
index 7b84be8..04c4326 100644 (file)
@@ -30,11 +30,14 @@ unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
   struct cursor *c = (struct cursor *) cursor;
   int ret;
 
-  /* We can only unwind using Dwarf into on MIPS: return failure code
-     if it's not present.  */
   ret = dwarf_make_proc_info (&c->dwarf);
-  if (ret < 0)
-    return ret;
+  if (ret < 0) {
+    /* Construct a dummy proc info if Dwarf failed */
+    memset (pi, 0, sizeof (*pi));
+    pi->start_ip = c->dwarf.ip;
+    pi->end_ip = c->dwarf.ip + 4;
+    return 0;
+  }
 
   *pi = c->dwarf.pi;
   return 0;
index 3df170c..bf7a8f5 100644 (file)
@@ -69,13 +69,6 @@ tdep_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -86,7 +79,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) (intptr_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index 9519402..e967324 100644 (file)
@@ -63,7 +63,7 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
     case UNW_MIPS_R26:
     case UNW_MIPS_R27:
     case UNW_MIPS_R28:
-    case UNW_MIPS_R29:
+
     case UNW_MIPS_R30:
     case UNW_MIPS_R31:
       loc = c->dwarf.loc[reg - UNW_MIPS_R0];
@@ -75,6 +75,7 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
       loc = c->dwarf.loc[reg];
       break;
 
+    case UNW_MIPS_R29:
     case UNW_MIPS_CFA:
       if (write)
         return -UNW_EREADONLYREG;
index 937136a..0235d52 100644 (file)
@@ -110,6 +110,96 @@ mips_handle_signal_frame (unw_cursor_t *cursor)
   return 1;
 }
 
+
+
+static inline
+int is_valid_fp_val(unw_word_t cfa_val, unw_word_t fp_val)
+{
+  return fp_val > 0 && cfa_val > 0 && fp_val >cfa_val && (fp_val - cfa_val < 0x4000);
+}
+
+static int _step_n64(struct cursor *c)
+{
+  #define FP_REG UNW_MIPS_R30
+  #define SP_REG UNW_MIPS_R29
+  #define RA_REG UNW_MIPS_R31
+
+  //TODO:handle plt entry
+  int ret;
+  unw_word_t current_fp_val = 0;
+  unw_word_t current_ra_val = 0;
+  unw_word_t current_sp_val = 0;
+  struct dwarf_loc up_fp_loc = DWARF_NULL_LOC;
+  struct dwarf_loc up_ra_loc = DWARF_NULL_LOC;
+
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[SP_REG], &current_sp_val);
+  if (ret < 0)
+    {
+      Debug (2, "returning %d [SP=0x%lx]\n", ret,
+             DWARF_GET_LOC (c->dwarf.loc[FP_REG]));
+      return ret;
+    }
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[FP_REG], &current_fp_val);
+  if (ret < 0)
+    {
+      Debug (2, "returning %d [FP=0x%lx]\n", ret,
+             DWARF_GET_LOC (c->dwarf.loc[FP_REG]));
+      return ret;
+    }
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RA_REG], &current_ra_val);
+  if (ret < 0)
+    {
+      Debug (2, "returning %d [RA=0x%lx]\n", ret,
+             DWARF_GET_LOC (c->dwarf.loc[RA_REG]));
+      return ret;
+    }
+
+  Debug(2, "BEGIN GUESSING WITH SP:%p FP:%p CFA:%p at %p, RA:%p\n",
+         current_sp_val, current_fp_val, c->dwarf.cfa,
+         c->dwarf.ip, current_ra_val
+         );
+
+  if (current_fp_val == current_sp_val) {
+    // Don't adjust FP
+    up_fp_loc = c->dwarf.loc[FP_REG];
+    up_ra_loc = c->dwarf.loc[RA_REG];
+  } else if (is_valid_fp_val(c->dwarf.cfa, current_fp_val)) {
+    /* Heuristic to determine incorrect guess.  For FP to be a
+       valid frame it needs to be above current CFA, but don't
+       let it go more than a little.  Note that we can't deduce
+       anything about new FP (fp1) since it may not be a frame
+       pointer in the frame above.  Just check we get the value. */
+    up_fp_loc = DWARF_MEM_LOC (c, current_fp_val+16);
+    up_ra_loc = DWARF_MEM_LOC (c, current_fp_val+24);
+    unw_word_t up_fp_val = 0;
+    ret = dwarf_get (&c->dwarf, up_fp_loc, &up_fp_val);
+    if (ret > 0 && is_valid_fp_val(current_fp_val, up_fp_val)) {
+      c->dwarf.loc[FP_REG] = up_fp_loc;
+    }
+  }
+
+  if (DWARF_IS_NULL_LOC (up_fp_loc))
+    {
+      ret = 0;
+      Debug (2, "NULL %%fp loc, returning %d\n", ret);
+      return ret;
+    }
+
+  c->dwarf.loc[UNW_MIPS_PC] = c->dwarf.loc[RA_REG];
+  c->dwarf.loc[RA_REG] = up_ra_loc;
+  c->dwarf.loc[SP_REG] = up_fp_loc;
+  c->dwarf.loc[FP_REG] = up_fp_loc;
+  c->dwarf.use_prev_instr = 1;
+
+  if (c->dwarf.ip == current_ra_val && current_fp_val == current_sp_val) {
+    // Backtrace stopped: frame did not save the PC
+    c->dwarf.ip = 0;
+  } else {
+    c->dwarf.ip = current_ra_val;
+  }
+  return (c->dwarf.ip == 0) ? 0 : 1;
+}
+
 int
 unw_step (unw_cursor_t *cursor)
 {
@@ -124,9 +214,11 @@ unw_step (unw_cursor_t *cursor)
   if (unlikely (ret == -UNW_ESTOPUNWIND))
     return ret;
 
-  /* Dwarf unwinding didn't work, stop.  */
+#if _MIPS_SIM == _ABI64
   if (unlikely (ret < 0))
-    return 0;
-
+    {
+      return _step_n64(c);
+    }
+#endif
   return (c->dwarf.ip == 0) ? 0 : 1;
 }
diff --git a/src/coreclr/src/pal/src/libunwind/src/os-solaris.c b/src/coreclr/src/pal/src/libunwind/src/os-solaris.c
new file mode 100644 (file)
index 0000000..3c140ef
--- /dev/null
@@ -0,0 +1,73 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003-2005 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include <limits.h>
+#include <stdio.h>
+
+#include "libunwind_i.h"
+#include "os-linux.h" // using linux header for map_iterator implementation
+
+int
+tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
+                    unsigned long *segbase, unsigned long *mapoff,
+                    char *path, size_t pathlen)
+{
+  struct map_iterator mi;
+  int found = 0, rc;
+  unsigned long hi;
+
+  if (maps_init (&mi, pid) < 0)
+    return -1;
+
+  while (maps_next (&mi, segbase, &hi, mapoff))
+    if (ip >= *segbase && ip < hi)
+      {
+        found = 1;
+        break;
+      }
+
+  if (!found)
+    {
+      maps_close (&mi);
+      return -1;
+    }
+  if (path)
+    {
+      strncpy(path, mi.path, pathlen);
+    }
+  rc = elf_map_image (ei, mi.path);
+  maps_close (&mi);
+  return rc;
+}
+
+#ifndef UNW_REMOTE_ONLY
+
+void
+tdep_get_exe_image_path (char *path)
+{
+  strcpy(path, getexecname());
+}
+
+#endif /* !UNW_REMOTE_ONLY */
index ba30244..7b45455 100644 (file)
@@ -91,9 +91,6 @@ tdep_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -104,7 +101,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index 4c88cd6..7bfb395 100644 (file)
@@ -95,9 +95,6 @@ tdep_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -108,7 +105,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index 2b92462..37cd4ff 100644 (file)
@@ -84,6 +84,9 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
 #elif defined(__arm__)
   if ((unsigned) reg < UNW_ARM_F0 || (unsigned) reg > UNW_ARM_F7)
     return -UNW_EBADREG;
+#elif defined(__aarch64__)
+  if ((unsigned) reg < UNW_AARCH64_V0 || (unsigned) reg > UNW_AARCH64_V31)
+    return -UNW_EBADREG;
 #else
 #error Fix me
 #endif
@@ -99,6 +102,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
           memcpy(&fpreg.fpr_acc[reg], val, sizeof(unw_fpreg_t));
 #elif defined(__arm__)
           memcpy(&fpreg.fpr[reg], val, sizeof(unw_fpreg_t));
+#elif defined(__aarch64__)
+          memcpy(&fpreg.fp_q[reg], val, sizeof(unw_fpreg_t));
 #else
 #error Fix me
 #endif
@@ -111,6 +116,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
           memcpy(val, &fpreg.fpr_acc[reg], sizeof(unw_fpreg_t));
 #elif defined(__arm__)
           memcpy(val, &fpreg.fpr[reg], sizeof(unw_fpreg_t));
+#elif defined(__aarch64__)
+          memcpy(val, &fpreg.fp_q[reg], sizeof(unw_fpreg_t));
 #else
 #error Fix me
 #endif
index cc5ed04..16671d4 100644 (file)
@@ -71,6 +71,11 @@ get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
 
 #else
 
+/* XXX fix me: there is currently no way to locate the dyn-info list
+       by a remote unwinder.  On ia64, this is done via a special
+       unwind-table entry.  Perhaps something similar can be done with
+       DWARF2 unwind info.  */
+
 static inline int
 get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
                int *countp)
index c82d1c9..52be799 100644 (file)
@@ -632,6 +632,40 @@ const int _UPT_reg_offset[UNW_REG_LAST + 1] =
     [UNW_TILEGX_R54]    = 0x1b0,
     [UNW_TILEGX_R55]    = 0x1b8,
     [UNW_TILEGX_PC]     = 0x1a0
+#elif defined(UNW_TARGET_S390X)
+    [UNW_S390X_R0]      = 0x10,
+    [UNW_S390X_R1]      = 0x18,
+    [UNW_S390X_R2]      = 0x20,
+    [UNW_S390X_R3]      = 0x28,
+    [UNW_S390X_R4]      = 0x30,
+    [UNW_S390X_R5]      = 0x38,
+    [UNW_S390X_R6]      = 0x40,
+    [UNW_S390X_R7]      = 0x48,
+    [UNW_S390X_R8]      = 0x50,
+    [UNW_S390X_R9]      = 0x58,
+    [UNW_S390X_R10]     = 0x60,
+    [UNW_S390X_R11]     = 0x68,
+    [UNW_S390X_R12]     = 0x70,
+    [UNW_S390X_R13]     = 0x78,
+    [UNW_S390X_R14]     = 0x80,
+    [UNW_S390X_R15]     = 0x88,
+    [UNW_S390X_F0]      = 0xe0,
+    [UNW_S390X_F1]      = 0xe8,
+    [UNW_S390X_F2]      = 0xf0,
+    [UNW_S390X_F3]      = 0xf8,
+    [UNW_S390X_F4]      = 0x100,
+    [UNW_S390X_F5]      = 0x108,
+    [UNW_S390X_F6]      = 0x110,
+    [UNW_S390X_F7]      = 0x118,
+    [UNW_S390X_F8]      = 0x120,
+    [UNW_S390X_F9]      = 0x128,
+    [UNW_S390X_F10]     = 0x130,
+    [UNW_S390X_F11]     = 0x138,
+    [UNW_S390X_F12]     = 0x140,
+    [UNW_S390X_F13]     = 0x148,
+    [UNW_S390X_F14]     = 0x150,
+    [UNW_S390X_F15]     = 0x150,
+    [UNW_S390X_IP]      = 0x08
 #else
 # error Fix me.
 #endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gapply_reg_state.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gapply_reg_state.c
new file mode 100644 (file)
index 0000000..82f056d
--- /dev/null
@@ -0,0 +1,37 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+                    void *reg_states_data)
+{
+  struct cursor *c = (struct cursor *) cursor;
+
+  return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gcreate_addr_space.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gcreate_addr_space.c
new file mode 100644 (file)
index 0000000..d411454
--- /dev/null
@@ -0,0 +1,62 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include <stdlib.h>
+
+#include "unwind_i.h"
+
+#if defined(_BIG_ENDIAN) && !defined(__BIG_ENDIAN)
+#define __BIG_ENDIAN _BIG_ENDIAN
+#endif
+
+unw_addr_space_t
+unw_create_addr_space (unw_accessors_t *a, int byte_order)
+{
+#ifdef UNW_LOCAL_ONLY
+  return NULL;
+#else
+  unw_addr_space_t as;
+
+  /*
+   * s390x supports only big-endian.
+   */
+  if (byte_order != 0 && byte_order != __BIG_ENDIAN)
+    return NULL;
+
+  as = malloc (sizeof (*as));
+  if (!as)
+    return NULL;
+
+  memset (as, 0, sizeof (*as));
+
+  as->acc = *a;
+
+  return as;
+#endif
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gget_proc_info.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gget_proc_info.c
new file mode 100644 (file)
index 0000000..50de1e4
--- /dev/null
@@ -0,0 +1,48 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+int
+unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
+{
+  struct cursor *c = (struct cursor *) cursor;
+
+  if (dwarf_make_proc_info (&c->dwarf) < 0)
+    {
+      /* On x86-64, some key routines such as _start() and _dl_start()
+         are missing DWARF unwind info.  We don't want to fail in that
+         case, because those frames are uninteresting and just mark
+         the end of the frame-chain anyhow.  */
+      memset (pi, 0, sizeof (*pi));
+      pi->start_ip = c->dwarf.ip;
+      pi->end_ip = c->dwarf.ip + 1;
+      return 0;
+    }
+  *pi = c->dwarf.pi;
+  return 0;
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gget_save_loc.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gget_save_loc.c
new file mode 100644 (file)
index 0000000..dc462c9
--- /dev/null
@@ -0,0 +1,86 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2004 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+int
+unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
+{
+  struct cursor *c = (struct cursor *) cursor;
+  dwarf_loc_t loc;
+
+  loc = DWARF_NULL_LOC;         /* default to "not saved" */
+
+  switch (reg)
+    {
+    case UNW_S390X_R6:
+    case UNW_S390X_R7:
+    case UNW_S390X_R8:
+    case UNW_S390X_R9:
+    case UNW_S390X_R10:
+    case UNW_S390X_R11:
+    case UNW_S390X_R12:
+    case UNW_S390X_R13:
+    case UNW_S390X_R15:
+    case UNW_S390X_F8:
+    case UNW_S390X_F9:
+    case UNW_S390X_F10:
+    case UNW_S390X_F11:
+    case UNW_S390X_F12:
+    case UNW_S390X_F13:
+    case UNW_S390X_F14:
+    case UNW_S390X_F15:
+      loc = c->dwarf.loc[reg];
+      break;
+
+    default:
+      break;
+    }
+
+  memset (sloc, 0, sizeof (*sloc));
+
+  if (DWARF_IS_NULL_LOC (loc))
+    {
+      sloc->type = UNW_SLT_NONE;
+      return 0;
+    }
+
+#if !defined(UNW_LOCAL_ONLY)
+  if (DWARF_IS_REG_LOC (loc))
+    {
+      sloc->type = UNW_SLT_REG;
+      sloc->u.regnum = DWARF_GET_LOC (loc);
+    }
+  else
+#endif
+    {
+      sloc->type = UNW_SLT_MEMORY;
+      sloc->u.addr = DWARF_GET_LOC (loc);
+    }
+  return 0;
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gglobal.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gglobal.c
new file mode 100644 (file)
index 0000000..e2abe89
--- /dev/null
@@ -0,0 +1,101 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "config.h"
+#include "unwind_i.h"
+#include "dwarf_i.h"
+
+HIDDEN define_lock (s390x_lock);
+HIDDEN int tdep_init_done;
+
+/* The API register numbers are exactly the same as the .eh_frame
+   registers, for now at least.  */
+HIDDEN const uint8_t dwarf_to_unw_regnum_map[DWARF_NUM_PRESERVED_REGS] =
+  {
+    UNW_S390X_R0,
+    UNW_S390X_R1,
+    UNW_S390X_R2,
+    UNW_S390X_R3,
+    UNW_S390X_R4,
+    UNW_S390X_R5,
+    UNW_S390X_R6,
+    UNW_S390X_R7,
+    UNW_S390X_R8,
+    UNW_S390X_R9,
+    UNW_S390X_R10,
+    UNW_S390X_R11,
+    UNW_S390X_R12,
+    UNW_S390X_R13,
+    UNW_S390X_R14,
+    UNW_S390X_R15,
+
+    UNW_S390X_F0,
+    UNW_S390X_F2,
+    UNW_S390X_F4,
+    UNW_S390X_F6,
+    UNW_S390X_F1,
+    UNW_S390X_F3,
+    UNW_S390X_F5,
+    UNW_S390X_F7,
+    UNW_S390X_F8,
+    UNW_S390X_F10,
+    UNW_S390X_F12,
+    UNW_S390X_F14,
+    UNW_S390X_F9,
+    UNW_S390X_F11,
+    UNW_S390X_F13,
+    UNW_S390X_F15,
+  };
+
+HIDDEN void
+tdep_init (void)
+{
+  intrmask_t saved_mask;
+
+  sigfillset (&unwi_full_mask);
+
+  lock_acquire (&s390x_lock, saved_mask);
+  {
+    if (tdep_init_done)
+      /* another thread else beat us to it... */
+      goto out;
+
+    mi_init ();
+
+    dwarf_init ();
+
+    tdep_init_mem_validate ();
+
+#ifndef UNW_REMOTE_ONLY
+    s390x_local_addr_space_init ();
+#endif
+    tdep_init_done = 1; /* signal that we're initialized... */
+  }
+ out:
+  lock_release (&s390x_lock, saved_mask);
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Ginit.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Ginit.c
new file mode 100644 (file)
index 0000000..db01743
--- /dev/null
@@ -0,0 +1,365 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002 Hewlett-Packard Co
+   Copyright (C) 2007 David Mosberger-Tang
+        Contributed by David Mosberger-Tang <dmosberger@gmail.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#include "unwind_i.h"
+
+#ifdef UNW_REMOTE_ONLY
+
+/* unw_local_addr_space is a NULL pointer in this case.  */
+unw_addr_space_t unw_local_addr_space;
+
+#else /* !UNW_REMOTE_ONLY */
+
+static struct unw_addr_space local_addr_space;
+
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
+
+static inline void *
+uc_addr (ucontext_t *uc, int reg)
+{
+  if (reg >= UNW_S390X_R0 && reg <= UNW_S390X_R15)
+    return &uc->uc_mcontext.gregs[reg - UNW_S390X_R0];
+  if (reg >= UNW_S390X_F0 && reg <= UNW_S390X_F15)
+    return &uc->uc_mcontext.fpregs.fprs[reg - UNW_S390X_F0];
+  if (reg == UNW_S390X_IP)
+    return &uc->uc_mcontext.psw.addr;
+
+  return NULL;
+}
+
+# ifdef UNW_LOCAL_ONLY
+
+HIDDEN void *
+tdep_uc_addr (ucontext_t *uc, int reg)
+{
+  return uc_addr (uc, reg);
+}
+
+# endif /* UNW_LOCAL_ONLY */
+
+static void
+put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
+{
+  /* it's a no-op */
+}
+
+static int
+get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
+                        void *arg)
+{
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
+  return 0;
+}
+
+#define PAGE_SIZE 4096
+#define PAGE_START(a)   ((a) & ~(PAGE_SIZE-1))
+
+static int mem_validate_pipe[2] = {-1, -1};
+
+static inline void
+open_pipe (void)
+{
+  /* ignore errors for closing invalid fd's */
+  close (mem_validate_pipe[0]);
+  close (mem_validate_pipe[1]);
+
+  pipe2 (mem_validate_pipe, O_CLOEXEC | O_NONBLOCK);
+}
+
+ALWAYS_INLINE
+static int
+write_validate (void *addr)
+{
+  int ret = -1;
+  ssize_t bytes = 0;
+
+  do
+    {
+      char buf;
+      bytes = read (mem_validate_pipe[0], &buf, 1);
+    }
+  while ( errno == EINTR );
+
+  int valid_read = (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK);
+  if (!valid_read)
+    {
+      // re-open closed pipe
+      open_pipe ();
+    }
+
+  do
+    {
+      /* use syscall insteadof write() so that ASAN does not complain */
+      ret = syscall (SYS_write, mem_validate_pipe[1], addr, 1);
+    }
+  while ( errno == EINTR );
+
+  return ret;
+}
+
+static int (*mem_validate_func) (void *addr, size_t len);
+static int msync_validate (void *addr, size_t len)
+{
+  if (msync (addr, len, MS_ASYNC) != 0)
+    {
+      return -1;
+    }
+
+  return write_validate (addr);
+}
+
+#ifdef HAVE_MINCORE
+static int mincore_validate (void *addr, size_t len)
+{
+  unsigned char mvec[2]; /* Unaligned access may cross page boundary */
+  size_t i;
+
+  /* mincore could fail with EAGAIN but we conservatively return -1
+     instead of looping. */
+  if (mincore (addr, len, mvec) != 0)
+    {
+      return -1;
+    }
+
+  for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++)
+    {
+      if (!(mvec[i] & 1)) return -1;
+    }
+
+  return write_validate (addr);
+}
+#endif
+
+/* Initialise memory validation method. On linux kernels <2.6.21,
+   mincore() returns incorrect value for MAP_PRIVATE mappings,
+   such as stacks. If mincore() was available at compile time,
+   check if we can actually use it. If not, use msync() instead. */
+HIDDEN void
+tdep_init_mem_validate (void)
+{
+  open_pipe ();
+
+#ifdef HAVE_MINCORE
+  unsigned char present = 1;
+  unw_word_t addr = PAGE_START((unw_word_t)&present);
+  unsigned char mvec[1];
+  int ret;
+  while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 &&
+         errno == EAGAIN) {}
+  if (ret == 0 && (mvec[0] & 1))
+    {
+      Debug(1, "using mincore to validate memory\n");
+      mem_validate_func = mincore_validate;
+    }
+  else
+#endif
+    {
+      Debug(1, "using msync to validate memory\n");
+      mem_validate_func = msync_validate;
+    }
+}
+
+/* Cache of already validated addresses */
+#define NLGA 4
+static unw_word_t last_good_addr[NLGA];
+static int lga_victim;
+
+static int
+validate_mem (unw_word_t addr)
+{
+  int i, victim;
+  size_t len;
+
+  if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
+    len = PAGE_SIZE;
+  else
+    len = PAGE_SIZE * 2;
+
+  addr = PAGE_START(addr);
+
+  if (addr == 0)
+    return -1;
+
+  for (i = 0; i < NLGA; i++)
+    {
+      if (last_good_addr[i] && (addr == last_good_addr[i]))
+        return 0;
+    }
+
+  if (mem_validate_func ((void *) addr, len) == -1)
+    return -1;
+
+  victim = lga_victim;
+  for (i = 0; i < NLGA; i++) {
+    if (!last_good_addr[victim]) {
+      last_good_addr[victim++] = addr;
+      return 0;
+    }
+    victim = (victim + 1) % NLGA;
+  }
+
+  /* All slots full. Evict the victim. */
+  last_good_addr[victim] = addr;
+  victim = (victim + 1) % NLGA;
+  lga_victim = victim;
+
+  return 0;
+}
+
+static int
+access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
+            void *arg)
+{
+  if (unlikely (write))
+    {
+      Debug (16, "mem[%016lx] <- %lx\n", addr, *val);
+      *(unw_word_t *) addr = *val;
+    }
+  else
+    {
+      /* validate address */
+      const struct cursor *c = (const struct cursor *)arg;
+      if (likely (c != NULL) && unlikely (c->validate)
+          && unlikely (validate_mem (addr))) {
+        Debug (16, "mem[%016lx] -> invalid\n", addr);
+        return -1;
+      }
+      *val = *(unw_word_t *) addr;
+      Debug (16, "mem[%016lx] -> %lx\n", addr, *val);
+    }
+  return 0;
+}
+
+static int
+access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
+            void *arg)
+{
+  unw_word_t *addr;
+  ucontext_t *uc = ((struct cursor *)arg)->uc;
+
+  if (unw_is_fpreg (reg))
+    goto badreg;
+
+  if (!(addr = uc_addr (uc, reg)))
+    goto badreg;
+
+  if (write)
+    {
+      *(unw_word_t *) addr = *val;
+      Debug (12, "%s <- 0x%016lx\n", unw_regname (reg), *val);
+    }
+  else
+    {
+      *val = *(unw_word_t *) addr;
+      Debug (12, "%s -> 0x%016lx\n", unw_regname (reg), *val);
+    }
+  return 0;
+
+ badreg:
+  Debug (1, "bad register number %u\n", reg);
+  return -UNW_EBADREG;
+}
+
+static int
+access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
+              int write, void *arg)
+{
+  ucontext_t *uc = ((struct cursor *)arg)->uc;
+  unw_fpreg_t *addr;
+
+  if (!unw_is_fpreg (reg))
+    goto badreg;
+
+  if (!(addr = uc_addr (uc, reg)))
+    goto badreg;
+
+  if (write)
+    {
+      Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
+             ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
+      *(unw_fpreg_t *) addr = *val;
+    }
+  else
+    {
+      *val = *(unw_fpreg_t *) addr;
+      Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
+             ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
+    }
+  return 0;
+
+ badreg:
+  Debug (1, "bad register number %u\n", reg);
+  /* attempt to access a non-preserved register */
+  return -UNW_EBADREG;
+}
+
+static int
+get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
+                      char *buf, size_t buf_len, unw_word_t *offp,
+                      void *arg)
+{
+  return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
+}
+
+HIDDEN void
+s390x_local_addr_space_init (void)
+{
+  memset (&local_addr_space, 0, sizeof (local_addr_space));
+  local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
+  local_addr_space.acc.put_unwind_info = put_unwind_info;
+  local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
+  local_addr_space.acc.access_mem = access_mem;
+  local_addr_space.acc.access_reg = access_reg;
+  local_addr_space.acc.access_fpreg = access_fpreg;
+  local_addr_space.acc.resume = s390x_local_resume;
+  local_addr_space.acc.get_proc_name = get_static_proc_name;
+  unw_flush_cache (&local_addr_space, 0, 0);
+
+  memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA);
+  lga_victim = 0;
+}
+
+#endif /* !UNW_REMOTE_ONLY */
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Ginit_local.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Ginit_local.c
new file mode 100644 (file)
index 0000000..5eaead0
--- /dev/null
@@ -0,0 +1,81 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+#include "init.h"
+
+#ifdef UNW_REMOTE_ONLY
+
+int
+unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+{
+  return -UNW_EINVAL;
+}
+
+#else /* !UNW_REMOTE_ONLY */
+
+static int
+unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
+{
+  struct cursor *c = (struct cursor *) cursor;
+
+  if (unlikely (!tdep_init_done))
+    tdep_init ();
+
+  Debug (1, "(cursor=%p)\n", c);
+
+  c->dwarf.as = unw_local_addr_space;
+  c->dwarf.as_arg = c;
+  c->uc = uc;
+  c->validate = 0;
+  return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+{
+  return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+  if (!flag)
+    {
+      return unw_init_local_common(cursor, uc, 1);
+    }
+  else if (flag == UNW_INIT_SIGNAL_FRAME)
+    {
+      return unw_init_local_common(cursor, uc, 0);
+    }
+  else
+    {
+      return -UNW_EINVAL;
+    }
+}
+
+#endif /* !UNW_REMOTE_ONLY */
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Ginit_remote.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Ginit_remote.c
new file mode 100644 (file)
index 0000000..efd61d6
--- /dev/null
@@ -0,0 +1,57 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "init.h"
+#include "unwind_i.h"
+
+int
+unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
+{
+#ifdef UNW_LOCAL_ONLY
+  return -UNW_EINVAL;
+#else /* !UNW_LOCAL_ONLY */
+  struct cursor *c = (struct cursor *) cursor;
+
+  if (!tdep_init_done)
+    tdep_init ();
+
+  Debug (1, "(cursor=%p)\n", c);
+
+  c->dwarf.as = as;
+  if (as == unw_local_addr_space)
+    {
+      c->dwarf.as_arg = c;
+      c->uc = as_arg;
+    }
+  else
+    {
+      c->dwarf.as_arg = as_arg;
+      c->uc = NULL;
+    }
+  return common_init (c, 0);
+#endif /* !UNW_LOCAL_ONLY */
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gis_signal_frame.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gis_signal_frame.c
new file mode 100644 (file)
index 0000000..7ed91e3
--- /dev/null
@@ -0,0 +1,77 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
+   Copyright (C) 2013 Linaro Limited
+   Copyright (C) 2017 IBM
+
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+/* The restorer stub will be a system call:
+   - rt_sigreturn: svc 173 (0x0aad)
+   - sigreturn:    svc 119 (0x0a77)
+*/
+
+int
+unw_is_signal_frame (unw_cursor_t *cursor)
+{
+#ifdef __linux__
+  struct cursor *c = (struct cursor *) cursor;
+  unw_word_t w0, ip;
+  unw_addr_space_t as;
+  unw_accessors_t *a;
+  void *arg;
+  int ret, shift = 48;
+
+  as = c->dwarf.as;
+  a = unw_get_accessors (as);
+  arg = c->dwarf.as_arg;
+
+  /* Align the instruction pointer to 8 bytes so that we guarantee
+     an 8 byte read from it won't cross a page boundary.
+     Instructions on s390x are 2 byte aligned.  */
+  ip = c->dwarf.ip & ~7;
+  shift -= (c->dwarf.ip - ip) * 8;
+
+  ret = (*a->access_mem) (as, ip, &w0, 0, arg);
+  if (ret < 0)
+    return ret;
+
+  /* extract first 2 bytes of the next instruction */
+  w0 = (w0 >> shift) & 0xffff;
+
+  /* sigreturn */
+  if (w0 == 0x0a77)
+    return 1;
+
+  /* rt_sigreturn */
+  if (w0 == 0x0aad)
+    return 2;
+
+  return 0;
+
+#else
+  return -UNW_ENOINFO;
+#endif
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Greg_states_iterate.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Greg_states_iterate.c
new file mode 100644 (file)
index 0000000..a17dc1b
--- /dev/null
@@ -0,0 +1,37 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+                       unw_reg_states_callback cb, void *token)
+{
+  struct cursor *c = (struct cursor *) cursor;
+
+  return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gregs.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gregs.c
new file mode 100644 (file)
index 0000000..1a48833
--- /dev/null
@@ -0,0 +1,116 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+HIDDEN int
+tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
+                 int write)
+{
+  dwarf_loc_t loc = DWARF_NULL_LOC;
+
+  switch (reg)
+    {
+    case UNW_S390X_CFA:
+      if (write)
+        return -UNW_EREADONLYREG;
+      *valp = c->dwarf.cfa;
+      return 0;
+
+    case UNW_S390X_R0:
+    case UNW_S390X_R1:
+    case UNW_S390X_R2:
+    case UNW_S390X_R3:
+    case UNW_S390X_R4:
+    case UNW_S390X_R5:
+    case UNW_S390X_R6:
+    case UNW_S390X_R7:
+    case UNW_S390X_R8:
+    case UNW_S390X_R9:
+    case UNW_S390X_R10:
+    case UNW_S390X_R11:
+    case UNW_S390X_R12:
+    case UNW_S390X_R13:
+    case UNW_S390X_R14:
+    case UNW_S390X_IP:
+      loc = c->dwarf.loc[reg];
+      break;
+
+    case UNW_S390X_R15:
+      if (write)
+        return -UNW_EREADONLYREG;
+      loc = c->dwarf.loc[reg];
+      break;
+
+    default:
+      Debug (1, "bad register number %u\n", reg);
+      return -UNW_EBADREG;
+    }
+
+  if (write)
+    return dwarf_put (&c->dwarf, loc, *valp);
+  else
+    return dwarf_get (&c->dwarf, loc, valp);
+}
+
+HIDDEN int
+tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp,
+                   int write)
+{
+  dwarf_loc_t loc = DWARF_NULL_LOC;
+
+  switch (reg)
+    {
+    case UNW_S390X_F0:
+    case UNW_S390X_F1:
+    case UNW_S390X_F2:
+    case UNW_S390X_F3:
+    case UNW_S390X_F4:
+    case UNW_S390X_F5:
+    case UNW_S390X_F6:
+    case UNW_S390X_F7:
+    case UNW_S390X_F8:
+    case UNW_S390X_F9:
+    case UNW_S390X_F10:
+    case UNW_S390X_F11:
+    case UNW_S390X_F12:
+    case UNW_S390X_F13:
+    case UNW_S390X_F14:
+    case UNW_S390X_F15:
+      loc = c->dwarf.loc[reg];
+      break;
+    default:
+      Debug (1, "bad register number %u\n", reg);
+      return -UNW_EBADREG;
+    }
+
+  if (write)
+    return dwarf_putfp (&c->dwarf, loc, *valp);
+  else
+    return dwarf_getfp (&c->dwarf, loc, valp);
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gresume.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gresume.c
new file mode 100644 (file)
index 0000000..fd9d130
--- /dev/null
@@ -0,0 +1,160 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include <stdlib.h>
+
+#include "unwind_i.h"
+
+#ifndef UNW_REMOTE_ONLY
+
+HIDDEN inline int
+s390x_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
+{
+  struct cursor *c = (struct cursor *) cursor;
+  ucontext_t uc = *c->uc;
+  ucontext_t *rt = NULL;
+  struct sigcontext *sc = NULL;
+  int i;
+  unw_word_t sp, ip;
+  uc.uc_mcontext.psw.addr = c->dwarf.ip;
+
+  /* Ensure c->pi is up-to-date.  On x86-64, it's relatively common to
+     be missing DWARF unwind info.  We don't want to fail in that
+     case, because the frame-chain still would let us do a backtrace
+     at least.  */
+  dwarf_make_proc_info (&c->dwarf);
+
+  switch (c->sigcontext_format)
+    {
+    case S390X_SCF_NONE:
+      Debug (8, "resuming at ip=%llx via setcontext()\n",
+                (unsigned long long) c->dwarf.ip);
+      setcontext (&uc);
+      abort(); /* unreachable */
+    case S390X_SCF_LINUX_SIGFRAME:
+      Debug (8, "resuming at ip=%llx via signal trampoline\n",
+                (unsigned long long) c->dwarf.ip);
+      sc = (struct sigcontext*)c->sigcontext_addr;
+      for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
+        sc->sregs->regs.gprs[i-UNW_S390X_R0] = uc.uc_mcontext.gregs[i-UNW_S390X_R0];
+      for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
+        sc->sregs->fpregs.fprs[i-UNW_S390X_F0] = uc.uc_mcontext.fpregs.fprs[i-UNW_S390X_F0].d;
+      sc->sregs->regs.psw.addr = uc.uc_mcontext.psw.addr;
+
+      sp = c->sigcontext_sp;
+      ip = c->sigcontext_pc;
+      __asm__ __volatile__ (
+        "lgr 15, %[sp]\n"
+        "br %[ip]\n"
+        : : [sp] "r" (sp), [ip] "r" (ip)
+      );
+      abort(); /* unreachable */
+    case S390X_SCF_LINUX_RT_SIGFRAME:
+      Debug (8, "resuming at ip=%llx via signal trampoline\n",
+                (unsigned long long) c->dwarf.ip);
+      rt = (ucontext_t*)c->sigcontext_addr;
+      for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
+        rt->uc_mcontext.gregs[i-UNW_S390X_R0] = uc.uc_mcontext.gregs[i-UNW_S390X_R0];
+      for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
+        rt->uc_mcontext.fpregs.fprs[i-UNW_S390X_F0] = uc.uc_mcontext.fpregs.fprs[i-UNW_S390X_F0];
+      rt->uc_mcontext.psw.addr = uc.uc_mcontext.psw.addr;
+
+      sp = c->sigcontext_sp;
+      ip = c->sigcontext_pc;
+      __asm__ __volatile__ (
+        "lgr 15, %[sp]\n"
+        "br %[ip]\n"
+        : : [sp] "r" (sp), [ip] "r" (ip)
+      );
+      abort(); /* unreachable */
+    }
+  return -UNW_EINVAL;
+}
+
+#endif /* !UNW_REMOTE_ONLY */
+
+/* This routine is responsible for copying the register values in
+   cursor C and establishing them as the current machine state. */
+
+static inline int
+establish_machine_state (struct cursor *c)
+{
+  int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *,
+                     int write, void *);
+  int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *,
+                       int write, void *);
+  unw_addr_space_t as = c->dwarf.as;
+  void *arg = c->dwarf.as_arg;
+  unw_fpreg_t fpval;
+  unw_word_t val;
+  int reg;
+
+  access_reg = as->acc.access_reg;
+  access_fpreg = as->acc.access_fpreg;
+
+  Debug (8, "copying out cursor state\n");
+
+  for (reg = 0; reg <= UNW_REG_LAST; ++reg)
+    {
+      Debug (16, "copying %s %d\n", unw_regname (reg), reg);
+      if (unw_is_fpreg (reg))
+        {
+          if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0)
+            (*access_fpreg) (as, reg, &fpval, 1, arg);
+        }
+      else
+        {
+          if (tdep_access_reg (c, reg, &val, 0) >= 0)
+            (*access_reg) (as, reg, &val, 1, arg);
+        }
+    }
+
+  if (c->dwarf.args_size)
+    {
+      if (tdep_access_reg (c, UNW_S390X_R15, &val, 0) >= 0)
+        {
+          val += c->dwarf.args_size;
+          (*access_reg) (as, UNW_S390X_R15, &val, 1, arg);
+        }
+    }
+  return 0;
+}
+
+int
+unw_resume (unw_cursor_t *cursor)
+{
+  struct cursor *c = (struct cursor *) cursor;
+  int ret;
+
+  Debug (1, "(cursor=%p)\n", c);
+
+  if ((ret = establish_machine_state (c)) < 0)
+    return ret;
+
+  return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c,
+                                     c->dwarf.as_arg);
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Gstep.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Gstep.c
new file mode 100644 (file)
index 0000000..0b79580
--- /dev/null
@@ -0,0 +1,146 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002-2004 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+#include <signal.h>
+
+static int
+s390x_handle_signal_frame (unw_cursor_t *cursor)
+{
+  struct cursor *c = (struct cursor *) cursor;
+  int ret, i;
+  unw_word_t sc_addr, sp, *gprs, *fprs, *psw;
+
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_R15], &sp);
+  if (ret < 0)
+    return ret;
+
+  /* Save the SP and PC to be able to return execution at this point
+     later in time (unw_resume).  */
+  c->sigcontext_sp = sp;
+  c->sigcontext_pc = c->dwarf.ip;
+  switch (c->sigcontext_format)
+    {
+    case S390X_SCF_LINUX_SIGFRAME: /* sigreturn */
+      sc_addr = sp + 160;
+      gprs = ((struct sigcontext*)sc_addr)->sregs->regs.gprs;
+      fprs = (unw_word_t*)((struct sigcontext*)sc_addr)->sregs->fpregs.fprs;
+      psw  = &((struct sigcontext*)sc_addr)->sregs->regs.psw.addr;
+      break;
+    case S390X_SCF_LINUX_RT_SIGFRAME: /* rt_sigreturn */
+      sc_addr = sp + sizeof(siginfo_t) + 8 + 160;
+      gprs = ((ucontext_t*)sc_addr)->uc_mcontext.gregs;
+      fprs = (unw_word_t*)((ucontext_t*)sc_addr)->uc_mcontext.fpregs.fprs;
+      psw  = &((ucontext_t*)sc_addr)->uc_mcontext.psw.addr;
+      break;
+    default:
+      return -UNW_EUNSPEC;
+    }
+
+  c->sigcontext_addr = sc_addr;
+
+  /* Update the dwarf cursor.
+     Set the location of the registers to the corresponding addresses of the
+     uc_mcontext / sigcontext structure contents.  */
+  for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i)
+    c->dwarf.loc[i] = DWARF_MEM_LOC (c, (unw_word_t) &gprs[i-UNW_S390X_R0]);
+  for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i)
+    c->dwarf.loc[i] = DWARF_MEM_LOC (c, (unw_word_t) &fprs[i-UNW_S390X_F0]);
+
+  c->dwarf.loc[UNW_S390X_IP] = DWARF_MEM_LOC (c, (unw_word_t) psw);
+
+  /* Set SP/CFA and PC/IP.
+     Normally the default CFA on s390x is r15+160. We do not add that offset
+     here because dwarf_step will add the offset.  */
+  dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_R15], &c->dwarf.cfa);
+  dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_IP], &c->dwarf.ip);
+
+  c->dwarf.pi_valid = 0;
+  c->dwarf.use_prev_instr = 0;
+
+  return 1;
+}
+
+int
+unw_step (unw_cursor_t *cursor)
+{
+  struct cursor *c = (struct cursor *) cursor;
+  int ret = 0, val = c->validate, sig;
+
+#if CONSERVATIVE_CHECKS
+  c->validate = 1;
+#endif
+
+  Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
+         c, c->dwarf.ip, c->dwarf.cfa);
+
+  /* Try DWARF-based unwinding... */
+  c->sigcontext_format = S390X_SCF_NONE;
+  ret = dwarf_step (&c->dwarf);
+
+#if CONSERVATIVE_CHECKS
+  c->validate = val;
+#endif
+
+  if (unlikely (ret == -UNW_ENOINFO))
+    {
+      /* GCC doesn't currently emit debug information for signal
+         trampolines on s390x so we check for them explicitly.
+
+         If there isn't debug information available we could also
+         try using the backchain (if available).
+
+         Other platforms also detect PLT entries here. That's
+         tricky to do reliably on s390x so I've left it out for
+         now.  */
+
+      /* Memory accesses here are quite likely to be unsafe. */
+      c->validate = 1;
+
+      /* Check if this is a signal frame. */
+      sig = unw_is_signal_frame (cursor);
+      if (sig > 0)
+        {
+          c->sigcontext_format = sig;
+          ret = s390x_handle_signal_frame (cursor);
+        }
+      else
+        {
+          c->dwarf.ip = 0;
+          ret = 0;
+        }
+
+      c->validate = val;
+      return ret;
+    }
+
+  if (unlikely (ret > 0 && c->dwarf.ip == 0))
+    return 0;
+
+  return ret;
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lapply_reg_state.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lapply_reg_state.c
new file mode 100644 (file)
index 0000000..7ebada4
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lcreate_addr_space.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lcreate_addr_space.c
new file mode 100644 (file)
index 0000000..0f2dc6b
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gcreate_addr_space.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lget_proc_info.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lget_proc_info.c
new file mode 100644 (file)
index 0000000..69028b0
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gget_proc_info.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lget_save_loc.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lget_save_loc.c
new file mode 100644 (file)
index 0000000..9ea048a
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gget_save_loc.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lglobal.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lglobal.c
new file mode 100644 (file)
index 0000000..8c43a67
--- /dev/null
@@ -0,0 +1,6 @@
+#define UNW_LOCAL_ONLY
+#include "config.h"
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gglobal.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Linit.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Linit.c
new file mode 100644 (file)
index 0000000..e9abfdd
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Ginit.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Linit_local.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Linit_local.c
new file mode 100644 (file)
index 0000000..68a1687
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Ginit_local.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Linit_remote.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Linit_remote.c
new file mode 100644 (file)
index 0000000..58cb04a
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Ginit_remote.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lis_signal_frame.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lis_signal_frame.c
new file mode 100644 (file)
index 0000000..b9a7c4f
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gis_signal_frame.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lreg_states_iterate.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lreg_states_iterate.c
new file mode 100644 (file)
index 0000000..f1eb1e7
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lregs.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lregs.c
new file mode 100644 (file)
index 0000000..2c9c75c
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gregs.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lresume.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lresume.c
new file mode 100644 (file)
index 0000000..41a8cf0
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gresume.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/Lstep.c b/src/coreclr/src/pal/src/libunwind/src/s390x/Lstep.c
new file mode 100644 (file)
index 0000000..c1ac3c7
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gstep.c"
+#endif
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/getcontext.S b/src/coreclr/src/pal/src/libunwind/src/s390x/getcontext.S
new file mode 100644 (file)
index 0000000..d35a3cf
--- /dev/null
@@ -0,0 +1,74 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2008 Google, Inc
+       Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
+   Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
+   Copyright (C) 2017 IBM
+
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+// int _Us390x_getcontext (unw_tdep_context_t *ucp)
+
+       .global _Us390x_getcontext
+       .type _Us390x_getcontext, @function
+_Us390x_getcontext:
+       .cfi_startproc
+
+       // Save the minimal set of registers required to restore the
+       // context. Generally speaking this is just the preserved
+       // registers but we've also saved the parameter registers
+       // so that return values can be modified too.
+
+       // save PSW address
+       // (not strictly needed but makes other code simpler)
+       stg   %r14,0x30(%r2)
+
+       // floating point parameters (not strictly needed)
+       std   %f0,0x100(%r2)
+       std   %f2,0x110(%r2)
+       std   %f4,0x120(%r2)
+       std   %f6,0x130(%r2)
+
+       // floating point preserved registers
+       stfpc 0xf8(%r2)
+       std   %f8,0x140(%r2)
+       std   %f9,0x148(%r2)
+       std   %f10,0x150(%r2)
+       std   %f11,0x158(%r2)
+       std   %f12,0x160(%r2)
+       std   %f13,0x168(%r2)
+       std   %f14,0x170(%r2)
+       std   %f15,0x178(%r2)
+
+       // preserved registers and parameters
+       lgr   %r1,%r2
+       lghi  %r2,0
+       stmg  %r2,%r15,0x48(%r1)
+
+       br    %r14
+
+       .cfi_endproc
+       .size _Us390x_getcontext, . - _Us390x_getcontext
+
+       // We do not need executable stack.
+       .section        .note.GNU-stack,"",@progbits
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/init.h b/src/coreclr/src/pal/src/libunwind/src/s390x/init.h
new file mode 100644 (file)
index 0000000..86ced38
--- /dev/null
@@ -0,0 +1,71 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+static inline int
+common_init (struct cursor *c, unsigned use_prev_instr)
+{
+  int ret;
+  int i;
+
+  for (i = UNW_S390X_R0; i <= UNW_S390X_R15; ++i) {
+    c->dwarf.loc[i] = DWARF_REG_LOC(&c->dwarf, i);
+  }
+  for (i = UNW_S390X_F0; i <= UNW_S390X_F15; ++i) {
+    c->dwarf.loc[i] = DWARF_FPREG_LOC(&c->dwarf, i);
+  }
+  /* IP isn't a real register, it is encoded in the PSW */
+  c->dwarf.loc[UNW_S390X_IP] = DWARF_REG_LOC(&c->dwarf, UNW_S390X_IP);
+
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_S390X_IP], &c->dwarf.ip);
+  if (ret < 0)
+    return ret;
+
+  /* Normally the CFA offset on s390x is biased, however this is taken
+     into account by the CFA offset in dwarf_step, so here we just mark
+     make it equal to the stack pointer.  */
+  ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_S390X_R15),
+                   &c->dwarf.cfa);
+  if (ret < 0)
+    return ret;
+
+  c->sigcontext_format = S390X_SCF_NONE;
+  c->sigcontext_addr = 0;
+
+  c->dwarf.args_size = 0;
+  c->dwarf.stash_frames = 0;
+  c->dwarf.use_prev_instr = use_prev_instr;
+  c->dwarf.pi_valid = 0;
+  c->dwarf.pi_is_dynamic = 0;
+  c->dwarf.hint = 0;
+  c->dwarf.prev_rs = 0;
+  c->dwarf.eh_valid_mask = 0;
+
+  return 0;
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/is_fpreg.c b/src/coreclr/src/pal/src/libunwind/src/s390x/is_fpreg.c
new file mode 100644 (file)
index 0000000..bc31f3e
--- /dev/null
@@ -0,0 +1,36 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (c) 2004-2005 Hewlett-Packard Development Company, L.P.
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "libunwind_i.h"
+
+int
+unw_is_fpreg (int regnum)
+{
+  /* vector registers? */
+  return regnum >= UNW_S390X_F0 && regnum <= UNW_S390X_F15;
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/regname.c b/src/coreclr/src/pal/src/libunwind/src/s390x/regname.c
new file mode 100644 (file)
index 0000000..2421b37
--- /dev/null
@@ -0,0 +1,57 @@
+/* libunwind - a platform-independent unwind library
+
+        Contributed by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+static const char *regname[] =
+  {
+    [UNW_S390X_R0]="R0",
+    [UNW_S390X_R1]="R1",
+    [UNW_S390X_R2]="R2",
+    [UNW_S390X_R3]="R3",
+    [UNW_S390X_R4]="R4",
+    [UNW_S390X_R5]="R5",
+    [UNW_S390X_R6]="R6",
+    [UNW_S390X_R7]="R7",
+    [UNW_S390X_R8]="R8",
+    [UNW_S390X_R9]="R9",
+    [UNW_S390X_R10]="R10",
+    [UNW_S390X_R11]="R11",
+    [UNW_S390X_R12]="R12",
+    [UNW_S390X_R13]="R13",
+    [UNW_S390X_R14]="R14",
+    [UNW_S390X_R15]="R15",
+
+    [UNW_S390X_IP]="IP"
+   };
+
+const char *
+unw_regname (unw_regnum_t reg)
+{
+  if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
+    return regname[reg];
+  else
+    return "???";
+}
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/setcontext.S b/src/coreclr/src/pal/src/libunwind/src/s390x/setcontext.S
new file mode 100644 (file)
index 0000000..6cf5568
--- /dev/null
@@ -0,0 +1,76 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2008 Google, Inc
+       Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
+   Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
+   Copyright (C) 2017 IBM
+
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+// int _Us390x_setcontext (const ucontext_t *ucp)
+
+       .global _Us390x_setcontext
+       .type _Us390x_setcontext, @function
+_Us390x_setcontext:
+       .cfi_startproc
+
+       // Must only restore registers saved by getcontext, other fields
+       // in the ucontext_t might be uninitialised.
+
+       // Stop this function being unwound. We are clobbering callee-save
+       // registers in this function so unwinding it is unsafe.
+       // Ideally we'd save callee-save registers, update the CFI for them
+       // and then switch to the new CFI once the context switch is
+       // complete.
+       .cfi_undefined %r14
+
+       // floating point parameters
+       ld    %f0,0x100(%r2)
+       ld    %f2,0x110(%r2)
+       ld    %f4,0x120(%r2)
+       ld    %f6,0x130(%r2)
+
+       // floating point preserved registers
+       lfpc  0xf8(%r2)
+       ld    %f8,0x140(%r2)
+       ld    %f9,0x148(%r2)
+       ld    %f10,0x150(%r2)
+       ld    %f11,0x158(%r2)
+       ld    %f12,0x160(%r2)
+       ld    %f13,0x168(%r2)
+       ld    %f14,0x170(%r2)
+       ld    %f15,0x178(%r2)
+
+       // preserved registers and parameters
+       lgr   %r1,%r2
+       lmg   %r2,%r15,0x48(%r1)
+
+       // restore PSW address
+       lg    %r1,0x30(%r1)
+       br    %r1
+
+       .cfi_endproc
+       .size _Us390x_setcontext, . - _Us390x_setcontext
+
+       // We do not need executable stack.
+       .section        .note.GNU-stack,"",@progbits
diff --git a/src/coreclr/src/pal/src/libunwind/src/s390x/unwind_i.h b/src/coreclr/src/pal/src/libunwind/src/s390x/unwind_i.h
new file mode 100644 (file)
index 0000000..6e4b99b
--- /dev/null
@@ -0,0 +1,48 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002, 2005 Hewlett-Packard Co
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+   Modified for s390x by Michael Munday <mike.munday@ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#ifndef unwind_i_h
+#define unwind_i_h
+
+#include <stdint.h>
+
+#include <libunwind-s390x.h>
+
+#include "libunwind_i.h"
+#include <sys/ucontext.h>
+
+#define s390x_lock                     UNW_OBJ(lock)
+#define s390x_local_resume             UNW_OBJ(local_resume)
+#define s390x_local_addr_space_init    UNW_OBJ(local_addr_space_init)
+#define setcontext                     UNW_ARCH_OBJ(setcontext)
+
+extern void s390x_local_addr_space_init (void);
+extern int s390x_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg);
+extern int setcontext (const ucontext_t *ucp);
+
+#endif /* unwind_i_h */
index 0e286f6..dd330ce 100644 (file)
@@ -31,8 +31,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #include "jmpbuf.h"
 #include "setjmp_i.h"
 
-#if !defined(_NSIG) && defined(_SIG_MAXSIG)
-# define _NSIG (_SIG_MAXSIG - 1)
+#if !defined(_NSIG)
+# if defined(_SIG_MAXSIG)
+#  define _NSIG (_SIG_MAXSIG - 1)
+# elif defined(NSIG)
+#  define _NSIG NSIG
+# endif
 #endif
 
 #if defined(__GLIBC__)
@@ -92,7 +96,7 @@ siglongjmp (sigjmp_buf env, int val)
       if (!resume_restores_sigmask (&c, wp) && wp[JB_MASK_SAVED])
         {
           /* sigmask was saved */
-#if defined(__linux__)
+#if defined(__linux__) || defined(__sun)
           if (UNW_NUM_EH_REGS < 4 || _NSIG > 16 * sizeof (unw_word_t))
             /* signal mask doesn't fit into EH arguments and we can't
                put it on the stack without overwriting something
index 52988a7..9fe96d2 100644 (file)
@@ -58,13 +58,6 @@ tdep_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -75,7 +68,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index 99ddb36..4563130 100644 (file)
@@ -37,7 +37,7 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
 #else /* !UNW_REMOTE_ONLY */
 
 static int
-unw_init_local (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr)
+unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr)
 {
   struct cursor *c = (struct cursor *) cursor;
 
index a263c92..5590baf 100644 (file)
@@ -55,7 +55,7 @@ sh_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
         char x[sizeof(regs)];
       };
 
-      asm volatile (
+      __asm__ __volatile__ (
         "mov.l @%0+, r8\n"
         "mov.l @%0+, r9\n"
         "mov.l @%0+, r10\n"
@@ -99,7 +99,7 @@ sh_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
 
       /* Set the SP and the PC in order to continue execution at the modified
          trampoline which restores the signal mask and the registers.  */
-      asm __volatile__ (
+      __asm__ __volatile__ (
         "mov %0, r15\n"
         "lds %1, pr\n"
         "rts\n"
index 7564a55..925e641 100644 (file)
@@ -64,13 +64,6 @@ tdep_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -81,7 +74,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) (intptr_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index 1505c5d..9a65faf 100644 (file)
@@ -7,5 +7,5 @@ Name: libunwind
 Description: libunwind base library
 Version: @VERSION@
 Libs: -L${libdir} -lunwind
-Libs.private: @LIBLZMA@
+Libs.private: @LIBLZMA@ @LIBZ@
 Cflags: -I${includedir}
index f6b8dc2..3cec74a 100644 (file)
@@ -54,13 +54,6 @@ tdep_uc_addr (ucontext_t *uc, int reg)
 
 # endif /* UNW_LOCAL_ONLY */
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -71,7 +64,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
index 0057c62..4056870 100644 (file)
@@ -44,6 +44,7 @@ unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
     case UNW_X86_64_R13: loc = c->dwarf.loc[R13]; break;
     case UNW_X86_64_R14: loc = c->dwarf.loc[R14]; break;
     case UNW_X86_64_R15: loc = c->dwarf.loc[R15]; break;
+    case UNW_X86_64_RIP: loc = c->dwarf.loc[RIP]; break;
 
     default:
       break;
index 8d1fbb4..9a7b195 100644 (file)
@@ -30,7 +30,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #include "dwarf_i.h"
 
 HIDDEN define_lock (x86_64_lock);
-HIDDEN int tdep_init_done;
+#ifdef HAVE_ATOMIC_OPS_H
+    HIDDEN AO_t tdep_init_done;
+#else
+    HIDDEN int tdep_init_done;
+#endif
 
 /* See comments for svr4_dbx_register_map[] in gcc/config/i386/i386.c.  */
 
@@ -77,15 +81,17 @@ HIDDEN void
 tdep_init (void)
 {
   intrmask_t saved_mask;
+  intrmask_t full_mask;
+  sigfillset (&full_mask);
 
-  sigfillset (&unwi_full_mask);
-
-  lock_acquire (&x86_64_lock, saved_mask);
+  SIGPROCMASK (SIG_SETMASK, &full_mask, &saved_mask);
+  mutex_lock (&x86_64_lock);
   {
-    if (tdep_init_done)
+    if (atomic_read(&tdep_init_done))
       /* another thread else beat us to it... */
       goto out;
 
+    sigfillset (&unwi_full_mask);
     mi_init ();
 
     dwarf_init ();
@@ -95,8 +101,9 @@ tdep_init (void)
 #ifndef UNW_REMOTE_ONLY
     x86_64_local_addr_space_init ();
 #endif
-    tdep_init_done = 1; /* signal that we're initialized... */
+    fetch_and_add1(&tdep_init_done); /* signal that we're initialized... */
   }
  out:
-  lock_release (&x86_64_lock, saved_mask);
+  mutex_unlock(&x86_64_lock);
+  SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
 }
index 2a84a1e..fd8d418 100644 (file)
@@ -49,13 +49,6 @@ static struct unw_addr_space local_addr_space;
 
 unw_addr_space_t unw_local_addr_space = &local_addr_space;
 
-HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-
-/* XXX fix me: there is currently no way to locate the dyn-info list
-       by a remote unwinder.  On ia64, this is done via a special
-       unwind-table entry.  Perhaps something similar can be done with
-       DWARF2 unwind info.  */
-
 static void
 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
 {
@@ -66,7 +59,13 @@ static int
 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
                         void *arg)
 {
-  *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
+#ifndef UNW_LOCAL_ONLY
+# pragma weak _U_dyn_info_list_addr
+  if (!_U_dyn_info_list_addr)
+    return -UNW_ENOINFO;
+#endif
+  // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so.
+  *dyn_info_list_addr = _U_dyn_info_list_addr ();
   return 0;
 }
 
@@ -75,14 +74,44 @@ get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
 
 static int mem_validate_pipe[2] = {-1, -1};
 
+#ifdef HAVE_PIPE2
+static inline void
+do_pipe2 (int pipefd[2])
+{
+  pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK);
+}
+#else
+static inline void
+set_pipe_flags (int fd)
+{
+  int fd_flags = fcntl (fd, F_GETFD, 0);
+  int status_flags = fcntl (fd, F_GETFL, 0);
+
+  fd_flags |= FD_CLOEXEC;
+  fcntl (fd, F_SETFD, fd_flags);
+
+  status_flags |= O_NONBLOCK;
+  fcntl (fd, F_SETFL, status_flags);
+}
+
+static inline void
+do_pipe2 (int pipefd[2])
+{
+  pipe (pipefd);
+  set_pipe_flags(pipefd[0]);
+  set_pipe_flags(pipefd[1]);
+}
+#endif
+
 static inline void
 open_pipe (void)
 {
-  /* ignore errors for closing invalid fd's */
-  close (mem_validate_pipe[0]);
-  close (mem_validate_pipe[1]);
+  if (mem_validate_pipe[0] != -1)
+    close (mem_validate_pipe[0]);
+  if (mem_validate_pipe[1] != -1)
+    close (mem_validate_pipe[1]);
 
-  pipe2 (mem_validate_pipe, O_CLOEXEC | O_NONBLOCK);
+  do_pipe2 (mem_validate_pipe);
 }
 
 ALWAYS_INLINE
@@ -131,20 +160,14 @@ static int msync_validate (void *addr, size_t len)
 static int mincore_validate (void *addr, size_t len)
 {
   unsigned char mvec[2]; /* Unaligned access may cross page boundary */
-  size_t i;
 
   /* mincore could fail with EAGAIN but we conservatively return -1
      instead of looping. */
-  if (mincore (addr, len, mvec) != 0)
+  if (mincore (addr, len, (char *)mvec) != 0)
     {
       return -1;
     }
 
-  for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++)
-    {
-      if (!(mvec[i] & 1)) return -1;
-    }
-
   return write_validate (addr);
 }
 #endif
@@ -163,9 +186,9 @@ tdep_init_mem_validate (void)
   unw_word_t addr = PAGE_START((unw_word_t)&present);
   unsigned char mvec[1];
   int ret;
-  while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 &&
+  while ((ret = mincore ((void*)addr, PAGE_SIZE, (char *)mvec)) == -1 &&
          errno == EAGAIN) {}
-  if (ret == 0 && (mvec[0] & 1))
+  if (ret == 0)
     {
       Debug(1, "using mincore to validate memory\n");
       mem_validate_func = mincore_validate;
@@ -180,13 +203,93 @@ tdep_init_mem_validate (void)
 
 /* Cache of already validated addresses */
 #define NLGA 4
-static unw_word_t last_good_addr[NLGA];
-static int lga_victim;
+#if defined(HAVE___THREAD) && HAVE___THREAD
+// thread-local variant
+static __thread unw_word_t last_good_addr[NLGA];
+static __thread int lga_victim;
 
 static int
-validate_mem (unw_word_t addr)
+is_cached_valid_mem(unw_word_t addr)
+{
+  int i;
+  for (i = 0; i < NLGA; i++)
+    {
+      if (addr == last_good_addr[i])
+        return 1;
+    }
+  return 0;
+}
+
+static void
+cache_valid_mem(unw_word_t addr)
+{
+  int i, victim;
+  victim = lga_victim;
+  for (i = 0; i < NLGA; i++) {
+    if (last_good_addr[victim] == 0) {
+      last_good_addr[victim] = addr;
+      return;
+    }
+    victim = (victim + 1) % NLGA;
+  }
+
+  /* All slots full. Evict the victim. */
+  last_good_addr[victim] = addr;
+  victim = (victim + 1) % NLGA;
+  lga_victim = victim;
+}
+
+#elif HAVE_ATOMIC_OPS_H
+// global, thread safe variant
+static AO_T last_good_addr[NLGA];
+static AO_T lga_victim;
+
+static int
+is_cached_valid_mem(unw_word_t addr)
+{
+  int i;
+  for (i = 0; i < NLGA; i++)
+    {
+      if (addr == AO_load(&last_good_addr[i]))
+        return 1;
+    }
+  return 0;
+}
+
+static void
+cache_valid_mem(unw_word_t addr)
 {
   int i, victim;
+  victim = AO_load(&lga_victim);
+  for (i = 0; i < NLGA; i++) {
+    if (AO_compare_and_swap(&last_good_addr[victim], 0, addr)) {
+      return;
+    }
+    victim = (victim + 1) % NLGA;
+  }
+
+  /* All slots full. Evict the victim. */
+  AO_store(&last_good_addr[victim], addr);
+  victim = (victim + 1) % NLGA;
+  AO_store(&lga_victim, victim);
+}
+#else
+// disabled, no cache
+static int
+is_cached_valid_mem(unw_word_t addr UNUSED)
+{
+  return 0;
+}
+
+static void
+cache_valid_mem(unw_word_t addr UNUSED)
+{
+}
+#endif
+
+static int
+validate_mem (unw_word_t addr)
+{
   size_t len;
 
   if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
@@ -199,28 +302,13 @@ validate_mem (unw_word_t addr)
   if (addr == 0)
     return -1;
 
-  for (i = 0; i < NLGA; i++)
-    {
-      if (last_good_addr[i] && (addr == last_good_addr[i]))
-        return 0;
-    }
+  if (is_cached_valid_mem(addr))
+    return 0;
 
   if (mem_validate_func ((void *) addr, len) == -1)
     return -1;
 
-  victim = lga_victim;
-  for (i = 0; i < NLGA; i++) {
-    if (!last_good_addr[victim]) {
-      last_good_addr[victim++] = addr;
-      return 0;
-    }
-    victim = (victim + 1) % NLGA;
-  }
-
-  /* All slots full. Evict the victim. */
-  last_good_addr[victim] = addr;
-  victim = (victim + 1) % NLGA;
-  lga_victim = victim;
+  cache_valid_mem(addr);
 
   return 0;
 }
@@ -334,9 +422,6 @@ x86_64_local_addr_space_init (void)
   local_addr_space.acc.resume = x86_64_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
-
-  memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA);
-  lga_victim = 0;
 }
 
 #endif /* !UNW_REMOTE_ONLY */
index 5eaead0..12a9e3e 100644 (file)
@@ -43,7 +43,7 @@ unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_i
 {
   struct cursor *c = (struct cursor *) cursor;
 
-  if (unlikely (!tdep_init_done))
+  if (unlikely (!atomic_read(&tdep_init_done)))
     tdep_init ();
 
   Debug (1, "(cursor=%p)\n", c);
index efd61d6..f411b23 100644 (file)
@@ -36,7 +36,7 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
 #else /* !UNW_LOCAL_ONLY */
   struct cursor *c = (struct cursor *) cursor;
 
-  if (!tdep_init_done)
+  if (!atomic_read(&tdep_init_done))
     tdep_init ();
 
   Debug (1, "(cursor=%p)\n", c);
diff --git a/src/coreclr/src/pal/src/libunwind/src/x86_64/Gos-solaris.c b/src/coreclr/src/pal/src/libunwind/src/x86_64/Gos-solaris.c
new file mode 100644 (file)
index 0000000..75258d6
--- /dev/null
@@ -0,0 +1,133 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002-2003 Hewlett-Packard Co
+       Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+#include "ucontext_i.h"
+
+#include <sys/syscall.h>
+
+struct sigframe {
+       uint64_t        signo;
+       uint64_t        sip;
+};
+
+int
+unw_is_signal_frame (unw_cursor_t *cursor)
+{
+  struct cursor *c = (struct cursor *) cursor;
+
+  c->sigcontext_format = (c->dwarf.ip == (unw_word_t)-1) ?
+    X86_64_SCF_SOLARIS_SIGFRAME : X86_64_SCF_NONE;
+
+  return (c->sigcontext_format);
+}
+
+HIDDEN int
+x86_64_handle_signal_frame (unw_cursor_t *cursor)
+{
+  struct cursor *c = (struct cursor *) cursor;
+  unw_word_t ucontext = c->dwarf.cfa + sizeof (struct sigframe);
+
+  if (c->sigcontext_format != X86_64_SCF_SOLARIS_SIGFRAME)
+    return -UNW_EBADFRAME;
+
+  c->sigcontext_addr = c->dwarf.cfa;
+
+  Debug(1, "signal frame cfa = %lx ucontext = %lx\n",
+    (uint64_t)c->dwarf.cfa, (uint64_t)ucontext);
+
+  struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
+  int ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
+
+  if (ret < 0)
+    {
+      Debug (2, "return %d\n", ret);
+      return ret;
+    }
+
+    c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
+    c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
+    c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
+    c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
+    c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
+    c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
+    c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
+    c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
+    c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
+    c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
+    c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
+    c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
+    c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
+    c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
+    c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
+    c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
+    c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
+
+    c->dwarf.use_prev_instr = 1;
+    return 0;
+}
+
+#ifndef UNW_REMOTE_ONLY
+HIDDEN void *
+x86_64_r_uc_addr (ucontext_t *uc, int reg)
+{
+  /* NOTE: common_init() in init.h inlines these for fast path access. */
+  void *addr;
+
+  switch (reg)
+    {
+    case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break;
+    case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break;
+    case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break;
+    case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break;
+    case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break;
+    case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break;
+    case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break;
+    case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break;
+    case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break;
+    case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break;
+    case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break;
+    case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break;
+    case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break;
+    case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break;
+    case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break;
+    case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break;
+    case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break;
+
+    default:
+      addr = NULL;
+    }
+  return addr;
+}
+
+HIDDEN NORETURN void
+x86_64_sigreturn (unw_cursor_t *cursor)
+{
+  abort();
+}
+
+#endif
index 2c7bc31..2a44f87 100644 (file)
@@ -110,10 +110,10 @@ tdep_stash_frame (struct dwarf_cursor *d, struct dwarf_reg_state *rs)
   }
 
   else if (f->frame_type == UNW_X86_64_FRAME_ALIGNED) {
-    Debug (4, " aligned frame, offset %li\n", f->cfa_reg_offset);
+    Debug (4, " aligned frame, offset %i\n", f->cfa_reg_offset);
   }
-
   /* PLT and guessed RBP-walked frames are handled in unw_step(). */
-  else
+  else {
     Debug (4, " unusual frame\n");
+  }
 }
index 1049817..d483119 100644 (file)
@@ -104,6 +104,7 @@ unw_step (unw_cursor_t *cursor)
               via CALLQ.  Try this for all non-signal trampoline
               code.  */
 
+      unw_word_t invalid_prev_rip = 0;
       unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
       struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
 
@@ -149,7 +150,10 @@ unw_step (unw_cursor_t *cursor)
               return ret;
             }
 
-          if (!rbp)
+          unw_word_t not_used;
+          invalid_prev_rip = dwarf_get(&c->dwarf, DWARF_MEM_LOC(c->dwarf, prev_ip), &not_used);
+
+          if (!rbp && invalid_prev_rip == 0)
             {
               /* Looks like we may have reached the end of the call-chain.  */
               rbp_loc = DWARF_NULL_LOC;
@@ -158,38 +162,90 @@ unw_step (unw_cursor_t *cursor)
             }
           else
             {
-              unw_word_t rbp1 = 0;
-              rbp_loc = DWARF_LOC(rbp, 0);
-              rsp_loc = DWARF_NULL_LOC;
-              rip_loc = DWARF_LOC (rbp + 8, 0);
-              ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
-              Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n",
-                     (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
-                     rbp, c->dwarf.cfa, rbp1);
-
-              /* Heuristic to determine incorrect guess.  For RBP to be a
-                 valid frame it needs to be above current CFA, but don't
-                 let it go more than a little.  Note that we can't deduce
-                 anything about new RBP (rbp1) since it may not be a frame
-                 pointer in the frame above.  Just check we get the value. */
-              if (ret < 0
-                  || rbp < c->dwarf.cfa
-                  || (rbp - c->dwarf.cfa) > 0x4000)
+              /*
+               * Check if previous RIP was invalid
+               * This could happen if a bad function pointer was
+               * followed and so the stack wasn't updated by the
+               * preamble
+               */
+              int rip_fixup_success = 0;
+              if (invalid_prev_rip != 0)
                 {
-                  rip_loc = DWARF_NULL_LOC;
-                  rbp_loc = DWARF_NULL_LOC;
-                }
+                    Debug (2, "Previous RIP 0x%lx was invalid, attempting fixup\n", prev_ip);
+                    unw_word_t rsp;
+                    ret = dwarf_get (&c->dwarf, c->dwarf.loc[RSP], &rsp);
 
-              c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
-              c->frame_info.cfa_reg_rsp = 0;
-              c->frame_info.cfa_reg_offset = 16;
-              c->frame_info.rbp_cfa_offset = -16;
-              c->dwarf.cfa += 16;
-            }
+                    /*Test to see if what we think is the previous RIP is valid*/
+                    unw_word_t new_ip = 0;
+                    if (dwarf_get(&c->dwarf, DWARF_MEM_LOC(c->dwarf, rsp), &new_ip) == 0)
+                      {
+                        Debug (2, "RSP 0x%lx looks valid\n", rsp);
+                        if ((ret = dwarf_get(&c->dwarf, DWARF_MEM_LOC(c->dwarf, new_ip), &not_used)) == 0)
+                          {
+                            Debug (2, "new_ip 0x%lx looks valid\n", new_ip);
+                            rip_fixup_success = 1;
+                            c->frame_info.cfa_reg_offset = 8;
+                            c->frame_info.cfa_reg_rsp = 1;
+                            c->frame_info.rbp_cfa_offset = -1;
+                            c->frame_info.rsp_cfa_offset = -1;
+                            c->frame_info.frame_type = UNW_X86_64_FRAME_OTHER;
+                            /*
+                             * The call should have pushed RIP to the stack
+                             * and since there was no preamble RSP hasn't been
+                             * touched so RIP should be at RSP.
+                             */
+                            c->dwarf.cfa += 8;
+                            /* Optimised x64 binaries don't use RBP it seems? */
+                            rbp_loc = DWARF_LOC (rbp, 0);
+                            rsp_loc = DWARF_LOC (rsp, 0);
+                            rip_loc = DWARF_LOC (rsp, 0);
+                          }
+                        else
+                          Debug (2, "new_ip 0x%lx dwarf_get(&c->dwarf, DWARF_MEM_LOC(c->dwarf, new_ip), &not_used) != 0\n", new_ip);
+                      }
+                               else
+                        Debug (2, "rsp 0x%lx dwarf_get(&c->dwarf, DWARF_MEM_LOC(c->dwarf, rsp), &new_ip) != 0\n", rsp);
+                  }
+              /*
+               * If the previous rip we found on the stack didn't look valid fall back
+               * to the previous method for finding a valid stack frame
+               */
+              if (!rip_fixup_success)
+                {
+                  Debug (2, "RIP fixup didn't work, falling back\n");
+                  unw_word_t rbp1 = 0;
+                  rbp_loc = DWARF_LOC(rbp, 0);
+                  rsp_loc = DWARF_NULL_LOC;
+                  rip_loc = DWARF_LOC (rbp + 8, 0);
+                  ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
+                  Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n",
+                         (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
+                         rbp, c->dwarf.cfa, rbp1);
+
+                  /* Heuristic to determine incorrect guess.  For RBP to be a
+                     valid frame it needs to be above current CFA, but don't
+                     let it go more than a little.  Note that we can't deduce
+                     anything about new RBP (rbp1) since it may not be a frame
+                     pointer in the frame above.  Just check we get the value. */
+                  if (ret < 0
+                      || rbp < c->dwarf.cfa
+                      || (rbp - c->dwarf.cfa) > 0x4000)
+                    {
+                      rip_loc = DWARF_NULL_LOC;
+                      rbp_loc = DWARF_NULL_LOC;
+                    }
 
+                  c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+                  c->frame_info.cfa_reg_rsp = 0;
+                  c->frame_info.cfa_reg_offset = 16;
+                  c->frame_info.rbp_cfa_offset = -16;
+                  c->dwarf.cfa += 16;
+
+                }
+            }
           /* Mark all registers unsaved */
           for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
-            c->dwarf.loc[i] = DWARF_NULL_LOC;
+          c->dwarf.loc[i] = DWARF_NULL_LOC;
 
           c->dwarf.loc[RBP] = rbp_loc;
           c->dwarf.loc[RSP] = rsp_loc;
@@ -197,7 +253,7 @@ unw_step (unw_cursor_t *cursor)
           c->dwarf.use_prev_instr = 1;
         }
 
-      if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
+      if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]) && invalid_prev_rip == 0)
         {
           ret = 0;
           Debug (2, "NULL %%rbp loc, returning %d\n", ret);
@@ -214,6 +270,13 @@ unw_step (unw_cursor_t *cursor)
               Debug (2, "returning %d\n", ret);
               return ret;
             }
+#if __sun
+          if (c->dwarf.ip == 0)
+            {
+              Debug (2, "returning 0\n");
+              return ret;
+            }
+#endif
           ret = 1;
         }
       else
index 7412271..824527f 100644 (file)
@@ -540,7 +540,7 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
       break;
 
     /* Record this address in stack trace. We skipped the first address. */
-    buffer[depth++] = (void *) (rip - d->use_prev_instr);
+    buffer[depth++] = (void *) rip;
   }
 
 #if UNW_DEBUG
diff --git a/src/coreclr/src/pal/src/libunwind/src/x86_64/Los-solaris.c b/src/coreclr/src/pal/src/libunwind/src/x86_64/Los-solaris.c
new file mode 100644 (file)
index 0000000..be64b2c
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gos-solaris.c"
+#endif
index 7a8b566..e145071 100644 (file)
@@ -57,11 +57,13 @@ _Ux86_64_getcontext:
        movq %rax, UC_MCONTEXT_GREGS_RAX(%rdi)
        movq %rcx, UC_MCONTEXT_GREGS_RCX(%rdi)
 
-#if defined __linux__
+#if defined __linux__ || defined __sun
        /* Save fp state (not needed, except for setcontext not
           restoring garbage).  */
        leaq UC_MCONTEXT_FPREGS_MEM(%rdi),%r8
+#ifdef UC_MCONTEXT_FPREGS_PTR
        movq %r8, UC_MCONTEXT_FPREGS_PTR(%rdi)
+#endif // UC_MCONTEXT_FPREGS_PTR
        fnstenv (%r8)
        stmxcsr FPREGS_OFFSET_MXCSR(%r8)
 #elif defined __FreeBSD__
index 358217d..17e5ae1 100644 (file)
@@ -37,9 +37,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
 _Ux86_64_setcontext:
 
-#if defined __linux__
+#if defined __linux__ || defined __sun
         /* restore fp state */
+#ifdef UC_MCONTEXT_FPREGS_PTR
        mov    UC_MCONTEXT_FPREGS_PTR(%rdi),%r8
+#else // UC_MCONTEXT_FPREGS_PTR
+       leaq UC_MCONTEXT_FPREGS_MEM(%rdi),%r8
+#endif // UC_MCONTEXT_FPREGS_PTR
        fldenv (%r8)
        ldmxcsr FPREGS_OFFSET_MXCSR(%r8)
 #elif defined __FreeBSD__
index aded941..e886c94 100644 (file)
@@ -78,5 +78,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #define UC_MCONTEXT_FPOWNED_FPU 0x20001
 #define UC_MCONTEXT_FPFMT_XMM   0x10002
 #define UC_MCONTEXT_MC_LEN_VAL  0x320
+#elif defined __sun
+#define UC_MCONTEXT_GREGS_R8   0x78
+#define UC_MCONTEXT_GREGS_R9   0x70
+#define UC_MCONTEXT_GREGS_R10  0x68
+#define UC_MCONTEXT_GREGS_R11  0x60
+#define UC_MCONTEXT_GREGS_R12  0x58
+#define UC_MCONTEXT_GREGS_R13  0x50
+#define UC_MCONTEXT_GREGS_R14  0x48
+#define UC_MCONTEXT_GREGS_R15  0x40
+#define UC_MCONTEXT_GREGS_RDI  0x80
+#define UC_MCONTEXT_GREGS_RSI  0x88
+#define UC_MCONTEXT_GREGS_RBP  0x90
+#define UC_MCONTEXT_GREGS_RBX  0x98
+#define UC_MCONTEXT_GREGS_RDX  0xa0
+#define UC_MCONTEXT_GREGS_RAX  0xb0
+#define UC_MCONTEXT_GREGS_RCX  0xa8
+#define UC_MCONTEXT_GREGS_RSP  0xe0
+#define UC_MCONTEXT_GREGS_RIP  0xc8
+#define UC_MCONTEXT_FPREGS_MEM 0x120
+#define FPREGS_OFFSET_MXCSR    0x18
 
 #endif
index beae2a3..d5b4844 100644 (file)
@@ -176,7 +176,7 @@ sighandler (int signal, void *siginfo UNUSED, void *context)
     {
       printf ("sighandler: got signal %d, sp=%p", signal, &sp);
 #if UNW_TARGET_IA64
-# if defined(__linux__)
+# if defined(__linux__) || defined __sun
       printf (" @ %lx", uc->uc_mcontext.sc_ip);
 # else
       {
@@ -189,13 +189,13 @@ sighandler (int signal, void *siginfo UNUSED, void *context)
       }
 # endif
 #elif UNW_TARGET_X86
-#if defined __linux__
+#if defined __linux__ || defined __sun
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
 #elif defined __FreeBSD__
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
 #endif
 #elif UNW_TARGET_X86_64
-#if defined __linux__
+#if defined __linux__ || defined __sun
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
 #elif defined __FreeBSD__
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
index fc1f646..48667bb 100644 (file)
@@ -207,7 +207,7 @@ sighandler (int signal, void *siginfo UNUSED, void *context)
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
 #endif
 #elif UNW_TARGET_X86_64
-#if defined __linux__
+#if defined __linux__ || defined __sun
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
 #elif defined __FreeBSD__
       printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
diff --git a/src/coreclr/src/pal/src/libunwind/tests/Gx64-test-dwarf-expressions.c b/src/coreclr/src/pal/src/libunwind/tests/Gx64-test-dwarf-expressions.c
new file mode 100644 (file)
index 0000000..209f871
--- /dev/null
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+
+static int verbose;
+static int nerrors;
+
+#define panic(args...)                                                   \
+       do { printf (args); ++nerrors; } while (0)
+
+// Assembly routine which sets up the stack for the test then calls another one
+// which clobbers the stack, and which in turn calls recover_register below
+extern int64_t DW_CFA_expression_testcase(int64_t regnum, int64_t height);
+
+// recover_register is called by the assembly routines. It returns the value of
+// a register at a specified height from the inner-most frame. The return value
+// is propagated back through the assembly routines to the testcase.
+extern int64_t recover_register(int64_t regnum, int64_t height)
+{
+  // Initialize cursor to current frame
+  int rc, i;
+  unw_cursor_t cursor;
+  unw_context_t context;
+  unw_getcontext(&context);
+  unw_init_local(&cursor, &context);
+  // Unwind frames until required height from inner-most frame (i.e. this one)
+  for (i = 0; i < height; ++i)
+    {
+      rc = unw_step(&cursor);
+      if (rc < 0)
+        panic("%s: unw_step failed on step %d with return code %d", __FUNCTION__, i, rc);
+      else if (rc == 0)
+        panic("%s: unw_step failed to reach the end of the stack", __FUNCTION__);
+      unw_word_t pc;
+      rc = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+      if (rc < 0 || pc == 0)
+        panic("%s: unw_get_reg failed to locate the program counter", __FUNCTION__);
+    }
+  // We're now at the required height, extract register
+  uint64_t value;
+  if ((rc = unw_get_reg(&cursor, (unw_regnum_t) regnum, &value)) != 0)
+    panic("%s: unw_get_reg failed to retrieve register %lu", __FUNCTION__, regnum);
+  return value;
+}
+
+int
+main (int argc, char **argv)
+{
+  if (argc > 1)
+    verbose = 1;
+
+  if (DW_CFA_expression_testcase(12, 1) != 0)
+    panic("r12 should be clobbered at height 1 (DW_CFA_expression_inner)");
+  if (DW_CFA_expression_testcase(12, 2) != 111222333)
+    panic("r12 should be restored at height 2 (DW_CFA_expression_testcase)");
+
+  if (nerrors > 0)
+    {
+      fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
+      exit (-1);
+    }
+
+  if (verbose)
+    printf ("SUCCESS.\n");
+  return 0;
+}
index 1cacb9f..e5127b9 100644 (file)
@@ -35,6 +35,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
 #include <sys/resource.h>
 #include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #define panic(args...)                         \
        { fprintf (stderr, args); exit (-1); }
diff --git a/src/coreclr/src/pal/src/libunwind/tests/Lx64-test-dwarf-expressions.c b/src/coreclr/src/pal/src/libunwind/tests/Lx64-test-dwarf-expressions.c
new file mode 100644 (file)
index 0000000..07e916e
--- /dev/null
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if !defined(UNW_REMOTE_ONLY)
+#include "Gx64-test-dwarf-expressions.c"
+#endif
index 4b0b9db..61d1bf8 100644 (file)
@@ -37,7 +37,11 @@ if ARCH_PPC64
 if USE_ALTIVEC
  noinst_PROGRAMS_arch += ppc64-test-altivec
 endif #USE_ALTIVEC
-endif #ARCH_PPC64
+else  #!ARCH_PPC64
+if ARCH_X86_64
+ check_PROGRAMS_arch +=        Gx64-test-dwarf-expressions Lx64-test-dwarf-expressions x64-unwind-badjmp-signal-frame
+endif #ARCH X86_64
+endif #!ARCH_PPC64
 endif #!ARCH_IA64
  check_PROGRAMS_cdep +=        Gtest-bt Ltest-bt Gtest-exc Ltest-exc            \
                        Gtest-init Ltest-init                            \
@@ -139,12 +143,21 @@ Gia64_test_nat_SOURCES = Gia64-test-nat.c ia64-test-nat-asm.S
 ia64_test_dyn1_SOURCES = ia64-test-dyn1.c ia64-dyn-asm.S flush-cache.S \
                                flush-cache.h
 ppc64_test_altivec_SOURCES = ppc64-test-altivec.c  ppc64-test-altivec-utils.c
+
+
+Gx64_test_dwarf_expressions_SOURCES =  Gx64-test-dwarf-expressions.c \
+                                                                                                                                                        x64-test-dwarf-expressions.S
+Lx64_test_dwarf_expressions_SOURCES =  Lx64-test-dwarf-expressions.c \
+                                                                                                                                                        x64-test-dwarf-expressions.S
+
+
 Gtest_init_SOURCES = Gtest-init.cxx
 Ltest_init_SOURCES = Ltest-init.cxx
 Ltest_cxx_exceptions_SOURCES = Ltest-cxx-exceptions.cxx
 
 Ltest_init_local_signal_SOURCES = Ltest-init-local-signal.c Ltest-init-local-signal-lib.c
 
+x64_unwind_badjmp_signal_frame_SOURCES = x64-unwind-badjmp-signal-frame.c
 Gtest_dyn1_SOURCES = Gtest-dyn1.c flush-cache.S flush-cache.h
 Ltest_dyn1_SOURCES = Ltest-dyn1.c flush-cache.S flush-cache.h
 test_static_link_SOURCES = test-static-link-loc.c test-static-link-gen.c
@@ -191,6 +204,7 @@ Ltest_init_local_signal_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
 
 Gtest_bt_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
 Gtest_concurrent_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) -lpthread
+x64_unwind_badjmp_signal_frame_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
 Gtest_dyn1_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
 Gtest_exc_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
 Gtest_init_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) @BACKTRACELIB@
@@ -232,3 +246,6 @@ Lia64_test_readonly_LDADD = $(LIBUNWIND_local)
 ia64_test_dyn1_LDADD = $(LIBUNWIND)
 ia64_test_sig_LDADD = $(LIBUNWIND)
 ppc64_test_altivec_LDADD = $(LIBUNWIND)
+
+Gx64_test_dwarf_expressions_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
+Lx64_test_dwarf_expressions_LDADD = $(LIBUNWIND_local)
index 6d00817..f43bca2 100644 (file)
@@ -85,6 +85,11 @@ filter_misc () {
        ignore _ftext
        ignore _gp
     fi
+
+    if [ ${os} == "solaris2.11" ]; then
+        ignore _PROCEDURE_LINKAGE_TABLE_
+        ignore _etext
+    fi
 }
 
 check_local_unw_abi () {
@@ -121,7 +126,7 @@ check_local_unw_abi () {
     match _U_dyn_register
 
     match unw_backtrace
-    match backtrace
+    @CONFIG_WEAK_BACKTRACE_TRUE@match backtrace
 
     case ${plat} in
        arm)
@@ -176,6 +181,14 @@ check_local_unw_abi () {
            match _U${plat}_get_exe_image_path
             match ${plat}_lock
             ;;
+       s390x)
+           match _U${plat}_get_elf_image
+           match _U${plat}_get_exe_image_path
+           match _U${plat}_is_fpreg
+           match _UL${plat}_dwarf_search_unwind_table
+           match _UL${plat}_dwarf_find_unwind_table
+           match _U${plat}_setcontext
+           ;;
 
        *)
            match _U${plat}_is_fpreg
@@ -276,6 +289,13 @@ check_generic_unw_abi () {
             match _U${plat}_local_addr_space_init
             match ${plat}_lock
             ;;
+       s390x)
+           match _U${plat}_is_fpreg
+           match _U${plat}_get_elf_image
+           match _U${plat}_get_exe_image_path
+           match _U${plat}_dwarf_search_unwind_table
+           match _U${plat}_dwarf_find_unwind_table
+           ;;
        *)
            match _U${plat}_is_fpreg
            match _U${plat}_dwarf_search_unwind_table
index 24c7805..bb99e33 100644 (file)
@@ -87,8 +87,13 @@ write_maps(char *fname)
 #endif
 
 #ifdef __GNUC__
+#ifndef __clang__
+// Gcc >= 8 became too good at inlining aliase c into b when using -O2 or -O3,
+// so force -O1 in all cases, otherwise a frame will be missing in the tests.
+#pragma GCC optimize "-O1"
+#endif
 int c(int x) NOINLINE ALIAS(b);
-#define compiler_barrier() asm volatile("");
+#define compiler_barrier() __asm__ __volatile__ ("");
 #else
 int c(int x);
 #define compiler_barrier()
index 5349823..fb06a38 100644 (file)
 #include <grp.h>
 
 /* For SIGSEGV handler code */
-#include <execinfo.h>
+#if HAVE_EXECINFO_H
+# include <execinfo.h>
+#else
+  extern int backtrace (void **, int);
+#endif
 #include <sys/ucontext.h>
 
 #include <libunwind-coredump.h>
@@ -242,7 +246,7 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
     void *array[50];
     int size;
     size = backtrace(array, 50);
-#ifdef __linux__
+#if defined __linux__ && HAVE_EXECINFO_H
     backtrace_symbols_fd(array, size, 2);
 #endif
   }
diff --git a/src/coreclr/src/pal/src/libunwind/tests/x64-test-dwarf-expressions.S b/src/coreclr/src/pal/src/libunwind/tests/x64-test-dwarf-expressions.S
new file mode 100644 (file)
index 0000000..f275625
--- /dev/null
@@ -0,0 +1,78 @@
+.global DW_CFA_expression_testcase
+
+.extern recover_register
+
+.text
+
+# CFI expressions were added in DWARF v3 to allow compilers to specify memory
+# locations or register values using DWARF programs. These programs are simple
+# stack-based operations which allow the compiler to encode integer mathematics
+# and other complex logic. CFI expressions are therefore more powerful than the
+# conventional register + offset schemes.
+#
+# These tests capture a bug we have fixed in libunwind. CFI expression programs
+# always start with the current CFA pushed onto the stack. This file contains a
+# pair of routines which test CFI expression parsing. Specifically they test
+# DW_CFA_expression logic, which uses DWARF expressions to compute the address
+# where a non-volatile register was stored.
+#
+# Main calls DW_CFA_expression_testcase, which sets up known state in a
+# non-volatile (caller-saved) register. We use r12 for this purpose. After this
+# DW_CFA_expression_testcase then calls DW_CFA_expression_inner, which clobbers
+# r12 after stashing its value on the stack. This routine contains a DWARF3 CFI
+# expression to restore the value of r12 on unwind which should allow libunwind
+# to recover clobbered state. DW_CFA_expression_inner calls recover_register to
+# retrieve the cached register value. This function recovers the register value
+# by using libunwind to unwind the stack through DW_CFA_expression_inner and up
+# to the call site in DW_CFA_expression_testcase. If our expression is correct,
+# libunwind will be able to restore r12 from the stack.
+#
+# BE CAREFUL WITH rdi, rsi, rax HERE! The arguments to recover_register are
+# passed in via rdi, rsi and I just let them flow through unchanged. Similarly
+# RAX flows back unchanged. Adding any function calls to the below may clobber
+# these registers and cause this test to fail mysteriously.
+
+
+########################################################
+# Test: Restoring a register using a DW_CFA_expression #
+# which uses implicit CFA pushed onto stack.           #
+########################################################
+
+.type DW_CFA_expression_testcase STT_FUNC
+DW_CFA_expression_testcase:
+  .cfi_startproc
+  push %r12
+  .cfi_adjust_cfa_offset 8
+  # Move our sentinel (known) value into non-volatile (Callee-saved) r12
+  mov $111222333, %r12
+  .cfi_rel_offset %r12, 0
+  call DW_CFA_expression_inner
+  pop %r12
+  .cfi_restore %r12
+  .cfi_adjust_cfa_offset -8
+  ret
+  .cfi_endproc
+.size DW_CFA_expression_testcase,.-DW_CFA_expression_testcase
+
+.type DW_CFA_expression_inner STT_FUNC
+DW_CFA_expression_inner:
+  .cfi_startproc
+  push %r12
+  .cfi_adjust_cfa_offset 8
+  # !! IMPORTANT BIT !! The test is all about how we parse the following bytes.
+  # Now we use an expression to describe where our sentinel value is stored:
+  # DW_CFA_expression(0x10), r12(0x0c), Length(0x02),        (preamble)
+  # DW_OP_lit16(0x40), DW_OP_minus(0x1c)                     (instructions)
+  # Parsing starts with the CFA on the stack, then pushes 16, then does a minus
+  # which is eqivalent to a=pop(), b=pop(), push(b-a), leaving us with a value
+  # of cfa-16 (cfa points at old rsp, cfa-8 is our rip, so we stored r12 at
+  # cfa-16).
+  xor %r12, %r12                             # Trash r12
+  .cfi_escape 0x10, 0x0c, 0x2, 0x40, 0x1c   # DW_CFA_expression for recovery
+  call recover_register
+  pop %r12
+  .cfi_restore %r12
+  .cfi_adjust_cfa_offset -8
+  ret
+  .cfi_endproc
+.size DW_CFA_expression_inner,.-DW_CFA_expression_inner
diff --git a/src/coreclr/src/pal/src/libunwind/tests/x64-unwind-badjmp-signal-frame.c b/src/coreclr/src/pal/src/libunwind/tests/x64-unwind-badjmp-signal-frame.c
new file mode 100644 (file)
index 0000000..c7b7cf7
--- /dev/null
@@ -0,0 +1,124 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2019 Brock York <twunknown AT gmail.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <execinfo.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+/*
+ * unwind in the signal handler checking the backtrace is correct
+ * after a bad jump.
+ */
+void handle_sigsegv(int signal, siginfo_t *info, void *ucontext)
+{
+  /*
+   * 0 = success
+   * !0 = general failure
+   * 77 = test skipped
+   * 99 = complete failure
+   */
+  int test_status = 0;
+  unw_cursor_t cursor; unw_context_t uc;
+  unw_word_t ip, sp, offset;
+  char name[1000];
+  int found_signal_frame = 0;
+  int i = 0;
+  char *names[] = {
+    "",
+    "main",
+  };
+  int names_count = sizeof(names) / sizeof(*names);
+
+  unw_getcontext(&uc);
+  unw_init_local(&cursor, &uc);
+
+  while (unw_step(&cursor) > 0 && !test_status)
+    {
+      if (unw_is_signal_frame(&cursor))
+        {
+          found_signal_frame = 1;
+        }
+      if (found_signal_frame)
+        {
+          unw_get_reg(&cursor, UNW_REG_IP, &ip);
+          unw_get_reg(&cursor, UNW_REG_SP, &sp);
+          memset(name, 0, sizeof(char) * 1000);
+          unw_get_proc_name(&cursor, name, sizeof(char) * 1000, &offset);
+          printf("ip = %lx, sp = %lx offset = %lx name = %s\n", (long) ip, (long) sp, (long) offset, name);
+          if (i < names_count)
+            {
+              if (strcmp(names[i], name) != 0)
+                {
+                  test_status = 1;
+                  printf("frame %s doesn't match expected frame %s\n", name, names[i]);
+                }
+              else
+                {
+                  i += 1;
+                }
+            }
+        }
+    }
+
+  if (i != names_count) //Make sure we found all the frames!
+    {
+      printf("Failed to find all frames i:%d != names_count:%d\n", i, names_count);
+      test_status = 1;
+    }
+
+  /*return test_status to test harness*/
+  exit(test_status);
+}
+
+void (*invalid_function)() = (void*)1;
+
+int main(int argc, char *argv[])
+{
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_sigaction = handle_sigsegv;
+  sa.sa_flags = SA_SIGINFO;
+  sigaction(SIGSEGV, &sa, NULL);
+
+  invalid_function();
+
+  /*
+   * 99 is the hard error exit status for automake tests:
+   * https://www.gnu.org/software/automake/manual/html_node/Scripts_002dbased-Testsuites.html#Scripts_002dbased-Testsuites
+   * If we dont end up in the signal handler something went horribly wrong.
+   */
+  return 99;
+}