From 15c82cd41beecf42a6fa514f6f575615a7042818 Mon Sep 17 00:00:00 2001 From: Thomas A Date: Sun, 5 Feb 2023 15:53:09 -0800 Subject: [PATCH] Update Source To libunwind-201 --- Makefile | 49 + apple-xbs-support/Libcompiler_rt.mk | 20 + apple-xbs-support/clang.mk | 123 + apple-xbs-support/clang_compiler_rt.mk | 4 + apple-xbs-support/clang_compiler_rt_os.mk | 4 + apple-xbs-support/clang_device.mk | 8 + apple-xbs-support/clang_libs_osx.mk | 4 + apple-xbs-support/clang_shims.mk | 79 + apple-xbs-support/helpers/installsrc.mk | 33 + apple-xbs-support/helpers/train_detection.mk | 79 + apple-xbs-support/libcxx.mk | 66 + apple-xbs-support/libcxx_Sim.mk | 1 + apple-xbs-support/libcxx_driverkit.mk | 1 + apple-xbs-support/libcxx_dyld.mk | 1 + apple-xbs-support/libcxx_dyld_Sim.mk | 1 + apple-xbs-support/libunwind.mk | 31 + apple-xbs-support/libunwind_Sim.mk | 2 + apple-xbs-support/libunwind_dyld.mk | 2 + apple-xbs-support/libunwind_dyld_Sim.mk | 2 + apple-xbs-support/tapi.mk | 168 + .../test/Libcompiler_rt/installsrc.test | 12 + apple-xbs-support/test/Makefile | 23 + apple-xbs-support/test/clang/installsrc.test | 17 + .../test/clang/installsrc_variant.test | 7 + apple-xbs-support/test/clang/shims.test | 22 + .../test/generic/missing-RC_ProjectName.test | 4 + .../test/generic/missing-SRCROOT.test | 3 + .../test/generic/train_detection.test | 187 + .../test/libcxx/install_libcxx.test | 27 + .../test/libcxx/install_libcxx_driverkit.test | 27 + .../test/libcxx/install_libcxx_dyld.test | 27 + ...nstall_libcxx_missing_project_version.test | 25 + apple-xbs-support/test/libcxx/installsrc.test | 65 + .../test/libcxx/per_tu_guarantee.test | 26 + apple-xbs-support/test/libunwind/install.test | 40 + .../test/libunwind/installsrc.test | 26 + .../test/libunwind/installsrc_variant.test | 25 + apple-xbs-support/test/lit.cfg | 43 + .../test/utils/find-clang-asan-version.test | 1 + .../utils/find-clang-asan-version | 3 + libunwind/.clang-format | 2 + libunwind/CMakeLists.txt.apple | 409 ++ libunwind/LICENSE.TXT | 311 ++ libunwind/apple-install-libunwind.sh | 156 + .../cmake/Modules/HandleCompilerRT.cmake | 64 + .../cmake/Modules/HandleLibunwindFlags.cmake | 272 + libunwind/cmake/caches/Apple-shared.cmake | 6 + libunwind/cmake/caches/Apple-static.cmake | 5 + libunwind/cmake/caches/Apple.cmake | 11 + libunwind/cmake/config-ix.cmake | 95 + libunwind/docs/AppleInternalTesting.md | 47 + libunwind/docs/BuildingLibunwind.rst | 161 + libunwind/docs/CMakeLists.txt | 7 + libunwind/docs/README.txt | 13 + libunwind/docs/conf.py | 252 + libunwind/docs/index.rst | 104 + libunwind/include/__libunwind_config.h | 159 + libunwind/include/libunwind.h | 1152 +++- .../include/mach-o/compact_unwind_encoding.h | 201 +- .../mach-o/compact_unwind_encoding.modulemap | 4 + libunwind/include/unwind.h | 497 +- libunwind/libunwind.order | 27 - libunwind/libunwind.xcodeproj/project.pbxproj | 546 -- .../contents.xcworkspacedata | 7 - .../UserInterfaceState.xcuserstate | Bin 57049 -> 0 bytes .../xcschemes/xcschememanagement.plist | 24 - libunwind/src/AddressSpace.hpp | 961 ++-- libunwind/src/CMakeLists.txt.apple | 260 + libunwind/src/CompactUnwinder.hpp | 1869 +++---- libunwind/src/DwarfInstructions.hpp | 2447 +++----- libunwind/src/DwarfParser.hpp | 1533 +++-- libunwind/src/EHHeaderParser.hpp | 169 + libunwind/src/FileAbstraction.hpp | 146 - libunwind/src/FrameHeaderCache.hpp | 149 + libunwind/src/InternalMacros.h | 104 - libunwind/src/RWMutex.hpp | 114 + libunwind/src/Registers.S | 261 - libunwind/src/Registers.hpp | 4971 +++++++++++++---- libunwind/src/Unwind-EHABI.cpp | 1003 ++++ libunwind/src/Unwind-EHABI.h | 50 + libunwind/src/Unwind-seh.cpp | 501 ++ libunwind/src/Unwind-sjlj.c | 877 +-- libunwind/src/UnwindCursor.hpp | 2712 ++++++--- libunwind/src/UnwindLevel1-gcc-ext.c | 524 +- libunwind/src/UnwindLevel1.c | 903 +-- libunwind/src/UnwindRegistersRestore.S | 1157 ++++ libunwind/src/UnwindRegistersSave.S | 1109 ++++ libunwind/src/Unwind_AppleExtras.cpp | 119 + libunwind/src/assembly.h | 165 + libunwind/src/config.h | 232 + libunwind/src/dwarf2.h | 454 +- libunwind/src/libunwind.cpp | 340 ++ libunwind/src/libunwind_ext.h | 69 + libunwind/src/libunwind_priv.h | 49 - libunwind/src/libuwind.cxx | 380 -- libunwind/src/unw_getcontext.S | 229 - libunwind/test/CMakeLists.txt | 35 + libunwind/test/alignment.pass.cpp | 28 + libunwind/test/frameheadercache_test.pass.cpp | 73 + libunwind/test/libunwind/__init__.py | 0 libunwind/test/libunwind/test/__init__.py | 0 libunwind/test/libunwind/test/config.py | 68 + libunwind/test/libunwind_01.pass.cpp | 63 + libunwind/test/libunwind_02.pass.cpp | 38 + libunwind/test/lit.cfg.py | 10 + libunwind/test/lit.site.cfg.in | 57 + libunwind/test/remember_state_leak.pass.sh.s | 56 + libunwind/test/signal_frame.pass.cpp | 33 + libunwind/test/unw_getcontext.pass.cpp | 8 + libunwind/testsuite/Unwind_Backtrace.c | 59 - libunwind/testsuite/Unwind_ForcedUnwind.cxx | 54 - libunwind/testsuite/backtrace.c | 71 - libunwind/testsuite/backtrace2.c | 7 - .../testsuite/dwarf_cache_dlclose.mk/Makefile | 17 - .../testsuite/dwarf_cache_dlclose.mk/foo.cxx | 20 - .../testsuite/dwarf_cache_dlclose.mk/main.c | 58 - .../testsuite/dynamic_fde_registration.cxx | 139 - libunwind/testsuite/end_of_stack.c | 39 - libunwind/testsuite/exception_32bit_lsda.s | 240 - libunwind/testsuite/exception_basic.cxx | 33 - .../testsuite/exception_catch_and_throw.cxx | 54 - libunwind/testsuite/exception_missing_eh.cxx | 52 - libunwind/testsuite/exception_missing_eh2.c | 14 - .../testsuite/exception_missing_eh2_x86_64.s | 13 - libunwind/testsuite/exception_rethrow.cxx | 54 - libunwind/testsuite/exception_signal.cxx | 57 - libunwind/testsuite/find_enclosing.c | 48 - libunwind/testsuite/objc_alt_handler.m | 50 - libunwind/testsuite/objc_exception_basic.m | 36 - libunwind/testsuite/personality.cxx | 170 - libunwind/testsuite/rethrow_missing_catch.cxx | 40 - libunwind/testsuite/run-all-tests.pl | 108 - libunwind/testsuite/terminate_is_handler.cxx | 31 - libunwind/testsuite/unw_getcontext.c | 26 - libunwind/testsuite/unwind_test_main.c | 46 - libunwind/testsuite/unwind_test_ppc.s | 502 -- libunwind/testsuite/unwind_test_ppc_frame.s | 339 -- libunwind/testsuite/unwind_test_x86.s | 104 - libunwind/testsuite/unwind_test_x86_64.s | 125 - ...unwind_test_x86_64_disable_compact_frame.s | 599 -- .../testsuite/unwind_test_x86_64_frame.s | 674 --- .../testsuite/unwind_test_x86_64_frameless.s | 583 -- .../unwind_test_x86_64_frameless_big.s | 598 -- .../testsuite/unwind_test_x86_64_unusual.s | 311 -- .../unwind_test_x86_disable_compact_frame.s | 589 -- libunwind/testsuite/unwind_test_x86_frame.s | 671 --- .../testsuite/unwind_test_x86_frameless.s | 516 -- .../testsuite/unwind_test_x86_frameless_big.s | 516 -- libunwind/testsuite/unwind_test_x86_unusual.s | 330 -- 149 files changed, 20953 insertions(+), 17186 deletions(-) create mode 100644 Makefile create mode 100644 apple-xbs-support/Libcompiler_rt.mk create mode 100644 apple-xbs-support/clang.mk create mode 100644 apple-xbs-support/clang_compiler_rt.mk create mode 100644 apple-xbs-support/clang_compiler_rt_os.mk create mode 100644 apple-xbs-support/clang_device.mk create mode 100644 apple-xbs-support/clang_libs_osx.mk create mode 100644 apple-xbs-support/clang_shims.mk create mode 100644 apple-xbs-support/helpers/installsrc.mk create mode 100644 apple-xbs-support/helpers/train_detection.mk create mode 100644 apple-xbs-support/libcxx.mk create mode 100644 apple-xbs-support/libcxx_Sim.mk create mode 100644 apple-xbs-support/libcxx_driverkit.mk create mode 100644 apple-xbs-support/libcxx_dyld.mk create mode 100644 apple-xbs-support/libcxx_dyld_Sim.mk create mode 100644 apple-xbs-support/libunwind.mk create mode 100644 apple-xbs-support/libunwind_Sim.mk create mode 100644 apple-xbs-support/libunwind_dyld.mk create mode 100644 apple-xbs-support/libunwind_dyld_Sim.mk create mode 100644 apple-xbs-support/tapi.mk create mode 100644 apple-xbs-support/test/Libcompiler_rt/installsrc.test create mode 100644 apple-xbs-support/test/Makefile create mode 100644 apple-xbs-support/test/clang/installsrc.test create mode 100644 apple-xbs-support/test/clang/installsrc_variant.test create mode 100644 apple-xbs-support/test/clang/shims.test create mode 100644 apple-xbs-support/test/generic/missing-RC_ProjectName.test create mode 100644 apple-xbs-support/test/generic/missing-SRCROOT.test create mode 100644 apple-xbs-support/test/generic/train_detection.test create mode 100644 apple-xbs-support/test/libcxx/install_libcxx.test create mode 100644 apple-xbs-support/test/libcxx/install_libcxx_driverkit.test create mode 100644 apple-xbs-support/test/libcxx/install_libcxx_dyld.test create mode 100644 apple-xbs-support/test/libcxx/install_libcxx_missing_project_version.test create mode 100644 apple-xbs-support/test/libcxx/installsrc.test create mode 100644 apple-xbs-support/test/libcxx/per_tu_guarantee.test create mode 100644 apple-xbs-support/test/libunwind/install.test create mode 100644 apple-xbs-support/test/libunwind/installsrc.test create mode 100644 apple-xbs-support/test/libunwind/installsrc_variant.test create mode 100644 apple-xbs-support/test/lit.cfg create mode 100644 apple-xbs-support/test/utils/find-clang-asan-version.test create mode 100755 apple-xbs-support/utils/find-clang-asan-version create mode 100644 libunwind/.clang-format create mode 100644 libunwind/CMakeLists.txt.apple create mode 100644 libunwind/LICENSE.TXT create mode 100755 libunwind/apple-install-libunwind.sh create mode 100644 libunwind/cmake/Modules/HandleCompilerRT.cmake create mode 100644 libunwind/cmake/Modules/HandleLibunwindFlags.cmake create mode 100644 libunwind/cmake/caches/Apple-shared.cmake create mode 100644 libunwind/cmake/caches/Apple-static.cmake create mode 100644 libunwind/cmake/caches/Apple.cmake create mode 100644 libunwind/cmake/config-ix.cmake create mode 100644 libunwind/docs/AppleInternalTesting.md create mode 100644 libunwind/docs/BuildingLibunwind.rst create mode 100644 libunwind/docs/CMakeLists.txt create mode 100644 libunwind/docs/README.txt create mode 100644 libunwind/docs/conf.py create mode 100644 libunwind/docs/index.rst create mode 100644 libunwind/include/__libunwind_config.h create mode 100644 libunwind/include/mach-o/compact_unwind_encoding.modulemap delete mode 100644 libunwind/libunwind.order delete mode 100644 libunwind/libunwind.xcodeproj/project.pbxproj delete mode 100644 libunwind/libunwind.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 libunwind/libunwind.xcodeproj/project.xcworkspace/xcuserdata/kledzik.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 libunwind/libunwind.xcodeproj/xcuserdata/kledzik.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 libunwind/src/CMakeLists.txt.apple create mode 100644 libunwind/src/EHHeaderParser.hpp delete mode 100644 libunwind/src/FileAbstraction.hpp create mode 100644 libunwind/src/FrameHeaderCache.hpp delete mode 100644 libunwind/src/InternalMacros.h create mode 100644 libunwind/src/RWMutex.hpp delete mode 100644 libunwind/src/Registers.S create mode 100644 libunwind/src/Unwind-EHABI.cpp create mode 100644 libunwind/src/Unwind-EHABI.h create mode 100644 libunwind/src/Unwind-seh.cpp create mode 100644 libunwind/src/UnwindRegistersRestore.S create mode 100644 libunwind/src/UnwindRegistersSave.S create mode 100644 libunwind/src/Unwind_AppleExtras.cpp create mode 100644 libunwind/src/assembly.h create mode 100644 libunwind/src/config.h create mode 100644 libunwind/src/libunwind.cpp create mode 100644 libunwind/src/libunwind_ext.h delete mode 100644 libunwind/src/libunwind_priv.h delete mode 100644 libunwind/src/libuwind.cxx delete mode 100644 libunwind/src/unw_getcontext.S create mode 100644 libunwind/test/CMakeLists.txt create mode 100644 libunwind/test/alignment.pass.cpp create mode 100644 libunwind/test/frameheadercache_test.pass.cpp create mode 100644 libunwind/test/libunwind/__init__.py create mode 100644 libunwind/test/libunwind/test/__init__.py create mode 100644 libunwind/test/libunwind/test/config.py create mode 100644 libunwind/test/libunwind_01.pass.cpp create mode 100644 libunwind/test/libunwind_02.pass.cpp create mode 100644 libunwind/test/lit.cfg.py create mode 100644 libunwind/test/lit.site.cfg.in create mode 100644 libunwind/test/remember_state_leak.pass.sh.s create mode 100644 libunwind/test/signal_frame.pass.cpp create mode 100644 libunwind/test/unw_getcontext.pass.cpp delete mode 100644 libunwind/testsuite/Unwind_Backtrace.c delete mode 100644 libunwind/testsuite/Unwind_ForcedUnwind.cxx delete mode 100644 libunwind/testsuite/backtrace.c delete mode 100644 libunwind/testsuite/backtrace2.c delete mode 100644 libunwind/testsuite/dwarf_cache_dlclose.mk/Makefile delete mode 100644 libunwind/testsuite/dwarf_cache_dlclose.mk/foo.cxx delete mode 100644 libunwind/testsuite/dwarf_cache_dlclose.mk/main.c delete mode 100644 libunwind/testsuite/dynamic_fde_registration.cxx delete mode 100644 libunwind/testsuite/end_of_stack.c delete mode 100644 libunwind/testsuite/exception_32bit_lsda.s delete mode 100644 libunwind/testsuite/exception_basic.cxx delete mode 100644 libunwind/testsuite/exception_catch_and_throw.cxx delete mode 100644 libunwind/testsuite/exception_missing_eh.cxx delete mode 100644 libunwind/testsuite/exception_missing_eh2.c delete mode 100644 libunwind/testsuite/exception_missing_eh2_x86_64.s delete mode 100644 libunwind/testsuite/exception_rethrow.cxx delete mode 100644 libunwind/testsuite/exception_signal.cxx delete mode 100644 libunwind/testsuite/find_enclosing.c delete mode 100644 libunwind/testsuite/objc_alt_handler.m delete mode 100644 libunwind/testsuite/objc_exception_basic.m delete mode 100644 libunwind/testsuite/personality.cxx delete mode 100644 libunwind/testsuite/rethrow_missing_catch.cxx delete mode 100644 libunwind/testsuite/run-all-tests.pl delete mode 100644 libunwind/testsuite/terminate_is_handler.cxx delete mode 100644 libunwind/testsuite/unw_getcontext.c delete mode 100644 libunwind/testsuite/unwind_test_main.c delete mode 100644 libunwind/testsuite/unwind_test_ppc.s delete mode 100644 libunwind/testsuite/unwind_test_ppc_frame.s delete mode 100644 libunwind/testsuite/unwind_test_x86.s delete mode 100644 libunwind/testsuite/unwind_test_x86_64.s delete mode 100644 libunwind/testsuite/unwind_test_x86_64_disable_compact_frame.s delete mode 100644 libunwind/testsuite/unwind_test_x86_64_frame.s delete mode 100644 libunwind/testsuite/unwind_test_x86_64_frameless.s delete mode 100644 libunwind/testsuite/unwind_test_x86_64_frameless_big.s delete mode 100644 libunwind/testsuite/unwind_test_x86_64_unusual.s delete mode 100644 libunwind/testsuite/unwind_test_x86_disable_compact_frame.s delete mode 100644 libunwind/testsuite/unwind_test_x86_frame.s delete mode 100644 libunwind/testsuite/unwind_test_x86_frameless.s delete mode 100644 libunwind/testsuite/unwind_test_x86_frameless_big.s delete mode 100644 libunwind/testsuite/unwind_test_x86_unusual.s diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..50e7990 --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +# Monorepo makefile: redirect to project-specific .mk for B&I logic. + +ifeq "$(RC_ProjectName)" "" +define NEWLINE + + +endef +projects := $(sort $(patsubst apple-xbs-support/%.mk,%, \ + $(wildcard apple-xbs-support/*.mk))) +$(error "RC_ProjectName not set, try one of:"$(NEWLINE)$(NEWLINE) \ + $(foreach p,$(projects),$$ make RC_ProjectName=$p$(NEWLINE)) \ + $(NEWLINE)) +endif + +ifeq "$(SRCROOT)" "" +$(error "SRCROOT not set") +endif + +# Note: APPLE_XBS_SUPPORT_MK is a lazy variable ('=' instead of ':=') that +# tracks the value of APPLE_XBS_SUPPORT_COMPUTED_RC_ProjectName. +APPLE_XBS_SUPPORT_COMPUTED_RC_ProjectName := $(RC_ProjectName) +APPLE_XBS_SUPPORT_MK = \ + apple-xbs-support/$(APPLE_XBS_SUPPORT_COMPUTED_RC_ProjectName).mk + +# Note: APPLE_XBS_SUPPORT_VARIANT_PREFIX is a lazy variable ('=' instead of +# ':=') that tracks the value of APPLE_XBS_SUPPORT_VARIANT. +APPLE_XBS_SUPPORT_VARIANT := +APPLE_XBS_SUPPORT_VARIANT_PREFIX = \ + $(if $(APPLE_XBS_SUPPORT_VARIANT),$(APPLE_XBS_SUPPORT_VARIANT)_,) + +# Check if there is a .mk file for this project name. +ifeq "$(shell stat $(APPLE_XBS_SUPPORT_MK) 2>/dev/null)" "" + +# Not found. If there's an underscore, try dropping the prefix. +ifneq "$(words $(subst _, ,$(RC_ProjectName)))" "1" +APPLE_XBS_SUPPORT_VARIANT := $(word 1,$(subst _, ,$(RC_ProjectName))) +APPLE_XBS_SUPPORT_COMPUTED_RC_ProjectName := \ + $(subst ^$(APPLE_XBS_SUPPORT_VARIANT_PREFIX),,^$(RC_ProjectName)) + +ifeq "$(shell stat $(APPLE_XBS_SUPPORT_MK) 2>/dev/null)" "" +# Still not found... revert to original to avoid bad error messages. +APPLE_XBS_SUPPORT_COMPUTED_RC_ProjectName := $(RC_ProjectName) +APPLE_XBS_SUPPORT_VARIANT := +endif +endif +endif + +$(info $(RC_ProjectName) => $(APPLE_XBS_SUPPORT_MK)) +include $(APPLE_XBS_SUPPORT_MK) diff --git a/apple-xbs-support/Libcompiler_rt.mk b/apple-xbs-support/Libcompiler_rt.mk new file mode 100644 index 0000000..7ab6ab7 --- /dev/null +++ b/apple-xbs-support/Libcompiler_rt.mk @@ -0,0 +1,20 @@ +############################################################################## +# Top-level targets executed by XBS for internal build of libcompiler_rt.dylib +############################################################################## + +MKDIR := /bin/mkdir -p -m 0755 + + +# Note: cannot use helpers/installsrc.mk because Libcompiler_rt is +# xcode project based and needs a different layout. + +.PHONY: installsrc +installsrc: + @echo "Installing source..." + $(_v) $(MKDIR) "$(SRCROOT)" + $(_v) cp -r compiler-rt/Libcompiler_rt.xcodeproj "$(SRCROOT)" + $(_v) $(MKDIR) "$(SRCROOT)/lib" + $(_v) cp -r compiler-rt/lib/builtins "$(SRCROOT)/lib/" + + + diff --git a/apple-xbs-support/clang.mk b/apple-xbs-support/clang.mk new file mode 100644 index 0000000..aa2091f --- /dev/null +++ b/apple-xbs-support/clang.mk @@ -0,0 +1,123 @@ +# apple-xbs-support/clang.mk +# Apple Internal B&I makefile for clang. + +################################################################################ +# Apple clang default B&I configuration. +################################################################################ + +Clang_Use_Assertions := 0 +Clang_Use_Optimized := 1 +# FIXME: remove, stop hardcoding it. +Clang_Version := 11.0.0 + +# Use LTO for clang but not clang_device +ifeq ($(APPLE_XBS_SUPPORT_COMPUTED_RC_ProjectName),clang) +Clang_Enable_LTO := THIN +else +Clang_Enable_LTO := 0 +endif + +################################################################################ +# Apple clang XBS targets. +################################################################################ + +# Default target. +all: help + +help: + @echo "usage: make [{VARIABLE=VALUE}*] " + @echo + @echo "The Apple Clang makefile is primarily intended for use with XBS." + @echo + @echo "Supported B&I related targets are:" + @echo " installsrc -- Copy source files from the current" \ + "directory to the SRCROOT." + @echo " clean -- Does nothing, just for XBS support." + @echo " installhdrs -- Does nothing, just for XBS support." + @echo " install -- Alias for install-clang." + @echo " install-clang -- Build the Apple Clang compiler." + +# Default is to build Clang. +install: clang + +# Install source uses the shared helper, but also fetches PGO data during +# submission to a B&I train. +installsrc-paths := \ + llvm \ + clang-tools-extra \ + clang-shims \ + compiler-rt \ + libcxx \ + libcxxabi \ + clang +include apple-xbs-support/helpers/installsrc.mk + +# FIXME: Fetch PGO data if we can. +installsrc: installsrc-helper + +# The clean target is run after installing sources, but we do nothing because +# the expectation is that we will just avoid copying in cruft during the +# installsrc phase. +clean: + +# We do not need to do anything for the install headers phase. +installhdrs: + +################################################################################ +# Apple clang build targets. +################################################################################ + +# The clang build target invokes CMake and ninja in the `build_clang` script. +BUILD_CLANG = $(SRCROOT)/clang/utils/buildit/build_clang + +# FIXME (Alex): export the Git version. +clang: $(OBJROOT) $(SYMROOT) $(DSTROOT) + cd $(OBJROOT) && \ + export LLVM_REPOSITORY=$(LLVM_REPOSITORY) && \ + $(BUILD_CLANG) $(Clang_Use_Assertions) $(Clang_Use_Optimized) $(Clang_Version) $(Clang_Enable_LTO) + +clang-libs: $(OBJROOT) $(SYMROOT) $(DSTROOT) + cd $(OBJROOT) && \ + export LLVM_REPOSITORY=$(LLVM_REPOSITORY) && \ + $(BUILD_CLANG) $(Clang_Use_Assertions) $(Clang_Use_Optimized) $(Clang_Version) $(Clang_Enable_LTO) build_libs + +BUILD_COMPILER_RT = $(SRCROOT)/compiler-rt/utils/buildit/build_compiler_rt + +compiler-rt: $(OBJROOT) $(SYMROOT) $(DSTROOT) + cd $(OBJROOT) && \ + $(BUILD_COMPILER_RT) $(Clang_Use_Assertions) $(Clang_Use_Optimized) $(Clang_Version) + +# FIXME: Workaround DT_TOOLCHAIN_DIR is incorrectly +# set when -developerDir is used or `DEVELOPER_DIR` environment variable is set +# when targeting non-macOS trains. +XCODE_TOOLCHAINS_DIR = Applications/Xcode.app/Contents/Developer/Toolchains +XCODE_TOOLCHAIN_DIR = $(XCODE_TOOLCHAINS_DIR)/$(notdir $(DT_TOOLCHAIN_DIR)) +XCODE_TOOLCHAIN_CLANG_LIBS_DIR = $(XCODE_TOOLCHAIN_DIR)/usr/lib/clang/$(Clang_Version)/lib/darwin +COMPILER_RT_PROJECT_DIR = $(RC_EMBEDDEDPROJECT_DIR)/$(APPLE_XBS_SUPPORT_VARIANT_PREFIX)clang_compiler_rt +COMPILER_RT_TOOLCHAIN_DYLIB_DIR = $(COMPILER_RT_PROJECT_DIR)/$(XCODE_TOOLCHAIN_CLANG_LIBS_DIR) +$(info COMPILER_RT_TOOLCHAIN_DYLIB_DIR:$(COMPILER_RT_TOOLCHAIN_DYLIB_DIR)) +COMPILER_RT_DYLIBS = $(filter-out %sim_dynamic.dylib,$(wildcard $(COMPILER_RT_TOOLCHAIN_DYLIB_DIR)/*_dynamic.dylib)) +$(info COMPILER_RT_DYLIBS:$(COMPILER_RT_DYLIBS)) +ifeq ($(findstring OSX,$(DT_TOOLCHAIN_DIR)),) + OS_DYLIBS = $(filter-out %osx_dynamic.dylib,$(COMPILER_RT_DYLIBS)) +else + OS_DYLIBS = $(COMPILER_RT_DYLIBS) +endif + +# TODO(dliew): Remove support for old path (rdar://problem/57350767). +include apple-xbs-support/helpers/train_detection.mk +OLD_COMPILER_RT_OS_INSTALL_PATH=/usr/local/lib/sanitizers +NEW_COMPILER_RT_OS_INSTALL_PATH=/usr/appleinternal/lib/sanitizers/ +NEW_COMPILER_RT_INSTALL_OS_VERSIONS := OSX-11.0 iOS-14.0 WatchOS-7.0 AppleTVOS-14.0 BridgeOS-5.0 +COMPILER_RT_OS_DYLIB_PERMISSIONS := u=rwx,g=rx,o=rx + +compiler-rt-os: + mkdir -p $(DSTROOT)$(OLD_COMPILER_RT_OS_INSTALL_PATH) + ditto $(OS_DYLIBS) $(DSTROOT)$(OLD_COMPILER_RT_OS_INSTALL_PATH) + chmod -vv $(COMPILER_RT_OS_DYLIB_PERMISSIONS) $(DSTROOT)$(OLD_COMPILER_RT_OS_INSTALL_PATH)/*.dylib + @if [ "X$(call os-train-version-is-at-least,$(NEW_COMPILER_RT_INSTALL_OS_VERSIONS))" = "X1" ]; then \ + echo Installing compiler-rt dylibs to new path: $(NEW_COMPILER_RT_OS_INSTALL_PATH); \ + mkdir -p $(DSTROOT)$(NEW_COMPILER_RT_OS_INSTALL_PATH); \ + ditto $(OS_DYLIBS) $(DSTROOT)$(NEW_COMPILER_RT_OS_INSTALL_PATH); \ + chmod -vv $(COMPILER_RT_OS_DYLIB_PERMISSIONS) $(DSTROOT)$(NEW_COMPILER_RT_OS_INSTALL_PATH)/*.dylib; \ + fi diff --git a/apple-xbs-support/clang_compiler_rt.mk b/apple-xbs-support/clang_compiler_rt.mk new file mode 100644 index 0000000..a2c6830 --- /dev/null +++ b/apple-xbs-support/clang_compiler_rt.mk @@ -0,0 +1,4 @@ +# apple-xbs-support/clang_compiler_rt.mk +# Redirect to the 'clang' base project. + +include apple-xbs-support/clang.mk diff --git a/apple-xbs-support/clang_compiler_rt_os.mk b/apple-xbs-support/clang_compiler_rt_os.mk new file mode 100644 index 0000000..0b3e5a3 --- /dev/null +++ b/apple-xbs-support/clang_compiler_rt_os.mk @@ -0,0 +1,4 @@ +# apple-xbs-support/clang_compiler_rt_os.mk +# Redirect to the 'clang' base project. + +include apple-xbs-support/clang.mk diff --git a/apple-xbs-support/clang_device.mk b/apple-xbs-support/clang_device.mk new file mode 100644 index 0000000..ff8e867 --- /dev/null +++ b/apple-xbs-support/clang_device.mk @@ -0,0 +1,8 @@ +# apple-xbs-support/clang_device.mk +# Redirect to the 'clang' base project. + +include apple-xbs-support/clang.mk + +# clang_device is configured to build using the 'install-cross' make target. +# in practice it can just use the clang target. +install-cross: clang diff --git a/apple-xbs-support/clang_libs_osx.mk b/apple-xbs-support/clang_libs_osx.mk new file mode 100644 index 0000000..2b92880 --- /dev/null +++ b/apple-xbs-support/clang_libs_osx.mk @@ -0,0 +1,4 @@ +# apple-xbs-support/clang_libs_osx.mk +# Redirect to the 'clang' base project. + +include apple-xbs-support/clang.mk diff --git a/apple-xbs-support/clang_shims.mk b/apple-xbs-support/clang_shims.mk new file mode 100644 index 0000000..80153c8 --- /dev/null +++ b/apple-xbs-support/clang_shims.mk @@ -0,0 +1,79 @@ +# +## B & I Makefile for gcc_select +# +# Copyright Apple Inc. 2002, 2003, 2007, 2009, 2011 + +#------------------------------------------------------------------------------# + +SHIMSROOT = $(SRCROOT)/clang-shims +DEVELOPER_DIR ?= / +DEV_DIR = $(DEVELOPER_DIR) +DT_TOOLCHAIN_DIR ?= $(DEVELOPER_DIR) +DEST_DIR = $(DSTROOT)$(DT_TOOLCHAIN_DIR) +GCC_LIBDIR = $(DSTROOT)$(DEV_DIR)/usr/lib/llvm-gcc/4.2.1 +CLTOOLS_DIR = /Library/Developer/CommandLineTools + +.PHONY: all install install-toolchain install-developer-dir \ + installhdrs installdoc clean installsym + +all: install + +$(OBJROOT)/c89.o : $(SHIMSROOT)/c89.c + $(CC) -c $^ -Wall -Os -g $(RC_CFLAGS) -o $@ + +$(OBJROOT)/c99.o : $(SHIMSROOT)/c99.c + $(CC) -c $^ -Wall -Werror -Os -g $(RC_CFLAGS) -o $@ + +$(OBJROOT)/ld.o : $(SHIMSROOT)/ld.c + $(CC) -c $^ -Wall -Werror -Os -g $(RC_CFLAGS) -o $@ + +$(OBJROOT)/gcc.o : $(SHIMSROOT)/gcc.c + $(CC) -c $^ -Wall -Werror -Os -g $(RC_CFLAGS) -o $@ + +$(OBJROOT)/libgcc.o : $(SHIMSROOT)/libgcc.c + $(CC) -c $^ -arch x86_64 -arch i386 -o $@ + +$(OBJROOT)/libgcc.a: $(OBJROOT)/libgcc.o + rm -f $@ + ar cru $@ $^ + ranlib $@ + +% : %.o + $(CC) $^ -g $(RC_CFLAGS) -o $@ + +%.dSYM : % + dsymutil $^ + +install: install-toolchain install-developer-dir $(OBJROOT)/ld installsym + install -s -c -m 555 $(OBJROOT)/ld $(DSTROOT)$(DEV_DIR)/usr/bin/ld + $(MAKE) DT_TOOLCHAIN_DIR=$(CLTOOLS_DIR) install-toolchain + $(MAKE) DEV_DIR=$(CLTOOLS_DIR) install-developer-dir + +install-toolchain: installdoc $(OBJROOT)/c99 $(OBJROOT)/c89 + mkdir -p $(DEST_DIR)/usr/bin + install -s -c -m 555 $(OBJROOT)/c99 $(DEST_DIR)/usr/bin/c99 + install -s -c -m 555 $(OBJROOT)/c89 $(DEST_DIR)/usr/bin/c89 + install -c -m 555 $(SHIMSROOT)/cpp $(DEST_DIR)/usr/bin/cpp + +install-developer-dir: $(OBJROOT)/gcc $(OBJROOT)/libgcc.a + mkdir -p $(DSTROOT)$(DEV_DIR)/usr/bin + install -s -c -m 555 $(OBJROOT)/gcc $(DSTROOT)$(DEV_DIR)/usr/bin/gcc + ln -s gcc $(DSTROOT)$(DEV_DIR)/usr/bin/g++ + mkdir -p $(GCC_LIBDIR)/include + for f in $(SHIMSROOT)/gcc-headers/*; do \ + install -c -m 444 $$f $(GCC_LIBDIR)/include; \ + done + install -c -m 444 $(OBJROOT)/libgcc.a $(GCC_LIBDIR) + +installsym: $(OBJROOT)/c99.dSYM $(OBJROOT)/c89.dSYM $(OBJROOT)/gcc.dSYM $(OBJROOT)/ld.dSYM + cp -rp $^ $(SYMROOT) + +installdoc: + mkdir -p $(DEST_DIR)/usr/share/man/man1 + install -c -m 444 $(SHIMSROOT)/c99.1 $(DEST_DIR)/usr/share/man/man1/c99.1 + install -c -m 444 $(SHIMSROOT)/c89.1 $(DEST_DIR)/usr/share/man/man1/c89.1 + +installhdrs: + +clean: + rm -rf $(OBJROOT)/c[89]9{,.dSYM} diff --git a/apple-xbs-support/helpers/installsrc.mk b/apple-xbs-support/helpers/installsrc.mk new file mode 100644 index 0000000..b44bc5a --- /dev/null +++ b/apple-xbs-support/helpers/installsrc.mk @@ -0,0 +1,33 @@ +# apple-xbs-support/helpers/installsrc.mk + +ifeq "$(installsrc-paths)" "" +$(error installsrc-paths unset; should be paths to include) +endif + +# Add defaults to any excludes that are manually +# specified. +installsrc-exclude := \ + $(installsrc-exclude) \ + .git .svn .DS_Store \ + .python_env \ + '*~' '.*~' '.*.sw?' + +MKDIR := /bin/mkdir -p -m 0755 + +# The individual B&I project makefiles should set their `installsrc` target +# to be `installsrc-helper`. +# +# We install the source using two tars piped together. +# We take particular care to: +# - Exclude any source control files. +# - Exclude any editor or OS cruft. +installsrc-helper: + @echo "Installing source..." + $(_v) $(MKDIR) "$(SRCROOT)" + $(_v) tar cf - \ + $(foreach p,$(installsrc-exclude), \ + --exclude "$(p)") \ + Makefile \ + apple-xbs-support \ + $(installsrc-paths) \ + | time tar xf - -C "$(SRCROOT)" diff --git a/apple-xbs-support/helpers/train_detection.mk b/apple-xbs-support/helpers/train_detection.mk new file mode 100644 index 0000000..375cddd --- /dev/null +++ b/apple-xbs-support/helpers/train_detection.mk @@ -0,0 +1,79 @@ +# Defines a list of known OS toolchains (i.e. toolchains submitted to an OS train). +# The Xcode default toolchain SHOULD NOT BE LISTED HERE. +KNOWN_OS_TOOLCHAINS := OSX iOS WatchOS AppleTVOS BridgeOS + + +# $(call toolchains-are-for-os,toolchains...) +# +# Check if all listed toolchains are OS toolchains +# - args[1]: space-seperated list of toolchains in the form or +# --. +# Example: $(call toolchains-are-for-os,OSX) => 1 +# Example: $(call toolchains-are-for-os,iOS) => 1 +# Example: $(call toolchains-are-for-os,iOS-7.0) => 1 +# Example: $(call toolchains-are-for-os,XcodeDefault) => +define toolchains-are-for-os +$(strip \ +$(if $(strip $(1)), +$(if \ + $(filter 0,\ + $(foreach x,$(1), + $(words \ + $(filter $(word 1,$(subst -, ,$(x))),$(KNOWN_OS_TOOLCHAINS))))),\ + ,1),)\ +) +endef + +define invert +$(if $(strip $(1)),,1) +endef + +# $(call toolchain-version-is-at-least,version-to-check,minimum-versions...) +# +# Check matching toolchain version is big enough. Expects one hyphen, between +# the toolchain name and version, then the major, a dot, and the minor. +# - args[1]: version to check, in -. form. +# - args[2]: space-separated list of versions that are big enough. +# Example: $(call toolchain-version-is-at-least,OSX-10.15,OSX-10.15 iOS-7.0) => 1 +# Example: $(call toolchain-version-is-at-least,iOS-6.2,OSX-10.15 iOS-7.0) => +define toolchain-version-is-at-least +$(strip \ +$(if $(strip $(filter-out 2,$(foreach x,$(1) $(2),$(words $(subst -, ,$(x)))))),\ + $(error expected one hyphen in each version, got $(1) $(2)),\ +$(if $(strip $(filter-out 2,$(foreach x,$(1) $(2),$(words $(subst ., ,$(x)))))),\ + $(error expected one dot in each version, got $(1) $(2)),\ +$(if $(call invert,$(call toolchains-are-for-os,$(1) $(2))),\ + $(error Unknown toolchain in "$(1) $(2)". Known toolchains are "$(KNOWN_OS_TOOLCHAINS)"),\ +$(if \ + $(filter $(1),\ + $(word 2,\ + $(shell printf "%s\n" $(1) \ + $(filter $(word 1,$(subst -, ,$(1)))-%,$(2)) \ + | sort --version-sort))),\ + 1,))))\ +) +endef + +# $(call toolchain-name-version,path/to/toolchain) +# +# Convert "path/to/Train1.2.3.4.xctoolchain" to "Train-1.2.3.4". +define toolchain-name-version +$(shell printf "%s" "$(basename $(notdir $(1)))" | sed -e 's,[0-9],-&,') +endef + +# $(call os-train-version-is-at-least,minimum-versions...) +# +# Check that the OS train being submitted to is at least the minimum version. +# - args[1]: space-separated list of versions of the form -.. +# +# Examples: +# $(call os-train-version-is-at-least,OSX-10.15 iOS-7.0 WatchOS-6.0 AppleTVOS-7.0 BridgeOS-4.0) +define os-train-version-is-at-least +$(strip \ +$(if $(DT_TOOLCHAIN_DIR),\ + $(call toolchain-version-is-at-least,\ + $(call toolchain-name-version,$(DT_TOOLCHAIN_DIR)),\ + $(1)),\ + $(error DT_TOOLCHAIN_DIR cannot be empty))\ +) +endef diff --git a/apple-xbs-support/libcxx.mk b/apple-xbs-support/libcxx.mk new file mode 100644 index 0000000..b692024 --- /dev/null +++ b/apple-xbs-support/libcxx.mk @@ -0,0 +1,66 @@ +############################################################################## +# Top-level targets executed by XBS for the internal build of libc++ and libc++abi +############################################################################## + +# Declare 'install' target first to make it default. +install: + +# Eventually we'll also want llvm/cmake and pieces, but for now keep this +# standalone. +installsrc-paths := libcxx libcxxabi llvm +include apple-xbs-support/helpers/installsrc.mk + +.PHONY: installsrc +installsrc: installsrc-helper + +.PHONY: install +install: + @echo "Installing libc++.dylib and libc++abi.dylib" + "${SRCROOT}/libcxx/utils/ci/apple-install-libcxx.sh" \ + --llvm-root "${SRCROOT}" \ + --build-dir "${OBJROOT}" \ + --install-dir "${DSTROOT}" \ + --symbols-dir "${SYMROOT}" \ + --sdk $(shell /usr/libexec/PlistBuddy -c "Print :CanonicalName string" "${SDKROOT}/SDKSettings.plist") \ + --architectures "${RC_ARCHS}" \ + --version "${RC_ProjectSourceVersion}" \ + --cache "${SRCROOT}/libcxx/cmake/caches/Apple.cmake" + +.PHONY: libcxx_dyld +libcxx_dyld: + @echo "Installing the various libc++abi-static.a for dyld" + "${SRCROOT}/libcxx/utils/ci/apple-install-libcxxabi-dyld.sh" \ + --llvm-root "${SRCROOT}" \ + --build-dir "${OBJROOT}" \ + --install-dir "${DSTROOT}" \ + --sdk $(shell /usr/libexec/PlistBuddy -c "Print :CanonicalName string" "${SDKROOT}/SDKSettings.plist") \ + --architectures "${RC_ARCHS}" + +.PHONY: libcxx_driverkit +libcxx_driverkit: + @echo "Installing DriverKit libc++.dylib and libc++abi.dylib" + "${SRCROOT}/libcxx/utils/ci/apple-install-libcxx.sh" \ + --llvm-root "${SRCROOT}" \ + --build-dir "${OBJROOT}" \ + --install-dir "${DSTROOT}/System/DriverKit" \ + --symbols-dir "${SYMROOT}" \ + --sdk $(shell /usr/libexec/PlistBuddy -c "Print :CanonicalName string" "${SDKROOT}/SDKSettings.plist") \ + --architectures "${RC_ARCHS}" \ + --version "${RC_ProjectSourceVersion}" \ + --cache "${SRCROOT}/libcxx/cmake/caches/AppleDriverKit.cmake" + +.PHONY: installhdrs +installhdrs: install + rm -r "${DSTROOT}/usr/lib" "${DSTROOT}/usr/local" + +.PHONY: installhdrs_dyld +installhdrs_dyld: + @echo "There are no headers to install for dyld's libc++abi" + +.PHONY: installhdrs_driverkit +installhdrs_driverkit: libcxx_driverkit + rm -r "${DSTROOT}/System/DriverKit/usr/lib" "${DSTROOT}/System/DriverKit/Runtime/usr/local" + +.PHONY: clean +clean: + @echo "Nothing to clean" diff --git a/apple-xbs-support/libcxx_Sim.mk b/apple-xbs-support/libcxx_Sim.mk new file mode 100644 index 0000000..48101cd --- /dev/null +++ b/apple-xbs-support/libcxx_Sim.mk @@ -0,0 +1 @@ +include apple-xbs-support/libcxx.mk diff --git a/apple-xbs-support/libcxx_driverkit.mk b/apple-xbs-support/libcxx_driverkit.mk new file mode 100644 index 0000000..48101cd --- /dev/null +++ b/apple-xbs-support/libcxx_driverkit.mk @@ -0,0 +1 @@ +include apple-xbs-support/libcxx.mk diff --git a/apple-xbs-support/libcxx_dyld.mk b/apple-xbs-support/libcxx_dyld.mk new file mode 100644 index 0000000..48101cd --- /dev/null +++ b/apple-xbs-support/libcxx_dyld.mk @@ -0,0 +1 @@ +include apple-xbs-support/libcxx.mk diff --git a/apple-xbs-support/libcxx_dyld_Sim.mk b/apple-xbs-support/libcxx_dyld_Sim.mk new file mode 100644 index 0000000..48101cd --- /dev/null +++ b/apple-xbs-support/libcxx_dyld_Sim.mk @@ -0,0 +1 @@ +include apple-xbs-support/libcxx.mk diff --git a/apple-xbs-support/libunwind.mk b/apple-xbs-support/libunwind.mk new file mode 100644 index 0000000..02bc576 --- /dev/null +++ b/apple-xbs-support/libunwind.mk @@ -0,0 +1,31 @@ +############################################################################## +# Top-level targets executed by XBS for the internal build of libunwind +############################################################################## + +# Declare 'install' target first to make it default. +install: + +# Eventually we'll also want llvm/cmake and pieces, but for now keep this +# standalone. +installsrc-paths := libunwind +include apple-xbs-support/helpers/installsrc.mk + +.PHONY: installsrc +installsrc: installsrc-helper + +.PHONY: install +install: + @echo "Installing libunwind.dylib" + "${SRCROOT}/libunwind/apple-install-libunwind.sh" $(INSTALLFLAGS) + +.PHONY: installapi +installapi: + @echo "We don't currently perform an installapi step here" + +.PHONY: installhdrs +installhdrs: + @echo "We don't currently install the libunwind headers here" + +.PHONY: clean +clean: + @echo "Nothing to clean" diff --git a/apple-xbs-support/libunwind_Sim.mk b/apple-xbs-support/libunwind_Sim.mk new file mode 100644 index 0000000..c620492 --- /dev/null +++ b/apple-xbs-support/libunwind_Sim.mk @@ -0,0 +1,2 @@ +INSTALLFLAGS := --sim +include apple-xbs-support/libunwind.mk diff --git a/apple-xbs-support/libunwind_dyld.mk b/apple-xbs-support/libunwind_dyld.mk new file mode 100644 index 0000000..1cc5116 --- /dev/null +++ b/apple-xbs-support/libunwind_dyld.mk @@ -0,0 +1,2 @@ +INSTALLFLAGS := --dyld +include apple-xbs-support/libunwind.mk diff --git a/apple-xbs-support/libunwind_dyld_Sim.mk b/apple-xbs-support/libunwind_dyld_Sim.mk new file mode 100644 index 0000000..7c416d3 --- /dev/null +++ b/apple-xbs-support/libunwind_dyld_Sim.mk @@ -0,0 +1,2 @@ +INSTALLFLAGS := --sim --dyld +include apple-xbs-support/libunwind.mk diff --git a/apple-xbs-support/tapi.mk b/apple-xbs-support/tapi.mk new file mode 100644 index 0000000..7b2a219 --- /dev/null +++ b/apple-xbs-support/tapi.mk @@ -0,0 +1,168 @@ +# +# Apple B&I Makefile +# +INSTALL := $(shell xcrun -f install) +BUILD_TAPI := $(SRCROOT)/tapi/utils/buildit/build_tapi + +# +# TAPI supports installapi per default. Allow B&I to change the default and +# print a status message to the log file. +# +SUPPORTS_TEXT_BASED_API ?= YES +$(info SUPPORTS_TEXT_BASED_API=$(SUPPORTS_TEXT_BASED_API)) + +# +# Common settings +# +TAPI_VERSION := 12.0.0 +TAPI_INSTALL_PREFIX := $(DSTROOT)/$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR) +TAPI_LIBRARY_PATH := $(TAPI_INSTALL_PREFIX)/usr/lib +TAPI_LOCAL_LIBRARY_PATH := $(TAPI_INSTALL_PREFIX)/usr/local/lib +TAPI_HEADER_PATH := $(TAPI_INSTALL_PREFIX)/usr/local/include + +TAPI_COMMON_OPTS := -dynamiclib \ + -xc++ \ + -std=c++11 \ + $(RC_ARCHS:%=-arch %) \ + -current_version $(RC_ProjectSourceVersion) \ + -compatibility_version 1 \ + -I$(TAPI_HEADER_PATH) + +TAPI_VERIFY_OPTS := $(TAPI_COMMON_OPTS) \ + --verify-mode=Pedantic + + +.PHONY: installsrc installhdrs installapi install tapi build installapi-verify clean + +# +# Only run the verify target if installapi is enabled. +# +ifeq ($(SUPPORTS_TEXT_BASED_API),YES) +install: installapi-verify +endif + +# Install source uses the shared helper, but also fetches PGO data during +# submission to a B&I train. +installsrc-paths := \ + llvm \ + clang \ + tapi + +include apple-xbs-support/helpers/installsrc.mk + +installsrc: installsrc-helper + +installhdrs: $(DSTROOT) + @echo + @echo ++++++++++++++++++++++ + @echo + Installing headers + + @echo ++++++++++++++++++++++ + @echo + ditto $(SRCROOT)/tapi/include/tapi/*.h $(TAPI_HEADER_PATH)/tapi/ + ditto $(SRCROOT)/tapi/include/tapi-c/*.h $(TAPI_HEADER_PATH)/tapi-c/ + # Generate Version.inc + echo "$(TAPI_VERSION)" | awk -F. '{ \ + printf "#define TAPI_VERSION %d.%d.%d\n", $$1, $$2, $$3; \ + printf "#define TAPI_VERSION_MAJOR %dU\n", $$1; \ + printf "#define TAPI_VERSION_MINOR %dU\n", $$2; \ + printf "#define TAPI_VERSION_PATCH %dU\n", $$3; \ + }' > $(TAPI_HEADER_PATH)/tapi/Version.inc + +installapi: installhdrs $(OBJROOT) $(DSTROOT) + @echo + @echo ++++++++++++++++++++++ + @echo + Running InstallAPI + + @echo ++++++++++++++++++++++ + @echo + + @if [ "$(SUPPORTS_TEXT_BASED_API)" != "YES" ]; then \ + echo "installapi for target 'tapi' was requested, but SUPPORTS_TEXT_BASED_API has been disabled."; \ + exit 1; \ + fi + + xcrun --sdk $(SDKROOT) tapi installapi \ + $(TAPI_COMMON_OPTS) \ + -allowable_client ld \ + -install_name @rpath/libtapi.dylib \ + -o $(OBJROOT)/libtapi.tbd \ + -exclude-private-header "**/tapi-c/*" \ + $(TAPI_INSTALL_PREFIX) + + xcrun --sdk $(SDKROOT) tapi installapi \ + $(TAPI_COMMON_OPTS) \ + -install_name @rpath/libtapiMRM.dylib \ + -o $(OBJROOT)/libtapiMRM.tbd \ + -exclude-private-header "**/tapi/*" \ + $(TAPI_INSTALL_PREFIX) + + $(INSTALL) -d -m 0755 $(TAPI_LIBRARY_PATH) + $(INSTALL) -c -m 0755 $(OBJROOT)/libtapi.tbd $(TAPI_LIBRARY_PATH)/libtapi.tbd + $(INSTALL) -d -m 0755 $(TAPI_LOCAL_LIBRARY_PATH) + $(INSTALL) -c -m 0755 $(OBJROOT)/libtapiMRM.tbd $(TAPI_LOCAL_LIBRARY_PATH)/libtapiMRM.tbd + +tapi: install +install: build + +build: $(OBJROOT) $(SYMROOT) $(DSTROOT) + @echo + @echo +++++++++++++++++++++ + @echo + Build and Install + + @echo +++++++++++++++++++++ + @echo + cd $(OBJROOT) && $(BUILD_TAPI) $(TAPI_VERSION) + +installapi-verify: build + @echo + @echo +++++++++++++++++++++++++++++++++ + @echo + Running InstallAPI and Verify + + @echo +++++++++++++++++++++++++++++++++ + @echo + + @if [ "$(SUPPORTS_TEXT_BASED_API)" != "YES" ]; then \ + echo "installapi for target 'tapi' was requested, but SUPPORTS_TEXT_BASED_API has been disabled."; \ + exit 1; \ + fi + + xcrun --sdk $(SDKROOT) tapi installapi \ + $(TAPI_VERIFY_OPTS) \ + -allowable_client ld \ + -install_name @rpath/libtapi.dylib \ + -o $(OBJROOT)/libtapi.tbd \ + --verify-against=$(TAPI_LIBRARY_PATH)/libtapi.dylib \ + -exclude-private-header "**/tapi-c/*" \ + $(TAPI_INSTALL_PREFIX) + + xcrun --sdk $(SDKROOT) tapi installapi \ + $(TAPI_VERIFY_OPTS) \ + -install_name @rpath/libtapiMRM.dylib \ + -o $(OBJROOT)/libtapiMRM.tbd \ + --verify-against=$(TAPI_LOCAL_LIBRARY_PATH)/libtapiMRM.dylib \ + -exclude-private-header "**/tapi/*" \ + $(TAPI_INSTALL_PREFIX) + + $(INSTALL) -d -m 0755 $(TAPI_LIBRARY_PATH) + $(INSTALL) -c -m 0755 $(OBJROOT)/libtapi.tbd $(TAPI_LIBRARY_PATH)/libtapi.tbd + $(INSTALL) -d -m 0755 $(TAPI_LOCAL_LIBRARY_PATH) + $(INSTALL) -c -m 0755 $(OBJROOT)/libtapiMRM.tbd $(TAPI_LOCAL_LIBRARY_PATH)/libtapiMRM.tbd + +clean: + @echo + @echo ++++++++++++ + @echo + Cleaning + + @echo ++++++++++++ + @echo + @if [ -d "$(OBJROOT)" -a "$(OBJROOT)" != "/" ]; then \ + echo '*** DELETING ' $(OBJROOT); \ + rm -rf "$(OBJROOT)"; \ + fi + @if [ -d "$(SYMROOT)" -a "$(SYMROOT)" != "/" ]; then \ + echo '*** DELETING ' $(SYMROOT); \ + rm -rf "$(SYMROOT)"; \ + fi + @if [ -d "$(DSTROOT)" -a "$(DSTROOT)" != "/" ]; then \ + echo '*** DELETING ' $(DSTROOT); \ + rm -rf "$(DSTROOT)"; \ + fi + +$(OBJROOT) $(SYMROOT) $(DSTROOT): + mkdir -p "$@" diff --git a/apple-xbs-support/test/Libcompiler_rt/installsrc.test b/apple-xbs-support/test/Libcompiler_rt/installsrc.test new file mode 100644 index 0000000..c94b859 --- /dev/null +++ b/apple-xbs-support/test/Libcompiler_rt/installsrc.test @@ -0,0 +1,12 @@ +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: make -C %src_root installsrc "SRCROOT=%t/dest" "RC_ProjectName=Libcompiler_rt" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/dest/Libcompiler_rt.xcodeproj +RUN: stat %t/dest/lib +RUN: ! stat %t/dest/cmake +RUN: ! stat %t/dest/make +RUN: ! stat %t/dest/test + diff --git a/apple-xbs-support/test/Makefile b/apple-xbs-support/test/Makefile new file mode 100644 index 0000000..3f35a7d --- /dev/null +++ b/apple-xbs-support/test/Makefile @@ -0,0 +1,23 @@ +## Makefile to run the `apple-xbs-support` tests. + +VENV_OUT=.python_env +PYTHON_ROOT := $(VENV_OUT)/bin/ + +all: check-lit + +clean: + rm -rf $(VENV_OUT) + +install-lit: $(VENV_OUT) Makefile + +$(VENV_OUT): + @echo "Setting up python venv & installing lit..." + python3 -m venv $(VENV_OUT) + $(PYTHON_ROOT)pip install lit + @echo "" + +check-lit: install-lit + @echo "Running 'apple-xbs-support' tests..." + $(PYTHON_ROOT)lit -vv . + +.PHONY: all clean install-lit check-lit diff --git a/apple-xbs-support/test/clang/installsrc.test b/apple-xbs-support/test/clang/installsrc.test new file mode 100644 index 0000000..3169763 --- /dev/null +++ b/apple-xbs-support/test/clang/installsrc.test @@ -0,0 +1,17 @@ +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: make -C %src_root installsrc "SRCROOT=%t/dest" "RC_ProjectName=clang" "RC_ProjectSourceVersion=9999.99.99" 2>&1 \ +RUN: | grep 'clang => apple-xbs-support/clang.mk' + +# Verify that we got all the subdirs we wanted. + +RUN: stat %t/dest/Makefile +RUN: stat %t/dest/apple-xbs-support +RUN: stat %t/dest/clang +RUN: stat %t/dest/clang-shims +RUN: stat %t/dest/clang-tools-extra +RUN: stat %t/dest/compiler-rt +RUN: stat %t/dest/libcxx +RUN: stat %t/dest/libcxxabi +RUN: stat %t/dest/llvm +RUN: ! stat %t/dest/polly diff --git a/apple-xbs-support/test/clang/installsrc_variant.test b/apple-xbs-support/test/clang/installsrc_variant.test new file mode 100644 index 0000000..c0210f8 --- /dev/null +++ b/apple-xbs-support/test/clang/installsrc_variant.test @@ -0,0 +1,7 @@ +# Check that variants can pass clang_compiler_rt content. +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: make -C %src_root installsrc "SRCROOT=%t/dest" "RC_ProjectName=Variant_clang" \ +RUN: "RC_ProjectSourceVersion=9999.99.99" 2>&1 \ +RUN: | tee %t/log \ +RUN: | grep 'COMPILER_RT_TOOLCHAIN_DYLIB_DIR:.*/Variant_clang_compiler_rt/' diff --git a/apple-xbs-support/test/clang/shims.test b/apple-xbs-support/test/clang/shims.test new file mode 100644 index 0000000..7e67c32 --- /dev/null +++ b/apple-xbs-support/test/clang/shims.test @@ -0,0 +1,22 @@ +# Build c99. +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: make -C %src_root \ +RUN: install -j 1 \ +RUN: RC_ProjectName=clang_shims RC_ProjectSourceVersion=9999.99.99 \ +RUN: OBJROOT="%t"/objroot DSTROOT="%t"/dstroot SRCROOT=%src_root \ +RUN: DEVELOPER_DIR="%DEVELOPER_DIR" + +# Check that c99 builds. +RUN: stat "%t/dstroot/%DEVELOPER_DIR"/usr/bin/c99 + +# Check that c99 calls out to clang for -d M. +# +# FIXME: Move this to clang-shims/test once we have a test suite set up. +REQUIRES: iworkdir=os +RUN: printf "%%s\n" >"%t/dstroot/%DEVELOPER_DIR"/usr/bin/clang \ +RUN: "#!/bin/sh" 'exec xcrun clang "$@"' +RUN: chmod +x "%t/dstroot/%DEVELOPER_DIR"/usr/bin/clang +RUN: "%t/dstroot/%DEVELOPER_DIR"/usr/bin/c99 -W macros \ +RUN: | grep "#define __APPLE__ 1" diff --git a/apple-xbs-support/test/generic/missing-RC_ProjectName.test b/apple-xbs-support/test/generic/missing-RC_ProjectName.test new file mode 100644 index 0000000..e8acb4d --- /dev/null +++ b/apple-xbs-support/test/generic/missing-RC_ProjectName.test @@ -0,0 +1,4 @@ +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: ! make -C %src_root 2>&1 | grep 'make RC_ProjectName=clang' +RUN: ! make -C %src_root 2>&1 | grep 'make RC_ProjectName=clang_device' diff --git a/apple-xbs-support/test/generic/missing-SRCROOT.test b/apple-xbs-support/test/generic/missing-SRCROOT.test new file mode 100644 index 0000000..15477a0 --- /dev/null +++ b/apple-xbs-support/test/generic/missing-SRCROOT.test @@ -0,0 +1,3 @@ +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: ! make -C %src_root RC_ProjectName=clang 2>&1 | grep 'SRCROOT not set' diff --git a/apple-xbs-support/test/generic/train_detection.test b/apple-xbs-support/test/generic/train_detection.test new file mode 100644 index 0000000..cdcc732 --- /dev/null +++ b/apple-xbs-support/test/generic/train_detection.test @@ -0,0 +1,187 @@ +############################################################################### +# Tests for train_detection.mk +############################################################################### +include train_detection.mk + +# Test success paths. +# RUN: %make_with_helpers -f %s + +# Dummy target that always succeeds +.PHONY: test +test: + @echo run tests. + +define assert_true +$(if $(strip $(1)),\ + $(info PASS assert_true:"$(1)"),\ + $(error FAIL assert_true:"$(1)")) +endef +define assert_false +$(if $(strip $(1)),\ + $(error FAIL assert_false:"$(1)"),\ + $(info PASS assert_false:"$(1)")) +endef +define str_is_eq +$(if $(shell [ "$(1)" = "$(2)" ] && echo 1),1,) +endef +define assert_str_eq +$(if $(call str_is_eq,$(1),$(2)),\ + $(info PASS assert_str_eq: "$(1)" == "$(2)"),\ + $(info FAIL assert_str_eq: "$(1)" != "$(2)")) +endef + +# Test str_is_eq +$(call assert_true,$(call str_is_eq,a,a,)) +$(call assert_true,$(call str_is_eq,abc,abc)) +$(call assert_false,$(call str_is_eq,abc,abcd)) +$(call assert_false,$(call str_is_eq,,abcd)) +$(call assert_false,$(call str_is_eq,abcd,)) +$(call assert_true,$(call str_is_eq,foo bar,foo bar)) +$(call assert_false,$(call str_is_eq,foo bar baz,foo bar)) +$(call assert_false,$(call str_is_eq,foo bar,foo bar baz)) + +# Test toolchains-are-for-os +$(call assert_true,$(call toolchains-are-for-os,OSX)) +$(call assert_true,$(call toolchains-are-for-os,iOS)) +$(call assert_true,$(call toolchains-are-for-os,WatchOS)) +$(call assert_true,$(call toolchains-are-for-os,AppleTVOS)) +$(call assert_true,$(call toolchains-are-for-os,BridgeOS)) +$(call assert_true,$(call toolchains-are-for-os,OSX-10.15)) +$(call assert_true,$(call toolchains-are-for-os,\ + OSX iOS WatchOS AppleTVOS BridgeOS)) +$(call assert_false,$(call toolchains-are-for-os,XcodeDefault)) +$(call assert_false,$(call toolchains-are-for-os,\ + OSX XcodeDefault)) +$(call assert_false,$(call toolchains-are-for-os,)) +$(call assert_false,$(call toolchains-are-for-os, )) + +# Test invert +$(call assert_false,$(call invert,1)) +$(call assert_true,$(call invert,)) +$(call assert_true,$(call invert, )) + +# Test toolchain-version-is-at-least +$(call assert_true,$(call toolchain-version-is-at-least,OSX-10.15,OSX-10.15)) +$(call assert_true,$(call toolchain-version-is-at-least,OSX-10.16,OSX-10.15)) +$(call assert_true,$(call toolchain-version-is-at-least,OSX-10.17,OSX-10.15)) +$(call assert_true,$(call toolchain-version-is-at-least,OSX-11.0,OSX-10.15)) +$(call assert_false,$(call toolchain-version-is-at-least,OSX-10.4,OSX-10.15)) +$(call assert_false,$(call toolchain-version-is-at-least,OSX-10.14,OSX-10.15)) +$(call assert_false,$(call toolchain-version-is-at-least,,OSX-10.15)) + +# Failure Paths +# RUN: (! %make_with_helpers -f %s \ +# RUN: TEST_FAILURE=toolchain-version-is-at-least0) 2>&1 | \ +# RUN: grep 'Unknown toolchain in " "' +ifeq ($(TEST_FAILURE),toolchain-version-is-at-least0) + $(call assert_false,$(call toolchain-version-is-at-least,,)) +endif + +# RUN: (! %make_with_helpers -f %s \ +# RUN: TEST_FAILURE=toolchain-version-is-at-least1) 2>&1 | \ +# RUN: grep 'expected one hyphen in each version' +ifeq ($(TEST_FAILURE),toolchain-version-is-at-least1) + $(call assert_false,$(call toolchain-version-is-at-least,,OSX)) +endif + +# RUN: (! %make_with_helpers -f %s \ +# RUN: TEST_FAILURE=toolchain-version-is-at-least2) 2>&1 | \ +# RUN: grep 'expected one dot in each version' +ifeq ($(TEST_FAILURE),toolchain-version-is-at-least2) + $(call assert_false,$(call toolchain-version-is-at-least,OSX-10.15,OSX-10)) +endif + +# RUN: (! %make_with_helpers -f %s \ +# RUN: TEST_FAILURE=toolchain-version-is-at-least3) 2>&1 | \ +# RUN: grep 'expected one hyphen in each version' +ifeq ($(TEST_FAILURE),toolchain-version-is-at-least3) + $(call assert_false,$(call toolchain-version-is-at-least,XcodeDefault,OSX-10)) +endif + +# RUN: (! %make_with_helpers -f %s \ +# RUN: TEST_FAILURE=toolchain-version-is-at-least4) 2>&1 | \ +# RUN: grep 'Unknown toolchain in "XcodeDefault-5.0 OSX-10.15"' +ifeq ($(TEST_FAILURE),toolchain-version-is-at-least4) + $(call assert_false,$(call toolchain-version-is-at-least,XcodeDefault-5.0,OSX-10.15)) +endif + +MIN_V := OSX-11.0 iOS-14.0 WatchOS-7.0 AppleTVOS-14.0 BridgeOS-5.0 +$(call assert_false,$(call toolchain-version-is-at-least,\ + OSX-10.15,$(MIN_V))) +$(call assert_true,$(call toolchain-version-is-at-least,\ + OSX-11.0,$(MIN_V))) +$(call assert_false,$(call toolchain-version-is-at-least,\ + iOS-13.0,$(MIN_V))) +$(call assert_true,$(call toolchain-version-is-at-least,\ + iOS-14.0,$(MIN_V))) +$(call assert_false,$(call toolchain-version-is-at-least,\ + WatchOS-6.0,$(MIN_V))) +$(call assert_true,$(call toolchain-version-is-at-least,\ + WatchOS-7.0,$(MIN_V))) +$(call assert_false,$(call toolchain-version-is-at-least,\ + AppleTVOS-13.0,$(MIN_V))) +$(call assert_true,$(call toolchain-version-is-at-least,\ + AppleTVOS-14.0,$(MIN_V))) +$(call assert_false,$(call toolchain-version-is-at-least,\ + BridgeOS-4.0,$(MIN_V))) +$(call assert_true,$(call toolchain-version-is-at-least,\ + BridgeOS-5.0,$(MIN_V))) +$(call assert_false,$(call toolchain-version-is-at-least,\ + OSX-10.15,iOS-13.0)) + +# Test toolchain-name-version +$(call assert_str_eq,$(call toolchain-name-version,/Applications/Xcode.app/Contents/Developer/Toolchains/OSX11.0.xctoolchain),OSX-11.0) +$(call assert_str_eq,$(call toolchain-name-version,/Applications/Xcode.app/Contents/Developer/Toolchains/iOS13.4.xctoolchain),iOS-13.4) +$(call assert_str_eq,$(call toolchain-name-version,/Applications/Xcode.app/Contents/Developer/Toolchains/WatchOS6.2.xctoolchain),WatchOS-6.2) +$(call assert_str_eq,$(call toolchain-name-version,/Applications/Xcode.app/Contents/Developer/Toolchains/AppleTVOS13.4.xctoolchain),AppleTVOS-13.4) +$(call assert_str_eq,$(call toolchain-name-version,/Applications/Xcode.app/Contents/Developer/Toolchains/BridgeOS4.0.xctoolchain),BridgeOS-4.0) +$(call assert_str_eq,$(call toolchain-name-version,/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain),XcodeDefault) + +# Test os-train-version-is-at-least +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/OSX11.0.xctoolchain +$(call assert_true,$(call os-train-version-is-at-least,OSX-10.15)) +$(call assert_true,$(call os-train-version-is-at-least,OSX-11.0)) +$(call assert_false,$(call os-train-version-is-at-least,OSX-11.1)) +$(call assert_true,$(call os-train-version-is-at-least,$(MIN_V))) +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.15.xctoolchain +$(call assert_false,$(call os-train-version-is-at-least,$(MIN_V))) + +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/iOS14.0.xctoolchain +$(call assert_true,$(call os-train-version-is-at-least,iOS-13.0)) +$(call assert_true,$(call os-train-version-is-at-least,iOS-14.0)) +$(call assert_false,$(call os-train-version-is-at-least,iOS-15.0)) +$(call assert_true,$(call os-train-version-is-at-least,$(MIN_V))) +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/iOS13.0.xctoolchain +$(call assert_false,$(call os-train-version-is-at-least,$(MIN_V))) + +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/WatchOS7.0.xctoolchain +$(call assert_true,$(call os-train-version-is-at-least,WatchOS-6.0)) +$(call assert_true,$(call os-train-version-is-at-least,WatchOS-7.0)) +$(call assert_false,$(call os-train-version-is-at-least,WatchOS-8.0)) +$(call assert_true,$(call os-train-version-is-at-least,$(MIN_V))) +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/WatchOS6.0.xctoolchain +$(call assert_false,$(call os-train-version-is-at-least,$(MIN_V))) + +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/AppleTVOS14.0.xctoolchain +$(call assert_true,$(call os-train-version-is-at-least,AppleTVOS-13.0)) +$(call assert_true,$(call os-train-version-is-at-least,AppleTVOS-14.0)) +$(call assert_false,$(call os-train-version-is-at-least,AppleTVOS-15.0)) +$(call assert_true,$(call os-train-version-is-at-least,$(MIN_V))) +DT_TOOLCHAIN_DIR=/Applications/Xcode.app/Contents/Developer/Toolchains/AppleTVOS13.0.xctoolchain +$(call assert_false,$(call os-train-version-is-at-least,$(MIN_V))) + +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/BridgeOS5.0.xctoolchain +$(call assert_true,$(call os-train-version-is-at-least,BridgeOS-4.0)) +$(call assert_true,$(call os-train-version-is-at-least,BridgeOS-5.0)) +$(call assert_false,$(call os-train-version-is-at-least,BridgeOS-6.0)) +$(call assert_true,$(call os-train-version-is-at-least,$(MIN_V))) +DT_TOOLCHAIN_DIR:=/Applications/Xcode.app/Contents/Developer/Toolchains/BridgeOS4.0.xctoolchain +$(call assert_false,$(call os-train-version-is-at-least,$(MIN_V))) + +# RUN: (! %make_with_helpers -f %s \ +# RUN: TEST_FAILURE=os-train-version-is-at-least0) 2>&1 | \ +# RUN: grep 'DT_TOOLCHAIN_DIR cannot be empty' +ifeq ($(TEST_FAILURE),os-train-version-is-at-least0) + DT_TOOLCHAIN_DIR := + $(call os-train-version-is-at-least,OSX-10.15) +endif diff --git a/apple-xbs-support/test/libcxx/install_libcxx.test b/apple-xbs-support/test/libcxx/install_libcxx.test new file mode 100644 index 0000000..94d728b --- /dev/null +++ b/apple-xbs-support/test/libcxx/install_libcxx.test @@ -0,0 +1,27 @@ +# Run the build for libcxx +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: mkdir -p %t/symroot +RUN: make -C "%src_root" install -j 1 RC_ProjectName=libcxx \ +RUN: RC_ProjectSourceVersion=9999.99.99 \ +RUN: OBJROOT="%t/objroot" \ +RUN: DSTROOT="%t/dstroot" \ +RUN: SYMROOT="%t/symroot" \ +RUN: SRCROOT="%src_root" \ +RUN: SDKROOT=$(xcrun --sdk macosx.internal --show-sdk-path) \ +RUN: RC_ARCHS=x86_64 + +# Check that libc++.1.dylib and libc++abi.dylib built in the right locations +RUN: stat "%t/dstroot/usr/lib/libc++.1.dylib" +RUN: stat "%t/dstroot/usr/lib/libc++abi.dylib" + +# Check that we installed the libc++ and libc++abi headers in the right location +RUN: stat "%t/dstroot/usr/include/c++/v1/__config" +RUN: stat "%t/dstroot/usr/include/cxxabi.h" + +# Check that the compatibility_version of libc++ and libc++abi is 1.0.0 +RUN: otool -L "%t/dstroot/usr/lib/libc++abi.dylib" | \ +RUN: grep "libc++abi.dylib" | grep "compatibility version 1.0.0" +RUN: otool -L "%t/dstroot/usr/lib/libc++.1.dylib" | \ +RUN: grep "libc++.1.dylib" | grep "compatibility version 1.0.0" diff --git a/apple-xbs-support/test/libcxx/install_libcxx_driverkit.test b/apple-xbs-support/test/libcxx/install_libcxx_driverkit.test new file mode 100644 index 0000000..1798360 --- /dev/null +++ b/apple-xbs-support/test/libcxx/install_libcxx_driverkit.test @@ -0,0 +1,27 @@ +# Run the build for libcxx_driverkit +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: mkdir -p %t/symroot +RUN: make -C "%src_root" libcxx_driverkit -j 1 RC_ProjectName=libcxx_driverkit \ +RUN: RC_ProjectSourceVersion=9999.99.99 \ +RUN: OBJROOT="%t/objroot" \ +RUN: DSTROOT="%t/dstroot" \ +RUN: SYMROOT="%t/symroot" \ +RUN: SRCROOT="%src_root" \ +RUN: SDKROOT=$(xcrun --sdk driverkit.macosx.internal --show-sdk-path) \ +RUN: RC_ARCHS=x86_64 + +# Check that libc++.dylib and libc++abi.dylib built in the right locations +RUN: stat "%t/dstroot/System/DriverKit/usr/lib/libc++.dylib" +RUN: stat "%t/dstroot/System/DriverKit/usr/lib/libc++abi.dylib" + +# Check that we installed the libc++ and libc++abi headers in the right location +RUN: stat "%t/dstroot/System/DriverKit/Runtime/usr/include/c++/v1/__config" +RUN: stat "%t/dstroot/System/DriverKit/Runtime/usr/include/cxxabi.h" + +# Check that the compatibility_version of libc++ and libc++abi is 1.0.0 +RUN: otool -L "%t/dstroot/System/DriverKit/usr/lib/libc++abi.dylib" | \ +RUN: grep "libc++abi.dylib" | grep "compatibility version 1.0.0" +RUN: otool -L "%t/dstroot/System/DriverKit/usr/lib/libc++.dylib" | \ +RUN: grep "libc++.dylib" | grep "compatibility version 1.0.0" diff --git a/apple-xbs-support/test/libcxx/install_libcxx_dyld.test b/apple-xbs-support/test/libcxx/install_libcxx_dyld.test new file mode 100644 index 0000000..1097f9a --- /dev/null +++ b/apple-xbs-support/test/libcxx/install_libcxx_dyld.test @@ -0,0 +1,27 @@ +# Run the build for libcxx_dyld +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: mkdir -p %t/symroot +RUN: make -C "%src_root" libcxx_dyld -j 1 RC_ProjectName=libcxx_dyld \ +RUN: RC_ProjectSourceVersion=9999.99.99 \ +RUN: OBJROOT="%t/objroot" \ +RUN: DSTROOT="%t/dstroot" \ +RUN: SYMROOT="%t/symroot" \ +RUN: SRCROOT="%src_root" \ +RUN: SDKROOT=$(xcrun --sdk macosx.internal --show-sdk-path) \ +RUN: RC_ARCHS=x86_64 + +# Check that libc++abi-static.a built in the right locations +RUN: stat "%t/dstroot/usr/local/lib/dyld/libc++abi-static.a" +RUN: stat "%t/dstroot/usr/local/lib/loaderd/libc++abi-static.a" +RUN: stat "%t/dstroot/usr/local/lib/system/libc++abi-static.a" + +# Make sure libc++abi-static.a doesn't use static initializers inside its +# dynamic cast implementation. Static initializers are not supported by dyld. +RUN: ! nm -og "%t/dstroot/usr/local/lib/dyld/libc++abi-static.a" | grep -E 'U\s+[_]+cxa_guard_acquire' | grep 'private_typeinfo.cpp' + +# Don't clobber content from libcxx. +RUN: ! stat "%t/dstroot/usr/include" +RUN: ! stat "%t/dstroot/usr/lib" +RUN: ! stat "%t/dstroot/usr/local/OpenSourceLicenses" diff --git a/apple-xbs-support/test/libcxx/install_libcxx_missing_project_version.test b/apple-xbs-support/test/libcxx/install_libcxx_missing_project_version.test new file mode 100644 index 0000000..578c75a --- /dev/null +++ b/apple-xbs-support/test/libcxx/install_libcxx_missing_project_version.test @@ -0,0 +1,25 @@ +# Make sure that if we build libcxx and forget to provide a project version, +# we get a clear error message. +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: mkdir -p %t/symroot +RUN: (! make -C "%src_root" install -j 1 RC_ProjectName=libcxx \ +RUN: OBJROOT="%t/objroot" \ +RUN: DSTROOT="%t/dstroot" \ +RUN: SYMROOT="%t/symroot" \ +RUN: SRCROOT="%src_root" \ +RUN: SDKROOT=$(xcrun --sdk macosx.internal --show-sdk-path) \ +RUN: RC_ARCHS=x86_64 2>&1) | grep "Argument to --version must not be empty" + +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: mkdir -p %t/symroot +RUN: (! make -C "%src_root" libcxx_driverkit -j 1 RC_ProjectName=libcxx_driverkit \ +RUN: OBJROOT="%t/objroot" \ +RUN: DSTROOT="%t/dstroot" \ +RUN: SYMROOT="%t/symroot" \ +RUN: SRCROOT="%src_root" \ +RUN: SDKROOT=$(xcrun --sdk driverkit.macosx.internal --show-sdk-path) \ +RUN: RC_ARCHS=x86_64 2>&1) | grep "Argument to --version must not be empty" diff --git a/apple-xbs-support/test/libcxx/installsrc.test b/apple-xbs-support/test/libcxx/installsrc.test new file mode 100644 index 0000000..a6b87df --- /dev/null +++ b/apple-xbs-support/test/libcxx/installsrc.test @@ -0,0 +1,65 @@ +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: make -C %src_root installsrc "SRCROOT=%t/dest" "RC_ProjectName=libcxx" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/dest/Makefile +RUN: stat %t/dest/apple-xbs-support +RUN: stat %t/dest/llvm +RUN: stat %t/dest/libcxx +RUN: stat %t/dest/libcxxabi +RUN: ! stat %t/dest/clang +RUN: ! stat %t/dest/libunwind + +RUN: mkdir -p %t/Sim +RUN: make -C %src_root installsrc "SRCROOT=%t/Sim" "RC_ProjectName=libcxx_Sim" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/Sim/Makefile +RUN: stat %t/Sim/apple-xbs-support +RUN: stat %t/Sim/llvm +RUN: stat %t/Sim/libcxx +RUN: stat %t/Sim/libcxxabi +RUN: ! stat %t/Sim/clang +RUN: ! stat %t/Sim/libunwind + +RUN: mkdir -p %t/driverkit +RUN: make -C %src_root installsrc "SRCROOT=%t/driverkit" "RC_ProjectName=libcxx_driverkit" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/driverkit/Makefile +RUN: stat %t/driverkit/apple-xbs-support +RUN: stat %t/driverkit/llvm +RUN: stat %t/driverkit/libcxx +RUN: stat %t/driverkit/libcxxabi +RUN: ! stat %t/driverkit/clang +RUN: ! stat %t/driverkit/libunwind + +RUN: mkdir -p %t/dyld +RUN: make -C %src_root installsrc "SRCROOT=%t/dyld" "RC_ProjectName=libcxx_dyld" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/dyld/Makefile +RUN: stat %t/dyld/apple-xbs-support +RUN: stat %t/dyld/llvm +RUN: stat %t/dyld/libcxx +RUN: stat %t/dyld/libcxxabi +RUN: ! stat %t/dyld/clang +RUN: ! stat %t/dyld/libunwind + +RUN: mkdir -p %t/dyldSim +RUN: make -C %src_root installsrc "SRCROOT=%t/dyldSim" "RC_ProjectName=libcxx_dyld_Sim" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/dyldSim/Makefile +RUN: stat %t/dyldSim/apple-xbs-support +RUN: stat %t/dyldSim/llvm +RUN: stat %t/dyldSim/libcxx +RUN: stat %t/dyldSim/libcxxabi +RUN: ! stat %t/dyldSim/clang +RUN: ! stat %t/dyldSim/libunwind diff --git a/apple-xbs-support/test/libcxx/per_tu_guarantee.test b/apple-xbs-support/test/libcxx/per_tu_guarantee.test new file mode 100644 index 0000000..4600f8a --- /dev/null +++ b/apple-xbs-support/test/libcxx/per_tu_guarantee.test @@ -0,0 +1,26 @@ +# Test that the per-TU guarantee is disabled internally, and enabled for the +# public SDK. + +RUN: rm -rf %t +RUN: mkdir -p %t/objroot +RUN: mkdir -p %t/dstroot +RUN: mkdir -p %t/symroot +RUN: make -C "%src_root" installhdrs -j 1 RC_ProjectName=libcxx \ +RUN: RC_ProjectSourceVersion=9999.99.99 \ +RUN: OBJROOT="%t/objroot" \ +RUN: DSTROOT="%t/dstroot" \ +RUN: SYMROOT="%t/symroot" \ +RUN: SRCROOT="%src_root" \ +RUN: SDKROOT=$(xcrun --sdk macosx.internal --show-sdk-path) \ +RUN: RC_ARCHS=x86_64 + +# The per-TU guarantee should be disabled in the internal SDK (i.e. by default) +RUN: echo "#include " \ +RUN: | xcrun clang -nostdinc++ -isystem %t/dstroot/usr/include/c++/v1 -x c++ - -E -dM \ +RUN: | grep '#define _LIBCPP_HIDE_FROM_ABI_PER_TU 0' + +# But it should be enabled in the public SDK (after running clang-sdk-sanitizer) +RUN: xcrun clang-sdk-sanitizer -i "%t/dstroot/usr/include/c++/v1/__config" +RUN: echo "#include " \ +RUN: | xcrun clang -nostdinc++ -isystem %t/dstroot/usr/include/c++/v1 -x c++ - -E -dM \ +RUN: | grep '#define _LIBCPP_HIDE_FROM_ABI_PER_TU 1' diff --git a/apple-xbs-support/test/libunwind/install.test b/apple-xbs-support/test/libunwind/install.test new file mode 100644 index 0000000..526939f --- /dev/null +++ b/apple-xbs-support/test/libunwind/install.test @@ -0,0 +1,40 @@ +# Check plain libunwind has no --sim. +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -v -e '--sim' + +# Check Sim libunwind has --sim. +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind_Sim" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -e '--sim' +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind_dyld_Sim" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -e '--sim' + +# Check that --dyld is correct. +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -v -e '--dyld' +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind_Sim" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -v -e '--dyld' +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind_dyld" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -e '--dyld' +RUN: env APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT=1 \ +RUN: make -C %src_root install "SRCROOT=%src_root" \ +RUN: "RC_ProjectName=libunwind_dyld_Sim" \ +RUN: | grep 'apple-install-libunwind.sh' \ +RUN: | grep -e '--dyld' diff --git a/apple-xbs-support/test/libunwind/installsrc.test b/apple-xbs-support/test/libunwind/installsrc.test new file mode 100644 index 0000000..18100f8 --- /dev/null +++ b/apple-xbs-support/test/libunwind/installsrc.test @@ -0,0 +1,26 @@ +RUN: rm -rf %t +RUN: mkdir -p %t/dest +RUN: make -C %src_root installsrc "SRCROOT=%t/dest" "RC_ProjectName=libunwind" 2>&1 \ +RUN: | grep 'libunwind => apple-xbs-support/libunwind.mk' + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/dest/Makefile +RUN: stat %t/dest/apple-xbs-support +RUN: stat %t/dest/libunwind +RUN: ! stat %t/dest/llvm +RUN: ! stat %t/dest/clang +RUN: ! stat %t/dest/libcxx + + +RUN: mkdir -p %t/Sim +RUN: make -C %src_root installsrc "SRCROOT=%t/Sim" "RC_ProjectName=libunwind_Sim" + +# Verify that we got all the subdirs we wanted, but not others. + +RUN: stat %t/Sim/Makefile +RUN: stat %t/Sim/apple-xbs-support +RUN: stat %t/Sim/libunwind +RUN: ! stat %t/Sim/llvm +RUN: ! stat %t/Sim/clang +RUN: ! stat %t/Sim/libcxx diff --git a/apple-xbs-support/test/libunwind/installsrc_variant.test b/apple-xbs-support/test/libunwind/installsrc_variant.test new file mode 100644 index 0000000..a4be975 --- /dev/null +++ b/apple-xbs-support/test/libunwind/installsrc_variant.test @@ -0,0 +1,25 @@ +# Test variant trains. +RUN: rm -rf %t +RUN: mkdir -p %t/variant/dest %t/variant/Sim +RUN: make -C %src_root installsrc "SRCROOT=%t/variant/dest" "RC_ProjectName=Variant_libunwind" 2>&1 \ +RUN: | grep 'Variant_libunwind => apple-xbs-support/libunwind.mk' +RUN: stat %t/variant/dest/Makefile +RUN: stat %t/variant/dest/apple-xbs-support +RUN: stat %t/variant/dest/libunwind +RUN: ! stat %t/variant/dest/llvm +RUN: ! stat %t/variant/dest/clang +RUN: ! stat %t/variant/dest/libcxx +RUN: make -C %src_root installsrc "SRCROOT=%t/variant/Sim" "RC_ProjectName=Variant_libunwind_Sim" 2>&1 \ +RUN: | grep 'Variant_libunwind_Sim => apple-xbs-support/libunwind_Sim.mk' +RUN: stat %t/variant/Sim/Makefile +RUN: stat %t/variant/Sim/apple-xbs-support +RUN: stat %t/variant/Sim/libunwind +RUN: ! stat %t/variant/Sim/llvm +RUN: ! stat %t/variant/Sim/clang +RUN: ! stat %t/variant/Sim/libcxx + +# Suffix is not a variant. Make sure we get a reasonable error message if the +# file is missing. +RUN: mkdir -p %t/suffix/dest %t/suffix/Sim +RUN: ! make -C %src_root installsrc "SRCROOT=%t/suffix/dest" "RC_ProjectName=libunwind_Suffix" 2>&1 \ +RUN: | grep 'libunwind_Suffix => apple-xbs-support/libunwind_Suffix.mk' diff --git a/apple-xbs-support/test/lit.cfg b/apple-xbs-support/test/lit.cfg new file mode 100644 index 0000000..abd4188 --- /dev/null +++ b/apple-xbs-support/test/lit.cfg @@ -0,0 +1,43 @@ +# -*- Python -*- + +import os +import lit + +# Configuration file for the 'lit' test runner. + +# name: The name of this test suite. +config.name = 'llvm-project:apple-xbs-support' + +# testFormat: The test format to use to interpret tests. +config.test_format = lit.formats.ShTest(True) + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = ['.test'] + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.dirname(os.path.join(__file__)) + +# test_exec_root: The root path where tests should be run. +config.test_exec_root = os.path.join(config.test_source_root, '.python_env') + +src_root = os.path.join(os.path.join(config.test_source_root, '..'), '..') +config.substitutions.append(('%src_root', src_root)) + +import subprocess +developer_dir = subprocess.check_output(["xcode-select", "-p"]) +config.substitutions.append(('%DEVELOPER_DIR', developer_dir.decode("utf-8").strip())) + +def check_cmd(cmd): + with open(os.devnull, 'w') as devnull: + if 0 == subprocess.call(cmd, stderr=devnull, stdout=devnull): + return True + return False + +# Check for -iworkdir=os. +if check_cmd(['xcrun', 'clang', '-iworkdir=os', '-fsyntax-only', '-x', 'c', + '/dev/null']): + config.available_features.add('iworkdir=os') + +helpers_dir = os.path.join(config.test_source_root, '..', 'helpers') +assert os.path.exists(helpers_dir) +config.substitutions.append(('%make_with_helpers', 'make -I {}'.format(helpers_dir))) diff --git a/apple-xbs-support/test/utils/find-clang-asan-version.test b/apple-xbs-support/test/utils/find-clang-asan-version.test new file mode 100644 index 0000000..7b0bd84 --- /dev/null +++ b/apple-xbs-support/test/utils/find-clang-asan-version.test @@ -0,0 +1 @@ +RUN: %src_root/apple-xbs-support/utils/find-clang-asan-version | grep "\d\d\d\d" diff --git a/apple-xbs-support/utils/find-clang-asan-version b/apple-xbs-support/utils/find-clang-asan-version new file mode 100755 index 0000000..a62379c --- /dev/null +++ b/apple-xbs-support/utils/find-clang-asan-version @@ -0,0 +1,3 @@ +#!/bin/sh +# Returns the ASAN version for the current clang. +echo "void foo(){}" | xcrun clang -x c -c -target x86_64-apple-macos10.15 - -S -Xclang -emit-llvm -fsanitize=address -o - | grep asan_version_mismatch | grep declare | cut -d ' ' -f 3 | cut -d '_' -f 9 | cut -d '(' -f 1 diff --git a/libunwind/.clang-format b/libunwind/.clang-format new file mode 100644 index 0000000..5bead5f --- /dev/null +++ b/libunwind/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM + diff --git a/libunwind/CMakeLists.txt.apple b/libunwind/CMakeLists.txt.apple new file mode 100644 index 0000000..6390b46 --- /dev/null +++ b/libunwind/CMakeLists.txt.apple @@ -0,0 +1,409 @@ +#=============================================================================== +# Setup Project +#=============================================================================== + +cmake_minimum_required(VERSION 3.13.4) + +if (POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default +endif() + +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" + ${CMAKE_MODULE_PATH} + ) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_BUILD) + project(libunwind LANGUAGES C CXX ASM) + + # Rely on llvm-config. + set(CONFIG_OUTPUT) + if(NOT LLVM_CONFIG_PATH) + find_program(LLVM_CONFIG_PATH "llvm-config") + endif() + if (DEFINED LLVM_PATH) + set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") + set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) + set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") + elseif(LLVM_CONFIG_PATH) + message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") + set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} "--includedir" "--prefix" "--src-root") + execute_process(COMMAND ${CONFIG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT) + if (NOT HAD_ERROR) + string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" + CONFIG_OUTPUT ${CONFIG_OUTPUT}) + else() + string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") + message(STATUS "${CONFIG_COMMAND_STR}") + message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") + endif() + + list(GET CONFIG_OUTPUT 0 INCLUDE_DIR) + list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT) + list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR) + + set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") + set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") + set(LLVM_LIT_PATH "${LLVM_PATH}/utils/lit/lit.py") + + # --cmakedir is supported since llvm r291218 (4.0 release) + execute_process( + COMMAND ${LLVM_CONFIG_PATH} --cmakedir + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ERROR_QUIET) + if(NOT HAD_ERROR) + string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG) + file(TO_CMAKE_PATH "${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG}" LLVM_CMAKE_PATH) + else() + file(TO_CMAKE_PATH "${LLVM_BINARY_DIR}" LLVM_BINARY_DIR_CMAKE_STYLE) + set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") + endif() + else() + message(WARNING "UNSUPPORTED LIBUNWIND CONFIGURATION DETECTED: " + "llvm-config not found and LLVM_MAIN_SRC_DIR not defined. " + "Reconfigure with -DLLVM_CONFIG=path/to/llvm-config " + "or -DLLVM_PATH=path/to/llvm-source-root.") + endif() + + if (EXISTS ${LLVM_CMAKE_PATH}) + # Enable warnings, otherwise -w gets added to the cflags by HandleLLVMOptions. + set(LLVM_ENABLE_WARNINGS ON) + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") + include("${LLVM_CMAKE_PATH}/AddLLVM.cmake") + include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake") + else() + message(WARNING "Not found: ${LLVM_CMAKE_PATH}") + endif() + + set(PACKAGE_NAME libunwind) + set(PACKAGE_VERSION 12.0.0git) + set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") + set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") + + if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) + set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) + else() + # Seek installed Lit. + find_program(LLVM_LIT "lit.py" ${LLVM_MAIN_SRC_DIR}/utils/lit + DOC "Path to lit.py") + endif() + + if (LLVM_LIT) + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LIT_ARGS_DEFAULT "-sv") + if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") + endif() + set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + + # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. + if (WIN32 AND NOT CYGWIN) + set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") + endif() + else() + set(LLVM_INCLUDE_TESTS OFF) + endif() + + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) +else() + set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py") +endif() + +#=============================================================================== +# Setup CMake Options +#=============================================================================== +include(CMakeDependentOption) +include(HandleCompilerRT) + +# Define options. +option(LIBUNWIND_BUILD_32_BITS "Build 32 bit libunwind" ${LLVM_BUILD_32_BITS}) +option(LIBUNWIND_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) +option(LIBUNWIND_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) +option(LIBUNWIND_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) +option(LIBUNWIND_ENABLE_SHARED "Build libunwind as a shared library." ON) +option(LIBUNWIND_ENABLE_STATIC "Build libunwind as a static library." ON) +option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." OFF) +option(LIBUNWIND_ENABLE_ARM_WMMX "Enable unwinding support for ARM WMMX registers." OFF) +option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON) +option(LIBUNWIND_WEAK_PTHREAD_LIB "Use weak references to refer to pthread functions." OFF) +option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF) +option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS}) +option(LIBUNWIND_IS_BAREMETAL "Build libunwind for baremetal targets." OFF) +option(LIBUNWIND_USE_FRAME_HEADER_CACHE "Cache frame headers for unwinding. Requires locking dl_iterate_phdr." OFF) + +set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") +option(LIBUNWIND_INSTALL_LIBRARY "Install the libunwind library." ON) +cmake_dependent_option(LIBUNWIND_INSTALL_STATIC_LIBRARY + "Install the static libunwind library." ON + "LIBUNWIND_ENABLE_STATIC;LIBUNWIND_INSTALL_LIBRARY" OFF) +cmake_dependent_option(LIBUNWIND_INSTALL_SHARED_LIBRARY + "Install the shared libunwind library." ON + "LIBUNWIND_ENABLE_SHARED;LIBUNWIND_INSTALL_LIBRARY" OFF) +set(LIBUNWIND_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.") +set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") +set(LIBUNWIND_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") +set(LIBUNWIND_TEST_LINKER_FLAGS "" CACHE STRING + "Additional linker flags for test programs.") +set(LIBUNWIND_TEST_COMPILER_FLAGS "" CACHE STRING + "Additional compiler flags for test programs.") +set(LIBUNWIND_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/lit.site.cfg.in" CACHE STRING + "The Lit testing configuration to use when running the tests.") + +if (NOT LIBUNWIND_ENABLE_SHARED AND NOT LIBUNWIND_ENABLE_STATIC) + message(FATAL_ERROR "libunwind must be built as either a shared or static library.") +endif() + +# Check that we can build with 32 bits if requested. +if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32) + if (LIBUNWIND_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM + message(STATUS "Building 32 bits executables and libraries.") + endif() +elseif(LIBUNWIND_BUILD_32_BITS) + message(FATAL_ERROR "LIBUNWIND_BUILD_32_BITS=ON is not supported on this platform.") +endif() + +option(LIBUNWIND_HERMETIC_STATIC_LIBRARY + "Do not export any symbols from the static library." OFF) + +#=============================================================================== +# Configure System +#=============================================================================== + +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + ${CMAKE_MODULE_PATH}) + +set(LIBUNWIND_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LIBUNWIND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) + set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++) + set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++) + if(LIBCXX_LIBDIR_SUBDIR) + string(APPEND LIBUNWIND_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR}) + string(APPEND LIBUNWIND_INSTALL_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR}) + endif() +elseif(LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) + set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX}) +else() + set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBUNWIND_LIBDIR_SUFFIX}) + set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX}) +endif() + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) + +set(LIBUNWIND_INSTALL_PREFIX "" CACHE STRING "Define libunwind destination prefix.") + +set(LIBUNWIND_C_FLAGS "") +set(LIBUNWIND_CXX_FLAGS "") +set(LIBUNWIND_COMPILE_FLAGS CACHE STRING "") +set(LIBUNWIND_LINK_FLAGS "") + +# Include macros for adding and removing libunwind flags. +include(HandleLibunwindFlags) + +#=============================================================================== +# Setup Compiler Flags +#=============================================================================== + +# Get required flags. +add_target_flags_if(LIBUNWIND_BUILD_32_BITS "-m32") + +if(LIBUNWIND_TARGET_TRIPLE) + add_target_flags("--target=${LIBUNWIND_TARGET_TRIPLE}") +elseif(CMAKE_CXX_COMPILER_TARGET) + set(LIBUNWIND_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}") +endif() +if(LIBUNWIND_GCC_TOOLCHAIN) + add_target_flags("--gcc-toolchain=${LIBUNWIND_GCC_TOOLCHAIN}") +elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN) + set(LIBUNWIND_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}") +endif() +if(LIBUNWIND_SYSROOT) + add_target_flags("--sysroot=${LIBUNWIND_SYSROOT}") +elseif(CMAKE_SYSROOT) + set(LIBUNWIND_SYSROOT "${CMAKE_SYSROOT}") +endif() + +if (LIBUNWIND_TARGET_TRIPLE) + set(TARGET_TRIPLE "${LIBUNWIND_TARGET_TRIPLE}") +endif() + +# Configure compiler. +include(config-ix) + +if (LIBUNWIND_USE_COMPILER_RT AND NOT LIBUNWIND_HAS_NODEFAULTLIBS_FLAG) + list(APPEND LIBUNWIND_LINK_FLAGS "-rtlib=compiler-rt") +endif() + +add_compile_flags_if_supported(-Werror=return-type) + +# Get warning flags +add_compile_flags_if_supported(-W) +add_compile_flags_if_supported(-Wall) +add_compile_flags_if_supported(-Wchar-subscripts) +add_compile_flags_if_supported(-Wconversion) +add_compile_flags_if_supported(-Wmismatched-tags) +add_compile_flags_if_supported(-Wmissing-braces) +add_compile_flags_if_supported(-Wnewline-eof) +add_compile_flags_if_supported(-Wno-unused-function) +add_compile_flags_if_supported(-Wshadow) +add_compile_flags_if_supported(-Wshorten-64-to-32) +add_compile_flags_if_supported(-Wsign-compare) +add_compile_flags_if_supported(-Wsign-conversion) +add_compile_flags_if_supported(-Wstrict-aliasing=2) +add_compile_flags_if_supported(-Wstrict-overflow=4) +add_compile_flags_if_supported(-Wunused-parameter) +add_compile_flags_if_supported(-Wunused-variable) +add_compile_flags_if_supported(-Wwrite-strings) +add_compile_flags_if_supported(-Wundef) + +add_compile_flags_if_supported(-Wno-suggest-override) + +if (LIBUNWIND_ENABLE_WERROR) + add_compile_flags_if_supported(-Werror) + add_compile_flags_if_supported(-WX) +else() + add_compile_flags_if_supported(-Wno-error) + add_compile_flags_if_supported(-WX-) +endif() + +if (LIBUNWIND_ENABLE_PEDANTIC) + add_compile_flags_if_supported(-pedantic) +endif() + +# Get feature flags. +# Exceptions +# Catches C++ exceptions only and tells the compiler to assume that extern C +# functions never throw a C++ exception. +add_cxx_compile_flags_if_supported(-fstrict-aliasing) +add_cxx_compile_flags_if_supported(-EHsc) + +# Don't run the linker in this CMake check. +# +# The reason why this was added is that when building libunwind for +# ARM Linux, we need to pass the -funwind-tables flag in order for it to +# work properly with ARM EHABI. +# +# However, when performing CMake checks, adding this flag causes the check +# to produce a false negative, because the compiler generates calls +# to __aeabi_unwind_cpp_pr0, which is defined in libunwind itself, +# which isn't built yet, so the linker complains about undefined symbols. +# +# This leads to libunwind not being built with this flag, which makes +# libunwind quite useless in this setup. +set(_previous_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +add_compile_flags_if_supported(-funwind-tables) +set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_previous_CMAKE_TRY_COMPILE_TARGET_TYPE}) + +if (LIBUNWIND_USES_ARM_EHABI AND NOT LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG) + message(SEND_ERROR "The -funwind-tables flag must be supported " + "because this target uses ARM Exception Handling ABI") +endif() + +add_cxx_compile_flags_if_supported(-fno-exceptions) +add_cxx_compile_flags_if_supported(-fno-rtti) + +# Ensure that we don't depend on C++ standard library. +if (LIBUNWIND_HAS_NOSTDINCXX_FLAG) + list(APPEND LIBUNWIND_COMPILE_FLAGS -nostdinc++) + # Remove -stdlib flags to prevent them from causing an unused flag warning. + string(REPLACE "-stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "-stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +# Assert +string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) +if (LIBUNWIND_ENABLE_ASSERTIONS) + # MSVC doesn't like _DEBUG on release builds. See PR 4379. + if (NOT MSVC) + add_compile_flags(-D_DEBUG) + endif() + + # On Release builds cmake automatically defines NDEBUG, so we + # explicitly undefine it: + if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + add_compile_flags(-UNDEBUG) + endif() +else() + if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + add_compile_flags(-DNDEBUG) + endif() +endif() + +# Cross-unwinding +if (NOT LIBUNWIND_ENABLE_CROSS_UNWINDING) + add_compile_flags(-D_LIBUNWIND_IS_NATIVE_ONLY) +endif() + +# Threading-support +if (NOT LIBUNWIND_ENABLE_THREADS) + add_compile_flags(-D_LIBUNWIND_HAS_NO_THREADS) +endif() + +# ARM WMMX register support +if (LIBUNWIND_ENABLE_ARM_WMMX) + # __ARM_WMMX is a compiler pre-define (as per the ACLE 2.0). Clang does not + # define this macro for any supported target at present. Therefore, here we + # provide the option to explicitly enable support for WMMX registers in the + # unwinder. + add_compile_flags(-D__ARM_WMMX) +endif() + +if(LIBUNWIND_IS_BAREMETAL) + add_compile_definitions(_LIBUNWIND_IS_BAREMETAL) +endif() + +if(LIBUNWIND_USE_FRAME_HEADER_CACHE) + add_compile_definitions(_LIBUNWIND_USE_FRAME_HEADER_CACHE) +endif() + +# This is the _ONLY_ place where add_definitions is called. +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +# Disable DLL annotations on Windows for static builds. +if (WIN32 AND LIBUNWIND_ENABLE_STATIC AND NOT LIBUNWIND_ENABLE_SHARED) + add_definitions(-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) +endif() + +if (LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) + if (LIBUNWIND_HAS_DL_LIB) + add_definitions(-D_LIBUNWIND_LINK_DL_LIB) + endif() + if (LIBUNWIND_HAS_PTHREAD_LIB) + add_definitions(-D_LIBUNWIND_LINK_PTHREAD_LIB) + endif() +endif() + +#=============================================================================== +# Setup Source Code +#=============================================================================== + +include_directories(include) + +add_subdirectory(src) + +if (LIBUNWIND_INCLUDE_DOCS) + add_subdirectory(docs) +endif() + +if (EXISTS ${LLVM_CMAKE_PATH}) + add_subdirectory(test) +endif() diff --git a/libunwind/LICENSE.TXT b/libunwind/LICENSE.TXT new file mode 100644 index 0000000..1e31206 --- /dev/null +++ b/libunwind/LICENSE.TXT @@ -0,0 +1,311 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== + +The libunwind library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +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 +CONTRIBUTORS 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 WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +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. diff --git a/libunwind/apple-install-libunwind.sh b/libunwind/apple-install-libunwind.sh new file mode 100755 index 0000000..129ca60 --- /dev/null +++ b/libunwind/apple-install-libunwind.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env bash + +set -e + +if [ ! "${APPLE_XBS_SUPPORT_PRINT_ARGS_AND_EXIT:-0}" = 0 ]; then + printf "%q" "$0" + while [ $# -gt 0 ]; do + printf " %q" "$1" + shift + done + printf "\n" + exit 0 +fi + +error() { + print "error: %s\n" "$*" >&2 + exit 1 +} + +# Default values. +IS_SIM_BUILD=false +DYLD=false + +# Parse command-line. +while [ $# -gt 0 ]; do + case "$1" in + --sim) IS_SIM_BUILD=true; shift;; + --dyld) DYLD=true; shift;; + -*) error "unrecognized flag '$1'";; + *) error "unexpected positional argument '$1'";; + esac +done + +run() { + local arg + { + printf "#" + for arg in "$@"; do + printf " %q" "$arg" + done + printf "\n" + } >&2 + + "$@" +} + +function step() { + separator="$(printf "%0.s-" $(seq 1 ${#1}))" + echo + echo "${separator}" + echo "${1}" + echo "${separator}" +} + +function build() { + sysroot="${1}" + arch="${2}" + config="${3}" + current_version="${4}" + build_platform="${5}" + + # Compute additional #defines based on the environment variables set by XBS. + defines="" + for var in $(env); do + if [[ "${var}" =~ RC_(SHOW|HIDE)_.+ ]]; then + defines+="-D${var};" + fi + done + if [ "${config}" = "static" ]; then + defines+="-DFOR_DYLD=1;-fno-stack-check" + else + defines+="-flto;" # Use LTO for shared library + fi + + NINJA=`xcrun -f ninja` + CLANG=`xcrun -sdk ${sysroot} -f clang` + CLANGXX=`xcrun -sdk ${sysroot} -f clang++` + GENERATOR=Ninja + VERBOSE="-v" + + # Configure libunwind. + # We hijack LD_TRACE_FILE here to avoid writing non-dependences into + # LD_TRACE_FILE, otherwise there will be lots of false dependency cycles. + run mkdir -p "${OBJROOT}/${arch}-${config}" + run pushd "${OBJROOT}/${arch}-${config}" + run env LD_TRACE_FILE="${OBJROOT}/${arch}-${config}/LD_TRACE" \ + xcrun cmake "${SRCROOT}"/libunwind \ + -G"${GENERATOR}" \ + -C "${SRCROOT}/libunwind/cmake/caches/Apple-${config}.cmake" \ + -DCMAKE_MAKE_PROGRAM=${NINJA} \ + -DCMAKE_C_COMPILER=${CLANG} \ + -DCMAKE_CXX_COMPILER=${CLANGXX} \ + -DCMAKE_INSTALL_PREFIX="${OBJROOT}/${arch}-${config}-install" \ + -DCMAKE_OSX_SYSROOT="${sysroot}" \ + -DCMAKE_OSX_ARCHITECTURES="${arch}" \ + -DLIBUNWIND_COMPILE_FLAGS="${defines}" \ + -DLIBUNWIND_APPLE_PLATFORM="${build_platform}" \ + -DLIBUNWIND_VERSION=${current_version} + run popd + + run xcrun cmake --build "${OBJROOT}/${arch}-${config}" \ + --target install-unwind -- ${VERBOSE} +} + +SYSROOT="${SDKROOT}" +FINAL_DSTROOT="${DSTROOT}" +FINAL_SYMROOT="${SYMROOT}" +CURRENT_VERSION=${RC_ProjectSourceVersion} +BUILD_PLATFORM=${RC_PROJECT_COMPILATION_PLATFORM} + +# +# Build the dylib for each architecture and create a universal dylib +# +for arch in ${RC_ARCHS}; do + if $DYLD; then + step "Building libunwind.a for architecture ${arch}" + build "${SYSROOT}" "${arch}" "static" "${CURRENT_VERSION}" "${BUILD_PLATFORM}" + else + step "Building libunwind.dylib for architecture ${arch}" + build "${SYSROOT}" "${arch}" "shared" "${CURRENT_VERSION}" "${BUILD_PLATFORM}" + fi +done + +if ! $DYLD; then + step "Creating a universal dylib from the dylibs for all architectures" + input_dylibs=$(for arch in ${RC_ARCHS}; do + echo "${OBJROOT}/${arch}-shared-install/lib/libunwind.dylib" + done) + run xcrun lipo -create ${input_dylibs} -output "${OBJROOT}/libunwind.dylib" + + step "Installing the universal dylib to ${FINAL_DSTROOT}/usr/lib/system" + run mkdir -p "${FINAL_DSTROOT}/usr/lib/system" + run cp "${OBJROOT}/libunwind.dylib" "${FINAL_DSTROOT}/usr/lib/system/libunwind.dylib" + + step "Producing dSYM bundle for the universal dylib" + run xcrun dsymutil "${FINAL_DSTROOT}/usr/lib/system/libunwind.dylib" \ + -o "${FINAL_SYMROOT}/libunwind.dSYM" + + step "Stripping the universal dylib from all debug symbols" + run xcrun strip -S "${FINAL_DSTROOT}/usr/lib/system/libunwind.dylib" + + # Install headers. + # + step "Copy headers" + run mkdir -p "${FINAL_DSTROOT}/usr/include" + run cp -r "${SRCROOT}/libunwind/include" "${FINAL_DSTROOT}/usr" +else + step "Creating universal static library" + input_static_libs=$(for arch in ${RC_ARCHS}; do + echo "${OBJROOT}/${arch}-static-install/lib/libunwind.a" + done) + run xcrun lipo -create ${input_static_libs} -output "${OBJROOT}/libunwind.a" + + run mkdir -p "${FINAL_DSTROOT}/usr/local/lib/dyld" + run cp "${OBJROOT}/libunwind.a" "${FINAL_DSTROOT}/usr/local/lib/dyld/libunwind.a" +fi diff --git a/libunwind/cmake/Modules/HandleCompilerRT.cmake b/libunwind/cmake/Modules/HandleCompilerRT.cmake new file mode 100644 index 0000000..77168e5 --- /dev/null +++ b/libunwind/cmake/Modules/HandleCompilerRT.cmake @@ -0,0 +1,64 @@ +function(find_compiler_rt_library name dest) + if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS) + message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function") + endif() + set(dest "" PARENT_SCOPE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) + list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") + endif() + get_property(LIBUNWIND_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE) + string(REPLACE " " ";" LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}") + list(APPEND CLANG_COMMAND ${LIBUNWIND_CXX_FLAGS}) + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) + string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") + message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}") + set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt library") + endif() +endfunction() + +function(find_compiler_rt_dir dest) + if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS) + message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function") + endif() + set(dest "" PARENT_SCOPE) + if (APPLE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS} + "-print-file-name=lib") + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_DIR + ) + string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR) + file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR) + set(LIBRARY_DIR "${LIBRARY_DIR}/darwin") + else() + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) + get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY) + endif() + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}") + message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}") + set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt directory") + endif() +endfunction() diff --git a/libunwind/cmake/Modules/HandleLibunwindFlags.cmake b/libunwind/cmake/Modules/HandleLibunwindFlags.cmake new file mode 100644 index 0000000..57ba0b8 --- /dev/null +++ b/libunwind/cmake/Modules/HandleLibunwindFlags.cmake @@ -0,0 +1,272 @@ +# HandleLibcxxFlags - A set of macros used to setup the flags used to compile +# and link libc++abi. These macros add flags to the following CMake variables. +# - LIBUNWIND_COMPILE_FLAGS: flags used to compile libunwind +# - LIBUNWIND_LINK_FLAGS: flags used to link libunwind +# - LIBUNWIND_LIBRARIES: libraries to link libunwind to. + +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + +unset(add_flag_if_supported) + +# Mangle the name of a compiler flag into a valid CMake identifier. +# Ex: --std=c++11 -> STD_EQ_CXX11 +macro(mangle_name str output) + string(STRIP "${str}" strippedStr) + string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}") + string(REPLACE "-" "_" strippedStr "${strippedStr}") + string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}") + string(REPLACE "+" "X" strippedStr "${strippedStr}") + string(TOUPPER "${strippedStr}" ${output}) +endmacro() + +# Remove a list of flags from all CMake variables that affect compile flags. +# This can be used to remove unwanted flags specified on the command line +# or added in other parts of LLVM's cmake configuration. +macro(remove_flags) + foreach(var ${ARGN}) + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}") + remove_definitions(${var}) + endforeach() +endmacro(remove_flags) + +macro(check_flag_supported flag) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") +endmacro() + +macro(append_flags DEST) + foreach(value ${ARGN}) + list(APPEND ${DEST} ${value}) + list(APPEND ${DEST} ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then append the specified list of flags to DEST +macro(append_flags_if condition DEST) + if (${condition}) + list(APPEND ${DEST} ${ARGN}) + endif() +endmacro() + +# Add each flag in the list specified by DEST if that flag is supported by the current compiler. +macro(append_flags_if_supported DEST) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + append_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${DEST} ${flag}) + endforeach() +endmacro() + +# Add a macro definition if condition is true. +macro(define_if condition def) + if (${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition if condition is not true. +macro(define_if_not condition def) + if (NOT ${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition to the __config_site file if the specified condition +# is 'true'. Note that '-D${def}' is not added. Instead it is expected that +# the build include the '__config_site' header. +macro(config_define_if condition def) + if (${condition}) + set(${def} ON) + set(LIBUNWIND_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define_if_not condition def) + if (NOT ${condition}) + set(${def} ON) + set(LIBUNWIND_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define value def) + set(${def} ${value}) + set(LIBUNWIND_NEEDS_SITE_CONFIG ON) +endmacro() + +# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', +# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'. +macro(add_target_flags) + foreach(value ${ARGN}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}") + list(APPEND LIBUNWIND_COMPILE_FLAGS ${value}) + list(APPEND LIBUNWIND_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to +# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBUNWIND_COMPILE_FLAGS' +# and 'LIBUNWIND_LINK_FLAGS'. +macro(add_target_flags_if condition) + if (${condition}) + add_target_flags(${ARGN}) + endif() +endmacro() + +# Add a specified list of flags to both 'LIBUNWIND_COMPILE_FLAGS' and +# 'LIBUNWIND_LINK_FLAGS'. +macro(add_flags) + foreach(value ${ARGN}) + list(APPEND LIBUNWIND_COMPILE_FLAGS ${value}) + list(APPEND LIBUNWIND_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to both +# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'. +macro(add_flags_if condition) + if (${condition}) + add_flags(${ARGN}) + endif() +endmacro() + +# Add each flag in the list to LIBUNWIND_COMPILE_FLAGS and LIBUNWIND_LINK_FLAGS +# if that flag is supported by the current compiler. +macro(add_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_COMPILE_FLAGS'. +macro(add_compile_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_COMPILE_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_COMPILE_FLAGS' +macro(add_compile_flags_if condition) + if (${condition}) + add_compile_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_COMPILE_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_C_FLAGS'. +macro(add_c_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_C_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_C_FLAGS' +macro(add_c_flags_if condition) + if (${condition}) + add_c_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_C_FLAGS' if the +# flag is supported by the C compiler. +macro(add_c_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_c_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_c_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_CXX_FLAGS'. +macro(add_cxx_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_CXX_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_CXX_FLAGS' +macro(add_cxx_flags_if condition) + if (${condition}) + add_cxx_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_CXX_FLAGS' if the +# flag is supported by the C compiler. +macro(add_cxx_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_cxx_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_LINK_FLAGS'. +macro(add_link_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_LINK_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_LINK_FLAGS' +macro(add_link_flags_if condition) + if (${condition}) + add_link_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_LINK_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_link_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_link_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of libraries or link flags to 'LIBUNWIND_LIBRARIES'. +macro(add_library_flags) + foreach(lib ${ARGN}) + list(APPEND LIBUNWIND_LIBRARIES ${lib}) + endforeach() +endmacro() + +# if 'condition' is true then add the specified list of libraries and flags +# to 'LIBUNWIND_LIBRARIES'. +macro(add_library_flags_if condition) + if(${condition}) + add_library_flags(${ARGN}) + endif() +endmacro() + +# Turn a comma separated CMake list into a space separated string. +macro(split_list listname) + string(REPLACE ";" " " ${listname} "${${listname}}") +endmacro() diff --git a/libunwind/cmake/caches/Apple-shared.cmake b/libunwind/cmake/caches/Apple-shared.cmake new file mode 100644 index 0000000..cc4063b --- /dev/null +++ b/libunwind/cmake/caches/Apple-shared.cmake @@ -0,0 +1,6 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Apple.cmake) + +set(CMAKE_INSTALL_NAME_DIR "/usr/lib/system" CACHE STRING "") +set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON CACHE BOOL "") +set(LIBUNWIND_ENABLE_STATIC OFF CACHE BOOL "") +set(LIBUNWIND_ENABLE_SHARED ON CACHE BOOL "") diff --git a/libunwind/cmake/caches/Apple-static.cmake b/libunwind/cmake/caches/Apple-static.cmake new file mode 100644 index 0000000..970d4b0 --- /dev/null +++ b/libunwind/cmake/caches/Apple-static.cmake @@ -0,0 +1,5 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Apple.cmake) + +set(CMAKE_INSTALL_NAME_DIR "/usr/local/lib/dyld" CACHE STRING "") +set(LIBUNWIND_ENABLE_STATIC ON CACHE BOOL "") +set(LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "") diff --git a/libunwind/cmake/caches/Apple.cmake b/libunwind/cmake/caches/Apple.cmake new file mode 100644 index 0000000..13357f3 --- /dev/null +++ b/libunwind/cmake/caches/Apple.cmake @@ -0,0 +1,11 @@ +set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "") + +set(LIBUNWIND_STANDALONE_BUILD ON CACHE BOOL "") +set(LIBUNWIND_APPLE_SYSTEM_BUILD ON CACHE BOOL "") +set(LIBUNWIND_APPLE_PLATFORM "osx" CACHE STRING "") + +set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -g" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Os -g" CACHE STRING "") +set(LIBUNWIND_ENABLE_ASSERTIONS OFF CACHE BOOL "") +set(LIBUNWIND_ENABLE_CROSS_UNWINDING ON CACHE BOOL "") +set(LIBUNWIND_VERSION "1.0" CACHE STRING "") diff --git a/libunwind/cmake/config-ix.cmake b/libunwind/cmake/config-ix.cmake new file mode 100644 index 0000000..3e42818 --- /dev/null +++ b/libunwind/cmake/config-ix.cmake @@ -0,0 +1,95 @@ +include(CMakePushCheckState) +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +include(CheckLibraryExists) +include(CheckSymbolExists) +include(CheckCSourceCompiles) + +check_library_exists(c fopen "" LIBUNWIND_HAS_C_LIB) + +if (NOT LIBUNWIND_USE_COMPILER_RT) + if (ANDROID) + check_library_exists(gcc __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_LIB) + else () + check_library_exists(gcc_s __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_S_LIB) + check_library_exists(gcc __absvdi2 "" LIBUNWIND_HAS_GCC_LIB) + endif () +endif() + +# libunwind is built with -nodefaultlibs, so we want all our checks to also +# use this option, otherwise we may end up with an inconsistency between +# the flags we think we require during configuration (if the checks are +# performed without -nodefaultlibs) and the flags that are actually +# required during compilation (which has the -nodefaultlibs). libc is +# required for the link to go through. We remove sanitizers from the +# configuration checks to avoid spurious link errors. +check_c_compiler_flag(-nodefaultlibs LIBUNWIND_HAS_NODEFAULTLIBS_FLAG) +if (LIBUNWIND_HAS_NODEFAULTLIBS_FLAG) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + if (LIBUNWIND_HAS_C_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES c) + endif () + if (LIBUNWIND_USE_COMPILER_RT) + find_compiler_rt_library(builtins LIBUNWIND_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBUNWIND_BUILTINS_LIBRARY}") + else () + if (LIBUNWIND_HAS_GCC_S_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + endif () + if (LIBUNWIND_HAS_GCC_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc) + endif () + endif () + if (MINGW) + # Mingw64 requires quite a few "C" runtime libraries in order for basic + # programs to link successfully with -nodefaultlibs. + if (LIBUNWIND_USE_COMPILER_RT) + set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY}) + else () + set(MINGW_RUNTIME gcc_s gcc) + endif() + set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} + moldname mingwex msvcrt) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) + endif() + if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") + endif () + if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") + endif () +endif () + +# Check compiler pragmas +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=unknown-pragmas") + check_c_source_compiles(" +#pragma comment(lib, \"c\") +int main() { return 0; } +" LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) + cmake_pop_check_state() +endif() + +# Check compiler flags +check_cxx_compiler_flag(-nostdinc++ LIBUNWIND_HAS_NOSTDINCXX_FLAG) + +# Check symbols +check_symbol_exists(__arm__ "" LIBUNWIND_TARGET_ARM) +check_symbol_exists(__USING_SJLJ_EXCEPTIONS__ "" LIBUNWIND_USES_SJLJ_EXCEPTIONS) +check_symbol_exists(__ARM_DWARF_EH__ "" LIBUNWIND_USES_DWARF_EH) + +if(LIBUNWIND_TARGET_ARM AND NOT LIBUNWIND_USES_SJLJ_EXCEPTIONS AND NOT LIBUNWIND_USES_DWARF_EH) + # This condition is copied from __libunwind_config.h + set(LIBUNWIND_USES_ARM_EHABI ON) +endif() + +# Check libraries +if(FUCHSIA) + set(LIBUNWIND_HAS_DL_LIB NO) + set(LIBUNWIND_HAS_PTHREAD_LIB NO) +else() + check_library_exists(dl dladdr "" LIBUNWIND_HAS_DL_LIB) + check_library_exists(pthread pthread_once "" LIBUNWIND_HAS_PTHREAD_LIB) +endif() diff --git a/libunwind/docs/AppleInternalTesting.md b/libunwind/docs/AppleInternalTesting.md new file mode 100644 index 0000000..c528de0 --- /dev/null +++ b/libunwind/docs/AppleInternalTesting.md @@ -0,0 +1,47 @@ +Apple Internal Testing for libunwind +==================================== + +## Open source testing + +To be setup: Setup CI for libunwind + +libunwind currently has very few lit tests. You can run them manually by: +``` +$ cmake -GNinja ... -DLLVM_ENABLE_PROJECTS="libunwind" .. $PATH_TO_LLVM_PROJECT/llvm +$ ninja check-unwind +``` + + +## PR Testing on stash + +llvm-project on stash has PR testing setup for libunwind on ATP. The PR job +is setup under: ``"Dev Tools" -> "libunwind"`` + +You can trigger the test directly on a stash PR by commenting: + +"@sweci [please] build libunwind for [TRAIN]" + +Currently, PR Testing only checks if libunwind builds successfully in XBS, +no runtime tests are performed. + + +## BATS testing + +You can test libunwind using BATS. Here is an example: + +``` +$ /SWE/CoreOS/Tools/bin/bats build --build CurrentGolden+ --project libunwind:$BRANCH --no-base-tag --no-radar -t test_dyld --dependents=soft --device Skylake_Broadwell_Haswell_OneRandom,H10P-OneRandom,H11_OneRandom,watch-m9-one-random,armv7k,atv,BridgeOSDefault-OneRandom -u $OD_USER +``` + +* CurrentGolden+ will build for all the downstream train for Golden, including iOS, tvOS, bridgeOS, etc. +* `--no-radar` can be replaced with `-r $RADAR_NUMBER` +* `--dependents=soft` will force BATS build important downstream clients, like dyld +* `-t` can specify tests to run after the build finishes. `test_dyld` is a good test since dyld2 uses libunwind extensively. The other tests that are good to run: `nightly` for nightly test, `guardian_validation_ring3` is another good one. +* `--device` is a long string of device that currently use to pick up one device for each architecture. It is important to test libunwind on all architectures. + +A good way to run BATS against PR on stash is to specify: `--project libunwind:refs/pull-requests/$PR_NUMBER/merge` + + +## SWB Testing + +You can also run SWB with libunwind submission. diff --git a/libunwind/docs/BuildingLibunwind.rst b/libunwind/docs/BuildingLibunwind.rst new file mode 100644 index 0000000..ad9dee0 --- /dev/null +++ b/libunwind/docs/BuildingLibunwind.rst @@ -0,0 +1,161 @@ +.. _BuildingLibunwind: + +================== +Building libunwind +================== + +.. contents:: + :local: + +.. _build instructions: + +Getting Started +=============== + +On Mac OS, the easiest way to get this library is to link with -lSystem. +However if you want to build tip-of-trunk from here (getting the bleeding +edge), read on. + +The basic steps needed to build libc++ are: + +#. Checkout LLVM, libunwind, and related projects: + + * ``cd where-you-want-llvm-to-live`` + * ``git clone https://github.com/llvm/llvm-project.git`` + +#. Configure and build libunwind: + + CMake is the only supported configuration system. + + Clang is the preferred compiler when building and using libunwind. + + * ``cd where you want to build llvm`` + * ``mkdir build`` + * ``cd build`` + * ``cmake -G -DLLVM_ENABLE_PROJECTS=libunwind [options] `` + + For more information about configuring libunwind see :ref:`CMake Options`. + + * ``make unwind`` --- will build libunwind. + * ``make check-unwind`` --- will run the test suite. + + Shared and static libraries for libunwind should now be present in llvm/build/lib. + +#. **Optional**: Install libunwind + + If your system already provides an unwinder, it is important to be careful + not to replace it. Remember Use the CMake option ``CMAKE_INSTALL_PREFIX`` to + select a safe place to install libunwind. + + * ``make install-unwind`` --- Will install the libraries and the headers + + +It is sometimes beneficial to build outside of the LLVM tree. An out-of-tree +build would look like this: + +.. code-block:: bash + + $ cd where-you-want-libunwind-to-live + $ # Check out llvm, and libunwind + $ ``svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm`` + $ ``svn co https://llvm.org/svn/llvm-project/libunwind/trunk libunwind`` + $ cd where-you-want-to-build + $ mkdir build && cd build + $ export CC=clang CXX=clang++ + $ cmake -DLLVM_PATH=path/to/llvm \ + path/to/libunwind + $ make + + +.. _CMake Options: + +CMake Options +============= + +Here are some of the CMake variables that are used often, along with a +brief explanation and LLVM-specific notes. For full documentation, check the +CMake docs or execute ``cmake --help-variable VARIABLE_NAME``. + +**CMAKE_BUILD_TYPE**:STRING + Sets the build type for ``make`` based generators. Possible values are + Release, Debug, RelWithDebInfo and MinSizeRel. On systems like Visual Studio + the user sets the build type with the IDE settings. + +**CMAKE_INSTALL_PREFIX**:PATH + Path where LLVM will be installed if "make install" is invoked or the + "INSTALL" target is built. + +**CMAKE_CXX_COMPILER**:STRING + The C++ compiler to use when building and testing libunwind. + + +.. _libunwind-specific options: + +libunwind specific options +-------------------------- + +.. option:: LIBUNWIND_BUILD_32_BITS:BOOL + + **Default**: Same as LLVM_BUILD_32_BITS + + Toggle whether libunwind should be built with -m32. + +.. option:: LIBUNWIND_ENABLE_ASSERTIONS:BOOL + + **Default**: ``ON`` + + Toggle assertions independent of the build mode. + +.. option:: LIBUNWIND_ENABLE_PEDANTIC:BOOL + + **Default**: ``ON`` + + Compile with -Wpedantic. + +.. option:: LIBUNWIND_ENABLE_WERROR:BOOL + + **Default**: ``ON`` + + Compile with -Werror + +.. option:: LIBUNWIND_ENABLE_SHARED:BOOL + + **Default**: ``ON`` + + Build libunwind as a shared library. + +.. option:: LIBUNWIND_ENABLE_STATIC:BOOL + + **Default**: ``ON`` + + Build libunwind as a static archive. + +.. option:: LIBUNWIND_ENABLE_CROSS_UNWINDING:BOOL + + **Default**: ``OFF`` + + Enable cross-platform unwinding support. + +.. option:: LIBUNWIND_ENABLE_ARM_WMMX:BOOL + + **Default**: ``OFF`` + + Enable unwinding support for ARM WMMX registers. + +.. option:: LIBUNWIND_ENABLE_THREADS:BOOL + + **Default**: ``ON`` + + Build libunwind with threading support. + +.. option:: LIBUNWIND_TARGET_TRIPLE:STRING + + Target triple for cross compiling + +.. option:: LIBUNWIND_GCC_TOOLCHAIN:PATH + + GCC toolchain for cross compiling + +.. option:: LIBUNWIND_SYSROOT + + Sysroot for cross compiling diff --git a/libunwind/docs/CMakeLists.txt b/libunwind/docs/CMakeLists.txt new file mode 100644 index 0000000..c226f2f --- /dev/null +++ b/libunwind/docs/CMakeLists.txt @@ -0,0 +1,7 @@ +include(FindSphinx) +if (SPHINX_FOUND) + include(AddSphinxTarget) + if (${SPHINX_OUTPUT_HTML}) + add_sphinx_target(html libunwind) + endif() +endif() diff --git a/libunwind/docs/README.txt b/libunwind/docs/README.txt new file mode 100644 index 0000000..968982f --- /dev/null +++ b/libunwind/docs/README.txt @@ -0,0 +1,13 @@ +libunwind Documentation +==================== + +The libunwind documentation is written using the Sphinx documentation generator. It is +currently tested with Sphinx 1.1.3. + +To build the documents into html configure libunwind with the following cmake options: + + * -DLLVM_ENABLE_SPHINX=ON + * -DLIBUNWIND_INCLUDE_DOCS=ON + +After configuring libunwind with these options the make rule `docs-libunwind-html` +should be available. diff --git a/libunwind/docs/conf.py b/libunwind/docs/conf.py new file mode 100644 index 0000000..6217ead --- /dev/null +++ b/libunwind/docs/conf.py @@ -0,0 +1,252 @@ +# -*- coding: utf-8 -*- +# +# libunwind documentation build configuration file. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +from datetime import date + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'libunwind' +copyright = u'2011-%d, LLVM Project' % date.today().year + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '12.0' +# The full version, including alpha/beta/rc tags. +release = '12.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%Y-%m-%d' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'friendly' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libunwinddoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('contents', 'libunwind.tex', u'libunwind Documentation', + u'LLVM project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('contents', 'libunwind', u'libunwind Documentation', + [u'LLVM project'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('contents', 'libunwind', u'libunwind Documentation', + u'LLVM project', 'libunwind', 'LLVM Unwinder', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# FIXME: Define intersphinx configration. +intersphinx_mapping = {} + + +# -- Options for extensions ---------------------------------------------------- + +# Enable this if you want TODOs to show up in the generated documentation. +todo_include_todos = True diff --git a/libunwind/docs/index.rst b/libunwind/docs/index.rst new file mode 100644 index 0000000..d134bf2 --- /dev/null +++ b/libunwind/docs/index.rst @@ -0,0 +1,104 @@ +.. _index: + +======================= +libunwind LLVM Unwinder +======================= + +Overview +======== + +libunwind is an implementation of the interface defined by the HP libunwind +project. It was contributed by Apple as a way to enable clang++ to port to +platforms that do not have a system unwinder. It is intended to be a small and +fast implementation of the ABI, leaving off some features of HP's libunwind +that never materialized (e.g. remote unwinding). + +The unwinder has two levels of API. The high level APIs are the `_Unwind_*` +functions which implement functionality required by `__cxa_*` exception +functions. The low level APIs are the `unw_*` functions which are an interface +defined by the old HP libunwind project. + +Getting Started with libunwind +------------------------------ + +.. toctree:: + :maxdepth: 2 + + BuildingLibunwind + +Current Status +-------------- + +libunwind is a production-quality unwinder, with platform support for DWARF +unwind info, SjLj, and ARM EHABI. + +The low level libunwind API was designed to work either in-process (aka local) +or to operate on another process (aka remote), but only the local path has been +implemented. Remote unwinding remains as future work. + +Platform and Compiler Support +----------------------------- + +libunwind is known to work on the following platforms: + +============ ======================== ============ ======================== +OS Arch Compilers Unwind Info +============ ======================== ============ ======================== +Any i386, x86_64, ARM Clang SjLj +Bare Metal ARM Clang, GCC EHABI +FreeBSD i386, x86_64, ARM64 Clang DWARF CFI +iOS ARM Clang SjLj +Linux ARM Clang, GCC EHABI +Linux i386, x86_64, ARM64 Clang, GCC DWARF CFI +macOS i386, x86_64 Clang, GCC DWARF CFI +NetBSD x86_64 Clang, GCC DWARF CFI +Windows i386, x86_64, ARM, ARM64 Clang DWARF CFI +============ ======================== ============ ======================== + +The following minimum compiler versions are strongly recommended. + +* Clang 3.5 and above +* GCC 4.7 and above. + +Anything older *may* work. + +Notes and Known Issues +---------------------- + +* TODO + + +Getting Involved +================ + +First please review our `Developer's Policy `__ +and `Getting started with LLVM `__. + +**Bug Reports** + +If you think you've found a bug in libunwind, please report it using +the `LLVM Bugzilla`_. If you're not sure, you +can post a message to the `cfe-dev mailing list`_ or on IRC. +Please include "libunwind" in your subject. + +**Patches** + +If you want to contribute a patch to libunwind, the best place for that is +`Phabricator `_. Please include [libunwind] in the subject and +add `cfe-commits` as a subscriber. Also make sure you are subscribed to the +`cfe-commits mailing list `_. + +**Discussion and Questions** + +Send discussions and questions to the +`cfe-dev mailing list `_. +Please include [libunwind] in the subject. + + +Quick Links +=========== +* `LLVM Homepage `_ +* `LLVM Bugzilla `_ +* `cfe-commits Mailing List`_ +* `cfe-dev Mailing List`_ +* `Browse libunwind Sources `_ diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h new file mode 100644 index 0000000..71d77ca --- /dev/null +++ b/libunwind/include/__libunwind_config.h @@ -0,0 +1,159 @@ +//===------------------------- __libunwind_config.h -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef ____LIBUNWIND_CONFIG_H__ +#define ____LIBUNWIND_CONFIG_H__ + +#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ + !defined(__ARM_DWARF_EH__) +#define _LIBUNWIND_ARM_EHABI +#endif + +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON 34 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64 + +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# if defined(__i386__) +# define _LIBUNWIND_TARGET_I386 +# define _LIBUNWIND_CONTEXT_SIZE 8 +# define _LIBUNWIND_CURSOR_SIZE 15 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 +# elif defined(__x86_64__) +# define _LIBUNWIND_TARGET_X86_64 1 +# if defined(_WIN64) +# define _LIBUNWIND_CONTEXT_SIZE 54 +# ifdef __SEH__ +# define _LIBUNWIND_CURSOR_SIZE 204 +# else +# define _LIBUNWIND_CURSOR_SIZE 66 +# endif +# else +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 +# elif defined(__powerpc64__) +# define _LIBUNWIND_TARGET_PPC64 1 +# define _LIBUNWIND_CONTEXT_SIZE 167 +# define _LIBUNWIND_CURSOR_SIZE 179 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 +# elif defined(__ppc__) +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_CONTEXT_SIZE 117 +# define _LIBUNWIND_CURSOR_SIZE 124 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC +# elif defined(__aarch64__) +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_CONTEXT_SIZE 66 +# if defined(__SEH__) +# define _LIBUNWIND_CURSOR_SIZE 164 +# else +# define _LIBUNWIND_CURSOR_SIZE 78 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 +# elif defined(__arm__) +# define _LIBUNWIND_TARGET_ARM 1 +# if defined(__SEH__) +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 80 +# elif defined(__ARM_WMMX) +# define _LIBUNWIND_CONTEXT_SIZE 61 +# define _LIBUNWIND_CURSOR_SIZE 68 +# else +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 49 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM +# elif defined(__or1k__) +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 16 +# define _LIBUNWIND_CURSOR_SIZE 24 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K +# elif defined(__hexagon__) +# define _LIBUNWIND_TARGET_HEXAGON 1 +// Values here change when : Registers.hpp - hexagon_thread_state_t change +# define _LIBUNWIND_CONTEXT_SIZE 18 +# define _LIBUNWIND_CURSOR_SIZE 24 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON +# elif defined(__mips__) +# if defined(_ABIO32) && _MIPS_SIM == _ABIO32 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 50 +# define _LIBUNWIND_CURSOR_SIZE 57 +# else +# define _LIBUNWIND_CONTEXT_SIZE 18 +# define _LIBUNWIND_CURSOR_SIZE 24 +# endif +# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 74 +# else +# define _LIBUNWIND_CONTEXT_SIZE 35 +# define _LIBUNWIND_CURSOR_SIZE 42 +# endif +# elif defined(_ABI64) && _MIPS_SIM == _ABI64 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 79 +# else +# define _LIBUNWIND_CONTEXT_SIZE 35 +# define _LIBUNWIND_CURSOR_SIZE 47 +# endif +# else +# error "Unsupported MIPS ABI and/or environment" +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS +# elif defined(__sparc__) + #define _LIBUNWIND_TARGET_SPARC 1 + #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC + #define _LIBUNWIND_CONTEXT_SIZE 16 + #define _LIBUNWIND_CURSOR_SIZE 23 +# elif defined(__riscv) +# if __riscv_xlen == 64 +# define _LIBUNWIND_TARGET_RISCV 1 +# define _LIBUNWIND_CONTEXT_SIZE 64 +# define _LIBUNWIND_CURSOR_SIZE 76 +# else +# error "Unsupported RISC-V ABI" +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV +# else +# error "Unsupported architecture." +# endif +#else // !_LIBUNWIND_IS_NATIVE_ONLY +# define _LIBUNWIND_TARGET_I386 +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_TARGET_PPC64 1 +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# define _LIBUNWIND_TARGET_SPARC 1 +# define _LIBUNWIND_TARGET_HEXAGON 1 +# define _LIBUNWIND_TARGET_RISCV 1 +# define _LIBUNWIND_CONTEXT_SIZE 167 +# define _LIBUNWIND_CURSOR_SIZE 179 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 +#endif // _LIBUNWIND_IS_NATIVE_ONLY + +#endif // ____LIBUNWIND_CONFIG_H__ diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index ea70420..6ec649a 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -1,302 +1,950 @@ -/* -*- mode: C; c-basic-offset: 4; -*- - * - * Copyright (c) 2008-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * - * C interface to libuwind - * - * Source compatible with libuwind API documented at: - * http://www.nongnu.org/libunwind/man/libunwind(3).html - * - */ - +//===---------------------------- libunwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Compatible with libunwind API documented at: +// http://www.nongnu.org/libunwind/man/libunwind(3).html +// +//===----------------------------------------------------------------------===// #ifndef __LIBUNWIND__ #define __LIBUNWIND__ +#include <__libunwind_config.h> + #include #include -#include -#include + +#ifdef __APPLE__ + #if __clang__ + #if __has_include() + #include + #endif + #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 + #include + #endif + + #ifdef __arm__ + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #elif defined(__OSX_AVAILABLE_STARTING) + #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) + #else + #include + #ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #else + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #endif + #endif +#else + #define LIBUNWIND_AVAIL +#endif + +#if defined(_WIN32) && defined(__SEH__) + #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16))) +#else + #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR +#endif /* error codes */ enum { - UNW_ESUCCESS = 0, /* no error */ - UNW_EUNSPEC = -6540, /* unspecified (general) error */ - UNW_ENOMEM = -6541, /* out of memory */ - UNW_EBADREG = -6542, /* bad register number */ - UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ - UNW_ESTOPUNWIND = -6544, /* stop unwinding */ - UNW_EINVALIDIP = -6545, /* invalid IP */ - UNW_EBADFRAME = -6546, /* bad frame */ - UNW_EINVAL = -6547, /* unsupported operation or bad value */ - UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ - UNW_ENOINFO = -6549 /* no unwind info found */ + UNW_ESUCCESS = 0, /* no error */ + UNW_EUNSPEC = -6540, /* unspecified (general) error */ + UNW_ENOMEM = -6541, /* out of memory */ + UNW_EBADREG = -6542, /* bad register number */ + UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ + UNW_ESTOPUNWIND = -6544, /* stop unwinding */ + UNW_EINVALIDIP = -6545, /* invalid IP */ + UNW_EBADFRAME = -6546, /* bad frame */ + UNW_EINVAL = -6547, /* unsupported operation or bad value */ + UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ + UNW_ENOINFO = -6549 /* no unwind info found */ +#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY) + , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */ +#endif }; +struct unw_context_t { + uint64_t data[_LIBUNWIND_CONTEXT_SIZE]; +}; +typedef struct unw_context_t unw_context_t; -struct unw_context_t { uint64_t data[128]; }; -typedef struct unw_context_t unw_context_t; +struct unw_cursor_t { + uint64_t data[_LIBUNWIND_CURSOR_SIZE]; +} LIBUNWIND_CURSOR_ALIGNMENT_ATTR; +typedef struct unw_cursor_t unw_cursor_t; -struct unw_cursor_t { uint64_t data[140]; }; -typedef struct unw_cursor_t unw_cursor_t; +typedef struct unw_addr_space *unw_addr_space_t; -typedef struct unw_addr_space* unw_addr_space_t; +typedef int unw_regnum_t; +typedef uintptr_t unw_word_t; +#if defined(__arm__) && !defined(__ARM_DWARF_EH__) +typedef uint64_t unw_fpreg_t; +#else +typedef double unw_fpreg_t; +#endif -typedef int unw_regnum_t; -typedef uint64_t unw_word_t; -typedef double unw_fpreg_t; - -struct unw_proc_info_t -{ - unw_word_t start_ip; /* start address of function */ - unw_word_t end_ip; /* address after end of function */ - unw_word_t lsda; /* address of language specific data area, or zero if not used */ - unw_word_t handler; /* personality routine, or zero if not used */ - unw_word_t gp; /* not used */ - unw_word_t flags; /* not used */ - uint32_t format; /* compact unwind encoding, or zero if none */ - uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */ - unw_word_t unwind_info; /* address of dwarf unwind info, or zero if none */ - unw_word_t extra; /* mach_header of mach-o image containing function */ +struct unw_proc_info_t { + unw_word_t start_ip; /* start address of function */ + unw_word_t end_ip; /* address after end of function */ + unw_word_t lsda; /* address of language specific data area, */ + /* or zero if not used */ + unw_word_t handler; /* personality routine, or zero if not used */ + unw_word_t gp; /* not used */ + unw_word_t flags; /* not used */ + uint32_t format; /* compact unwind encoding, or zero if none */ + uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */ + unw_word_t unwind_info; /* address of DWARF unwind info, or zero */ + unw_word_t extra; /* mach_header of mach-o image containing func */ }; typedef struct unw_proc_info_t unw_proc_info_t; - #ifdef __cplusplus extern "C" { #endif -#if !__arm__ -extern int unw_getcontext(unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_init_local(unw_cursor_t*, unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_step(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_get_reg(unw_cursor_t*, unw_regnum_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_get_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_set_reg(unw_cursor_t*, unw_regnum_t, unw_word_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_set_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_resume(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); +extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL; +extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL; +extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL; +extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL; +extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL; -extern const char* unw_regname(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_get_proc_info(unw_cursor_t*, unw_proc_info_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_is_fpreg(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_is_signal_frame(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); -extern int unw_get_proc_name(unw_cursor_t*, char*, size_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0); +#ifdef __arm__ +/* Save VFP registers in FSTMX format (instead of FSTMD). */ +extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL; +#endif + + +extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; +extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; //extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); -#endif - - -#if UNW_REMOTE -/* - * Mac OS X "remote" API for unwinding other processes on same machine - * - */ -extern unw_addr_space_t unw_local_addr_space; -extern unw_addr_space_t unw_create_addr_space_for_task(task_t); -extern void unw_destroy_addr_space(unw_addr_space_t); -extern int unw_init_remote_thread(unw_cursor_t*, unw_addr_space_t, thread_t*); -#endif - - -/* - * traditional libuwind "remote" API - * NOT IMPLEMENTED on Mac OS X - * - * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, thread_t*); - * extern unw_accessors_t unw_get_accessors(unw_addr_space_t); - * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int); - * extern void unw_flush_cache(unw_addr_space_t, unw_word_t, unw_word_t); - * extern int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t); - * extern void _U_dyn_register(unw_dyn_info_t*); - * extern void _U_dyn_cancel(unw_dyn_info_t*); - */ +extern unw_addr_space_t unw_local_addr_space; #ifdef __cplusplus } #endif - -// architecture independent register numbers +// architecture independent register numbers enum { - UNW_REG_IP = -1, // instruction pointer - UNW_REG_SP = -2, // stack pointer + UNW_REG_IP = -1, // instruction pointer + UNW_REG_SP = -2, // stack pointer }; - // 32-bit x86 registers enum { - UNW_X86_EAX = 0, - UNW_X86_ECX = 1, - UNW_X86_EDX = 2, - UNW_X86_EBX = 3, - UNW_X86_EBP = 4, - UNW_X86_ESP = 5, - UNW_X86_ESI = 6, - UNW_X86_EDI = 7 + UNW_X86_EAX = 0, + UNW_X86_ECX = 1, + UNW_X86_EDX = 2, + UNW_X86_EBX = 3, + UNW_X86_EBP = 4, + UNW_X86_ESP = 5, + UNW_X86_ESI = 6, + UNW_X86_EDI = 7 }; - // 64-bit x86_64 registers enum { - UNW_X86_64_RAX = 0, - UNW_X86_64_RDX = 1, - UNW_X86_64_RCX = 2, - UNW_X86_64_RBX = 3, - UNW_X86_64_RSI = 4, - UNW_X86_64_RDI = 5, - UNW_X86_64_RBP = 6, - UNW_X86_64_RSP = 7, - UNW_X86_64_R8 = 8, - UNW_X86_64_R9 = 9, - UNW_X86_64_R10 = 10, - UNW_X86_64_R11 = 11, - UNW_X86_64_R12 = 12, - UNW_X86_64_R13 = 13, - UNW_X86_64_R14 = 14, - UNW_X86_64_R15 = 15 + UNW_X86_64_RAX = 0, + UNW_X86_64_RDX = 1, + UNW_X86_64_RCX = 2, + UNW_X86_64_RBX = 3, + UNW_X86_64_RSI = 4, + UNW_X86_64_RDI = 5, + UNW_X86_64_RBP = 6, + UNW_X86_64_RSP = 7, + UNW_X86_64_R8 = 8, + UNW_X86_64_R9 = 9, + UNW_X86_64_R10 = 10, + UNW_X86_64_R11 = 11, + UNW_X86_64_R12 = 12, + UNW_X86_64_R13 = 13, + UNW_X86_64_R14 = 14, + UNW_X86_64_R15 = 15, + UNW_X86_64_RIP = 16, + UNW_X86_64_XMM0 = 17, + UNW_X86_64_XMM1 = 18, + UNW_X86_64_XMM2 = 19, + UNW_X86_64_XMM3 = 20, + UNW_X86_64_XMM4 = 21, + UNW_X86_64_XMM5 = 22, + UNW_X86_64_XMM6 = 23, + UNW_X86_64_XMM7 = 24, + UNW_X86_64_XMM8 = 25, + UNW_X86_64_XMM9 = 26, + UNW_X86_64_XMM10 = 27, + UNW_X86_64_XMM11 = 28, + UNW_X86_64_XMM12 = 29, + UNW_X86_64_XMM13 = 30, + UNW_X86_64_XMM14 = 31, + UNW_X86_64_XMM15 = 32, }; // 32-bit ppc register numbers enum { - UNW_PPC_R0 = 0, - UNW_PPC_R1 = 1, - UNW_PPC_R2 = 2, - UNW_PPC_R3 = 3, - UNW_PPC_R4 = 4, - UNW_PPC_R5 = 5, - UNW_PPC_R6 = 6, - UNW_PPC_R7 = 7, - UNW_PPC_R8 = 8, - UNW_PPC_R9 = 9, - UNW_PPC_R10 = 10, - UNW_PPC_R11 = 11, - UNW_PPC_R12 = 12, - UNW_PPC_R13 = 13, - UNW_PPC_R14 = 14, - UNW_PPC_R15 = 15, - UNW_PPC_R16 = 16, - UNW_PPC_R17 = 17, - UNW_PPC_R18 = 18, - UNW_PPC_R19 = 19, - UNW_PPC_R20 = 20, - UNW_PPC_R21 = 21, - UNW_PPC_R22 = 22, - UNW_PPC_R23 = 23, - UNW_PPC_R24 = 24, - UNW_PPC_R25 = 25, - UNW_PPC_R26 = 26, - UNW_PPC_R27 = 27, - UNW_PPC_R28 = 28, - UNW_PPC_R29 = 29, - UNW_PPC_R30 = 30, - UNW_PPC_R31 = 31, - UNW_PPC_F0 = 32, - UNW_PPC_F1 = 33, - UNW_PPC_F2 = 34, - UNW_PPC_F3 = 35, - UNW_PPC_F4 = 36, - UNW_PPC_F5 = 37, - UNW_PPC_F6 = 38, - UNW_PPC_F7 = 39, - UNW_PPC_F8 = 40, - UNW_PPC_F9 = 41, - UNW_PPC_F10 = 42, - UNW_PPC_F11 = 43, - UNW_PPC_F12 = 44, - UNW_PPC_F13 = 45, - UNW_PPC_F14 = 46, - UNW_PPC_F15 = 47, - UNW_PPC_F16 = 48, - UNW_PPC_F17 = 49, - UNW_PPC_F18 = 50, - UNW_PPC_F19 = 51, - UNW_PPC_F20 = 52, - UNW_PPC_F21 = 53, - UNW_PPC_F22 = 54, - UNW_PPC_F23 = 55, - UNW_PPC_F24 = 56, - UNW_PPC_F25 = 57, - UNW_PPC_F26 = 58, - UNW_PPC_F27 = 59, - UNW_PPC_F28 = 60, - UNW_PPC_F29 = 61, - UNW_PPC_F30 = 62, - UNW_PPC_F31 = 63, - UNW_PPC_MQ = 64, - UNW_PPC_LR = 65, - UNW_PPC_CTR = 66, - UNW_PPC_AP = 67, - UNW_PPC_CR0 = 68, - UNW_PPC_CR1 = 69, - UNW_PPC_CR2 = 70, - UNW_PPC_CR3 = 71, - UNW_PPC_CR4 = 72, - UNW_PPC_CR5 = 73, - UNW_PPC_CR6 = 74, - UNW_PPC_CR7 = 75, - UNW_PPC_XER = 76, - UNW_PPC_V0 = 77, - UNW_PPC_V1 = 78, - UNW_PPC_V2 = 79, - UNW_PPC_V3 = 80, - UNW_PPC_V4 = 81, - UNW_PPC_V5 = 82, - UNW_PPC_V6 = 83, - UNW_PPC_V7 = 84, - UNW_PPC_V8 = 85, - UNW_PPC_V9 = 86, - UNW_PPC_V10 = 87, - UNW_PPC_V11 = 88, - UNW_PPC_V12 = 89, - UNW_PPC_V13 = 90, - UNW_PPC_V14 = 91, - UNW_PPC_V15 = 92, - UNW_PPC_V16 = 93, - UNW_PPC_V17 = 94, - UNW_PPC_V18 = 95, - UNW_PPC_V19 = 96, - UNW_PPC_V20 = 97, - UNW_PPC_V21 = 98, - UNW_PPC_V22 = 99, - UNW_PPC_V23 = 100, - UNW_PPC_V24 = 101, - UNW_PPC_V25 = 102, - UNW_PPC_V26 = 103, - UNW_PPC_V27 = 104, - UNW_PPC_V28 = 105, - UNW_PPC_V29 = 106, - UNW_PPC_V30 = 107, - UNW_PPC_V31 = 108, - UNW_PPC_VRSAVE = 109, - UNW_PPC_VSCR = 110, - UNW_PPC_SPE_ACC = 111, - UNW_PPC_SPEFSCR = 112 - + UNW_PPC_R0 = 0, + UNW_PPC_R1 = 1, + UNW_PPC_R2 = 2, + UNW_PPC_R3 = 3, + UNW_PPC_R4 = 4, + UNW_PPC_R5 = 5, + UNW_PPC_R6 = 6, + UNW_PPC_R7 = 7, + UNW_PPC_R8 = 8, + UNW_PPC_R9 = 9, + UNW_PPC_R10 = 10, + UNW_PPC_R11 = 11, + UNW_PPC_R12 = 12, + UNW_PPC_R13 = 13, + UNW_PPC_R14 = 14, + UNW_PPC_R15 = 15, + UNW_PPC_R16 = 16, + UNW_PPC_R17 = 17, + UNW_PPC_R18 = 18, + UNW_PPC_R19 = 19, + UNW_PPC_R20 = 20, + UNW_PPC_R21 = 21, + UNW_PPC_R22 = 22, + UNW_PPC_R23 = 23, + UNW_PPC_R24 = 24, + UNW_PPC_R25 = 25, + UNW_PPC_R26 = 26, + UNW_PPC_R27 = 27, + UNW_PPC_R28 = 28, + UNW_PPC_R29 = 29, + UNW_PPC_R30 = 30, + UNW_PPC_R31 = 31, + UNW_PPC_F0 = 32, + UNW_PPC_F1 = 33, + UNW_PPC_F2 = 34, + UNW_PPC_F3 = 35, + UNW_PPC_F4 = 36, + UNW_PPC_F5 = 37, + UNW_PPC_F6 = 38, + UNW_PPC_F7 = 39, + UNW_PPC_F8 = 40, + UNW_PPC_F9 = 41, + UNW_PPC_F10 = 42, + UNW_PPC_F11 = 43, + UNW_PPC_F12 = 44, + UNW_PPC_F13 = 45, + UNW_PPC_F14 = 46, + UNW_PPC_F15 = 47, + UNW_PPC_F16 = 48, + UNW_PPC_F17 = 49, + UNW_PPC_F18 = 50, + UNW_PPC_F19 = 51, + UNW_PPC_F20 = 52, + UNW_PPC_F21 = 53, + UNW_PPC_F22 = 54, + UNW_PPC_F23 = 55, + UNW_PPC_F24 = 56, + UNW_PPC_F25 = 57, + UNW_PPC_F26 = 58, + UNW_PPC_F27 = 59, + UNW_PPC_F28 = 60, + UNW_PPC_F29 = 61, + UNW_PPC_F30 = 62, + UNW_PPC_F31 = 63, + UNW_PPC_MQ = 64, + UNW_PPC_LR = 65, + UNW_PPC_CTR = 66, + UNW_PPC_AP = 67, + UNW_PPC_CR0 = 68, + UNW_PPC_CR1 = 69, + UNW_PPC_CR2 = 70, + UNW_PPC_CR3 = 71, + UNW_PPC_CR4 = 72, + UNW_PPC_CR5 = 73, + UNW_PPC_CR6 = 74, + UNW_PPC_CR7 = 75, + UNW_PPC_XER = 76, + UNW_PPC_V0 = 77, + UNW_PPC_V1 = 78, + UNW_PPC_V2 = 79, + UNW_PPC_V3 = 80, + UNW_PPC_V4 = 81, + UNW_PPC_V5 = 82, + UNW_PPC_V6 = 83, + UNW_PPC_V7 = 84, + UNW_PPC_V8 = 85, + UNW_PPC_V9 = 86, + UNW_PPC_V10 = 87, + UNW_PPC_V11 = 88, + UNW_PPC_V12 = 89, + UNW_PPC_V13 = 90, + UNW_PPC_V14 = 91, + UNW_PPC_V15 = 92, + UNW_PPC_V16 = 93, + UNW_PPC_V17 = 94, + UNW_PPC_V18 = 95, + UNW_PPC_V19 = 96, + UNW_PPC_V20 = 97, + UNW_PPC_V21 = 98, + UNW_PPC_V22 = 99, + UNW_PPC_V23 = 100, + UNW_PPC_V24 = 101, + UNW_PPC_V25 = 102, + UNW_PPC_V26 = 103, + UNW_PPC_V27 = 104, + UNW_PPC_V28 = 105, + UNW_PPC_V29 = 106, + UNW_PPC_V30 = 107, + UNW_PPC_V31 = 108, + UNW_PPC_VRSAVE = 109, + UNW_PPC_VSCR = 110, + UNW_PPC_SPE_ACC = 111, + UNW_PPC_SPEFSCR = 112 }; +// 64-bit ppc register numbers +enum { + UNW_PPC64_R0 = 0, + UNW_PPC64_R1 = 1, + UNW_PPC64_R2 = 2, + UNW_PPC64_R3 = 3, + UNW_PPC64_R4 = 4, + UNW_PPC64_R5 = 5, + UNW_PPC64_R6 = 6, + UNW_PPC64_R7 = 7, + UNW_PPC64_R8 = 8, + UNW_PPC64_R9 = 9, + UNW_PPC64_R10 = 10, + UNW_PPC64_R11 = 11, + UNW_PPC64_R12 = 12, + UNW_PPC64_R13 = 13, + UNW_PPC64_R14 = 14, + UNW_PPC64_R15 = 15, + UNW_PPC64_R16 = 16, + UNW_PPC64_R17 = 17, + UNW_PPC64_R18 = 18, + UNW_PPC64_R19 = 19, + UNW_PPC64_R20 = 20, + UNW_PPC64_R21 = 21, + UNW_PPC64_R22 = 22, + UNW_PPC64_R23 = 23, + UNW_PPC64_R24 = 24, + UNW_PPC64_R25 = 25, + UNW_PPC64_R26 = 26, + UNW_PPC64_R27 = 27, + UNW_PPC64_R28 = 28, + UNW_PPC64_R29 = 29, + UNW_PPC64_R30 = 30, + UNW_PPC64_R31 = 31, + UNW_PPC64_F0 = 32, + UNW_PPC64_F1 = 33, + UNW_PPC64_F2 = 34, + UNW_PPC64_F3 = 35, + UNW_PPC64_F4 = 36, + UNW_PPC64_F5 = 37, + UNW_PPC64_F6 = 38, + UNW_PPC64_F7 = 39, + UNW_PPC64_F8 = 40, + UNW_PPC64_F9 = 41, + UNW_PPC64_F10 = 42, + UNW_PPC64_F11 = 43, + UNW_PPC64_F12 = 44, + UNW_PPC64_F13 = 45, + UNW_PPC64_F14 = 46, + UNW_PPC64_F15 = 47, + UNW_PPC64_F16 = 48, + UNW_PPC64_F17 = 49, + UNW_PPC64_F18 = 50, + UNW_PPC64_F19 = 51, + UNW_PPC64_F20 = 52, + UNW_PPC64_F21 = 53, + UNW_PPC64_F22 = 54, + UNW_PPC64_F23 = 55, + UNW_PPC64_F24 = 56, + UNW_PPC64_F25 = 57, + UNW_PPC64_F26 = 58, + UNW_PPC64_F27 = 59, + UNW_PPC64_F28 = 60, + UNW_PPC64_F29 = 61, + UNW_PPC64_F30 = 62, + UNW_PPC64_F31 = 63, + // 64: reserved + UNW_PPC64_LR = 65, + UNW_PPC64_CTR = 66, + // 67: reserved + UNW_PPC64_CR0 = 68, + UNW_PPC64_CR1 = 69, + UNW_PPC64_CR2 = 70, + UNW_PPC64_CR3 = 71, + UNW_PPC64_CR4 = 72, + UNW_PPC64_CR5 = 73, + UNW_PPC64_CR6 = 74, + UNW_PPC64_CR7 = 75, + UNW_PPC64_XER = 76, + UNW_PPC64_V0 = 77, + UNW_PPC64_V1 = 78, + UNW_PPC64_V2 = 79, + UNW_PPC64_V3 = 80, + UNW_PPC64_V4 = 81, + UNW_PPC64_V5 = 82, + UNW_PPC64_V6 = 83, + UNW_PPC64_V7 = 84, + UNW_PPC64_V8 = 85, + UNW_PPC64_V9 = 86, + UNW_PPC64_V10 = 87, + UNW_PPC64_V11 = 88, + UNW_PPC64_V12 = 89, + UNW_PPC64_V13 = 90, + UNW_PPC64_V14 = 91, + UNW_PPC64_V15 = 92, + UNW_PPC64_V16 = 93, + UNW_PPC64_V17 = 94, + UNW_PPC64_V18 = 95, + UNW_PPC64_V19 = 96, + UNW_PPC64_V20 = 97, + UNW_PPC64_V21 = 98, + UNW_PPC64_V22 = 99, + UNW_PPC64_V23 = 100, + UNW_PPC64_V24 = 101, + UNW_PPC64_V25 = 102, + UNW_PPC64_V26 = 103, + UNW_PPC64_V27 = 104, + UNW_PPC64_V28 = 105, + UNW_PPC64_V29 = 106, + UNW_PPC64_V30 = 107, + UNW_PPC64_V31 = 108, + // 109, 111-113: OpenPOWER ELF V2 ABI: reserved + // Borrowing VRSAVE number from PPC32. + UNW_PPC64_VRSAVE = 109, + UNW_PPC64_VSCR = 110, + UNW_PPC64_TFHAR = 114, + UNW_PPC64_TFIAR = 115, + UNW_PPC64_TEXASR = 116, + UNW_PPC64_VS0 = UNW_PPC64_F0, + UNW_PPC64_VS1 = UNW_PPC64_F1, + UNW_PPC64_VS2 = UNW_PPC64_F2, + UNW_PPC64_VS3 = UNW_PPC64_F3, + UNW_PPC64_VS4 = UNW_PPC64_F4, + UNW_PPC64_VS5 = UNW_PPC64_F5, + UNW_PPC64_VS6 = UNW_PPC64_F6, + UNW_PPC64_VS7 = UNW_PPC64_F7, + UNW_PPC64_VS8 = UNW_PPC64_F8, + UNW_PPC64_VS9 = UNW_PPC64_F9, + UNW_PPC64_VS10 = UNW_PPC64_F10, + UNW_PPC64_VS11 = UNW_PPC64_F11, + UNW_PPC64_VS12 = UNW_PPC64_F12, + UNW_PPC64_VS13 = UNW_PPC64_F13, + UNW_PPC64_VS14 = UNW_PPC64_F14, + UNW_PPC64_VS15 = UNW_PPC64_F15, + UNW_PPC64_VS16 = UNW_PPC64_F16, + UNW_PPC64_VS17 = UNW_PPC64_F17, + UNW_PPC64_VS18 = UNW_PPC64_F18, + UNW_PPC64_VS19 = UNW_PPC64_F19, + UNW_PPC64_VS20 = UNW_PPC64_F20, + UNW_PPC64_VS21 = UNW_PPC64_F21, + UNW_PPC64_VS22 = UNW_PPC64_F22, + UNW_PPC64_VS23 = UNW_PPC64_F23, + UNW_PPC64_VS24 = UNW_PPC64_F24, + UNW_PPC64_VS25 = UNW_PPC64_F25, + UNW_PPC64_VS26 = UNW_PPC64_F26, + UNW_PPC64_VS27 = UNW_PPC64_F27, + UNW_PPC64_VS28 = UNW_PPC64_F28, + UNW_PPC64_VS29 = UNW_PPC64_F29, + UNW_PPC64_VS30 = UNW_PPC64_F30, + UNW_PPC64_VS31 = UNW_PPC64_F31, + UNW_PPC64_VS32 = UNW_PPC64_V0, + UNW_PPC64_VS33 = UNW_PPC64_V1, + UNW_PPC64_VS34 = UNW_PPC64_V2, + UNW_PPC64_VS35 = UNW_PPC64_V3, + UNW_PPC64_VS36 = UNW_PPC64_V4, + UNW_PPC64_VS37 = UNW_PPC64_V5, + UNW_PPC64_VS38 = UNW_PPC64_V6, + UNW_PPC64_VS39 = UNW_PPC64_V7, + UNW_PPC64_VS40 = UNW_PPC64_V8, + UNW_PPC64_VS41 = UNW_PPC64_V9, + UNW_PPC64_VS42 = UNW_PPC64_V10, + UNW_PPC64_VS43 = UNW_PPC64_V11, + UNW_PPC64_VS44 = UNW_PPC64_V12, + UNW_PPC64_VS45 = UNW_PPC64_V13, + UNW_PPC64_VS46 = UNW_PPC64_V14, + UNW_PPC64_VS47 = UNW_PPC64_V15, + UNW_PPC64_VS48 = UNW_PPC64_V16, + UNW_PPC64_VS49 = UNW_PPC64_V17, + UNW_PPC64_VS50 = UNW_PPC64_V18, + UNW_PPC64_VS51 = UNW_PPC64_V19, + UNW_PPC64_VS52 = UNW_PPC64_V20, + UNW_PPC64_VS53 = UNW_PPC64_V21, + UNW_PPC64_VS54 = UNW_PPC64_V22, + UNW_PPC64_VS55 = UNW_PPC64_V23, + UNW_PPC64_VS56 = UNW_PPC64_V24, + UNW_PPC64_VS57 = UNW_PPC64_V25, + UNW_PPC64_VS58 = UNW_PPC64_V26, + UNW_PPC64_VS59 = UNW_PPC64_V27, + UNW_PPC64_VS60 = UNW_PPC64_V28, + UNW_PPC64_VS61 = UNW_PPC64_V29, + UNW_PPC64_VS62 = UNW_PPC64_V30, + UNW_PPC64_VS63 = UNW_PPC64_V31 +}; +// 64-bit ARM64 registers +enum { + UNW_ARM64_X0 = 0, + UNW_ARM64_X1 = 1, + UNW_ARM64_X2 = 2, + UNW_ARM64_X3 = 3, + UNW_ARM64_X4 = 4, + UNW_ARM64_X5 = 5, + UNW_ARM64_X6 = 6, + UNW_ARM64_X7 = 7, + UNW_ARM64_X8 = 8, + UNW_ARM64_X9 = 9, + UNW_ARM64_X10 = 10, + UNW_ARM64_X11 = 11, + UNW_ARM64_X12 = 12, + UNW_ARM64_X13 = 13, + UNW_ARM64_X14 = 14, + UNW_ARM64_X15 = 15, + UNW_ARM64_X16 = 16, + UNW_ARM64_X17 = 17, + UNW_ARM64_X18 = 18, + UNW_ARM64_X19 = 19, + UNW_ARM64_X20 = 20, + UNW_ARM64_X21 = 21, + UNW_ARM64_X22 = 22, + UNW_ARM64_X23 = 23, + UNW_ARM64_X24 = 24, + UNW_ARM64_X25 = 25, + UNW_ARM64_X26 = 26, + UNW_ARM64_X27 = 27, + UNW_ARM64_X28 = 28, + UNW_ARM64_X29 = 29, + UNW_ARM64_FP = 29, + UNW_ARM64_X30 = 30, + UNW_ARM64_LR = 30, + UNW_ARM64_X31 = 31, + UNW_ARM64_SP = 31, + // reserved block + UNW_ARM64_RA_SIGN_STATE = 34, + // reserved block + UNW_ARM64_D0 = 64, + UNW_ARM64_D1 = 65, + UNW_ARM64_D2 = 66, + UNW_ARM64_D3 = 67, + UNW_ARM64_D4 = 68, + UNW_ARM64_D5 = 69, + UNW_ARM64_D6 = 70, + UNW_ARM64_D7 = 71, + UNW_ARM64_D8 = 72, + UNW_ARM64_D9 = 73, + UNW_ARM64_D10 = 74, + UNW_ARM64_D11 = 75, + UNW_ARM64_D12 = 76, + UNW_ARM64_D13 = 77, + UNW_ARM64_D14 = 78, + UNW_ARM64_D15 = 79, + UNW_ARM64_D16 = 80, + UNW_ARM64_D17 = 81, + UNW_ARM64_D18 = 82, + UNW_ARM64_D19 = 83, + UNW_ARM64_D20 = 84, + UNW_ARM64_D21 = 85, + UNW_ARM64_D22 = 86, + UNW_ARM64_D23 = 87, + UNW_ARM64_D24 = 88, + UNW_ARM64_D25 = 89, + UNW_ARM64_D26 = 90, + UNW_ARM64_D27 = 91, + UNW_ARM64_D28 = 92, + UNW_ARM64_D29 = 93, + UNW_ARM64_D30 = 94, + UNW_ARM64_D31 = 95, +}; +// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. +// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3. +// In this scheme, even though the 64-bit floating point registers D0-D31 +// overlap physically with the 32-bit floating pointer registers S0-S31, +// they are given a non-overlapping range of register numbers. +// +// Commented out ranges are not preserved during unwinding. +enum { + UNW_ARM_R0 = 0, + UNW_ARM_R1 = 1, + UNW_ARM_R2 = 2, + UNW_ARM_R3 = 3, + UNW_ARM_R4 = 4, + UNW_ARM_R5 = 5, + UNW_ARM_R6 = 6, + UNW_ARM_R7 = 7, + UNW_ARM_R8 = 8, + UNW_ARM_R9 = 9, + UNW_ARM_R10 = 10, + UNW_ARM_R11 = 11, + UNW_ARM_R12 = 12, + UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP + UNW_ARM_R13 = 13, + UNW_ARM_LR = 14, + UNW_ARM_R14 = 14, + UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP + UNW_ARM_R15 = 15, + // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31. + UNW_ARM_S0 = 64, + UNW_ARM_S1 = 65, + UNW_ARM_S2 = 66, + UNW_ARM_S3 = 67, + UNW_ARM_S4 = 68, + UNW_ARM_S5 = 69, + UNW_ARM_S6 = 70, + UNW_ARM_S7 = 71, + UNW_ARM_S8 = 72, + UNW_ARM_S9 = 73, + UNW_ARM_S10 = 74, + UNW_ARM_S11 = 75, + UNW_ARM_S12 = 76, + UNW_ARM_S13 = 77, + UNW_ARM_S14 = 78, + UNW_ARM_S15 = 79, + UNW_ARM_S16 = 80, + UNW_ARM_S17 = 81, + UNW_ARM_S18 = 82, + UNW_ARM_S19 = 83, + UNW_ARM_S20 = 84, + UNW_ARM_S21 = 85, + UNW_ARM_S22 = 86, + UNW_ARM_S23 = 87, + UNW_ARM_S24 = 88, + UNW_ARM_S25 = 89, + UNW_ARM_S26 = 90, + UNW_ARM_S27 = 91, + UNW_ARM_S28 = 92, + UNW_ARM_S29 = 93, + UNW_ARM_S30 = 94, + UNW_ARM_S31 = 95, + // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP. + // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX) + UNW_ARM_WR0 = 112, + UNW_ARM_WR1 = 113, + UNW_ARM_WR2 = 114, + UNW_ARM_WR3 = 115, + UNW_ARM_WR4 = 116, + UNW_ARM_WR5 = 117, + UNW_ARM_WR6 = 118, + UNW_ARM_WR7 = 119, + UNW_ARM_WR8 = 120, + UNW_ARM_WR9 = 121, + UNW_ARM_WR10 = 122, + UNW_ARM_WR11 = 123, + UNW_ARM_WR12 = 124, + UNW_ARM_WR13 = 125, + UNW_ARM_WR14 = 126, + UNW_ARM_WR15 = 127, + // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} + // 134-143 -- Reserved + // 144-150 -- R8_USR-R14_USR + // 151-157 -- R8_FIQ-R14_FIQ + // 158-159 -- R13_IRQ-R14_IRQ + // 160-161 -- R13_ABT-R14_ABT + // 162-163 -- R13_UND-R14_UND + // 164-165 -- R13_SVC-R14_SVC + // 166-191 -- Reserved + UNW_ARM_WC0 = 192, + UNW_ARM_WC1 = 193, + UNW_ARM_WC2 = 194, + UNW_ARM_WC3 = 195, + // 196-199 -- wC4-wC7 (Intel wireless MMX control) + // 200-255 -- Reserved + UNW_ARM_D0 = 256, + UNW_ARM_D1 = 257, + UNW_ARM_D2 = 258, + UNW_ARM_D3 = 259, + UNW_ARM_D4 = 260, + UNW_ARM_D5 = 261, + UNW_ARM_D6 = 262, + UNW_ARM_D7 = 263, + UNW_ARM_D8 = 264, + UNW_ARM_D9 = 265, + UNW_ARM_D10 = 266, + UNW_ARM_D11 = 267, + UNW_ARM_D12 = 268, + UNW_ARM_D13 = 269, + UNW_ARM_D14 = 270, + UNW_ARM_D15 = 271, + UNW_ARM_D16 = 272, + UNW_ARM_D17 = 273, + UNW_ARM_D18 = 274, + UNW_ARM_D19 = 275, + UNW_ARM_D20 = 276, + UNW_ARM_D21 = 277, + UNW_ARM_D22 = 278, + UNW_ARM_D23 = 279, + UNW_ARM_D24 = 280, + UNW_ARM_D25 = 281, + UNW_ARM_D26 = 282, + UNW_ARM_D27 = 283, + UNW_ARM_D28 = 284, + UNW_ARM_D29 = 285, + UNW_ARM_D30 = 286, + UNW_ARM_D31 = 287, + // 288-319 -- Reserved for VFP/Neon + // 320-8191 -- Reserved + // 8192-16383 -- Unspecified vendor co-processor register. +}; + +// OpenRISC1000 register numbers +enum { + UNW_OR1K_R0 = 0, + UNW_OR1K_R1 = 1, + UNW_OR1K_R2 = 2, + UNW_OR1K_R3 = 3, + UNW_OR1K_R4 = 4, + UNW_OR1K_R5 = 5, + UNW_OR1K_R6 = 6, + UNW_OR1K_R7 = 7, + UNW_OR1K_R8 = 8, + UNW_OR1K_R9 = 9, + UNW_OR1K_R10 = 10, + UNW_OR1K_R11 = 11, + UNW_OR1K_R12 = 12, + UNW_OR1K_R13 = 13, + UNW_OR1K_R14 = 14, + UNW_OR1K_R15 = 15, + UNW_OR1K_R16 = 16, + UNW_OR1K_R17 = 17, + UNW_OR1K_R18 = 18, + UNW_OR1K_R19 = 19, + UNW_OR1K_R20 = 20, + UNW_OR1K_R21 = 21, + UNW_OR1K_R22 = 22, + UNW_OR1K_R23 = 23, + UNW_OR1K_R24 = 24, + UNW_OR1K_R25 = 25, + UNW_OR1K_R26 = 26, + UNW_OR1K_R27 = 27, + UNW_OR1K_R28 = 28, + UNW_OR1K_R29 = 29, + UNW_OR1K_R30 = 30, + UNW_OR1K_R31 = 31, + UNW_OR1K_EPCR = 32, +}; + +// MIPS registers +enum { + UNW_MIPS_R0 = 0, + UNW_MIPS_R1 = 1, + UNW_MIPS_R2 = 2, + UNW_MIPS_R3 = 3, + UNW_MIPS_R4 = 4, + UNW_MIPS_R5 = 5, + UNW_MIPS_R6 = 6, + UNW_MIPS_R7 = 7, + UNW_MIPS_R8 = 8, + UNW_MIPS_R9 = 9, + UNW_MIPS_R10 = 10, + UNW_MIPS_R11 = 11, + UNW_MIPS_R12 = 12, + UNW_MIPS_R13 = 13, + UNW_MIPS_R14 = 14, + UNW_MIPS_R15 = 15, + UNW_MIPS_R16 = 16, + UNW_MIPS_R17 = 17, + UNW_MIPS_R18 = 18, + UNW_MIPS_R19 = 19, + UNW_MIPS_R20 = 20, + UNW_MIPS_R21 = 21, + UNW_MIPS_R22 = 22, + UNW_MIPS_R23 = 23, + UNW_MIPS_R24 = 24, + UNW_MIPS_R25 = 25, + UNW_MIPS_R26 = 26, + UNW_MIPS_R27 = 27, + UNW_MIPS_R28 = 28, + UNW_MIPS_R29 = 29, + UNW_MIPS_R30 = 30, + UNW_MIPS_R31 = 31, + UNW_MIPS_F0 = 32, + UNW_MIPS_F1 = 33, + UNW_MIPS_F2 = 34, + UNW_MIPS_F3 = 35, + UNW_MIPS_F4 = 36, + UNW_MIPS_F5 = 37, + UNW_MIPS_F6 = 38, + UNW_MIPS_F7 = 39, + UNW_MIPS_F8 = 40, + UNW_MIPS_F9 = 41, + UNW_MIPS_F10 = 42, + UNW_MIPS_F11 = 43, + UNW_MIPS_F12 = 44, + UNW_MIPS_F13 = 45, + UNW_MIPS_F14 = 46, + UNW_MIPS_F15 = 47, + UNW_MIPS_F16 = 48, + UNW_MIPS_F17 = 49, + UNW_MIPS_F18 = 50, + UNW_MIPS_F19 = 51, + UNW_MIPS_F20 = 52, + UNW_MIPS_F21 = 53, + UNW_MIPS_F22 = 54, + UNW_MIPS_F23 = 55, + UNW_MIPS_F24 = 56, + UNW_MIPS_F25 = 57, + UNW_MIPS_F26 = 58, + UNW_MIPS_F27 = 59, + UNW_MIPS_F28 = 60, + UNW_MIPS_F29 = 61, + UNW_MIPS_F30 = 62, + UNW_MIPS_F31 = 63, + UNW_MIPS_HI = 64, + UNW_MIPS_LO = 65, +}; + +// SPARC registers +enum { + UNW_SPARC_G0 = 0, + UNW_SPARC_G1 = 1, + UNW_SPARC_G2 = 2, + UNW_SPARC_G3 = 3, + UNW_SPARC_G4 = 4, + UNW_SPARC_G5 = 5, + UNW_SPARC_G6 = 6, + UNW_SPARC_G7 = 7, + UNW_SPARC_O0 = 8, + UNW_SPARC_O1 = 9, + UNW_SPARC_O2 = 10, + UNW_SPARC_O3 = 11, + UNW_SPARC_O4 = 12, + UNW_SPARC_O5 = 13, + UNW_SPARC_O6 = 14, + UNW_SPARC_O7 = 15, + UNW_SPARC_L0 = 16, + UNW_SPARC_L1 = 17, + UNW_SPARC_L2 = 18, + UNW_SPARC_L3 = 19, + UNW_SPARC_L4 = 20, + UNW_SPARC_L5 = 21, + UNW_SPARC_L6 = 22, + UNW_SPARC_L7 = 23, + UNW_SPARC_I0 = 24, + UNW_SPARC_I1 = 25, + UNW_SPARC_I2 = 26, + UNW_SPARC_I3 = 27, + UNW_SPARC_I4 = 28, + UNW_SPARC_I5 = 29, + UNW_SPARC_I6 = 30, + UNW_SPARC_I7 = 31, +}; + +// Hexagon register numbers +enum { + UNW_HEXAGON_R0, + UNW_HEXAGON_R1, + UNW_HEXAGON_R2, + UNW_HEXAGON_R3, + UNW_HEXAGON_R4, + UNW_HEXAGON_R5, + UNW_HEXAGON_R6, + UNW_HEXAGON_R7, + UNW_HEXAGON_R8, + UNW_HEXAGON_R9, + UNW_HEXAGON_R10, + UNW_HEXAGON_R11, + UNW_HEXAGON_R12, + UNW_HEXAGON_R13, + UNW_HEXAGON_R14, + UNW_HEXAGON_R15, + UNW_HEXAGON_R16, + UNW_HEXAGON_R17, + UNW_HEXAGON_R18, + UNW_HEXAGON_R19, + UNW_HEXAGON_R20, + UNW_HEXAGON_R21, + UNW_HEXAGON_R22, + UNW_HEXAGON_R23, + UNW_HEXAGON_R24, + UNW_HEXAGON_R25, + UNW_HEXAGON_R26, + UNW_HEXAGON_R27, + UNW_HEXAGON_R28, + UNW_HEXAGON_R29, + UNW_HEXAGON_R30, + UNW_HEXAGON_R31, + UNW_HEXAGON_P3_0, + UNW_HEXAGON_PC, +}; + +// RISC-V registers. These match the DWARF register numbers defined by section +// 4 of the RISC-V ELF psABI specification, which can be found at: +// +// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md +enum { + UNW_RISCV_X0 = 0, + UNW_RISCV_X1 = 1, + UNW_RISCV_X2 = 2, + UNW_RISCV_X3 = 3, + UNW_RISCV_X4 = 4, + UNW_RISCV_X5 = 5, + UNW_RISCV_X6 = 6, + UNW_RISCV_X7 = 7, + UNW_RISCV_X8 = 8, + UNW_RISCV_X9 = 9, + UNW_RISCV_X10 = 10, + UNW_RISCV_X11 = 11, + UNW_RISCV_X12 = 12, + UNW_RISCV_X13 = 13, + UNW_RISCV_X14 = 14, + UNW_RISCV_X15 = 15, + UNW_RISCV_X16 = 16, + UNW_RISCV_X17 = 17, + UNW_RISCV_X18 = 18, + UNW_RISCV_X19 = 19, + UNW_RISCV_X20 = 20, + UNW_RISCV_X21 = 21, + UNW_RISCV_X22 = 22, + UNW_RISCV_X23 = 23, + UNW_RISCV_X24 = 24, + UNW_RISCV_X25 = 25, + UNW_RISCV_X26 = 26, + UNW_RISCV_X27 = 27, + UNW_RISCV_X28 = 28, + UNW_RISCV_X29 = 29, + UNW_RISCV_X30 = 30, + UNW_RISCV_X31 = 31, + UNW_RISCV_F0 = 32, + UNW_RISCV_F1 = 33, + UNW_RISCV_F2 = 34, + UNW_RISCV_F3 = 35, + UNW_RISCV_F4 = 36, + UNW_RISCV_F5 = 37, + UNW_RISCV_F6 = 38, + UNW_RISCV_F7 = 39, + UNW_RISCV_F8 = 40, + UNW_RISCV_F9 = 41, + UNW_RISCV_F10 = 42, + UNW_RISCV_F11 = 43, + UNW_RISCV_F12 = 44, + UNW_RISCV_F13 = 45, + UNW_RISCV_F14 = 46, + UNW_RISCV_F15 = 47, + UNW_RISCV_F16 = 48, + UNW_RISCV_F17 = 49, + UNW_RISCV_F18 = 50, + UNW_RISCV_F19 = 51, + UNW_RISCV_F20 = 52, + UNW_RISCV_F21 = 53, + UNW_RISCV_F22 = 54, + UNW_RISCV_F23 = 55, + UNW_RISCV_F24 = 56, + UNW_RISCV_F25 = 57, + UNW_RISCV_F26 = 58, + UNW_RISCV_F27 = 59, + UNW_RISCV_F28 = 60, + UNW_RISCV_F29 = 61, + UNW_RISCV_F30 = 62, + UNW_RISCV_F31 = 63, +}; #endif - diff --git a/libunwind/include/mach-o/compact_unwind_encoding.h b/libunwind/include/mach-o/compact_unwind_encoding.h index aa7f6db..a3036e8 100644 --- a/libunwind/include/mach-o/compact_unwind_encoding.h +++ b/libunwind/include/mach-o/compact_unwind_encoding.h @@ -1,56 +1,41 @@ -/* -*- mode: C; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2008-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===------------------ mach-o/compact_unwind_encoding.h ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Darwin's alternative to DWARF based unwind encodings. +// +//===----------------------------------------------------------------------===// + #ifndef __COMPACT_UNWIND_ENCODING__ #define __COMPACT_UNWIND_ENCODING__ #include - - // -// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section -// of object files. Or compilers can emit compact unwind information in +// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section +// of object files. Or compilers can emit compact unwind information in // the __LD,__compact_unwind section. // -// When the linker creates a final linked image, it will create a -// __TEXT,__unwind_info section. This section is a small and fast way for the -// runtime to access unwind info for any given function. If the compiler emitted -// compact unwind info for the function, that compact unwind info will be encoded -// in the __TEXT,__unwind_info section. If the compiler emitted dwarf unwind info, -// the __TEXT,__unwind_info section will contain the offset of the FDE in the -// __TEXT,__eh_frame section in the final linked image. +// When the linker creates a final linked image, it will create a +// __TEXT,__unwind_info section. This section is a small and fast way for the +// runtime to access unwind info for any given function. If the compiler +// emitted compact unwind info for the function, that compact unwind info will +// be encoded in the __TEXT,__unwind_info section. If the compiler emitted +// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset +// of the FDE in the __TEXT,__eh_frame section in the final linked image. // -// Note: Previously, the linker would transform some dwarf unwind infos into +// Note: Previously, the linker would transform some DWARF unwind infos into // compact unwind info. But that is fragile and no longer done. // -// The compact unwind endoding is a 32-bit value which encoded in an architecture -// specific way, which registers to restore from where, and how to unwind out -// of the function. +// The compact unwind endoding is a 32-bit value which encoded in an +// architecture specific way, which registers to restore from where, and how +// to unwind out of the function. // typedef uint32_t compact_unwind_encoding_t; @@ -72,7 +57,7 @@ enum { // 1-bit: has lsda // 2-bit: personality index // -// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf +// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF // ebp based: // 15-bits (5*3-bits per reg) register permutation // 8-bits for stack offset @@ -88,15 +73,15 @@ enum { UNWIND_X86_MODE_STACK_IMMD = 0x02000000, UNWIND_X86_MODE_STACK_IND = 0x03000000, UNWIND_X86_MODE_DWARF = 0x04000000, - + UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, - + UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, - + UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, }; @@ -113,26 +98,26 @@ enum { // // For x86 there are four modes for the compact unwind encoding: // UNWIND_X86_MODE_EBP_FRAME: -// EBP based frame where EBP is push on stack immediately after return address, -// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current -// EPB value, then EBP is restored by popping off the stack, and the return +// EBP based frame where EBP is push on stack immediately after return address, +// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current +// EPB value, then EBP is restored by popping off the stack, and the return // is done by popping the stack once more into the pc. // All non-volatile registers that need to be restored must have been saved -// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4 +// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4 // is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved // are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries. -// Each entry contains which register to restore. +// Each entry contains which register to restore. // UNWIND_X86_MODE_STACK_IMMD: // A "frameless" (EBP not used as frame pointer) function with a small -// constant stack size. To return, a constant (encoded in the compact -// unwind encoding) is added to the ESP. Then the return is done by +// constant stack size. To return, a constant (encoded in the compact +// unwind encoding) is added to the ESP. Then the return is done by // popping the stack into the pc. // All non-volatile registers that need to be restored must have been saved // on the stack immediately after the return address. The stack_size/4 is // encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024). // The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT. // UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were -// saved and their order. +// saved and their order. // UNWIND_X86_MODE_STACK_IND: // A "frameless" (EBP not used as frame pointer) function large constant // stack size. This case is like the previous, except the stack size is too @@ -142,11 +127,15 @@ enum { // UNWIND_X86_FRAMELESS_STACK_SIZE. // UNWIND_X86_MODE_DWARF: // No compact unwind encoding is available. Instead the low 24-bits of the -// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. // This mode is never used in object files. It is only generated by the -// linker in final linked images which have only dwarf unwind info for a +// linker in final linked images which have only DWARF unwind info for a // function. // +// The permutation encoding is a Lehmer code sequence encoded into a +// single variable-base number so we can encode the ordering of up to +// six registers in a 10-bit space. +// // The following is the algorithm used to create the permutation encoding used // with frameless stacks. It is passed the number of registers to be saved and // an array of the register numbers saved. @@ -165,21 +154,21 @@ enum { // uint32_t permutationEncoding = 0; // switch ( registerCount ) { // case 6: -// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] -// + 6*renumregs[2] + 2*renumregs[3] +// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] +// + 6*renumregs[2] + 2*renumregs[3] // + renumregs[4]); // break; // case 5: -// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] -// + 6*renumregs[3] + 2*renumregs[4] +// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] +// + 6*renumregs[3] + 2*renumregs[4] // + renumregs[5]); // break; // case 4: -// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] +// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] // + 3*renumregs[4] + renumregs[5]); // break; // case 3: -// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] +// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] // + renumregs[5]); // break; // case 2: @@ -203,7 +192,7 @@ enum { // 1-bit: has lsda // 2-bit: personality index // -// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf +// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF // rbp based: // 15-bits (5*3-bits per reg) register permutation // 8-bits for stack offset @@ -219,7 +208,7 @@ enum { UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, UNWIND_X86_64_MODE_STACK_IND = 0x03000000, UNWIND_X86_64_MODE_DWARF = 0x04000000, - + UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, @@ -243,12 +232,12 @@ enum { // // For x86_64 there are four modes for the compact unwind encoding: // UNWIND_X86_64_MODE_RBP_FRAME: -// RBP based frame where RBP is push on stack immediately after return address, +// RBP based frame where RBP is push on stack immediately after return address, // then RSP is moved to RBP. Thus, to unwind RSP is restored with the current // EPB value, then RBP is restored by popping off the stack, and the return // is done by popping the stack once more into the pc. // All non-volatile registers that need to be restored must have been saved -// in a small range in the stack that starts RBP-8 to RBP-1020. The offset/4 +// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8 // is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved // are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries. // Each entry contains which register to restore. @@ -258,8 +247,8 @@ enum { // unwind encoding) is added to the RSP. Then the return is done by // popping the stack into the pc. // All non-volatile registers that need to be restored must have been saved -// on the stack immediately after the return address. The stack_size/4 is -// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 1024). +// on the stack immediately after the return address. The stack_size/8 is +// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048). // The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT. // UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were // saved and their order. @@ -272,13 +261,75 @@ enum { // UNWIND_X86_64_FRAMELESS_STACK_SIZE. // UNWIND_X86_64_MODE_DWARF: // No compact unwind encoding is available. Instead the low 24-bits of the -// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. // This mode is never used in object files. It is only generated by the -// linker in final linked images which have only dwarf unwind info for a +// linker in final linked images which have only DWARF unwind info for a // function. // +// ARM64 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 4=frame-based, 3=DWARF, 2=frameless +// frameless: +// 12-bits of stack size +// frame-based: +// 4-bits D reg pairs saved +// 5-bits X reg pairs saved +// DWARF: +// 24-bits offset of DWARF FDE in __eh_frame section +// +enum { + UNWIND_ARM64_MODE_MASK = 0x0F000000, + UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, + UNWIND_ARM64_MODE_DWARF = 0x03000000, + UNWIND_ARM64_MODE_FRAME = 0x04000000, + + UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, + UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, + UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, + UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, + UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, + UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, + UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, + UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, + UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, + + UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, + UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; +// For arm64 there are three modes for the compact unwind encoding: +// UNWIND_ARM64_MODE_FRAME: +// This is a standard arm64 prolog where FP/LR are immediately pushed on the +// stack, then SP is copied to FP. If there are any non-volatile registers +// saved, then are copied into the stack frame in pairs in a contiguous +// range right below the saved FP/LR pair. Any subset of the five X pairs +// and four D pairs can be saved, but the memory layout must be in register +// number order. +// UNWIND_ARM64_MODE_FRAMELESS: +// A "frameless" leaf function, where FP/LR are not saved. The return address +// remains in LR throughout the function. If any non-volatile registers +// are saved, they must be pushed onto the stack before any stack space is +// allocated for local variables. The stack sized (including any saved +// non-volatile registers) divided by 16 is encoded in the bits +// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. +// UNWIND_ARM64_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only DWARF unwind info for a +// function. +// + + + + + + //////////////////////////////////////////////////////////////////////////////// // @@ -294,7 +345,7 @@ enum { // This section is a table, initially with one row per function (that needs // unwind info). The table columns and some conceptual entries are: // -// range-start pointer to start of function/range +// range-start pointer to start of function/range // range-length // compact-unwind-encoding 32-bit encoding // personality-function or zero if no personality function @@ -335,7 +386,7 @@ enum { // saved at that range of the function. // // If a particular function is so wacky that there is no compact unwind way -// to encode it, then the compiler can emit traditional dwarf unwind info. +// to encode it, then the compiler can emit traditional DWARF unwind info. // The runtime will use which ever is available. // // Runtime support for compact unwind encodings are only available on 10.6 @@ -367,19 +418,19 @@ struct unwind_info_section_header uint32_t indexSectionOffset; uint32_t indexCount; // compact_unwind_encoding_t[] - // uintptr_t personalities[] + // uint32_t personalities[] // unwind_info_section_header_index_entry[] // unwind_info_section_header_lsda_index_entry[] }; -struct unwind_info_section_header_index_entry +struct unwind_info_section_header_index_entry { uint32_t functionOffset; uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range }; -struct unwind_info_section_header_lsda_index_entry +struct unwind_info_section_header_lsda_index_entry { uint32_t functionOffset; uint32_t lsdaOffset; @@ -389,10 +440,10 @@ struct unwind_info_section_header_lsda_index_entry // There are two kinds of second level index pages: regular and compressed. // A compressed page can hold up to 1021 entries, but it cannot be used // if too many different encoding types are used. The regular page holds -// 511 entries. +// 511 entries. // -struct unwind_info_regular_second_level_entry +struct unwind_info_regular_second_level_entry { uint32_t functionOffset; compact_unwind_encoding_t encoding; @@ -415,7 +466,7 @@ struct unwind_info_compressed_second_level_page_header uint16_t entryCount; uint16_t encodingsPageOffset; uint16_t encodingsCount; - // 32-bit entry array + // 32-bit entry array // encodings array }; diff --git a/libunwind/include/mach-o/compact_unwind_encoding.modulemap b/libunwind/include/mach-o/compact_unwind_encoding.modulemap new file mode 100644 index 0000000..3b838b8 --- /dev/null +++ b/libunwind/include/mach-o/compact_unwind_encoding.modulemap @@ -0,0 +1,4 @@ +module MachO.compact_unwind_encoding [system] [extern_c] { + header "compact_unwind_encoding.h" + export * +} diff --git a/libunwind/include/unwind.h b/libunwind/include/unwind.h index e99bf8d..1d3444c 100644 --- a/libunwind/include/unwind.h +++ b/libunwind/include/unwind.h @@ -1,99 +1,159 @@ -/* -*- mode: C++; c-basic-offset: 4; -*- - * - * Copyright (c) 2010-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * - * C interface to libuwind - * - * Source compatible with Level 1 Base ABI documented at: - * http://www.codesourcery.com/public/cxx-abi/abi-eh.html - * - */ - +//===------------------------------- unwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// C++ ABI Level 1 ABI documented at: +// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// #ifndef __UNWIND_H__ #define __UNWIND_H__ +#include <__libunwind_config.h> + #include #include -#include +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32) +#include +#include +#endif + +#if defined(__APPLE__) +#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) +#else +#define LIBUNWIND_UNAVAIL +#endif typedef enum { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8 + _URC_NO_REASON = 0, + _URC_OK = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, +#if defined(_LIBUNWIND_ARM_EHABI) + _URC_FAILURE = 9 +#endif } _Unwind_Reason_Code; typedef enum { - _UA_SEARCH_PHASE = 1, - _UA_CLEANUP_PHASE = 2, - _UA_HANDLER_FRAME = 4, - _UA_FORCE_UNWIND = 8, - _UA_END_OF_STACK = 16 // gcc extension to C++ ABI + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16 // gcc extension to C++ ABI } _Unwind_Action; +typedef struct _Unwind_Context _Unwind_Context; // opaque -struct _Unwind_Context; // opaque -struct _Unwind_Exception; // forward declaration +#if defined(_LIBUNWIND_ARM_EHABI) +typedef uint32_t _Unwind_State; -struct _Unwind_Exception { - uint64_t exception_class; - void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc); - uintptr_t private_1; // non-zero means forced unwind - uintptr_t private_2; // holds sp that phase1 found for phase2 to use -#if !__LP64__ - // The gcc implementation of _Unwind_Exception used attribute mode on the above fields - // which had the side effect of causing this whole struct to round up to 32 bytes in size. - // To be more explicit, we add pad fields added for binary compatibility. - uint32_t reserved[3]; -#endif -}; +static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; +static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1; +static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; +static const _Unwind_State _US_ACTION_MASK = 3; +/* Undocumented flag for force unwinding. */ +static const _Unwind_State _US_FORCE_UNWIND = 8; +typedef uint32_t _Unwind_EHT_Header; + +struct _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ + +struct _Unwind_Control_Block { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*); + + /* Unwinder cache, private fields for the unwinder's use */ + struct { + uint32_t reserved1; /* init reserved1 to 0, then don't touch */ + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + uint32_t reserved5; + } unwinder_cache; + + /* Propagation barrier cache (valid after phase 1): */ + struct { + uint32_t sp; + uint32_t bitpattern[5]; + } barrier_cache; + + /* Cleanup cache (preserved over cleanup): */ + struct { + uint32_t bitpattern[4]; + } cleanup_cache; + + /* Pr cache (for pr's benefit): */ + struct { + uint32_t fnstart; /* function start address */ + _Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */ + uint32_t additional; + uint32_t reserved1; + } pr_cache; + + long long int :0; /* Enforce the 8-byte alignment */ +} __attribute__((__aligned__(8))); typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) - (int version, - _Unwind_Action actions, - uint64_t exceptionClass, - struct _Unwind_Exception* exceptionObject, - struct _Unwind_Context* context, - void* stop_parameter ); + (_Unwind_State state, + _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context); +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( + _Unwind_State state, _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context); +#else +struct _Unwind_Context; // opaque +struct _Unwind_Exception; // forward declaration +typedef struct _Unwind_Exception _Unwind_Exception; -typedef _Unwind_Reason_Code (*__personality_routine) - (int version, - _Unwind_Action actions, - uint64_t exceptionClass, - struct _Unwind_Exception* exceptionObject, - struct _Unwind_Context* context); - +struct _Unwind_Exception { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code reason, + _Unwind_Exception *exc); +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) + uintptr_t private_[6]; +#else + uintptr_t private_1; // non-zero means forced unwind + uintptr_t private_2; // holds sp that phase1 found for phase2 to use +#endif +#if __SIZEOF_POINTER__ == 4 + // The implementation of _Unwind_Exception uses an attribute mode on the + // above fields which has the side effect of causing this whole struct to + // round up to 32 bytes in size (48 with SEH). To be more explicit, we add + // pad fields added for binary compatibility. + uint32_t reserved[3]; +#endif + // The Itanium ABI requires that _Unwind_Exception objects are "double-word + // aligned". GCC has interpreted this to mean "use the maximum useful + // alignment for the target"; so do we. +} __attribute__((__aligned__)); + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int version, + _Unwind_Action actions, + uint64_t exceptionClass, + _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context, + void* stop_parameter ); + +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( + int version, _Unwind_Action actions, uint64_t exceptionClass, + _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); +#endif - #ifdef __cplusplus extern "C" { #endif @@ -101,132 +161,235 @@ extern "C" { // // The following are the base functions documented by the C++ ABI // -#if __arm__ - extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object); - extern void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object); +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object); #else - extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object); - extern void _Unwind_Resume(struct _Unwind_Exception* exception_object); +extern _Unwind_Reason_Code + _Unwind_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_Resume(_Unwind_Exception *exception_object); #endif -extern void _Unwind_DeleteException(struct _Unwind_Exception* exception_object); -extern uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index); -extern void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value); -extern uintptr_t _Unwind_GetIP(struct _Unwind_Context* context); -extern void _Unwind_SetIP(struct _Unwind_Context*, uintptr_t new_value); -extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context); -extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context); -#if __arm__ - extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter ); -#else - extern _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter ); +extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); + +#if defined(_LIBUNWIND_ARM_EHABI) +typedef enum { + _UVRSC_CORE = 0, /* integer register */ + _UVRSC_VFP = 1, /* vfp */ + _UVRSC_WMMXD = 3, /* Intel WMMX data register */ + _UVRSC_WMMXC = 4 /* Intel WMMX control register */ +} _Unwind_VRS_RegClass; + +typedef enum { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5 +} _Unwind_VRS_DataRepresentation; + +typedef enum { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2 +} _Unwind_VRS_Result; + +extern void _Unwind_Complete(_Unwind_Exception* exception_object); + +extern _Unwind_VRS_Result +_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep); + +extern _Unwind_VRS_Result +_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep); + +extern _Unwind_VRS_Result +_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t discriminator, + _Unwind_VRS_DataRepresentation representation); +#endif + +#if !defined(_LIBUNWIND_ARM_EHABI) + +extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); +extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value); +extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); +extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); + +#else // defined(_LIBUNWIND_ARM_EHABI) + +#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) +#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern +#else +#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__ +#endif + +// These are de facto helper functions for ARM, which delegate the function +// calls to _Unwind_VRS_Get/Set(). These are not a part of ARM EHABI +// specification, thus these function MUST be inlined. Please don't replace +// these with the "extern" function declaration; otherwise, the program +// including this header won't be ABI compatible and will result in +// link error when we are linking the program with libgcc. + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) { + uintptr_t value = 0; + _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); + return value; +} + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t value) { + _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); +} + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + // remove the thumb-bit before returning + return _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1); +} + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { + uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1); + _Unwind_SetGR(context, 15, value | thumb_bit); +} +#endif // defined(_LIBUNWIND_ARM_EHABI) + +extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); +extern uintptr_t + _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter); +#else +extern _Unwind_Reason_Code + _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter); +#endif + +#ifdef __USING_SJLJ_EXCEPTIONS__ +typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t; +extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); +extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); #endif -#if __arm__ - typedef struct _Unwind_FunctionContext* _Unwind_FunctionContext_t; - extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); - extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); -#endif - // // The following are semi-suppoted extensions to the C++ ABI // - // -// called by __cxa_rethrow(). +// called by __cxa_rethrow(). // -#if __arm__ - extern _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object); +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object); #else - extern _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object); +extern _Unwind_Reason_Code + _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object); #endif - -// -// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the +// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the // _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack // or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON. -// -typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*); -extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*); +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, + void *); +extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); + +// _Unwind_GetCFA is a gcc extension that can be called from within a +// personality handler to get the CFA (stack pointer before call) of +// current frame. +extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *); -// -// _Unwind_GetCFA is a gcc extension that can be called from within a personality -// handler to get the CFA (stack pointer before call) of current frame. -// -extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context*); +// _Unwind_GetIPInfo is a gcc extension that can be called from within a +// personality handler. Similar to _Unwind_GetIP() but also returns in +// *ipBefore a non-zero value if the instruction pointer is at or before the +// instruction causing the unwind. Normally, in a function call, the IP returned +// is the return address which is after the call instruction and may be past the +// end of the function containing the call instruction. +extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore); -// -// _Unwind_GetIPInfo is a gcc extension that can be called from within a personality -// handler. Similar to _Unwind_GetIP() but also returns in *ipBefore a non-zero -// value if the instruction pointer is at or before the instruction causing -// the unwind. Normally, in a function call, the IP returned is the return address -// which is after the call instruction and may be past the end of the function -// containing the call instruction. -// -extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore); +// __register_frame() is used with dynamically generated code to register the +// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point +// to its function and optional LSDA. +// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and +// 10.5 it was buggy and did not actually register the FDE with the unwinder. +// In 10.6 and later it does register properly. +extern void __register_frame(const void *fde); +extern void __deregister_frame(const void *fde); - -// -// __register_frame() is used with dynamically generated code to register the FDE -// for a generated (JIT) code. The FDE must use pc-rel addressing to point to its -// function and optional LSDA. __register_frame() has existed in all versions of -// Mac OS X, but in 10.4 and 10.5 it was buggy and did not actually register the -// FDE with the unwinder. In 10.6 and later it does register properly. -// -extern void __register_frame(const void* fde); -extern void __deregister_frame(const void* fde); - - -// // _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has -// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind info" -// which the runtime uses in preference to dwarf unwind info. This function -// will only work if the target function has an FDE but no compact unwind info. -// -struct dwarf_eh_bases -{ - uintptr_t tbase; - uintptr_t dbase; - uintptr_t func; +// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind +// info" which the runtime uses in preference to DWARF unwind info. This +// function will only work if the target function has an FDE but no compact +// unwind info. +struct dwarf_eh_bases { + uintptr_t tbase; + uintptr_t dbase; + uintptr_t func; }; -extern const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases*); +extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *); -// // This function attempts to find the start (address of first instruction) of -// a function given an address inside the function. It only works if the function -// has an FDE (dwarf unwind info). +// a function given an address inside the function. It only works if the +// function has an FDE (DWARF unwind info). // This function is unimplemented on Mac OS X 10.6 and later. Instead, use // _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result. -extern void* _Unwind_FindEnclosingFunction(void* pc); +extern void *_Unwind_FindEnclosingFunction(void *pc); +// Mac OS X does not support text-rel and data-rel addressing so these functions +// are unimplemented +extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) + LIBUNWIND_UNAVAIL; +extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) + LIBUNWIND_UNAVAIL; -// Mac OS X does not support text-rel and data-rel addressing so these functions are unimplemented -extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) __attribute__((unavailable)); -extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) __attribute__((unavailable)); - - - -// Mac OS X 10.4 and 10.5 had implementations of these functions in libgcc_s.dylib, -// but they never worked. These functions are no longer available. -extern void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db) __attribute__((unavailable)); -extern void __register_frame_info(const void* fde, void* ob) __attribute__((unavailable)); -extern void __register_frame_info_table_bases(const void* fde, void* ob,void* tb, void* db) __attribute__((unavailable)); -extern void __register_frame_info_table(const void* fde, void* ob) __attribute__((unavailable)); -extern void __register_frame_table(const void* fde) __attribute__((unavailable)); -extern void* __deregister_frame_info(const void* fde) __attribute__((unavailable)); -extern void* __deregister_frame_info_bases(const void* fde) __attribute__((unavailable)); +// Mac OS X 10.4 and 10.5 had implementations of these functions in +// libgcc_s.dylib, but they never worked. +/// These functions are no longer available on Mac OS X. +extern void __register_frame_info_bases(const void *fde, void *ob, void *tb, + void *db) LIBUNWIND_UNAVAIL; +extern void __register_frame_info(const void *fde, void *ob) + LIBUNWIND_UNAVAIL; +extern void __register_frame_info_table_bases(const void *fde, void *ob, + void *tb, void *db) + LIBUNWIND_UNAVAIL; +extern void __register_frame_info_table(const void *fde, void *ob) + LIBUNWIND_UNAVAIL; +extern void __register_frame_table(const void *fde) + LIBUNWIND_UNAVAIL; +extern void *__deregister_frame_info(const void *fde) + LIBUNWIND_UNAVAIL; +extern void *__deregister_frame_info_bases(const void *fde) + LIBUNWIND_UNAVAIL; +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#ifndef _WIN32 +typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; +typedef struct _CONTEXT CONTEXT; +typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; +#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 +typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; +#endif +// This is the common wrapper for GCC-style personality functions with SEH. +extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc, + void *frame, CONTEXT *ctx, + DISPATCHER_CONTEXT *disp, + _Unwind_Personality_Fn pers); +#endif #ifdef __cplusplus } #endif - - #endif // __UNWIND_H__ - - diff --git a/libunwind/libunwind.order b/libunwind/libunwind.order deleted file mode 100644 index 7f66eb7..0000000 --- a/libunwind/libunwind.order +++ /dev/null @@ -1,27 +0,0 @@ -__Unwind_RaiseException -_unw_getcontext -_unw_init_local -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE24setInfoBasedOnIPRegisterEb -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE6getRegEi -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE33getInfoFromCompactEncodingSectionEyyy -_unw_step -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE4stepEv -x86_64:__ZN9libunwind22CompactUnwinder_x86_64INS_17LocalAddressSpaceEE23stepWithCompactEncodingEjyRS1_RNS_16Registers_x86_64E -x86_64:__ZN9libunwind22CompactUnwinder_x86_64INS_17LocalAddressSpaceEE31stepWithCompactEncodingRBPFrameEjyRS1_RNS_16Registers_x86_64E -_unw_get_proc_info -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE7getInfoEP15unw_proc_info_t -__Unwind_GetLanguageSpecificData -__Unwind_GetRegionStart -__Unwind_GetIP -_unw_get_reg -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE8validRegEi -_unwind_phase2 -__Unwind_SetGR -_unw_set_reg -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE6setRegEiy -__Unwind_SetIP -_unw_resume -x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE6jumptoEv -x86_64:__ZN9libunwind16Registers_x86_646jumptoEv -__Unwind_DeleteException - diff --git a/libunwind/libunwind.xcodeproj/project.pbxproj b/libunwind/libunwind.xcodeproj/project.pbxproj deleted file mode 100644 index d13e6fe..0000000 --- a/libunwind/libunwind.xcodeproj/project.pbxproj +++ /dev/null @@ -1,546 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 45; - objects = { - -/* Begin PBXAggregateTarget section */ - F93A98ED0EC91269000D227E /* all */ = { - isa = PBXAggregateTarget; - buildConfigurationList = F93A98F70EC91298000D227E /* Build configuration list for PBXAggregateTarget "all" */; - buildPhases = ( - F97377A8133A82A600BDE64E /* Simulator clean up */, - ); - dependencies = ( - F992F1FB11A35E2F0008F9B0 /* PBXTargetDependency */, - F93A98F50EC9127A000D227E /* PBXTargetDependency */, - ); - name = all; - productName = macosx; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - F9276EFD0E6E0B6100B731C9 /* libuwind.cxx in Sources */ = {isa = PBXBuildFile; fileRef = F98BEABC0D121A4000F298D0 /* libuwind.cxx */; }; - F9276EFE0E6E0B6100B731C9 /* UnwindLevel1.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */; }; - F9276F000E6E0B6100B731C9 /* Registers.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA710D10CC1700F298D0 /* Registers.s */; }; - F9276F010E6E0B6100B731C9 /* unw_getcontext.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */; }; - F9276F280E6E0D1400B731C9 /* UnwindLevel1-gcc-ext.c in Sources */ = {isa = PBXBuildFile; fileRef = F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */; }; - F92A25C413C69AEE008F010E /* libunwind.h in install usr-include */ = {isa = PBXBuildFile; fileRef = F98BE9080D0F3D7D00F298D0 /* libunwind.h */; }; - F92A25C513C69AEE008F010E /* unwind.h in install usr-include */ = {isa = PBXBuildFile; fileRef = F9ABAAA91118B2BB00A06182 /* unwind.h */; }; - F92A25C913C69B39008F010E /* compact_unwind_encoding.h in install usr-include-mach-o */ = {isa = PBXBuildFile; fileRef = F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */; }; - F938B7C70F97F50D0096ACC8 /* Unwind-sjlj.c in Sources */ = {isa = PBXBuildFile; fileRef = F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */; }; - F95A3D8B0DE3A8AA004B72E5 /* libuwind.cxx in Sources */ = {isa = PBXBuildFile; fileRef = F98BEABC0D121A4000F298D0 /* libuwind.cxx */; settings = {COMPILER_FLAGS = "-fno-exceptions"; }; }; - F95A3D8C0DE3A8AA004B72E5 /* Registers.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA710D10CC1700F298D0 /* Registers.s */; }; - F95A3D8D0DE3A8AA004B72E5 /* unw_getcontext.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */; }; - F95A3D8E0DE3A8AA004B72E5 /* UnwindLevel1.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */; }; - F95A3D8F0DE3A8AA004B72E5 /* UnwindLevel1-gcc-ext.c in Sources */ = {isa = PBXBuildFile; fileRef = F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */; }; - F98F98F311A47E2C00D21E1F /* Unwind-sjlj.c in Sources */ = {isa = PBXBuildFile; fileRef = F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - F93A98F40EC9127A000D227E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = F9276EFA0E6E0B6100B731C9; - remoteInfo = "dyld-libunwind"; - }; - F992F1FA11A35E2F0008F9B0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = F95A3D890DE3A8AA004B72E5; - remoteInfo = "libunwind-system"; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - F92A25CA13C69B62008F010E /* install usr-include */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/include"; - dstSubfolderSpec = 0; - files = ( - F92A25C413C69AEE008F010E /* libunwind.h in install usr-include */, - F92A25C513C69AEE008F010E /* unwind.h in install usr-include */, - ); - name = "install usr-include"; - runOnlyForDeploymentPostprocessing = 1; - }; - F92A25CB13C69B62008F010E /* install usr-include-mach-o */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/include/mach-o"; - dstSubfolderSpec = 0; - files = ( - F92A25C913C69B39008F010E /* compact_unwind_encoding.h in install usr-include-mach-o */, - ); - name = "install usr-include-mach-o"; - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "UnwindLevel1-gcc-ext.c"; path = "src/UnwindLevel1-gcc-ext.c"; sourceTree = ""; }; - F9276F140E6E0B6100B731C9 /* libunwind.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libunwind.a; sourceTree = BUILT_PRODUCTS_DIR; }; - F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = UnwindLevel1.c; path = src/UnwindLevel1.c; sourceTree = ""; }; - F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "Unwind-sjlj.c"; path = "src/Unwind-sjlj.c"; sourceTree = ""; }; - F94138D00D1C7AC600B5EA0C /* dwarf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2.h; path = src/dwarf2.h; sourceTree = ""; }; - F94139850D25A12200B5EA0C /* UnwindCursor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = UnwindCursor.hpp; path = src/UnwindCursor.hpp; sourceTree = ""; }; - F9413A530D25D7E100B5EA0C /* AddressSpace.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = AddressSpace.hpp; path = src/AddressSpace.hpp; sourceTree = ""; }; - F9413A540D25D7E100B5EA0C /* Registers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Registers.hpp; path = src/Registers.hpp; sourceTree = ""; }; - F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libunwind.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; - F95BE2990D2EB9EA007E3672 /* DwarfInstructions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DwarfInstructions.hpp; path = src/DwarfInstructions.hpp; sourceTree = ""; }; - F95BE31A0D2EED80007E3672 /* CompactUnwinder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CompactUnwinder.hpp; path = src/CompactUnwinder.hpp; sourceTree = ""; }; - F95BE4DC0D343AB9007E3672 /* DwarfParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DwarfParser.hpp; path = src/DwarfParser.hpp; sourceTree = ""; }; - F95DF59A0DEDD12800B8DA7A /* InternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InternalMacros.h; path = src/InternalMacros.h; sourceTree = ""; }; - F98BE9080D0F3D7D00F298D0 /* libunwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libunwind.h; path = include/libunwind.h; sourceTree = ""; }; - F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = unw_getcontext.s; path = src/unw_getcontext.s; sourceTree = ""; }; - F98BEA710D10CC1700F298D0 /* Registers.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = Registers.s; path = src/Registers.s; sourceTree = ""; }; - F98BEABC0D121A4000F298D0 /* libuwind.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = libuwind.cxx; path = src/libuwind.cxx; sourceTree = ""; }; - F98BEAC40D121B7800F298D0 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/FileAbstraction.hpp; sourceTree = ""; }; - F98F98E311A475B300D21E1F /* libunwind.order */ = {isa = PBXFileReference; explicitFileType = sourcecode.exports; fileEncoding = 4; path = libunwind.order; sourceTree = ""; }; - F9AB4BC61194E18500F870C2 /* libunwind_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libunwind_priv.h; path = src/libunwind_priv.h; sourceTree = ""; }; - F9ABAAA91118B2BB00A06182 /* unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unwind.h; path = include/unwind.h; sourceTree = ""; }; - F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compact_unwind_encoding.h; path = "include/mach-o/compact_unwind_encoding.h"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - F95A3D900DE3A8AA004B72E5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 08FB7794FE84155DC02AAC07 /* libunwind */ = { - isa = PBXGroup; - children = ( - F90DFABC0D8A1E9B003302A1 /* include */, - 08FB7795FE84155DC02AAC07 /* src */, - 1AB674ADFE9D54B511CA2CBB /* Products */, - ); - name = libunwind; - sourceTree = ""; - }; - 08FB7795FE84155DC02AAC07 /* src */ = { - isa = PBXGroup; - children = ( - F9413A530D25D7E100B5EA0C /* AddressSpace.hpp */, - F95BE31A0D2EED80007E3672 /* CompactUnwinder.hpp */, - F94138D00D1C7AC600B5EA0C /* dwarf2.h */, - F95BE4DC0D343AB9007E3672 /* DwarfParser.hpp */, - F95BE2990D2EB9EA007E3672 /* DwarfInstructions.hpp */, - F98BEAC40D121B7800F298D0 /* FileAbstraction.hpp */, - F95DF59A0DEDD12800B8DA7A /* InternalMacros.h */, - F98BEABC0D121A4000F298D0 /* libuwind.cxx */, - F9AB4BC61194E18500F870C2 /* libunwind_priv.h */, - F9413A540D25D7E100B5EA0C /* Registers.hpp */, - F98BEA710D10CC1700F298D0 /* Registers.s */, - F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */, - F94139850D25A12200B5EA0C /* UnwindCursor.hpp */, - F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */, - F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */, - F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */, - F98F98E311A475B300D21E1F /* libunwind.order */, - ); - name = src; - sourceTree = ""; - }; - 1AB674ADFE9D54B511CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */, - F9276F140E6E0B6100B731C9 /* libunwind.a */, - ); - name = Products; - sourceTree = ""; - }; - F90DFABC0D8A1E9B003302A1 /* include */ = { - isa = PBXGroup; - children = ( - F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */, - F9ABAAA91118B2BB00A06182 /* unwind.h */, - F98BE9080D0F3D7D00F298D0 /* libunwind.h */, - ); - name = include; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - F9276EFA0E6E0B6100B731C9 /* dyld-libunwind.a */ = { - isa = PBXNativeTarget; - buildConfigurationList = F9276F110E6E0B6100B731C9 /* Build configuration list for PBXNativeTarget "dyld-libunwind.a" */; - buildPhases = ( - F9276EFC0E6E0B6100B731C9 /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "dyld-libunwind.a"; - productName = libunwind; - productReference = F9276F140E6E0B6100B731C9 /* libunwind.a */; - productType = "com.apple.product-type.library.static"; - }; - F95A3D890DE3A8AA004B72E5 /* libunwind.dylib */ = { - isa = PBXNativeTarget; - buildConfigurationList = F95A3D920DE3A8AA004B72E5 /* Build configuration list for PBXNativeTarget "libunwind.dylib" */; - buildPhases = ( - F95A3D8A0DE3A8AA004B72E5 /* Sources */, - F95A3D900DE3A8AA004B72E5 /* Frameworks */, - F92A25CA13C69B62008F010E /* install usr-include */, - F92A25CB13C69B62008F010E /* install usr-include-mach-o */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = libunwind.dylib; - productName = libunwind; - productReference = F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */; - productType = "com.apple.product-type.library.dynamic"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 08FB7793FE84155DC02AAC07 /* Project object */ = { - isa = PBXProject; - attributes = { - }; - buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "libunwind" */; - compatibilityVersion = "Xcode 3.0"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 08FB7794FE84155DC02AAC07 /* libunwind */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - F93A98ED0EC91269000D227E /* all */, - F9276EFA0E6E0B6100B731C9 /* dyld-libunwind.a */, - F95A3D890DE3A8AA004B72E5 /* libunwind.dylib */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXShellScriptBuildPhase section */ - F97377A8133A82A600BDE64E /* Simulator clean up */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 8; - files = ( - ); - inputPaths = ( - ); - name = "Simulator clean up"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "if [ \"${PLATFORM_NAME}\" == \"iphonesimulator\" ]\nthen\n # when simulator runs on 10.7 only, we can stop deleting usr/lib/system/libunwind.dylib\n rm -rf \"${DSTROOT}/usr\"\n rm -rf \"${DSTROOT}/$SDKROOT/usr/local\"\nfi\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - F9276EFC0E6E0B6100B731C9 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - F9276EFD0E6E0B6100B731C9 /* libuwind.cxx in Sources */, - F938B7C70F97F50D0096ACC8 /* Unwind-sjlj.c in Sources */, - F9276EFE0E6E0B6100B731C9 /* UnwindLevel1.c in Sources */, - F9276F280E6E0D1400B731C9 /* UnwindLevel1-gcc-ext.c in Sources */, - F9276F000E6E0B6100B731C9 /* Registers.s in Sources */, - F9276F010E6E0B6100B731C9 /* unw_getcontext.s in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - F95A3D8A0DE3A8AA004B72E5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - F95A3D8B0DE3A8AA004B72E5 /* libuwind.cxx in Sources */, - F95A3D8C0DE3A8AA004B72E5 /* Registers.s in Sources */, - F95A3D8D0DE3A8AA004B72E5 /* unw_getcontext.s in Sources */, - F95A3D8E0DE3A8AA004B72E5 /* UnwindLevel1.c in Sources */, - F95A3D8F0DE3A8AA004B72E5 /* UnwindLevel1-gcc-ext.c in Sources */, - F98F98F311A47E2C00D21E1F /* Unwind-sjlj.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - F93A98F50EC9127A000D227E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = F9276EFA0E6E0B6100B731C9 /* dyld-libunwind.a */; - targetProxy = F93A98F40EC9127A000D227E /* PBXContainerItemProxy */; - }; - F992F1FB11A35E2F0008F9B0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = F95A3D890DE3A8AA004B72E5 /* libunwind.dylib */; - targetProxy = F992F1FA11A35E2F0008F9B0 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 1DEB914F08733D8E0010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LIBRARY = "libc++"; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; - USE_HEADERMAP = NO; - }; - name = Debug; - }; - 1DEB915008733D8E0010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LIBRARY = "libc++"; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; - USE_HEADERMAP = NO; - }; - name = Release; - }; - F9276F120E6E0B6100B731C9 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = ( - i386, - x86_64, - ppc, - ); - GCC_ALTIVEC_EXTENSIONS = YES; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_ENABLE_CPP_EXCEPTIONS = NO; - GCC_ENABLE_CPP_RTTI = NO; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = FOR_DYLD; - GCC_SYMBOLS_PRIVATE_EXTERN = YES; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; - GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; - GCC_WARN_MISSING_PARENTHESES = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - GCC_WARN_UNINITIALIZED_AUTOS = NO; - GCC_WARN_UNUSED_VALUE = YES; - HEADER_SEARCH_PATHS = "$(SRCROOT)/include"; - OTHER_CFLAGS = "-fexceptions"; - OTHER_CPLUSPLUSFLAGS = "-funwind-tables"; - PRODUCT_NAME = unwind; - WARNING_CFLAGS = "-Wall"; - }; - name = Debug; - }; - F9276F130E6E0B6100B731C9 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - GCC_ALTIVEC_EXTENSIONS = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_CPP_EXCEPTIONS = NO; - GCC_ENABLE_CPP_RTTI = NO; - GCC_OPTIMIZATION_LEVEL = 3; - GCC_PREPROCESSOR_DEFINITIONS = ( - FOR_DYLD, - NDEBUG, - ); - GCC_SYMBOLS_PRIVATE_EXTERN = YES; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - HEADER_SEARCH_PATHS = "$(SRCROOT)/include"; - INSTALL_PATH = /usr/local/lib/dyld; - OTHER_CFLAGS = "-fexceptions"; - OTHER_CPLUSPLUSFLAGS = "-funwind-tables"; - PRODUCT_NAME = unwind; - }; - name = Release; - }; - F93A98EE0EC91269000D227E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - PRODUCT_NAME = macosx; - }; - name = Debug; - }; - F93A98EF0EC91269000D227E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - PRODUCT_NAME = macosx; - ZERO_LINK = NO; - }; - name = Release; - }; - F95A3D930DE3A8AA004B72E5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = ( - x86_64, - i386, - ); - EXECUTABLE_EXTENSION = dylib; - GCC_ALTIVEC_EXTENSIONS = YES; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_ENABLE_BUILTIN_FUNCTIONS = YES; - GCC_ENABLE_CPP_EXCEPTIONS = NO; - GCC_ENABLE_CPP_RTTI = NO; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ""; - GCC_SYMBOLS_PRIVATE_EXTERN = YES; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; - GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; - GCC_WARN_MISSING_PARENTHESES = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - GCC_WARN_UNINITIALIZED_AUTOS = NO; - GCC_WARN_UNUSED_VALUE = YES; - HEADER_SEARCH_PATHS = "$(SRCROOT)/include"; - INSTALL_PATH = /usr/lib/system; - INSTALL_PATH_PREFIX = "$(INSTALL_PATH_PREFIX_$(PLATFORM_NAME))"; - INSTALL_PATH_PREFIX_iphonesimulator = "$(SDKROOT)"; - IS_ZIPPERED = YES; - LIBSYSTEM_LIBS = "$(LIBSYSTEM_LIBS_$(PLATFORM_NAME))"; - LIBSYSTEM_LIBS_iphoneos = "-lsystem_c -ldyld"; - LIBSYSTEM_LIBS_iphonesimulator = "-lsystem_sim_c -ldyld_sim -Wl,-upward-lSystem"; - LIBSYSTEM_LIBS_macosx = "-lsystem_malloc -lsystem_pthread -lsystem_platform -lsystem_c -ldyld -lkeymgr "; - MACH_O_TYPE = mh_dylib; - OTHER_CFLAGS = "-fexceptions"; - OTHER_CPLUSPLUSFLAGS = "-funwind-tables"; - OTHER_LDFLAGS = ( - "-L$(SDKROOT)/usr/lib/system", - "-nodefaultlibs", - "$(LIBSYSTEM_LIBS)", - "-Wl,-umbrella,System", - ); - PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))"; - PRODUCT_NAME_iphoneos = libunwind; - PRODUCT_NAME_iphonesimulator = libunwind_sim; - PRODUCT_NAME_macosx = libunwind; - WARNING_CFLAGS = "-Wall"; - }; - name = Debug; - }; - F95A3D940DE3A8AA004B72E5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; - GCC_ALTIVEC_EXTENSIONS = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_BUILTIN_FUNCTIONS = YES; - GCC_ENABLE_CPP_EXCEPTIONS = NO; - GCC_ENABLE_CPP_RTTI = NO; - GCC_OPTIMIZATION_LEVEL = s; - GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; - GCC_SYMBOLS_PRIVATE_EXTERN = YES; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - HEADER_SEARCH_PATHS = "$(SRCROOT)/include"; - INSTALL_PATH = "$(INSTALL_PATH_PREFIX)/usr/lib/system"; - INSTALL_PATH_PREFIX = "$(INSTALL_PATH_PREFIX_$(PLATFORM_NAME))"; - INSTALL_PATH_PREFIX_iphonesimulator = "$(SDKROOT)"; - IS_ZIPPERED = YES; - LD_DYLIB_INSTALL_NAME = "/usr/lib/system/$(PRODUCT_NAME).dylib"; - LIBSYSTEM_LIBS = "$(LIBSYSTEM_LIBS_$(PLATFORM_NAME))"; - LIBSYSTEM_LIBS_iphoneos = "-lsystem_c -ldyld -Wl,-upward-lSystem"; - LIBSYSTEM_LIBS_iphonesimulator = "-lsystem_sim_c -ldyld_sim -Wl,-upward-lSystem"; - LIBSYSTEM_LIBS_macosx = "-lsystem_malloc -lsystem_pthread -lsystem_platform -lsystem_c -ldyld -lkeymgr "; - MACH_O_TYPE = mh_dylib; - ORDER_FILE = "$(SRCROOT)/libunwind.order"; - OTHER_CFLAGS = "-fexceptions"; - OTHER_CPLUSPLUSFLAGS = "-funwind-tables"; - OTHER_LDFLAGS = ( - "-L$(SDKROOT)/usr/lib/system", - "-nodefaultlibs", - "$(LIBSYSTEM_LIBS)", - "-Wl,-umbrella,System", - "-L/usr/lib/system", - ); - PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))"; - PRODUCT_NAME_iphoneos = libunwind; - PRODUCT_NAME_iphonesimulator = libunwind_sim; - PRODUCT_NAME_macosx = libunwind; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "libunwind" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB914F08733D8E0010E9CD /* Debug */, - 1DEB915008733D8E0010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - F9276F110E6E0B6100B731C9 /* Build configuration list for PBXNativeTarget "dyld-libunwind.a" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F9276F120E6E0B6100B731C9 /* Debug */, - F9276F130E6E0B6100B731C9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - F93A98F70EC91298000D227E /* Build configuration list for PBXAggregateTarget "all" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F93A98EE0EC91269000D227E /* Debug */, - F93A98EF0EC91269000D227E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - F95A3D920DE3A8AA004B72E5 /* Build configuration list for PBXNativeTarget "libunwind.dylib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F95A3D930DE3A8AA004B72E5 /* Debug */, - F95A3D940DE3A8AA004B72E5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; -} diff --git a/libunwind/libunwind.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/libunwind/libunwind.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/libunwind/libunwind.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/libunwind/libunwind.xcodeproj/project.xcworkspace/xcuserdata/kledzik.xcuserdatad/UserInterfaceState.xcuserstate b/libunwind/libunwind.xcodeproj/project.xcworkspace/xcuserdata/kledzik.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 43c6a07292e4c66b749988e8ca14e50e5a4b9e96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57049 zcmce92S8KT_y4;$$(xalfRX@$8<0KR0Rlu>l7Qff2ob3Wl;O60w|npT?Q*nMyLaud zt=+>ewcGB!_g?>V-^&XLNf_GSzx@s%=X~zD_nv$1x$Bb^UF~f>y%`yY7{p*k$LJXY z!y2zNUe%DY*45q9*4fdJ(z)UoS95PqV@gwZ^Qt!Zvm>Rqvnzr@r)<47TsMp17@mn_ zqL^rAJTrlr$V_4;GgFwU%rqvC$!BcLJZ3&q!BjF;Of^%(EMOKg4a`!em088KF~=~g znRcd=*}!aMj$;UOI&%hdCUXUIC36*XHFFKKmD$Ez&+KAuVQyvaWA0}jU>;=lGLJD& zF;6ouFo&2onfI74m@k>1nO_it5W*-H#i221EQ&`aWJU=n5hbCCXc9_C(@-Irj%J{l zXfCQncH}^Hs2(ju4X6<Ba(PDQ7o3($q=3Unp93T;K( z(GGMyx)t4qZbuKG2hm>i5PBFrf*wbQ&@1Rw^cs2{y@B4;F*?1D*Gak%UAQhv7o!`a zGwBj_$+`);$+}eCG+mZ1S685$p_{F<=t^{Dx_P=vU5(DJtJgK^mgtrT|2qB~u8mhN2L1-grMm+7w1U9H=uyHy4!Sj>h96q zr+ZNMuW#5L%CtTp~|qp;4mySEHW%LEH^Y8RvOw2?S@W6x1rCl-muAVoPiilGMs8S!*I6Y zJi~>COAMDAt~6X@*lxJau*-0x;TFT~hPw>+8tymjH9TT?%fW9PAzYz=E?>)A$j3F~B6ur78LyPEA_yV*W=ExU<5o;{U4 zpS^&+guRlzirvO;XLqtUu(z|yq8_8s;k z_G9)-_B-|u_D{~hv7E?-anW1?m&he?Q@K1^u6k(z;MMx7eglr*CC=_N2bA%$nDwGTJg(_iz;1CuH zi-e`Za-msRDYOagLZ{Fz^a<;QO~P>k5l#|L70wXO7S0nc6fO}i7p@ep5w;803A=mWlJkO0htE5xhCZQ`}! z_2LcU&Ejq1o#H*>ed2@S!{Vdj6XMh2bK(o)%i1CPhl4r8p^GN|44$9n#&>9_az;A!(oVxb&3ttn|F}l5|jdReD1@EWImzAbl)-CVeS= zBYiLZB>gJ=A^mM+j5;H06pTh=s4>DAZHzUJHJXh{#uVd3;}m0>F~gW`%rh1mXBy`i zi;PxdxpBU+%DBMjFfKGMHZC)^7+uDd#*M~J#?8hp#^a2~8)YLgo?txDc#`pC<0-~d zjb|FqH(qSKtS+Uauf6>sBQPQ(F-9hoiC9==PhaiY(6b2s-#u^Dr!==W_4I6KMlm5W zmUY{iFeY5q6ZDmw=nPBAD9FprD=E!Q%gHLvNz1VmXQo+-@~vsPh1RUxyv&k}LaWso z7G*23F6``H-P6_7>?-MO?px#P=+#Od&6t>!olFc9%fvBbn6XT}Y>-)*lX+Q?#hr|q zNnjG;qj5~KEXkwf5Ex15OF3UoafVIu242|K(bBojS!J(v_4IajH?3%Q*?XIMT_sJu zP0p}5Dym30Iy>7}Gf3tSK*$+3+Z)Eww4%7Pqqn=Wz1`LAEVfz-t=Xk{X_ovF zE7USKC#^8AxG*ihu)va0P?S}glUeKxO8@{%b1zKqo@)BQEb|mz+TFAUN{sdV0pyCj zj5)xhLT{uo>9j9e!1C&FeZ>kb&p=qGH?Xs24>P|Ai{f}el#HW7qDRN4OqrTGEjKTJ zy4vy1FmrBJVopwBVrEW8Mq*)BR$>PH3%!;Bf62^Gtb>-Ep6LvWY;Rl9*Rc+oE`5D- zXN#+=yYm=lScG?zsqI?h42y=pYW>^ahzCQ%!XqN1+^*C>p*q*uO299=XqME|3*KOB zf&Xb++2-n&g)mm;7t+$R3-S-d#Kw(Tq&i^-G+l%GqpJt(ud>&8^y_Ta4r*OXt!t&L z+ttzR+8#Hyp~_yZq+bV3=Fo(s9j#Dn-;eBV8(p%I`Xn6+StVITIa!5inU><*w5+1S;auB5ZdPhyPG;to)Wl7+r&ALP^D?$4LGsZf@LaXfaT^n327I$)cc+Ol)QE`d2 zw5;4VZ+=B(Rdv;ZTDzmJeyN72mGNk*5M2btFo82b@%jwWLIZLi>rHamA#lorz&Mkg?XUV2J3;3?Y$e?U6oBetHF=8 zf;>aiR^q8=Ro|Kw;Ce{b$*dq_0m6@77Q;eiL)hz(poc?XN`_IH1u1zI<6!!jP0abs zPDrjFW}al8XI^E#X1-;4Bvns!!P4E@Yncf{Flz4i`Av* z@^!_K=&sToqics0w-b`wZb)<2>efS|yO~k`!ASjoST6YdqdQJE9$+$)w!;! zX>D6;6MW(fOY;soJ^{9_x2?UccY~$d)ntcY*<0V{TBkyI)ahr=u+*RsC9a;f){X!O z)Cd*7&DFCM^i@NtWEi8hL@jtl$~ML>$8KZlyMI4=x_ZqSQz|D z>s;B?+R@hA*W#*4o_mt4biLZ$YnTq-(aWr1a<#I%nBIV8uT#n%CnqM)?b_-Ewu#vc zBggG0mhSGR4Le{!Y+-U?>?*&iWggGS%COTM$`d+vFvoire*$wdld_#TkvU18AWz)R zoWz_ePn0JqZD@D3!}8hH;^{_bSYiVW^y$zM^V@pUJs+e)knU^l?dx`F)jEs0kY*NV zGv_epGUvg7y+EEUPm!m}sdAc}zLU8KJn|Cw?`6#8@-*W zT9mGHz=YroOM*Ywx|(6C(q_5Rw)S2ZogAzkbkMY@9_BI12cyWfva{Re(NH1d0n%Pv zNi&tc9?xfPG@3WKvlJ+{7ve3Ib~g#t*Q&amxt598#_W(YwlUYqnKU<}qV-MfeXbr$ zkGJS<=0@tNH^^Drn49EmIi=Av!E0!@F?TU3JDA&XP#hEwr*7#)@#4Yo1~Ex;$G>QHR)D%#t0+561Ley%p+5o+rM=&Jn)h#XccYEK8H6XpnOED}GG)i16oBG;&l@e6=ME9Ti zbG2H?AzeK%h?;0B0hwI5W{@XbE^1eDFE77E<4_88HA6B+^494k(XdjUQht9@o&4;ek({p_Ev z7Hgl?)mAveVwyYGq&IbSwY$_MMLJzmKz!3`y%@nRZ>j=7opgUwiq2+jY@`J*w5YGGy~Xb8?FA3i3J%K;E+5>;ruKGNZ>X99P_=&PM!hhC zlq3iB$*bMb7OjVb25mqa<#xH#6KT;FL*|t>15w z=e8{O35%zrvj?KmGzp!jq$*uB8lRKsqj3?s6tW9+F}g(VmV36N%h2U=ue_GVk9f7l z%20q6M=>nBa+`A(%PUKDU zMtK84w>!hKR>A9)&}2D6B!laRiRUQ8*fp#xXb+$Kf$}ERM$}Y{m&V5hvksI2otl z@puBBh$rF6cnY41Q*jzj$J1~I&V*HLHmqZFVI`XnYuQ3P9nZis@hm(W&%txC1sCCB zT!O8*6qn(0Y{T>Ld|ZJmaTTt{HFyE8h4rrk*Wr4+5I5jPya+GGOYl;>3_J01+=N%) zX54~ZcqMMdt8g1W2Cs(o@*3QMJ8>7Ro4auj?!|q0EnbJ$;|+Kt-h?;fE%-QmJglh+ zJ^|L%C*hOvDfm=aU!RW8z-QvK@Y(nrd@eo@pN}uV7vhUx-F*qZ6xQCC4M4)4d$;}`IY_$659AHWCkA^Zw{ z6~BgGhgJWZ_$_=Gzm4C)@8b9H`}hO=A^r$|j6cDj;?MBs_zV0c{tEU6zQNz(@9_8d z2mB-c33dv8!N20)@bCB!{3rek|Be5V&ydfO&z8@T&y~-U&zCQdFO)BmFP1NnFO@Ho zFPHx(Um;&9UnO5HUn6gox5?Y(9rCsEb@ER6dU=<;TfRZQQNBsOS-wTSRlZHWUA{xU zQ@%^STfRrWSKcGvC*LnWAU`PYl^>EHmLHM#$&bp9$&brV$WO{o$xqAA$j{2p$@}H! z*{!ad0{z3jx{z?8>{zd*({!RW}{zLv#{!9K_{zv|oAci1B z5GF`R5NuQ%2x19>J!76Afgq6}i6A3EqX-HiD3qWug2D-kASjZcD1xF1f_yKApjd+9 z2pU7sSc2jSG7)4ZD1o3vf|3XtM^G|BDFlrtXaYeK37SOEWP+v;G?k!Kg3<^|CukZ$ z83bh#ltoZBK{*8F5|l?!K0yTp6%sU^pcw?sBxn{vvk96*&|HEn1QiifOi&3yR)R_i zDkG?zAR9sR2%1k&1woYrRS{H8Pz^x~2&yH>PLPA3I)ds6T1Zd>L5&10B4{x|O9)y@ z&@zIY1T811iJ%n(H51fAkc*&|1ho>hil8=vjv;6@LG1*sA*h3(PJ+4!I+mbrf_ez* zC8&>}wFE)JwVoiDoi-A*iJ;8{Z6WA5f{rIhCWsJp0zoGdbP_=)6LbnerxJ7;L8lXR z20>>MbQVEp6Lbzi=Mr=tLFW^60YMiMbP+)p6LbkdmlAXtL6;NsKZ33x=t_dFBIs&@ zt|4eELE8x0PS6g5t|jO?f_4&gJwdw&+D*_61l>r`O$6O6Cm&!W9nxW)t`RoVdz3v~ z`AnGCk&^WGLdFTZ1wETLTS`i74qJ7VrNU`1nQvF-a@cEQmHkck?uEJqyaWEsF}bi4 zrv9##AX40zfw%xxTV3tYgho-J#DPN9RTYg+OR>XNZ*^K~i_10XFe;rqP}*KsQ&U~* zu$DM$DlCrD>e@;$SFL3vRTw)^q25vfTkRCsBRHB0PDDyxLu+rhTOH0COYwYXrKQSN zYPCC@G)=FmwU*i%H1s&ClZ2BcG!T(?Sfm$EvB{;61KX|y}l7Pl|7l{%bI>8cV-ZHcqOR#a=L zwe`1MCWSB$gea=BRg^gELDEv?@HA8ol^r`!wye0=S#Pbi!+6jdCZ7sU9Vkf6w^dkc zp%Y514PaAst<|aauBJGhDvled==J~yIGUx%R$+5AYVxzF{1iX=hT@7k*jjL^e&Q^J zQk_+n%KloXlimthE-0mHH*<*s98$#nmMqzbp<|n5}B4!b+*$+<}F8`qK^I zEVo*~x9rZ++UiOe5w;2#W9s2n)JOCN}4si~>36(MP<*T2oQo zSZS?tI4i2vUej!ErP33EN!L`{9pDrY`|RMIn$9s)XN-@I7Uz6ga7}PIpZ4pba^`?| zwDp{{1GTbysBDyvYzg$T*DSV{O2qj{Xx7zO9G>ZG0~H(ZBc@Fca6G8QZ}4dFa=XXD zHdB=}9~IBs01>{n%u44y*wwZbgVB~sTmMKn-rp$ud|Qn+KWMc(fr^=YN+_`_< zTkKYdVBpP~=*d(x#Ya^6T!U0XxH8>o8mCc>*Z>-KM`QnNcqWzdbsrVi9oZWzi>fO; zzIhIn_HD&VOL4Wm0h+<%b86FQW}Ht|#-Vao6P%F3e5+JY3r4kdRn9t?F(*QbBVN$N|&V4k{aiD%v_$!w%Wz&1zZ#LzD()&BmQnXnem=Nh8duFi%v1GuzbJ zY2b9Yo2pFgSAm&jK1_opHap~GFjGTTQ&s`~;WI_uM3qwem0-TGTWcZbgPS8I%De=g zWpmh_G$n$7*`L?lN;MPuHDM-Kjnsx6Ek~=)9aK1}U)W#LSp>eWiQhc{+uGpHE+OZk zeyBuBO?VF#j_k(gIGb)_7nary}wFBGry^=o08kM|E|D&kXexmGtUxPnJ+=u|vB%A&s*_ z4ojy9&E{vRidVg$?-a8E-ZLnkr!wY#1Lj+;H8A1Z>gmKsr|{Y;kL*iSHospM8gfBh zHORR=2|`^RolVqP+mmON09wD}9;6^C{UEhgPv@1^f=4W@uAT4eg0E7IaRD{dJhIVO z{*9sKX~g$b>oAq~@;#^)#2YH&v|H&41Qr=y;_p&%uNJdgYb;8-ruv@K3X3wW2R@*( zUPD>y0iT}zmnhkp{2HprjivUK81fn#k^_* zmG|dp>tsM36nACL)K%d_2id- zP~9=!y2{iIMXAAF>z%);T%xy}wZU3k2iZML2%hxSEv;v$v?+)*bZq~kQ?H|o zhf+D8cJG%{gA-KMo%=y*?(IwZ2&$XxZM~Onouj4>!V|3gE!yzVM-Nh%Pci+emo{qk zv4a$*_J(^YqxIids^HTCsy9?xe7sz5rgA=B(O-*xqcqecDm}rw&eWIbH~?8?rnEcD zOJV6`aac5+6sj}PTSp7HTE0_ST>*2w5_dGEiBxHvw^G0Pn!0yKPNDKXV@}Is-T4HZ zdRIAYr8ZA!)~8XG1n(j=75^kjpFxFV0||T0>-uaemEt2sQ)k7CoiM}t`$Qhq@M+MR zx*}Lq_AgBR+oq7}O!6*8jYVo6pp|2-f@L)HjMkzvsg}=xURVop3EJIn?9ZX16Or9T zU&AEUH1)2c8&K*7hkK5wgU)+ndF9?L> z*|Hc3l7k|p4zS7I2q{n{Y*}degO^2~fU%HjP7bU&NE0ujYViZqptIfn2+>3Hr=?VK zppz(WF$nx}s+5TAaEDKs80k)r({3w+{Sz3SjtZ-iP-#UpyN&UeR!6gEOG>|zNLvM=r#7>LZoT=m@TpXMlApMH zf1cLKV;<;gl{$lJrTA(23j3rcX9qS*F$hu=FA-%40Sip^7l?ZKAT2Z}FGyFP=J;x8b7_NyVmbp4y-R>-3 zMJ}-x)s-pDOS3qddsom=uYv6v5m-Y(9_&!ir4As%d<|Q+bdys9yODy;9Ij>Vy?G_9 z6w^w=)~AMa3q{Hu8i}4D(7XXw(XgVicx`R!Z>JD*hX>&q=}K!s(q86tug^4t?xJW# zBScezjaD_qyFE>HFU89l9$rZ!q-T&#DLWv=nnm}IpnhsZf&d7|CR*Z26Q)}2+(o~4 z1ocz9UYRvupqIf64)LmbAwBu?)bA0BHw-7G9q4uh*x0JFR?tmXZBo*z`WOY9GIV3n zk>;#$RBL)qQoZb<^{5fGR+=EVb5IT7848d$JOJn&*gmO*0agU-YkIV+oR#YLQw+<{ z80v7Xu5s8ZZHv^A3azWmp5AMO7b)Ddq2XwqN@1G`*7lyAa{U3STrfOkM>))*C3Z_G zZ56Pmzi(fmD8m@$%HVWw?gjR`*C|rg@a(Cps;!2Tri$w78c*B4MfHa<#?`i^9UQ2A zwVry1q6HX}eelL_O=5B9nl88+*PU3}4wo-CZ+0g|J~Q?EL0V=|gqn&v*v+l8`yhQ3 z*p`Z>j@G`WR@eiljav-oyH1-Ow%KX+3EMgJ4_a+Lr3jgRZR?BR9(opgrE|Wu5%%#) zH1#j2dg>7B#W3hW)!qnmm3Dlu|C(y14WVhPQkIdB8+vW6>c69^(}z%1_Cu9zTrDuF zt0%9u%a0Vte~<*MJIo#s!fHHwi~3)vvVW)#s0?urh6dd^sJ77~IpvJJ(FxmYo`V(r z@58}^g%u1pa8O86+`F(P?&XTp4!!EN2L6lU>TpKvgbPxCfgd zoFe(h!9kEzN7MA9sDAKqqgg^@hL&~J)WDWWu@$D9{shhtLvez4OAwq|*bvn$8AA~k z1#MnHP!I9wX`!0=R?yS|9&f4}y)>Y?uMWTuUfToec9s_T4JKMn@ImTdj=SFOT`^Cd zr`erI@d`&^w-27jtYiu^V+1hnYB?=+j%pg%G_vgInf} zwa{wuv|APh^Y>tQmC@DR*$ithWu5BQhU*#hT3M~n7|5jv{$nXHf_v?uG*P9!%xkc2P`nI65F0qZKSZF3kEa6Qfr^E!+KcR=@e+6)Tc=m%d1&j?qx zb-)%zk!uw^80zfyUu?paIeIMuaEq+vmUCqT8OF5jI)1_a9(|uOvX`d2`=I;oDpw(DQ z;L4iK6l*;YO&E zIK#zQb>9VA!K(!tDYAb&7)H}V-d5t-wlOTBIMyR;$s)K}KzD?E_tOkc3TZnsNI+BS z831+#g*_r?%FA&&s-4+caJcIT0PH%7CZI`N0LWDovh>KBKuO*MV6LW^B}axyR{{PV z)j<)DaP-sE2rjO|_E?3JM$G{5$5MFz-NxW9>NQAhmGt^2beD2~;ct2`#V$Y6#!znG zSz&WUId}40^EIrasP++{dWNg}I<~S$O6SK?Xc7nowQ#4L-r3XQ!A4rZNJg8d080^^ zae~DVY^%KQ{TQ}T$g(4`Sv!eNpZm)lLl>&V=C_h*#ryN;r|0 zFp>y9pe3{tAVqOh)5W?6`4oyglJFA*xyrhb9++rdcRGdj-!L1NH$yt7p2O8?hgpWR zjLb&Ca#kv#Q3mm-hEA-sm2J8|@H)C(x6{|aJQwWm|8c4NVCF$EflXL(x( zJ5mr7s_WpUj}{;NL&IgXgr*Vtu9_&p8qa<05e^5n7N*YS$>aP}s4Hl3{;6p2mZ9$E zE>5e2wh^J68__FZboJ|B)YY`8$`RH~$$4lU)Raou1ESL*Y<*Tav^%hdZ4`PW!_li- z>ge_XJR^bEF!gYRIUs+&mLiYD9X-PluHLGTT$DRubSdib@#`t5|2lN=Mps&*u4;Z2 z+zp57Tgu?Rqc*y4pnyj>VZ#=%74BmycfIJbk%oEmQ5dPLuQa#N0B@s!Bgsv@noJ=bt)mW7rhYihx<@Hm&~+VM zcnq|z7WVDn#w?sXz?ErBMWfy3apxx}*r4HhAeg;BwpPNar)JgD6ll>OPSHof0xQr%@-)rpi_N--6M4osN5`~SDlOD zsKNsK8U4q+hL6rd&a{*&sPM`yWLwni;(RL*7~M2jQ?B(!i$?NdV@GUK+?x;)gB#f|xf(tCP zbv((>5C2UOuwP2=m6y=XQ6~gF?+xIeX%WL6`2pLC-eZ6TrL6>Fela~khv~#?yZSd; zKxVbw;yw_D`9gih>v=`1o(xk7_1UWT!LH#?s-8WlxSPUod;#pBet405k2B z(W*Jo($Unu0qzme{X_aA@EfWdr5iSHrVp@G-=f=k5XF?a3+@)V{gg!%sd^Yl0a28@ zVDxRZ8&-K(?pfipdI~=4sK7NlISK{Dr~_-PTy}y+u=Vr+^_=GKS}kGbx0EQCi|7x^ zlVNQ-V?~NsG-AX`Yh`sUT!Mol%9Qw|SvZQ~6^s}U9EZ#U`cCm7w4DR^( zS5_I|z)@PNY&&a+krZ)(zg@#YbUzYtFEZ#L@H`vQ;73#V+W!Pz-O+{Vkls(!@Z%_c z>5<_p4Fa_jLMds=I=R2ZK!+BEv|;+ zS`9UyqAIMPz7vM0LG7;QzHXqj^^2hJTC1)WI1}jgK8u5{e-z;U8Du(zwhht-Lqo&0 zBUsTxp3r}FnVm&p8;%MV?kG~@t@JWATt1j-PXF0zik(u|3TuU{Q zd^Ny!h3Q3kPO9F4(tM_lif0Zf?riH?)!6|o&ujYHDW9~a-aysk2B_Pei){1>ljrb) zT};K|eZ}Bvnfu8M{Ye8{MkP}RlMH4`6V*%}RC7&Jb7#+bt*92N5bLV|jRVg(y&h<> ztpQ+Rp{Q{6&_`x&b2@u8*kh=|l!35*3VuzwhUyLIIG=(v>)|UW*iL52HWtXGZuJl~ zvC6qt@U93$3N;hEj$IEA&Qzj3;LxMgp#zyScd#4SjZE%PV(^3on6n2eyD1ad&FmIN z;VstwAhRb1=8}AcJ&ipb>U0KsCVLipHhT_xE_)uZ?G8j<)=zCoAHOLQYk-Be|Igrx zHn=XbzIvsm+y5Cs4-j+@L3;_ho1pvQHl@-AlnUF2kF}(eVy1hD?mf)d3bP=4Auuqq zz_fKQP%yHWvX_C~mopajibee;)hRX*w1;xv-q+6%t+xNw>@_eHpwxcySd|V-(W+@` z>)y_8rHwzROyu$Zs{b5RSTT2_o7rpG>nP*pgEFHQbUnK(a1U)~cT@a8ou_Kv$le6c za|Sj{zrDU>x7*p9DcrE-`x^u-ACpidpk7z9qe`N zUFc@|%@ix(krRAnL3+0f!V_E}lNo~c$s5%A+{^BP3&lXowVl0}$yNLDe%g=V5s%4z zK#$N*teu&eRRCY}kd@_O)@C1OA7@goWglVpv5&Hk5%dH>PZIPLK~G=HKEXbTUSyvp z=ox}u0B%i!UXoK9DqJfS7X8NBw$@e3Pm5HZWtGN~e$$7Cv(>})tc{Zw*+aCrm)Mut z1MES9o+aoxg7y>i{I$S?Z9$hY2|!Uj8hBVoQ3}to^-bMvl!6!t?Op3A>2yzR(>j&B z9NxzHe(GjYwl@RIC%i23`A|`Zh6gVH=I*vG2=c(hJlaP@L8m;(nyv4$?=vae*!Ku} zaT{X+qrjkW`0|pT&UQCfJFT%M{R#USNGlY$?B@i%?B>8_zXA?i_G|VVf({UL$isrm ze$W0qkgt|~gh^n3gFcW)5p<9;){U3l{In-B$=qau-j;#u@EuC`OBv}krf-$=e90pU${{YDo5p1@5|_zd$7OTy zO2-lO z?ia6ed0ak}QNR^))1jP9ZWi0e&1PyE;EVa%;SE?veOD9wZ|~w}3f<95y#ze0#XWq3 z1&_s)V%AM&PRsg~An=U$y`}_iE@z=r0ta-CpAhtc7QsJO#xYk4xBHzyF!&CKBBg zqAMV}LZX{NbTes$h$`xKHLdRIZ0qRlQNH;JxQ1IGR=LUURX?Pw3|CKSXE(&{o+auR zMA@5Hxz>PNMXA5m_H{t8f+w^P@;l)>ZbG$LU;R=X2w!8=pXm2$bhLsheD?&U@3(cV z>;!R**4QH+tA0O)@61EX*V^O+?j#5dlsNR^ZQRKO{UU4Mrof%Xok2eWhk0Zh2P~bx z_J4E^cQNH?4o1n&T|z0@xyvafJ3+ruPIiKRcayS1a|Ne~R$cNM>XKUt`ooJSo7=%% zOL?*h`ir1H6(($z)Oypq$7_|@&E4!KwdQW3q}Bxey@R_2?crb+`v+L9(Z95_j*`h* zHSun0;yna29^z{5KJJmhh^x7M+@l(CHNlAJ#(OhYtEkVYEYIAt+;iN1?s@J7?nUk; z?q%)(caS^8y~4f9y~e%Hy}`Z7y~Q2o-saxn-sRro-se8xKIA^)KIT5*KIJ~+KIgvR zzU02*zUIE+zU98-zUO}6e&l}Qe&&ARe&v4Se&_z+{^b7R{^tJS{^c1S@tD`~dfvdZ zJje6Az>B=Z8~IUu2p`Ia@!@;~AIV4Y(fnvWhL7dr_%ZxgKAt!6WW_>KG~ zelx#?KaM}1mwCdUz@NyU#GlNc!k@~Y#-Glg!Jo;W#h=Ze!=KBa$Dhw%z+cE;#9z!` z!e7c?#$V3=kH3PylD~?-n!kqM%5USh^E>!!`Rn+d{Pp}Uem8#ue;B%eZ;*e=om>zmLD4e}I3G-^)M5Kg>VE@8cikALAeApWvV5pW>h9pW&b7 zpX2xQ&+{+vFY+((FY^cZgZv@>75-KJHU4$}4gO93E&ee7HvbO)F8?0?KK}v#A^#Eo zG5-nwDgPP&IsXO!CI1z{z;Uf3SWmElV3uHxV4h%sV3A;nU?ah!2o51Ql;ALe!wHTc zIFjHff};r@O>hjsu>{8vJci)01jiF>BG^oD0>Oy{ClNf3;ADbR2p&)H1cE0LJc;1R z1WzG&D#57)rxBb^@HB!m2+kxpi{Na6a|q5QIFI0bf(r;PBzQW(GYFnZ@GOF76Fi6D zxddAXE+V*?;1YtZ1eX$AMsPX7HiG97JfGkSf-4EGBDk918iE%PTuZQ>UZuiwM4$;7bU;l;Fz< zzMSCy5qt%~R}y>`!B-P}4Z&Lp-bV0tf_D&nEy33jyp!PT3EoBUZh~(h_(pf}bb&1%h8B_$7j0Cinos2MInz@GAtrO7Lq0 zzfSNQ1iwk}TLd2__-%sUA^2T_-y`^afESM;Y1ffbdf|CMRd_bH=5{T zh%T1s;)rex(Tyd#c%m~Aotfwoh%S-nl89~`(IpdIif6}yR~|Y$~(pputf99L&agRMDxmH#1XPY3(7mhBVmaa49XsrhqYOIN)(hOT2S5^ z9x+R_pgcJ|0+whYgc>>|OSGW89tDwb$Lc@Q`}mS{nF z)He*4XhC_ccLXfag7Q9Z_$<+a@(gd}EYX7U+HQm_(Sq`*&aW`{bI9P7)PnMW?!RJ* z7L*rsN5&E@C~xPEoF!UN-pmb`C0bCPzzx9?EhrDzhQksqDDTgLNqVy!3(DKFVX#CC z$`i7YvP28YTd`rYL<`E>FJGEpFUDSaXipEo-TUo=@}O&EEYX7URBLFKXhC^|6bc|W3x|=hL<`CzhCx}P1?5e`a9E-R<*|WRhkMAVg0e&l%8LT8 zdcirY@>JjJXjo9*2zaps55f{HC@%nxk|kPDZvBshC0bDK^$(vVT2OB84=(Rb`z$;` zL#CJS4bBoRC|B^kT5J%OXhFGJ?=_UQ9`L^FDZD_-ACe_nP;S9{nK?L1v~XwuD!t%K zDQJ9Iq6OuKx>s!mVTl%$OXo+x5-li~$$c1Whhm8qlxyNXY{kQ7i58R_;68l7DwDwg zmS{n_)a}CuJP1p)pxoE?A(i!#_PPHdC^xZ>fF)W`E>|ac)7^T8c>tDZLAfaHW0HqO za==#v2+DAFt?dfqtXhiL$8N5%wW99+D+m zRPF(fkR@7FuKf<5C0bN2_4NY(G!d%T2!vG4kQ2`f+bp1uBeWPC0b0UCJmn@T2yYAj({av z%%KGglOGMcfqDAE*=ZIONMdfd-l}nVvWr-G*TajRlM!DQiwhSlPlvP^0KPf7A9FK%0T2$^j4#^TN zDt8=*W{DP+%Z$Thi58VBjU#1=7M1Ib!()jSl?#o7utbZ>1;!(1i58WsjU#7?7S$V$ zeniYeu|$jN4M#scb*}bfi59zP02nDtwAe$nM#2&;uB94Der5$>i554g1$c8l!@cZ5 zSfa(vRAYE7(cjy_0b|6c%_yAQtT9#<>A&N4LVNOlZz6>iMOSHI;BKfnU z2CPf~mT2*Dsy~b|uC}f6rZ@l#x3(^PilPM=lY??Rd#|R&XM?oNpa_9jqQ&O}+oDlt z4$TrRzC;m@m?c^~NY#g;5e~!>Ext-MkBB8&e1od`GxGV?TGj z>Oi55SjAVYO;z&)8Shf}<}ZG*8y zi{DTX|DhJJjRUeoi{DcO|2e@I!Jj2s{E6!QCoIw8uN2BZ4r(UAvu-bjn88@0#Xl&L ze;gbH$%iFc{F~|rA2*sMUXyKcAeLx}p*X?2B?yieOSGh;2#frvCcJ9$pRhzrEG;Ma zAO%YYl;ifuAS}_6K=F>6C0a647=O~B;MEVp5-o*NAb+M2FCfp;?qRV+OA!>%f2s@y zsLq(dSfZt9iuT{IL`$(0%Rf~d+%k7}DsSSwNJ6Bs6wKd)2XHgHwF9w4OJ<7TKb8U` zxCv+!GkjU1r6h{u&kQ;MhYrd99qQq;L`x|Y{{NgMTAE0U@u%iHYBFknmS|}TEy~|R z-JDhyN<7{M_(OSF_t!Ti0!i?HixSfZso3O^{_)&O|w zcM5;d;4INnAq74{Qo})6qNSM>IcRr}kR@80Gg3P}4KM^tv{Xcq{o_IKp7S94utZB% ziZdu3)qpNiL$K0Gfmx!Zatb*pcUy2sASba?Hf(>=VQD^vJtAisoF!VSI*KL;%n~gv zppb)->jiIuAS}_6gJO<^)zPb`0x!qy*UN^JR&aIw|r8oXtwyQz7ZrxF?+@Zc=b(y6ql{}YyI z=?n@zlHuspErYT|OJ`H$k+`F0I0k2lmd>M~{_D`e8(qm+0<%O*7gE3@oUntiL`#<( zg^>#Vm*y7konYy53OJJ7)T=2KKyQ|4=}L+=l6+zy+CY|Q>6)Xp&zmJ$+J3anH-IHt zx{d<+Z_ao*jn~GQ;w*!*L`%DdtgbJEGEJF+vP4TaQnaA!x{ zmTsp&gN_T|Iu3&+TDps3`fpGU(hoscqNRH&(x6kl&vuko%u>I9J}^tPbU%e1bfpmt zc5s$xX)gsHG`|c6tZe0Y=8Iq~(b6MFY`Ic^meBi8s*fF=r)nmCk*V4$GefY$s7b)nV3x&X-!C9iE0~B)5InxKy zYp^K3;l~m!y+Q&1uUVp{*J&yLr!3LZTmMZFgRn$P@6aNKJMxc!C0cr)7I4HY(b7j$ z{U}(XrB5lqf58$heL;}|kU{$KO{*RX+eO}7(}S}_OJ7s)|AZx4`i?>c;Eg?EmT2im ziWq>0cL>B_EYZ?06z^zRqNU%1)YC&-I#QNs=`V`-f5s9m{Y&Bh?^vRZnBxDpEYU^- z#XM@3Xd_Qy2ID#%q_2ixi8e|UJAik3{J=AP42vb&7((&>LzZY`I0Xz4IEHUvaF%Fe z6a^13+J_H5fF;@(LlOULmT2P`iu#|jL>o;$?NnjpEYZe#syCqHdOSG|( z=q7kLmyF7}R`9NHa|0Tk#wI3Wn{heOP18)R1 zkmtJ&yz88JK)$Bbj9GP%rj zW)8cTeGIsUUuQpLzhJ)w%H1E?-`GFczuAAe3EV7h9=DKd7!=U_YRKy$Z-%@d@?prwA)khP9`ZxTpP^!CcxYVcxX^;oIiVGy3qtLo zb)kzwmxL}0T^`ySdTHpjp|^+L8G3iVHbp56n1IYU+l$FQHnehvFQ?C-FD!r5>xJSsdUJT5#w+#H@5o)(@SJ}o>myga-vydiv1_|kA^ zcvE;s__5(V;cLU!hi?o&HT;b5v%=2}KR^7!@GHZ2gkKkaefaM18^ia6KODX<{IT#S z!uN;25dKp5f$&4&Z-;*o{(bn5;XjA}8vaiN6M-Z25o|?}^+K`9S2}$cG~z zk9;}u^~g6P4@bTe`Elf@k)KC?75Ponn5e9%c~SPL`lyDeMNzF$YopdjZH(F+bzGDj zbwbohQ5QyC9Cc~b|Dvvn+8VVZYG>50sJo-~MIDa%F4`D9B|0yZ81Ss!zJ42d~0=H!^OV$O*< zFXn=ni(;;dxgqA(nA>CSjM)=&f6Rk155>G4^KUF4E5u5%QL%Bcrq~IwlVhjGrp3;V zEsw2@T^74Mc13JUY-{Y5vDd}k5qn?k1F?H!AC7%8_UYJXWB13t5c^8(;W!j$iklW! z5H}-kR@|JpinzwO#c@mHoN-NY&2g@{?zrB#b#WWxHpd+oN8(P5+a32r+*e~F#$=6I zIA(eL4e>X{-x7aY{2lRk#orUZC;tBU2jd@#eG_|M|Mi2o}7oA~eIe~AAn{+IaQ;{S;MEB+r7W5OoA zi8b*i(PT7*n8HjErYO^BQ>Dc)o@C7Q;WQcM#}lT1@gsit&OhAGRGW6CoXn5LU% znr55knu<&%rczV6X`ZRVRAs6$)tVfpdQ*dGk!gu(nQ6Icg{j4~(zMESjH%t!Vd^q< zn|e)aP3uh?O`A=}nPk%mrjtykm`*dDVLHonj_Ewp1*VHkmzw@(y2`ZGw8OO1wA*x( z=~mMnrn^mhOb?hIGVL=xZhFe}tm%2vOQwUSS50r24x8RJePH_7^qJ{P(>JE?O+T4_ zHT_}w+sv4CX4Wj2jpk5uggM$AYaVMho0H5b=85Jh<}`DLIoq6PE;P?H&oLL7t>$v` zd~=m~f!SeRXkKJqYF=(`Hm@|dncK~s=5BMJdA)g)`8YE%pJYDOe1`dK^LgeA&6k)j zH(zPK#=PBpoq3n}M)NJ^+s${G?=|0V-fMou{FwPk^E2lC<`>Ne%&(YVH@{_m$Nawe zBlD-`FU((?zcc@6{>A*e`7iUo2{^%!z$ZuvAqn9LQ3){#V-idWi3!OG6A~sTq$W&D z$V$jfC`g!*FgwALP?AuVFfXApp(eqeP@mA4uq45mup+^guqt77LPx@}3B3vH5;i7m zNstpxOgJUs^n|k#&P})=;o^kL60S(NI$>+V?u0uN?oN0u;k|?(5`Is_iBjUI#EFR+ ziCKwtiOUj~C!UgcZsPfgwkH7`?%FO82H zKYD!b_}Sy6HQ|N{&rLWq;nfLWPxxiRZxf>?nkFVpESp#}v3BAK6VIG@_Qc&2@0fVk z#6uI`p7`!0c2el1@JXqYawp|aS~RJ7l55i0lP;Nb*`&Rbo}Bdbq;DtvHtCPav6GV~ zCr>V#Jb!ZKEx}Gw@-d>@)MJvn*8nL-zNVtC1pz5lxb6zO=+FdHs#DI z7frcj%KcLwoAShzPp5o0<%g;K)bOd1Q&XqrPR*aXd}`a&)l*NLde+o)rrtdDo~e7L zzBl#rsb8k*Q%9wSre>rTrp`$1OFb@CPQ5<$w$wXPUrT*2^@B7nEi5e}EiY|Onk8*T z+Um45X{V;0mv%wgEot|r-Iw-u+9zqBrR&p2rH7_xq!*^oNN-E;PVY^>GX1*r>(gIP ze?R@hY0NZXnlvqaTK=@cX^qoXOlz5T!L%!;T{Ugrv}dR7pZ3+XpQrtr5tU)eNXV$k zXv|ogK{C$BI4fgs#*-OOXMB_KYsT-HqcamSlQK&(D>JJz*JqN<6EknlyeD%{=G&Q{ zWPX+vmKB#ZHfvT^X;yhwb5?s+N7ltzS7&X_dM4{Y)}gF_v-xZ>drEe8c5b#adsX%^ z*%xGAk$qM6quI}8KcD?$_Fvimc}BzXekYvI}wx zmK3-OS_{rBxTxTgg1rS#7Cc?>dBG0_KNZFojxU^8IIqxNSXa2dkQAO+czxk*g?CKX zO*c*tnO-x!ar)xvS54nJeb@9)r++v7hZ$35WY5T*v3>@bapH`pXS_V);7oC5~;?Z?{p*`KxVcZ_wUI3_r{92*>)9Qz#4I`-E^*O}`Q>sHov z)*V}SSKZ#ahwIt;(E9LtNBz=zXZ>~cx76QO|8xC63z>z*3o8~@Ej(}G1uf>MN+~Ng`7cE}0_}axcFTQp0&x`+A!Yo<5q-DvB;czr1ky*~>3ke%bP`m;bW-wDv>+oct%w|>+5-Kx-4v8%?cvaPCJY#BnWJn{aY+k`vGO`%Oaj9%K>r z3VTDs9s!b**jfj+R*R!tEmE|K;14Jr-ONs=m)XU=8E1n!=jH`iQlJwT!irwT88YwT<;D>oZmaE0T4RC1n+`+^nBi7g?8CS6EkB zzp);$Ub0@Z-r(=x0r)6<5*~;L<1_JD_+oqoz6xK1ufw_w;XmWu_znCP-h=ny_wc{) z0sJvO%pSp>%noMHV27}0v*)uHu@|$KvX`;9v%g@+uyMAAozE^}m$1v(RqP+wm)XCu zdx_D+R3eC&PJ|Gl#A;$4v5^QPwh`gPE@C$kP3$F(6WOBjemqL?Tn zDu`;rNwg4dqLc6v=ZSw4uQ&@h%Q*Wuhd3fm8mEZU$Z6rYIh`DubCz?CbAi*vxy|{5 z)5p2TdBAzZdBS7 zZZCI``-c0Le3uL$N0DR5_sC#!COL}?CFhaz$wlO1GJ@PqMw9!<1LSxAd#1%moaB&v zQcWh3X3|R9$xJebbdUvP5qX~MCkM%A4>8F!eX}7K{L+z*sOIOafCt5SR`^Kq#08=7UAxWAF)B z0ak-`U?T_v+dw#o08wBU*bSn=K5!7kfFs~I_!gW3--CF70}kK;0QevQNPrxufEE~l z30Q$0q=F2P4IH2V6oWEQ32HzsXaLQi4Rio6@Pi-0d2k8*41NW_fg9j=a2xc3Kf!(Q z5IhD?!N0*v@EZIFz6(dfF>oB52;YZ+Fc{8+v*BF$AzTO-!=-RJTm{#{4RABu3O|LP z!$`Ojeg*fyz3>1$1Y_Ybcmke;ry&!vAOT58K?H?R3}sLWHBb)|p#>(v6qpXPU@pvu zMX(fBz-s7%^{@%H!glC^KKKLt30{Pk;T3odUWd2fzu+IR58i_h;3N11K8G*hEBFSz zg96ZK^d6dkCZnln8k&J-p*iRSv;cjCmY`*5C0c{lqfKZF+KxU$JJ1*COY{%)HQJB9 zL5I;%^iLFrzC#RzAvWToGYBF95+Ny4AT`nhRESDYIjTZVREHW- z3v#1QM5D9l9J+wI&@bpJ>P9zF54wZyqJH!j8bE{S85%;v=rw;Ne>8tFe-(cXe>eXi z{}5lmSMXK*3VuDmk$;un!@n&UCkPZw6GRAh3-$=k2t)#jpibZxbO;6nLxPvWAYrI* zt}sj(A&eB_LLfv!r?5rXCj4Far|@3F=!D4$Qxdi(e37s#ft>&o_zA@cH3_bSTM2y$ z{h}aIsA#U}TT#4-CCU~Ri%La3qJGhR@dWWS@pSPj@n-QBajf{H_&c#uoG3PntHh1s zX7OF|fcUW_P%>LGM-ndCCHYEnMk10(Bw3OoNr}WSxg@zPc_Miw`CA$&oh_Xs-7NiF zx9&_K9qrY=dmCELL_@CXs1ndReWkP1Y{!l|7U_ zl24P*kWzA|daQbxdcAt1`iT0J`m|c3wy16DN_B&} zN&Tz(clEzC0h$S#Ntz{^HJWvrgPP--6B?5yRgX{rk>QF(P!(6^`-hN`dj)QLx5p|VUl6JVY?yR5NE&)xIt^M8j=jH2A|=q z;j!VR;gxZrak+7&G1?eoj5R8aiAJ-r$>=fC#(Tym#%GB$6F*E`kQkY`C-Lh5i$_Ji;W{;URKQg~C4_iVk^DPT4VU`F>q(xv+SX7o;OPi(L^1$-kGGq<0&bKbK zMq6X7u~wN?Z#7z-))s4=W(5_8InQdyGBSo^3C-m)alMU)YC}S0-;t4oem#tCO|K zmy&-=zMe8GWkJfKlzk~jQjVo0rDUb#q;#j;N$E}fD0OA(>eQ2|tWq#a)~0Pu+ny#%)2A8Jd}$Zcy3!}5Pfwqj9-SVO9-D4TPfbrxKbQVX`mY%yGbUzC z&iE?hK*l#2+6-$(QpWX+KQiuSew?{Fb8RM`2{KV;Nv1QiHgh0zDD!33imZ)Uo3l=5 z5n0?US5|A5JL~W4QQ2d%w`A|gj>=YK8?#N>XS2Jqf6iH+vms|wjwnZ+qs{T>T*|qe zJ1KX1?#$fdx!>n9b1QQja+`989U~kg9g&Vbj;|dWhs9xYTy|V{+{{~%w=r*XUUFVe zo+JO={Bijc^7rH)%0HZM$xqME%%wh?QH47T zQwtr1`GvO&?-xEOT2r*8Xj_r4$W~-8>MeR$^r(1!@%G~IVqLMV*j{|AxUaasB&;N& zB(fx>B)255WT0fIVl~$AvmA)-|x9m{aiL$sdS6OSByZpWKspUcC zhssZs$CbOvTg%-QV=CUSm|78C5mOOc;i_n@a94g%xuo)wN<*c+GNrP=aXhmm)xFhyHJ{Y1tJzS)uaVa%YtGmFT64`g z%elb0$jNYWojhlQv%~3ezIBatjdSgD9dR9VWx0x6C9dbLH?Fs}yK4{D9;&UXZLDps z8&mgw-PF48>o|2}ou}@nx(oFm)-SDJRuAeW^|Jb(>aWyaZJ5=tpkYyiv_aQkXt>)j z(D1l1sxi88Z(~WLv$3|Zzj3hfY187SRZVM}xJ`nlgr=^h?xq{fA~A^Ra=fLsrLCpCHL!Jd>zvlptwbxgwW_tTwYhCvTVUI?w!>|4 zZKvAG+v?gH++*ES+=1@H?l|`;ca6K*-P#_|KB0Y5drbSc?I+vo+THCP9pgKKI)Xbm z9sCYq$1fc>JAUt6*}17RtW)2a)S29Quk%UgGf#wPw`Y%s@`ycBPobyEQ{%bo8Sp&z zj`s$6gT3p#+q|E8*|-g56*Z7yFm`m-*NGH~GW- oTm6y#DF06XUjG6AA^%}N=I8jq|6TXq88PC&PRRYQ|6f1)AN$PA_W%F@ diff --git a/libunwind/libunwind.xcodeproj/xcuserdata/kledzik.xcuserdatad/xcschemes/xcschememanagement.plist b/libunwind/libunwind.xcodeproj/xcuserdata/kledzik.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index f336f59..0000000 --- a/libunwind/libunwind.xcodeproj/xcuserdata/kledzik.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - SchemeUserState - - all.xcscheme - - orderHint - 0 - - dyld-libunwind.a.xcscheme - - orderHint - 1 - - libunwind.dylib.xcscheme - - orderHint - 2 - - - - diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 60672c1..ee431ab 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -1,30 +1,13 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2008-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===------------------------- AddressSpace.hpp ---------------------------===// // -// C++ interface to lower levels of libuwind +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// +// Abstracts accessing local vs remote address spaces. +// +//===----------------------------------------------------------------------===// #ifndef __ADDRESSSPACE_HPP__ #define __ADDRESSSPACE_HPP__ @@ -32,400 +15,632 @@ #include #include #include -#include -#include -#include -#include -#include +#include -#include "FileAbstraction.hpp" #include "libunwind.h" -#include "InternalMacros.h" +#include "config.h" #include "dwarf2.h" +#include "EHHeaderParser.hpp" +#include "Registers.hpp" - -#if __i386__ && defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -// For iOS simulator to link, we need a __dyld section -// We need one to access private _dyld_func_lookup function. - -struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); }; - -static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL }; - - -static int my_dyld_func_lookup(const char* dyld_func_name, void **address) -{ - return (*myDyldSection.lookup)(dyld_func_name, address); -} - -bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) -{ - static void* (*p)(void*, dyld_unwind_sections*) = NULL; - - if(p == NULL) - my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p); - return p(addr, info); -} +#ifndef _LIBUNWIND_USE_DLADDR + #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) + #define _LIBUNWIND_USE_DLADDR 1 + #else + #define _LIBUNWIND_USE_DLADDR 0 + #endif #endif +#if _LIBUNWIND_USE_DLADDR +#include +#if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB) +#pragma comment(lib, "dl") +#endif +#endif + +#if defined(_LIBUNWIND_ARM_EHABI) +struct EHABIIndexEntry { + uint32_t functionOffset; + uint32_t data; +}; +#endif + +#ifdef __APPLE__ + + struct dyld_unwind_sections + { + const struct mach_header* mh; + const void* dwarf_section; + uintptr_t dwarf_section_length; + const void* compact_unwind_section; + uintptr_t compact_unwind_section_length; + }; + + // In 10.7.0 or later, libSystem.dylib implements this function. + extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); + +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) + +// When statically linked on bare-metal, the symbols for the EH table are looked +// up without going through the dynamic loader. + +// The following linker script may be used to produce the necessary sections and symbols. +// Unless the --eh-frame-hdr linker option is provided, the section is not generated +// and does not take space in the output file. +// +// .eh_frame : +// { +// __eh_frame_start = .; +// KEEP(*(.eh_frame)) +// __eh_frame_end = .; +// } +// +// .eh_frame_hdr : +// { +// KEEP(*(.eh_frame_hdr)) +// } +// +// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; +// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; + +extern char __eh_frame_start; +extern char __eh_frame_end; + +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) +extern char __eh_frame_hdr_start; +extern char __eh_frame_hdr_end; +#endif + +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) + +// When statically linked on bare-metal, the symbols for the EH table are looked +// up without going through the dynamic loader. +extern char __exidx_start; +extern char __exidx_end; + +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) + +#include +#include + +#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \ + defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) + +#include + +#endif namespace libunwind { -/// -/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread -/// in the same process. It compiles away and making local unwinds very fast. -/// -class LocalAddressSpace -{ -public: - - #if __LP64__ - typedef uint64_t pint_t; - typedef int64_t sint_t; - #else - typedef uint32_t pint_t; - typedef int32_t sint_t; - #endif - uint8_t get8(pint_t addr) { return *((uint8_t*)addr); } - uint16_t get16(pint_t addr) { return *((uint16_t*)addr); } - uint32_t get32(pint_t addr) { return *((uint32_t*)addr); } - uint64_t get64(pint_t addr) { return *((uint64_t*)addr); } - double getDouble(pint_t addr) { return *((double*)addr); } - v128 getVector(pint_t addr) { return *((v128*)addr); } - uintptr_t getP(pint_t addr); - static uint64_t getULEB128(pint_t& addr, pint_t end); - static int64_t getSLEB128(pint_t& addr, pint_t end); - - pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding); - bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset); - bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart); - +/// Used by findUnwindSections() to return info about needed sections. +struct UnwindInfoSections { +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \ + defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + // No dso_base for SEH or ARM EHABI. + uintptr_t dso_base; +#endif +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + uintptr_t dwarf_section; + uintptr_t dwarf_section_length; +#endif +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + uintptr_t dwarf_index_section; + uintptr_t dwarf_index_section_length; +#endif +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + uintptr_t compact_unwind_section; + uintptr_t compact_unwind_section_length; +#endif +#if defined(_LIBUNWIND_ARM_EHABI) + uintptr_t arm_section; + uintptr_t arm_section_length; +#endif }; -LocalAddressSpace sThisAddress; -inline uintptr_t LocalAddressSpace::getP(pint_t addr) -{ -#if __LP64__ - return get64(addr); +/// LocalAddressSpace is used as a template parameter to UnwindCursor when +/// unwinding a thread in the same process. The wrappers compile away, +/// making local unwinds fast. +class _LIBUNWIND_HIDDEN LocalAddressSpace { +public: + typedef uintptr_t pint_t; + typedef intptr_t sint_t; + uint8_t get8(pint_t addr) { + uint8_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uint16_t get16(pint_t addr) { + uint16_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uint32_t get32(pint_t addr) { + uint32_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uint64_t get64(pint_t addr) { + uint64_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + double getDouble(pint_t addr) { + double val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + v128 getVector(pint_t addr) { + v128 val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uintptr_t getP(pint_t addr); + uint64_t getRegister(pint_t addr); + static uint64_t getULEB128(pint_t &addr, pint_t end); + static int64_t getSLEB128(pint_t &addr, pint_t end); + + pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, + pint_t datarelBase = 0, + pint_t *resultAddr = nullptr); + bool findFunctionName(pint_t addr, char *buf, size_t bufLen, + unw_word_t *offset); + bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); + bool findOtherFDE(pint_t targetAddr, pint_t &fde); + + static LocalAddressSpace sThisAddressSpace; +}; + +inline uintptr_t LocalAddressSpace::getP(pint_t addr) { +#if __SIZEOF_POINTER__ == 8 + return get64(addr); #else - return get32(addr); + return get32(addr); #endif } -/* Read a ULEB128 into a 64-bit word. */ -inline uint64_t -LocalAddressSpace::getULEB128(pint_t& addr, pint_t end) -{ - const uint8_t* p = (uint8_t*)addr; - const uint8_t* pend = (uint8_t*)end; - uint64_t result = 0; - int bit = 0; - do { - uint64_t b; - - if ( p == pend ) - ABORT("truncated uleb128 expression"); - - b = *p & 0x7f; - - if (bit >= 64 || b << bit >> bit != b) { - ABORT("malformed uleb128 expression"); - } - else { - result |= b << bit; - bit += 7; - } - } while ( *p++ >= 0x80 ); - addr = (pint_t)p; - return result; +inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { +#if __SIZEOF_POINTER__ == 8 || defined(__mips64) + return get64(addr); +#else + return get32(addr); +#endif } -/* Read a SLEB128 into a 64-bit word. */ -inline int64_t -LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end) -{ - const uint8_t* p = (uint8_t*)addr; - int64_t result = 0; - int bit = 0; - uint8_t byte; - do { - byte = *p++; - result |= ((byte & 0x7f) << bit); - bit += 7; - } while (byte & 0x80); - // sign extend negative numbers - if ( (byte & 0x40) != 0 ) - result |= (-1LL) << bit; - addr = (pint_t)p; - return result; +/// Read a ULEB128 into a 64-bit word. +inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { + const uint8_t *p = (uint8_t *)addr; + const uint8_t *pend = (uint8_t *)end; + uint64_t result = 0; + int bit = 0; + do { + uint64_t b; + + if (p == pend) + _LIBUNWIND_ABORT("truncated uleb128 expression"); + + b = *p & 0x7f; + + if (bit >= 64 || b << bit >> bit != b) { + _LIBUNWIND_ABORT("malformed uleb128 expression"); + } else { + result |= b << bit; + bit += 7; + } + } while (*p++ >= 0x80); + addr = (pint_t) p; + return result; } -LocalAddressSpace::pint_t -LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding) -{ - pint_t startAddr = addr; - const uint8_t* p = (uint8_t*)addr; - pint_t result; - - // first get value - switch (encoding & 0x0F) { - case DW_EH_PE_ptr: - result = getP(addr); - p += sizeof(pint_t); - addr = (pint_t)p; - break; - case DW_EH_PE_uleb128: - result = getULEB128(addr, end); - break; - case DW_EH_PE_udata2: - result = get16(addr); - p += 2; - addr = (pint_t)p; - break; - case DW_EH_PE_udata4: - result = get32(addr); - p += 4; - addr = (pint_t)p; - break; - case DW_EH_PE_udata8: - result = get64(addr); - p += 8; - addr = (pint_t)p; - break; - case DW_EH_PE_sleb128: - result = getSLEB128(addr, end); - break; - case DW_EH_PE_sdata2: - result = (int16_t)get16(addr); - p += 2; - addr = (pint_t)p; - break; - case DW_EH_PE_sdata4: - result = (int32_t)get32(addr); - p += 4; - addr = (pint_t)p; - break; - case DW_EH_PE_sdata8: - result = get64(addr); - p += 8; - addr = (pint_t)p; - break; - default: - ABORT("unknown pointer encoding"); - } - - // then add relative offset - switch ( encoding & 0x70 ) { - case DW_EH_PE_absptr: - // do nothing - break; - case DW_EH_PE_pcrel: - result += startAddr; - break; - case DW_EH_PE_textrel: - ABORT("DW_EH_PE_textrel pointer encoding not supported"); - break; - case DW_EH_PE_datarel: - ABORT("DW_EH_PE_datarel pointer encoding not supported"); - break; - case DW_EH_PE_funcrel: - ABORT("DW_EH_PE_funcrel pointer encoding not supported"); - break; - case DW_EH_PE_aligned: - ABORT("DW_EH_PE_aligned pointer encoding not supported"); - break; - default: - ABORT("unknown pointer encoding"); - break; - } - - if ( encoding & DW_EH_PE_indirect ) - result = getP(result); - - return result; +/// Read a SLEB128 into a 64-bit word. +inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { + const uint8_t *p = (uint8_t *)addr; + const uint8_t *pend = (uint8_t *)end; + int64_t result = 0; + int bit = 0; + uint8_t byte; + do { + if (p == pend) + _LIBUNWIND_ABORT("truncated sleb128 expression"); + byte = *p++; + result |= (uint64_t)(byte & 0x7f) << bit; + bit += 7; + } while (byte & 0x80); + // sign extend negative numbers + if ((byte & 0x40) != 0 && bit < 64) + result |= (-1ULL) << bit; + addr = (pint_t) p; + return result; } +inline LocalAddressSpace::pint_t +LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, + pint_t datarelBase, pint_t *resultAddr) { + pint_t startAddr = addr; + const uint8_t *p = (uint8_t *)addr; + pint_t result; -inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart) -{ - dyld_unwind_sections info; - if ( _dyld_find_unwind_sections((void*)addr, &info) ) { - mh = (pint_t)info.mh; - dwarfStart = (pint_t)info.dwarf_section; - dwarfLen = (pint_t)info.dwarf_section_length; - compactStart = (pint_t)info.compact_unwind_section; - return true; - } - return false; + // first get value + switch (encoding & 0x0F) { + case DW_EH_PE_ptr: + result = getP(addr); + p += sizeof(pint_t); + addr = (pint_t) p; + break; + case DW_EH_PE_uleb128: + result = (pint_t)getULEB128(addr, end); + break; + case DW_EH_PE_udata2: + result = get16(addr); + p += 2; + addr = (pint_t) p; + break; + case DW_EH_PE_udata4: + result = get32(addr); + p += 4; + addr = (pint_t) p; + break; + case DW_EH_PE_udata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t) p; + break; + case DW_EH_PE_sleb128: + result = (pint_t)getSLEB128(addr, end); + break; + case DW_EH_PE_sdata2: + // Sign extend from signed 16-bit value. + result = (pint_t)(int16_t)get16(addr); + p += 2; + addr = (pint_t) p; + break; + case DW_EH_PE_sdata4: + // Sign extend from signed 32-bit value. + result = (pint_t)(int32_t)get32(addr); + p += 4; + addr = (pint_t) p; + break; + case DW_EH_PE_sdata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t) p; + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + } + + // then add relative offset + switch (encoding & 0x70) { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + result += startAddr; + break; + case DW_EH_PE_textrel: + _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); + break; + case DW_EH_PE_datarel: + // DW_EH_PE_datarel is only valid in a few places, so the parameter has a + // default value of 0, and we abort in the event that someone calls this + // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. + if (datarelBase == 0) + _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); + result += datarelBase; + break; + case DW_EH_PE_funcrel: + _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); + break; + case DW_EH_PE_aligned: + _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + break; + } + + if (encoding & DW_EH_PE_indirect) { + if (resultAddr) + *resultAddr = result; + result = getP(result); + } else { + if (resultAddr) + *resultAddr = startAddr; + } + + return result; } +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) -inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset) -{ - dl_info dyldInfo; - if ( dladdr((void*)addr, &dyldInfo) ) { - if ( dyldInfo.dli_sname != NULL ) { - strlcpy(buf, dyldInfo.dli_sname, bufLen); - *offset = (addr - (pint_t)dyldInfo.dli_saddr); - return true; - } - } - return false; +// The ElfW() macro for pointer-size independent ELF header traversal is not +// provided by on some systems (e.g., FreeBSD). On these systems the +// data structures are just called Elf_XXX. Define ElfW() locally. +#if !defined(ElfW) + #define ElfW(type) Elf_##type +#endif +#if !defined(Elf_Half) + typedef ElfW(Half) Elf_Half; +#endif +#if !defined(Elf_Phdr) + typedef ElfW(Phdr) Elf_Phdr; +#endif +#if !defined(Elf_Addr) + typedef ElfW(Addr) Elf_Addr; +#endif + +static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) { + Elf_Addr image_base = pinfo->dlpi_addr; +#if defined(__ANDROID__) && __ANDROID_API__ < 18 + if (image_base == 0) { + // Normally, an image base of 0 indicates a non-PIE executable. On + // versions of Android prior to API 18, the dynamic linker reported a + // dlpi_addr of 0 for PIE executables. Compute the true image base + // using the PT_PHDR segment. + // See https://github.com/android/ndk/issues/505. + for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { + const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; + if (phdr->p_type == PT_PHDR) { + image_base = reinterpret_cast(pinfo->dlpi_phdr) - + phdr->p_vaddr; + break; + } + } + } +#endif + return image_base; } - - -#if UNW_REMOTE - -/// -/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread -/// in the another process. The other process can be a different endianness and a different -/// pointer size and is handled by the P template parameter. -/// -template -class OtherAddressSpace -{ -public: - OtherAddressSpace(task_t task) : fTask(task) {} - - typedef typename P::uint_t pint_t; - - uint8_t get8(pint_t addr); - uint16_t get16(pint_t addr); - uint32_t get32(pint_t addr); - uint64_t get64(pint_t addr); - pint_t getP(pint_t addr); - uint64_t getULEB128(pint_t& addr, pint_t end); - int64_t getSLEB128(pint_t& addr, pint_t end); - pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding); - bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset); - bool findUnwindSections(pint_t addr, unwind_sections& info); -private: - void* localCopy(pint_t addr); - - - task_t fTask; +struct _LIBUNWIND_HIDDEN dl_iterate_cb_data { + LocalAddressSpace *addressSpace; + UnwindInfoSections *sects; + uintptr_t targetAddr; }; +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." + #endif -template -uint8_t OtherAddressSpace

::get8(pint_t addr) -{ - return *((uint8_t*)localCopy(addr)); +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) +#include "FrameHeaderCache.hpp" + +// Typically there is one cache per process, but when libunwind is built as a +// hermetic static library, then each shared object may have its own cache. +static FrameHeaderCache TheFrameHeaderCache; +#endif + +static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base, + dl_iterate_cb_data *cbdata) { + if (phdr->p_type == PT_LOAD) { + uintptr_t begin = image_base + phdr->p_vaddr; + uintptr_t end = begin + phdr->p_memsz; + if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { + cbdata->sects->dso_base = begin; + cbdata->sects->dwarf_section_length = phdr->p_memsz; + return true; + } + } + return false; } -template -uint16_t OtherAddressSpace

::get16(pint_t addr) -{ - return P::E::get16(*(uint16_t*)localCopy(addr)); +static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, + size_t pinfo_size, void *data) { + auto cbdata = static_cast(data); + if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) + return 0; +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + if (TheFrameHeaderCache.find(pinfo, pinfo_size, data)) + return 1; +#else + // Avoid warning about unused variable. + (void)pinfo_size; +#endif + + Elf_Addr image_base = calculateImageBase(pinfo); + bool found_obj = false; + bool found_hdr = false; + + // Third phdr is usually the executable phdr. + if (pinfo->dlpi_phnum > 2) + found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata); + + // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know + // that there is one or more phdrs. + for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) { + const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1]; + if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) { + EHHeaderParser::EHHeaderInfo hdrInfo; + uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr; + cbdata->sects->dwarf_index_section = eh_frame_hdr_start; + cbdata->sects->dwarf_index_section_length = phdr->p_memsz; + found_hdr = EHHeaderParser::decodeEHHdr( + *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, + hdrInfo); + if (found_hdr) + cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; + } else if (!found_obj) { + found_obj = checkAddrInSegment(phdr, image_base, cbdata); + } + if (found_obj && found_hdr) { +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + TheFrameHeaderCache.add(cbdata->sects); +#endif + return 1; + } + } + cbdata->sects->dwarf_section_length = 0; + return 0; } -template -uint32_t OtherAddressSpace

::get32(pint_t addr) -{ - return P::E::get32(*(uint32_t*)localCopy(addr)); +#elif defined(_LIBUNWIND_ARM_EHABI) + +static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, + void *data) { + auto *cbdata = static_cast(data); + bool found_obj = false; + bool found_hdr = false; + + assert(cbdata); + assert(cbdata->sects); + + if (cbdata->targetAddr < pinfo->dlpi_addr) + return 0; + + Elf_Addr image_base = calculateImageBase(pinfo); + + for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { + const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; + if (phdr->p_type == PT_LOAD) { + uintptr_t begin = image_base + phdr->p_vaddr; + uintptr_t end = begin + phdr->p_memsz; + if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) + found_obj = true; + } else if (phdr->p_type == PT_ARM_EXIDX) { + uintptr_t exidx_start = image_base + phdr->p_vaddr; + cbdata->sects->arm_section = exidx_start; + cbdata->sects->arm_section_length = phdr->p_memsz; + found_hdr = true; + } + } + return found_obj && found_hdr; } -template -uint64_t OtherAddressSpace

::get64(pint_t addr) -{ - return P::E::get64(*(uint64_t*)localCopy(addr)); -} +#endif +#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) -template -typename P::uint_t OtherAddressSpace

::getP(pint_t addr) -{ - return P::getP(*(uint64_t*)localCopy(addr)); -} -template -uint64_t OtherAddressSpace

::getULEB128(pint_t& addr, pint_t end) -{ - uintptr_t size = (end - addr); - LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr); - LocalAddressSpace::pint_t sladdr = laddr; - uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size); - addr += (laddr-sladdr); - return result; -} +inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, + UnwindInfoSections &info) { +#ifdef __APPLE__ + dyld_unwind_sections dyldInfo; + if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { + info.dso_base = (uintptr_t)dyldInfo.mh; + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; + info.dwarf_section_length = dyldInfo.dwarf_section_length; + #endif + info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; + info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; + return true; + } +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) + info.dso_base = 0; + // Bare metal is statically linked, so no need to ask the dynamic loader + info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); + info.dwarf_section = (uintptr_t)(&__eh_frame_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", + (void *)info.dwarf_section, (void *)info.dwarf_section_length); +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start); + info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", + (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); +#endif + if (info.dwarf_section_length) + return true; +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) + // Bare metal is statically linked, so no need to ask the dynamic loader + info.arm_section = (uintptr_t)(&__exidx_start); + info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", + (void *)info.arm_section, (void *)info.arm_section_length); + if (info.arm_section && info.arm_section_length) + return true; +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) + HMODULE mods[1024]; + HANDLE process = GetCurrentProcess(); + DWORD needed; -template -int64_t OtherAddressSpace

::getSLEB128(pint_t& addr, pint_t end) -{ - uintptr_t size = (end - addr); - LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr); - LocalAddressSpace::pint_t sladdr = laddr; - uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size); - addr += (laddr-sladdr); - return result; -} + if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) { + DWORD err = GetLastError(); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, " + "returned error %d", (int)err); + return false; + } -template -void* OtherAddressSpace

::localCopy(pint_t addr) -{ - // FIX ME -} + for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { + PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; + PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); + PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; + PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); + bool found_obj = false; + bool found_hdr = false; -template -bool OtherAddressSpace

::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset) -{ - // FIX ME + info.dso_base = (uintptr_t)mods[i]; + for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { + uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; + uintptr_t end = begin + pish->Misc.VirtualSize; + if (!strncmp((const char *)pish->Name, ".text", + IMAGE_SIZEOF_SHORT_NAME)) { + if (targetAddr >= begin && targetAddr < end) + found_obj = true; + } else if (!strncmp((const char *)pish->Name, ".eh_frame", + IMAGE_SIZEOF_SHORT_NAME)) { + info.dwarf_section = begin; + info.dwarf_section_length = pish->Misc.VirtualSize; + found_hdr = true; + } + if (found_obj && found_hdr) + return true; + } + } + return false; +#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) + // Don't even bother, since Windows has functions that do all this stuff + // for us. + (void)targetAddr; + (void)info; + return true; +#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) + int length = 0; + info.arm_section = + (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); + info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry); + if (info.arm_section && info.arm_section_length) + return true; +#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + dl_iterate_cb_data cb_data = {this, &info, targetAddr}; + int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); + return static_cast(found); +#endif + + return false; } +inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { + // TO DO: if OS has way to dynamically register FDEs, check that. + (void)targetAddr; + (void)fde; + return false; +} -/// -/// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to. -/// -struct unw_addr_space -{ - cpu_type_t cpuType; - task_t taskPort; -}; - - -/// -/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining -/// a 32-bit intel process. -/// -struct unw_addr_space_i386 : public unw_addr_space -{ - unw_addr_space_i386(task_t task) : oas(task) {} - OtherAddressSpace > oas; -}; - - -/// -/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining -/// a 64-bit intel process. -/// -struct unw_addr_space_x86_64 : public unw_addr_space -{ - unw_addr_space_x86_64(task_t task) : oas(task) {} - OtherAddressSpace > oas; -}; - - -/// -/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining -/// a 32-bit PowerPC process. -/// -struct unw_addr_space_ppc : public unw_addr_space -{ - unw_addr_space_ppc(task_t task) : oas(task) {} - OtherAddressSpace > oas; -}; - - -#endif // UNW_REMOTE - - -} // namespace libunwind +inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, + size_t bufLen, + unw_word_t *offset) { +#if _LIBUNWIND_USE_DLADDR + Dl_info dyldInfo; + if (dladdr((void *)addr, &dyldInfo)) { + if (dyldInfo.dli_sname != NULL) { +#ifdef __APPLE__ + strlcpy(buf, dyldInfo.dli_sname, bufLen); +#else + snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); +#endif + *offset = (addr - (pint_t) dyldInfo.dli_saddr); + return true; + } + } +#else + (void)addr; + (void)buf; + (void)bufLen; + (void)offset; +#endif + return false; +} +} // namespace libunwind #endif // __ADDRESSSPACE_HPP__ - - - - diff --git a/libunwind/src/CMakeLists.txt.apple b/libunwind/src/CMakeLists.txt.apple new file mode 100644 index 0000000..6fe8c46 --- /dev/null +++ b/libunwind/src/CMakeLists.txt.apple @@ -0,0 +1,260 @@ +# Get sources + +set(LIBUNWIND_CXX_SOURCES + libunwind.cpp + Unwind-EHABI.cpp + Unwind-seh.cpp + ) +if(APPLE AND LIBUNWIND_ENABLE_SHARED) + list(APPEND LIBUNWIND_CXX_SOURCES + Unwind_AppleExtras.cpp + ) +endif() + +set(LIBUNWIND_C_SOURCES + UnwindLevel1.c + UnwindLevel1-gcc-ext.c + Unwind-sjlj.c + ) +set_source_files_properties(${LIBUNWIND_C_SOURCES} + PROPERTIES + COMPILE_FLAGS "-std=c99") + +set(LIBUNWIND_ASM_SOURCES + UnwindRegistersRestore.S + UnwindRegistersSave.S + ) + +# See add_asm_sources() in compiler-rt for explanation of this workaround. +if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17)) + set_source_files_properties(${LIBUNWIND_ASM_SOURCES} PROPERTIES LANGUAGE C) +endif() + +set(LIBUNWIND_HEADERS + AddressSpace.hpp + assembly.h + CompactUnwinder.hpp + config.h + dwarf2.h + DwarfInstructions.hpp + DwarfParser.hpp + EHHeaderParser.hpp + FrameHeaderCache.hpp + libunwind_ext.h + Registers.hpp + RWMutex.hpp + Unwind-EHABI.h + UnwindCursor.hpp + ../include/libunwind.h + ../include/unwind.h + ) +if(APPLE) + list(APPEND LIBUNWIND_HEADERS + ../include/mach-o/compact_unwind_encoding.h + ) +endif() + +if (MSVC_IDE) + # Force them all into the headers dir on MSVC, otherwise they end up at + # project scope because they don't have extensions. + source_group("Header Files" FILES ${LIBUNWIND_HEADERS}) +endif() + +set(LIBUNWIND_SOURCES + ${LIBUNWIND_CXX_SOURCES} + ${LIBUNWIND_C_SOURCES} + ${LIBUNWIND_ASM_SOURCES}) + +# Generate library list. +if (NOT LIBUNWIND_APPLE_SYSTEM_BUILD) +add_library_flags_if(LIBUNWIND_HAS_C_LIB c) +if (LIBUNWIND_USE_COMPILER_RT) + add_library_flags("${LIBUNWIND_BUILTINS_LIBRARY}") +else() + add_library_flags_if(LIBUNWIND_HAS_GCC_S_LIB gcc_s) + add_library_flags_if(LIBUNWIND_HAS_GCC_LIB gcc) +endif() +add_library_flags_if(LIBUNWIND_HAS_DL_LIB dl) +if (LIBUNWIND_ENABLE_THREADS) + add_library_flags_if(LIBUNWIND_HAS_PTHREAD_LIB pthread) + add_compile_flags_if(LIBUNWIND_WEAK_PTHREAD_LIB -DLIBUNWIND_USE_WEAK_PTHREAD=1) +endif() +endif() + +# Setup flags. +add_link_flags_if_supported(-nodefaultlibs) + +# MINGW_LIBRARIES is defined in config-ix.cmake +add_library_flags_if(MINGW "${MINGW_LIBRARIES}") + +if (LIBUNWIND_ENABLE_SHARED AND + NOT (LIBUNWIND_SUPPORTS_FNO_EXCEPTIONS_FLAG AND + LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG)) + message(FATAL_ERROR + "Compiler doesn't support generation of unwind tables if exception " + "support is disabled. Building libunwind DSO with runtime dependency " + "on C++ ABI library is not supported.") +endif() + +function(get_iosmac_version mac_version sysroot output) + execute_process(COMMAND + /usr/libexec/PlistBuddy -c "Print :VersionMap:macOS_iOSMac:${mac_version} string" ${sysroot}/SDKSettings.plist + OUTPUT_VARIABLE + stdout + RESULT_VARIABLE + error_code) + if (error_code EQUAL 0) + string(STRIP ${stdout} iosmac_version) + message(STATUS "catalyst version for macos ${mac_version} is ${iosmac_version}") + set(${output} ${iosmac_version} PARENT_SCOPE) + else() + message(WARNING "failed to lookup catalyst version") + endif() +endfunction() + +if (APPLE) + add_compile_flags("-U__STRICT_ANSI__") + if (LIBUNWIND_APPLE_SYSTEM_BUILD) + add_link_flags("-nostdlib -dead_strip -lsystem_malloc -lsystem_c -ldyld -Wl,-upward-lcompiler_rt") + if (LIBUNWIND_APPLE_PLATFORM MATCHES "^osx") + add_link_flags("-lsystem_pthread -lsystem_platform -Wl,-upward-lc++abi") + + # For osx, add iosmac version flag in XBS to build zippered version + set(OSX_DEPLOYMENT_TARGET $ENV{MACOSX_DEPLOYMENT_TARGET}) + if (OSX_DEPLOYMENT_TARGET) + # Lookup iosmac version using XBS environment + get_iosmac_version(${OSX_DEPLOYMENT_TARGET} ${CMAKE_OSX_SYSROOT} IOSMAC_VERSION) + if (IOSMAC_VERSION) + add_link_flags("-Wl,-iosmac_version_min,${IOSMAC_VERSION}") + endif() + endif() + elseif(LIBUNWIND_APPLE_PLATFORM MATCHES "_sim$") + add_link_flags("-lsystem_sim_pthread -lsystem_sim_platform") + else() + add_link_flags("-lsystem_pthread -lsystem_platform") + endif() + add_link_flags("-L/usr/lib/system -Wl,-umbrella,System -compatibility_version 1") + if(LIBUNWIND_COMPILE_FLAGS MATCHES "-flto") + set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libunwind-lto.o) + add_link_flags("-Wl,-object_path_lto,${lto_object}") + endif() + if (NOT LIBUNWIND_VERSION) + message(FATAL_ERROR "LIBUNWIND_VERSION needs to be set for apple system build") + endif() + add_link_flags("-current_version ${LIBUNWIND_VERSION}") + else () + add_link_flags("-compatibility_version 1" "-install_name /usr/lib/libunwind.1.dylib") + + if (CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6") + add_link_flags("-current_version ${LIBUNWIND_VERSION}" "/usr/lib/libSystem.B.dylib") + endif () + endif() +endif () + +string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}") +string(REPLACE ";" " " LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}") +string(REPLACE ";" " " LIBUNWIND_C_FLAGS "${LIBUNWIND_C_FLAGS}") +string(REPLACE ";" " " LIBUNWIND_LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}") + +set_property(SOURCE ${LIBUNWIND_CXX_SOURCES} + APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_CXX_FLAGS}") +set_property(SOURCE ${LIBUNWIND_C_SOURCES} + APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_C_FLAGS}") + +# NOTE: avoid implicit dependencies on C++ runtimes. libunwind uses C++ for +# ease, but does not rely on C++ at runtime. +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") + +# Build the shared library. +if (LIBUNWIND_ENABLE_SHARED) + add_library(unwind_shared SHARED ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS}) + if (NOT LIBUNWIND_APPLE_SYSTEM_BUILD) + if(CMAKE_C_COMPILER_ID STREQUAL MSVC) + target_compile_options(unwind_shared PRIVATE /GR-) + else() + target_compile_options(unwind_shared PRIVATE -fno-rtti) + endif() + if(COMMAND llvm_setup_rpath) + llvm_setup_rpath(unwind_shared) + endif() + endif() + target_link_libraries(unwind_shared PRIVATE ${LIBUNWIND_LIBRARIES}) + if (LIBUNWIND_APPLE_SYSTEM_BUILD) + set_target_properties(unwind_shared PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}" + LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}" + OUTPUT_NAME "unwind" ) + else() + set_target_properties(unwind_shared PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}" + LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}" + LINKER_LANGUAGE C + OUTPUT_NAME "unwind" + VERSION "1.0" + SOVERSION "1") + endif() + list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_shared") + if (LIBUNWIND_INSTALL_SHARED_LIBRARY) + list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_shared") + endif() +endif() + +# Build the static library. +if (LIBUNWIND_ENABLE_STATIC) + add_library(unwind_static STATIC ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS}) + if(CMAKE_C_COMPILER_ID STREQUAL MSVC) + target_compile_options(unwind_static PRIVATE /GR-) + else() + target_compile_options(unwind_static PRIVATE -fno-rtti) + endif() + target_link_libraries(unwind_static PRIVATE ${LIBUNWIND_LIBRARIES}) + set_target_properties(unwind_static PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}" + LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}" + LINKER_LANGUAGE C + OUTPUT_NAME "unwind") + + if(LIBUNWIND_HERMETIC_STATIC_LIBRARY) + append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility=hidden) + append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility-global-new-delete-hidden) + target_compile_options(unwind_static PRIVATE ${UNWIND_STATIC_LIBRARY_FLAGS}) + target_compile_definitions(unwind_static PRIVATE _LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) + endif() + + list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_static") + if (LIBUNWIND_INSTALL_STATIC_LIBRARY) + list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_static") + endif() +endif() + +# Add a meta-target for both libraries. +add_custom_target(unwind DEPENDS ${LIBUNWIND_BUILD_TARGETS}) + +if (LIBUNWIND_INSTALL_LIBRARY) + install(TARGETS ${LIBUNWIND_INSTALL_TARGETS} + LIBRARY DESTINATION ${LIBUNWIND_INSTALL_PREFIX}${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind + ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_PREFIX}${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind) +endif() + +if (NOT CMAKE_CONFIGURATION_TYPES AND LIBUNWIND_INSTALL_LIBRARY) + add_custom_target(install-unwind + DEPENDS unwind + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=unwind + -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") + add_custom_target(install-unwind-stripped + DEPENDS unwind + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=unwind + -DCMAKE_INSTALL_DO_STRIP=1 + -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") +endif() diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp index 10b4078..d09e024 100644 --- a/libunwind/src/CompactUnwinder.hpp +++ b/libunwind/src/CompactUnwinder.hpp @@ -1,1028 +1,945 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2008 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===-------------------------- CompactUnwinder.hpp -----------------------===// // -// C++ interface to lower levels of libuwind +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// +// Does runtime stack unwinding using compact unwind encodings. +// +//===----------------------------------------------------------------------===// #ifndef __COMPACT_UNWINDER_HPP__ #define __COMPACT_UNWINDER_HPP__ #include -#include #include #include #include -#include "AddressSpace.hpp" #include "Registers.hpp" - - -#define EXTRACT_BITS(value, mask) \ - ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) ) - -#define SUPPORT_OLD_BINARIES 0 +#define EXTRACT_BITS(value, mask) \ + ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1)) namespace libunwind { - - -/// -/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka unwind) by -/// modifying a Registers_x86 register set -/// +#if defined(_LIBUNWIND_TARGET_I386) +/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_x86 register set template -class CompactUnwinder_x86 -{ +class CompactUnwinder_x86 { public: - static int stepWithCompactEncoding(compact_unwind_encoding_t info, uint32_t functionStart, A& addressSpace, Registers_x86& registers); - + static int stepWithCompactEncoding(compact_unwind_encoding_t info, + uint32_t functionStart, A &addressSpace, + Registers_x86 ®isters); + private: - typename A::pint_t pint_t; - - static void frameUnwind(A& addressSpace, Registers_x86& registers); - static void framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers); - static int stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers); - static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers, bool indirectStackSize); -#if SUPPORT_OLD_BINARIES - static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers); -#endif + typename A::pint_t pint_t; + + static void frameUnwind(A &addressSpace, Registers_x86 ®isters); + static void framelessUnwind(A &addressSpace, + typename A::pint_t returnAddressLocation, + Registers_x86 ®isters); + static int + stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, + uint32_t functionStart, A &addressSpace, + Registers_x86 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize); }; - +template +int CompactUnwinder_x86::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters) { + switch (compactEncoding & UNWIND_X86_MODE_MASK) { + case UNWIND_X86_MODE_EBP_FRAME: + return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_X86_MODE_STACK_IMMD: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, false); + case UNWIND_X86_MODE_STACK_IND: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, true); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} template -int CompactUnwinder_x86::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers) -{ - //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding); - switch ( compactEncoding & UNWIND_X86_MODE_MASK ) { -#if SUPPORT_OLD_BINARIES - case UNWIND_X86_MODE_COMPATIBILITY: - return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers); -#endif - case UNWIND_X86_MODE_EBP_FRAME: - return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, addressSpace, registers); - case UNWIND_X86_MODE_STACK_IMMD: - return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false); - case UNWIND_X86_MODE_STACK_IND: - return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true); - } - ABORT("invalid compact unwind encoding"); +int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters) { + uint32_t savedRegistersOffset = + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); + + uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; + for (int i = 0; i < 5; ++i) { + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_REG_NONE: + // no register saved in this slot + break; + case UNWIND_X86_REG_EBX: + registers.setEBX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ECX: + registers.setECX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDX: + registers.setEDX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDI: + registers.setEDI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ESI: + registers.setESI(addressSpace.get32(savedRegisters)); + break; + default: + (void)functionStart; + _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " + "function starting at 0x%X", + compactEncoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 4; + savedRegistersLocations = (savedRegistersLocations >> 3); + } + frameUnwind(addressSpace, registers); + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_x86::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) { + uint32_t stackSizeEncoded = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); + uint32_t regCount = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); + uint32_t stackSize = stackSizeEncoded * 4; + if (indirectStackSize) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); + stackSize = subl + 4 * stackAdjust; + } + // decompress permutation + uint32_t permunreg[6]; + switch (regCount) { + case 6: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation / 60; + permutation -= (permunreg[0] * 60); + permunreg[1] = permutation / 12; + permutation -= (permunreg[1] * 12); + permunreg[2] = permutation / 3; + permutation -= (permunreg[2] * 3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation / 20; + permutation -= (permunreg[0] * 20); + permunreg[1] = permutation / 4; + permutation -= (permunreg[1] * 4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation / 5; + permutation -= (permunreg[0] * 5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // re-number registers back to standard numbers + int registersSaved[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (uint32_t i = 0; i < regCount; ++i) { + uint32_t renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permunreg[i]) { + registersSaved[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; + for (uint32_t i = 0; i < regCount; ++i) { + switch (registersSaved[i]) { + case UNWIND_X86_REG_EBX: + registers.setEBX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ECX: + registers.setECX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDX: + registers.setEDX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDI: + registers.setEDI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ESI: + registers.setESI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EBP: + registers.setEBP(addressSpace.get32(savedRegisters)); + break; + default: + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " + "function starting at 0x%X", + encoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 4; + } + framelessUnwind(addressSpace, savedRegisters, registers); + return UNW_STEP_SUCCESS; } template -int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, - A& addressSpace, Registers_x86& registers) -{ - uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); - uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); - - uint64_t savedRegisters = registers.getEBP() - 4*savedRegistersOffset; - for (int i=0; i < 5; ++i) { - switch (savedRegistersLocations & 0x7) { - case UNWIND_X86_REG_NONE: - // no register saved in this slot - break; - case UNWIND_X86_REG_EBX: - registers.setEBX(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_ECX: - registers.setECX(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_EDX: - registers.setEDX(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_EDI: - registers.setEDI(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_ESI: - registers.setESI(addressSpace.get32(savedRegisters)); - break; - default: - DEBUG_MESSAGE("bad register for EBP frame, encoding=%08X for function starting at 0x%X\n", compactEncoding, functionStart); - ABORT("invalid compact unwind encoding"); - } - savedRegisters += 4; - savedRegistersLocations = (savedRegistersLocations >> 3); - } - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; -} - - -template -int CompactUnwinder_x86::stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding, uint32_t functionStart, - A& addressSpace, Registers_x86& registers, bool indirectStackSize) -{ - uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); - uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); - uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); - uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); - uint32_t stackSize = stackSizeEncoded*4; - if ( indirectStackSize ) { - // stack size is encoded in subl $xxx,%esp instruction - uint32_t subl = addressSpace.get32(functionStart+stackSizeEncoded); - stackSize = subl + 4*stackAdjust; - } - // decompress permutation - int permunreg[6]; - switch ( regCount ) { - case 6: - permunreg[0] = permutation/120; - permutation -= (permunreg[0]*120); - permunreg[1] = permutation/24; - permutation -= (permunreg[1]*24); - permunreg[2] = permutation/6; - permutation -= (permunreg[2]*6); - permunreg[3] = permutation/2; - permutation -= (permunreg[3]*2); - permunreg[4] = permutation; - permunreg[5] = 0; - break; - case 5: - permunreg[0] = permutation/120; - permutation -= (permunreg[0]*120); - permunreg[1] = permutation/24; - permutation -= (permunreg[1]*24); - permunreg[2] = permutation/6; - permutation -= (permunreg[2]*6); - permunreg[3] = permutation/2; - permutation -= (permunreg[3]*2); - permunreg[4] = permutation; - break; - case 4: - permunreg[0] = permutation/60; - permutation -= (permunreg[0]*60); - permunreg[1] = permutation/12; - permutation -= (permunreg[1]*12); - permunreg[2] = permutation/3; - permutation -= (permunreg[2]*3); - permunreg[3] = permutation; - break; - case 3: - permunreg[0] = permutation/20; - permutation -= (permunreg[0]*20); - permunreg[1] = permutation/4; - permutation -= (permunreg[1]*4); - permunreg[2] = permutation; - break; - case 2: - permunreg[0] = permutation/5; - permutation -= (permunreg[0]*5); - permunreg[1] = permutation; - break; - case 1: - permunreg[0] = permutation; - break; - } - // re-number registers back to standard numbers - int registersSaved[6]; - bool used[7] = { false, false, false, false, false, false, false }; - for (uint32_t i=0; i < regCount; ++i) { - int renum = 0; - for (int u=1; u < 7; ++u) { - if ( !used[u] ) { - if ( renum == permunreg[i] ) { - registersSaved[i] = u; - used[u] = true; - break; - } - ++renum; - } - } - } - uint64_t savedRegisters = registers.getSP() + stackSize - 4 - 4*regCount; - for (uint32_t i=0; i < regCount; ++i) { - switch ( registersSaved[i] ) { - case UNWIND_X86_REG_EBX: - registers.setEBX(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_ECX: - registers.setECX(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_EDX: - registers.setEDX(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_EDI: - registers.setEDI(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_ESI: - registers.setESI(addressSpace.get32(savedRegisters)); - break; - case UNWIND_X86_REG_EBP: - registers.setEBP(addressSpace.get32(savedRegisters)); - break; - default: - DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%X\n", encoding, functionStart); - ABORT("invalid compact unwind encoding"); - } - savedRegisters += 4; - } - framelessUnwind(addressSpace, savedRegisters, registers); - return UNW_STEP_SUCCESS; -} - - -#if SUPPORT_OLD_BINARIES -template -int CompactUnwinder_x86::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers) -{ - //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding); - typename A::pint_t savedRegisters; - uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_SIZE); - uint32_t stackSize; - uint32_t stackAdjust; - switch (compactEncoding & UNWIND_X86_CASE_MASK ) { - case UNWIND_X86_UNWIND_INFO_UNSPECIFIED: - return UNW_ENOINFO; - - case UNWIND_X86_EBP_FRAME_NO_REGS: - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_EBX: - savedRegisters = registers.getEBP() - 4; - registers.setEBX(addressSpace.get32(savedRegisters)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_ESI: - savedRegisters = registers.getEBP() - 4; - registers.setESI(addressSpace.get32(savedRegisters)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_EDI: - savedRegisters = registers.getEBP() - 4; - registers.setEDI(addressSpace.get32(savedRegisters)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_EBX_ESI: - savedRegisters = registers.getEBP() - 8; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_ESI_EDI: - savedRegisters = registers.getEBP() - 8; - registers.setESI(addressSpace.get32(savedRegisters)); - registers.setEDI(addressSpace.get32(savedRegisters+4)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_EBX_ESI_EDI: - savedRegisters = registers.getEBP() - 12; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - registers.setEDI(addressSpace.get32(savedRegisters+8)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_EBP_FRAME_EBX_EDI: - savedRegisters = registers.getEBP() - 8; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setEDI(addressSpace.get32(savedRegisters+4)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_NO_REGS: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*0; - framelessUnwind(addressSpace, savedRegisters+4*0, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_EBX: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*1; - registers.setEBX(addressSpace.get32(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+4*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_ESI: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*1; - registers.setESI(addressSpace.get32(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+4*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_EDI: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*1; - registers.setEDI(addressSpace.get32(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+4*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_EBX_ESI: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*2; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - framelessUnwind(addressSpace, savedRegisters+4*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_ESI_EDI: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*2; - registers.setESI(addressSpace.get32(savedRegisters)); - registers.setEDI(addressSpace.get32(savedRegisters+4)); - framelessUnwind(addressSpace, savedRegisters+4*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_ESI_EDI_EBP: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*3; - registers.setESI(addressSpace.get32(savedRegisters)); - registers.setEDI(addressSpace.get32(savedRegisters+4)); - registers.setEBP(addressSpace.get32(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+4*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_EBX_ESI_EDI: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*3; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - registers.setEDI(addressSpace.get32(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+4*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IMM_STK_EBX_ESI_EDI_EBP: - stackSize = stackValue * 4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*4; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - registers.setEDI(addressSpace.get32(savedRegisters+8)); - registers.setEBP(addressSpace.get32(savedRegisters+12)); - framelessUnwind(addressSpace, savedRegisters+4*4, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_NO_REGS: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*0; - framelessUnwind(addressSpace, savedRegisters+4*0, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_EBX: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*1; - registers.setEBX(addressSpace.get32(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+4*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_ESI: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*1; - registers.setESI(addressSpace.get32(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+4*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_EDI: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*1; - registers.setEDI(addressSpace.get32(savedRegisters)); - return UNW_STEP_SUCCESS; - framelessUnwind(addressSpace, savedRegisters+4*1, registers); - - case UNWIND_X86_IND_STK_EBX_ESI: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*2; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - framelessUnwind(addressSpace, savedRegisters+4*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_ESI_EDI: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*2; - registers.setESI(addressSpace.get32(savedRegisters)); - registers.setEDI(addressSpace.get32(savedRegisters+4)); - framelessUnwind(addressSpace, savedRegisters+4*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_ESI_EDI_EBP: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*3; - registers.setESI(addressSpace.get32(savedRegisters)); - registers.setEDI(addressSpace.get32(savedRegisters+4)); - registers.setEBP(addressSpace.get32(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+4*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_EBX_ESI_EDI: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*3; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - registers.setEDI(addressSpace.get32(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+4*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_IND_STK_EBX_ESI_EDI_EBP: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST); - stackSize += stackAdjust*4; - savedRegisters = registers.getSP() + stackSize - 4 - 4*4; - registers.setEBX(addressSpace.get32(savedRegisters)); - registers.setESI(addressSpace.get32(savedRegisters+4)); - registers.setEDI(addressSpace.get32(savedRegisters+8)); - registers.setEBP(addressSpace.get32(savedRegisters+12)); - framelessUnwind(addressSpace, savedRegisters+4*4, registers); - return UNW_STEP_SUCCESS; - - default: - DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%X\n", - compactEncoding & UNWIND_X86_CASE_MASK, functionStart); - ABORT("unknown compact unwind encoding"); - } - return UNW_EINVAL; -} -#endif // SUPPORT_OLD_BINARIES - - - -template -void CompactUnwinder_x86::frameUnwind(A& addressSpace, Registers_x86& registers) -{ - typename A::pint_t bp = registers.getEBP(); - // ebp points to old ebp - registers.setEBP(addressSpace.get32(bp)); - // old esp is ebp less saved ebp and return address - registers.setSP(bp+8); - // pop return address into eip - registers.setIP(addressSpace.get32(bp+4)); +void CompactUnwinder_x86::frameUnwind(A &addressSpace, + Registers_x86 ®isters) { + typename A::pint_t bp = registers.getEBP(); + // ebp points to old ebp + registers.setEBP(addressSpace.get32(bp)); + // old esp is ebp less saved ebp and return address + registers.setSP((uint32_t)bp + 8); + // pop return address into eip + registers.setIP(addressSpace.get32(bp + 4)); } template -void CompactUnwinder_x86::framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers) -{ - // return address is on stack after last saved register - registers.setIP(addressSpace.get32(returnAddressLocation)); - // old esp is before return address - registers.setSP(returnAddressLocation+4); +void CompactUnwinder_x86::framelessUnwind( + A &addressSpace, typename A::pint_t returnAddressLocation, + Registers_x86 ®isters) { + // return address is on stack after last saved register + registers.setIP(addressSpace.get32(returnAddressLocation)); + // old esp is before return address + registers.setSP((uint32_t)returnAddressLocation + 4); } +#endif // _LIBUNWIND_TARGET_I386 - - - -/// -/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka unwind) by -/// modifying a Registers_x86_64 register set -/// +#if defined(_LIBUNWIND_TARGET_X86_64) +/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_x86_64 register set template -class CompactUnwinder_x86_64 -{ +class CompactUnwinder_x86_64 { public: - static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers); - + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters); + private: - typename A::pint_t pint_t; - - static void frameUnwind(A& addressSpace, Registers_x86_64& registers); - static void framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers); - static int stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers); - static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers, bool indirectStackSize); -#if SUPPORT_OLD_BINARIES - static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers); -#endif + typename A::pint_t pint_t; + + static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); + static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, + Registers_x86_64 ®isters); + static int + stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize); }; - template -int CompactUnwinder_x86_64::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers) -{ - //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding); - switch ( compactEncoding & UNWIND_X86_64_MODE_MASK ) { -#if SUPPORT_OLD_BINARIES - case UNWIND_X86_64_MODE_COMPATIBILITY: - return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers); -#endif - case UNWIND_X86_64_MODE_RBP_FRAME: - return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, addressSpace, registers); - case UNWIND_X86_64_MODE_STACK_IMMD: - return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false); - case UNWIND_X86_64_MODE_STACK_IND: - return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true); - } - ABORT("invalid compact unwind encoding"); -} - - -template -int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, - A& addressSpace, Registers_x86_64& registers) -{ - uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); - uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); - - uint64_t savedRegisters = registers.getRBP() - 8*savedRegistersOffset; - for (int i=0; i < 5; ++i) { - switch (savedRegistersLocations & 0x7) { - case UNWIND_X86_64_REG_NONE: - // no register saved in this slot - break; - case UNWIND_X86_64_REG_RBX: - registers.setRBX(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R12: - registers.setR12(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R13: - registers.setR13(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R14: - registers.setR14(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R15: - registers.setR15(addressSpace.get64(savedRegisters)); - break; - default: - DEBUG_MESSAGE("bad register for RBP frame, encoding=%08X for function starting at 0x%llX\n", compactEncoding, functionStart); - ABORT("invalid compact unwind encoding"); - } - savedRegisters += 8; - savedRegistersLocations = (savedRegistersLocations >> 3); - } - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; -} - - -template -int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding, uint64_t functionStart, - A& addressSpace, Registers_x86_64& registers, bool indirectStackSize) -{ - uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); - uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); - uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); - uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); - uint32_t stackSize = stackSizeEncoded*8; - if ( indirectStackSize ) { - // stack size is encoded in subl $xxx,%esp instruction - uint32_t subl = addressSpace.get32(functionStart+stackSizeEncoded); - stackSize = subl + 8*stackAdjust; - } - // decompress permutation - int permunreg[6]; - switch ( regCount ) { - case 6: - permunreg[0] = permutation/120; - permutation -= (permunreg[0]*120); - permunreg[1] = permutation/24; - permutation -= (permunreg[1]*24); - permunreg[2] = permutation/6; - permutation -= (permunreg[2]*6); - permunreg[3] = permutation/2; - permutation -= (permunreg[3]*2); - permunreg[4] = permutation; - permunreg[5] = 0; - break; - case 5: - permunreg[0] = permutation/120; - permutation -= (permunreg[0]*120); - permunreg[1] = permutation/24; - permutation -= (permunreg[1]*24); - permunreg[2] = permutation/6; - permutation -= (permunreg[2]*6); - permunreg[3] = permutation/2; - permutation -= (permunreg[3]*2); - permunreg[4] = permutation; - break; - case 4: - permunreg[0] = permutation/60; - permutation -= (permunreg[0]*60); - permunreg[1] = permutation/12; - permutation -= (permunreg[1]*12); - permunreg[2] = permutation/3; - permutation -= (permunreg[2]*3); - permunreg[3] = permutation; - break; - case 3: - permunreg[0] = permutation/20; - permutation -= (permunreg[0]*20); - permunreg[1] = permutation/4; - permutation -= (permunreg[1]*4); - permunreg[2] = permutation; - break; - case 2: - permunreg[0] = permutation/5; - permutation -= (permunreg[0]*5); - permunreg[1] = permutation; - break; - case 1: - permunreg[0] = permutation; - break; - } - // re-number registers back to standard numbers - int registersSaved[6]; - bool used[7] = { false, false, false, false, false, false, false }; - for (uint32_t i=0; i < regCount; ++i) { - int renum = 0; - for (int u=1; u < 7; ++u) { - if ( !used[u] ) { - if ( renum == permunreg[i] ) { - registersSaved[i] = u; - used[u] = true; - break; - } - ++renum; - } - } - } - uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8*regCount; - for (uint32_t i=0; i < regCount; ++i) { - switch ( registersSaved[i] ) { - case UNWIND_X86_64_REG_RBX: - registers.setRBX(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R12: - registers.setR12(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R13: - registers.setR13(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R14: - registers.setR14(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_R15: - registers.setR15(addressSpace.get64(savedRegisters)); - break; - case UNWIND_X86_64_REG_RBP: - registers.setRBP(addressSpace.get64(savedRegisters)); - break; - default: - DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%llX\n", encoding, functionStart); - ABORT("invalid compact unwind encoding"); - } - savedRegisters += 8; - } - framelessUnwind(addressSpace, savedRegisters, registers); - return UNW_STEP_SUCCESS; -} - -#if SUPPORT_OLD_BINARIES -template -int CompactUnwinder_x86_64::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers) -{ - uint64_t savedRegisters; - uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_SIZE); - uint64_t stackSize; - uint32_t stackAdjust; - - switch (compactEncoding & UNWIND_X86_64_CASE_MASK ) { - case UNWIND_X86_64_UNWIND_INFO_UNSPECIFIED: - return UNW_ENOINFO; - - case UNWIND_X86_64_RBP_FRAME_NO_REGS: - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_RBP_FRAME_RBX: - savedRegisters = registers.getRBP() - 8*1; - registers.setRBX(addressSpace.get64(savedRegisters)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_RBP_FRAME_RBX_R12: - savedRegisters = registers.getRBP() - 8*2; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13: - savedRegisters = registers.getRBP() - 8*3; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14: - savedRegisters = registers.getRBP() - 8*4; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - registers.setR14(addressSpace.get64(savedRegisters+24)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14_R15: - savedRegisters = registers.getRBP() - 8*5; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - registers.setR14(addressSpace.get64(savedRegisters+24)); - registers.setR15(addressSpace.get64(savedRegisters+32)); - frameUnwind(addressSpace, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_NO_REGS: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*0; - framelessUnwind(addressSpace, savedRegisters+8*0, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*1; - registers.setRBX(addressSpace.get64(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+8*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_R12: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*2; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+8*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_RBP: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*2; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+8*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_R12_R13: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*3; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - framelessUnwind(addressSpace, savedRegisters+8*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*4; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - registers.setR14(addressSpace.get64(savedRegisters+24)); - framelessUnwind(addressSpace, savedRegisters+8*4, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14_R15: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*5; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - registers.setR14(addressSpace.get64(savedRegisters+24)); - registers.setR15(addressSpace.get64(savedRegisters+32)); - framelessUnwind(addressSpace, savedRegisters+8*5, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14_R15: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*6; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - registers.setR13(addressSpace.get64(savedRegisters+24)); - registers.setR14(addressSpace.get64(savedRegisters+32)); - registers.setR15(addressSpace.get64(savedRegisters+40)); - framelessUnwind(addressSpace, savedRegisters+8*6, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_RBP_R12: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*3; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - framelessUnwind(addressSpace, savedRegisters+8*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*4; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - registers.setR13(addressSpace.get64(savedRegisters+24)); - framelessUnwind(addressSpace, savedRegisters+8*4, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14: - stackSize = stackValue * 8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*5; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - registers.setR13(addressSpace.get64(savedRegisters+24)); - registers.setR14(addressSpace.get64(savedRegisters+32)); - framelessUnwind(addressSpace, savedRegisters+8*5, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_NO_REGS: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*0; - framelessUnwind(addressSpace, savedRegisters+8*0, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*1; - registers.setRBX(addressSpace.get64(savedRegisters)); - framelessUnwind(addressSpace, savedRegisters+8*1, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_R12: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*2; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+8*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_RBP: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*2; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - framelessUnwind(addressSpace, savedRegisters+8*2, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_R12_R13: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*3; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - framelessUnwind(addressSpace, savedRegisters+8*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*4; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - registers.setR14(addressSpace.get64(savedRegisters+24)); - framelessUnwind(addressSpace, savedRegisters+8*4, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14_R15: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*5; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setR12(addressSpace.get64(savedRegisters+8)); - registers.setR13(addressSpace.get64(savedRegisters+16)); - registers.setR14(addressSpace.get64(savedRegisters+24)); - registers.setR15(addressSpace.get64(savedRegisters+32)); - framelessUnwind(addressSpace, savedRegisters+8*5, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14_R15: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*6; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - registers.setR13(addressSpace.get64(savedRegisters+24)); - registers.setR14(addressSpace.get64(savedRegisters+32)); - registers.setR15(addressSpace.get64(savedRegisters+40)); - framelessUnwind(addressSpace, savedRegisters+8*6, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_RBP_R12: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*3; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - framelessUnwind(addressSpace, savedRegisters+8*3, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*4; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - registers.setR13(addressSpace.get64(savedRegisters+24)); - framelessUnwind(addressSpace, savedRegisters+8*4, registers); - return UNW_STEP_SUCCESS; - - case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14: - stackSize = addressSpace.get32(functionStart+stackValue); - stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST); - stackSize += stackAdjust*8; - savedRegisters = registers.getSP() + stackSize - 8 - 8*5; - registers.setRBX(addressSpace.get64(savedRegisters)); - registers.setRBP(addressSpace.get64(savedRegisters+8)); - registers.setR12(addressSpace.get64(savedRegisters+16)); - registers.setR13(addressSpace.get64(savedRegisters+24)); - registers.setR14(addressSpace.get64(savedRegisters+32)); - framelessUnwind(addressSpace, savedRegisters+8*5, registers); - return UNW_STEP_SUCCESS; - - default: - DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%llX\n", - compactEncoding & UNWIND_X86_64_CASE_MASK, functionStart); - ABORT("unknown compact unwind encoding"); - } - return UNW_EINVAL; -} -#endif // SUPPORT_OLD_BINARIES - - -template -void CompactUnwinder_x86_64::frameUnwind(A& addressSpace, Registers_x86_64& registers) -{ - uint64_t rbp = registers.getRBP(); - // ebp points to old ebp - registers.setRBP(addressSpace.get64(rbp)); - // old esp is ebp less saved ebp and return address - registers.setSP(rbp+16); - // pop return address into eip - registers.setIP(addressSpace.get64(rbp+8)); +int CompactUnwinder_x86_64::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters) { + switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { + case UNWIND_X86_64_MODE_RBP_FRAME: + return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_X86_64_MODE_STACK_IMMD: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, false); + case UNWIND_X86_64_MODE_STACK_IND: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, true); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); } template -void CompactUnwinder_x86_64::framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers) -{ - // return address is on stack after last saved register - registers.setIP(addressSpace.get64(returnAddressLocation)); - // old esp is before return address - registers.setSP(returnAddressLocation+8); +int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters) { + uint32_t savedRegistersOffset = + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); + + uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; + for (int i = 0; i < 5; ++i) { + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_64_REG_NONE: + // no register saved in this slot + break; + case UNWIND_X86_64_REG_RBX: + registers.setRBX(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R12: + registers.setR12(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R13: + registers.setR13(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R14: + registers.setR14(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R15: + registers.setR15(addressSpace.get64(savedRegisters)); + break; + default: + (void)functionStart; + _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " + "function starting at 0x%llX", + compactEncoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 8; + savedRegistersLocations = (savedRegistersLocations >> 3); + } + frameUnwind(addressSpace, registers); + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters, bool indirectStackSize) { + uint32_t stackSizeEncoded = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); + uint32_t regCount = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); + uint32_t stackSize = stackSizeEncoded * 8; + if (indirectStackSize) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); + stackSize = subl + 8 * stackAdjust; + } + // decompress permutation + uint32_t permunreg[6]; + switch (regCount) { + case 6: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation / 60; + permutation -= (permunreg[0] * 60); + permunreg[1] = permutation / 12; + permutation -= (permunreg[1] * 12); + permunreg[2] = permutation / 3; + permutation -= (permunreg[2] * 3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation / 20; + permutation -= (permunreg[0] * 20); + permunreg[1] = permutation / 4; + permutation -= (permunreg[1] * 4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation / 5; + permutation -= (permunreg[0] * 5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // re-number registers back to standard numbers + int registersSaved[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (uint32_t i = 0; i < regCount; ++i) { + uint32_t renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permunreg[i]) { + registersSaved[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; + for (uint32_t i = 0; i < regCount; ++i) { + switch (registersSaved[i]) { + case UNWIND_X86_64_REG_RBX: + registers.setRBX(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R12: + registers.setR12(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R13: + registers.setR13(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R14: + registers.setR14(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R15: + registers.setR15(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_RBP: + registers.setRBP(addressSpace.get64(savedRegisters)); + break; + default: + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " + "function starting at 0x%llX", + encoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 8; + } + framelessUnwind(addressSpace, savedRegisters, registers); + return UNW_STEP_SUCCESS; } -}; // namespace libunwind +template +void CompactUnwinder_x86_64::frameUnwind(A &addressSpace, + Registers_x86_64 ®isters) { + uint64_t rbp = registers.getRBP(); + // ebp points to old ebp + registers.setRBP(addressSpace.get64(rbp)); + // old esp is ebp less saved ebp and return address + registers.setSP(rbp + 16); + // pop return address into eip + registers.setIP(addressSpace.get64(rbp + 8)); +} + +template +void CompactUnwinder_x86_64::framelessUnwind(A &addressSpace, + uint64_t returnAddressLocation, + Registers_x86_64 ®isters) { + // return address is on stack after last saved register + registers.setIP(addressSpace.get64(returnAddressLocation)); + // old esp is before return address + registers.setSP(returnAddressLocation + 8); +} +#endif // _LIBUNWIND_TARGET_X86_64 +#if defined(_LIBUNWIND_TARGET_AARCH64) +/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_arm64 register set +template +class CompactUnwinder_arm64 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + unw_word_t procInfoFlags, Registers_arm64 ®isters); + +private: + typename A::pint_t pint_t; + + static int + stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + unw_word_t procInfoFlags, Registers_arm64 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, unw_word_t procInfoFlags, Registers_arm64 ®isters); +}; + +template +int CompactUnwinder_arm64::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, unw_word_t procInfoFlags, Registers_arm64 ®isters) { + switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { + case UNWIND_ARM64_MODE_FRAME: + return stepWithCompactEncodingFrame(compactEncoding, functionStart, + addressSpace, procInfoFlags, registers); + case UNWIND_ARM64_MODE_FRAMELESS: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, procInfoFlags, registers); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, + unw_word_t procInfoFlags, + Registers_arm64 ®isters) { + uint32_t stackSize = + 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); + + uint64_t savedRegisterLoc = registers.getSP() + stackSize; + + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + registers.setFloatRegister(UNW_ARM64_D8, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D9, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + registers.setFloatRegister(UNW_ARM64_D10, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D11, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + registers.setFloatRegister(UNW_ARM64_D12, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D13, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + registers.setFloatRegister(UNW_ARM64_D14, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D15, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + Registers_arm64::reg_t linkRegister = registers.getRegister(UNW_ARM64_LR); + + // subtract stack size off of sp + registers.setSP(savedRegisterLoc); + + registers.normalizeNewLinkRegister(linkRegister, procInfoFlags); + + // set pc to be value in lr + registers.setIP(linkRegister); + + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_arm64::stepWithCompactEncodingFrame( + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, + unw_word_t procInfoFlags, Registers_arm64 ®isters) { + uint64_t savedRegisterLoc = registers.getFP() - 8; + + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + registers.setFloatRegister(UNW_ARM64_D8, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D9, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + registers.setFloatRegister(UNW_ARM64_D10, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D11, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + registers.setFloatRegister(UNW_ARM64_D12, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D13, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + registers.setFloatRegister(UNW_ARM64_D14, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D15, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + uint64_t fp = registers.getFP(); + // fp points to old fp + registers.setFP(addressSpace.get64(fp)); + // old sp is fp less saved fp and lr + registers.setSP(fp + 16); + + // pop return address into pc + Registers_arm64::reg_t linkRegister = addressSpace.get64(fp + 8); + + registers.normalizeNewLinkRegister(linkRegister, procInfoFlags); + + registers.setIP(linkRegister); + + return UNW_STEP_SUCCESS; +} +#endif // _LIBUNWIND_TARGET_AARCH64 + + +#if defined(_LIBUNWIND_TARGET_ARM) + +/// CompactUnwinder_arm uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_arm register set +template +class CompactUnwinder_arm { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm ®isters); + +private: + typename A::pint_t pint_t; + + static int + stepFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm ®isters); + static int + stepFrameD(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm ®isters); +}; + +template +int CompactUnwinder_arm::stepWithCompactEncoding( + compact_unwind_encoding_t encoding, uint64_t functionStart, + A &addressSpace, Registers_arm ®isters) { + switch (encoding & UNWIND_ARM_MODE_MASK) { + case UNWIND_ARM_MODE_FRAME: + return stepFrame(encoding, functionStart, addressSpace, registers); + case UNWIND_ARM_MODE_FRAME_D: + return stepFrameD(encoding, functionStart,addressSpace, registers); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_arm::stepFrame(compact_unwind_encoding_t encoding, + uint64_t, A &addressSpace, + Registers_arm ®isters) { + uint32_t stackAdjust = + 4 * EXTRACT_BITS(encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK); + + uint32_t fp = registers.getRegister(UNW_ARM_R7); + uint32_t savedRegisterLoc = fp - 4; + + if (encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R6) { + registers.setRegister(UNW_ARM_R6, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R5) { + registers.setRegister(UNW_ARM_R5, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R4) { + registers.setRegister(UNW_ARM_R4, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R12) { + registers.setRegister(UNW_ARM_R12, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R11) { + registers.setRegister(UNW_ARM_R11, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R10) { + registers.setRegister(UNW_ARM_R10, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R9) { + registers.setRegister(UNW_ARM_R9, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R8) { + registers.setRegister(UNW_ARM_R8, addressSpace.get32(savedRegisterLoc)); + savedRegisterLoc -= 4; + } + + // fp points to old fp + registers.setRegister(UNW_ARM_R7, addressSpace.get32(fp)); + // old sp is fp less saved fp and lr + registers.setSP(fp + 8 + stackAdjust); + // pop return address into pc + registers.setIP(addressSpace.get32(fp + 4)); + + return UNW_STEP_SUCCESS; +} + + +template +int CompactUnwinder_arm::stepFrameD(compact_unwind_encoding_t encoding, + uint64_t, A &addressSpace, + Registers_arm ®isters) { + uint32_t stackAdjust = + 4 * EXTRACT_BITS(encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK); + + uint32_t fp = registers.getRegister(UNW_ARM_R7); + uint32_t loc = fp; + + if (encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R6) { + loc -= 4; + registers.setRegister(UNW_ARM_R6, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R5) { + loc -= 4; + registers.setRegister(UNW_ARM_R5, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R4) { + loc -= 4; + registers.setRegister(UNW_ARM_R4, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R12) { + loc -= 4; + registers.setRegister(UNW_ARM_R12, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R11) { + loc -= 4; + registers.setRegister(UNW_ARM_R11, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R10) { + loc -= 4; + registers.setRegister(UNW_ARM_R10, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R9) { + loc -= 4; + registers.setRegister(UNW_ARM_R9, addressSpace.get32(loc)); + } + if (encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R8) { + loc -= 4; + registers.setRegister(UNW_ARM_R8, addressSpace.get32(loc)); + } + + uint32_t dRegSaveCount = + EXTRACT_BITS(encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK); + + uint32_t loc16; + switch ( dRegSaveCount ) { + case 0: + // vpush {d8} + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc-8)); + break; + case 1: + // vpush {d10} + // vpush {d8} + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc-16)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc-8)); + break; + case 2: + // vpush {d12} + // vpush {d10} + // vpush {d8} + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc-24)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc-16)); + registers.setFloatRegister(UNW_ARM_D12, addressSpace.getDouble(loc-8)); + break; + case 3: + // vpush {d14} + // vpush {d12} + // vpush {d10} + // vpush {d8} + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc-32)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc-24)); + registers.setFloatRegister(UNW_ARM_D12, addressSpace.getDouble(loc-16)); + registers.setFloatRegister(UNW_ARM_D14, addressSpace.getDouble(loc-8)); + break; + case 4: + // vpush {d14} + // vpush {d12} + // sp = (sp - 24) & (-16); + // vst {d8, d9, d10} + registers.setFloatRegister(UNW_ARM_D12, addressSpace.getDouble(loc-16)); + registers.setFloatRegister(UNW_ARM_D14, addressSpace.getDouble(loc-8)); + loc16 = (loc-40) & 0xFFFFFFF0; + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc16)); + registers.setFloatRegister(UNW_ARM_D9, addressSpace.getDouble(loc16+8)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc16+16)); + break; + case 5: + // vpush {d14} + // sp = (sp - 40) & (-16); + // vst {d8, d9, d10, d11} + // vst {d12} + registers.setFloatRegister(UNW_ARM_D14, addressSpace.getDouble(loc-8)); + loc16 = (loc-48) & 0xFFFFFFF0; + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc16)); + registers.setFloatRegister(UNW_ARM_D9, addressSpace.getDouble(loc16+8)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc16+16)); + registers.setFloatRegister(UNW_ARM_D11, addressSpace.getDouble(loc16+24)); + registers.setFloatRegister(UNW_ARM_D12, addressSpace.getDouble(loc16+32)); + break; + case 6: + // sp = (sp - 56) & (-16); + // vst {d8, d9, d10, d11} + // vst {d12, d13, d14} + loc16 = (loc-56) & 0xFFFFFFF0; + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc16)); + registers.setFloatRegister(UNW_ARM_D9, addressSpace.getDouble(loc16+8)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc16+16)); + registers.setFloatRegister(UNW_ARM_D11, addressSpace.getDouble(loc16+24)); + registers.setFloatRegister(UNW_ARM_D12, addressSpace.getDouble(loc16+32)); + registers.setFloatRegister(UNW_ARM_D13, addressSpace.getDouble(loc16+40)); + registers.setFloatRegister(UNW_ARM_D14, addressSpace.getDouble(loc16+48)); + break; + case 7: + // sp = (sp - 64) & (-16); + // vst {d8, d9, d10, d11} + // vst {d12, d13, d14, d15} + loc16 = (loc-64) & 0xFFFFFFF0; + registers.setFloatRegister(UNW_ARM_D8, addressSpace.getDouble(loc16)); + registers.setFloatRegister(UNW_ARM_D9, addressSpace.getDouble(loc16+8)); + registers.setFloatRegister(UNW_ARM_D10, addressSpace.getDouble(loc16+16)); + registers.setFloatRegister(UNW_ARM_D11, addressSpace.getDouble(loc16+24)); + registers.setFloatRegister(UNW_ARM_D12, addressSpace.getDouble(loc16+32)); + registers.setFloatRegister(UNW_ARM_D13, addressSpace.getDouble(loc16+40)); + registers.setFloatRegister(UNW_ARM_D14, addressSpace.getDouble(loc16+48)); + registers.setFloatRegister(UNW_ARM_D15, addressSpace.getDouble(loc16+56)); + break; + default: + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + + + // fp points to old fp + registers.setRegister(UNW_ARM_R7, addressSpace.get32(fp)); + // old sp is fp less saved fp and lr + registers.setSP(fp + 8 + stackAdjust); + // pop return address into pc + registers.setIP(addressSpace.get32(fp + 4)); + + return UNW_STEP_SUCCESS; +} + +#endif // _LIBUNWIND_TARGET_ARM + + +} // namespace libunwind + #endif // __COMPACT_UNWINDER_HPP__ - - - - diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index d063ebc..5b5e00e 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -1,30 +1,13 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2008 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===-------------------------- DwarfInstructions.hpp ---------------------===// // -// processor specific parsing of dwarf unwind instructions +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// +// Processor specific interpretation of DWARF unwind info. +// +//===----------------------------------------------------------------------===// #ifndef __DWARF_INSTRUCTIONS_HPP__ #define __DWARF_INSTRUCTIONS_HPP__ @@ -33,1708 +16,812 @@ #include #include -#include -#include - -#include -#include - #include "dwarf2.h" -#include "AddressSpace.hpp" #include "Registers.hpp" #include "DwarfParser.hpp" -#include "InternalMacros.h" -//#include "CompactUnwinder.hpp" +#include "config.h" -#define EXTRACT_BITS(value, mask) \ - ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) ) -#define CFI_INVALID_ADDRESS ((pint_t)(-1)) namespace libunwind { -/// -/// Used by linker when parsing __eh_frame section -/// -template -struct CFI_Reference { - typedef typename A::pint_t pint_t; - uint8_t encodingOfTargetAddress; - uint32_t offsetInCFI; - pint_t targetAddress; -}; -template -struct CFI_Atom_Info { - typedef typename A::pint_t pint_t; - pint_t address; - uint32_t size; - bool isCIE; - union { - struct { - CFI_Reference function; - CFI_Reference cie; - CFI_Reference lsda; - uint32_t compactUnwindInfo; - } fdeInfo; - struct { - CFI_Reference personality; - } cieInfo; - } u; -}; -typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg); - -/// -/// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture -/// +/// DwarfInstructions maps abtract DWARF unwind instructions to a particular +/// architecture template -class DwarfInstructions -{ +class DwarfInstructions { public: - typedef typename A::pint_t pint_t; - typedef typename A::sint_t sint_t; + typedef typename A::pint_t pint_t; + typedef typename A::sint_t sint_t; - static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, - CFI_Atom_Info* infos, uint32_t infosCount, void* ref, WarnFunc warn); + static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, + unw_word_t procInfoFlags, + R ®isters, bool &isSignalFrame); - - static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, - pint_t* lsda, pint_t* personality, - char warningBuffer[1024]); - - static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers); - private: - enum { - DW_X86_64_RET_ADDR = 16 - }; + enum { + DW_X86_64_RET_ADDR = 16 + }; - enum { - DW_X86_RET_ADDR = 8 - }; + enum { + DW_X86_RET_ADDR = 8 + }; - static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue); - static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa, - const typename CFI_Parser::RegisterLocation& savedReg); - static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa, - const typename CFI_Parser::RegisterLocation& savedReg); - static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa, - const typename CFI_Parser::RegisterLocation& savedReg); - - // x86 specific variants - static int lastRestoreReg(const Registers_x86&); - static bool isReturnAddressRegister(int regNum, const Registers_x86&); - static pint_t getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, const Registers_x86&); + typedef typename CFI_Parser::RegisterLocation RegisterLocation; + typedef typename CFI_Parser::PrologInfo PrologInfo; + typedef typename CFI_Parser::FDE_Info FDE_Info; + typedef typename CFI_Parser::CIE_Info CIE_Info; - static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure); - static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&); - static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, - const Registers_x86&, const typename CFI_Parser::PrologInfo& prolog, - char warningBuffer[1024]); + static pint_t evaluateExpression(pint_t expression, A &addressSpace, + const R ®isters, + pint_t initialStackValue); + static pint_t getSavedRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + static double getSavedFloatRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); - // x86_64 specific variants - static int lastRestoreReg(const Registers_x86_64&); - static bool isReturnAddressRegister(int regNum, const Registers_x86_64&); - static pint_t getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, const Registers_x86_64&); - - static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure); - static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&); - static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, - const Registers_x86_64&, const typename CFI_Parser::PrologInfo& prolog, - char warningBuffer[1024]); - - // ppc specific variants - static int lastRestoreReg(const Registers_ppc&); - static bool isReturnAddressRegister(int regNum, const Registers_ppc&); - static pint_t getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, const Registers_ppc&); - static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&); - static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, - const Registers_ppc&, const typename CFI_Parser::PrologInfo& prolog, - char warningBuffer[1024]); + static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, + const R ®isters) { + if (prolog.cfaRegister != 0) + return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + + prolog.cfaRegisterOffset); + if (prolog.cfaExpression != 0) + return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, + registers, 0); + assert(0 && "getCFA(): unknown location"); + __builtin_unreachable(); + } }; - - template -const char* DwarfInstructions::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, - CFI_Atom_Info* infos, uint32_t infosCount, void* ref, WarnFunc warn) -{ - typename CFI_Parser::CIE_Info cieInfo; - CFI_Atom_Info* entry = infos; - CFI_Atom_Info* end = &infos[infosCount]; - const pint_t ehSectionEnd = ehSectionStart + sectionLength; - for (pint_t p=ehSectionStart; p < ehSectionEnd; ) { - pint_t currentCFI = p; - uint64_t cfiLength = addressSpace.get32(p); - p += 4; - if ( cfiLength == 0xffffffff ) { - // 0xffffffff means length is really next 8 bytes - cfiLength = addressSpace.get64(p); - p += 8; - } - if ( cfiLength == 0 ) - return NULL; // end marker - if ( entry >= end ) - return "too little space allocated for parseCFIs"; - pint_t nextCFI = p + cfiLength; - uint32_t id = addressSpace.get32(p); - if ( id == 0 ) { - // is CIE - const char* err = CFI_Parser::parseCIE(addressSpace, currentCFI, &cieInfo); - if ( err != NULL ) - return err; - entry->address = currentCFI; - entry->size = nextCFI - currentCFI; - entry->isCIE = true; - entry->u.cieInfo.personality.targetAddress = cieInfo.personality; - entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE; - entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding; - ++entry; - } - else { - // is FDE - entry->address = currentCFI; - entry->size = nextCFI - currentCFI; - entry->isCIE = false; - entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS; - entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS; - entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS; - uint32_t ciePointer = addressSpace.get32(p); - pint_t cieStart = p-ciePointer; - // validate pointer to CIE is within section - if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) ) - return "FDE points to CIE outside __eh_frame section"; - // optimize usual case where cie is same for all FDEs - if ( cieStart != cieInfo.cieStart ) { - const char* err = CFI_Parser::parseCIE(addressSpace, cieStart, &cieInfo); - if ( err != NULL ) - return err; - } - entry->u.fdeInfo.cie.targetAddress = cieStart; - entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI; - entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel; - p += 4; - // parse pc begin and range - pint_t offsetOfFunctionAddress = p-currentCFI; - pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding); - pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F); - //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange)); - // test if pc is within the function this FDE covers - entry->u.fdeInfo.function.targetAddress = pcStart; - entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress; - entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding; - // check for augmentation length - if ( cieInfo.fdesHaveAugmentationData ) { - uintptr_t augLen = addressSpace.getULEB128(p, nextCFI); - pint_t endOfAug = p + augLen; - if ( cieInfo.lsdaEncoding != 0 ) { - // peek at value (without indirection). Zero means no lsda - pint_t lsdaStart = p; - if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) { - // reset pointer and re-parse lsda address - p = lsdaStart; - pint_t offsetOfLSDAAddress = p-currentCFI; - entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding); - entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress; - entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding; - } - } - p = endOfAug; - } - // compute compact unwind encoding - typename CFI_Parser::FDE_Info fdeInfo; - fdeInfo.fdeStart = currentCFI; - fdeInfo.fdeLength = nextCFI - currentCFI; - fdeInfo.fdeInstructions = p; - fdeInfo.pcStart = pcStart; - fdeInfo.pcEnd = pcStart + pcRange; - fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress; - typename CFI_Parser::PrologInfo prolog; - R dummy; // for proper selection of architecture specific functions - if ( CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) { - char warningBuffer[1024]; - entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer); - if ( fdeInfo.lsda != CFI_INVALID_ADDRESS ) - entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA; - if ( warningBuffer[0] != '\0' ) - warn(ref, fdeInfo.pcStart, warningBuffer); - } - else { - warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed"); - entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy); - } - ++entry; - } - p = nextCFI; - } - if ( entry != end ) - return "wrong entry count for parseCFIs"; - return NULL; // success -} +typename A::pint_t DwarfInstructions::getSavedRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value); + case CFI_Parser::kRegisterAtExpression: + return (pint_t)addressSpace.getRegister(evaluateExpression( + (pint_t)savedReg.value, addressSpace, registers, cfa)); + case CFI_Parser::kRegisterIsExpression: + return evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa); + case CFI_Parser::kRegisterInRegister: + return registers.getRegister((int)savedReg.value); -template -compact_unwind_encoding_t DwarfInstructions::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, - pint_t* lsda, pint_t* personality, - char warningBuffer[1024]) -{ - typename CFI_Parser::FDE_Info fdeInfo; - typename CFI_Parser::CIE_Info cieInfo; - R dummy; // for proper selection of architecture specific functions - if ( CFI_Parser::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) { - typename CFI_Parser::PrologInfo prolog; - if ( CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) { - *lsda = fdeInfo.lsda; - *personality = cieInfo.personality; - compact_unwind_encoding_t encoding; - encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer); - if ( fdeInfo.lsda != 0 ) - encoding |= UNWIND_HAS_LSDA; - return encoding; - } - else { - strcpy(warningBuffer, "dwarf unwind instructions could not be parsed"); - return encodeToUseDwarf(dummy); - } - } - else { - strcpy(warningBuffer, "dwarf FDE could not be parsed"); - return encodeToUseDwarf(dummy); - } -} - - -template -typename A::pint_t DwarfInstructions::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa, - const typename CFI_Parser::RegisterLocation& savedReg) -{ - switch ( savedReg.location ) { - case CFI_Parser::kRegisterInCFA: - return addressSpace.getP(cfa + savedReg.value); - - case CFI_Parser::kRegisterAtExpression: - return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa)); - - case CFI_Parser::kRegisterIsExpression: - return evaluateExpression(savedReg.value, addressSpace, registers, cfa); - - case CFI_Parser::kRegisterInRegister: - return registers.getRegister(savedReg.value); - - case CFI_Parser::kRegisterUnused: - case CFI_Parser::kRegisterOffsetFromCFA: - // FIX ME - break; - } - ABORT("unsupported restore location for register"); + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for register"); } template -double DwarfInstructions::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa, - const typename CFI_Parser::RegisterLocation& savedReg) -{ - switch ( savedReg.location ) { - case CFI_Parser::kRegisterInCFA: - return addressSpace.getDouble(cfa + savedReg.value); +double DwarfInstructions::getSavedFloatRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getDouble(cfa + (pint_t)savedReg.value); - case CFI_Parser::kRegisterAtExpression: - return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa)); + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getDouble( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); - case CFI_Parser::kRegisterIsExpression: - case CFI_Parser::kRegisterUnused: - case CFI_Parser::kRegisterOffsetFromCFA: - case CFI_Parser::kRegisterInRegister: - // FIX ME - break; - } - ABORT("unsupported restore location for float register"); + case CFI_Parser::kRegisterIsExpression: + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + case CFI_Parser::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for float register"); } template -v128 DwarfInstructions::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa, - const typename CFI_Parser::RegisterLocation& savedReg) -{ - switch ( savedReg.location ) { - case CFI_Parser::kRegisterInCFA: - return addressSpace.getVector(cfa + savedReg.value); +v128 DwarfInstructions::getSavedVectorRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getVector(cfa + (pint_t)savedReg.value); - case CFI_Parser::kRegisterAtExpression: - return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa)); + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getVector( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); - case CFI_Parser::kRegisterIsExpression: - case CFI_Parser::kRegisterUnused: - case CFI_Parser::kRegisterOffsetFromCFA: - case CFI_Parser::kRegisterInRegister: - // FIX ME - break; - } - ABORT("unsupported restore location for vector register"); -} - - -template -int DwarfInstructions::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers) -{ - //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart); - typename CFI_Parser::FDE_Info fdeInfo; - typename CFI_Parser::CIE_Info cieInfo; - if ( CFI_Parser::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) { - typename CFI_Parser::PrologInfo prolog; - if ( CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) { - R newRegisters = registers; - - // get pointer to cfa (architecture specific) - pint_t cfa = getCFA(addressSpace, prolog, registers); - - // restore registers that dwarf says were saved - pint_t returnAddress = 0; - for (int i=0; i <= lastRestoreReg(newRegisters); ++i) { - if ( prolog.savedRegisters[i].location != CFI_Parser::kRegisterUnused ) { - if ( registers.validFloatRegister(i) ) - newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); - else if ( registers.validVectorRegister(i) ) - newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); - else if ( isReturnAddressRegister(i, registers) ) - returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]); - else if ( registers.validRegister(i) ) - newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); - else - return UNW_EBADREG; - } - } - - // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA - newRegisters.setSP(cfa); - - // return address is address after call site instruction, so setting IP to that does a return - newRegisters.setIP(returnAddress); - - // do the actual step by replacing the register set with the new ones - registers = newRegisters; - - return UNW_STEP_SUCCESS; - } - } - return UNW_EBADFRAME; -} - - - -template -typename A::pint_t DwarfInstructions::evaluateExpression(pint_t expression, A& addressSpace, - const R& registers, pint_t initialStackValue) -{ - const bool log = false; - pint_t p = expression; - pint_t expressionEnd = expression+20; // just need something until length is read - uint64_t length = addressSpace.getULEB128(p, expressionEnd); - expressionEnd = p + length; - if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length); - pint_t stack[100]; - pint_t* sp = stack; - *(++sp) = initialStackValue; - - while ( p < expressionEnd ) { - if (log) { - for(pint_t* t = sp; t > stack; --t) { - fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t)); - } - } - uint8_t opcode = addressSpace.get8(p++); - sint_t svalue; - pint_t value; - uint32_t reg; - switch (opcode) { - case DW_OP_addr: - // push immediate address sized value - value = addressSpace.getP(p); - p += sizeof(pint_t); - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_deref: - // pop stack, dereference, push result - value = *sp--; - *(++sp) = addressSpace.getP(value); - if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_const1u: - // push immediate 1 byte value - value = addressSpace.get8(p); - p += 1; - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_const1s: - // push immediate 1 byte signed value - svalue = (int8_t)addressSpace.get8(p); - p += 1; - *(++sp) = svalue; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); - break; - - case DW_OP_const2u: - // push immediate 2 byte value - value = addressSpace.get16(p); - p += 2; - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_const2s: - // push immediate 2 byte signed value - svalue = (int16_t)addressSpace.get16(p); - p += 2; - *(++sp) = svalue; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); - break; - - case DW_OP_const4u: - // push immediate 4 byte value - value = addressSpace.get32(p); - p += 4; - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_const4s: - // push immediate 4 byte signed value - svalue = (int32_t)addressSpace.get32(p); - p += 4; - *(++sp) = svalue; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); - break; - - case DW_OP_const8u: - // push immediate 8 byte value - value = addressSpace.get64(p); - p += 8; - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_const8s: - // push immediate 8 byte signed value - value = (int32_t)addressSpace.get64(p); - p += 8; - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_constu: - // push immediate ULEB128 value - value = addressSpace.getULEB128(p, expressionEnd); - *(++sp) = value; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_consts: - // push immediate SLEB128 value - svalue = addressSpace.getSLEB128(p, expressionEnd); - *(++sp) = svalue; - if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); - break; - - case DW_OP_dup: - // push top of stack - value = *sp; - *(++sp) = value; - if (log) fprintf(stderr, "duplicate top of stack\n"); - break; - - case DW_OP_drop: - // pop - --sp; - if (log) fprintf(stderr, "pop top of stack\n"); - break; - - case DW_OP_over: - // dup second - value = sp[-1]; - *(++sp) = value; - if (log) fprintf(stderr, "duplicate second in stack\n"); - break; - - case DW_OP_pick: - // pick from - reg = addressSpace.get8(p); - p += 1; - value = sp[-reg]; - *(++sp) = value; - if (log) fprintf(stderr, "duplicate %d in stack\n", reg); - break; - - case DW_OP_swap: - // swap top two - value = sp[0]; - sp[0] = sp[-1]; - sp[-1] = value; - if (log) fprintf(stderr, "swap top of stack\n"); - break; - - case DW_OP_rot: - // rotate top three - value = sp[0]; - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = value; - if (log) fprintf(stderr, "rotate top three of stack\n"); - break; - - case DW_OP_xderef: - // pop stack, dereference, push result - value = *sp--; - *sp = *((uint64_t*)value); - if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_abs: - svalue = *sp; - if ( svalue < 0 ) - *sp = -svalue; - if (log) fprintf(stderr, "abs\n"); - break; - - case DW_OP_and: - value = *sp--; - *sp &= value; - if (log) fprintf(stderr, "and\n"); - break; - - case DW_OP_div: - svalue = *sp--; - *sp = *sp / svalue; - if (log) fprintf(stderr, "div\n"); - break; - - case DW_OP_minus: - svalue = *sp--; - *sp = *sp - svalue; - if (log) fprintf(stderr, "minus\n"); - break; - - case DW_OP_mod: - svalue = *sp--; - *sp = *sp % svalue; - if (log) fprintf(stderr, "module\n"); - break; - - case DW_OP_mul: - svalue = *sp--; - *sp = *sp * svalue; - if (log) fprintf(stderr, "mul\n"); - break; - - case DW_OP_neg: - *sp = 0 - *sp; - if (log) fprintf(stderr, "neg\n"); - break; - - case DW_OP_not: - svalue = *sp; - *sp = ~svalue; - if (log) fprintf(stderr, "not\n"); - break; - - case DW_OP_or: - value = *sp--; - *sp |= value; - if (log) fprintf(stderr, "or\n"); - break; - - case DW_OP_plus: - value = *sp--; - *sp += value; - if (log) fprintf(stderr, "plus\n"); - break; - - case DW_OP_plus_uconst: - // pop stack, add uelb128 constant, push result - *sp += addressSpace.getULEB128(p, expressionEnd); - if (log) fprintf(stderr, "add constant\n"); - break; - - case DW_OP_shl: - value = *sp--; - *sp = *sp << value; - if (log) fprintf(stderr, "shift left\n"); - break; - - case DW_OP_shr: - value = *sp--; - *sp = *sp >> value; - if (log) fprintf(stderr, "shift left\n"); - break; - - case DW_OP_shra: - value = *sp--; - svalue = *sp; - *sp = svalue >> value; - if (log) fprintf(stderr, "shift left arithmetric\n"); - break; - - case DW_OP_xor: - value = *sp--; - *sp ^= value; - if (log) fprintf(stderr, "xor\n"); - break; - - case DW_OP_skip: - svalue = (int16_t)addressSpace.get16(p); - p += 2; - p += svalue; - if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue); - break; - - case DW_OP_bra: - svalue = (int16_t)addressSpace.get16(p); - p += 2; - if ( *sp-- ) - p += svalue; - if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue); - break; - - case DW_OP_eq: - value = *sp--; - *sp = (*sp == value); - if (log) fprintf(stderr, "eq\n"); - break; - - case DW_OP_ge: - value = *sp--; - *sp = (*sp >= value); - if (log) fprintf(stderr, "ge\n"); - break; - - case DW_OP_gt: - value = *sp--; - *sp = (*sp > value); - if (log) fprintf(stderr, "gt\n"); - break; - - case DW_OP_le: - value = *sp--; - *sp = (*sp <= value); - if (log) fprintf(stderr, "le\n"); - break; - - case DW_OP_lt: - value = *sp--; - *sp = (*sp < value); - if (log) fprintf(stderr, "lt\n"); - break; - - case DW_OP_ne: - value = *sp--; - *sp = (*sp != value); - if (log) fprintf(stderr, "ne\n"); - break; - - case DW_OP_lit0: - case DW_OP_lit1: - case DW_OP_lit2: - case DW_OP_lit3: - case DW_OP_lit4: - case DW_OP_lit5: - case DW_OP_lit6: - case DW_OP_lit7: - case DW_OP_lit8: - case DW_OP_lit9: - case DW_OP_lit10: - case DW_OP_lit11: - case DW_OP_lit12: - case DW_OP_lit13: - case DW_OP_lit14: - case DW_OP_lit15: - case DW_OP_lit16: - case DW_OP_lit17: - case DW_OP_lit18: - case DW_OP_lit19: - case DW_OP_lit20: - case DW_OP_lit21: - case DW_OP_lit22: - case DW_OP_lit23: - case DW_OP_lit24: - case DW_OP_lit25: - case DW_OP_lit26: - case DW_OP_lit27: - case DW_OP_lit28: - case DW_OP_lit29: - case DW_OP_lit30: - case DW_OP_lit31: - value = opcode - DW_OP_lit0; - *(++sp) = value; - if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_reg0: - case DW_OP_reg1: - case DW_OP_reg2: - case DW_OP_reg3: - case DW_OP_reg4: - case DW_OP_reg5: - case DW_OP_reg6: - case DW_OP_reg7: - case DW_OP_reg8: - case DW_OP_reg9: - case DW_OP_reg10: - case DW_OP_reg11: - case DW_OP_reg12: - case DW_OP_reg13: - case DW_OP_reg14: - case DW_OP_reg15: - case DW_OP_reg16: - case DW_OP_reg17: - case DW_OP_reg18: - case DW_OP_reg19: - case DW_OP_reg20: - case DW_OP_reg21: - case DW_OP_reg22: - case DW_OP_reg23: - case DW_OP_reg24: - case DW_OP_reg25: - case DW_OP_reg26: - case DW_OP_reg27: - case DW_OP_reg28: - case DW_OP_reg29: - case DW_OP_reg30: - case DW_OP_reg31: - reg = opcode - DW_OP_reg0; - *(++sp) = registers.getRegister(reg); - if (log) fprintf(stderr, "push reg %d\n", reg); - break; - - case DW_OP_regx: - reg = addressSpace.getULEB128(p, expressionEnd); - *(++sp) = registers.getRegister(reg); - if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue); - break; - - case DW_OP_breg0: - case DW_OP_breg1: - case DW_OP_breg2: - case DW_OP_breg3: - case DW_OP_breg4: - case DW_OP_breg5: - case DW_OP_breg6: - case DW_OP_breg7: - case DW_OP_breg8: - case DW_OP_breg9: - case DW_OP_breg10: - case DW_OP_breg11: - case DW_OP_breg12: - case DW_OP_breg13: - case DW_OP_breg14: - case DW_OP_breg15: - case DW_OP_breg16: - case DW_OP_breg17: - case DW_OP_breg18: - case DW_OP_breg19: - case DW_OP_breg20: - case DW_OP_breg21: - case DW_OP_breg22: - case DW_OP_breg23: - case DW_OP_breg24: - case DW_OP_breg25: - case DW_OP_breg26: - case DW_OP_breg27: - case DW_OP_breg28: - case DW_OP_breg29: - case DW_OP_breg30: - case DW_OP_breg31: - reg = opcode - DW_OP_breg0; - svalue = addressSpace.getSLEB128(p, expressionEnd); - *(++sp) = registers.getRegister(reg) + svalue; - if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue); - break; - - case DW_OP_bregx: - reg = addressSpace.getULEB128(p, expressionEnd); - svalue = addressSpace.getSLEB128(p, expressionEnd); - *(++sp) = registers.getRegister(reg) + svalue; - if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue); - break; - - case DW_OP_fbreg: - ABORT("DW_OP_fbreg not implemented"); - break; - - case DW_OP_piece: - ABORT("DW_OP_piece not implemented"); - break; - - case DW_OP_deref_size: - // pop stack, dereference, push result - value = *sp--; - switch ( addressSpace.get8(p++) ) { - case 1: - value = addressSpace.get8(value); - break; - case 2: - value = addressSpace.get16(value); - break; - case 4: - value = addressSpace.get32(value); - break; - case 8: - value = addressSpace.get64(value); - break; - default: - ABORT("DW_OP_deref_size with bad size"); - } - *(++sp) = value; - if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value); - break; - - case DW_OP_xderef_size: - case DW_OP_nop: - case DW_OP_push_object_addres: - case DW_OP_call2: - case DW_OP_call4: - case DW_OP_call_ref: - default: - ABORT("dwarf opcode not implemented"); - } - - } - if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp); - return *sp; -} - - - -// -// x86_64 specific functions -// - -template -int DwarfInstructions::lastRestoreReg(const Registers_x86_64&) -{ - COMPILE_TIME_ASSERT( (int)CFI_Parser::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR ); - return DW_X86_64_RET_ADDR; + case CFI_Parser::kRegisterIsExpression: + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + case CFI_Parser::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for vector register"); } template -bool DwarfInstructions::isReturnAddressRegister(int regNum, const Registers_x86_64&) -{ - return (regNum == DW_X86_64_RET_ADDR); +int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, + pint_t fdeStart, + unw_word_t procInfoFlags, + R ®isters, + bool &isSignalFrame) { + FDE_Info fdeInfo; + CIE_Info cieInfo; + if (CFI_Parser::decodeFDE(addressSpace, fdeStart, &fdeInfo, + &cieInfo) == NULL) { + PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, + R::getArch(), &prolog)) { + // get pointer to cfa (architecture specific) + pint_t cfa = getCFA(addressSpace, prolog, registers); + + // restore registers that DWARF says were saved + R newRegisters = registers; + typename R::reg_t returnAddress = 0; + const int lastReg = R::lastDwarfRegNum(); + assert(static_cast(CFI_Parser::kMaxRegisterNumber) >= lastReg && + "register range too large"); + assert(lastReg >= (int)cieInfo.returnAddressRegister && + "register range does not contain return address register"); + for (int i = 0; i <= lastReg; ++i) { + if (prolog.savedRegisters[i].location != + CFI_Parser::kRegisterUnused) { + if (registers.validFloatRegister(i)) + newRegisters.setFloatRegister( + i, getSavedFloatRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else if (registers.validVectorRegister(i)) + newRegisters.setVectorRegister( + i, getSavedVectorRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else if (i == (int)cieInfo.returnAddressRegister) + returnAddress = getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i]); + else if (registers.validRegister(i)) + newRegisters.setRegister( + i, getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else + return UNW_EBADREG; + } + } + + // By definition, the CFA is the stack pointer at the call site, so + // restoring SP means setting it to CFA. + newRegisters.setSP(cfa); + + isSignalFrame = cieInfo.isSignalFrame; + +#if defined(_LIBUNWIND_TARGET_AARCH64) + // If the target is aarch64 then the return address may have been signed + // using the v8.3 pointer authentication extensions. The original + // return address needs to be authenticated before the return address is + // restored. autia1716 is used instead of autia as autia1716 assembles + // to a NOP on pre-v8.3a architectures. + if ((R::getArch() == REGISTERS_ARM64) && + prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) { +#if !defined(_LIBUNWIND_IS_NATIVE_ONLY) + return UNW_ECROSSRASIGNING; +#else + register unsigned long long x17 __asm("x17") = returnAddress; + register unsigned long long x16 __asm("x16") = cfa; + + // These are the autia1716/autib1716 instructions. The hint instructions + // are used here as gcc does not assemble autia1716/autib1716 for pre + // armv8.3a targets. + if (cieInfo.addressesSignedWithBKey) + asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716 + else + asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716 + returnAddress = x17; +#endif + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + if (R::getArch() == REGISTERS_SPARC) { + // Skip call site instruction and delay slot + returnAddress += 8; + // Skip unimp instruction if function returns a struct + if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0) + returnAddress += 4; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) +#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1) +#define PPC64_ELFV1_R2_OFFSET 40 +#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1) +#define PPC64_ELFV2_R2_OFFSET 24 + // If the instruction at return address is a TOC (r2) restore, + // then r2 was saved and needs to be restored. + // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24, + // while in ELFv1 ABI it is saved at SP + 40. + if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) { + pint_t sp = newRegisters.getRegister(UNW_REG_SP); + pint_t r2 = 0; + switch (addressSpace.get32(returnAddress)) { + case PPC64_ELFV1_R2_LOAD_INST_ENCODING: + r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET); + break; + case PPC64_ELFV2_R2_LOAD_INST_ENCODING: + r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET); + break; + } + if (r2) + newRegisters.setRegister(UNW_PPC64_R2, r2); + } +#endif + + newRegisters.normalizeNewLinkRegister(returnAddress, procInfoFlags); + + // Return address is address after call site instruction, so setting IP to + // that does simualates a return. + newRegisters.setIP(returnAddress); + + // Simulate the step by replacing the register set with the new ones. + registers = newRegisters; + + return UNW_STEP_SUCCESS; + } + } + return UNW_EBADFRAME; } template -typename A::pint_t DwarfInstructions::getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, - const Registers_x86_64& registers) -{ - if ( prolog.cfaRegister != 0 ) - return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; - else if ( prolog.cfaExpression != 0 ) - return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0); - else - ABORT("getCFA(): unknown location for x86_64 cfa"); +typename A::pint_t +DwarfInstructions::evaluateExpression(pint_t expression, A &addressSpace, + const R ®isters, + pint_t initialStackValue) { + const bool log = false; + pint_t p = expression; + pint_t expressionEnd = expression + 20; // temp, until len read + pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd); + expressionEnd = p + length; + if (log) + fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n", + (uint64_t)length); + pint_t stack[100]; + pint_t *sp = stack; + *(++sp) = initialStackValue; + + while (p < expressionEnd) { + if (log) { + for (pint_t *t = sp; t > stack; --t) { + fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t)); + } + } + uint8_t opcode = addressSpace.get8(p++); + sint_t svalue, svalue2; + pint_t value; + uint32_t reg; + switch (opcode) { + case DW_OP_addr: + // push immediate address sized value + value = addressSpace.getP(p); + p += sizeof(pint_t); + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_deref: + // pop stack, dereference, push result + value = *sp--; + *(++sp) = addressSpace.getP(value); + if (log) + fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const1u: + // push immediate 1 byte value + value = addressSpace.get8(p); + p += 1; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const1s: + // push immediate 1 byte signed value + svalue = (int8_t) addressSpace.get8(p); + p += 1; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_const2u: + // push immediate 2 byte value + value = addressSpace.get16(p); + p += 2; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const2s: + // push immediate 2 byte signed value + svalue = (int16_t) addressSpace.get16(p); + p += 2; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_const4u: + // push immediate 4 byte value + value = addressSpace.get32(p); + p += 4; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const4s: + // push immediate 4 byte signed value + svalue = (int32_t)addressSpace.get32(p); + p += 4; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_const8u: + // push immediate 8 byte value + value = (pint_t)addressSpace.get64(p); + p += 8; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const8s: + // push immediate 8 byte signed value + value = (pint_t)addressSpace.get64(p); + p += 8; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_constu: + // push immediate ULEB128 value + value = (pint_t)addressSpace.getULEB128(p, expressionEnd); + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_consts: + // push immediate SLEB128 value + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_dup: + // push top of stack + value = *sp; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate top of stack\n"); + break; + + case DW_OP_drop: + // pop + --sp; + if (log) + fprintf(stderr, "pop top of stack\n"); + break; + + case DW_OP_over: + // dup second + value = sp[-1]; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate second in stack\n"); + break; + + case DW_OP_pick: + // pick from + reg = addressSpace.get8(p); + p += 1; + value = sp[-(int)reg]; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate %d in stack\n", reg); + break; + + case DW_OP_swap: + // swap top two + value = sp[0]; + sp[0] = sp[-1]; + sp[-1] = value; + if (log) + fprintf(stderr, "swap top of stack\n"); + break; + + case DW_OP_rot: + // rotate top three + value = sp[0]; + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = value; + if (log) + fprintf(stderr, "rotate top three of stack\n"); + break; + + case DW_OP_xderef: + // pop stack, dereference, push result + value = *sp--; + *sp = *((pint_t*)value); + if (log) + fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_abs: + svalue = (sint_t)*sp; + if (svalue < 0) + *sp = (pint_t)(-svalue); + if (log) + fprintf(stderr, "abs\n"); + break; + + case DW_OP_and: + value = *sp--; + *sp &= value; + if (log) + fprintf(stderr, "and\n"); + break; + + case DW_OP_div: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 / svalue); + if (log) + fprintf(stderr, "div\n"); + break; + + case DW_OP_minus: + value = *sp--; + *sp = *sp - value; + if (log) + fprintf(stderr, "minus\n"); + break; + + case DW_OP_mod: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 % svalue); + if (log) + fprintf(stderr, "module\n"); + break; + + case DW_OP_mul: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 * svalue); + if (log) + fprintf(stderr, "mul\n"); + break; + + case DW_OP_neg: + *sp = 0 - *sp; + if (log) + fprintf(stderr, "neg\n"); + break; + + case DW_OP_not: + svalue = (sint_t)(*sp); + *sp = (pint_t)(~svalue); + if (log) + fprintf(stderr, "not\n"); + break; + + case DW_OP_or: + value = *sp--; + *sp |= value; + if (log) + fprintf(stderr, "or\n"); + break; + + case DW_OP_plus: + value = *sp--; + *sp += value; + if (log) + fprintf(stderr, "plus\n"); + break; + + case DW_OP_plus_uconst: + // pop stack, add uelb128 constant, push result + *sp += static_cast(addressSpace.getULEB128(p, expressionEnd)); + if (log) + fprintf(stderr, "add constant\n"); + break; + + case DW_OP_shl: + value = *sp--; + *sp = *sp << value; + if (log) + fprintf(stderr, "shift left\n"); + break; + + case DW_OP_shr: + value = *sp--; + *sp = *sp >> value; + if (log) + fprintf(stderr, "shift left\n"); + break; + + case DW_OP_shra: + value = *sp--; + svalue = (sint_t)*sp; + *sp = (pint_t)(svalue >> value); + if (log) + fprintf(stderr, "shift left arithmetric\n"); + break; + + case DW_OP_xor: + value = *sp--; + *sp ^= value; + if (log) + fprintf(stderr, "xor\n"); + break; + + case DW_OP_skip: + svalue = (int16_t) addressSpace.get16(p); + p += 2; + p = (pint_t)((sint_t)p + svalue); + if (log) + fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue); + break; + + case DW_OP_bra: + svalue = (int16_t) addressSpace.get16(p); + p += 2; + if (*sp--) + p = (pint_t)((sint_t)p + svalue); + if (log) + fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue); + break; + + case DW_OP_eq: + value = *sp--; + *sp = (*sp == value); + if (log) + fprintf(stderr, "eq\n"); + break; + + case DW_OP_ge: + value = *sp--; + *sp = (*sp >= value); + if (log) + fprintf(stderr, "ge\n"); + break; + + case DW_OP_gt: + value = *sp--; + *sp = (*sp > value); + if (log) + fprintf(stderr, "gt\n"); + break; + + case DW_OP_le: + value = *sp--; + *sp = (*sp <= value); + if (log) + fprintf(stderr, "le\n"); + break; + + case DW_OP_lt: + value = *sp--; + *sp = (*sp < value); + if (log) + fprintf(stderr, "lt\n"); + break; + + case DW_OP_ne: + value = *sp--; + *sp = (*sp != value); + if (log) + fprintf(stderr, "ne\n"); + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + value = static_cast(opcode - DW_OP_lit0); + *(++sp) = value; + if (log) + fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + reg = static_cast(opcode - DW_OP_reg0); + *(++sp) = registers.getRegister((int)reg); + if (log) + fprintf(stderr, "push reg %d\n", reg); + break; + + case DW_OP_regx: + reg = static_cast(addressSpace.getULEB128(p, expressionEnd)); + *(++sp) = registers.getRegister((int)reg); + if (log) + fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + reg = static_cast(opcode - DW_OP_breg0); + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + svalue += static_cast(registers.getRegister((int)reg)); + *(++sp) = (pint_t)(svalue); + if (log) + fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); + break; + + case DW_OP_bregx: + reg = static_cast(addressSpace.getULEB128(p, expressionEnd)); + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + svalue += static_cast(registers.getRegister((int)reg)); + *(++sp) = (pint_t)(svalue); + if (log) + fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); + break; + + case DW_OP_fbreg: + _LIBUNWIND_ABORT("DW_OP_fbreg not implemented"); + break; + + case DW_OP_piece: + _LIBUNWIND_ABORT("DW_OP_piece not implemented"); + break; + + case DW_OP_deref_size: + // pop stack, dereference, push result + value = *sp--; + switch (addressSpace.get8(p++)) { + case 1: + value = addressSpace.get8(value); + break; + case 2: + value = addressSpace.get16(value); + break; + case 4: + value = addressSpace.get32(value); + break; + case 8: + value = (pint_t)addressSpace.get64(value); + break; + default: + _LIBUNWIND_ABORT("DW_OP_deref_size with bad size"); + } + *(++sp) = value; + if (log) + fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_xderef_size: + case DW_OP_nop: + case DW_OP_push_object_addres: + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_call_ref: + default: + _LIBUNWIND_ABORT("DWARF opcode not implemented"); + } + + } + if (log) + fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp); + return *sp; } -template -compact_unwind_encoding_t DwarfInstructions::encodeToUseDwarf(const Registers_x86_64&) -{ - return UNWIND_X86_64_MODE_DWARF; -} - -template -compact_unwind_encoding_t DwarfInstructions::encodeToUseDwarf(const Registers_x86&) -{ - return UNWIND_X86_MODE_DWARF; -} - - - -template -uint32_t DwarfInstructions::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure) -{ - if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) { - failure = true; - return 0; - } - unsigned int slotIndex = regOffsetFromBaseOffset/8; - - switch ( reg ) { - case UNW_X86_64_RBX: - return UNWIND_X86_64_REG_RBX << (slotIndex*3); - case UNW_X86_64_R12: - return UNWIND_X86_64_REG_R12 << (slotIndex*3); - case UNW_X86_64_R13: - return UNWIND_X86_64_REG_R13 << (slotIndex*3); - case UNW_X86_64_R14: - return UNWIND_X86_64_REG_R14 << (slotIndex*3); - case UNW_X86_64_R15: - return UNWIND_X86_64_REG_R15 << (slotIndex*3); - } - - // invalid register - failure = true; - return 0; -} - - - -template -compact_unwind_encoding_t DwarfInstructions::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, - const Registers_x86_64& r, const typename CFI_Parser::PrologInfo& prolog, - char warningBuffer[1024]) -{ - warningBuffer[0] = '\0'; - - if ( prolog.registerSavedTwiceInCIE == DW_X86_64_RET_ADDR ) { - warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker - return UNWIND_X86_64_MODE_DWARF; - } - // don't create compact unwind info for unsupported dwarf kinds - if ( prolog.registerSavedMoreThanOnce ) { - strcpy(warningBuffer, "register saved more than once (might be shrink wrap)"); - return UNWIND_X86_64_MODE_DWARF; - } - if ( prolog.cfaOffsetWasNegative ) { - strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)"); - return UNWIND_X86_64_MODE_DWARF; - } - if ( prolog.spExtraArgSize != 0 ) { - strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size"); - return UNWIND_X86_64_MODE_DWARF; - } - if ( prolog.sameValueUsed ) { - strcpy(warningBuffer, "dwarf uses DW_CFA_same_value"); - return UNWIND_X86_64_MODE_DWARF; - } - - // figure out which kind of frame this function uses - bool standardRBPframe = ( - (prolog.cfaRegister == UNW_X86_64_RBP) - && (prolog.cfaRegisterOffset == 16) - && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser::kRegisterInCFA) - && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) ); - bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP); - if ( !standardRBPframe && !standardRSPframe ) { - // no compact encoding for this - strcpy(warningBuffer, "does not use RBP or RSP based frame"); - return UNWIND_X86_64_MODE_DWARF; - } - - // scan which registers are saved - int saveRegisterCount = 0; - bool rbxSaved = false; - bool r12Saved = false; - bool r13Saved = false; - bool r14Saved = false; - bool r15Saved = false; - bool rbpSaved = false; - for (int i=0; i < 64; ++i) { - if ( prolog.savedRegisters[i].location != CFI_Parser::kRegisterUnused ) { - if ( prolog.savedRegisters[i].location != CFI_Parser::kRegisterInCFA ) { - sprintf(warningBuffer, "register %d saved somewhere other that in frame", i); - return UNWIND_X86_64_MODE_DWARF; - } - switch (i) { - case UNW_X86_64_RBX: - rbxSaved = true; - ++saveRegisterCount; - break; - case UNW_X86_64_R12: - r12Saved = true; - ++saveRegisterCount; - break; - case UNW_X86_64_R13: - r13Saved = true; - ++saveRegisterCount; - break; - case UNW_X86_64_R14: - r14Saved = true; - ++saveRegisterCount; - break; - case UNW_X86_64_R15: - r15Saved = true; - ++saveRegisterCount; - break; - case UNW_X86_64_RBP: - rbpSaved = true; - ++saveRegisterCount; - break; - case DW_X86_64_RET_ADDR: - break; - default: - sprintf(warningBuffer, "non-standard register %d being saved in prolog", i); - return UNWIND_X86_64_MODE_DWARF; - } - } - } - const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value; - const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value; - const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value; - const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value; - const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value; - const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value; - - // encode standard RBP frames - compact_unwind_encoding_t encoding = 0; - if ( standardRBPframe ) { - // | | - // +--------------+ <- CFA - // | ret addr | - // +--------------+ - // | rbp | - // +--------------+ <- rbp - // ~ ~ - // +--------------+ - // | saved reg3 | - // +--------------+ <- CFA - offset+16 - // | saved reg2 | - // +--------------+ <- CFA - offset+8 - // | saved reg1 | - // +--------------+ <- CFA - offset - // | | - // +--------------+ - // | | - // <- rsp - // - encoding = UNWIND_X86_64_MODE_RBP_FRAME; - - // find save location of farthest register from rbp - int furthestCfaOffset = 0; - if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetRBX; - if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetR12; - if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetR13; - if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetR14; - if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetR15; - - if ( furthestCfaOffset == 0 ) { - // no registers saved, nothing more to encode - return encoding; - } - - // add stack offset to encoding - int rbpOffset = furthestCfaOffset + 16; - int encodedOffset = rbpOffset/(-8); - if ( encodedOffset > 255 ) { - strcpy(warningBuffer, "offset of saved registers too far to encode"); - return UNWIND_X86_64_MODE_DWARF; - } - encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET)); - - // add register saved from each stack location - bool encodingFailure = false; - if ( rbxSaved ) - encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure); - if ( r12Saved ) - encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure); - if ( r13Saved ) - encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure); - if ( r14Saved ) - encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure); - if ( r15Saved ) - encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure); - - if ( encodingFailure ){ - strcpy(warningBuffer, "saved registers not contiguous"); - return UNWIND_X86_64_MODE_DWARF; - } - - return encoding; - } - else { - // | | - // +--------------+ <- CFA - // | ret addr | - // +--------------+ - // | saved reg1 | - // +--------------+ <- CFA - 16 - // | saved reg2 | - // +--------------+ <- CFA - 24 - // | saved reg3 | - // +--------------+ <- CFA - 32 - // | saved reg4 | - // +--------------+ <- CFA - 40 - // | saved reg5 | - // +--------------+ <- CFA - 48 - // | saved reg6 | - // +--------------+ <- CFA - 56 - // | | - // <- esp - // - - // for RSP based frames we need to encode stack size in unwind info - encoding = UNWIND_X86_64_MODE_STACK_IMMD; - uint64_t stackValue = prolog.cfaRegisterOffset / 8; - uint32_t stackAdjust = 0; - bool immedStackSize = true; - const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE); - if ( stackValue > stackMaxImmedValue ) { - // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function - if ( prolog.codeOffsetAtStackDecrement == 0 ) { - strcpy(warningBuffer, "stack size is large but stack subq instruction not found"); - return UNWIND_X86_64_MODE_DWARF; - } - pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4; - #if __EXCEPTIONS - try { - #endif - uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns); - stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8; - #if __EXCEPTIONS - } - catch (...) { - strcpy(warningBuffer, "stack size is large but stack subq instruction not found"); - return UNWIND_X86_64_MODE_DWARF; - } - #endif - stackValue = functionContentAdjustStackIns - funcAddr; - immedStackSize = false; - if ( stackAdjust > 7 ) { - strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size"); - return UNWIND_X86_64_MODE_DWARF; - } - encoding = UNWIND_X86_64_MODE_STACK_IND; - } - - - // validate that saved registers are all within 6 slots abutting return address - int registers[6]; - for (int i=0; i < 6;++i) - registers[i] = 0; - if ( r15Saved ) { - if ( cfaOffsetR15 < -56 ) { - strcpy(warningBuffer, "r15 is saved too far from return address"); - return UNWIND_X86_64_MODE_DWARF; - } - registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15; - } - if ( r14Saved ) { - if ( cfaOffsetR14 < -56 ) { - strcpy(warningBuffer, "r14 is saved too far from return address"); - return UNWIND_X86_64_MODE_DWARF; - } - registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14; - } - if ( r13Saved ) { - if ( cfaOffsetR13 < -56 ) { - strcpy(warningBuffer, "r13 is saved too far from return address"); - return UNWIND_X86_64_MODE_DWARF; - } - registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13; - } - if ( r12Saved ) { - if ( cfaOffsetR12 < -56 ) { - strcpy(warningBuffer, "r12 is saved too far from return address"); - return UNWIND_X86_64_MODE_DWARF; - } - registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12; - } - if ( rbxSaved ) { - if ( cfaOffsetRBX < -56 ) { - strcpy(warningBuffer, "rbx is saved too far from return address"); - return UNWIND_X86_64_MODE_DWARF; - } - registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX; - } - if ( rbpSaved ) { - if ( cfaOffsetRBP < -56 ) { - strcpy(warningBuffer, "rbp is saved too far from return address"); - return UNWIND_X86_64_MODE_DWARF; - } - registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP; - } - - // validate that saved registers are contiguous and abut return address on stack - for (int i=0; i < saveRegisterCount; ++i) { - if ( registers[5-i] == 0 ) { - strcpy(warningBuffer, "registers not save contiguously in stack"); - return UNWIND_X86_64_MODE_DWARF; - } - } - - // encode register permutation - // the 10-bits are encoded differently depending on the number of registers saved - int renumregs[6]; - for (int i=6-saveRegisterCount; i < 6; ++i) { - int countless = 0; - for (int j=6-saveRegisterCount; j < i; ++j) { - if ( registers[j] < registers[i] ) - ++countless; - } - renumregs[i] = registers[i] - countless -1; - } - uint32_t permutationEncoding = 0; - switch ( saveRegisterCount ) { - case 6: - permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]); - break; - case 5: - permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]); - break; - case 4: - permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]); - break; - case 3: - permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]); - break; - case 2: - permutationEncoding |= (5*renumregs[4] + renumregs[5]); - break; - case 1: - permutationEncoding |= (renumregs[5]); - break; - } - - encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE)); - encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST)); - encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT)); - encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION)); - return encoding; - } -} - - - - -// -// x86 specific functions -// -template -int DwarfInstructions::lastRestoreReg(const Registers_x86&) -{ - COMPILE_TIME_ASSERT( (int)CFI_Parser::kMaxRegisterNumber > (int)DW_X86_RET_ADDR ); - return DW_X86_RET_ADDR; -} - -template -bool DwarfInstructions::isReturnAddressRegister(int regNum, const Registers_x86&) -{ - return (regNum == DW_X86_RET_ADDR); -} - -template -typename A::pint_t DwarfInstructions::getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, - const Registers_x86& registers) -{ - if ( prolog.cfaRegister != 0 ) - return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; - else if ( prolog.cfaExpression != 0 ) - return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0); - else - ABORT("getCFA(): unknown location for x86 cfa"); -} - - - - - -template -uint32_t DwarfInstructions::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure) -{ - if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) { - failure = true; - return 0; - } - unsigned int slotIndex = regOffsetFromBaseOffset/4; - - switch ( reg ) { - case UNW_X86_EBX: - return UNWIND_X86_REG_EBX << (slotIndex*3); - case UNW_X86_ECX: - return UNWIND_X86_REG_ECX << (slotIndex*3); - case UNW_X86_EDX: - return UNWIND_X86_REG_EDX << (slotIndex*3); - case UNW_X86_EDI: - return UNWIND_X86_REG_EDI << (slotIndex*3); - case UNW_X86_ESI: - return UNWIND_X86_REG_ESI << (slotIndex*3); - } - - // invalid register - failure = true; - return 0; -} - -template -compact_unwind_encoding_t DwarfInstructions::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, - const Registers_x86& r, const typename CFI_Parser::PrologInfo& prolog, - char warningBuffer[1024]) -{ - warningBuffer[0] = '\0'; - - if ( prolog.registerSavedTwiceInCIE == DW_X86_RET_ADDR ) { - warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker - return UNWIND_X86_64_MODE_DWARF; - } - // don't create compact unwind info for unsupported dwarf kinds - if ( prolog.registerSavedMoreThanOnce ) { - strcpy(warningBuffer, "register saved more than once (might be shrink wrap)"); - return UNWIND_X86_MODE_DWARF; - } - if ( prolog.spExtraArgSize != 0 ) { - strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size"); - return UNWIND_X86_MODE_DWARF; - } - if ( prolog.sameValueUsed ) { - strcpy(warningBuffer, "dwarf uses DW_CFA_same_value"); - return UNWIND_X86_MODE_DWARF; - } - - // figure out which kind of frame this function uses - bool standardEBPframe = ( - (prolog.cfaRegister == UNW_X86_EBP) - && (prolog.cfaRegisterOffset == 8) - && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser::kRegisterInCFA) - && (prolog.savedRegisters[UNW_X86_EBP].value == -8) ); - bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP); - if ( !standardEBPframe && !standardESPframe ) { - // no compact encoding for this - strcpy(warningBuffer, "does not use EBP or ESP based frame"); - return UNWIND_X86_MODE_DWARF; - } - - // scan which registers are saved - int saveRegisterCount = 0; - bool ebxSaved = false; - bool ecxSaved = false; - bool edxSaved = false; - bool esiSaved = false; - bool ediSaved = false; - bool ebpSaved = false; - for (int i=0; i < 64; ++i) { - if ( prolog.savedRegisters[i].location != CFI_Parser::kRegisterUnused ) { - if ( prolog.savedRegisters[i].location != CFI_Parser::kRegisterInCFA ) { - sprintf(warningBuffer, "register %d saved somewhere other that in frame", i); - return UNWIND_X86_MODE_DWARF; - } - switch (i) { - case UNW_X86_EBX: - ebxSaved = true; - ++saveRegisterCount; - break; - case UNW_X86_ECX: - ecxSaved = true; - ++saveRegisterCount; - break; - case UNW_X86_EDX: - edxSaved = true; - ++saveRegisterCount; - break; - case UNW_X86_ESI: - esiSaved = true; - ++saveRegisterCount; - break; - case UNW_X86_EDI: - ediSaved = true; - ++saveRegisterCount; - break; - case UNW_X86_EBP: - ebpSaved = true; - ++saveRegisterCount; - break; - case DW_X86_RET_ADDR: - break; - default: - sprintf(warningBuffer, "non-standard register %d being saved in prolog", i); - return UNWIND_X86_MODE_DWARF; - } - } - } - const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value; - const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value; - const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value; - const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value; - const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value; - const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value; - - // encode standard RBP frames - compact_unwind_encoding_t encoding = 0; - if ( standardEBPframe ) { - // | | - // +--------------+ <- CFA - // | ret addr | - // +--------------+ - // | ebp | - // +--------------+ <- ebp - // ~ ~ - // +--------------+ - // | saved reg3 | - // +--------------+ <- CFA - offset+8 - // | saved reg2 | - // +--------------+ <- CFA - offset+e - // | saved reg1 | - // +--------------+ <- CFA - offset - // | | - // +--------------+ - // | | - // <- esp - // - encoding = UNWIND_X86_MODE_EBP_FRAME; - - // find save location of farthest register from ebp - int furthestCfaOffset = 0; - if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetEBX; - if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetECX; - if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetEDX; - if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetEDI; - if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) ) - furthestCfaOffset = cfaOffsetESI; - - if ( furthestCfaOffset == 0 ) { - // no registers saved, nothing more to encode - return encoding; - } - - // add stack offset to encoding - int ebpOffset = furthestCfaOffset + 8; - int encodedOffset = ebpOffset/(-4); - if ( encodedOffset > 255 ) { - strcpy(warningBuffer, "offset of saved registers too far to encode"); - return UNWIND_X86_MODE_DWARF; - } - encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET)); - - // add register saved from each stack location - bool encodingFailure = false; - if ( ebxSaved ) - encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure); - if ( ecxSaved ) - encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure); - if ( edxSaved ) - encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure); - if ( ediSaved ) - encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure); - if ( esiSaved ) - encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure); - - if ( encodingFailure ){ - strcpy(warningBuffer, "saved registers not contiguous"); - return UNWIND_X86_MODE_DWARF; - } - - return encoding; - } - else { - // | | - // +--------------+ <- CFA - // | ret addr | - // +--------------+ - // | saved reg1 | - // +--------------+ <- CFA - 8 - // | saved reg2 | - // +--------------+ <- CFA - 12 - // | saved reg3 | - // +--------------+ <- CFA - 16 - // | saved reg4 | - // +--------------+ <- CFA - 20 - // | saved reg5 | - // +--------------+ <- CFA - 24 - // | saved reg6 | - // +--------------+ <- CFA - 28 - // | | - // <- esp - // - - // for ESP based frames we need to encode stack size in unwind info - encoding = UNWIND_X86_MODE_STACK_IMMD; - uint64_t stackValue = prolog.cfaRegisterOffset / 4; - uint32_t stackAdjust = 0; - bool immedStackSize = true; - const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE); - if ( stackValue > stackMaxImmedValue ) { - // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function - pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4; - #if __EXCEPTIONS - try { - #endif - uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns); - stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4; - #if __EXCEPTIONS - } - catch (...) { - strcpy(warningBuffer, "stack size is large but stack subl instruction not found"); - return UNWIND_X86_MODE_DWARF; - } - #endif - stackValue = functionContentAdjustStackIns - funcAddr; - immedStackSize = false; - if ( stackAdjust > 7 ) { - strcpy(warningBuffer, "stack subl instruction is too different from dwarf stack size"); - return UNWIND_X86_MODE_DWARF; - } - encoding = UNWIND_X86_MODE_STACK_IND; - } - - - // validate that saved registers are all within 6 slots abutting return address - int registers[6]; - for (int i=0; i < 6;++i) - registers[i] = 0; - if ( ebxSaved ) { - if ( cfaOffsetEBX < -28 ) { - strcpy(warningBuffer, "ebx is saved too far from return address"); - return UNWIND_X86_MODE_DWARF; - } - registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX; - } - if ( ecxSaved ) { - if ( cfaOffsetECX < -28 ) { - strcpy(warningBuffer, "ecx is saved too far from return address"); - return UNWIND_X86_MODE_DWARF; - } - registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX; - } - if ( edxSaved ) { - if ( cfaOffsetEDX < -28 ) { - strcpy(warningBuffer, "edx is saved too far from return address"); - return UNWIND_X86_MODE_DWARF; - } - registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX; - } - if ( ediSaved ) { - if ( cfaOffsetEDI < -28 ) { - strcpy(warningBuffer, "edi is saved too far from return address"); - return UNWIND_X86_MODE_DWARF; - } - registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI; - } - if ( esiSaved ) { - if ( cfaOffsetESI < -28 ) { - strcpy(warningBuffer, "esi is saved too far from return address"); - return UNWIND_X86_MODE_DWARF; - } - registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI; - } - if ( ebpSaved ) { - if ( cfaOffsetEBP < -28 ) { - strcpy(warningBuffer, "ebp is saved too far from return address"); - return UNWIND_X86_MODE_DWARF; - } - registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP; - } - - // validate that saved registers are contiguous and abut return address on stack - for (int i=0; i < saveRegisterCount; ++i) { - if ( registers[5-i] == 0 ) { - strcpy(warningBuffer, "registers not save contiguously in stack"); - return UNWIND_X86_MODE_DWARF; - } - } - - // encode register permutation - // the 10-bits are encoded differently depending on the number of registers saved - int renumregs[6]; - for (int i=6-saveRegisterCount; i < 6; ++i) { - int countless = 0; - for (int j=6-saveRegisterCount; j < i; ++j) { - if ( registers[j] < registers[i] ) - ++countless; - } - renumregs[i] = registers[i] - countless -1; - } - uint32_t permutationEncoding = 0; - switch ( saveRegisterCount ) { - case 6: - permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]); - break; - case 5: - permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]); - break; - case 4: - permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]); - break; - case 3: - permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]); - break; - case 2: - permutationEncoding |= (5*renumregs[4] + renumregs[5]); - break; - case 1: - permutationEncoding |= (renumregs[5]); - break; - } - - encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE)); - encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST)); - encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT)); - encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION)); - return encoding; - } -} - - - - - - - -// -// ppc specific functions -// -template -int DwarfInstructions::lastRestoreReg(const Registers_ppc&) -{ - COMPILE_TIME_ASSERT( (int)CFI_Parser::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR ); - return UNW_PPC_SPEFSCR; -} - -template -bool DwarfInstructions::isReturnAddressRegister(int regNum, const Registers_ppc&) -{ - return (regNum == UNW_PPC_LR); -} - -template -typename A::pint_t DwarfInstructions::getCFA(A& addressSpace, const typename CFI_Parser::PrologInfo& prolog, - const Registers_ppc& registers) -{ - if ( prolog.cfaRegister != 0 ) - return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; - else if ( prolog.cfaExpression != 0 ) - return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0); - else - ABORT("getCFA(): unknown location for ppc cfa"); -} - - -template -compact_unwind_encoding_t DwarfInstructions::encodeToUseDwarf(const Registers_ppc&) -{ - return UNWIND_X86_MODE_DWARF; -} - - -template -compact_unwind_encoding_t DwarfInstructions::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, - const Registers_ppc& r, const typename CFI_Parser::PrologInfo& prolog, - char warningBuffer[1024]) -{ - warningBuffer[0] = '\0'; - return UNWIND_X86_MODE_DWARF; -} - - - - } // namespace libunwind - #endif // __DWARF_INSTRUCTIONS_HPP__ - - - - diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp index 2e4a3bb..f166917 100644 --- a/libunwind/src/DwarfParser.hpp +++ b/libunwind/src/DwarfParser.hpp @@ -1,819 +1,814 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2008-2010 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===--------------------------- DwarfParser.hpp --------------------------===// // -// processor specific parsing of dwarf unwind instructions +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// +// Parses DWARF CFIs (FDEs and CIEs). +// +//===----------------------------------------------------------------------===// #ifndef __DWARF_PARSER_HPP__ #define __DWARF_PARSER_HPP__ +#include #include #include #include -#include - #include "libunwind.h" #include "dwarf2.h" +#include "Registers.hpp" -#include "AddressSpace.hpp" +#include "config.h" namespace libunwind { - -/// /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. -/// See Dwarf Spec for details: -/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +/// See DWARF Spec for details: +/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html /// template -class CFI_Parser -{ +class CFI_Parser { public: - typedef typename A::pint_t pint_t; + typedef typename A::pint_t pint_t; - /// - /// Information encoded in a CIE (Common Information Entry) - /// - struct CIE_Info { - pint_t cieStart; - pint_t cieLength; - pint_t cieInstructions; - uint8_t pointerEncoding; - uint8_t lsdaEncoding; - uint8_t personalityEncoding; - uint8_t personalityOffsetInCIE; - pint_t personality; - int codeAlignFactor; - int dataAlignFactor; - bool isSignalFrame; - bool fdesHaveAugmentationData; - }; - - /// - /// Information about an FDE (Frame Description Entry) - /// - struct FDE_Info { - pint_t fdeStart; - pint_t fdeLength; - pint_t fdeInstructions; - pint_t pcStart; - pint_t pcEnd; - pint_t lsda; - }; + /// Information encoded in a CIE (Common Information Entry) + struct CIE_Info { + pint_t cieStart; + pint_t cieLength; + pint_t cieInstructions; + uint8_t pointerEncoding; + uint8_t lsdaEncoding; + uint8_t personalityEncoding; + uint8_t personalityOffsetInCIE; + pint_t personality; + uint32_t codeAlignFactor; + int dataAlignFactor; + bool isSignalFrame; + bool fdesHaveAugmentationData; + uint8_t returnAddressRegister; +#if defined(_LIBUNWIND_TARGET_AARCH64) + bool addressesSignedWithBKey; +#endif + }; - /// - /// Used by linker when parsing __eh_frame section - /// - struct FDE_Reference { - pint_t address; - uint32_t offsetInFDE; - uint8_t encodingOfAddress; - }; - struct FDE_Atom_Info { - pint_t fdeAddress; - FDE_Reference function; - FDE_Reference cie; - FDE_Reference lsda; - }; - struct CIE_Atom_Info { - pint_t cieAddress; - FDE_Reference personality; - }; - - - /// - /// Information about a frame layout and registers saved determined - /// by "running" the dwarf FDE "instructions" - /// - enum { kMaxRegisterNumber = 120 }; - enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA, - kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ; - struct RegisterLocation { - RegisterSavedWhere location; - int64_t value; - }; - struct PrologInfo { - uint32_t cfaRegister; - int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset - int64_t cfaExpression; // CFA = expression - uint32_t spExtraArgSize; - uint32_t codeOffsetAtStackDecrement; - uint8_t registerSavedTwiceInCIE; - bool registersInOtherRegisters; - bool registerSavedMoreThanOnce; - bool cfaOffsetWasNegative; - bool sameValueUsed; - RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers - }; + /// Information about an FDE (Frame Description Entry) + struct FDE_Info { + pint_t fdeStart; + pint_t fdeLength; + pint_t fdeInstructions; + pint_t pcStart; + pint_t pcEnd; + pint_t lsda; + }; - struct PrologInfoStackEntry { - PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i) - : next(n), info(i) {} - PrologInfoStackEntry* next; - PrologInfo info; - }; + enum { + kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER + }; + enum RegisterSavedWhere { + kRegisterUnused, + kRegisterInCFA, + kRegisterOffsetFromCFA, + kRegisterInRegister, + kRegisterAtExpression, + kRegisterIsExpression + }; + struct RegisterLocation { + RegisterSavedWhere location; + bool initialStateSaved; + int64_t value; + }; + /// Information about a frame layout and registers saved determined + /// by "running" the DWARF FDE "instructions" + struct PrologInfo { + uint32_t cfaRegister; + int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset + int64_t cfaExpression; // CFA = expression + uint32_t spExtraArgSize; + uint32_t codeOffsetAtStackDecrement; + bool registersInOtherRegisters; + bool sameValueUsed; + RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; + enum class InitializeTime { kLazy, kNormal }; - static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo); - static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo); - static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results); - static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, - std::vector& fdes, std::vector& cies); - static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength); + // When saving registers, this data structure is lazily initialized. + PrologInfo(InitializeTime IT = InitializeTime::kNormal) { + if (IT == InitializeTime::kNormal) + memset(this, 0, sizeof(*this)); + } + void checkSaveRegister(uint64_t reg, PrologInfo &initialState) { + if (!savedRegisters[reg].initialStateSaved) { + initialState.savedRegisters[reg] = savedRegisters[reg]; + savedRegisters[reg].initialStateSaved = true; + } + } + void setRegister(uint64_t reg, RegisterSavedWhere newLocation, + int64_t newValue, PrologInfo &initialState) { + checkSaveRegister(reg, initialState); + savedRegisters[reg].location = newLocation; + savedRegisters[reg].value = newValue; + } + void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation, + PrologInfo &initialState) { + checkSaveRegister(reg, initialState); + savedRegisters[reg].location = newLocation; + } + void setRegisterValue(uint64_t reg, int64_t newValue, + PrologInfo &initialState) { + checkSaveRegister(reg, initialState); + savedRegisters[reg].value = newValue; + } + void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) { + if (savedRegisters[reg].initialStateSaved) + savedRegisters[reg] = initialState.savedRegisters[reg]; + // else the register still holds its initial state + } + }; - static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo); + struct PrologInfoStackEntry { + PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) + : next(n), info(i) {} + PrologInfoStackEntry *next; + PrologInfo info; + }; + + static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, + uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, + CIE_Info *cieInfo); + static const char *decodeFDE(A &addressSpace, pint_t fdeStart, + FDE_Info *fdeInfo, CIE_Info *cieInfo); + static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, + const CIE_Info &cieInfo, pint_t upToPC, + int arch, PrologInfo *results); + + static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); private: - static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo, - pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results); + static bool parseInstructions(A &addressSpace, pint_t instructions, + pint_t instructionsEnd, const CIE_Info &cieInfo, + pint_t pcoffset, + PrologInfoStackEntry *&rememberStack, int arch, + PrologInfo *results); }; - -/// -/// Parse a FDE into a CIE_Info and an FDE_Info -/// +/// Parse a FDE into a CIE_Info and an FDE_Info template -const char* CFI_Parser::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo) -{ - pint_t p = fdeStart; - uint64_t cfiLength = addressSpace.get32(p); - p += 4; - if ( cfiLength == 0xffffffff ) { - // 0xffffffff means length is really next 8 bytes - cfiLength = addressSpace.get64(p); - p += 8; - } - if ( cfiLength == 0 ) - return "FDE has zero length"; // end marker - uint32_t ciePointer = addressSpace.get32(p); - if ( ciePointer == 0 ) - return "FDE is really a CIE"; // this is a CIE not an FDE - pint_t nextCFI = p + cfiLength; - pint_t cieStart = p-ciePointer; - const char* err = parseCIE(addressSpace, cieStart, cieInfo); - if (err != NULL) - return err; - p += 4; - // parse pc begin and range - pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); - pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); - // parse rest of info - fdeInfo->lsda = 0; - // check for augmentation length - if ( cieInfo->fdesHaveAugmentationData ) { - uintptr_t augLen = addressSpace.getULEB128(p, nextCFI); - pint_t endOfAug = p + augLen; - if ( cieInfo->lsdaEncoding != 0 ) { - // peek at value (without indirection). Zero means no lsda - pint_t lsdaStart = p; - if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) { - // reset pointer and re-parse lsda address - p = lsdaStart; - fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); - } - } - p = endOfAug; - } - fdeInfo->fdeStart = fdeStart; - fdeInfo->fdeLength = nextCFI - fdeStart; - fdeInfo->fdeInstructions = p; - fdeInfo->pcStart = pcStart; - fdeInfo->pcEnd = pcStart+pcRange; - return NULL; // success +const char *CFI_Parser::decodeFDE(A &addressSpace, pint_t fdeStart, + FDE_Info *fdeInfo, CIE_Info *cieInfo) { + pint_t p = fdeStart; + pint_t cfiLength = (pint_t)addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return "FDE has zero length"; // end marker + uint32_t ciePointer = addressSpace.get32(p); + if (ciePointer == 0) + return "FDE is really a CIE"; // this is a CIE not an FDE + pint_t nextCFI = p + cfiLength; + pint_t cieStart = p - ciePointer; + const char *err = parseCIE(addressSpace, cieStart, cieInfo); + if (err != NULL) + return err; + p += 4; + // Parse pc begin and range. + pint_t pcStart = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + pint_t pcRange = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); + // Parse rest of info. + fdeInfo->lsda = 0; + // Check for augmentation length. + if (cieInfo->fdesHaveAugmentationData) { + pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); + pint_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { + // Peek at value (without indirection). Zero means no LSDA. + pint_t lsdaStart = p; + if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != + 0) { + // Reset pointer and re-parse LSDA address. + p = lsdaStart; + fdeInfo->lsda = + addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = fdeStart; + fdeInfo->fdeLength = nextCFI - fdeStart; + fdeInfo->fdeInstructions = p; + fdeInfo->pcStart = pcStart; + fdeInfo->pcEnd = pcStart + pcRange; + return NULL; // success } - -/// /// Scan an eh_frame section to find an FDE for a pc -/// template -bool CFI_Parser::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo) -{ - //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); - pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; - const pint_t ehSectionEnd = p + sectionLength; - while ( p < ehSectionEnd ) { - pint_t currentCFI = p; - //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); - uint64_t cfiLength = addressSpace.get32(p); - p += 4; - if ( cfiLength == 0xffffffff ) { - // 0xffffffff means length is really next 8 bytes - cfiLength = addressSpace.get64(p); - p += 8; - } - if ( cfiLength == 0 ) - return false; // end marker - uint32_t id = addressSpace.get32(p); - if ( id == 0 ) { - // skip over CIEs - p += cfiLength; - } - else { - // process FDE to see if it covers pc - pint_t nextCFI = p + cfiLength; - uint32_t ciePointer = addressSpace.get32(p); - pint_t cieStart = p-ciePointer; - // validate pointer to CIE is within section - if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) { - if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) { - p += 4; - // parse pc begin and range - pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); - pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); - //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange)); - // test if pc is within the function this FDE covers - if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) { - // parse rest of info - fdeInfo->lsda = 0; - // check for augmentation length - if ( cieInfo->fdesHaveAugmentationData ) { - uintptr_t augLen = addressSpace.getULEB128(p, nextCFI); - pint_t endOfAug = p + augLen; - if ( cieInfo->lsdaEncoding != 0 ) { - // peek at value (without indirection). Zero means no lsda - pint_t lsdaStart = p; - if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) { - // reset pointer and re-parse lsda address - p = lsdaStart; - fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); - } - } - p = endOfAug; - } - fdeInfo->fdeStart = currentCFI; - fdeInfo->fdeLength = nextCFI - currentCFI; - fdeInfo->fdeInstructions = p; - fdeInfo->pcStart = pcStart; - fdeInfo->pcEnd = pcStart+pcRange; - //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange)); - return true; - } - else { - //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange)); - // pc is not in begin/range, skip this FDE - } - } - else { - // malformed CIE, now augmentation describing pc range encoding - //fprintf(stderr, "malformed CIE\n"); - } - } - else { - // malformed FDE. CIE is bad - //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n", - // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd); - } - p = nextCFI; - } - } - //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc); - return false; +bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, + uint32_t sectionLength, pint_t fdeHint, + FDE_Info *fdeInfo, CIE_Info *cieInfo) { + //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); + pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; + const pint_t ehSectionEnd = p + sectionLength; + while (p < ehSectionEnd) { + pint_t currentCFI = p; + //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); + pint_t cfiLength = addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return false; // end marker + uint32_t id = addressSpace.get32(p); + if (id == 0) { + // Skip over CIEs. + p += cfiLength; + } else { + // Process FDE to see if it covers pc. + pint_t nextCFI = p + cfiLength; + uint32_t ciePointer = addressSpace.get32(p); + pint_t cieStart = p - ciePointer; + // Validate pointer to CIE is within section. + if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { + if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { + p += 4; + // Parse pc begin and range. + pint_t pcStart = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + pint_t pcRange = addressSpace.getEncodedP( + p, nextCFI, cieInfo->pointerEncoding & 0x0F); + // Test if pc is within the function this FDE covers. + if ((pcStart < pc) && (pc <= pcStart + pcRange)) { + // parse rest of info + fdeInfo->lsda = 0; + // check for augmentation length + if (cieInfo->fdesHaveAugmentationData) { + pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); + pint_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { + // Peek at value (without indirection). Zero means no LSDA. + pint_t lsdaStart = p; + if (addressSpace.getEncodedP( + p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { + // Reset pointer and re-parse LSDA address. + p = lsdaStart; + fdeInfo->lsda = addressSpace + .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = currentCFI; + fdeInfo->fdeLength = nextCFI - currentCFI; + fdeInfo->fdeInstructions = p; + fdeInfo->pcStart = pcStart; + fdeInfo->pcEnd = pcStart + pcRange; + return true; + } else { + // pc is not in begin/range, skip this FDE + } + } else { + // Malformed CIE, now augmentation describing pc range encoding. + } + } else { + // malformed FDE. CIE is bad + } + p = nextCFI; + } + } + return false; } - - -/// /// Extract info from a CIE -/// template -const char* CFI_Parser::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo) -{ - //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie); - cieInfo->pointerEncoding = 0; - cieInfo->lsdaEncoding = 0; - cieInfo->personalityEncoding = 0; - cieInfo->personalityOffsetInCIE = 0; - cieInfo->personality = 0; - cieInfo->codeAlignFactor = 0; - cieInfo->dataAlignFactor = 0; - cieInfo->isSignalFrame = false; - cieInfo->fdesHaveAugmentationData = false; - cieInfo->cieStart = cie; - pint_t p = cie; - uint64_t cieLength = addressSpace.get32(p); - p += 4; - pint_t cieContentEnd = p + cieLength; - if ( cieLength == 0xffffffff ) { - // 0xffffffff means length is really next 8 bytes - cieLength = addressSpace.get64(p); - p += 8; - cieContentEnd = p + cieLength; - } - if ( cieLength == 0 ) - return NULL; - // CIE ID is always 0 - if ( addressSpace.get32(p) != 0 ) - return "CIE ID is not zero"; - p += 4; - // Version is always 1 or 3 - uint8_t version = addressSpace.get8(p); - if ( (version != 1) && (version != 3) ) - return "CIE version is not 1 or 3"; - ++p; - // save start of augmentation string and find end - pint_t strStart = p; - while ( addressSpace.get8(p) != 0 ) - ++p; - ++p; - // parse code aligment factor - cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd); - // parse data alignment factor - cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd); - // parse return address register - addressSpace.getULEB128(p, cieContentEnd); - // parse augmentation data based on augmentation string - const char* result = NULL; - if ( addressSpace.get8(strStart) == 'z' ) { - // parse augmentation data length - addressSpace.getULEB128(p, cieContentEnd); - for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) { - switch ( addressSpace.get8(s) ) { - case 'z': - cieInfo->fdesHaveAugmentationData = true; - break; - case 'P': - cieInfo->personalityEncoding = addressSpace.get8(p); - ++p; - cieInfo->personalityOffsetInCIE = p-cie; - cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); - break; - case 'L': - cieInfo->lsdaEncoding = addressSpace.get8(p); - ++p; - break; - case 'R': - cieInfo->pointerEncoding = addressSpace.get8(p); - ++p; - break; - case 'S': - cieInfo->isSignalFrame = true; - break; - default: - // ignore unknown letters - break; - } - } - } - cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; - cieInfo->cieInstructions = p; - return result; +const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, + CIE_Info *cieInfo) { + cieInfo->pointerEncoding = 0; + cieInfo->lsdaEncoding = DW_EH_PE_omit; + cieInfo->personalityEncoding = 0; + cieInfo->personalityOffsetInCIE = 0; + cieInfo->personality = 0; + cieInfo->codeAlignFactor = 0; + cieInfo->dataAlignFactor = 0; + cieInfo->isSignalFrame = false; + cieInfo->fdesHaveAugmentationData = false; +#if defined(_LIBUNWIND_TARGET_AARCH64) + cieInfo->addressesSignedWithBKey = false; +#endif + cieInfo->cieStart = cie; + pint_t p = cie; + pint_t cieLength = (pint_t)addressSpace.get32(p); + p += 4; + pint_t cieContentEnd = p + cieLength; + if (cieLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cieLength = (pint_t)addressSpace.get64(p); + p += 8; + cieContentEnd = p + cieLength; + } + if (cieLength == 0) + return NULL; + // CIE ID is always 0 + if (addressSpace.get32(p) != 0) + return "CIE ID is not zero"; + p += 4; + // Version is always 1 or 3 + uint8_t version = addressSpace.get8(p); + if ((version != 1) && (version != 3)) + return "CIE version is not 1 or 3"; + ++p; + // save start of augmentation string and find end + pint_t strStart = p; + while (addressSpace.get8(p) != 0) + ++p; + ++p; + // parse code aligment factor + cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); + // parse data alignment factor + cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); + // parse return address register + uint64_t raReg = (version == 1) ? addressSpace.get8(p++) + : addressSpace.getULEB128(p, cieContentEnd); + assert(raReg < 255 && "return address register too large"); + cieInfo->returnAddressRegister = (uint8_t)raReg; + // parse augmentation data based on augmentation string + const char *result = NULL; + pint_t resultAddr = 0; + if (addressSpace.get8(strStart) == 'z') { + // parse augmentation data length + addressSpace.getULEB128(p, cieContentEnd); + for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { + switch (addressSpace.get8(s)) { + case 'z': + cieInfo->fdesHaveAugmentationData = true; + break; + case 'P': + cieInfo->personalityEncoding = addressSpace.get8(p); + ++p; + cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); + cieInfo->personality = addressSpace + .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding, + /*datarelBase=*/0, &resultAddr); + break; + case 'L': + cieInfo->lsdaEncoding = addressSpace.get8(p); + ++p; + break; + case 'R': + cieInfo->pointerEncoding = addressSpace.get8(p); + ++p; + break; + case 'S': + cieInfo->isSignalFrame = true; + break; +#if defined(_LIBUNWIND_TARGET_AARCH64) + case 'B': + cieInfo->addressesSignedWithBKey = true; + break; +#endif + default: + // ignore unknown letters + break; + } + } + } + cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; + cieInfo->cieInstructions = p; + return result; } +/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE template -uint32_t CFI_Parser::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength) -{ - uint32_t count = 0; - const pint_t ehSectionEnd = ehSectionStart + sectionLength; - for (pint_t p=ehSectionStart; p < ehSectionEnd; ) { - uint64_t cfiLength = addressSpace.get32(p); - p += 4; - if ( cfiLength == 0xffffffff ) { - // 0xffffffff means length is really next 8 bytes - cfiLength = addressSpace.get64(p); - p += 8; - } - if ( cfiLength == 0 ) - return count; // end marker - ++count; - p += cfiLength; - } - return count; +bool CFI_Parser::parseFDEInstructions(A &addressSpace, + const FDE_Info &fdeInfo, + const CIE_Info &cieInfo, pint_t upToPC, + int arch, PrologInfo *results) { + PrologInfoStackEntry *rememberStack = NULL; + + // parse CIE then FDE instructions + bool returnValue = + parseInstructions(addressSpace, cieInfo.cieInstructions, + cieInfo.cieStart + cieInfo.cieLength, cieInfo, + (pint_t)(-1), rememberStack, arch, results) && + parseInstructions(addressSpace, fdeInfo.fdeInstructions, + fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, + upToPC - fdeInfo.pcStart, rememberStack, arch, results); + +#if !defined(_LIBUNWIND_NO_HEAP) + // Clean up rememberStack. Even in the case where every DW_CFA_remember_state + // is paired with a DW_CFA_restore_state, parseInstructions can skip restore + // opcodes if it reaches the target PC and stops interpreting, so we have to + // make sure we don't leak memory. + while (rememberStack) { + PrologInfoStackEntry *next = rememberStack->next; + free(rememberStack); + rememberStack = next; + } +#endif + + return returnValue; } - - +/// "run" the DWARF instructions template -const char* CFI_Parser::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, - std::vector& fdes, std::vector& cies) -{ - const pint_t ehSectionEnd = ehSectionStart + sectionLength; - for (pint_t p=ehSectionStart; p < ehSectionEnd; ) { - pint_t currentCFI = p; - uint64_t cfiLength = addressSpace.get32(p); - p += 4; - if ( cfiLength == 0xffffffff ) { - // 0xffffffff means length is really next 8 bytes - cfiLength = addressSpace.get64(p); - p += 8; - } - if ( cfiLength == 0 ) - return NULL; // end marker - uint32_t id = addressSpace.get32(p); - if ( id == 0 ) { - // is CIE - CIE_Info cieInfo; - const char* err = parseCIE(addressSpace, currentCFI, &cieInfo); - if ( err != NULL ) - return err; - CIE_Atom_Info entry; - entry.cieAddress = currentCFI; - entry.personality.address = cieInfo.personality; - entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE; - entry.personality.encodingOfAddress = cieInfo.personalityEncoding; - cies.push_back(entry); - p += cfiLength; - } - else { - // is FDE - FDE_Atom_Info entry; - entry.fdeAddress = currentCFI; - entry.function.address = 0; - entry.cie.address = 0; - entry.lsda.address = 0; - pint_t nextCFI = p + cfiLength; - uint32_t ciePointer = addressSpace.get32(p); - pint_t cieStart = p-ciePointer; - // validate pointer to CIE is within section - if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) ) - return "FDE points to CIE outside __eh_frame section"; - CIE_Info cieInfo; - const char* err = parseCIE(addressSpace, cieStart, &cieInfo); - if ( err != NULL ) - return err; - entry.cie.address = cieStart; - entry.cie.offsetInFDE = p-currentCFI; - entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel; - p += 4; - // parse pc begin and range - pint_t offsetOfFunctionAddress = p-currentCFI; - pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding); - pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F); - //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange)); - // test if pc is within the function this FDE covers - entry.function.address = pcStart; - entry.function.offsetInFDE = offsetOfFunctionAddress; - entry.function.encodingOfAddress = cieInfo.pointerEncoding; - // skip over augmentation length - if ( cieInfo.fdesHaveAugmentationData ) { - uintptr_t augLen = addressSpace.getULEB128(p, nextCFI); - pint_t endOfAug = p + augLen; - if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) { - pint_t offsetOfLSDAAddress = p-currentCFI; - entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding); - entry.lsda.offsetInFDE = offsetOfLSDAAddress; - entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding; - } - p = endOfAug; - } - fdes.push_back(entry); - p = nextCFI; - } - } - return NULL; // success +bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, + pint_t instructionsEnd, + const CIE_Info &cieInfo, pint_t pcoffset, + PrologInfoStackEntry *&rememberStack, + int arch, PrologInfo *results) { + pint_t p = instructions; + pint_t codeOffset = 0; + // initialState initialized as registers in results are modified. Use + // PrologInfo accessor functions to avoid reading uninitialized data. + PrologInfo initialState(PrologInfo::InitializeTime::kLazy); + + _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n", + static_cast(instructionsEnd)); + + // see DWARF Spec, section 6.4.2 for details on unwind opcodes + while ((p < instructionsEnd) && (codeOffset < pcoffset)) { + uint64_t reg; + uint64_t reg2; + int64_t offset; + uint64_t length; + uint8_t opcode = addressSpace.get8(p); + uint8_t operand; +#if !defined(_LIBUNWIND_NO_HEAP) + PrologInfoStackEntry *entry; +#endif + ++p; + switch (opcode) { + case DW_CFA_nop: + _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); + break; + case DW_CFA_set_loc: + codeOffset = + addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); + _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); + break; + case DW_CFA_advance_loc1: + codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); + p += 1; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_advance_loc2: + codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); + p += 2; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_advance_loc4: + codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); + p += 4; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_restore_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); + return false; + } + results->restoreRegisterToInitialState(reg, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_undefined: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_undefined DWARF unwind, reg too big"); + return false; + } + results->setRegisterLocation(reg, kRegisterUnused, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_same_value: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_same_value DWARF unwind, reg too big"); + return false; + } + // DW_CFA_same_value unsupported + // "same value" means register was stored in frame, but its current + // value has not changed, so no need to restore from frame. + // We model this as if the register was never saved. + results->setRegisterLocation(reg, kRegisterUnused, initialState); + // set flag to disable conversion to compact unwind + results->sameValueUsed = true; + _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + reg2 = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg too big"); + return false; + } + if (reg2 > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg2 too big"); + return false; + } + results->setRegister(reg, kRegisterInRegister, (int64_t)reg2, + initialState); + // set flag to disable conversion to compact unwind + results->registersInOtherRegisters = true; + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); + break; +#if !defined(_LIBUNWIND_NO_HEAP) + case DW_CFA_remember_state: + // avoid operator new, because that would be an upward dependency + entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); + if (entry != NULL) { + entry->next = rememberStack; + entry->info = *results; + rememberStack = entry; + } else { + return false; + } + _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); + break; + case DW_CFA_restore_state: + if (rememberStack != NULL) { + PrologInfoStackEntry *top = rememberStack; + *results = top->info; + rememberStack = top->next; + free((char *)top); + } else { + return false; + } + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); + break; +#endif + case DW_CFA_def_cfa: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset); + break; + case DW_CFA_def_cfa_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); + break; + case DW_CFA_def_cfa_offset: + results->cfaRegisterOffset = (int32_t) + addressSpace.getULEB128(p, instructionsEnd); + results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_def_cfa_expression: + results->cfaRegister = 0; + results->cfaExpression = (int64_t)p; + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 + ", length=%" PRIu64 ")\n", + results->cfaExpression, length); + break; + case DW_CFA_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_expression DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterAtExpression, (int64_t)p, + initialState); + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", " + "length=%" PRIu64 ")\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_offset_extended_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); + return false; + } + offset = + addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = + addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_offset_sf: + results->cfaRegisterOffset = (int32_t) + (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); + results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_val_offset: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG( + "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); + break; + case DW_CFA_val_offset_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); + return false; + } + offset = + addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); + break; + case DW_CFA_val_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_expression DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterIsExpression, (int64_t)p, + initialState); + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_GNU_args_size: + length = addressSpace.getULEB128(p, instructionsEnd); + results->spExtraArgSize = (uint32_t)length; + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); + break; + case DW_CFA_GNU_negative_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " + "unwind, reg too big"); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, -offset, initialState); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); + break; + +#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) + // The same constant is used to represent different instructions on + // AArch64 (negate_ra_state) and SPARC (window_save). + static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, + "uses the same constant"); + case DW_CFA_AARCH64_negate_ra_state: + switch (arch) { +#if defined(_LIBUNWIND_TARGET_AARCH64) + case REGISTERS_ARM64: { + int64_t value = + results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1; + results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); + } break; +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + // case DW_CFA_GNU_window_save: + case REGISTERS_SPARC: + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); + for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { + results->setRegister(reg, kRegisterInRegister, + ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0, + initialState); + } + + for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { + results->setRegister(reg, kRegisterInCFA, + ((int64_t)reg - UNW_SPARC_L0) * 4, initialState); + } + break; +#endif + } + break; +#else + (void)arch; +#endif + + default: + operand = opcode & 0x3F; + switch (opcode & 0xC0) { + case DW_CFA_offset: + reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", + operand, offset); + break; + case DW_CFA_advance_loc: + codeOffset += operand * cieInfo.codeAlignFactor; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_restore: + reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } + results->restoreRegisterToInitialState(reg, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", + static_cast(operand)); + break; + default: + _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); + return false; + } + } + } + + return true; } - - -/// -/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE -/// -template -bool CFI_Parser::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results) -{ - // clear results - bzero(results, sizeof(PrologInfo)); - PrologInfoStackEntry* rememberStack = NULL; - - // parse CIE then FDE instructions - return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength, - cieInfo, (pint_t)(-1), rememberStack, results) - && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength, - cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results); -} - - -/// -/// "run" the dwarf instructions -/// -template -bool CFI_Parser::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo, - pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results) -{ - const bool logDwarf = false; - pint_t p = instructions; - uint32_t codeOffset = 0; - PrologInfo initialState = *results; - if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd); - - // see Dwarf Spec, section 6.4.2 for details on unwind opcodes - while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) { - uint64_t reg; - uint64_t reg2; - int64_t offset; - uint64_t length; - uint8_t opcode = addressSpace.get8(p); - uint8_t operand; - PrologInfoStackEntry* entry; - ++p; - switch (opcode) { - case DW_CFA_nop: - if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n"); - break; - case DW_CFA_set_loc: - codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); - if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n"); - break; - case DW_CFA_advance_loc1: - codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); - p += 1; - if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset); - break; - case DW_CFA_advance_loc2: - codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); - p += 2; - if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset); - break; - case DW_CFA_advance_loc4: - codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); - p += 4; - if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset); - break; - case DW_CFA_offset_extended: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n"); - return false; - } - if ( results->savedRegisters[reg].location != kRegisterUnused ) - results->registerSavedMoreThanOnce = true; - results->savedRegisters[reg].location = kRegisterInCFA; - results->savedRegisters[reg].value = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset); - break; - case DW_CFA_restore_extended: - reg = addressSpace.getULEB128(p, instructionsEnd);; - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n"); - return false; - } - results->savedRegisters[reg] = initialState.savedRegisters[reg]; - if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg); - break; - case DW_CFA_undefined: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n"); - return false; - } - results->savedRegisters[reg].location = kRegisterUnused; - if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg); - break; - case DW_CFA_same_value: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n"); - return false; - } - // DW_CFA_same_value unsupported - // "same value" means register was stored in frame, but its current - // value has not changed, so no need to restore from frame. - // We model this as if the register was never saved. - results->savedRegisters[reg].location = kRegisterUnused; - // set flag to disable conversion to compact unwind - results->sameValueUsed = true; - if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg); - break; - case DW_CFA_register: - reg = addressSpace.getULEB128(p, instructionsEnd); - reg2 = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n"); - return false; - } - if ( reg2 > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n"); - return false; - } - results->savedRegisters[reg].location = kRegisterInRegister; - results->savedRegisters[reg].value = reg2; - // set flag to disable conversion to compact unwind - results->registersInOtherRegisters = true; - if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2); - break; - case DW_CFA_remember_state: - // avoid operator new, because that would be an upward dependency - entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry)); - if ( entry != NULL ) { - entry->next = rememberStack; - entry->info = *results; - rememberStack = entry; - } - else { - return false; - } - if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n"); - break; - case DW_CFA_restore_state: - if ( rememberStack != NULL ) { - PrologInfoStackEntry* top = rememberStack; - *results = top->info; - rememberStack = top->next; - free((char*)top); - } - else { - return false; - } - if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n"); - break; - case DW_CFA_def_cfa: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n"); - return false; - } - results->cfaRegister = reg; - results->cfaRegisterOffset = offset; - if ( offset > 0x80000000 ) - results->cfaOffsetWasNegative = true; - if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset); - break; - case DW_CFA_def_cfa_register: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n"); - return false; - } - results->cfaRegister = reg; - if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg); - break; - case DW_CFA_def_cfa_offset: - results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd); - results->codeOffsetAtStackDecrement = codeOffset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset); - break; - case DW_CFA_def_cfa_expression: - results->cfaRegister = 0; - results->cfaExpression = p; - length = addressSpace.getULEB128(p, instructionsEnd); - p += length; - if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n", - results->cfaExpression, length); - break; - case DW_CFA_expression: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n"); - return false; - } - results->savedRegisters[reg].location = kRegisterAtExpression; - results->savedRegisters[reg].value = p; - length = addressSpace.getULEB128(p, instructionsEnd); - p += length; - if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n", - reg, results->savedRegisters[reg].value, length); - break; - case DW_CFA_offset_extended_sf: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n"); - return false; - } - offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - if ( results->savedRegisters[reg].location != kRegisterUnused ) - results->registerSavedMoreThanOnce = true; - results->savedRegisters[reg].location = kRegisterInCFA; - results->savedRegisters[reg].value = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset); - break; - case DW_CFA_def_cfa_sf: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); - return false; - } - results->cfaRegister = reg; - results->cfaRegisterOffset = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset); - break; - case DW_CFA_def_cfa_offset_sf: - results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - results->codeOffsetAtStackDecrement = codeOffset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset); - break; - case DW_CFA_val_offset: - reg = addressSpace.getULEB128(p, instructionsEnd); - offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - results->savedRegisters[reg].location = kRegisterOffsetFromCFA; - results->savedRegisters[reg].value = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset); - break; - case DW_CFA_val_offset_sf: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); - return false; - } - offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - results->savedRegisters[reg].location = kRegisterOffsetFromCFA; - results->savedRegisters[reg].value = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset); - break; - case DW_CFA_val_expression: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); - return false; - } - results->savedRegisters[reg].location = kRegisterIsExpression; - results->savedRegisters[reg].value = p; - length = addressSpace.getULEB128(p, instructionsEnd); - p += length; - if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n", - reg, results->savedRegisters[reg].value, length); - break; - case DW_CFA_GNU_args_size: - offset = addressSpace.getULEB128(p, instructionsEnd); - results->spExtraArgSize = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset); - break; - case DW_CFA_GNU_negative_offset_extended: - reg = addressSpace.getULEB128(p, instructionsEnd); - if ( reg > kMaxRegisterNumber ) { - fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n"); - return false; - } - offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - if ( results->savedRegisters[reg].location != kRegisterUnused ) - results->registerSavedMoreThanOnce = true; - results->savedRegisters[reg].location = kRegisterInCFA; - results->savedRegisters[reg].value = -offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset); - break; - default: - operand = opcode & 0x3F; - switch ( opcode & 0xC0 ) { - case DW_CFA_offset: - reg = operand; - offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; - if ( results->savedRegisters[reg].location != kRegisterUnused ) { - // look for idiom of PC saved twice in CIE to mean disable compact unwind encoding - if ( (pcoffset == (pint_t)(-1)) - && (results->savedRegisters[reg].location == kRegisterInCFA) - && (results->savedRegisters[reg].value == offset) ) - results->registerSavedTwiceInCIE = reg; - else - results->registerSavedMoreThanOnce = true; - } - results->savedRegisters[reg].location = kRegisterInCFA; - results->savedRegisters[reg].value = offset; - if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset); - break; - case DW_CFA_advance_loc: - codeOffset += operand * cieInfo.codeAlignFactor; - if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset); - break; - case DW_CFA_restore: - // Python crashes when handling an exception thrown by an obj-c object - // libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag - //return true; // gcc-4.5 starts the epilog with this - reg = operand; - results->savedRegisters[reg] = initialState.savedRegisters[reg]; - if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg); - break; - default: - if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); - return false; - } - } - } - - return true; -} - - -} // namespace libunwind - +} // namespace libunwind #endif // __DWARF_PARSER_HPP__ - - - - diff --git a/libunwind/src/EHHeaderParser.hpp b/libunwind/src/EHHeaderParser.hpp new file mode 100644 index 0000000..f97cca5 --- /dev/null +++ b/libunwind/src/EHHeaderParser.hpp @@ -0,0 +1,169 @@ +//===------------------------- EHHeaderParser.hpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Parses ELF .eh_frame_hdr sections. +// +//===----------------------------------------------------------------------===// + +#ifndef __EHHEADERPARSER_HPP__ +#define __EHHEADERPARSER_HPP__ + +#include "libunwind.h" + +#include "DwarfParser.hpp" + +namespace libunwind { + +/// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section. +/// +/// See DWARF spec for details: +/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +/// +template class EHHeaderParser { +public: + typedef typename A::pint_t pint_t; + + /// Information encoded in the EH frame header. + struct EHHeaderInfo { + pint_t eh_frame_ptr; + size_t fde_count; + pint_t table; + uint8_t table_enc; + }; + + static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, + EHHeaderInfo &ehHdrInfo); + static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, + uint32_t sectionLength, + typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo); + +private: + static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry, + pint_t ehHdrStart, pint_t ehHdrEnd, + uint8_t tableEnc, + typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo); + static size_t getTableEntrySize(uint8_t tableEnc); +}; + +template +bool EHHeaderParser::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, + pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) { + pint_t p = ehHdrStart; + uint8_t version = addressSpace.get8(p++); + if (version != 1) { + _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version"); + return false; + } + + uint8_t eh_frame_ptr_enc = addressSpace.get8(p++); + uint8_t fde_count_enc = addressSpace.get8(p++); + ehHdrInfo.table_enc = addressSpace.get8(p++); + + ehHdrInfo.eh_frame_ptr = + addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart); + ehHdrInfo.fde_count = + fde_count_enc == DW_EH_PE_omit + ? 0 + : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); + ehHdrInfo.table = p; + + return true; +} + +template +bool EHHeaderParser::decodeTableEntry( + A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd, + uint8_t tableEnc, typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo) { + // Have to decode the whole FDE for the PC range anyway, so just throw away + // the PC start. + addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart); + pint_t fde = + addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart); + const char *message = + CFI_Parser::decodeFDE(addressSpace, fde, fdeInfo, cieInfo); + if (message != NULL) { + _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s", + message); + return false; + } + + return true; +} + +template +bool EHHeaderParser::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, + uint32_t sectionLength, + typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo) { + pint_t ehHdrEnd = ehHdrStart + sectionLength; + + EHHeaderParser::EHHeaderInfo hdrInfo; + if (!EHHeaderParser::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, + hdrInfo)) + return false; + + if (hdrInfo.fde_count == 0) return false; + + size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc); + pint_t tableEntry; + + size_t low = 0; + for (size_t len = hdrInfo.fde_count; len > 1;) { + size_t mid = low + (len / 2); + tableEntry = hdrInfo.table + mid * tableEntrySize; + pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd, + hdrInfo.table_enc, ehHdrStart); + + if (start == pc) { + low = mid; + break; + } else if (start < pc) { + low = mid; + len -= (len / 2); + } else { + len /= 2; + } + } + + tableEntry = hdrInfo.table + low * tableEntrySize; + if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd, + hdrInfo.table_enc, fdeInfo, cieInfo)) { + if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd) + return true; + } + + return false; +} + +template +size_t EHHeaderParser::getTableEntrySize(uint8_t tableEnc) { + switch (tableEnc & 0x0f) { + case DW_EH_PE_sdata2: + case DW_EH_PE_udata2: + return 4; + case DW_EH_PE_sdata4: + case DW_EH_PE_udata4: + return 8; + case DW_EH_PE_sdata8: + case DW_EH_PE_udata8: + return 16; + case DW_EH_PE_sleb128: + case DW_EH_PE_uleb128: + _LIBUNWIND_ABORT("Can't binary search on variable length encoded data."); + case DW_EH_PE_omit: + return 0; + default: + _LIBUNWIND_ABORT("Unknown DWARF encoding for search table."); + } +} + +} + +#endif diff --git a/libunwind/src/FileAbstraction.hpp b/libunwind/src/FileAbstraction.hpp deleted file mode 100644 index 9b6f7e9..0000000 --- a/libunwind/src/FileAbstraction.hpp +++ /dev/null @@ -1,146 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2005-2008 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef __FILE_ABSTRACTION__ -#define __FILE_ABSTRACTION__ - - -#include -#include -#include - -#ifdef __OPTIMIZE__ -#define INLINE __attribute__((always_inline)) -#else -#define INLINE -#endif - -// -// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants -// -// For example: to make a utility that handles 32-bit little enidan files use: Pointer32 -// -// -// get16() read a 16-bit number from an E endian struct -// set16() write a 16-bit number to an E endian struct -// get32() read a 32-bit number from an E endian struct -// set32() write a 32-bit number to an E endian struct -// get64() read a 64-bit number from an E endian struct -// set64() write a 64-bit number to an E endian struct -// -// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field) -// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field) -// -// getBitsRaw() read a bit field from a struct with native endianness -// setBitsRaw() write a bit field from a struct with native endianness -// - -class BigEndian -{ -public: - static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); } - static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); } - - static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); } - static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); } - - static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); } - static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); } - - static uint32_t getBits(const uint32_t& from, - uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); } - static void setBits(uint32_t& into, uint32_t value, - uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); } - - static uint32_t getBitsRaw(const uint32_t& from, - uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<> firstBit) & ((1< -class Pointer32 -{ -public: - typedef uint32_t uint_t; - typedef _E E; - - static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); } - static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); } -}; - - -template -class Pointer64 -{ -public: - typedef uint64_t uint_t; - typedef _E E; - - static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); } - static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); } -}; - - - - - - -#endif // __FILE_ABSTRACTION__ - - diff --git a/libunwind/src/FrameHeaderCache.hpp b/libunwind/src/FrameHeaderCache.hpp new file mode 100644 index 0000000..813fcd4 --- /dev/null +++ b/libunwind/src/FrameHeaderCache.hpp @@ -0,0 +1,149 @@ +//===-FrameHeaderCache.hpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Cache the elf program headers necessary to unwind the stack more efficiently +// in the presence of many dsos. +// +//===----------------------------------------------------------------------===// + +#ifndef __FRAMEHEADER_CACHE_HPP__ +#define __FRAMEHEADER_CACHE_HPP__ + +#include "config.h" +#include + +#ifdef _LIBUNWIND_DEBUG_FRAMEHEADER_CACHE +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) _LIBUNWIND_LOG0(x) +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__) +#else +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) +#endif + +// This cache should only be be used from within a dl_iterate_phdr callback. +// dl_iterate_phdr does the necessary synchronization to prevent problems +// with concurrent access via the libc load lock. Adding synchronization +// for other uses is possible, but not currently done. + +class _LIBUNWIND_HIDDEN FrameHeaderCache { + struct CacheEntry { + uintptr_t LowPC() { return Info.dso_base; }; + uintptr_t HighPC() { return Info.dso_base + Info.dwarf_section_length; }; + UnwindInfoSections Info; + CacheEntry *Next; + }; + + static const size_t kCacheEntryCount = 8; + + // Can't depend on the C++ standard library in libunwind, so use an array to + // allocate the entries, and two linked lists for ordering unused and recently + // used entries. FIXME: Would the the extra memory for a doubly-linked list + // be better than the runtime cost of traversing a very short singly-linked + // list on a cache miss? The entries themselves are all small and consecutive, + // so unlikely to cause page faults when following the pointers. The memory + // spent on additional pointers could also be spent on more entries. + + CacheEntry Entries[kCacheEntryCount]; + CacheEntry *MostRecentlyUsed; + CacheEntry *Unused; + + void resetCache() { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE0("FrameHeaderCache reset"); + MostRecentlyUsed = nullptr; + Unused = &Entries[0]; + for (size_t i = 0; i < kCacheEntryCount - 1; i++) { + Entries[i].Next = &Entries[i + 1]; + } + Entries[kCacheEntryCount - 1].Next = nullptr; + } + + bool cacheNeedsReset(dl_phdr_info *PInfo) { + // C libraries increment dl_phdr_info.adds and dl_phdr_info.subs when + // loading and unloading shared libraries. If these values change between + // iterations of dl_iterate_phdr, then invalidate the cache. + + // These are static to avoid needing an initializer, and unsigned long long + // because that is their type within the extended dl_phdr_info. Initialize + // these to something extremely unlikely to be found upon the first call to + // dl_iterate_phdr. + static unsigned long long LastAdds = ULLONG_MAX; + static unsigned long long LastSubs = ULLONG_MAX; + if (PInfo->dlpi_adds != LastAdds || PInfo->dlpi_subs != LastSubs) { + // Resetting the entire cache is a big hammer, but this path is rare-- + // usually just on the very first call, when the cache is empty anyway--so + // added complexity doesn't buy much. + LastAdds = PInfo->dlpi_adds; + LastSubs = PInfo->dlpi_subs; + resetCache(); + return true; + } + return false; + } + +public: + bool find(dl_phdr_info *PInfo, size_t, void *data) { + if (cacheNeedsReset(PInfo) || MostRecentlyUsed == nullptr) + return false; + + auto *CBData = static_cast(data); + CacheEntry *Current = MostRecentlyUsed; + CacheEntry *Previous = nullptr; + while (Current != nullptr) { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE( + "FrameHeaderCache check %lx in [%lx - %lx)", CBData->targetAddr, + Current->LowPC(), Current->HighPC()); + if (Current->LowPC() <= CBData->targetAddr && + CBData->targetAddr < Current->HighPC()) { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE( + "FrameHeaderCache hit %lx in [%lx - %lx)", CBData->targetAddr, + Current->LowPC(), Current->HighPC()); + if (Previous) { + // If there is no Previous, then Current is already the + // MostRecentlyUsed, and no need to move it up. + Previous->Next = Current->Next; + Current->Next = MostRecentlyUsed; + MostRecentlyUsed = Current; + } + *CBData->sects = Current->Info; + return true; + } + Previous = Current; + Current = Current->Next; + } + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache miss for address %lx", + CBData->targetAddr); + return false; + } + + void add(const UnwindInfoSections *UIS) { + CacheEntry *Current = nullptr; + + if (Unused != nullptr) { + Current = Unused; + Unused = Unused->Next; + } else { + Current = MostRecentlyUsed; + CacheEntry *Previous = nullptr; + while (Current->Next != nullptr) { + Previous = Current; + Current = Current->Next; + } + Previous->Next = nullptr; + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache evict [%lx - %lx)", + Current->LowPC(), Current->HighPC()); + } + + Current->Info = *UIS; + Current->Next = MostRecentlyUsed; + MostRecentlyUsed = Current; + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache add [%lx - %lx)", + MostRecentlyUsed->LowPC(), + MostRecentlyUsed->HighPC()); + } +}; + +#endif // __FRAMEHEADER_CACHE_HPP__ diff --git a/libunwind/src/InternalMacros.h b/libunwind/src/InternalMacros.h deleted file mode 100644 index f21e6dc..0000000 --- a/libunwind/src/InternalMacros.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2008-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -#ifndef INTERNAL_MACROS_H -#define INTERNAL_MACROS_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn)); -#ifdef __cplusplus -} -#endif - -#define UNW_STEP_SUCCESS 1 -#define UNW_STEP_END 0 - - -struct v128 { unsigned int vec[4]; }; - - -#define EXPORT __attribute__((visibility("default"))) - -#define COMPILE_TIME_ASSERT( expr ) \ - extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) ); - -#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg) - -#if NDEBUG - #define DEBUG_MESSAGE(msg, ...) - #define DEBUG_PRINT_API(msg, ...) - #define DEBUG_PRINT_UNWINDING_TEST 0 - #define DEBUG_PRINT_UNWINDING(msg, ...) - #define DEBUG_LOG_NON_ZERO(x) x; - #define INITIALIZE_DEBUG_PRINT_API - #define INITIALIZE_DEBUG_PRINT_UNWINDING -#else - #define DEBUG_MESSAGE(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) - #ifdef __cplusplus - extern "C" { - #endif - extern bool logAPIs(); - extern bool logUnwinding(); - #ifdef __cplusplus - } - #endif - #define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); } - #define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr, msg, __VA_ARGS__); } while(0) - #define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr, msg, __VA_ARGS__); } while(0) - #define DEBUG_PRINT_UNWINDING_TEST logUnwinding() - #define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; } - #define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; } -#endif - - -// static linker symbols to prevent wrong two level namespace for _Unwind symbols -#if __arm__ - #define NOT_HERE_BEFORE_5_0(sym) \ - extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \ - extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \ - extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \ - extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \ - extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \ - extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \ - extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp43 = 0; -#endif - -#define NOT_HERE_BEFORE_10_6(sym) \ - extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ - extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; -#define NEVER_HERE(sym) \ - extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ - extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \ - extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0; - - - -#endif // INTERNAL_MACROS_H diff --git a/libunwind/src/RWMutex.hpp b/libunwind/src/RWMutex.hpp new file mode 100644 index 0000000..fcd3f49 --- /dev/null +++ b/libunwind/src/RWMutex.hpp @@ -0,0 +1,114 @@ +//===----------------------------- Registers.hpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Abstract interface to shared reader/writer log, hiding platform and +// configuration differences. +// +//===----------------------------------------------------------------------===// + +#ifndef __RWMUTEX_HPP__ +#define __RWMUTEX_HPP__ + +#if defined(_WIN32) +#include +#elif !defined(_LIBUNWIND_HAS_NO_THREADS) +#include +#if defined(__ELF__) && defined(_LIBUNWIND_LINK_PTHREAD_LIB) +#pragma comment(lib, "pthread") +#endif +#endif + +namespace libunwind { + +#if defined(_LIBUNWIND_HAS_NO_THREADS) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return true; } + bool unlock_shared() { return true; } + bool lock() { return true; } + bool unlock() { return true; } +}; + +#elif defined(_WIN32) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { + AcquireSRWLockShared(&_lock); + return true; + } + bool unlock_shared() { + ReleaseSRWLockShared(&_lock); + return true; + } + bool lock() { + AcquireSRWLockExclusive(&_lock); + return true; + } + bool unlock() { + ReleaseSRWLockExclusive(&_lock); + return true; + } + +private: + SRWLOCK _lock = SRWLOCK_INIT; +}; + +#elif !defined(LIBUNWIND_USE_WEAK_PTHREAD) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; } + bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; } + bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; } + bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; } + +private: + pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; +}; + +#else + +extern "C" int __attribute__((weak)) +pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg); +extern "C" int __attribute__((weak)) +pthread_rwlock_rdlock(pthread_rwlock_t *lock); +extern "C" int __attribute__((weak)) +pthread_rwlock_wrlock(pthread_rwlock_t *lock); +extern "C" int __attribute__((weak)) +pthread_rwlock_unlock(pthread_rwlock_t *lock); + +// Calls to the locking functions are gated on pthread_create, and not the +// functions themselves, because the data structure should only be locked if +// another thread has been created. This is what similar libraries do. + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { + return !pthread_create || (pthread_rwlock_rdlock(&_lock) == 0); + } + bool unlock_shared() { + return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0); + } + bool lock() { + return !pthread_create || (pthread_rwlock_wrlock(&_lock) == 0); + } + bool unlock() { + return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0); + } + +private: + pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; +}; + +#endif + +} // namespace libunwind + +#endif // __RWMUTEX_HPP__ diff --git a/libunwind/src/Registers.S b/libunwind/src/Registers.S deleted file mode 100644 index 80b5592..0000000 --- a/libunwind/src/Registers.S +++ /dev/null @@ -1,261 +0,0 @@ - - -#if __i386__ - .text - .globl __ZN9libunwind13Registers_x866jumptoEv - .private_extern __ZN9libunwind13Registers_x866jumptoEv -__ZN9libunwind13Registers_x866jumptoEv: -# -# void libunwind::Registers_x86::jumpto() -# -# On entry: -# + + -# +-----------------------+ -# + thread_state pointer + -# +-----------------------+ -# + return address + -# +-----------------------+ <-- SP -# + + - movl 4(%esp), %eax - # set up eax and ret on new stack location - movl 28(%eax), %edx # edx holds new stack pointer - subl $8,%edx - movl %edx, 28(%eax) - movl 0(%eax), %ebx - movl %ebx, 0(%edx) - movl 40(%eax), %ebx - movl %ebx, 4(%edx) - # we now have ret and eax pushed onto where new stack will be - # restore all registers - movl 4(%eax), %ebx - movl 8(%eax), %ecx - movl 12(%eax), %edx - movl 16(%eax), %edi - movl 20(%eax), %esi - movl 24(%eax), %ebp - movl 28(%eax), %esp - # skip ss - # skip eflags - pop %eax # eax was already pushed on new stack - ret # eip was already pushed on new stack - # skip cs - # skip ds - # skip es - # skip fs - # skip gs - -#elif __x86_64__ - - .text - .globl __ZN9libunwind16Registers_x86_646jumptoEv - .private_extern __ZN9libunwind16Registers_x86_646jumptoEv -__ZN9libunwind16Registers_x86_646jumptoEv: -# -# void libunwind::Registers_x86_64::jumpto() -# -# On entry, thread_state pointer is in rdi - - movq 56(%rdi), %rax # rax holds new stack pointer - subq $16, %rax - movq %rax, 56(%rdi) - movq 32(%rdi), %rbx # store new rdi on new stack - movq %rbx, 0(%rax) - movq 128(%rdi), %rbx # store new rip on new stack - movq %rbx, 8(%rax) - # restore all registers - movq 0(%rdi), %rax - movq 8(%rdi), %rbx - movq 16(%rdi), %rcx - movq 24(%rdi), %rdx - # restore rdi later - movq 40(%rdi), %rsi - movq 48(%rdi), %rbp - # restore rsp later - movq 64(%rdi), %r8 - movq 72(%rdi), %r9 - movq 80(%rdi), %r10 - movq 88(%rdi), %r11 - movq 96(%rdi), %r12 - movq 104(%rdi), %r13 - movq 112(%rdi), %r14 - movq 120(%rdi), %r15 - # skip rflags - # skip cs - # skip fs - # skip gs - movq 56(%rdi), %rsp # cut back rsp to new location - pop %rdi # rdi was saved here earlier - ret # rip was saved here - - -#elif __ppc__ - - .text - .globl __ZN9libunwind13Registers_ppc6jumptoEv - .private_extern __ZN9libunwind13Registers_ppc6jumptoEv -__ZN9libunwind13Registers_ppc6jumptoEv: -; -; void libunwind::Registers_ppc::jumpto() -; -; On entry: -; thread_state pointer is in r3 -; - - ; restore integral registerrs - ; skip r0 for now - ; skip r1 for now - lwz r2, 16(r3) - ; skip r3 for now - ; skip r4 for now - ; skip r5 for now - lwz r6, 32(r3) - lwz r7, 36(r3) - lwz r8, 40(r3) - lwz r9, 44(r3) - lwz r10, 48(r3) - lwz r11, 52(r3) - lwz r12, 56(r3) - lwz r13, 60(r3) - lwz r14, 64(r3) - lwz r15, 68(r3) - lwz r16, 72(r3) - lwz r17, 76(r3) - lwz r18, 80(r3) - lwz r19, 84(r3) - lwz r20, 88(r3) - lwz r21, 92(r3) - lwz r22, 96(r3) - lwz r23,100(r3) - lwz r24,104(r3) - lwz r25,108(r3) - lwz r26,112(r3) - lwz r27,116(r3) - lwz r28,120(r3) - lwz r29,124(r3) - lwz r30,128(r3) - lwz r31,132(r3) - - ; restore float registers - lfd f0, 160(r3) - lfd f1, 168(r3) - lfd f2, 176(r3) - lfd f3, 184(r3) - lfd f4, 192(r3) - lfd f5, 200(r3) - lfd f6, 208(r3) - lfd f7, 216(r3) - lfd f8, 224(r3) - lfd f9, 232(r3) - lfd f10,240(r3) - lfd f11,248(r3) - lfd f12,256(r3) - lfd f13,264(r3) - lfd f14,272(r3) - lfd f15,280(r3) - lfd f16,288(r3) - lfd f17,296(r3) - lfd f18,304(r3) - lfd f19,312(r3) - lfd f20,320(r3) - lfd f21,328(r3) - lfd f22,336(r3) - lfd f23,344(r3) - lfd f24,352(r3) - lfd f25,360(r3) - lfd f26,368(r3) - lfd f27,376(r3) - lfd f28,384(r3) - lfd f29,392(r3) - lfd f30,400(r3) - lfd f31,408(r3) - - ; restore vector registers if any are in use - lwz r5,156(r3) ; test VRsave - cmpwi r5,0 - beq Lnovec - - subi r4,r1,16 - rlwinm r4,r4,0,0,27 ; mask low 4-bits - ; r4 is now a 16-byte aligned pointer into the red zone - ; the fVectorRegisters may not be 16-byte aligned so copy via red zone temp buffer - - -#define LOAD_VECTOR_UNALIGNEDl(_index) \ - andis. r0,r5,(1<<(15-_index)) @\ - beq Ldone ## _index @\ - lwz r0, 424+_index*16(r3) @\ - stw r0, 0(r4) @\ - lwz r0, 424+_index*16+4(r3) @\ - stw r0, 4(r4) @\ - lwz r0, 424+_index*16+8(r3) @\ - stw r0, 8(r4) @\ - lwz r0, 424+_index*16+12(r3)@\ - stw r0, 12(r4) @\ - lvx v ## _index,0,r4 @\ -Ldone ## _index: - -#define LOAD_VECTOR_UNALIGNEDh(_index) \ - andi. r0,r5,(1<<(31-_index)) @\ - beq Ldone ## _index @\ - lwz r0, 424+_index*16(r3) @\ - stw r0, 0(r4) @\ - lwz r0, 424+_index*16+4(r3) @\ - stw r0, 4(r4) @\ - lwz r0, 424+_index*16+8(r3) @\ - stw r0, 8(r4) @\ - lwz r0, 424+_index*16+12(r3)@\ - stw r0, 12(r4) @\ - lvx v ## _index,0,r4 @\ - Ldone ## _index: - - - LOAD_VECTOR_UNALIGNEDl(0) - LOAD_VECTOR_UNALIGNEDl(1) - LOAD_VECTOR_UNALIGNEDl(2) - LOAD_VECTOR_UNALIGNEDl(3) - LOAD_VECTOR_UNALIGNEDl(4) - LOAD_VECTOR_UNALIGNEDl(5) - LOAD_VECTOR_UNALIGNEDl(6) - LOAD_VECTOR_UNALIGNEDl(7) - LOAD_VECTOR_UNALIGNEDl(8) - LOAD_VECTOR_UNALIGNEDl(9) - LOAD_VECTOR_UNALIGNEDl(10) - LOAD_VECTOR_UNALIGNEDl(11) - LOAD_VECTOR_UNALIGNEDl(12) - LOAD_VECTOR_UNALIGNEDl(13) - LOAD_VECTOR_UNALIGNEDl(14) - LOAD_VECTOR_UNALIGNEDl(15) - LOAD_VECTOR_UNALIGNEDh(16) - LOAD_VECTOR_UNALIGNEDh(17) - LOAD_VECTOR_UNALIGNEDh(18) - LOAD_VECTOR_UNALIGNEDh(19) - LOAD_VECTOR_UNALIGNEDh(20) - LOAD_VECTOR_UNALIGNEDh(21) - LOAD_VECTOR_UNALIGNEDh(22) - LOAD_VECTOR_UNALIGNEDh(23) - LOAD_VECTOR_UNALIGNEDh(24) - LOAD_VECTOR_UNALIGNEDh(25) - LOAD_VECTOR_UNALIGNEDh(26) - LOAD_VECTOR_UNALIGNEDh(27) - LOAD_VECTOR_UNALIGNEDh(28) - LOAD_VECTOR_UNALIGNEDh(29) - LOAD_VECTOR_UNALIGNEDh(30) - LOAD_VECTOR_UNALIGNEDh(31) - -Lnovec: - lwz r0, 136(r3) ; __cr - mtocrf 255,r0 - lwz r0, 148(r3) ; __ctr - mtctr r0 - lwz r0, 0(r3) ; __ssr0 - mtctr r0 - lwz r0, 8(r3) ; do r0 now - lwz r5,28(r3) ; do r5 now - lwz r4,24(r3) ; do r4 now - lwz r1,12(r3) ; do sp now - lwz r3,20(r3) ; do r3 last - bctr - - -#endif - diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index ad45ec8..61be55b 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -1,1093 +1,4038 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===----------------------------- Registers.hpp --------------------------===// // -// C++ interface to lower levels of libuwind +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// +// Models register sets for supported processors. +// +//===----------------------------------------------------------------------===// #ifndef __REGISTERS_HPP__ #define __REGISTERS_HPP__ #include -#include -#include -#include -#include -#include +#include #include "libunwind.h" -#include "InternalMacros.h" +#include "config.h" +#include "libunwind_ext.h" + namespace libunwind { +// For emulating 128-bit registers +struct v128 { uint32_t vec[4]; }; -/// -/// Registers_x86 holds the register state of a thread in a 32-bit intel process. -/// -class Registers_x86 -{ -public: - Registers_x86(); - Registers_x86(const void* registers); - - bool validRegister(int num) const; - uint32_t getRegister(int num) const; - void setRegister(int num, uint32_t value); - bool validFloatRegister(int num) const { return false; } - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); - bool validVectorRegister(int num) const { return false; } - v128 getVectorRegister(int num) const; - void setVectorRegister(int num, v128 value); - const char* getRegisterName(int num); - void jumpto(); - - uint32_t getSP() const { return fRegisters.__esp; } - void setSP(uint32_t value) { fRegisters.__esp = value; } - uint32_t getIP() const { return fRegisters.__eip; } - void setIP(uint32_t value) { fRegisters.__eip = value; } - uint32_t getEBP() const { return fRegisters.__ebp; } - void setEBP(uint32_t value) { fRegisters.__ebp = value; } - uint32_t getEBX() const { return fRegisters.__ebx; } - void setEBX(uint32_t value) { fRegisters.__ebx = value; } - uint32_t getECX() const { return fRegisters.__ecx; } - void setECX(uint32_t value) { fRegisters.__ecx = value; } - uint32_t getEDX() const { return fRegisters.__edx; } - void setEDX(uint32_t value) { fRegisters.__edx = value; } - uint32_t getESI() const { return fRegisters.__esi; } - void setESI(uint32_t value) { fRegisters.__esi = value; } - uint32_t getEDI() const { return fRegisters.__edi; } - void setEDI(uint32_t value) { fRegisters.__edi = value; } - -private: - struct GPRs - { - unsigned int __eax; - unsigned int __ebx; - unsigned int __ecx; - unsigned int __edx; - unsigned int __edi; - unsigned int __esi; - unsigned int __ebp; - unsigned int __esp; - unsigned int __ss; - unsigned int __eflags; - unsigned int __eip; - unsigned int __cs; - unsigned int __ds; - unsigned int __es; - unsigned int __fs; - unsigned int __gs; - }; - - GPRs fRegisters; +enum { + REGISTERS_X86, + REGISTERS_X86_64, + REGISTERS_PPC, + REGISTERS_PPC64, + REGISTERS_ARM64, + REGISTERS_ARM, + REGISTERS_OR1K, + REGISTERS_MIPS_O32, + REGISTERS_MIPS_NEWABI, + REGISTERS_SPARC, + REGISTERS_HEXAGON, + REGISTERS_RISCV, }; -inline Registers_x86::Registers_x86(const void* registers) -{ - COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) ); - fRegisters = *((GPRs*)registers); -} +#if defined(_LIBUNWIND_TARGET_I386) +class _LIBUNWIND_HIDDEN Registers_x86; +extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); +/// Registers_x86 holds the register state of a thread in a 32-bit intel +/// process. +class _LIBUNWIND_HIDDEN Registers_x86 { +public: + Registers_x86(); + Registers_x86(const void *registers); -inline Registers_x86::Registers_x86() -{ - bzero(&fRegisters, sizeof(fRegisters)); -} + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int) const { return false; } + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int) const { return false; } + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { __libunwind_Registers_x86_jumpto(this); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } + static int getArch() { return REGISTERS_X86; } + uint32_t getSP() const { return _registers.__esp; } + void setSP(uint32_t value) { _registers.__esp = value; } + uint32_t getIP() const { return _registers.__eip; } + void setIP(uint32_t value) { _registers.__eip = value; } + uint32_t getEBP() const { return _registers.__ebp; } + void setEBP(uint32_t value) { _registers.__ebp = value; } + uint32_t getEBX() const { return _registers.__ebx; } + void setEBX(uint32_t value) { _registers.__ebx = value; } + uint32_t getECX() const { return _registers.__ecx; } + void setECX(uint32_t value) { _registers.__ecx = value; } + uint32_t getEDX() const { return _registers.__edx; } + void setEDX(uint32_t value) { _registers.__edx = value; } + uint32_t getESI() const { return _registers.__esi; } + void setESI(uint32_t value) { _registers.__esi = value; } + uint32_t getEDI() const { return _registers.__edi; } + void setEDI(uint32_t value) { _registers.__edi = value; } -inline bool Registers_x86::validRegister(int regNum) const -{ - if ( regNum == UNW_REG_IP ) - return true; - if ( regNum == UNW_REG_SP ) - return true; - if ( regNum < 0 ) - return false; - if ( regNum > 7 ) - return false; - return true; -} + typedef uint32_t reg_t; + void normalizeNewLinkRegister(reg_t&, unw_word_t) { } + void normalizeExistingLinkRegister(reg_t&) { } -inline uint32_t Registers_x86::getRegister(int regNum) const -{ - switch ( regNum ) { - case UNW_REG_IP: - return fRegisters.__eip; - case UNW_REG_SP: - return fRegisters.__esp; - case UNW_X86_EAX: - return fRegisters.__eax; - case UNW_X86_ECX: - return fRegisters.__ecx; - case UNW_X86_EDX: - return fRegisters.__edx; - case UNW_X86_EBX: - return fRegisters.__ebx; - case UNW_X86_EBP: - return fRegisters.__ebp; - case UNW_X86_ESP: - return fRegisters.__esp; - case UNW_X86_ESI: - return fRegisters.__esi; - case UNW_X86_EDI: - return fRegisters.__edi; - } - ABORT("unsupported x86 register"); -} - -inline void Registers_x86::setRegister(int regNum, uint32_t value) -{ - switch ( regNum ) { - case UNW_REG_IP: - fRegisters.__eip = value; - return; - case UNW_REG_SP: - fRegisters.__esp = value; - return; - case UNW_X86_EAX: - fRegisters.__eax = value; - return; - case UNW_X86_ECX: - fRegisters.__ecx = value; - return; - case UNW_X86_EDX: - fRegisters.__edx = value; - return; - case UNW_X86_EBX: - fRegisters.__ebx = value; - return; - case UNW_X86_EBP: - fRegisters.__ebp = value; - return; - case UNW_X86_ESP: - fRegisters.__esp = value; - return; - case UNW_X86_ESI: - fRegisters.__esi = value; - return; - case UNW_X86_EDI: - fRegisters.__edi = value; - return; - } - ABORT("unsupported x86 register"); -} - -inline const char* Registers_x86::getRegisterName(int regNum) -{ - switch ( regNum ) { - case UNW_REG_IP: - return "ip"; - case UNW_REG_SP: - return "esp"; - case UNW_X86_EAX: - return "eax"; - case UNW_X86_ECX: - return "ecx"; - case UNW_X86_EDX: - return "edx"; - case UNW_X86_EBX: - return "ebx"; - case UNW_X86_EBP: - return "ebp"; - case UNW_X86_ESP: - return "esp"; - case UNW_X86_ESI: - return "esi"; - case UNW_X86_EDI: - return "edi"; - default: - return "unknown register"; - } -} - -inline double Registers_x86::getFloatRegister(int num) const -{ - ABORT("no x86 float registers"); -} - -inline void Registers_x86::setFloatRegister(int num, double value) -{ - ABORT("no x86 float registers"); -} - -inline v128 Registers_x86::getVectorRegister(int num) const -{ - ABORT("no x86 vector registers"); -} - -inline void Registers_x86::setVectorRegister(int num, v128 value) -{ - ABORT("no x86 vector registers"); -} - - - - -/// -/// Registers_x86_64 holds the register state of a thread in a 64-bit intel process. -/// -class Registers_x86_64 -{ -public: - Registers_x86_64(); - Registers_x86_64(const void* registers); - - bool validRegister(int num) const; - uint64_t getRegister(int num) const; - void setRegister(int num, uint64_t value); - bool validFloatRegister(int num) const{ return false; } - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); - bool validVectorRegister(int num) const { return false; } - v128 getVectorRegister(int num) const; - void setVectorRegister(int num, v128 value); - const char* getRegisterName(int num); - void jumpto(); - uint64_t getSP() const { return fRegisters.__rsp; } - void setSP(uint64_t value) { fRegisters.__rsp = value; } - uint64_t getIP() const { return fRegisters.__rip; } - void setIP(uint64_t value) { fRegisters.__rip = value; } - uint64_t getRBP() const { return fRegisters.__rbp; } - void setRBP(uint64_t value) { fRegisters.__rbp = value; } - uint64_t getRBX() const { return fRegisters.__rbx; } - void setRBX(uint64_t value) { fRegisters.__rbx = value; } - uint64_t getR12() const { return fRegisters.__r12; } - void setR12(uint64_t value) { fRegisters.__r12 = value; } - uint64_t getR13() const { return fRegisters.__r13; } - void setR13(uint64_t value) { fRegisters.__r13 = value; } - uint64_t getR14() const { return fRegisters.__r14; } - void setR14(uint64_t value) { fRegisters.__r14 = value; } - uint64_t getR15() const { return fRegisters.__r15; } - void setR15(uint64_t value) { fRegisters.__r15 = value; } private: - struct GPRs - { - __uint64_t __rax; - __uint64_t __rbx; - __uint64_t __rcx; - __uint64_t __rdx; - __uint64_t __rdi; - __uint64_t __rsi; - __uint64_t __rbp; - __uint64_t __rsp; - __uint64_t __r8; - __uint64_t __r9; - __uint64_t __r10; - __uint64_t __r11; - __uint64_t __r12; - __uint64_t __r13; - __uint64_t __r14; - __uint64_t __r15; - __uint64_t __rip; - __uint64_t __rflags; - __uint64_t __cs; - __uint64_t __fs; - __uint64_t __gs; - }; - GPRs fRegisters; + struct GPRs { + unsigned int __eax; + unsigned int __ebx; + unsigned int __ecx; + unsigned int __edx; + unsigned int __edi; + unsigned int __esi; + unsigned int __ebp; + unsigned int __esp; + unsigned int __ss; + unsigned int __eflags; + unsigned int __eip; + unsigned int __cs; + unsigned int __ds; + unsigned int __es; + unsigned int __fs; + unsigned int __gs; + }; + + GPRs _registers; }; -inline Registers_x86_64::Registers_x86_64(const void* registers) -{ - COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) ); - fRegisters = *((GPRs*)registers); +inline Registers_x86::Registers_x86(const void *registers) { + static_assert((check_fit::does_fit), + "x86 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); } -inline Registers_x86_64::Registers_x86_64() -{ - bzero(&fRegisters, sizeof(fRegisters)); +inline Registers_x86::Registers_x86() { + memset(&_registers, 0, sizeof(_registers)); } - -inline bool Registers_x86_64::validRegister(int regNum) const -{ - if ( regNum == UNW_REG_IP ) - return true; - if ( regNum == UNW_REG_SP ) - return true; - if ( regNum < 0 ) - return false; - if ( regNum > 15 ) - return false; - return true; +inline bool Registers_x86::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 7) + return false; + return true; } -inline uint64_t Registers_x86_64::getRegister(int regNum) const -{ - switch ( regNum ) { - case UNW_REG_IP: - return fRegisters.__rip; - case UNW_REG_SP: - return fRegisters.__rsp; - case UNW_X86_64_RAX: - return fRegisters.__rax; - case UNW_X86_64_RDX: - return fRegisters.__rdx; - case UNW_X86_64_RCX: - return fRegisters.__rcx; - case UNW_X86_64_RBX: - return fRegisters.__rbx; - case UNW_X86_64_RSI: - return fRegisters.__rsi; - case UNW_X86_64_RDI: - return fRegisters.__rdi; - case UNW_X86_64_RBP: - return fRegisters.__rbp; - case UNW_X86_64_RSP: - return fRegisters.__rsp; - case UNW_X86_64_R8: - return fRegisters.__r8; - case UNW_X86_64_R9: - return fRegisters.__r9; - case UNW_X86_64_R10: - return fRegisters.__r10; - case UNW_X86_64_R11: - return fRegisters.__r11; - case UNW_X86_64_R12: - return fRegisters.__r12; - case UNW_X86_64_R13: - return fRegisters.__r13; - case UNW_X86_64_R14: - return fRegisters.__r14; - case UNW_X86_64_R15: - return fRegisters.__r15; - } - ABORT("unsupported x86_64 register"); +inline uint32_t Registers_x86::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__eip; + case UNW_REG_SP: + return _registers.__esp; + case UNW_X86_EAX: + return _registers.__eax; + case UNW_X86_ECX: + return _registers.__ecx; + case UNW_X86_EDX: + return _registers.__edx; + case UNW_X86_EBX: + return _registers.__ebx; +#if !defined(__APPLE__) + case UNW_X86_ESP: +#else + case UNW_X86_EBP: +#endif + return _registers.__ebp; +#if !defined(__APPLE__) + case UNW_X86_EBP: +#else + case UNW_X86_ESP: +#endif + return _registers.__esp; + case UNW_X86_ESI: + return _registers.__esi; + case UNW_X86_EDI: + return _registers.__edi; + } + _LIBUNWIND_ABORT("unsupported x86 register"); } -inline void Registers_x86_64::setRegister(int regNum, uint64_t value) -{ - switch ( regNum ) { - case UNW_REG_IP: - fRegisters.__rip = value; - return; - case UNW_REG_SP: - fRegisters.__rsp = value; - return; - case UNW_X86_64_RAX: - fRegisters.__rax = value; - return; - case UNW_X86_64_RDX: - fRegisters.__rdx = value; - return; - case UNW_X86_64_RCX: - fRegisters.__rcx = value; - return; - case UNW_X86_64_RBX: - fRegisters.__rbx = value; - return; - case UNW_X86_64_RSI: - fRegisters.__rsi = value; - return; - case UNW_X86_64_RDI: - fRegisters.__rdi = value; - return; - case UNW_X86_64_RBP: - fRegisters.__rbp = value; - return; - case UNW_X86_64_RSP: - fRegisters.__rsp = value; - return; - case UNW_X86_64_R8: - fRegisters.__r8 = value; - return; - case UNW_X86_64_R9: - fRegisters.__r9 = value; - return; - case UNW_X86_64_R10: - fRegisters.__r10 = value; - return; - case UNW_X86_64_R11: - fRegisters.__r11 = value; - return; - case UNW_X86_64_R12: - fRegisters.__r12 = value; - return; - case UNW_X86_64_R13: - fRegisters.__r13 = value; - return; - case UNW_X86_64_R14: - fRegisters.__r14 = value; - return; - case UNW_X86_64_R15: - fRegisters.__r15 = value; - return; - } - ABORT("unsupported x86_64 register"); +inline void Registers_x86::setRegister(int regNum, uint32_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__eip = value; + return; + case UNW_REG_SP: + _registers.__esp = value; + return; + case UNW_X86_EAX: + _registers.__eax = value; + return; + case UNW_X86_ECX: + _registers.__ecx = value; + return; + case UNW_X86_EDX: + _registers.__edx = value; + return; + case UNW_X86_EBX: + _registers.__ebx = value; + return; +#if !defined(__APPLE__) + case UNW_X86_ESP: +#else + case UNW_X86_EBP: +#endif + _registers.__ebp = value; + return; +#if !defined(__APPLE__) + case UNW_X86_EBP: +#else + case UNW_X86_ESP: +#endif + _registers.__esp = value; + return; + case UNW_X86_ESI: + _registers.__esi = value; + return; + case UNW_X86_EDI: + _registers.__edi = value; + return; + } + _LIBUNWIND_ABORT("unsupported x86 register"); } -inline const char* Registers_x86_64::getRegisterName(int regNum) -{ - switch ( regNum ) { - case UNW_REG_IP: - return "rip"; - case UNW_REG_SP: - return "rsp"; - case UNW_X86_64_RAX: - return "rax"; - case UNW_X86_64_RDX: - return "rdx"; - case UNW_X86_64_RCX: - return "rcx"; - case UNW_X86_64_RBX: - return "rbx"; - case UNW_X86_64_RSI: - return "rsi"; - case UNW_X86_64_RDI: - return "rdi"; - case UNW_X86_64_RBP: - return "rbp"; - case UNW_X86_64_RSP: - return "rsp"; - case UNW_X86_64_R8: - return "r8"; - case UNW_X86_64_R9: - return "r9"; - case UNW_X86_64_R10: - return "r10"; - case UNW_X86_64_R11: - return "r11"; - case UNW_X86_64_R12: - return "r12"; - case UNW_X86_64_R13: - return "r13"; - case UNW_X86_64_R14: - return "r14"; - case UNW_X86_64_R15: - return "r15"; - default: - return "unknown register"; - } +inline const char *Registers_x86::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "esp"; + case UNW_X86_EAX: + return "eax"; + case UNW_X86_ECX: + return "ecx"; + case UNW_X86_EDX: + return "edx"; + case UNW_X86_EBX: + return "ebx"; + case UNW_X86_EBP: + return "ebp"; + case UNW_X86_ESP: + return "esp"; + case UNW_X86_ESI: + return "esi"; + case UNW_X86_EDI: + return "edi"; + default: + return "unknown register"; + } } -double Registers_x86_64::getFloatRegister(int num) const -{ - ABORT("no x86_64 float registers"); +inline double Registers_x86::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no x86 float registers"); } -void Registers_x86_64::setFloatRegister(int num, double value) -{ - ABORT("no x86_64 float registers"); +inline void Registers_x86::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no x86 float registers"); } -inline v128 Registers_x86_64::getVectorRegister(int num) const -{ - ABORT("no x86_64 vector registers"); +inline v128 Registers_x86::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no x86 vector registers"); } -inline void Registers_x86_64::setVectorRegister(int num, v128 value) -{ - ABORT("no x86_64 vector registers"); +inline void Registers_x86::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no x86 vector registers"); } +#endif // _LIBUNWIND_TARGET_I386 -/// -/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process. -/// -class Registers_ppc -{ -public: - Registers_ppc(); - Registers_ppc(const void* registers); +#if defined(_LIBUNWIND_TARGET_X86_64) +/// Registers_x86_64 holds the register state of a thread in a 64-bit intel +/// process. +class _LIBUNWIND_HIDDEN Registers_x86_64; +extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); +class _LIBUNWIND_HIDDEN Registers_x86_64 { +public: + Registers_x86_64(); + Registers_x86_64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int) const { return false; } + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { __libunwind_Registers_x86_64_jumpto(this); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } + static int getArch() { return REGISTERS_X86_64; } + + uint64_t getSP() const { return _registers.__rsp; } + void setSP(uint64_t value) { _registers.__rsp = value; } + uint64_t getIP() const { return _registers.__rip; } + void setIP(uint64_t value) { _registers.__rip = value; } + uint64_t getRBP() const { return _registers.__rbp; } + void setRBP(uint64_t value) { _registers.__rbp = value; } + uint64_t getRBX() const { return _registers.__rbx; } + void setRBX(uint64_t value) { _registers.__rbx = value; } + uint64_t getR12() const { return _registers.__r12; } + void setR12(uint64_t value) { _registers.__r12 = value; } + uint64_t getR13() const { return _registers.__r13; } + void setR13(uint64_t value) { _registers.__r13 = value; } + uint64_t getR14() const { return _registers.__r14; } + void setR14(uint64_t value) { _registers.__r14 = value; } + uint64_t getR15() const { return _registers.__r15; } + void setR15(uint64_t value) { _registers.__r15 = value; } + + typedef uint64_t reg_t; + void normalizeNewLinkRegister(reg_t&, unw_word_t) { } + void normalizeExistingLinkRegister(reg_t&) { } - bool validRegister(int num) const; - uint32_t getRegister(int num) const; - void setRegister(int num, uint32_t value); - bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); - bool validVectorRegister(int num) const; - v128 getVectorRegister(int num) const; - void setVectorRegister(int num, v128 value); - void jumpto(); - const char* getRegisterName(int num); - uint64_t getSP() const { return fRegisters.__r1; } - void setSP(uint64_t value) { fRegisters.__r1 = value; } - uint64_t getIP() const { return fRegisters.__srr0; } - void setIP(uint64_t value) { fRegisters.__srr0 = value; } private: - struct ppc_thread_state_t - { - unsigned int __srr0; /* Instruction address register (PC) */ - unsigned int __srr1; /* Machine state register (supervisor) */ - unsigned int __r0; - unsigned int __r1; - unsigned int __r2; - unsigned int __r3; - unsigned int __r4; - unsigned int __r5; - unsigned int __r6; - unsigned int __r7; - unsigned int __r8; - unsigned int __r9; - unsigned int __r10; - unsigned int __r11; - unsigned int __r12; - unsigned int __r13; - unsigned int __r14; - unsigned int __r15; - unsigned int __r16; - unsigned int __r17; - unsigned int __r18; - unsigned int __r19; - unsigned int __r20; - unsigned int __r21; - unsigned int __r22; - unsigned int __r23; - unsigned int __r24; - unsigned int __r25; - unsigned int __r26; - unsigned int __r27; - unsigned int __r28; - unsigned int __r29; - unsigned int __r30; - unsigned int __r31; - unsigned int __cr; /* Condition register */ - unsigned int __xer; /* User's integer exception register */ - unsigned int __lr; /* Link register */ - unsigned int __ctr; /* Count register */ - unsigned int __mq; /* MQ register (601 only) */ - unsigned int __vrsave; /* Vector Save Register */ - }; - - struct ppc_float_state_t - { - double __fpregs[32]; - - unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */ - unsigned int __fpscr; /* floating point status register */ - }; - - ppc_thread_state_t fRegisters; - ppc_float_state_t fFloatRegisters; - v128 fVectorRegisters[32]; // offset 424 + struct GPRs { + uint64_t __rax; + uint64_t __rbx; + uint64_t __rcx; + uint64_t __rdx; + uint64_t __rdi; + uint64_t __rsi; + uint64_t __rbp; + uint64_t __rsp; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __rip; + uint64_t __rflags; + uint64_t __cs; + uint64_t __fs; + uint64_t __gs; +#if defined(_WIN64) + uint64_t __padding; // 16-byte align +#endif + }; + GPRs _registers; +#if defined(_WIN64) + v128 _xmm[16]; +#endif }; +inline Registers_x86_64::Registers_x86_64(const void *registers) { + static_assert((check_fit::does_fit), + "x86_64 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); +} + +inline Registers_x86_64::Registers_x86_64() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_x86_64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 15) + return false; + return true; +} + +inline uint64_t Registers_x86_64::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__rip; + case UNW_REG_SP: + return _registers.__rsp; + case UNW_X86_64_RAX: + return _registers.__rax; + case UNW_X86_64_RDX: + return _registers.__rdx; + case UNW_X86_64_RCX: + return _registers.__rcx; + case UNW_X86_64_RBX: + return _registers.__rbx; + case UNW_X86_64_RSI: + return _registers.__rsi; + case UNW_X86_64_RDI: + return _registers.__rdi; + case UNW_X86_64_RBP: + return _registers.__rbp; + case UNW_X86_64_RSP: + return _registers.__rsp; + case UNW_X86_64_R8: + return _registers.__r8; + case UNW_X86_64_R9: + return _registers.__r9; + case UNW_X86_64_R10: + return _registers.__r10; + case UNW_X86_64_R11: + return _registers.__r11; + case UNW_X86_64_R12: + return _registers.__r12; + case UNW_X86_64_R13: + return _registers.__r13; + case UNW_X86_64_R14: + return _registers.__r14; + case UNW_X86_64_R15: + return _registers.__r15; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__rip = value; + return; + case UNW_REG_SP: + _registers.__rsp = value; + return; + case UNW_X86_64_RAX: + _registers.__rax = value; + return; + case UNW_X86_64_RDX: + _registers.__rdx = value; + return; + case UNW_X86_64_RCX: + _registers.__rcx = value; + return; + case UNW_X86_64_RBX: + _registers.__rbx = value; + return; + case UNW_X86_64_RSI: + _registers.__rsi = value; + return; + case UNW_X86_64_RDI: + _registers.__rdi = value; + return; + case UNW_X86_64_RBP: + _registers.__rbp = value; + return; + case UNW_X86_64_RSP: + _registers.__rsp = value; + return; + case UNW_X86_64_R8: + _registers.__r8 = value; + return; + case UNW_X86_64_R9: + _registers.__r9 = value; + return; + case UNW_X86_64_R10: + _registers.__r10 = value; + return; + case UNW_X86_64_R11: + _registers.__r11 = value; + return; + case UNW_X86_64_R12: + _registers.__r12 = value; + return; + case UNW_X86_64_R13: + _registers.__r13 = value; + return; + case UNW_X86_64_R14: + _registers.__r14 = value; + return; + case UNW_X86_64_R15: + _registers.__r15 = value; + return; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline const char *Registers_x86_64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "rip"; + case UNW_REG_SP: + return "rsp"; + case UNW_X86_64_RAX: + return "rax"; + case UNW_X86_64_RDX: + return "rdx"; + case UNW_X86_64_RCX: + return "rcx"; + case UNW_X86_64_RBX: + return "rbx"; + case UNW_X86_64_RSI: + return "rsi"; + case UNW_X86_64_RDI: + return "rdi"; + case UNW_X86_64_RBP: + return "rbp"; + case UNW_X86_64_RSP: + return "rsp"; + case UNW_X86_64_R8: + return "r8"; + case UNW_X86_64_R9: + return "r9"; + case UNW_X86_64_R10: + return "r10"; + case UNW_X86_64_R11: + return "r11"; + case UNW_X86_64_R12: + return "r12"; + case UNW_X86_64_R13: + return "r13"; + case UNW_X86_64_R14: + return "r14"; + case UNW_X86_64_R15: + return "r15"; + case UNW_X86_64_XMM0: + return "xmm0"; + case UNW_X86_64_XMM1: + return "xmm1"; + case UNW_X86_64_XMM2: + return "xmm2"; + case UNW_X86_64_XMM3: + return "xmm3"; + case UNW_X86_64_XMM4: + return "xmm4"; + case UNW_X86_64_XMM5: + return "xmm5"; + case UNW_X86_64_XMM6: + return "xmm6"; + case UNW_X86_64_XMM7: + return "xmm7"; + case UNW_X86_64_XMM8: + return "xmm8"; + case UNW_X86_64_XMM9: + return "xmm9"; + case UNW_X86_64_XMM10: + return "xmm10"; + case UNW_X86_64_XMM11: + return "xmm11"; + case UNW_X86_64_XMM12: + return "xmm12"; + case UNW_X86_64_XMM13: + return "xmm13"; + case UNW_X86_64_XMM14: + return "xmm14"; + case UNW_X86_64_XMM15: + return "xmm15"; + default: + return "unknown register"; + } +} + +inline double Registers_x86_64::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no x86_64 float registers"); +} + +inline void Registers_x86_64::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no x86_64 float registers"); +} + +inline bool Registers_x86_64::validVectorRegister(int regNum) const { +#if defined(_WIN64) + if (regNum < UNW_X86_64_XMM0) + return false; + if (regNum > UNW_X86_64_XMM15) + return false; + return true; +#else + (void)regNum; // suppress unused parameter warning + return false; +#endif +} + +inline v128 Registers_x86_64::getVectorRegister(int regNum) const { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + return _xmm[regNum - UNW_X86_64_XMM0]; +#else + (void)regNum; // suppress unused parameter warning + _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif +} + +inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + _xmm[regNum - UNW_X86_64_XMM0] = value; +#else + (void)regNum; (void)value; // suppress unused parameter warnings + _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif +} +#endif // _LIBUNWIND_TARGET_X86_64 -inline Registers_ppc::Registers_ppc(const void* registers) +#if defined(_LIBUNWIND_TARGET_PPC) +/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC +/// process. +class _LIBUNWIND_HIDDEN Registers_ppc { +public: + Registers_ppc(); + Registers_ppc(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; } + static int getArch() { return REGISTERS_PPC; } + + uint64_t getSP() const { return _registers.__r1; } + void setSP(uint32_t value) { _registers.__r1 = value; } + uint64_t getIP() const { return _registers.__srr0; } + void setIP(uint32_t value) { _registers.__srr0 = value; } + + typedef uint32_t reg_t; + void normalizeNewLinkRegister(reg_t&, unw_word_t) { } + void normalizeExistingLinkRegister(reg_t&) { } + +private: + struct ppc_thread_state_t { + unsigned int __srr0; /* Instruction address register (PC) */ + unsigned int __srr1; /* Machine state register (supervisor) */ + unsigned int __r0; + unsigned int __r1; + unsigned int __r2; + unsigned int __r3; + unsigned int __r4; + unsigned int __r5; + unsigned int __r6; + unsigned int __r7; + unsigned int __r8; + unsigned int __r9; + unsigned int __r10; + unsigned int __r11; + unsigned int __r12; + unsigned int __r13; + unsigned int __r14; + unsigned int __r15; + unsigned int __r16; + unsigned int __r17; + unsigned int __r18; + unsigned int __r19; + unsigned int __r20; + unsigned int __r21; + unsigned int __r22; + unsigned int __r23; + unsigned int __r24; + unsigned int __r25; + unsigned int __r26; + unsigned int __r27; + unsigned int __r28; + unsigned int __r29; + unsigned int __r30; + unsigned int __r31; + unsigned int __cr; /* Condition register */ + unsigned int __xer; /* User's integer exception register */ + unsigned int __lr; /* Link register */ + unsigned int __ctr; /* Count register */ + unsigned int __mq; /* MQ register (601 only) */ + unsigned int __vrsave; /* Vector Save Register */ + }; + + struct ppc_float_state_t { + double __fpregs[32]; + + unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */ + unsigned int __fpscr; /* floating point status register */ + }; + + ppc_thread_state_t _registers; + ppc_float_state_t _floatRegisters; + v128 _vectorRegisters[32]; // offset 424 +}; + +inline Registers_ppc::Registers_ppc(const void *registers) { + static_assert((check_fit::does_fit), + "ppc registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + static_assert(sizeof(ppc_thread_state_t) == 160, + "expected float register offset to be 160"); + memcpy(&_floatRegisters, + static_cast(registers) + sizeof(ppc_thread_state_t), + sizeof(_floatRegisters)); + static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424, + "expected vector register offset to be 424 bytes"); + memcpy(_vectorRegisters, + static_cast(registers) + sizeof(ppc_thread_state_t) + + sizeof(ppc_float_state_t), + sizeof(_vectorRegisters)); +} + +inline Registers_ppc::Registers_ppc() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_floatRegisters, 0, sizeof(_floatRegisters)); + memset(&_vectorRegisters, 0, sizeof(_vectorRegisters)); +} + +inline bool Registers_ppc::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum == UNW_PPC_VRSAVE) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_PPC_R31) + return true; + if (regNum == UNW_PPC_MQ) + return true; + if (regNum == UNW_PPC_LR) + return true; + if (regNum == UNW_PPC_CTR) + return true; + if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7)) + return true; + return false; +} + +inline uint32_t Registers_ppc::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__srr0; + case UNW_REG_SP: + return _registers.__r1; + case UNW_PPC_R0: + return _registers.__r0; + case UNW_PPC_R1: + return _registers.__r1; + case UNW_PPC_R2: + return _registers.__r2; + case UNW_PPC_R3: + return _registers.__r3; + case UNW_PPC_R4: + return _registers.__r4; + case UNW_PPC_R5: + return _registers.__r5; + case UNW_PPC_R6: + return _registers.__r6; + case UNW_PPC_R7: + return _registers.__r7; + case UNW_PPC_R8: + return _registers.__r8; + case UNW_PPC_R9: + return _registers.__r9; + case UNW_PPC_R10: + return _registers.__r10; + case UNW_PPC_R11: + return _registers.__r11; + case UNW_PPC_R12: + return _registers.__r12; + case UNW_PPC_R13: + return _registers.__r13; + case UNW_PPC_R14: + return _registers.__r14; + case UNW_PPC_R15: + return _registers.__r15; + case UNW_PPC_R16: + return _registers.__r16; + case UNW_PPC_R17: + return _registers.__r17; + case UNW_PPC_R18: + return _registers.__r18; + case UNW_PPC_R19: + return _registers.__r19; + case UNW_PPC_R20: + return _registers.__r20; + case UNW_PPC_R21: + return _registers.__r21; + case UNW_PPC_R22: + return _registers.__r22; + case UNW_PPC_R23: + return _registers.__r23; + case UNW_PPC_R24: + return _registers.__r24; + case UNW_PPC_R25: + return _registers.__r25; + case UNW_PPC_R26: + return _registers.__r26; + case UNW_PPC_R27: + return _registers.__r27; + case UNW_PPC_R28: + return _registers.__r28; + case UNW_PPC_R29: + return _registers.__r29; + case UNW_PPC_R30: + return _registers.__r30; + case UNW_PPC_R31: + return _registers.__r31; + case UNW_PPC_LR: + return _registers.__lr; + case UNW_PPC_CR0: + return (_registers.__cr & 0xF0000000); + case UNW_PPC_CR1: + return (_registers.__cr & 0x0F000000); + case UNW_PPC_CR2: + return (_registers.__cr & 0x00F00000); + case UNW_PPC_CR3: + return (_registers.__cr & 0x000F0000); + case UNW_PPC_CR4: + return (_registers.__cr & 0x0000F000); + case UNW_PPC_CR5: + return (_registers.__cr & 0x00000F00); + case UNW_PPC_CR6: + return (_registers.__cr & 0x000000F0); + case UNW_PPC_CR7: + return (_registers.__cr & 0x0000000F); + case UNW_PPC_VRSAVE: + return _registers.__vrsave; + } + _LIBUNWIND_ABORT("unsupported ppc register"); +} + +inline void Registers_ppc::setRegister(int regNum, uint32_t value) { + //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value); + switch (regNum) { + case UNW_REG_IP: + _registers.__srr0 = value; + return; + case UNW_REG_SP: + _registers.__r1 = value; + return; + case UNW_PPC_R0: + _registers.__r0 = value; + return; + case UNW_PPC_R1: + _registers.__r1 = value; + return; + case UNW_PPC_R2: + _registers.__r2 = value; + return; + case UNW_PPC_R3: + _registers.__r3 = value; + return; + case UNW_PPC_R4: + _registers.__r4 = value; + return; + case UNW_PPC_R5: + _registers.__r5 = value; + return; + case UNW_PPC_R6: + _registers.__r6 = value; + return; + case UNW_PPC_R7: + _registers.__r7 = value; + return; + case UNW_PPC_R8: + _registers.__r8 = value; + return; + case UNW_PPC_R9: + _registers.__r9 = value; + return; + case UNW_PPC_R10: + _registers.__r10 = value; + return; + case UNW_PPC_R11: + _registers.__r11 = value; + return; + case UNW_PPC_R12: + _registers.__r12 = value; + return; + case UNW_PPC_R13: + _registers.__r13 = value; + return; + case UNW_PPC_R14: + _registers.__r14 = value; + return; + case UNW_PPC_R15: + _registers.__r15 = value; + return; + case UNW_PPC_R16: + _registers.__r16 = value; + return; + case UNW_PPC_R17: + _registers.__r17 = value; + return; + case UNW_PPC_R18: + _registers.__r18 = value; + return; + case UNW_PPC_R19: + _registers.__r19 = value; + return; + case UNW_PPC_R20: + _registers.__r20 = value; + return; + case UNW_PPC_R21: + _registers.__r21 = value; + return; + case UNW_PPC_R22: + _registers.__r22 = value; + return; + case UNW_PPC_R23: + _registers.__r23 = value; + return; + case UNW_PPC_R24: + _registers.__r24 = value; + return; + case UNW_PPC_R25: + _registers.__r25 = value; + return; + case UNW_PPC_R26: + _registers.__r26 = value; + return; + case UNW_PPC_R27: + _registers.__r27 = value; + return; + case UNW_PPC_R28: + _registers.__r28 = value; + return; + case UNW_PPC_R29: + _registers.__r29 = value; + return; + case UNW_PPC_R30: + _registers.__r30 = value; + return; + case UNW_PPC_R31: + _registers.__r31 = value; + return; + case UNW_PPC_MQ: + _registers.__mq = value; + return; + case UNW_PPC_LR: + _registers.__lr = value; + return; + case UNW_PPC_CTR: + _registers.__ctr = value; + return; + case UNW_PPC_CR0: + _registers.__cr &= 0x0FFFFFFF; + _registers.__cr |= (value & 0xF0000000); + return; + case UNW_PPC_CR1: + _registers.__cr &= 0xF0FFFFFF; + _registers.__cr |= (value & 0x0F000000); + return; + case UNW_PPC_CR2: + _registers.__cr &= 0xFF0FFFFF; + _registers.__cr |= (value & 0x00F00000); + return; + case UNW_PPC_CR3: + _registers.__cr &= 0xFFF0FFFF; + _registers.__cr |= (value & 0x000F0000); + return; + case UNW_PPC_CR4: + _registers.__cr &= 0xFFFF0FFF; + _registers.__cr |= (value & 0x0000F000); + return; + case UNW_PPC_CR5: + _registers.__cr &= 0xFFFFF0FF; + _registers.__cr |= (value & 0x00000F00); + return; + case UNW_PPC_CR6: + _registers.__cr &= 0xFFFFFF0F; + _registers.__cr |= (value & 0x000000F0); + return; + case UNW_PPC_CR7: + _registers.__cr &= 0xFFFFFFF0; + _registers.__cr |= (value & 0x0000000F); + return; + case UNW_PPC_VRSAVE: + _registers.__vrsave = value; + return; + // not saved + return; + case UNW_PPC_XER: + _registers.__xer = value; + return; + case UNW_PPC_AP: + case UNW_PPC_VSCR: + case UNW_PPC_SPEFSCR: + // not saved + return; + } + _LIBUNWIND_ABORT("unsupported ppc register"); +} + +inline bool Registers_ppc::validFloatRegister(int regNum) const { + if (regNum < UNW_PPC_F0) + return false; + if (regNum > UNW_PPC_F31) + return false; + return true; +} + +inline double Registers_ppc::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _floatRegisters.__fpregs[regNum - UNW_PPC_F0]; +} + +inline void Registers_ppc::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value; +} + +inline bool Registers_ppc::validVectorRegister(int regNum) const { + if (regNum < UNW_PPC_V0) + return false; + if (regNum > UNW_PPC_V31) + return false; + return true; +} + +inline v128 Registers_ppc::getVectorRegister(int regNum) const { + assert(validVectorRegister(regNum)); + v128 result = _vectorRegisters[regNum - UNW_PPC_V0]; + return result; +} + +inline void Registers_ppc::setVectorRegister(int regNum, v128 value) { + assert(validVectorRegister(regNum)); + _vectorRegisters[regNum - UNW_PPC_V0] = value; +} + +inline const char *Registers_ppc::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_PPC_R0: + return "r0"; + case UNW_PPC_R1: + return "r1"; + case UNW_PPC_R2: + return "r2"; + case UNW_PPC_R3: + return "r3"; + case UNW_PPC_R4: + return "r4"; + case UNW_PPC_R5: + return "r5"; + case UNW_PPC_R6: + return "r6"; + case UNW_PPC_R7: + return "r7"; + case UNW_PPC_R8: + return "r8"; + case UNW_PPC_R9: + return "r9"; + case UNW_PPC_R10: + return "r10"; + case UNW_PPC_R11: + return "r11"; + case UNW_PPC_R12: + return "r12"; + case UNW_PPC_R13: + return "r13"; + case UNW_PPC_R14: + return "r14"; + case UNW_PPC_R15: + return "r15"; + case UNW_PPC_R16: + return "r16"; + case UNW_PPC_R17: + return "r17"; + case UNW_PPC_R18: + return "r18"; + case UNW_PPC_R19: + return "r19"; + case UNW_PPC_R20: + return "r20"; + case UNW_PPC_R21: + return "r21"; + case UNW_PPC_R22: + return "r22"; + case UNW_PPC_R23: + return "r23"; + case UNW_PPC_R24: + return "r24"; + case UNW_PPC_R25: + return "r25"; + case UNW_PPC_R26: + return "r26"; + case UNW_PPC_R27: + return "r27"; + case UNW_PPC_R28: + return "r28"; + case UNW_PPC_R29: + return "r29"; + case UNW_PPC_R30: + return "r30"; + case UNW_PPC_R31: + return "r31"; + case UNW_PPC_F0: + return "fp0"; + case UNW_PPC_F1: + return "fp1"; + case UNW_PPC_F2: + return "fp2"; + case UNW_PPC_F3: + return "fp3"; + case UNW_PPC_F4: + return "fp4"; + case UNW_PPC_F5: + return "fp5"; + case UNW_PPC_F6: + return "fp6"; + case UNW_PPC_F7: + return "fp7"; + case UNW_PPC_F8: + return "fp8"; + case UNW_PPC_F9: + return "fp9"; + case UNW_PPC_F10: + return "fp10"; + case UNW_PPC_F11: + return "fp11"; + case UNW_PPC_F12: + return "fp12"; + case UNW_PPC_F13: + return "fp13"; + case UNW_PPC_F14: + return "fp14"; + case UNW_PPC_F15: + return "fp15"; + case UNW_PPC_F16: + return "fp16"; + case UNW_PPC_F17: + return "fp17"; + case UNW_PPC_F18: + return "fp18"; + case UNW_PPC_F19: + return "fp19"; + case UNW_PPC_F20: + return "fp20"; + case UNW_PPC_F21: + return "fp21"; + case UNW_PPC_F22: + return "fp22"; + case UNW_PPC_F23: + return "fp23"; + case UNW_PPC_F24: + return "fp24"; + case UNW_PPC_F25: + return "fp25"; + case UNW_PPC_F26: + return "fp26"; + case UNW_PPC_F27: + return "fp27"; + case UNW_PPC_F28: + return "fp28"; + case UNW_PPC_F29: + return "fp29"; + case UNW_PPC_F30: + return "fp30"; + case UNW_PPC_F31: + return "fp31"; + case UNW_PPC_LR: + return "lr"; + default: + return "unknown register"; + } + +} +#endif // _LIBUNWIND_TARGET_PPC + +#if defined(_LIBUNWIND_TARGET_PPC64) +/// Registers_ppc64 holds the register state of a thread in a 64-bit PowerPC +/// process. +class _LIBUNWIND_HIDDEN Registers_ppc64 { +public: + Registers_ppc64(); + Registers_ppc64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; } + static int getArch() { return REGISTERS_PPC64; } + + uint64_t getSP() const { return _registers.__r1; } + void setSP(uint64_t value) { _registers.__r1 = value; } + uint64_t getIP() const { return _registers.__srr0; } + void setIP(uint64_t value) { _registers.__srr0 = value; } + +private: + struct ppc64_thread_state_t { + uint64_t __srr0; // Instruction address register (PC) + uint64_t __srr1; // Machine state register (supervisor) + uint64_t __r0; + uint64_t __r1; + uint64_t __r2; + uint64_t __r3; + uint64_t __r4; + uint64_t __r5; + uint64_t __r6; + uint64_t __r7; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __r16; + uint64_t __r17; + uint64_t __r18; + uint64_t __r19; + uint64_t __r20; + uint64_t __r21; + uint64_t __r22; + uint64_t __r23; + uint64_t __r24; + uint64_t __r25; + uint64_t __r26; + uint64_t __r27; + uint64_t __r28; + uint64_t __r29; + uint64_t __r30; + uint64_t __r31; + uint64_t __cr; // Condition register + uint64_t __xer; // User's integer exception register + uint64_t __lr; // Link register + uint64_t __ctr; // Count register + uint64_t __vrsave; // Vector Save Register + }; + + union ppc64_vsr_t { + struct asfloat_s { + double f; + uint64_t v2; + } asfloat; + v128 v; + }; + + ppc64_thread_state_t _registers; + ppc64_vsr_t _vectorScalarRegisters[64]; + + static int getVectorRegNum(int num); +}; + +inline Registers_ppc64::Registers_ppc64(const void *registers) { + static_assert((check_fit::does_fit), + "ppc64 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + static_assert(sizeof(_registers) == 312, + "expected vector scalar register offset to be 312"); + memcpy(&_vectorScalarRegisters, + static_cast(registers) + sizeof(_registers), + sizeof(_vectorScalarRegisters)); + static_assert(sizeof(_registers) + + sizeof(_vectorScalarRegisters) == 1336, + "expected vector register offset to be 1336 bytes"); +} + +inline Registers_ppc64::Registers_ppc64() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vectorScalarRegisters, 0, sizeof(_vectorScalarRegisters)); +} + +inline bool Registers_ppc64::validRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + case UNW_REG_SP: + case UNW_PPC64_XER: + case UNW_PPC64_LR: + case UNW_PPC64_CTR: + case UNW_PPC64_VRSAVE: + return true; + } + + if (regNum >= UNW_PPC64_R0 && regNum <= UNW_PPC64_R31) + return true; + if (regNum >= UNW_PPC64_CR0 && regNum <= UNW_PPC64_CR7) + return true; + + return false; +} + +inline uint64_t Registers_ppc64::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__srr0; + case UNW_PPC64_R0: + return _registers.__r0; + case UNW_PPC64_R1: + case UNW_REG_SP: + return _registers.__r1; + case UNW_PPC64_R2: + return _registers.__r2; + case UNW_PPC64_R3: + return _registers.__r3; + case UNW_PPC64_R4: + return _registers.__r4; + case UNW_PPC64_R5: + return _registers.__r5; + case UNW_PPC64_R6: + return _registers.__r6; + case UNW_PPC64_R7: + return _registers.__r7; + case UNW_PPC64_R8: + return _registers.__r8; + case UNW_PPC64_R9: + return _registers.__r9; + case UNW_PPC64_R10: + return _registers.__r10; + case UNW_PPC64_R11: + return _registers.__r11; + case UNW_PPC64_R12: + return _registers.__r12; + case UNW_PPC64_R13: + return _registers.__r13; + case UNW_PPC64_R14: + return _registers.__r14; + case UNW_PPC64_R15: + return _registers.__r15; + case UNW_PPC64_R16: + return _registers.__r16; + case UNW_PPC64_R17: + return _registers.__r17; + case UNW_PPC64_R18: + return _registers.__r18; + case UNW_PPC64_R19: + return _registers.__r19; + case UNW_PPC64_R20: + return _registers.__r20; + case UNW_PPC64_R21: + return _registers.__r21; + case UNW_PPC64_R22: + return _registers.__r22; + case UNW_PPC64_R23: + return _registers.__r23; + case UNW_PPC64_R24: + return _registers.__r24; + case UNW_PPC64_R25: + return _registers.__r25; + case UNW_PPC64_R26: + return _registers.__r26; + case UNW_PPC64_R27: + return _registers.__r27; + case UNW_PPC64_R28: + return _registers.__r28; + case UNW_PPC64_R29: + return _registers.__r29; + case UNW_PPC64_R30: + return _registers.__r30; + case UNW_PPC64_R31: + return _registers.__r31; + case UNW_PPC64_CR0: + return (_registers.__cr & 0xF0000000); + case UNW_PPC64_CR1: + return (_registers.__cr & 0x0F000000); + case UNW_PPC64_CR2: + return (_registers.__cr & 0x00F00000); + case UNW_PPC64_CR3: + return (_registers.__cr & 0x000F0000); + case UNW_PPC64_CR4: + return (_registers.__cr & 0x0000F000); + case UNW_PPC64_CR5: + return (_registers.__cr & 0x00000F00); + case UNW_PPC64_CR6: + return (_registers.__cr & 0x000000F0); + case UNW_PPC64_CR7: + return (_registers.__cr & 0x0000000F); + case UNW_PPC64_XER: + return _registers.__xer; + case UNW_PPC64_LR: + return _registers.__lr; + case UNW_PPC64_CTR: + return _registers.__ctr; + case UNW_PPC64_VRSAVE: + return _registers.__vrsave; + } + _LIBUNWIND_ABORT("unsupported ppc64 register"); +} + +inline void Registers_ppc64::setRegister(int regNum, uint64_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__srr0 = value; + return; + case UNW_PPC64_R0: + _registers.__r0 = value; + return; + case UNW_PPC64_R1: + case UNW_REG_SP: + _registers.__r1 = value; + return; + case UNW_PPC64_R2: + _registers.__r2 = value; + return; + case UNW_PPC64_R3: + _registers.__r3 = value; + return; + case UNW_PPC64_R4: + _registers.__r4 = value; + return; + case UNW_PPC64_R5: + _registers.__r5 = value; + return; + case UNW_PPC64_R6: + _registers.__r6 = value; + return; + case UNW_PPC64_R7: + _registers.__r7 = value; + return; + case UNW_PPC64_R8: + _registers.__r8 = value; + return; + case UNW_PPC64_R9: + _registers.__r9 = value; + return; + case UNW_PPC64_R10: + _registers.__r10 = value; + return; + case UNW_PPC64_R11: + _registers.__r11 = value; + return; + case UNW_PPC64_R12: + _registers.__r12 = value; + return; + case UNW_PPC64_R13: + _registers.__r13 = value; + return; + case UNW_PPC64_R14: + _registers.__r14 = value; + return; + case UNW_PPC64_R15: + _registers.__r15 = value; + return; + case UNW_PPC64_R16: + _registers.__r16 = value; + return; + case UNW_PPC64_R17: + _registers.__r17 = value; + return; + case UNW_PPC64_R18: + _registers.__r18 = value; + return; + case UNW_PPC64_R19: + _registers.__r19 = value; + return; + case UNW_PPC64_R20: + _registers.__r20 = value; + return; + case UNW_PPC64_R21: + _registers.__r21 = value; + return; + case UNW_PPC64_R22: + _registers.__r22 = value; + return; + case UNW_PPC64_R23: + _registers.__r23 = value; + return; + case UNW_PPC64_R24: + _registers.__r24 = value; + return; + case UNW_PPC64_R25: + _registers.__r25 = value; + return; + case UNW_PPC64_R26: + _registers.__r26 = value; + return; + case UNW_PPC64_R27: + _registers.__r27 = value; + return; + case UNW_PPC64_R28: + _registers.__r28 = value; + return; + case UNW_PPC64_R29: + _registers.__r29 = value; + return; + case UNW_PPC64_R30: + _registers.__r30 = value; + return; + case UNW_PPC64_R31: + _registers.__r31 = value; + return; + case UNW_PPC64_CR0: + _registers.__cr &= 0x0FFFFFFF; + _registers.__cr |= (value & 0xF0000000); + return; + case UNW_PPC64_CR1: + _registers.__cr &= 0xF0FFFFFF; + _registers.__cr |= (value & 0x0F000000); + return; + case UNW_PPC64_CR2: + _registers.__cr &= 0xFF0FFFFF; + _registers.__cr |= (value & 0x00F00000); + return; + case UNW_PPC64_CR3: + _registers.__cr &= 0xFFF0FFFF; + _registers.__cr |= (value & 0x000F0000); + return; + case UNW_PPC64_CR4: + _registers.__cr &= 0xFFFF0FFF; + _registers.__cr |= (value & 0x0000F000); + return; + case UNW_PPC64_CR5: + _registers.__cr &= 0xFFFFF0FF; + _registers.__cr |= (value & 0x00000F00); + return; + case UNW_PPC64_CR6: + _registers.__cr &= 0xFFFFFF0F; + _registers.__cr |= (value & 0x000000F0); + return; + case UNW_PPC64_CR7: + _registers.__cr &= 0xFFFFFFF0; + _registers.__cr |= (value & 0x0000000F); + return; + case UNW_PPC64_XER: + _registers.__xer = value; + return; + case UNW_PPC64_LR: + _registers.__lr = value; + return; + case UNW_PPC64_CTR: + _registers.__ctr = value; + return; + case UNW_PPC64_VRSAVE: + _registers.__vrsave = value; + return; + } + _LIBUNWIND_ABORT("unsupported ppc64 register"); +} + +inline bool Registers_ppc64::validFloatRegister(int regNum) const { + return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31; +} + +inline double Registers_ppc64::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f; +} + +inline void Registers_ppc64::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value; +} + +inline bool Registers_ppc64::validVectorRegister(int regNum) const { +#ifdef PPC64_HAS_VMX + if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31) + return true; + if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63) + return true; +#else + if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31) + return true; +#endif + return false; +} + +inline int Registers_ppc64::getVectorRegNum(int num) { - COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) ); - fRegisters = *((ppc_thread_state_t*)registers); - fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160)); - memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters)); + if (num >= UNW_PPC64_VS0 && num <= UNW_PPC64_VS31) + return num - UNW_PPC64_VS0; + else + return num - UNW_PPC64_VS32 + 32; } -inline Registers_ppc::Registers_ppc() -{ - bzero(&fRegisters, sizeof(fRegisters)); - bzero(&fFloatRegisters, sizeof(fFloatRegisters)); - bzero(&fVectorRegisters, sizeof(fVectorRegisters)); +inline v128 Registers_ppc64::getVectorRegister(int regNum) const { + assert(validVectorRegister(regNum)); + return _vectorScalarRegisters[getVectorRegNum(regNum)].v; } - -inline bool Registers_ppc::validRegister(int regNum) const -{ - if ( regNum == UNW_REG_IP ) - return true; - if ( regNum == UNW_REG_SP ) - return true; - if ( regNum == UNW_PPC_VRSAVE ) - return true; - if ( regNum < 0 ) - return false; - if ( regNum <= UNW_PPC_R31 ) - return true; - if ( regNum == UNW_PPC_MQ ) - return true; - if ( regNum == UNW_PPC_LR ) - return true; - if ( regNum == UNW_PPC_CTR ) - return true; - if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) ) - return true; - return false; +inline void Registers_ppc64::setVectorRegister(int regNum, v128 value) { + assert(validVectorRegister(regNum)); + _vectorScalarRegisters[getVectorRegNum(regNum)].v = value; } +inline const char *Registers_ppc64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_PPC64_R0: + return "r0"; + case UNW_PPC64_R1: + return "r1"; + case UNW_PPC64_R2: + return "r2"; + case UNW_PPC64_R3: + return "r3"; + case UNW_PPC64_R4: + return "r4"; + case UNW_PPC64_R5: + return "r5"; + case UNW_PPC64_R6: + return "r6"; + case UNW_PPC64_R7: + return "r7"; + case UNW_PPC64_R8: + return "r8"; + case UNW_PPC64_R9: + return "r9"; + case UNW_PPC64_R10: + return "r10"; + case UNW_PPC64_R11: + return "r11"; + case UNW_PPC64_R12: + return "r12"; + case UNW_PPC64_R13: + return "r13"; + case UNW_PPC64_R14: + return "r14"; + case UNW_PPC64_R15: + return "r15"; + case UNW_PPC64_R16: + return "r16"; + case UNW_PPC64_R17: + return "r17"; + case UNW_PPC64_R18: + return "r18"; + case UNW_PPC64_R19: + return "r19"; + case UNW_PPC64_R20: + return "r20"; + case UNW_PPC64_R21: + return "r21"; + case UNW_PPC64_R22: + return "r22"; + case UNW_PPC64_R23: + return "r23"; + case UNW_PPC64_R24: + return "r24"; + case UNW_PPC64_R25: + return "r25"; + case UNW_PPC64_R26: + return "r26"; + case UNW_PPC64_R27: + return "r27"; + case UNW_PPC64_R28: + return "r28"; + case UNW_PPC64_R29: + return "r29"; + case UNW_PPC64_R30: + return "r30"; + case UNW_PPC64_R31: + return "r31"; + case UNW_PPC64_CR0: + return "cr0"; + case UNW_PPC64_CR1: + return "cr1"; + case UNW_PPC64_CR2: + return "cr2"; + case UNW_PPC64_CR3: + return "cr3"; + case UNW_PPC64_CR4: + return "cr4"; + case UNW_PPC64_CR5: + return "cr5"; + case UNW_PPC64_CR6: + return "cr6"; + case UNW_PPC64_CR7: + return "cr7"; + case UNW_PPC64_XER: + return "xer"; + case UNW_PPC64_LR: + return "lr"; + case UNW_PPC64_CTR: + return "ctr"; + case UNW_PPC64_VRSAVE: + return "vrsave"; + case UNW_PPC64_F0: + return "fp0"; + case UNW_PPC64_F1: + return "fp1"; + case UNW_PPC64_F2: + return "fp2"; + case UNW_PPC64_F3: + return "fp3"; + case UNW_PPC64_F4: + return "fp4"; + case UNW_PPC64_F5: + return "fp5"; + case UNW_PPC64_F6: + return "fp6"; + case UNW_PPC64_F7: + return "fp7"; + case UNW_PPC64_F8: + return "fp8"; + case UNW_PPC64_F9: + return "fp9"; + case UNW_PPC64_F10: + return "fp10"; + case UNW_PPC64_F11: + return "fp11"; + case UNW_PPC64_F12: + return "fp12"; + case UNW_PPC64_F13: + return "fp13"; + case UNW_PPC64_F14: + return "fp14"; + case UNW_PPC64_F15: + return "fp15"; + case UNW_PPC64_F16: + return "fp16"; + case UNW_PPC64_F17: + return "fp17"; + case UNW_PPC64_F18: + return "fp18"; + case UNW_PPC64_F19: + return "fp19"; + case UNW_PPC64_F20: + return "fp20"; + case UNW_PPC64_F21: + return "fp21"; + case UNW_PPC64_F22: + return "fp22"; + case UNW_PPC64_F23: + return "fp23"; + case UNW_PPC64_F24: + return "fp24"; + case UNW_PPC64_F25: + return "fp25"; + case UNW_PPC64_F26: + return "fp26"; + case UNW_PPC64_F27: + return "fp27"; + case UNW_PPC64_F28: + return "fp28"; + case UNW_PPC64_F29: + return "fp29"; + case UNW_PPC64_F30: + return "fp30"; + case UNW_PPC64_F31: + return "fp31"; + case UNW_PPC64_V0: + return "v0"; + case UNW_PPC64_V1: + return "v1"; + case UNW_PPC64_V2: + return "v2"; + case UNW_PPC64_V3: + return "v3"; + case UNW_PPC64_V4: + return "v4"; + case UNW_PPC64_V5: + return "v5"; + case UNW_PPC64_V6: + return "v6"; + case UNW_PPC64_V7: + return "v7"; + case UNW_PPC64_V8: + return "v8"; + case UNW_PPC64_V9: + return "v9"; + case UNW_PPC64_V10: + return "v10"; + case UNW_PPC64_V11: + return "v11"; + case UNW_PPC64_V12: + return "v12"; + case UNW_PPC64_V13: + return "v13"; + case UNW_PPC64_V14: + return "v14"; + case UNW_PPC64_V15: + return "v15"; + case UNW_PPC64_V16: + return "v16"; + case UNW_PPC64_V17: + return "v17"; + case UNW_PPC64_V18: + return "v18"; + case UNW_PPC64_V19: + return "v19"; + case UNW_PPC64_V20: + return "v20"; + case UNW_PPC64_V21: + return "v21"; + case UNW_PPC64_V22: + return "v22"; + case UNW_PPC64_V23: + return "v23"; + case UNW_PPC64_V24: + return "v24"; + case UNW_PPC64_V25: + return "v25"; + case UNW_PPC64_V26: + return "v26"; + case UNW_PPC64_V27: + return "v27"; + case UNW_PPC64_V28: + return "v28"; + case UNW_PPC64_V29: + return "v29"; + case UNW_PPC64_V30: + return "v30"; + case UNW_PPC64_V31: + return "v31"; + } + return "unknown register"; +} +#endif // _LIBUNWIND_TARGET_PPC64 -inline uint32_t Registers_ppc::getRegister(int regNum) const -{ - switch ( regNum ) { - case UNW_REG_IP: - return fRegisters.__srr0; - case UNW_REG_SP: - return fRegisters.__r1; - case UNW_PPC_R0: - return fRegisters.__r0; - case UNW_PPC_R1: - return fRegisters.__r1; - case UNW_PPC_R2: - return fRegisters.__r2; - case UNW_PPC_R3: - return fRegisters.__r3; - case UNW_PPC_R4: - return fRegisters.__r4; - case UNW_PPC_R5: - return fRegisters.__r5; - case UNW_PPC_R6: - return fRegisters.__r6; - case UNW_PPC_R7: - return fRegisters.__r7; - case UNW_PPC_R8: - return fRegisters.__r8; - case UNW_PPC_R9: - return fRegisters.__r9; - case UNW_PPC_R10: - return fRegisters.__r10; - case UNW_PPC_R11: - return fRegisters.__r11; - case UNW_PPC_R12: - return fRegisters.__r12; - case UNW_PPC_R13: - return fRegisters.__r13; - case UNW_PPC_R14: - return fRegisters.__r14; - case UNW_PPC_R15: - return fRegisters.__r15; - case UNW_PPC_R16: - return fRegisters.__r16; - case UNW_PPC_R17: - return fRegisters.__r17; - case UNW_PPC_R18: - return fRegisters.__r18; - case UNW_PPC_R19: - return fRegisters.__r19; - case UNW_PPC_R20: - return fRegisters.__r20; - case UNW_PPC_R21: - return fRegisters.__r21; - case UNW_PPC_R22: - return fRegisters.__r22; - case UNW_PPC_R23: - return fRegisters.__r23; - case UNW_PPC_R24: - return fRegisters.__r24; - case UNW_PPC_R25: - return fRegisters.__r25; - case UNW_PPC_R26: - return fRegisters.__r26; - case UNW_PPC_R27: - return fRegisters.__r27; - case UNW_PPC_R28: - return fRegisters.__r28; - case UNW_PPC_R29: - return fRegisters.__r29; - case UNW_PPC_R30: - return fRegisters.__r30; - case UNW_PPC_R31: - return fRegisters.__r31; - case UNW_PPC_LR: - return fRegisters.__lr; - case UNW_PPC_CR0: - return (fRegisters.__cr & 0xF0000000); - case UNW_PPC_CR1: - return (fRegisters.__cr & 0x0F000000); - case UNW_PPC_CR2: - return (fRegisters.__cr & 0x00F00000); - case UNW_PPC_CR3: - return (fRegisters.__cr & 0x000F0000); - case UNW_PPC_CR4: - return (fRegisters.__cr & 0x0000F000); - case UNW_PPC_CR5: - return (fRegisters.__cr & 0x00000F00); - case UNW_PPC_CR6: - return (fRegisters.__cr & 0x000000F0); - case UNW_PPC_CR7: - return (fRegisters.__cr & 0x0000000F); - case UNW_PPC_VRSAVE: - return fRegisters.__vrsave; - } - ABORT("unsupported ppc register"); + +#if defined(_LIBUNWIND_TARGET_AARCH64) +/// Registers_arm64 holds the register state of a thread in a 64-bit arm +/// process. +class _LIBUNWIND_HIDDEN Registers_arm64; +extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +class _LIBUNWIND_HIDDEN Registers_arm64 { +public: + Registers_arm64(); + Registers_arm64(const void *registers); + Registers_arm64(const Registers_arm64&); + Registers_arm64& operator=(const Registers_arm64&); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { __libunwind_Registers_arm64_jumpto(this); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } + static int getArch() { return REGISTERS_ARM64; } + + uint64_t getSP() const { return _registers.__sp; } + void setSP(uint64_t value) { _registers.__sp = value; } + uint64_t getIP() const { + uint64_t value = _registers.__pc; + return value; + } + void setIP(uint64_t value) { + _registers.__pc = value; + } + uint64_t getFP() const { return _registers.__fp; } + void setFP(uint64_t value) { _registers.__fp = value; } + + typedef uint64_t reg_t; + void normalizeNewLinkRegister(reg_t& linkRegister, unw_word_t procInfoFlags) { + (void)linkRegister; + (void)procInfoFlags; + } + + void normalizeExistingLinkRegister(reg_t& linkRegister) { + (void)linkRegister; + } + + // arm64_32 and i386 simulator hack + void normalizeNewLinkRegister(uint32_t&, unw_word_t) { } + void normalizeExistingLinkRegister(uint32_t&) { } + +private: + struct GPRs { + uint64_t __x[29]; // x0-x28 + uint64_t __fp; // Frame pointer x29 + uint64_t __lr; // Link register x30 + uint64_t __sp; // Stack pointer x31 + uint64_t __pc; // Program counter + uint64_t __ra_sign_state; // RA sign state register + }; + + GPRs _registers; + double _vectorHalfRegisters[32]; + // Currently only the lower double in 128-bit vectore registers + // is perserved during unwinding. We could define new register + // numbers (> 96) which mean whole vector registers, then this + // struct would need to change to contain whole vector registers. +}; + +inline Registers_arm64::Registers_arm64(const void *registers) { + static_assert((check_fit::does_fit), + "arm64 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); + static_assert(sizeof(GPRs) == 0x110, + "expected VFP registers to be at offset 272"); + memcpy(_vectorHalfRegisters, + static_cast(registers) + sizeof(GPRs), + sizeof(_vectorHalfRegisters)); } - -inline void Registers_ppc::setRegister(int regNum, uint32_t value) -{ - //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value); - switch ( regNum ) { - case UNW_REG_IP: - fRegisters.__srr0 = value; - return; - case UNW_REG_SP: - fRegisters.__r1 = value; - return; - case UNW_PPC_R0: - fRegisters.__r0 = value; - return; - case UNW_PPC_R1: - fRegisters.__r1 = value; - return; - case UNW_PPC_R2: - fRegisters.__r2 = value; - return; - case UNW_PPC_R3: - fRegisters.__r3 = value; - return; - case UNW_PPC_R4: - fRegisters.__r4 = value; - return; - case UNW_PPC_R5: - fRegisters.__r5 = value; - return; - case UNW_PPC_R6: - fRegisters.__r6 = value; - return; - case UNW_PPC_R7: - fRegisters.__r7 = value; - return; - case UNW_PPC_R8: - fRegisters.__r8 = value; - return; - case UNW_PPC_R9: - fRegisters.__r9 = value; - return; - case UNW_PPC_R10: - fRegisters.__r10 = value; - return; - case UNW_PPC_R11: - fRegisters.__r11 = value; - return; - case UNW_PPC_R12: - fRegisters.__r12 = value; - return; - case UNW_PPC_R13: - fRegisters.__r13 = value; - return; - case UNW_PPC_R14: - fRegisters.__r14 = value; - return; - case UNW_PPC_R15: - fRegisters.__r15 = value; - return; - case UNW_PPC_R16: - fRegisters.__r16 = value; - return; - case UNW_PPC_R17: - fRegisters.__r17 = value; - return; - case UNW_PPC_R18: - fRegisters.__r18 = value; - return; - case UNW_PPC_R19: - fRegisters.__r19 = value; - return; - case UNW_PPC_R20: - fRegisters.__r20 = value; - return; - case UNW_PPC_R21: - fRegisters.__r21 = value; - return; - case UNW_PPC_R22: - fRegisters.__r22 = value; - return; - case UNW_PPC_R23: - fRegisters.__r23 = value; - return; - case UNW_PPC_R24: - fRegisters.__r24 = value; - return; - case UNW_PPC_R25: - fRegisters.__r25 = value; - return; - case UNW_PPC_R26: - fRegisters.__r26 = value; - return; - case UNW_PPC_R27: - fRegisters.__r27 = value; - return; - case UNW_PPC_R28: - fRegisters.__r28 = value; - return; - case UNW_PPC_R29: - fRegisters.__r29 = value; - return; - case UNW_PPC_R30: - fRegisters.__r30 = value; - return; - case UNW_PPC_R31: - fRegisters.__r31 = value; - return; - case UNW_PPC_MQ: - fRegisters.__mq = value; - return; - case UNW_PPC_LR: - fRegisters.__lr = value; - return; - case UNW_PPC_CTR: - fRegisters.__ctr = value; - return; - case UNW_PPC_CR0: - fRegisters.__cr &= 0x0FFFFFFF; - fRegisters.__cr |= (value & 0xF0000000); - return; - case UNW_PPC_CR1: - fRegisters.__cr &= 0xF0FFFFFF; - fRegisters.__cr |= (value & 0x0F000000); - return; - case UNW_PPC_CR2: - fRegisters.__cr &= 0xFF0FFFFF; - fRegisters.__cr |= (value & 0x00F00000); - return; - case UNW_PPC_CR3: - fRegisters.__cr &= 0xFFF0FFFF; - fRegisters.__cr |= (value & 0x000F0000); - return; - case UNW_PPC_CR4: - fRegisters.__cr &= 0xFFFF0FFF; - fRegisters.__cr |= (value & 0x0000F000); - return; - case UNW_PPC_CR5: - fRegisters.__cr &= 0xFFFFF0FF; - fRegisters.__cr |= (value & 0x00000F00); - return; - case UNW_PPC_CR6: - fRegisters.__cr &= 0xFFFFFF0F; - fRegisters.__cr |= (value & 0x000000F0); - return; - case UNW_PPC_CR7: - fRegisters.__cr &= 0xFFFFFFF0; - fRegisters.__cr |= (value & 0x0000000F); - return; - case UNW_PPC_VRSAVE: - fRegisters.__vrsave = value; - return; - // not saved - return; - case UNW_PPC_XER: - fRegisters.__xer = value; - return; - case UNW_PPC_AP: - case UNW_PPC_VSCR: - case UNW_PPC_SPEFSCR: - // not saved - return; - } - ABORT("unsupported ppc register"); +inline Registers_arm64::Registers_arm64(const Registers_arm64& other) { + *this = other; } -inline bool Registers_ppc::validFloatRegister(int regNum) const -{ - if ( regNum < UNW_PPC_F0 ) - return false; - if ( regNum > UNW_PPC_F31 ) - return false; - return true; +inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& other) { + memcpy(&_registers, &other._registers, sizeof(_registers)); + memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters, + sizeof(_vectorHalfRegisters)); + return *this; } -inline double Registers_ppc::getFloatRegister(int regNum) const -{ - assert(validFloatRegister(regNum)); - return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0]; +inline Registers_arm64::Registers_arm64() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); } -inline void Registers_ppc::setFloatRegister(int regNum, double value) -{ - //fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value); - assert(validFloatRegister(regNum)); - fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value; +inline bool Registers_arm64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 95) + return false; + if (regNum == UNW_ARM64_RA_SIGN_STATE) + return true; + if ((regNum > 31) && (regNum < 64)) + return false; + return true; } - -inline bool Registers_ppc::validVectorRegister(int regNum) const -{ - if ( regNum < UNW_PPC_V0 ) - return false; - if ( regNum > UNW_PPC_V31 ) - return false; - return true; +inline uint64_t Registers_arm64::getRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return getIP(); + if (regNum == UNW_REG_SP) + return _registers.__sp; + if (regNum == UNW_ARM64_RA_SIGN_STATE) + return _registers.__ra_sign_state; + if ((regNum >= 0) && (regNum < 32)) + return _registers.__x[regNum]; + _LIBUNWIND_ABORT("unsupported arm64 register"); } -v128 Registers_ppc::getVectorRegister(int regNum) const -{ - assert(validVectorRegister(regNum)); - v128 result = fVectorRegisters[regNum-UNW_PPC_V0]; - //fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n", - // this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]); - return result; +inline void Registers_arm64::setRegister(int regNum, uint64_t value) { + if (regNum == UNW_REG_IP) + setIP(value); + else if (regNum == UNW_REG_SP) + _registers.__sp = value; + else if (regNum == UNW_ARM64_RA_SIGN_STATE) + _registers.__ra_sign_state = value; + else if ((regNum >= 0) && (regNum < 32)) + _registers.__x[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported arm64 register"); } -void Registers_ppc::setVectorRegister(int regNum, v128 value) -{ - assert(validVectorRegister(regNum)); - //fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n", - // this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2], - // fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]); - fVectorRegisters[regNum-UNW_PPC_V0] = value; +inline const char *Registers_arm64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_REG_SP: + return "sp"; + case UNW_ARM64_X0: + return "x0"; + case UNW_ARM64_X1: + return "x1"; + case UNW_ARM64_X2: + return "x2"; + case UNW_ARM64_X3: + return "x3"; + case UNW_ARM64_X4: + return "x4"; + case UNW_ARM64_X5: + return "x5"; + case UNW_ARM64_X6: + return "x6"; + case UNW_ARM64_X7: + return "x7"; + case UNW_ARM64_X8: + return "x8"; + case UNW_ARM64_X9: + return "x9"; + case UNW_ARM64_X10: + return "x10"; + case UNW_ARM64_X11: + return "x11"; + case UNW_ARM64_X12: + return "x12"; + case UNW_ARM64_X13: + return "x13"; + case UNW_ARM64_X14: + return "x14"; + case UNW_ARM64_X15: + return "x15"; + case UNW_ARM64_X16: + return "x16"; + case UNW_ARM64_X17: + return "x17"; + case UNW_ARM64_X18: + return "x18"; + case UNW_ARM64_X19: + return "x19"; + case UNW_ARM64_X20: + return "x20"; + case UNW_ARM64_X21: + return "x21"; + case UNW_ARM64_X22: + return "x22"; + case UNW_ARM64_X23: + return "x23"; + case UNW_ARM64_X24: + return "x24"; + case UNW_ARM64_X25: + return "x25"; + case UNW_ARM64_X26: + return "x26"; + case UNW_ARM64_X27: + return "x27"; + case UNW_ARM64_X28: + return "x28"; + case UNW_ARM64_X29: + return "fp"; + case UNW_ARM64_X30: + return "lr"; + case UNW_ARM64_X31: + return "sp"; + case UNW_ARM64_D0: + return "d0"; + case UNW_ARM64_D1: + return "d1"; + case UNW_ARM64_D2: + return "d2"; + case UNW_ARM64_D3: + return "d3"; + case UNW_ARM64_D4: + return "d4"; + case UNW_ARM64_D5: + return "d5"; + case UNW_ARM64_D6: + return "d6"; + case UNW_ARM64_D7: + return "d7"; + case UNW_ARM64_D8: + return "d8"; + case UNW_ARM64_D9: + return "d9"; + case UNW_ARM64_D10: + return "d10"; + case UNW_ARM64_D11: + return "d11"; + case UNW_ARM64_D12: + return "d12"; + case UNW_ARM64_D13: + return "d13"; + case UNW_ARM64_D14: + return "d14"; + case UNW_ARM64_D15: + return "d15"; + case UNW_ARM64_D16: + return "d16"; + case UNW_ARM64_D17: + return "d17"; + case UNW_ARM64_D18: + return "d18"; + case UNW_ARM64_D19: + return "d19"; + case UNW_ARM64_D20: + return "d20"; + case UNW_ARM64_D21: + return "d21"; + case UNW_ARM64_D22: + return "d22"; + case UNW_ARM64_D23: + return "d23"; + case UNW_ARM64_D24: + return "d24"; + case UNW_ARM64_D25: + return "d25"; + case UNW_ARM64_D26: + return "d26"; + case UNW_ARM64_D27: + return "d27"; + case UNW_ARM64_D28: + return "d28"; + case UNW_ARM64_D29: + return "d29"; + case UNW_ARM64_D30: + return "d30"; + case UNW_ARM64_D31: + return "d31"; + default: + return "unknown register"; + } } - -inline const char* Registers_ppc::getRegisterName(int regNum) -{ - switch ( regNum ) { - case UNW_REG_IP: - return "ip"; - case UNW_REG_SP: - return "sp"; - case UNW_PPC_R0: - return "r0"; - case UNW_PPC_R1: - return "r1"; - case UNW_PPC_R2: - return "r2"; - case UNW_PPC_R3: - return "r3"; - case UNW_PPC_R4: - return "r4"; - case UNW_PPC_R5: - return "r5"; - case UNW_PPC_R6: - return "r6"; - case UNW_PPC_R7: - return "r7"; - case UNW_PPC_R8: - return "r8"; - case UNW_PPC_R9: - return "r9"; - case UNW_PPC_R10: - return "r10"; - case UNW_PPC_R11: - return "r11"; - case UNW_PPC_R12: - return "r12"; - case UNW_PPC_R13: - return "r13"; - case UNW_PPC_R14: - return "r14"; - case UNW_PPC_R15: - return "r15"; - case UNW_PPC_R16: - return "r16"; - case UNW_PPC_R17: - return "r17"; - case UNW_PPC_R18: - return "r18"; - case UNW_PPC_R19: - return "r19"; - case UNW_PPC_R20: - return "r20"; - case UNW_PPC_R21: - return "r21"; - case UNW_PPC_R22: - return "r22"; - case UNW_PPC_R23: - return "r23"; - case UNW_PPC_R24: - return "r24"; - case UNW_PPC_R25: - return "r25"; - case UNW_PPC_R26: - return "r26"; - case UNW_PPC_R27: - return "r27"; - case UNW_PPC_R28: - return "r28"; - case UNW_PPC_R29: - return "r29"; - case UNW_PPC_R30: - return "r30"; - case UNW_PPC_R31: - return "r31"; - case UNW_PPC_F0: - return "fp0"; - case UNW_PPC_F1: - return "fp1"; - case UNW_PPC_F2: - return "fp2"; - case UNW_PPC_F3: - return "fp3"; - case UNW_PPC_F4: - return "fp4"; - case UNW_PPC_F5: - return "fp5"; - case UNW_PPC_F6: - return "fp6"; - case UNW_PPC_F7: - return "fp7"; - case UNW_PPC_F8: - return "fp8"; - case UNW_PPC_F9: - return "fp9"; - case UNW_PPC_F10: - return "fp10"; - case UNW_PPC_F11: - return "fp11"; - case UNW_PPC_F12: - return "fp12"; - case UNW_PPC_F13: - return "fp13"; - case UNW_PPC_F14: - return "fp14"; - case UNW_PPC_F15: - return "fp15"; - case UNW_PPC_F16: - return "fp16"; - case UNW_PPC_F17: - return "fp17"; - case UNW_PPC_F18: - return "fp18"; - case UNW_PPC_F19: - return "fp19"; - case UNW_PPC_F20: - return "fp20"; - case UNW_PPC_F21: - return "fp21"; - case UNW_PPC_F22: - return "fp22"; - case UNW_PPC_F23: - return "fp23"; - case UNW_PPC_F24: - return "fp24"; - case UNW_PPC_F25: - return "fp25"; - case UNW_PPC_F26: - return "fp26"; - case UNW_PPC_F27: - return "fp27"; - case UNW_PPC_F28: - return "fp28"; - case UNW_PPC_F29: - return "fp29"; - case UNW_PPC_F30: - return "fp30"; - case UNW_PPC_F31: - return "fp31"; - case UNW_PPC_LR: - return "lr"; - default: - return "unknown register"; - } - - +inline bool Registers_arm64::validFloatRegister(int regNum) const { + if (regNum < UNW_ARM64_D0) + return false; + if (regNum > UNW_ARM64_D31) + return false; + return true; } +inline double Registers_arm64::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorHalfRegisters[regNum - UNW_ARM64_D0]; +} -} // namespace libunwind +inline void Registers_arm64::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value; +} + +inline bool Registers_arm64::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_arm64::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no arm64 vector register support yet"); +} + +inline void Registers_arm64::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no arm64 vector register support yet"); +} +#endif // _LIBUNWIND_TARGET_AARCH64 + +#if defined(_LIBUNWIND_TARGET_ARM) +/// Registers_arm holds the register state of a thread in a 32-bit arm +/// process. +/// +/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit, +/// this uses more memory than required. +class _LIBUNWIND_HIDDEN Registers_arm { +public: + Registers_arm(); + Registers_arm(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + unw_fpreg_t getFloatRegister(int num); + void setFloatRegister(int num, unw_fpreg_t value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { + restoreSavedFloatRegisters(); + restoreCoreAndJumpTo(); + } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; } + static int getArch() { return REGISTERS_ARM; } + + uint32_t getSP() const { return _registers.__sp; } + void setSP(uint32_t value) { _registers.__sp = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + + typedef uint32_t reg_t; + void normalizeNewLinkRegister(reg_t&, unw_word_t) { } + void normalizeExistingLinkRegister(reg_t&) { } + + void saveVFPAsX() { + assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15); + _use_X_for_vfp_save = true; + } + + void restoreSavedFloatRegisters() { + if (_saved_vfp_d0_d15) { + if (_use_X_for_vfp_save) + restoreVFPWithFLDMX(_vfp_d0_d15_pad); + else + restoreVFPWithFLDMD(_vfp_d0_d15_pad); + } + if (_saved_vfp_d16_d31) + restoreVFPv3(_vfp_d16_d31); +#if defined(__ARM_WMMX) + if (_saved_iwmmx) + restoreiWMMX(_iwmmx); + if (_saved_iwmmx_control) + restoreiWMMXControl(_iwmmx_control); +#endif + } + +private: + struct GPRs { + uint32_t __r[13]; // r0-r12 + uint32_t __sp; // Stack pointer r13 + uint32_t __lr; // Link register r14 + uint32_t __pc; // Program counter r15 + }; + + static void saveVFPWithFSTMD(void*); + static void saveVFPWithFSTMX(void*); + static void saveVFPv3(void*); + static void restoreVFPWithFLDMD(void*); + static void restoreVFPWithFLDMX(void*); + static void restoreVFPv3(void*); +#if defined(__ARM_WMMX) + static void saveiWMMX(void*); + static void saveiWMMXControl(uint32_t*); + static void restoreiWMMX(void*); + static void restoreiWMMXControl(uint32_t*); +#endif + void restoreCoreAndJumpTo(); + + // ARM registers + GPRs _registers; + + // We save floating point registers lazily because we can't know ahead of + // time which ones are used. See EHABI #4.7. + + // Whether D0-D15 are saved in the FTSMX instead of FSTMD format. + // + // See EHABI #7.5 that explains how matching instruction sequences for load + // and store need to be used to correctly restore the exact register bits. + bool _use_X_for_vfp_save; + // Whether VFP D0-D15 are saved. + bool _saved_vfp_d0_d15; + // Whether VFPv3 D16-D31 are saved. + bool _saved_vfp_d16_d31; + // VFP registers D0-D15, + padding if saved using FSTMX + unw_fpreg_t _vfp_d0_d15_pad[17]; + // VFPv3 registers D16-D31, always saved using FSTMD + unw_fpreg_t _vfp_d16_d31[16]; +#if defined(__ARM_WMMX) + // Whether iWMMX data registers are saved. + bool _saved_iwmmx; + // Whether iWMMX control registers are saved. + mutable bool _saved_iwmmx_control; + // iWMMX registers + unw_fpreg_t _iwmmx[16]; + // iWMMX control registers + mutable uint32_t _iwmmx_control[4]; +#endif +}; + +inline Registers_arm::Registers_arm(const void *registers) + : _use_X_for_vfp_save(false), + _saved_vfp_d0_d15(false), + _saved_vfp_d16_d31(false) { + static_assert((check_fit::does_fit), + "arm registers do not fit into unw_context_t"); + // See __unw_getcontext() note about data. + memcpy(&_registers, registers, sizeof(_registers)); + memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); + memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); +#if defined(__ARM_WMMX) + _saved_iwmmx = false; + _saved_iwmmx_control = false; + memset(&_iwmmx, 0, sizeof(_iwmmx)); + memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); +#endif +} + +inline Registers_arm::Registers_arm() + : _use_X_for_vfp_save(false), + _saved_vfp_d0_d15(false), + _saved_vfp_d16_d31(false) { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); + memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); +#if defined(__ARM_WMMX) + _saved_iwmmx = false; + _saved_iwmmx_control = false; + memset(&_iwmmx, 0, sizeof(_iwmmx)); + memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); +#endif +} + +inline bool Registers_arm::validRegister(int regNum) const { + // Returns true for all non-VFP registers supported by the EHABI + // virtual register set (VRS). + if (regNum == UNW_REG_IP) + return true; + + if (regNum == UNW_REG_SP) + return true; + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) + return true; + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) + return true; +#endif + + return false; +} + +inline uint32_t Registers_arm::getRegister(int regNum) const { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) + return _registers.__sp; + + if (regNum == UNW_ARM_LR) + return _registers.__lr; + + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) + return _registers.__pc; + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) + return _registers.__r[regNum]; + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { + if (!_saved_iwmmx_control) { + _saved_iwmmx_control = true; + saveiWMMXControl(_iwmmx_control); + } + return _iwmmx_control[regNum - UNW_ARM_WC0]; + } +#endif + + _LIBUNWIND_ABORT("unsupported arm register"); +} + +inline void Registers_arm::setRegister(int regNum, uint32_t value) { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { + _registers.__sp = value; + return; + } + + if (regNum == UNW_ARM_LR) { + _registers.__lr = value; + return; + } + + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) { + _registers.__pc = value; + return; + } + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) { + _registers.__r[regNum] = value; + return; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { + if (!_saved_iwmmx_control) { + _saved_iwmmx_control = true; + saveiWMMXControl(_iwmmx_control); + } + _iwmmx_control[regNum - UNW_ARM_WC0] = value; + return; + } +#endif + + _LIBUNWIND_ABORT("unsupported arm register"); +} + +inline const char *Registers_arm::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + case UNW_ARM_IP: // UNW_ARM_R15 is alias + return "pc"; + case UNW_ARM_LR: // UNW_ARM_R14 is alias + return "lr"; + case UNW_REG_SP: + case UNW_ARM_SP: // UNW_ARM_R13 is alias + return "sp"; + case UNW_ARM_R0: + return "r0"; + case UNW_ARM_R1: + return "r1"; + case UNW_ARM_R2: + return "r2"; + case UNW_ARM_R3: + return "r3"; + case UNW_ARM_R4: + return "r4"; + case UNW_ARM_R5: + return "r5"; + case UNW_ARM_R6: + return "r6"; + case UNW_ARM_R7: + return "r7"; + case UNW_ARM_R8: + return "r8"; + case UNW_ARM_R9: + return "r9"; + case UNW_ARM_R10: + return "r10"; + case UNW_ARM_R11: + return "r11"; + case UNW_ARM_R12: + return "r12"; + case UNW_ARM_S0: + return "s0"; + case UNW_ARM_S1: + return "s1"; + case UNW_ARM_S2: + return "s2"; + case UNW_ARM_S3: + return "s3"; + case UNW_ARM_S4: + return "s4"; + case UNW_ARM_S5: + return "s5"; + case UNW_ARM_S6: + return "s6"; + case UNW_ARM_S7: + return "s7"; + case UNW_ARM_S8: + return "s8"; + case UNW_ARM_S9: + return "s9"; + case UNW_ARM_S10: + return "s10"; + case UNW_ARM_S11: + return "s11"; + case UNW_ARM_S12: + return "s12"; + case UNW_ARM_S13: + return "s13"; + case UNW_ARM_S14: + return "s14"; + case UNW_ARM_S15: + return "s15"; + case UNW_ARM_S16: + return "s16"; + case UNW_ARM_S17: + return "s17"; + case UNW_ARM_S18: + return "s18"; + case UNW_ARM_S19: + return "s19"; + case UNW_ARM_S20: + return "s20"; + case UNW_ARM_S21: + return "s21"; + case UNW_ARM_S22: + return "s22"; + case UNW_ARM_S23: + return "s23"; + case UNW_ARM_S24: + return "s24"; + case UNW_ARM_S25: + return "s25"; + case UNW_ARM_S26: + return "s26"; + case UNW_ARM_S27: + return "s27"; + case UNW_ARM_S28: + return "s28"; + case UNW_ARM_S29: + return "s29"; + case UNW_ARM_S30: + return "s30"; + case UNW_ARM_S31: + return "s31"; + case UNW_ARM_D0: + return "d0"; + case UNW_ARM_D1: + return "d1"; + case UNW_ARM_D2: + return "d2"; + case UNW_ARM_D3: + return "d3"; + case UNW_ARM_D4: + return "d4"; + case UNW_ARM_D5: + return "d5"; + case UNW_ARM_D6: + return "d6"; + case UNW_ARM_D7: + return "d7"; + case UNW_ARM_D8: + return "d8"; + case UNW_ARM_D9: + return "d9"; + case UNW_ARM_D10: + return "d10"; + case UNW_ARM_D11: + return "d11"; + case UNW_ARM_D12: + return "d12"; + case UNW_ARM_D13: + return "d13"; + case UNW_ARM_D14: + return "d14"; + case UNW_ARM_D15: + return "d15"; + case UNW_ARM_D16: + return "d16"; + case UNW_ARM_D17: + return "d17"; + case UNW_ARM_D18: + return "d18"; + case UNW_ARM_D19: + return "d19"; + case UNW_ARM_D20: + return "d20"; + case UNW_ARM_D21: + return "d21"; + case UNW_ARM_D22: + return "d22"; + case UNW_ARM_D23: + return "d23"; + case UNW_ARM_D24: + return "d24"; + case UNW_ARM_D25: + return "d25"; + case UNW_ARM_D26: + return "d26"; + case UNW_ARM_D27: + return "d27"; + case UNW_ARM_D28: + return "d28"; + case UNW_ARM_D29: + return "d29"; + case UNW_ARM_D30: + return "d30"; + case UNW_ARM_D31: + return "d31"; + default: + return "unknown register"; + } +} + +inline bool Registers_arm::validFloatRegister(int regNum) const { + // NOTE: Consider the intel MMX registers floating points so the + // __unw_get_fpreg can be used to transmit the 64-bit data back. + return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31)) +#if defined(__ARM_WMMX) + || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15)) +#endif + ; +} + +inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) { + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { + if (!_saved_vfp_d0_d15) { + _saved_vfp_d0_d15 = true; + if (_use_X_for_vfp_save) + saveVFPWithFSTMX(_vfp_d0_d15_pad); + else + saveVFPWithFSTMD(_vfp_d0_d15_pad); + } + return _vfp_d0_d15_pad[regNum - UNW_ARM_D0]; + } + + if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { + if (!_saved_vfp_d16_d31) { + _saved_vfp_d16_d31 = true; + saveVFPv3(_vfp_d16_d31); + } + return _vfp_d16_d31[regNum - UNW_ARM_D16]; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { + if (!_saved_iwmmx) { + _saved_iwmmx = true; + saveiWMMX(_iwmmx); + } + return _iwmmx[regNum - UNW_ARM_WR0]; + } +#endif + + _LIBUNWIND_ABORT("Unknown ARM float register"); +} + +inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) { + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { + if (!_saved_vfp_d0_d15) { + _saved_vfp_d0_d15 = true; + if (_use_X_for_vfp_save) + saveVFPWithFSTMX(_vfp_d0_d15_pad); + else + saveVFPWithFSTMD(_vfp_d0_d15_pad); + } + _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value; + return; + } + + if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { + if (!_saved_vfp_d16_d31) { + _saved_vfp_d16_d31 = true; + saveVFPv3(_vfp_d16_d31); + } + _vfp_d16_d31[regNum - UNW_ARM_D16] = value; + return; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { + if (!_saved_iwmmx) { + _saved_iwmmx = true; + saveiWMMX(_iwmmx); + } + _iwmmx[regNum - UNW_ARM_WR0] = value; + return; + } +#endif + + _LIBUNWIND_ABORT("Unknown ARM float register"); +} + +inline bool Registers_arm::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_arm::getVectorRegister(int) const { + _LIBUNWIND_ABORT("ARM vector support not implemented"); +} + +inline void Registers_arm::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("ARM vector support not implemented"); +} +#endif // _LIBUNWIND_TARGET_ARM +#if defined(_LIBUNWIND_TARGET_OR1K) +/// Registers_or1k holds the register state of a thread in an OpenRISC1000 +/// process. +class _LIBUNWIND_HIDDEN Registers_or1k { +public: + Registers_or1k(); + Registers_or1k(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; } + static int getArch() { return REGISTERS_OR1K; } + + uint64_t getSP() const { return _registers.__r[1]; } + void setSP(uint32_t value) { _registers.__r[1] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct or1k_thread_state_t { + unsigned int __r[32]; // r0-r31 + unsigned int __pc; // Program counter + unsigned int __epcr; // Program counter at exception + }; + + or1k_thread_state_t _registers; +}; + +inline Registers_or1k::Registers_or1k(const void *registers) { + static_assert((check_fit::does_fit), + "or1k registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_or1k::Registers_or1k() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_or1k::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_OR1K_R31) + return true; + if (regNum == UNW_OR1K_EPCR) + return true; + return false; +} + +inline uint32_t Registers_or1k::getRegister(int regNum) const { + if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) + return _registers.__r[regNum - UNW_OR1K_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[1]; + case UNW_OR1K_EPCR: + return _registers.__epcr; + } + _LIBUNWIND_ABORT("unsupported or1k register"); +} + +inline void Registers_or1k::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) { + _registers.__r[regNum - UNW_OR1K_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[1] = value; + return; + case UNW_OR1K_EPCR: + _registers.__epcr = value; + return; + } + _LIBUNWIND_ABORT("unsupported or1k register"); +} + +inline bool Registers_or1k::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_or1k::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("or1k float support not implemented"); +} + +inline void Registers_or1k::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("or1k float support not implemented"); +} + +inline bool Registers_or1k::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_or1k::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("or1k vector support not implemented"); +} + +inline void Registers_or1k::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("or1k vector support not implemented"); +} + +inline const char *Registers_or1k::getRegisterName(int regNum) { + switch (regNum) { + case UNW_OR1K_R0: + return "r0"; + case UNW_OR1K_R1: + return "r1"; + case UNW_OR1K_R2: + return "r2"; + case UNW_OR1K_R3: + return "r3"; + case UNW_OR1K_R4: + return "r4"; + case UNW_OR1K_R5: + return "r5"; + case UNW_OR1K_R6: + return "r6"; + case UNW_OR1K_R7: + return "r7"; + case UNW_OR1K_R8: + return "r8"; + case UNW_OR1K_R9: + return "r9"; + case UNW_OR1K_R10: + return "r10"; + case UNW_OR1K_R11: + return "r11"; + case UNW_OR1K_R12: + return "r12"; + case UNW_OR1K_R13: + return "r13"; + case UNW_OR1K_R14: + return "r14"; + case UNW_OR1K_R15: + return "r15"; + case UNW_OR1K_R16: + return "r16"; + case UNW_OR1K_R17: + return "r17"; + case UNW_OR1K_R18: + return "r18"; + case UNW_OR1K_R19: + return "r19"; + case UNW_OR1K_R20: + return "r20"; + case UNW_OR1K_R21: + return "r21"; + case UNW_OR1K_R22: + return "r22"; + case UNW_OR1K_R23: + return "r23"; + case UNW_OR1K_R24: + return "r24"; + case UNW_OR1K_R25: + return "r25"; + case UNW_OR1K_R26: + return "r26"; + case UNW_OR1K_R27: + return "r27"; + case UNW_OR1K_R28: + return "r28"; + case UNW_OR1K_R29: + return "r29"; + case UNW_OR1K_R30: + return "r30"; + case UNW_OR1K_R31: + return "r31"; + case UNW_OR1K_EPCR: + return "EPCR"; + default: + return "unknown register"; + } + +} +#endif // _LIBUNWIND_TARGET_OR1K + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) +/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS +/// process. +class _LIBUNWIND_HIDDEN Registers_mips_o32 { +public: + Registers_mips_o32(); + Registers_mips_o32(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } + static int getArch() { return REGISTERS_MIPS_O32; } + + uint32_t getSP() const { return _registers.__r[29]; } + void setSP(uint32_t value) { _registers.__r[29] = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct mips_o32_thread_state_t { + uint32_t __r[32]; + uint32_t __pc; + uint32_t __hi; + uint32_t __lo; + }; + + mips_o32_thread_state_t _registers; +#ifdef __mips_hard_float + /// O32 with 32-bit floating point registers only uses half of this + /// space. However, using the same layout for 32-bit vs 64-bit + /// floating point registers results in a single context size for + /// O32 with hard float. + uint32_t _padding; + double _floats[32]; +#endif +}; + +inline Registers_mips_o32::Registers_mips_o32(const void *registers) { + static_assert((check_fit::does_fit), + "mips_o32 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_o32::Registers_mips_o32() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_o32::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; +#if __mips_isa_rev != 6 + if (regNum == UNW_MIPS_HI) + return true; + if (regNum == UNW_MIPS_LO) + return true; +#endif +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#endif + // FIXME: DSP accumulator registers, MSA registers + return false; +} + +inline uint32_t Registers_mips_o32::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { + uint32_t *p; + + if (regNum % 2 == 0) + p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; + else + p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; + return *p; + } +#endif + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + case UNW_MIPS_HI: + return _registers.__hi; + case UNW_MIPS_LO: + return _registers.__lo; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { + uint32_t *p; + + if (regNum % 2 == 0) + p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; + else + p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; + *p = value; + return; + } +#endif + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + case UNW_MIPS_HI: + _registers.__hi = value; + return; + case UNW_MIPS_LO: + _registers.__lo = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline bool Registers_mips_o32::validFloatRegister(int regNum) const { +#if defined(__mips_hard_float) && __mips_fpr == 64 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#else + (void)regNum; +#endif + return false; +} + +inline double Registers_mips_o32::getFloatRegister(int regNum) const { +#if defined(__mips_hard_float) && __mips_fpr == 64 + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_MIPS_F0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +#endif +} + +inline void Registers_mips_o32::setFloatRegister(int regNum, + double value) { +#if defined(__mips_hard_float) && __mips_fpr == 64 + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_MIPS_F0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +#endif +} + +inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline const char *Registers_mips_o32::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + case UNW_MIPS_F0: + return "$f0"; + case UNW_MIPS_F1: + return "$f1"; + case UNW_MIPS_F2: + return "$f2"; + case UNW_MIPS_F3: + return "$f3"; + case UNW_MIPS_F4: + return "$f4"; + case UNW_MIPS_F5: + return "$f5"; + case UNW_MIPS_F6: + return "$f6"; + case UNW_MIPS_F7: + return "$f7"; + case UNW_MIPS_F8: + return "$f8"; + case UNW_MIPS_F9: + return "$f9"; + case UNW_MIPS_F10: + return "$f10"; + case UNW_MIPS_F11: + return "$f11"; + case UNW_MIPS_F12: + return "$f12"; + case UNW_MIPS_F13: + return "$f13"; + case UNW_MIPS_F14: + return "$f14"; + case UNW_MIPS_F15: + return "$f15"; + case UNW_MIPS_F16: + return "$f16"; + case UNW_MIPS_F17: + return "$f17"; + case UNW_MIPS_F18: + return "$f18"; + case UNW_MIPS_F19: + return "$f19"; + case UNW_MIPS_F20: + return "$f20"; + case UNW_MIPS_F21: + return "$f21"; + case UNW_MIPS_F22: + return "$f22"; + case UNW_MIPS_F23: + return "$f23"; + case UNW_MIPS_F24: + return "$f24"; + case UNW_MIPS_F25: + return "$f25"; + case UNW_MIPS_F26: + return "$f26"; + case UNW_MIPS_F27: + return "$f27"; + case UNW_MIPS_F28: + return "$f28"; + case UNW_MIPS_F29: + return "$f29"; + case UNW_MIPS_F30: + return "$f30"; + case UNW_MIPS_F31: + return "$f31"; + case UNW_MIPS_HI: + return "$hi"; + case UNW_MIPS_LO: + return "$lo"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_O32 + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) +/// Registers_mips_newabi holds the register state of a thread in a +/// MIPS process using NEWABI (the N32 or N64 ABIs). +class _LIBUNWIND_HIDDEN Registers_mips_newabi { +public: + Registers_mips_newabi(); + Registers_mips_newabi(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } + static int getArch() { return REGISTERS_MIPS_NEWABI; } + + uint64_t getSP() const { return _registers.__r[29]; } + void setSP(uint64_t value) { _registers.__r[29] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint64_t value) { _registers.__pc = value; } + +private: + struct mips_newabi_thread_state_t { + uint64_t __r[32]; + uint64_t __pc; + uint64_t __hi; + uint64_t __lo; + }; + + mips_newabi_thread_state_t _registers; +#ifdef __mips_hard_float + double _floats[32]; +#endif +}; + +inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) { + static_assert((check_fit::does_fit), + "mips_newabi registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_newabi::Registers_mips_newabi() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_newabi::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; +#if __mips_isa_rev != 6 + if (regNum == UNW_MIPS_HI) + return true; + if (regNum == UNW_MIPS_LO) + return true; +#endif + // FIXME: Hard float, DSP accumulator registers, MSA registers + return false; +} + +inline uint64_t Registers_mips_newabi::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + case UNW_MIPS_HI: + return _registers.__hi; + case UNW_MIPS_LO: + return _registers.__lo; + } + _LIBUNWIND_ABORT("unsupported mips_newabi register"); +} + +inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + case UNW_MIPS_HI: + _registers.__hi = value; + return; + case UNW_MIPS_LO: + _registers.__lo = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_newabi register"); +} + +inline bool Registers_mips_newabi::validFloatRegister(int regNum) const { +#ifdef __mips_hard_float + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#else + (void)regNum; +#endif + return false; +} + +inline double Registers_mips_newabi::getFloatRegister(int regNum) const { +#ifdef __mips_hard_float + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_MIPS_F0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("mips_newabi float support not implemented"); +#endif +} + +inline void Registers_mips_newabi::setFloatRegister(int regNum, + double value) { +#ifdef __mips_hard_float + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_MIPS_F0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("mips_newabi float support not implemented"); +#endif +} + +inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_newabi::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); +} + +inline void Registers_mips_newabi::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); +} + +inline const char *Registers_mips_newabi::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + case UNW_MIPS_F0: + return "$f0"; + case UNW_MIPS_F1: + return "$f1"; + case UNW_MIPS_F2: + return "$f2"; + case UNW_MIPS_F3: + return "$f3"; + case UNW_MIPS_F4: + return "$f4"; + case UNW_MIPS_F5: + return "$f5"; + case UNW_MIPS_F6: + return "$f6"; + case UNW_MIPS_F7: + return "$f7"; + case UNW_MIPS_F8: + return "$f8"; + case UNW_MIPS_F9: + return "$f9"; + case UNW_MIPS_F10: + return "$f10"; + case UNW_MIPS_F11: + return "$f11"; + case UNW_MIPS_F12: + return "$f12"; + case UNW_MIPS_F13: + return "$f13"; + case UNW_MIPS_F14: + return "$f14"; + case UNW_MIPS_F15: + return "$f15"; + case UNW_MIPS_F16: + return "$f16"; + case UNW_MIPS_F17: + return "$f17"; + case UNW_MIPS_F18: + return "$f18"; + case UNW_MIPS_F19: + return "$f19"; + case UNW_MIPS_F20: + return "$f20"; + case UNW_MIPS_F21: + return "$f21"; + case UNW_MIPS_F22: + return "$f22"; + case UNW_MIPS_F23: + return "$f23"; + case UNW_MIPS_F24: + return "$f24"; + case UNW_MIPS_F25: + return "$f25"; + case UNW_MIPS_F26: + return "$f26"; + case UNW_MIPS_F27: + return "$f27"; + case UNW_MIPS_F28: + return "$f28"; + case UNW_MIPS_F29: + return "$f29"; + case UNW_MIPS_F30: + return "$f30"; + case UNW_MIPS_F31: + return "$f31"; + case UNW_MIPS_HI: + return "$hi"; + case UNW_MIPS_LO: + return "$lo"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_NEWABI + +#if defined(_LIBUNWIND_TARGET_SPARC) +/// Registers_sparc holds the register state of a thread in a 32-bit Sparc +/// process. +class _LIBUNWIND_HIDDEN Registers_sparc { +public: + Registers_sparc(); + Registers_sparc(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; } + static int getArch() { return REGISTERS_SPARC; } + + uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; } + void setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; } + uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; } + void setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; } + +private: + struct sparc_thread_state_t { + unsigned int __regs[32]; + }; + + sparc_thread_state_t _registers; +}; + +inline Registers_sparc::Registers_sparc(const void *registers) { + static_assert((check_fit::does_fit), + "sparc registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_sparc::Registers_sparc() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_sparc::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_SPARC_I7) + return true; + return false; +} + +inline uint32_t Registers_sparc::getRegister(int regNum) const { + if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { + return _registers.__regs[regNum]; + } + + switch (regNum) { + case UNW_REG_IP: + return _registers.__regs[UNW_SPARC_O7]; + case UNW_REG_SP: + return _registers.__regs[UNW_SPARC_O6]; + } + _LIBUNWIND_ABORT("unsupported sparc register"); +} + +inline void Registers_sparc::setRegister(int regNum, uint32_t value) { + if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { + _registers.__regs[regNum] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__regs[UNW_SPARC_O7] = value; + return; + case UNW_REG_SP: + _registers.__regs[UNW_SPARC_O6] = value; + return; + } + _LIBUNWIND_ABORT("unsupported sparc register"); +} + +inline bool Registers_sparc::validFloatRegister(int) const { return false; } + +inline double Registers_sparc::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no Sparc float registers"); +} + +inline void Registers_sparc::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no Sparc float registers"); +} + +inline bool Registers_sparc::validVectorRegister(int) const { return false; } + +inline v128 Registers_sparc::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no Sparc vector registers"); +} + +inline void Registers_sparc::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no Sparc vector registers"); +} + +inline const char *Registers_sparc::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_SPARC_G0: + return "g0"; + case UNW_SPARC_G1: + return "g1"; + case UNW_SPARC_G2: + return "g2"; + case UNW_SPARC_G3: + return "g3"; + case UNW_SPARC_G4: + return "g4"; + case UNW_SPARC_G5: + return "g5"; + case UNW_SPARC_G6: + return "g6"; + case UNW_SPARC_G7: + return "g7"; + case UNW_SPARC_O0: + return "o0"; + case UNW_SPARC_O1: + return "o1"; + case UNW_SPARC_O2: + return "o2"; + case UNW_SPARC_O3: + return "o3"; + case UNW_SPARC_O4: + return "o4"; + case UNW_SPARC_O5: + return "o5"; + case UNW_REG_SP: + case UNW_SPARC_O6: + return "sp"; + case UNW_SPARC_O7: + return "o7"; + case UNW_SPARC_L0: + return "l0"; + case UNW_SPARC_L1: + return "l1"; + case UNW_SPARC_L2: + return "l2"; + case UNW_SPARC_L3: + return "l3"; + case UNW_SPARC_L4: + return "l4"; + case UNW_SPARC_L5: + return "l5"; + case UNW_SPARC_L6: + return "l6"; + case UNW_SPARC_L7: + return "l7"; + case UNW_SPARC_I0: + return "i0"; + case UNW_SPARC_I1: + return "i1"; + case UNW_SPARC_I2: + return "i2"; + case UNW_SPARC_I3: + return "i3"; + case UNW_SPARC_I4: + return "i4"; + case UNW_SPARC_I5: + return "i5"; + case UNW_SPARC_I6: + return "fp"; + case UNW_SPARC_I7: + return "i7"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_SPARC + +#if defined(_LIBUNWIND_TARGET_HEXAGON) +/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6 +/// process. +class _LIBUNWIND_HIDDEN Registers_hexagon { +public: + Registers_hexagon(); + Registers_hexagon(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON; } + static int getArch() { return REGISTERS_HEXAGON; } + + uint32_t getSP() const { return _registers.__r[UNW_HEXAGON_R29]; } + void setSP(uint32_t value) { _registers.__r[UNW_HEXAGON_R29] = value; } + uint32_t getIP() const { return _registers.__r[UNW_HEXAGON_PC]; } + void setIP(uint32_t value) { _registers.__r[UNW_HEXAGON_PC] = value; } + +private: + struct hexagon_thread_state_t { + unsigned int __r[35]; + }; + + hexagon_thread_state_t _registers; +}; + +inline Registers_hexagon::Registers_hexagon(const void *registers) { + static_assert((check_fit::does_fit), + "hexagon registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_hexagon::Registers_hexagon() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_hexagon::validRegister(int regNum) const { + if (regNum <= UNW_HEXAGON_R31) + return true; + return false; +} + +inline uint32_t Registers_hexagon::getRegister(int regNum) const { + if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31) + return _registers.__r[regNum - UNW_HEXAGON_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__r[UNW_HEXAGON_PC]; + case UNW_REG_SP: + return _registers.__r[UNW_HEXAGON_R29]; + } + _LIBUNWIND_ABORT("unsupported hexagon register"); +} + +inline void Registers_hexagon::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31) { + _registers.__r[regNum - UNW_HEXAGON_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__r[UNW_HEXAGON_PC] = value; + return; + case UNW_REG_SP: + _registers.__r[UNW_HEXAGON_R29] = value; + return; + } + _LIBUNWIND_ABORT("unsupported hexagon register"); +} + +inline bool Registers_hexagon::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_hexagon::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("hexagon float support not implemented"); +} + +inline void Registers_hexagon::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("hexagon float support not implemented"); +} + +inline bool Registers_hexagon::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_hexagon::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("hexagon vector support not implemented"); +} + +inline void Registers_hexagon::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("hexagon vector support not implemented"); +} + +inline const char *Registers_hexagon::getRegisterName(int regNum) { + switch (regNum) { + case UNW_HEXAGON_R0: + return "r0"; + case UNW_HEXAGON_R1: + return "r1"; + case UNW_HEXAGON_R2: + return "r2"; + case UNW_HEXAGON_R3: + return "r3"; + case UNW_HEXAGON_R4: + return "r4"; + case UNW_HEXAGON_R5: + return "r5"; + case UNW_HEXAGON_R6: + return "r6"; + case UNW_HEXAGON_R7: + return "r7"; + case UNW_HEXAGON_R8: + return "r8"; + case UNW_HEXAGON_R9: + return "r9"; + case UNW_HEXAGON_R10: + return "r10"; + case UNW_HEXAGON_R11: + return "r11"; + case UNW_HEXAGON_R12: + return "r12"; + case UNW_HEXAGON_R13: + return "r13"; + case UNW_HEXAGON_R14: + return "r14"; + case UNW_HEXAGON_R15: + return "r15"; + case UNW_HEXAGON_R16: + return "r16"; + case UNW_HEXAGON_R17: + return "r17"; + case UNW_HEXAGON_R18: + return "r18"; + case UNW_HEXAGON_R19: + return "r19"; + case UNW_HEXAGON_R20: + return "r20"; + case UNW_HEXAGON_R21: + return "r21"; + case UNW_HEXAGON_R22: + return "r22"; + case UNW_HEXAGON_R23: + return "r23"; + case UNW_HEXAGON_R24: + return "r24"; + case UNW_HEXAGON_R25: + return "r25"; + case UNW_HEXAGON_R26: + return "r26"; + case UNW_HEXAGON_R27: + return "r27"; + case UNW_HEXAGON_R28: + return "r28"; + case UNW_HEXAGON_R29: + return "r29"; + case UNW_HEXAGON_R30: + return "r30"; + case UNW_HEXAGON_R31: + return "r31"; + default: + return "unknown register"; + } + +} +#endif // _LIBUNWIND_TARGET_HEXAGON + + +#if defined(_LIBUNWIND_TARGET_RISCV) +/// Registers_riscv holds the register state of a thread in a 64-bit RISC-V +/// process. +class _LIBUNWIND_HIDDEN Registers_riscv { +public: + Registers_riscv(); + Registers_riscv(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV; } + static int getArch() { return REGISTERS_RISCV; } + + uint64_t getSP() const { return _registers[2]; } + void setSP(uint64_t value) { _registers[2] = value; } + uint64_t getIP() const { return _registers[0]; } + void setIP(uint64_t value) { _registers[0] = value; } + +private: + // _registers[0] holds the pc + uint64_t _registers[32]; + double _floats[32]; +}; + +inline Registers_riscv::Registers_riscv(const void *registers) { + static_assert((check_fit::does_fit), + "riscv registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); + static_assert(sizeof(_registers) == 0x100, + "expected float registers to be at offset 256"); + memcpy(_floats, + static_cast(registers) + sizeof(_registers), + sizeof(_floats)); +} + +inline Registers_riscv::Registers_riscv() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_floats, 0, sizeof(_floats)); +} + +inline bool Registers_riscv::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > UNW_RISCV_F31) + return false; + return true; +} + +inline uint64_t Registers_riscv::getRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return _registers[0]; + if (regNum == UNW_REG_SP) + return _registers[2]; + if (regNum == UNW_RISCV_X0) + return 0; + if ((regNum > 0) && (regNum < 32)) + return _registers[regNum]; + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline void Registers_riscv::setRegister(int regNum, uint64_t value) { + if (regNum == UNW_REG_IP) + _registers[0] = value; + else if (regNum == UNW_REG_SP) + _registers[2] = value; + else if (regNum == UNW_RISCV_X0) + /* x0 is hardwired to zero */ + return; + else if ((regNum > 0) && (regNum < 32)) + _registers[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline const char *Registers_riscv::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_REG_SP: + return "sp"; + case UNW_RISCV_X0: + return "zero"; + case UNW_RISCV_X1: + return "ra"; + case UNW_RISCV_X2: + return "sp"; + case UNW_RISCV_X3: + return "gp"; + case UNW_RISCV_X4: + return "tp"; + case UNW_RISCV_X5: + return "t0"; + case UNW_RISCV_X6: + return "t1"; + case UNW_RISCV_X7: + return "t2"; + case UNW_RISCV_X8: + return "s0"; + case UNW_RISCV_X9: + return "s1"; + case UNW_RISCV_X10: + return "a0"; + case UNW_RISCV_X11: + return "a1"; + case UNW_RISCV_X12: + return "a2"; + case UNW_RISCV_X13: + return "a3"; + case UNW_RISCV_X14: + return "a4"; + case UNW_RISCV_X15: + return "a5"; + case UNW_RISCV_X16: + return "a6"; + case UNW_RISCV_X17: + return "a7"; + case UNW_RISCV_X18: + return "s2"; + case UNW_RISCV_X19: + return "s3"; + case UNW_RISCV_X20: + return "s4"; + case UNW_RISCV_X21: + return "s5"; + case UNW_RISCV_X22: + return "s6"; + case UNW_RISCV_X23: + return "s7"; + case UNW_RISCV_X24: + return "s8"; + case UNW_RISCV_X25: + return "s9"; + case UNW_RISCV_X26: + return "s10"; + case UNW_RISCV_X27: + return "s11"; + case UNW_RISCV_X28: + return "t3"; + case UNW_RISCV_X29: + return "t4"; + case UNW_RISCV_X30: + return "t5"; + case UNW_RISCV_X31: + return "t6"; + case UNW_RISCV_F0: + return "ft0"; + case UNW_RISCV_F1: + return "ft1"; + case UNW_RISCV_F2: + return "ft2"; + case UNW_RISCV_F3: + return "ft3"; + case UNW_RISCV_F4: + return "ft4"; + case UNW_RISCV_F5: + return "ft5"; + case UNW_RISCV_F6: + return "ft6"; + case UNW_RISCV_F7: + return "ft7"; + case UNW_RISCV_F8: + return "fs0"; + case UNW_RISCV_F9: + return "fs1"; + case UNW_RISCV_F10: + return "fa0"; + case UNW_RISCV_F11: + return "fa1"; + case UNW_RISCV_F12: + return "fa2"; + case UNW_RISCV_F13: + return "fa3"; + case UNW_RISCV_F14: + return "fa4"; + case UNW_RISCV_F15: + return "fa5"; + case UNW_RISCV_F16: + return "fa6"; + case UNW_RISCV_F17: + return "fa7"; + case UNW_RISCV_F18: + return "fs2"; + case UNW_RISCV_F19: + return "fs3"; + case UNW_RISCV_F20: + return "fs4"; + case UNW_RISCV_F21: + return "fs5"; + case UNW_RISCV_F22: + return "fs6"; + case UNW_RISCV_F23: + return "fs7"; + case UNW_RISCV_F24: + return "fs8"; + case UNW_RISCV_F25: + return "fs9"; + case UNW_RISCV_F26: + return "fs10"; + case UNW_RISCV_F27: + return "fs11"; + case UNW_RISCV_F28: + return "ft8"; + case UNW_RISCV_F29: + return "ft9"; + case UNW_RISCV_F30: + return "ft10"; + case UNW_RISCV_F31: + return "ft11"; + default: + return "unknown register"; + } +} + +inline bool Registers_riscv::validFloatRegister(int regNum) const { + if (regNum < UNW_RISCV_F0) + return false; + if (regNum > UNW_RISCV_F31) + return false; + return true; +} + +inline double Registers_riscv::getFloatRegister(int regNum) const { +#if defined(__riscv_flen) && __riscv_flen == 64 + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_RISCV_F0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("libunwind not built with float support"); +#endif +} + +inline void Registers_riscv::setFloatRegister(int regNum, double value) { +#if defined(__riscv_flen) && __riscv_flen == 64 + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_RISCV_F0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("libunwind not built with float support"); +#endif +} + +inline bool Registers_riscv::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_riscv::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} + +inline void Registers_riscv::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} +#endif // _LIBUNWIND_TARGET_RISCV +} // namespace libunwind #endif // __REGISTERS_HPP__ - - - - diff --git a/libunwind/src/Unwind-EHABI.cpp b/libunwind/src/Unwind-EHABI.cpp new file mode 100644 index 0000000..32b5cbc --- /dev/null +++ b/libunwind/src/Unwind-EHABI.cpp @@ -0,0 +1,1003 @@ +//===--------------------------- Unwind-EHABI.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements ARM zero-cost C++ exceptions +// +//===----------------------------------------------------------------------===// + +#include "Unwind-EHABI.h" + +#if defined(_LIBUNWIND_ARM_EHABI) + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "libunwind.h" +#include "libunwind_ext.h" +#include "unwind.h" + +namespace { + +// Strange order: take words in order, but inside word, take from most to least +// signinficant byte. +uint8_t getByte(const uint32_t* data, size_t offset) { + const uint8_t* byteData = reinterpret_cast(data); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))]; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return byteData[offset]; +#else +#error "Unable to determine endianess" +#endif +} + +const char* getNextWord(const char* data, uint32_t* out) { + *out = *reinterpret_cast(data); + return data + 4; +} + +const char* getNextNibble(const char* data, uint32_t* out) { + *out = *reinterpret_cast(data); + return data + 2; +} + +struct Descriptor { + // See # 9.2 + typedef enum { + SU16 = 0, // Short descriptor, 16-bit entries + LU16 = 1, // Long descriptor, 16-bit entries + LU32 = 3, // Long descriptor, 32-bit entries + RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, + RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, + RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 + } Format; + + // See # 9.2 + typedef enum { + CLEANUP = 0x0, + FUNC = 0x1, + CATCH = 0x2, + INVALID = 0x4 + } Kind; +}; + +_Unwind_Reason_Code ProcessDescriptors( + _Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context, + Descriptor::Format format, + const char* descriptorStart, + uint32_t flags) { + + // EHT is inlined in the index using compact form. No descriptors. #5 + if (flags & 0x1) + return _URC_CONTINUE_UNWIND; + + // TODO: We should check the state here, and determine whether we need to + // perform phase1 or phase2 unwinding. + (void)state; + + const char* descriptor = descriptorStart; + uint32_t descriptorWord; + getNextWord(descriptor, &descriptorWord); + while (descriptorWord) { + // Read descriptor based on # 9.2. + uint32_t length; + uint32_t offset; + switch (format) { + case Descriptor::LU32: + descriptor = getNextWord(descriptor, &length); + descriptor = getNextWord(descriptor, &offset); + case Descriptor::LU16: + descriptor = getNextNibble(descriptor, &length); + descriptor = getNextNibble(descriptor, &offset); + default: + assert(false); + return _URC_FAILURE; + } + + // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. + Descriptor::Kind kind = + static_cast((length & 0x1) | ((offset & 0x1) << 1)); + + // Clear off flag from last bit. + length &= ~1u; + offset &= ~1u; + uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; + uintptr_t scopeEnd = scopeStart + length; + uintptr_t pc = _Unwind_GetIP(context); + bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); + + switch (kind) { + case Descriptor::CLEANUP: { + // TODO(ajwong): Handle cleanup descriptors. + break; + } + case Descriptor::FUNC: { + // TODO(ajwong): Handle function descriptors. + break; + } + case Descriptor::CATCH: { + // Catch descriptors require gobbling one more word. + uint32_t landing_pad; + descriptor = getNextWord(descriptor, &landing_pad); + + if (isInScope) { + // TODO(ajwong): This is only phase1 compatible logic. Implement + // phase2. + landing_pad = signExtendPrel31(landing_pad & ~0x80000000); + if (landing_pad == 0xffffffff) { + return _URC_HANDLER_FOUND; + } else if (landing_pad == 0xfffffffe) { + return _URC_FAILURE; + } else { + /* + bool is_reference_type = landing_pad & 0x80000000; + void* matched_object; + if (__cxxabiv1::__cxa_type_match( + ucbp, reinterpret_cast(landing_pad), + is_reference_type, + &matched_object) != __cxxabiv1::ctm_failed) + return _URC_HANDLER_FOUND; + */ + _LIBUNWIND_ABORT("Type matching not implemented"); + } + } + break; + } + default: + _LIBUNWIND_ABORT("Invalid descriptor kind found."); + } + + getNextWord(descriptor, &descriptorWord); + } + + return _URC_CONTINUE_UNWIND; +} + +static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context) { + // Read the compact model EHT entry's header # 6.3 + const uint32_t* unwindingData = ucbp->pr_cache.ehtp; + assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry"); + Descriptor::Format format = + static_cast((*unwindingData & 0x0f000000) >> 24); + + const char *lsda = + reinterpret_cast(_Unwind_GetLanguageSpecificData(context)); + + // Handle descriptors before unwinding so they are processed in the context + // of the correct stack frame. + _Unwind_Reason_Code result = + ProcessDescriptors(state, ucbp, context, format, lsda, + ucbp->pr_cache.additional); + + if (result != _URC_CONTINUE_UNWIND) + return result; + + if (__unw_step(reinterpret_cast(context)) != UNW_STEP_SUCCESS) + return _URC_FAILURE; + return _URC_CONTINUE_UNWIND; +} + +// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / +// _UVRSD_UINT32. +uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { + return ((1U << (count_minus_one + 1)) - 1) << start; +} + +// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / +// _UVRSD_DOUBLE. +uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { + return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1); +} + +} // end anonymous namespace + +/** + * Decodes an EHT entry. + * + * @param data Pointer to EHT. + * @param[out] off Offset from return value (in bytes) to begin interpretation. + * @param[out] len Number of bytes in unwind code. + * @return Pointer to beginning of unwind code. + */ +extern "C" const uint32_t* +decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { + if ((*data & 0x80000000) == 0) { + // 6.2: Generic Model + // + // EHT entry is a prel31 pointing to the PR, followed by data understood + // only by the personality routine. Fortunately, all existing assembler + // implementations, including GNU assembler, LLVM integrated assembler, + // and ARM assembler, assume that the unwind opcodes come after the + // personality rountine address. + *off = 1; // First byte is size data. + *len = (((data[1] >> 24) & 0xff) + 1) * 4; + data++; // Skip the first word, which is the prel31 offset. + } else { + // 6.3: ARM Compact Model + // + // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded + // by format: + Descriptor::Format format = + static_cast((*data & 0x0f000000) >> 24); + switch (format) { + case Descriptor::SU16: + *len = 4; + *off = 1; + break; + case Descriptor::LU16: + case Descriptor::LU32: + *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); + *off = 2; + break; + default: + return nullptr; + } + } + return data; +} + +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data, + size_t offset, size_t len) { + bool wrotePC = false; + bool finish = false; + while (offset < len && !finish) { + uint8_t byte = getByte(data, offset++); + if ((byte & 0x80) == 0) { + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + if (byte & 0x40) + sp -= (((uint32_t)byte & 0x3f) << 2) + 4; + else + sp += ((uint32_t)byte << 2) + 4; + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + } else { + switch (byte & 0xf0) { + case 0x80: { + if (offset >= len) + return _URC_FAILURE; + uint32_t registers = + (((uint32_t)byte & 0x0f) << 12) | + (((uint32_t)getByte(data, offset++)) << 4); + if (!registers) + return _URC_FAILURE; + if (registers & (1 << 15)) + wrotePC = true; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0x90: { + uint8_t reg = byte & 0x0f; + if (reg == 13 || reg == 15) + return _URC_FAILURE; + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, + _UVRSD_UINT32, &sp); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + break; + } + case 0xa0: { + uint32_t registers = RegisterMask(4, byte & 0x07); + if (byte & 0x08) + registers |= 1 << 14; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0xb0: { + switch (byte) { + case 0xb0: + finish = true; + break; + case 0xb1: { + if (offset >= len) + return _URC_FAILURE; + uint8_t registers = getByte(data, offset++); + if (registers & 0xf0 || !registers) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0xb2: { + uint32_t addend = 0; + uint32_t shift = 0; + // This decodes a uleb128 value. + while (true) { + if (offset >= len) + return _URC_FAILURE; + uint32_t v = getByte(data, offset++); + addend |= (v & 0x7f) << shift; + if ((v & 0x80) == 0) + break; + shift += 7; + } + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + sp += 0x204 + (addend << 2); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + break; + } + case 0xb3: { + uint8_t v = getByte(data, offset++); + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(static_cast(v >> 4), + v & 0x0f), _UVRSD_VFPX); + break; + } + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + return _URC_FAILURE; + default: + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(8, byte & 0x07), _UVRSD_VFPX); + break; + } + break; + } + case 0xc0: { + switch (byte) { +#if defined(__ARM_WMMX) + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: + _Unwind_VRS_Pop(context, _UVRSC_WMMXD, + RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); + break; + case 0xc6: { + uint8_t v = getByte(data, offset++); + uint8_t start = static_cast(v >> 4); + uint8_t count_minus_one = v & 0xf; + if (start + count_minus_one >= 16) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_WMMXD, + RegisterRange(start, count_minus_one), + _UVRSD_DOUBLE); + break; + } + case 0xc7: { + uint8_t v = getByte(data, offset++); + if (!v || v & 0xf0) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); + break; + } +#endif + case 0xc8: + case 0xc9: { + uint8_t v = getByte(data, offset++); + uint8_t start = + static_cast(((byte == 0xc8) ? 16 : 0) + (v >> 4)); + uint8_t count_minus_one = v & 0xf; + if (start + count_minus_one >= 32) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(start, count_minus_one), + _UVRSD_DOUBLE); + break; + } + default: + return _URC_FAILURE; + } + break; + } + case 0xd0: { + if (byte & 0x08) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), + _UVRSD_DOUBLE); + break; + } + default: + return _URC_FAILURE; + } + } + } + if (!wrotePC) { + uint32_t lr; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); + } + return _URC_CONTINUE_UNWIND; +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +static _Unwind_Reason_Code +unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during + // phase 1 and then restoring it to the "primary VRS" for phase 2. The + // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. + // In this implementation, the phases don't share the VRS backing store. + // Instead, they are passed the original |uc| and they create a new VRS + // from scratch thus achieving the same effect. + __unw_init_local(cursor, uc); + + // Walk each frame looking for a place to stop. + for (bool handlerNotFound = true; handlerNotFound;) { + + // See if frame has code to run (has personality routine). + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR", + static_cast(exception_object)); + return _URC_FATAL_PHASE1_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + static_cast(exception_object), pc, + frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // If there is a personality routine, ask it if it will want to stop at + // this frame. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(long)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): calling personality function %p", + static_cast(exception_object), + reinterpret_cast(reinterpret_cast(p))); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p " + "additional %x", + static_cast(exception_object), personalityResult, + exception_object->pr_cache.fnstart, + static_cast(exception_object->pr_cache.ehtp), + exception_object->pr_cache.additional); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember stack pointer at the frame + handlerNotFound = false; + // p should have initialized barrier_cache. EHABI #7.3.5 + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", + static_cast(exception_object)); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", + static_cast(exception_object)); + // continue unwinding + break; + + // EHABI #7.3.3 + case _URC_FAILURE: + return _URC_FAILURE; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", + static_cast(exception_object)); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + +static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object, + bool resume) { + // See comment at the start of unwind_phase1 regarding VRS integrity. + __unw_init_local(cursor, uc); + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", + static_cast(exception_object)); + int frame_count = 0; + + // Walk each frame until we reach where search phase said to stop. + while (true) { + // Ask libunwind to get next frame (skip over first which is + // _Unwind_RaiseException or _Unwind_Resume). + // + // Resume only ever makes sense for 1 frame. + _Unwind_State state = + resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; + if (resume && frame_count == 1) { + // On a resume, first unwind the _Unwind_Resume() frame. The next frame + // is now the landing pad for the cleanup from a previous execution of + // phase2. To continue unwindingly correctly, replace VRS[15] with the + // IP of the frame that the previous run of phase2 installed the context + // for. After this, continue unwinding as if normal. + // + // See #7.4.6 for details. + __unw_set_reg(cursor, UNW_REG_IP, + exception_object->unwinder_cache.reserved2); + resume = false; + } + + // Get info about this frame. + unw_word_t sp; + unw_proc_info_t frameInfo; + __unw_get_reg(cursor, UNW_REG_SP, &sp); + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE2_ERROR", + static_cast(exception_object)); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", + static_cast(exception_object), frameInfo.start_ip, + functionName, sp, frameInfo.lsda, + frameInfo.handler); + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(long)(frameInfo.handler); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); + // EHABI #7.2 + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(state, exception_object, context); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // Continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", + static_cast(exception_object)); + // EHABI #7.2 + if (sp == exception_object->barrier_cache.sp) { + // Phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now in phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", + static_cast(exception_object)); + // Personality routine says to transfer control to landing pad. + // We may get control back if landing pad calls _Unwind_Resume(). + if (_LIBUNWIND_TRACING_UNWINDING) { + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + __unw_get_reg(cursor, UNW_REG_SP, &sp); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " + "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR, + static_cast(exception_object), + pc, sp); + } + + { + // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume + // is called back, to find this same frame. + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + exception_object->unwinder_cache.reserved2 = (uint32_t)pc; + } + __unw_resume(cursor); + // __unw_resume() only returns if there was an error. + return _URC_FATAL_PHASE2_ERROR; + + // # EHABI #7.4.3 + case _URC_FAILURE: + abort(); + + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + frame_count++; + } + + // Clean up phase did not resume at the frame that the search phase + // said it would... + return _URC_FATAL_PHASE2_ERROR; +} + +/// Called by __cxa_throw. Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + static_cast(exception_object)); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // This field for is for compatibility with GCC to say this isn't a forced + // unwind. EHABI #7.2 + exception_object->unwinder_cache.reserved1 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(&uc, &cursor, exception_object, false); +} + +_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { + // This is to be called when exception handling completes to give us a chance + // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. + (void)exception_object; +} + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call __cxa_rethrow() which +/// in turn calls _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", + static_cast(exception_object)); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, + // which is in the same position as private_1 below. + // TODO(ajwong): Who wronte the above? Why is it true? + unwind_phase2(&uc, &cursor, exception_object, true); + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.lsda; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx", + static_cast(context), (long long)result); + return result; +} + +static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, + void* valuep) { + uint64_t value = 0; + switch (representation) { + case _UVRSD_UINT32: + case _UVRSD_FLOAT: + memcpy(&value, valuep, sizeof(uint32_t)); + break; + + case _UVRSD_VFPX: + case _UVRSD_UINT64: + case _UVRSD_DOUBLE: + memcpy(&value, valuep, sizeof(uint64_t)); + break; + } + return value; +} + +_LIBUNWIND_EXPORT _Unwind_VRS_Result +_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep) { + _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " + "rep=%d, value=0x%llX)", + static_cast(context), regclass, regno, + representation, + ValueAsBitPattern(representation, valuep)); + unw_cursor_t *cursor = (unw_cursor_t *)context; + switch (regclass) { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 || regno > 15) + return _UVRSR_FAILED; + return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), + *(unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_VFP: + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + if (representation == _UVRSD_VFPX) { + // Can only touch d0-15 with FSTMFDX. + if (regno > 15) + return _UVRSR_FAILED; + __unw_save_vfp_as_X(cursor); + } else { + if (regno > 31) + return _UVRSR_FAILED; + } + return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), + *(unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#if defined(__ARM_WMMX) + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), + *(unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXD: + if (representation != _UVRSD_DOUBLE || regno > 31) + return _UVRSR_FAILED; + return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), + *(unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#else + case _UVRSC_WMMXC: + case _UVRSC_WMMXD: + break; +#endif + } + _LIBUNWIND_ABORT("unsupported register class"); +} + +static _Unwind_VRS_Result +_Unwind_VRS_Get_Internal(_Unwind_Context *context, + _Unwind_VRS_RegClass regclass, uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + switch (regclass) { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 || regno > 15) + return _UVRSR_FAILED; + return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), + (unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_VFP: + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + if (representation == _UVRSD_VFPX) { + // Can only touch d0-15 with FSTMFDX. + if (regno > 15) + return _UVRSR_FAILED; + __unw_save_vfp_as_X(cursor); + } else { + if (regno > 31) + return _UVRSR_FAILED; + } + return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), + (unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#if defined(__ARM_WMMX) + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), + (unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXD: + if (representation != _UVRSD_DOUBLE || regno > 31) + return _UVRSR_FAILED; + return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), + (unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#else + case _UVRSC_WMMXC: + case _UVRSC_WMMXD: + break; +#endif + } + _LIBUNWIND_ABORT("unsupported register class"); +} + +_LIBUNWIND_EXPORT _Unwind_VRS_Result +_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep) { + _Unwind_VRS_Result result = + _Unwind_VRS_Get_Internal(context, regclass, regno, representation, + valuep); + _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " + "rep=%d, value=0x%llX, result = %d)", + static_cast(context), regclass, regno, + representation, + ValueAsBitPattern(representation, valuep), result); + return result; +} + +_Unwind_VRS_Result +_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t discriminator, + _Unwind_VRS_DataRepresentation representation) { + _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " + "discriminator=%d, representation=%d)", + static_cast(context), regclass, discriminator, + representation); + switch (regclass) { + case _UVRSC_WMMXC: +#if !defined(__ARM_WMMX) + break; +#endif + case _UVRSC_CORE: { + if (representation != _UVRSD_UINT32) + return _UVRSR_FAILED; + // When popping SP from the stack, we don't want to override it from the + // computed new stack location. See EHABI #7.5.4 table 3. + bool poppedSP = false; + uint32_t* sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + for (uint32_t i = 0; i < 16; ++i) { + if (!(discriminator & static_cast(1 << i))) + continue; + uint32_t value = *sp++; + if (regclass == _UVRSC_CORE && i == 13) + poppedSP = true; + if (_Unwind_VRS_Set(context, regclass, i, + _UVRSD_UINT32, &value) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + } + if (!poppedSP) { + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp); + } + return _UVRSR_OK; + } + case _UVRSC_WMMXD: +#if !defined(__ARM_WMMX) + break; +#endif + case _UVRSC_VFP: { + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + uint32_t first = discriminator >> 16; + uint32_t count = discriminator & 0xffff; + uint32_t end = first+count; + uint32_t* sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard + // format 1", which is equivalent to FSTMD + a padding word. + for (uint32_t i = first; i < end; ++i) { + // SP is only 32-bit aligned so don't copy 64-bit at a time. + uint64_t w0 = *sp++; + uint64_t w1 = *sp++; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint64_t value = (w1 << 32) | w0; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint64_t value = (w0 << 32) | w1; +#else +#error "Unable to determine endianess" +#endif + if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != + _UVRSR_OK) + return _UVRSR_FAILED; + } + if (representation == _UVRSD_VFPX) + ++sp; + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + } + } + _LIBUNWIND_ABORT("unsupported register class"); +} + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX", + static_cast(context), (long long)result); + return result; +} + + +/// Called by personality handler during phase 2 if a foreign exception +// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", + static_cast(exception_object)); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__gnu_unwind_frame(_Unwind_Exception *exception_object, + struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + if (__unw_step(cursor) != UNW_STEP_SUCCESS) + return _URC_FAILURE; + return _URC_OK; +} + +#endif // defined(_LIBUNWIND_ARM_EHABI) diff --git a/libunwind/src/Unwind-EHABI.h b/libunwind/src/Unwind-EHABI.h new file mode 100644 index 0000000..6897082 --- /dev/null +++ b/libunwind/src/Unwind-EHABI.h @@ -0,0 +1,50 @@ +//===------------------------- Unwind-EHABI.hpp ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +//===----------------------------------------------------------------------===// + +#ifndef __UNWIND_EHABI_H__ +#define __UNWIND_EHABI_H__ + +#include <__libunwind_config.h> + +#if defined(_LIBUNWIND_ARM_EHABI) + +#include +#include + +// Unable to unwind in the ARM index table (section 5 EHABI). +#define UNW_EXIDX_CANTUNWIND 0x1 + +static inline uint32_t signExtendPrel31(uint32_t data) { + return data | ((data & 0x40000000u) << 1); +} + +static inline uint32_t readPrel31(const uint32_t *data) { + return (((uint32_t)(uintptr_t)data) + signExtendPrel31(*data)); +} + +#if defined(__cplusplus) +extern "C" { +#endif + +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( + _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); + +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( + _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); + +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( + _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // defined(_LIBUNWIND_ARM_EHABI) + +#endif // __UNWIND_EHABI_H__ diff --git a/libunwind/src/Unwind-seh.cpp b/libunwind/src/Unwind-seh.cpp new file mode 100644 index 0000000..403ab2d --- /dev/null +++ b/libunwind/src/Unwind-seh.cpp @@ -0,0 +1,501 @@ +//===--------------------------- Unwind-seh.cpp ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements SEH-based Itanium C++ exceptions. +// +//===----------------------------------------------------------------------===// + +#include "config.h" + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "libunwind_ext.h" +#include "UnwindCursor.hpp" + +using namespace libunwind; + +#define STATUS_USER_DEFINED (1u << 29) + +#define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') + +#define MAKE_CUSTOM_STATUS(s, c) \ + ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c))) +#define MAKE_GCC_EXCEPTION(c) \ + MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24)) + +/// SEH exception raised by libunwind when the program calls +/// \c _Unwind_RaiseException. +#define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343 +/// SEH exception raised by libunwind to initiate phase 2 of exception +/// handling. +#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 + +/// Class of foreign exceptions based on unrecognized SEH exceptions. +static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0 + +/// Exception cleanup routine used by \c _GCC_specific_handler to +/// free foreign exceptions. +static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) { + (void)urc; + if (exc->exception_class != kSEHExceptionClass) + _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception"); + free(exc); +} + +static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); +static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor); +static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, + DISPATCHER_CONTEXT *disp); + +/// Common implementation of SEH-style handler functions used by Itanium- +/// style frames. Depending on how and why it was called, it may do one of: +/// a) Delegate to the given Itanium-style personality function; or +/// b) Initiate a collided unwind to halt unwinding. +_LIBUNWIND_EXPORT EXCEPTION_DISPOSITION +_GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, + DISPATCHER_CONTEXT *disp, _Unwind_Personality_Fn pers) { + unw_cursor_t cursor; + _Unwind_Exception *exc; + _Unwind_Action action; + struct _Unwind_Context *ctx = nullptr; + _Unwind_Reason_Code urc; + uintptr_t retval, target; + bool ours = false; + + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)", + ms_exc->ExceptionCode, ms_exc->ExceptionFlags, + (void *)frame); + if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { + if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { + // Set up the upper return value (the lower one and the target PC + // were set in the call to RtlUnwindEx()) for the landing pad. +#ifdef __x86_64__ + disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; +#elif defined(__arm__) + disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; +#elif defined(__aarch64__) + disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; +#endif + } + // This is the collided unwind to the landing pad. Nothing to do. + return ExceptionContinueSearch; + } + + if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { + // This is (probably) a libunwind-controlled exception/unwind. Recover the + // parameters which we set below, and pass them to the personality function. + ours = true; + exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; + if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { + ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; + action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; + } + } else { + // Foreign exception. + exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception)); + exc->exception_class = kSEHExceptionClass; + exc->exception_cleanup = seh_exc_cleanup; + memset(exc->private_, 0, sizeof(exc->private_)); + } + if (!ctx) { + __unw_init_seh(&cursor, disp->ContextRecord); + __unw_seh_set_disp_ctx(&cursor, disp); + __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1); + ctx = (struct _Unwind_Context *)&cursor; + + if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { + if (ours && ms_exc->NumberParameters > 1) + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); + else + action = _UA_SEARCH_PHASE; + } else { + if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); + else + action = _UA_CLEANUP_PHASE; + } + } + + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality " + "function %p(1, %d, %llx, %p, %p)", + (void *)pers, action, exc->exception_class, + (void *)exc, (void *)ctx); + urc = pers(1, action, exc->exception_class, exc, ctx); + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); + switch (urc) { + case _URC_CONTINUE_UNWIND: + // If we're in phase 2, and the personality routine said to continue + // at the target frame, we're in real trouble. + if (action & _UA_HANDLER_FRAME) + _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); + return ExceptionContinueSearch; + case _URC_HANDLER_FOUND: + // If we were called by __libunwind_seh_personality(), indicate that + // a handler was found; otherwise, initiate phase 2 by unwinding. + if (ours && ms_exc->NumberParameters > 1) + return 4 /* ExecptionExecuteHandler in mingw */; + // This should never happen in phase 2. + if (IS_UNWINDING(ms_exc->ExceptionFlags)) + _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); + exc->private_[1] = (ULONG_PTR)frame; + if (ours) { + ms_exc->NumberParameters = 4; + ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; + } + // FIXME: Indicate target frame in foreign case! + // phase 2: the clean up phase + RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); + _LIBUNWIND_ABORT("RtlUnwindEx() failed"); + case _URC_INSTALL_CONTEXT: { + // If we were called by __libunwind_seh_personality(), indicate that + // a handler was found; otherwise, it's time to initiate a collided + // unwind to the target. + if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) + return 4 /* ExecptionExecuteHandler in mingw */; + // This should never happen in phase 1. + if (!IS_UNWINDING(ms_exc->ExceptionFlags)) + _LIBUNWIND_ABORT("Personality installed context during phase 1!"); +#ifdef __x86_64__ + exc->private_[2] = disp->TargetIp; + __unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); + __unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); +#elif defined(__arm__) + exc->private_[2] = disp->TargetPc; + __unw_get_reg(&cursor, UNW_ARM_R0, &retval); + __unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); +#elif defined(__aarch64__) + exc->private_[2] = disp->TargetPc; + __unw_get_reg(&cursor, UNW_ARM64_X0, &retval); + __unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]); +#endif + __unw_get_reg(&cursor, UNW_REG_IP, &target); + ms_exc->ExceptionCode = STATUS_GCC_UNWIND; +#ifdef __x86_64__ + ms_exc->ExceptionInformation[2] = disp->TargetIp; +#elif defined(__arm__) || defined(__aarch64__) + ms_exc->ExceptionInformation[2] = disp->TargetPc; +#endif + ms_exc->ExceptionInformation[3] = exc->private_[3]; + // Give NTRTL some scratch space to keep track of the collided unwind. + // Don't use the one that was passed in; we don't want to overwrite the + // context in the DISPATCHER_CONTEXT. + CONTEXT new_ctx; + RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); + _LIBUNWIND_ABORT("RtlUnwindEx() failed"); + } + // Anything else indicates a serious problem. + default: return ExceptionContinueExecution; + } +} + +/// Personality function returned by \c __unw_get_proc_info() in SEH contexts. +/// This is a wrapper that calls the real SEH handler function, which in +/// turn (at least, for Itanium-style frames) calls the real Itanium +/// personality function (see \c _GCC_specific_handler()). +extern "C" _Unwind_Reason_Code +__libunwind_seh_personality(int version, _Unwind_Action state, + uint64_t klass, _Unwind_Exception *exc, + struct _Unwind_Context *context) { + (void)version; + (void)klass; + EXCEPTION_RECORD ms_exc; + bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = 0; + ms_exc.NumberParameters = 3; + ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; + ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; + ms_exc.ExceptionInformation[2] = state; + DISPATCHER_CONTEXT *disp_ctx = + __unw_seh_get_disp_ctx((unw_cursor_t *)context); + EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, + (PVOID)disp_ctx->EstablisherFrame, + disp_ctx->ContextRecord, + disp_ctx); + switch (ms_act) { + case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; + case 4 /*ExceptionExecuteHandler*/: + return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; + default: + return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; + } +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, + _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + unw_cursor_t cursor2; + __unw_init_local(&cursor2, uc); + + // Walk each frame until we reach where search phase said to stop + while (__unw_step(&cursor2) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 + ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + __unw_resume(&cursor2); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + +/// Called by \c __cxa_throw(). Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + (void *)exception_object); + + // Mark that this is a non-forced unwind, so _Unwind_Resume() + // can do the right thing. + memset(exception_object->private_, 0, sizeof(exception_object->private_)); + + // phase 1: the search phase + // We'll let the system do that for us. + RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); + + // If we get here, either something went horribly wrong or we reached the + // top of the stack. Either way, let libc++abi call std::terminate(). + return _URC_END_OF_STACK; +} + +/// When \c _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function; the landing +/// pad code may then call \c _Unwind_Resume() to continue with the +/// unwinding. Note: the call to \c _Unwind_Resume() is from compiler +/// geneated user code. All other \c _Unwind_* routines are called +/// by the C++ runtime \c __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call \c __cxa_rethrow() which +/// in turn calls \c _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); + + if (exception_object->private_[0] != 0) { + unw_context_t uc; + + __unw_getcontext(&uc); + unwind_phase2_forced(&uc, exception_object, + (_Unwind_Stop_Fn) exception_object->private_[0], + (void *)exception_object->private_[4]); + } else { + // Recover the parameters for the unwind from the exception object + // so we can start unwinding again. + EXCEPTION_RECORD ms_exc; + CONTEXT ms_ctx; + UNWIND_HISTORY_TABLE hist; + + memset(&ms_exc, 0, sizeof(ms_exc)); + memset(&hist, 0, sizeof(hist)); + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ms_exc.NumberParameters = 4; + ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; + ms_exc.ExceptionInformation[1] = exception_object->private_[1]; + ms_exc.ExceptionInformation[2] = exception_object->private_[2]; + ms_exc.ExceptionInformation[3] = exception_object->private_[3]; + RtlUnwindEx((PVOID)exception_object->private_[1], + (PVOID)exception_object->private_[2], &ms_exc, + exception_object, &ms_ctx, &hist); + } + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement \c longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + __unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->private_[0] = (uintptr_t) stop; + exception_object->private_[4] = (uintptr_t) stop_parameter; + + // do it + return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); +} + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + uintptr_t result = + (uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context); + uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { +#ifdef _LIBUNWIND_TARGET_X86_64 + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#elif defined(_LIBUNWIND_TARGET_ARM) + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#else + return UNW_EINVAL; +#endif +} + +static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) { +#ifdef _LIBUNWIND_TARGET_X86_64 + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#elif defined(_LIBUNWIND_TARGET_ARM) + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#else + return nullptr; +#endif +} + +static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, + DISPATCHER_CONTEXT *disp) { +#ifdef _LIBUNWIND_TARGET_X86_64 + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#elif defined(_LIBUNWIND_TARGET_ARM) + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#endif +} + +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) diff --git a/libunwind/src/Unwind-sjlj.c b/libunwind/src/Unwind-sjlj.c index b44937d..85a4cc3 100644 --- a/libunwind/src/Unwind-sjlj.c +++ b/libunwind/src/Unwind-sjlj.c @@ -1,491 +1,516 @@ -/* -*- mode: C++; c-basic-offset: 4; -*- - * - * Copyright (c) 2008-2011 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * - * Implements setjump-longjump based C++ exceptions - * - */ +//===--------------------------- Unwind-sjlj.c ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements setjump-longjump based C++ exceptions +// +//===----------------------------------------------------------------------===// +#include + +#include #include #include #include -#include -#include -#include -#include -#if !FOR_DYLD - #include -#endif -#include "unwind.h" -#include "InternalMacros.h" -// -// ARM uses setjump/longjump based C++ exceptions. -// Other architectures use "zero cost" exceptions. -// -// With SJLJ based exceptions any function that has a catch clause or needs to do any clean up when -// an exception propagates through it, needs to call _Unwind_SjLj_Register() at the start of the -// function and _Unwind_SjLj_Unregister() at the end. The register function is called with the -// address of a block of memory in the function's stack frame. The runtime keeps a linked list -// (stack) of these blocks - one per thread. The calling function also sets the personality -// and lsda fields of the block. -// -// -#if __arm__ +#include "config.h" -struct _Unwind_FunctionContext -{ - // next function in stack of handlers - struct _Unwind_FunctionContext* prev; +/// With SJLJ based exceptions, any function that has a catch clause or needs to +/// do any clean up when an exception propagates through it, needs to call +/// \c _Unwind_SjLj_Register at the start of the function and +/// \c _Unwind_SjLj_Unregister at the end. The register function is called with +/// the address of a block of memory in the function's stack frame. The runtime +/// keeps a linked list (stack) of these blocks - one per thread. The calling +/// function also sets the personality and lsda fields of the block. - // set by calling function before registering to be the landing pad - uintptr_t resumeLocation; - - // set by personality handler to be parameters passed to landing pad function - uintptr_t resumeParameters[4]; +#if defined(_LIBUNWIND_BUILD_SJLJ_APIS) - // set by calling function before registering - __personality_routine personality; // arm offset=24 - uintptr_t lsda; // arm offset=28 +struct _Unwind_FunctionContext { + // next function in stack of handlers + struct _Unwind_FunctionContext *prev; - // variable length array, contains registers to restore - // 0 = r7, 1 = pc, 2 = sp - void* jbuf[]; + // set by calling function before registering to be the landing pad + uint32_t resumeLocation; + + // set by personality handler to be parameters passed to landing pad function + uint32_t resumeParameters[4]; + + // set by calling function before registering + _Unwind_Personality_Fn personality; // arm offset=24 + uintptr_t lsda; // arm offset=28 + + // variable length array, contains registers to restore + // 0 = r7, 1 = pc, 2 = sp + void *jbuf[]; }; - -#if FOR_DYLD - // implemented in dyld - extern struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack(); - extern void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc); +#if defined(_LIBUNWIND_HAS_NO_THREADS) +# define _LIBUNWIND_THREAD_LOCAL #else - static struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack() - { - return (struct _Unwind_FunctionContext*)_pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); - } - - static void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc) - { - _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); - } +# if __STDC_VERSION__ >= 201112L +# define _LIBUNWIND_THREAD_LOCAL _Thread_local +# elif defined(_MSC_VER) +# define _LIBUNWIND_THREAD_LOCAL __declspec(thread) +# elif defined(__GNUC__) || defined(__clang__) +# define _LIBUNWIND_THREAD_LOCAL __thread +# else +# error Unable to create thread local storage +# endif #endif -// -// Called at start of each function that catches exceptions -// -EXPORT void _Unwind_SjLj_Register(struct _Unwind_FunctionContext* fc) -{ - fc->prev = __Unwind_SjLj_GetTopOfFunctionStack(); - __Unwind_SjLj_SetTopOfFunctionStack(fc); +#if !defined(FOR_DYLD) + +#if defined(__APPLE__) +#include +#else +static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL; +#endif + +static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { +#if defined(__APPLE__) + return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); +#else + return stack; +#endif +} + +static void +__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { +#if defined(__APPLE__) + _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); +#else + stack = fc; +#endif +} + +#endif + + +/// Called at start of each function that catches exceptions +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) { + fc->prev = __Unwind_SjLj_GetTopOfFunctionStack(); + __Unwind_SjLj_SetTopOfFunctionStack(fc); } -// -// Called at end of each function that catches exceptions -// -EXPORT void _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext* fc) -{ - __Unwind_SjLj_SetTopOfFunctionStack(fc->prev); +/// Called at end of each function that catches exceptions +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) { + __Unwind_SjLj_SetTopOfFunctionStack(fc->prev); } -static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception* exception_object) -{ - _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); - DEBUG_PRINT_UNWINDING("unwind_phase1: initial function-context=%p\n", c); +static _Unwind_Reason_Code +unwind_phase1(struct _Unwind_Exception *exception_object) { + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p", + (void *)c); - // walk each frame looking for a place to stop - for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { + // walk each frame looking for a place to stop + for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { - // check for no more frames - if ( c == NULL ) { - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): reached bottom => _URC_END_OF_STACK\n", exception_object); - return _URC_END_OF_STACK; - } - - DEBUG_PRINT_UNWINDING("unwind_phase1: function-context=%p\n", c); - // if there is a personality routine, ask it if it will want to stop at this frame - if ( c->personality != NULL ) { - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, c->personality); - _Unwind_Reason_Code personalityResult = (*c->personality)(1, _UA_SEARCH_PHASE, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)c); - switch ( personalityResult ) { - case _URC_HANDLER_FOUND: - // found a catch clause or locals that need destructing in this frame - // stop search and remember function context - handlerNotFound = false; - exception_object->private_2 = (uintptr_t)c; - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object); - return _URC_NO_REASON; - - case _URC_CONTINUE_UNWIND: - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); - // continue unwinding - break; - - default: - // something went wrong - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object); - return _URC_FATAL_PHASE1_ERROR; - } - } - } - return _URC_NO_REASON; + // check for no more frames + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c); + // if there is a personality routine, ask it if it will want to stop at this + // frame + if (c->personality != NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling " + "personality function %p", + (void *)exception_object, + (void *)c->personality); + _Unwind_Reason_Code personalityResult = (*c->personality)( + 1, _UA_SEARCH_PHASE, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember function context + handlerNotFound = false; + exception_object->private_2 = (uintptr_t) c; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_HANDLER_FOUND", + (void *)exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // continue unwinding + break; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; } -static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); - - // walk each frame until we reach where search phase said to stop - _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); - while ( true ) { - DEBUG_PRINT_UNWINDING("unwind_phase2s(ex_ojb=%p): function-context=%p\n", exception_object, c); +static _Unwind_Reason_Code +unwind_phase2(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", + (void *)exception_object); - // check for no more frames - if ( c == NULL ) { - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object); - return _URC_END_OF_STACK; - } - - // if there is a personality routine, tell it we are unwinding - if ( c->personality != NULL ) { - _Unwind_Action action = _UA_CLEANUP_PHASE; - if ( (uintptr_t)c == exception_object->private_2 ) - action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1 - _Unwind_Reason_Code personalityResult = (*c->personality)(1, action, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)c); - switch ( personalityResult ) { - case _URC_CONTINUE_UNWIND: - // continue unwinding - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); - if ( (uintptr_t)c == exception_object->private_2 ) { - // phase 1 said we would stop at this frame, but we did not... - ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here"); - } - break; - case _URC_INSTALL_CONTEXT: - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT, will resume at landing pad %p\n", exception_object, c->jbuf[1]); - // personality routine says to transfer control to landing pad - // we may get control back if landing pad calls _Unwind_Resume() - __Unwind_SjLj_SetTopOfFunctionStack(c); - __builtin_longjmp(c->jbuf, 1); - // unw_resume() only returns if there was an error - return _URC_FATAL_PHASE2_ERROR; - default: - // something went wrong - DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult); - return _URC_FATAL_PHASE2_ERROR; - } - } - c = c->prev; - } + // walk each frame until we reach where search phase said to stop + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + while (true) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p", + (void *)exception_object, (void *)c); - // clean up phase did not resume at the frame that the search phase said it would - return _URC_FATAL_PHASE2_ERROR; + // check for no more frames + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } + + // if there is a personality routine, tell it we are unwinding + if (c->personality != NULL) { + _Unwind_Action action = _UA_CLEANUP_PHASE; + if ((uintptr_t) c == exception_object->private_2) + action = (_Unwind_Action)( + _UA_CLEANUP_PHASE | + _UA_HANDLER_FRAME); // tell personality this was the frame it marked + // in phase 1 + _Unwind_Reason_Code personalityResult = + (*c->personality)(1, action, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", + (void *)exception_object); + if ((uintptr_t) c == exception_object->private_2) { + // phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now if phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " + "_URC_INSTALL_CONTEXT, will resume at " + "landing pad %p", + (void *)exception_object, c->jbuf[1]); + // personality routine says to transfer control to landing pad + // we may get control back if landing pad calls _Unwind_Resume() + __Unwind_SjLj_SetTopOfFunctionStack(c); + __builtin_longjmp(c->jbuf, 1); + // __unw_resume() only returns if there was an error + return _URC_FATAL_PHASE2_ERROR; + default: + // something went wrong + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + c = c->prev; + } + + // clean up phase did not resume at the frame that the search phase said it + // would + return _URC_FATAL_PHASE2_ERROR; } -static _Unwind_Reason_Code unwind_phase2_forced(struct _Unwind_Exception* exception_object, - _Unwind_Stop_Fn stop, void* stop_parameter) -{ - // walk each frame until we reach where search phase said to stop - _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); - while ( true ) { +static _Unwind_Reason_Code +unwind_phase2_forced(struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + // walk each frame until we reach where search phase said to stop + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + while (true) { - // get next frame (skip over first which is _Unwind_RaiseException) - if ( c == NULL ) { - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object); - return _URC_END_OF_STACK; - } - - // call stop function at each frame - _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE); - _Unwind_Reason_Code stopResult = (*stop)(1, action, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)c, stop_parameter); - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult); - if ( stopResult != _URC_NO_REASON ) { - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object); - return _URC_FATAL_PHASE2_ERROR; - } - - // if there is a personality routine, tell it we are unwinding - if ( c->personality != NULL ) { - __personality_routine p = (__personality_routine)c->personality; - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p); - _Unwind_Reason_Code personalityResult = (*p)(1, action, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)c); - switch ( personalityResult ) { - case _URC_CONTINUE_UNWIND: - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object); - // destructors called, continue unwinding - break; - case _URC_INSTALL_CONTEXT: - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object); - // we may get control back if landing pad calls _Unwind_Resume() - __Unwind_SjLj_SetTopOfFunctionStack(c); - __builtin_longjmp(c->jbuf, 1); - break; - default: - // something went wrong - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n", - exception_object, personalityResult); - return _URC_FATAL_PHASE2_ERROR; - } - } - c = c->prev; - } + // get next frame (skip over first which is _Unwind_RaiseException) + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } - // call stop function one last time and tell it we've reached the end of the stack - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object); - _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK); - (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)c, stop_parameter); - - // clean up phase did not resume at the frame that the search phase said it would - return _URC_FATAL_PHASE2_ERROR; + // call stop function at each frame + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c, stop_parameter); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // if there is a personality routine, tell it we are unwinding + if (c->personality != NULL) { + _Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "calling personality function %p", + (void *)exception_object, (void *)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_CONTINUE_UNWIND", + (void *)exception_object); + // destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_INSTALL_CONTEXT", + (void *)exception_object); + // we may get control back if landing pad calls _Unwind_Resume() + __Unwind_SjLj_SetTopOfFunctionStack(c); + __builtin_longjmp(c->jbuf, 1); + break; + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + c = c->prev; + } + + // call stop function one last time and tell it we've reached the end of the + // stack + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c, stop_parameter); + + // clean up phase did not resume at the frame that the search phase said it + // would + return _URC_FATAL_PHASE2_ERROR; } -// -// Called by __cxa_throw. Only returns if there is a fatal error -// -EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object); +/// Called by __cxa_throw. Only returns if there is a fatal error +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)", + (void *)exception_object); - // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing - exception_object->private_1 = 0; - exception_object->private_2 = 0; + // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right + // thing + exception_object->private_1 = 0; + exception_object->private_2 = 0; - // phase 1: the search phase - _Unwind_Reason_Code phase1 = unwind_phase1(exception_object); - if ( phase1 != _URC_NO_REASON ) - return phase1; - - // phase 2: the clean up phase - return unwind_phase2(exception_object); -} + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; - -// -// When _Unwind_RaiseException() is in phase2, it hands control -// to the personality function at each frame. The personality -// may force a jump to a landing pad in that function, the landing -// pad code may then call _Unwind_Resume() to continue with the -// unwinding. Note: the call to _Unwind_Resume() is from compiler -// geneated user code. All other _Unwind_* routines are called -// by the C++ runtime __cxa_* routines. -// -// Re-throwing an exception is implemented by having the code call -// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() -// -EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object); - - if ( exception_object->private_1 != 0 ) - unwind_phase2_forced(exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2); - else - unwind_phase2(exception_object); - - // clients assume _Unwind_Resume() does not return, so all we can do is abort. - ABORT("_Unwind_SjLj_Resume() can't return"); -} - - -// -// Called by __cxa_rethrow() -// -EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1); - // if this is non-forced and a stopping place was found, then this is a re-throw - // call _Unwind_RaiseException() as if this was a new exception - if ( exception_object->private_1 == 0 ) { - return _Unwind_SjLj_RaiseException(exception_object); - // should return if there is no catch clause, so that __cxa_rethrow can call std::terminate() - } - - // call through to _Unwind_Resume() which distiguishes between forced and regular exceptions - _Unwind_SjLj_Resume(exception_object); - ABORT("__Unwind_SjLj_Resume_or_Rethrow() called _Unwind_SjLj_Resume() which unexpectedly returned"); -} - - -// -// Called by personality handler during phase 2 to get LSDA for current frame -// -EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context) -{ - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%0lX\n", context, ufc->lsda); - return ufc->lsda; -} - - -// -// Called by personality handler during phase 2 to get register values -// -EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index) -{ - DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d)\n", context, index); - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - return ufc->resumeParameters[index]; + // phase 2: the clean up phase + return unwind_phase2(exception_object); } -// -// Called by personality handler during phase 2 to alter register values -// -EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value) -{ - DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n", context, index, new_value); - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - ufc->resumeParameters[index] = new_value; +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Re-throwing an exception is implemented by having the code call +/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)", + (void *)exception_object); + + if (exception_object->private_1 != 0) + unwind_phase2_forced(exception_object, + (_Unwind_Stop_Fn) exception_object->private_1, + (void *)exception_object->private_2); + else + unwind_phase2(exception_object); + + // clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return"); } -// -// Called by personality handler during phase 2 to get instruction pointer -// -EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context) -{ - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, ufc->resumeLocation+1); - return ufc->resumeLocation+1; -} +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " + "private_1=%" PRIuPTR, + (void *)exception_object, exception_object->private_1); + // If this is non-forced and a stopping place was found, then this is a + // re-throw. + // Call _Unwind_RaiseException() as if this was a new exception. + if (exception_object->private_1 == 0) { + return _Unwind_SjLj_RaiseException(exception_object); + // should return if there is no catch clause, so that __cxa_rethrow can call + // std::terminate() + } -// -// Called by personality handler during phase 2 to get instruction pointer -// ipBefore is a boolean that says if IP is already adjusted to be the call -// site address. Normally IP is the return address. -// -EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore) -{ - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - *ipBefore = 0; - DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", context, ipBefore, ufc->resumeLocation+1); - return ufc->resumeLocation+1; + // Call through to _Unwind_Resume() which distiguishes between forced and + // regular exceptions. + _Unwind_SjLj_Resume(exception_object); + _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called " + "_Unwind_SjLj_Resume() which unexpectedly returned"); } -// -// Called by personality handler during phase 2 to alter instruction pointer -// -EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value) -{ - DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", context, new_value); - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - ufc->resumeLocation = new_value-1; -} - -// -// Called by personality handler during phase 2 to find the start of the function -// -EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context) -{ - // Not supported or needed for sjlj based unwinding - DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p)\n", context); - return 0; -} - -// -// Called by personality handler during phase 2 if a foreign exception is caught -// -EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object); - if ( exception_object->exception_cleanup != NULL ) - (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object); +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) " + "=> 0x%" PRIuPTR, + (void *)context, ufc->lsda); + return ufc->lsda; } -// -// Called by personality handler during phase 2 to get base address for data relative encodings -// -EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) -{ - // Not supported or needed for sjlj based unwinding - DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context); - ABORT("_Unwind_GetDataRelBase() not implemented"); +/// Called by personality handler during phase 2 to get register values. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, + int index) { + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context, + index); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + return ufc->resumeParameters[index]; } -// -// Called by personality handler during phase 2 to get base address for text relative encodings -// -EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) -{ - // Not supported or needed for sjlj based unwinding - DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context); - ABORT("_Unwind_GetTextRelBase() not implemented"); +/// Called by personality handler during phase 2 to alter register values. +_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR + ")", + (void *)context, index, new_value); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + ufc->resumeParameters[index] = new_value; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32, + (void *)context, ufc->resumeLocation + 1); + return ufc->resumeLocation + 1; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +/// ipBefore is a boolean that says if IP is already adjusted to be the call +/// site address. Normally IP is the return address. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + *ipBefore = 0; + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32, + (void *)context, (void *)ipBefore, + ufc->resumeLocation + 1); + return ufc->resumeLocation + 1; +} + + +/// Called by personality handler during phase 2 to alter instruction pointer. +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")", + (void *)context, new_value); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + ufc->resumeLocation = new_value - 1; +} + + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context); + return 0; +} + + +/// Called by personality handler during phase 2 if a foreign exception +/// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", + (void *)exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); } -// -// Called by personality handler to get Call Frame Area for current frame -// -EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context) -{ - DEBUG_PRINT_API("_Unwind_GetCFA(context=%p)\n", context); - if ( context != NULL ) { - _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context; - // setjmp/longjmp based exceptions don't have a true CFA - // the SP in the jmpbuf is the closest approximation - return (uintptr_t)ufc->jbuf[2]; - } - return 0; +/// Called by personality handler during phase 2 to get base address for data +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetDataRelBase(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); } - -#if !FOR_DYLD && __IPHONE_OS_VERSION_MIN_REQUIRED -// -// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in earlier versions -// -NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData) -NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart) -NOT_HERE_BEFORE_5_0(_Unwind_GetIP) -NOT_HERE_BEFORE_5_0(_Unwind_SetGR) -NOT_HERE_BEFORE_5_0(_Unwind_SetIP) -NOT_HERE_BEFORE_5_0(_Unwind_DeleteException) -NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register) -NOT_HERE_BEFORE_5_0(_Unwind_GetGR) -NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo) -NOT_HERE_BEFORE_5_0(_Unwind_GetCFA) -NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume) -NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException) -NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) -NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) -#endif // !FOR_DYLD +/// Called by personality handler during phase 2 to get base address for text +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetTextRelBase(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); +} -#endif // __arm__ +/// Called by personality handler to get "Call Frame Area" for current frame. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context); + if (context != NULL) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + // Setjmp/longjmp based exceptions don't have a true CFA. + // Instead, the SP in the jmpbuf is the closest approximation. + return (uintptr_t) ufc->jbuf[2]; + } + return 0; +} + +#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index b86a329..ac04019 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1,30 +1,12 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2007-2009 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - +//===------------------------- UnwindCursor.hpp ---------------------------===// // -// C++ interface to lower levels of libuwind +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// +// C++ interface to lower levels of libunwind +//===----------------------------------------------------------------------===// #ifndef __UNWINDCURSOR_HPP__ #define __UNWINDCURSOR_HPP__ @@ -32,881 +14,2047 @@ #include #include #include -#include -#include +#include -#include "libunwind.h" - -#include "AddressSpace.hpp" -#include "Registers.hpp" -#include "DwarfInstructions.hpp" -#include "CompactUnwinder.hpp" -#include "InternalMacros.h" - -#if __MAC_OS_X_VERSION_MIN_REQUIRED - #define KEYMGR_SUPPPORT 1 -#else - #define KEYMGR_SUPPPORT 0 +#ifdef _WIN32 + #include + #include +#endif +#ifdef __APPLE__ + #include #endif +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and +// earlier) SDKs. +// MinGW-w64 has always provided this struct. + #if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \ + !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 +struct _DISPATCHER_CONTEXT { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + PEXCEPTION_ROUTINE LanguageHandler; + PVOID HandlerData; + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; +}; + #endif -#if KEYMGR_SUPPPORT -// private keymgr stuff -#define KEYMGR_GCC3_DW2_OBJ_LIST 302 -extern "C" { - extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr); - extern void* _keymgr_get_and_lock_processwide_ptr(int key); +struct UNWIND_INFO { + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + uint16_t UnwindCodes[2]; }; -// undocumented libgcc "struct object" -struct libgcc_object -{ - void* start; - void* unused1; - void* unused2; - void* fde; - unsigned long encoding; - void* fde_end; - libgcc_object* next; -}; +extern "C" _Unwind_Reason_Code __libunwind_seh_personality( + int, _Unwind_Action, uint64_t, _Unwind_Exception *, + struct _Unwind_Context *); -// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST -struct libgcc_object_info { - struct libgcc_object* seen_objects; - struct libgcc_object* unseen_objects; - unsigned spare[2]; -}; -#endif // KEYMGR_SUPPPORT +#endif +#include "config.h" + +#include "AddressSpace.hpp" +#include "CompactUnwinder.hpp" +#include "config.h" +#include "DwarfInstructions.hpp" +#include "EHHeaderParser.hpp" +#include "libunwind.h" +#include "Registers.hpp" +#include "RWMutex.hpp" +#include "Unwind-EHABI.h" namespace libunwind { -#if !FOR_DYLD +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +/// Cache of recently found FDEs. template -class DwarfFDECache -{ +class _LIBUNWIND_HIDDEN DwarfFDECache { + typedef typename A::pint_t pint_t; public: - typedef typename A::pint_t pint_t; - static pint_t findFDE(pint_t mh, pint_t pc); - static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); - static void removeAllIn(pint_t mh); - static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); -private: - static void dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide); - - struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; }; + static constexpr pint_t kSearchAll = static_cast(-1); + static pint_t findFDE(pint_t mh, pint_t pc); + static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); + static void removeAllIn(pint_t mh); + static void iterateCacheEntries(void (*func)(unw_word_t ip_start, + unw_word_t ip_end, + unw_word_t fde, unw_word_t mh)); - // these fields are all static to avoid needing an initializer - // there is only one instance of this class per process - static pthread_rwlock_t fgLock; - static bool fgRegisteredForDyldUnloads; - // can't use std::vector<> here because this code must live in libSystem.dylib (which is below libstdc++.dylib) - static entry* fgBuffer; - static entry* fgBufferUsed; - static entry* fgBufferEnd; - static entry fgInitialBuffer[64]; +private: + + struct entry { + pint_t mh; + pint_t ip_start; + pint_t ip_end; + pint_t fde; + }; + + // These fields are all static to avoid needing an initializer. + // There is only one instance of this class per process. + static RWMutex _lock; +#ifdef __APPLE__ + static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); + static bool _registeredForDyldUnloads; +#endif + static entry *_buffer; + static entry *_bufferUsed; + static entry *_bufferEnd; + static entry _initialBuffer[64]; }; -template typename DwarfFDECache::entry* DwarfFDECache::fgBuffer = fgInitialBuffer; -template typename DwarfFDECache::entry* DwarfFDECache::fgBufferUsed = fgInitialBuffer; -template typename DwarfFDECache::entry* DwarfFDECache::fgBufferEnd = &fgInitialBuffer[64]; -template typename DwarfFDECache::entry DwarfFDECache::fgInitialBuffer[64]; +template +typename DwarfFDECache::entry * +DwarfFDECache::_buffer = _initialBuffer; template -pthread_rwlock_t DwarfFDECache::fgLock = PTHREAD_RWLOCK_INITIALIZER; - -template -bool DwarfFDECache::fgRegisteredForDyldUnloads = false; - +typename DwarfFDECache::entry * +DwarfFDECache::_bufferUsed = _initialBuffer; template -typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) -{ - pint_t result = NULL; - DEBUG_LOG_NON_ZERO(::pthread_rwlock_rdlock(&fgLock)); - for(entry* p=fgBuffer; p < fgBufferUsed; ++p) { - if ( (mh == p->mh) || (mh == 0) ) { - if ( (p->ip_start <= pc) && (pc < p->ip_end) ) { - result = p->fde; - break; - } - } - } - DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); - //fprintf(stderr, "DwarfFDECache::findFDE(mh=0x%llX, pc=0x%llX) => 0x%llX\n", (uint64_t)mh, (uint64_t)pc, (uint64_t)result); - return result; +typename DwarfFDECache::entry * +DwarfFDECache::_bufferEnd = &_initialBuffer[64]; + +template +typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; + +template +RWMutex DwarfFDECache::_lock; + +#ifdef __APPLE__ +template +bool DwarfFDECache::_registeredForDyldUnloads = false; +#endif + +template +typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { + pint_t result = 0; + _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); + for (entry *p = _buffer; p < _bufferUsed; ++p) { + if ((mh == p->mh) || (mh == kSearchAll)) { + if ((p->ip_start <= pc) && (pc < p->ip_end)) { + result = p->fde; + break; + } + } + } + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared()); + return result; } template -void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde) -{ - //fprintf(stderr, "DwarfFDECache::add(mh=0x%llX, ip_start=0x%llX, ip_end=0x%llX, fde=0x%llX) pthread=%p\n", - // (uint64_t)mh, (uint64_t)ip_start, (uint64_t)ip_end, (uint64_t)fde, pthread_self()); - DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock)); - if ( fgBufferUsed >= fgBufferEnd ) { - int oldSize = fgBufferEnd - fgBuffer; - int newSize = oldSize*4; - entry* newBuffer = (entry*)malloc(newSize*sizeof(entry)); // can't use operator new in libSystem.dylib - memcpy(newBuffer, fgBuffer, oldSize*sizeof(entry)); - //fprintf(stderr, "DwarfFDECache::add() growing buffer to %d\n", newSize); - if ( fgBuffer != fgInitialBuffer ) - free(fgBuffer); - fgBuffer = newBuffer; - fgBufferUsed = &newBuffer[oldSize]; - fgBufferEnd = &newBuffer[newSize]; - } - fgBufferUsed->mh = mh; - fgBufferUsed->ip_start = ip_start; - fgBufferUsed->ip_end = ip_end; - fgBufferUsed->fde = fde; - ++fgBufferUsed; - if ( !fgRegisteredForDyldUnloads ) { - _dyld_register_func_for_remove_image(&dyldUnloadHook); - fgRegisteredForDyldUnloads = true; - } - DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); -} - - - -template -void DwarfFDECache::removeAllIn(pint_t mh) -{ - DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock)); - entry* d=fgBuffer; - for(const entry* s=fgBuffer; s < fgBufferUsed; ++s) { - if ( s->mh != mh ) { - if ( d != s ) - *d = *s; - ++d; - } - } - fgBufferUsed = d; - DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); -} - - -template -void DwarfFDECache::dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide) -{ - removeAllIn((pint_t)mh); +void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, + pint_t fde) { +#if !defined(_LIBUNWIND_NO_HEAP) + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + if (_bufferUsed >= _bufferEnd) { + size_t oldSize = (size_t)(_bufferEnd - _buffer); + size_t newSize = oldSize * 4; + // Can't use operator new (we are below it). + entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); + memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); + if (_buffer != _initialBuffer) + free(_buffer); + _buffer = newBuffer; + _bufferUsed = &newBuffer[oldSize]; + _bufferEnd = &newBuffer[newSize]; + } + _bufferUsed->mh = mh; + _bufferUsed->ip_start = ip_start; + _bufferUsed->ip_end = ip_end; + _bufferUsed->fde = fde; + ++_bufferUsed; +#ifdef __APPLE__ + if (!_registeredForDyldUnloads) { + _dyld_register_func_for_remove_image(&dyldUnloadHook); + _registeredForDyldUnloads = true; + } +#endif + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +#endif } template -void DwarfFDECache::iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) -{ - DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock)); - for(entry* p=fgBuffer; p < fgBufferUsed; ++p) { - (*func)(p->ip_start, p->ip_end, p->fde, p->mh); - } - DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); +void DwarfFDECache::removeAllIn(pint_t mh) { + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + entry *d = _buffer; + for (const entry *s = _buffer; s < _bufferUsed; ++s) { + if (s->mh != mh) { + if (d != s) + *d = *s; + ++d; + } + } + _bufferUsed = d; + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } -#endif // !FOR_DYLD +#ifdef __APPLE__ +template +void DwarfFDECache::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { + removeAllIn((pint_t) mh); +} +#endif +template +void DwarfFDECache::iterateCacheEntries(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + for (entry *p = _buffer; p < _bufferUsed; ++p) { + (*func)(p->ip_start, p->ip_end, p->fde, p->mh); + } + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +} +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) -template -class UnwindSectionHeader { +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) +template class UnwindSectionHeader { public: - UnwindSectionHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t version() const { + return _addressSpace.get32(_addr + + offsetof(unwind_info_section_header, version)); + } + uint32_t commonEncodingsArraySectionOffset() const { + return _addressSpace.get32(_addr + + offsetof(unwind_info_section_header, + commonEncodingsArraySectionOffset)); + } + uint32_t commonEncodingsArrayCount() const { + return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, + commonEncodingsArrayCount)); + } + uint32_t personalityArraySectionOffset() const { + return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, + personalityArraySectionOffset)); + } + uint32_t personalityArrayCount() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, personalityArrayCount)); + } + uint32_t indexSectionOffset() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, indexSectionOffset)); + } + uint32_t indexCount() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, indexCount)); + } - uint32_t version() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, version)); } - uint32_t commonEncodingsArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); } - uint32_t commonEncodingsArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); } - uint32_t personalityArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); } - uint32_t personalityArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArrayCount)); } - uint32_t indexSectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexSectionOffset)); } - uint32_t indexCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexCount)); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; }; -template -class UnwindSectionIndexArray { +template class UnwindSectionIndexArray { public: - UnwindSectionIndexArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + functionOffset)); + } + uint32_t secondLevelPagesSectionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + secondLevelPagesSectionOffset)); + } + uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + lsdaIndexArraySectionOffset)); + } - uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); } - uint32_t secondLevelPagesSectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); } - uint32_t lsdaIndexArraySectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; }; - -template -class UnwindSectionRegularPageHeader { +template class UnwindSectionRegularPageHeader { public: - UnwindSectionRegularPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t kind() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); + } + uint16_t entryPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_regular_second_level_page_header, + entryPageOffset)); + } + uint16_t entryCount() const { + return _addressSpace.get16( + _addr + + offsetof(unwind_info_regular_second_level_page_header, entryCount)); + } - uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_regular_second_level_page_header, kind)); } - uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); } - uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; }; - -template -class UnwindSectionRegularArray { +template class UnwindSectionRegularArray { public: - UnwindSectionRegularArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, + functionOffset)); + } + uint32_t encoding(uint32_t index) const { + return _addressSpace.get32( + _addr + + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); + } - uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); } - uint32_t encoding(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; }; - -template -class UnwindSectionCompressedPageHeader { +template class UnwindSectionCompressedPageHeader { public: - UnwindSectionCompressedPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t kind() const { + return _addressSpace.get32( + _addr + + offsetof(unwind_info_compressed_second_level_page_header, kind)); + } + uint16_t entryPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + entryPageOffset)); + } + uint16_t entryCount() const { + return _addressSpace.get16( + _addr + + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); + } + uint16_t encodingsPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + encodingsPageOffset)); + } + uint16_t encodingsCount() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + encodingsCount)); + } - uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_compressed_second_level_page_header, kind)); } - uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); } - uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); } - uint16_t encodingsPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); } - uint16_t encodingsCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; }; - -template -class UnwindSectionCompressedArray { +template class UnwindSectionCompressedArray { public: - UnwindSectionCompressedArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( + _addressSpace.get32(_addr + index * sizeof(uint32_t))); + } + uint16_t encodingIndex(uint32_t index) const { + return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( + _addressSpace.get32(_addr + index * sizeof(uint32_t))); + } - uint32_t functionOffset(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); } - uint16_t encodingIndex(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; }; - -template -class UnwindSectionLsdaArray { +template class UnwindSectionLsdaArray { public: - UnwindSectionLsdaArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} + UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, + index, functionOffset)); + } + uint32_t lsdaOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, + index, lsdaOffset)); + } - uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); } - int32_t lsdaOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); } private: - A& fAddressSpace; - typename A::pint_t fAddr; + A &_addressSpace; + typename A::pint_t _addr; +}; +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +class _LIBUNWIND_HIDDEN AbstractUnwindCursor { +public: + // NOTE: provide a class specific placement deallocation function (S5.3.4 p20) + // This avoids an unnecessary dependency to libc++abi. + void operator delete(void *, size_t) {} + + virtual ~AbstractUnwindCursor() {} + virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); } + virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); } + virtual void setReg(int, unw_word_t) { + _LIBUNWIND_ABORT("setReg not implemented"); + } + virtual bool validFloatReg(int) { + _LIBUNWIND_ABORT("validFloatReg not implemented"); + } + virtual unw_fpreg_t getFloatReg(int) { + _LIBUNWIND_ABORT("getFloatReg not implemented"); + } + virtual void setFloatReg(int, unw_fpreg_t) { + _LIBUNWIND_ABORT("setFloatReg not implemented"); + } + virtual int step() { _LIBUNWIND_ABORT("step not implemented"); } + virtual void getInfo(unw_proc_info_t *) { + _LIBUNWIND_ABORT("getInfo not implemented"); + } + virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); } + virtual bool isSignalFrame() { + _LIBUNWIND_ABORT("isSignalFrame not implemented"); + } + virtual bool getFunctionName(char *, size_t, unw_word_t *) { + _LIBUNWIND_ABORT("getFunctionName not implemented"); + } + virtual void setInfoBasedOnIPRegister(bool = false) { + _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented"); + } + virtual const char *getRegisterName(int) { + _LIBUNWIND_ABORT("getRegisterName not implemented"); + } +#ifdef __arm__ + virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } +#endif +}; + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) + +/// \c UnwindCursor contains all state (including all register values) during +/// an unwind. This is normally stack-allocated inside a unw_cursor_t. +template +class UnwindCursor : public AbstractUnwindCursor { + typedef typename A::pint_t pint_t; +public: + UnwindCursor(unw_context_t *context, A &as); + UnwindCursor(CONTEXT *context, A &as); + UnwindCursor(A &as, void *threadArg); + virtual ~UnwindCursor() {} + virtual bool validReg(int); + virtual unw_word_t getReg(int); + virtual void setReg(int, unw_word_t); + virtual bool validFloatReg(int); + virtual unw_fpreg_t getFloatReg(int); + virtual void setFloatReg(int, unw_fpreg_t); + virtual int step(); + virtual void getInfo(unw_proc_info_t *); + virtual void jumpto(); + virtual bool isSignalFrame(); + virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); + virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); + virtual const char *getRegisterName(int num); +#ifdef __arm__ + virtual void saveVFPAsX(); +#endif + + DISPATCHER_CONTEXT *getDispatcherContext() { return &_dispContext; } + void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; } + + // libunwind does not and should not depend on C++ library which means that we + // need our own defition of inline placement new. + static void *operator new(size_t, UnwindCursor *p) { return p; } + +private: + + pint_t getLastPC() const { return _dispContext.ControlPc; } + void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; } + RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { + _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc, + &_dispContext.ImageBase, + _dispContext.HistoryTable); + *base = _dispContext.ImageBase; + return _dispContext.FunctionEntry; + } + bool getInfoFromSEH(pint_t pc); + int stepWithSEHData() { + _dispContext.LanguageHandler = RtlVirtualUnwind(UNW_FLAG_UHANDLER, + _dispContext.ImageBase, + _dispContext.ControlPc, + _dispContext.FunctionEntry, + _dispContext.ContextRecord, + &_dispContext.HandlerData, + &_dispContext.EstablisherFrame, + NULL); + // Update some fields of the unwind info now, since we have them. + _info.lsda = reinterpret_cast(_dispContext.HandlerData); + if (_dispContext.LanguageHandler) { + _info.handler = reinterpret_cast(__libunwind_seh_personality); + } else + _info.handler = 0; + return UNW_STEP_SUCCESS; + } + + A &_addressSpace; + unw_proc_info_t _info; + DISPATCHER_CONTEXT _dispContext; + CONTEXT _msContext; + UNWIND_HISTORY_TABLE _histTable; + bool _unwindInfoMissing; }; template -class UnwindCursor -{ -public: - UnwindCursor(unw_context_t* context, A& as); - UnwindCursor(A& as, thread_t thread); - virtual ~UnwindCursor() {} - virtual bool validReg(int); - virtual uint64_t getReg(int); - virtual void setReg(int, uint64_t); - virtual bool validFloatReg(int); - virtual double getFloatReg(int); - virtual void setFloatReg(int, double); - virtual int step(); - virtual void getInfo(unw_proc_info_t*); - virtual void jumpto(); - virtual const char* getRegisterName(int num); - virtual bool isSignalFrame(); - virtual bool getFunctionName(char* buf, size_t bufLen, unw_word_t* offset); - virtual void setInfoBasedOnIPRegister(bool isReturnAddress=false); +UnwindCursor::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _unwindInfoMissing(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + static_assert((alignof(UnwindCursor) <= alignof(unw_cursor_t)), + "UnwindCursor<> requires more alignment than unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); + memset(&_histTable, 0, sizeof(_histTable)); + _dispContext.ContextRecord = &_msContext; + _dispContext.HistoryTable = &_histTable; + // Initialize MS context from ours. + R r(context); + _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT; +#if defined(_LIBUNWIND_TARGET_X86_64) + _msContext.Rax = r.getRegister(UNW_X86_64_RAX); + _msContext.Rcx = r.getRegister(UNW_X86_64_RCX); + _msContext.Rdx = r.getRegister(UNW_X86_64_RDX); + _msContext.Rbx = r.getRegister(UNW_X86_64_RBX); + _msContext.Rsp = r.getRegister(UNW_X86_64_RSP); + _msContext.Rbp = r.getRegister(UNW_X86_64_RBP); + _msContext.Rsi = r.getRegister(UNW_X86_64_RSI); + _msContext.Rdi = r.getRegister(UNW_X86_64_RDI); + _msContext.R8 = r.getRegister(UNW_X86_64_R8); + _msContext.R9 = r.getRegister(UNW_X86_64_R9); + _msContext.R10 = r.getRegister(UNW_X86_64_R10); + _msContext.R11 = r.getRegister(UNW_X86_64_R11); + _msContext.R12 = r.getRegister(UNW_X86_64_R12); + _msContext.R13 = r.getRegister(UNW_X86_64_R13); + _msContext.R14 = r.getRegister(UNW_X86_64_R14); + _msContext.R15 = r.getRegister(UNW_X86_64_R15); + _msContext.Rip = r.getRegister(UNW_REG_IP); + union { + v128 v; + M128A m; + } t; + t.v = r.getVectorRegister(UNW_X86_64_XMM0); + _msContext.Xmm0 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM1); + _msContext.Xmm1 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM2); + _msContext.Xmm2 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM3); + _msContext.Xmm3 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM4); + _msContext.Xmm4 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM5); + _msContext.Xmm5 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM6); + _msContext.Xmm6 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM7); + _msContext.Xmm7 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM8); + _msContext.Xmm8 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM9); + _msContext.Xmm9 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM10); + _msContext.Xmm10 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM11); + _msContext.Xmm11 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM12); + _msContext.Xmm12 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM13); + _msContext.Xmm13 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM14); + _msContext.Xmm14 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM15); + _msContext.Xmm15 = t.m; +#elif defined(_LIBUNWIND_TARGET_ARM) + _msContext.R0 = r.getRegister(UNW_ARM_R0); + _msContext.R1 = r.getRegister(UNW_ARM_R1); + _msContext.R2 = r.getRegister(UNW_ARM_R2); + _msContext.R3 = r.getRegister(UNW_ARM_R3); + _msContext.R4 = r.getRegister(UNW_ARM_R4); + _msContext.R5 = r.getRegister(UNW_ARM_R5); + _msContext.R6 = r.getRegister(UNW_ARM_R6); + _msContext.R7 = r.getRegister(UNW_ARM_R7); + _msContext.R8 = r.getRegister(UNW_ARM_R8); + _msContext.R9 = r.getRegister(UNW_ARM_R9); + _msContext.R10 = r.getRegister(UNW_ARM_R10); + _msContext.R11 = r.getRegister(UNW_ARM_R11); + _msContext.R12 = r.getRegister(UNW_ARM_R12); + _msContext.Sp = r.getRegister(UNW_ARM_SP); + _msContext.Lr = r.getRegister(UNW_ARM_LR); + _msContext.Pc = r.getRegister(UNW_ARM_IP); + for (int i = UNW_ARM_D0; i <= UNW_ARM_D31; ++i) { + union { + uint64_t w; + double d; + } d; + d.d = r.getFloatRegister(i); + _msContext.D[i - UNW_ARM_D0] = d.w; + } +#elif defined(_LIBUNWIND_TARGET_AARCH64) + for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i) + _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i); + _msContext.Sp = r.getRegister(UNW_REG_SP); + _msContext.Pc = r.getRegister(UNW_REG_IP); + for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i) + _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i); +#endif +} - void operator delete(void* p, size_t size) {} +template +UnwindCursor::UnwindCursor(CONTEXT *context, A &as) + : _addressSpace(as), _unwindInfoMissing(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); + memset(&_histTable, 0, sizeof(_histTable)); + _dispContext.ContextRecord = &_msContext; + _dispContext.HistoryTable = &_histTable; + _msContext = *context; +} -private: - typedef typename A::pint_t pint_t; - typedef uint32_t EncodedUnwindInfo; - bool getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart); - bool getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE); +template +bool UnwindCursor::validReg(int regNum) { + if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true; +#if defined(_LIBUNWIND_TARGET_X86_64) + if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true; +#elif defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true; +#endif + return false; +} - int stepWithDwarfFDE() - { return DwarfInstructions::stepWithDwarf(fAddressSpace, this->getReg(UNW_REG_IP), fInfo.unwind_info, fRegisters); } - - int stepWithCompactEncoding() { R dummy; return stepWithCompactEncoding(dummy); } - int stepWithCompactEncoding(Registers_x86_64&) - { return CompactUnwinder_x86_64::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); } - int stepWithCompactEncoding(Registers_x86&) - { return CompactUnwinder_x86::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); } - int stepWithCompactEncoding(Registers_ppc&) - { return UNW_EINVAL; } +template +unw_word_t UnwindCursor::getReg(int regNum) { + switch (regNum) { +#if defined(_LIBUNWIND_TARGET_X86_64) + case UNW_REG_IP: return _msContext.Rip; + case UNW_X86_64_RAX: return _msContext.Rax; + case UNW_X86_64_RDX: return _msContext.Rdx; + case UNW_X86_64_RCX: return _msContext.Rcx; + case UNW_X86_64_RBX: return _msContext.Rbx; + case UNW_REG_SP: + case UNW_X86_64_RSP: return _msContext.Rsp; + case UNW_X86_64_RBP: return _msContext.Rbp; + case UNW_X86_64_RSI: return _msContext.Rsi; + case UNW_X86_64_RDI: return _msContext.Rdi; + case UNW_X86_64_R8: return _msContext.R8; + case UNW_X86_64_R9: return _msContext.R9; + case UNW_X86_64_R10: return _msContext.R10; + case UNW_X86_64_R11: return _msContext.R11; + case UNW_X86_64_R12: return _msContext.R12; + case UNW_X86_64_R13: return _msContext.R13; + case UNW_X86_64_R14: return _msContext.R14; + case UNW_X86_64_R15: return _msContext.R15; +#elif defined(_LIBUNWIND_TARGET_ARM) + case UNW_ARM_R0: return _msContext.R0; + case UNW_ARM_R1: return _msContext.R1; + case UNW_ARM_R2: return _msContext.R2; + case UNW_ARM_R3: return _msContext.R3; + case UNW_ARM_R4: return _msContext.R4; + case UNW_ARM_R5: return _msContext.R5; + case UNW_ARM_R6: return _msContext.R6; + case UNW_ARM_R7: return _msContext.R7; + case UNW_ARM_R8: return _msContext.R8; + case UNW_ARM_R9: return _msContext.R9; + case UNW_ARM_R10: return _msContext.R10; + case UNW_ARM_R11: return _msContext.R11; + case UNW_ARM_R12: return _msContext.R12; + case UNW_REG_SP: + case UNW_ARM_SP: return _msContext.Sp; + case UNW_ARM_LR: return _msContext.Lr; + case UNW_REG_IP: + case UNW_ARM_IP: return _msContext.Pc; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + case UNW_REG_SP: return _msContext.Sp; + case UNW_REG_IP: return _msContext.Pc; + default: return _msContext.X[regNum - UNW_ARM64_X0]; +#endif + } + _LIBUNWIND_ABORT("unsupported register"); +} -#if FOR_DYLD - #if __ppc__ - bool mustUseDwarf() const { return true; } - #else - bool mustUseDwarf() const { return false; } - #endif +template +void UnwindCursor::setReg(int regNum, unw_word_t value) { + switch (regNum) { +#if defined(_LIBUNWIND_TARGET_X86_64) + case UNW_REG_IP: _msContext.Rip = value; break; + case UNW_X86_64_RAX: _msContext.Rax = value; break; + case UNW_X86_64_RDX: _msContext.Rdx = value; break; + case UNW_X86_64_RCX: _msContext.Rcx = value; break; + case UNW_X86_64_RBX: _msContext.Rbx = value; break; + case UNW_REG_SP: + case UNW_X86_64_RSP: _msContext.Rsp = value; break; + case UNW_X86_64_RBP: _msContext.Rbp = value; break; + case UNW_X86_64_RSI: _msContext.Rsi = value; break; + case UNW_X86_64_RDI: _msContext.Rdi = value; break; + case UNW_X86_64_R8: _msContext.R8 = value; break; + case UNW_X86_64_R9: _msContext.R9 = value; break; + case UNW_X86_64_R10: _msContext.R10 = value; break; + case UNW_X86_64_R11: _msContext.R11 = value; break; + case UNW_X86_64_R12: _msContext.R12 = value; break; + case UNW_X86_64_R13: _msContext.R13 = value; break; + case UNW_X86_64_R14: _msContext.R14 = value; break; + case UNW_X86_64_R15: _msContext.R15 = value; break; +#elif defined(_LIBUNWIND_TARGET_ARM) + case UNW_ARM_R0: _msContext.R0 = value; break; + case UNW_ARM_R1: _msContext.R1 = value; break; + case UNW_ARM_R2: _msContext.R2 = value; break; + case UNW_ARM_R3: _msContext.R3 = value; break; + case UNW_ARM_R4: _msContext.R4 = value; break; + case UNW_ARM_R5: _msContext.R5 = value; break; + case UNW_ARM_R6: _msContext.R6 = value; break; + case UNW_ARM_R7: _msContext.R7 = value; break; + case UNW_ARM_R8: _msContext.R8 = value; break; + case UNW_ARM_R9: _msContext.R9 = value; break; + case UNW_ARM_R10: _msContext.R10 = value; break; + case UNW_ARM_R11: _msContext.R11 = value; break; + case UNW_ARM_R12: _msContext.R12 = value; break; + case UNW_REG_SP: + case UNW_ARM_SP: _msContext.Sp = value; break; + case UNW_ARM_LR: _msContext.Lr = value; break; + case UNW_REG_IP: + case UNW_ARM_IP: _msContext.Pc = value; break; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + case UNW_REG_SP: _msContext.Sp = value; break; + case UNW_REG_IP: _msContext.Pc = value; break; + case UNW_ARM64_X0: + case UNW_ARM64_X1: + case UNW_ARM64_X2: + case UNW_ARM64_X3: + case UNW_ARM64_X4: + case UNW_ARM64_X5: + case UNW_ARM64_X6: + case UNW_ARM64_X7: + case UNW_ARM64_X8: + case UNW_ARM64_X9: + case UNW_ARM64_X10: + case UNW_ARM64_X11: + case UNW_ARM64_X12: + case UNW_ARM64_X13: + case UNW_ARM64_X14: + case UNW_ARM64_X15: + case UNW_ARM64_X16: + case UNW_ARM64_X17: + case UNW_ARM64_X18: + case UNW_ARM64_X19: + case UNW_ARM64_X20: + case UNW_ARM64_X21: + case UNW_ARM64_X22: + case UNW_ARM64_X23: + case UNW_ARM64_X24: + case UNW_ARM64_X25: + case UNW_ARM64_X26: + case UNW_ARM64_X27: + case UNW_ARM64_X28: + case UNW_ARM64_FP: + case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break; +#endif + default: + _LIBUNWIND_ABORT("unsupported register"); + } +} + +template +bool UnwindCursor::validFloatReg(int regNum) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true; + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true; #else - bool mustUseDwarf() const { R dummy; uint32_t offset; return dwarfWithOffset(dummy, offset); } + (void)regNum; +#endif + return false; +} + +template +unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { + union { + uint32_t w; + float f; + } d; + d.w = _msContext.S[regNum - UNW_ARM_S0]; + return d.f; + } + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { + union { + uint64_t w; + double d; + } d; + d.w = _msContext.D[regNum - UNW_ARM_D0]; + return d.d; + } + _LIBUNWIND_ABORT("unsupported float register"); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + return _msContext.V[regNum - UNW_ARM64_D0].D[0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("float registers unimplemented"); +#endif +} + +template +void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { + union { + uint32_t w; + float f; + } d; + d.f = value; + _msContext.S[regNum - UNW_ARM_S0] = d.w; + } + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { + union { + uint64_t w; + double d; + } d; + d.d = value; + _msContext.D[regNum - UNW_ARM_D0] = d.w; + } + _LIBUNWIND_ABORT("unsupported float register"); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + _msContext.V[regNum - UNW_ARM64_D0].D[0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("float registers unimplemented"); +#endif +} + +template void UnwindCursor::jumpto() { + RtlRestoreContext(&_msContext, nullptr); +} + +#ifdef __arm__ +template void UnwindCursor::saveVFPAsX() {} #endif - bool dwarfWithOffset(uint32_t& offset) const { R dummy; return dwarfWithOffset(dummy, offset); } - bool dwarfWithOffset(Registers_x86_64&, uint32_t& offset) const { - if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) { - offset = (fInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); - return true; - } -#if SUPPORT_OLD_BINARIES - if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_COMPATIBILITY ) { - if ( (fInfo.format & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) { - offset = 0; - return true; - } - } -#endif - return false; - } - bool dwarfWithOffset(Registers_x86&, uint32_t& offset) const { - if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) { - offset = (fInfo.format & UNWIND_X86_DWARF_SECTION_OFFSET); - return true; - } -#if SUPPORT_OLD_BINARIES - if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_COMPATIBILITY ) { - if ( (fInfo.format & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) { - offset = 0; - return true; - } - } -#endif - return false; - } - bool dwarfWithOffset(Registers_ppc&, uint32_t& offset) const { return true; } - +template +const char *UnwindCursor::getRegisterName(int regNum) { + return R::getRegisterName(regNum); +} - compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); } - compact_unwind_encoding_t dwarfEncoding(Registers_x86_64&) const { return UNWIND_X86_64_MODE_DWARF; } - compact_unwind_encoding_t dwarfEncoding(Registers_x86&) const { return UNWIND_X86_MODE_DWARF; } - compact_unwind_encoding_t dwarfEncoding(Registers_ppc&) const { return 0; } +template bool UnwindCursor::isSignalFrame() { + return false; +} - unw_proc_info_t fInfo; - R fRegisters; - A& fAddressSpace; - bool fUnwindInfoMissing; - bool fIsSignalFrame; +#else // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32) + +/// UnwindCursor contains all state (including all register values) during +/// an unwind. This is normally stack allocated inside a unw_cursor_t. +template +class UnwindCursor : public AbstractUnwindCursor{ + typedef typename A::pint_t pint_t; +public: + UnwindCursor(unw_context_t *context, A &as); + UnwindCursor(A &as, void *threadArg); + virtual ~UnwindCursor() {} + virtual bool validReg(int); + virtual unw_word_t getReg(int); + virtual void setReg(int, unw_word_t); + virtual bool validFloatReg(int); + virtual unw_fpreg_t getFloatReg(int); + virtual void setFloatReg(int, unw_fpreg_t); + virtual int step(); + virtual void getInfo(unw_proc_info_t *); + virtual void jumpto(); + virtual bool isSignalFrame(); + virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); + virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); + virtual const char *getRegisterName(int num); +#ifdef __arm__ + virtual void saveVFPAsX(); +#endif + + // libunwind does not and should not depend on C++ library which means that we + // need our own defition of inline placement new. + static void *operator new(size_t, UnwindCursor *p) { return p; } + +private: + +#if defined(_LIBUNWIND_ARM_EHABI) + bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s); + + int stepWithEHABI() { + size_t len = 0; + size_t off = 0; + // FIXME: Calling decode_eht_entry() here is violating the libunwind + // abstraction layer. + const uint32_t *ehtp = + decode_eht_entry(reinterpret_cast(_info.unwind_info), + &off, &len); + if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) != + _URC_CONTINUE_UNWIND) + return UNW_STEP_END; + return UNW_STEP_SUCCESS; + } +#endif + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + bool getInfoFromFdeCie(const typename CFI_Parser::FDE_Info &fdeInfo, + const typename CFI_Parser::CIE_Info &cieInfo, + pint_t pc, uintptr_t dso_base); + bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint=0); + int stepWithDwarfFDE() { + typename R::reg_t pc = this->getReg(UNW_REG_IP); + _registers.normalizeExistingLinkRegister(pc); + return DwarfInstructions::stepWithDwarf(_addressSpace, + pc, + (pint_t)_info.unwind_info, + _info.flags, + _registers, _isSignalFrame); + } +#endif + + void setProcInfoFlags() { + } + +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + bool getInfoFromCompactEncodingSection(pint_t pc, + const UnwindInfoSections §s); + int stepWithCompactEncoding() { + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + if ( compactSaysUseDwarf() ) + return stepWithDwarfFDE(); + #endif + R dummy; + return stepWithCompactEncoding(dummy); + } + +#if defined(_LIBUNWIND_TARGET_X86_64) + int stepWithCompactEncoding(Registers_x86_64 &) { + return CompactUnwinder_x86_64::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_I386) + int stepWithCompactEncoding(Registers_x86 &) { + return CompactUnwinder_x86::stepWithCompactEncoding( + _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC) + int stepWithCompactEncoding(Registers_ppc &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) + int stepWithCompactEncoding(Registers_ppc64 &) { + return UNW_EINVAL; + } +#endif + + +#if defined(_LIBUNWIND_TARGET_AARCH64) + int stepWithCompactEncoding(Registers_arm64 &) { + return CompactUnwinder_arm64::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _info.flags, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_ARM) + int stepWithCompactEncoding(Registers_arm &) { + return CompactUnwinder_arm::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + int stepWithCompactEncoding(Registers_mips_o32 &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) + int stepWithCompactEncoding(Registers_mips_newabi &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; } +#endif + +#if defined (_LIBUNWIND_TARGET_RISCV) + int stepWithCompactEncoding(Registers_riscv &) { + return UNW_EINVAL; + } +#endif + + bool compactSaysUseDwarf(uint32_t *offset=NULL) const { + R dummy; + return compactSaysUseDwarf(dummy, offset); + } + +#if defined(_LIBUNWIND_TARGET_X86_64) + bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { + if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); + return true; + } + return false; + } +#endif + +#if defined(_LIBUNWIND_TARGET_I386) + bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { + if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); + return true; + } + return false; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC) + bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) + bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_AARCH64) + bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { + if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); + return true; + } + return false; + } +#endif + +#if defined(_LIBUNWIND_TARGET_ARM) + bool compactSaysUseDwarf(Registers_arm &, uint32_t *offset) const { + if ((_info.format & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_ARM_DWARF_SECTION_OFFSET); + return true; + } + return false; + + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) + bool compactSaysUseDwarf(Registers_mips_newabi &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; } +#endif + +#if defined (_LIBUNWIND_TARGET_RISCV) + bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const { + return true; + } +#endif + +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + compact_unwind_encoding_t dwarfEncoding() const { + R dummy; + return dwarfEncoding(dummy); + } + +#if defined(_LIBUNWIND_TARGET_X86_64) + compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { + return UNWIND_X86_64_MODE_DWARF; + } +#endif + +#if defined(_LIBUNWIND_TARGET_I386) + compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { + return UNWIND_X86_MODE_DWARF; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC) + compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) + compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_AARCH64) + compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { + return UNWIND_ARM64_MODE_DWARF; + } +#endif + +#if defined(_LIBUNWIND_TARGET_ARM) + compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const { + return UNWIND_ARM_MODE_DWARF; + } +#endif + +#if defined (_LIBUNWIND_TARGET_OR1K) + compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_HEXAGON) + compact_unwind_encoding_t dwarfEncoding(Registers_hexagon &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_MIPS_O32) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_MIPS_NEWABI) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_newabi &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; } +#endif + +#if defined (_LIBUNWIND_TARGET_RISCV) + compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const { + return 0; + } +#endif + +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + // For runtime environments using SEH unwind data without Windows runtime + // support. + pint_t getLastPC() const { /* FIXME: Implement */ return 0; } + void setLastPC(pint_t pc) { /* FIXME: Implement */ } + RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { + /* FIXME: Implement */ + *base = 0; + return nullptr; + } + bool getInfoFromSEH(pint_t pc); + int stepWithSEHData() { /* FIXME: Implement */ return 0; } +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + + + A &_addressSpace; + R _registers; + unw_proc_info_t _info; + bool _unwindInfoMissing; + bool _isSignalFrame; }; -typedef UnwindCursor AbstractUnwindCursor; template -UnwindCursor::UnwindCursor(unw_context_t* context, A& as) - : fRegisters(context), fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false) -{ - COMPILE_TIME_ASSERT( sizeof(UnwindCursor) < sizeof(unw_cursor_t) ); - - bzero(&fInfo, sizeof(fInfo)); +UnwindCursor::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _registers(context), _unwindInfoMissing(false), + _isSignalFrame(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + static_assert((alignof(UnwindCursor) <= alignof(unw_cursor_t)), + "UnwindCursor<> requires more alignment than unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); } template -UnwindCursor::UnwindCursor(A& as, thread_t thread) - : fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false) -{ - bzero(&fInfo, sizeof(fInfo)); - // FIXME - // fill in fRegisters from thread -} - -template -bool UnwindCursor::validReg(int regNum) -{ - return fRegisters.validRegister(regNum); -} - -template -uint64_t UnwindCursor::getReg(int regNum) -{ - return fRegisters.getRegister(regNum); -} - -template -void UnwindCursor::setReg(int regNum, uint64_t value) -{ - fRegisters.setRegister(regNum, value); -} - -template -bool UnwindCursor::validFloatReg(int regNum) -{ - return fRegisters.validFloatRegister(regNum); -} - -template -double UnwindCursor::getFloatReg(int regNum) -{ - return fRegisters.getFloatRegister(regNum); -} - -template -void UnwindCursor::setFloatReg(int regNum, double value) -{ - fRegisters.setFloatRegister(regNum, value); -} - -template -void UnwindCursor::jumpto() -{ - fRegisters.jumpto(); -} - -template -const char* UnwindCursor::getRegisterName(int regNum) -{ - return fRegisters.getRegisterName(regNum); -} - -template -bool UnwindCursor::isSignalFrame() -{ - return fIsSignalFrame; +UnwindCursor::UnwindCursor(A &as, void *) + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { + memset(&_info, 0, sizeof(_info)); + // FIXME + // fill in _registers from thread arg } template -bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE) -{ - typename CFI_Parser::FDE_Info fdeInfo; - typename CFI_Parser::CIE_Info cieInfo; - bool foundFDE = false; - bool foundInCache = false; - // if compact encoding table gave offset into dwarf section, go directly there - if ( sectionOffsetOfFDE != 0 ) { - foundFDE = CFI_Parser::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, ehSectionStart+sectionOffsetOfFDE, &fdeInfo, &cieInfo); - } -#if !FOR_DYLD - if ( !foundFDE ) { - // otherwise, search cache of previously found FDEs - pint_t cachedFDE = DwarfFDECache::findFDE(mh, pc); - //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%llX) cachedFDE=0x%llX\n", (uint64_t)pc, (uint64_t)cachedFDE); - if ( cachedFDE != 0 ) { - foundFDE = CFI_Parser::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, cachedFDE, &fdeInfo, &cieInfo); - foundInCache = foundFDE; - //fprintf(stderr, "cachedFDE=0x%llX, foundInCache=%d\n", (uint64_t)cachedFDE, foundInCache); - } - } -#endif - if ( !foundFDE ) { - // still not found, do full scan of __eh_frame section - foundFDE = CFI_Parser::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, 0, &fdeInfo, &cieInfo); - } - if ( foundFDE ) { - typename CFI_Parser::PrologInfo prolog; - if ( CFI_Parser::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) { - // save off parsed FDE info - fInfo.start_ip = fdeInfo.pcStart; - fInfo.end_ip = fdeInfo.pcEnd; - fInfo.lsda = fdeInfo.lsda; - fInfo.handler = cieInfo.personality; - fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function - fInfo.flags = 0; - fInfo.format = dwarfEncoding(); - fInfo.unwind_info = fdeInfo.fdeStart; - fInfo.unwind_info_size = fdeInfo.fdeLength; - fInfo.extra = (unw_word_t)mh; - if ( !foundInCache && (sectionOffsetOfFDE == 0) ) { - // don't add to cache entries the compact encoding table can find quickly - //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%0llX), mh=0x%llX, start_ip=0x%0llX, fde=0x%0llX, personality=0x%0llX\n", - // (uint64_t)pc, (uint64_t)mh, fInfo.start_ip, fInfo.unwind_info, fInfo.handler); -#if !FOR_DYLD - DwarfFDECache::add(mh, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); -#endif - } - return true; - } - } - //DEBUG_MESSAGE("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); - return false; +bool UnwindCursor::validReg(int regNum) { + return _registers.validRegister(regNum); } - template -bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart) -{ - const bool log = false; - if ( log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)mh); - - const UnwindSectionHeader sectionHeader(fAddressSpace, unwindSectionStart); - if ( sectionHeader.version() != UNWIND_SECTION_VERSION ) - return false; - - // do a binary search of top level index to find page with unwind info - uint32_t targetFunctionOffset = pc - mh; - const UnwindSectionIndexArray topIndex(fAddressSpace, unwindSectionStart + sectionHeader.indexSectionOffset()); - uint32_t low = 0; - uint32_t high = sectionHeader.indexCount(); - const uint32_t last = high - 1; - while ( low < high ) { - uint32_t mid = (low + high)/2; - //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", mid, low, high, topIndex.functionOffset(mid)); - if ( topIndex.functionOffset(mid) <= targetFunctionOffset ) { - if ( (mid == last) || (topIndex.functionOffset(mid+1) > targetFunctionOffset) ) { - low = mid; - break; - } - else { - low = mid+1; - } - } - else { - high = mid; - } - } - const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); - const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low+1); - const pint_t secondLevelAddr = unwindSectionStart+topIndex.secondLevelPagesSectionOffset(low); - const pint_t lsdaArrayStartAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low); - const pint_t lsdaArrayEndAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low+1); - if ( log ) fprintf(stderr, "\tfirst level search for result index=%d to secondLevelAddr=0x%llX\n", - low, (uint64_t)secondLevelAddr); - // do a binary search of second level page index - uint32_t encoding = 0; - pint_t funcStart = 0; - pint_t funcEnd = 0; - pint_t lsda = 0; - pint_t personality = 0; - uint32_t pageKind = fAddressSpace.get32(secondLevelAddr); - if ( pageKind == UNWIND_SECOND_LEVEL_REGULAR ) { - // regular page - UnwindSectionRegularPageHeader pageHeader(fAddressSpace, secondLevelAddr); - UnwindSectionRegularArray pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset()); - // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset - if ( log ) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in regular page starting at secondLevelAddr=0x%llX\n", - (uint64_t)targetFunctionOffset, (uint64_t)secondLevelAddr); - uint32_t low = 0; - uint32_t high = pageHeader.entryCount(); - while ( low < high ) { - uint32_t mid = (low + high)/2; - if ( pageIndex.functionOffset(mid) <= targetFunctionOffset ) { - if ( mid == (uint32_t)(pageHeader.entryCount()-1) ) { - // at end of table - low = mid; - funcEnd = firstLevelNextPageFunctionOffset + mh; - break; - } - else if ( pageIndex.functionOffset(mid+1) > targetFunctionOffset ) { - // next is too big, so we found it - low = mid; - funcEnd = pageIndex.functionOffset(low+1) + mh; - break; - } - else { - low = mid+1; - } - } - else { - high = mid; - } - } - encoding = pageIndex.encoding(low); - funcStart = pageIndex.functionOffset(low) + mh; - if ( pc < funcStart ) { - if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd); - return false; - } - if ( pc > funcEnd ) { - if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd); - return false; - } - } - else if ( pageKind == UNWIND_SECOND_LEVEL_COMPRESSED ) { - // compressed page - UnwindSectionCompressedPageHeader pageHeader(fAddressSpace, secondLevelAddr); - UnwindSectionCompressedArray pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset()); - const uint32_t targetFunctionPageOffset = targetFunctionOffset - firstLevelFunctionOffset; - // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset - if ( log ) fprintf(stderr, "\tbinary search of compressed page starting at secondLevelAddr=0x%llX\n", (uint64_t)secondLevelAddr); - uint32_t low = 0; - const uint32_t last = pageHeader.entryCount() - 1; - uint32_t high = pageHeader.entryCount(); - while ( low < high ) { - uint32_t mid = (low + high)/2; - if ( pageIndex.functionOffset(mid) <= targetFunctionPageOffset ) { - if ( (mid == last) || (pageIndex.functionOffset(mid+1) > targetFunctionPageOffset) ) { - low = mid; - break; - } - else { - low = mid+1; - } - } - else { - high = mid; - } - } - funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + mh; - if ( low < last ) - funcEnd = pageIndex.functionOffset(low+1) + firstLevelFunctionOffset + mh; - else - funcEnd = firstLevelNextPageFunctionOffset + mh; - if ( pc < funcStart ) { - DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcStart=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart); - return false; - } - if ( pc > funcEnd ) { - DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcEnd); - return false; - } - uint16_t encodingIndex = pageIndex.encodingIndex(low); - if ( encodingIndex < sectionHeader.commonEncodingsArrayCount() ) { - // encoding is in common table in section header - encoding = fAddressSpace.get32(unwindSectionStart+sectionHeader.commonEncodingsArraySectionOffset()+encodingIndex*sizeof(uint32_t)); - } - else { - // encoding is in page specific table - uint16_t pageEncodingIndex = encodingIndex-sectionHeader.commonEncodingsArrayCount(); - encoding = fAddressSpace.get32(secondLevelAddr+pageHeader.encodingsPageOffset()+pageEncodingIndex*sizeof(uint32_t)); - } - } - else { - DEBUG_MESSAGE("malformed __unwind_info at 0x%0llX bad second level page\n", (uint64_t)unwindSectionStart); - return false; - } - - // look up LSDA, if encoding says function has one - if ( encoding & UNWIND_HAS_LSDA ) { - UnwindSectionLsdaArray lsdaIndex(fAddressSpace, lsdaArrayStartAddr); - uint32_t funcStartOffset = funcStart - mh; - uint32_t low = 0; - uint32_t high = (lsdaArrayEndAddr-lsdaArrayStartAddr)/sizeof(unwind_info_section_header_lsda_index_entry); - // binary search looks for entry with exact match for functionOffset - if ( log ) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset); - while ( low < high ) { - uint32_t mid = (low + high)/2; - if ( lsdaIndex.functionOffset(mid) == funcStartOffset ) { - lsda = lsdaIndex.lsdaOffset(mid) + mh; - break; - } - else if ( lsdaIndex.functionOffset(mid) < funcStartOffset ) { - low = mid+1; - } - else { - high = mid; - } - } - if ( lsda == 0 ) { - DEBUG_MESSAGE("found encoding 0x%08X with HAS_LSDA bit set for pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t)pc); - return false; - } - } - - // extact personality routine, if encoding says function has one - uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK)); - if ( personalityIndex != 0 ) { - --personalityIndex; // change 1-based to zero-based index - if ( personalityIndex > sectionHeader.personalityArrayCount() ) { - DEBUG_MESSAGE("found encoding 0x%08X with personality index %d, but personality table has only %d entires\n", - encoding, personalityIndex, sectionHeader.personalityArrayCount()); - return false; - } - int32_t personalityDelta = fAddressSpace.get32(unwindSectionStart+sectionHeader.personalityArraySectionOffset()+personalityIndex*sizeof(uint32_t)); - pint_t personalityPointer = personalityDelta + mh; - personality = fAddressSpace.getP(personalityPointer); - if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), personalityDelta=0x%08X, personality=0x%08llX\n", - (uint64_t)pc, personalityDelta, (uint64_t)personality); - } - - if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", - (uint64_t)pc, encoding, (uint64_t)lsda, (uint64_t)funcStart); - fInfo.start_ip = funcStart; - fInfo.end_ip = funcEnd; - fInfo.lsda = lsda; - fInfo.handler = personality; - fInfo.gp = 0; - fInfo.flags = 0; - fInfo.format = encoding; - fInfo.unwind_info = 0; - fInfo.unwind_info_size = 0; - fInfo.extra = mh; - return true; +unw_word_t UnwindCursor::getReg(int regNum) { + return _registers.getRegister(regNum); } - +template +void UnwindCursor::setReg(int regNum, unw_word_t value) { + _registers.setRegister(regNum, (typename A::pint_t)value); +} template -void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) -{ - pint_t pc = this->getReg(UNW_REG_IP); - - // if the last line of a function is a "throw" the compile sometimes - // emits no instructions after the call to __cxa_throw. This means - // the return address is actually the start of the next function. - // To disambiguate this, back up the pc when we know it is a return - // address. - if ( isReturnAddress ) - --pc; - - // ask address space object to find unwind sections for this pc - pint_t mh; - pint_t dwarfStart; - pint_t dwarfLength; - pint_t compactStart; - if ( fAddressSpace.findUnwindSections(pc, mh, dwarfStart, dwarfLength, compactStart) ) { - // if there is a compact unwind encoding table, look there first - if ( compactStart != 0 ) { - if ( this->getInfoFromCompactEncodingSection(pc, mh, compactStart) ) { -#if !FOR_DYLD - // found info in table, done unless encoding says to use dwarf - uint32_t offsetInDwarfSection; - if ( (dwarfStart != 0) && dwarfWithOffset(offsetInDwarfSection) ) { - if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, offsetInDwarfSection) ) { - // found info in dwarf, done - return; - } - } -#endif - // if unwind table has entry, but entry says there is no unwind info, note that - if ( fInfo.format == 0 ) - fUnwindInfoMissing = true; +bool UnwindCursor::validFloatReg(int regNum) { + return _registers.validFloatRegister(regNum); +} - // old compact encoding - if ( !mustUseDwarf() ) { - return; - } - } - } -#if !FOR_DYLD || __ppc__ - // if there is dwarf unwind info, look there next - if ( dwarfStart != 0 ) { - if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, 0) ) { - // found info in dwarf, done - return; - } - } -#endif - } - -#if !FOR_DYLD - // the PC is not in code loaded by dyld, look through __register_frame() registered FDEs - pint_t cachedFDE = DwarfFDECache::findFDE(0, pc); - if ( cachedFDE != 0 ) { - CFI_Parser::FDE_Info fdeInfo; - CFI_Parser::CIE_Info cieInfo; - const char* msg = CFI_Parser::decodeFDE(fAddressSpace, cachedFDE, &fdeInfo, &cieInfo); - if ( msg == NULL ) { - typename CFI_Parser::PrologInfo prolog; - if ( CFI_Parser::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) { - // save off parsed FDE info - fInfo.start_ip = fdeInfo.pcStart; - fInfo.end_ip = fdeInfo.pcEnd; - fInfo.lsda = fdeInfo.lsda; - fInfo.handler = cieInfo.personality; - fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function - fInfo.flags = 0; - fInfo.format = dwarfEncoding(); - fInfo.unwind_info = fdeInfo.fdeStart; - fInfo.unwind_info_size = fdeInfo.fdeLength; - fInfo.extra = 0; - return; - } - } - } - -#if KEYMGR_SUPPPORT - // lastly check for old style keymgr registration of dynamically generated FDEs - // acquire exclusive access to libgcc_object_info - libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); - if ( head != NULL ) { - // look at each FDE in keymgr - for (libgcc_object* ob = head->unseen_objects; ob != NULL; ob = ob->next) { - CFI_Parser::FDE_Info fdeInfo; - CFI_Parser::CIE_Info cieInfo; - const char* msg = CFI_Parser::decodeFDE(fAddressSpace, (pint_t)ob->fde, &fdeInfo, &cieInfo); - if ( msg == NULL ) { - // see if this FDE is for a function that includes the pc we are looking for - if ( (fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) ) { - typename CFI_Parser::PrologInfo prolog; - if ( CFI_Parser::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) { - // save off parsed FDE info - fInfo.start_ip = fdeInfo.pcStart; - fInfo.end_ip = fdeInfo.pcEnd; - fInfo.lsda = fdeInfo.lsda; - fInfo.handler = cieInfo.personality; - fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function - fInfo.flags = 0; - fInfo.format = dwarfEncoding(); - fInfo.unwind_info = fdeInfo.fdeStart; - fInfo.unwind_info_size = fdeInfo.fdeLength; - fInfo.extra = 0; - _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); - return; - } - } - } - } - } - // release libgcc_object_info - _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); -#endif // KEYMGR_SUPPPORT - +template +unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { + return _registers.getFloatRegister(regNum); +} + +template +void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { + _registers.setFloatRegister(regNum, value); +} + +template void UnwindCursor::jumpto() { + _registers.jumpto(); +} + +#ifdef __arm__ +template void UnwindCursor::saveVFPAsX() { + _registers.saveVFPAsX(); +} #endif - // no unwind info, flag that we can't reliable unwind - fUnwindInfoMissing = true; +template +const char *UnwindCursor::getRegisterName(int regNum) { + return _registers.getRegisterName(regNum); } +template bool UnwindCursor::isSignalFrame() { + return _isSignalFrame; +} + +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + +#if defined(_LIBUNWIND_ARM_EHABI) +template +struct EHABISectionIterator { + typedef EHABISectionIterator _Self; + + typedef typename A::pint_t value_type; + typedef typename A::pint_t* pointer; + typedef typename A::pint_t& reference; + typedef size_t size_type; + typedef size_t difference_type; + + static _Self begin(A& addressSpace, const UnwindInfoSections& sects) { + return _Self(addressSpace, sects, 0); + } + static _Self end(A& addressSpace, const UnwindInfoSections& sects) { + return _Self(addressSpace, sects, + sects.arm_section_length / sizeof(EHABIIndexEntry)); + } + + EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i) + : _i(i), _addressSpace(&addressSpace), _sects(§s) {} + + _Self& operator++() { ++_i; return *this; } + _Self& operator+=(size_t a) { _i += a; return *this; } + _Self& operator--() { assert(_i > 0); --_i; return *this; } + _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; } + + _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; } + _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; } + + size_t operator-(const _Self& other) const { return _i - other._i; } + + bool operator==(const _Self& other) const { + assert(_addressSpace == other._addressSpace); + assert(_sects == other._sects); + return _i == other._i; + } + + bool operator!=(const _Self& other) const { + assert(_addressSpace == other._addressSpace); + assert(_sects == other._sects); + return _i != other._i; + } + + typename A::pint_t operator*() const { return functionAddress(); } + + typename A::pint_t functionAddress() const { + typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( + EHABIIndexEntry, _i, functionOffset); + return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr)); + } + + typename A::pint_t dataAddress() { + typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( + EHABIIndexEntry, _i, data); + return indexAddr; + } + + private: + size_t _i; + A* _addressSpace; + const UnwindInfoSections* _sects; +}; + +namespace { + +template +EHABISectionIterator EHABISectionUpperBound( + EHABISectionIterator first, + EHABISectionIterator last, + typename A::pint_t value) { + size_t len = last - first; + while (len > 0) { + size_t l2 = len / 2; + EHABISectionIterator m = first + l2; + if (value < *m) { + len = l2; + } else { + first = ++m; + len -= l2 + 1; + } + } + return first; +} + +} template -int UnwindCursor::step() -{ - // bottom of stack is defined as when no more unwind info - if ( fUnwindInfoMissing ) - return UNW_STEP_END; +bool UnwindCursor::getInfoFromEHABISection( + pint_t pc, + const UnwindInfoSections §s) { + EHABISectionIterator begin = + EHABISectionIterator::begin(_addressSpace, sects); + EHABISectionIterator end = + EHABISectionIterator::end(_addressSpace, sects); + if (begin == end) + return false; - // apply unwinding to register set - int result; - if ( this->mustUseDwarf() ) - result = this->stepWithDwarfFDE(); - else - result = this->stepWithCompactEncoding(); - - // update info based on new PC - if ( result == UNW_STEP_SUCCESS ) { - this->setInfoBasedOnIPRegister(true); - if ( fUnwindInfoMissing ) - return UNW_STEP_END; - } + EHABISectionIterator itNextPC = EHABISectionUpperBound(begin, end, pc); + if (itNextPC == begin) + return false; + EHABISectionIterator itThisPC = itNextPC - 1; - return result; + pint_t thisPC = itThisPC.functionAddress(); + // If an exception is thrown from a function, corresponding to the last entry + // in the table, we don't really know the function extent and have to choose a + // value for nextPC. Choosing max() will allow the range check during trace to + // succeed. + pint_t nextPC = (itNextPC == end) ? UINTPTR_MAX : itNextPC.functionAddress(); + pint_t indexDataAddr = itThisPC.dataAddress(); + + if (indexDataAddr == 0) + return false; + + uint32_t indexData = _addressSpace.get32(indexDataAddr); + if (indexData == UNW_EXIDX_CANTUNWIND) + return false; + + // If the high bit is set, the exception handling table entry is inline inside + // the index table entry on the second word (aka |indexDataAddr|). Otherwise, + // the table points at an offset in the exception handling table (section 5 + // EHABI). + pint_t exceptionTableAddr; + uint32_t exceptionTableData; + bool isSingleWordEHT; + if (indexData & 0x80000000) { + exceptionTableAddr = indexDataAddr; + // TODO(ajwong): Should this data be 0? + exceptionTableData = indexData; + isSingleWordEHT = true; + } else { + exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData); + exceptionTableData = _addressSpace.get32(exceptionTableAddr); + isSingleWordEHT = false; + } + + // Now we know the 3 things: + // exceptionTableAddr -- exception handler table entry. + // exceptionTableData -- the data inside the first word of the eht entry. + // isSingleWordEHT -- whether the entry is in the index. + unw_word_t personalityRoutine = 0xbadf00d; + bool scope32 = false; + uintptr_t lsda; + + // If the high bit in the exception handling table entry is set, the entry is + // in compact form (section 6.3 EHABI). + if (exceptionTableData & 0x80000000) { + // Grab the index of the personality routine from the compact form. + uint32_t choice = (exceptionTableData & 0x0f000000) >> 24; + uint32_t extraWords = 0; + switch (choice) { + case 0: + personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0; + extraWords = 0; + scope32 = false; + lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4); + break; + case 1: + personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1; + extraWords = (exceptionTableData & 0x00ff0000) >> 16; + scope32 = false; + lsda = exceptionTableAddr + (extraWords + 1) * 4; + break; + case 2: + personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2; + extraWords = (exceptionTableData & 0x00ff0000) >> 16; + scope32 = true; + lsda = exceptionTableAddr + (extraWords + 1) * 4; + break; + default: + _LIBUNWIND_ABORT("unknown personality routine"); + return false; + } + + if (isSingleWordEHT) { + if (extraWords != 0) { + _LIBUNWIND_ABORT("index inlined table detected but pr function " + "requires extra words"); + return false; + } + } + } else { + pint_t personalityAddr = + exceptionTableAddr + signExtendPrel31(exceptionTableData); + personalityRoutine = personalityAddr; + + // ARM EHABI # 6.2, # 9.2 + // + // +---- ehtp + // v + // +--------------------------------------+ + // | +--------+--------+--------+-------+ | + // | |0| prel31 to personalityRoutine | | + // | +--------+--------+--------+-------+ | + // | | N | unwind opcodes | | <-- UnwindData + // | +--------+--------+--------+-------+ | + // | | Word 2 unwind opcodes | | + // | +--------+--------+--------+-------+ | + // | ... | + // | +--------+--------+--------+-------+ | + // | | Word N unwind opcodes | | + // | +--------+--------+--------+-------+ | + // | | LSDA | | <-- lsda + // | | ... | | + // | +--------+--------+--------+-------+ | + // +--------------------------------------+ + + uint32_t *UnwindData = reinterpret_cast(exceptionTableAddr) + 1; + uint32_t FirstDataWord = *UnwindData; + size_t N = ((FirstDataWord >> 24) & 0xff); + size_t NDataWords = N + 1; + lsda = reinterpret_cast(UnwindData + NDataWords); + } + + _info.start_ip = thisPC; + _info.end_ip = nextPC; + _info.handler = personalityRoutine; + _info.unwind_info = exceptionTableAddr; + _info.lsda = lsda; + // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0. + _info.flags = (isSingleWordEHT ? 1 : 0) | (scope32 ? 0x2 : 0); // Use enum? + + return true; } +#endif +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +template +bool UnwindCursor::getInfoFromFdeCie( + const typename CFI_Parser::FDE_Info &fdeInfo, + const typename CFI_Parser::CIE_Info &cieInfo, pint_t pc, + uintptr_t dso_base) { + typename CFI_Parser::PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, + R::getArch(), &prolog)) { + // Save off parsed FDE info + _info.start_ip = fdeInfo.pcStart; + _info.end_ip = fdeInfo.pcEnd; + _info.lsda = fdeInfo.lsda; + _info.handler = cieInfo.personality; + // Some frameless functions need SP altered when resuming in function, so + // propagate spExtraArgSize. + _info.gp = prolog.spExtraArgSize; + _info.flags = 0; + _info.format = dwarfEncoding(); + _info.unwind_info = fdeInfo.fdeStart; + _info.unwind_info_size = static_cast(fdeInfo.fdeLength); + _info.extra = static_cast(dso_base); + setProcInfoFlags(); + return true; + } + return false; +} template -void UnwindCursor::getInfo(unw_proc_info_t* info) -{ - *info = fInfo; +bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, + const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + bool foundFDE = false; + bool foundInCache = false; + // If compact encoding table gave offset into dwarf section, go directly there + if (fdeSectionOffsetHint != 0) { + foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, + sects.dwarf_section + fdeSectionOffsetHint, + &fdeInfo, &cieInfo); + } +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (!foundFDE && (sects.dwarf_index_section != 0)) { + foundFDE = EHHeaderParser::findFDE( + _addressSpace, pc, sects.dwarf_index_section, + (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo); + } +#endif + if (!foundFDE) { + // otherwise, search cache of previously found FDEs. + pint_t cachedFDE = DwarfFDECache::findFDE(sects.dso_base, pc); + if (cachedFDE != 0) { + foundFDE = + CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, + cachedFDE, &fdeInfo, &cieInfo); + foundInCache = foundFDE; + } + } + if (!foundFDE) { + // Still not found, do full scan of __eh_frame section. + foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, 0, + &fdeInfo, &cieInfo); + } + if (foundFDE) { + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) { + // Add to cache (to make next lookup faster) if we had no hint + // and there was no index. + if (!foundInCache && (fdeSectionOffsetHint == 0)) { + #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (sects.dwarf_index_section == 0) + #endif + DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } + return true; + } + } + //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc); + return false; } +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) +template +bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, + const UnwindInfoSections §s) { + const bool log = false; + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", + (uint64_t)pc, (uint64_t)sects.dso_base); + + const UnwindSectionHeader sectionHeader(_addressSpace, + sects.compact_unwind_section); + if (sectionHeader.version() != UNWIND_SECTION_VERSION) + return false; + + // do a binary search of top level index to find page with unwind info + pint_t targetFunctionOffset = pc - sects.dso_base; + const UnwindSectionIndexArray topIndex(_addressSpace, + sects.compact_unwind_section + + sectionHeader.indexSectionOffset()); + uint32_t low = 0; + uint32_t high = sectionHeader.indexCount(); + uint32_t last = high - 1; + while (low < high) { + uint32_t mid = (low + high) / 2; + //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", + //mid, low, high, topIndex.functionOffset(mid)); + if (topIndex.functionOffset(mid) <= targetFunctionOffset) { + if ((mid == last) || + (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { + low = mid; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); + const uint32_t firstLevelNextPageFunctionOffset = + topIndex.functionOffset(low + 1); + const pint_t secondLevelAddr = + sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low); + const pint_t lsdaArrayStartAddr = + sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); + const pint_t lsdaArrayEndAddr = + sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1); + if (log) + fprintf(stderr, "\tfirst level search for result index=%d " + "to secondLevelAddr=0x%llX\n", + low, (uint64_t) secondLevelAddr); + // do a binary search of second level page index + uint32_t encoding = 0; + pint_t funcStart = 0; + pint_t funcEnd = 0; + pint_t lsda = 0; + pint_t personality = 0; + uint32_t pageKind = _addressSpace.get32(secondLevelAddr); + if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { + // regular page + UnwindSectionRegularPageHeader pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionRegularArray pageIndex( + _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); + // binary search looks for entry with e where index[e].offset <= pc < + // index[e+1].offset + if (log) + fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " + "regular page starting at secondLevelAddr=0x%llX\n", + (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); + low = 0; + high = pageHeader.entryCount(); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { + if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { + // at end of table + low = mid; + funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; + break; + } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { + // next is too big, so we found it + low = mid; + funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + encoding = pageIndex.encoding(low); + funcStart = pageIndex.functionOffset(low) + sects.dso_base; + if (pc < funcStart) { + if (log) + fprintf( + stderr, + "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); + return false; + } + if (pc > funcEnd) { + if (log) + fprintf( + stderr, + "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); + return false; + } + } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { + // compressed page + UnwindSectionCompressedPageHeader pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionCompressedArray pageIndex( + _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); + const uint32_t targetFunctionPageOffset = + (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); + // binary search looks for entry with e where index[e].offset <= pc < + // index[e+1].offset + if (log) + fprintf(stderr, "\tbinary search of compressed page starting at " + "secondLevelAddr=0x%llX\n", + (uint64_t) secondLevelAddr); + low = 0; + last = pageHeader.entryCount() - 1; + high = pageHeader.entryCount(); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { + if ((mid == last) || + (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { + low = mid; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + + sects.dso_base; + if (low < last) + funcEnd = + pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset + + sects.dso_base; + else + funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; + if (pc < funcStart) { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " + "level compressed unwind table. funcStart=0x%llX", + (uint64_t) pc, (uint64_t) funcStart); + return false; + } + if (pc > funcEnd) { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " + "level compressed unwind table. funcEnd=0x%llX", + (uint64_t) pc, (uint64_t) funcEnd); + return false; + } + uint16_t encodingIndex = pageIndex.encodingIndex(low); + if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { + // encoding is in common table in section header + encoding = _addressSpace.get32( + sects.compact_unwind_section + + sectionHeader.commonEncodingsArraySectionOffset() + + encodingIndex * sizeof(uint32_t)); + } else { + // encoding is in page specific table + uint16_t pageEncodingIndex = + encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); + encoding = _addressSpace.get32(secondLevelAddr + + pageHeader.encodingsPageOffset() + + pageEncodingIndex * sizeof(uint32_t)); + } + } else { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " + "level page", + (uint64_t) sects.compact_unwind_section); + return false; + } + + // look up LSDA, if encoding says function has one + if (encoding & UNWIND_HAS_LSDA) { + UnwindSectionLsdaArray lsdaIndex(_addressSpace, lsdaArrayStartAddr); + uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); + low = 0; + high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / + sizeof(unwind_info_section_header_lsda_index_entry); + // binary search looks for entry with exact match for functionOffset + if (log) + fprintf(stderr, + "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", + funcStartOffset); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (lsdaIndex.functionOffset(mid) == funcStartOffset) { + lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; + break; + } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { + low = mid + 1; + } else { + high = mid; + } + } + if (lsda == 0) { + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " + "pc=0x%0llX, but lsda table has no entry", + encoding, (uint64_t) pc); + return false; + } + } + + // extract personality routine, if encoding says function has one + uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> + (__builtin_ctz(UNWIND_PERSONALITY_MASK)); + if (personalityIndex != 0) { + --personalityIndex; // change 1-based to zero-based index + if (personalityIndex >= sectionHeader.personalityArrayCount()) { + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " + "but personality table has only %d entries", + encoding, personalityIndex, + sectionHeader.personalityArrayCount()); + return false; + } + int32_t personalityDelta = (int32_t)_addressSpace.get32( + sects.compact_unwind_section + + sectionHeader.personalityArraySectionOffset() + + personalityIndex * sizeof(uint32_t)); + pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; + personality = _addressSpace.getP(personalityPointer); + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " + "personalityDelta=0x%08X, personality=0x%08llX\n", + (uint64_t) pc, personalityDelta, (uint64_t) personality); + } + + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " + "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", + (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); + _info.start_ip = funcStart; + _info.end_ip = funcEnd; + _info.lsda = lsda; + _info.handler = personality; + _info.gp = 0; + _info.flags = 0; + _info.format = encoding; + _info.unwind_info = 0; + _info.unwind_info_size = 0; + _info.extra = sects.dso_base; + setProcInfoFlags(); + return true; +} +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +template +bool UnwindCursor::getInfoFromSEH(pint_t pc) { + pint_t base; + RUNTIME_FUNCTION *unwindEntry = lookUpSEHUnwindInfo(pc, &base); + if (!unwindEntry) { + _LIBUNWIND_DEBUG_LOG("\tpc not in table, pc=0x%llX", (uint64_t) pc); + return false; + } + _info.gp = 0; + _info.flags = 0; + _info.format = 0; + _info.unwind_info_size = sizeof(RUNTIME_FUNCTION); + _info.unwind_info = reinterpret_cast(unwindEntry); + _info.extra = base; + _info.start_ip = base + unwindEntry->BeginAddress; +#ifdef _LIBUNWIND_TARGET_X86_64 + _info.end_ip = base + unwindEntry->EndAddress; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + UNWIND_INFO *xdata = reinterpret_cast(base + unwindEntry->UnwindData); + if (xdata->Flags & (UNW_FLAG_EHANDLER|UNW_FLAG_UHANDLER)) { + // The personality is given in the UNWIND_INFO itself. The LSDA immediately + // follows the UNWIND_INFO. (This follows how both Clang and MSVC emit + // these structures.) + // N.B. UNWIND_INFO structs are DWORD-aligned. + uint32_t lastcode = (xdata->CountOfCodes + 1) & ~1; + const uint32_t *handler = reinterpret_cast(&xdata->UnwindCodes[lastcode]); + _info.lsda = reinterpret_cast(handler+1); + if (*handler) { + _info.handler = reinterpret_cast(__libunwind_seh_personality); + } else + _info.handler = 0; + } else { + _info.lsda = 0; + _info.handler = 0; + } + } +#elif defined(_LIBUNWIND_TARGET_ARM) + _info.end_ip = _info.start_ip + unwindEntry->FunctionLength; + _info.lsda = 0; // FIXME + _info.handler = 0; // FIXME +#endif + setLastPC(pc); + return true; +} +#endif + template -bool UnwindCursor::getFunctionName(char* buf, size_t bufLen, unw_word_t* offset) -{ - return fAddressSpace.findFunctionName(this->getReg(UNW_REG_IP), buf, bufLen, offset); +void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { + typename R::reg_t pc = this->getReg(UNW_REG_IP); +#if defined(_LIBUNWIND_ARM_EHABI) + // Remove the thumb bit so the IP represents the actual instruction address. + // This matches the behaviour of _Unwind_GetIP on arm. + pc &= (pint_t)~0x1; +#endif + + _registers.normalizeExistingLinkRegister(pc); + + // Exit early if at the top of the stack. + if (pc == 0) { + _unwindInfoMissing = true; + return; + } + + // If the last line of a function is a "throw" the compiler sometimes + // emits no instructions after the call to __cxa_throw. This means + // the return address is actually the start of the next function. + // To disambiguate this, back up the pc when we know it is a return + // address. + if (isReturnAddress) + --pc; + + // Ask address space object to find unwind sections for this pc. + UnwindInfoSections sects; + if (_addressSpace.findUnwindSections(pc, sects)) { +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + // If there is a compact unwind encoding table, look there first. + if (sects.compact_unwind_section != 0) { + if (this->getInfoFromCompactEncodingSection(pc, sects)) { + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + // Found info in table, done unless encoding says to use dwarf. + uint32_t dwarfOffset; + if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { + if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { + // found info in dwarf, done + return; + } + } + #endif + // If unwind table has entry, but entry says there is no unwind info, + // record that we have no unwind info. + if (_info.format == 0) + _unwindInfoMissing = true; + return; + } + } +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + // If there is SEH unwind info, look there next. + if (this->getInfoFromSEH(pc)) + return; +#endif + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + // If there is dwarf unwind info, look there next. + if (sects.dwarf_section != 0) { + if (this->getInfoFromDwarfSection(pc, sects)) { + // found info in dwarf, done + return; + } + } +#endif + +#if defined(_LIBUNWIND_ARM_EHABI) + // If there is ARM EHABI unwind info, look there next. + if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) + return; +#endif + } + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + // There is no static unwind info for this pc. Look to see if an FDE was + // dynamically registered for it. + pint_t cachedFDE = DwarfFDECache::findFDE(DwarfFDECache::kSearchAll, + pc); + if (cachedFDE != 0) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + if (!CFI_Parser::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo)) + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0)) + return; + } + + // Lastly, ask AddressSpace object about platform specific ways to locate + // other FDEs. + pint_t fde; + if (_addressSpace.findOtherFDE(pc, fde)) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + if (!CFI_Parser::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { + // Double check this FDE is for a function that includes the pc. + if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0)) + return; + } + } +#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + + // no unwind info, flag that we can't reliably unwind + _unwindInfoMissing = true; } -}; // namespace libunwind +template +int UnwindCursor::step() { + // Bottom of stack is defined is when unwind info cannot be found. + if (_unwindInfoMissing) + return UNW_STEP_END; + // Use unwinding info to modify register set as if function returned. + int result; +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + result = this->stepWithCompactEncoding(); +#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + result = this->stepWithSEHData(); +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + result = this->stepWithDwarfFDE(); +#elif defined(_LIBUNWIND_ARM_EHABI) + result = this->stepWithEHABI(); +#else + #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ + _LIBUNWIND_SUPPORT_SEH_UNWIND or \ + _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ + _LIBUNWIND_ARM_EHABI +#endif + + // update info based on new PC + if (result == UNW_STEP_SUCCESS) { + this->setInfoBasedOnIPRegister(true); + if (_unwindInfoMissing) + return UNW_STEP_END; + } + + return result; +} + +template +void UnwindCursor::getInfo(unw_proc_info_t *info) { + if (_unwindInfoMissing) + memset(info, 0, sizeof(*info)); + else + *info = _info; +} + +template +bool UnwindCursor::getFunctionName(char *buf, size_t bufLen, + unw_word_t *offset) { + typename R::reg_t pc = this->getReg(UNW_REG_IP); + + _registers.normalizeExistingLinkRegister(pc); + + return _addressSpace.findFunctionName(pc, buf, bufLen, offset); +} + +} // namespace libunwind #endif // __UNWINDCURSOR_HPP__ - - - - diff --git a/libunwind/src/UnwindLevel1-gcc-ext.c b/libunwind/src/UnwindLevel1-gcc-ext.c index 4147aaf..310b836 100644 --- a/libunwind/src/UnwindLevel1-gcc-ext.c +++ b/libunwind/src/UnwindLevel1-gcc-ext.c @@ -1,306 +1,326 @@ -/* -*- mode: C++; c-basic-offset: 4; -*- - * - * Copyright (c) 2008-2010 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * Implements gcc extensions to the C++ ABI Exception Handling Level 1 as documented at: - * - * using libunwind - * - */ - -#include +//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements gcc extensions to the C++ ABI Exception Handling Level 1. +// +//===----------------------------------------------------------------------===// + +#include #include -#include +#include #include +#include +#include +#include "config.h" +#include "libunwind_ext.h" #include "libunwind.h" +#include "Unwind-EHABI.h" #include "unwind.h" -#include "libunwind_priv.h" -#include "InternalMacros.h" +#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) -#if __ppc__ || __i386__ || __x86_64__ +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +#define private_1 private_[0] +#endif -// -// Called by __cxa_rethrow() -// -EXPORT _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1); - // if this is non-forced and a stopping place was found, then this is a re-throw - // call _Unwind_RaiseException() as if this was a new exception - if ( exception_object->private_1 == 0 ) { - return _Unwind_RaiseException(exception_object); - // should return if there is no catch clause, so that __cxa_rethrow can call std::terminate() - } - - // call through to _Unwind_Resume() which distiguishes between forced and regular exceptions - _Unwind_Resume(exception_object); - ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException() which unexpectedly returned"); +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { +#if defined(_LIBUNWIND_ARM_EHABI) + _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld", + (void *)exception_object, + (long)exception_object->unwinder_cache.reserved1); +#else + _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR, + (void *)exception_object, + (intptr_t)exception_object->private_1); +#endif + +#if defined(_LIBUNWIND_ARM_EHABI) + // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, + // which is in the same position as private_1 below. + return _Unwind_RaiseException(exception_object); +#else + // If this is non-forced and a stopping place was found, then this is a + // re-throw. + // Call _Unwind_RaiseException() as if this was a new exception + if (exception_object->private_1 == 0) { + return _Unwind_RaiseException(exception_object); + // Will return if there is no catch clause, so that __cxa_rethrow can call + // std::terminate(). + } + + // Call through to _Unwind_Resume() which distiguishes between forced and + // regular exceptions. + _Unwind_Resume(exception_object); + _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()" + " which unexpectedly returned"); +#endif } -// -// Called by personality handler during phase 2 to get base address for data relative encodings -// -EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) -{ - DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context); - ABORT("_Unwind_GetDataRelBase() not implemented"); -} - -// -// Called by personality handler during phase 2 to get base address for text relative encodings -// -EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) -{ - DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context); - ABORT("_Unwind_GetTextRelBase() not implemented"); +/// Called by personality handler during phase 2 to get base address for data +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetDataRelBase(struct _Unwind_Context *context) { + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); } - -// -// Scans unwind information to find the function that contains the -// specified code address "pc". -// -EXPORT void* _Unwind_FindEnclosingFunction(void* pc) -{ - DEBUG_PRINT_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc); - // This is slow, but works. - // We create an unwind cursor then alter the IP to be pc - unw_cursor_t cursor; - unw_context_t uc; - unw_proc_info_t info; - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc); - if ( unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS ) - return (void*)(long)info.start_ip; - else - return NULL; +/// Called by personality handler during phase 2 to get base address for text +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetTextRelBase(struct _Unwind_Context *context) { + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); } -// -// Walk every frame and call trace function at each one. If trace function -// returns anything other than _URC_NO_REASON, then walk is terminated. -// -EXPORT _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void* ref) -{ - unw_cursor_t cursor; - unw_context_t uc; - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - - DEBUG_PRINT_API("_Unwind_Backtrace(callback=%p)\n", callback); +/// Scans unwind information to find the function that contains the +/// specified code address "pc". +_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { + _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc); + // This is slow, but works. + // We create an unwind cursor then alter the IP to be pc + unw_cursor_t cursor; + unw_context_t uc; + unw_proc_info_t info; + __unw_getcontext(&uc); + __unw_init_local(&cursor, &uc); + __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc); + if (__unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) + return (void *)(intptr_t) info.start_ip; + else + return NULL; +} - // walk each frame - while ( true ) { +/// Walk every frame and call trace function at each one. If trace function +/// returns anything other than _URC_NO_REASON, then walk is terminated. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { + unw_cursor_t cursor; + unw_context_t uc; + __unw_getcontext(&uc); + __unw_init_local(&cursor, &uc); - // ask libuwind to get next frame (skip over first frame which is _Unwind_Backtrace()) - if ( unw_step(&cursor) <= 0 ) { - DEBUG_PRINT_UNWINDING(" _backtrace: ended because cursor reached bottom of stack, returning %d\n", _URC_END_OF_STACK); - return _URC_END_OF_STACK; - } - - // debugging - if ( DEBUG_PRINT_UNWINDING_TEST ) { - char functionName[512]; - unw_proc_info_t frameInfo; - unw_word_t offset; - unw_get_proc_name(&cursor, functionName, 512, &offset); - unw_get_proc_info(&cursor, &frameInfo); - DEBUG_PRINT_UNWINDING(" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n", - frameInfo.start_ip, functionName, frameInfo.lsda, &cursor); - } - - // call trace function with this frame - _Unwind_Reason_Code result = (*callback)((struct _Unwind_Context*)(&cursor), ref); - if ( result != _URC_NO_REASON ) { - DEBUG_PRINT_UNWINDING(" _backtrace: ended because callback returned %d\n", result); - return result; - } - } + _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)", + (void *)(uintptr_t)callback); + +#if defined(_LIBUNWIND_ARM_EHABI) + // Create a mock exception object for force unwinding. + _Unwind_Exception ex; + memset(&ex, '\0', sizeof(ex)); + ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0 +#endif + + // walk each frame + while (true) { + _Unwind_Reason_Code result; + +#if !defined(_LIBUNWIND_ARM_EHABI) + // ask libunwind to get next frame (skip over first frame which is + // _Unwind_Backtrace()) + if (__unw_step(&cursor) <= 0) { + _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached " + "bottom of stack, returning %d", + _URC_END_OF_STACK); + return _URC_END_OF_STACK; + } +#else + // Get the information for this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) { + return _URC_END_OF_STACK; + } + + // Update the pr_cache in the mock exception object. + const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info; + ex.pr_cache.fnstart = frameInfo.start_ip; + ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo; + ex.pr_cache.additional= frameInfo.flags; + + struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor; + // Get and call the personality function to unwind the frame. + _Unwind_Personality_Fn handler = (_Unwind_Personality_Fn)frameInfo.handler; + if (handler == NULL) { + return _URC_END_OF_STACK; + } + if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) != + _URC_CONTINUE_UNWIND) { + return _URC_END_OF_STACK; + } +#endif // defined(_LIBUNWIND_ARM_EHABI) + + // debugging + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_proc_info_t frame; + unw_word_t offset; + __unw_get_proc_name(&cursor, functionName, 512, &offset); + __unw_get_proc_info(&cursor, &frame); + _LIBUNWIND_TRACE_UNWINDING( + " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p", + frame.start_ip, functionName, frame.lsda, + (void *)&cursor); + } + + // call trace function with this frame + result = (*callback)((struct _Unwind_Context *)(&cursor), ref); + if (result != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + " _backtrace: ended because callback returned %d", result); + return result; + } + } } -// -// Find dwarf unwind info for an address 'pc' in some function. -// -EXPORT const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases* bases) -{ - // This is slow, but works. - // We create an unwind cursor then alter the IP to be pc - unw_cursor_t cursor; - unw_context_t uc; - unw_proc_info_t info; - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc); - unw_get_proc_info(&cursor, &info); - bases->tbase = info.extra; - bases->dbase = 0; // dbase not used on Mac OS X - bases->func = info.start_ip; - DEBUG_PRINT_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, (void*)(long)info.unwind_info); - return (void*)(long)info.unwind_info; +/// Find DWARF unwind info for an address 'pc' in some function. +_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, + struct dwarf_eh_bases *bases) { + // This is slow, but works. + // We create an unwind cursor then alter the IP to be pc + unw_cursor_t cursor; + unw_context_t uc; + unw_proc_info_t info; + __unw_getcontext(&uc); + __unw_init_local(&cursor, &uc); + __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc); + __unw_get_proc_info(&cursor, &info); + bases->tbase = (uintptr_t)info.extra; + bases->dbase = 0; // dbase not used on Mac OS X + bases->func = (uintptr_t)info.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc, + (void *)(intptr_t) info.unwind_info); + return (void *)(intptr_t) info.unwind_info; +} + +/// Returns the CFA (call frame area, or stack pointer at start of function) +/// for the current context. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + __unw_get_reg(cursor, UNW_REG_SP, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return (uintptr_t)result; } +/// Called by personality handler during phase 2 to get instruction pointer. +/// ipBefore is a boolean that says if IP is already adjusted to be the call +/// site address. Normally IP is the return address. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore) { + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context); + int isSignalFrame = __unw_is_signal_frame((unw_cursor_t *)context); + // Negative means some kind of error (probably UNW_ENOINFO), but we have no + // good way to report that, and this maintains backward compatibility with the + // implementation that hard-coded zero in every case, even signal frames. + if (isSignalFrame <= 0) + *ipBefore = 0; + else + *ipBefore = 1; + return _Unwind_GetIP(context); +} -EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context) -{ - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_word_t result; - unw_get_reg(cursor, UNW_REG_SP, &result); - DEBUG_PRINT_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, (uint64_t)result); - return result; +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +/// Called by programs with dynamic code generators that want +/// to register a dynamically generated FDE. +/// This function has existed on Mac OS X since 10.4, but +/// was broken until 10.6. +_LIBUNWIND_EXPORT void __register_frame(const void *fde) { + _LIBUNWIND_TRACE_API("__register_frame(%p)", fde); + __unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde); } -// -// Called by personality handler during phase 2 to get instruction pointer. -// ipBefore is a boolean that says if IP is already adjusted to be the call -// site address. Normally IP is the return address. -// -EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore) -{ - DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p)\n", context); - *ipBefore = 0; - return _Unwind_GetIP(context); +/// Called by programs with dynamic code generators that want +/// to unregister a dynamically generated FDE. +/// This function has existed on Mac OS X since 10.4, but +/// was broken until 10.6. +_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { + _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde); + __unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde); } -// -// Called by programs with dynamic code generators that want -// to register a dynamically generated FDE. -// This function has existed on Mac OS X since 10.4, but -// never worked before. -// -EXPORT void __register_frame(const void* fde) -{ - DEBUG_PRINT_API("__register_frame(%p)\n", fde); - _unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde); -} - - -// -// Called by programs with dynamic code generators that want -// to unregister a dynamically generated FDE. -// This function has existed on Mac OS X since 10.4, but -// never worked before. -// -EXPORT void __deregister_frame(const void* fde) -{ - DEBUG_PRINT_API("__deregister_frame(%p)\n", fde); - _unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde); -} - - - -// -// The following register/deregister functions are gcc extensions. +// The following register/deregister functions are gcc extensions. // They have existed on Mac OS X, but have never worked because Mac OS X // before 10.6 used keymgr to track known FDEs, but these functions // never got updated to use keymgr. // For now, we implement these as do-nothing functions to keep any existing // applications working. We also add the not in 10.6 symbol so that nwe // application won't be able to use them. -// -EXPORT void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db) -{ - DEBUG_PRINT_API("__register_frame_info_bases(%p,%p, %p, %p)\n", fde, ob, tb, db); - // do nothing, this function never worked in Mac OS X +#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS) +_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob, + void *tb, void *db) { + (void)fde; + (void)ob; + (void)tb; + (void)db; + _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)", + fde, ob, tb, db); + // do nothing, this function never worked in Mac OS X } -EXPORT void __register_frame_info(const void* fde, void* ob) -{ - DEBUG_PRINT_API("__register_frame_info(%p, %p)\n", fde, ob); - // do nothing, this function never worked in Mac OS X +_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) { + (void)fde; + (void)ob; + _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob); + // do nothing, this function never worked in Mac OS X } - -EXPORT void __register_frame_info_table_bases(const void* fde, void* ob, void* tb, void* db) -{ - DEBUG_PRINT_API("__register_frame_info_table_bases(%p,%p, %p, %p)\n", fde, ob, tb, db); - // do nothing, this function never worked in Mac OS X +_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde, + void *ob, void *tb, + void *db) { + (void)fde; + (void)ob; + (void)tb; + (void)db; + _LIBUNWIND_TRACE_API("__register_frame_info_table_bases" + "(%p,%p, %p, %p)", fde, ob, tb, db); + // do nothing, this function never worked in Mac OS X } -EXPORT void __register_frame_info_table(const void* fde, void* ob) -{ - DEBUG_PRINT_API("__register_frame_info_table(%p, %p)\n", fde, ob); - // do nothing, this function never worked in Mac OS X +_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) { + (void)fde; + (void)ob; + _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob); + // do nothing, this function never worked in Mac OS X } -EXPORT void __register_frame_table(const void* fde) -{ - DEBUG_PRINT_API("__register_frame_table(%p)\n", fde); - // do nothing, this function never worked in Mac OS X +_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde); + // do nothing, this function never worked in Mac OS X } -EXPORT void* __deregister_frame_info(const void* fde) -{ - DEBUG_PRINT_API("__deregister_frame_info(%p)\n", fde); - // do nothing, this function never worked in Mac OS X - return NULL; +_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde); + // do nothing, this function never worked in Mac OS X + return NULL; } -EXPORT void* __deregister_frame_info_bases(const void* fde) -{ - DEBUG_PRINT_API("__deregister_frame_info_bases(%p)\n", fde); - // do nothing, this function never worked in Mac OS X - return NULL; +_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde); + // do nothing, this function never worked in Mac OS X + return NULL; } +#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS) +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) - - -// -// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions -// -NOT_HERE_BEFORE_10_6(_Unwind_Backtrace) -NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction) -NOT_HERE_BEFORE_10_6(_Unwind_GetCFA) -NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase) -NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase) -NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow) -NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo) - -NOT_HERE_BEFORE_10_6(__register_frame) -NOT_HERE_BEFORE_10_6(__deregister_frame) - - -// -// symbols in libSystem.dylib for compatibility, but we don't want any new code using them -// -NEVER_HERE(__register_frame_info_bases) -NEVER_HERE(__register_frame_info) -NEVER_HERE(__register_frame_info_table_bases) -NEVER_HERE(__register_frame_info_table) -NEVER_HERE(__register_frame_table) -NEVER_HERE(__deregister_frame_info) -NEVER_HERE(__deregister_frame_info_bases) - - -#endif // __ppc__ || __i386__ || __x86_64__ - +#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c index 422491e..add4caa 100644 --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -1,455 +1,518 @@ -/* -*- mode: C++; c-basic-offset: 4; -*- - * - * Copyright (c) 2008-2010 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * - * Implements C++ ABI Exception Handling Level 1 as documented at: - * - * using libunwind - * - */ +//===------------------------- UnwindLevel1.c -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements C++ ABI Exception Handling Level 1 as documented at: +// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html +// using libunwind +// +//===----------------------------------------------------------------------===// +// ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are +// defining inline functions to delegate the function calls to +// _Unwind_VRS_{Get,Set}(). However, some applications might declare the +// function protetype directly (instead of including ), thus we need +// to export these functions from libunwind.so as well. +#define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 + +#include #include #include #include #include #include +#include "config.h" #include "libunwind.h" +#include "libunwind_ext.h" #include "unwind.h" -#include "InternalMacros.h" -#if __ppc__ || __i386__ || __x86_64__ -static _Unwind_Reason_Code unwind_phase1(unw_context_t* uc, struct _Unwind_Exception* exception_object) -{ - unw_cursor_t cursor1; - unw_init_local(&cursor1, uc); - - // walk each frame looking for a place to stop - for (bool handlerNotFound = true; handlerNotFound; ) { +#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) - // ask libuwind to get next frame (skip over first which is _Unwind_RaiseException) - int stepResult = unw_step(&cursor1); - if ( stepResult == 0 ) { - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object); - return _URC_END_OF_STACK; - } - else if ( stepResult < 0 ) { - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); - return _URC_FATAL_PHASE1_ERROR; - } - - // see if frame has code to run (has personality routine) - unw_proc_info_t frameInfo; - unw_word_t sp; - if ( unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS ) { - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); - return _URC_FATAL_PHASE1_ERROR; - } - - // debugging - if ( DEBUG_PRINT_UNWINDING_TEST ) { - char functionName[512]; - unw_word_t offset; - if ( (unw_get_proc_name(&cursor1, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) ) - strcpy(functionName, ".anonymous."); - unw_word_t pc; - unw_get_reg(&cursor1, UNW_REG_IP, &pc); - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n", - exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); - } - - // if there is a personality routine, ask it if it will want to stop at this frame - if ( frameInfo.handler != 0 ) { - __personality_routine p = (__personality_routine)(long)(frameInfo.handler); - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, p); - _Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)(&cursor1)); - switch ( personalityResult ) { - case _URC_HANDLER_FOUND: - // found a catch clause or locals that need destructing in this frame - // stop search and remember stack pointer at the frame - handlerNotFound = false; - unw_get_reg(&cursor1, UNW_REG_SP, &sp); - exception_object->private_2 = sp; - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object); - return _URC_NO_REASON; - - case _URC_CONTINUE_UNWIND: - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); - // continue unwinding - break; - - default: - // something went wrong - DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object); - return _URC_FATAL_PHASE1_ERROR; - } - } - } - return _URC_NO_REASON; +#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND + +static _Unwind_Reason_Code +unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + __unw_init_local(cursor, uc); + + // Walk each frame looking for a place to stop. + bool handlerNotFound = true; + while (handlerNotFound) { + // Ask libunwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = __unw_step(cursor); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_step failed => " + "_URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // See if frame has code to run (has personality routine). + unw_proc_info_t frameInfo; + unw_word_t sp; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", + (void *)exception_object, pc, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // If there is a personality routine, ask it if it will want to stop at + // this frame. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember stack pointer at the frame + handlerNotFound = false; + __unw_get_reg(cursor, UNW_REG_SP, &sp); + exception_object->private_2 = (uintptr_t)sp; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", + (void *)exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", + (void *)exception_object); + // continue unwinding + break; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; } -static _Unwind_Reason_Code unwind_phase2(unw_context_t* uc, struct _Unwind_Exception* exception_object) -{ - unw_cursor_t cursor2; - unw_init_local(&cursor2, uc); - - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); - - // walk each frame until we reach where search phase said to stop - while ( true ) { +static _Unwind_Reason_Code +unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + __unw_init_local(cursor, uc); - // ask libuwind to get next frame (skip over first which is _Unwind_RaiseException) - int stepResult = unw_step(&cursor2); - if ( stepResult == 0 ) { - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object); - return _URC_END_OF_STACK; - } - else if ( stepResult < 0 ) { - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); - return _URC_FATAL_PHASE2_ERROR; - } - - // get info about this frame - unw_word_t sp; - unw_proc_info_t frameInfo; - unw_get_reg(&cursor2, UNW_REG_SP, &sp); - if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) { - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); - return _URC_FATAL_PHASE2_ERROR; - } - - // debugging - if ( DEBUG_PRINT_UNWINDING_TEST ) { - char functionName[512]; - unw_word_t offset; - if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) ) - strcpy(functionName, ".anonymous."); - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, lsda=0x%llX, personality=0x%llX\n", - exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); - } - - // if there is a personality routine, tell it we are unwinding - if ( frameInfo.handler != 0 ) { - __personality_routine p = (__personality_routine)(long)(frameInfo.handler); - _Unwind_Action action = _UA_CLEANUP_PHASE; - if ( sp == exception_object->private_2 ) - action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1 - _Unwind_Reason_Code personalityResult = (*p)(1, action, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)(&cursor2)); - switch ( personalityResult ) { - case _URC_CONTINUE_UNWIND: - // continue unwinding - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); - if ( sp == exception_object->private_2 ) { - // phase 1 said we would stop at this frame, but we did not... - ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here"); - } - break; - case _URC_INSTALL_CONTEXT: - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object); - // personality routine says to transfer control to landing pad - // we may get control back if landing pad calls _Unwind_Resume() - if ( DEBUG_PRINT_UNWINDING_TEST ) { - unw_word_t pc; - unw_word_t sp; - unw_get_reg(&cursor2, UNW_REG_IP, &pc); - unw_get_reg(&cursor2, UNW_REG_SP, &sp); - DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp); - } - unw_resume(&cursor2); - // unw_resume() only returns if there was an error - return _URC_FATAL_PHASE2_ERROR; - default: - // something went wrong - DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult); - return _URC_FATAL_PHASE2_ERROR; - } - } - } + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", + (void *)exception_object); - // clean up phase did not resume at the frame that the search phase said it would - return _URC_FATAL_PHASE2_ERROR; + // Walk each frame until we reach where search phase said to stop. + while (true) { + + // Ask libunwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = __unw_step(cursor); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step failed => " + "_URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // Get info about this frame. + unw_word_t sp; + unw_proc_info_t frameInfo; + __unw_get_reg(cursor, UNW_REG_SP, &sp); + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR + ", personality=0x%" PRIxPTR, + (void *)exception_object, frameInfo.start_ip, + functionName, sp, frameInfo.lsda, + frameInfo.handler); + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + _Unwind_Action action = _UA_CLEANUP_PHASE; + if (sp == exception_object->private_2) { + // Tell personality this was the frame it marked in phase 1. + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); + } + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // Continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", + (void *)exception_object); + if (sp == exception_object->private_2) { + // Phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now in phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", + (void *)exception_object); + // Personality routine says to transfer control to landing pad. + // We may get control back if landing pad calls _Unwind_Resume(). + if (_LIBUNWIND_TRACING_UNWINDING) { + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + __unw_get_reg(cursor, UNW_REG_SP, &sp); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " + "user code with ip=0x%" PRIxPTR + ", sp=0x%" PRIxPTR, + (void *)exception_object, pc, sp); + } + __unw_resume(cursor); + // __unw_resume() only returns if there was an error. + return _URC_FATAL_PHASE2_ERROR; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Clean up phase did not resume at the frame that the search phase + // said it would... + return _URC_FATAL_PHASE2_ERROR; +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + __unw_init_local(cursor, uc); + + // Walk each frame until we reach where search phase said to stop + while (__unw_step(cursor) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + __unw_resume(cursor); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; } -static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t* uc, struct _Unwind_Exception* exception_object, - _Unwind_Stop_Fn stop, void* stop_parameter) -{ - unw_cursor_t cursor2; - unw_init_local(&cursor2, uc); - - // walk each frame until we reach where search phase said to stop - while ( unw_step(&cursor2) > 0 ) { - - // get info about this frame - unw_proc_info_t frameInfo; - if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) { - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step failed => _URC_END_OF_STACK\n", exception_object); - return _URC_FATAL_PHASE1_ERROR; - } - - // debugging - if ( DEBUG_PRINT_UNWINDING_TEST ) { - char functionName[512]; - unw_word_t offset; - if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) ) - strcpy(functionName, ".anonymous."); - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n", - exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); - } - - // call stop function at each frame - _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE); - _Unwind_Reason_Code stopResult = (*stop)(1, action, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)(&cursor2), stop_parameter); - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult); - if ( stopResult != _URC_NO_REASON ) { - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object); - return _URC_FATAL_PHASE2_ERROR; - } - - // if there is a personality routine, tell it we are unwinding - if ( frameInfo.handler != 0 ) { - __personality_routine p = (__personality_routine)(long)(frameInfo.handler); - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p); - _Unwind_Reason_Code personalityResult = (*p)(1, action, - exception_object->exception_class, exception_object, - (struct _Unwind_Context*)(&cursor2)); - switch ( personalityResult ) { - case _URC_CONTINUE_UNWIND: - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object); - // destructors called, continue unwinding - break; - case _URC_INSTALL_CONTEXT: - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object); - // we may get control back if landing pad calls _Unwind_Resume() - unw_resume(&cursor2); - break; - default: - // something went wrong - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n", - exception_object, personalityResult); - return _URC_FATAL_PHASE2_ERROR; - } - } - } +/// Called by __cxa_throw. Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + (void *)exception_object); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); - // call stop function one last time and tell it we've reached the end of the stack - DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object); - _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK); - (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)(&cursor2), stop_parameter); - - // clean up phase did not resume at the frame that the search phase said it would - return _URC_FATAL_PHASE2_ERROR; -} + // Mark that this is a non-forced unwind, so _Unwind_Resume() + // can do the right thing. + exception_object->private_1 = 0; + exception_object->private_2 = 0; + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; -// -// Called by __cxa_throw. Only returns if there is a fatal error -// -EXPORT _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_RaiseException(ex_obj=%p)\n", exception_object); - unw_context_t uc; - unw_getcontext(&uc); - - // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing - exception_object->private_1 = 0; - exception_object->private_2 = 0; - - // phase 1: the search phase - _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object); - if ( phase1 != _URC_NO_REASON ) - return phase1; - - // phase 2: the clean up phase - return unwind_phase2(&uc, exception_object); -} - - -// -// When _Unwind_RaiseException() is in phase2, it hands control -// to the personality function at each frame. The personality -// may force a jump to a landing pad in that function, the landing -// pad code may then call _Unwind_Resume() to continue with the -// unwinding. Note: the call to _Unwind_Resume() is from compiler -// geneated user code. All other _Unwind_* routines are called -// by the C++ runtime __cxa_* routines. -// -// Re-throwing an exception is implemented by having the code call -// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() -// -EXPORT void _Unwind_Resume(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_Resume(ex_obj=%p)\n", exception_object); - unw_context_t uc; - unw_getcontext(&uc); - - if ( exception_object->private_1 != 0 ) - unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2); - else - unwind_phase2(&uc, exception_object); - - // clients assume _Unwind_Resume() does not return, so all we can do is abort. - ABORT("_Unwind_Resume() can't return"); + // phase 2: the clean up phase + return unwind_phase2(&uc, &cursor, exception_object); } -// -// Not used by C++. -// Unwinds stack, calling "stop" function at each frame -// Could be used to implement longjmp(). -// -EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter) -{ - DEBUG_PRINT_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", exception_object, stop); - unw_context_t uc; - unw_getcontext(&uc); +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call __cxa_rethrow() which +/// in turn calls _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); - // mark that this is a forced unwind, so _Unwind_Resume() can do the right thing - exception_object->private_1 = (uintptr_t)stop; - exception_object->private_2 = (uintptr_t)stop_parameter; - - // doit - return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); -} + if (exception_object->private_1 != 0) + unwind_phase2_forced(&uc, &cursor, exception_object, + (_Unwind_Stop_Fn) exception_object->private_1, + (void *)exception_object->private_2); + else + unwind_phase2(&uc, &cursor, exception_object); - -// -// Called by personality handler during phase 2 to get LSDA for current frame -// -EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context) -{ - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_proc_info_t frameInfo; - uintptr_t result = 0; - if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS ) - result = frameInfo.lsda; - DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result); - if ( result != 0 ) { - if ( *((uint8_t*)result) != 0xFF ) - DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result); - } - return result; -} - - -// -// Called by personality handler during phase 2 to get register values -// -EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index) -{ - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_word_t result; - unw_get_reg(cursor, index, &result); - DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n", context, index, (uint64_t)result); - return result; -} - - -// -// Called by personality handler during phase 2 to alter register values -// -EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value) -{ - DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0llX)\n", context, index, (uint64_t)new_value); - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_set_reg(cursor, index, new_value); -} - - -// -// Called by personality handler during phase 2 to get instruction pointer -// -EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context) -{ - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_word_t result; - unw_get_reg(cursor, UNW_REG_IP, &result); - DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context, (uint64_t)result); - return result; -} - - -// -// Called by personality handler during phase 2 to alter instruction pointer -// -EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value) -{ - DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", context, (uint64_t)new_value); - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_set_reg(cursor, UNW_REG_IP, new_value); -} - - -// -// Called by personality handler during phase 2 to find the start of the function -// -EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context) -{ - unw_cursor_t* cursor = (unw_cursor_t*)context; - unw_proc_info_t frameInfo; - uintptr_t result = 0; - if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS ) - result = frameInfo.start_ip; - DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result); - return result; -} - - -// -// Called by personality handler during phase 2 if a foreign exception is caught -// -EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object) -{ - DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object); - if ( exception_object->exception_cleanup != NULL ) - (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object); + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); } +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); -// -// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions -// -NOT_HERE_BEFORE_10_6(_Unwind_DeleteException) -NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE) -NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind) -NOT_HERE_BEFORE_10_6(_Unwind_GetGR) -NOT_HERE_BEFORE_10_6(_Unwind_GetIP) -NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData) -NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart) -NOT_HERE_BEFORE_10_6(_Unwind_RaiseException) -NOT_HERE_BEFORE_10_6(_Unwind_Resume) -NOT_HERE_BEFORE_10_6(_Unwind_SetGR) -NOT_HERE_BEFORE_10_6(_Unwind_SetIP) + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->private_1 = (uintptr_t) stop; + exception_object->private_2 = (uintptr_t) stop_parameter; -#endif // __ppc__ || __i386__ || __x86_64__ + // do it + return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter); +} + + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.lsda; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + if (result != 0) { + if (*((uint8_t *)result) != 0xFF) + _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF", + result); + } + return result; +} + + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND + +/// Called by personality handler during phase 2 if a foreign exception +// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", + (void *)exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + +/// Called by personality handler during phase 2 to get register values. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetGR(struct _Unwind_Context *context, int index) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + __unw_get_reg(cursor, index, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, + (void *)context, index, result); + return (uintptr_t)result; +} + +/// Called by personality handler during phase 2 to alter register values. +_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t value) { + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR + ")", + (void *)context, index, value); + unw_cursor_t *cursor = (unw_cursor_t *)context; + __unw_set_reg(cursor, index, value); +} + +/// Called by personality handler during phase 2 to get instruction pointer. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + __unw_get_reg(cursor, UNW_REG_IP, &result); + + + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return (uintptr_t)result; +} + +/// Called by personality handler during phase 2 to alter instruction pointer, +/// such as setting where the landing pad is, so _Unwind_Resume() will +/// start executing in the landing pad. +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t value) { + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")", + (void *)context, value); + unw_cursor_t *cursor = (unw_cursor_t *)context; + __unw_set_reg(cursor, UNW_REG_IP, value); +} + +#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S new file mode 100644 index 0000000..88a10c0 --- /dev/null +++ b/libunwind/src/UnwindRegistersRestore.S @@ -0,0 +1,1157 @@ +//===-------------------- UnwindRegistersRestore.S ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "assembly.h" + + .text + +#if !defined(__USING_SJLJ_EXCEPTIONS__) + +#if defined(__i386__) +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto) +# +# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); +# +# On entry: +# + + +# +-----------------------+ +# + thread_state pointer + +# +-----------------------+ +# + return address + +# +-----------------------+ <-- SP +# + + + movl 4(%esp), %eax + # set up eax and ret on new stack location + movl 28(%eax), %edx # edx holds new stack pointer + subl $8,%edx + movl %edx, 28(%eax) + movl 0(%eax), %ebx + movl %ebx, 0(%edx) + movl 40(%eax), %ebx + movl %ebx, 4(%edx) + # we now have ret and eax pushed onto where new stack will be + # restore all registers + movl 4(%eax), %ebx + movl 8(%eax), %ecx + movl 12(%eax), %edx + movl 16(%eax), %edi + movl 20(%eax), %esi + movl 24(%eax), %ebp + movl 28(%eax), %esp + # skip ss + # skip eflags + pop %eax # eax was already pushed on new stack + ret # eip was already pushed on new stack + # skip cs + # skip ds + # skip es + # skip fs + # skip gs + +#elif defined(__x86_64__) + +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) +# +# extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); +# +#if defined(_WIN64) +# On entry, thread_state pointer is in rcx; move it into rdi +# to share restore code below. Since this routine restores and +# overwrites all registers, we can use the same registers for +# pointers and temporaries as on unix even though win64 normally +# mustn't clobber some of them. + movq %rcx, %rdi +#else +# On entry, thread_state pointer is in rdi +#endif + + movq 56(%rdi), %rax # rax holds new stack pointer + subq $16, %rax + movq %rax, 56(%rdi) + movq 32(%rdi), %rbx # store new rdi on new stack + movq %rbx, 0(%rax) + movq 128(%rdi), %rbx # store new rip on new stack + movq %rbx, 8(%rax) + # restore all registers + movq 0(%rdi), %rax + movq 8(%rdi), %rbx + movq 16(%rdi), %rcx + movq 24(%rdi), %rdx + # restore rdi later + movq 40(%rdi), %rsi + movq 48(%rdi), %rbp + # restore rsp later + movq 64(%rdi), %r8 + movq 72(%rdi), %r9 + movq 80(%rdi), %r10 + movq 88(%rdi), %r11 + movq 96(%rdi), %r12 + movq 104(%rdi), %r13 + movq 112(%rdi), %r14 + movq 120(%rdi), %r15 + # skip rflags + # skip cs + # skip fs + # skip gs + +#if defined(_WIN64) + movdqu 176(%rdi),%xmm0 + movdqu 192(%rdi),%xmm1 + movdqu 208(%rdi),%xmm2 + movdqu 224(%rdi),%xmm3 + movdqu 240(%rdi),%xmm4 + movdqu 256(%rdi),%xmm5 + movdqu 272(%rdi),%xmm6 + movdqu 288(%rdi),%xmm7 + movdqu 304(%rdi),%xmm8 + movdqu 320(%rdi),%xmm9 + movdqu 336(%rdi),%xmm10 + movdqu 352(%rdi),%xmm11 + movdqu 368(%rdi),%xmm12 + movdqu 384(%rdi),%xmm13 + movdqu 400(%rdi),%xmm14 + movdqu 416(%rdi),%xmm15 +#endif + movq 56(%rdi), %rsp # cut back rsp to new location + pop %rdi # rdi was saved here earlier + ret # rip was saved here + + +#elif defined(__powerpc64__) + +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv) +// +// void libunwind::Registers_ppc64::jumpto() +// +// On entry: +// thread_state pointer is in r3 +// + +// load register (GPR) +#define PPC64_LR(n) \ + ld %r##n, (8 * (n + 2))(%r3) + + // restore integral registers + // skip r0 for now + // skip r1 for now + PPC64_LR(2) + // skip r3 for now + // skip r4 for now + // skip r5 for now + PPC64_LR(6) + PPC64_LR(7) + PPC64_LR(8) + PPC64_LR(9) + PPC64_LR(10) + PPC64_LR(11) + PPC64_LR(12) + PPC64_LR(13) + PPC64_LR(14) + PPC64_LR(15) + PPC64_LR(16) + PPC64_LR(17) + PPC64_LR(18) + PPC64_LR(19) + PPC64_LR(20) + PPC64_LR(21) + PPC64_LR(22) + PPC64_LR(23) + PPC64_LR(24) + PPC64_LR(25) + PPC64_LR(26) + PPC64_LR(27) + PPC64_LR(28) + PPC64_LR(29) + PPC64_LR(30) + PPC64_LR(31) + +#ifdef PPC64_HAS_VMX + + // restore VS registers + // (note that this also restores floating point registers and V registers, + // because part of VS is mapped to these registers) + + addi %r4, %r3, PPC64_OFFS_FP + +// load VS register +#define PPC64_LVS(n) \ + lxvd2x %vs##n, 0, %r4 ;\ + addi %r4, %r4, 16 + + // restore the first 32 VS regs (and also all floating point regs) + PPC64_LVS(0) + PPC64_LVS(1) + PPC64_LVS(2) + PPC64_LVS(3) + PPC64_LVS(4) + PPC64_LVS(5) + PPC64_LVS(6) + PPC64_LVS(7) + PPC64_LVS(8) + PPC64_LVS(9) + PPC64_LVS(10) + PPC64_LVS(11) + PPC64_LVS(12) + PPC64_LVS(13) + PPC64_LVS(14) + PPC64_LVS(15) + PPC64_LVS(16) + PPC64_LVS(17) + PPC64_LVS(18) + PPC64_LVS(19) + PPC64_LVS(20) + PPC64_LVS(21) + PPC64_LVS(22) + PPC64_LVS(23) + PPC64_LVS(24) + PPC64_LVS(25) + PPC64_LVS(26) + PPC64_LVS(27) + PPC64_LVS(28) + PPC64_LVS(29) + PPC64_LVS(30) + PPC64_LVS(31) + + // use VRSAVE to conditionally restore the remaining VS regs, + // that are where the V regs are mapped + + ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave + cmpwi %r5, 0 + beq Lnovec + +// conditionally load VS +#define PPC64_CLVS_BOTTOM(n) \ + beq Ldone##n ;\ + addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\ + lxvd2x %vs##n, 0, %r4 ;\ +Ldone##n: + +#define PPC64_CLVSl(n) \ + andis. %r0, %r5, (1<<(47-n)) ;\ +PPC64_CLVS_BOTTOM(n) + +#define PPC64_CLVSh(n) \ + andi. %r0, %r5, (1<<(63-n)) ;\ +PPC64_CLVS_BOTTOM(n) + + PPC64_CLVSl(32) + PPC64_CLVSl(33) + PPC64_CLVSl(34) + PPC64_CLVSl(35) + PPC64_CLVSl(36) + PPC64_CLVSl(37) + PPC64_CLVSl(38) + PPC64_CLVSl(39) + PPC64_CLVSl(40) + PPC64_CLVSl(41) + PPC64_CLVSl(42) + PPC64_CLVSl(43) + PPC64_CLVSl(44) + PPC64_CLVSl(45) + PPC64_CLVSl(46) + PPC64_CLVSl(47) + PPC64_CLVSh(48) + PPC64_CLVSh(49) + PPC64_CLVSh(50) + PPC64_CLVSh(51) + PPC64_CLVSh(52) + PPC64_CLVSh(53) + PPC64_CLVSh(54) + PPC64_CLVSh(55) + PPC64_CLVSh(56) + PPC64_CLVSh(57) + PPC64_CLVSh(58) + PPC64_CLVSh(59) + PPC64_CLVSh(60) + PPC64_CLVSh(61) + PPC64_CLVSh(62) + PPC64_CLVSh(63) + +#else + +// load FP register +#define PPC64_LF(n) \ + lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) + + // restore float registers + PPC64_LF(0) + PPC64_LF(1) + PPC64_LF(2) + PPC64_LF(3) + PPC64_LF(4) + PPC64_LF(5) + PPC64_LF(6) + PPC64_LF(7) + PPC64_LF(8) + PPC64_LF(9) + PPC64_LF(10) + PPC64_LF(11) + PPC64_LF(12) + PPC64_LF(13) + PPC64_LF(14) + PPC64_LF(15) + PPC64_LF(16) + PPC64_LF(17) + PPC64_LF(18) + PPC64_LF(19) + PPC64_LF(20) + PPC64_LF(21) + PPC64_LF(22) + PPC64_LF(23) + PPC64_LF(24) + PPC64_LF(25) + PPC64_LF(26) + PPC64_LF(27) + PPC64_LF(28) + PPC64_LF(29) + PPC64_LF(30) + PPC64_LF(31) + + // restore vector registers if any are in use + ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave + cmpwi %r5, 0 + beq Lnovec + + subi %r4, %r1, 16 + // r4 is now a 16-byte aligned pointer into the red zone + // the _vectorScalarRegisters may not be 16-byte aligned + // so copy via red zone temp buffer + +#define PPC64_CLV_UNALIGNED_BOTTOM(n) \ + beq Ldone##n ;\ + ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\ + std %r0, 0(%r4) ;\ + ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\ + std %r0, 8(%r4) ;\ + lvx %v##n, 0, %r4 ;\ +Ldone ## n: + +#define PPC64_CLV_UNALIGNEDl(n) \ + andis. %r0, %r5, (1<<(15-n)) ;\ +PPC64_CLV_UNALIGNED_BOTTOM(n) + +#define PPC64_CLV_UNALIGNEDh(n) \ + andi. %r0, %r5, (1<<(31-n)) ;\ +PPC64_CLV_UNALIGNED_BOTTOM(n) + + PPC64_CLV_UNALIGNEDl(0) + PPC64_CLV_UNALIGNEDl(1) + PPC64_CLV_UNALIGNEDl(2) + PPC64_CLV_UNALIGNEDl(3) + PPC64_CLV_UNALIGNEDl(4) + PPC64_CLV_UNALIGNEDl(5) + PPC64_CLV_UNALIGNEDl(6) + PPC64_CLV_UNALIGNEDl(7) + PPC64_CLV_UNALIGNEDl(8) + PPC64_CLV_UNALIGNEDl(9) + PPC64_CLV_UNALIGNEDl(10) + PPC64_CLV_UNALIGNEDl(11) + PPC64_CLV_UNALIGNEDl(12) + PPC64_CLV_UNALIGNEDl(13) + PPC64_CLV_UNALIGNEDl(14) + PPC64_CLV_UNALIGNEDl(15) + PPC64_CLV_UNALIGNEDh(16) + PPC64_CLV_UNALIGNEDh(17) + PPC64_CLV_UNALIGNEDh(18) + PPC64_CLV_UNALIGNEDh(19) + PPC64_CLV_UNALIGNEDh(20) + PPC64_CLV_UNALIGNEDh(21) + PPC64_CLV_UNALIGNEDh(22) + PPC64_CLV_UNALIGNEDh(23) + PPC64_CLV_UNALIGNEDh(24) + PPC64_CLV_UNALIGNEDh(25) + PPC64_CLV_UNALIGNEDh(26) + PPC64_CLV_UNALIGNEDh(27) + PPC64_CLV_UNALIGNEDh(28) + PPC64_CLV_UNALIGNEDh(29) + PPC64_CLV_UNALIGNEDh(30) + PPC64_CLV_UNALIGNEDh(31) + +#endif + +Lnovec: + ld %r0, PPC64_OFFS_CR(%r3) + mtcr %r0 + ld %r0, PPC64_OFFS_SRR0(%r3) + mtctr %r0 + + PPC64_LR(0) + PPC64_LR(5) + PPC64_LR(4) + PPC64_LR(1) + PPC64_LR(3) + bctr + +#elif defined(__ppc__) + +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) +// +// void libunwind::Registers_ppc::jumpto() +// +// On entry: +// thread_state pointer is in r3 +// + + // restore integral registerrs + // skip r0 for now + // skip r1 for now + lwz %r2, 16(%r3) + // skip r3 for now + // skip r4 for now + // skip r5 for now + lwz %r6, 32(%r3) + lwz %r7, 36(%r3) + lwz %r8, 40(%r3) + lwz %r9, 44(%r3) + lwz %r10, 48(%r3) + lwz %r11, 52(%r3) + lwz %r12, 56(%r3) + lwz %r13, 60(%r3) + lwz %r14, 64(%r3) + lwz %r15, 68(%r3) + lwz %r16, 72(%r3) + lwz %r17, 76(%r3) + lwz %r18, 80(%r3) + lwz %r19, 84(%r3) + lwz %r20, 88(%r3) + lwz %r21, 92(%r3) + lwz %r22, 96(%r3) + lwz %r23,100(%r3) + lwz %r24,104(%r3) + lwz %r25,108(%r3) + lwz %r26,112(%r3) + lwz %r27,116(%r3) + lwz %r28,120(%r3) + lwz %r29,124(%r3) + lwz %r30,128(%r3) + lwz %r31,132(%r3) + + // restore float registers + lfd %f0, 160(%r3) + lfd %f1, 168(%r3) + lfd %f2, 176(%r3) + lfd %f3, 184(%r3) + lfd %f4, 192(%r3) + lfd %f5, 200(%r3) + lfd %f6, 208(%r3) + lfd %f7, 216(%r3) + lfd %f8, 224(%r3) + lfd %f9, 232(%r3) + lfd %f10,240(%r3) + lfd %f11,248(%r3) + lfd %f12,256(%r3) + lfd %f13,264(%r3) + lfd %f14,272(%r3) + lfd %f15,280(%r3) + lfd %f16,288(%r3) + lfd %f17,296(%r3) + lfd %f18,304(%r3) + lfd %f19,312(%r3) + lfd %f20,320(%r3) + lfd %f21,328(%r3) + lfd %f22,336(%r3) + lfd %f23,344(%r3) + lfd %f24,352(%r3) + lfd %f25,360(%r3) + lfd %f26,368(%r3) + lfd %f27,376(%r3) + lfd %f28,384(%r3) + lfd %f29,392(%r3) + lfd %f30,400(%r3) + lfd %f31,408(%r3) + + // restore vector registers if any are in use + lwz %r5, 156(%r3) // test VRsave + cmpwi %r5, 0 + beq Lnovec + + subi %r4, %r1, 16 + rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits + // r4 is now a 16-byte aligned pointer into the red zone + // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer + + +#define LOAD_VECTOR_UNALIGNEDl(_index) \ + andis. %r0, %r5, (1<<(15-_index)) SEPARATOR \ + beq Ldone ## _index SEPARATOR \ + lwz %r0, 424+_index*16(%r3) SEPARATOR \ + stw %r0, 0(%r4) SEPARATOR \ + lwz %r0, 424+_index*16+4(%r3) SEPARATOR \ + stw %r0, 4(%r4) SEPARATOR \ + lwz %r0, 424+_index*16+8(%r3) SEPARATOR \ + stw %r0, 8(%r4) SEPARATOR \ + lwz %r0, 424+_index*16+12(%r3) SEPARATOR \ + stw %r0, 12(%r4) SEPARATOR \ + lvx %v ## _index, 0, %r4 SEPARATOR \ + Ldone ## _index: + +#define LOAD_VECTOR_UNALIGNEDh(_index) \ + andi. %r0, %r5, (1<<(31-_index)) SEPARATOR \ + beq Ldone ## _index SEPARATOR \ + lwz %r0, 424+_index*16(%r3) SEPARATOR \ + stw %r0, 0(%r4) SEPARATOR \ + lwz %r0, 424+_index*16+4(%r3) SEPARATOR \ + stw %r0, 4(%r4) SEPARATOR \ + lwz %r0, 424+_index*16+8(%r3) SEPARATOR \ + stw %r0, 8(%r4) SEPARATOR \ + lwz %r0, 424+_index*16+12(%r3) SEPARATOR \ + stw %r0, 12(%r4) SEPARATOR \ + lvx %v ## _index, 0, %r4 SEPARATOR \ + Ldone ## _index: + + + LOAD_VECTOR_UNALIGNEDl(0) + LOAD_VECTOR_UNALIGNEDl(1) + LOAD_VECTOR_UNALIGNEDl(2) + LOAD_VECTOR_UNALIGNEDl(3) + LOAD_VECTOR_UNALIGNEDl(4) + LOAD_VECTOR_UNALIGNEDl(5) + LOAD_VECTOR_UNALIGNEDl(6) + LOAD_VECTOR_UNALIGNEDl(7) + LOAD_VECTOR_UNALIGNEDl(8) + LOAD_VECTOR_UNALIGNEDl(9) + LOAD_VECTOR_UNALIGNEDl(10) + LOAD_VECTOR_UNALIGNEDl(11) + LOAD_VECTOR_UNALIGNEDl(12) + LOAD_VECTOR_UNALIGNEDl(13) + LOAD_VECTOR_UNALIGNEDl(14) + LOAD_VECTOR_UNALIGNEDl(15) + LOAD_VECTOR_UNALIGNEDh(16) + LOAD_VECTOR_UNALIGNEDh(17) + LOAD_VECTOR_UNALIGNEDh(18) + LOAD_VECTOR_UNALIGNEDh(19) + LOAD_VECTOR_UNALIGNEDh(20) + LOAD_VECTOR_UNALIGNEDh(21) + LOAD_VECTOR_UNALIGNEDh(22) + LOAD_VECTOR_UNALIGNEDh(23) + LOAD_VECTOR_UNALIGNEDh(24) + LOAD_VECTOR_UNALIGNEDh(25) + LOAD_VECTOR_UNALIGNEDh(26) + LOAD_VECTOR_UNALIGNEDh(27) + LOAD_VECTOR_UNALIGNEDh(28) + LOAD_VECTOR_UNALIGNEDh(29) + LOAD_VECTOR_UNALIGNEDh(30) + LOAD_VECTOR_UNALIGNEDh(31) + +Lnovec: + lwz %r0, 136(%r3) // __cr + mtcr %r0 + lwz %r0, 148(%r3) // __ctr + mtctr %r0 + lwz %r0, 0(%r3) // __ssr0 + mtctr %r0 + lwz %r0, 8(%r3) // do r0 now + lwz %r5, 28(%r3) // do r5 now + lwz %r4, 24(%r3) // do r4 now + lwz %r1, 12(%r3) // do sp now + lwz %r3, 20(%r3) // do r3 last + bctr + +#elif defined(__aarch64__) + +// +// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +// +// On entry: +// thread_state pointer is in x0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) + // skip restore of x0,x1 for now + ldp x2, x3, [x0, #0x010] + ldp x4, x5, [x0, #0x020] + ldp x6, x7, [x0, #0x030] + ldp x8, x9, [x0, #0x040] + ldp x10,x11, [x0, #0x050] + ldp x12,x13, [x0, #0x060] + ldp x14,x15, [x0, #0x070] + // x16 and x17 were clobbered by the call into the unwinder, so no point in + // restoring them. + ldp x18,x19, [x0, #0x090] + ldp x20,x21, [x0, #0x0A0] + ldp x22,x23, [x0, #0x0B0] + ldp x24,x25, [x0, #0x0C0] + ldp x26,x27, [x0, #0x0D0] + ldp x28,x29, [x0, #0x0E0] + + ldp d0, d1, [x0, #0x110] + ldp d2, d3, [x0, #0x120] + ldp d4, d5, [x0, #0x130] + ldp d6, d7, [x0, #0x140] + ldp d8, d9, [x0, #0x150] + ldp d10,d11, [x0, #0x160] + ldp d12,d13, [x0, #0x170] + ldp d14,d15, [x0, #0x180] + ldp d16,d17, [x0, #0x190] + ldp d18,d19, [x0, #0x1A0] + ldp d20,d21, [x0, #0x1B0] + ldp d22,d23, [x0, #0x1C0] + ldp d24,d25, [x0, #0x1D0] + ldp d26,d27, [x0, #0x1E0] + ldp d28,d29, [x0, #0x1F0] + ldr d30, [x0, #0x200] + ldr d31, [x0, #0x208] + + // Finally, restore sp. This must be done after the the last read from the + // context struct, because it is allocated on the stack, and an exception + // could clobber the de-allocated portion of the stack after sp has been + // restored. + + ldr x16, [x0, #0x0F8] // load sp into scratch + ldr lr, [x0, #0x100] // restore pc into lr + + ldp x0, x1, [x0, #0x000] // restore x0,x1 + mov sp,x16 // restore sp + ret + +#elif defined(__arm__) + +#if !defined(__ARM_ARCH_ISA_ARM) +#if (__ARM_ARCH_ISA_THUMB == 2) + .syntax unified +#endif + .thumb +#endif + +@ +@ void libunwind::Registers_arm::restoreCoreAndJumpTo() +@ +@ On entry: +@ thread_state pointer is in r0 +@ + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) +#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 + @ r8-r11: ldm into r1-r4, then mov to r8-r11 + adds r0, #0x20 + ldm r0!, {r1-r4} + subs r0, #0x30 + mov r8, r1 + mov r9, r2 + mov r10, r3 + mov r11, r4 + @ r12 does not need loading, it it the intra-procedure-call scratch register + ldr r2, [r0, #0x34] + ldr r3, [r0, #0x3c] + mov sp, r2 + mov lr, r3 @ restore pc into lr + ldm r0, {r0-r7} +#else + @ Use lr as base so that r0 can be restored. + mov lr, r0 + @ 32bit thumb-2 restrictions for ldm: + @ . the sp (r13) cannot be in the list + @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction + ldm lr, {r0-r12} + ldr sp, [lr, #52] + ldr lr, [lr, #60] @ restore pc into lr +#endif + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPv) + @ VFP and iwMMX instructions are only available when compiling with the flags + @ that enable them. We do not want to do that in the library (because we do not + @ want the compiler to generate instructions that access those) but this is + @ only accessed if the personality routine needs these registers. Use of + @ these registers implies they are, actually, available on the target, so + @ it's ok to execute. + @ So, generate the instruction using the corresponding coprocessor mnemonic. + vldmia r0, {d0-d15} + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPv) + vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPv) + vldmia r0, {d16-d31} + JMP(lr) + +#if defined(__ARM_WMMX) + +@ +@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPv) + ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8 + ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 + ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8 + ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8 + ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8 + ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8 + ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8 + ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8 + ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8 + ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8 + ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8 + ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8 + ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8 + ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8 + ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 + ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) + ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4 + ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 + ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 + ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 + JMP(lr) + +#endif + +#elif defined(__or1k__) + +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) +# +# void libunwind::Registers_or1k::jumpto() +# +# On entry: +# thread_state pointer is in r3 +# + + # restore integral registers + l.lwz r0, 0(r3) + l.lwz r1, 4(r3) + l.lwz r2, 8(r3) + # skip r3 for now + l.lwz r4, 16(r3) + l.lwz r5, 20(r3) + l.lwz r6, 24(r3) + l.lwz r7, 28(r3) + l.lwz r8, 32(r3) + # skip r9 + l.lwz r10, 40(r3) + l.lwz r11, 44(r3) + l.lwz r12, 48(r3) + l.lwz r13, 52(r3) + l.lwz r14, 56(r3) + l.lwz r15, 60(r3) + l.lwz r16, 64(r3) + l.lwz r17, 68(r3) + l.lwz r18, 72(r3) + l.lwz r19, 76(r3) + l.lwz r20, 80(r3) + l.lwz r21, 84(r3) + l.lwz r22, 88(r3) + l.lwz r23, 92(r3) + l.lwz r24, 96(r3) + l.lwz r25,100(r3) + l.lwz r26,104(r3) + l.lwz r27,108(r3) + l.lwz r28,112(r3) + l.lwz r29,116(r3) + l.lwz r30,120(r3) + l.lwz r31,124(r3) + + # at last, restore r3 + l.lwz r3, 12(r3) + + # load new pc into ra + l.lwz r9, 128(r3) + # jump to pc + l.jr r9 + l.nop + +#elif defined(__hexagon__) +# On entry: +# thread_state pointer is in r2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv) +# +# void libunwind::Registers_hexagon::jumpto() +# + r8 = memw(r0+#32) + r9 = memw(r0+#36) + r10 = memw(r0+#40) + r11 = memw(r0+#44) + + r12 = memw(r0+#48) + r13 = memw(r0+#52) + r14 = memw(r0+#56) + r15 = memw(r0+#60) + + r16 = memw(r0+#64) + r17 = memw(r0+#68) + r18 = memw(r0+#72) + r19 = memw(r0+#76) + + r20 = memw(r0+#80) + r21 = memw(r0+#84) + r22 = memw(r0+#88) + r23 = memw(r0+#92) + + r24 = memw(r0+#96) + r25 = memw(r0+#100) + r26 = memw(r0+#104) + r27 = memw(r0+#108) + + r28 = memw(r0+#112) + r29 = memw(r0+#116) + r30 = memw(r0+#120) + r31 = memw(r0+#132) + + r1 = memw(r0+#128) + c4 = r1 // Predicate register + r1 = memw(r0+#4) + r0 = memw(r0) + jumpr r31 +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 + +// +// void libunwind::Registers_mips_o32::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) + .set push + .set noat + .set noreorder + .set nomacro +#ifdef __mips_hard_float +#if __mips_fpr != 64 + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) +#else + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f1, (4 * 36 + 8 * 1)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f3, (4 * 36 + 8 * 3)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f5, (4 * 36 + 8 * 5)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f7, (4 * 36 + 8 * 7)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f9, (4 * 36 + 8 * 9)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f11, (4 * 36 + 8 * 11)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f13, (4 * 36 + 8 * 13)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f15, (4 * 36 + 8 * 15)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f17, (4 * 36 + 8 * 17)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f19, (4 * 36 + 8 * 19)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f21, (4 * 36 + 8 * 21)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f23, (4 * 36 + 8 * 23)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f25, (4 * 36 + 8 * 25)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f27, (4 * 36 + 8 * 27)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f29, (4 * 36 + 8 * 29)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) + ldc1 $f31, (4 * 36 + 8 * 31)($4) +#endif +#endif + // restore hi and lo + lw $8, (4 * 33)($4) + mthi $8 + lw $8, (4 * 34)($4) + mtlo $8 + // r0 is zero + lw $1, (4 * 1)($4) + lw $2, (4 * 2)($4) + lw $3, (4 * 3)($4) + // skip a0 for now + lw $5, (4 * 5)($4) + lw $6, (4 * 6)($4) + lw $7, (4 * 7)($4) + lw $8, (4 * 8)($4) + lw $9, (4 * 9)($4) + lw $10, (4 * 10)($4) + lw $11, (4 * 11)($4) + lw $12, (4 * 12)($4) + lw $13, (4 * 13)($4) + lw $14, (4 * 14)($4) + lw $15, (4 * 15)($4) + lw $16, (4 * 16)($4) + lw $17, (4 * 17)($4) + lw $18, (4 * 18)($4) + lw $19, (4 * 19)($4) + lw $20, (4 * 20)($4) + lw $21, (4 * 21)($4) + lw $22, (4 * 22)($4) + lw $23, (4 * 23)($4) + lw $24, (4 * 24)($4) + lw $25, (4 * 25)($4) + lw $26, (4 * 26)($4) + lw $27, (4 * 27)($4) + lw $28, (4 * 28)($4) + lw $29, (4 * 29)($4) + lw $30, (4 * 30)($4) + // load new pc into ra + lw $31, (4 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + lw $4, (4 * 4)($4) + .set pop + +#elif defined(__mips64) + +// +// void libunwind::Registers_mips_newabi::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv) + .set push + .set noat + .set noreorder + .set nomacro +#ifdef __mips_hard_float + ldc1 $f0, (8 * 35)($4) + ldc1 $f1, (8 * 36)($4) + ldc1 $f2, (8 * 37)($4) + ldc1 $f3, (8 * 38)($4) + ldc1 $f4, (8 * 39)($4) + ldc1 $f5, (8 * 40)($4) + ldc1 $f6, (8 * 41)($4) + ldc1 $f7, (8 * 42)($4) + ldc1 $f8, (8 * 43)($4) + ldc1 $f9, (8 * 44)($4) + ldc1 $f10, (8 * 45)($4) + ldc1 $f11, (8 * 46)($4) + ldc1 $f12, (8 * 47)($4) + ldc1 $f13, (8 * 48)($4) + ldc1 $f14, (8 * 49)($4) + ldc1 $f15, (8 * 50)($4) + ldc1 $f16, (8 * 51)($4) + ldc1 $f17, (8 * 52)($4) + ldc1 $f18, (8 * 53)($4) + ldc1 $f19, (8 * 54)($4) + ldc1 $f20, (8 * 55)($4) + ldc1 $f21, (8 * 56)($4) + ldc1 $f22, (8 * 57)($4) + ldc1 $f23, (8 * 58)($4) + ldc1 $f24, (8 * 59)($4) + ldc1 $f25, (8 * 60)($4) + ldc1 $f26, (8 * 61)($4) + ldc1 $f27, (8 * 62)($4) + ldc1 $f28, (8 * 63)($4) + ldc1 $f29, (8 * 64)($4) + ldc1 $f30, (8 * 65)($4) + ldc1 $f31, (8 * 66)($4) +#endif + // restore hi and lo + ld $8, (8 * 33)($4) + mthi $8 + ld $8, (8 * 34)($4) + mtlo $8 + // r0 is zero + ld $1, (8 * 1)($4) + ld $2, (8 * 2)($4) + ld $3, (8 * 3)($4) + // skip a0 for now + ld $5, (8 * 5)($4) + ld $6, (8 * 6)($4) + ld $7, (8 * 7)($4) + ld $8, (8 * 8)($4) + ld $9, (8 * 9)($4) + ld $10, (8 * 10)($4) + ld $11, (8 * 11)($4) + ld $12, (8 * 12)($4) + ld $13, (8 * 13)($4) + ld $14, (8 * 14)($4) + ld $15, (8 * 15)($4) + ld $16, (8 * 16)($4) + ld $17, (8 * 17)($4) + ld $18, (8 * 18)($4) + ld $19, (8 * 19)($4) + ld $20, (8 * 20)($4) + ld $21, (8 * 21)($4) + ld $22, (8 * 22)($4) + ld $23, (8 * 23)($4) + ld $24, (8 * 24)($4) + ld $25, (8 * 25)($4) + ld $26, (8 * 26)($4) + ld $27, (8 * 27)($4) + ld $28, (8 * 28)($4) + ld $29, (8 * 29)($4) + ld $30, (8 * 30)($4) + // load new pc into ra + ld $31, (8 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + ld $4, (8 * 4)($4) + .set pop + +#elif defined(__sparc__) + +// +// void libunwind::Registers_sparc_o32::jumpto() +// +// On entry: +// thread_state pointer is in o0 +// +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) + ta 3 + ldd [%o0 + 64], %l0 + ldd [%o0 + 72], %l2 + ldd [%o0 + 80], %l4 + ldd [%o0 + 88], %l6 + ldd [%o0 + 96], %i0 + ldd [%o0 + 104], %i2 + ldd [%o0 + 112], %i4 + ldd [%o0 + 120], %i6 + ld [%o0 + 60], %o7 + jmp %o7 + nop + +#elif defined(__riscv) && __riscv_xlen == 64 + +// +// void libunwind::Registers_riscv::jumpto() +// +// On entry: +// thread_state pointer is in a0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv) +#if defined(__riscv_flen) && __riscv_flen == 64 + fld f0, (8 * 32 + 8 * 0)(a0) + fld f1, (8 * 32 + 8 * 1)(a0) + fld f2, (8 * 32 + 8 * 2)(a0) + fld f3, (8 * 32 + 8 * 3)(a0) + fld f4, (8 * 32 + 8 * 4)(a0) + fld f5, (8 * 32 + 8 * 5)(a0) + fld f6, (8 * 32 + 8 * 6)(a0) + fld f7, (8 * 32 + 8 * 7)(a0) + fld f8, (8 * 32 + 8 * 8)(a0) + fld f9, (8 * 32 + 8 * 9)(a0) + fld f10, (8 * 32 + 8 * 10)(a0) + fld f11, (8 * 32 + 8 * 11)(a0) + fld f12, (8 * 32 + 8 * 12)(a0) + fld f13, (8 * 32 + 8 * 13)(a0) + fld f14, (8 * 32 + 8 * 14)(a0) + fld f15, (8 * 32 + 8 * 15)(a0) + fld f16, (8 * 32 + 8 * 16)(a0) + fld f17, (8 * 32 + 8 * 17)(a0) + fld f18, (8 * 32 + 8 * 18)(a0) + fld f19, (8 * 32 + 8 * 19)(a0) + fld f20, (8 * 32 + 8 * 20)(a0) + fld f21, (8 * 32 + 8 * 21)(a0) + fld f22, (8 * 32 + 8 * 22)(a0) + fld f23, (8 * 32 + 8 * 23)(a0) + fld f24, (8 * 32 + 8 * 24)(a0) + fld f25, (8 * 32 + 8 * 25)(a0) + fld f26, (8 * 32 + 8 * 26)(a0) + fld f27, (8 * 32 + 8 * 27)(a0) + fld f28, (8 * 32 + 8 * 28)(a0) + fld f29, (8 * 32 + 8 * 29)(a0) + fld f30, (8 * 32 + 8 * 30)(a0) + fld f31, (8 * 32 + 8 * 31)(a0) +#endif + + // x0 is zero + ld x1, (8 * 0)(a0) // restore pc into ra + ld x2, (8 * 2)(a0) + ld x3, (8 * 3)(a0) + ld x4, (8 * 4)(a0) + ld x5, (8 * 5)(a0) + ld x6, (8 * 6)(a0) + ld x7, (8 * 7)(a0) + ld x8, (8 * 8)(a0) + ld x9, (8 * 9)(a0) + // skip a0 for now + ld x11, (8 * 11)(a0) + ld x12, (8 * 12)(a0) + ld x13, (8 * 13)(a0) + ld x14, (8 * 14)(a0) + ld x15, (8 * 15)(a0) + ld x16, (8 * 16)(a0) + ld x17, (8 * 17)(a0) + ld x18, (8 * 18)(a0) + ld x19, (8 * 19)(a0) + ld x20, (8 * 20)(a0) + ld x21, (8 * 21)(a0) + ld x22, (8 * 22)(a0) + ld x23, (8 * 23)(a0) + ld x24, (8 * 24)(a0) + ld x25, (8 * 25)(a0) + ld x26, (8 * 26)(a0) + ld x27, (8 * 27)(a0) + ld x28, (8 * 28)(a0) + ld x29, (8 * 29)(a0) + ld x30, (8 * 30)(a0) + ld x31, (8 * 31)(a0) + ld x10, (8 * 10)(a0) // restore a0 + + ret // jump to ra + +#endif + +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S new file mode 100644 index 0000000..e5a968c --- /dev/null +++ b/libunwind/src/UnwindRegistersSave.S @@ -0,0 +1,1109 @@ +//===------------------------ UnwindRegistersSave.S -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "assembly.h" + + .text + +#if !defined(__USING_SJLJ_EXCEPTIONS__) + +#if defined(__i386__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# + + +# +-----------------------+ +# + thread_state pointer + +# +-----------------------+ +# + return address + +# +-----------------------+ <-- SP +# + + +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + push %eax + movl 8(%esp), %eax + movl %ebx, 4(%eax) + movl %ecx, 8(%eax) + movl %edx, 12(%eax) + movl %edi, 16(%eax) + movl %esi, 20(%eax) + movl %ebp, 24(%eax) + movl %esp, %edx + addl $8, %edx + movl %edx, 28(%eax) # store what sp was at call site as esp + # skip ss + # skip eflags + movl 4(%esp), %edx + movl %edx, 40(%eax) # store return address as eip + # skip cs + # skip ds + # skip es + # skip fs + # skip gs + movl (%esp), %edx + movl %edx, (%eax) # store original eax + popl %eax + xorl %eax, %eax # return UNW_ESUCCESS + ret + +#elif defined(__x86_64__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in rdi +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) +#if defined(_WIN64) +#define PTR %rcx +#define TMP %rdx +#else +#define PTR %rdi +#define TMP %rsi +#endif + + movq %rax, (PTR) + movq %rbx, 8(PTR) + movq %rcx, 16(PTR) + movq %rdx, 24(PTR) + movq %rdi, 32(PTR) + movq %rsi, 40(PTR) + movq %rbp, 48(PTR) + movq %rsp, 56(PTR) + addq $8, 56(PTR) + movq %r8, 64(PTR) + movq %r9, 72(PTR) + movq %r10, 80(PTR) + movq %r11, 88(PTR) + movq %r12, 96(PTR) + movq %r13,104(PTR) + movq %r14,112(PTR) + movq %r15,120(PTR) + movq (%rsp),TMP + movq TMP,128(PTR) # store return address as rip + # skip rflags + # skip cs + # skip fs + # skip gs + +#if defined(_WIN64) + movdqu %xmm0,176(PTR) + movdqu %xmm1,192(PTR) + movdqu %xmm2,208(PTR) + movdqu %xmm3,224(PTR) + movdqu %xmm4,240(PTR) + movdqu %xmm5,256(PTR) + movdqu %xmm6,272(PTR) + movdqu %xmm7,288(PTR) + movdqu %xmm8,304(PTR) + movdqu %xmm9,320(PTR) + movdqu %xmm10,336(PTR) + movdqu %xmm11,352(PTR) + movdqu %xmm12,368(PTR) + movdqu %xmm13,384(PTR) + movdqu %xmm14,400(PTR) + movdqu %xmm15,416(PTR) +#endif + xorl %eax, %eax # return UNW_ESUCCESS + ret + +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + .set push + .set noat + .set noreorder + .set nomacro + sw $1, (4 * 1)($4) + sw $2, (4 * 2)($4) + sw $3, (4 * 3)($4) + sw $4, (4 * 4)($4) + sw $5, (4 * 5)($4) + sw $6, (4 * 6)($4) + sw $7, (4 * 7)($4) + sw $8, (4 * 8)($4) + sw $9, (4 * 9)($4) + sw $10, (4 * 10)($4) + sw $11, (4 * 11)($4) + sw $12, (4 * 12)($4) + sw $13, (4 * 13)($4) + sw $14, (4 * 14)($4) + sw $15, (4 * 15)($4) + sw $16, (4 * 16)($4) + sw $17, (4 * 17)($4) + sw $18, (4 * 18)($4) + sw $19, (4 * 19)($4) + sw $20, (4 * 20)($4) + sw $21, (4 * 21)($4) + sw $22, (4 * 22)($4) + sw $23, (4 * 23)($4) + sw $24, (4 * 24)($4) + sw $25, (4 * 25)($4) + sw $26, (4 * 26)($4) + sw $27, (4 * 27)($4) + sw $28, (4 * 28)($4) + sw $29, (4 * 29)($4) + sw $30, (4 * 30)($4) + sw $31, (4 * 31)($4) + # Store return address to pc + sw $31, (4 * 32)($4) + # hi and lo + mfhi $8 + sw $8, (4 * 33)($4) + mflo $8 + sw $8, (4 * 34)($4) +#ifdef __mips_hard_float +#if __mips_fpr != 64 + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) +#else + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f1, (4 * 36 + 8 * 1)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f3, (4 * 36 + 8 * 3)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f5, (4 * 36 + 8 * 5)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f7, (4 * 36 + 8 * 7)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f9, (4 * 36 + 8 * 9)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f11, (4 * 36 + 8 * 11)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f13, (4 * 36 + 8 * 13)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f15, (4 * 36 + 8 * 15)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f17, (4 * 36 + 8 * 17)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f19, (4 * 36 + 8 * 19)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f21, (4 * 36 + 8 * 21)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f23, (4 * 36 + 8 * 23)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f25, (4 * 36 + 8 * 25)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f27, (4 * 36 + 8 * 27)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f29, (4 * 36 + 8 * 29)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) + sdc1 $f31, (4 * 36 + 8 * 31)($4) +#endif +#endif + jr $31 + # return UNW_ESUCCESS + or $2, $0, $0 + .set pop + +#elif defined(__mips64) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + .set push + .set noat + .set noreorder + .set nomacro + sd $1, (8 * 1)($4) + sd $2, (8 * 2)($4) + sd $3, (8 * 3)($4) + sd $4, (8 * 4)($4) + sd $5, (8 * 5)($4) + sd $6, (8 * 6)($4) + sd $7, (8 * 7)($4) + sd $8, (8 * 8)($4) + sd $9, (8 * 9)($4) + sd $10, (8 * 10)($4) + sd $11, (8 * 11)($4) + sd $12, (8 * 12)($4) + sd $13, (8 * 13)($4) + sd $14, (8 * 14)($4) + sd $15, (8 * 15)($4) + sd $16, (8 * 16)($4) + sd $17, (8 * 17)($4) + sd $18, (8 * 18)($4) + sd $19, (8 * 19)($4) + sd $20, (8 * 20)($4) + sd $21, (8 * 21)($4) + sd $22, (8 * 22)($4) + sd $23, (8 * 23)($4) + sd $24, (8 * 24)($4) + sd $25, (8 * 25)($4) + sd $26, (8 * 26)($4) + sd $27, (8 * 27)($4) + sd $28, (8 * 28)($4) + sd $29, (8 * 29)($4) + sd $30, (8 * 30)($4) + sd $31, (8 * 31)($4) + # Store return address to pc + sd $31, (8 * 32)($4) + # hi and lo + mfhi $8 + sd $8, (8 * 33)($4) + mflo $8 + sd $8, (8 * 34)($4) +#ifdef __mips_hard_float + sdc1 $f0, (8 * 35)($4) + sdc1 $f1, (8 * 36)($4) + sdc1 $f2, (8 * 37)($4) + sdc1 $f3, (8 * 38)($4) + sdc1 $f4, (8 * 39)($4) + sdc1 $f5, (8 * 40)($4) + sdc1 $f6, (8 * 41)($4) + sdc1 $f7, (8 * 42)($4) + sdc1 $f8, (8 * 43)($4) + sdc1 $f9, (8 * 44)($4) + sdc1 $f10, (8 * 45)($4) + sdc1 $f11, (8 * 46)($4) + sdc1 $f12, (8 * 47)($4) + sdc1 $f13, (8 * 48)($4) + sdc1 $f14, (8 * 49)($4) + sdc1 $f15, (8 * 50)($4) + sdc1 $f16, (8 * 51)($4) + sdc1 $f17, (8 * 52)($4) + sdc1 $f18, (8 * 53)($4) + sdc1 $f19, (8 * 54)($4) + sdc1 $f20, (8 * 55)($4) + sdc1 $f21, (8 * 56)($4) + sdc1 $f22, (8 * 57)($4) + sdc1 $f23, (8 * 58)($4) + sdc1 $f24, (8 * 59)($4) + sdc1 $f25, (8 * 60)($4) + sdc1 $f26, (8 * 61)($4) + sdc1 $f27, (8 * 62)($4) + sdc1 $f28, (8 * 63)($4) + sdc1 $f29, (8 * 64)($4) + sdc1 $f30, (8 * 65)($4) + sdc1 $f31, (8 * 66)($4) +#endif + jr $31 + # return UNW_ESUCCESS + or $2, $0, $0 + .set pop + +# elif defined(__mips__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# Just trap for the time being. +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + teq $0, $0 + +#elif defined(__powerpc64__) + +// +// extern int __unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in r3 +// +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + +// store register (GPR) +#define PPC64_STR(n) \ + std %r##n, (8 * (n + 2))(%r3) + + // save GPRs + PPC64_STR(0) + mflr %r0 + std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0 + PPC64_STR(1) + PPC64_STR(2) + PPC64_STR(3) + PPC64_STR(4) + PPC64_STR(5) + PPC64_STR(6) + PPC64_STR(7) + PPC64_STR(8) + PPC64_STR(9) + PPC64_STR(10) + PPC64_STR(11) + PPC64_STR(12) + PPC64_STR(13) + PPC64_STR(14) + PPC64_STR(15) + PPC64_STR(16) + PPC64_STR(17) + PPC64_STR(18) + PPC64_STR(19) + PPC64_STR(20) + PPC64_STR(21) + PPC64_STR(22) + PPC64_STR(23) + PPC64_STR(24) + PPC64_STR(25) + PPC64_STR(26) + PPC64_STR(27) + PPC64_STR(28) + PPC64_STR(29) + PPC64_STR(30) + PPC64_STR(31) + + mfcr %r0 + std %r0, PPC64_OFFS_CR(%r3) + mfxer %r0 + std %r0, PPC64_OFFS_XER(%r3) + mflr %r0 + std %r0, PPC64_OFFS_LR(%r3) + mfctr %r0 + std %r0, PPC64_OFFS_CTR(%r3) + mfvrsave %r0 + std %r0, PPC64_OFFS_VRSAVE(%r3) + +#ifdef PPC64_HAS_VMX + // save VS registers + // (note that this also saves floating point registers and V registers, + // because part of VS is mapped to these registers) + + addi %r4, %r3, PPC64_OFFS_FP + +// store VS register +#define PPC64_STVS(n) \ + stxvd2x %vs##n, 0, %r4 ;\ + addi %r4, %r4, 16 + + PPC64_STVS(0) + PPC64_STVS(1) + PPC64_STVS(2) + PPC64_STVS(3) + PPC64_STVS(4) + PPC64_STVS(5) + PPC64_STVS(6) + PPC64_STVS(7) + PPC64_STVS(8) + PPC64_STVS(9) + PPC64_STVS(10) + PPC64_STVS(11) + PPC64_STVS(12) + PPC64_STVS(13) + PPC64_STVS(14) + PPC64_STVS(15) + PPC64_STVS(16) + PPC64_STVS(17) + PPC64_STVS(18) + PPC64_STVS(19) + PPC64_STVS(20) + PPC64_STVS(21) + PPC64_STVS(22) + PPC64_STVS(23) + PPC64_STVS(24) + PPC64_STVS(25) + PPC64_STVS(26) + PPC64_STVS(27) + PPC64_STVS(28) + PPC64_STVS(29) + PPC64_STVS(30) + PPC64_STVS(31) + PPC64_STVS(32) + PPC64_STVS(33) + PPC64_STVS(34) + PPC64_STVS(35) + PPC64_STVS(36) + PPC64_STVS(37) + PPC64_STVS(38) + PPC64_STVS(39) + PPC64_STVS(40) + PPC64_STVS(41) + PPC64_STVS(42) + PPC64_STVS(43) + PPC64_STVS(44) + PPC64_STVS(45) + PPC64_STVS(46) + PPC64_STVS(47) + PPC64_STVS(48) + PPC64_STVS(49) + PPC64_STVS(50) + PPC64_STVS(51) + PPC64_STVS(52) + PPC64_STVS(53) + PPC64_STVS(54) + PPC64_STVS(55) + PPC64_STVS(56) + PPC64_STVS(57) + PPC64_STVS(58) + PPC64_STVS(59) + PPC64_STVS(60) + PPC64_STVS(61) + PPC64_STVS(62) + PPC64_STVS(63) + +#else + +// store FP register +#define PPC64_STF(n) \ + stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3) + + // save float registers + PPC64_STF(0) + PPC64_STF(1) + PPC64_STF(2) + PPC64_STF(3) + PPC64_STF(4) + PPC64_STF(5) + PPC64_STF(6) + PPC64_STF(7) + PPC64_STF(8) + PPC64_STF(9) + PPC64_STF(10) + PPC64_STF(11) + PPC64_STF(12) + PPC64_STF(13) + PPC64_STF(14) + PPC64_STF(15) + PPC64_STF(16) + PPC64_STF(17) + PPC64_STF(18) + PPC64_STF(19) + PPC64_STF(20) + PPC64_STF(21) + PPC64_STF(22) + PPC64_STF(23) + PPC64_STF(24) + PPC64_STF(25) + PPC64_STF(26) + PPC64_STF(27) + PPC64_STF(28) + PPC64_STF(29) + PPC64_STF(30) + PPC64_STF(31) + + // save vector registers + + // Use 16-bytes below the stack pointer as an + // aligned buffer to save each vector register. + // Note that the stack pointer is always 16-byte aligned. + subi %r4, %r1, 16 + +#define PPC64_STV_UNALIGNED(n) \ + stvx %v##n, 0, %r4 ;\ + ld %r5, 0(%r4) ;\ + std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\ + ld %r5, 8(%r4) ;\ + std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3) + + PPC64_STV_UNALIGNED(0) + PPC64_STV_UNALIGNED(1) + PPC64_STV_UNALIGNED(2) + PPC64_STV_UNALIGNED(3) + PPC64_STV_UNALIGNED(4) + PPC64_STV_UNALIGNED(5) + PPC64_STV_UNALIGNED(6) + PPC64_STV_UNALIGNED(7) + PPC64_STV_UNALIGNED(8) + PPC64_STV_UNALIGNED(9) + PPC64_STV_UNALIGNED(10) + PPC64_STV_UNALIGNED(11) + PPC64_STV_UNALIGNED(12) + PPC64_STV_UNALIGNED(13) + PPC64_STV_UNALIGNED(14) + PPC64_STV_UNALIGNED(15) + PPC64_STV_UNALIGNED(16) + PPC64_STV_UNALIGNED(17) + PPC64_STV_UNALIGNED(18) + PPC64_STV_UNALIGNED(19) + PPC64_STV_UNALIGNED(20) + PPC64_STV_UNALIGNED(21) + PPC64_STV_UNALIGNED(22) + PPC64_STV_UNALIGNED(23) + PPC64_STV_UNALIGNED(24) + PPC64_STV_UNALIGNED(25) + PPC64_STV_UNALIGNED(26) + PPC64_STV_UNALIGNED(27) + PPC64_STV_UNALIGNED(28) + PPC64_STV_UNALIGNED(29) + PPC64_STV_UNALIGNED(30) + PPC64_STV_UNALIGNED(31) + +#endif + + li %r3, 0 // return UNW_ESUCCESS + blr + + +#elif defined(__ppc__) + +// +// extern int unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in r3 +// +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + stw %r0, 8(%r3) + mflr %r0 + stw %r0, 0(%r3) // store lr as ssr0 + stw %r1, 12(%r3) + stw %r2, 16(%r3) + stw %r3, 20(%r3) + stw %r4, 24(%r3) + stw %r5, 28(%r3) + stw %r6, 32(%r3) + stw %r7, 36(%r3) + stw %r8, 40(%r3) + stw %r9, 44(%r3) + stw %r10, 48(%r3) + stw %r11, 52(%r3) + stw %r12, 56(%r3) + stw %r13, 60(%r3) + stw %r14, 64(%r3) + stw %r15, 68(%r3) + stw %r16, 72(%r3) + stw %r17, 76(%r3) + stw %r18, 80(%r3) + stw %r19, 84(%r3) + stw %r20, 88(%r3) + stw %r21, 92(%r3) + stw %r22, 96(%r3) + stw %r23,100(%r3) + stw %r24,104(%r3) + stw %r25,108(%r3) + stw %r26,112(%r3) + stw %r27,116(%r3) + stw %r28,120(%r3) + stw %r29,124(%r3) + stw %r30,128(%r3) + stw %r31,132(%r3) + + // save VRSave register + mfspr %r0, 256 + stw %r0, 156(%r3) + // save CR registers + mfcr %r0 + stw %r0, 136(%r3) + // save CTR register + mfctr %r0 + stw %r0, 148(%r3) + + // save float registers + stfd %f0, 160(%r3) + stfd %f1, 168(%r3) + stfd %f2, 176(%r3) + stfd %f3, 184(%r3) + stfd %f4, 192(%r3) + stfd %f5, 200(%r3) + stfd %f6, 208(%r3) + stfd %f7, 216(%r3) + stfd %f8, 224(%r3) + stfd %f9, 232(%r3) + stfd %f10,240(%r3) + stfd %f11,248(%r3) + stfd %f12,256(%r3) + stfd %f13,264(%r3) + stfd %f14,272(%r3) + stfd %f15,280(%r3) + stfd %f16,288(%r3) + stfd %f17,296(%r3) + stfd %f18,304(%r3) + stfd %f19,312(%r3) + stfd %f20,320(%r3) + stfd %f21,328(%r3) + stfd %f22,336(%r3) + stfd %f23,344(%r3) + stfd %f24,352(%r3) + stfd %f25,360(%r3) + stfd %f26,368(%r3) + stfd %f27,376(%r3) + stfd %f28,384(%r3) + stfd %f29,392(%r3) + stfd %f30,400(%r3) + stfd %f31,408(%r3) + + + // save vector registers + + subi %r4, %r1, 16 + rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits + // r4 is now a 16-byte aligned pointer into the red zone + +#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ + stvx _vec, 0, %r4 SEPARATOR \ + lwz %r5, 0(%r4) SEPARATOR \ + stw %r5, _offset(%r3) SEPARATOR \ + lwz %r5, 4(%r4) SEPARATOR \ + stw %r5, _offset+4(%r3) SEPARATOR \ + lwz %r5, 8(%r4) SEPARATOR \ + stw %r5, _offset+8(%r3) SEPARATOR \ + lwz %r5, 12(%r4) SEPARATOR \ + stw %r5, _offset+12(%r3) + + SAVE_VECTOR_UNALIGNED( %v0, 424+0x000) + SAVE_VECTOR_UNALIGNED( %v1, 424+0x010) + SAVE_VECTOR_UNALIGNED( %v2, 424+0x020) + SAVE_VECTOR_UNALIGNED( %v3, 424+0x030) + SAVE_VECTOR_UNALIGNED( %v4, 424+0x040) + SAVE_VECTOR_UNALIGNED( %v5, 424+0x050) + SAVE_VECTOR_UNALIGNED( %v6, 424+0x060) + SAVE_VECTOR_UNALIGNED( %v7, 424+0x070) + SAVE_VECTOR_UNALIGNED( %v8, 424+0x080) + SAVE_VECTOR_UNALIGNED( %v9, 424+0x090) + SAVE_VECTOR_UNALIGNED(%v10, 424+0x0A0) + SAVE_VECTOR_UNALIGNED(%v11, 424+0x0B0) + SAVE_VECTOR_UNALIGNED(%v12, 424+0x0C0) + SAVE_VECTOR_UNALIGNED(%v13, 424+0x0D0) + SAVE_VECTOR_UNALIGNED(%v14, 424+0x0E0) + SAVE_VECTOR_UNALIGNED(%v15, 424+0x0F0) + SAVE_VECTOR_UNALIGNED(%v16, 424+0x100) + SAVE_VECTOR_UNALIGNED(%v17, 424+0x110) + SAVE_VECTOR_UNALIGNED(%v18, 424+0x120) + SAVE_VECTOR_UNALIGNED(%v19, 424+0x130) + SAVE_VECTOR_UNALIGNED(%v20, 424+0x140) + SAVE_VECTOR_UNALIGNED(%v21, 424+0x150) + SAVE_VECTOR_UNALIGNED(%v22, 424+0x160) + SAVE_VECTOR_UNALIGNED(%v23, 424+0x170) + SAVE_VECTOR_UNALIGNED(%v24, 424+0x180) + SAVE_VECTOR_UNALIGNED(%v25, 424+0x190) + SAVE_VECTOR_UNALIGNED(%v26, 424+0x1A0) + SAVE_VECTOR_UNALIGNED(%v27, 424+0x1B0) + SAVE_VECTOR_UNALIGNED(%v28, 424+0x1C0) + SAVE_VECTOR_UNALIGNED(%v29, 424+0x1D0) + SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0) + SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0) + + li %r3, 0 // return UNW_ESUCCESS + blr + + +#elif defined(__aarch64__) + +// +// extern int __unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in x0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + stp x0, x1, [x0, #0x000] + stp x2, x3, [x0, #0x010] + stp x4, x5, [x0, #0x020] + stp x6, x7, [x0, #0x030] + stp x8, x9, [x0, #0x040] + stp x10,x11, [x0, #0x050] + stp x12,x13, [x0, #0x060] + stp x14,x15, [x0, #0x070] + stp x16,x17, [x0, #0x080] + stp x18,x19, [x0, #0x090] + stp x20,x21, [x0, #0x0A0] + stp x22,x23, [x0, #0x0B0] + stp x24,x25, [x0, #0x0C0] + stp x26,x27, [x0, #0x0D0] + stp x28,x29, [x0, #0x0E0] + str x30, [x0, #0x0F0] + mov x1,sp + str x1, [x0, #0x0F8] + str x30, [x0, #0x100] // store return address as pc + // skip cpsr + stp d0, d1, [x0, #0x110] + stp d2, d3, [x0, #0x120] + stp d4, d5, [x0, #0x130] + stp d6, d7, [x0, #0x140] + stp d8, d9, [x0, #0x150] + stp d10,d11, [x0, #0x160] + stp d12,d13, [x0, #0x170] + stp d14,d15, [x0, #0x180] + stp d16,d17, [x0, #0x190] + stp d18,d19, [x0, #0x1A0] + stp d20,d21, [x0, #0x1B0] + stp d22,d23, [x0, #0x1C0] + stp d24,d25, [x0, #0x1D0] + stp d26,d27, [x0, #0x1E0] + stp d28,d29, [x0, #0x1F0] + str d30, [x0, #0x200] + str d31, [x0, #0x208] + mov x0, #0 // return UNW_ESUCCESS + ret + +#elif defined(__arm__) + +#if !defined(__ARM_ARCH_ISA_ARM) +#if (__ARM_ARCH_ISA_THUMB == 2) + .syntax unified +#endif + .thumb +#endif + +@ +@ extern int __unw_getcontext(unw_context_t* thread_state) +@ +@ On entry: +@ thread_state pointer is in r0 +@ +@ Per EHABI #4.7 this only saves the core integer registers. +@ EHABI #7.4.5 notes that in general all VRS registers should be restored +@ however this is very hard to do for VFP registers because it is unknown +@ to the library how many registers are implemented by the architecture. +@ Instead, VFP registers are demand saved by logic external to __unw_getcontext. +@ + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) +#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 + stm r0!, {r0-r7} + mov r1, r8 + mov r2, r9 + mov r3, r10 + stm r0!, {r1-r3} + mov r1, r11 + mov r2, sp + mov r3, lr + str r1, [r0, #0] @ r11 + @ r12 does not need storing, it it the intra-procedure-call scratch register + str r2, [r0, #8] @ sp + str r3, [r0, #12] @ lr + str r3, [r0, #16] @ store return address as pc + @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. + @ It is safe to use here though because we are about to return, and cpsr is + @ not expected to be preserved. + movs r0, #0 @ return UNW_ESUCCESS +#else + @ 32bit thumb-2 restrictions for stm: + @ . the sp (r13) cannot be in the list + @ . the pc (r15) cannot be in the list in an STM instruction + stm r0, {r0-r12} + str sp, [r0, #52] + str lr, [r0, #56] + str lr, [r0, #60] @ store return address as pc + mov r0, #0 @ return UNW_ESUCCESS +#endif + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPv) + vstmia r0, {d0-d15} + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPv) + vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPv) + @ VFP and iwMMX instructions are only available when compiling with the flags + @ that enable them. We do not want to do that in the library (because we do not + @ want the compiler to generate instructions that access those) but this is + @ only accessed if the personality routine needs these registers. Use of + @ these registers implies they are, actually, available on the target, so + @ it's ok to execute. + @ So, generate the instructions using the corresponding coprocessor mnemonic. + vstmia r0, {d16-d31} + JMP(lr) + +#if defined(_LIBUNWIND_ARM_WMMX) + +@ +@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPv) + stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 + stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 + stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 + stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8 + stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8 + stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8 + stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8 + stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8 + stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8 + stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8 + stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8 + stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8 + stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8 + stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 + stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 + stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) + stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 + stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 + stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 + stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 + JMP(lr) + +#endif + +#elif defined(__or1k__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in r3 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + l.sw 0(r3), r0 + l.sw 4(r3), r1 + l.sw 8(r3), r2 + l.sw 12(r3), r3 + l.sw 16(r3), r4 + l.sw 20(r3), r5 + l.sw 24(r3), r6 + l.sw 28(r3), r7 + l.sw 32(r3), r8 + l.sw 36(r3), r9 + l.sw 40(r3), r10 + l.sw 44(r3), r11 + l.sw 48(r3), r12 + l.sw 52(r3), r13 + l.sw 56(r3), r14 + l.sw 60(r3), r15 + l.sw 64(r3), r16 + l.sw 68(r3), r17 + l.sw 72(r3), r18 + l.sw 76(r3), r19 + l.sw 80(r3), r20 + l.sw 84(r3), r21 + l.sw 88(r3), r22 + l.sw 92(r3), r23 + l.sw 96(r3), r24 + l.sw 100(r3), r25 + l.sw 104(r3), r26 + l.sw 108(r3), r27 + l.sw 112(r3), r28 + l.sw 116(r3), r29 + l.sw 120(r3), r30 + l.sw 124(r3), r31 + # store ra to pc + l.sw 128(r3), r9 + # zero epcr + l.sw 132(r3), r0 + +#elif defined(__hexagon__) +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in r0 +# +#define OFFSET(offset) (offset/4) +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + memw(r0+#32) = r8 + memw(r0+#36) = r9 + memw(r0+#40) = r10 + memw(r0+#44) = r11 + + memw(r0+#48) = r12 + memw(r0+#52) = r13 + memw(r0+#56) = r14 + memw(r0+#60) = r15 + + memw(r0+#64) = r16 + memw(r0+#68) = r17 + memw(r0+#72) = r18 + memw(r0+#76) = r19 + + memw(r0+#80) = r20 + memw(r0+#84) = r21 + memw(r0+#88) = r22 + memw(r0+#92) = r23 + + memw(r0+#96) = r24 + memw(r0+#100) = r25 + memw(r0+#104) = r26 + memw(r0+#108) = r27 + + memw(r0+#112) = r28 + memw(r0+#116) = r29 + memw(r0+#120) = r30 + memw(r0+#124) = r31 + r1 = c4 // Predicate register + memw(r0+#128) = r1 + r1 = memw(r30) // *FP == Saved FP + r1 = r31 + memw(r0+#132) = r1 + + jumpr r31 + +#elif defined(__sparc__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in o0 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + ta 3 + add %o7, 8, %o7 + std %g0, [%o0 + 0] + std %g2, [%o0 + 8] + std %g4, [%o0 + 16] + std %g6, [%o0 + 24] + std %o0, [%o0 + 32] + std %o2, [%o0 + 40] + std %o4, [%o0 + 48] + std %o6, [%o0 + 56] + std %l0, [%o0 + 64] + std %l2, [%o0 + 72] + std %l4, [%o0 + 80] + std %l6, [%o0 + 88] + std %i0, [%o0 + 96] + std %i2, [%o0 + 104] + std %i4, [%o0 + 112] + std %i6, [%o0 + 120] + jmp %o7 + clr %o0 // return UNW_ESUCCESS + +#elif defined(__riscv) && __riscv_xlen == 64 + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + sd x1, (8 * 0)(a0) // store ra as pc + sd x1, (8 * 1)(a0) + sd x2, (8 * 2)(a0) + sd x3, (8 * 3)(a0) + sd x4, (8 * 4)(a0) + sd x5, (8 * 5)(a0) + sd x6, (8 * 6)(a0) + sd x7, (8 * 7)(a0) + sd x8, (8 * 8)(a0) + sd x9, (8 * 9)(a0) + sd x10, (8 * 10)(a0) + sd x11, (8 * 11)(a0) + sd x12, (8 * 12)(a0) + sd x13, (8 * 13)(a0) + sd x14, (8 * 14)(a0) + sd x15, (8 * 15)(a0) + sd x16, (8 * 16)(a0) + sd x17, (8 * 17)(a0) + sd x18, (8 * 18)(a0) + sd x19, (8 * 19)(a0) + sd x20, (8 * 20)(a0) + sd x21, (8 * 21)(a0) + sd x22, (8 * 22)(a0) + sd x23, (8 * 23)(a0) + sd x24, (8 * 24)(a0) + sd x25, (8 * 25)(a0) + sd x26, (8 * 26)(a0) + sd x27, (8 * 27)(a0) + sd x28, (8 * 28)(a0) + sd x29, (8 * 29)(a0) + sd x30, (8 * 30)(a0) + sd x31, (8 * 31)(a0) + +#if defined(__riscv_flen) && __riscv_flen == 64 + fsd f0, (8 * 32 + 8 * 0)(a0) + fsd f1, (8 * 32 + 8 * 1)(a0) + fsd f2, (8 * 32 + 8 * 2)(a0) + fsd f3, (8 * 32 + 8 * 3)(a0) + fsd f4, (8 * 32 + 8 * 4)(a0) + fsd f5, (8 * 32 + 8 * 5)(a0) + fsd f6, (8 * 32 + 8 * 6)(a0) + fsd f7, (8 * 32 + 8 * 7)(a0) + fsd f8, (8 * 32 + 8 * 8)(a0) + fsd f9, (8 * 32 + 8 * 9)(a0) + fsd f10, (8 * 32 + 8 * 10)(a0) + fsd f11, (8 * 32 + 8 * 11)(a0) + fsd f12, (8 * 32 + 8 * 12)(a0) + fsd f13, (8 * 32 + 8 * 13)(a0) + fsd f14, (8 * 32 + 8 * 14)(a0) + fsd f15, (8 * 32 + 8 * 15)(a0) + fsd f16, (8 * 32 + 8 * 16)(a0) + fsd f17, (8 * 32 + 8 * 17)(a0) + fsd f18, (8 * 32 + 8 * 18)(a0) + fsd f19, (8 * 32 + 8 * 19)(a0) + fsd f20, (8 * 32 + 8 * 20)(a0) + fsd f21, (8 * 32 + 8 * 21)(a0) + fsd f22, (8 * 32 + 8 * 22)(a0) + fsd f23, (8 * 32 + 8 * 23)(a0) + fsd f24, (8 * 32 + 8 * 24)(a0) + fsd f25, (8 * 32 + 8 * 25)(a0) + fsd f26, (8 * 32 + 8 * 26)(a0) + fsd f27, (8 * 32 + 8 * 27)(a0) + fsd f28, (8 * 32 + 8 * 28)(a0) + fsd f29, (8 * 32 + 8 * 29)(a0) + fsd f30, (8 * 32 + 8 * 30)(a0) + fsd f31, (8 * 32 + 8 * 31)(a0) +#endif + + li a0, 0 // return UNW_ESUCCESS + ret // jump to ra +#endif + + WEAK_ALIAS(__unw_getcontext, unw_getcontext) + +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + +NO_EXEC_STACK_DIRECTIVE diff --git a/libunwind/src/Unwind_AppleExtras.cpp b/libunwind/src/Unwind_AppleExtras.cpp new file mode 100644 index 0000000..1e759e6 --- /dev/null +++ b/libunwind/src/Unwind_AppleExtras.cpp @@ -0,0 +1,119 @@ +//===--------------------- Unwind_AppleExtras.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +//===----------------------------------------------------------------------===// + +#include "config.h" + + +// static linker symbols to prevent wrong two level namespace for _Unwind symbols +#if __arm__ +#if defined(__USING_SJLJ_EXCEPTIONS__) && defined(TARGET_OS_IOS) + #define NOT_HERE_BEFORE_5_0(sym) \ + extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \ + extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \ + extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\ + __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \ + extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \ + extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \ + extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \ + extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp43 = 0; +#else // defined(__USING_SJLJ_EXCEPTIONS__) && defined(TARGET_OS_IOS) + #define NOT_HERE_BEFORE_5_0(sym) + #define NOT_HERE_BEFORE_10_6(sym) + #define NEVER_HERE(sym) +#endif // defined(__USING_SJLJ_EXCEPTIONS__) && defined(TARGET_OS_IOS) +#elif defined(__aarch64__) + #define NOT_HERE_BEFORE_10_6(sym) + #define NEVER_HERE(sym) +#else + #define NOT_HERE_BEFORE_10_6(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; + #define NEVER_HERE(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \ + extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp6 = 0; +#endif + + +#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) + +// +// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in +// earlier versions +// +NOT_HERE_BEFORE_10_6(_Unwind_DeleteException) +NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE) +NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind) +NOT_HERE_BEFORE_10_6(_Unwind_GetGR) +NOT_HERE_BEFORE_10_6(_Unwind_GetIP) +NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData) +NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart) +NOT_HERE_BEFORE_10_6(_Unwind_RaiseException) +NOT_HERE_BEFORE_10_6(_Unwind_Resume) +NOT_HERE_BEFORE_10_6(_Unwind_SetGR) +NOT_HERE_BEFORE_10_6(_Unwind_SetIP) +NOT_HERE_BEFORE_10_6(_Unwind_Backtrace) +NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction) +NOT_HERE_BEFORE_10_6(_Unwind_GetCFA) +NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase) +NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase) +NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow) +NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo) +NOT_HERE_BEFORE_10_6(__register_frame) +NOT_HERE_BEFORE_10_6(__deregister_frame) + +// +// symbols in libSystem.dylib for compatibility, but we don't want any new code +// using them +// +NEVER_HERE(__register_frame_info_bases) +NEVER_HERE(__register_frame_info) +NEVER_HERE(__register_frame_info_table_bases) +NEVER_HERE(__register_frame_info_table) +NEVER_HERE(__register_frame_table) +NEVER_HERE(__deregister_frame_info) +NEVER_HERE(__deregister_frame_info_bases) + +#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) + + + + +#if defined(_LIBUNWIND_BUILD_SJLJ_APIS) +// +// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in +// earlier versions +// +NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData) +NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart) +NOT_HERE_BEFORE_5_0(_Unwind_GetIP) +NOT_HERE_BEFORE_5_0(_Unwind_SetGR) +NOT_HERE_BEFORE_5_0(_Unwind_SetIP) +NOT_HERE_BEFORE_5_0(_Unwind_DeleteException) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register) +NOT_HERE_BEFORE_5_0(_Unwind_GetGR) +NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo) +NOT_HERE_BEFORE_5_0(_Unwind_GetCFA) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) + +#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h new file mode 100644 index 0000000..4cf179e --- /dev/null +++ b/libunwind/src/assembly.h @@ -0,0 +1,165 @@ +/* ===-- assembly.h - libUnwind assembler support macros -------------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + * ===----------------------------------------------------------------------=== + * + * This file defines macros for use in libUnwind assembler source. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef UNWIND_ASSEMBLY_H +#define UNWIND_ASSEMBLY_H + +#if defined(__powerpc64__) +#define SEPARATOR ; +#define PPC64_OFFS_SRR0 0 +#define PPC64_OFFS_CR 272 +#define PPC64_OFFS_XER 280 +#define PPC64_OFFS_LR 288 +#define PPC64_OFFS_CTR 296 +#define PPC64_OFFS_VRSAVE 304 +#define PPC64_OFFS_FP 312 +#define PPC64_OFFS_V 824 +#ifdef _ARCH_PWR8 +#define PPC64_HAS_VMX +#endif +#elif defined(__APPLE__) && defined(__aarch64__) +#define SEPARATOR %% +#else +#define SEPARATOR ; +#endif + +#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) +#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR +#define PPC64_OPD2 SEPARATOR \ + .p2align 3 SEPARATOR \ + .quad .Lfunc_begin0 SEPARATOR \ + .quad .TOC.@tocbase SEPARATOR \ + .quad 0 SEPARATOR \ + .text SEPARATOR \ +.Lfunc_begin0: +#else +#define PPC64_OPD1 +#define PPC64_OPD2 +#endif + +#define GLUE2(a, b) a ## b +#define GLUE(a, b) GLUE2(a, b) +#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) + +#if defined(__APPLE__) + +#define SYMBOL_IS_FUNC(name) +#define EXPORT_SYMBOL(name) +#define HIDDEN_SYMBOL(name) .private_extern name +#define WEAK_SYMBOL(name) .weak_reference name +#define WEAK_ALIAS(name, aliasname) \ + .globl SYMBOL_NAME(aliasname) SEPARATOR \ + WEAK_SYMBOL(aliasname) SEPARATOR \ + SYMBOL_NAME(aliasname) = SYMBOL_NAME(name) + +#define NO_EXEC_STACK_DIRECTIVE + +#elif defined(__ELF__) + +#if defined(__arm__) +#define SYMBOL_IS_FUNC(name) .type name,%function +#else +#define SYMBOL_IS_FUNC(name) .type name,@function +#endif +#define EXPORT_SYMBOL(name) +#define HIDDEN_SYMBOL(name) .hidden name +#define WEAK_SYMBOL(name) .weak name + +#if defined(__hexagon__) +#define WEAK_ALIAS(name, aliasname) \ + WEAK_SYMBOL(aliasname) SEPARATOR \ + .equiv SYMBOL_NAME(aliasname), SYMBOL_NAME(name) +#else +#define WEAK_ALIAS(name, aliasname) \ + WEAK_SYMBOL(aliasname) SEPARATOR \ + SYMBOL_NAME(aliasname) = SYMBOL_NAME(name) +#endif + +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ + defined(__linux__) +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits +#else +#define NO_EXEC_STACK_DIRECTIVE +#endif + +#elif defined(_WIN32) + +#define SYMBOL_IS_FUNC(name) \ + .def name SEPARATOR \ + .scl 2 SEPARATOR \ + .type 32 SEPARATOR \ + .endef +#define EXPORT_SYMBOL2(name) \ + .section .drectve,"yn" SEPARATOR \ + .ascii "-export:", #name, "\0" SEPARATOR \ + .text +#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) +#define EXPORT_SYMBOL(name) +#else +#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name) +#endif +#define HIDDEN_SYMBOL(name) + +#if defined(__MINGW32__) +#define WEAK_ALIAS(name, aliasname) \ + .globl SYMBOL_NAME(aliasname) SEPARATOR \ + EXPORT_SYMBOL(aliasname) SEPARATOR \ + SYMBOL_NAME(aliasname) = SYMBOL_NAME(name) +#else +#define WEAK_ALIAS3(name, aliasname) \ + .section .drectve,"yn" SEPARATOR \ + .ascii "-alternatename:", #aliasname, "=", #name, "\0" SEPARATOR \ + .text +#define WEAK_ALIAS2(name, aliasname) \ + WEAK_ALIAS3(name, aliasname) +#define WEAK_ALIAS(name, aliasname) \ + EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + WEAK_ALIAS2(SYMBOL_NAME(name), SYMBOL_NAME(aliasname)) +#endif + +#define NO_EXEC_STACK_DIRECTIVE + +#elif defined(__sparc__) + +#else + +#error Unsupported target + +#endif + +#define DEFINE_LIBUNWIND_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + PPC64_OPD1 \ + SYMBOL_NAME(name): \ + PPC64_OPD2 + +#if defined(__arm__) +#if !defined(__ARM_ARCH) +#define __ARM_ARCH 4 +#endif + +#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 +#define ARM_HAS_BX +#endif + +#ifdef ARM_HAS_BX +#define JMP(r) bx r +#else +#define JMP(r) mov pc, r +#endif +#endif /* __arm__ */ + +#endif /* UNWIND_ASSEMBLY_H */ diff --git a/libunwind/src/config.h b/libunwind/src/config.h new file mode 100644 index 0000000..ee944ab --- /dev/null +++ b/libunwind/src/config.h @@ -0,0 +1,232 @@ +//===----------------------------- config.h -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Defines macros used within libunwind project. +// +//===----------------------------------------------------------------------===// + + +#ifndef LIBUNWIND_CONFIG_H +#define LIBUNWIND_CONFIG_H + +#include +#include +#include +#include + +#include <__libunwind_config.h> + +// Platform specific configuration defines. +#ifdef __APPLE__ + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #ifndef FOR_DYLD + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #endif +#elif defined(_WIN32) + #ifdef __SEH__ + #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1 + #else + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #endif +#elif defined(_LIBUNWIND_IS_BAREMETAL) + #if !defined(_LIBUNWIND_ARM_EHABI) + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 + #endif +#elif defined(__BIONIC__) && defined(_LIBUNWIND_ARM_EHABI) + // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After + // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster. + #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1 +#else + // Assume an ELF system with a dl_iterate_phdr function. + #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1 + #if !defined(_LIBUNWIND_ARM_EHABI) + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 + #endif +#endif + +#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS) + #define _LIBUNWIND_EXPORT + #define _LIBUNWIND_HIDDEN +#else + #if !defined(__ELF__) && !defined(__MACH__) + #define _LIBUNWIND_EXPORT __declspec(dllexport) + #define _LIBUNWIND_HIDDEN + #else + #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) + #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) + #endif +#endif + +#define STR(a) #a +#define XSTR(a) STR(a) +#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name + +#if defined(__APPLE__) +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + __asm__(".globl " SYMBOL_NAME(aliasname)); \ + __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ + __attribute__((weak_import)); +#elif defined(__ELF__) +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ + __attribute__((weak, alias(#name))); +#elif defined(_WIN32) +#if defined(__MINGW32__) +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ + __attribute__((alias(#name))); +#else +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + __pragma(comment(linker, "/alternatename:" SYMBOL_NAME(aliasname) "=" \ + SYMBOL_NAME(name))) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname; +#endif +#else +#error Unsupported target +#endif + +#if defined(__USING_SJLJ_EXCEPTIONS__) +#define _LIBUNWIND_BUILD_SJLJ_APIS +#endif + +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) +#define _LIBUNWIND_SUPPORT_FRAME_APIS +#endif + +#if defined(__i386__) || defined(__x86_64__) || \ + defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__arm__) || \ + defined(__aarch64__) || \ + defined(__mips__) || \ + defined(__riscv) || \ + defined(__hexagon__) +#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS) +#define _LIBUNWIND_BUILD_ZERO_COST_APIS +#endif +#endif + +#if defined(__powerpc64__) && defined(_ARCH_PWR8) +#define PPC64_HAS_VMX +#endif + +#ifdef FOR_DYLD +#ifdef __cplusplus +extern "C" { +#endif + extern void _ZN4dyld3logEPKcz(const char *, ...); +#ifdef __cplusplus +} +#endif +#endif + +#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_ABORT(msg) \ + do { \ + abort(); \ + } while (0) +#elif defined(FOR_DYLD) +#define _LIBUNWIND_ABORT(msg) \ + do { \ + _ZN4dyld3logEPKcz("%s %s:%d - %s\n", __func__, __FILE__, __LINE__, msg); \ + abort(); \ + } while (0) +#else +#define _LIBUNWIND_ABORT(msg) \ + do { \ + fprintf(stderr, "libunwind: %s - %s\n", __func__, msg); \ + fflush(stderr); \ + abort(); \ + } while (0) +#endif + +#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_LOG0(msg) +#define _LIBUNWIND_LOG(msg, ...) +#elif defined(FOR_DYLD) +#define _LIBUNWIND_LOG0(msg) _ZN4dyld3logEPKcz(msg) +#define _LIBUNWIND_LOG(msg, ...) _ZN4dyld3logEPKcz(msg, __VA_ARGS__) +#else +#define _LIBUNWIND_LOG0(msg) \ + fprintf(stderr, "libunwind: " msg "\n") +#define _LIBUNWIND_LOG(msg, ...) \ + fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__) +#endif + +#if defined(NDEBUG) + #define _LIBUNWIND_LOG_IF_FALSE(x) x +#else + #define _LIBUNWIND_LOG_IF_FALSE(x) \ + do { \ + bool _ret = x; \ + if (!_ret) \ + _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \ + } while (0) +#endif + +// Macros that define away in non-Debug builds +#ifdef NDEBUG + #define _LIBUNWIND_DEBUG_LOG(msg, ...) + #define _LIBUNWIND_TRACE_API(msg, ...) + #define _LIBUNWIND_TRACING_UNWINDING (0) + #define _LIBUNWIND_TRACING_DWARF (0) + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) + #define _LIBUNWIND_TRACE_DWARF(...) +#else + #ifdef __cplusplus + extern "C" { + #endif + extern bool logAPIs(); + extern bool logUnwinding(); + extern bool logDWARF(); + #ifdef __cplusplus + } + #endif + #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) + #define _LIBUNWIND_TRACE_API(msg, ...) \ + do { \ + if (logAPIs()) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while (0) + #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() + #define _LIBUNWIND_TRACING_DWARF logDWARF() + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ + do { \ + if (logUnwinding()) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while (0) + #define _LIBUNWIND_TRACE_DWARF(...) \ + do { \ + if (logDWARF()) \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +#endif + +#ifdef __cplusplus +// Used to fit UnwindCursor and Registers_xxx types against unw_context_t / +// unw_cursor_t sized memory blocks. +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# define COMP_OP == +#else +# define COMP_OP <= +#endif +template +struct check_fit { + template + struct blk_count { + static const size_t count = + (sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t); + }; + static const bool does_fit = + (blk_count<_Type>::count COMP_OP blk_count<_Mem>::count); +}; +#undef COMP_OP +#endif // __cplusplus + +#endif // LIBUNWIND_CONFIG_H diff --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h index c4fe5eb..40f0daf 100644 --- a/libunwind/src/dwarf2.h +++ b/libunwind/src/dwarf2.h @@ -1,255 +1,239 @@ +//===------------------------------- dwarf2.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + + /* - * Copyright (c) 2007-2008 Apple, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* These constants were taken from version 3 of the DWARF standard, + These constants were taken from version 3 of the DWARF standard, which is Copyright (c) 2005 Free Standards Group, and - Copyright (c) 1992, 1993 UNIX International, Inc. + Copyright (c) 1992, 1993 UNIX International, Inc. */ - #ifndef __DWARF2__ #define __DWARF2__ -// dwarf unwind instructions +// DWARF unwind instructions enum { - DW_CFA_nop = 0x0, - DW_CFA_set_loc = 0x1, - DW_CFA_advance_loc1 = 0x2, - DW_CFA_advance_loc2 = 0x3, - DW_CFA_advance_loc4 = 0x4, - DW_CFA_offset_extended = 0x5, - DW_CFA_restore_extended = 0x6, - DW_CFA_undefined = 0x7, - DW_CFA_same_value = 0x8, - DW_CFA_register = 0x9, - DW_CFA_remember_state = 0xA, - DW_CFA_restore_state = 0xB, - DW_CFA_def_cfa = 0xC, - DW_CFA_def_cfa_register = 0xD, - DW_CFA_def_cfa_offset = 0xE, - DW_CFA_def_cfa_expression = 0xF, - DW_CFA_expression = 0x10, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_def_cfa_sf = 0x12, - DW_CFA_def_cfa_offset_sf = 0x13, - DW_CFA_val_offset = 0x14, - DW_CFA_val_offset_sf = 0x15, - DW_CFA_val_expression = 0x16, - DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta - DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register - DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register - - // GNU extensions - DW_CFA_GNU_window_save = 0x2D, - DW_CFA_GNU_args_size = 0x2E, - DW_CFA_GNU_negative_offset_extended = 0x2F + DW_CFA_nop = 0x0, + DW_CFA_set_loc = 0x1, + DW_CFA_advance_loc1 = 0x2, + DW_CFA_advance_loc2 = 0x3, + DW_CFA_advance_loc4 = 0x4, + DW_CFA_offset_extended = 0x5, + DW_CFA_restore_extended = 0x6, + DW_CFA_undefined = 0x7, + DW_CFA_same_value = 0x8, + DW_CFA_register = 0x9, + DW_CFA_remember_state = 0xA, + DW_CFA_restore_state = 0xB, + DW_CFA_def_cfa = 0xC, + DW_CFA_def_cfa_register = 0xD, + DW_CFA_def_cfa_offset = 0xE, + DW_CFA_def_cfa_expression = 0xF, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta + DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register + DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register + + // GNU extensions + DW_CFA_GNU_window_save = 0x2D, + DW_CFA_GNU_args_size = 0x2E, + DW_CFA_GNU_negative_offset_extended = 0x2F, + + // AARCH64 extensions + DW_CFA_AARCH64_negate_ra_state = 0x2D }; -// FSF exception handling Pointer-Encoding constants -// Used in CFI augmentation by gcc compiler +// FSF exception handling Pointer-Encoding constants +// Used in CFI augmentation by GCC enum { - DW_EH_PE_ptr = 0x00, - DW_EH_PE_uleb128 = 0x01, - DW_EH_PE_udata2 = 0x02, - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_udata8 = 0x04, - DW_EH_PE_signed = 0x08, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0A, - DW_EH_PE_sdata4 = 0x0B, - DW_EH_PE_sdata8 = 0x0C, - DW_EH_PE_absptr = 0x00, - DW_EH_PE_pcrel = 0x10, - DW_EH_PE_textrel = 0x20, - DW_EH_PE_datarel = 0x30, - DW_EH_PE_funcrel = 0x40, - DW_EH_PE_aligned = 0x50, - DW_EH_PE_indirect = 0x80, - DW_EH_PE_omit = 0xFF + DW_EH_PE_ptr = 0x00, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_signed = 0x08, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + DW_EH_PE_absptr = 0x00, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + DW_EH_PE_indirect = 0x80, + DW_EH_PE_omit = 0xFF }; -// DWARF expressions +// DWARF expressions enum { - DW_OP_addr = 0x03, // constant address (size target specific) - DW_OP_deref = 0x06, - DW_OP_const1u = 0x08, // 1-byte constant - DW_OP_const1s = 0x09, // 1-byte constant - DW_OP_const2u = 0x0A, // 2-byte constant - DW_OP_const2s = 0x0B, // 2-byte constant - DW_OP_const4u = 0x0C, // 4-byte constant - DW_OP_const4s = 0x0D, // 4-byte constant - DW_OP_const8u = 0x0E, // 8-byte constant - DW_OP_const8s = 0x0F, // 8-byte constant - DW_OP_constu = 0x10, // ULEB128 constant - DW_OP_consts = 0x11, // SLEB128 constant - DW_OP_dup = 0x12, - DW_OP_drop = 0x13, - DW_OP_over = 0x14, - DW_OP_pick = 0x15, // 1-byte stack index - DW_OP_swap = 0x16, - DW_OP_rot = 0x17, - DW_OP_xderef = 0x18, - DW_OP_abs = 0x19, - DW_OP_and = 0x1A, - DW_OP_div = 0x1B, - DW_OP_minus = 0x1C, - DW_OP_mod = 0x1D, - DW_OP_mul = 0x1E, - DW_OP_neg = 0x1F, - DW_OP_not = 0x20, - DW_OP_or = 0x21, - DW_OP_plus = 0x22, - DW_OP_plus_uconst = 0x23, // ULEB128 addend - DW_OP_shl = 0x24, - DW_OP_shr = 0x25, - DW_OP_shra = 0x26, - DW_OP_xor = 0x27, - DW_OP_skip = 0x2F, // signed 2-byte constant - DW_OP_bra = 0x28, // signed 2-byte constant - DW_OP_eq = 0x29, - DW_OP_ge = 0x2A, - DW_OP_gt = 0x2B, - DW_OP_le = 0x2C, - DW_OP_lt = 0x2D, - DW_OP_ne = 0x2E, - DW_OP_lit0 = 0x30, // Literal 0 - DW_OP_lit1 = 0x31, // Literal 1 - DW_OP_lit2 = 0x32, // Literal 2 - DW_OP_lit3 = 0x33, // Literal 3 - DW_OP_lit4 = 0x34, // Literal 4 - DW_OP_lit5 = 0x35, // Literal 5 - DW_OP_lit6 = 0x36, // Literal 6 - DW_OP_lit7 = 0x37, // Literal 7 - DW_OP_lit8 = 0x38, // Literal 8 - DW_OP_lit9 = 0x39, // Literal 9 - DW_OP_lit10 = 0x3A, // Literal 10 - DW_OP_lit11 = 0x3B, // Literal 11 - DW_OP_lit12 = 0x3C, // Literal 12 - DW_OP_lit13 = 0x3D, // Literal 13 - DW_OP_lit14 = 0x3E, // Literal 14 - DW_OP_lit15 = 0x3F, // Literal 15 - DW_OP_lit16 = 0x40, // Literal 16 - DW_OP_lit17 = 0x41, // Literal 17 - DW_OP_lit18 = 0x42, // Literal 18 - DW_OP_lit19 = 0x43, // Literal 19 - DW_OP_lit20 = 0x44, // Literal 20 - DW_OP_lit21 = 0x45, // Literal 21 - DW_OP_lit22 = 0x46, // Literal 22 - DW_OP_lit23 = 0x47, // Literal 23 - DW_OP_lit24 = 0x48, // Literal 24 - DW_OP_lit25 = 0x49, // Literal 25 - DW_OP_lit26 = 0x4A, // Literal 26 - DW_OP_lit27 = 0x4B, // Literal 27 - DW_OP_lit28 = 0x4C, // Literal 28 - DW_OP_lit29 = 0x4D, // Literal 29 - DW_OP_lit30 = 0x4E, // Literal 30 - DW_OP_lit31 = 0x4F, // Literal 31 - DW_OP_reg0 = 0x50, // Contents of reg0 - DW_OP_reg1 = 0x51, // Contents of reg1 - DW_OP_reg2 = 0x52, // Contents of reg2 - DW_OP_reg3 = 0x53, // Contents of reg3 - DW_OP_reg4 = 0x54, // Contents of reg4 - DW_OP_reg5 = 0x55, // Contents of reg5 - DW_OP_reg6 = 0x56, // Contents of reg6 - DW_OP_reg7 = 0x57, // Contents of reg7 - DW_OP_reg8 = 0x58, // Contents of reg8 - DW_OP_reg9 = 0x59, // Contents of reg9 - DW_OP_reg10 = 0x5A, // Contents of reg10 - DW_OP_reg11 = 0x5B, // Contents of reg11 - DW_OP_reg12 = 0x5C, // Contents of reg12 - DW_OP_reg13 = 0x5D, // Contents of reg13 - DW_OP_reg14 = 0x5E, // Contents of reg14 - DW_OP_reg15 = 0x5F, // Contents of reg15 - DW_OP_reg16 = 0x60, // Contents of reg16 - DW_OP_reg17 = 0x61, // Contents of reg17 - DW_OP_reg18 = 0x62, // Contents of reg18 - DW_OP_reg19 = 0x63, // Contents of reg19 - DW_OP_reg20 = 0x64, // Contents of reg20 - DW_OP_reg21 = 0x65, // Contents of reg21 - DW_OP_reg22 = 0x66, // Contents of reg22 - DW_OP_reg23 = 0x67, // Contents of reg23 - DW_OP_reg24 = 0x68, // Contents of reg24 - DW_OP_reg25 = 0x69, // Contents of reg25 - DW_OP_reg26 = 0x6A, // Contents of reg26 - DW_OP_reg27 = 0x6B, // Contents of reg27 - DW_OP_reg28 = 0x6C, // Contents of reg28 - DW_OP_reg29 = 0x6D, // Contents of reg29 - DW_OP_reg30 = 0x6E, // Contents of reg30 - DW_OP_reg31 = 0x6F, // Contents of reg31 - DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset - DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset - DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset - DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset - DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset - DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset - DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset - DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset - DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset - DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset - DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset - DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset - DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset - DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset - DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset - DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset - DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset - DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset - DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset - DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset - DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset - DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset - DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset - DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset - DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset - DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset - DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset - DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset - DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset - DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset - DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset - DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset - DW_OP_regx = 0x90, // ULEB128 register - DW_OP_fbreg = 0x91, // SLEB128 offset - DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset - DW_OP_piece = 0x93, // ULEB128 size of piece addressed - DW_OP_deref_size = 0x94, // 1-byte size of data retrieved - DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved - DW_OP_nop = 0x96, - DW_OP_push_object_addres = 0x97, - DW_OP_call2 = 0x98, // 2-byte offset of DIE - DW_OP_call4 = 0x99, // 4-byte offset of DIE - DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE - DW_OP_lo_user = 0xE0, - DW_OP_APPLE_uninit = 0xF0, - DW_OP_hi_user = 0xFF + DW_OP_addr = 0x03, // constant address (size target specific) + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, // 1-byte constant + DW_OP_const1s = 0x09, // 1-byte constant + DW_OP_const2u = 0x0A, // 2-byte constant + DW_OP_const2s = 0x0B, // 2-byte constant + DW_OP_const4u = 0x0C, // 4-byte constant + DW_OP_const4s = 0x0D, // 4-byte constant + DW_OP_const8u = 0x0E, // 8-byte constant + DW_OP_const8s = 0x0F, // 8-byte constant + DW_OP_constu = 0x10, // ULEB128 constant + DW_OP_consts = 0x11, // SLEB128 constant + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, // 1-byte stack index + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1A, + DW_OP_div = 0x1B, + DW_OP_minus = 0x1C, + DW_OP_mod = 0x1D, + DW_OP_mul = 0x1E, + DW_OP_neg = 0x1F, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, // ULEB128 addend + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_skip = 0x2F, // signed 2-byte constant + DW_OP_bra = 0x28, // signed 2-byte constant + DW_OP_eq = 0x29, + DW_OP_ge = 0x2A, + DW_OP_gt = 0x2B, + DW_OP_le = 0x2C, + DW_OP_lt = 0x2D, + DW_OP_ne = 0x2E, + DW_OP_lit0 = 0x30, // Literal 0 + DW_OP_lit1 = 0x31, // Literal 1 + DW_OP_lit2 = 0x32, // Literal 2 + DW_OP_lit3 = 0x33, // Literal 3 + DW_OP_lit4 = 0x34, // Literal 4 + DW_OP_lit5 = 0x35, // Literal 5 + DW_OP_lit6 = 0x36, // Literal 6 + DW_OP_lit7 = 0x37, // Literal 7 + DW_OP_lit8 = 0x38, // Literal 8 + DW_OP_lit9 = 0x39, // Literal 9 + DW_OP_lit10 = 0x3A, // Literal 10 + DW_OP_lit11 = 0x3B, // Literal 11 + DW_OP_lit12 = 0x3C, // Literal 12 + DW_OP_lit13 = 0x3D, // Literal 13 + DW_OP_lit14 = 0x3E, // Literal 14 + DW_OP_lit15 = 0x3F, // Literal 15 + DW_OP_lit16 = 0x40, // Literal 16 + DW_OP_lit17 = 0x41, // Literal 17 + DW_OP_lit18 = 0x42, // Literal 18 + DW_OP_lit19 = 0x43, // Literal 19 + DW_OP_lit20 = 0x44, // Literal 20 + DW_OP_lit21 = 0x45, // Literal 21 + DW_OP_lit22 = 0x46, // Literal 22 + DW_OP_lit23 = 0x47, // Literal 23 + DW_OP_lit24 = 0x48, // Literal 24 + DW_OP_lit25 = 0x49, // Literal 25 + DW_OP_lit26 = 0x4A, // Literal 26 + DW_OP_lit27 = 0x4B, // Literal 27 + DW_OP_lit28 = 0x4C, // Literal 28 + DW_OP_lit29 = 0x4D, // Literal 29 + DW_OP_lit30 = 0x4E, // Literal 30 + DW_OP_lit31 = 0x4F, // Literal 31 + DW_OP_reg0 = 0x50, // Contents of reg0 + DW_OP_reg1 = 0x51, // Contents of reg1 + DW_OP_reg2 = 0x52, // Contents of reg2 + DW_OP_reg3 = 0x53, // Contents of reg3 + DW_OP_reg4 = 0x54, // Contents of reg4 + DW_OP_reg5 = 0x55, // Contents of reg5 + DW_OP_reg6 = 0x56, // Contents of reg6 + DW_OP_reg7 = 0x57, // Contents of reg7 + DW_OP_reg8 = 0x58, // Contents of reg8 + DW_OP_reg9 = 0x59, // Contents of reg9 + DW_OP_reg10 = 0x5A, // Contents of reg10 + DW_OP_reg11 = 0x5B, // Contents of reg11 + DW_OP_reg12 = 0x5C, // Contents of reg12 + DW_OP_reg13 = 0x5D, // Contents of reg13 + DW_OP_reg14 = 0x5E, // Contents of reg14 + DW_OP_reg15 = 0x5F, // Contents of reg15 + DW_OP_reg16 = 0x60, // Contents of reg16 + DW_OP_reg17 = 0x61, // Contents of reg17 + DW_OP_reg18 = 0x62, // Contents of reg18 + DW_OP_reg19 = 0x63, // Contents of reg19 + DW_OP_reg20 = 0x64, // Contents of reg20 + DW_OP_reg21 = 0x65, // Contents of reg21 + DW_OP_reg22 = 0x66, // Contents of reg22 + DW_OP_reg23 = 0x67, // Contents of reg23 + DW_OP_reg24 = 0x68, // Contents of reg24 + DW_OP_reg25 = 0x69, // Contents of reg25 + DW_OP_reg26 = 0x6A, // Contents of reg26 + DW_OP_reg27 = 0x6B, // Contents of reg27 + DW_OP_reg28 = 0x6C, // Contents of reg28 + DW_OP_reg29 = 0x6D, // Contents of reg29 + DW_OP_reg30 = 0x6E, // Contents of reg30 + DW_OP_reg31 = 0x6F, // Contents of reg31 + DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset + DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset + DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset + DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset + DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset + DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset + DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset + DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset + DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset + DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset + DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset + DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset + DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset + DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset + DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset + DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset + DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset + DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset + DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset + DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset + DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset + DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset + DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset + DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset + DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset + DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset + DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset + DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset + DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset + DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset + DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset + DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset + DW_OP_regx = 0x90, // ULEB128 register + DW_OP_fbreg = 0x91, // SLEB128 offset + DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset + DW_OP_piece = 0x93, // ULEB128 size of piece addressed + DW_OP_deref_size = 0x94, // 1-byte size of data retrieved + DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved + DW_OP_nop = 0x96, + DW_OP_push_object_addres = 0x97, + DW_OP_call2 = 0x98, // 2-byte offset of DIE + DW_OP_call4 = 0x99, // 4-byte offset of DIE + DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE + DW_OP_lo_user = 0xE0, + DW_OP_APPLE_uninit = 0xF0, + DW_OP_hi_user = 0xFF }; - - #endif - - - diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp new file mode 100644 index 0000000..8f2168d --- /dev/null +++ b/libunwind/src/libunwind.cpp @@ -0,0 +1,340 @@ +//===--------------------------- libunwind.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements unw_* functions from +// +//===----------------------------------------------------------------------===// + +#include + +#include "libunwind_ext.h" +#include "config.h" + + +#include + + +#if !defined(__USING_SJLJ_EXCEPTIONS__) +#include "AddressSpace.hpp" +#include "UnwindCursor.hpp" + +using namespace libunwind; + +/// internal object to represent this processes address space +LocalAddressSpace LocalAddressSpace::sThisAddressSpace; + +_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = + (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; + +/// Create a cursor of a thread in this process given 'context' recorded by +/// __unw_getcontext(). +_LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor, + unw_context_t *context) { + _LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)", + static_cast(cursor), + static_cast(context)); +#if defined(__i386__) +# define REGISTER_KIND Registers_x86 +#elif defined(__x86_64__) +# define REGISTER_KIND Registers_x86_64 +#elif defined(__powerpc64__) +# define REGISTER_KIND Registers_ppc64 +#elif defined(__ppc__) +# define REGISTER_KIND Registers_ppc +#elif defined(__aarch64__) +# define REGISTER_KIND Registers_arm64 +#elif defined(__arm__) +# define REGISTER_KIND Registers_arm +#elif defined(__or1k__) +# define REGISTER_KIND Registers_or1k +#elif defined(__hexagon__) +# define REGISTER_KIND Registers_hexagon +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 +# define REGISTER_KIND Registers_mips_o32 +#elif defined(__mips64) +# define REGISTER_KIND Registers_mips_newabi +#elif defined(__mips__) +# warning The MIPS architecture is not supported with this ABI and environment! +#elif defined(__sparc__) +# define REGISTER_KIND Registers_sparc +#elif defined(__riscv) && __riscv_xlen == 64 +# define REGISTER_KIND Registers_riscv +#else +# error Architecture not supported +#endif + // Use "placement new" to allocate UnwindCursor in the cursor buffer. + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#undef REGISTER_KIND + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->setInfoBasedOnIPRegister(); + + return UNW_ESUCCESS; +} +_LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local) + +/// Get value of specified register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_word_t *value) { + _LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)", + static_cast(cursor), regNum, + static_cast(value)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + *value = co->getReg(regNum); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg) + +/// Set value of specified register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_word_t value) { + _LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR + ")", + static_cast(cursor), regNum, value); + typedef LocalAddressSpace::pint_t pint_t; + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + // specical case altering IP to re-find info (being called by personality + // function) + if (regNum == UNW_REG_IP) { + unw_proc_info_t info; + // First, get the FDE for the old location and then update it. + co->getInfo(&info); + + + pint_t sp = (pint_t)co->getReg(UNW_REG_SP); + + + pint_t orgArgSize = (pint_t)info.gp; + uint64_t orgFuncStart = info.start_ip; + // and adjust REG_SP if there was a DW_CFA_GNU_args_size + // If the original call expects stack adjustment, perform this now. + // Normal frame unwinding would have included the offset already in the + // CFA computation. + // Note: for PA-RISC and other platforms where the stack grows up, + // this should actually be - info.gp. LLVM doesn't currently support + // any such platforms and Clang doesn't export a macro for them. + if ((orgFuncStart == info.start_ip) && (orgArgSize != 0)) { + co->setReg(UNW_REG_SP, sp + orgArgSize); + co->setReg(UNW_REG_IP, value); + } else { + co->setReg(UNW_REG_IP, value); + } + co->setInfoBasedOnIPRegister(false); + } else { + co->setReg(regNum, (pint_t)value); + } + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg) + +/// Get value of specified float register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_fpreg_t *value) { + _LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)", + static_cast(cursor), regNum, + static_cast(value)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validFloatReg(regNum)) { + *value = co->getFloatReg(regNum); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg) + +/// Set value of specified float register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_fpreg_t value) { +#if defined(_LIBUNWIND_ARM_EHABI) + _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", + static_cast(cursor), regNum, value); +#else + _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)", + static_cast(cursor), regNum, value); +#endif + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validFloatReg(regNum)) { + co->setFloatReg(regNum, value); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg) + +/// Move cursor to next frame. +_LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->step(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step) + +/// Get unwind info at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor, + unw_proc_info_t *info) { + _LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)", + static_cast(cursor), static_cast(info)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->getInfo(info); + if (info->end_ip == 0) + return UNW_ENOINFO; + return UNW_ESUCCESS; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info) + +/// Resume execution at cursor position (aka longjump). +_LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->jumpto(); + return UNW_EUNSPEC; +} +_LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume) + +/// Get name of function at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf, + size_t bufLen, unw_word_t *offset) { + _LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)", + static_cast(cursor), static_cast(buf), + static_cast(bufLen)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->getFunctionName(buf, bufLen, offset)) + return UNW_ESUCCESS; + return UNW_EUNSPEC; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name) + +/// Checks if a register is a floating-point register. +_LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor, + unw_regnum_t regNum) { + _LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)", + static_cast(cursor), regNum); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->validFloatReg(regNum); +} +_LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg) + +/// Checks if a register is a floating-point register. +_LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor, + unw_regnum_t regNum) { + _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)", + static_cast(cursor), regNum); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->getRegisterName(regNum); +} +_LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname) + +/// Checks if current frame is signal trampoline. +_LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)", + static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->isSignalFrame(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame) + +#ifdef __arm__ +// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD +_LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)", + static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->saveVFPAsX(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X) +#endif + + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +/// SPI: walks cached DWARF entries +_LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { + _LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)", + reinterpret_cast(func)); + DwarfFDECache::iterateCacheEntries(func); +} +_LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache, + unw_iterate_dwarf_unwind_cache) + +/// IPI: for __register_frame() +void __unw_add_dynamic_fde(unw_word_t fde) { + CFI_Parser::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + const char *message = CFI_Parser::decodeFDE( + LocalAddressSpace::sThisAddressSpace, + (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); + if (message == NULL) { + // dynamically registered FDEs don't have a mach_header group they are in. + // Use fde as mh_group + unw_word_t mh_group = fdeInfo.fdeStart; + DwarfFDECache::add((LocalAddressSpace::pint_t)mh_group, + fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } else { + _LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message); + } +} + +/// IPI: for __deregister_frame() +void __unw_remove_dynamic_fde(unw_word_t fde) { + // fde is own mh_group + DwarfFDECache::removeAllIn((LocalAddressSpace::pint_t)fde); +} +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#endif // !defined(__USING_SJLJ_EXCEPTIONS__) + + + +// Add logging hooks in Debug builds only +#ifndef NDEBUG +#include + +_LIBUNWIND_HIDDEN +bool logAPIs() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); + checked = true; + } + return log; +} + +_LIBUNWIND_HIDDEN +bool logUnwinding() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); + checked = true; + } + return log; +} + +_LIBUNWIND_HIDDEN +bool logDWARF() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL); + checked = true; + } + return log; +} + +#endif // NDEBUG + diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h new file mode 100644 index 0000000..ba9861d --- /dev/null +++ b/libunwind/src/libunwind_ext.h @@ -0,0 +1,69 @@ +//===------------------------ libunwind_ext.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Extensions to libunwind API. +// +//===----------------------------------------------------------------------===// + +#ifndef __LIBUNWIND_EXT__ +#define __LIBUNWIND_EXT__ + +#include "config.h" +#include +#include + +#define UNW_STEP_SUCCESS 1 +#define UNW_STEP_END 0 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int __unw_getcontext(unw_context_t *); +extern int __unw_init_local(unw_cursor_t *, unw_context_t *); +extern int __unw_step(unw_cursor_t *); +extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *); +extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *); +extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t); +extern int __unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t); +extern int __unw_resume(unw_cursor_t *); + +#ifdef __arm__ +/* Save VFP registers in FSTMX format (instead of FSTMD). */ +extern void __unw_save_vfp_as_X(unw_cursor_t *); +#endif + +extern const char *__unw_regname(unw_cursor_t *, unw_regnum_t); +extern int __unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *); +extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t); +extern int __unw_is_signal_frame(unw_cursor_t *); +extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *); + +// SPI +extern void __unw_iterate_dwarf_unwind_cache(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); + +// IPI +extern void __unw_add_dynamic_fde(unw_word_t fde); +extern void __unw_remove_dynamic_fde(unw_word_t fde); + +#if defined(_LIBUNWIND_ARM_EHABI) +extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*); +extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, + const uint32_t *data, + size_t offset, size_t len); +#endif + +#ifdef __cplusplus +} +#endif + +enum ProcInfoFlags { + ProcInfoFlags_NoFlags = 0, +}; + +#endif // __LIBUNWIND_EXT__ diff --git a/libunwind/src/libunwind_priv.h b/libunwind/src/libunwind_priv.h deleted file mode 100644 index 5efa586..0000000 --- a/libunwind/src/libunwind_priv.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; -*- - * - * Copyright (c) 2008 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - */ - -#ifndef __LIBUNWIND_PRIV__ -#define __LIBUNWIND_PRIV__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - // SPI - extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); - - // IPI - extern void _unw_add_dynamic_fde(unw_word_t fde); - extern void _unw_remove_dynamic_fde(unw_word_t fde); - -#ifdef __cplusplus -} -#endif - - - - -#endif - diff --git a/libunwind/src/libuwind.cxx b/libunwind/src/libuwind.cxx deleted file mode 100644 index 8d59507..0000000 --- a/libunwind/src/libuwind.cxx +++ /dev/null @@ -1,380 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2007-2008 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include -#include -#include - -#include "libunwind.h" -#include "libunwind_priv.h" - -#include "UnwindCursor.hpp" - - - -using namespace libunwind; - - -// setup debug logging hooks -INITIALIZE_DEBUG_PRINT_API -INITIALIZE_DEBUG_PRINT_UNWINDING - - -#if __ppc__ || __i386__ || __x86_64__ - -// internal object to represent this processes address space -static LocalAddressSpace sThisAddressSpace; - -/// -/// record the registers and stack position of the caller -/// -extern int unw_getcontext(unw_context_t*); -// note: unw_getcontext() implemented in assembly - - -/// -/// create a cursor of a thread in this process given 'context' recorded by unw_getcontext() -/// -EXPORT int unw_init_local(unw_cursor_t* cursor, unw_context_t* context) -{ - DEBUG_PRINT_API("unw_init_local(cursor=%p, context=%p)\n", cursor, context); - // use "placement new" to allocate UnwindCursor in the cursor buffer -#if __i386__ - new ((void*)cursor) UnwindCursor(context, sThisAddressSpace); -#elif __x86_64__ - new ((void*)cursor) UnwindCursor(context, sThisAddressSpace); -#elif __ppc__ - new ((void*)cursor) UnwindCursor(context, sThisAddressSpace); -#endif - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - co->setInfoBasedOnIPRegister(); - - return UNW_ESUCCESS; -} - -#if UNW_REMOTE - -EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&sThisAddressSpace; - -/// -/// create a cursor into a thread in another process -/// -EXPORT int unw_init_remote_thread(unw_cursor_t* cursor, unw_addr_space_t as, thread_t thread) -{ - // special case: unw_init_remote(xx, unw_local_addr_space, xx) - if ( as == (unw_addr_space_t)&sThisAddressSpace ) - return unw_init_local(cursor, NULL); //FIXME - - // use "placement new" to allocate UnwindCursor in the cursor buffer - switch ( as->cpuType ) { - case CPU_TYPE_I386: - new ((void*)cursor) UnwindCursor >, - Registers_x86>(((unw_addr_space_i386*)as)->oas, thread); - break; - case CPU_TYPE_X86_64: - new ((void*)cursor) UnwindCursor >, - Registers_x86_64>(((unw_addr_space_x86_64*)as)->oas, thread); - break; - case CPU_TYPE_POWERPC: - new ((void*)cursor) UnwindCursor >, - Registers_ppc>(((unw_addr_space_ppc*)as)->oas, thread); - break; - default: - return UNW_EUNSPEC; - } - return UNW_ESUCCESS; -} - -static bool rosetta(task_t task) -{ - return false; // FIXME -} - -static bool is64bit(task_t task) -{ - return false; // FIXME -} - -/// -/// create an address_space object for use in examining another task -/// -EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) -{ -#if __i386__ - if ( rosetta(task) ) { - unw_addr_space_ppc* as = new unw_addr_space_ppc(task); - as->taskPort = task; - as->cpuType = CPU_TYPE_POWERPC; - //as->oas - } - else if ( is64bit(task) ) { - unw_addr_space_x86_64* as = new unw_addr_space_x86_64(task); - as->taskPort = task; - as->cpuType = CPU_TYPE_X86_64; - //as->oas - } - else { - unw_addr_space_i386* as = new unw_addr_space_i386(task); - as->taskPort = task; - as->cpuType = CPU_TYPE_I386; - //as->oas - } -#else - // FIXME -#endif -} - - -/// -/// delete an address_space object -/// -EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) -{ - switch ( asp->cpuType ) { -#if __i386__ || __x86_64__ - case CPU_TYPE_I386: - { - unw_addr_space_i386* as = (unw_addr_space_i386*)asp; - delete as; - } - break; - case CPU_TYPE_X86_64: - { - unw_addr_space_x86_64* as = (unw_addr_space_x86_64*)asp; - delete as; - } - break; -#endif - case CPU_TYPE_POWERPC: - { - unw_addr_space_ppc* as = (unw_addr_space_ppc*)asp; - delete as; - } - break; - } -} -#endif // UNW_REMOTE - - -/// -/// get value of specified register at cursor position in stack frame -/// -EXPORT int unw_get_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t* value) -{ - DEBUG_PRINT_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - if ( co->validReg(regNum) ) { - *value = co->getReg(regNum); - return UNW_ESUCCESS; - } - return UNW_EBADREG; -} - - -/// -/// set value of specified register at cursor position in stack frame -/// -EXPORT int unw_set_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t value) -{ - DEBUG_PRINT_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", cursor, regNum, value); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - if ( co->validReg(regNum) ) { - co->setReg(regNum, value); - // specical case altering IP to re-find info (being called by personality function) - if ( regNum == UNW_REG_IP ) { - unw_proc_info_t info; - co->getInfo(&info); - uint64_t orgArgSize = info.gp; - uint64_t orgFuncStart = info.start_ip; - co->setInfoBasedOnIPRegister(false); - // and adjust REG_SP if there was a DW_CFA_GNU_args_size - if ( (orgFuncStart == info.start_ip) && (orgArgSize != 0) ) - co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize); - } - return UNW_ESUCCESS; - } - return UNW_EBADREG; -} - - -/// -/// get value of specified float register at cursor position in stack frame -/// -EXPORT int unw_get_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t* value) -{ - DEBUG_PRINT_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - if ( co->validFloatReg(regNum) ) { - *value = co->getFloatReg(regNum); - return UNW_ESUCCESS; - } - return UNW_EBADREG; -} - -/// -/// set value of specified float register at cursor position in stack frame -/// -EXPORT int unw_set_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t value) -{ - DEBUG_PRINT_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", cursor, regNum, value); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - if ( co->validFloatReg(regNum) ) { - co->setFloatReg(regNum, value); - return UNW_ESUCCESS; - } - return UNW_EBADREG; -} - - -/// -/// move cursor to next frame -/// -EXPORT int unw_step(unw_cursor_t* cursor) -{ - DEBUG_PRINT_API("unw_step(cursor=%p)\n", cursor); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - return co->step(); -} - - -/// -/// get unwind info at cursor position in stack frame -/// -EXPORT int unw_get_proc_info(unw_cursor_t* cursor, unw_proc_info_t* info) -{ - DEBUG_PRINT_API("unw_get_proc_info(cursor=%p, &info=%p)\n", cursor, info); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - co->getInfo(info); - if ( info->end_ip == 0 ) - return UNW_ENOINFO; - else - return UNW_ESUCCESS; -} - -/// -/// resume execution at cursor position (aka longjump) -/// -EXPORT int unw_resume(unw_cursor_t* cursor) -{ - DEBUG_PRINT_API("unw_resume(cursor=%p)\n", cursor); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - co->jumpto(); - return UNW_EUNSPEC; -} - - -/// -/// get name of function at cursor position in stack frame -/// -EXPORT int unw_get_proc_name(unw_cursor_t* cursor, char* buf, size_t bufLen, unw_word_t* offset) -{ - DEBUG_PRINT_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%ld)\n", cursor, buf, bufLen); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - if ( co->getFunctionName(buf, bufLen, offset) ) - return UNW_ESUCCESS; - else - return UNW_EUNSPEC; -} - - -/// -/// checks if a register is a floating-point register -/// -EXPORT int unw_is_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum) -{ - DEBUG_PRINT_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", cursor, regNum); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - return co->validFloatReg(regNum); -} - - -/// -/// checks if a register is a floating-point register -/// -EXPORT const char* unw_regname(unw_cursor_t* cursor, unw_regnum_t regNum) -{ - DEBUG_PRINT_API("unw_regname(cursor=%p, regNum=%d)\n", cursor, regNum); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - return co->getRegisterName(regNum); -} - - -/// -/// checks if current frame is signal trampoline -/// -EXPORT int unw_is_signal_frame(unw_cursor_t* cursor) -{ - DEBUG_PRINT_API("unw_is_signal_frame(cursor=%p)\n", cursor); - AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; - return co->isSignalFrame(); -} - -#if !FOR_DYLD -/// -/// SPI: walks cached dwarf entries -/// -EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) -{ - DEBUG_PRINT_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func); - DwarfFDECache::iterateCacheEntries(func); -} -#endif // !FOR_DYLD - - -#if !FOR_DYLD -// -// IPI: for __register_frame() -// -void _unw_add_dynamic_fde(unw_word_t fde) -{ - CFI_Parser::FDE_Info fdeInfo; - CFI_Parser::CIE_Info cieInfo; - const char* message = CFI_Parser::decodeFDE(sThisAddressSpace, (LocalAddressSpace::pint_t)fde, & fdeInfo, &cieInfo); - if ( message == NULL ) { - // dynamically registered FDEs don't have a mach_header group they are in. Use fde as mh_group - unw_word_t mh_group = fdeInfo.fdeStart; - DwarfFDECache::add(mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); - } - else { - DEBUG_MESSAGE("_unw_add_dynamic_fde: bad fde: %s", message); - } -} - -// -// IPI: for __deregister_frame() -// -void _unw_remove_dynamic_fde(unw_word_t fde) -{ - // fde is own mh_group - DwarfFDECache::removeAllIn(fde); -} -#endif - - -#endif // __ppc__ || __i386__ || __x86_64__ - - - - diff --git a/libunwind/src/unw_getcontext.S b/libunwind/src/unw_getcontext.S deleted file mode 100644 index 8d3a451..0000000 --- a/libunwind/src/unw_getcontext.S +++ /dev/null @@ -1,229 +0,0 @@ - -#if __i386__ || __x86_64__ || __ppc__ - - .text - .globl _unw_getcontext -_unw_getcontext: - -#endif // __i386__ || __x86_64__ || __ppc__ - - -#if __i386__ - -# -# extern int unw_getcontext(unw_context_t* thread_state) -# -# On entry: -# + + -# +-----------------------+ -# + thread_state pointer + -# +-----------------------+ -# + return address + -# +-----------------------+ <-- SP -# + + -# - push %eax - movl 8(%esp), %eax - movl %ebx, 4(%eax) - movl %ecx, 8(%eax) - movl %edx, 12(%eax) - movl %edi, 16(%eax) - movl %esi, 20(%eax) - movl %ebp, 24(%eax) - movl %esp, %edx - addl $8, %edx - movl %edx, 28(%eax) # store what sp was at call site as esp - # skip ss - # skip eflags - movl 4(%esp), %edx - movl %edx, 40(%eax) # store return address as eip - # skip cs - # skip ds - # skip es - # skip fs - # skip gs - movl (%esp), %edx - movl %edx, (%eax) # store original eax - popl %eax - xorl %eax, %eax # return UNW_ESUCCESS - ret - -#elif __x86_64__ - -# -# extern int unw_getcontext(unw_context_t* thread_state) -# -# On entry: -# thread_state pointer is in rdi -# - movq %rax, (%rdi) - movq %rbx, 8(%rdi) - movq %rcx, 16(%rdi) - movq %rdx, 24(%rdi) - movq %rdi, 32(%rdi) - movq %rsi, 40(%rdi) - movq %rbp, 48(%rdi) - movq %rsp, 56(%rdi) - addq $8, 56(%rdi) - movq %r8, 64(%rdi) - movq %r9, 72(%rdi) - movq %r10, 80(%rdi) - movq %r11, 88(%rdi) - movq %r12, 96(%rdi) - movq %r13,104(%rdi) - movq %r14,112(%rdi) - movq %r15,120(%rdi) - movq (%rsp),%rsi - movq %rsi,128(%rdi) # store return address as rip - # skip rflags - # skip cs - # skip fs - # skip gs - xorl %eax, %eax # return UNW_ESUCCESS - ret - -#elif __ppc__ - -; -; extern int unw_getcontext(unw_context_t* thread_state) -; -; On entry: -; thread_state pointer is in r3 -; - stw r0, 8(r3) - mflr r0 - stw r0, 0(r3) ; store lr as ssr0 - stw r1, 12(r3) - stw r2, 16(r3) - stw r3, 20(r3) - stw r4, 24(r3) - stw r5, 28(r3) - stw r6, 32(r3) - stw r7, 36(r3) - stw r8, 40(r3) - stw r9, 44(r3) - stw r10, 48(r3) - stw r11, 52(r3) - stw r12, 56(r3) - stw r13, 60(r3) - stw r14, 64(r3) - stw r15, 68(r3) - stw r16, 72(r3) - stw r17, 76(r3) - stw r18, 80(r3) - stw r19, 84(r3) - stw r20, 88(r3) - stw r21, 92(r3) - stw r22, 96(r3) - stw r23,100(r3) - stw r24,104(r3) - stw r25,108(r3) - stw r26,112(r3) - stw r27,116(r3) - stw r28,120(r3) - stw r29,124(r3) - stw r30,128(r3) - stw r31,132(r3) - - ; save VRSave register - mfspr r0,256 - stw r0,156(r3) - ; save CR registers - mfcr r0 - stw r0,136(r3) - ; save CTR register - mfctr r0 - stw r0,148(r3) - - ; save float registers - stfd f0, 160(r3) - stfd f1, 168(r3) - stfd f2, 176(r3) - stfd f3, 184(r3) - stfd f4, 192(r3) - stfd f5, 200(r3) - stfd f6, 208(r3) - stfd f7, 216(r3) - stfd f8, 224(r3) - stfd f9, 232(r3) - stfd f10,240(r3) - stfd f11,248(r3) - stfd f12,256(r3) - stfd f13,264(r3) - stfd f14,272(r3) - stfd f15,280(r3) - stfd f16,288(r3) - stfd f17,296(r3) - stfd f18,304(r3) - stfd f19,312(r3) - stfd f20,320(r3) - stfd f21,328(r3) - stfd f22,336(r3) - stfd f23,344(r3) - stfd f24,352(r3) - stfd f25,360(r3) - stfd f26,368(r3) - stfd f27,376(r3) - stfd f28,384(r3) - stfd f29,392(r3) - stfd f30,400(r3) - stfd f31,408(r3) - - - ; save vector registers - - subi r4,r1,16 - rlwinm r4,r4,0,0,27 ; mask low 4-bits - ; r4 is now a 16-byte aligned pointer into the red zone - -#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ - stvx _vec,0,r4 @\ - lwz r5, 0(r4) @\ - stw r5, _offset(r3) @\ - lwz r5, 4(r4) @\ - stw r5, _offset+4(r3) @\ - lwz r5, 8(r4) @\ - stw r5, _offset+8(r3) @\ - lwz r5, 12(r4) @\ - stw r5, _offset+12(r3) - - SAVE_VECTOR_UNALIGNED( v0, 424+0x000) - SAVE_VECTOR_UNALIGNED( v1, 424+0x010) - SAVE_VECTOR_UNALIGNED( v2, 424+0x020) - SAVE_VECTOR_UNALIGNED( v3, 424+0x030) - SAVE_VECTOR_UNALIGNED( v4, 424+0x040) - SAVE_VECTOR_UNALIGNED( v5, 424+0x050) - SAVE_VECTOR_UNALIGNED( v6, 424+0x060) - SAVE_VECTOR_UNALIGNED( v7, 424+0x070) - SAVE_VECTOR_UNALIGNED( v8, 424+0x080) - SAVE_VECTOR_UNALIGNED( v9, 424+0x090) - SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0) - SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0) - SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0) - SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0) - SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0) - SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0) - SAVE_VECTOR_UNALIGNED(v16, 424+0x100) - SAVE_VECTOR_UNALIGNED(v17, 424+0x110) - SAVE_VECTOR_UNALIGNED(v18, 424+0x120) - SAVE_VECTOR_UNALIGNED(v19, 424+0x130) - SAVE_VECTOR_UNALIGNED(v20, 424+0x140) - SAVE_VECTOR_UNALIGNED(v21, 424+0x150) - SAVE_VECTOR_UNALIGNED(v22, 424+0x160) - SAVE_VECTOR_UNALIGNED(v23, 424+0x170) - SAVE_VECTOR_UNALIGNED(v24, 424+0x180) - SAVE_VECTOR_UNALIGNED(v25, 424+0x190) - SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0) - SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0) - SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0) - SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0) - SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0) - SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0) - - li r3, 0 ; return UNW_ESUCCESS - blr - - - -#endif - diff --git a/libunwind/test/CMakeLists.txt b/libunwind/test/CMakeLists.txt new file mode 100644 index 0000000..2b945e6 --- /dev/null +++ b/libunwind/test/CMakeLists.txt @@ -0,0 +1,35 @@ +include(AddLLVM) # for add_lit_testsuite +macro(pythonize_bool var) + if (${var}) + set(${var} True) + else() + set(${var} False) + endif() +endmacro() + +if (NOT DEFINED LIBCXX_ENABLE_SHARED) + set(LIBCXX_ENABLE_SHARED ON) +endif() + +pythonize_bool(LIBUNWIND_BUILD_32_BITS) +pythonize_bool(LIBCXX_ENABLE_SHARED) +pythonize_bool(LIBUNWIND_ENABLE_SHARED) +pythonize_bool(LIBUNWIND_ENABLE_THREADS) +pythonize_bool(LIBUNWIND_USES_ARM_EHABI) +pythonize_bool(LIBUNWIND_USE_COMPILER_RT) +pythonize_bool(LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY) +set(LIBUNWIND_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING + "TargetInfo to use when setting up test environment.") +set(LIBUNWIND_LIBCXX_PATH "${CMAKE_CURRENT_LIST_DIR}/../../libcxx") +set(LIBUNWIND_EXECUTOR "${Python3_EXECUTABLE} ${LIBUNWIND_LIBCXX_PATH}/utils/run.py" CACHE STRING + "Executor to use when running tests.") + +set(AUTO_GEN_COMMENT "## Autogenerated by libunwind configuration.\n# Do not edit!") +configure_lit_site_cfg( + "${LIBUNWIND_TEST_CONFIG}" + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + MAIN_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py") + +add_lit_testsuite(check-unwind "Running libunwind tests" + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS unwind ${LIBUNWIND_TEST_DEPS}) diff --git a/libunwind/test/alignment.pass.cpp b/libunwind/test/alignment.pass.cpp new file mode 100644 index 0000000..b0da7f1 --- /dev/null +++ b/libunwind/test/alignment.pass.cpp @@ -0,0 +1,28 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// The Itanium ABI requires that _Unwind_Exception objects are "double-word +// aligned". + +#include + +// EHABI : 8-byte aligned +// itanium: largest supported alignment for the system +#if defined(_LIBUNWIND_ARM_EHABI) +static_assert(alignof(_Unwind_Control_Block) == 8, + "_Unwind_Control_Block must be double-word aligned"); +#else +struct MaxAligned {} __attribute__((__aligned__)); +static_assert(alignof(_Unwind_Exception) == alignof(MaxAligned), + "_Unwind_Exception must be maximally aligned"); +#endif + +int main() +{ +} diff --git a/libunwind/test/frameheadercache_test.pass.cpp b/libunwind/test/frameheadercache_test.pass.cpp new file mode 100644 index 0000000..7f2d8e2 --- /dev/null +++ b/libunwind/test/frameheadercache_test.pass.cpp @@ -0,0 +1,73 @@ +// The other libunwind tests don't test internal interfaces, so the include path +// is a little wonky. +#include "../src/config.h" + +// Only run this test under supported configurations. + +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) && \ + defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) && \ + defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + +#include +#include + +// This file defines several of the data structures needed here, +// and includes FrameHeaderCache.hpp as well. +#include "../src/AddressSpace.hpp" + +#define kBaseAddr 0xFFF000 +#define kDwarfSectionLength 0xFF + +using namespace libunwind; + +int main() { + FrameHeaderCache FHC; + struct dl_phdr_info PInfo; + memset(&PInfo, 0, sizeof(PInfo)); + // The cache itself should only care about these two fields--they + // tell the cache to invalidate or not; everything else is handled + // by AddressSpace.hpp. + PInfo.dlpi_adds = 6; + PInfo.dlpi_subs = 7; + + UnwindInfoSections UIS; + UIS.dso_base = kBaseAddr; + UIS.dwarf_section_length = kDwarfSectionLength; + dl_iterate_cb_data CBData; + // Unused by the cache. + CBData.addressSpace = nullptr; + CBData.sects = &UIS; + CBData.targetAddr = kBaseAddr + 1; + + // Nothing present, shouldn't find. + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + FHC.add(&UIS); + // Just added. Should find. + if (!FHC.find(&PInfo, 0, &CBData)) + abort(); + // Cache is invalid. Shouldn't find. + PInfo.dlpi_adds++; + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + + FHC.add(&UIS); + CBData.targetAddr = kBaseAddr - 1; + // Shouldn't find something outside of the addresses. + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + // Add enough things to the cache that the entry is evicted. + for (int i = 0; i < 9; i++) { + UIS.dso_base = kBaseAddr + (kDwarfSectionLength * i); + FHC.add(&UIS); + } + CBData.targetAddr = kBaseAddr; + // Should have been evicted. + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + return 0; +} + +#else +int main() { return 0;} +#endif diff --git a/libunwind/test/libunwind/__init__.py b/libunwind/test/libunwind/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libunwind/test/libunwind/test/__init__.py b/libunwind/test/libunwind/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libunwind/test/libunwind/test/config.py b/libunwind/test/libunwind/test/config.py new file mode 100644 index 0000000..977f9a0 --- /dev/null +++ b/libunwind/test/libunwind/test/config.py @@ -0,0 +1,68 @@ +#===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +#===----------------------------------------------------------------------===## +import os +import sys + +from libcxx.test.config import Configuration as LibcxxConfiguration + + +class Configuration(LibcxxConfiguration): + # pylint: disable=redefined-outer-name + def __init__(self, lit_config, config): + super(Configuration, self).__init__(lit_config, config) + self.libunwind_src_root = None + self.libunwind_obj_root = None + self.abi_library_path = None + self.libcxx_src_root = None + + def configure_src_root(self): + self.libunwind_src_root = (self.get_lit_conf('libunwind_src_root') + or os.path.dirname(self.config.test_source_root)) + self.libcxx_src_root = (self.get_lit_conf('libcxx_src_root') + or os.path.join(self.libunwind_src_root, '..', 'libcxx')) + + def configure_obj_root(self): + self.libunwind_obj_root = self.get_lit_conf('libunwind_obj_root') + super(Configuration, self).configure_obj_root() + + def has_cpp_feature(self, feature, required_value): + return int(self.cxx.dumpMacros().get('__cpp_' + feature, 0)) >= required_value + + def configure_features(self): + super(Configuration, self).configure_features() + if self.get_lit_bool('arm_ehabi', False): + self.config.available_features.add('libunwind-arm-ehabi') + + def configure_compile_flags(self): + self.cxx.compile_flags += ['-DLIBUNWIND_NO_TIMER'] + # Stack unwinding tests need unwinding tables and these are not + # generated by default on all Targets. + self.cxx.compile_flags += ['-funwind-tables'] + if not self.get_lit_bool('enable_threads', True): + self.cxx.compile_flags += ['-D_LIBUNWIND_HAS_NO_THREADS'] + self.config.available_features.add('libunwind-no-threads') + super(Configuration, self).configure_compile_flags() + + def configure_compile_flags_header_includes(self): + self.configure_config_site_header() + + libunwind_headers = self.get_lit_conf( + 'libunwind_headers', + os.path.join(self.libunwind_src_root, 'include')) + if not os.path.isdir(libunwind_headers): + self.lit_config.fatal("libunwind_headers='%s' is not a directory." + % libunwind_headers) + self.cxx.compile_flags += ['-I' + libunwind_headers] + + def configure_link_flags_cxx_library(self): + # libunwind tests should not link with libc++ + pass + + def configure_link_flags_abi_library(self): + # libunwind tests should not link with libc++abi + pass diff --git a/libunwind/test/libunwind_01.pass.cpp b/libunwind/test/libunwind_01.pass.cpp new file mode 100644 index 0000000..db5d53d --- /dev/null +++ b/libunwind/test/libunwind_01.pass.cpp @@ -0,0 +1,63 @@ +#include +#include + +void backtrace(int lower_bound) { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + int n = 0; + do { + ++n; + if (n > 100) { + abort(); + } + } while (unw_step(&cursor) > 0); + + if (n < lower_bound) { + abort(); + } +} + +void test1(int i) { + backtrace(i); +} + +void test2(int i, int j) { + backtrace(i); + test1(j); +} + +void test3(int i, int j, int k) { + backtrace(i); + test2(j, k); +} + +void test_no_info() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + unw_proc_info_t info; + int ret = unw_get_proc_info(&cursor, &info); + if (ret != UNW_ESUCCESS) + abort(); + + // Set the IP to an address clearly outside any function. + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0); + + ret = unw_get_proc_info(&cursor, &info); + if (ret != UNW_ENOINFO) + abort(); +} + +int main() { + test1(1); + test2(1, 2); + test3(1, 2, 3); + test_no_info(); +} diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp new file mode 100644 index 0000000..a0efd1d --- /dev/null +++ b/libunwind/test/libunwind_02.pass.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#define EXPECTED_NUM_FRAMES 50 +#define NUM_FRAMES_UPPER_BOUND 100 + +_Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) { + (void)context; + int *i = (int *)cnt; + ++*i; + if (*i > NUM_FRAMES_UPPER_BOUND) { + abort(); + } + return _URC_NO_REASON; +} + +void test_backtrace() { + int n = 0; + _Unwind_Backtrace(&callback, &n); + if (n < EXPECTED_NUM_FRAMES) { + abort(); + } +} + +int test(int i) { + if (i == 0) { + test_backtrace(); + return 0; + } else { + return i + test(i - 1); + } +} + +int main() { + int total = test(50); + assert(total == 1275); +} diff --git a/libunwind/test/lit.cfg.py b/libunwind/test/lit.cfg.py new file mode 100644 index 0000000..647464a --- /dev/null +++ b/libunwind/test/lit.cfg.py @@ -0,0 +1,10 @@ +# All the Lit configuration is handled in the site configs -- this file is only +# left as a canary to catch invocations of Lit that do not go through llvm-lit. +# +# Invocations that go through llvm-lit will automatically use the right Lit +# site configuration inside the build directory. + +lit_config.fatal( + "You seem to be running Lit directly -- you should be running Lit through " + "/bin/llvm-lit, which will ensure that the right Lit configuration " + "file is used.") diff --git a/libunwind/test/lit.site.cfg.in b/libunwind/test/lit.site.cfg.in new file mode 100644 index 0000000..8ff770f --- /dev/null +++ b/libunwind/test/lit.site.cfg.in @@ -0,0 +1,57 @@ +@AUTO_GEN_COMMENT@ + +import os +import site + +config.cxx_under_test = "@CMAKE_CXX_COMPILER@" +config.project_obj_root = "@CMAKE_BINARY_DIR@" +config.libunwind_src_root = "@LIBUNWIND_SOURCE_DIR@" +config.libunwind_obj_root = "@LIBUNWIND_BINARY_DIR@" +config.abi_library_path = "@LIBUNWIND_LIBRARY_DIR@" +config.libcxx_src_root = "@LIBUNWIND_LIBCXX_PATH@" +config.libunwind_headers = "@LIBUNWIND_SOURCE_DIR@/include" +config.cxx_library_root = "@LIBUNWIND_LIBCXX_LIBRARY_PATH@" +config.llvm_unwinder = True +config.builtins_library = "@LIBUNWIND_BUILTINS_LIBRARY@" +config.enable_threads = @LIBUNWIND_ENABLE_THREADS@ +config.use_sanitizer = "@LLVM_USE_SANITIZER@" +config.enable_32bit = @LIBUNWIND_BUILD_32_BITS@ +config.target_info = "@LIBUNWIND_TARGET_INFO@" +config.test_linker_flags = "@LIBUNWIND_TEST_LINKER_FLAGS@" +config.test_compiler_flags = "@LIBUNWIND_TEST_COMPILER_FLAGS@" +config.executor = "@LIBUNWIND_EXECUTOR@" +config.libunwind_shared = @LIBUNWIND_ENABLE_SHARED@ +config.enable_shared = @LIBCXX_ENABLE_SHARED@ +config.arm_ehabi = @LIBUNWIND_USES_ARM_EHABI@ +config.host_triple = "@LLVM_HOST_TRIPLE@" +config.target_triple = "@TARGET_TRIPLE@" +config.sysroot = "@LIBUNWIND_SYSROOT@" +config.gcc_toolchain = "@LIBUNWIND_GCC_TOOLCHAIN@" +config.cxx_ext_threads = @LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY@ + +site.addsitedir(os.path.join(config.libunwind_src_root, 'test')) +site.addsitedir(os.path.join(config.libcxx_src_root, 'utils')) + +# name: The name of this test suite. +config.name = 'libunwind' + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = ['.cpp', '.s'] + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.join(config.libunwind_src_root, 'test') + +# Allow expanding substitutions that are based on other substitutions +config.recursiveExpansionLimit = 10 + +# Infer the test_exec_root from the build directory. +config.test_exec_root = os.path.join(config.libunwind_obj_root, 'test') + +import libcxx.test.format +config.test_format = libcxx.test.format.CxxStandardLibraryTest() + +lit_config.note('Using configuration variant: libunwind') +import libunwind.test.config +configuration = libunwind.test.config.Configuration(lit_config, config) +configuration.configure() +configuration.print_config_info() diff --git a/libunwind/test/remember_state_leak.pass.sh.s b/libunwind/test/remember_state_leak.pass.sh.s new file mode 100644 index 0000000..eb363d0 --- /dev/null +++ b/libunwind/test/remember_state_leak.pass.sh.s @@ -0,0 +1,56 @@ +# REQUIRES: x86, linux +# RUN: %{build} -target x86_64-unknown-linux-gnu +# RUN: %{run} + +# The following assembly is a translation of this code: +# +# _Unwind_Reason_Code callback(int, _Unwind_Action, long unsigned int, +# _Unwind_Exception*, _Unwind_Context*, void*) { +# return _Unwind_Reason_Code(0); +# } +# +# int main() { +# asm(".cfi_remember_state\n\t"); +# _Unwind_Exception exc; +# _Unwind_ForcedUnwind(&exc, callback, 0); +# asm(".cfi_restore_state\n\t"); +# } +# +# When unwinding, the CFI parser will stop parsing opcodes after the current PC, +# so in this case the DW_CFA_restore_state opcode will never be processed and, +# if the library doesn't clean up properly, the store allocated by +# DW_CFA_remember_state will be leaked. +# +# This test will fail when linked with an asan-enabled libunwind if the +# remembered state is leaked. + + SIZEOF_UNWIND_EXCEPTION = 32 + + .text +callback: + xorl %eax, %eax + retq + + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc + subq $8, %rsp # Adjust stack alignment + subq $SIZEOF_UNWIND_EXCEPTION, %rsp + .cfi_def_cfa_offset 48 + .cfi_remember_state + movq %rsp, %rdi + movabsq $callback, %rsi + xorl %edx, %edx + callq _Unwind_ForcedUnwind + .cfi_restore_state + xorl %eax, %eax + addq $SIZEOF_UNWIND_EXCEPTION, %rsp + addq $8, %rsp # Undo stack alignment adjustment + .cfi_def_cfa_offset 8 + retq +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + # -- End function diff --git a/libunwind/test/signal_frame.pass.cpp b/libunwind/test/signal_frame.pass.cpp new file mode 100644 index 0000000..025e932 --- /dev/null +++ b/libunwind/test/signal_frame.pass.cpp @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that functions marked as signal frames are reported as such. +// +// XFAIL: darwin + +// UNSUPPORTED: libunwind-arm-ehabi + +#include +#include +#include + +void test() { + asm(".cfi_signal_frame"); + unw_cursor_t cursor; + unw_context_t uc; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + assert(unw_step(&cursor) > 0); + assert(unw_is_signal_frame(&cursor)); +} + +int main() { + test(); + return 0; +} diff --git a/libunwind/test/unw_getcontext.pass.cpp b/libunwind/test/unw_getcontext.pass.cpp new file mode 100644 index 0000000..b012706 --- /dev/null +++ b/libunwind/test/unw_getcontext.pass.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main() { + unw_context_t context; + int ret = unw_getcontext(&context); + assert(ret == UNW_ESUCCESS); +} diff --git a/libunwind/testsuite/Unwind_Backtrace.c b/libunwind/testsuite/Unwind_Backtrace.c deleted file mode 100644 index e8f5c7b..0000000 --- a/libunwind/testsuite/Unwind_Backtrace.c +++ /dev/null @@ -1,59 +0,0 @@ - -// -// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -fomit-frame-pointer -// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -Wl,-no_compact_unwind -// TEST-OPTIONS: backtrace2.c -arch x86_64 -// TEST-OPTIONS: backtrace2.c -arch x86_64 -fomit-frame-pointer -// TEST-OPTIONS: backtrace2.c -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: backtrace2.c -arch ppc -fexceptions -// -// Tests _Unwind_Backtrace() -// - -#include -#include -#include -#include - -#include "unwind.h" - - -// put intermediate function into another file so compiler does not optimze away -extern int foo(); - -static const char* expected[] = { "bar", "foo", "main" }; - -static int step = 0; -static _Unwind_Reason_Code handler(struct _Unwind_Context* context, void* ref) -{ - if ( step > 2 ) - return _URC_NORMAL_STOP; - struct dl_info dyldInfo; - if ( dladdr((void*)_Unwind_GetIP(context), &dyldInfo) ) { - if ( strcmp(dyldInfo.dli_sname, expected[step]) != 0 ) { - fprintf(stderr, "unexpected frame %s\n", dyldInfo.dli_sname); - exit(1); - } - ++step; - } - else { - exit(1); - } - return _URC_NO_REASON; -} - - - -int bar() -{ - _Unwind_Backtrace(&handler, NULL); - return (step == 2); -} - - -int main() -{ - return foo(); -} - diff --git a/libunwind/testsuite/Unwind_ForcedUnwind.cxx b/libunwind/testsuite/Unwind_ForcedUnwind.cxx deleted file mode 100644 index 41c44c5..0000000 --- a/libunwind/testsuite/Unwind_ForcedUnwind.cxx +++ /dev/null @@ -1,54 +0,0 @@ - -// -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc -// -// Tests _Unwind_ForcedUnwind() -// - -#include -#include -#include - -#include "unwind.h" - - - -static bool exceptionCaught = false; - - -static _Unwind_Reason_Code stop_func(int version, _Unwind_Action actions, uint64_t exceptionClass, - _Unwind_Exception* exceptionObject, _Unwind_Context* context, void* stop_parameter) -{ - if ( actions & _UA_END_OF_STACK ) { - if ( exceptionCaught ) - exit(0); - else - exit(1); - } - return _URC_NO_REASON; -} - - -void test() -{ - try { - _Unwind_Exception* except_obj = (_Unwind_Exception*)calloc(sizeof(_Unwind_Exception), 1); - _Unwind_ForcedUnwind(except_obj, stop_func, NULL); - } - catch(...) { - // forced unwindind should run this catch clause - exceptionCaught = true; - throw; - } -} - -int main() -{ - test(); - return 1; -} - diff --git a/libunwind/testsuite/backtrace.c b/libunwind/testsuite/backtrace.c deleted file mode 100644 index 5054ab5..0000000 --- a/libunwind/testsuite/backtrace.c +++ /dev/null @@ -1,71 +0,0 @@ - -// -// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -fomit-frame-pointer -// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -Wl,-no_compact_unwind -// TEST-OPTIONS: backtrace2.c -arch x86_64 -// TEST-OPTIONS: backtrace2.c -arch x86_64 -fomit-frame-pointer -// TEST-OPTIONS: backtrace2.c -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: backtrace2.c -arch ppc -fexceptions -// -// Basic backtrace test -// - -#include -#include -#include -#include - -#include "libunwind.h" - -static const char* other_expected[] = { "bar", "foo", "work", "_pthread_start", NULL, NULL }; -static const char* main_expected[] = { "bar", "foo", "main", NULL, NULL }; - - -// put intermediate function into another file so compiler does not optimze away -extern int foo(const char** list); - - -int bar(const char** list) -{ - char functionName[64]; - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t offset; - - int index = 0; - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - do { - unw_get_proc_name(&cursor, functionName, 64, &offset); - //fprintf(stderr, "in function: %s\n", functionName); - if ( (list[index] != NULL) && (strcmp(functionName, list[index]) != 0) ) { - //fprintf(stderr, "unexpected function: %s\n", functionName); - exit(1); - } - ++index; - } while (unw_step(&cursor) > 0); - return 0; -} - -static void* work(void* arg) -{ - foo((const char**)arg); - return NULL; -} - - -int main() -{ - // test back traces on another thread - pthread_t worker1; - if ( pthread_create(&worker1, NULL, work, other_expected) != 0 ) { - exit(0); - } - void* result; - pthread_join(worker1, &result); - - // test back traces on main thread - return foo(main_expected); -} - diff --git a/libunwind/testsuite/backtrace2.c b/libunwind/testsuite/backtrace2.c deleted file mode 100644 index 060fc69..0000000 --- a/libunwind/testsuite/backtrace2.c +++ /dev/null @@ -1,7 +0,0 @@ - -extern int bar(const char** list); - -int foo(const char** list) -{ - return bar(list); -} diff --git a/libunwind/testsuite/dwarf_cache_dlclose.mk/Makefile b/libunwind/testsuite/dwarf_cache_dlclose.mk/Makefile deleted file mode 100644 index 0b0302b..0000000 --- a/libunwind/testsuite/dwarf_cache_dlclose.mk/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - - - - -all: - @g++ foo.cxx -dynamiclib -o libfoo.dylib -arch i386 -arch x86_64 -Wl,-no_compact_unwind - @gcc main.c -arch i386 -o main-i386 - @./main-i386 && echo "PASS dwarf-cache-dlclose -arch i386" - @gcc main.c -arch x86_64 -o main-x86_64 - @./main-x86_64 && echo "PASS dwarf-cache-dlclose -arch x86_64" -# @gcc main.c -arch ppc -o main-ppc -# @./main-ppc && echo "PASS dwarf-cache-dlclose -arch ppc" - -clean: - @rm -f libfoo.dylib main-i386 main-x86_64 main-ppc - - diff --git a/libunwind/testsuite/dwarf_cache_dlclose.mk/foo.cxx b/libunwind/testsuite/dwarf_cache_dlclose.mk/foo.cxx deleted file mode 100644 index 3414465..0000000 --- a/libunwind/testsuite/dwarf_cache_dlclose.mk/foo.cxx +++ /dev/null @@ -1,20 +0,0 @@ - -#include -void bar() -{ - throw "wow"; -} - -extern "C" void foo(); - -void foo() -{ - try { - bar(); - } - catch(...) { - //fprintf(stderr, "caught\n"); - } - - -} diff --git a/libunwind/testsuite/dwarf_cache_dlclose.mk/main.c b/libunwind/testsuite/dwarf_cache_dlclose.mk/main.c deleted file mode 100644 index 44645e5..0000000 --- a/libunwind/testsuite/dwarf_cache_dlclose.mk/main.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include - -extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); - - - -typedef void (*FooProc)(); -static FooProc foo; - -static bool fooInCache = false; -static void callback(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh) -{ - //fprintf(stderr, "ip_start = 0x%llX, ip_end = 0x%llX\n", ip_start, ip_end); - if ( (unw_word_t)(long)foo == ip_start ) - fooInCache = true; -} - - -int main() -{ - void* handle = dlopen("libfoo.dylib", RTLD_FIRST); - if ( handle == NULL ) { - printf("FAIL: dlopen could not load libfoo.dylib\n"); - return 1; - } - - foo = (FooProc)dlsym(handle, "foo"); - if ( foo == NULL ) { - printf("FAIL: dlsym could not find foo\n"); - return 1; - } - - //fprintf(stderr, "foo=%p\n", foo); - (*foo)(); - - // verify foo is in cache - fooInCache = false; - unw_iterate_dwarf_unwind_cache(&callback); - if ( !fooInCache ) { - printf("FAIL: foo is not in cache\n"); - return 1; - } - - dlclose(handle); - //fprintf(stderr, "dlclose\n"); - - // verify foo is no longer in cache - fooInCache = false; - unw_iterate_dwarf_unwind_cache(&callback); - if ( fooInCache ){ - printf("FAIL: foo is still in cache\n"); - return 1; - } - - return 0; -} diff --git a/libunwind/testsuite/dynamic_fde_registration.cxx b/libunwind/testsuite/dynamic_fde_registration.cxx deleted file mode 100644 index 3d3a68f..0000000 --- a/libunwind/testsuite/dynamic_fde_registration.cxx +++ /dev/null @@ -1,139 +0,0 @@ - -// -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// - -#include -#include -#include -#include -#include -#include - -#include "unwind.h" - -// private keymgr stuff -#define KEYMGR_GCC3_DW2_OBJ_LIST 302 -extern "C" { - extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr); - extern void* _keymgr_get_and_lock_processwide_ptr(int key); -}; - - -// undocumented libgcc "struct object" -struct libgcc_object -{ - void* start; - void* unused1; - void* unused2; - void* fde; - unsigned long encoding; - void* fde_end; - libgcc_object* next; -}; - -// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST -struct libgcc_object_info { - struct libgcc_object* seen_objects; - struct libgcc_object* unseen_objects; - unsigned spare[2]; -}; - - -// Some application have reverse engineer libgcc and do the equivalent -// of my_keymgr_register_frame() to register dynamically created code. -static void my_keymgr_register_frame(void* fde) -{ - // acquire exclusive access to libgcc_object_info - libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); - - // create new object - libgcc_object* ob = (libgcc_object*)calloc(sizeof(libgcc_object), 1); - ob->fde = fde; - - // insert new object into linked list - ob->next = head->unseen_objects; - head->unseen_objects = ob; - - // release libgcc_object_info - _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); -} - - - -void check(bool shouldFindMain) -{ - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t offset; - bool foundMain = false; - char functionName[256]; - //fprintf(stderr, "check(shouldFindMain=%d)\n", shouldFindMain); - - int level = 1; - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - do { - unw_get_proc_name(&cursor, functionName, 64, &offset); - //fprintf(stderr, "level=%d in function: %s\n", level, functionName); - if ( strcmp(functionName, "main") == 0 ) - foundMain = true; - ++level; - strcpy(functionName, "junk"); - } while (unw_step(&cursor) > 0); - - if ( foundMain == shouldFindMain ) - return; - - fprintf(stderr, "failing because shouldFindMain=%d and foundMain=%d\n", shouldFindMain, foundMain); - exit(1); -} - - - - -void foo(bool shouldFindMain, void (*func)(bool)) -{ - (*func)(shouldFindMain); - __asm__ volatile(""); // disable tail call optimization -} - -typedef void (*checkFuncProc)(bool shouldFindMain, void (*func)(bool)); - - -int main() -{ - struct dwarf_eh_bases junk; - const void* foo_eh_src = _Unwind_Find_FDE((void*)((long)&foo + 1), &junk); - // copy foo and its fde to a dynamically allocated buffer - unsigned long deltaToFDE = (uintptr_t)foo_eh_src - (uintptr_t)&foo; - unsigned long size = deltaToFDE + 100; - size = ((size + 4095) & (-4096)); - vm_address_t addr = 0; - if ( vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE) != KERN_SUCCESS ) - exit(1); - memcpy((void*)addr, (void*)&foo, size); - mprotect((void*)addr, size, PROT_READ|PROT_EXEC); - // make pointer to copy of foo and copy of fde - checkFuncProc checkFunc = (checkFuncProc)addr; - void* foo_eh = (void*)(addr + deltaToFDE); - - // call check() with unwind info unregistered, verify fails - (*checkFunc)(false, check); - - // call check() with unwind info registered, verify succeeds - __register_frame(foo_eh); - (*checkFunc)(true, check); - - // call check() with unwind info unregistered, verify fails - __deregister_frame(foo_eh); - (*checkFunc)(false, check); - - // call check() with unwind info added via keymgr, verify succeeds - my_keymgr_register_frame(foo_eh); - (*checkFunc)(true, check); - - return 0; -} - diff --git a/libunwind/testsuite/end_of_stack.c b/libunwind/testsuite/end_of_stack.c deleted file mode 100644 index d876797..0000000 --- a/libunwind/testsuite/end_of_stack.c +++ /dev/null @@ -1,39 +0,0 @@ - -// -// TEST-OPTIONS: -arch i386 -fexceptions -// TEST-OPTIONS: -arch i386 -fexceptions -fomit-frame-pointer -// TEST-OPTIONS: -arch i386 -fexceptions -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -fomit-frame-pointer -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc -fexceptions - - -// -// Tests _Unwind_RaiseException() returns _URC_END_OF_STACK if there is nothing to catch the exception -// - -#include -#include -#include - -#include "unwind.h" - - -struct _Unwind_Exception ex; - -int main() -{ - ex.exception_class = ((uint64_t)'mymy' << 32) | (uint64_t)'exex'; - ex.exception_cleanup = NULL; - ex.private_1 = 0; - ex.private_2 = 0; - - _Unwind_Reason_Code result = _Unwind_RaiseException(&ex); - - if ( result == _URC_END_OF_STACK ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/exception_32bit_lsda.s b/libunwind/testsuite/exception_32bit_lsda.s deleted file mode 100644 index ed6a805..0000000 --- a/libunwind/testsuite/exception_32bit_lsda.s +++ /dev/null @@ -1,240 +0,0 @@ - -// TEST-OPTIONS: -arch x86_64 -lstdc++ -Wl,-no_compact_unwind - - - .section __TEXT,__text,regular,pure_instructions - .globl __Z3foov - .align 4, 0x90 -__Z3foov: -Leh_func_begin1: - pushq %rbp -Ltmp0: - movq %rsp, %rbp -Ltmp1: - subq $16, %rsp -Ltmp2: - movabsq $4, %rax - movq %rax, %rdi - callq ___cxa_allocate_exception - movq %rax, -16(%rbp) - movq -16(%rbp), %rax - movl $10, (%rax) - movq -16(%rbp), %rax - movq __ZTIi@GOTPCREL(%rip), %rcx - leaq (%rcx), %rcx - movabsq $0, %rdx - movq %rax, %rdi - movq %rcx, %rsi - callq ___cxa_throw -Leh_func_end1: - - .globl _main - .align 4, 0x90 -_main: -Leh_func_begin2: - pushq %rbp -Ltmp6: - movq %rsp, %rbp -Ltmp7: - subq $48, %rsp -Ltmp8: - movl $1, -28(%rbp) - movl $2, -28(%rbp) -Ltmp3: - callq __Z3foov -Ltmp4: - jmp LBB2_1 -LBB2_1: - movl $3, -28(%rbp) - jmp LBB2_10 -LBB2_2: - movq -40(%rbp), %rax - movq %rax, %rdi - callq ___cxa_begin_catch - movq %rax, -24(%rbp) - movq -24(%rbp), %rax - movl (%rax), %eax - movl %eax, -32(%rbp) - movl -28(%rbp), %eax - cmpl $2, %eax - je LBB2_4 - movl $1, -12(%rbp) - movl -12(%rbp), %eax - movl %eax, -12(%rbp) - movl -12(%rbp), %eax - movl %eax, -12(%rbp) - movl $0, -8(%rbp) - jmp LBB2_7 -LBB2_4: - movl -32(%rbp), %eax - cmpl $10, %eax - je LBB2_6 - movl $1, -12(%rbp) - movl -12(%rbp), %eax - movl %eax, -12(%rbp) - movl -12(%rbp), %eax - movl %eax, -12(%rbp) - movl $0, -8(%rbp) - jmp LBB2_7 -LBB2_6: - movl $4, -28(%rbp) - movl $1, -8(%rbp) -LBB2_7: - callq ___cxa_end_catch - movl -8(%rbp), %eax - cmpl $1, %eax - jne LBB2_9 - jmp LBB2_10 -LBB2_9: - jmp LBB2_13 -LBB2_10: - movl -28(%rbp), %eax - cmpl $4, %eax - jne LBB2_12 - movl $0, -12(%rbp) - jmp LBB2_13 -LBB2_12: - movl $1, -12(%rbp) -LBB2_13: - movl -12(%rbp), %eax - movl %eax, -4(%rbp) - movl -4(%rbp), %eax - addq $48, %rsp - popq %rbp - ret -LBB2_15: -Ltmp5: - movq %rax, -40(%rbp) - movq -40(%rbp), %rax - movl %edx, %eax - movl %eax, -44(%rbp) - movl $2, %eax - movl -44(%rbp), %ecx - cmpl %eax, %ecx - je LBB2_2 - movq -40(%rbp), %rax - movq %rax, %rdi - callq __Unwind_Resume_or_Rethrow -Leh_func_end2: - - - .section __TEXT,__gcc_except_tab - .align 2 -GCC_except_table2: -Lexception2: - .byte 255 - .byte 155 - .byte 168 - .space 1 - .byte 3 - .byte 26 -Lset0 = Ltmp3-Leh_func_begin2 - .long Lset0 -Lset1 = Ltmp4-Ltmp3 - .long Lset1 -Lset2 = Ltmp5-Leh_func_begin2 - .long Lset2 - .byte 3 -Lset3 = Ltmp4-Leh_func_begin2 - .long Lset3 -Lset4 = Leh_func_end2-Ltmp4 - .long Lset4 - .long 0 - .byte 0 - - - .byte 1 - .byte 0 - - .byte 2 - .byte 125 - - .long __ZTIi@GOTPCREL+4 - .long 0 - .align 2 - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame0: -Lsection_eh_frame: -Leh_frame_common: -Lset5 = Leh_frame_common_end-Leh_frame_common_begin - .long Lset5 -Leh_frame_common_begin: - .long 0 - .byte 1 - .asciz "zPLR" - .byte 1 - .byte 120 - .byte 16 - .byte 7 - .byte 155 - .long ___gxx_personality_v0@GOTPCREL+4 - .byte 0x1B // lsda encoding DW_EH_PE_pcrel + DW_EH_PE_sdata4 - .byte 16 - .byte 12 - .byte 7 - .byte 8 - .byte 144 - .byte 1 - .align 3 -Leh_frame_common_end: - - .globl __Z3foov.eh -__Z3foov.eh: -Lset6 = Leh_frame_end1-Leh_frame_begin1 - .long Lset6 -Leh_frame_begin1: -Lset7 = Leh_frame_begin1-Leh_frame_common - .long Lset7 -Ltmp9: - .quad Leh_func_begin1-Ltmp9 -Lset8 = Leh_func_end1-Leh_func_begin1 - .quad Lset8 - .byte 4 - .long 0 - .byte 4 -Lset9 = Ltmp0-Leh_func_begin1 - .long Lset9 - .byte 14 - .byte 16 - .byte 134 - .byte 2 - .byte 4 -Lset10 = Ltmp1-Ltmp0 - .long Lset10 - .byte 13 - .byte 6 - .align 3 -Leh_frame_end1: - - .globl _main.eh -_main.eh: -Lset11 = Leh_frame_end2-Leh_frame_begin2 - .long Lset11 -Leh_frame_begin2: -Lset12 = Leh_frame_begin2-Leh_frame_common - .long Lset12 -Ltmp10: - .quad Leh_func_begin2-Ltmp10 -Lset13 = Leh_func_end2-Leh_func_begin2 - .quad Lset13 - .byte 4 -Ltmp11: - .long Lexception2-Ltmp11 - .byte 4 -Lset14 = Ltmp6-Leh_func_begin2 - .long Lset14 - .byte 14 - .byte 16 - .byte 134 - .byte 2 - .byte 4 -Lset15 = Ltmp7-Ltmp6 - .long Lset15 - .byte 13 - .byte 6 - .align 3 -Leh_frame_end2: - - -.subsections_via_symbols diff --git a/libunwind/testsuite/exception_basic.cxx b/libunwind/testsuite/exception_basic.cxx deleted file mode 100644 index 0d95dce..0000000 --- a/libunwind/testsuite/exception_basic.cxx +++ /dev/null @@ -1,33 +0,0 @@ - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc - - -int foo() { throw 10; } - - -int main() -{ - int state = 1; - try { - state = 2; - foo(); - state = 3; - } - catch (int x) { - if ( state != 2 ) - return 1; - if ( x != 10 ) - return 1; - state = 4; - } - - if ( state == 4 ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/exception_catch_and_throw.cxx b/libunwind/testsuite/exception_catch_and_throw.cxx deleted file mode 100644 index 7596c20..0000000 --- a/libunwind/testsuite/exception_catch_and_throw.cxx +++ /dev/null @@ -1,54 +0,0 @@ - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc - -#include - -int global = 0; - -int bar() -{ - global = 1; - throw 10; - -} - - -void foo() -{ - try { - bar(); - } - catch(int x) { - global = 2; - throw x; - } -} - - - -int main() -{ - int state = 1; - try { - state = 2; - foo(); - state = 3; - } - catch (int x) { - if ( state != 2 ) - return 1; - if ( x != 10 ) - return 1; - state = 4; - } - - if ( (state == 4) && (global == 2) ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/exception_missing_eh.cxx b/libunwind/testsuite/exception_missing_eh.cxx deleted file mode 100644 index 077355c..0000000 --- a/libunwind/testsuite/exception_missing_eh.cxx +++ /dev/null @@ -1,52 +0,0 @@ - - -// TEST-OPTIONS: -x c exception_missing_eh2.c -arch i386 -// TEST-OPTIONS: -x c exception_missing_eh2.c -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -x c exception_missing_eh2.c -arch ppc -// TEST-OPTIONS: exception_missing_eh2_x86_64.s -arch x86_64 -// TEST-OPTIONS: exception_missing_eh2_x86_64.s -arch x86_64 -Wl,-no_compact_unwind - - -#include - -#include - -extern "C" { - extern int bar(); - extern int foo(); -} - - -int foo() { throw 10; } - -static void term() -{ - // terminate called, as we want - exit(0); -} - - -int main() -{ - std::set_terminate(term); - - int state = 1; - try { - state = 2; - // bar() calls foo() which throws - // but, bar is missing eh info, so terminate() is called - bar(); - state = 3; - } - catch (int x) { - if ( state != 2 ) - return 1; - if ( x != 10 ) - return 1; - state = 4; - } - - // should not get here - exit(1); -} - diff --git a/libunwind/testsuite/exception_missing_eh2.c b/libunwind/testsuite/exception_missing_eh2.c deleted file mode 100644 index 87b7f0f..0000000 --- a/libunwind/testsuite/exception_missing_eh2.c +++ /dev/null @@ -1,14 +0,0 @@ - - -// bar() calls foo() -// this is in a separate file because we want bar() to not have eh info - -extern int foo(); - -int global; - -int bar() { - int x = foo(); - ++global; // to prevent tail call optimization - return x; -} diff --git a/libunwind/testsuite/exception_missing_eh2_x86_64.s b/libunwind/testsuite/exception_missing_eh2_x86_64.s deleted file mode 100644 index cb3d9f0..0000000 --- a/libunwind/testsuite/exception_missing_eh2_x86_64.s +++ /dev/null @@ -1,13 +0,0 @@ - -/* Need assembly to create bar() without eh info */ - - .text -.globl _bar -_bar: - pushq %rbp - movq %rsp, %rbp - subq $16, %rsp - movl $0, %eax - call _foo - leave - ret diff --git a/libunwind/testsuite/exception_rethrow.cxx b/libunwind/testsuite/exception_rethrow.cxx deleted file mode 100644 index 30c6009..0000000 --- a/libunwind/testsuite/exception_rethrow.cxx +++ /dev/null @@ -1,54 +0,0 @@ - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc - -#include - -int global = 0; - -int bar() -{ - global = 1; - throw 10; - -} - - -void foo() -{ - try { - bar(); - } - catch(int x) { - global = 2; - throw; - } -} - - - -int main() -{ - int state = 1; - try { - state = 2; - foo(); - state = 3; - } - catch (int x) { - if ( state != 2 ) - return 1; - if ( x != 10 ) - return 1; - state = 4; - } - - if ( (state == 4) && (global == 2) ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/exception_signal.cxx b/libunwind/testsuite/exception_signal.cxx deleted file mode 100644 index 7acbe88..0000000 --- a/libunwind/testsuite/exception_signal.cxx +++ /dev/null @@ -1,57 +0,0 @@ - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch ppc - -#include -#include -#include -#include -#include - -void segfault(int sig) -{ - ::signal(SIGBUS, SIG_DFL); - ::signal(SIGSEGV, SIG_DFL); - - //fprintf(stderr, "bus error handler for pid=%d\n", getpid()); - //sleep(30); - throw "seg fault"; -} - - -__attribute__((noinline)) void boom(int* p) -{ - // do allocation, so compiler won't optimize away catch clause in main() - int* x = new int[100]; - *x = *p; -} - -int main() -{ - ::signal(SIGBUS, segfault); - ::signal(SIGSEGV, segfault); - - int state = 1; - try { - state = 2; - boom(NULL); - state = 3; - } - catch (const char* msg) { - //fprintf(stderr, "caught %s\n", msg); - if ( state != 2 ) - exit(1); - state = 4; - } - catch(...) { - //fprintf(stderr, "caught ...\n"); - exit(1); - } - - if ( state == 4 ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/find_enclosing.c b/libunwind/testsuite/find_enclosing.c deleted file mode 100644 index cb56200..0000000 --- a/libunwind/testsuite/find_enclosing.c +++ /dev/null @@ -1,48 +0,0 @@ - -// -// TEST-OPTIONS: -arch i386 -fexceptions -fomit-frame-pointer -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch i386 -fexceptions -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -fomit-frame-pointer -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc -fexceptions -// -// Basic _Unwind_FindEnclosingFunction test -// -// _Unwind_FindEnclosingFunction() is supposed to return the start of a -// function given an address in the function. It uses FDE info. -// - -#include -#include -#include -#include - -#include "unwind.h" - -int bar(int x) -{ - // dummy call to force dwarf info generation - _Unwind_GetIP(NULL); - return x + 20; -} - -int foo(int x) -{ - // dummy call to force dwarf info generation - _Unwind_GetIP(NULL); - return x + 10; -} - - -int main() -{ - uint8_t* addrInBar = (uint8_t*)bar + 4; - uint8_t* addrInFoo = (uint8_t*)foo + 4; - if ( _Unwind_FindEnclosingFunction(addrInBar) != &bar ) - return 1; - if ( _Unwind_FindEnclosingFunction(addrInFoo) != &foo ) - return 1; - - return 0; -} - diff --git a/libunwind/testsuite/objc_alt_handler.m b/libunwind/testsuite/objc_alt_handler.m deleted file mode 100644 index 48b2ef2..0000000 --- a/libunwind/testsuite/objc_alt_handler.m +++ /dev/null @@ -1,50 +0,0 @@ - -// TEST-OPTIONS: -arch x86_64 -framework Foundation -// TEST-OPTIONS: -arch x86_64 -framework Foundation -Wl,-no_compact_unwind - - -#include - -// private SPI for AppKit -extern int _NSAddAltHandler2(void (*proc)(NSException* exc, void* context), void* context); - - -int foo() -{ - @throw [NSException exceptionWithName:NSGenericException reason:@"many" userInfo:nil]; -} - -static void handler(NSException* exc, void* context) -{ - int* paltState = (int*)context; - *paltState = 1; -} - - -int main() -{ - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - int state = 1; - int altState = 0; - @try { - _NSAddAltHandler2(handler, &altState); - state = 2; - foo(); - state = 3; - } - @catch(id exception) { - if ( state != 2 ) - return 1; - if ( altState == 0 ) - return 1; - if ( [[exception name] isEqualToString:NSGenericException] ) - state = 4; - } - - if ( state == 4 ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/objc_exception_basic.m b/libunwind/testsuite/objc_exception_basic.m deleted file mode 100644 index 67eb0f1..0000000 --- a/libunwind/testsuite/objc_exception_basic.m +++ /dev/null @@ -1,36 +0,0 @@ - -// TEST-OPTIONS: -arch x86_64 -framework Foundation -// TEST-OPTIONS: -arch x86_64 -framework Foundation -Wl,-no_compact_unwind - - -#include - -int foo() -{ - @throw [NSException exceptionWithName:NSGenericException reason:@"many" userInfo:nil]; -} - - -int main() -{ - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - int state = 1; - @try { - state = 2; - foo(); - state = 3; - } - @catch(id exception) { - if ( state != 2 ) - return 1; - if ( [[exception name] isEqualToString:NSGenericException] ) - state = 4; - } - - if ( state == 4 ) - return 0; - else - return 1; -} - diff --git a/libunwind/testsuite/personality.cxx b/libunwind/testsuite/personality.cxx deleted file mode 100644 index 3ffbcb8..0000000 --- a/libunwind/testsuite/personality.cxx +++ /dev/null @@ -1,170 +0,0 @@ - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc - -#include -#include -#include -#include - -#include "unwind.h" - -static __personality_routine realPersonality = (__personality_routine)dlsym(RTLD_DEFAULT, "__gxx_personality_v0"); - -int count = 0; - -const char* actionString(_Unwind_Action act) -{ - static char buffer[100]; - buffer[0] = '\0'; - - if ( act & _UA_SEARCH_PHASE ) - strcat(buffer, "_UA_SEARCH_PHASE "); - if ( act & _UA_CLEANUP_PHASE ) - strcat(buffer, "_UA_CLEANUP_PHASE "); - if ( act & _UA_HANDLER_FRAME ) - strcat(buffer, "_UA_HANDLER_FRAME "); - if ( act & _UA_FORCE_UNWIND ) - strcat(buffer, "_UA_FORCE_UNWIND "); - if ( act & _UA_END_OF_STACK ) - strcat(buffer, "_UA_END_OF_STACK "); - if ( act & 0xFFFFFFE0 ) - strcat(buffer, "unknown bits "); - return buffer; -} - -const char* reasonString(_Unwind_Reason_Code reason) -{ - switch (reason) { - case _URC_NO_REASON: - return "_URC_NO_REASON"; - case _URC_FOREIGN_EXCEPTION_CAUGHT: - return "_URC_FOREIGN_EXCEPTION_CAUGHT"; - case _URC_FATAL_PHASE2_ERROR: - return "_URC_FATAL_PHASE2_ERROR"; - case _URC_FATAL_PHASE1_ERROR: - return "_URC_FATAL_PHASE1_ERROR"; - case _URC_NORMAL_STOP: - return "_URC_NORMAL_STOP"; - case _URC_END_OF_STACK: - return "_URC_END_OF_STACK"; - case _URC_HANDLER_FOUND: - return "_URC_HANDLER_FOUND"; - case _URC_INSTALL_CONTEXT: - return "_URC_INSTALL_CONTEXT"; - case _URC_CONTINUE_UNWIND: - return "_URC_CONTINUE_UNWIND"; - } - return "unknown reason code"; -} - -bool fooCaught = false; -bool mainInnerCaught = false; -bool mainOuterCaught = false; - -struct Expected { - bool fooCaught; - bool mainInnerCaught; - bool mainOuterCaught; - _Unwind_Action action; - _Unwind_Reason_Code result; -}; - -#define _UA_CLEANUP_PHASE_HANDLER_FRAME (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME) - -const Expected shouldBe[] = { - { false, false, false, _UA_SEARCH_PHASE, _URC_HANDLER_FOUND }, - { false, false, false, _UA_CLEANUP_PHASE_HANDLER_FRAME, _URC_INSTALL_CONTEXT }, - { true, false, false, _UA_SEARCH_PHASE, _URC_CONTINUE_UNWIND }, - { true, false, false, _UA_SEARCH_PHASE, _URC_HANDLER_FOUND }, - { true, false, false, _UA_CLEANUP_PHASE, _URC_INSTALL_CONTEXT }, - { true, false, false, _UA_CLEANUP_PHASE, _URC_CONTINUE_UNWIND }, - { true, false, false, _UA_CLEANUP_PHASE_HANDLER_FRAME, _URC_INSTALL_CONTEXT }, - { true, true, false, _UA_SEARCH_PHASE, _URC_HANDLER_FOUND }, - { true, true, false, _UA_CLEANUP_PHASE_HANDLER_FRAME, _URC_INSTALL_CONTEXT } -}; - - -extern "C" { - __attribute__((visibility("hidden"))) _Unwind_Reason_Code __gxx_personality_v0( - int version, _Unwind_Action actions, uint64_t exceptionClass, - struct _Unwind_Exception* exceptionObject, _Unwind_Context* context) - { - - _Unwind_Reason_Code result = (*realPersonality)(version, actions, exceptionClass, - exceptionObject, context); - //fprintf(stderr, "fooCaught=%d, mainInnerCaught=%d, mainOuterCaught=%d, ", - // fooCaught, mainInnerCaught, mainOuterCaught); - //fprintf(stderr, "personality(%d, %s, 0x%llX, %p, %p) => %s\n", version, actionString(actions), - // exceptionClass, exceptionObject, context, reasonString(result)); - if ( shouldBe[count].fooCaught != fooCaught ) { - fprintf(stderr, "count=%d, fooCaught=%d\n", count, fooCaught); - abort(); - } - if ( shouldBe[count].mainInnerCaught != mainInnerCaught ) { - fprintf(stderr, "count=%d, mainInnerCaught=%d\n", count, mainInnerCaught); - abort(); - } - if ( shouldBe[count].mainOuterCaught != mainOuterCaught ) { - fprintf(stderr, "count=%d, mainOuterCaught=%d\n", count, mainOuterCaught); - abort(); - } - if ( shouldBe[count].action != actions ) { - fprintf(stderr, "count=%d, actions=%s\n", count, actionString(actions)); - abort(); - } - if ( shouldBe[count].result != result ) { - fprintf(stderr, "count=%d, result=%s\n", count, reasonString(result)); - abort(); - } - if ( count++ > 12 ) - abort(); - return result; - - } -} - - -int __attribute__((noinline)) bar() -{ - throw 10; -} - - -void __attribute__((noinline)) foo() -{ - try { - bar(); - } - catch(int x) { - fooCaught = true; - throw; - } -} - - - -int main() -{ - try { - try { - foo(); - } - catch (int x) { - mainInnerCaught = true; - throw; - } - } - catch (...) { - mainOuterCaught = true; - } - if ( count != 9 ) { - fprintf(stderr, "count=%d\n", count); - abort(); - } - return 0; -} - diff --git a/libunwind/testsuite/rethrow_missing_catch.cxx b/libunwind/testsuite/rethrow_missing_catch.cxx deleted file mode 100644 index f98e59b..0000000 --- a/libunwind/testsuite/rethrow_missing_catch.cxx +++ /dev/null @@ -1,40 +0,0 @@ - - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind - - -#include - -#include - - -int foo() -{ - try { - throw 10; - } - catch (...) { - throw; - } -} - -static void term() -{ - // terminate called, as we want - exit(0); -} - - -int main() -{ - std::set_terminate(term); - - foo(); - - // should not get here - exit(1); -} - diff --git a/libunwind/testsuite/run-all-tests.pl b/libunwind/testsuite/run-all-tests.pl deleted file mode 100644 index 7745d3b..0000000 --- a/libunwind/testsuite/run-all-tests.pl +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use File::stat; -use Cwd; - - -my $testCaseFilter = '*'; -if ( $#ARGV == 0 ) { - $testCaseFilter = $ARGV[0]; -} - -my $useLocalDylib = 0; -my $headerPath = "-I../include -I../src"; -if ( stat('../build/Debug/libunwind.dylib') ) { - printf "### running with ../build/Debug/libunwind.dylib ###\n"; - $useLocalDylib = 1; -} - -my $canRunPPC = 0; -if ( stat('/usr/libexec/oah/translate') ) { -# $canRunPPC = 1; -} - - -# -# Search current directory for all files with TEST-OPTIONS: comments -# Compile and link each file with specified options -# Execute result and print PASS or FAIL -# -my $path = shift; -# get list of dylibs linked against -open(FILE, "grep -H 'TEST-OPTIONS:' $testCaseFilter |"); -$/ = "\n"; -while ( ) { - if ($_ =~ m/^(.+):.+TEST-OPTIONS:(.+)/) { - my $file = $1; - my $options = "$2"; - my $ppc = 0; - if ( $options =~ /arch ppc/ ) { - $ppc = 1; - } - if ( $file !~ "run-all-tests.pl" ) { - my $exit; - if ( $ppc && !$canRunPPC ) { - # don't try to build ppc tests - } - elsif ( $file =~ /^(.+)\.cxx/ ) { - #printf "c++ $file $options $headerPath -o /tmp/run-all-tests.a.out\n"; - $exit = system("c++ $file $options $headerPath -o /tmp/run-all-tests.a.out"); - } - else { - #printf "cc $file $options $headerPath -o /tmp/run-all-tests.a.out\n"; - $exit = system("cc $file $options $headerPath -o /tmp/run-all-tests.a.out"); - } - if ( $ppc && ($useLocalDylib || !$canRunPPC) ) { - #printf "SKIP $file $options\n"; - } - elsif ( $exit == 0 ) { - if ( $useLocalDylib ) { - $ENV{'DYLD_LIBRARY_PATH'} = '../build/Debug'; - } - my $exit = system("/tmp/run-all-tests.a.out"); - if ( $useLocalDylib ) { - $ENV{'DYLD_LIBRARY_PATH'} = ''; - } - if ( $exit == 0 ) { - printf "PASS $file $options\n"; - } - else { - printf "FAIL $file $options (runtime failure)\n"; - } - } - else { - printf "FAIL $file $options (could not compile)\n"; - } - } - } -} -close FILE; - -# -# Search for .mk directories and run make in each one -# -my $cwd = getcwd(); -open(FILE, "ls -1 |"); -$/ = "\n"; -while ( ) { - if ($_ =~ m/^(.+\.mk)$/) { - my $dir = $1; - if ( ($testCaseFilter =~ /\*/) || ($dir =~ /$testCaseFilter/) ) { - if ( $useLocalDylib ) { - $ENV{'DYLD_LIBRARY_PATH'} = "$cwd/../build/Debug"; - } - my $exit = system("cd $dir && make"); - if ( $useLocalDylib ) { - $ENV{'DYLD_LIBRARY_PATH'} = ''; - } - system("cd $dir && make clean"); - } - } -} -close FILE; - - - - diff --git a/libunwind/testsuite/terminate_is_handler.cxx b/libunwind/testsuite/terminate_is_handler.cxx deleted file mode 100644 index 113f346..0000000 --- a/libunwind/testsuite/terminate_is_handler.cxx +++ /dev/null @@ -1,31 +0,0 @@ - -// TEST-OPTIONS: -arch i386 -// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc - -#include -#include -#include -#include - - -void my_terminate() { - try { - throw; - } catch (char *s) { - if ( (s == NULL) || (strcmp(s, "my exception") != 0) ) - exit(1); - //printf("caught rethrown %p %s\n", s, s); - exit(0); - } -} - - -int main() -{ - std::set_terminate(&my_terminate); - throw "my exception"; -} - diff --git a/libunwind/testsuite/unw_getcontext.c b/libunwind/testsuite/unw_getcontext.c deleted file mode 100644 index a81de42..0000000 --- a/libunwind/testsuite/unw_getcontext.c +++ /dev/null @@ -1,26 +0,0 @@ - -// -// TEST-OPTIONS: -arch i386 -fexceptions -// TEST-OPTIONS: -arch i386 -fexceptions -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch x86_64 -// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind -// TEST-OPTIONS: -arch ppc -fexceptions -// - -#include -#include -#include - -#include "libunwind.h" - -int main() -{ - // verify unw_getcontext() returns no UNW_ESUCCESS - unw_context_t uc; - if ( unw_getcontext(&uc) == UNW_ESUCCESS ) - return 0; - else - return 1; - -} - diff --git a/libunwind/testsuite/unwind_test_main.c b/libunwind/testsuite/unwind_test_main.c deleted file mode 100644 index 9f284f4..0000000 --- a/libunwind/testsuite/unwind_test_main.c +++ /dev/null @@ -1,46 +0,0 @@ - -#include -#include -#include - -#include "libunwind.h" - -extern int unwind_tester(void*); -extern void* unwind_tester_list[]; - -int main() -{ - // loop over all function pointers in unwind_tester_list - // and call unwind_tester() on each one. If it returns - // non-zero, then that test failed. - void** p; - for(p=unwind_tester_list; *p != NULL; ++p) { - //fprintf(stderr, "unwind_tester(%p)\n", *p); - if ( unwind_tester(*p) ) - return 1; - } - return 0; -} - -// called by test function -// we unwind through the test function -// and resume at caller (unwind_tester) -void uwind_to_main() -{ - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t offset; - - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - if ( unw_step(&cursor) > 0 ) { - // now in test function - if ( unw_step(&cursor) > 0 ) { - // now in unwind_tester - unw_resume(&cursor); - } - } - // error if we got here - exit(1); -} - diff --git a/libunwind/testsuite/unwind_test_ppc.s b/libunwind/testsuite/unwind_test_ppc.s deleted file mode 100644 index 06acc6b..0000000 --- a/libunwind/testsuite/unwind_test_ppc.s +++ /dev/null @@ -1,502 +0,0 @@ - -# -# This is a generic function to test that restoring registers during unwinding work correctly. -# - - .literal4 - .align 2 -LC14: .long 1096810496 -LC15: .long 1097859072 -LC16: .long 1098907648 -LC17: .long 1099431936 -LC18: .long 1099956224 -LC19: .long 1100480512 -LC20: .long 1101004800 -LC21: .long 1101529088 -LC22: .long 1102053376 -LC23: .long 1102577664 -LC24: .long 1103101952 -LC25: .long 1103626240 -LC26: .long 1104150528 -LC27: .long 1104674816 -LC28: .long 1105199104 -LC29: .long 1105723392 -LC30: .long 1106247680 -LC31: .long 1106771968 - - .literal16 -LV23: .long 0x23232323, 0x23232322, 0x23232321, 0x23232320 -LV24: .long 0x24242424, 0x24242422, 0x24242421, 0x24242420 -LV25: .long 0x25252525, 0x25252522, 0x25252521, 0x25252520 -LV26: .long 0x26262626, 0x26262622, 0x26262621, 0x26262620 -LV27: .long 0x27272727, 0x27272722, 0x27272721, 0x27272720 -LV28: .long 0x28282828, 0x28282822, 0x28282821, 0x28282820 -LV29: .long 0x29292929, 0x29292922, 0x29292921, 0x29292920 -LV30: .long 0x30303030, 0x30303022, 0x30303021, 0x30303020 -LV31: .long 0x31313131, 0x31313122, 0x31313121, 0x31313120 - - .text -.globl _unwind_tester -_unwind_tester: -LFB2: - mflr r0 -LCFI43: - bl saveFP ; save f14-f31 -LCFI44: - stmw r13,-220(r1) -LCFI45: - stwu r1,-336(r1) -LCFI46: - - # load magic values into non-volatile registers - lis r31,0x3333 - ori r31,r31,0x3131 - lis r30,0x3333 - ori r30,r30,0x3030 - lis r29,0x2222 - ori r29,r29,0x2929 - lis r28,0x2222 - ori r28,r28,0x2828 - lis r27,0x2222 - ori r27,r27,0x2727 - lis r26,0x2222 - ori r26,r26,0x2626 - lis r25,0x2222 - ori r25,r25,0x2525 - lis r24,0x2222 - ori r24,r24,0x2424 - lis r23,0x2222 - ori r23,r23,0x2323 - lis r22,0x2222 - ori r22,r22,0x2222 - lis r21,0x2222 - ori r21,r21,0x2121 - lis r20,0x2222 - ori r20,r20,0x2020 - lis r19,0x1111 - ori r19,r19,0x1919 - lis r18,0x1111 - ori r18,r18,0x1818 - lis r17,0x1111 - ori r17,r17,0x1717 - lis r16,0x1111 - ori r16,r16,0x1616 - lis r15,0x1111 - ori r15,r15,0x1515 - lis r14,0x1111 - ori r14,r14,0x1414 - lis r13,0x1111 - ori r13,r13,0x1313 - - lis r2,ha16(LC14) - lfs f14,lo16(LC14)(r2) - lis r2,ha16(LC15) - lfs f15,lo16(LC15)(r2) - lis r2,ha16(LC16) - lfs f16,lo16(LC16)(r2) - lis r2,ha16(LC17) - lfs f17,lo16(LC17)(r2) - lis r2,ha16(LC18) - lfs f18,lo16(LC18)(r2) - lis r2,ha16(LC19) - lfs f19,lo16(LC19)(r2) - lis r2,ha16(LC20) - lfs f20,lo16(LC20)(r2) - lis r2,ha16(LC21) - lfs f21,lo16(LC21)(r2) - lis r2,ha16(LC22) - lfs f22,lo16(LC22)(r2) - lis r2,ha16(LC23) - lfs f23,lo16(LC23)(r2) - lis r2,ha16(LC24) - lfs f24,lo16(LC24)(r2) - lis r2,ha16(LC25) - lfs f25,lo16(LC25)(r2) - lis r2,ha16(LC26) - lfs f26,lo16(LC26)(r2) - lis r2,ha16(LC27) - lfs f27,lo16(LC27)(r2) - lis r2,ha16(LC28) - lfs f28,lo16(LC28)(r2) - lis r2,ha16(LC29) - lfs f29,lo16(LC29)(r2) - lis r2,ha16(LC30) - lfs f30,lo16(LC30)(r2) - lis r2,ha16(LC31) - lfs f31,lo16(LC31)(r2) - - lis r2,ha16(LV23) - la r2,lo16(LV23)(r2) - lvx v23,0,r2 - lis r2,ha16(LV24) - la r2,lo16(LV24)(r2) - lvx v24,0,r2 - lis r2,ha16(LV25) - la r2,lo16(LV25)(r2) - lvx v25,0,r2 - lis r2,ha16(LV26) - la r2,lo16(LV26)(r2) - lvx v26,0,r2 - lis r2,ha16(LV27) - la r2,lo16(LV27)(r2) - lvx v27,0,r2 - lis r2,ha16(LV28) - la r2,lo16(LV28)(r2) - lvx v28,0,r2 - lis r2,ha16(LV29) - la r2,lo16(LV29)(r2) - lvx v29,0,r2 - lis r2,ha16(LV30) - la r2,lo16(LV30)(r2) - lvx v30,0,r2 - lis r2,ha16(LV31) - la r2,lo16(LV31)(r2) - lvx v31,0,r2 - - lis r2,0x1234 - ori r2,r2,0x5678 - mtocrf 255,r2 - - # call test function which will invoke unwinder which "returns" here - mtctr r3 - bctrl - - # verify that non-volatile registers still contain magic values - lis r3,0x3333 - ori r3,r3,0x3131 - cmpw r3,r31 - bne L2 - lis r3,0x3333 - ori r3,r3,0x3030 - cmpw r3,r30 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2929 - cmpw r3,r29 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2828 - cmpw r3,r28 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2727 - cmpw r3,r27 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2626 - cmpw r3,r26 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2525 - cmpw r3,r25 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2424 - cmpw r3,r24 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2323 - cmpw r3,r23 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2222 - cmpw r3,r22 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2121 - cmpw r3,r21 - bne L2 - lis r3,0x2222 - ori r3,r3,0x2020 - cmpw r3,r20 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1919 - cmpw r3,r19 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1818 - cmpw r3,r18 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1717 - cmpw r3,r17 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1616 - cmpw r3,r16 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1515 - cmpw r3,r15 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1414 - cmpw r3,r14 - bne L2 - lis r3,0x1111 - ori r3,r3,0x1313 - cmpw r3,r13 - bne L2 - - lis r2,ha16(LC14) - lfs f1,lo16(LC14)(r2) - fcmpu cr7,f1,f14 - bne cr7,L2 - lis r2,ha16(LC15) - lfs f1,lo16(LC15)(r2) - fcmpu cr7,f1,f15 - bne cr7,L2 - lis r2,ha16(LC16) - lfs f1,lo16(LC16)(r2) - fcmpu cr7,f1,f16 - bne cr7,L2 - lis r2,ha16(LC17) - lfs f1,lo16(LC17)(r2) - fcmpu cr7,f1,f17 - bne cr7,L2 - lis r2,ha16(LC18) - lfs f1,lo16(LC18)(r2) - fcmpu cr7,f1,f18 - bne cr7,L2 - lis r2,ha16(LC19) - lfs f1,lo16(LC19)(r2) - fcmpu cr7,f1,f19 - bne cr7,L2 - lis r2,ha16(LC20) - lfs f1,lo16(LC20)(r2) - fcmpu cr7,f1,f20 - bne cr7,L2 - lis r2,ha16(LC21) - lfs f1,lo16(LC21)(r2) - fcmpu cr7,f1,f21 - bne cr7,L2 - lis r2,ha16(LC22) - lfs f1,lo16(LC22)(r2) - fcmpu cr7,f1,f22 - bne cr7,L2 - lis r2,ha16(LC23) - lfs f1,lo16(LC23)(r2) - fcmpu cr7,f1,f23 - bne cr7,L2 - lis r2,ha16(LC24) - lfs f1,lo16(LC24)(r2) - fcmpu cr7,f1,f24 - bne cr7,L2 - lis r2,ha16(LC25) - lfs f1,lo16(LC25)(r2) - fcmpu cr7,f1,f25 - bne cr7,L2 - lis r2,ha16(LC26) - lfs f1,lo16(LC26)(r2) - fcmpu cr7,f1,f26 - bne cr7,L2 - lis r2,ha16(LC27) - lfs f1,lo16(LC27)(r2) - fcmpu cr7,f1,f27 - bne cr7,L2 - lis r2,ha16(LC28) - lfs f1,lo16(LC28)(r2) - fcmpu cr7,f1,f28 - bne cr7,L2 - lis r2,ha16(LC29) - lfs f1,lo16(LC29)(r2) - fcmpu cr7,f1,f29 - bne cr7,L2 - lis r2,ha16(LC30) - lfs f1,lo16(LC30)(r2) - fcmpu cr7,f1,f30 - bne cr7,L2 - lis r2,ha16(LC31) - lfs f1,lo16(LC31)(r2) - fcmpu cr7,f1,f31 - bne cr7,L2 - - lis r2,ha16(LV23) - la r2,lo16(LV23)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v23 - beq cr6,L2 - lis r2,ha16(LV24) - la r2,lo16(LV24)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v24 - beq cr6,L2 - lis r2,ha16(LV25) - la r2,lo16(LV25)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v25 - beq cr6,L2 - lis r2,ha16(LV26) - la r2,lo16(LV26)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v26 - beq cr6,L2 - lis r2,ha16(LV27) - la r2,lo16(LV27)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v27 - beq cr6,L2 - lis r2,ha16(LV28) - la r2,lo16(LV28)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v28 - beq cr6,L2 - lis r2,ha16(LV29) - la r2,lo16(LV29)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v29 - beq cr6,L2 - lis r2,ha16(LV30) - la r2,lo16(LV30)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v30 - beq cr6,L2 - lis r2,ha16(LV31) - la r2,lo16(LV31)(r2) - lvx v1,0,r2 - vcmpequw. v0,v1,v31 - beq cr6,L2 - - mfcr r3 - lis r2,0x00FF - ori r2,r2,0xF000 - and r3,r3,r2 - lis r2,0x0034 - ori r2,r2,0x5000 - cmpw r3,r2 - bne L2 - - li r3,0 - b L3 -L2: li r3,1 -L3: - - addi r1,r1,336 - lwz r0,8(r1) - lmw r13,-220(r1) - mtlr r0 - b restFP ; restore f14-f31 -LFE2: - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 ; Length of Common Information Entry -LSCIE1: - .long 0x0 ; CIE Identifier Tag - .byte 0x1 ; CIE Version - .ascii "zR\0" ; CIE Augmentation - .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor - .byte 0x41 ; CIE RA Column - .byte 0x1 ; uleb128 0x1; Augmentation size - .byte 0x10 ; FDE Encoding (pcrel) - .byte 0xc ; DW_CFA_def_cfa - .byte 0x1 ; uleb128 0x1 - .byte 0x0 ; uleb128 0x0 - .align 2 -LECIE1: - - .globl _unwind_tester.eh -_unwind_tester.eh: -LSFDE27: - .set L$set$34,LEFDE27-LASFDE27 - .long L$set$34 ; FDE Length -LASFDE27: - .long LASFDE27-EH_frame1 ; FDE CIE offset - .long LFB2-. ; FDE initial location - .set L$set$35,LFE2-LFB2 - .long L$set$35 ; FDE address range - .byte 0x0 ; uleb128 0x0; Augmentation size - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$36,LCFI43-LFB2 - .long L$set$36 - .byte 0x9 ; DW_CFA_register - .byte 0x41 ; uleb128 0x41 - .byte 0x0 ; uleb128 0x0 - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$37,LCFI46-LCFI43 - .long L$set$37 - .byte 0xe ; DW_CFA_def_cfa_offset - .byte 0xd0,0x2 ; uleb128 0x150 - .byte 0x9f ; DW_CFA_offset, column 0x1f - .byte 0x25 ; uleb128 0x25 - .byte 0x9e ; DW_CFA_offset, column 0x1e - .byte 0x26 ; uleb128 0x26 - .byte 0x9d ; DW_CFA_offset, column 0x1d - .byte 0x27 ; uleb128 0x27 - .byte 0x9c ; DW_CFA_offset, column 0x1c - .byte 0x28 ; uleb128 0x28 - .byte 0x9b ; DW_CFA_offset, column 0x1b - .byte 0x29 ; uleb128 0x29 - .byte 0x9a ; DW_CFA_offset, column 0x1a - .byte 0x2a ; uleb128 0x2a - .byte 0x99 ; DW_CFA_offset, column 0x19 - .byte 0x2b ; uleb128 0x2b - .byte 0x98 ; DW_CFA_offset, column 0x18 - .byte 0x2c ; uleb128 0x2c - .byte 0x97 ; DW_CFA_offset, column 0x17 - .byte 0x2d ; uleb128 0x2d - .byte 0x96 ; DW_CFA_offset, column 0x16 - .byte 0x2e ; uleb128 0x2e - .byte 0x95 ; DW_CFA_offset, column 0x15 - .byte 0x2f ; uleb128 0x2f - .byte 0x94 ; DW_CFA_offset, column 0x14 - .byte 0x30 ; uleb128 0x30 - .byte 0x93 ; DW_CFA_offset, column 0x13 - .byte 0x31 ; uleb128 0x31 - .byte 0x92 ; DW_CFA_offset, column 0x12 - .byte 0x32 ; uleb128 0x32 - .byte 0x91 ; DW_CFA_offset, column 0x11 - .byte 0x33 ; uleb128 0x33 - .byte 0x90 ; DW_CFA_offset, column 0x10 - .byte 0x34 ; uleb128 0x34 - .byte 0x8f ; DW_CFA_offset, column 0xf - .byte 0x35 ; uleb128 0x35 - .byte 0x8e ; DW_CFA_offset, column 0xe - .byte 0x36 ; uleb128 0x36 - .byte 0x8d ; DW_CFA_offset, column 0xd - .byte 0x37 ; uleb128 0x37 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x41 ; uleb128 0x41 - .byte 0x7e ; sleb128 -2 - .byte 0xbf ; DW_CFA_offset, column 0x3f - .byte 0x2 ; uleb128 0x2 - .byte 0xbe ; DW_CFA_offset, column 0x3e - .byte 0x4 ; uleb128 0x4 - .byte 0xbd ; DW_CFA_offset, column 0x3d - .byte 0x6 ; uleb128 0x6 - .byte 0xbc ; DW_CFA_offset, column 0x3c - .byte 0x8 ; uleb128 0x8 - .byte 0xbb ; DW_CFA_offset, column 0x3b - .byte 0xa ; uleb128 0xa - .byte 0xba ; DW_CFA_offset, column 0x3a - .byte 0xc ; uleb128 0xc - .byte 0xb9 ; DW_CFA_offset, column 0x39 - .byte 0xe ; uleb128 0xe - .byte 0xb8 ; DW_CFA_offset, column 0x38 - .byte 0x10 ; uleb128 0x10 - .byte 0xb7 ; DW_CFA_offset, column 0x37 - .byte 0x12 ; uleb128 0x12 - .byte 0xb6 ; DW_CFA_offset, column 0x36 - .byte 0x14 ; uleb128 0x14 - .byte 0xb5 ; DW_CFA_offset, column 0x35 - .byte 0x16 ; uleb128 0x16 - .byte 0xb4 ; DW_CFA_offset, column 0x34 - .byte 0x18 ; uleb128 0x18 - .byte 0xb3 ; DW_CFA_offset, column 0x33 - .byte 0x1a ; uleb128 0x1a - .byte 0xb2 ; DW_CFA_offset, column 0x32 - .byte 0x1c ; uleb128 0x1c - .byte 0xb1 ; DW_CFA_offset, column 0x31 - .byte 0x1e ; uleb128 0x1e - .byte 0xb0 ; DW_CFA_offset, column 0x30 - .byte 0x20 ; uleb128 0x20 - .byte 0xaf ; DW_CFA_offset, column 0x2f - .byte 0x22 ; uleb128 0x22 - .byte 0xae ; DW_CFA_offset, column 0x2e - .byte 0x24 ; uleb128 0x24 - .align 2 -LEFDE27: diff --git a/libunwind/testsuite/unwind_test_ppc_frame.s b/libunwind/testsuite/unwind_test_ppc_frame.s deleted file mode 100644 index 9afb3fe..0000000 --- a/libunwind/testsuite/unwind_test_ppc_frame.s +++ /dev/null @@ -1,339 +0,0 @@ - - -# TEST-OPTIONS: unwind_test_main.c unwind_test_ppc.s -arch ppc -fexceptions -faltivec - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .long _test_v24_v31 - .long _test_r29_r31 - .long _test_f26_f31 - .long _test_ccr2_ccr4_ctr - .long 0 - - - .text - .align 2 - .globl _test_r29_r31 -_test_r29_r31: -LFB11: - mflr r0 - stmw r29,-12(r1) - stw r0,8(r1) - stwu r1,-80(r1) -LCFI10: - # trash non-volatile registers - li r31,0 - li r30,0 - li r29,0 - # force unwind that should restore non-volatile register - bl _uwind_to_main - addi r1,r1,80 - lwz r0,8(r1) - lmw r29,-12(r1) - mtlr r0 - blr -LFE11: - - - .text - .align 2 - .globl _test_ccr2_ccr4_ctr -_test_ccr2_ccr4_ctr: -LFB11a: - mflr r0 - stw r0,8(r1) - mfcr r0 - stw r0,-12(r1) - stw r0,-8(r1) - mfctr r0 - stw r0,-4(r1) - stwu r1,-80(r1) -LCFI10a: - # trash non-volatile registers - li r3,0 - mtocrf 40,r3 - mtctr r3 - # force unwind that should restore non-volatile register - bl _uwind_to_main - addi r1,r1,80 - lwz r0,-4(r1) - mtctr r0 - lwz r0,-8(r1) - mtocrf 4,r0 - lwz r0,-12(r1) - mtocrf 128,r0 - lwz r0,8(r1) - mtlr r0 - blr -LFE11a: - - - .align 2 - .globl _test_f26_f31 -_test_f26_f31: -LFB4: - mflr r0 -LCFI43: - bl saveFP+48 ; save f26-f31 -LCFI44: - stwu r1,-144(r1) -LCFI45: - # trash non-volatile registers - fsub f31,f31,f31 - fsub f30,f30,f30 - fsub f29,f29,f29 - fsub f28,f28,f28 - fsub f27,f27,f27 - fsub f26,f26,f26 - # force unwind that should restore non-volatile register - bl _uwind_to_main - lwz r0,8(r1) - mtlr r0 - b restFP+48 ; restore f26-f31 -LFE4: - .align 2 - - - .align 2 - .globl _test_v24_v31 -_test_v24_v31: -LFB3: - mflr r0 - stw r0,8(r1) - stwu r1,-352(r1) -LCFI2: - li r0,208 - stvx v24,r1,r0 - li r0,224 - stvx v25,r1,r0 - li r0,240 - stvx v26,r1,r0 - li r0,256 - stvx v27,r1,r0 - li r0,272 - stvx v28,r1,r0 - li r0,288 - stvx v29,r1,r0 - li r0,304 - stvx v30,r1,r0 - li r0,320 - stvx v31,r1,r0 -LCFI11: - mfspr r0,256 - stw r0,348(r1) - oris r0,r0,0x3ff0 - ori r0,r0,255 - mtspr 256,r0 - - # trash non-volatile registers - vor v24,v20,v20 - vor v25,v20,v20 - vor v26,v20,v20 - vor v27,v20,v20 - vor v28,v20,v20 - vor v29,v20,v20 - vor v30,v20,v20 - vor v31,v20,v20 - - # force unwind that should restore non-volatile register - bl _uwind_to_main - - li r0,208 - lwz r12,348(r1) - lvx v24,r1,r0 - li r0,224 - lvx v25,r1,r0 - li r0,240 - lvx v26,r1,r0 - li r0,256 - lvx v27,r1,r0 - li r0,272 - lvx v28,r1,r0 - li r0,288 - lvx v29,r1,r0 - li r0,304 - lvx v30,r1,r0 - li r0,320 - lvx v31,r1,r0 - mtspr 256,r12 - addi r1,r1,352 - lwz r0,8(r1) - mtlr r0 - blr -LFE3: - - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 ; Length of Common Information Entry -LSCIE1: - .long 0x0 ; CIE Identifier Tag - .byte 0x1 ; CIE Version - .ascii "zR\0" ; CIE Augmentation - .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor - .byte 0x41 ; CIE RA Column - .byte 0x1 ; uleb128 0x1; Augmentation size - .byte 0x10 ; FDE Encoding (pcrel) - .byte 0xc ; DW_CFA_def_cfa - .byte 0x1 ; uleb128 0x1 - .byte 0x0 ; uleb128 0x0 - .align 2 -LECIE1: - - - .globl _test_r29_r31.eh -_test_r29_r31.eh: -LSFDE9: - .set L$set$7,LEFDE9-LASFDE9 - .long L$set$7 ; FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 ; FDE CIE offset - .long LFB11-. ; FDE initial location - .set L$set$8,LFE11-LFB11 - .long L$set$8 ; FDE address range - .byte 0x0 ; uleb128 0x0; Augmentation size - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$9,LCFI10-LFB11 - .long L$set$9 - .byte 0xe ; DW_CFA_def_cfa_offset - .byte 0x50 ; uleb128 0x50 - .byte 0x9f ; DW_CFA_offset, column 0x1f - .byte 0x1 ; uleb128 0x1 - .byte 0x9e ; DW_CFA_offset, column 0x1e - .byte 0x2 ; uleb128 0x2 - .byte 0x9d ; DW_CFA_offset, column 0x1d - .byte 0x3 ; uleb128 0x3 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x41 ; uleb128 0x41 - .byte 0x7e ; sleb128 -2 - .align 2 -LEFDE9: - - .globl _test_ccr2_ccr4_ctr.eh -_test_ccr2_ccr4_ctr.eh: -LSFDE9a: - .set L$set$7,LEFDE9a-LASFDE9a - .long L$set$7 ; FDE Length -LASFDE9a: - .long LASFDE9a-EH_frame1 ; FDE CIE offset - .long LFB11a-. ; FDE initial location - .set L$set$8,LFE11a-LFB11a - .long L$set$8 ; FDE address range - .byte 0x0 ; uleb128 0x0; Augmentation size - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$9,LCFI10a-LFB11a - .long L$set$9 - .byte 0xe ; DW_CFA_def_cfa_offset - .byte 0x50 ; uleb128 0x50 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x42 ; uleb128 0x42 - .byte 0x01 ; sleb128 1 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x48 ; uleb128 0x48 - .byte 0x02 ; sleb128 2 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x46 ; uleb128 0x46 - .byte 0x03 ; sleb128 3 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x41 ; uleb128 0x41 - .byte 0x7e ; sleb128 -2 - .align 2 -LEFDE9a: - - - - .globl _test_f26_f31 -_test_f26_f31.eh: -LSFDE29: - .set L$set$34,LEFDE29-LASFDE29 - .long L$set$34 ; FDE Length -LASFDE29: - .long LASFDE29-EH_frame1 ; FDE CIE offset - .long LFB4-. ; FDE initial location - .set L$set$35,LFE4-LFB4 - .long L$set$35 ; FDE address range - .byte 0x0 ; uleb128 0x0; Augmentation size - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$36,LCFI43-LFB4 - .long L$set$36 - .byte 0x9 ; DW_CFA_register - .byte 0x41 ; uleb128 0x41 - .byte 0x0 ; uleb128 0x0 - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$37,LCFI45-LCFI43 - .long L$set$37 - .byte 0xe ; DW_CFA_def_cfa_offset - .byte 0x90,0x1 ; uleb128 0x90 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x41 ; uleb128 0x41 - .byte 0x7e ; sleb128 -2 - .byte 0xbf ; DW_CFA_offset, column 0x3f - .byte 0x2 ; uleb128 0x2 - .byte 0xbe ; DW_CFA_offset, column 0x3e - .byte 0x4 ; uleb128 0x4 - .byte 0xbd ; DW_CFA_offset, column 0x3d - .byte 0x6 ; uleb128 0x6 - .byte 0xbc ; DW_CFA_offset, column 0x3c - .byte 0x8 ; uleb128 0x8 - .byte 0xbb ; DW_CFA_offset, column 0x3b - .byte 0xa ; uleb128 0xa - .byte 0xba ; DW_CFA_offset, column 0x3a - .byte 0xc ; uleb128 0xc - .align 2 -LEFDE29: - - - .globl _test_v24_v31.eh -_test_v24_v31.eh: -LSFDE3: - .set L$set$1,LEFDE3-LASFDE3 - .long L$set$1 ; FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 ; FDE CIE offset - .long LFB3-. ; FDE initial location - .set L$set$2,LFE3-LFB3 - .long L$set$2 ; FDE address range - .byte 0x0 ; uleb128 0x0; Augmentation size - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$3,LCFI2-LFB3 - .long L$set$3 - .byte 0xe ; DW_CFA_def_cfa_offset - .byte 0xe0,0x2 ; uleb128 0x160 - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$4,LCFI11-LCFI2 - .long L$set$4 - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x6c ; uleb128 0x6c - .byte 0x8 ; uleb128 0x8 - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x6b ; uleb128 0x6b - .byte 0xc ; uleb128 0xc - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x6a ; uleb128 0x6a - .byte 0x10 ; uleb128 0x10 - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x69 ; uleb128 0x69 - .byte 0x14 ; uleb128 0x14 - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x68 ; uleb128 0x68 - .byte 0x18 ; uleb128 0x18 - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x67 ; uleb128 0x67 - .byte 0x1c ; uleb128 0x1c - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x66 ; uleb128 0x66 - .byte 0x20 ; uleb128 0x20 - .byte 0x5 ; DW_CFA_offset_extended - .byte 0x65 ; uleb128 0x65 - .byte 0x24 ; uleb128 0x24 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x41 ; uleb128 0x41 - .byte 0x7e ; sleb128 -2 - .align 2 -LEFDE3: - - diff --git a/libunwind/testsuite/unwind_test_x86.s b/libunwind/testsuite/unwind_test_x86.s deleted file mode 100644 index 07de46b..0000000 --- a/libunwind/testsuite/unwind_test_x86.s +++ /dev/null @@ -1,104 +0,0 @@ - -# -# This is a generic function to test that restoring registers during unwinding work correctly. -# - - .text -.globl _unwind_tester -_unwind_tester: -LFB2: - pushl %ebp -LCFI0: - movl %esp, %ebp -LCFI1: - subl $56, %esp -LCFI2: - movl %ebx, -12(%ebp) -LCFI3: - movl %esi, -8(%ebp) -LCFI4: - movl %edi, -4(%ebp) -LCFI5: - # load magic values into non-volatile registers - movl $0x12344321, %ebx - movl $0x56788765, %esi - movl $0xABCDDCBA, %edi - # call test function which will invoke unwinder which "returns" here - call *8(%ebp) - # verify that non-volatile registers still contain magic values - cmpl $0x12344321, %ebx - jne L2 - cmpl $0x56788765, %esi - jne L2 - cmpl $0xABCDDCBA, %edi - jne L2 - movl $0, %eax - jmp L3 -L2: movl $1, %eax -L3: - movl -12(%ebp), %ebx - movl -8(%ebp), %esi - movl -4(%ebp), %edi - leave - ret -LFE2: - - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c # sleb128 -4; CIE Data Alignment Factor - .byte 0x8 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x5 # uleb128 0x5 - .byte 0x4 # uleb128 0x4 - .byte 0x88 # DW_CFA_offset, column 0x8 - .byte 0x1 # uleb128 0x1 - .align 2 -LECIE1: - -.globl _unwind_tester.eh -_unwind_tester.eh: -LSFDE1: - .set L$set$1,LEFDE1-LASFDE1 - .long L$set$1 # FDE Length -LASFDE1: - .long LASFDE1-EH_frame1 # FDE CIE offset - .long LFB2-. # FDE initial location - .set L$set$2,LFE2-LFB2 - .long L$set$2 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$3,LCFI0-LFB2 - .long L$set$3 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$4,LCFI1-LCFI0 - .long L$set$4 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$5,LCFI5-LCFI1 - .long L$set$5 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE1: - - diff --git a/libunwind/testsuite/unwind_test_x86_64.s b/libunwind/testsuite/unwind_test_x86_64.s deleted file mode 100644 index 3589fe7..0000000 --- a/libunwind/testsuite/unwind_test_x86_64.s +++ /dev/null @@ -1,125 +0,0 @@ - -# -# This is a generic function to test that restoring registers during unwinding work correctly. -# - - .text -.globl _unwind_tester -_unwind_tester: -LFB3: - pushq %rbp -LCFI45: - movq %rsp, %rbp -LCFI46: - movq %rbx, -40(%rbp) -LCFI47: - movq %r12, -32(%rbp) -LCFI48: - movq %r13, -24(%rbp) -LCFI49: - movq %r14, -16(%rbp) -LCFI50: - movq %r15, -8(%rbp) -LCFI51: - subq $48, %rsp -LCFI52: - # load magic values into non-volatile registers - movq $0x1234567887654321, %rbx - movq $0x02468ACEECA86420, %r12 - movq $0x13579BDFFDB97531, %r13 - movq $0x1122334455667788, %r14 - movq $0x0022446688AACCEE, %r15 - # call test function which will invoke unwinder which "returns" here - call *%rdi - # verify that non-volatile registers still contain magic values - movq $0x1234567887654321, %rax - cmpq %rax, %rbx - jne L2 - movq $0x02468ACEECA86420, %rax - cmpq %rax, %r12 - jne L2 - movq $0x13579BDFFDB97531, %rax - cmpq %rax, %r13 - jne L2 - movq $0x1122334455667788, %rax - cmpq %rax, %r14 - jne L2 - movq $0x0022446688AACCEE, %rax - cmpq %rax, %r15 - jne L2 - movl $0, %eax - jmp L3 -L2: movl $1, %eax -L3: - movq -40(%rbp), %rbx - movq -32(%rbp), %r12 - movq -24(%rbp), %r13 - movq -16(%rbp), %r14 - movq -8(%rbp), %r15 - leave - ret -LFE3: - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x78 # sleb128 -8; CIE Data Alignment Factor - .byte 0x10 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x7 # uleb128 0x7 - .byte 0x8 # uleb128 0x8 - .byte 0x90 # DW_CFA_offset, column 0x10 - .byte 0x1 # uleb128 0x1 - .align 3 -LECIE1: - -.globl _unwind_tester.eh -_unwind_tester.eh: -LSFDE23: - .set L$set$52,LEFDE23-LASFDE23 - .long L$set$52 # FDE Length -LASFDE23: - .long LASFDE23-EH_frame1 # FDE CIE offset - .quad LFB3-. # FDE initial location - .set L$set$53,LFE3-LFB3 - .quad L$set$53 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$54,LCFI45-LFB3 - .long L$set$54 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x10 # uleb128 0x10 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$55,LCFI46-LCFI45 - .long L$set$55 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x6 # uleb128 0x6 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$56,LCFI52-LCFI46 - .long L$set$56 - .byte 0x8f # DW_CFA_offset, column 0xf - .byte 0x3 # uleb128 0x3 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x4 # uleb128 0x4 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x5 # uleb128 0x5 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x6 # uleb128 0x6 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x7 # uleb128 0x7 - .align 3 -LEFDE23: - - - diff --git a/libunwind/testsuite/unwind_test_x86_64_disable_compact_frame.s b/libunwind/testsuite/unwind_test_x86_64_disable_compact_frame.s deleted file mode 100644 index c0cdf16..0000000 --- a/libunwind/testsuite/unwind_test_x86_64_disable_compact_frame.s +++ /dev/null @@ -1,599 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 - - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .quad _test_no_reg - .quad _test_rbx - .quad _test_rbx_r12 - .quad _test_rbx_r14 - .quad _test_rbx_r12_r13 - .quad _test_rbx_r12_r13_r14 - .quad _test_r14_r13_r12_rbx - .quad _test_rbx_r12_r13_r14_r15 - .quad _test_r13_rbx_r14_r15_r12 - .quad 0 - - - .text - -LFE14: -.globl _test_no_reg -_test_no_reg: -LFB13: - pushq %rbp -LCFI2: - movq %rsp, %rbp -LCFI3: - call _uwind_to_main - leave - ret -LFE13: - - -.globl _test_rbx -_test_rbx: -LFB10: - pushq %rbp -LCFI8: - movq %rsp, %rbp -LCFI9: - pushq %rbx -LCFI10: - subq $8, %rsp -LCFI11: - movq $0, %rbx - call _uwind_to_main - addq $8, %rsp - popq %rbx - leave - ret -LFE10: - - -.globl _test_rbx_r12 -_test_rbx_r12: -LFB8: - pushq %rbp -LCFI16: - movq %rsp, %rbp -LCFI17: - movq %rbx, -16(%rbp) -LCFI18: - movq %r12, -8(%rbp) -LCFI19: - subq $16, %rsp -LCFI20: - movq $0, %rbx - movq $0, %r12 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - leave - ret -LFE8: - - -.globl _test_rbx_r14 -_test_rbx_r14: -LFB8a: - pushq %rbp -LCFI16a: - movq %rsp, %rbp -LCFI17a: - movq %rbx, -16(%rbp) -LCFI18a: - movq %r14, -8(%rbp) -LCFI19a: - subq $16, %rsp -LCFI20a: - movq $0, %rbx - movq $0, %r14 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r14 - leave - ret -LFE8a: - - -.globl _test_rbx_r12_r13 -_test_rbx_r12_r13: -LFB6: - pushq %rbp -LCFI26: - movq %rsp, %rbp -LCFI27: - movq %rbx, -24(%rbp) -LCFI28: - movq %r12, -16(%rbp) -LCFI29: - movq %r13, -8(%rbp) -LCFI30: - subq $32, %rsp -LCFI31: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - call _uwind_to_main - movq -24(%rbp), %rbx - movq -16(%rbp), %r12 - movq -8(%rbp), %r13 - leave - ret -LFE6: - -.globl _test_rbx_r12_r13_r14 -_test_rbx_r12_r13_r14: -LFB4: - pushq %rbp -LCFI38: - movq %rsp, %rbp -LCFI39: - movq %rbx, -32(%rbp) -LCFI40: - movq %r12, -24(%rbp) -LCFI41: - movq %r13, -16(%rbp) -LCFI42: - movq %r14, -8(%rbp) -LCFI43: - subq $32, %rsp -LCFI44: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - movq 16(%rsp), %r13 - movq 24(%rsp), %r14 - leave - ret -LFE4: - -.globl _test_r14_r13_r12_rbx -_test_r14_r13_r12_rbx: -LFB4a: - pushq %rbp -LCFI38a: - movq %rsp, %rbp -LCFI39a: - movq %r14, -32(%rbp) -LCFI40a: - movq %r13, -24(%rbp) -LCFI41a: - movq %r12, -16(%rbp) -LCFI42a: - movq %rbx, -8(%rbp) -LCFI43a: - subq $32, %rsp -LCFI44a: - movq $0, %r14 - movq $0, %r13 - movq $0, %r12 - movq $0, %rbx - call _uwind_to_main - movq -32(%rbp), %r14 - movq -24(%rbp), %r13 - movq -16(%rbp), %r12 - movq -8(%rbp), %rbx - leave - ret -LFE4a: - - -.globl _test_rbx_r12_r13_r14_r15 -_test_rbx_r12_r13_r14_r15: -LFB3: - pushq %rbp -LCFI45: - movq %rsp, %rbp -LCFI46: - movq %rbx, -40(%rbp) -LCFI47: - movq %r12, -32(%rbp) -LCFI48: - movq %r13, -24(%rbp) -LCFI49: - movq %r14, -16(%rbp) -LCFI50: - movq %r15, -8(%rbp) -LCFI51: - subq $48, %rsp -LCFI52: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq -40(%rbp), %rbx - movq -32(%rbp), %r12 - movq -24(%rbp), %r13 - movq -16(%rbp), %r14 - movq -8(%rbp), %r15 - leave - ret -LFE3: - - -.globl _test_r13_rbx_r14_r15_r12 -_test_r13_rbx_r14_r15_r12: -LFB3a: - pushq %rbp -LCFI45a: - movq %rsp, %rbp -LCFI46a: - movq %r13, -40(%rbp) -LCFI47a: - movq %rbx, -32(%rbp) -LCFI48a: - movq %r14, -24(%rbp) -LCFI49a: - movq %r15, -16(%rbp) -LCFI50a: - movq %r12, -8(%rbp) -LCFI51a: - subq $48, %rsp -LCFI52a: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - movq $0, %r15 - call _uwind_to_main - movq -40(%rbp), %r13 - movq -32(%rbp), %rbx - movq -24(%rbp), %r14 - movq -16(%rbp), %r15 - movq -8(%rbp), %r12 - leave - ret -LFE3a: - - - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 -LSCIE1: - .long 0x0 - .byte 0x1 - .ascii "zR\0" - .byte 0x1 - .byte 0x78 - .byte 0x10 - .byte 0x1 - .byte 0x10 - .byte 0xc - .byte 0x7 - .byte 0x8 - .byte 0x90 // DW_CFA_offset(ret_addr, -8) - .byte 0x1 - .byte 0x90 // DW_CFA_offset(ret_addr, -8) - .byte 0x1 // this repeat is idiom that means don't create compact unwind info - .align 3 -LECIE1: - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE3: - .set L$set$5,LEFDE3-LASFDE3 - .long L$set$5 -LASFDE3: - .long LASFDE3-EH_frame1 - .quad LFB13-. - .set L$set$6,LFE13-LFB13 - .quad L$set$6 - .byte 0x0 - .byte 0x4 - .set L$set$7,LCFI2-LFB13 - .long L$set$7 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$8,LCFI3-LCFI2 - .long L$set$8 - .byte 0xd - .byte 0x6 - .align 3 -LEFDE3: - -.globl _test_rbx.eh -_test_rbx.eh: -LSFDE9: - .set L$set$17,LEFDE9-LASFDE9 - .long L$set$17 -LASFDE9: - .long LASFDE9-EH_frame1 - .quad LFB10-. - .set L$set$18,LFE10-LFB10 - .quad L$set$18 - .byte 0x0 - .byte 0x4 - .set L$set$19,LCFI8-LFB10 - .long L$set$19 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$20,LCFI9-LCFI8 - .long L$set$20 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$21,LCFI11-LCFI9 - .long L$set$21 - .byte 0x83 - .byte 0x3 - .align 3 -LEFDE9: - -.globl _test_rbx_r12.eh -_test_rbx_r12.eh: -LSFDE13: - .set L$set$27,LEFDE13-LASFDE13 - .long L$set$27 -LASFDE13: - .long LASFDE13-EH_frame1 - .quad LFB8-. - .set L$set$28,LFE8-LFB8 - .quad L$set$28 - .byte 0x0 - .byte 0x4 - .set L$set$29,LCFI16-LFB8 - .long L$set$29 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$30,LCFI17-LCFI16 - .long L$set$30 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$31,LCFI20-LCFI17 - .long L$set$31 - .byte 0x8c - .byte 0x3 - .byte 0x83 - .byte 0x4 - .align 3 -LEFDE13: - -.globl _test_rbx_r14.eh -_test_rbx_r14.eh: -LSFDE13a: - .set L$set$27a,LEFDE13a-LASFDE13a - .long L$set$27a -LASFDE13a: - .long LASFDE13a-EH_frame1 - .quad LFB8a-. - .set L$set$28a,LFE8a-LFB8a - .quad L$set$28a - .byte 0x0 - .byte 0x4 - .set L$set$29a,LCFI16a-LFB8a - .long L$set$29a - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$30a,LCFI17a-LCFI16a - .long L$set$30a - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$31a,LCFI20a-LCFI17a - .long L$set$31a - .byte 0x8e - .byte 0x3 - .byte 0x83 - .byte 0x4 - .align 3 -LEFDE13a: - - -.globl _test_rbx_r12_r13.eh -_test_rbx_r12_r13.eh: -LSFDE17: - .set L$set$37,LEFDE17-LASFDE17 - .long L$set$37 -LASFDE17: - .long LASFDE17-EH_frame1 - .quad LFB6-. - .set L$set$38,LFE6-LFB6 - .quad L$set$38 - .byte 0x0 - .byte 0x4 - .set L$set$39,LCFI26-LFB6 - .long L$set$39 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$40,LCFI27-LCFI26 - .long L$set$40 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$41,LCFI31-LCFI27 - .long L$set$41 - .byte 0x8d - .byte 0x3 - .byte 0x8c - .byte 0x4 - .byte 0x83 - .byte 0x5 - .align 3 -LEFDE17: - - -.globl _test_rbx_r12_r13_r14.eh -_test_rbx_r12_r13_r14.eh: -LSFDE21: - .set L$set$47,LEFDE21-LASFDE21 - .long L$set$47 -LASFDE21: - .long LASFDE21-EH_frame1 - .quad LFB4-. - .set L$set$48,LFE4-LFB4 - .quad L$set$48 - .byte 0x0 - .byte 0x4 - .set L$set$49,LCFI38-LFB4 - .long L$set$49 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$50,LCFI39-LCFI38 - .long L$set$50 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$51,LCFI44-LCFI39 - .long L$set$51 - .byte 0x8e - .byte 0x3 - .byte 0x8d - .byte 0x4 - .byte 0x8c - .byte 0x5 - .byte 0x83 - .byte 0x6 - .align 3 -LEFDE21: - -.globl _test_r14_r13_r12_rbx.eh -_test_r14_r13_r12_rbx.eh: -LSFDE21a: - .set L$set$47a,LEFDE21a-LASFDE21a - .long L$set$47a -LASFDE21a: - .long LASFDE21a-EH_frame1 - .quad LFB4a-. - .set L$set$48a,LFE4a-LFB4a - .quad L$set$48a - .byte 0x0 - .byte 0x4 - .set L$set$49a,LCFI38a-LFB4a - .long L$set$49a - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$50a,LCFI39a-LCFI38a - .long L$set$50a - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$51a,LCFI44a-LCFI39a - .long L$set$51a - .byte 0x8e - .byte 0x6 - .byte 0x8d - .byte 0x5 - .byte 0x8c - .byte 0x4 - .byte 0x83 - .byte 0x3 - .align 3 -LEFDE21a: - - -.globl _test_rbx_r12_r13_r14_r15.eh -_test_rbx_r12_r13_r14_r15.eh: -LSFDE23: - .set L$set$52,LEFDE23-LASFDE23 - .long L$set$52 -LASFDE23: - .long LASFDE23-EH_frame1 - .quad LFB3-. - .set L$set$53,LFE3-LFB3 - .quad L$set$53 - .byte 0x0 - .byte 0x4 - .set L$set$54,LCFI45-LFB3 - .long L$set$54 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$55,LCFI46-LCFI45 - .long L$set$55 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$56,LCFI52-LCFI46 - .long L$set$56 - .byte 0x8f - .byte 0x3 - .byte 0x8e - .byte 0x4 - .byte 0x8d - .byte 0x5 - .byte 0x8c - .byte 0x6 - .byte 0x83 - .byte 0x7 - .align 3 -LEFDE23: - - -.globl _test_r13_rbx_r14_r15_r12.eh -_test_r13_rbx_r14_r15_r12.eh: -LSFDE23a: - .set L$set$52a,LEFDE23a-LASFDE23a - .long L$set$52a -LASFDE23a: - .long LASFDE23a-EH_frame1 - .quad LFB3a-. - .set L$set$53a,LFE3a-LFB3a - .quad L$set$53a - .byte 0x0 - .byte 0x4 - .set L$set$54a,LCFI45a-LFB3a - .long L$set$54a - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$55a,LCFI46a-LCFI45a - .long L$set$55a - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$56a,LCFI52a-LCFI46a - .long L$set$56a - .byte 0x8c - .byte 0x3 - .byte 0x8f - .byte 0x4 - .byte 0x8e - .byte 0x5 - .byte 0x83 - .byte 0x6 - .byte 0x8d - .byte 0x7 - .align 3 -LEFDE23a: - - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_64_frame.s b/libunwind/testsuite/unwind_test_x86_64_frame.s deleted file mode 100644 index 023201e..0000000 --- a/libunwind/testsuite/unwind_test_x86_64_frame.s +++ /dev/null @@ -1,674 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_COMPACT_UNWIND=1 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_EH_FRAME=1 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_COMPACT_UNWIND=1 -DUSE_EH_FRAME=1 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_EH_FRAME=1 -Wl,-no_compact_unwind - - - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .quad _test_no_reg - .quad _test_rbx - .quad _test_rbx_r12 - .quad _test_rbx_r14 - .quad _test_rbx_r12_r13 - .quad _test_rbx_r12_r13_r14 - .quad _test_r14_r13_r12_rbx - .quad _test_rbx_r12_r13_r14_r15 - .quad _test_r13_rbx_r14_r15_r12 - .quad 0 - - - .text - -LFE14: -.globl _test_no_reg -_test_no_reg: -LFB13: - pushq %rbp -LCFI2: - movq %rsp, %rbp -LCFI3: - call _uwind_to_main - leave - ret -LFE13: - - -.globl _test_rbx -_test_rbx: -LFB10: - pushq %rbp -LCFI8: - movq %rsp, %rbp -LCFI9: - pushq %rbx -LCFI10: - subq $8, %rsp -LCFI11: - movq $0, %rbx - call _uwind_to_main - addq $8, %rsp - popq %rbx - leave - ret -LFE10: - - -.globl _test_rbx_r12 -_test_rbx_r12: -LFB8: - pushq %rbp -LCFI16: - movq %rsp, %rbp -LCFI17: - movq %rbx, -16(%rbp) -LCFI18: - movq %r12, -8(%rbp) -LCFI19: - subq $16, %rsp -LCFI20: - movq $0, %rbx - movq $0, %r12 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - leave - ret -LFE8: - - -.globl _test_rbx_r14 -_test_rbx_r14: -LFB8a: - pushq %rbp -LCFI16a: - movq %rsp, %rbp -LCFI17a: - movq %rbx, -16(%rbp) -LCFI18a: - movq %r14, -8(%rbp) -LCFI19a: - subq $16, %rsp -LCFI20a: - movq $0, %rbx - movq $0, %r14 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r14 - leave - ret -LFE8a: - - -.globl _test_rbx_r12_r13 -_test_rbx_r12_r13: -LFB6: - pushq %rbp -LCFI26: - movq %rsp, %rbp -LCFI27: - movq %rbx, -24(%rbp) -LCFI28: - movq %r12, -16(%rbp) -LCFI29: - movq %r13, -8(%rbp) -LCFI30: - subq $32, %rsp -LCFI31: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - call _uwind_to_main - movq -24(%rbp), %rbx - movq -16(%rbp), %r12 - movq -8(%rbp), %r13 - leave - ret -LFE6: - -.globl _test_rbx_r12_r13_r14 -_test_rbx_r12_r13_r14: -LFB4: - pushq %rbp -LCFI38: - movq %rsp, %rbp -LCFI39: - movq %rbx, -32(%rbp) -LCFI40: - movq %r12, -24(%rbp) -LCFI41: - movq %r13, -16(%rbp) -LCFI42: - movq %r14, -8(%rbp) -LCFI43: - subq $32, %rsp -LCFI44: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - movq 16(%rsp), %r13 - movq 24(%rsp), %r14 - leave - ret -LFE4: - -.globl _test_r14_r13_r12_rbx -_test_r14_r13_r12_rbx: -LFB4a: - pushq %rbp -LCFI38a: - movq %rsp, %rbp -LCFI39a: - movq %r14, -32(%rbp) -LCFI40a: - movq %r13, -24(%rbp) -LCFI41a: - movq %r12, -16(%rbp) -LCFI42a: - movq %rbx, -8(%rbp) -LCFI43a: - subq $32, %rsp -LCFI44a: - movq $0, %r14 - movq $0, %r13 - movq $0, %r12 - movq $0, %rbx - call _uwind_to_main - movq -32(%rbp), %r14 - movq -24(%rbp), %r13 - movq -16(%rbp), %r12 - movq -8(%rbp), %rbx - leave - ret -LFE4a: - - -.globl _test_rbx_r12_r13_r14_r15 -_test_rbx_r12_r13_r14_r15: -LFB3: - pushq %rbp -LCFI45: - movq %rsp, %rbp -LCFI46: - movq %rbx, -40(%rbp) -LCFI47: - movq %r12, -32(%rbp) -LCFI48: - movq %r13, -24(%rbp) -LCFI49: - movq %r14, -16(%rbp) -LCFI50: - movq %r15, -8(%rbp) -LCFI51: - subq $48, %rsp -LCFI52: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq -40(%rbp), %rbx - movq -32(%rbp), %r12 - movq -24(%rbp), %r13 - movq -16(%rbp), %r14 - movq -8(%rbp), %r15 - leave - ret -LFE3: - - -.globl _test_r13_rbx_r14_r15_r12 -_test_r13_rbx_r14_r15_r12: -LFB3a: - pushq %rbp -LCFI45a: - movq %rsp, %rbp -LCFI46a: - movq %r13, -40(%rbp) -LCFI47a: - movq %rbx, -32(%rbp) -LCFI48a: - movq %r14, -24(%rbp) -LCFI49a: - movq %r15, -16(%rbp) -LCFI50a: - movq %r12, -8(%rbp) -LCFI51a: - subq $48, %rsp -LCFI52a: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - movq $0, %r15 - call _uwind_to_main - movq -40(%rbp), %r13 - movq -32(%rbp), %rbx - movq -24(%rbp), %r14 - movq -16(%rbp), %r15 - movq -8(%rbp), %r12 - leave - ret -LFE3a: - - - -#if USE_EH_FRAME - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 -LSCIE1: - .long 0x0 - .byte 0x1 - .ascii "zR\0" - .byte 0x1 - .byte 0x78 - .byte 0x10 - .byte 0x1 - .byte 0x10 - .byte 0xc - .byte 0x7 - .byte 0x8 - .byte 0x90 - .byte 0x1 - .align 3 -LECIE1: - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE3: - .set L$set$5,LEFDE3-LASFDE3 - .long L$set$5 -LASFDE3: - .long LASFDE3-EH_frame1 - .quad LFB13-. - .set L$set$6,LFE13-LFB13 - .quad L$set$6 - .byte 0x0 - .byte 0x4 - .set L$set$7,LCFI2-LFB13 - .long L$set$7 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$8,LCFI3-LCFI2 - .long L$set$8 - .byte 0xd - .byte 0x6 - .align 3 -LEFDE3: - -.globl _test_rbx.eh -_test_rbx.eh: -LSFDE9: - .set L$set$17,LEFDE9-LASFDE9 - .long L$set$17 -LASFDE9: - .long LASFDE9-EH_frame1 - .quad LFB10-. - .set L$set$18,LFE10-LFB10 - .quad L$set$18 - .byte 0x0 - .byte 0x4 - .set L$set$19,LCFI8-LFB10 - .long L$set$19 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$20,LCFI9-LCFI8 - .long L$set$20 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$21,LCFI11-LCFI9 - .long L$set$21 - .byte 0x83 - .byte 0x3 - .align 3 -LEFDE9: - -.globl _test_rbx_r12.eh -_test_rbx_r12.eh: -LSFDE13: - .set L$set$27,LEFDE13-LASFDE13 - .long L$set$27 -LASFDE13: - .long LASFDE13-EH_frame1 - .quad LFB8-. - .set L$set$28,LFE8-LFB8 - .quad L$set$28 - .byte 0x0 - .byte 0x4 - .set L$set$29,LCFI16-LFB8 - .long L$set$29 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$30,LCFI17-LCFI16 - .long L$set$30 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$31,LCFI20-LCFI17 - .long L$set$31 - .byte 0x8c - .byte 0x3 - .byte 0x83 - .byte 0x4 - .align 3 -LEFDE13: - -.globl _test_rbx_r14.eh -_test_rbx_r14.eh: -LSFDE13a: - .set L$set$27a,LEFDE13a-LASFDE13a - .long L$set$27a -LASFDE13a: - .long LASFDE13a-EH_frame1 - .quad LFB8a-. - .set L$set$28a,LFE8a-LFB8a - .quad L$set$28a - .byte 0x0 - .byte 0x4 - .set L$set$29a,LCFI16a-LFB8a - .long L$set$29a - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$30a,LCFI17a-LCFI16a - .long L$set$30a - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$31a,LCFI20a-LCFI17a - .long L$set$31a - .byte 0x8e - .byte 0x3 - .byte 0x83 - .byte 0x4 - .align 3 -LEFDE13a: - - -.globl _test_rbx_r12_r13.eh -_test_rbx_r12_r13.eh: -LSFDE17: - .set L$set$37,LEFDE17-LASFDE17 - .long L$set$37 -LASFDE17: - .long LASFDE17-EH_frame1 - .quad LFB6-. - .set L$set$38,LFE6-LFB6 - .quad L$set$38 - .byte 0x0 - .byte 0x4 - .set L$set$39,LCFI26-LFB6 - .long L$set$39 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$40,LCFI27-LCFI26 - .long L$set$40 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$41,LCFI31-LCFI27 - .long L$set$41 - .byte 0x8d - .byte 0x3 - .byte 0x8c - .byte 0x4 - .byte 0x83 - .byte 0x5 - .align 3 -LEFDE17: - - -.globl _test_rbx_r12_r13_r14.eh -_test_rbx_r12_r13_r14.eh: -LSFDE21: - .set L$set$47,LEFDE21-LASFDE21 - .long L$set$47 -LASFDE21: - .long LASFDE21-EH_frame1 - .quad LFB4-. - .set L$set$48,LFE4-LFB4 - .quad L$set$48 - .byte 0x0 - .byte 0x4 - .set L$set$49,LCFI38-LFB4 - .long L$set$49 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$50,LCFI39-LCFI38 - .long L$set$50 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$51,LCFI44-LCFI39 - .long L$set$51 - .byte 0x8e - .byte 0x3 - .byte 0x8d - .byte 0x4 - .byte 0x8c - .byte 0x5 - .byte 0x83 - .byte 0x6 - .align 3 -LEFDE21: - -.globl _test_r14_r13_r12_rbx.eh -_test_r14_r13_r12_rbx.eh: -LSFDE21a: - .set L$set$47a,LEFDE21a-LASFDE21a - .long L$set$47a -LASFDE21a: - .long LASFDE21a-EH_frame1 - .quad LFB4a-. - .set L$set$48a,LFE4a-LFB4a - .quad L$set$48a - .byte 0x0 - .byte 0x4 - .set L$set$49a,LCFI38a-LFB4a - .long L$set$49a - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$50a,LCFI39a-LCFI38a - .long L$set$50a - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$51a,LCFI44a-LCFI39a - .long L$set$51a - .byte 0x8e - .byte 0x6 - .byte 0x8d - .byte 0x5 - .byte 0x8c - .byte 0x4 - .byte 0x83 - .byte 0x3 - .align 3 -LEFDE21a: - - -.globl _test_rbx_r12_r13_r14_r15.eh -_test_rbx_r12_r13_r14_r15.eh: -LSFDE23: - .set L$set$52,LEFDE23-LASFDE23 - .long L$set$52 -LASFDE23: - .long LASFDE23-EH_frame1 - .quad LFB3-. - .set L$set$53,LFE3-LFB3 - .quad L$set$53 - .byte 0x0 - .byte 0x4 - .set L$set$54,LCFI45-LFB3 - .long L$set$54 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$55,LCFI46-LCFI45 - .long L$set$55 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$56,LCFI52-LCFI46 - .long L$set$56 - .byte 0x8f - .byte 0x3 - .byte 0x8e - .byte 0x4 - .byte 0x8d - .byte 0x5 - .byte 0x8c - .byte 0x6 - .byte 0x83 - .byte 0x7 - .align 3 -LEFDE23: - - -.globl _test_r13_rbx_r14_r15_r12.eh -_test_r13_rbx_r14_r15_r12.eh: -LSFDE23a: - .set L$set$52a,LEFDE23a-LASFDE23a - .long L$set$52a -LASFDE23a: - .long LASFDE23a-EH_frame1 - .quad LFB3a-. - .set L$set$53a,LFE3a-LFB3a - .quad L$set$53a - .byte 0x0 - .byte 0x4 - .set L$set$54a,LCFI45a-LFB3a - .long L$set$54a - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$55a,LCFI46a-LCFI45a - .long L$set$55a - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$56a,LCFI52a-LCFI46a - .long L$set$56a - .byte 0x8c - .byte 0x3 - .byte 0x8f - .byte 0x4 - .byte 0x8e - .byte 0x5 - .byte 0x83 - .byte 0x6 - .byte 0x8d - .byte 0x7 - .align 3 -LEFDE23a: -#endif // USE_EH_FRAME - - - -#if USE_COMPACT_UNWIND - - .section __LD,__compact_unwind,regular,debug - - .quad _test_no_reg - .set L101,LFE13-_test_no_reg - .long L101 - .long 0x01000000 - .quad 0 - .quad 0 - - .quad _test_rbx - .set L102,LFE10-_test_rbx - .long L102 - .long 0x01010001 - .quad 0 - .quad 0 - - .quad _test_rbx_r12 - .set L103,LFE8-_test_rbx_r12 - .long L103 - .long 0x01020011 - .quad 0 - .quad 0 - - .quad _test_rbx_r14 - .set L104,LFE8a-_test_rbx_r14 - .long L104 - .long 0x01020021 - .quad 0 - .quad 0 - - .quad _test_rbx_r12_r13 - .set L105,LFE6-_test_rbx_r12_r13 - .long L105 - .long 0x010300D1 - .quad 0 - .quad 0 - - .quad _test_rbx_r12_r13_r14 - .set L106,LFE4-_test_rbx_r12_r13_r14 - .long L106 - .long 0x010408D1 - .quad 0 - .quad 0 - - .quad _test_r14_r13_r12_rbx - .set L107,LFE4a-_test_r14_r13_r12_rbx - .long L107 - .long 0x0104029C - .quad 0 - .quad 0 - - .quad _test_rbx_r12_r13_r14_r15 - .set L108,LFE3-_test_rbx_r12_r13_r14_r15 - .long L108 - .long 0x010558D1 - .quad 0 - .quad 0 - - .quad _test_r13_rbx_r14_r15_r12 - .set L109,LFE3a-_test_r13_rbx_r14_r15_r12 - .long L109 - .long 0x01052B0B - .quad 0 - .quad 0 - -#endif // USE_COMPACT_UNWIND - - - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_64_frameless.s b/libunwind/testsuite/unwind_test_x86_64_frameless.s deleted file mode 100644 index 5b312ef..0000000 --- a/libunwind/testsuite/unwind_test_x86_64_frameless.s +++ /dev/null @@ -1,583 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -Wl,-no_compact_unwind - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .quad _test_no_reg - .quad _test_rbx - .quad _test_rbx_r12 - .quad _test_rbx_r12_r13 - .quad _test_rbx_r12_r13_r14 - .quad _test_rbx_r12_r13_r14_r15 - .quad _test_rbx_rbp - .quad _test_rbx_rbp_r12 - .quad _test_rbx_rbp_r12_r13 - .quad _test_rbx_rbp_r12_r13_r14 - .quad _test_rbx_rbp_r12_r13_r14_r15 - .quad 0 - - - .text - -.globl _test_no_reg -_test_no_reg: -LFB13: - subq $8, %rsp -LCFI0: - call _uwind_to_main - addq $8, %rsp - ret -LFE13: - - -.globl _test_rbx -_test_rbx: -LFB10: - pushq %rbx -LCFI3: - movq $0, %rbx - call _uwind_to_main - popq %rbx - ret -LFE10: - - -.globl _test_rbx_r12 -_test_rbx_r12: -LFB8: - movq %rbx, -16(%rsp) -LCFI5: - movq %r12, -8(%rsp) -LCFI6: - subq $24, %rsp -LCFI7: - movq $0, %rbx - movq $0, %r12 - call _uwind_to_main - movq 8(%rsp), %rbx - movq 16(%rsp), %r12 - addq $24, %rsp - ret -LFE8: - - -.globl _test_rbx_rbp -_test_rbx_rbp: -LFB7: - movq %rbx, -16(%rsp) -LCFI8: - movq %rbp, -8(%rsp) -LCFI9: - subq $24, %rsp -LCFI10: - movq $0, %rbp - movq $0, %rbx - call _uwind_to_main - movq 8(%rsp), %rbx - movq 16(%rsp), %rbp - addq $24, %rsp - ret -LFE7: - - -.globl _test_rbx_r12_r13 -_test_rbx_r12_r13: -LFB6: - movq %rbx, -24(%rsp) -LCFI11: - movq %r12, -16(%rsp) -LCFI12: - movq %r13, -8(%rsp) -LCFI13: - subq $24, %rsp -LCFI14: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - movq 16(%rsp), %r13 - addq $24, %rsp - ret -LFE6: - - - -.globl _test_rbx_r12_r13_r14 -_test_rbx_r12_r13_r14: -LFB4: - movq %rbx, -32(%rsp) -LCFI19: - movq %r12, -24(%rsp) -LCFI20: - movq %r13, -16(%rsp) -LCFI21: - movq %r14, -8(%rsp) -LCFI22: - subq $40, %rsp -LCFI23: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq 8(%rsp), %rbx - movq 16(%rsp), %r12 - movq 24(%rsp), %r13 - movq 32(%rsp), %r14 - addq $40, %rsp - ret -LFE4: - - -.globl _test_rbx_r12_r13_r14_r15 -_test_rbx_r12_r13_r14_r15: -LFB3: - movq %rbx, -40(%rsp) -LCFI24: - movq %r12, -32(%rsp) -LCFI25: - movq %r13, -24(%rsp) -LCFI26: - movq %r14, -16(%rsp) -LCFI27: - movq %r15, -8(%rsp) -LCFI28: - subq $40, %rsp -LCFI29: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - movq $0, %r15 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - movq 16(%rsp), %r13 - movq 24(%rsp), %r14 - movq 32(%rsp), %r15 - addq $40, %rsp - ret -LFE3: - - -.globl _test_rbx_rbp_r12_r13_r14_r15 -_test_rbx_rbp_r12_r13_r14_r15: -LFB2: - movq %rbx, -48(%rsp) -LCFI30: - movq %rbp, -40(%rsp) -LCFI31: - movq %r12, -32(%rsp) -LCFI32: - movq %r13, -24(%rsp) -LCFI33: - movq %r14, -16(%rsp) -LCFI34: - movq %r15, -8(%rsp) -LCFI35: - subq $72, %rsp -LCFI36: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - movq $0, %r15 - call _uwind_to_main - movq 24(%rsp), %rbx - movq 32(%rsp), %rbp - movq 40(%rsp), %r12 - movq 48(%rsp), %r13 - movq 56(%rsp), %r14 - movq 64(%rsp), %r15 - addq $72, %rsp - ret -LFE2: - - - -.globl _test_rbx_rbp_r12 -_test_rbx_rbp_r12: -LFB11: - movq %rbx, -24(%rsp) - movq %rbp, -16(%rsp) - movq %r12, -8(%rsp) - subq $24, %rsp -LCFI11a: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %rbp - movq 16(%rsp), %r12 - addq $24, %rsp - ret -LFE11: - - - -.globl _test_rbx_rbp_r12_r13 -_test_rbx_rbp_r12_r13: -LFB457: - movq %rbx, -32(%rsp) - movq %rbp, -24(%rsp) - movq %r12, -16(%rsp) - movq %r13, -8(%rsp) - subq $40, %rsp -LFB457a: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - movq $0, %r13 - call _uwind_to_main - movq 8(%rsp), %rbx - movq 16(%rsp), %rbp - movq 24(%rsp), %r12 - movq 32(%rsp), %r13 - addq $40, %rsp - ret -LFE457: - - -.globl _test_rbx_rbp_r12_r13_r14 -_test_rbx_rbp_r12_r13_r14: -LFB17: - movq %rbx, -40(%rsp) - movq %rbp, -32(%rsp) - movq %r12, -24(%rsp) - movq %r13, -16(%rsp) - movq %r14, -8(%rsp) - subq $40, %rsp -LFB17a: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %rbp - movq 16(%rsp), %r12 - movq 24(%rsp), %r13 - movq 32(%rsp), %r14 - addq $40, %rsp - ret -LFE17: - - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x78 # sleb128 -8; CIE Data Alignment Factor - .byte 0x10 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x7 # uleb128 0x7 - .byte 0x8 # uleb128 0x8 - .byte 0x90 # DW_CFA_offset, column 0x10 - .byte 0x1 # uleb128 0x1 - .align 3 -LECIE1: - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE3: - .set L$set$3,LEFDE3-LASFDE3 - .long L$set$3 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .quad LFB13-. # FDE initial location - .set L$set$4,LFE13-LFB13 - .quad L$set$4 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$5,LCFI0-LFB13 - .long L$set$5 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x10 # uleb128 0x10 - .align 3 -LEFDE3: - -.globl _test_rbx.eh -_test_rbx.eh: -LSFDE9: - .set L$set$12,LEFDE9-LASFDE9 - .long L$set$12 # FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 # FDE CIE offset - .quad LFB10-. # FDE initial location - .set L$set$13,LFE10-LFB10 - .quad L$set$13 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14,LCFI3-LFB10 - .long L$set$14 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x10 # uleb128 0x10 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x2 # uleb128 0x2 - .align 3 -LEFDE9: - -.globl _test_rbx_r12.eh -_test_rbx_r12.eh: -LSFDE13: - .set L$set$18,LEFDE13-LASFDE13 - .long L$set$18 # FDE Length -LASFDE13: - .long LASFDE13-EH_frame1 # FDE CIE offset - .quad LFB8-. # FDE initial location - .set L$set$19,LFE8-LFB8 - .quad L$set$19 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$20,LCFI7-LFB8 - .long L$set$20 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 3 -LEFDE13: - - -.globl _test_rbx_rbp.eh -_test_rbx_rbp.eh: -LSFDE14: - .set L$set$21,LEFDE14-LASFDE14 - .long L$set$21 # FDE Length -LASFDE14: - .long LASFDE14-EH_frame1 # FDE CIE offset - .quad LFB7-. # FDE initial location - .set L$set$22,LFE7-LFB7 - .quad L$set$22 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23,LCFI10-LFB7 - .long L$set$23 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 3 -LEFDE14: - - -.globl _test_rbx_r12_r13.eh -_test_rbx_r12_r13.eh: -LSFDE17: - .set L$set$24,LEFDE17-LASFDE17 - .long L$set$24 # FDE Length -LASFDE17: - .long LASFDE17-EH_frame1 # FDE CIE offset - .quad LFB6-. # FDE initial location - .set L$set$25,LFE6-LFB6 - .quad L$set$25 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$26,LCFI14-LFB6 - .long L$set$26 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x2 # uleb128 0x2 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 3 -LEFDE17: - -.globl _test_rbx_r12_r13_r14.eh -_test_rbx_r12_r13_r14.eh: -LSFDE21: - .set L$set$30,LEFDE21-LASFDE21 - .long L$set$30 # FDE Length -LASFDE21: - .long LASFDE21-EH_frame1 # FDE CIE offset - .quad LFB4-. # FDE initial location - .set L$set$31,LFE4-LFB4 - .quad L$set$31 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32,LCFI23-LFB4 - .long L$set$32 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x30 # uleb128 0x30 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x2 # uleb128 0x2 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x3 # uleb128 0x3 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 3 -LEFDE21: - - -.globl _test_rbx_r12_r13_r14_r15.eh -_test_rbx_r12_r13_r14_r15.eh: -LSFDE23: - .set L$set$33,LEFDE23-LASFDE23 - .long L$set$33 # FDE Length -LASFDE23: - .long LASFDE23-EH_frame1 # FDE CIE offset - .quad LFB3-. # FDE initial location - .set L$set$34,LFE3-LFB3 - .quad L$set$34 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$35,LCFI29-LFB3 - .long L$set$35 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x30 # uleb128 0x30 - .byte 0x8f # DW_CFA_offset, column 0xf - .byte 0x2 # uleb128 0x2 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x3 # uleb128 0x3 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x4 # uleb128 0x4 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x5 # uleb128 0x5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x6 # uleb128 0x6 - .align 3 -LEFDE23: - - -.globl _test_rbx_rbp_r12_r13_r14_r15.eh -_test_rbx_rbp_r12_r13_r14_r15.eh: -LSFDE25: - .set L$set$36,LEFDE25-LASFDE25 - .long L$set$36 # FDE Length -LASFDE25: - .long LASFDE25-EH_frame1 # FDE CIE offset - .quad LFB2-. # FDE initial location - .set L$set$37,LFE2-LFB2 - .quad L$set$37 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$38,LCFI36-LFB2 - .long L$set$38 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x50 # uleb128 0x50 - .byte 0x8f # DW_CFA_offset, column 0xf - .byte 0x2 # uleb128 0x2 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x3 # uleb128 0x3 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x4 # uleb128 0x4 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x5 # uleb128 0x5 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x6 # uleb128 0x6 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x7 # uleb128 0x7 - .align 3 -LEFDE25: - - -.globl _test_rbx_rbp_r12.eh -_test_rbx_rbp_r12.eh: -LSFDE11: - .set L$set$24a,LEFDE11-LASFDE11 - .long L$set$24a # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .quad LFB11-. # FDE initial location - .set L$set$25a,LFE11-LFB11 - .quad L$set$25a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$26a,LCFI11a-LFB11 - .long L$set$26a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 3 -LEFDE11: - - -.globl _test_rbx_rbp_r12_r13.eh -_test_rbx_rbp_r12_r13.eh: - .set L$set$30a,LEFDE457-LASFDE457 - .long L$set$30a # FDE Length -LASFDE457: - .long LASFDE457-EH_frame1 # FDE CIE offset - .quad LFB457-. # FDE initial location - .set L$set$31a,LFE457-LFB457 - .quad L$set$31a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32a,LCFI23-LFB4 - .long L$set$32a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x30 # uleb128 0x30 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x2 # uleb128 0x2 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 3 -LEFDE457: - - -.globl _test_rbx_rbp_r12_r13_r14.eh -_test_rbx_rbp_r12_r13_r14.eh: - .set L$set$33a,LEFDE117-LASFDE117 - .long L$set$33a # FDE Length -LASFDE117: - .long LASFDE117-EH_frame1 # FDE CIE offset - .quad LFB17-. # FDE initial location - .set L$set$34a,LFE17-LFB17 - .quad L$set$34a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$35a,LCFI29-LFB3 - .long L$set$35a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x30 # uleb128 0x30 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x2 # uleb128 0x2 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x3 # uleb128 0x3 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x4 # uleb128 0x4 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x5 # uleb128 0x5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x6 # uleb128 0x6 - .align 3 -LEFDE117: - - - - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_64_frameless_big.s b/libunwind/testsuite/unwind_test_x86_64_frameless_big.s deleted file mode 100644 index e39278f..0000000 --- a/libunwind/testsuite/unwind_test_x86_64_frameless_big.s +++ /dev/null @@ -1,598 +0,0 @@ - - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -Wl,-no_compact_unwind - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .quad _test_no_reg - .quad _test_rbx - .quad _test_rbx_r12 - .quad _test_rbx_r12_r13 - .quad _test_rbx_r12_r13_r14 - .quad _test_rbx_r12_r13_r14_r15 - .quad _test_rbx_rbp - .quad _test_rbx_rbp_r12 - .quad _test_rbx_rbp_r12_r13 - .quad _test_rbx_rbp_r12_r13_r14 - .quad _test_rbx_rbp_r12_r13_r14_r15 - .quad 0 - - - .text - - -.globl _test_no_reg -_test_no_reg: -LFB13: - subq $160008, %rsp -LCFI0: - call _uwind_to_main - addq $160008, %rsp - ret -LFE13: - - - -.globl _test_rbx -_test_rbx: -LFB10: - pushq %rbx -LCFI3: - subq $160000, %rsp -LCFI4: - movq $0, %rbx - call _uwind_to_main - addq $160000, %rsp - popq %rbx - ret -LFE10: - - -.globl _test_rbx_r12 -_test_rbx_r12: -LFB8: - movq %rbx, -16(%rsp) -LCFI7: - movq %r12, -8(%rsp) -LCFI8: - subq $160024, %rsp -LCFI9: - movq $0, %rbx - movq $0, %r12 - call _uwind_to_main - movq 160008(%rsp), %rbx - movq 160016(%rsp), %r12 - addq $160024, %rsp - ret -LFE8: - - -.globl _test_rbx_rbp -_test_rbx_rbp: -LFB7: - movq %rbx, -16(%rsp) -LCFI10: - movq %rbp, -8(%rsp) -LCFI11: - subq $160024, %rsp -LCFI12: - movq $0, %rbp - movq $0, %rbx - call _uwind_to_main - movq 160008(%rsp), %rbx - movq 160016(%rsp), %rbp - addq $160024, %rsp - ret -LFE7: - - -.globl _test_rbx_r12_r13 -_test_rbx_r12_r13: -LFB6: - movq %rbx, -24(%rsp) -LCFI13: - movq %r12, -16(%rsp) -LCFI14: - movq %r13, -8(%rsp) -LCFI15: - subq $160024, %rsp -LCFI16: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - call _uwind_to_main - movq 160000(%rsp), %rbx - movq 160008(%rsp), %r12 - movq 160016(%rsp), %r13 - addq $160024, %rsp - ret -LFE6: - - -.globl _test_rbx_rbp_r12 -_test_rbx_rbp_r12: -LFB9: - movq %rbx, -24(%rsp) - movq %rbp, -16(%rsp) - movq %r12, -8(%rsp) - subq $160024, %rsp -LCFI9a: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - call _uwind_to_main - movq 160000(%rsp), %rbx - movq 160008(%rsp), %rbp - movq 160016(%rsp), %r12 - addq $160024, %rsp - ret -LFE9: - - - - -.globl _test_rbx_r12_r13_r14 -_test_rbx_r12_r13_r14: -LFB4: - movq %rbx, -32(%rsp) -LCFI21: - movq %r12, -24(%rsp) -LCFI22: - movq %r13, -16(%rsp) -LCFI23: - movq %r14, -8(%rsp) -LCFI24: - subq $160040, %rsp -LCFI25: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq 160008(%rsp), %rbx - movq 160016(%rsp), %r12 - movq 160024(%rsp), %r13 - movq 160032(%rsp), %r14 - addq $160040, %rsp - ret -LFE4: - - -.globl _test_rbx_r12_r13_r14_r15 -_test_rbx_r12_r13_r14_r15: -LFB3: - movq %rbx, -40(%rsp) -LCFI26: - movq %r12, -32(%rsp) -LCFI27: - movq %r13, -24(%rsp) -LCFI28: - movq %r14, -16(%rsp) -LCFI29: - movq %r15, -8(%rsp) -LCFI30: - subq $160040, %rsp -LCFI31: - movq $0, %rbx - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - movq $0, %r15 - call _uwind_to_main - movq 160000(%rsp), %rbx - movq 160008(%rsp), %r12 - movq 160016(%rsp), %r13 - movq 160024(%rsp), %r14 - movq 160032(%rsp), %r15 - addq $160040, %rsp - ret -LFE3: - - -.globl _test_rbx_rbp_r12_r13_r14_r15 -_test_rbx_rbp_r12_r13_r14_r15: -LFB2: - movq %rbx, -48(%rsp) -LCFI32: - movq %rbp, -40(%rsp) -LCFI33: - movq %r12, -32(%rsp) -LCFI34: - movq %r13, -24(%rsp) -LCFI35: - movq %r14, -16(%rsp) -LCFI36: - movq %r15, -8(%rsp) -LCFI37: - subq $160072, %rsp -LCFI38: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - movq $0, %r15 - call _uwind_to_main - movq 160024(%rsp), %rbx - movq 160032(%rsp), %rbp - movq 160040(%rsp), %r12 - movq 160048(%rsp), %r13 - movq 160056(%rsp), %r14 - movq 160064(%rsp), %r15 - addq $160072, %rsp - ret -LFE2: - - -.globl _test_rbx_rbp_r12_r13 -_test_rbx_rbp_r12_r13: -LFB457: - movq %rbx, -32(%rsp) -LCFI18: - movq %rbp, -24(%rsp) -LCFI19: - movq %r12, -16(%rsp) - movq %r13, -8(%rsp) - subq $160040, %rsp -LCFI20: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - movq $0, %r13 - call _uwind_to_main - movq 160008(%rsp), %rbx - movq 160016(%rsp), %rbp - movq 160024(%rsp), %r12 - movq 160032(%rsp), %r13 - addq $160040, %rsp - ret -LFE457: - - -.globl _test_rbx_rbp_r12_r13_r14 -_test_rbx_rbp_r12_r13_r14: -LFB17: - movq %rbx, -40(%rsp) - movq %rbp, -32(%rsp) - movq %r12, -24(%rsp) - movq %r13, -16(%rsp) - movq %r14, -8(%rsp) - subq $160040, %rsp -LFB17a: - movq $0, %rbx - movq $0, %rbp - movq $0, %r12 - movq $0, %r13 - movq $0, %r14 - call _uwind_to_main - movq 160000(%rsp), %rbx - movq 160008(%rsp), %rbp - movq 160016(%rsp), %r12 - movq 160024(%rsp), %r13 - movq 160032(%rsp), %r14 - addq $160040, %rsp - ret -LFE17: - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x78 # sleb128 -8; CIE Data Alignment Factor - .byte 0x10 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x7 # uleb128 0x7 - .byte 0x8 # uleb128 0x8 - .byte 0x90 # DW_CFA_offset, column 0x10 - .byte 0x1 # uleb128 0x1 - .align 3 -LECIE1: - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE3: - .set L$set$3,LEFDE3-LASFDE3 - .long L$set$3 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .quad LFB13-. # FDE initial location - .set L$set$4,LFE13-LFB13 - .quad L$set$4 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$5,LCFI0-LFB13 - .long L$set$5 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x90,0xe2,0x9 # uleb128 0x27110 - .align 3 -LEFDE3: - - -.globl _test_rbx.eh -_test_rbx.eh: -LSFDE9: - .set L$set$12,LEFDE9-LASFDE9 - .long L$set$12 # FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 # FDE CIE offset - .quad LFB10-. # FDE initial location - .set L$set$13,LFE10-LFB10 - .quad L$set$13 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14,LCFI3-LFB10 - .long L$set$14 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x10 # uleb128 0x10 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$15,LCFI4-LCFI3 - .long L$set$15 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x90,0xe2,0x9 # uleb128 0x27110 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x2 # uleb128 0x2 - .align 3 -LEFDE9: - - -.globl _test_rbx_r12.eh -_test_rbx_r12.eh: -LSFDE13: - .set L$set$20,LEFDE13-LASFDE13 - .long L$set$20 # FDE Length -LASFDE13: - .long LASFDE13-EH_frame1 # FDE CIE offset - .quad LFB8-. # FDE initial location - .set L$set$21,LFE8-LFB8 - .quad L$set$21 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22,LCFI9-LFB8 - .long L$set$22 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xe2,0x9 # uleb128 0x27120 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 3 -LEFDE13: - - -.globl _test_rbx_rbp.eh -_test_rbx_rbp.eh: -LSFDE14: - .set L$set$23,LEFDE14-LASFDE14 - .long L$set$23 # FDE Length -LASFDE14: - .long LASFDE14-EH_frame1 # FDE CIE offset - .quad LFB7-. # FDE initial location - .set L$set$24,LFE7-LFB7 - .quad L$set$24 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$25,LCFI12-LFB7 - .long L$set$25 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xe2,0x9 # uleb128 0x27120 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 3 -LEFDE14: - - -.globl _test_rbx_r12_r13.eh -_test_rbx_r12_r13.eh: -LSFDE17: - .set L$set$26,LEFDE17-LASFDE17 - .long L$set$26 # FDE Length -LASFDE17: - .long LASFDE17-EH_frame1 # FDE CIE offset - .quad LFB6-. # FDE initial location - .set L$set$27,LFE6-LFB6 - .quad L$set$27 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$28,LCFI16-LFB6 - .long L$set$28 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xe2,0x9 # uleb128 0x27120 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x2 # uleb128 0x2 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 3 -LEFDE17: - - - -.globl _test_rbx_r12_r13_r14.eh -_test_rbx_r12_r13_r14.eh: -LSFDE21: - .set L$set$32,LEFDE21-LASFDE21 - .long L$set$32 # FDE Length -LASFDE21: - .long LASFDE21-EH_frame1 # FDE CIE offset - .quad LFB4-. # FDE initial location - .set L$set$33,LFE4-LFB4 - .quad L$set$33 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34,LCFI25-LFB4 - .long L$set$34 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xb0,0xe2,0x9 # uleb128 0x27130 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x2 # uleb128 0x2 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x3 # uleb128 0x3 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 3 -LEFDE21: - - -.globl _test_rbx_r12_r13_r14_r15.eh -_test_rbx_r12_r13_r14_r15.eh: -LSFDE23: - .set L$set$35,LEFDE23-LASFDE23 - .long L$set$35 # FDE Length -LASFDE23: - .long LASFDE23-EH_frame1 # FDE CIE offset - .quad LFB3-. # FDE initial location - .set L$set$36,LFE3-LFB3 - .quad L$set$36 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$37,LCFI31-LFB3 - .long L$set$37 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xb0,0xe2,0x9 # uleb128 0x27130 - .byte 0x8f # DW_CFA_offset, column 0xf - .byte 0x2 # uleb128 0x2 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x3 # uleb128 0x3 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x4 # uleb128 0x4 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x5 # uleb128 0x5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x6 # uleb128 0x6 - .align 3 -LEFDE23: - - -.globl _test_rbx_rbp_r12_r13_r14_r15.eh -_test_rbx_rbp_r12_r13_r14_r15.eh: -LSFDE25: - .set L$set$38,LEFDE25-LASFDE25 - .long L$set$38 # FDE Length -LASFDE25: - .long LASFDE25-EH_frame1 # FDE CIE offset - .quad LFB2-. # FDE initial location - .set L$set$39,LFE2-LFB2 - .quad L$set$39 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$40,LCFI38-LFB2 - .long L$set$40 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xd0,0xe2,0x9 # uleb128 0x27150 - .byte 0x8f # DW_CFA_offset, column 0xf - .byte 0x2 # uleb128 0x2 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x3 # uleb128 0x3 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x4 # uleb128 0x4 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x5 # uleb128 0x5 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x6 # uleb128 0x6 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x7 # uleb128 0x7 - .align 3 -LEFDE25: - - -.globl _test_rbx_rbp_r12_r13.eh -_test_rbx_rbp_r12_r13.eh: -LSFDE11: - .set L$set$17a,LEFDE11-LASFDE11 - .long L$set$17a # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .quad LFB457-. # FDE initial location - .set L$set$18a,LFE457-LFB457 - .quad L$set$18a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19a,LCFI20-LFB457 - .long L$set$19a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xb0,0xe2,0x9 # uleb128 0x27130 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x2 # uleb128 0x2 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 3 -LEFDE11: - - -.globl _test_rbx_rbp_r12_r13_r14.eh -_test_rbx_rbp_r12_r13_r14.eh: -LSFDE7: - .set L$set$35a,LEFDE7-LASFDE7 - .long L$set$35a # FDE Length -LASFDE7: - .long LASFDE7-EH_frame1 # FDE CIE offset - .quad LFB17-. # FDE initial location - .set L$set$36a,LFE17-LFB17 - .quad L$set$36a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$37a,LFB17a-LFB17 - .long L$set$37a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xb0,0xe2,0x9 # uleb128 0x27130 - .byte 0x8e # DW_CFA_offset, column 0xe - .byte 0x2 # uleb128 0x2 - .byte 0x8d # DW_CFA_offset, column 0xd - .byte 0x3 # uleb128 0x3 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x4 # uleb128 0x4 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x5 # uleb128 0x5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x6 # uleb128 0x6 - .align 3 -LEFDE7: - - -.globl _test_rbx_rbp_r12.eh -_test_rbx_rbp_r12.eh: -LSFDE19: - .set L$set$26a,LEFDE19-LASFDE19 - .long L$set$26a # FDE Length -LASFDE19: - .long LASFDE19-EH_frame1 # FDE CIE offset - .quad LFB9-. # FDE initial location - .set L$set$27a,LFE9-LFB9 - .quad L$set$27a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$28a,LCFI9a-LFB9 - .long L$set$28a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xe2,0x9 # uleb128 0x27120 - .byte 0x8c # DW_CFA_offset, column 0xc - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 3 -LEFDE19: - - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_64_unusual.s b/libunwind/testsuite/unwind_test_x86_64_unusual.s deleted file mode 100644 index 6847146..0000000 --- a/libunwind/testsuite/unwind_test_x86_64_unusual.s +++ /dev/null @@ -1,311 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -Wl,-no_compact_unwind - - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .quad _test_no_reg - .quad Ltest_rbx - .quad _test_rbx_pad_r12 - .quad _test_rbx_same_value - .quad _test_rbx_same_register - .quad 0 - - - .text - - -.globl _test_big_frameless_stack_odd_dwarf -_test_big_frameless_stack_odd_dwarf: -L100: - subq $160016, %rsp -L102: - movq $0, %rbx - call _uwind_to_main - addq $160016, %rsp - ret -L103: - - -LFE14: -.globl _test_no_reg -_test_no_reg: -LFB13: - pushq %rbp -LCFI2: - movq %rsp, %rbp -LCFI3: - call _uwind_to_main - leave - ret -LFE13: - - -Ltest_rbx: -LFB10: - pushq %rbp -LCFI8: - movq %rsp, %rbp -LCFI9: - pushq %rbx -LCFI10: - subq $8, %rsp -LCFI11: - movq $0, %rbx - call _uwind_to_main - addq $8, %rsp - popq %rbx - leave - ret -LFE10: - - -.globl _test_rbx_pad_r12 -_test_rbx_pad_r12: -LFB8: - pushq %rbp -LCFI16: - movq %rsp, %rbp -LCFI17: - movq %rbx, -56(%rbp) -LCFI18: - movq %r12, -8(%rbp) -LCFI19: - subq $64, %rsp -LCFI20: - movq $0, %rbx - movq $0, %r12 - call _uwind_to_main - movq (%rsp), %rbx - movq 8(%rsp), %r12 - leave - ret -LFE8: - - -.globl _test_rbx_same_value -_test_rbx_same_value: -LFB10b: - jmp L33 - pushq %rbx -LCFI3b: - movq $0, %rbx - call _uwind_to_main - popq %rbx - ret -L33: - pushq $0 - call _uwind_to_main - popq %rax - ret -LFE10b: - - -.globl _test_rbx_same_register -_test_rbx_same_register: -LFB10c: - jmp L34 - pushq %rbx -LCFI3c: - movq $0, %rbx - call _uwind_to_main - popq %rbx - ret -L34: - pushq $0 - call _uwind_to_main - popq %rax - ret -LFE10c: - - - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 -LSCIE1: - .long 0x0 - .byte 0x1 - .ascii "zR\0" - .byte 0x1 - .byte 0x78 - .byte 0x10 - .byte 0x1 - .byte 0x10 - .byte 0xc - .byte 0x7 - .byte 0x8 - .byte 0x90 - .byte 0x1 - .align 3 -LECIE1: - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE3: - .set L$set$5,LEFDE3-LASFDE3 - .long L$set$5 -LASFDE3: - .long LASFDE3-EH_frame1 - .quad LFB13-. - .set L$set$6,LFE13-LFB13 - .quad L$set$6 - .byte 0x0 - .byte 0x4 - .set L$set$7,LCFI2-LFB13 - .long L$set$7 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$8,LCFI3-LCFI2 - .long L$set$8 - .byte 0xd - .byte 0x6 - .align 3 -LEFDE3: - -Ltest_rbx.eh: -LSFDE9: - .set L$set$17,LEFDE9-LASFDE9 - .long L$set$17 -LASFDE9: - .long LASFDE9-EH_frame1 - .quad LFB10-. - .set L$set$18,LFE10-LFB10 - .quad L$set$18 - .byte 0x0 - .byte 0x4 - .set L$set$19,LCFI8-LFB10 - .long L$set$19 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$20,LCFI9-LCFI8 - .long L$set$20 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$21,LCFI11-LCFI9 - .long L$set$21 - .byte 0x83 - .byte 0x3 - .align 3 -LEFDE9: - -.globl _test_rbx_pad_r12.eh -_test_rbx_pad_r12.eh: -LSFDE13: - .set L$set$27,LEFDE13-LASFDE13 - .long L$set$27 -LASFDE13: - .long LASFDE13-EH_frame1 - .quad LFB8-. - .set L$set$28,LFE8-LFB8 - .quad L$set$28 - .byte 0x0 - .byte 0x4 - .set L$set$29,LCFI16-LFB8 - .long L$set$29 - .byte 0xe - .byte 0x10 - .byte 0x86 - .byte 0x2 - .byte 0x4 - .set L$set$30,LCFI17-LCFI16 - .long L$set$30 - .byte 0xd - .byte 0x6 - .byte 0x4 - .set L$set$31,LCFI20-LCFI17 - .long L$set$31 - .byte 0x8c - .byte 0x3 - .byte 0x83 - .byte 0x9 - .align 3 -LEFDE13: - - - -.globl _test_big_frameless_stack_odd_dwarf.eh -_test_big_frameless_stack_odd_dwarf.eh: - .set L$set$12a,LEFDE9a-LASFDE9a - .long L$set$12a # FDE Length -LASFDE9a: - .long LASFDE9a-EH_frame1 # FDE CIE offset - .quad L100-. # FDE initial location - .set L$set$13a,L103-L100 - .quad L$set$13a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .long 7 - .byte 0xc # DW_CFA_def_cfa - .byte 0x07 # uleb128 7 - .byte 0x90,0xe2,0x9 # uleb128 0x27110 - .align 3 -LEFDE9a: - - -.globl _test_rbx_same_value.eh -_test_rbx_same_value.eh: -LSFDE9b: - .set L$set$12,LEFDE9b-LASFDE9b - .long L$set$12 # FDE Length -LASFDE9b: - .long LASFDE9b-EH_frame1 # FDE CIE offset - .quad LFB10b-. # FDE initial location - .set L$set$13,LFE10b-LFB10b - .quad L$set$13 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14,LCFI3b-LFB10b - .long L$set$14 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x10 # uleb128 0x10 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$15,L33-LCFI3b - .long L$set$15 - .byte 0x08 # DW_CFA_same_value - .byte 0x3 # uleb128 0x3 - .align 3 -LEFDE9b: - - -.globl _test_rbx_same_register.eh -_test_rbx_same_register.eh: -LSFDE9c: - .set L$set$12c,LEFDE9c-LASFDE9c - .long L$set$12c # FDE Length -LASFDE9c: - .long LASFDE9c-EH_frame1 # FDE CIE offset - .quad LFB10c-. # FDE initial location - .set L$set$16c,LFE10c-LFB10c - .quad L$set$16c # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$17c,LCFI3c-LFB10c - .long L$set$17c - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x10 # uleb128 0x10 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18c,L34-LCFI3c - .long L$set$18c - .byte 0x09 # DW_CFA_register - .byte 0x3 # uleb128 0x3 - .byte 0x3 # uleb128 0x3 - .align 3 -LEFDE9c: - - diff --git a/libunwind/testsuite/unwind_test_x86_disable_compact_frame.s b/libunwind/testsuite/unwind_test_x86_disable_compact_frame.s deleted file mode 100644 index 2d76631..0000000 --- a/libunwind/testsuite/unwind_test_x86_disable_compact_frame.s +++ /dev/null @@ -1,589 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .long _test_no_reg - .long _test_ebx - .long _test_esi - .long _test_edi - .long _test_ebx_esi - .long _test_esi_edi - .long _test_ebx_edi - .long _test_ebx_esi_edi - .long _test_edi_esi_ebx - .long _test_pad_ebx_edi - .long 0 - - - .text - -.globl _test_ebx -_test_ebx: -LFB13: - pushl %ebp -LCFI2: - movl %esp, %ebp -LCFI3: - pushl %ebx -LCFI4: - subl $20, %esp -LCFI5: - movl $0, %ebx - call _uwind_to_main - addl $20, %esp - popl %ebx - leave - ret -LFE13: - -.globl _test_no_reg -_test_no_reg: -LFB12: - pushl %ebp -LCFI6: - movl %esp, %ebp -LCFI7: - subl $24, %esp -LCFI8: - call _uwind_to_main - leave - ret -LFE12: - -.globl _test_esi -_test_esi: -LFB10: - pushl %ebp -LCFI13: - movl %esp, %ebp -LCFI14: - pushl %esi -LCFI15: - subl $20, %esp -LCFI16: - movl $0, %esi - call _uwind_to_main - addl $20, %esp - popl %esi - leave - ret -LFE10: - -.globl _test_edi -_test_edi: -LFB11: - pushl %ebp -LCFI9: - movl %esp, %ebp -LCFI10: - pushl %edi -LCFI11: - subl $20, %esp -LCFI12: - movl $0, %edi - call _uwind_to_main - addl $20, %esp - popl %edi - leave - ret -LFE11: - -.globl _test_ebx_esi -_test_ebx_esi: -LFB9: - pushl %ebp -LCFI17: - movl %esp, %ebp -LCFI18: - subl $24, %esp -LCFI19: - movl %ebx, -8(%ebp) -LCFI20: - movl %esi, -4(%ebp) -LCFI21: - movl $0, %ebx - movl $0, %esi - call _uwind_to_main - movl -8(%ebp), %ebx - movl -4(%ebp), %esi - leave - ret -LFE9: - - -.globl _test_esi_edi -_test_esi_edi: -LFB8: - pushl %ebp -LCFI22: - movl %esp, %ebp -LCFI23: - subl $24, %esp -LCFI24: - movl %esi, -8(%ebp) -LCFI25: - movl %edi, -4(%ebp) -LCFI26: - movl $0, %edi - movl $0, %esi - call _uwind_to_main - movl -8(%ebp), %esi - movl -4(%ebp), %edi - leave - ret -LFE8: - -.globl _test_ebx_edi -_test_ebx_edi: -LFB91: - pushl %ebp -LCFI171: - movl %esp, %ebp -LCFI181: - subl $24, %esp -LCFI191: - movl %ebx, -8(%ebp) -LCFI201: - movl %edi, -4(%ebp) -LCFI211: - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl -8(%ebp), %ebx - movl -4(%ebp), %edi - leave - ret -LFE91: - -.globl _test_ebx_esi_edi -_test_ebx_esi_edi: -LFB7: - pushl %ebp -LCFI27: - movl %esp, %ebp -LCFI28: - subl $40, %esp -LCFI29: - movl %ebx, -12(%ebp) -LCFI30: - movl %esi, -8(%ebp) -LCFI31: - movl %edi, -4(%ebp) -LCFI32: - movl $0, %ebx - movl $0, %edi - movl $0, %esi - call _uwind_to_main - movl -12(%ebp), %ebx - movl -8(%ebp), %esi - movl -4(%ebp), %edi - leave - ret -LFE7: - - -.globl _test_edi_esi_ebx -_test_edi_esi_ebx: -LFB7a: - pushl %ebp -LCFI27a: - movl %esp, %ebp -LCFI28a: - subl $40, %esp -LCFI29a: - movl %edi, -12(%ebp) -LCFI30a: - movl %esi, -8(%ebp) -LCFI31a: - movl %ebx, -4(%ebp) -LCFI32a: - movl $0, %ebx - movl $0, %esi - movl $0, %edi - call _uwind_to_main - movl -12(%ebp), %edi - movl -8(%ebp), %esi - movl -4(%ebp), %ebx - leave - ret -LFE7a: - - - -.globl _test_pad_ebx_edi -_test_pad_ebx_edi: -LFB91a: - pushl %ebp -LCFI171a: - movl %esp, %ebp -LCFI181a: - subl $88, %esp -LCFI191a: - movl %ebx, -72(%ebp) -LCFI201a: - movl %edi, -68(%ebp) -LCFI211a: - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl -72(%ebp), %ebx - movl -68(%ebp), %edi - leave - ret -LFE91a: - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c # sleb128 -4; CIE Data Alignment Factor - .byte 0x8 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x5 # uleb128 0x5 - .byte 0x4 # uleb128 0x4 - .byte 0x88 # DW_CFA_offset, column 0x8 - .byte 0x1 # uleb128 0x1 - .byte 0x88 # DW_CFA_offset, column 0x8 // duplicate save in CIE means disable compact unwind encoding - .byte 0x1 # uleb128 0x1 - .align 2 -LECIE1: - - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE5: - .set L$set$6,LEFDE5-LASFDE5 - .long L$set$6 # FDE Length -LASFDE5: - .long LASFDE5-EH_frame1 # FDE CIE offset - .long LFB12-. # FDE initial location - .set L$set$7,LFE12-LFB12 - .long L$set$7 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$8,LCFI6-LFB12 - .long L$set$8 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$9,LCFI7-LCFI6 - .long L$set$9 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE5: - - -.globl _test_ebx.eh -_test_ebx.eh: -LSFDE3: - .set L$set$1,LEFDE3-LASFDE3 - .long L$set$1 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .long LFB13-. # FDE initial location - .set L$set$2,LFE13-LFB13 - .long L$set$2 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$3,LCFI2-LFB13 - .long L$set$3 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$4,LCFI3-LCFI2 - .long L$set$4 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$5,LCFI5-LCFI3 - .long L$set$5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE3: - - -.globl _test_esi.eh -_test_esi.eh: -LSFDE9: - .set L$set$15,LEFDE9-LASFDE9 - .long L$set$15 # FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 # FDE CIE offset - .long LFB10-. # FDE initial location - .set L$set$16,LFE10-LFB10 - .long L$set$16 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$17,LCFI13-LFB10 - .long L$set$17 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18,LCFI14-LCFI13 - .long L$set$18 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19,LCFI16-LCFI14 - .long L$set$19 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE9: - - -.globl _test_edi.eh -_test_edi.eh: -LSFDE10: - .set L$set$15a,LEFDE10-LASFDE10 - .long L$set$15a # FDE Length -LASFDE10: - .long LASFDE10-EH_frame1 # FDE CIE offset - .long LFB11-. # FDE initial location - .set L$set$16a,LFE11-LFB11 - .long L$set$16a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$17a,LCFI9-LFB11 - .long L$set$17a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18a,LCFI10-LCFI9 - .long L$set$18a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19a,LCFI12-LCFI10 - .long L$set$19a - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE10: - -.globl _test_ebx_esi.eh -_test_ebx_esi.eh: -LSFDE11: - .set L$set$20,LEFDE11-LASFDE11 - .long L$set$20 # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .long LFB9-. # FDE initial location - .set L$set$21,LFE9-LFB9 - .long L$set$21 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22,LCFI17-LFB9 - .long L$set$22 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23,LCFI18-LCFI17 - .long L$set$23 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24,LCFI21-LCFI18 - .long L$set$24 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE11: - -.globl _test_esi_edi.eh -_test_esi_edi.eh: -LSFDE13: - .set L$set$25,LEFDE13-LASFDE13 - .long L$set$25 # FDE Length -LASFDE13: - .long LASFDE13-EH_frame1 # FDE CIE offset - .long LFB8-. # FDE initial location - .set L$set$26,LFE8-LFB8 - .long L$set$26 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$27,LCFI22-LFB8 - .long L$set$27 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$28,LCFI23-LCFI22 - .long L$set$28 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$29,LCFI26-LCFI23 - .long L$set$29 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE13: - -.globl _test_ebx_edi.eh -_test_ebx_edi.eh: -LSFDE111: - .set L$set$20a,LEFDE11-LASFDE11 - .long L$set$20a # FDE Length -LASFDE111: - .long LASFDE111-EH_frame1 # FDE CIE offset - .long LFB91-. # FDE initial location - .set L$set$21a,LFE91-LFB91 - .long L$set$21a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22a,LCFI171-LFB91 - .long L$set$22a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23a,LCFI181-LCFI171 - .long L$set$23a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24a,LCFI211-LCFI181 - .long L$set$24a - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE111: - -.globl _test_ebx_esi_edi.eh -_test_ebx_esi_edi.eh: -LSFDE15: - .set L$set$30,LEFDE15-LASFDE15 - .long L$set$30 # FDE Length -LASFDE15: - .long LASFDE15-EH_frame1 # FDE CIE offset - .long LFB7-. # FDE initial location - .set L$set$31,LFE7-LFB7 - .long L$set$31 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32,LCFI27-LFB7 - .long L$set$32 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33,LCFI28-LCFI27 - .long L$set$33 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34,LCFI32-LCFI28 - .long L$set$34 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE15: - - -.globl _test_edi_esi_ebx.eh -_test_edi_esi_ebx.eh: -LSFDE15a: - .set L$set$30a,LEFDE15a-LASFDE15a - .long L$set$30a # FDE Length -LASFDE15a: - .long LASFDE15a-EH_frame1 # FDE CIE offset - .long LFB7a-. # FDE initial location - .set L$set$31a,LFE7a-LFB7a - .long L$set$31a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32a,LCFI27a-LFB7a - .long L$set$32a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33a,LCFI28a-LCFI27a - .long L$set$33a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34a,LCFI32a-LCFI28a - .long L$set$34a - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE15a: - - -.globl _test_pad_ebx_edi.eh -_test_pad_ebx_edi.eh: -LSFDE111a: - .set L$set$20b,LEFDE111a-LASFDE111a - .long L$set$20b # FDE Length -LASFDE111a: - .long LASFDE111a-EH_frame1 # FDE CIE offset - .long LFB91a-. # FDE initial location - .set L$set$21b,LFE91a-LFB91a - .long L$set$21b # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22b,LCFI171a-LFB91a - .long L$set$22b - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23b,LCFI181a-LCFI171a - .long L$set$23b - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24b,LCFI211a-LCFI181a - .long L$set$24b - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x13 # uleb128 0x13 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x14 # uleb128 0x14 - .align 2 -LEFDE111a: - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_frame.s b/libunwind/testsuite/unwind_test_x86_frame.s deleted file mode 100644 index b964808..0000000 --- a/libunwind/testsuite/unwind_test_x86_frame.s +++ /dev/null @@ -1,671 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_COMPACT_UNWIND=1 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_EH_FRAME=1 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_COMPACT_UNWIND=1 -DUSE_EH_FRAME=1 -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_EH_FRAME=1 -Wl,-no_compact_unwind - - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .long _test_no_reg - .long _test_ebx - .long _test_esi - .long _test_edi - .long _test_ebx_esi - .long _test_esi_edi - .long _test_ebx_edi - .long _test_ebx_esi_edi - .long _test_edi_esi_ebx - .long _test_pad_ebx_edi - .long 0 - - - .text - -.globl _test_ebx -_test_ebx: -LFB13: - pushl %ebp -LCFI2: - movl %esp, %ebp -LCFI3: - pushl %ebx -LCFI4: - subl $20, %esp -LCFI5: - movl $0, %ebx - call _uwind_to_main - addl $20, %esp - popl %ebx - leave - ret -LFE13: - -.globl _test_no_reg -_test_no_reg: -LFB12: - pushl %ebp -LCFI6: - movl %esp, %ebp -LCFI7: - subl $24, %esp -LCFI8: - call _uwind_to_main - leave - ret -LFE12: - -.globl _test_esi -_test_esi: -LFB10: - pushl %ebp -LCFI13: - movl %esp, %ebp -LCFI14: - pushl %esi -LCFI15: - subl $20, %esp -LCFI16: - movl $0, %esi - call _uwind_to_main - addl $20, %esp - popl %esi - leave - ret -LFE10: - -.globl _test_edi -_test_edi: -LFB11: - pushl %ebp -LCFI9: - movl %esp, %ebp -LCFI10: - pushl %edi -LCFI11: - subl $20, %esp -LCFI12: - movl $0, %edi - call _uwind_to_main - addl $20, %esp - popl %edi - leave - ret -LFE11: - -.globl _test_ebx_esi -_test_ebx_esi: -LFB9: - pushl %ebp -LCFI17: - movl %esp, %ebp -LCFI18: - subl $24, %esp -LCFI19: - movl %ebx, -8(%ebp) -LCFI20: - movl %esi, -4(%ebp) -LCFI21: - movl $0, %ebx - movl $0, %esi - call _uwind_to_main - movl -8(%ebp), %ebx - movl -4(%ebp), %esi - leave - ret -LFE9: - - -.globl _test_esi_edi -_test_esi_edi: -LFB8: - pushl %ebp -LCFI22: - movl %esp, %ebp -LCFI23: - subl $24, %esp -LCFI24: - movl %esi, -8(%ebp) -LCFI25: - movl %edi, -4(%ebp) -LCFI26: - movl $0, %edi - movl $0, %esi - call _uwind_to_main - movl -8(%ebp), %esi - movl -4(%ebp), %edi - leave - ret -LFE8: - -.globl _test_ebx_edi -_test_ebx_edi: -LFB91: - pushl %ebp -LCFI171: - movl %esp, %ebp -LCFI181: - subl $24, %esp -LCFI191: - movl %ebx, -8(%ebp) -LCFI201: - movl %edi, -4(%ebp) -LCFI211: - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl -8(%ebp), %ebx - movl -4(%ebp), %edi - leave - ret -LFE91: - -.globl _test_ebx_esi_edi -_test_ebx_esi_edi: -LFB7: - pushl %ebp -LCFI27: - movl %esp, %ebp -LCFI28: - subl $40, %esp -LCFI29: - movl %ebx, -12(%ebp) -LCFI30: - movl %esi, -8(%ebp) -LCFI31: - movl %edi, -4(%ebp) -LCFI32: - movl $0, %ebx - movl $0, %edi - movl $0, %esi - call _uwind_to_main - movl -12(%ebp), %ebx - movl -8(%ebp), %esi - movl -4(%ebp), %edi - leave - ret -LFE7: - - -.globl _test_edi_esi_ebx -_test_edi_esi_ebx: -LFB7a: - pushl %ebp -LCFI27a: - movl %esp, %ebp -LCFI28a: - subl $40, %esp -LCFI29a: - movl %edi, -12(%ebp) -LCFI30a: - movl %esi, -8(%ebp) -LCFI31a: - movl %ebx, -4(%ebp) -LCFI32a: - movl $0, %ebx - movl $0, %esi - movl $0, %edi - call _uwind_to_main - movl -12(%ebp), %edi - movl -8(%ebp), %esi - movl -4(%ebp), %ebx - leave - ret -LFE7a: - - - -.globl _test_pad_ebx_edi -_test_pad_ebx_edi: -LFB91a: - pushl %ebp -LCFI171a: - movl %esp, %ebp -LCFI181a: - subl $88, %esp -LCFI191a: - movl %ebx, -72(%ebp) -LCFI201a: - movl %edi, -68(%ebp) -LCFI211a: - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl -72(%ebp), %ebx - movl -68(%ebp), %edi - leave - ret -LFE91a: - - -#if USE_EH_FRAME - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c # sleb128 -4; CIE Data Alignment Factor - .byte 0x8 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x5 # uleb128 0x5 - .byte 0x4 # uleb128 0x4 - .byte 0x88 # DW_CFA_offset, column 0x8 - .byte 0x1 # uleb128 0x1 - .align 2 -LECIE1: - - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE5: - .set L$set$6,LEFDE5-LASFDE5 - .long L$set$6 # FDE Length -LASFDE5: - .long LASFDE5-EH_frame1 # FDE CIE offset - .long LFB12-. # FDE initial location - .set L$set$7,LFE12-LFB12 - .long L$set$7 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$8,LCFI6-LFB12 - .long L$set$8 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$9,LCFI7-LCFI6 - .long L$set$9 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE5: - - -.globl _test_ebx.eh -_test_ebx.eh: -LSFDE3: - .set L$set$1,LEFDE3-LASFDE3 - .long L$set$1 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .long LFB13-. # FDE initial location - .set L$set$2,LFE13-LFB13 - .long L$set$2 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$3,LCFI2-LFB13 - .long L$set$3 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$4,LCFI3-LCFI2 - .long L$set$4 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$5,LCFI5-LCFI3 - .long L$set$5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE3: - - -.globl _test_esi.eh -_test_esi.eh: -LSFDE9: - .set L$set$15,LEFDE9-LASFDE9 - .long L$set$15 # FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 # FDE CIE offset - .long LFB10-. # FDE initial location - .set L$set$16,LFE10-LFB10 - .long L$set$16 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$17,LCFI13-LFB10 - .long L$set$17 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18,LCFI14-LCFI13 - .long L$set$18 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19,LCFI16-LCFI14 - .long L$set$19 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE9: - - -.globl _test_edi.eh -_test_edi.eh: -LSFDE10: - .set L$set$15a,LEFDE10-LASFDE10 - .long L$set$15a # FDE Length -LASFDE10: - .long LASFDE10-EH_frame1 # FDE CIE offset - .long LFB11-. # FDE initial location - .set L$set$16a,LFE11-LFB11 - .long L$set$16a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$17a,LCFI9-LFB11 - .long L$set$17a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18a,LCFI10-LCFI9 - .long L$set$18a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19a,LCFI12-LCFI10 - .long L$set$19a - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE10: - -.globl _test_ebx_esi.eh -_test_ebx_esi.eh: -LSFDE11: - .set L$set$20,LEFDE11-LASFDE11 - .long L$set$20 # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .long LFB9-. # FDE initial location - .set L$set$21,LFE9-LFB9 - .long L$set$21 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22,LCFI17-LFB9 - .long L$set$22 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23,LCFI18-LCFI17 - .long L$set$23 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24,LCFI21-LCFI18 - .long L$set$24 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE11: - -.globl _test_esi_edi.eh -_test_esi_edi.eh: -LSFDE13: - .set L$set$25,LEFDE13-LASFDE13 - .long L$set$25 # FDE Length -LASFDE13: - .long LASFDE13-EH_frame1 # FDE CIE offset - .long LFB8-. # FDE initial location - .set L$set$26,LFE8-LFB8 - .long L$set$26 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$27,LCFI22-LFB8 - .long L$set$27 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$28,LCFI23-LCFI22 - .long L$set$28 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$29,LCFI26-LCFI23 - .long L$set$29 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE13: - -.globl _test_ebx_edi.eh -_test_ebx_edi.eh: -LSFDE111: - .set L$set$20a,LEFDE11-LASFDE11 - .long L$set$20a # FDE Length -LASFDE111: - .long LASFDE111-EH_frame1 # FDE CIE offset - .long LFB91-. # FDE initial location - .set L$set$21a,LFE91-LFB91 - .long L$set$21a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22a,LCFI171-LFB91 - .long L$set$22a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23a,LCFI181-LCFI171 - .long L$set$23a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24a,LCFI211-LCFI181 - .long L$set$24a - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE111: - -.globl _test_ebx_esi_edi.eh -_test_ebx_esi_edi.eh: -LSFDE15: - .set L$set$30,LEFDE15-LASFDE15 - .long L$set$30 # FDE Length -LASFDE15: - .long LASFDE15-EH_frame1 # FDE CIE offset - .long LFB7-. # FDE initial location - .set L$set$31,LFE7-LFB7 - .long L$set$31 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32,LCFI27-LFB7 - .long L$set$32 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33,LCFI28-LCFI27 - .long L$set$33 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34,LCFI32-LCFI28 - .long L$set$34 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE15: - - -.globl _test_edi_esi_ebx.eh -_test_edi_esi_ebx.eh: -LSFDE15a: - .set L$set$30a,LEFDE15a-LASFDE15a - .long L$set$30a # FDE Length -LASFDE15a: - .long LASFDE15a-EH_frame1 # FDE CIE offset - .long LFB7a-. # FDE initial location - .set L$set$31a,LFE7a-LFB7a - .long L$set$31a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32a,LCFI27a-LFB7a - .long L$set$32a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33a,LCFI28a-LCFI27a - .long L$set$33a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34a,LCFI32a-LCFI28a - .long L$set$34a - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE15a: - - -.globl _test_pad_ebx_edi.eh -_test_pad_ebx_edi.eh: -LSFDE111a: - .set L$set$20b,LEFDE111a-LASFDE111a - .long L$set$20b # FDE Length -LASFDE111a: - .long LASFDE111a-EH_frame1 # FDE CIE offset - .long LFB91a-. # FDE initial location - .set L$set$21b,LFE91a-LFB91a - .long L$set$21b # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22b,LCFI171a-LFB91a - .long L$set$22b - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23b,LCFI181a-LCFI171a - .long L$set$23b - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24b,LCFI211a-LCFI181a - .long L$set$24b - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x13 # uleb128 0x13 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x14 # uleb128 0x14 - .align 2 -LEFDE111a: -#endif // USE_EH_FRAME - - - -#if USE_COMPACT_UNWIND - - .section __LD,__compact_unwind,regular,debug - - .long _test_no_reg - .set L101,LFE13-_test_no_reg - .long L101 - .long 0x01000000 - .long 0 - .long 0 - - .long _test_ebx - .set L102,LFE13-_test_ebx - .long L102 - .long 0x01010001 - .long 0 - .long 0 - - .long _test_esi - .set L103,LFE10-_test_esi - .long L103 - .long 0x01010005 - .long 0 - .long 0 - - .long _test_edi - .set L104,LFE11-_test_edi - .long L104 - .long 0x01010004 - .long 0 - .long 0 - - .long _test_ebx_esi - .set L105,LFE9-_test_ebx_esi - .long L105 - .long 0x01020029 - .long 0 - .long 0 - - .long _test_esi_edi - .set L106,LFE8-_test_esi_edi - .long L106 - .long 0x01020025 - .long 0 - .long 0 - - .long _test_ebx_edi - .set L107,LFE91-_test_ebx_edi - .long L107 - .long 0x01020021 - .long 0 - .long 0 - - .long _test_ebx_esi_edi - .set L108,LFE7-_test_ebx_esi_edi - .long L108 - .long 0x01030129 - .long 0 - .long 0 - - .long _test_edi_esi_ebx - .set L109,LFE7a-_test_edi_esi_ebx - .long L109 - .long 0x0103006C - .long 0 - .long 0 - - .long _test_pad_ebx_edi - .set L110,LFE91a-_test_pad_ebx_edi - .long L110 - .long 0x01120021 - .long 0 - .long 0 - -#endif // USE_COMPACT_UNWIND - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_frameless.s b/libunwind/testsuite/unwind_test_x86_frameless.s deleted file mode 100644 index 9e70d6c..0000000 --- a/libunwind/testsuite/unwind_test_x86_frameless.s +++ /dev/null @@ -1,516 +0,0 @@ - - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -Wl,-no_compact_unwind - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .long _test_no_reg - .long _test_ebx - .long _test_esi - .long _test_edi - .long _test_ebx_esi - .long _test_esi_edi - .long _test_esi_edi_ebp - .long _test_ebx_esi_edi - .long _test_ebx_esi_edi_ebp - .long _test_esi_ebp_ebx_edi - .long 0 - - - .text - -.globl _test_ebx -_test_ebx: -LFB13: - pushl %ebx -LCFI0: - subl $24, %esp -LCFI1: - movl $0, %ebx - call _uwind_to_main - addl $24, %esp - popl %ebx - ret -LFE13: - - -.globl _test_no_reg -_test_no_reg: -LFB12: - subl $28, %esp -LCFI2: - call _uwind_to_main - addl $28, %esp - ret -LFE12: - - -.globl _test_esi -_test_esi: -LFB10: - pushl %esi -LCFI5: - subl $24, %esp -LCFI6: - movl $0, %esi - call _uwind_to_main - addl $24, %esp - popl %esi - ret -LFE10: - - -.globl _test_edi -_test_edi: -LFB11: - pushl %edi -LCFI3: - subl $24, %esp -LCFI4: - movl $0, %edi - call _uwind_to_main - addl $24, %esp - popl %edi - ret -LFE11: - - -.globl _test_ebx_esi -_test_ebx_esi: -LFB9: - subl $28, %esp -LCFI7: - movl %ebx, 20(%esp) -LCFI8: - movl %esi, 24(%esp) -LCFI9: - movl $0, %ebx - movl $0, %esi - call _uwind_to_main - movl 20(%esp), %ebx - movl 24(%esp), %esi - addl $28, %esp - ret -LFE9: - - -.globl _test_esi_edi -_test_esi_edi: -LFB8: - subl $28, %esp -LCFI10: - movl %esi, 20(%esp) -LCFI11: - movl %edi, 24(%esp) -LCFI12: - movl $0, %esi - movl $0, %edi - call _uwind_to_main - movl 20(%esp), %esi - movl 24(%esp), %edi - addl $28, %esp - ret -LFE8: - - - -.globl _test_ebx_esi_edi -_test_ebx_esi_edi: -LFB7: - subl $28, %esp -LCFI13: - movl %ebx, 16(%esp) -LCFI14: - movl %esi, 20(%esp) -LCFI15: - movl %edi, 24(%esp) -LCFI16: - movl $0, %ebx - movl $0, %esi - movl $0, %edi - call _uwind_to_main - movl 16(%esp), %ebx - movl 20(%esp), %esi - movl 24(%esp), %edi - addl $28, %esp - ret -LFE7: - - -.globl _test_esi_edi_ebp -_test_esi_edi_ebp: -LFB6: - subl $28, %esp -LCFI17: - movl %esi, 16(%esp) -LCFI18: - movl %edi, 20(%esp) -LCFI19: - movl %ebp, 24(%esp) -LCFI20: - movl $0, %esi - movl $0, %edi - movl $0, %ebp - call _uwind_to_main - movl 16(%esp), %esi - movl 20(%esp), %edi - movl 24(%esp), %ebp - addl $28, %esp - ret -LFE6: - - -.globl _test_ebx_esi_edi_ebp -_test_ebx_esi_edi_ebp: -LFB5: - subl $60, %esp -LCFI21: - movl %ebx, 44(%esp) -LCFI22: - movl %esi, 48(%esp) -LCFI23: - movl %edi, 52(%esp) -LCFI24: - movl %ebp, 56(%esp) -LCFI25: - movl $0, %ebx - movl $0, %esi - movl $0, %edi - movl $0, %ebp - call _uwind_to_main - movl 44(%esp), %ebx - movl 48(%esp), %esi - movl 52(%esp), %edi - movl 56(%esp), %ebp - addl $60, %esp - ret -LFE5: - -.globl _test_esi_ebp_ebx_edi -_test_esi_ebp_ebx_edi: -LFB5a: - subl $60, %esp -LCFI21a: - movl %esi, 44(%esp) -LCFI22a: - movl %ebp, 48(%esp) -LCFI23a: - movl %ebx, 52(%esp) -LCFI24a: - movl %edi, 56(%esp) -LCFI25a: - movl $0, %esi - movl $0, %ebp - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl 44(%esp), %esi - movl 48(%esp), %ebp - movl 52(%esp), %ebx - movl 56(%esp), %edi - addl $60, %esp - ret -LFE5a: - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c # sleb128 -4; CIE Data Alignment Factor - .byte 0x8 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x5 # uleb128 0x5 - .byte 0x4 # uleb128 0x4 - .byte 0x88 # DW_CFA_offset, column 0x8 - .byte 0x1 # uleb128 0x1 - .align 2 -LECIE1: - - -.globl _test_ebx.eh -_test_ebx.eh: -LSFDE3: - .set L$set$1,LEFDE3-LASFDE3 - .long L$set$1 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .long LFB13-. # FDE initial location - .set L$set$2,LFE13-LFB13 - .long L$set$2 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$3,LCFI0-LFB13 - .long L$set$3 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$4,LCFI1-LCFI0 - .long L$set$4 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x2 # uleb128 0x2 - .align 2 -LEFDE3: - - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE5: - .set L$set$5,LEFDE5-LASFDE5 - .long L$set$5 # FDE Length -LASFDE5: - .long LASFDE5-EH_frame1 # FDE CIE offset - .long LFB12-. # FDE initial location - .set L$set$6,LFE12-LFB12 - .long L$set$6 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$7,LCFI2-LFB12 - .long L$set$7 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .align 2 -LEFDE5: - - -.globl _test_esi.eh -_test_esi.eh: -LSFDE9: - .set L$set$12,LEFDE9-LASFDE9 - .long L$set$12 # FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 # FDE CIE offset - .long LFB10-. # FDE initial location - .set L$set$13,LFE10-LFB10 - .long L$set$13 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14,LCFI5-LFB10 - .long L$set$14 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$15,LCFI6-LCFI5 - .long L$set$15 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .align 2 -LEFDE9: - - -.globl _test_edi.eh -_test_edi.eh: -LSFDE10: - .set L$set$12a,LEFDE10-LASFDE10 - .long L$set$12a # FDE Length -LASFDE10: - .long LASFDE10-EH_frame1 # FDE CIE offset - .long LFB11-. # FDE initial location - .set L$set$13a,LFE11-LFB11 - .long L$set$13a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14a,LCFI3-LFB11 - .long L$set$14a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$15a,LCFI4-LCFI3 - .long L$set$15a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .align 2 -LEFDE10: - - - -.globl _test_ebx_esi.eh -_test_ebx_esi.eh: -LSFDE11: - .set L$set$16,LEFDE11-LASFDE11 - .long L$set$16 # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .long LFB9-. # FDE initial location - .set L$set$17,LFE9-LFB9 - .long L$set$17 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18,LCFI7-LFB9 - .long L$set$18 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19,LCFI9-LCFI7 - .long L$set$19 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE11: - - -.globl _test_esi_edi.eh -_test_esi_edi.eh: -LSFDE13: - .set L$set$20,LEFDE13-LASFDE13 - .long L$set$20 # FDE Length -LASFDE13: - .long LASFDE13-EH_frame1 # FDE CIE offset - .long LFB8-. # FDE initial location - .set L$set$21,LFE8-LFB8 - .long L$set$21 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22,LCFI10-LFB8 - .long L$set$22 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23,LCFI12-LCFI10 - .long L$set$23 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE13: - - -.globl _test_ebx_esi_edi.eh -_test_ebx_esi_edi.eh: -LSFDE15: - .set L$set$24,LEFDE15-LASFDE15 - .long L$set$24 # FDE Length -LASFDE15: - .long LASFDE15-EH_frame1 # FDE CIE offset - .long LFB7-. # FDE initial location - .set L$set$25,LFE7-LFB7 - .long L$set$25 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$26,LCFI13-LFB7 - .long L$set$26 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$27,LCFI16-LCFI13 - .long L$set$27 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE15: - - -.globl _test_esi_edi_ebp.eh -_test_esi_edi_ebp.eh: -LSFDE17: - .set L$set$28,LEFDE17-LASFDE17 - .long L$set$28 # FDE Length -LASFDE17: - .long LASFDE17-EH_frame1 # FDE CIE offset - .long LFB6-. # FDE initial location - .set L$set$29,LFE6-LFB6 - .long L$set$29 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$30,LCFI17-LFB6 - .long L$set$30 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x20 # uleb128 0x20 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$31,LCFI20-LCFI17 - .long L$set$31 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE17: - - -.globl _test_ebx_esi_edi_ebp.eh -_test_ebx_esi_edi_ebp.eh: -LSFDE19: - .set L$set$32,LEFDE19-LASFDE19 - .long L$set$32 # FDE Length -LASFDE19: - .long LASFDE19-EH_frame1 # FDE CIE offset - .long LFB5-. # FDE initial location - .set L$set$33,LFE5-LFB5 - .long L$set$33 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34,LCFI21-LFB5 - .long L$set$34 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x40 # uleb128 0x40 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$35,LCFI25-LCFI21 - .long L$set$35 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE19: - -.globl _test_esi_ebp_ebx_edi.eh -_test_esi_ebp_ebx_edi.eh: -LSFDE19a: - .set L$set$32a,LEFDE19a-LASFDE19a - .long L$set$32a # FDE Length -LASFDE19a: - .long LASFDE19a-EH_frame1 # FDE CIE offset - .long LFB5a-. # FDE initial location - .set L$set$33a,LFE5a-LFB5a - .long L$set$33a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34a,LCFI21a-LFB5a - .long L$set$34a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x40 # uleb128 0x40 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$35a,LCFI25a-LCFI21a - .long L$set$35a - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x4 # uleb128 0x4 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE19a: - - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_frameless_big.s b/libunwind/testsuite/unwind_test_x86_frameless_big.s deleted file mode 100644 index 752536e..0000000 --- a/libunwind/testsuite/unwind_test_x86_frameless_big.s +++ /dev/null @@ -1,516 +0,0 @@ - - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -Wl,-no_compact_unwind - - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .long _test_no_reg - .long _test_ebx - .long _test_esi - .long _test_edi - .long _test_ebx_esi - .long _test_esi_edi - .long _test_esi_edi_ebp - .long _test_ebx_esi_edi - .long _test_ebx_esi_ebp - .long _test_ebx_esi_edi_ebp - .long 0 - - - .text - -.globl _test_ebx -_test_ebx: -LFB13: - pushl %ebx -LCFI0: - subl $80024, %esp -LCFI1: - movl $0, %ebx - call _uwind_to_main - addl $80024, %esp - popl %ebx - ret -LFE13: - - -.globl _test_no_reg -_test_no_reg: -LFB12: - subl $80028, %esp -LCFI2: - call _uwind_to_main - addl $80028, %esp - ret -LFE12: - - -.globl _test_esi -_test_esi: -LFB10: - pushl %esi -LCFI5: - subl $80024, %esp -LCFI6: - movl $0, %esi - call _uwind_to_main - addl $80024, %esp - popl %esi - ret -LFE10: - - -.globl _test_edi -_test_edi: -LFB11: - pushl %edi -LCFI3: - subl $80024, %esp -LCFI4: - movl $0, %edi - call _uwind_to_main - addl $80024, %esp - popl %edi - ret -LFE11: - - -.globl _test_ebx_esi -_test_ebx_esi: -LFB9: - nop - subl $80028, %esp -LCFI7: - movl %ebx, 80020(%esp) -LCFI8: - movl %esi, 80024(%esp) -LCFI9: - movl $0, %ebx - movl $0, %esi - call _uwind_to_main - movl 80020(%esp), %ebx - movl 80024(%esp), %esi - addl $80028, %esp - ret -LFE9: - - -.globl _test_esi_edi -_test_esi_edi: -LFB8: - subl $80028, %esp -LCFI10: - movl %esi, 80020(%esp) -LCFI11: - movl %edi, 80024(%esp) -LCFI12: - movl $0, %esi - movl $0, %edi - call _uwind_to_main - movl 80020(%esp), %esi - movl 80024(%esp), %edi - addl $80028, %esp - ret -LFE8: - - - -.globl _test_ebx_esi_edi -_test_ebx_esi_edi: -LFB7: - subl $80028, %esp -LCFI13: - movl %ebx, 80016(%esp) -LCFI14: - movl %esi, 80020(%esp) -LCFI15: - movl %edi, 80024(%esp) -LCFI16: - movl $0, %ebx - movl $0, %esi - movl $0, %edi - call _uwind_to_main - movl 80016(%esp), %ebx - movl 80020(%esp), %esi - movl 80024(%esp), %edi - addl $80028, %esp - ret -LFE7: - - -.globl _test_ebx_esi_ebp -_test_ebx_esi_ebp: -LFB7a: - subl $80028, %esp -LCFI13a: - movl %ebx, 80016(%esp) -LCFI14a: - movl %esi, 80020(%esp) -LCFI15a: - movl %ebp, 80024(%esp) -LCFI16a: - movl $0, %ebx - movl $0, %esi - movl $0, %ebp - call _uwind_to_main - movl 80016(%esp), %ebx - movl 80020(%esp), %esi - movl 80024(%esp), %ebp - addl $80028, %esp - ret -LFE7a: - - - -.globl _test_esi_edi_ebp -_test_esi_edi_ebp: -LFB6: - subl $80028, %esp -LCFI17: - movl %esi, 80016(%esp) -LCFI18: - movl %edi, 80020(%esp) -LCFI19: - movl %ebp, 80024(%esp) -LCFI20: - movl $0, %esi - movl $0, %edi - movl $0, %ebp - call _uwind_to_main - movl 80016(%esp), %esi - movl 80020(%esp), %edi - movl 80024(%esp), %ebp - addl $80028, %esp - ret -LFE6: - - -.globl _test_ebx_esi_edi_ebp -_test_ebx_esi_edi_ebp: -LFB5: - subl $80028, %esp -LCFI21: - movl %ebx, 80012(%esp) -LCFI22: - movl %esi, 80016(%esp) -LCFI23: - movl %edi, 80020(%esp) -LCFI24: - movl %ebp, 80024(%esp) -LCFI25: - movl $0, %ebx - movl $0, %esi - movl $0, %edi - movl $0, %ebp - call _uwind_to_main - movl 80012(%esp), %ebx - movl 80016(%esp), %esi - movl 80020(%esp), %edi - movl 80024(%esp), %ebp - addl $80028, %esp - ret -LFE5: - - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c # sleb128 -4; CIE Data Alignment Factor - .byte 0x8 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x5 # uleb128 0x5 - .byte 0x4 # uleb128 0x4 - .byte 0x88 # DW_CFA_offset, column 0x8 - .byte 0x1 # uleb128 0x1 - .align 2 -LECIE1: - - -.globl _test_ebx.eh -_test_ebx.eh: -LSFDE3: - .set L$set$1,LEFDE3-LASFDE3 - .long L$set$1 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .long LFB13-. # FDE initial location - .set L$set$2,LFE13-LFB13 - .long L$set$2 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$3,LCFI0-LFB13 - .long L$set$3 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$4,LCFI1-LCFI0 - .long L$set$4 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x2 # uleb128 0x2 - .align 2 -LEFDE3: - - -.globl _test_no_reg.eh -_test_no_reg.eh: -LSFDE5: - .set L$set$5,LEFDE5-LASFDE5 - .long L$set$5 # FDE Length -LASFDE5: - .long LASFDE5-EH_frame1 # FDE CIE offset - .long LFB12-. # FDE initial location - .set L$set$6,LFE12-LFB12 - .long L$set$6 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$7,LCFI2-LFB12 - .long L$set$7 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .align 2 -LEFDE5: - - -.globl _test_esi.eh -_test_esi.eh: -LSFDE9: - .set L$set$12,LEFDE9-LASFDE9 - .long L$set$12 # FDE Length -LASFDE9: - .long LASFDE9-EH_frame1 # FDE CIE offset - .long LFB10-. # FDE initial location - .set L$set$13,LFE10-LFB10 - .long L$set$13 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14,LCFI5-LFB10 - .long L$set$14 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$15,LCFI6-LCFI5 - .long L$set$15 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .align 2 -LEFDE9: - - -.globl _test_edi.eh -_test_edi.eh: -LSFDE10: - .set L$set$12a,LEFDE10-LASFDE10 - .long L$set$12a # FDE Length -LASFDE10: - .long LASFDE10-EH_frame1 # FDE CIE offset - .long LFB11-. # FDE initial location - .set L$set$13a,LFE11-LFB11 - .long L$set$13a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$14a,LCFI3-LFB11 - .long L$set$14a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$15a,LCFI4-LCFI3 - .long L$set$15a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .align 2 -LEFDE10: - - - -.globl _test_ebx_esi.eh -_test_ebx_esi.eh: -LSFDE11: - .set L$set$16,LEFDE11-LASFDE11 - .long L$set$16 # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .long LFB9-. # FDE initial location - .set L$set$17,LFE9-LFB9 - .long L$set$17 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$18,LCFI7-LFB9 - .long L$set$18 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$19,LCFI9-LCFI7 - .long L$set$19 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x2 # uleb128 0x2 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE11: - - -.globl _test_esi_edi.eh -_test_esi_edi.eh: -LSFDE13: - .set L$set$20,LEFDE13-LASFDE13 - .long L$set$20 # FDE Length -LASFDE13: - .long LASFDE13-EH_frame1 # FDE CIE offset - .long LFB8-. # FDE initial location - .set L$set$21,LFE8-LFB8 - .long L$set$21 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22,LCFI10-LFB8 - .long L$set$22 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23,LCFI12-LCFI10 - .long L$set$23 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .align 2 -LEFDE13: - - -.globl _test_ebx_esi_edi.eh -_test_ebx_esi_edi.eh: -LSFDE15: - .set L$set$24,LEFDE15-LASFDE15 - .long L$set$24 # FDE Length -LASFDE15: - .long LASFDE15-EH_frame1 # FDE CIE offset - .long LFB7-. # FDE initial location - .set L$set$25,LFE7-LFB7 - .long L$set$25 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$26,LCFI13-LFB7 - .long L$set$26 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$27,LCFI16-LCFI13 - .long L$set$27 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE15: - - -.globl _test_ebx_esi_ebp.eh -_test_ebx_esi_ebp.eh: -LSFDE15a: - .set L$set$24a,LEFDE15a-LASFDE15a - .long L$set$24a # FDE Length -LASFDE15a: - .long LASFDE15a-EH_frame1 # FDE CIE offset - .long LFB7a-. # FDE initial location - .set L$set$25a,LFE7a-LFB7a - .long L$set$25a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$26a,LCFI13a-LFB7a - .long L$set$26a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$27a,LCFI16a-LCFI13a - .long L$set$27a - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x3 # uleb128 0x3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE15a: - - - -.globl _test_esi_edi_ebp.eh -_test_esi_edi_ebp.eh: -LSFDE17: - .set L$set$28,LEFDE17-LASFDE17 - .long L$set$28 # FDE Length -LASFDE17: - .long LASFDE17-EH_frame1 # FDE CIE offset - .long LFB6-. # FDE initial location - .set L$set$29,LFE6-LFB6 - .long L$set$29 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$30,LCFI17-LFB6 - .long L$set$30 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$31,LCFI20-LCFI17 - .long L$set$31 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE17: - - -.globl _test_ebx_esi_edi_ebp.eh -_test_ebx_esi_edi_ebp.eh: -LSFDE19: - .set L$set$32,LEFDE19-LASFDE19 - .long L$set$32 # FDE Length -LASFDE19: - .long LASFDE19-EH_frame1 # FDE CIE offset - .long LFB5-. # FDE initial location - .set L$set$33,LFE5-LFB5 - .long L$set$33 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34,LCFI21-LFB5 - .long L$set$34 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0xa0,0xf1,0x4 # uleb128 0x138a0 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$35,LCFI25-LCFI21 - .long L$set$35 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE19: - - - .subsections_via_symbols diff --git a/libunwind/testsuite/unwind_test_x86_unusual.s b/libunwind/testsuite/unwind_test_x86_unusual.s deleted file mode 100644 index 4e1060c..0000000 --- a/libunwind/testsuite/unwind_test_x86_unusual.s +++ /dev/null @@ -1,330 +0,0 @@ - -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -Wl,-no_compact_unwind - - - .data -.globl _unwind_tester_list -_unwind_tester_list: - .long _test_ebx_wrong_slot - .long _test_esi_in_ebx - .long _test_edi_pad_ebx - .long _test_coal_ebx_esi_edi - .long Ltest_edi_pad_ebx - .long 0 - - - .text - -.globl _test_ebx_wrong_slot -_test_ebx_wrong_slot: -LFB13: - pushl %ebp -LCFI2: - movl %esp, %ebp -LCFI3: - subl $4, %esp - pushl %ebx -LCFI4: - subl $16, %esp -LCFI5: - movl $0, %ebx - call _uwind_to_main - addl $16, %esp - popl %ebx - addl $4, %esp - leave - ret -LFE13: - - -.globl _test_esi_in_ebx -_test_esi_in_ebx: -LFB9: - pushl %ebp -LCFI17: - movl %esp, %ebp -LCFI18: - subl $24, %esp -LCFI19: - movl %ebx, -8(%ebp) -LCFI20: - movl %esi, %ebx -LCFI21: - movl $0, %esi - call _uwind_to_main - movl %ebx, %esi - movl -8(%ebp), %ebx - leave - ret -LFE9: - - - -.globl _test_edi_pad_ebx -_test_edi_pad_ebx: -LFB7a: - pushl %ebp -LCFI27a: - movl %esp, %ebp -LCFI28a: - subl $140, %esp -LCFI29a: - movl %edi, -44(%ebp) -LCFI30a: -LCFI31a: - movl %ebx, -4(%ebp) -LCFI32a: - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl -44(%ebp), %edi - movl -4(%ebp), %ebx - leave - ret -LFE7a: - -Ltest_edi_pad_ebx: -LFB7b: - pushl %ebp -LCFI27b: - movl %esp, %ebp -LCFI28b: - subl $140, %esp -LCFI29b: - movl %edi, -44(%ebp) -LCFI30b: -LCFI31b: - movl %ebx, -4(%ebp) -LCFI32b: - movl $0, %ebx - movl $0, %edi - call _uwind_to_main - movl -44(%ebp), %edi - movl -4(%ebp), %ebx - leave - ret -LFE7b: - - - - .section __TEXT,__textcoal_nt,coalesced,pure_instructions - .globl _test_coal_ebx_esi_edi - .weak_definition _test_coal_ebx_esi_edi -_test_coal_ebx_esi_edi: -LFB7: - pushl %ebp -LCFI27: - movl %esp, %ebp -LCFI28: - subl $40, %esp -LCFI29: - movl %ebx, -12(%ebp) -LCFI30: - movl %esi, -8(%ebp) -LCFI31: - movl %edi, -4(%ebp) -LCFI32: - movl $0, %ebx - movl $0, %edi - movl $0, %esi - call _uwind_to_main - movl -12(%ebp), %ebx - movl -8(%ebp), %esi - movl -4(%ebp), %edi - leave - ret -LFE7: - - - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 # Length of Common Information Entry -LSCIE1: - .long 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x7c # sleb128 -4; CIE Data Alignment Factor - .byte 0x8 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte 0x10 # FDE Encoding (pcrel) - .byte 0xc # DW_CFA_def_cfa - .byte 0x5 # uleb128 0x5 - .byte 0x4 # uleb128 0x4 - .byte 0x88 # DW_CFA_offset, column 0x8 - .byte 0x1 # uleb128 0x1 - .align 2 -LECIE1: - - - -.globl _test_ebx_wrong_slot.eh -_test_ebx_wrong_slot.eh: -LSFDE3: - .set L$set$1,LEFDE3-LASFDE3 - .long L$set$1 # FDE Length -LASFDE3: - .long LASFDE3-EH_frame1 # FDE CIE offset - .long LFB13-. # FDE initial location - .set L$set$2,LFE13-LFB13 - .long L$set$2 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$3,LCFI2-LFB13 - .long L$set$3 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$4,LCFI3-LCFI2 - .long L$set$4 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$5,LCFI5-LCFI3 - .long L$set$5 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE3: - - -.globl _test_esi_in_ebx.eh -_test_esi_in_ebx.eh: -LSFDE11: - .set L$set$20,LEFDE11-LASFDE11 - .long L$set$20 # FDE Length -LASFDE11: - .long LASFDE11-EH_frame1 # FDE CIE offset - .long LFB9-. # FDE initial location - .set L$set$21,LFE9-LFB9 - .long L$set$21 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$22,LCFI17-LFB9 - .long L$set$22 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$23,LCFI18-LCFI17 - .long L$set$23 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$24,LCFI21-LCFI18 - .long L$set$24 - .byte 0x09, 0x06, 0x03 # DW_CFA_register 6, 3 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x4 # uleb128 0x4 - .align 2 -LEFDE11: - - -.globl _test_edi_pad_ebx.eh -_test_edi_pad_ebx.eh: -LSFDE15a: - .set L$set$30,LEFDE15a-LASFDE15a - .long L$set$30 # FDE Length -LASFDE15a: - .long LASFDE15a-EH_frame1 # FDE CIE offset - .long LFB7a-. # FDE initial location - .set L$set$31,LFE7a-LFB7a - .long L$set$31 # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32,LCFI27a-LFB7a - .long L$set$32 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33,LCFI28a-LCFI27a - .long L$set$33 - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34,LCFI32a-LCFI28a - .long L$set$34 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0xD # uleb128 0xD - .align 2 -LEFDE15a: - -ltest_edi_pad_ebx.eh: -LSFDE15b: - .set L$set$30a,LEFDE15b-LASFDE15b - .long L$set$30a # FDE Length -LASFDE15b: - .long LASFDE15b-EH_frame1 # FDE CIE offset - .long LFB7b-. # FDE initial location - .set L$set$31a,LFE7b-LFB7b - .long L$set$31a # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32a,LCFI27b-LFB7b - .long L$set$32a - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33a,LCFI28b-LCFI27b - .long L$set$33a - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34a,LCFI32b-LCFI28b - .long L$set$34a - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x3 # uleb128 0x3 - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0xD # uleb128 0xD - .align 2 -LEFDE15b: - -.globl _test_coal_ebx_esi_edi.eh -_test_coal_ebx_esi_edi.eh: -LSFDE15: - .set L$set$30b,LEFDE15-LASFDE15 - .long L$set$30b # FDE Length -LASFDE15: - .long LASFDE15-EH_frame1 # FDE CIE offset - .long LFB7-. # FDE initial location - .set L$set$31b,LFE7-LFB7 - .long L$set$31b # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$32b,LCFI27-LFB7 - .long L$set$32b - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x8 # uleb128 0x8 - .byte 0x84 # DW_CFA_offset, column 0x4 - .byte 0x2 # uleb128 0x2 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$33b,LCFI28-LCFI27 - .long L$set$33b - .byte 0xd # DW_CFA_def_cfa_register - .byte 0x4 # uleb128 0x4 - .byte 0x4 # DW_CFA_advance_loc4 - .set L$set$34b,LCFI32-LCFI28 - .long L$set$34b - .byte 0x87 # DW_CFA_offset, column 0x7 - .byte 0x3 # uleb128 0x3 - .byte 0x86 # DW_CFA_offset, column 0x6 - .byte 0x4 # uleb128 0x4 - .byte 0x83 # DW_CFA_offset, column 0x3 - .byte 0x5 # uleb128 0x5 - .align 2 -LEFDE15: - - - - .subsections_via_symbols