From 74e6d0169f8749c03b0938b98a6115bbbccb234c Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 15 Dec 2021 18:02:20 +0200 Subject: [PATCH] Update libunwind to v1.6.2 (#62092) * Update libunwind to v1.6.2 * Apply libunwind changes from 1b5719c Co-authored-by: Jan Vorlicek * Suppress Wincompatible-pointer-types on arm64 * Fix remote unwinding on win-arm64 * Mark base as both input and output Co-authored-by: Jan Vorlicek Co-authored-by: Jan Vorlicek Co-authored-by: Jan Vorlicek --- src/coreclr/pal/src/libunwind/.travis.yml | 71 ++- src/coreclr/pal/src/libunwind/CMakeLists.txt | 2 + src/coreclr/pal/src/libunwind/ChangeLog | 52 +- src/coreclr/pal/src/libunwind/Makefile.am | 10 +- src/coreclr/pal/src/libunwind/README | 10 +- src/coreclr/pal/src/libunwind/README.md | 2 +- src/coreclr/pal/src/libunwind/autogen.sh | 9 - src/coreclr/pal/src/libunwind/configure.ac | 39 +- src/coreclr/pal/src/libunwind/include/dwarf.h | 5 + .../pal/src/libunwind/include/dwarf_i.h | 2 +- .../src/libunwind/include/libunwind-aarch64.h | 29 +- .../pal/src/libunwind/include/libunwind-arm.h | 55 ++- .../src/libunwind/include/libunwind-dynamic.h | 1 + .../src/libunwind/include/libunwind-mips.h | 2 +- .../src/libunwind/include/libunwind-ppc64.h | 2 +- .../src/libunwind/include/libunwind-ptrace.h | 1 + .../src/libunwind/include/libunwind-riscv.h | 187 ++++++++ .../pal/src/libunwind/include/libunwind.h.in | 2 + .../pal/src/libunwind/include/libunwind_i.h | 82 +++- .../pal/src/libunwind/include/remote.h | 6 +- .../include/tdep-aarch64/libunwind_i.h | 14 +- .../libunwind/include/tdep-arm/libunwind_i.h | 1 + .../include/tdep-riscv/dwarf-config.h | 50 ++ .../src/libunwind/include/tdep-riscv/jmpbuf.h | 49 ++ .../include/tdep-riscv/libunwind_i.h | 303 ++++++++++++ .../include/tdep-x86_64/libunwind_i.h | 38 +- .../src/libunwind/include/tdep/dwarf-config.h | 2 + .../pal/src/libunwind/include/tdep/jmpbuf.h | 2 + .../libunwind/include/tdep/libunwind_i.h.in | 2 + .../pal/src/libunwind/include/win/sys/mman.h | 1 + .../pal/src/libunwind/include/win/sys/stat.h | 35 ++ .../pal/src/libunwind/libunwind-version.txt | 12 +- src/coreclr/pal/src/libunwind/src/Makefile.am | 43 +- .../src/aarch64/Gcreate_addr_space.c | 5 +- .../pal/src/libunwind/src/aarch64/Gglobal.c | 2 + .../pal/src/libunwind/src/aarch64/Ginit.c | 250 +++++++++- .../src/libunwind/src/aarch64/Ginit_local.c | 4 +- .../src/libunwind/src/aarch64/Ginit_remote.c | 11 +- .../pal/src/libunwind/src/aarch64/Gresume.c | 2 +- .../pal/src/libunwind/src/aarch64/Gstep.c | 20 +- .../libunwind/src/arm/Gcreate_addr_space.c | 5 +- .../pal/src/libunwind/src/arm/Gex_tables.c | 2 +- .../pal/src/libunwind/src/arm/Gglobal.c | 5 + .../pal/src/libunwind/src/arm/Gresume.c | 2 +- .../src/coredump/_UCD_access_reg_linux.c | 8 + .../src/coredump/_UCD_corefile_elf.c | 126 +++++ .../src/libunwind/src/coredump/_UCD_create.c | 183 ++----- .../src/coredump/_UCD_elf_map_image.c | 6 +- .../src/coredump/_UCD_find_proc_info.c | 8 +- .../src/coredump/_UCD_get_mapinfo_generic.c | 34 ++ .../src/coredump/_UCD_get_mapinfo_linux.c | 134 ++++++ .../src/coredump/_UCD_get_proc_name.c | 4 +- .../coredump/_UCD_get_threadinfo_prstatus.c | 121 +++++ .../libunwind/src/coredump/_UCD_internal.h | 16 +- .../coredump/_UPT_get_dyn_info_list_addr.c | 15 +- .../pal/src/libunwind/src/dl-iterate-phdr.c | 95 ++++ .../libunwind/src/dwarf/Gfind_proc_info-lsb.c | 87 +++- .../libunwind/src/dwarf/Gfind_unwind_table.c | 1 + src/coreclr/pal/src/libunwind/src/elf32.h | 4 +- src/coreclr/pal/src/libunwind/src/elf64.h | 4 +- src/coreclr/pal/src/libunwind/src/elfxx.c | 9 +- src/coreclr/pal/src/libunwind/src/elfxx.h | 4 +- .../libunwind/src/hppa/Gcreate_addr_space.c | 2 +- .../pal/src/libunwind/src/hppa/Gresume.c | 6 +- .../libunwind/src/ia64/Gcreate_addr_space.c | 8 +- .../pal/src/libunwind/src/ia64/Ginit.c | 8 +- .../pal/src/libunwind/src/ia64/Ginit_local.c | 4 +- .../pal/src/libunwind/src/ia64/Gregs.c | 2 +- .../pal/src/libunwind/src/ia64/Gresume.c | 6 +- .../pal/src/libunwind/src/ia64/Gstep.c | 4 +- .../src/libunwind/src/ia64/dyn_info_list.S | 2 +- .../pal/src/libunwind/src/ia64/unwind_i.h | 2 +- .../libunwind/src/mips/Gcreate_addr_space.c | 8 +- .../pal/src/libunwind/src/mips/Ginit.c | 2 +- .../pal/src/libunwind/src/mips/Gstep.c | 7 +- src/coreclr/pal/src/libunwind/src/os-linux.c | 36 +- src/coreclr/pal/src/libunwind/src/os-linux.h | 19 +- .../pal/src/libunwind/src/os-solaris.c | 2 +- .../libunwind/src/ppc32/Gcreate_addr_space.c | 2 +- .../pal/src/libunwind/src/ppc32/Gresume.c | 2 - .../pal/src/libunwind/src/ppc32/unwind_i.h | 2 +- .../libunwind/src/ppc64/Gcreate_addr_space.c | 13 +- .../pal/src/libunwind/src/ppc64/Ginit.c | 18 +- .../pal/src/libunwind/src/ppc64/Gresume.c | 2 - .../pal/src/libunwind/src/ppc64/Gstep.c | 11 +- .../pal/src/libunwind/src/ppc64/ucontext_i.h | 279 ++++++----- .../pal/src/libunwind/src/ppc64/unwind_i.h | 2 +- .../libunwind/src/ptrace/_UPT_access_fpreg.c | 7 + .../libunwind/src/ptrace/_UPT_access_reg.c | 10 + .../src/ptrace/_UPT_find_proc_info.c | 2 +- .../src/ptrace/_UPT_get_dyn_info_list_addr.c | 4 +- .../libunwind/src/ptrace/_UPT_get_proc_name.c | 4 +- .../libunwind/src/ptrace/_UPT_reg_offset.c | 88 ++++ .../libunwind/src/riscv/Gapply_reg_state.c | 36 ++ .../libunwind/src/riscv/Gcreate_addr_space.c | 54 +++ .../src/libunwind/src/riscv/Gget_proc_info.c | 45 ++ .../src/libunwind/src/riscv/Gget_save_loc.c | 97 ++++ .../pal/src/libunwind/src/riscv/Gglobal.c | 128 +++++ .../pal/src/libunwind/src/riscv/Ginit.c | 448 ++++++++++++++++++ .../pal/src/libunwind/src/riscv/Ginit_local.c | 81 ++++ .../src/libunwind/src/riscv/Ginit_remote.c | 55 +++ .../libunwind/src/riscv/Gis_signal_frame.c | 79 +++ .../libunwind/src/riscv/Greg_states_iterate.c | 36 ++ .../pal/src/libunwind/src/riscv/Gregs.c | 95 ++++ .../pal/src/libunwind/src/riscv/Gresume.c | 122 +++++ .../pal/src/libunwind/src/riscv/Gstep.c | 130 +++++ .../libunwind/src/riscv/Lapply_reg_state.c | 5 + .../libunwind/src/riscv/Lcreate_addr_space.c | 5 + .../src/libunwind/src/riscv/Lget_proc_info.c | 5 + .../src/libunwind/src/riscv/Lget_save_loc.c | 5 + .../pal/src/libunwind/src/riscv/Lglobal.c | 5 + .../pal/src/libunwind/src/riscv/Linit.c | 5 + .../pal/src/libunwind/src/riscv/Linit_local.c | 5 + .../src/libunwind/src/riscv/Linit_remote.c | 5 + .../libunwind/src/riscv/Lis_signal_frame.c | 5 + .../libunwind/src/riscv/Lreg_states_iterate.c | 5 + .../pal/src/libunwind/src/riscv/Lregs.c | 5 + .../pal/src/libunwind/src/riscv/Lresume.c | 5 + .../pal/src/libunwind/src/riscv/Lstep.c | 5 + src/coreclr/pal/src/libunwind/src/riscv/asm.h | 46 ++ .../pal/src/libunwind/src/riscv/getcontext.S | 87 ++++ .../pal/src/libunwind/src/riscv/init.h | 65 +++ .../pal/src/libunwind/src/riscv/is_fpreg.c | 31 ++ .../pal/src/libunwind/src/riscv/offsets.h | 13 + .../pal/src/libunwind/src/riscv/regname.c | 59 +++ .../pal/src/libunwind/src/riscv/setcontext.S | 87 ++++ .../pal/src/libunwind/src/riscv/siglongjmp.S | 7 + .../pal/src/libunwind/src/riscv/unwind_i.h | 46 ++ .../libunwind/src/s390x/Gcreate_addr_space.c | 6 +- .../pal/src/libunwind/src/s390x/Gglobal.c | 2 +- .../src/libunwind/src/sh/Gcreate_addr_space.c | 5 +- .../libunwind/src/tilegx/Gcreate_addr_space.c | 8 +- .../pal/src/libunwind/src/tilegx/Ginit.c | 2 +- .../libunwind/src/win/pal-single-threaded.c | 13 +- .../pal/src/libunwind/src/x86/Gos-linux.c | 4 + .../pal/src/libunwind/src/x86_64/Ginit.c | 20 +- .../src/libunwind/src/x86_64/Ginit_local.c | 5 +- .../src/libunwind/src/x86_64/Ginit_remote.c | 5 +- .../src/libunwind/src/x86_64/Gos-freebsd.c | 36 +- .../pal/src/libunwind/src/x86_64/Gos-linux.c | 5 +- .../pal/src/libunwind/src/x86_64/Gresume.c | 3 +- .../pal/src/libunwind/src/x86_64/Gstep.c | 16 +- .../pal/src/libunwind/src/x86_64/Gtrace.c | 35 +- .../pal/src/libunwind/src/x86_64/init.h | 6 +- .../pal/src/libunwind/src/x86_64/unwind_i.h | 2 +- .../pal/src/libunwind/tests/Gia64-test-nat.c | 4 +- .../pal/src/libunwind/tests/Gtest-exc.c | 22 +- .../src/libunwind/tests/Ltest-mem-validate.c | 22 +- .../pal/src/libunwind/tests/Makefile.am | 6 + .../src/libunwind/tests/check-namespace.sh.in | 15 + .../libunwind/tests/test-coredump-unwind.c | 15 +- .../pal/src/libunwind/tests/test-ptrace.c | 6 +- .../pal/src/libunwind/tests/test-setjmp.c | 4 + 153 files changed, 4412 insertions(+), 619 deletions(-) mode change 100644 => 120000 src/coreclr/pal/src/libunwind/README.md delete mode 100755 src/coreclr/pal/src/libunwind/autogen.sh create mode 100644 src/coreclr/pal/src/libunwind/include/libunwind-riscv.h create mode 100644 src/coreclr/pal/src/libunwind/include/tdep-riscv/dwarf-config.h create mode 100644 src/coreclr/pal/src/libunwind/include/tdep-riscv/jmpbuf.h create mode 100644 src/coreclr/pal/src/libunwind/include/tdep-riscv/libunwind_i.h create mode 100644 src/coreclr/pal/src/libunwind/include/win/sys/stat.h create mode 100644 src/coreclr/pal/src/libunwind/src/coredump/_UCD_corefile_elf.c create mode 100644 src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_generic.c create mode 100644 src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_linux.c create mode 100644 src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_threadinfo_prstatus.c create mode 100644 src/coreclr/pal/src/libunwind/src/dl-iterate-phdr.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gapply_reg_state.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gcreate_addr_space.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gget_proc_info.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gget_save_loc.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gglobal.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Ginit.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Ginit_local.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Ginit_remote.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gis_signal_frame.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Greg_states_iterate.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gregs.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gresume.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Gstep.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lapply_reg_state.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lcreate_addr_space.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lget_proc_info.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lget_save_loc.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lglobal.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Linit.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Linit_local.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Linit_remote.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lis_signal_frame.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lreg_states_iterate.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lregs.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lresume.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/Lstep.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/asm.h create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/getcontext.S create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/init.h create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/is_fpreg.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/offsets.h create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/regname.c create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/setcontext.S create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/siglongjmp.S create mode 100644 src/coreclr/pal/src/libunwind/src/riscv/unwind_i.h diff --git a/src/coreclr/pal/src/libunwind/.travis.yml b/src/coreclr/pal/src/libunwind/.travis.yml index 90b828678e827..dd16ee24e9665 100644 --- a/src/coreclr/pal/src/libunwind/.travis.yml +++ b/src/coreclr/pal/src/libunwind/.travis.yml @@ -2,20 +2,35 @@ sudo: required language: c compiler: gcc env: -- TARGET=x86_64-linux-gnu -- TARGET=x86-linux-gnu -- TARGET=arm-linux-gnueabihf -- TARGET=aarch64-linux-gnu -- TARGET=mipsel-unknown-linux-gnu -# Currently experiencing build failures here -#- TARGET=powerpc64-linux-gnu +- HOST=x86_64-linux-gnu OPT=-O0 +- HOST=x86-linux-gnu OPT=-O0 +- HOST=arm-linux-gnueabihf OPT=-O0 +- HOST=aarch64-linux-gnu OPT=-O0 +- HOST=mipsel-linux-gnu OPT=-O0 +- HOST=powerpc64-linux-gnu OPT=-O0 +- HOST=x86_64-linux-gnu OPT=-O2 +- HOST=x86-linux-gnu OPT=-O2 +- HOST=arm-linux-gnueabihf OPT=-O2 +- HOST=aarch64-linux-gnu OPT=-O2 +- HOST=mipsel-linux-gnu OPT=-O2 +- HOST=powerpc64-linux-gnu OPT=-O2 +- HOST=x86_64-linux-gnu OPT=-O3 +- HOST=x86-linux-gnu OPT=-O3 +- HOST=arm-linux-gnueabihf OPT=-O3 +- HOST=aarch64-linux-gnu OPT=-O3 +- HOST=mipsel-linux-gnu OPT=-O3 +- HOST=powerpc64-linux-gnu OPT=-O3 linux-s390x: &linux-s390x os: linux arch: s390x - env: TARGET=s390x-linux-gnu + env: HOST=s390x-linux-gnu BUILD=s390x-linux-gnu script: - - ./autogen.sh + - | + CFLAGS="$OPT" + CXXFLAGS="$OPT" + export CFLAGS CXXFLAGS + - autoreconf -i - ./configure - make -j32 - ulimit -c unlimited @@ -25,23 +40,45 @@ windows-remote-only: &windows-remote-only os: windows compiler: msvc script: - - cmake -G "Visual Studio 15 2017" -A ${HOST} -S . -B bin/windows-${HOST}/${TARGET} - - cmake --build bin/windows-${HOST}/${TARGET} + - cmake -G "Visual Studio 15 2017" -A ${WINHOST} -S . -B bin/windows-${WINHOST}/${TARGET} + - cmake --build bin/windows-${WINHOST}/${TARGET} script: -- ./autogen.sh -- ./configure --target=$TARGET --host=$HOST +- | + BUILD=x86_64-linux-gnu + export BUILD + if [ $HOST = 'x86-linux-gnu' ]; then + sudo apt-get update + sudo apt-get install -yqq -o=Dpkg::Use-Pty=0 g++-multilib + CFLAGS=" -m32" + CXXFLAGS=" -m32" + export CFLAGS CXXFLAGS + elif [ $HOST != 'x86_64-linux-gnu' ]; then + sudo apt-get update + sudo apt-get install -yqq -o=Dpkg::Use-Pty=0 g++-$HOST + CC=$HOST-gcc + CXX=$HOST-g++ + export CC CXX + fi +- | + CFLAGS="$CFLAGS $OPT" + CXXFLAGS="$CXXFLAGS $OPT" + export CFLAGS CXXFLAGS +- autoreconf -i +- ./configure CC=$CC CXX=$CXX CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" --build=$BUILD --host=$HOST - make -j32 - 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 +- if [ $HOST = 'x86_64-linux-gnu' ]; then make check -j32; fi + +after_failure: cat tests/test-suite.log 2>/dev/null jobs: include: - <<: *linux-s390x - <<: *windows-remote-only - env: TARGET=x86_64-linux-gnu HOST=x64 + env: WINHOST=x64 TARGET=x86_64-linux-gnu - <<: *windows-remote-only - env: TARGET=arm-linux-gnueabihf HOST=Win32 + env: WINHOST=Win32 TARGET=arm-linux-gnueabihf - <<: *windows-remote-only - env: TARGET=aarch64-linux-gnu HOST=x64 + env: WINHOST=x64 TARGET=aarch64-linux-gnu diff --git a/src/coreclr/pal/src/libunwind/CMakeLists.txt b/src/coreclr/pal/src/libunwind/CMakeLists.txt index 6e31eae9f716e..17659432fd0e4 100644 --- a/src/coreclr/pal/src/libunwind/CMakeLists.txt +++ b/src/coreclr/pal/src/libunwind/CMakeLists.txt @@ -67,6 +67,8 @@ if(CLR_CMAKE_HOST_UNIX) endif() # We compile code with -std=c99 and the asm keyword is not recognized as it is a gnu extension add_definitions(-Dasm=__asm__) + # Disable warning for a bug in the libunwind source src/aarch64/Ginit.c, but not in code that we exercise + add_compile_options(-Wno-incompatible-pointer-types) elseif(CLR_CMAKE_HOST_ARCH_I386) # Disable warning for a bug in the libunwind source src/x86/Gos-linux.c, but not in code that we exercise add_compile_options(-Wno-incompatible-pointer-types) diff --git a/src/coreclr/pal/src/libunwind/ChangeLog b/src/coreclr/pal/src/libunwind/ChangeLog index dfa24b957cb22..8713adc8ef0cb 100644 --- a/src/coreclr/pal/src/libunwind/ChangeLog +++ b/src/coreclr/pal/src/libunwind/ChangeLog @@ -1,55 +1,7 @@ *********************************************************** - Discontinued. See git log instead at +Discontinued. See git log instead at - http://www.kernel.org/git/gitweb.cgi?p=libs/libunwind/libunwind.git;a=log + https://github.com/libunwind/libunwind/commits/master *********************************************************** - -2002-11-08 David Mosberger-Tang - - * src/ia64/unwind_i.h (ia64_getfp): Change from macro to inline - function. Check "loc" argument for being NULL before dereferencing it. - (ia64_putfp): Ditto. - (ia64_get): Ditto. - (ia64_put): Ditto. - -2002-01-18 David Mosberger-Tang - - * src/ia64/parser.c (__ia64_unw_create_state_record): Set - IA64_FLAG_HAS_HANDLER if the unwind info descriptors indicate that - there a handler. - - * src/ia64/regs.c (__ia64_access_reg): Return zero for UNW_REG_HANDLER - in frames that don't have a personality routine. - - * src/ia64/unwind_i.h (IA64_FLAG_HAS_HANDLER): New flag. - - * src/ia64/regs.c (__ia64_access_reg): When reading UNW_REG_HANDLER, - account for the fact that the personality address is gp-relative. - - * src/ia64/parser.c (__ia64_unw_create_state_record): Fix - initialization of segbase and len. - -2002-01-17 David Mosberger-Tang - - * include/unwind-ia64.h: Include via "unwind.h" to ensure - the file is picked up from same directory. - -2002-01-16 David Mosberger-Tang - - * include/unwind.h: Define UNW_ESTOPUNWIND. This error code may - be returned by acquire_unwind_info() to force termination of - unwinding. An application may want to do this when encountering a - call frame for dynamically generated code, for example. - - * unwind.h: Pass opaque argument pointer to acquire_unwind_info() - and release_unwind_info() like we do for access_mem() etc. - -2002-01-14 David Mosberger-Tang - - * Version 0.0 released. - -2002-01-11 David Mosberger-Tang - - * ChangeLog created. diff --git a/src/coreclr/pal/src/libunwind/Makefile.am b/src/coreclr/pal/src/libunwind/Makefile.am index 8132fa4cb952a..9bb2413dc984e 100644 --- a/src/coreclr/pal/src/libunwind/Makefile.am +++ b/src/coreclr/pal/src/libunwind/Makefile.am @@ -44,9 +44,15 @@ endif if ARCH_S390X include_HEADERS += include/libunwind-s390x.h endif +if ARCH_RISCV +include_HEADERS += include/libunwind-riscv.h +endif if !REMOTE_ONLY -include_HEADERS += include/libunwind.h include/unwind.h +include_HEADERS += include/libunwind.h +if BUILD_UNWIND_HEADER +include_HEADERS += include/unwind.h +endif endif nodist_include_HEADERS = include/libunwind-common.h @@ -89,6 +95,8 @@ noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.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-riscv/dwarf-config.h \ + include/tdep-riscv/jmpbuf.h include/tdep-riscv/libunwind_i.h \ include/tdep/libunwind_i.h \ include/tdep/jmpbuf.h include/tdep/dwarf-config.h diff --git a/src/coreclr/pal/src/libunwind/README b/src/coreclr/pal/src/libunwind/README index 0dc8ccf9e741e..9427144c826e9 100644 --- a/src/coreclr/pal/src/libunwind/README +++ b/src/coreclr/pal/src/libunwind/README @@ -2,8 +2,7 @@ [![Build Status](https://travis-ci.org/libunwind/libunwind.svg?branch=master)](https://travis-ci.org/libunwind/libunwind) -This is version 1.4 of the unwind library. This library supports -several architecture/operating-system combinations: +This library supports several architecture/operating-system combinations: | System | Architecture | Status | | :------ | :----------- | :----- | @@ -11,12 +10,14 @@ several architecture/operating-system combinations: | Linux | x86 | ✓ | | Linux | ARM | ✓ | | Linux | AArch64 | ✓ | +| Linux | PPC32 | ✓ | | 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 | +| Linux | RISC-V | 64-bit only | | HP-UX | IA-64 | Mostly works, but known to have serious limitations | | FreeBSD | x86-64 | ✓ | | FreeBSD | x86 | ✓ | @@ -34,7 +35,7 @@ such dependencies - p, provides its own implementation - empty, no requirement -| Archtecture | getcontext | setcontext | +| Architecture | getcontext | setcontext | |--------------|------------|------------| | aarch64 | p | | | arm | p | | @@ -43,6 +44,7 @@ such dependencies | mips | p | | | ppc32 | r | | | ppc64 | r | r | +| riscv | p | p | | s390x | p | p | | sh | r | | | tilegx | r | r | @@ -54,7 +56,7 @@ such dependencies In general, this library can be built and installed with the following commands: - $ ./autogen.sh # Needed only for building from git. Depends on libtool. + $ autoreconf -i # Needed only for building from git. Depends on libtool. $ ./configure $ make $ make install prefix=PREFIX diff --git a/src/coreclr/pal/src/libunwind/README.md b/src/coreclr/pal/src/libunwind/README.md deleted file mode 100644 index e845566c06f9b..0000000000000 --- a/src/coreclr/pal/src/libunwind/README.md +++ /dev/null @@ -1 +0,0 @@ -README diff --git a/src/coreclr/pal/src/libunwind/README.md b/src/coreclr/pal/src/libunwind/README.md new file mode 120000 index 0000000000000..100b93820ade4 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/README.md @@ -0,0 +1 @@ +README \ No newline at end of file diff --git a/src/coreclr/pal/src/libunwind/autogen.sh b/src/coreclr/pal/src/libunwind/autogen.sh deleted file mode 100755 index b08bc831f6447..0000000000000 --- a/src/coreclr/pal/src/libunwind/autogen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. -( - cd "$srcdir" && - autoreconf --force -v --install -) || exit -test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/src/coreclr/pal/src/libunwind/configure.ac b/src/coreclr/pal/src/libunwind/configure.ac index 73d654c57548b..2893f0cf26907 100644 --- a/src/coreclr/pal/src/libunwind/configure.ac +++ b/src/coreclr/pal/src/libunwind/configure.ac @@ -1,8 +1,8 @@ define(pkg_major, 1) -define(pkg_minor, 5) -define(pkg_extra, -rc1) +define(pkg_minor, 6) +define(pkg_extra, 2) define(pkg_maintainer, libunwind-devel@nongnu.org) -define(mkvers, $1.$2$3) +define(mkvers, $1.$2.$3) dnl Process this file with autoconf to produce a configure script. AC_INIT([libunwind],[mkvers(pkg_major, pkg_minor, pkg_extra)],[pkg_maintainer]) AC_CONFIG_SRCDIR(src/mi/backtrace.c) @@ -34,9 +34,10 @@ esac dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h sys/endian.h execinfo.h \ - ia64intrin.h sys/uc_access.h unistd.h signal.h sys/types.h \ - sys/procfs.h sys/ptrace.h byteswap.h elf.h sys/elf.h link.h sys/link.h) +AC_CHECK_HEADERS(asm/ptrace_offsets.h asm/ptrace.h endian.h sys/endian.h sys/param.h \ + execinfo.h ia64intrin.h sys/uc_access.h unistd.h signal.h sys/types.h \ + sys/procfs.h sys/ptrace.h sys/syscall.h byteswap.h elf.h sys/elf.h \ + link.h sys/link.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -96,6 +97,7 @@ AC_DEFUN([SET_ARCH],[ [sh*],[$2=sh], [amd64],[$2=x86_64], [tile*],[$2=tilegx], + [riscv*],[$2=riscv], [$2=$1]) ]) dnl SET_ARCH @@ -118,7 +120,7 @@ esac AC_ARG_ENABLE(coredump, AS_HELP_STRING([--enable-coredump],[building libunwind-coredump library]),, - [AS_CASE([$host_arch], [aarch64*|arm*|mips*|sh*|x86*|tile*], [enable_coredump=yes], [enable_coredump=no])] + [AS_CASE([$host_arch], [aarch64*|arm*|mips*|sh*|x86*|tile*|riscv*], [enable_coredump=yes], [enable_coredump=no])] ) AC_MSG_CHECKING([if we should build libunwind-coredump]) @@ -134,7 +136,7 @@ AC_MSG_RESULT([$enable_ptrace]) AC_ARG_ENABLE(setjmp, AS_HELP_STRING([--enable-setjmp],[building libunwind-setjmp library]),, - [AS_IF([test x$target_arch == x$host_arch], [enable_setjmp=yes], [enable_setjmp=no])] + [AS_IF([test x$target_arch = x$host_arch], [enable_setjmp=yes], [enable_setjmp=no])] ) AC_ARG_ENABLE(documentation, @@ -149,6 +151,13 @@ AC_ARG_ENABLE(weak-backtrace, AS_HELP_STRING([--disable-weak-backtrace],[Do not provide the weak 'backtrace' symbol.]),, [enable_weak_backtrace=yes]) +AC_ARG_ENABLE(unwind-header, + AS_HELP_STRING([--disable-unwind-header],[Do not export the 'unwind.h' header]),, + [enable_unwind_header=yes]) + +AC_MSG_CHECKING([if we should export unwind.h]) +AC_MSG_RESULT([$enable_unwind_header]) + AC_MSG_CHECKING([if we should build libunwind-setjmp]) AC_MSG_RESULT([$enable_setjmp]) @@ -164,6 +173,7 @@ AC_MSG_RESULT([$target_os]) AM_CONDITIONAL(BUILD_COREDUMP, test x$enable_coredump = xyes) AM_CONDITIONAL(BUILD_PTRACE, test x$enable_ptrace = xyes) AM_CONDITIONAL(BUILD_SETJMP, test x$enable_setjmp = xyes) +AM_CONDITIONAL(BUILD_UNWIND_HEADER, test "x$enable_unwind_header" = xyes) AM_CONDITIONAL(NO_PTRACE_TEST, test x$build_arch != x$host_arch) AM_CONDITIONAL(REMOTE_ONLY, test x$target_arch != x$host_arch) AM_CONDITIONAL(ARCH_AARCH64, test x$target_arch = xaarch64) @@ -178,6 +188,7 @@ 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(ARCH_RISCV, test x$target_arch = xriscv) 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) @@ -188,7 +199,7 @@ 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|s390x|tilegx) use_elf64=yes; AC_MSG_RESULT([64]);; -(mips) use_elfxx=yes; AC_MSG_RESULT([xx]);; +(mips|riscv) use_elfxx=yes; AC_MSG_RESULT([xx]);; *) AC_MSG_ERROR([Unknown ELF target: ${target_arch}]) esac AM_CONDITIONAL(USE_ELF32, [test x$use_elf32 = xyes]) @@ -204,12 +215,6 @@ fi AM_CONDITIONAL(USE_DWARF, [test x$use_dwarf = xyes]) AC_MSG_RESULT([$use_dwarf]) -if test x$target_arch = xppc64; then - libdir='${exec_prefix}/lib64' - AC_MSG_NOTICE([PowerPC64 detected, lib will be installed ${libdir}]); - AC_SUBST([libdir]) -fi - AC_MSG_CHECKING([whether to restrict build to remote support]) if test x$target_arch != x$host_arch; then CPPFLAGS="${CPPFLAGS} -DUNW_REMOTE_ONLY" @@ -240,6 +245,7 @@ case $target_arch in arm*) enable_cxx_exceptions=no;; mips*) enable_cxx_exceptions=no;; tile*) enable_cxx_exceptions=no;; + s390x*) enable_cxx_exceptions=no;; *) enable_cxx_exceptions=yes;; esac ]) @@ -255,6 +261,9 @@ case "${target_arch}" in (aarch64) enable_debug_frame=yes;; (*) enable_debug_frame=no;; esac]) +if test x$remote_only = xyes; then + enable_debug_frame=no +fi if test x$enable_debug_frame = xyes; then AC_DEFINE([CONFIG_DEBUG_FRAME], [], [Enable Debug Frame]) fi diff --git a/src/coreclr/pal/src/libunwind/include/dwarf.h b/src/coreclr/pal/src/libunwind/include/dwarf.h index 6a56fe2d7e91d..175c419bbe394 100644 --- a/src/coreclr/pal/src/libunwind/include/dwarf.h +++ b/src/coreclr/pal/src/libunwind/include/dwarf.h @@ -46,6 +46,9 @@ struct elf_dyn_info; #else #error Could not find #endif + #if defined(__ANDROID__) && defined(__arm__) && __ANDROID_API__ < 21 + int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *); + #endif #endif #include @@ -367,6 +370,8 @@ struct unw_debug_frame_list /* The start (inclusive) and end (exclusive) of the described region. */ unw_word_t start; unw_word_t end; + /* ELF load offset */ + unw_word_t load_offset; /* The debug frame itself. */ char *debug_frame; size_t debug_frame_size; diff --git a/src/coreclr/pal/src/libunwind/include/dwarf_i.h b/src/coreclr/pal/src/libunwind/include/dwarf_i.h index 983b9f5c2afbc..b3e4c1b405516 100644 --- a/src/coreclr/pal/src/libunwind/include/dwarf_i.h +++ b/src/coreclr/pal/src/libunwind/include/dwarf_i.h @@ -142,7 +142,7 @@ dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, *addr += 1; ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); -#if __BYTE_ORDER == __LITTLE_ENDIAN +#if UNW_BYTE_ORDER == UNW_LITTLE_ENDIAN val >>= 8*off; #else val >>= 8*(sizeof (unw_word_t) - 1 - off); diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-aarch64.h b/src/coreclr/pal/src/libunwind/include/libunwind-aarch64.h index d78fbd44921f6..a5265c4627bf9 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind-aarch64.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind-aarch64.h @@ -183,6 +183,7 @@ typedef struct unw_tdep_save_loc } unw_tdep_save_loc_t; +#ifdef __linux__ /* 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. */ @@ -202,7 +203,15 @@ typedef struct unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; +#ifndef __ANDROID__ sigset_t uc_sigmask; +#else + union { + sigset_t uc_sigmask; + sigset64_t uc_sigmask64; + }; + char __padding[128 - sizeof(sigset_t)]; +#endif struct unw_sigcontext uc_mcontext; } unw_tdep_context_t; @@ -214,16 +223,19 @@ typedef struct uint32_t fpcr; uint64_t vregs[64]; } unw_fpsimd_context_t; - +#else +/* On AArch64, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; +#endif #include "libunwind-common.h" #include "libunwind-dynamic.h" -#define unw_tdep_getcontext(uc) (({ \ +#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; \ - __asm__ __volatile__ ( \ + 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" \ "stp x4, x5, [%[base], #32]\n" \ @@ -239,11 +251,14 @@ typedef struct "stp x24, x25, [%[base], #192]\n" \ "stp x26, x27, [%[base], #208]\n" \ "stp x28, x29, [%[base], #224]\n" \ - "str x30, [%[base], #240]\n" \ "mov x1, sp\n" \ - "stp x1, x30, [%[base], #248]\n" \ + "stp x30, x1, [%[base], #240]\n" \ + "adr x1, ret%=\n" \ + "str x1, [%[base], #256]\n" \ + "mov %[base], #0\n" \ + "ret%=:\n" \ : [base] "+r" (unw_base) : : "x1", "memory"); \ - }), 0) + (int)unw_base; }) #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) extern int unw_tdep_is_fpreg (int); diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-arm.h b/src/coreclr/pal/src/libunwind/include/libunwind-arm.h index 8e72f42bbbb98..793ada0894ee2 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind-arm.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind-arm.h @@ -244,7 +244,7 @@ typedef enum UNW_TDEP_LAST_REG = UNW_ARM_D31, - UNW_TDEP_IP = UNW_ARM_R14, /* A little white lie. */ + UNW_TDEP_IP = UNW_ARM_R15, UNW_TDEP_SP = UNW_ARM_R13, UNW_TDEP_EH = UNW_ARM_R0 /* FIXME. */ } @@ -269,32 +269,43 @@ typedef struct unw_tdep_context } unw_tdep_context_t; -/* There is no getcontext() on ARM. Use a stub version which only saves GP - registers. FIXME: Not ideal, may not be sufficient for all libunwind - use cases. Stores pc+8, which is only approximately correct, really. */ +/* FIXME: this is a stub version which only saves GP registers. Not ideal, but + may be sufficient for all libunwind use cases. + In thumb mode, we return directly back to thumb mode on return (with bx), to + avoid altering any registers after unw_resume. */ #ifndef __thumb__ -#define unw_tdep_getcontext(uc) (({ \ - unw_tdep_context_t *unw_ctx = (uc); \ - register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \ - __asm__ __volatile__ ( \ - "stmia %[base], {r0-r15}" \ - "adds %[base], #64" \ - "vstmia %[base], {d0-d15}" \ - : : [base] "r" (unw_base) : "memory"); \ - }), 0) +#define unw_tdep_getcontext(uc) ({ \ + unw_tdep_context_t *unw_ctx = (uc); \ + register unsigned long *r0 __asm__ ("r0"); \ + register unsigned long *unw_base __asm__ ("r1") = unw_ctx->regs; \ + __asm__ __volatile__ ( \ + "mov r0, #0\n" \ + "stmia %[base]!, {r0-r15}\n" \ + "vstmia %[base], {d0-d15}\n" /* this also aligns return address to value stored by stmia */ \ + : [r0] "=r" (r0) : [base] "r" (unw_base) : "memory"); \ + (int)r0; }) #else /* __thumb__ */ -#define unw_tdep_getcontext(uc) (({ \ +#define unw_tdep_getcontext(uc) ({ \ unw_tdep_context_t *unw_ctx = (uc); \ - register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \ + register unsigned long *r0 __asm__ ("r0"); \ + register unsigned long *unw_base __asm__ ("r1") = unw_ctx->regs; \ __asm__ __volatile__ ( \ - ".align 2\nbx pc\nnop\n.code 32\n" \ - "stmia %[base], {r0-r15}\n" \ - "adds %[base], #64\n" \ + ".align 2\n" \ + "bx pc\n" \ + "nop\n" \ + ".code 32\n" \ + "mov r0, #0\n" \ + "stmia %[base], {r0-r14}\n" \ + "adr r0, ret%=+1\n" \ + "stmia %[base]!, {r0}\n" \ "vstmia %[base], {d0-d15}\n" \ - "orr %[base], pc, #1\nbx %[base]\n" \ - ".code 16\n" \ - : [base] "+r" (unw_base) : : "memory", "cc"); \ - }), 0) + "orr r0, pc, #1\n" \ + "bx r0\n" \ + ".code 16\n" \ + "mov r0, #0\n" \ + "ret%=:\n" \ + : [r0] "=r" (r0), [base] "+r" (unw_base) : : "memory", "cc"); \ + (int)r0; }) #endif #include "libunwind-dynamic.h" diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-dynamic.h b/src/coreclr/pal/src/libunwind/include/libunwind-dynamic.h index edb0bbd343db7..dc31b12efc9d0 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind-dynamic.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind-dynamic.h @@ -141,6 +141,7 @@ typedef struct unw_dyn_info unw_word_t gp; /* global-pointer in effect for this entry */ int32_t format; /* real type: unw_dyn_info_format_t */ int32_t pad; + unw_word_t load_offset; /* ELF load offset */ union { unw_dyn_proc_info_t pi; diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-mips.h b/src/coreclr/pal/src/libunwind/include/libunwind-mips.h index ced34b2027af6..d1cc1b7e280a2 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind-mips.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind-mips.h @@ -30,7 +30,7 @@ extern "C" { #endif #include -#include +#include #ifdef mips # undef mips diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-ppc64.h b/src/coreclr/pal/src/libunwind/include/libunwind-ppc64.h index 9944628da02f7..fed478bedcd71 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind-ppc64.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind-ppc64.h @@ -72,7 +72,7 @@ typedef uint64_t unw_word_t; typedef int64_t unw_sword_t; #endif -typedef long double unw_tdep_fpreg_t; +typedef double unw_tdep_fpreg_t; /* * Vector register (in PowerPC64 used for AltiVec registers) diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-ptrace.h b/src/coreclr/pal/src/libunwind/include/libunwind-ptrace.h index 801325c4d4d00..916dbd246bf5b 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind-ptrace.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind-ptrace.h @@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define libunwind_ptrace_h #include +#include #if defined(__cplusplus) || defined(c_plusplus) extern "C" { diff --git a/src/coreclr/pal/src/libunwind/include/libunwind-riscv.h b/src/coreclr/pal/src/libunwind/include/libunwind-riscv.h new file mode 100644 index 0000000000000..e74db0f93183a --- /dev/null +++ b/src/coreclr/pal/src/libunwind/include/libunwind-riscv.h @@ -0,0 +1,187 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for riscv by Zhaofeng Li + +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 +#include +#include + +#define UNW_TARGET riscv +#define UNW_TARGET_RISCV 1 + +#define _U_TDEP_QP_TRUE 0 /* ignored - 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. */ +/* FIXME for riscv: Figure out a more reasonable size */ +#define UNW_TDEP_CURSOR_LEN 4096 + +#if __riscv_xlen == 32 +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; +#elif __riscv_xlen == 64 +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; +#endif + +#if __riscv_flen == 64 +typedef double unw_tdep_fpreg_t; +#elif __riscv_flen == 32 +typedef float unw_tdep_fpreg_t; +#else +# error "Unsupported RISC-V floating-point size" +#endif + +/* Also see src/riscv/Gglobal.c. This ordering is consistent with + https://github.com/riscv/riscv-elf-psabi-doc/blob/74ecf07bcebd0cb4bf3c39f3f9d96946cd6aba61/riscv-elf.md#dwarf-register-numbers- */ + +typedef enum + { + /* integer registers */ + UNW_RISCV_X0, + UNW_RISCV_X1, + UNW_RISCV_X2, + UNW_RISCV_X3, + UNW_RISCV_X4, + UNW_RISCV_X5, + UNW_RISCV_X6, + UNW_RISCV_X7, + UNW_RISCV_X8, + UNW_RISCV_X9, + UNW_RISCV_X10, + UNW_RISCV_X11, + UNW_RISCV_X12, + UNW_RISCV_X13, + UNW_RISCV_X14, + UNW_RISCV_X15, + UNW_RISCV_X16, + UNW_RISCV_X17, + UNW_RISCV_X18, + UNW_RISCV_X19, + UNW_RISCV_X20, + UNW_RISCV_X21, + UNW_RISCV_X22, + UNW_RISCV_X23, + UNW_RISCV_X24, + UNW_RISCV_X25, + UNW_RISCV_X26, + UNW_RISCV_X27, + UNW_RISCV_X28, + UNW_RISCV_X29, + UNW_RISCV_X30, + UNW_RISCV_X31, + + /* floating point registers */ + UNW_RISCV_F0, + UNW_RISCV_F1, + UNW_RISCV_F2, + UNW_RISCV_F3, + UNW_RISCV_F4, + UNW_RISCV_F5, + UNW_RISCV_F6, + UNW_RISCV_F7, + UNW_RISCV_F8, + UNW_RISCV_F9, + UNW_RISCV_F10, + UNW_RISCV_F11, + UNW_RISCV_F12, + UNW_RISCV_F13, + UNW_RISCV_F14, + UNW_RISCV_F15, + UNW_RISCV_F16, + UNW_RISCV_F17, + UNW_RISCV_F18, + UNW_RISCV_F19, + UNW_RISCV_F20, + UNW_RISCV_F21, + UNW_RISCV_F22, + UNW_RISCV_F23, + UNW_RISCV_F24, + UNW_RISCV_F25, + UNW_RISCV_F26, + UNW_RISCV_F27, + UNW_RISCV_F28, + UNW_RISCV_F29, + UNW_RISCV_F30, + UNW_RISCV_F31, + + UNW_RISCV_PC, + + UNW_TDEP_LAST_REG = UNW_RISCV_PC, + + /* The CFA is the value of SP in previous frame */ + UNW_RISCV_CFA = UNW_RISCV_X2, + + UNW_TDEP_IP = UNW_RISCV_PC, + UNW_TDEP_SP = UNW_RISCV_X2, + UNW_TDEP_EH = UNW_RISCV_X10, + } +riscv_regnum_t; + +/* https://github.com/gcc-mirror/gcc/blob/16e2427f50c208dfe07d07f18009969502c25dc8/gcc/config/riscv/riscv.h#L104-L106 */ +#define UNW_TDEP_NUM_EH_REGS 4 + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + char unused; + } +unw_tdep_save_loc_t; + +/* On riscv, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +typedef struct + { + /* no riscv-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 */ diff --git a/src/coreclr/pal/src/libunwind/include/libunwind.h.in b/src/coreclr/pal/src/libunwind/include/libunwind.h.in index a13e7767325df..dfea76626b622 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind.h.in +++ b/src/coreclr/pal/src/libunwind/include/libunwind.h.in @@ -27,6 +27,8 @@ # include "libunwind-tilegx.h" #elif defined __s390x__ # include "libunwind-s390x.h" +#elif defined __riscv || defined __riscv__ +# include "libunwind-riscv.h" #else # error "Unsupported arch" #endif diff --git a/src/coreclr/pal/src/libunwind/include/libunwind_i.h b/src/coreclr/pal/src/libunwind/include/libunwind_i.h index aca1ee315b177..fea5c26077433 100644 --- a/src/coreclr/pal/src/libunwind/include/libunwind_i.h +++ b/src/coreclr/pal/src/libunwind/include/libunwind_i.h @@ -63,38 +63,78 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #else # error Could not locate #endif +#if defined(ELFCLASS32) +# define UNW_ELFCLASS32 ELFCLASS32 +#else +# define UNW_ELFCLASS32 1 +#endif +#if defined(ELFCLASS64) +# define UNW_ELFCLASS64 ELFCLASS64 +#else +# define UNW_ELFCLASS64 2 +#endif #if defined(HAVE_ENDIAN_H) # include #elif defined(HAVE_SYS_ENDIAN_H) # include -# if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN) -# define __LITTLE_ENDIAN _LITTLE_ENDIAN -# endif -# if defined(_BIG_ENDIAN) && !defined(__BIG_ENDIAN) -# define __BIG_ENDIAN _BIG_ENDIAN -# endif -# if defined(_BYTE_ORDER) && !defined(__BYTE_ORDER) -# define __BYTE_ORDER _BYTE_ORDER -# endif +#elif defined(HAVE_SYS_PARAM_H) +# include +#endif + +#if defined(__LITTLE_ENDIAN) +# define UNW_LITTLE_ENDIAN __LITTLE_ENDIAN +#elif defined(_LITTLE_ENDIAN) +# define UNW_LITTLE_ENDIAN _LITTLE_ENDIAN +#elif defined(LITTLE_ENDIAN) +# define UNW_LITTLE_ENDIAN LITTLE_ENDIAN +#else +# define UNW_LITTLE_ENDIAN 1234 +#endif + +#if defined(__BIG_ENDIAN) +# define UNW_BIG_ENDIAN __BIG_ENDIAN +#elif defined(_BIG_ENDIAN) +# define UNW_BIG_ENDIAN _BIG_ENDIAN +#elif defined(BIG_ENDIAN) +# define UNW_BIG_ENDIAN BIG_ENDIAN +#else +# define UNW_BIG_ENDIAN 4321 +#endif + +#if defined(__BYTE_ORDER) +# define UNW_BYTE_ORDER __BYTE_ORDER +#elif defined(_BYTE_ORDER) +# define UNW_BYTE_ORDER _BYTE_ORDER +#elif defined(BIG_ENDIAN) +# define UNW_BYTE_ORDER BYTE_ORDER #else -# define __LITTLE_ENDIAN 1234 -# define __BIG_ENDIAN 4321 # if defined(__hpux) -# define __BYTE_ORDER __BIG_ENDIAN -# elif defined(__QNX__) -# if defined(__BIGENDIAN__) -# define __BYTE_ORDER __BIG_ENDIAN -# elif defined(__LITTLEENDIAN__) -# define __BYTE_ORDER __LITTLE_ENDIAN -# else -# error Host has unknown byte-order. -# endif +# define UNW_BYTE_ORDER UNW_BIG_ENDIAN # else -# error Host has unknown byte-order. +# error Target has unknown byte ordering. # endif #endif +static inline int +byte_order_is_valid(int byte_order) +{ + return byte_order != UNW_BIG_ENDIAN + && byte_order != UNW_LITTLE_ENDIAN; +} + +static inline int +byte_order_is_big_endian(int byte_order) +{ + return byte_order == UNW_BIG_ENDIAN; +} + +static inline int +target_is_big_endian() +{ + return byte_order_is_big_endian(UNW_BYTE_ORDER); +} + #if defined(HAVE__BUILTIN_UNREACHABLE) # define unreachable() __builtin_unreachable() #else diff --git a/src/coreclr/pal/src/libunwind/include/remote.h b/src/coreclr/pal/src/libunwind/include/remote.h index 064d6309adb7e..b3ac97f6ef836 100644 --- a/src/coreclr/pal/src/libunwind/include/remote.h +++ b/src/coreclr/pal/src/libunwind/include/remote.h @@ -58,7 +58,7 @@ fetch8 (unw_addr_space_t as, unw_accessors_t *a, ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); -#if __BYTE_ORDER == __LITTLE_ENDIAN +#if UNW_BYTE_ORDER == UNW_LITTLE_ENDIAN val >>= 8*off; #else val >>= 8*(WSIZE - 1 - off); @@ -81,7 +81,7 @@ fetch16 (unw_addr_space_t as, unw_accessors_t *a, ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); -#if __BYTE_ORDER == __LITTLE_ENDIAN +#if UNW_BYTE_ORDER == UNW_LITTLE_ENDIAN val >>= 8*off; #else val >>= 8*(WSIZE - 2 - off); @@ -104,7 +104,7 @@ fetch32 (unw_addr_space_t as, unw_accessors_t *a, ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); -#if __BYTE_ORDER == __LITTLE_ENDIAN +#if UNW_BYTE_ORDER == UNW_LITTLE_ENDIAN val >>= 8*off; #else val >>= 8*(WSIZE - 4 - off); diff --git a/src/coreclr/pal/src/libunwind/include/tdep-aarch64/libunwind_i.h b/src/coreclr/pal/src/libunwind/include/tdep-aarch64/libunwind_i.h index fc4416069e9c9..d96833a219e4f 100644 --- a/src/coreclr/pal/src/libunwind/include/tdep-aarch64/libunwind_i.h +++ b/src/coreclr/pal/src/libunwind/include/tdep-aarch64/libunwind_i.h @@ -102,8 +102,16 @@ struct cursor 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) #ifdef UNW_LOCAL_ONLY @@ -112,10 +120,10 @@ struct cursor # define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) # define DWARF_IS_REG_LOC(l) 0 # define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ - tdep_uc_addr((c)->as_arg, (r)), 0)) + tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) # define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) # define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ - tdep_uc_addr((c)->as_arg, (r)), 0)) + tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) static inline int dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) @@ -265,6 +273,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_getcontext_trace UNW_ARCH_OBJ(getcontext_trace) #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. */ @@ -303,6 +312,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) extern atomic_bool 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); diff --git a/src/coreclr/pal/src/libunwind/include/tdep-arm/libunwind_i.h b/src/coreclr/pal/src/libunwind/include/tdep-arm/libunwind_i.h index 36ceca386c535..88ebfb0693326 100644 --- a/src/coreclr/pal/src/libunwind/include/tdep-arm/libunwind_i.h +++ b/src/coreclr/pal/src/libunwind/include/tdep-arm/libunwind_i.h @@ -320,6 +320,7 @@ extern void tdep_stash_frame (struct dwarf_cursor *c, #define UNW_ARM_METHOD_DWARF 0x01 #define UNW_ARM_METHOD_FRAME 0x02 #define UNW_ARM_METHOD_EXIDX 0x04 +#define UNW_ARM_METHOD_LR 0x08 #define unwi_unwind_method UNW_OBJ(unwind_method) extern int unwi_unwind_method; diff --git a/src/coreclr/pal/src/libunwind/include/tdep-riscv/dwarf-config.h b/src/coreclr/pal/src/libunwind/include/tdep-riscv/dwarf-config.h new file mode 100644 index 0000000000000..78277761d8c2c --- /dev/null +++ b/src/coreclr/pal/src/libunwind/include/tdep-riscv/dwarf-config.h @@ -0,0 +1,50 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for riscv by Zhaofeng Li + +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 dwarf_config_h +#define dwarf_config_h + +/* 32 integer registers + 32 floating-point registers + 2 pseudo-registers */ +#define DWARF_NUM_PRESERVED_REGS 66 + +#define DWARF_REGNUM_MAP_LENGTH DWARF_NUM_PRESERVED_REGS + +/* Not big-endian. */ +#define dwarf_is_big_endian(addr_space) 0 + +/* 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 RISCV_LOC_TYPE_* macros. */ + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/src/coreclr/pal/src/libunwind/include/tdep-riscv/jmpbuf.h b/src/coreclr/pal/src/libunwind/include/tdep-riscv/jmpbuf.h new file mode 100644 index 0000000000000..8831f6900c99d --- /dev/null +++ b/src/coreclr/pal/src/libunwind/include/tdep-riscv/jmpbuf.h @@ -0,0 +1,49 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by Zhaofeng Li + +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__ + +/* https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/riscv/setjmp.S;h=0b92016b311b11aa9eeb62b38c670a262f1924c9;hb=HEAD */ +#define JB_SP 13 +#define JB_RP 0 + +#if __riscv_xlen == 64 + +/* GCC's internal structure for this depends on the floating-point ABI: + https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/riscv/rv64/jmp_buf-macros.h;h=be9199e514bf4f15f0612327b8b762e29a2b7862;hb=HEAD +*/ + +#if defined __riscv_float_abi_double +# define JB_MASK_SAVED (208>>3) +# define JB_MASK (216>>3) +#else +# error "Unsupported RISC-V floating point ABI" +#endif /* __riscv_float_abi_double */ + +#else +# error "Add offsets here" +#endif /* __riscv_xlen */ + +#endif diff --git a/src/coreclr/pal/src/libunwind/include/tdep-riscv/libunwind_i.h b/src/coreclr/pal/src/libunwind/include/tdep-riscv/libunwind_i.h new file mode 100644 index 0000000000000..4404a47510a4c --- /dev/null +++ b/src/coreclr/pal/src/libunwind/include/tdep-riscv/libunwind_i.h @@ -0,0 +1,303 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + + Modified for riscv by Zhaofeng Li + +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 RISCV_LIBUNWIND_I_H +#define RISCV_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include +#include + +/* FIXME: Remote across address sizes? */ + +#if __riscv_xlen == 64 +# include "elf64.h" +#elif __riscv_xlen == 32 +# include "elf32.h" +#else +# error "Unsupported address size" +#endif + +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no riscv-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + + int big_endian; + unsigned int addr_size; + + unw_caching_policy_t caching_policy; + _Atomic uint32_t cache_generation; + 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; +}; + +#define tdep_big_endian(as) ((as)->big_endian) + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + enum + { + RISCV_SCF_NONE, // 0 + RISCV_SCF_LINUX_RT_SIGFRAME, // 1 + } + 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) + +#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_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_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_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) (intptr_t) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) (intptr_t) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# 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_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# 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_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + /* FIXME: unw_word_t may not be equal to FLEN */ + addr = DWARF_GET_LOC (loc); +#if __riscv_xlen == __riscv_flen + return (*c->as->acc.access_mem) (c->as, addr, (unw_word_t *) valp, + 0, c->as_arg); +#else +# error "FIXME" +#endif +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + /* FIXME: unw_word_t may not be equal to FLEN */ + addr = DWARF_GET_LOC (loc); +#if __riscv_xlen == __riscv_flen + return (*c->as->acc.access_mem) (c->as, addr, (unw_word_t *) valp, + 1, c->as_arg); +#else +# error "FIXME" +#endif +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (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); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_mem_validate UNW_OBJ(init_mem_validate) +#define tdep_init_done UNW_OBJ(init_done) +#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_uc_addr UNW_ARCH_OBJ(uc_addr) +#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,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) + +#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) + +extern atomic_bool 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 (ucontext_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 /* RISCV_LIBUNWIND_I_H */ diff --git a/src/coreclr/pal/src/libunwind/include/tdep-x86_64/libunwind_i.h b/src/coreclr/pal/src/libunwind/include/tdep-x86_64/libunwind_i.h index 07a8a7ae2c7b3..ff0436a09c42a 100644 --- a/src/coreclr/pal/src/libunwind/include/tdep-x86_64/libunwind_i.h +++ b/src/coreclr/pal/src/libunwind/include/tdep-x86_64/libunwind_i.h @@ -31,6 +31,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Target-dependent definitions that are internal to libunwind but need to be shared with target-independent code. */ +#include #include #include #include @@ -90,15 +91,44 @@ struct cursor } sigcontext_format; unw_word_t sigcontext_addr; - int validate; - ucontext_t *uc; }; +#define AS_ARG_UCONTEXT_MASK ~0x1UL +#define AS_ARG_VALIDATE_MASK 0x1UL + +#define AS_ARG_GET_UC_PTR(arg) \ + ((ucontext_t *) ((uintptr_t) arg & AS_ARG_UCONTEXT_MASK)) +#define AS_ARG_GET_VALIDATE(arg) \ + ((int) ((uintptr_t) arg & AS_ARG_VALIDATE_MASK)) + static inline ucontext_t * dwarf_get_uc(const struct dwarf_cursor *cursor) { - const struct cursor *c = (struct cursor *) cursor->as_arg; - return c->uc; + assert(cursor->as == unw_local_addr_space); + return AS_ARG_GET_UC_PTR(cursor->as_arg); +} + +static inline int +dwarf_get_validate(const struct dwarf_cursor *cursor) +{ + assert(cursor->as == unw_local_addr_space); + return AS_ARG_GET_VALIDATE(cursor->as_arg); +} + +static inline void +dwarf_set_validate(const struct dwarf_cursor *cursor, const int validate) +{ + assert(cursor->as == unw_local_addr_space); + uintptr_t *packed_args = (uintptr_t *) &cursor->as_arg; + *packed_args |= (AS_ARG_VALIDATE_MASK & validate); +} + +static inline void * +dwarf_build_as_arg(const ucontext_t *uc, const int validate) { + uintptr_t packed_args = (uintptr_t) uc; + assert((packed_args & AS_ARG_VALIDATE_MASK) == 0); + packed_args |= (AS_ARG_VALIDATE_MASK & validate); + return (void *) packed_args; } #define DWARF_GET_LOC(l) ((l).val) diff --git a/src/coreclr/pal/src/libunwind/include/tdep/dwarf-config.h b/src/coreclr/pal/src/libunwind/include/tdep/dwarf-config.h index e27e2a2369033..0cfd079e66ca6 100644 --- a/src/coreclr/pal/src/libunwind/include/tdep/dwarf-config.h +++ b/src/coreclr/pal/src/libunwind/include/tdep/dwarf-config.h @@ -25,6 +25,8 @@ # include "tdep-x86_64/dwarf-config.h" #elif defined __tilegx__ # include "tdep-tilegx/dwarf-config.h" +#elif defined __riscv || defined __riscv__ +# include "tdep-riscv/dwarf-config.h" #else # error "Unsupported arch" #endif diff --git a/src/coreclr/pal/src/libunwind/include/tdep/jmpbuf.h b/src/coreclr/pal/src/libunwind/include/tdep/jmpbuf.h index 13093a0cdc3fa..77d35c3da4de1 100644 --- a/src/coreclr/pal/src/libunwind/include/tdep/jmpbuf.h +++ b/src/coreclr/pal/src/libunwind/include/tdep/jmpbuf.h @@ -23,6 +23,8 @@ # include "tdep-x86_64/jmpbuf.h" #elif defined __tilegx__ # include "tdep-tilegx/jmpbuf.h" +#elif defined __riscv || defined __riscv__ +# include "tdep-riscv/jmpbuf.h" #else # error "Unsupported arch" #endif diff --git a/src/coreclr/pal/src/libunwind/include/tdep/libunwind_i.h.in b/src/coreclr/pal/src/libunwind/include/tdep/libunwind_i.h.in index c47299640e8e6..a40f7cf6112b2 100644 --- a/src/coreclr/pal/src/libunwind/include/tdep/libunwind_i.h.in +++ b/src/coreclr/pal/src/libunwind/include/tdep/libunwind_i.h.in @@ -27,6 +27,8 @@ # include "tdep-tilegx/libunwind_i.h" #elif defined __s390x__ # include "tdep-s390x/libunwind_i.h" +#elif defined __riscv || defined __riscv__ +# include "tdep-riscv/libunwind_i.h" #else # error "Unsupported arch" #endif diff --git a/src/coreclr/pal/src/libunwind/include/win/sys/mman.h b/src/coreclr/pal/src/libunwind/include/win/sys/mman.h index 51d2d10853b84..0a3f6f93b5fec 100644 --- a/src/coreclr/pal/src/libunwind/include/win/sys/mman.h +++ b/src/coreclr/pal/src/libunwind/include/win/sys/mman.h @@ -16,6 +16,7 @@ #define MAP_PRIVATE 2 #define PROT_READ 4 #define PROT_WRITE 8 +#define PROT_EXEC 16 void* mmap(void *, size_t, int, int, int, size_t); int munmap(void *, size_t); diff --git a/src/coreclr/pal/src/libunwind/include/win/sys/stat.h b/src/coreclr/pal/src/libunwind/include/win/sys/stat.h new file mode 100644 index 0000000000000..a5b54deaca06f --- /dev/null +++ b/src/coreclr/pal/src/libunwind/include/win/sys/stat.h @@ -0,0 +1,35 @@ +// This is an incomplete & imprecice implementation of the Posix +// standard file by the same name + +// Since this is only intended for VC++ compilers +// use #pragma once instead of guard macros +#pragma once + +#ifdef _MSC_VER // Only for cross compilation to windows + +#include + +#define S_IFMT 00170000 +#define S_IFDIR 0040000 + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +struct stat +{ + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + unsigned short st_rdev; + unsigned short st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; + +int stat(const char *path, struct stat *buf); +int fstat(int fd, struct stat *buf); + +#endif // _MSC_VER diff --git a/src/coreclr/pal/src/libunwind/libunwind-version.txt b/src/coreclr/pal/src/libunwind/libunwind-version.txt index 566086b14aee9..bdb4658cda99b 100644 --- a/src/coreclr/pal/src/libunwind/libunwind-version.txt +++ b/src/coreclr/pal/src/libunwind/libunwind-version.txt @@ -1,7 +1,7 @@ -v1.5-rc1-28-g9165d2a1 -https://github.com/libunwind/libunwind/commit/9165d2a150d707d3037c2045f2cdc0fabd5fee98 +v1.6.2 +https://github.com/libunwind/libunwind/commit/b3ca1b59a795a617877c01fe5d299ab7a07ff29d -Remove upstream CMakelist.txt & src/CMakelist.txt, keep .NET Core custom version -Keep .NET Core oop directory -Apply https://github.com/libunwind/libunwind/pull/186 -Apply https://github.com/libunwind/libunwind/pull/245 +Replace CMakeLists.txt, src/CMakeLists.txt, configure.cmake with .NET custom version +Keep .NET oop directory +Reapply changes from https://github.com/dotnet/runtime/commit/1b5719c2e3dde393531eaeb5b5cde05dabeef5b8 +Apply https://github.com/libunwind/libunwind/pull/317 diff --git a/src/coreclr/pal/src/libunwind/src/Makefile.am b/src/coreclr/pal/src/libunwind/src/Makefile.am index ff977446a7c2b..2b5b02959e99e 100644 --- a/src/coreclr/pal/src/libunwind/src/Makefile.am +++ b/src/coreclr/pal/src/libunwind/src/Makefile.am @@ -60,6 +60,7 @@ libunwind_coredump_la_SOURCES = \ coredump/_UCD_elf_map_image.c \ coredump/_UCD_find_proc_info.c \ coredump/_UCD_get_proc_name.c \ + coredump/_UCD_corefile_elf.c \ \ coredump/_UPT_elf.c \ coredump/_UPT_access_fpreg.c \ @@ -146,7 +147,7 @@ libunwind_la_SOURCES_local = \ $(libunwind_la_SOURCES_local_unwind) noinst_HEADERS += os-linux.h -libunwind_la_SOURCES_os_linux = os-linux.c +libunwind_la_SOURCES_os_linux = os-linux.c dl-iterate-phdr.c libunwind_la_SOURCES_os_hpux = os-hpux.c @@ -246,6 +247,8 @@ noinst_HEADERS += ia64/init.h ia64/offsets.h ia64/regs.h \ ia64/ucontext_i.h ia64/unwind_decoder.h ia64/unwind_i.h libunwind_la_SOURCES_ia64_common = $(libunwind_la_SOURCES_common) \ ia64/regname.c +libunwind_la_EXTRAS_ia64 = ia64/mk_cursor_i ia64/mk_Lcursor_i.c \ + ia64/mk_Gcursor_i.c # The list of files that go into libunwind: libunwind_la_SOURCES_ia64 = $(libunwind_la_SOURCES_ia64_common) \ @@ -336,6 +339,26 @@ libunwind_tilegx_la_SOURCES_tilegx = $(libunwind_la_SOURCES_tilegx_common) \ tilegx/Gglobal.c tilegx/Ginit.c tilegx/Ginit_local.c tilegx/Ginit_remote.c \ tilegx/Gis_signal_frame.c tilegx/Gregs.c tilegx/Gresume.c tilegx/Gstep.c +# The list of files that go info libunwind and libunwind-riscv: +noinst_HEADERS += riscv/init.h riscv/offsets.h riscv/unwind_i.h riscv/asm.h +libunwind_la_SOURCES_riscv_common = $(libunwind_la_SOURCES_common) \ + riscv/is_fpreg.c riscv/regname.c + +# The list of files that go into libunwind: +libunwind_la_SOURCES_riscv = $(libunwind_la_SOURCES_riscv_common) \ + $(libunwind_la_SOURCES_local) \ + riscv/getcontext.S riscv/setcontext.S \ + riscv/Lapply_reg_state.c riscv/Lreg_states_iterate.c \ + riscv/Lcreate_addr_space.c riscv/Lget_proc_info.c riscv/Lget_save_loc.c \ + riscv/Lglobal.c riscv/Linit.c riscv/Linit_local.c riscv/Linit_remote.c \ + riscv/Lis_signal_frame.c riscv/Lregs.c riscv/Lresume.c riscv/Lstep.c + +libunwind_riscv_la_SOURCES_riscv = $(libunwind_la_SOURCES_riscv_common) \ + $(libunwind_la_SOURCES_generic) \ + riscv/Gapply_reg_state.c riscv/Greg_states_iterate.c \ + riscv/Gcreate_addr_space.c riscv/Gget_proc_info.c riscv/Gget_save_loc.c \ + riscv/Gglobal.c riscv/Ginit.c riscv/Ginit_local.c riscv/Ginit_remote.c \ + riscv/Gis_signal_frame.c riscv/Gregs.c riscv/Gresume.c riscv/Gstep.c # The list of files that go both into libunwind and libunwind-x86: noinst_HEADERS += x86/init.h x86/offsets.h x86/unwind_i.h @@ -520,6 +543,8 @@ if OS_LINUX libunwind_la_SOURCES_arm_os = arm/Gos-linux.c libunwind_la_SOURCES_arm_os_local = arm/Los-linux.c libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_linux.c + libunwind_coredump_la_SOURCES += coredump/_UCD_get_threadinfo_prstatus.c + libunwind_coredump_la_SOURCES += coredump/_UCD_get_mapinfo_linux.c endif if OS_HPUX @@ -538,6 +563,8 @@ if OS_FREEBSD libunwind_la_SOURCES_arm_os = arm/Gos-freebsd.c libunwind_la_SOURCES_arm_os_local = arm/Los-freebsd.c libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_freebsd.c + libunwind_coredump_la_SOURCES += coredump/_UCD_get_threadinfo_prstatus.c + libunwind_coredump_la_SOURCES += coredump/_UCD_get_mapinfo_generic.c endif if OS_SOLARIS @@ -635,6 +662,18 @@ if !REMOTE_ONLY endif libunwind_setjmp_la_SOURCES += tilegx/siglongjmp.S else +if ARCH_RISCV + lib_LTLIBRARIES += libunwind-riscv.la + libunwind_la_SOURCES = $(libunwind_la_SOURCES_riscv) + libunwind_riscv_la_SOURCES = $(libunwind_riscv_la_SOURCES_riscv) + libunwind_riscv_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) + libunwind_riscv_la_LIBADD = libunwind-dwarf-generic.la + libunwind_riscv_la_LIBADD += libunwind-elf64.la +if !REMOTE_ONLY + libunwind_riscv_la_LIBADD += libunwind.la -lc +endif + libunwind_setjmp_la_SOURCES += riscv/siglongjmp.S +else if ARCH_X86 lib_LTLIBRARIES += libunwind-x86.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_x86) $(libunwind_x86_la_SOURCES_os) @@ -712,6 +751,7 @@ endif # ARCH_PPC64 endif # ARCH_PPC32 endif # ARCH_X86_64 endif # ARCH_X86 +endif # ARCH_RISCV endif # ARCH_TILEGX endif # ARCH_MIPS endif # ARCH_HPPA @@ -742,6 +782,7 @@ EXTRA_DIST = $(libunwind_la_SOURCES_aarch64) \ $(libunwind_la_SOURCES_arm) \ $(libunwind_la_SOURCES_hppa) \ $(libunwind_la_SOURCES_ia64) \ + $(libunwind_la_EXTRAS_ia64) \ $(libunwind_la_SOURCES_mips) \ $(libunwind_la_SOURCES_sh) \ $(libunwind_la_SOURCES_x86) \ diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/aarch64/Gcreate_addr_space.c index f217adc745540..ac2b85e2f76ff 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Gcreate_addr_space.c @@ -37,8 +37,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) unw_addr_space_t as; /* AArch64 supports little-endian and big-endian. */ - if (byte_order != 0 && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; as = malloc (sizeof (*as)); @@ -50,7 +49,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) as->acc = *a; /* Default to little-endian for AArch64. */ - if (byte_order == 0 || byte_order == __LITTLE_ENDIAN) + if (byte_order == 0 || byte_order == UNW_LITTLE_ENDIAN) as->big_endian = 0; else as->big_endian = 1; diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Gglobal.c b/src/coreclr/pal/src/libunwind/src/aarch64/Gglobal.c index 854b54914db8b..23bececa992cf 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Gglobal.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Gglobal.c @@ -48,6 +48,8 @@ tdep_init (void) dwarf_init (); #ifndef UNW_REMOTE_ONLY + tdep_init_mem_validate (); + aarch64_local_addr_space_init (); #endif atomic_store(&tdep_init_done, 1); /* signal that we're initialized... */ diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Ginit.c b/src/coreclr/pal/src/libunwind/src/aarch64/Ginit.c index 35389762f27ed..2b08feb363b51 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Ginit.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Ginit.c @@ -24,8 +24,11 @@ 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 #include #include +#include +#include #include "unwind_i.h" @@ -81,17 +84,256 @@ get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *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}; + +#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) +{ + if (mem_validate_pipe[0] != -1) + close (mem_validate_pipe[0]); + if (mem_validate_pipe[1] != -1) + close (mem_validate_pipe[1]); + + do_pipe2 (mem_validate_pipe); +} + +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 + { + ret = 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 */ + + /* mincore could fail with EAGAIN but we conservatively return -1 + instead of looping. */ + if (mincore (addr, len, (unsigned char *)mvec) != 0) + { + 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, (unsigned char *)mvec)) == -1 && + errno == EAGAIN) {} + if (ret == 0) + { + 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 +#if defined(HAVE___CACHE_PER_THREAD) && HAVE___CACHE_PER_THREAD +// thread-local variant +static _Thread_local unw_word_t last_good_addr[NLGA]; +static _Thread_local int lga_victim; + +static int +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; +} + +#else +// global, thread safe variant +static _Atomic unw_word_t last_good_addr[NLGA]; +static _Atomic int lga_victim; + +static int +is_cached_valid_mem(unw_word_t addr) +{ + int i; + for (i = 0; i < NLGA; i++) + { + if (addr == atomic_load(&last_good_addr[i])) + return 1; + } + return 0; +} + +static void +cache_valid_mem(unw_word_t addr) +{ + int i, victim; + victim = atomic_load(&lga_victim); + unw_word_t zero = 0; + for (i = 0; i < NLGA; i++) { + if (atomic_compare_exchange_strong(&last_good_addr[victim], &zero, addr)) { + return; + } + victim = (victim + 1) % NLGA; + } + + /* All slots full. Evict the victim. */ + atomic_store(&last_good_addr[victim], addr); + victim = (victim + 1) % NLGA; + atomic_store(&lga_victim, victim); +} +#endif + +static int +validate_mem (unw_word_t addr) +{ + 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; + + if (is_cached_valid_mem(addr)) + return 0; + + if (mem_validate_func ((void *) addr, len) == -1) + return -1; + + cache_valid_mem(addr); + + return 0; +} + static int access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { - if (write) + if (unlikely (write)) { Debug (16, "mem[%lx] <- %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[%lx] -> %lx\n", addr, *val); } @@ -103,7 +345,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, void *arg) { unw_word_t *addr; - unw_tdep_context_t *uc = arg; + unw_tdep_context_t *uc = ((struct cursor *)arg)->uc; if (unw_is_fpreg (reg)) goto badreg; @@ -132,7 +374,7 @@ static int access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, int write, void *arg) { - unw_tdep_context_t *uc = arg; + unw_tdep_context_t *uc = ((struct cursor *)arg)->uc; unw_fpreg_t *addr; if (!unw_is_fpreg (reg)) @@ -182,7 +424,7 @@ aarch64_local_addr_space_init (void) local_addr_space.acc.access_fpreg = access_fpreg; local_addr_space.acc.resume = aarch64_local_resume; local_addr_space.acc.get_proc_name = get_static_proc_name; - local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + local_addr_space.big_endian = target_is_big_endian(); unw_flush_cache (&local_addr_space, 0, 0); } diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_local.c b/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_local.c index 3f0080ade06cc..4a055fb0938ba 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_local.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_local.c @@ -47,7 +47,9 @@ unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_pre Debug (1, "(cursor=%p)\n", c); c->dwarf.as = unw_local_addr_space; - c->dwarf.as_arg = uc; + c->dwarf.as_arg = c; + c->uc = uc; + c->validate = 0; return common_init (c, use_prev_instr); } diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_remote.c b/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_remote.c index 26d11ba942b18..e300173ca4722 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_remote.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Ginit_remote.c @@ -39,7 +39,16 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) Debug (1, "(cursor=%p)\n", c); c->dwarf.as = as; - c->dwarf.as_arg = as_arg; + if (as == unw_local_addr_space) + { + c->dwarf.as_arg = c; + c->uc = as_arg; + } + else + { + c->dwarf.as_arg = as_arg; + c->uc = 0; + } return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ } diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Gresume.c b/src/coreclr/pal/src/libunwind/src/aarch64/Gresume.c index 2cc161360ef53..445bac70f0dd4 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Gresume.c @@ -34,7 +34,7 @@ aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) { #ifdef __linux__ struct cursor *c = (struct cursor *) cursor; - unw_tdep_context_t *uc = c->dwarf.as_arg; + unw_tdep_context_t *uc = c->uc; if (c->sigcontext_format == AARCH64_SCF_NONE) { diff --git a/src/coreclr/pal/src/libunwind/src/aarch64/Gstep.c b/src/coreclr/pal/src/libunwind/src/aarch64/Gstep.c index fdf64a73f3304..92e2a66634ca4 100644 --- a/src/coreclr/pal/src/libunwind/src/aarch64/Gstep.c +++ b/src/coreclr/pal/src/libunwind/src/aarch64/Gstep.c @@ -70,7 +70,7 @@ aarch64_handle_signal_frame (unw_cursor_t *cursor) c->sigcontext_sp = c->dwarf.cfa; c->sigcontext_pc = c->dwarf.ip; - if (ret) + if (ret > 0) { c->sigcontext_format = AARCH64_SCF_LINUX_RT_SIGFRAME; sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF; @@ -134,14 +134,30 @@ int unw_step (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; + int validate = c->validate; int ret; Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx))\n", c, c->dwarf.ip, c->dwarf.cfa); + /* Validate all addresses before dereferencing. */ + c->validate = 1; + /* Check if this is a signal frame. */ - if (unw_is_signal_frame (cursor) > 0) + ret = unw_is_signal_frame (cursor); + if (ret > 0) return aarch64_handle_signal_frame (cursor); + else if (unlikely (ret < 0)) + { + /* IP points to non-mapped memory. */ + /* This is probably SIGBUS. */ + /* Try to load LR in IP to recover. */ + Debug(1, "Invalid address found in the call stack: 0x%lx\n", c->dwarf.ip); + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_X30], &c->dwarf.ip); + } + + /* Restore default memory validation state */ + c->validate = validate; ret = dwarf_step (&c->dwarf); Debug(1, "dwarf_step()=%d\n", ret); diff --git a/src/coreclr/pal/src/libunwind/src/arm/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/arm/Gcreate_addr_space.c index 7b2d6bacfdcd7..d4bdb4167f5b7 100644 --- a/src/coreclr/pal/src/libunwind/src/arm/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/arm/Gcreate_addr_space.c @@ -37,8 +37,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) /* * ARM supports little-endian and big-endian. */ - if (byte_order != 0 && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; as = malloc (sizeof (*as)); @@ -50,7 +49,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) as->acc = *a; /* Default to little-endian for ARM. */ - if (byte_order == 0 || byte_order == __LITTLE_ENDIAN) + if (byte_order == 0 || byte_order == UNW_LITTLE_ENDIAN) as->big_endian = 0; else as->big_endian = 1; diff --git a/src/coreclr/pal/src/libunwind/src/arm/Gex_tables.c b/src/coreclr/pal/src/libunwind/src/arm/Gex_tables.c index 2778441eca4e0..7c1f29a0c9f9a 100644 --- a/src/coreclr/pal/src/libunwind/src/arm/Gex_tables.c +++ b/src/coreclr/pal/src/libunwind/src/arm/Gex_tables.c @@ -383,7 +383,7 @@ arm_exidx_extract (struct dwarf_cursor *c, uint8_t *buf) return nbuf; } -int +static int arm_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) diff --git a/src/coreclr/pal/src/libunwind/src/arm/Gglobal.c b/src/coreclr/pal/src/libunwind/src/arm/Gglobal.c index 2fb1d21117b10..0700f930f4095 100644 --- a/src/coreclr/pal/src/libunwind/src/arm/Gglobal.c +++ b/src/coreclr/pal/src/libunwind/src/arm/Gglobal.c @@ -29,7 +29,12 @@ HIDDEN define_lock (arm_lock); HIDDEN atomic_bool tdep_init_done = 0; /* Unwinding methods to use. See UNW_METHOD_ enums */ +#if defined(__ANDROID__) +/* Android only supports three types of unwinding methods. */ +HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_DWARF | UNW_ARM_METHOD_EXIDX | UNW_ARM_METHOD_LR; +#else HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_ALL; +#endif HIDDEN void tdep_init (void) diff --git a/src/coreclr/pal/src/libunwind/src/arm/Gresume.c b/src/coreclr/pal/src/libunwind/src/arm/Gresume.c index 3b9dfb33e60a7..ed284e7277973 100644 --- a/src/coreclr/pal/src/libunwind/src/arm/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/arm/Gresume.c @@ -50,7 +50,7 @@ arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) regs[6] = uc->regs[10]; regs[7] = uc->regs[11]; /* FP */ regs[8] = uc->regs[13]; /* SP */ - regs[9] = uc->regs[14]; /* LR */ + regs[9] = uc->regs[15]; /* PC */ struct regs_overlay { char x[sizeof(regs)]; diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_access_reg_linux.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_access_reg_linux.c index 43792f849b3d7..27eef12386794 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_access_reg_linux.c +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_access_reg_linux.c @@ -57,6 +57,14 @@ _UCD_access_reg (unw_addr_space_t as, #elif defined(UNW_TARGET_S390X) if (regnum > UNW_S390X_R15) goto badreg; +#elif defined(UNW_TARGET_IA64) || defined(UNW_TARGET_HPPA) || defined(UNW_TARGET_PPC32) || defined(UNW_TARGET_PPC64) + if (regnum >= ARRAY_SIZE(ui->prstatus->pr_reg)) + goto badreg; +#elif defined(UNW_TARGET_RISCV) + if (regnum == UNW_RISCV_PC) + regnum = 0; + else if (regnum > UNW_RISCV_X31) + goto badreg; #else #if defined(UNW_TARGET_MIPS) static const uint8_t remap_regs[] = diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_corefile_elf.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_corefile_elf.c new file mode 100644 index 0000000000000..045e0437b63dd --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_corefile_elf.c @@ -0,0 +1,126 @@ +/** + * Support functions for ELF corefiles + */ +/* + 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 "_UCD_internal.h" + +#include +#include +#include +#include + + +/** + * Read an ELF segment into an allocated memory buffer. + * @param[in] ui the unwind-coredump context + * @param[in] phdr pointer to the PHDR of the segment to load + * @param[out] segment pointer to the segment loaded + * @param[out] segment_size size of the @segment in bytes + * + * Allocates an appropriately-sized buffer to contain the segment of the + * coredump described by @phdr and reads it in from the core file. + * + * The caller is responsible for freeing the allocated segment memory. + * + * @returns UNW_SUCCESS on success, something else otherwise. + */ +HIDDEN int +_UCD_elf_read_segment(struct UCD_info *ui, coredump_phdr_t *phdr, uint8_t **segment, size_t *segment_size) +{ + int ret = -UNW_EUNSPEC; + if (lseek(ui->coredump_fd, phdr->p_offset, SEEK_SET) != (off_t)phdr->p_offset) + { + Debug(0, "errno %d setting offset to %lu in '%s': %s\n", + errno, phdr->p_offset, ui->coredump_filename, strerror(errno)); + return ret; + } + + *segment_size = phdr->p_filesz; + *segment = malloc(*segment_size); + if (*segment == NULL) + { + Debug(0, "error %zu bytes of memory for segment\n", *segment_size); + return ret; + } + + if (read(ui->coredump_fd, *segment, *segment_size) != (ssize_t)*segment_size) + { + Debug(0, "errno %d reading %zu bytes from '%s': %s\n", + errno, *segment_size, ui->coredump_filename, strerror(errno)); + return ret; + } + + ret = UNW_ESUCCESS; + return ret; +} + + +/** + * Parse a PT_NOTE segment into zero or more notes and visit each one + * @param[in] segment pointer to the PT_NOTE segment + * @param[in] segment_size size of @p segment in bytes + * @param[in] visit callback to process to the notes + * @param[in] arg context to forward to the callback + * + * One PT_NOTE segment might contain many variable-length notes. Parsing them + * out is just a matter of calculating the size of each note from the size + * fields contained in the (fixed-size) note header and adjusting for 4-byte + * alignment. + * + * For each note found the @p visit callback will be invoked. If the callback + * returns anything but UNW_ESUCCESS, traversal of the notes will be terminated + * and processing will return immediately, passing the return code through. + * + * @returns UNW_SUCCESS on success or the return value from @p visit otherwise. + */ +HIDDEN int +_UCD_elf_visit_notes(uint8_t *segment, size_t segment_size, note_visitor_t visit, void *arg) +{ + int ret = UNW_ESUCCESS; + size_t parsed_size = 0; + while (parsed_size < segment_size) + { + /* + * Note that Elf32_Nhdr and Elf64_Nhdr are identical, so it doesn't matter which + * structure is chosen here. I chose the one with the larger number because + * bigger is better. + */ + Elf64_Nhdr *note = (Elf64_Nhdr *)(segment + parsed_size); + unsigned header_size = sizeof(Elf64_Nhdr); + unsigned name_size = UNW_ALIGN(note->n_namesz, 4); + unsigned desc_size = UNW_ALIGN(note->n_descsz, 4); + unsigned note_size = header_size + name_size + desc_size; + char *name = (char *)(note) + header_size; + uint8_t *desc = (uint8_t *)(note) + header_size + name_size; + + ret = visit(note->n_namesz, note->n_descsz, note->n_type, name, desc, arg); + if (ret != UNW_ESUCCESS) + { + break; + } + + parsed_size += note_size; + } + return ret; +} + diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_create.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_create.c index 4c430efb27b53..9b4b7fe39b851 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_create.c +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_create.c @@ -30,47 +30,17 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if defined(HAVE_BYTESWAP_H) #include #endif -#if defined(HAVE_ENDIAN_H) -# include -#elif defined(HAVE_SYS_ENDIAN_H) -# include -#endif -#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN -# define WE_ARE_BIG_ENDIAN 1 -# define WE_ARE_LITTLE_ENDIAN 0 -#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN -# define WE_ARE_BIG_ENDIAN 0 -# define WE_ARE_LITTLE_ENDIAN 1 -#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN -# define WE_ARE_BIG_ENDIAN 1 -# define WE_ARE_LITTLE_ENDIAN 0 -#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN -# define WE_ARE_BIG_ENDIAN 0 -# define WE_ARE_LITTLE_ENDIAN 1 -#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN -# define WE_ARE_BIG_ENDIAN 1 -# define WE_ARE_LITTLE_ENDIAN 0 -#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN -# define WE_ARE_BIG_ENDIAN 0 -# define WE_ARE_LITTLE_ENDIAN 1 -#elif defined(__386__) -# define WE_ARE_BIG_ENDIAN 0 -# define WE_ARE_LITTLE_ENDIAN 1 -#else -# error "Can't determine endianness" -#endif -#include +#if defined(HAVE_ELF_H) +# include +#elif defined(HAVE_SYS_ELF_H) +# include +#endif #include /* struct elf_prstatus */ #include "_UCD_lib.h" #include "_UCD_internal.h" -#define NOTE_DATA(_hdr) STRUCT_MEMBER_P((_hdr), sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4)) -#define NOTE_SIZE(_hdr) (sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4) + UNW_ALIGN((_hdr)->n_descsz, 4)) -#define NOTE_NEXT(_hdr) STRUCT_MEMBER_P((_hdr), NOTE_SIZE(_hdr)) -#define NOTE_FITS_IN(_hdr, _size) ((_size) >= sizeof (Elf32_Nhdr) && (_size) >= NOTE_SIZE (_hdr)) -#define NOTE_FITS(_hdr, _end) NOTE_FITS_IN((_hdr), (unsigned long)((char *)(_end) - (char *)(_hdr))) struct UCD_info * _UCD_create(const char *filename) @@ -118,7 +88,7 @@ _UCD_create(const char *filename) goto err; } - if (WE_ARE_LITTLE_ENDIAN != (elf_header32.e_ident[EI_DATA] == ELFDATA2LSB)) + if (target_is_big_endian() && (elf_header32.e_ident[EI_DATA] == ELFDATA2LSB)) { Debug(0, "'%s' is endian-incompatible\n", filename); goto err; @@ -205,72 +175,42 @@ _UCD_create(const char *filename) } } - unsigned i = 0; - coredump_phdr_t *cur = phdrs; - while (i < size) - { - Debug(2, "phdr[%03d]: type:%d", i, cur->p_type); - if (cur->p_type == PT_NOTE) - { - Elf32_Nhdr *note_hdr, *note_end; - unsigned n_threads; - - ui->note_phdr = malloc(cur->p_filesz); - if (lseek(fd, cur->p_offset, SEEK_SET) != (off_t)cur->p_offset - || (uoff_t)read(fd, ui->note_phdr, cur->p_filesz) != cur->p_filesz) - { - Debug(0, "Can't read PT_NOTE from '%s'\n", filename); - goto err; - } - - note_end = STRUCT_MEMBER_P (ui->note_phdr, cur->p_filesz); - - /* Count number of threads */ - n_threads = 0; - note_hdr = (Elf32_Nhdr *)ui->note_phdr; - while (NOTE_FITS (note_hdr, note_end)) - { - if (note_hdr->n_type == NT_PRSTATUS) - n_threads++; - - note_hdr = NOTE_NEXT (note_hdr); - } - - ui->n_threads = n_threads; - ui->threads = malloc(sizeof (void *) * n_threads); - - n_threads = 0; - note_hdr = (Elf32_Nhdr *)ui->note_phdr; - while (NOTE_FITS (note_hdr, note_end)) - { - if (note_hdr->n_type == NT_PRSTATUS) - ui->threads[n_threads++] = NOTE_DATA (note_hdr); - - note_hdr = NOTE_NEXT (note_hdr); - } - } - if (cur->p_type == PT_LOAD) - { - Debug(2, " ofs:%08llx va:%08llx filesize:%08llx memsize:%08llx flg:%x", - (unsigned long long) cur->p_offset, - (unsigned long long) cur->p_vaddr, - (unsigned long long) cur->p_filesz, - (unsigned long long) cur->p_memsz, - cur->p_flags - ); - if (cur->p_filesz < cur->p_memsz) - { - Debug(2, " partial"); - } - if (cur->p_flags & PF_X) - { - Debug(2, " executable"); - } - } - Debug(2, "\n"); - i++; - cur++; - } + int ret = _UCD_get_threadinfo(ui, phdrs, size); + if (ret != UNW_ESUCCESS) { + Debug(0, "failure retrieving thread info from core file\n"); + goto err; + } + + ret = _UCD_get_mapinfo(ui, phdrs, size); + if (ret != UNW_ESUCCESS) { + Debug(0, "failure retrieving file mapping from core file\n"); + goto err; + } + + coredump_phdr_t *cur = phdrs; + for (unsigned i = 0; i < size; ++i) + { + if (cur->p_type == PT_LOAD) + { + Debug(2, " ofs:%08llx va:%08llx filesize:%08llx memsize:%08llx flg:%x", + (unsigned long long) cur->p_offset, + (unsigned long long) cur->p_vaddr, + (unsigned long long) cur->p_filesz, + (unsigned long long) cur->p_memsz, + cur->p_flags + ); + if (cur->p_filesz < cur->p_memsz) + { + Debug(2, " partial"); + } + if (cur->p_flags & PF_X) + { + Debug(2, " executable"); + } + } + Debug(2, "\n"); + cur++; + } if (ui->n_threads == 0) { @@ -278,7 +218,7 @@ _UCD_create(const char *filename) goto err; } - ui->prstatus = ui->threads[0]; + ui->prstatus = &ui->threads[0]; return ui; @@ -295,7 +235,7 @@ int _UCD_get_num_threads(struct UCD_info *ui) void _UCD_select_thread(struct UCD_info *ui, int n) { if (n >= 0 && n < ui->n_threads) - ui->prstatus = ui->threads[n]; + ui->prstatus = &ui->threads[n]; } pid_t _UCD_get_pid(struct UCD_info *ui) @@ -358,41 +298,6 @@ int _UCD_add_backing_file_at_segment(struct UCD_info *ui, int phdr_no, const cha } //TODO: else loudly complain? Maybe even fail? - if (phdr->p_filesz != 0) - { -//TODO: loop and compare in smaller blocks - char *core_buf = malloc(phdr->p_filesz); - char *file_buf = malloc(phdr->p_filesz); - if (lseek(ui->coredump_fd, phdr->p_offset, SEEK_SET) != (off_t)phdr->p_offset - || (uoff_t)read(ui->coredump_fd, core_buf, phdr->p_filesz) != phdr->p_filesz - ) - { - Debug(0, "Error reading from coredump file\n"); - err_read: - free(core_buf); - free(file_buf); - goto err; - } - if ((uoff_t)read(fd, file_buf, phdr->p_filesz) != phdr->p_filesz) - { - Debug(0, "Error reading from '%s'\n", filename); - goto err_read; - } - int r = memcmp(core_buf, file_buf, phdr->p_filesz); - free(core_buf); - free(file_buf); - if (r != 0) - { - Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file do not match\n", - phdr_no, (unsigned long long)phdr->p_filesz - ); - } else { - Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file match\n", - phdr_no, (unsigned long long)phdr->p_filesz - ); - } - } - /* Success */ return 0; diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_elf_map_image.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_elf_map_image.c index 4b3db0bbff7ee..99fd25e83a962 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_elf_map_image.c +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_elf_map_image.c @@ -21,7 +21,11 @@ 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 +#if defined(HAVE_ELF_H) +# include +#elif defined(HAVE_SYS_ELF_H) +# include +#endif #include "_UCD_lib.h" #include "_UCD_internal.h" diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_find_proc_info.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_find_proc_info.c index 33b66c8edbe1d..35e1624ced63e 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_find_proc_info.c +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_find_proc_info.c @@ -21,7 +21,11 @@ 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 +#if defined(HAVE_ELF_H) +# include +#elif defined(HAVE_SYS_ELF_H) +# include +#endif #include "_UCD_lib.h" #include "_UCD_internal.h" @@ -31,7 +35,7 @@ get_unwind_info(struct UCD_info *ui, unw_addr_space_t as, unw_word_t ip) { unsigned long segbase, mapoff; -#if UNW_TARGET_IA64 && defined(__linux) +#if UNW_TARGET_IA64 && defined(__linux__) if (!ui->edi.ktab.start_ip && _Uia64_get_kernel_table (&ui->edi.ktab) < 0) return -UNW_ENOINFO; diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_generic.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_generic.c new file mode 100644 index 0000000000000..19945d728a774 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_generic.c @@ -0,0 +1,34 @@ +/** + * Extract filemap info from a coredump (generic) + */ +/* + 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 "_UCD_internal.h" + + +int +_UCD_get_mapinfo(struct UCD_info *ui, coredump_phdr_t *phdrs, unsigned phdr_size) +{ + int ret = UNW_ESUCCESS; /* it's OK if there are no file mappings */ + + return ret; +} diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_linux.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_linux.c new file mode 100644 index 0000000000000..0df2107fb31b2 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_mapinfo_linux.c @@ -0,0 +1,134 @@ +/** + * Extract filemap info from a coredump (Linux and similar) + */ +/* + 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 "_UCD_internal.h" + + +/** + * The format of the NT_FILE note is not well documented, but it goes something + * like this. + * + * The note has a header containing the @i count of the number of file maps, plus a + * value of the size of the offset field in each map. Since we don;t care about + * the offset field in a core file, there is no further information available on + * exactly what the means. + * + * Following the header are @count mapinfo structures. The mapinfo structure consists of + * a start address, and end address, and some wacky offset thing. The start and + * end address are the virtual addresses of a LOAD segment that was mapped from + * the named file. + * + * Following the array of mapinfo structures is a block of null-terminated C strings + * containing the mapped file names. They are ordered correspondingly to each + * entry in the map structure array. + */ +typedef struct { + unsigned long count; + unsigned long pagesz; +} linux_mapinfo_hdr_t; + +typedef struct { + unsigned long start; + unsigned long end; + unsigned long offset; +} linux_mapinfo_t; + + +/** + * Map a file note to program headers + * + * If a NT_FILE note is recognized, parse it and add the resulting backing files + * to the program header list. + * + * Any file names that end in the string "(deleted)" are ignored. + */ +static int +_handle_file_note(uint32_t n_namesz, uint32_t n_descsz, uint32_t n_type, char *name, uint8_t *desc, void *arg) +{ + struct UCD_info *ui = (struct UCD_info *)arg; +#ifdef NT_FILE + if (n_type == NT_FILE) + { + Debug(0, "found a PT_FILE note\n"); + static const char * deleted = "(deleted)"; + size_t deleted_len = strlen(deleted); + static const size_t mapinfo_offset = sizeof(linux_mapinfo_hdr_t); + + linux_mapinfo_hdr_t *mapinfo = (linux_mapinfo_hdr_t *)desc; + linux_mapinfo_t *maps = (linux_mapinfo_t *)(desc + mapinfo_offset); + char *strings = (char *)(desc + mapinfo_offset + sizeof(linux_mapinfo_t)*mapinfo->count); + for (unsigned long i = 0; i < mapinfo->count; ++i) + { + size_t len = strlen(strings); + for (unsigned p = 0; p < ui->phdrs_count; ++p) + { + if (ui->phdrs[p].p_type == PT_LOAD + && maps[i].start >= ui->phdrs[p].p_vaddr + && maps[i].end <= ui->phdrs[p].p_vaddr + ui->phdrs[p].p_filesz) + { + if (len > deleted_len && memcmp(strings + len - deleted_len, deleted, deleted_len)) + { + _UCD_add_backing_file_at_segment(ui, p, strings); + } + break; + } + } + strings += (len + 1); + } + } +#endif + return UNW_ESUCCESS; +} + + +/** + * Get filemap info from core file (Linux and similar) + * + * If there is a mapinfo not in the core file, map its contents to the phdrs. + * + * Since there may or may not be any mapinfo notes it's OK for this function to + * fail. + */ +int +_UCD_get_mapinfo(struct UCD_info *ui, coredump_phdr_t *phdrs, unsigned phdr_size) +{ + int ret = UNW_ESUCCESS; /* it's OK if there are no file mappings */ + + for (unsigned i = 0; i < phdr_size; ++i) + { + if (phdrs[i].p_type == PT_NOTE) + { + uint8_t *segment; + size_t segment_size; + ret = _UCD_elf_read_segment(ui, &phdrs[i], &segment, &segment_size); + if (ret == UNW_ESUCCESS) + { + _UCD_elf_visit_notes(segment, segment_size, _handle_file_note, ui); + free(segment); + } + } + } + + return ret; +} diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_proc_name.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_proc_name.c index 3a4c9b8213c6d..cd5ee8922324f 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_proc_name.c +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_proc_name.c @@ -64,9 +64,9 @@ _UCD_get_proc_name (unw_addr_space_t as, unw_word_t ip, { struct UCD_info *ui = arg; -#if ELF_CLASS == ELFCLASS64 +#if UNW_ELF_CLASS == UNW_ELFCLASS64 return _Uelf64_CD_get_proc_name (ui, as, ip, buf, buf_len, offp); -#elif ELF_CLASS == ELFCLASS32 +#elif UNW_ELF_CLASS == UNW_ELFCLASS32 return _Uelf32_CD_get_proc_name (ui, as, ip, buf, buf_len, offp); #else return -UNW_ENOINFO; diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_threadinfo_prstatus.c b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_threadinfo_prstatus.c new file mode 100644 index 0000000000000..455525661c5bc --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_get_threadinfo_prstatus.c @@ -0,0 +1,121 @@ +/** + * Extract threadinfo from a coredump (targets with NT_PRSTATUS) + */ +/* + 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 "_UCD_internal.h" + +#if defined(HAVE_ELF_H) +# include +#elif defined(HAVE_SYS_ELF_H) +# include +#endif + + +/** + * Accumulate a count of the number of thread notes + * + * This _UCD_elf_visit_notes() callback just increments a count for each + * NT_PRSTATUS note seen. + */ +static int +_count_thread_notes(uint32_t n_namesz, uint32_t n_descsz, uint32_t n_type, char *name, uint8_t *desc, void *arg) +{ + size_t *thread_count = (size_t *)arg; + if (n_type == NT_PRSTATUS) + { + ++*thread_count; + } + return UNW_ESUCCESS; +} + + +/** + * Save a thread note to the unwind-coredump context + * + * This _UCD_elf_visit_notes() callback just copies the actual data structure + * from any NT_PRSTATUS note seen into an array of such structures and + * increments the count. + */ +static int +_save_thread_notes(uint32_t n_namesz, uint32_t n_descsz, uint32_t n_type, char *name, uint8_t *desc, void *arg) +{ + struct UCD_info *ui = (struct UCD_info *)arg; + if (n_type == NT_PRSTATUS) + { + memcpy(&ui->threads[ui->n_threads], desc, sizeof(struct PRSTATUS_STRUCT)); + ++ui->n_threads; + } + return UNW_ESUCCESS; +} + + +/** + * Get thread info from core file + * + * On Linux threads are emulated by cloned processes sharing an address space + * and the process information is described by a note in the core file of type + * NT_PRSTATUS. In fact, on Linux, the state of a thread is described by a + * CPU-dependent group of notes but right now we're only going to care about the + * one process-status note. This statement is also true for FreeBSD. + * + * Depending on how the core file is created, there may be one PT_NOTE segment + * with multiple NT_PRSTATUS notes in it, or multiple PT_NOTE segments. Just to + * be safe, it's better to assume there are multiple PT_NOTE segments each with + * multiple NT_PRSTATUS notes, as that covers all the cases. + */ +int +_UCD_get_threadinfo(struct UCD_info *ui, coredump_phdr_t *phdrs, unsigned phdr_size) +{ + int ret = -UNW_ENOINFO; + + for (unsigned i = 0; i < phdr_size; ++i) + { + Debug(8, "phdr[%03d]: type:%d", i, phdrs[i].p_type); + if (phdrs[i].p_type == PT_NOTE) + { + size_t thread_count = 0; + uint8_t *segment; + size_t segment_size; + ret = _UCD_elf_read_segment(ui, &phdrs[i], &segment, &segment_size); + if (ret == UNW_ESUCCESS) + { + _UCD_elf_visit_notes(segment, segment_size, _count_thread_notes, &thread_count); + Debug(2, "found %zu threads\n", thread_count); + + size_t new_size = sizeof(struct PRSTATUS_STRUCT) * (ui->n_threads + thread_count); + ui->threads = realloc(ui->threads, new_size); + if (ui->threads == NULL) + { + Debug(0, "error allocating %zu bytes of memory \n", new_size); + free(segment); + return -UNW_EUNSPEC; + } + _UCD_elf_visit_notes(segment, segment_size, _save_thread_notes, ui); + + free(segment); + } + } + } + + return ret; +} diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_internal.h b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_internal.h index 3c95a2a0038c7..f51502052949b 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UCD_internal.h +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UCD_internal.h @@ -92,14 +92,20 @@ struct UCD_info void *note_phdr; /* allocated or NULL */ struct PRSTATUS_STRUCT *prstatus; /* points inside note_phdr */ int n_threads; - struct PRSTATUS_STRUCT **threads; - + struct PRSTATUS_STRUCT *threads; struct elf_dyn_info edi; }; -extern coredump_phdr_t * _UCD_get_elf_image(struct UCD_info *ui, unw_word_t ip); -#define STRUCT_MEMBER_P(struct_p, struct_offset) ((void *) ((char*) (struct_p) + (long) (struct_offset))) -#define STRUCT_MEMBER(member_type, struct_p, struct_offset) (*(member_type*) STRUCT_MEMBER_P ((struct_p), (struct_offset))) +typedef int (*note_visitor_t)(uint32_t, uint32_t, uint32_t, char *, uint8_t *, void *); + + +coredump_phdr_t * _UCD_get_elf_image(struct UCD_info *ui, unw_word_t ip); + +int _UCD_elf_read_segment(struct UCD_info *ui, coredump_phdr_t *phdr, uint8_t **segment, size_t *segment_size); +int _UCD_elf_visit_notes(uint8_t *segment, size_t segment_size, note_visitor_t visit, void *arg); +int _UCD_get_threadinfo(struct UCD_info *ui, coredump_phdr_t *phdrs, unsigned phdr_size); +int _UCD_get_mapinfo(struct UCD_info *ui, coredump_phdr_t *phdrs, unsigned phdr_size); + #endif diff --git a/src/coreclr/pal/src/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c b/src/coreclr/pal/src/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c index 739ed0569b9e6..7548d63320f33 100644 --- a/src/coreclr/pal/src/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c +++ b/src/coreclr/pal/src/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c @@ -26,9 +26,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "_UCD_lib.h" #include "_UCD_internal.h" -#if UNW_TARGET_IA64 && defined(__linux) +#if UNW_TARGET_IA64 && defined(__linux__) # include "elf64.h" # include "os-linux.h" +# include "../ptrace/_UPT_internal.h" static inline int get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, @@ -38,28 +39,26 @@ get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, struct UPT_info *ui = arg; struct map_iterator mi; char path[PATH_MAX]; - unw_dyn_info_t *di; unw_word_t res; int count = 0; maps_init (&mi, ui->pid); - while (maps_next (&mi, &lo, &hi, &off)) + while (maps_next (&mi, &lo, &hi, &off, NULL)) { if (off) continue; - invalidate_edi (&ui->edi); + invalidate_edi(&ui->edi); - if (elf_map_image (&ui->ei, path) < 0) + if (elf_map_image (&ui->edi.ei, path) < 0) /* ignore unmappable stuff like "/SYSV00001b58 (deleted)" */ continue; Debug (16, "checking object %s\n", path); - di = tdep_find_unwind_table (&ui->edi, as, path, lo, off); - if (di) + if (tdep_find_unwind_table (&ui->edi, as, path, lo, off, 0) > 0) { - res = _Uia64_find_dyn_list (as, di, arg); + res = _Uia64_find_dyn_list (as, &ui->edi.di_cache, arg); if (res && count++ == 0) { Debug (12, "dyn_info_list_addr = 0x%lx\n", (long) res); diff --git a/src/coreclr/pal/src/libunwind/src/dl-iterate-phdr.c b/src/coreclr/pal/src/libunwind/src/dl-iterate-phdr.c new file mode 100644 index 0000000000000..b14b765d9bf4e --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/dl-iterate-phdr.c @@ -0,0 +1,95 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +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(__ANDROID__) && __ANDROID_API__ < 21 + +#include +#include + +#include "libunwind_i.h" +#include "os-linux.h" + +#ifndef IS_ELF +/* Copied from NDK header. */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) +#endif + +typedef int (*unw_iterate_phdr_impl) (int (*callback) ( + struct dl_phdr_info *info, + size_t size, void *data), + void *data); + +HIDDEN int +dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, size_t size, void *data), + void *data) +{ + static int initialized = 0; + static unw_iterate_phdr_impl libc_impl; + int rc = 0; + struct map_iterator mi; + unsigned long start, end, offset, flags; + + if (!initialized) + { + libc_impl = dlsym (RTLD_NEXT, "dl_iterate_phdr"); + initialized = 1; + } + + if (libc_impl != NULL) + return libc_impl (callback, data); + + if (maps_init (&mi, getpid()) < 0) + return -1; + + while (maps_next (&mi, &start, &end, &offset, &flags)) + { + Elf_W(Ehdr) *ehdr = (Elf_W(Ehdr) *) start; + Dl_info canonical_info; + + if (mi.path[0] != '\0' && (flags & PROT_READ) != 0 && IS_ELF (*ehdr) + && dladdr (ehdr, &canonical_info) != 0 + && ehdr == canonical_info.dli_fbase) + { + struct dl_phdr_info info; + Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) (start + ehdr->e_phoff); + + info.dlpi_addr = start; + info.dlpi_name = canonical_info.dli_fname; + info.dlpi_phdr = phdr; + info.dlpi_phnum = ehdr->e_phnum; + + rc = callback (&info, sizeof (info), data); + } + } + + maps_close (&mi); + + return rc; +} + +#endif diff --git a/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_proc_info-lsb.c b/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_proc_info-lsb.c index 0cfb4d4faea05..7f170915f61f4 100644 --- a/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_proc_info-lsb.c +++ b/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_proc_info-lsb.c @@ -46,7 +46,7 @@ struct table_entry #ifndef UNW_REMOTE_ONLY -#ifdef __linux +#ifdef __linux__ #include "os-linux.h" #endif @@ -107,13 +107,18 @@ linear_search (unw_addr_space_t as, unw_word_t ip, /* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */ static int -load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) +load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local, + unw_word_t segbase, unw_word_t *load_offset) { struct elf_image ei; + Elf_W (Ehdr) *ehdr; + Elf_W (Phdr) *phdr; Elf_W (Shdr) *shdr; + int i; int ret; ei.image = NULL; + *load_offset = 0; ret = elf_w (load_debuglink) (file, &ei, is_local); if (ret != 0) @@ -127,6 +132,7 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) return 1; } +#if defined(SHF_COMPRESSED) if (shdr->sh_flags & SHF_COMPRESSED) { unsigned long destSize; @@ -135,7 +141,15 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) if (chdr->ch_type == ELFCOMPRESS_ZLIB) { *bufsize = destSize = chdr->ch_size; - GET_MEMORY(*buf, *bufsize); + + GET_MEMORY (*buf, *bufsize); + if (!*buf) + { + Debug (2, "failed to allocate zlib .debug_frame buffer, skipping\n"); + munmap(ei.image, ei.size); + return 1; + } + ret = uncompress((unsigned char *)*buf, &destSize, shdr->sh_offset + ei.image + sizeof(*chdr), shdr->sh_size - sizeof(*chdr)); @@ -161,14 +175,38 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) } else { +#endif *bufsize = shdr->sh_size; - GET_MEMORY(*buf, *bufsize); + + GET_MEMORY (*buf, *bufsize); + if (!*buf) + { + Debug (2, "failed to allocate .debug_frame buffer, skipping\n"); + munmap(ei.image, ei.size); + return 1; + } memcpy(*buf, shdr->sh_offset + ei.image, *bufsize); Debug (4, "read %zd bytes of .debug_frame from offset %zd\n", *bufsize, shdr->sh_offset); +#if defined(SHF_COMPRESSED) } +#endif + + ehdr = ei.image; + phdr = (Elf_W (Phdr) *) ((char *) ei.image + ehdr->e_phoff); + + for (i = 0; i < ehdr->e_phnum; ++i) + if (phdr[i].p_type == PT_LOAD) + { + *load_offset = segbase - phdr[i].p_vaddr; + + Debug (4, "%s load offset is 0x%zx\n", file, *load_offset); + + break; + } + munmap(ei.image, ei.size); return 0; } @@ -180,7 +218,7 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) static int find_binary_for_address (unw_word_t ip, char *name, size_t name_size) { -#if defined(__linux) && (!UNW_REMOTE_ONLY) +#if defined(__linux__) && (!UNW_REMOTE_ONLY) struct map_iterator mi; int found = 0; int pid = getpid (); @@ -189,7 +227,7 @@ find_binary_for_address (unw_word_t ip, char *name, size_t name_size) if (maps_init (&mi, pid) != 0) return 1; - while (maps_next (&mi, &segbase, &hi, &mapoff)) + while (maps_next (&mi, &segbase, &hi, &mapoff, NULL)) if (ip >= segbase && ip < hi) { size_t len = strlen (mi.path); @@ -212,8 +250,8 @@ find_binary_for_address (unw_word_t ip, char *name, size_t name_size) pointer to debug frame descriptor, or zero if not found. */ static struct unw_debug_frame_list * -locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname, - unw_word_t start, unw_word_t end) +locate_debug_info (unw_addr_space_t as, unw_word_t addr, unw_word_t segbase, + const char *dlname, unw_word_t start, unw_word_t end) { struct unw_debug_frame_list *w, *fdesc = 0; char path[PATH_MAX]; @@ -221,6 +259,7 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname, int err; char *buf; size_t bufsize; + unw_word_t load_offset; /* First, see if we loaded this frame already. */ @@ -247,14 +286,21 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname, else name = (char*) dlname; - err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space); + err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space, + segbase, &load_offset); if (!err) { - GET_MEMORY(fdesc, sizeof (struct unw_debug_frame_list)); + GET_MEMORY (fdesc, sizeof (struct unw_debug_frame_list)); + if (!fdesc) + { + Debug (2, "failed to allocate frame list entry\n"); + return 0; + } fdesc->start = start; fdesc->end = end; + fdesc->load_offset = load_offset; fdesc->debug_frame = buf; fdesc->debug_frame_size = bufsize; fdesc->index = NULL; @@ -392,7 +438,8 @@ dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip, Debug (15, "Trying to find .debug_frame for %s\n", obj_name); - fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end); + fdesc = locate_debug_info (unw_local_addr_space, ip, segbase, obj_name, start, + end); if (!fdesc) { @@ -450,6 +497,7 @@ dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip, di->format = UNW_INFO_FORMAT_TABLE; di->start_ip = fdesc->start; di->end_ip = fdesc->end; + di->load_offset = fdesc->load_offset; 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); @@ -912,12 +960,14 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, ip_base = segbase; } + Debug (6, "lookup IP 0x%lx\n", (long) (ip - ip_base - di->load_offset)); + #ifndef UNW_REMOTE_ONLY if (as == unw_local_addr_space) { - e = lookup (table, table_len, ip - ip_base); + e = lookup (table, table_len, ip - ip_base - di->load_offset); if (e && &e[1] < &table[table_len]) - last_ip = e[1].start_ip_offset + ip_base; + last_ip = e[1].start_ip_offset + ip_base + di->load_offset; else last_ip = di->end_ip; } @@ -925,7 +975,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, #endif { #ifndef UNW_LOCAL_ONLY - int32_t last_ip_offset = di->end_ip - ip_base; + int32_t last_ip_offset = di->end_ip - ip_base - di->load_offset; segbase = di->u.rti.segbase; if ((ret = remote_lookup (as, (uintptr_t) table, table_len, ip - ip_base, &ent, &last_ip_offset, arg)) < 0) @@ -933,7 +983,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, if (ret) { e = &ent; - last_ip = last_ip_offset + ip_base; + last_ip = last_ip_offset + ip_base + di->load_offset; } else e = NULL; /* no info found */ @@ -947,8 +997,8 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, unwind info. */ return -UNW_ENOINFO; } - Debug (15, "ip=0x%lx, start_ip=0x%lx\n", - (long) ip, (long) (e->start_ip_offset)); + Debug (15, "ip=0x%lx, load_offset=0x%lx, start_ip=0x%lx\n", + (long) ip, (long) di->load_offset, (long) (e->start_ip_offset)); if (debug_frame_base) fde_addr = e->fde_offset + debug_frame_base; else @@ -972,6 +1022,9 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, pi->flags = UNW_PI_FLAG_DEBUG_FRAME; } + pi->start_ip += di->load_offset; + pi->end_ip += di->load_offset; + #if defined(NEED_LAST_IP) pi->last_ip = last_ip; #else diff --git a/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_unwind_table.c b/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_unwind_table.c index f5f7ad06c3b67..a6198ad2f3189 100644 --- a/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_unwind_table.c +++ b/src/coreclr/pal/src/libunwind/src/dwarf/Gfind_unwind_table.c @@ -193,6 +193,7 @@ dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, edi->di_cache.start_ip = start_ip; edi->di_cache.end_ip = end_ip; + edi->di_cache.load_offset = 0; edi->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE; edi->di_cache.u.rti.name_ptr = 0; /* two 32-bit values (ip_offset/fde_offset) per table-entry: */ diff --git a/src/coreclr/pal/src/libunwind/src/elf32.h b/src/coreclr/pal/src/libunwind/src/elf32.h index 2c7bca4c9dcca..9747630a3d731 100644 --- a/src/coreclr/pal/src/libunwind/src/elf32.h +++ b/src/coreclr/pal/src/libunwind/src/elf32.h @@ -1,8 +1,8 @@ #ifndef elf32_h #define elf32_h -#ifndef ELF_CLASS -#define ELF_CLASS ELFCLASS32 +#ifndef UNW_ELF_CLASS +# define UNW_ELF_CLASS UNW_ELFCLASS32 #endif #include "elfxx.h" diff --git a/src/coreclr/pal/src/libunwind/src/elf64.h b/src/coreclr/pal/src/libunwind/src/elf64.h index 091fba8e1f84e..1956c73c979ed 100644 --- a/src/coreclr/pal/src/libunwind/src/elf64.h +++ b/src/coreclr/pal/src/libunwind/src/elf64.h @@ -1,8 +1,8 @@ #ifndef elf64_h #define elf64_h -#ifndef ELF_CLASS -#define ELF_CLASS ELFCLASS64 +#ifndef UNW_ELF_CLASS +# define UNW_ELF_CLASS UNW_ELFCLASS64 #endif #include "elfxx.h" diff --git a/src/coreclr/pal/src/libunwind/src/elfxx.c b/src/coreclr/pal/src/libunwind/src/elfxx.c index 2589a3d43b628..321cfb979b761 100644 --- a/src/coreclr/pal/src/libunwind/src/elfxx.c +++ b/src/coreclr/pal/src/libunwind/src/elfxx.c @@ -165,14 +165,19 @@ elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase, Elf_W (Ehdr) *ehdr; Elf_W (Phdr) *phdr; int i; + // mapoff is obtained from mmap informations, so is always aligned on a page size. + // PT_LOAD program headers p_offset however is not guaranteed to be aligned on a + // page size, ld.lld generate libraries where this is not the case. So we must + // make sure we compare both values with the same alignment. + unsigned long pagesize_alignment_mask = ~(((unsigned long)getpagesize()) - 1UL); ehdr = ei->image; phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff); for (i = 0; i < ehdr->e_phnum; ++i) - if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) + if (phdr[i].p_type == PT_LOAD && (phdr[i].p_offset & pagesize_alignment_mask) == mapoff) { - offset = segbase - phdr[i].p_vaddr; + offset = segbase - phdr[i].p_vaddr + (phdr[i].p_offset & (~pagesize_alignment_mask)); break; } diff --git a/src/coreclr/pal/src/libunwind/src/elfxx.h b/src/coreclr/pal/src/libunwind/src/elfxx.h index 830432c2ed1c9..fe5fcbcdfd4df 100644 --- a/src/coreclr/pal/src/libunwind/src/elfxx.h +++ b/src/coreclr/pal/src/libunwind/src/elfxx.h @@ -32,7 +32,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "libunwind_i.h" -#if ELF_CLASS == ELFCLASS32 +#if UNW_ELF_CLASS == UNW_ELFCLASS32 # define ELF_W(x) ELF32_##x # define Elf_W(x) Elf32_##x # define elf_w(x) _Uelf32_##x @@ -64,7 +64,7 @@ elf_w (valid_object) (struct elf_image *ei) return 0; return (memcmp (ei->image, ELFMAG, SELFMAG) == 0 - && ((uint8_t *) ei->image)[EI_CLASS] == ELF_CLASS + && ((uint8_t *) ei->image)[EI_CLASS] == UNW_ELF_CLASS && ((uint8_t *) ei->image)[EI_VERSION] != EV_NONE && ((uint8_t *) ei->image)[EI_VERSION] <= EV_CURRENT); } diff --git a/src/coreclr/pal/src/libunwind/src/hppa/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/hppa/Gcreate_addr_space.c index 8a6cb8b4e67a5..4e197c4b5709c 100644 --- a/src/coreclr/pal/src/libunwind/src/hppa/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/hppa/Gcreate_addr_space.c @@ -38,7 +38,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) /* * hppa supports only big-endian. */ - if (byte_order != 0 && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order != UNW_BIG_ENDIAN) return NULL; as = malloc (sizeof (*as)); diff --git a/src/coreclr/pal/src/libunwind/src/hppa/Gresume.c b/src/coreclr/pal/src/libunwind/src/hppa/Gresume.c index 6c11f140364b9..24f85f234242f 100644 --- a/src/coreclr/pal/src/libunwind/src/hppa/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/hppa/Gresume.c @@ -29,7 +29,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UNW_REMOTE_ONLY -#if defined(__linux) +#if defined(__linux__) # include @@ -48,12 +48,12 @@ my_rt_sigreturn (void *new_sp, int in_syscall) abort (); } -#endif /* __linux */ +#endif /* __linux__ */ HIDDEN inline int hppa_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) { -#if defined(__linux) +#if defined(__linux__) struct cursor *c = (struct cursor *) cursor; ucontext_t *uc = c->dwarf.as_arg; diff --git a/src/coreclr/pal/src/libunwind/src/ia64/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/ia64/Gcreate_addr_space.c index 7ad29cbbd3935..27a8e713cb341 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/ia64/Gcreate_addr_space.c @@ -39,9 +39,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) * IA-64 supports only big or little-endian, not weird stuff like * PDP_ENDIAN. */ - if (byte_order != 0 - && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; as = malloc (sizeof (*as)); @@ -55,9 +53,9 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) if (byte_order == 0) /* use host default: */ - as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + as->big_endian = target_is_big_endian(); else - as->big_endian = (byte_order == __BIG_ENDIAN); + as->big_endian = byte_order_is_big_endian(byte_order); return as; #endif } diff --git a/src/coreclr/pal/src/libunwind/src/ia64/Ginit.c b/src/coreclr/pal/src/libunwind/src/ia64/Ginit.c index 8601bb3ca885f..4c70a33ccd8d1 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/Ginit.c +++ b/src/coreclr/pal/src/libunwind/src/ia64/Ginit.c @@ -356,8 +356,8 @@ HIDDEN void ia64_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); - local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); -#if defined(__linux) + local_addr_space.big_endian = target_is_big_endian(); +#if defined(__linux__) local_addr_space.abi = ABI_LINUX; #elif defined(__hpux) local_addr_space.abi = ABI_HPUX; @@ -407,7 +407,7 @@ ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, unw_word_t *valp, become possible at some point in the future, the copy-in/copy-out needs to be adjusted to do byte-swapping if necessary. */ - assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN)); + assert (c->as->big_endian == target_is_big_endian()); dst = (unw_word_t *) ucp; for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8) @@ -475,7 +475,7 @@ ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *valp, become possible at some point in the future, the copy-in/copy-out needs to be adjusted to do byte-swapping if necessary. */ - assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN)); + assert (c->as->big_endian == target_is_big_endian()); dst = (unw_word_t *) ucp; for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8) diff --git a/src/coreclr/pal/src/libunwind/src/ia64/Ginit_local.c b/src/coreclr/pal/src/libunwind/src/ia64/Ginit_local.c index ed993f02adc27..2455dd285e539 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/Ginit_local.c +++ b/src/coreclr/pal/src/libunwind/src/ia64/Ginit_local.c @@ -39,7 +39,7 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) static inline void set_as_arg (struct cursor *c, unw_context_t *uc) { -#if defined(__linux) && defined(__KERNEL__) +#if defined(__linux__) && defined(__KERNEL__) c->task = current; c->as_arg = &uc->sw; #else @@ -51,7 +51,7 @@ static inline int get_initial_stack_pointers (struct cursor *c, unw_context_t *uc, unw_word_t *sp, unw_word_t *bsp) { -#if defined(__linux) +#if defined(__linux__) unw_word_t sol, bspstore; #ifdef __KERNEL__ diff --git a/src/coreclr/pal/src/libunwind/src/ia64/Gregs.c b/src/coreclr/pal/src/libunwind/src/ia64/Gregs.c index ac6f738a6cdbd..f2fd0fd846d21 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/Gregs.c +++ b/src/coreclr/pal/src/libunwind/src/ia64/Gregs.c @@ -30,7 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ static inline ia64_loc_t linux_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) { -#if !defined(UNW_LOCAL_ONLY) || defined(__linux) +#if !defined(UNW_LOCAL_ONLY) || defined(__linux__) unw_word_t addr = c->sigcontext_addr, flags, tmp_addr; int i; diff --git a/src/coreclr/pal/src/libunwind/src/ia64/Gresume.c b/src/coreclr/pal/src/libunwind/src/ia64/Gresume.c index 68fe8a659efa3..9fc6bc7ad701a 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/ia64/Gresume.c @@ -33,7 +33,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ static inline int local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) { -#if defined(__linux) +#if defined(__linux__) unw_word_t dirty_partition[2048]; /* AR.RSC.LOADRS is a 14-bit field */ unw_word_t val, sol, sof, pri_unat, n, pfs, bspstore, dirty_rnat; struct cursor *c = (struct cursor *) cursor; @@ -184,7 +184,7 @@ remote_install_cursor (struct cursor *c) unw_word_t val; int reg; -#if defined(__linux) && !defined(UNW_REMOTE_ONLY) +#if defined(__linux__) && !defined(UNW_REMOTE_ONLY) if (c->as == unw_local_addr_space) { /* Take a short-cut: we directly resume out of the cursor and @@ -233,7 +233,7 @@ remote_install_cursor (struct cursor *c) MEMIFY (IA64_REG_F31, UNW_IA64_FR + 31); } else -#endif /* __linux && !UNW_REMOTE_ONLY */ +#endif /* __linux__ && !UNW_REMOTE_ONLY */ { access_reg = c->as->acc.access_reg; access_fpreg = c->as->acc.access_fpreg; diff --git a/src/coreclr/pal/src/libunwind/src/ia64/Gstep.c b/src/coreclr/pal/src/libunwind/src/ia64/Gstep.c index df4ecb8796c6e..70455e3ae206e 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/Gstep.c +++ b/src/coreclr/pal/src/libunwind/src/ia64/Gstep.c @@ -30,7 +30,7 @@ static inline int linux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc, unw_word_t *num_regsp) { -#if defined(UNW_LOCAL_ONLY) && !defined(__linux) +#if defined(UNW_LOCAL_ONLY) && !defined(__linux__) return -UNW_EINVAL; #else unw_word_t sc_addr; @@ -64,7 +64,7 @@ static inline int linux_interrupt (struct cursor *c, ia64_loc_t prev_cfm_loc, unw_word_t *num_regsp, int marker) { -#if defined(UNW_LOCAL_ONLY) && !(defined(__linux) && defined(__KERNEL__)) +#if defined(UNW_LOCAL_ONLY) && !(defined(__linux__) && defined(__KERNEL__)) return -UNW_EINVAL; #else unw_word_t sc_addr, num_regs; diff --git a/src/coreclr/pal/src/libunwind/src/ia64/dyn_info_list.S b/src/coreclr/pal/src/libunwind/src/ia64/dyn_info_list.S index 31265f66a064d..125a9efdb4790 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/dyn_info_list.S +++ b/src/coreclr/pal/src/libunwind/src/ia64/dyn_info_list.S @@ -16,7 +16,7 @@ string "dyn-list" /* lsda */ data8 @gprel(_U_dyn_info_list) - .section .IA_64.unwind, "a", "progbits" + .section .IA_64.unwind, "ao", "unwind" data8 0, 0, @segrel(.info) #endif diff --git a/src/coreclr/pal/src/libunwind/src/ia64/unwind_i.h b/src/coreclr/pal/src/libunwind/src/ia64/unwind_i.h index 8ccbb46c93067..f92fe89c55e13 100644 --- a/src/coreclr/pal/src/libunwind/src/ia64/unwind_i.h +++ b/src/coreclr/pal/src/libunwind/src/ia64/unwind_i.h @@ -61,7 +61,7 @@ inlined_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr) case UNW_IA64_NAT + 0: addr = &unw.read_only.r0; break; case UNW_IA64_FR + 0: addr = &unw.read_only.f0; break; case UNW_IA64_FR + 1: - if (__BYTE_ORDER == __BIG_ENDIAN) + if (target_is_big_endian()) addr = &unw.read_only.f1_be; else addr = &unw.read_only.f1_le; diff --git a/src/coreclr/pal/src/libunwind/src/mips/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/mips/Gcreate_addr_space.c index 24e0d3b1536a2..acc6cf0fb8ac8 100644 --- a/src/coreclr/pal/src/libunwind/src/mips/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/mips/Gcreate_addr_space.c @@ -38,9 +38,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) * MIPS supports only big or little-endian, not weird stuff like * PDP_ENDIAN. */ - if (byte_order != 0 - && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; as = malloc (sizeof (*as)); @@ -53,9 +51,9 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) if (byte_order == 0) /* use host default: */ - as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + as->big_endian = target_is_big_endian(); else - as->big_endian = (byte_order == __BIG_ENDIAN); + as->big_endian = (byte_order == UNW_BIG_ENDIAN); /* FIXME! There is no way to specify the ABI. */ #if _MIPS_SIM == _ABIO32 diff --git a/src/coreclr/pal/src/libunwind/src/mips/Ginit.c b/src/coreclr/pal/src/libunwind/src/mips/Ginit.c index bf7a8f5a8f444..84a34352016b8 100644 --- a/src/coreclr/pal/src/libunwind/src/mips/Ginit.c +++ b/src/coreclr/pal/src/libunwind/src/mips/Ginit.c @@ -183,7 +183,7 @@ HIDDEN void mips_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); - local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + local_addr_space.big_endian = target_is_big_endian(); #if _MIPS_SIM == _ABIO32 local_addr_space.abi = UNW_MIPS_ABI_O32; #elif _MIPS_SIM == _ABIN32 diff --git a/src/coreclr/pal/src/libunwind/src/mips/Gstep.c b/src/coreclr/pal/src/libunwind/src/mips/Gstep.c index 0235d523f0399..79fea71f4de1f 100644 --- a/src/coreclr/pal/src/libunwind/src/mips/Gstep.c +++ b/src/coreclr/pal/src/libunwind/src/mips/Gstep.c @@ -214,11 +214,14 @@ unw_step (unw_cursor_t *cursor) if (unlikely (ret == -UNW_ESTOPUNWIND)) return ret; -#if _MIPS_SIM == _ABI64 if (unlikely (ret < 0)) { +#if _MIPS_SIM == _ABI64 return _step_n64(c); - } +#else + return ret; #endif + } + return (c->dwarf.ip == 0) ? 0 : 1; } diff --git a/src/coreclr/pal/src/libunwind/src/os-linux.c b/src/coreclr/pal/src/libunwind/src/os-linux.c index 8a00669fb3c0f..c42d2c5fcfcdd 100644 --- a/src/coreclr/pal/src/libunwind/src/os-linux.c +++ b/src/coreclr/pal/src/libunwind/src/os-linux.c @@ -25,6 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include +#include #include "libunwind_i.h" #include "os-linux.h" @@ -37,11 +38,15 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, struct map_iterator mi; int found = 0, rc; unsigned long hi; + char root[sizeof ("/proc/0123456789/root")], *cp; + char *full_path; + struct stat st; + if (maps_init (&mi, pid) < 0) return -1; - while (maps_next (&mi, segbase, &hi, mapoff)) + while (maps_next (&mi, segbase, &hi, mapoff, NULL)) if (ip >= *segbase && ip < hi) { found = 1; @@ -53,11 +58,36 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, maps_close (&mi); return -1; } + + full_path = mi.path; + + /* Get process root */ + memcpy (root, "/proc/", 6); + cp = unw_ltoa (root + 6, pid); + assert (cp + 6 < root + sizeof (root)); + memcpy (cp, "/root", 6); + + if (!stat(root, &st) && S_ISDIR(st.st_mode)) + { + full_path = (char*) malloc (strlen (root) + strlen (mi.path) + 1); + if (!full_path) + full_path = mi.path; + else + { + strcpy (full_path, root); + strcat (full_path, mi.path); + } + } + if (path) { - strncpy(path, mi.path, pathlen); + strncpy(path, full_path, pathlen); } - rc = elf_map_image (ei, mi.path); + rc = elf_map_image (ei, full_path); + + if (full_path && full_path != mi.path) + free (full_path); + maps_close (&mi); return rc; } diff --git a/src/coreclr/pal/src/libunwind/src/os-linux.h b/src/coreclr/pal/src/libunwind/src/os-linux.h index 5a9b0b405d96e..29aab5cf40ae4 100644 --- a/src/coreclr/pal/src/libunwind/src/os-linux.h +++ b/src/coreclr/pal/src/libunwind/src/os-linux.h @@ -201,7 +201,8 @@ scan_string (char *cp, char *valp, size_t buf_size) static inline int maps_next (struct map_iterator *mi, - unsigned long *low, unsigned long *high, unsigned long *offset) + unsigned long *low, unsigned long *high, unsigned long *offset, + unsigned long *flags) { char perm[16], dash = 0, colon = 0, *cp; unsigned long major, minor, inum; @@ -275,6 +276,22 @@ maps_next (struct map_iterator *mi, cp = scan_string (cp, NULL, 0); if (dash != '-' || colon != ':') continue; /* skip line with unknown or bad format */ + if (flags) + { + *flags = 0; + if (perm[0] == 'r') + { + *flags |= PROT_READ; + } + if (perm[1] == 'w') + { + *flags |= PROT_WRITE; + } + if (perm[2] == 'x') + { + *flags |= PROT_EXEC; + } + } return 1; } return 0; diff --git a/src/coreclr/pal/src/libunwind/src/os-solaris.c b/src/coreclr/pal/src/libunwind/src/os-solaris.c index 3c140ef29c93e..f0210db1f2b72 100644 --- a/src/coreclr/pal/src/libunwind/src/os-solaris.c +++ b/src/coreclr/pal/src/libunwind/src/os-solaris.c @@ -41,7 +41,7 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, if (maps_init (&mi, pid) < 0) return -1; - while (maps_next (&mi, segbase, &hi, mapoff)) + while (maps_next (&mi, segbase, &hi, mapoff, NULL)) if (ip >= *segbase && ip < hi) { found = 1; diff --git a/src/coreclr/pal/src/libunwind/src/ppc32/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/ppc32/Gcreate_addr_space.c index aaa68bb3543d0..0418f18f088dd 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc32/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/ppc32/Gcreate_addr_space.c @@ -40,7 +40,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) /* * We support only big-endian on Linux ppc32. */ - if (byte_order != 0 && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order != UNW_BIG_ENDIAN) return NULL; as = malloc (sizeof (*as)); diff --git a/src/coreclr/pal/src/libunwind/src/ppc32/Gresume.c b/src/coreclr/pal/src/libunwind/src/ppc32/Gresume.c index c0f95837b33c1..b0f04fa00abf8 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc32/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/ppc32/Gresume.c @@ -31,8 +31,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UNW_REMOTE_ONLY -#include - /* sigreturn() is a no-op on x86_64 glibc. */ static NORETURN inline long diff --git a/src/coreclr/pal/src/libunwind/src/ppc32/unwind_i.h b/src/coreclr/pal/src/libunwind/src/ppc32/unwind_i.h index ad32d0565441f..defce9741ef4d 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc32/unwind_i.h +++ b/src/coreclr/pal/src/libunwind/src/ppc32/unwind_i.h @@ -33,7 +33,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include -#include +#include #define ppc32_lock UNW_OBJ(lock) #define ppc32_local_resume UNW_OBJ(local_resume) diff --git a/src/coreclr/pal/src/libunwind/src/ppc64/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/ppc64/Gcreate_addr_space.c index bd48555d4e829..9e409309a65b6 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc64/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/ppc64/Gcreate_addr_space.c @@ -40,9 +40,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) /* * We support both big- and little-endian on Linux ppc64. */ - if (byte_order != 0 - && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; as = malloc (sizeof (*as)); @@ -55,16 +53,21 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) if (byte_order == 0) /* use host default: */ - as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + as->big_endian = target_is_big_endian(); else - as->big_endian = (byte_order == __BIG_ENDIAN); + as->big_endian = byte_order_is_big_endian(byte_order); +/* FreeBSD 13 and up are always ELFv2. */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 13 + as->abi = UNW_PPC64_ABI_ELFv2; +#else /* FIXME! There is no way to specify the ABI. Default to ELFv1 on big-endian and ELFv2 on little-endian. */ if (as->big_endian) as->abi = UNW_PPC64_ABI_ELFv1; else as->abi = UNW_PPC64_ABI_ELFv2; +#endif return as; #endif diff --git a/src/coreclr/pal/src/libunwind/src/ppc64/Ginit.c b/src/coreclr/pal/src/libunwind/src/ppc64/Ginit.c index 7bfb395a7923c..b9683ae2dd651 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc64/Ginit.c +++ b/src/coreclr/pal/src/libunwind/src/ppc64/Ginit.c @@ -48,13 +48,25 @@ uc_addr (ucontext_t *uc, int reg) void *addr; if ((unsigned) (reg - UNW_PPC64_R0) < 32) +#if defined(__linux__) addr = &uc->uc_mcontext.gp_regs[reg - UNW_PPC64_R0]; +#elif defined(__FreeBSD__) + addr = &uc->uc_mcontext.mc_gpr[reg - UNW_PPC64_R0]; +#endif else if ((unsigned) (reg - UNW_PPC64_F0) < 32) +#if defined(__linux__) addr = &uc->uc_mcontext.fp_regs[reg - UNW_PPC64_F0]; +#elif defined(__FreeBSD__) + addr = &uc->uc_mcontext.mc_fpreg[reg - UNW_PPC64_F0]; +#endif else if ((unsigned) (reg - UNW_PPC64_V0) < 32) +#if defined(__linux__) addr = (uc->uc_mcontext.v_regs == 0) ? NULL : &uc->uc_mcontext.v_regs->vrregs[reg - UNW_PPC64_V0][0]; +#elif defined(__FreeBSD__) + addr = &uc->uc_mcontext.mc_avec[(reg - UNW_PPC64_V0)*2]; +#endif else { @@ -80,7 +92,11 @@ uc_addr (ucontext_t *uc, int reg) default: return NULL; } +#if defined(__linux__) addr = &uc->uc_mcontext.gp_regs[gregs_idx]; +#elif defined(__FreeBSD__) + addr = &uc->uc_mcontext.mc_gpr[gregs_idx]; +#endif } return addr; } @@ -211,7 +227,7 @@ HIDDEN void ppc64_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); - local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + local_addr_space.big_endian = target_is_big_endian(); #if _CALL_ELF == 2 local_addr_space.abi = UNW_PPC64_ABI_ELFv2; #else diff --git a/src/coreclr/pal/src/libunwind/src/ppc64/Gresume.c b/src/coreclr/pal/src/libunwind/src/ppc64/Gresume.c index 0d832d0d97bd3..f9455ef85f2ff 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc64/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/ppc64/Gresume.c @@ -31,8 +31,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UNW_REMOTE_ONLY -#include - /* sigreturn() is a no-op on x86_64 glibc. */ static NORETURN inline long diff --git a/src/coreclr/pal/src/libunwind/src/ppc64/Gstep.c b/src/coreclr/pal/src/libunwind/src/ppc64/Gstep.c index f44e959105471..27c8bebc64476 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc64/Gstep.c +++ b/src/coreclr/pal/src/libunwind/src/ppc64/Gstep.c @@ -139,8 +139,8 @@ unw_step (unw_cursor_t * cursor) c->sigcontext_format = PPC_SCF_LINUX_RT_SIGFRAME; c->sigcontext_addr = ucontext; - sp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R1, 0); - ip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_NIP, 0); + sp_loc = DWARF_LOC ((ucontext + UC_MCONTEXT_GREGS_R1), 0); + ip_loc = DWARF_LOC ((ucontext + UC_MCONTEXT_GREGS_NIP), 0); ret = dwarf_get (&c->dwarf, sp_loc, &c->dwarf.cfa); if (ret < 0) @@ -311,8 +311,15 @@ unw_step (unw_cursor_t * cursor) /* Note that there is no .eh_section register column for the FPSCR register. I don't know why this is. */ +#if defined(__linux__) v_regs_loc = DWARF_LOC (ucontext + UC_MCONTEXT_V_REGS, 0); ret = dwarf_get (&c->dwarf, v_regs_loc, &v_regs_ptr); +#elif defined(__FreeBSD__) + /* Offset into main structure. */ + v_regs_ptr = (ucontext + UC_MCONTEXT_V_REGS); + ret = 0; +#endif + if (ret < 0) { Debug (2, "returning %d\n", ret); diff --git a/src/coreclr/pal/src/libunwind/src/ppc64/ucontext_i.h b/src/coreclr/pal/src/libunwind/src/ppc64/ucontext_i.h index 2ddfdb865a71b..c6a1aa4789cd8 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc64/ucontext_i.h +++ b/src/coreclr/pal/src/libunwind/src/ppc64/ucontext_i.h @@ -28,6 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#if defined(__linux__) /* These values were derived by reading /usr/src/linux-2.6.18-1.8/arch/um/include/sysdep-ppc/ptrace.h and /usr/src/linux-2.6.18-1.8/arch/powerpc/kernel/ppc32.h @@ -49,125 +50,177 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define VSCR_IDX 32 #define VRSAVE_IDX 33 +#define UC_MCONTEXT_V_REGS ( ((void *)&dmy_ctxt.uc_mcontext.v_regs - (void *)&dmy_ctxt) ) + +#define _UC_MCONTEXT_GPR(x) ( ((void *)&dmy_ctxt.uc_mcontext.gp_regs[x] - (void *)&dmy_ctxt) ) +#define _UC_MCONTEXT_FPR(x) ( ((void *)&dmy_ctxt.uc_mcontext.fp_regs[x] - (void *)&dmy_ctxt) ) +#define _UC_MCONTEXT_VR(x) ( ((void *)&dmy_vrregset.vrregs[x] - (void *)&dmy_vrregset) ) + /* These are dummy structures used only for obtaining the offsets of the various structure members. */ static ucontext_t dmy_ctxt; static vrregset_t dmy_vrregset; -#define UC_MCONTEXT_GREGS_R0 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[0] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R1 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[1] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R2 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[2] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R3 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[3] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R4 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[4] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R5 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[5] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R6 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[6] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R7 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[7] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R8 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[8] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R9 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[9] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R10 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[10] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R11 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[11] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R12 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[12] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R13 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[13] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R14 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[14] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R15 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[15] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R16 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[16] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R17 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[17] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R18 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[18] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R19 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[19] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R20 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[20] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R21 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[21] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R22 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[22] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R23 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[23] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R24 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[24] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R25 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[25] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R26 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[26] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R27 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[27] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R28 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[28] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R29 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[29] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R30 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[30] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_R31 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[31] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_NIP ((void *)&dmy_ctxt.uc_mcontext.gp_regs[NIP_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_MSR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[MSR_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_ORIG_GPR3 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[ORIG_GPR3_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_CTR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[CTR_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_LINK ((void *)&dmy_ctxt.uc_mcontext.gp_regs[LINK_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_XER ((void *)&dmy_ctxt.uc_mcontext.gp_regs[XER_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_CCR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[CCR_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_SOFTE ((void *)&dmy_ctxt.uc_mcontext.gp_regs[SOFTE_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_TRAP ((void *)&dmy_ctxt.uc_mcontext.gp_regs[TRAP_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_DAR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[DAR_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_DSISR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[DSISR_IDX] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_GREGS_RESULT ((void *)&dmy_ctxt.uc_mcontext.gp_regs[RESULT_IDX] - (void *)&dmy_ctxt) - -#define UC_MCONTEXT_FREGS_R0 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[0] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R1 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[1] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R2 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[2] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R3 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[3] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R4 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[4] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R5 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[5] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R6 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[6] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R7 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[7] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R8 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[8] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R9 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[9] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R10 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[10] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R11 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[11] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R12 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[12] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R13 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[13] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R14 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[14] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R15 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[15] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R16 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[16] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R17 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[17] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R18 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[18] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R19 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[19] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R20 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[20] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R21 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[21] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R22 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[22] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R23 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[23] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R24 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[24] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R25 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[25] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R26 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[26] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R27 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[27] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R28 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[28] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R29 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[29] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R30 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[30] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_R31 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[31] - (void *)&dmy_ctxt) -#define UC_MCONTEXT_FREGS_FPSCR ((void *)&dmy_ctxt.uc_mcontext.fp_regs[32] - (void *)&dmy_ctxt) - -#define UC_MCONTEXT_V_REGS ((void *)&dmy_ctxt.uc_mcontext.v_regs - (void *)&dmy_ctxt) - -#define UC_MCONTEXT_VREGS_R0 ((void *)&dmy_vrregset.vrregs[0] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R1 ((void *)&dmy_vrregset.vrregs[1] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R2 ((void *)&dmy_vrregset.vrregs[2] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R3 ((void *)&dmy_vrregset.vrregs[3] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R4 ((void *)&dmy_vrregset.vrregs[4] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R5 ((void *)&dmy_vrregset.vrregs[5] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R6 ((void *)&dmy_vrregset.vrregs[6] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R7 ((void *)&dmy_vrregset.vrregs[7] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R8 ((void *)&dmy_vrregset.vrregs[8] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R9 ((void *)&dmy_vrregset.vrregs[9] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R10 ((void *)&dmy_vrregset.vrregs[10] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R11 ((void *)&dmy_vrregset.vrregs[11] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R12 ((void *)&dmy_vrregset.vrregs[12] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R13 ((void *)&dmy_vrregset.vrregs[13] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R14 ((void *)&dmy_vrregset.vrregs[14] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R15 ((void *)&dmy_vrregset.vrregs[15] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R16 ((void *)&dmy_vrregset.vrregs[16] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R17 ((void *)&dmy_vrregset.vrregs[17] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R18 ((void *)&dmy_vrregset.vrregs[18] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R19 ((void *)&dmy_vrregset.vrregs[19] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R20 ((void *)&dmy_vrregset.vrregs[20] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R21 ((void *)&dmy_vrregset.vrregs[21] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R22 ((void *)&dmy_vrregset.vrregs[22] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R23 ((void *)&dmy_vrregset.vrregs[23] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R24 ((void *)&dmy_vrregset.vrregs[24] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R25 ((void *)&dmy_vrregset.vrregs[25] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R26 ((void *)&dmy_vrregset.vrregs[26] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R27 ((void *)&dmy_vrregset.vrregs[27] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R28 ((void *)&dmy_vrregset.vrregs[28] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R29 ((void *)&dmy_vrregset.vrregs[29] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R30 ((void *)&dmy_vrregset.vrregs[30] - (void *)&dmy_vrregset) -#define UC_MCONTEXT_VREGS_R31 ((void *)&dmy_vrregset.vrregs[31] - (void *)&dmy_vrregset) +#elif defined(__FreeBSD__) +/* See /usr/src/sys/powerpc/include/ucontext.h. + FreeBSD uses a different structure than Linux. +*/ + +#define NIP_IDX 36 +#define MSR_IDX 37 +//#define ORIG_GPR3_IDX +#define CTR_IDX 35 +#define LINK_IDX 32 +#define XER_IDX 34 +#define CCR_IDX 33 +//#define SOFTE_IDX +//#define TRAP_IDX +#define DAR_IDX 39 +#define DSISR_IDX 40 +//#define RESULT_IDX + +#define UC_MCONTEXT_V_REGS (((void *)&dmy_ctxt.mc_avec - (void *)&dmy_ctxt)) + +#define _UC_MCONTEXT_GPR(_x) ( ((void *)&dmy_ctxt.mc_gpr[_x] - (void *)&dmy_ctxt) ) +#define _UC_MCONTEXT_FPR(_x) ( ((void *)&dmy_ctxt.mc_fpreg[_x] - (void *)&dmy_ctxt) ) +#define _UC_MCONTEXT_VR(_x) ( ((void *)&dmy_ctxt.mc_avec[_x] - (void *)&dmy_ctxt.mc_avec) ) + +/* These are dummy structures used only for obtaining the offsets of the + various structure members. */ +static struct __mcontext dmy_ctxt; + +#else +#error "Not implemented!" +#endif + +#define UC_MCONTEXT_GREGS_R0 _UC_MCONTEXT_GPR(0) +#define UC_MCONTEXT_GREGS_R1 _UC_MCONTEXT_GPR(1) +#define UC_MCONTEXT_GREGS_R2 _UC_MCONTEXT_GPR(2) +#define UC_MCONTEXT_GREGS_R3 _UC_MCONTEXT_GPR(3) +#define UC_MCONTEXT_GREGS_R4 _UC_MCONTEXT_GPR(4) +#define UC_MCONTEXT_GREGS_R5 _UC_MCONTEXT_GPR(5) +#define UC_MCONTEXT_GREGS_R6 _UC_MCONTEXT_GPR(6) +#define UC_MCONTEXT_GREGS_R7 _UC_MCONTEXT_GPR(7) +#define UC_MCONTEXT_GREGS_R8 _UC_MCONTEXT_GPR(8) +#define UC_MCONTEXT_GREGS_R9 _UC_MCONTEXT_GPR(9) +#define UC_MCONTEXT_GREGS_R10 _UC_MCONTEXT_GPR(10) +#define UC_MCONTEXT_GREGS_R11 _UC_MCONTEXT_GPR(11) +#define UC_MCONTEXT_GREGS_R12 _UC_MCONTEXT_GPR(12) +#define UC_MCONTEXT_GREGS_R13 _UC_MCONTEXT_GPR(13) +#define UC_MCONTEXT_GREGS_R14 _UC_MCONTEXT_GPR(14) +#define UC_MCONTEXT_GREGS_R15 _UC_MCONTEXT_GPR(15) +#define UC_MCONTEXT_GREGS_R16 _UC_MCONTEXT_GPR(16) +#define UC_MCONTEXT_GREGS_R17 _UC_MCONTEXT_GPR(17) +#define UC_MCONTEXT_GREGS_R18 _UC_MCONTEXT_GPR(18) +#define UC_MCONTEXT_GREGS_R19 _UC_MCONTEXT_GPR(19) +#define UC_MCONTEXT_GREGS_R20 _UC_MCONTEXT_GPR(20) +#define UC_MCONTEXT_GREGS_R21 _UC_MCONTEXT_GPR(21) +#define UC_MCONTEXT_GREGS_R22 _UC_MCONTEXT_GPR(22) +#define UC_MCONTEXT_GREGS_R23 _UC_MCONTEXT_GPR(23) +#define UC_MCONTEXT_GREGS_R24 _UC_MCONTEXT_GPR(24) +#define UC_MCONTEXT_GREGS_R25 _UC_MCONTEXT_GPR(25) +#define UC_MCONTEXT_GREGS_R26 _UC_MCONTEXT_GPR(26) +#define UC_MCONTEXT_GREGS_R27 _UC_MCONTEXT_GPR(27) +#define UC_MCONTEXT_GREGS_R28 _UC_MCONTEXT_GPR(28) +#define UC_MCONTEXT_GREGS_R29 _UC_MCONTEXT_GPR(29) +#define UC_MCONTEXT_GREGS_R30 _UC_MCONTEXT_GPR(30) +#define UC_MCONTEXT_GREGS_R31 _UC_MCONTEXT_GPR(31) +#define UC_MCONTEXT_GREGS_NIP _UC_MCONTEXT_GPR(NIP_IDX) +#define UC_MCONTEXT_GREGS_MSR _UC_MCONTEXT_GPR(MSR_IDX) +#ifdef ORIG_GPR3_IDX +#define UC_MCONTEXT_GREGS_ORIG_GPR3 _UC_MCONTEXT_GPR(ORIG_GPR3_IDX) +#endif +#define UC_MCONTEXT_GREGS_CTR _UC_MCONTEXT_GPR(CTR_IDX) +#define UC_MCONTEXT_GREGS_LINK _UC_MCONTEXT_GPR(LINK_IDX) +#define UC_MCONTEXT_GREGS_XER _UC_MCONTEXT_GPR(XER_IDX) +#define UC_MCONTEXT_GREGS_CCR _UC_MCONTEXT_GPR(CCR_IDX) +#ifdef SOFTE_IDX +#define UC_MCONTEXT_GREGS_SOFTE _UC_MCONTEXT_GPR(SOFTE_IDX) +#endif +#ifdef TRAP_IDX +#define UC_MCONTEXT_GREGS_TRAP _UC_MCONTEXT_GPR(TRAP_IDX) +#endif +#define UC_MCONTEXT_GREGS_DAR _UC_MCONTEXT_GPR(DAR_IDX) +#define UC_MCONTEXT_GREGS_DSISR _UC_MCONTEXT_GPR(DSISR_IDX) +#ifdef RESULT_IDX +#define UC_MCONTEXT_GREGS_RESULT _UC_MCONTEXT_GPR(RESULT_IDX) +#endif + +#define UC_MCONTEXT_FREGS_R0 _UC_MCONTEXT_FPR(0) +#define UC_MCONTEXT_FREGS_R1 _UC_MCONTEXT_FPR(1) +#define UC_MCONTEXT_FREGS_R2 _UC_MCONTEXT_FPR(2) +#define UC_MCONTEXT_FREGS_R3 _UC_MCONTEXT_FPR(3) +#define UC_MCONTEXT_FREGS_R4 _UC_MCONTEXT_FPR(4) +#define UC_MCONTEXT_FREGS_R5 _UC_MCONTEXT_FPR(5) +#define UC_MCONTEXT_FREGS_R6 _UC_MCONTEXT_FPR(6) +#define UC_MCONTEXT_FREGS_R7 _UC_MCONTEXT_FPR(7) +#define UC_MCONTEXT_FREGS_R8 _UC_MCONTEXT_FPR(8) +#define UC_MCONTEXT_FREGS_R9 _UC_MCONTEXT_FPR(9) +#define UC_MCONTEXT_FREGS_R10 _UC_MCONTEXT_FPR(10) +#define UC_MCONTEXT_FREGS_R11 _UC_MCONTEXT_FPR(11) +#define UC_MCONTEXT_FREGS_R12 _UC_MCONTEXT_FPR(12) +#define UC_MCONTEXT_FREGS_R13 _UC_MCONTEXT_FPR(13) +#define UC_MCONTEXT_FREGS_R14 _UC_MCONTEXT_FPR(14) +#define UC_MCONTEXT_FREGS_R15 _UC_MCONTEXT_FPR(15) +#define UC_MCONTEXT_FREGS_R16 _UC_MCONTEXT_FPR(16) +#define UC_MCONTEXT_FREGS_R17 _UC_MCONTEXT_FPR(17) +#define UC_MCONTEXT_FREGS_R18 _UC_MCONTEXT_FPR(18) +#define UC_MCONTEXT_FREGS_R19 _UC_MCONTEXT_FPR(19) +#define UC_MCONTEXT_FREGS_R20 _UC_MCONTEXT_FPR(20) +#define UC_MCONTEXT_FREGS_R21 _UC_MCONTEXT_FPR(21) +#define UC_MCONTEXT_FREGS_R22 _UC_MCONTEXT_FPR(22) +#define UC_MCONTEXT_FREGS_R23 _UC_MCONTEXT_FPR(23) +#define UC_MCONTEXT_FREGS_R24 _UC_MCONTEXT_FPR(24) +#define UC_MCONTEXT_FREGS_R25 _UC_MCONTEXT_FPR(25) +#define UC_MCONTEXT_FREGS_R26 _UC_MCONTEXT_FPR(26) +#define UC_MCONTEXT_FREGS_R27 _UC_MCONTEXT_FPR(27) +#define UC_MCONTEXT_FREGS_R28 _UC_MCONTEXT_FPR(28) +#define UC_MCONTEXT_FREGS_R29 _UC_MCONTEXT_FPR(29) +#define UC_MCONTEXT_FREGS_R30 _UC_MCONTEXT_FPR(30) +#define UC_MCONTEXT_FREGS_R31 _UC_MCONTEXT_FPR(31) +#define UC_MCONTEXT_FREGS_FPSCR _UC_MCONTEXT_FPR(32) + + +#define UC_MCONTEXT_VREGS_R0 _UC_MCONTEXT_VR(0) +#define UC_MCONTEXT_VREGS_R1 _UC_MCONTEXT_VR(1) +#define UC_MCONTEXT_VREGS_R2 _UC_MCONTEXT_VR(2) +#define UC_MCONTEXT_VREGS_R3 _UC_MCONTEXT_VR(3) +#define UC_MCONTEXT_VREGS_R4 _UC_MCONTEXT_VR(4) +#define UC_MCONTEXT_VREGS_R5 _UC_MCONTEXT_VR(5) +#define UC_MCONTEXT_VREGS_R6 _UC_MCONTEXT_VR(6) +#define UC_MCONTEXT_VREGS_R7 _UC_MCONTEXT_VR(7) +#define UC_MCONTEXT_VREGS_R8 _UC_MCONTEXT_VR(8) +#define UC_MCONTEXT_VREGS_R9 _UC_MCONTEXT_VR(9) +#define UC_MCONTEXT_VREGS_R10 _UC_MCONTEXT_VR(10) +#define UC_MCONTEXT_VREGS_R11 _UC_MCONTEXT_VR(11) +#define UC_MCONTEXT_VREGS_R12 _UC_MCONTEXT_VR(12) +#define UC_MCONTEXT_VREGS_R13 _UC_MCONTEXT_VR(13) +#define UC_MCONTEXT_VREGS_R14 _UC_MCONTEXT_VR(14) +#define UC_MCONTEXT_VREGS_R15 _UC_MCONTEXT_VR(15) +#define UC_MCONTEXT_VREGS_R16 _UC_MCONTEXT_VR(16) +#define UC_MCONTEXT_VREGS_R17 _UC_MCONTEXT_VR(17) +#define UC_MCONTEXT_VREGS_R18 _UC_MCONTEXT_VR(18) +#define UC_MCONTEXT_VREGS_R19 _UC_MCONTEXT_VR(19) +#define UC_MCONTEXT_VREGS_R20 _UC_MCONTEXT_VR(20) +#define UC_MCONTEXT_VREGS_R21 _UC_MCONTEXT_VR(21) +#define UC_MCONTEXT_VREGS_R22 _UC_MCONTEXT_VR(22) +#define UC_MCONTEXT_VREGS_R23 _UC_MCONTEXT_VR(23) +#define UC_MCONTEXT_VREGS_R24 _UC_MCONTEXT_VR(24) +#define UC_MCONTEXT_VREGS_R25 _UC_MCONTEXT_VR(25) +#define UC_MCONTEXT_VREGS_R26 _UC_MCONTEXT_VR(26) +#define UC_MCONTEXT_VREGS_R27 _UC_MCONTEXT_VR(27) +#define UC_MCONTEXT_VREGS_R28 _UC_MCONTEXT_VR(28) +#define UC_MCONTEXT_VREGS_R29 _UC_MCONTEXT_VR(29) +#define UC_MCONTEXT_VREGS_R30 _UC_MCONTEXT_VR(30) +#define UC_MCONTEXT_VREGS_R31 _UC_MCONTEXT_VR(31) +#if defined(__linux__) #define UC_MCONTEXT_VREGS_VSCR ((void *)&dmy_vrregset.vscr - (void *)&dmy_vrregset) #define UC_MCONTEXT_VREGS_VRSAVE ((void *)&dmy_vrregset.vrsave - (void *)&dmy_vrregset) +#elif defined(__FreeBSD__) +#define UC_MCONTEXT_VREGS_VSCR ((void *)&dmy_ctxt.mc_av[0] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_VREGS_VRSAVE ((void *)&dmy_ctxt.mc_av[1] - (void *)&dmy_ctxt) +#else +#error "Not implemented!" +#endif #endif diff --git a/src/coreclr/pal/src/libunwind/src/ppc64/unwind_i.h b/src/coreclr/pal/src/libunwind/src/ppc64/unwind_i.h index 26bbc2df83af7..96c279a5d9e1a 100644 --- a/src/coreclr/pal/src/libunwind/src/ppc64/unwind_i.h +++ b/src/coreclr/pal/src/libunwind/src/ppc64/unwind_i.h @@ -33,7 +33,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include -#include +#include #define ppc64_lock UNW_OBJ(lock) #define ppc64_local_resume UNW_OBJ(local_resume) diff --git a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_fpreg.c b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_fpreg.c index 37cd4ffe1c2f7..bae343833932e 100644 --- a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_fpreg.c +++ b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_fpreg.c @@ -87,6 +87,9 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, #elif defined(__aarch64__) if ((unsigned) reg < UNW_AARCH64_V0 || (unsigned) reg > UNW_AARCH64_V31) return -UNW_EBADREG; +#elif defined(__powerpc64__) + if ((unsigned) reg < UNW_PPC64_F0 || (unsigned) reg > UNW_PPC64_F31) + return -UNW_EBADREG; #else #error Fix me #endif @@ -104,6 +107,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, memcpy(&fpreg.fpr[reg], val, sizeof(unw_fpreg_t)); #elif defined(__aarch64__) memcpy(&fpreg.fp_q[reg], val, sizeof(unw_fpreg_t)); +#elif defined(__powerpc64__) + memcpy(&fpreg.fpreg[reg], val, sizeof(unw_fpreg_t)); #else #error Fix me #endif @@ -118,6 +123,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, memcpy(val, &fpreg.fpr[reg], sizeof(unw_fpreg_t)); #elif defined(__aarch64__) memcpy(val, &fpreg.fp_q[reg], sizeof(unw_fpreg_t)); +#elif defined(__powerpc64__) + memcpy(val, &fpreg.fpreg[reg], sizeof(unw_fpreg_t)); #else #error Fix me #endif diff --git a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_reg.c b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_reg.c index ce25c783b043a..0e247053f13bc 100644 --- a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_reg.c +++ b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_access_reg.c @@ -268,6 +268,16 @@ _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, } #endif /* End of IA64 */ +#if UNW_TARGET_RISCV + if (reg == UNW_RISCV_X0) { + if (write) + goto badreg; + + *val = 0; + return 0; + } +#endif /* End of RISCV */ + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) { #if UNW_DEBUG diff --git a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_find_proc_info.c b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_find_proc_info.c index b3209f451ea9f..0450b0847b459 100644 --- a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_find_proc_info.c +++ b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_find_proc_info.c @@ -38,7 +38,7 @@ get_unwind_info (struct elf_dyn_info *edi, pid_t pid, unw_addr_space_t as, unw_w unsigned long segbase, mapoff; char path[PATH_MAX]; -#if UNW_TARGET_IA64 && defined(__linux) +#if UNW_TARGET_IA64 && defined(__linux__) if (!edi->ktab.start_ip && _Uia64_get_kernel_table (&edi->ktab) < 0) return -UNW_ENOINFO; diff --git a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c index 16671d453e1f2..a71f80d3dbd9d 100644 --- a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c +++ b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c @@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "_UPT_internal.h" -#if UNW_TARGET_IA64 && defined(__linux) +#if UNW_TARGET_IA64 && defined(__linux__) # include "elf64.h" # include "os-linux.h" @@ -41,7 +41,7 @@ get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, int count = 0; maps_init (&mi, ui->pid); - while (maps_next (&mi, &lo, &hi, &off)) + while (maps_next (&mi, &lo, &hi, &off, NULL)) { if (off) continue; diff --git a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_proc_name.c b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_proc_name.c index 79c1f38e256ce..4fc93e747719b 100644 --- a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_proc_name.c +++ b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_get_proc_name.c @@ -32,9 +32,9 @@ _UPT_get_proc_name (unw_addr_space_t as, unw_word_t ip, { struct UPT_info *ui = arg; -#if ELF_CLASS == ELFCLASS64 +#if UNW_ELF_CLASS == UNW_ELFCLASS64 return _Uelf64_get_proc_name (as, ui->pid, ip, buf, buf_len, offp); -#elif ELF_CLASS == ELFCLASS32 +#elif UNW_ELF_CLASS == UNW_ELFCLASS32 return _Uelf32_get_proc_name (as, ui->pid, ip, buf, buf_len, offp); #else return -UNW_ENOINFO; diff --git a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_reg_offset.c b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_reg_offset.c index 52be799980db3..b7dd3b79a8afe 100644 --- a/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_reg_offset.c +++ b/src/coreclr/pal/src/libunwind/src/ptrace/_UPT_reg_offset.c @@ -28,10 +28,57 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#ifdef HAVE_ASM_PTRACE_H +# include +#endif + #ifdef HAVE_ASM_PTRACE_OFFSETS_H # include #endif +#if defined(__powerpc64__) && defined(__FreeBSD__) +#define PT_R0 0 +#define PT_R1 1 +#define PT_R2 2 +#define PT_R3 3 +#define PT_R4 4 +#define PT_R5 5 +#define PT_R6 6 +#define PT_R7 7 +#define PT_R8 8 +#define PT_R9 9 +#define PT_R10 10 +#define PT_R11 11 +#define PT_R12 12 +#define PT_R13 13 +#define PT_R14 14 +#define PT_R15 15 +#define PT_R16 16 +#define PT_R17 17 +#define PT_R18 18 +#define PT_R19 19 +#define PT_R20 20 +#define PT_R21 21 +#define PT_R22 22 +#define PT_R23 23 +#define PT_R24 24 +#define PT_R25 25 +#define PT_R26 26 +#define PT_R27 27 +#define PT_R28 28 +#define PT_R29 29 +#define PT_R30 30 +#define PT_R31 31 +#define PT_NIP 32 +#define PT_CTR 35 +#define PT_LNK 36 +#define PT_XER 37 +#define PT_FPR0 48 +#define PT_VR0 82 +#define PT_VSCR (PT_VR0 + 32*2 + 1) +#define PT_VRSAVE (PT_VR0 + 33*2) +#endif + const int _UPT_reg_offset[UNW_REG_LAST + 1] = { #ifdef HAVE_ASM_PTRACE_OFFSETS_H @@ -666,6 +713,47 @@ const int _UPT_reg_offset[UNW_REG_LAST + 1] = [UNW_S390X_F14] = 0x150, [UNW_S390X_F15] = 0x150, [UNW_S390X_IP] = 0x08 +#elif defined(UNW_TARGET_RISCV) + +#if __riscv_xlen == 64 +# define RISCV_REG_OFFSET(x) (8*x) +#elif __riscv_xlen == 32 +# define RISCV_REG_OFFSET(x) (4*x) +#else +# error "Unsupported address size" +#endif + [UNW_RISCV_PC] = RISCV_REG_OFFSET(0), + [UNW_RISCV_X1] = RISCV_REG_OFFSET(1), + [UNW_RISCV_X2] = RISCV_REG_OFFSET(2), + [UNW_RISCV_X3] = RISCV_REG_OFFSET(3), + [UNW_RISCV_X4] = RISCV_REG_OFFSET(4), + [UNW_RISCV_X5] = RISCV_REG_OFFSET(5), + [UNW_RISCV_X6] = RISCV_REG_OFFSET(6), + [UNW_RISCV_X7] = RISCV_REG_OFFSET(7), + [UNW_RISCV_X8] = RISCV_REG_OFFSET(8), + [UNW_RISCV_X9] = RISCV_REG_OFFSET(9), + [UNW_RISCV_X10] = RISCV_REG_OFFSET(10), + [UNW_RISCV_X11] = RISCV_REG_OFFSET(11), + [UNW_RISCV_X12] = RISCV_REG_OFFSET(12), + [UNW_RISCV_X13] = RISCV_REG_OFFSET(13), + [UNW_RISCV_X14] = RISCV_REG_OFFSET(14), + [UNW_RISCV_X15] = RISCV_REG_OFFSET(15), + [UNW_RISCV_X16] = RISCV_REG_OFFSET(16), + [UNW_RISCV_X17] = RISCV_REG_OFFSET(17), + [UNW_RISCV_X18] = RISCV_REG_OFFSET(18), + [UNW_RISCV_X19] = RISCV_REG_OFFSET(19), + [UNW_RISCV_X20] = RISCV_REG_OFFSET(20), + [UNW_RISCV_X21] = RISCV_REG_OFFSET(21), + [UNW_RISCV_X22] = RISCV_REG_OFFSET(22), + [UNW_RISCV_X23] = RISCV_REG_OFFSET(23), + [UNW_RISCV_X24] = RISCV_REG_OFFSET(24), + [UNW_RISCV_X25] = RISCV_REG_OFFSET(25), + [UNW_RISCV_X26] = RISCV_REG_OFFSET(26), + [UNW_RISCV_X27] = RISCV_REG_OFFSET(27), + [UNW_RISCV_X28] = RISCV_REG_OFFSET(28), + [UNW_RISCV_X29] = RISCV_REG_OFFSET(29), + [UNW_RISCV_X30] = RISCV_REG_OFFSET(30), + [UNW_RISCV_X31] = RISCV_REG_OFFSET(31), #else # error Fix me. #endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Gapply_reg_state.c b/src/coreclr/pal/src/libunwind/src/riscv/Gapply_reg_state.c new file mode 100644 index 0000000000000..09299ac585244 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gapply_reg_state.c @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + Copyright (c) 2004 Max Asbock + +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/pal/src/libunwind/src/riscv/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/riscv/Gcreate_addr_space.c new file mode 100644 index 0000000000000..5cf016417db13 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gcreate_addr_space.c @@ -0,0 +1,54 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +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 + +#include "unwind_i.h" + +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; + + /* + * We only support little-endian for now. + */ + if (byte_order != 0 && byte_order != __LITTLE_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/pal/src/libunwind/src/riscv/Gget_proc_info.c b/src/coreclr/pal/src/libunwind/src/riscv/Gget_proc_info.c new file mode 100644 index 0000000000000..ff11c59bdad8f --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gget_proc_info.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +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; + int ret; + + ret = dwarf_make_proc_info (&c->dwarf); + + if (ret < 0) { + /* No DWARF info? */ + 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/pal/src/libunwind/src/riscv/Gget_save_loc.c b/src/coreclr/pal/src/libunwind/src/riscv/Gget_save_loc.c new file mode 100644 index 0000000000000..342f8654fbc66 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gget_save_loc.c @@ -0,0 +1,97 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2021 Zhaofeng Li + +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; + + switch (reg) + { + case UNW_RISCV_X1: + case UNW_RISCV_X2: + case UNW_RISCV_X3: + case UNW_RISCV_X4: + case UNW_RISCV_X5: + case UNW_RISCV_X6: + case UNW_RISCV_X7: + case UNW_RISCV_X8: + case UNW_RISCV_X9: + case UNW_RISCV_X10: + case UNW_RISCV_X11: + case UNW_RISCV_X12: + case UNW_RISCV_X13: + case UNW_RISCV_X14: + case UNW_RISCV_X15: + case UNW_RISCV_X16: + case UNW_RISCV_X17: + case UNW_RISCV_X18: + case UNW_RISCV_X19: + case UNW_RISCV_X20: + case UNW_RISCV_X21: + case UNW_RISCV_X22: + case UNW_RISCV_X23: + case UNW_RISCV_X24: + case UNW_RISCV_X25: + case UNW_RISCV_X26: + case UNW_RISCV_X27: + case UNW_RISCV_X28: + case UNW_RISCV_X29: + case UNW_RISCV_X30: + case UNW_RISCV_X31: + case UNW_RISCV_PC: + loc = c->dwarf.loc[reg - UNW_RISCV_X0]; + break; + + default: + loc = DWARF_NULL_LOC; /* default to "not saved" */ + 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/pal/src/libunwind/src/riscv/Gglobal.c b/src/coreclr/pal/src/libunwind/src/riscv/Gglobal.c new file mode 100644 index 0000000000000..cb8009e1d2696 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gglobal.c @@ -0,0 +1,128 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2021 Zhaofeng Li + +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 "dwarf_i.h" + +HIDDEN define_lock (riscv_lock); +HIDDEN atomic_bool tdep_init_done = 0; + +/* Our ordering is already consistent with + https://github.com/riscv/riscv-elf-psabi-doc/blob/74ecf07bcebd0cb4bf3c39f3f9d96946cd6aba61/riscv-elf.md#dwarf-register-numbers- */ +HIDDEN const uint8_t dwarf_to_unw_regnum_map[] = + { + UNW_RISCV_X0, + UNW_RISCV_X1, + UNW_RISCV_X2, + UNW_RISCV_X3, + UNW_RISCV_X4, + UNW_RISCV_X5, + UNW_RISCV_X6, + UNW_RISCV_X7, + UNW_RISCV_X8, + UNW_RISCV_X9, + UNW_RISCV_X10, + UNW_RISCV_X11, + UNW_RISCV_X12, + UNW_RISCV_X13, + UNW_RISCV_X14, + UNW_RISCV_X15, + UNW_RISCV_X16, + UNW_RISCV_X17, + UNW_RISCV_X18, + UNW_RISCV_X19, + UNW_RISCV_X20, + UNW_RISCV_X21, + UNW_RISCV_X22, + UNW_RISCV_X23, + UNW_RISCV_X24, + UNW_RISCV_X25, + UNW_RISCV_X26, + UNW_RISCV_X27, + UNW_RISCV_X28, + UNW_RISCV_X29, + UNW_RISCV_X30, + UNW_RISCV_X31, + + UNW_RISCV_F0, + UNW_RISCV_F1, + UNW_RISCV_F2, + UNW_RISCV_F3, + UNW_RISCV_F4, + UNW_RISCV_F5, + UNW_RISCV_F6, + UNW_RISCV_F7, + UNW_RISCV_F8, + UNW_RISCV_F9, + UNW_RISCV_F10, + UNW_RISCV_F11, + UNW_RISCV_F12, + UNW_RISCV_F13, + UNW_RISCV_F14, + UNW_RISCV_F15, + UNW_RISCV_F16, + UNW_RISCV_F17, + UNW_RISCV_F18, + UNW_RISCV_F19, + UNW_RISCV_F20, + UNW_RISCV_F21, + UNW_RISCV_F22, + UNW_RISCV_F23, + UNW_RISCV_F24, + UNW_RISCV_F25, + UNW_RISCV_F26, + UNW_RISCV_F27, + UNW_RISCV_F28, + UNW_RISCV_F29, + UNW_RISCV_F30, + UNW_RISCV_F31, + }; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&riscv_lock, saved_mask); + + if (atomic_load(&tdep_init_done)) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + tdep_init_mem_validate (); + + riscv_local_addr_space_init (); +#endif + atomic_store(&tdep_init_done, 1); /* signal that we're initialized... */ + + out: + lock_release (&riscv_lock, saved_mask); +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Ginit.c b/src/coreclr/pal/src/libunwind/src/riscv/Ginit.c new file mode 100644 index 0000000000000..907f72962a9e7 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Ginit.c @@ -0,0 +1,448 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + Copyright (C) 2021 Zhaofeng Li + +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 +#include +#include + +#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; + +/* + NB: as_arg is the cursor (see Ginit_local.c) +*/ + +static inline void * +uc_addr (unw_context_t *uc, int reg) +{ + /* FIXME: Floating-point? */ + + unw_word_t *regs = (unw_word_t*)&uc->uc_mcontext; + if (reg >= UNW_RISCV_X1 && reg <= UNW_RISCV_X31) + return ®s[reg]; + else if (reg >= UNW_RISCV_F0 && reg <= UNW_RISCV_F31) + { + unw_fpreg_t *fpregs = (unw_fpreg_t*)(regs + 32); + return &fpregs[reg - UNW_RISCV_F0]; + } + else if (reg == UNW_RISCV_PC) + return ®s[0]; + else + return NULL; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (unw_context_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; +} + +// Memory validation routines are from aarch64 + +#define PAGE_SIZE 4096 +#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1)) + +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) +{ + if (mem_validate_pipe[0] != -1) + close (mem_validate_pipe[0]); + if (mem_validate_pipe[1] != -1) + close (mem_validate_pipe[1]); + + do_pipe2 (mem_validate_pipe); +} + +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 + { + ret = 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 */ + + /* mincore could fail with EAGAIN but we conservatively return -1 + instead of looping. */ + if (mincore (addr, len, (unsigned char *)mvec) != 0) + { + 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, (unsigned char *)mvec)) == -1 && + errno == EAGAIN) {} + if (ret == 0) + { + 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 +#if defined(HAVE___CACHE_PER_THREAD) && HAVE___CACHE_PER_THREAD +// thread-local variant +static _Thread_local unw_word_t last_good_addr[NLGA]; +static _Thread_local int lga_victim; + +static int +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; +} + +#else +// global, thread safe variant +static _Atomic unw_word_t last_good_addr[NLGA]; +static _Atomic int lga_victim; + +static int +is_cached_valid_mem(unw_word_t addr) +{ + int i; + for (i = 0; i < NLGA; i++) + { + if (addr == atomic_load(&last_good_addr[i])) + return 1; + } + return 0; +} + +static void +cache_valid_mem(unw_word_t addr) +{ + int i, victim; + victim = atomic_load(&lga_victim); + unw_word_t zero = 0; + for (i = 0; i < NLGA; i++) { + if (atomic_compare_exchange_strong(&last_good_addr[victim], &zero, addr)) { + return; + } + victim = (victim + 1) % NLGA; + } + + /* All slots full. Evict the victim. */ + atomic_store(&last_good_addr[victim], addr); + victim = (victim + 1) % NLGA; + atomic_store(&lga_victim, victim); +} +#endif + +static int +validate_mem (unw_word_t addr) +{ + 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; + + if (is_cached_valid_mem(addr)) + return 0; + + if (mem_validate_func ((void *) addr, len) == -1) + return -1; + + cache_valid_mem(addr); + + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (16, "mem[%p] <- %lx\n", addr, *val); + *(unw_word_t *) (intptr_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[%lx] -> %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; + unw_tdep_context_t *uc = ((struct cursor *)arg)->uc; + + if (unw_is_fpreg (reg)) + goto badreg; + + Debug (16, "reg = %s\n", unw_regname (reg)); + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *addr = *val; + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %lx\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 *fpval, int write, + void *arg) +{ + struct cursor *c = (struct cursor *)arg; + + unw_fpreg_t *addr; + unw_context_t *uc = c->uc; + + if (!unw_is_fpreg (reg)) + goto badreg; + + Debug (16, "reg = %s\n", unw_regname (reg)); + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *addr = *fpval; + Debug (12, "%s <- %lx\n", unw_regname (reg), *fpval); + } + else + { + *fpval = *(unw_word_t *) addr; + Debug (12, "%s -> %lx\n", unw_regname (reg), *fpval); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + 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 elf_w (get_proc_name) (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +riscv_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + + local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY; + local_addr_space.addr_size = sizeof (void *); + 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 = riscv_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + local_addr_space.big_endian = target_is_big_endian(); + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Ginit_local.c b/src/coreclr/pal/src/libunwind/src/riscv/Ginit_local.c new file mode 100644 index 0000000000000..255e75a2bf5bd --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Ginit_local.c @@ -0,0 +1,81 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + Copyright (C) 2021 Zhaofeng Li + +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 (!atomic_load(&tdep_init_done)) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = cursor; + c->uc = uc; + c->validate = 1; + + return common_init (c, use_prev_instr); +} + +int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +int +unw_init_local2 (unw_cursor_t *cursor, unw_context_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/pal/src/libunwind/src/riscv/Ginit_remote.c b/src/coreclr/pal/src/libunwind/src/riscv/Ginit_remote.c new file mode 100644 index 0000000000000..08f5f158249c6 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Ginit_remote.c @@ -0,0 +1,55 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +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 (!atomic_load(&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 = 0; + } + + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Gis_signal_frame.c b/src/coreclr/pal/src/libunwind/src/riscv/Gis_signal_frame.c new file mode 100644 index 0000000000000..923563431c814 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gis_signal_frame.c @@ -0,0 +1,79 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2021 Zhaofeng Li + +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" + +#ifdef __linux__ + +/* + The stub looks like: + + addi x17, zero, 139 0x08b00893 + ecall 0x00000073 + + See . +*/ +#define SIGRETURN_I0 0x08b00893 +#define SIGRETURN_I1 0x00000073 + +#endif /* __linux__ */ + +int +unw_is_signal_frame (unw_cursor_t *cursor) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor*) cursor; + unw_word_t i0, i1, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors_int (as); + arg = c->dwarf.as_arg; + + ip = c->dwarf.ip; + + if (!ip || !a->access_mem || (ip & (sizeof(unw_word_t) - 1))) + return 0; + + if ((ret = (*a->access_mem) (as, ip, &i0, 0, arg)) < 0) + return ret; + + if ((ret = (*a->access_mem) (as, ip + 4, &i1, 0, arg)) < 0) + return ret; + + if ((i0 & 0xffffffff) == SIGRETURN_I0 && (i1 & 0xffffffff) == SIGRETURN_I1) + { + Debug (8, "cursor at signal frame\n"); + return 1; + } + + return 0; +#else + return -UNW_ENOINFO; +#endif +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Greg_states_iterate.c b/src/coreclr/pal/src/libunwind/src/riscv/Greg_states_iterate.c new file mode 100644 index 0000000000000..b436370cfbc33 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Greg_states_iterate.c @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + Copyright (c) 2004 Max Asbock + +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/pal/src/libunwind/src/riscv/Gregs.c b/src/coreclr/pal/src/libunwind/src/riscv/Gregs.c new file mode 100644 index 0000000000000..61db986813fd7 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gregs.c @@ -0,0 +1,95 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2021 Zhaofeng Li + +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; + + if (reg >= UNW_RISCV_F0 && reg <= UNW_RISCV_F31) + return -UNW_EBADREG; + + switch (reg) + { + case UNW_RISCV_X0: + if (write) + return -UNW_EREADONLYREG; + *valp = 0; + return 0; + case UNW_TDEP_IP: + if (write) + { + Debug (16, "pc is now 0x%lx\n", *valp); + c->dwarf.ip = *valp; + } + + /* We store PC in place of the hard-wired X0 */ + loc = c->dwarf.loc[0]; + + /* FIXME: Is IP valid? */ + break; + case UNW_TDEP_SP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + default: + loc = c->dwarf.loc[reg]; + break; + } + + 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; + + if (reg < UNW_RISCV_F0 || reg > UNW_RISCV_F31) + return -UNW_EBADREG; + + loc = c->dwarf.loc[reg]; + + if (write) + { + return dwarf_putfp (&c->dwarf, loc, *valp); + } + else + { + return dwarf_getfp (&c->dwarf, loc, valp); + } +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Gresume.c b/src/coreclr/pal/src/libunwind/src/riscv/Gresume.c new file mode 100644 index 0000000000000..c157ea6eb40e7 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gresume.c @@ -0,0 +1,122 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +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 "offsets.h" +#include + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +riscv_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = c->uc; + + unw_word_t *mcontext = (unw_word_t*) &uc->uc_mcontext; + mcontext[0] = c->dwarf.ip; + + if (c->sigcontext_format == RISCV_SCF_NONE) + { + /* Restore PC in RA */ + mcontext[1] = c->dwarf.ip; + + Debug (8, "resuming at ip=0x%lx via setcontext()\n", c->dwarf.ip); + + setcontext(uc); + } + else + { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + unw_word_t *regs = (unw_word_t*)sc; + + regs[0] = c->dwarf.ip; + for (int i = UNW_RISCV_X1; i <= UNW_RISCV_F31; ++i) { + regs[i] = mcontext[i]; + } + + Debug (8, "resuming at ip=0x%lx via sigreturn() (trampoline @ 0x%lx, sp @ 0x%lx)\n", c->dwarf.ip, c->sigcontext_pc, c->sigcontext_sp); + + // Jump back to the trampoline + __asm__ __volatile__ ( + "mv sp, %0\n" + "jr %1 \n" + : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc) + ); + } + + unreachable(); +#else +# warning Implement me +#endif + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +static inline int +establish_machine_state (struct cursor *c) +{ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = UNW_RISCV_X1; 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) + as->acc.access_fpreg (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &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/pal/src/libunwind/src/riscv/Gstep.c b/src/coreclr/pal/src/libunwind/src/riscv/Gstep.c new file mode 100644 index 0000000000000..5126b0efd7d8b --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Gstep.c @@ -0,0 +1,130 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2021 Zhaofeng Li + +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 "offsets.h" + +static int +riscv_handle_signal_frame (unw_cursor_t *cursor) +{ + int ret, i; + struct cursor *c = (struct cursor *) cursor; + unw_word_t sp, sp_addr = c->dwarf.cfa; + struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0); + + if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0) + return -UNW_EUNSPEC; + + if (!unw_is_signal_frame (cursor)) + return -UNW_EUNSPEC; + +#ifdef __linux__ + /* rt_sigframe contains the siginfo structure, the ucontext, and then + the trampoline. We store the mcontext inside ucontext as sigcontext_addr. + */ + c->sigcontext_format = RISCV_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = sp_addr + sizeof (siginfo_t) + UC_MCONTEXT_REGS_OFF; + c->sigcontext_sp = sp_addr; + c->sigcontext_pc = c->dwarf.ip; +#else + /* Not making any assumption at all - You need to implement this */ + return -UNW_EUNSPEC; +#endif + + /* Update the dwarf cursor. + Set the location of the registers to the corresponding addresses of the + uc_mcontext / sigcontext structure contents. */ + +#define SC_REG_OFFSET(X) (8 * X) + + /* The PC is stored in place of X0 in sigcontext */ + c->dwarf.loc[UNW_TDEP_IP] = DWARF_LOC (c->sigcontext_addr + SC_REG_OFFSET(UNW_RISCV_X0), 0); + + for (i = UNW_RISCV_X1; i <= UNW_RISCV_F31; i++) + { + c->dwarf.loc[i] = DWARF_LOC (c->sigcontext_addr + SC_REG_OFFSET(i), 0); + } + + /* Set SP/CFA and PC/IP. */ + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_TDEP_SP], &c->dwarf.cfa); + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_TDEP_IP], &c->dwarf.ip); + + return 1; +} + +int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int validate = c->validate; + int ret; + + Debug (1, "(cursor=%p, ip=0x%016lx, sp=0x%016lx)\n", + c, c->dwarf.ip, c->dwarf.cfa); + + /* Validate all addresses before dereferencing. */ + c->validate = 1; + + /* Special handling the signal frame. */ + if (unw_is_signal_frame (cursor) > 0) + return riscv_handle_signal_frame (cursor); + + /* Restore default memory validation state */ + c->validate = validate; + + /* Try DWARF-based unwinding... */ + ret = dwarf_step (&c->dwarf); + + if (unlikely (ret == -UNW_ESTOPUNWIND)) + return ret; + + /* DWARF unwinding didn't work, let's tread carefully here */ + if (unlikely (ret < 0)) + { + Debug (1, "DWARF unwinding failed (cursor=%p, ip=0x%016lx, sp=0x%016lx)\n", c, c->dwarf.ip, c->dwarf.cfa); + + /* Try RA/X1? */ + c->dwarf.loc[UNW_RISCV_PC] = c->dwarf.loc[UNW_RISCV_X1]; + c->dwarf.loc[UNW_RISCV_X1] = DWARF_NULL_LOC; + if (!DWARF_IS_NULL_LOC (c->dwarf.loc[UNW_RISCV_PC])) + { + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_RISCV_PC], &c->dwarf.ip); + if (ret < 0) + { + Debug (2, "Failed to get PC from return address: %d\n", ret); + return ret; + } + + Debug (2, "ra= 0x%016lx\n", c->dwarf.ip); + ret = 1; + } + else + { + c->dwarf.ip = 0; + } + } + + return (c->dwarf.ip == 0) ? 0 : 1; +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lapply_reg_state.c b/src/coreclr/pal/src/libunwind/src/riscv/Lapply_reg_state.c new file mode 100644 index 0000000000000..7ebada480e564 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/riscv/Lcreate_addr_space.c new file mode 100644 index 0000000000000..0f2dc6be90145 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lget_proc_info.c b/src/coreclr/pal/src/libunwind/src/riscv/Lget_proc_info.c new file mode 100644 index 0000000000000..69028b019fcd5 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lget_save_loc.c b/src/coreclr/pal/src/libunwind/src/riscv/Lget_save_loc.c new file mode 100644 index 0000000000000..9ea048a9076ba --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lglobal.c b/src/coreclr/pal/src/libunwind/src/riscv/Lglobal.c new file mode 100644 index 0000000000000..6d7b489e14bd9 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Linit.c b/src/coreclr/pal/src/libunwind/src/riscv/Linit.c new file mode 100644 index 0000000000000..e9abfdd46a3e0 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Linit_local.c b/src/coreclr/pal/src/libunwind/src/riscv/Linit_local.c new file mode 100644 index 0000000000000..68a1687e85444 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Linit_remote.c b/src/coreclr/pal/src/libunwind/src/riscv/Linit_remote.c new file mode 100644 index 0000000000000..58cb04ab7cd1f --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lis_signal_frame.c b/src/coreclr/pal/src/libunwind/src/riscv/Lis_signal_frame.c new file mode 100644 index 0000000000000..b9a7c4f51ad9f --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lreg_states_iterate.c b/src/coreclr/pal/src/libunwind/src/riscv/Lreg_states_iterate.c new file mode 100644 index 0000000000000..f1eb1e79dcdcc --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lregs.c b/src/coreclr/pal/src/libunwind/src/riscv/Lregs.c new file mode 100644 index 0000000000000..2c9c75cd7d9a1 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lresume.c b/src/coreclr/pal/src/libunwind/src/riscv/Lresume.c new file mode 100644 index 0000000000000..41a8cf003de4a --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/Lstep.c b/src/coreclr/pal/src/libunwind/src/riscv/Lstep.c new file mode 100644 index 0000000000000..c1ac3c7547f00 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/asm.h b/src/coreclr/pal/src/libunwind/src/riscv/asm.h new file mode 100644 index 0000000000000..7f7b444f931c9 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/asm.h @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2021 Zhaofeng Li + +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 __riscv_xlen == 32 +# define STORE sw +# define LOAD lw +# define SZREG 4 +#elif __riscv_xlen == 64 +# define STORE sd +# define LOAD ld +# define SZREG 8 +#endif + +#if __riscv_flen == 64 +# define SZFREG 8 +# define STORE_FP fsd +# define LOAD_FP fld +#elif __riscv_flen == 32 +# define SZFREG 4 +# define STORE_FP fsw +# define LOAD_FP flw +#else +# error "Unsupported RISC-V floating-point length" +#endif + diff --git a/src/coreclr/pal/src/libunwind/src/riscv/getcontext.S b/src/coreclr/pal/src/libunwind/src/riscv/getcontext.S new file mode 100644 index 0000000000000..9c24888b86177 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/getcontext.S @@ -0,0 +1,87 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2021 Zhaofeng Li + +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 "offsets.h" +#include "asm.h" + +#define REG(X) (UC_MCONTEXT_REGS_OFF + SZREG * X)(a0) +#define FREG(X) (UC_MCONTEXT_REGS_OFF + SZREG * 32 + SZFREG * X)(a0) + + .text + .global _Uriscv_getcontext + .type _Uriscv_getcontext, @function +_Uriscv_getcontext: + .cfi_startproc + + STORE ra, REG(0) + STORE ra, REG(1) + STORE sp, REG(2) + STORE s0, REG(8) + STORE s1, REG(9) + STORE x0, REG(10) /* Write 0 to a0 */ + STORE a1, REG(11) + STORE a2, REG(12) + STORE a3, REG(13) + STORE a4, REG(14) + STORE a5, REG(15) + STORE a6, REG(16) + STORE a7, REG(17) + STORE s2, REG(18) + STORE s3, REG(19) + STORE s4, REG(20) + STORE s5, REG(21) + STORE s6, REG(22) + STORE s7, REG(23) + STORE s8, REG(24) + STORE s9, REG(25) + STORE s10, REG(26) + STORE s11, REG(27) + +#ifdef STORE_FP + /* The FCSR is always 32-bits and comes after all registers */ + frcsr a1 + sw a1, FREG(32) + + STORE_FP fs0, FREG(8) + STORE_FP fs1, FREG(9) + STORE_FP fs2, FREG(18) + STORE_FP fs3, FREG(19) + STORE_FP fs4, FREG(20) + STORE_FP fs5, FREG(21) + STORE_FP fs6, FREG(22) + STORE_FP fs7, FREG(23) + STORE_FP fs8, FREG(24) + STORE_FP fs9, FREG(25) + STORE_FP fs10, FREG(26) + STORE_FP fs11, FREG(27) +#endif + + li a0, 0 + ret + + .cfi_endproc + .size _Uriscv_getcontext, . - _Uriscv_getcontext + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/src/coreclr/pal/src/libunwind/src/riscv/init.h b/src/coreclr/pal/src/libunwind/src/riscv/init.h new file mode 100644 index 0000000000000..163ddb42765ef --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/init.h @@ -0,0 +1,65 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + Copyright (C) 2021 Zhaofeng Li + +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, i; + + for (i = 0; i < 32; i++) + c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, UNW_RISCV_X0 + i); + + for (i = 32; i < DWARF_NUM_PRESERVED_REGS; i++) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + c->dwarf.loc[UNW_RISCV_PC] = DWARF_REG_LOC (&c->dwarf, UNW_RISCV_PC); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_RISCV_PC], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_TDEP_SP), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = RISCV_SCF_NONE; + c->sigcontext_addr = 0; + c->sigcontext_sp = 0; + c->sigcontext_pc = 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; + + return 0; +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/is_fpreg.c b/src/coreclr/pal/src/libunwind/src/riscv/is_fpreg.c new file mode 100644 index 0000000000000..f5a6dc4e31a19 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/is_fpreg.c @@ -0,0 +1,31 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +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) +{ + return (regnum >= UNW_RISCV_F0 && regnum <= UNW_RISCV_F31); +} diff --git a/src/coreclr/pal/src/libunwind/src/riscv/offsets.h b/src/coreclr/pal/src/libunwind/src/riscv/offsets.h new file mode 100644 index 0000000000000..66a2eef62a90b --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/offsets.h @@ -0,0 +1,13 @@ +#ifdef __linux__ + +/* Linux-specific definitions: */ + +/* The RISC-V ucontext has the following structure: + + https://github.com/torvalds/linux/blob/44db63d1ad8d71c6932cbe007eb41f31c434d140/arch/riscv/include/uapi/asm/ucontext.h +*/ +#define UC_MCONTEXT_REGS_OFF 176 + +#else +# error "Unsupported OS" +#endif diff --git a/src/coreclr/pal/src/libunwind/src/riscv/regname.c b/src/coreclr/pal/src/libunwind/src/riscv/regname.c new file mode 100644 index 0000000000000..370383ac69dc5 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/regname.c @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +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[] = + { + /* 0. */ + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + /* 8. */ + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + /* 16. */ + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + /* 24. */ + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", + + /* 0. */ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + /* 8. */ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + /* 16. */ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + /* 24. */ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + + /* pc */ + "pc" + }; + +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/pal/src/libunwind/src/riscv/setcontext.S b/src/coreclr/pal/src/libunwind/src/riscv/setcontext.S new file mode 100644 index 0000000000000..43f0b92906060 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/setcontext.S @@ -0,0 +1,87 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2021 Zhaofeng Li + +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 "offsets.h" +#include "asm.h" + +#define REG(X) (UC_MCONTEXT_REGS_OFF + SZREG * X)(a0) +#define FREG(X) (UC_MCONTEXT_REGS_OFF + SZREG * 32 + SZFREG * X)(a0) + + .text + .global _Uriscv_setcontext + .type _Uriscv_setcontext, @function +_Uriscv_setcontext: + .cfi_startproc + +#ifdef LOAD_FP + /* The FCSR is always 32-bits and comes after all registers */ + lw a1, FREG(32) + fscsr a1 + + LOAD_FP fs0, FREG(8) + LOAD_FP fs1, FREG(9) + LOAD_FP fs2, FREG(18) + LOAD_FP fs3, FREG(19) + LOAD_FP fs4, FREG(20) + LOAD_FP fs5, FREG(21) + LOAD_FP fs6, FREG(22) + LOAD_FP fs7, FREG(23) + LOAD_FP fs8, FREG(24) + LOAD_FP fs9, FREG(25) + LOAD_FP fs10, FREG(26) + LOAD_FP fs11, FREG(27) +#endif + + LOAD t1, REG(0) + LOAD ra, REG(1) + LOAD sp, REG(2) + LOAD s0, REG(8) + LOAD s1, REG(9) + LOAD a1, REG(11) + LOAD a2, REG(12) + LOAD a3, REG(13) + LOAD a4, REG(14) + LOAD a5, REG(15) + LOAD a6, REG(16) + LOAD a7, REG(17) + LOAD s2, REG(18) + LOAD s3, REG(19) + LOAD s4, REG(20) + LOAD s5, REG(21) + LOAD s6, REG(22) + LOAD s7, REG(23) + LOAD s8, REG(24) + LOAD s9, REG(25) + LOAD s10, REG(26) + LOAD s11, REG(27) + + LOAD a0, REG(10) + + jr t1 + + .cfi_endproc + .size _Uriscv_setcontext, . - _Uriscv_setcontext + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/src/coreclr/pal/src/libunwind/src/riscv/siglongjmp.S b/src/coreclr/pal/src/libunwind/src/riscv/siglongjmp.S new file mode 100644 index 0000000000000..9960691d9960a --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/siglongjmp.S @@ -0,0 +1,7 @@ + /* Dummy implementation for now. */ + .globl _UI_siglongjmp_cont + .globl _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + ret diff --git a/src/coreclr/pal/src/libunwind/src/riscv/unwind_i.h b/src/coreclr/pal/src/libunwind/src/riscv/unwind_i.h new file mode 100644 index 0000000000000..3a045da0ace22 --- /dev/null +++ b/src/coreclr/pal/src/libunwind/src/riscv/unwind_i.h @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +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 +#include + +#include + +#include "libunwind_i.h" + +#define riscv_lock UNW_OBJ(lock) +#define riscv_local_resume UNW_OBJ(local_resume) +#define riscv_local_addr_space_init UNW_OBJ(local_addr_space_init) +#define setcontext UNW_ARCH_OBJ (setcontext) + +extern void riscv_local_addr_space_init (void); +extern int riscv_local_resume (unw_addr_space_t as, + unw_cursor_t *cursor, + void *arg); +extern int setcontext (const ucontext_t *ucp); + +#endif /* unwind_i_h */ diff --git a/src/coreclr/pal/src/libunwind/src/s390x/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/s390x/Gcreate_addr_space.c index d411454932bc4..094e6cad05f70 100644 --- a/src/coreclr/pal/src/libunwind/src/s390x/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/s390x/Gcreate_addr_space.c @@ -31,10 +31,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #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) { @@ -46,7 +42,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) /* * s390x supports only big-endian. */ - if (byte_order != 0 && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order != UNW_BIG_ENDIAN) return NULL; as = malloc (sizeof (*as)); diff --git a/src/coreclr/pal/src/libunwind/src/s390x/Gglobal.c b/src/coreclr/pal/src/libunwind/src/s390x/Gglobal.c index be49c3f68227e..20544a57fa017 100644 --- a/src/coreclr/pal/src/libunwind/src/s390x/Gglobal.c +++ b/src/coreclr/pal/src/libunwind/src/s390x/Gglobal.c @@ -89,9 +89,9 @@ tdep_init (void) dwarf_init (); +#ifndef UNW_REMOTE_ONLY tdep_init_mem_validate (); -#ifndef UNW_REMOTE_ONLY s390x_local_addr_space_init (); #endif atomic_store(&tdep_init_done, 1); /* signal that we're initialized... */ diff --git a/src/coreclr/pal/src/libunwind/src/sh/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/sh/Gcreate_addr_space.c index 6ca3a384da0b7..cc6bf6584ee97 100644 --- a/src/coreclr/pal/src/libunwind/src/sh/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/sh/Gcreate_addr_space.c @@ -36,8 +36,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) unw_addr_space_t as; /* SH supports little-endian and big-endian. */ - if (byte_order != 0 && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; as = malloc (sizeof (*as)); @@ -49,7 +48,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) as->acc = *a; /* Default to little-endian for SH. */ - if (byte_order == 0 || byte_order == __LITTLE_ENDIAN) + if (byte_order == 0 || byte_order == UNW_LITTLE_ENDIAN) as->big_endian = 0; else as->big_endian = 1; diff --git a/src/coreclr/pal/src/libunwind/src/tilegx/Gcreate_addr_space.c b/src/coreclr/pal/src/libunwind/src/tilegx/Gcreate_addr_space.c index da66813bc091f..a37c1282f610f 100644 --- a/src/coreclr/pal/src/libunwind/src/tilegx/Gcreate_addr_space.c +++ b/src/coreclr/pal/src/libunwind/src/tilegx/Gcreate_addr_space.c @@ -37,9 +37,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) * Tilegx supports only big or little-endian, not weird stuff like * PDP_ENDIAN. */ - if (byte_order != 0 - && byte_order != __LITTLE_ENDIAN - && byte_order != __BIG_ENDIAN) + if (byte_order != 0 && byte_order_is_valid(byte_order) == 0) return NULL; unw_addr_space_t as = malloc (sizeof (*as)); @@ -52,9 +50,9 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order) if (byte_order == 0) /* use host default: */ - as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + as->big_endian = target_is_big_endian(); else - as->big_endian = (byte_order == __BIG_ENDIAN); + as->big_endian = (byte_order == UNW_BIG_ENDIAN); as->abi = UNW_TILEGX_ABI_N64; as->addr_size = 8; diff --git a/src/coreclr/pal/src/libunwind/src/tilegx/Ginit.c b/src/coreclr/pal/src/libunwind/src/tilegx/Ginit.c index 925e6413246be..9d6c92ad4f91e 100644 --- a/src/coreclr/pal/src/libunwind/src/tilegx/Ginit.c +++ b/src/coreclr/pal/src/libunwind/src/tilegx/Ginit.c @@ -147,7 +147,7 @@ __attribute__((weak)) void tilegx_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); - local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + local_addr_space.big_endian = target_is_big_endian(); local_addr_space.abi = UNW_TILEGX_ABI_N64; local_addr_space.addr_size = sizeof (void *); diff --git a/src/coreclr/pal/src/libunwind/src/win/pal-single-threaded.c b/src/coreclr/pal/src/libunwind/src/win/pal-single-threaded.c index c4f4e780c5832..b46ff2da551e6 100644 --- a/src/coreclr/pal/src/libunwind/src/win/pal-single-threaded.c +++ b/src/coreclr/pal/src/libunwind/src/win/pal-single-threaded.c @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. // This is minimal implementation of posix functions files required to cross compile // libunwind on a Windows host for UNW_REMOTE_ONLY application. @@ -12,11 +13,11 @@ #include #include #include +#include #include #include "libunwind_i.h" #include "compiler.h" - int getpagesize(void) { // 4096 is truth for most targets @@ -111,3 +112,13 @@ unw_accessors_t * unw_get_accessors_int (unw_addr_space_t as) { return unw_get_accessors(as); } + +int stat(const char *path, struct stat *buf) +{ + return 0; +} + +int fstat(int fd, struct stat *buf) +{ + return 0; +} diff --git a/src/coreclr/pal/src/libunwind/src/x86/Gos-linux.c b/src/coreclr/pal/src/libunwind/src/x86/Gos-linux.c index fb9a5e346123a..d448dce7357bd 100644 --- a/src/coreclr/pal/src/libunwind/src/x86/Gos-linux.c +++ b/src/coreclr/pal/src/libunwind/src/x86/Gos-linux.c @@ -298,12 +298,16 @@ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc); +#if !defined(__ANDROID__) x86_sigreturn (sc); +#endif } else { Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip); +#if !defined(__ANDROID__) setcontext (uc); +#endif } return -UNW_EINVAL; } diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Ginit.c b/src/coreclr/pal/src/libunwind/src/x86_64/Ginit.c index 800c5f6fe0abf..0b121bc9137d3 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Ginit.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Ginit.c @@ -26,6 +26,7 @@ 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" #ifdef HAVE_CONFIG_H #include #endif @@ -34,7 +35,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include -#include +#if defined(HAVE_SYS_SYSCALL_H) +# include +#endif #include #include "unwind_i.h" @@ -138,8 +141,12 @@ write_validate (void *addr) do { - /* use syscall insteadof write() so that ASAN does not complain */ - ret = syscall (SYS_write, mem_validate_pipe[1], addr, 1); +#ifdef HAVE_SYS_SYSCALL_H + /* use syscall insteadof write() so that ASAN does not complain */ + ret = syscall (SYS_write, mem_validate_pipe[1], addr, 1); +#else + ret = write (mem_validate_pipe[1], addr, 1); +#endif } while ( errno == EINTR ); @@ -315,8 +322,7 @@ access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, else { /* validate address */ - const struct cursor *c = (const struct cursor *)arg; - if (likely (c != NULL) && unlikely (c->validate) + if (unlikely (AS_ARG_GET_VALIDATE(arg)) && unlikely (validate_mem (addr))) { Debug (16, "mem[%016lx] -> invalid\n", addr); return -1; @@ -332,7 +338,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 = ((struct cursor *)arg)->uc; + ucontext_t *uc = AS_ARG_GET_UC_PTR(arg); if (unw_is_fpreg (reg)) goto badreg; @@ -361,7 +367,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 = ((struct cursor *)arg)->uc; + ucontext_t *uc = AS_ARG_GET_UC_PTR(arg); unw_fpreg_t *addr; if (!unw_is_fpreg (reg)) diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_local.c b/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_local.c index 06a7c49741527..bf771de384c67 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_local.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_local.c @@ -25,6 +25,7 @@ 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" #include "unwind_i.h" #include "init.h" @@ -49,9 +50,7 @@ unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_i Debug (1, "(cursor=%p)\n", c); c->dwarf.as = unw_local_addr_space; - c->dwarf.as_arg = c; - c->uc = uc; - c->validate = 0; + c->dwarf.as_arg = dwarf_build_as_arg(uc, /*validate*/ 0); return common_init (c, use_prev_instr); } diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_remote.c b/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_remote.c index 9ab1d6df11fc8..51761a7102f92 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_remote.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Ginit_remote.c @@ -26,6 +26,7 @@ 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 "libunwind_i.h" #include "unwind_i.h" int @@ -44,13 +45,11 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as = as; if (as == unw_local_addr_space) { - c->dwarf.as_arg = c; - c->uc = as_arg; + c->dwarf.as_arg = dwarf_build_as_arg(as_arg, /*validate*/ 0); } else { c->dwarf.as_arg = as_arg; - c->uc = NULL; } return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Gos-freebsd.c b/src/coreclr/pal/src/libunwind/src/x86_64/Gos-freebsd.c index 883025c88ddc9..91a465c6c50bd 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Gos-freebsd.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Gos-freebsd.c @@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #endif -#include +#include #include #include #include @@ -192,23 +192,23 @@ x86_64_sigreturn (unw_cursor_t *cursor) ucontext_t *uc = (ucontext_t *)(c->sigcontext_addr + offsetof(struct sigframe, sf_uc)); - uc->uc_mcontext.mc_r8 = c->uc->uc_mcontext.mc_r8; - uc->uc_mcontext.mc_r9 = c->uc->uc_mcontext.mc_r9; - uc->uc_mcontext.mc_r10 = c->uc->uc_mcontext.mc_r10; - uc->uc_mcontext.mc_r11 = c->uc->uc_mcontext.mc_r11; - uc->uc_mcontext.mc_r12 = c->uc->uc_mcontext.mc_r12; - uc->uc_mcontext.mc_r13 = c->uc->uc_mcontext.mc_r13; - uc->uc_mcontext.mc_r14 = c->uc->uc_mcontext.mc_r14; - uc->uc_mcontext.mc_r15 = c->uc->uc_mcontext.mc_r15; - uc->uc_mcontext.mc_rdi = c->uc->uc_mcontext.mc_rdi; - uc->uc_mcontext.mc_rsi = c->uc->uc_mcontext.mc_rsi; - uc->uc_mcontext.mc_rbp = c->uc->uc_mcontext.mc_rbp; - uc->uc_mcontext.mc_rbx = c->uc->uc_mcontext.mc_rbx; - uc->uc_mcontext.mc_rdx = c->uc->uc_mcontext.mc_rdx; - uc->uc_mcontext.mc_rax = c->uc->uc_mcontext.mc_rax; - uc->uc_mcontext.mc_rcx = c->uc->uc_mcontext.mc_rcx; - uc->uc_mcontext.mc_rsp = c->uc->uc_mcontext.mc_rsp; - uc->uc_mcontext.mc_rip = c->uc->uc_mcontext.mc_rip; + uc->uc_mcontext.mc_r8 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r8; + uc->uc_mcontext.mc_r9 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r9; + uc->uc_mcontext.mc_r10 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r10; + uc->uc_mcontext.mc_r11 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r11; + uc->uc_mcontext.mc_r12 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r12; + uc->uc_mcontext.mc_r13 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r13; + uc->uc_mcontext.mc_r14 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r14; + uc->uc_mcontext.mc_r15 = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_r15; + uc->uc_mcontext.mc_rdi = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rdi; + uc->uc_mcontext.mc_rsi = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rsi; + uc->uc_mcontext.mc_rbp = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rbp; + uc->uc_mcontext.mc_rbx = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rbx; + uc->uc_mcontext.mc_rdx = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rdx; + uc->uc_mcontext.mc_rax = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rax; + uc->uc_mcontext.mc_rcx = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rcx; + uc->uc_mcontext.mc_rsp = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rsp; + uc->uc_mcontext.mc_rip = dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_rip; Debug (8, "resuming at ip=%llx via sigreturn(%p)\n", (unsigned long long) c->dwarf.ip, uc); diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Gos-linux.c b/src/coreclr/pal/src/libunwind/src/x86_64/Gos-linux.c index bd142345eddd4..b4893297b16fb 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Gos-linux.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Gos-linux.c @@ -25,6 +25,7 @@ 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" #include "unwind_i.h" #include "ucontext_i.h" @@ -140,7 +141,7 @@ x86_64_sigreturn (unw_cursor_t *cursor) struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; mcontext_t *sc_mcontext = &((ucontext_t*)sc)->uc_mcontext; /* Copy in saved uc - all preserved regs are at the start of sigcontext */ - memcpy(sc_mcontext, &c->uc->uc_mcontext, + memcpy(sc_mcontext, &dwarf_get_uc(&c->dwarf)->uc_mcontext, DWARF_NUM_PRESERVED_REGS * sizeof(unw_word_t)); Debug (8, "resuming at ip=%llx via sigreturn(%p)\n", @@ -148,7 +149,7 @@ x86_64_sigreturn (unw_cursor_t *cursor) __asm__ __volatile__ ("mov %0, %%rsp;" "mov %1, %%rax;" "syscall" - :: "r"(sc), "i"(SYS_rt_sigreturn) + :: "r"((uint64_t)sc), "i"(SYS_rt_sigreturn) : "memory"); abort(); } diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Gresume.c b/src/coreclr/pal/src/libunwind/src/x86_64/Gresume.c index 944cdaae192d8..becb1bd6cd769 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Gresume.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Gresume.c @@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#include "libunwind_i.h" #include "offsets.h" #include "unwind_i.h" @@ -36,7 +37,7 @@ HIDDEN inline int x86_64_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 *uc = dwarf_get_uc(&c->dwarf); /* 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 diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Gstep.c b/src/coreclr/pal/src/libunwind/src/x86_64/Gstep.c index d4831197cb39e..3c5c3830ff439 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Gstep.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Gstep.c @@ -25,6 +25,7 @@ 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" #include "unwind_i.h" #include @@ -59,8 +60,11 @@ unw_step (unw_cursor_t *cursor) int ret, i; #if CONSERVATIVE_CHECKS - int val = c->validate; - c->validate = 1; + int val = 0; + if (c->dwarf.as == unw_local_addr_space) { + val = dwarf_get_validate(&c->dwarf); + dwarf_set_validate(&c->dwarf, 1); + } #endif Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n", @@ -71,7 +75,9 @@ unw_step (unw_cursor_t *cursor) ret = dwarf_step (&c->dwarf); #if CONSERVATIVE_CHECKS - c->validate = val; + if (c->dwarf.as == unw_local_addr_space) { + dwarf_set_validate(&c->dwarf, val); + } #endif if (ret < 0 && ret != -UNW_ENOINFO) @@ -110,7 +116,9 @@ unw_step (unw_cursor_t *cursor) /* We could get here because of missing/bad unwind information. Validate all addresses before dereferencing. */ - c->validate = 1; + if (c->dwarf.as == unw_local_addr_space) { + dwarf_set_validate(&c->dwarf, 1); + } Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/Gtrace.c b/src/coreclr/pal/src/libunwind/src/x86_64/Gtrace.c index 40be17eb6e9fc..963a858f27f5a 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/Gtrace.c +++ b/src/coreclr/pal/src/libunwind/src/x86_64/Gtrace.c @@ -22,6 +22,7 @@ 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" #include "unwind_i.h" #include "ucontext_i.h" #include @@ -206,10 +207,7 @@ trace_cache_get (void) RIP using current CFA, RBP and RSP values. Modifies CURSOR to that location, performs one unw_step(), and fills F with what was discovered about the location. Returns F. - - FIXME: This probably should tell DWARF handling to never evaluate - or use registers other than RBP, RSP and RIP in case there is - highly unusual unwind info which uses these creatively. */ +*/ static unw_tdep_frame_t * trace_init_addr (unw_tdep_frame_t *f, unw_cursor_t *cursor, @@ -237,6 +235,9 @@ trace_init_addr (unw_tdep_frame_t *f, their desired values. Then perform the step. */ d->ip = rip + d->use_prev_instr; d->cfa = cfa; + for(int i = 0; i < DWARF_NUM_PRESERVED_REGS; i++) { + d->loc[i] = DWARF_NULL_LOC; + } d->loc[UNW_X86_64_RIP] = DWARF_REG_LOC (d, UNW_X86_64_RIP); d->loc[UNW_X86_64_RBP] = DWARF_REG_LOC (d, UNW_X86_64_RBP); d->loc[UNW_X86_64_RSP] = DWARF_REG_LOC (d, UNW_X86_64_RSP); @@ -403,6 +404,7 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) int maxdepth = 0; int depth = 0; int ret; + int validate = 0; /* Check input parametres. */ if (unlikely(! cursor || ! buffer || ! size || (maxdepth = *size) <= 0)) @@ -473,14 +475,17 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) { case UNW_X86_64_FRAME_GUESSED: /* Fall thru to standard processing after forcing validation. */ - c->validate = 1; + if (d->as == unw_local_addr_space) + dwarf_set_validate(d, 1); case UNW_X86_64_FRAME_STANDARD: /* Advance standard traceable frame. */ cfa = (f->cfa_reg_rsp ? rsp : rbp) + f->cfa_reg_offset; - ACCESS_MEM_FAST(ret, c->validate, d, cfa - 8, rip); + if (d->as == unw_local_addr_space) + validate = dwarf_get_validate(d); + ACCESS_MEM_FAST(ret, validate, d, cfa - 8, rip); if (likely(ret >= 0) && likely(f->rbp_cfa_offset != -1)) - ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->rbp_cfa_offset, rbp); + ACCESS_MEM_FAST(ret, validate, d, cfa + f->rbp_cfa_offset, rbp); /* Don't bother reading RSP from DWARF, CFA becomes new RSP. */ rsp = cfa; @@ -492,11 +497,13 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) case UNW_X86_64_FRAME_SIGRETURN: cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */ - ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RIP, rip); + if (d->as == unw_local_addr_space) + validate = dwarf_get_validate(d); + ACCESS_MEM_FAST(ret, validate, d, cfa + UC_MCONTEXT_GREGS_RIP, rip); if (likely(ret >= 0)) - ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RBP, rbp); + ACCESS_MEM_FAST(ret, validate, d, cfa + UC_MCONTEXT_GREGS_RBP, rbp); if (likely(ret >= 0)) - ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RSP, rsp); + ACCESS_MEM_FAST(ret, validate, d, cfa + UC_MCONTEXT_GREGS_RSP, rsp); /* Resume stack at signal restoration point. The stack is not necessarily continuous here, especially with sigaltstack(). */ @@ -510,11 +517,13 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) /* Address of RIP was pushed on the stack via a simple * def_cfa_expr - result stack offset stored in cfa_reg_offset */ cfa = (f->cfa_reg_rsp ? rsp : rbp) + f->cfa_reg_offset; - ACCESS_MEM_FAST(ret, c->validate, d, cfa, cfa); + if (d->as == unw_local_addr_space) + validate = dwarf_get_validate(d); + ACCESS_MEM_FAST(ret, validate, d, cfa, cfa); if (likely(ret >= 0)) - ACCESS_MEM_FAST(ret, c->validate, d, cfa - 8, rip); + ACCESS_MEM_FAST(ret, validate, d, cfa - 8, rip); if (likely(ret >= 0)) - ACCESS_MEM_FAST(ret, c->validate, d, rbp, rbp); + ACCESS_MEM_FAST(ret, validate, d, rbp, rbp); /* Don't bother reading RSP from DWARF, CFA becomes new RSP. */ rsp = cfa; diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/init.h b/src/coreclr/pal/src/libunwind/src/x86_64/init.h index a7a996f127275..f4b7cf5dc4dd4 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/init.h +++ b/src/coreclr/pal/src/libunwind/src/x86_64/init.h @@ -28,13 +28,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" /* Avoid a trip to x86_64_r_uc_addr() for purely local initialisation. */ -#if defined UNW_LOCAL_ONLY && defined __linux +#if defined UNW_LOCAL_ONLY && defined __linux__ # define REG_INIT_LOC(c, rlc, ruc) \ - DWARF_LOC ((unw_word_t) &c->uc->uc_mcontext.gregs[REG_ ## ruc], 0) + DWARF_LOC ((unw_word_t) &dwarf_get_uc(&c->dwarf)->uc_mcontext.gregs[REG_ ## ruc], 0) #elif defined UNW_LOCAL_ONLY && defined __FreeBSD__ # define REG_INIT_LOC(c, rlc, ruc) \ - DWARF_LOC ((unw_word_t) &c->uc->uc_mcontext.mc_ ## rlc, 0) + DWARF_LOC ((unw_word_t) &dwarf_get_uc(&c->dwarf)->uc_mcontext.mc_ ## rlc, 0) #else # define REG_INIT_LOC(c, rlc, ruc) \ diff --git a/src/coreclr/pal/src/libunwind/src/x86_64/unwind_i.h b/src/coreclr/pal/src/libunwind/src/x86_64/unwind_i.h index e95a60ff37676..49fa078fb21cf 100644 --- a/src/coreclr/pal/src/libunwind/src/x86_64/unwind_i.h +++ b/src/coreclr/pal/src/libunwind/src/x86_64/unwind_i.h @@ -33,7 +33,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "libunwind_i.h" -#include +#include /* DWARF column numbers for x86_64: */ #define RAX 0 diff --git a/src/coreclr/pal/src/libunwind/tests/Gia64-test-nat.c b/src/coreclr/pal/src/libunwind/tests/Gia64-test-nat.c index 89df54e0b0ee3..58099d621679e 100644 --- a/src/coreclr/pal/src/libunwind/tests/Gia64-test-nat.c +++ b/src/coreclr/pal/src/libunwind/tests/Gia64-test-nat.c @@ -132,7 +132,7 @@ sighandler (int signal, void *siginfo, void *context) save_func_t **arg0; ucontext_t *uc = context; -#if defined(__linux) +#if defined(__linux__) { long sof; int sp; @@ -159,7 +159,7 @@ sighandler (int signal, void *siginfo, void *context) (*arg0[0]) (arg0 + 1, arg1); /* skip over the instruction which triggered sighandler() */ -#if defined(__linux) +#if defined(__linux__) ++uc->uc_mcontext.sc_ip; #elif defined(HAVE_SYS_UC_ACCESS_H) { diff --git a/src/coreclr/pal/src/libunwind/tests/Gtest-exc.c b/src/coreclr/pal/src/libunwind/tests/Gtest-exc.c index 1170bdd03fd98..29c1993f2dee8 100644 --- a/src/coreclr/pal/src/libunwind/tests/Gtest-exc.c +++ b/src/coreclr/pal/src/libunwind/tests/Gtest-exc.c @@ -24,6 +24,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* This illustrates the basics of using the unwind interface for exception handling. */ +#include "compiler.h" + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -54,6 +56,8 @@ raise_exception (void) unw_cursor_t cursor; unw_context_t uc; int i; + unw_word_t ip; + unw_word_t sp; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) @@ -62,6 +66,14 @@ raise_exception (void) return; } + if (verbose) + { + printf ("raise_exception(): sp=%p\n", (void*) &sp); + unw_get_reg (&cursor, UNW_REG_IP, &ip); + unw_get_reg (&cursor, UNW_REG_SP, &sp); + printf ("\t #%-3d ip=%p sp=%p\n", 0, (void*) ip, (void*) sp); + } + /* unwind to top-most frame a(), skipping over b() and raise_exception(): */ for (i = 0; i < depth + 2; ++i) if (unw_step (&cursor) < 0) @@ -69,6 +81,12 @@ raise_exception (void) panic ("unw_step() failed!\n"); return; } + else if (verbose) + { + unw_get_reg (&cursor, UNW_REG_IP, &ip); + unw_get_reg (&cursor, UNW_REG_SP, &sp); + printf ("\t #%-3d ip=%p sp=%p\n", i + 1, (void*) ip, (void*) sp); + } unw_resume (&cursor); /* transfer control to exception handler */ } @@ -86,7 +104,7 @@ get_bsp (void) #endif } -int +int NOINLINE a (int n) { long stack; @@ -118,7 +136,7 @@ a (int n) return result; } -void +void NOINLINE b (int n) { if ((n & 1) == 0) diff --git a/src/coreclr/pal/src/libunwind/tests/Ltest-mem-validate.c b/src/coreclr/pal/src/libunwind/tests/Ltest-mem-validate.c index e5127b90628fc..251c34ea76db4 100644 --- a/src/coreclr/pal/src/libunwind/tests/Ltest-mem-validate.c +++ b/src/coreclr/pal/src/libunwind/tests/Ltest-mem-validate.c @@ -47,8 +47,11 @@ void * stack_start; void do_backtrace (void) { - void* buffer[1024]; - int size = 1024; + /* + We make the assumption that we are able to rewind far enough + (steps > 5) before touching the forbidden region in the stack, + at which point the unwinding should stop gracefully. + */ mprotect((void*)((uintptr_t)stack_start & ~(PAGE_SIZE - 1)), PAGE_SIZE, PROT_NONE); @@ -68,6 +71,7 @@ void do_backtrace (void) unw_get_reg (&cursor, UNW_REG_SP, &sp); ret = unw_step (&cursor); + printf("ip=%lx, sp=%lx -> %d\n", ip, sp, ret); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); @@ -78,14 +82,16 @@ void do_backtrace (void) if (steps < 5) { + printf("not enough steps: %d, need 5\n", steps); exit(-1); } + printf("success, steps: %d\n", steps); mprotect((void*)((uintptr_t)stack_start & ~(PAGE_SIZE - 1)), PAGE_SIZE, PROT_READ|PROT_WRITE); } -void consume_and_run (int depth) +void NOINLINE consume_and_run (int depth) { unw_cursor_t cursor; unw_context_t uc; @@ -108,6 +114,14 @@ main (int argc, char **argv UNUSED) stack_start = &start; + /* + We need to make the frame at least the size protected by + the mprotect call so we are not forbidding access to + unrelated regions. + */ + char string[PAGE_SIZE]; + sprintf (string, "hello\n"); + // Initialize pipe mem validate check, opens file descriptors unw_getcontext(&uc); if (unw_init_local (&cursor, &uc) < 0) @@ -121,7 +135,7 @@ main (int argc, char **argv UNUSED) if (!childpid) { /* Close fds and make sure we still work */ - int ret = close(i); + close(i); } int status; diff --git a/src/coreclr/pal/src/libunwind/tests/Makefile.am b/src/coreclr/pal/src/libunwind/tests/Makefile.am index 61d1bf875a8c8..c783fc312db8e 100644 --- a/src/coreclr/pal/src/libunwind/tests/Makefile.am +++ b/src/coreclr/pal/src/libunwind/tests/Makefile.am @@ -1,4 +1,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -fno-optimize-sibling-calls EXTRA_DIST = run-ia64-test-dyn1 run-ptrace-mapper run-ptrace-misc \ run-check-namespace run-coredump-unwind \ @@ -115,6 +116,10 @@ if ARCH_MIPS XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP) endif +if ARCH_RISCV +XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP) +endif + if ARCH_ARM # ARM Linux kernel >=2.6.39 removed PTRACE_SINGLESTEP emulation XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP) @@ -216,6 +221,7 @@ Gperf_trace_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Ltest_bt_LDADD = $(LIBUNWIND_local) Ltest_concurrent_LDADD = $(LIBUNWIND_local) -lpthread +Ltest_cxx_exceptions_LDADD = $(LIBUNWIND_local) Ltest_dyn1_LDADD = $(LIBUNWIND_local) Ltest_exc_LDADD = $(LIBUNWIND_local) Ltest_init_LDADD = $(LIBUNWIND_local) diff --git a/src/coreclr/pal/src/libunwind/tests/check-namespace.sh.in b/src/coreclr/pal/src/libunwind/tests/check-namespace.sh.in index f43bca263bc35..f99fb59f7760b 100644 --- a/src/coreclr/pal/src/libunwind/tests/check-namespace.sh.in +++ b/src/coreclr/pal/src/libunwind/tests/check-namespace.sh.in @@ -189,6 +189,14 @@ check_local_unw_abi () { match _UL${plat}_dwarf_find_unwind_table match _U${plat}_setcontext ;; + riscv) + 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 @@ -296,6 +304,13 @@ check_generic_unw_abi () { match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table ;; + riscv) + match _U${plat}_get_elf_image + match _U${plat}_get_exe_image_path + match _U${plat}_is_fpreg + 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 diff --git a/src/coreclr/pal/src/libunwind/tests/test-coredump-unwind.c b/src/coreclr/pal/src/libunwind/tests/test-coredump-unwind.c index fb06a38effa10..93d9a0ee61747 100644 --- a/src/coreclr/pal/src/libunwind/tests/test-coredump-unwind.c +++ b/src/coreclr/pal/src/libunwind/tests/test-coredump-unwind.c @@ -62,7 +62,7 @@ #else extern int backtrace (void **, int); #endif -#include +#include #include @@ -322,7 +322,7 @@ main(int argc UNUSED, char **argv) if (*colon != ':') error_msg_and_die("Bad format: '%s'", *argv); if (_UCD_add_backing_file_at_vaddr(ui, vaddr, colon + 1) < 0) - error_msg_and_die("Can't add backing file '%s'", colon + 1); + error_msg("Can't add backing file '%s'", colon + 1); argv++; } @@ -338,11 +338,16 @@ main(int argc UNUSED, char **argv) if (ret < 0) error_msg_and_die("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret); - if (!testcase) - printf("\tip=0x%08lx proc=%08lx-%08lx handler=0x%08lx lsda=0x%08lx\n", + if (!testcase) { + char proc_name[128]; + unw_word_t off; + unw_get_proc_name(&c, proc_name, sizeof(proc_name), &off); + + printf("\tip=0x%08lx proc=%08lx-%08lx handler=0x%08lx lsda=0x%08lx %s\n", (long) ip, (long) pi.start_ip, (long) pi.end_ip, - (long) pi.handler, (long) pi.lsda); + (long) pi.handler, (long) pi.lsda, proc_name); + } if (testcase && test_cur < TEST_FRAMES) { diff --git a/src/coreclr/pal/src/libunwind/tests/test-ptrace.c b/src/coreclr/pal/src/libunwind/tests/test-ptrace.c index e7c7883f38f9e..846bcd80079b4 100644 --- a/src/coreclr/pal/src/libunwind/tests/test-ptrace.c +++ b/src/coreclr/pal/src/libunwind/tests/test-ptrace.c @@ -178,7 +178,7 @@ main (int argc, char **argv) if (argc == 1) { - static char *args[] = { "self", "/bin/ls", "/usr", NULL }; + static char *args[] = { "self", "ls", "/", NULL }; /* automated test case */ argv = args; @@ -233,7 +233,11 @@ main (int argc, char **argv) fprintf(stderr, "Need to specify a command line for the child\n"); exit (-1); } +#ifdef __FreeBSD__ execve (argv[optind], argv + optind, environ); +#else + execvpe (argv[optind], argv + optind, environ); +#endif _exit (-1); } atexit (target_pid_kill); diff --git a/src/coreclr/pal/src/libunwind/tests/test-setjmp.c b/src/coreclr/pal/src/libunwind/tests/test-setjmp.c index 769b71b2228c6..59d1c5a083b30 100644 --- a/src/coreclr/pal/src/libunwind/tests/test-setjmp.c +++ b/src/coreclr/pal/src/libunwind/tests/test-setjmp.c @@ -149,6 +149,10 @@ main (int argc, char **argv UNUSED) if (argc > 1) verbose = 1; + memset (&sigset1, 0, sizeof (sigset1)); + memset (&sigset2, 0, sizeof (sigset2)); + memset (&sigset3, 0, sizeof (sigset3)); + sigemptyset ((sigset_t *) &sigset1); sigaddset ((sigset_t *) &sigset1, SIGUSR1); sigemptyset ((sigset_t *) &sigset2);