Update Source To libunwind-201

This commit is contained in:
Thomas A 2023-02-05 15:53:09 -08:00
parent 3644e77cbe
commit 15c82cd41b
149 changed files with 20953 additions and 17186 deletions

49
Makefile Normal file
View File

@ -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)

View File

@ -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/"

123
apple-xbs-support/clang.mk Normal file
View File

@ -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}*] <target>"
@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 <rdar://problem/57402006> 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

View File

@ -0,0 +1,4 @@
# apple-xbs-support/clang_compiler_rt.mk
# Redirect to the 'clang' base project.
include apple-xbs-support/clang.mk

View File

@ -0,0 +1,4 @@
# apple-xbs-support/clang_compiler_rt_os.mk
# Redirect to the 'clang' base project.
include apple-xbs-support/clang.mk

View File

@ -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

View File

@ -0,0 +1,4 @@
# apple-xbs-support/clang_libs_osx.mk
# Redirect to the 'clang' base project.
include apple-xbs-support/clang.mk

View File

@ -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}

View File

@ -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)"

View File

@ -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 <name> or
# <name>-<major>-<minor>.
# 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) => <empty>
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 <name>-<major>.<minor> 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) => <empty>
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 <train>-<major>.<minor>.
#
# 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

View File

@ -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"

View File

@ -0,0 +1 @@
include apple-xbs-support/libcxx.mk

View File

@ -0,0 +1 @@
include apple-xbs-support/libcxx.mk

View File

@ -0,0 +1 @@
include apple-xbs-support/libcxx.mk

View File

@ -0,0 +1 @@
include apple-xbs-support/libcxx.mk

View File

@ -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"

View File

@ -0,0 +1,2 @@
INSTALLFLAGS := --sim
include apple-xbs-support/libunwind.mk

View File

@ -0,0 +1,2 @@
INSTALLFLAGS := --dyld
include apple-xbs-support/libunwind.mk

View File

@ -0,0 +1,2 @@
INSTALLFLAGS := --sim --dyld
include apple-xbs-support/libunwind.mk

168
apple-xbs-support/tapi.mk Normal file
View File

@ -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 "$@"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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/'

View File

@ -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"

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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 <version>" \
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 <version>" \
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'

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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)))

View File

@ -0,0 +1 @@
RUN: %src_root/apple-xbs-support/utils/find-clang-asan-version | grep "\d\d\d\d"

View File

@ -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

2
libunwind/.clang-format Normal file
View File

@ -0,0 +1,2 @@
BasedOnStyle: LLVM

View File

@ -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()

311
libunwind/LICENSE.TXT Normal file
View File

@ -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.

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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 "")

View File

@ -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 "")

View File

@ -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 "")

View File

@ -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()

View File

@ -0,0 +1,47 @@
Apple Internal Testing for libunwind
====================================
## Open source testing
To be setup: <rdar://problem/57362849> 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.

View File

@ -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 <generator> -DLLVM_ENABLE_PROJECTS=libunwind [options] <path to llvm sources>``
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

View File

@ -0,0 +1,7 @@
include(FindSphinx)
if (SPHINX_FOUND)
include(AddSphinxTarget)
if (${SPHINX_OUTPUT_HTML})
add_sphinx_target(html libunwind)
endif()
endif()

13
libunwind/docs/README.txt Normal file
View File

@ -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.

252
libunwind/docs/conf.py Normal file
View File

@ -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
# "<project> v<release> 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 <link> 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

104
libunwind/docs/index.rst Normal file
View File

@ -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 <https://llvm.org/docs/DeveloperPolicy.html>`__
and `Getting started with LLVM <https://llvm.org/docs/GettingStarted.html>`__.
**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 <https://llvm.org/docs/Phabricator.html>`_. 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 <http://lists.llvm.org/mailman/listinfo/cfe-commits>`_.
**Discussion and Questions**
Send discussions and questions to the
`cfe-dev mailing list <http://lists.llvm.org/mailman/listinfo/cfe-dev>`_.
Please include [libunwind] in the subject.
Quick Links
===========
* `LLVM Homepage <https://llvm.org/>`_
* `LLVM Bugzilla <https://bugs.llvm.org/>`_
* `cfe-commits Mailing List`_
* `cfe-dev Mailing List`_
* `Browse libunwind Sources <https://github.com/llvm/llvm-project/blob/master/libunwind/>`_

View File

@ -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__

View File

@ -1,42 +1,53 @@
/* -*- 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 <stdint.h>
#include <stddef.h>
#include <mach/mach_types.h>
#ifdef __APPLE__
#if __clang__
#if __has_include(<Availability.h>)
#include <Availability.h>
#endif
#elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
#include <Availability.h>
#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 <AvailabilityMacros.h>
#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 {
@ -51,98 +62,84 @@ enum {
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[128]; };
struct unw_context_t {
uint64_t data[_LIBUNWIND_CONTEXT_SIZE];
};
typedef struct unw_context_t unw_context_t;
struct unw_cursor_t { uint64_t data[140]; };
struct unw_cursor_t {
uint64_t data[_LIBUNWIND_CURSOR_SIZE];
} LIBUNWIND_CURSOR_ALIGNMENT_ATTR;
typedef struct unw_cursor_t unw_cursor_t;
typedef struct unw_addr_space *unw_addr_space_t;
typedef int unw_regnum_t;
typedef uint64_t unw_word_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
struct unw_proc_info_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 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 */
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*);
*/
#ifdef __cplusplus
}
#endif
// architecture independent register numbers
enum {
UNW_REG_IP = -1, // instruction pointer
UNW_REG_SP = -2, // stack pointer
};
// 32-bit x86 registers
enum {
UNW_X86_EAX = 0,
@ -155,7 +152,6 @@ enum {
UNW_X86_EDI = 7
};
// 64-bit x86_64 registers
enum {
UNW_X86_64_RAX = 0,
@ -173,7 +169,24 @@ enum {
UNW_X86_64_R12 = 12,
UNW_X86_64_R13 = 13,
UNW_X86_64_R14 = 14,
UNW_X86_64_R15 = 15
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,
};
@ -292,11 +305,646 @@ enum {
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

View File

@ -1,26 +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@
*/
//===------------------ 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__
@ -28,29 +15,27 @@
#include <stdint.h>
//
// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section
// 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.
// 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
@ -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.
@ -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
@ -248,7 +237,7 @@ enum {
// 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.
//
////////////////////////////////////////////////////////////////////////////////
//
@ -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,7 +418,7 @@ 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[]
};

View File

@ -0,0 +1,4 @@
module MachO.compact_unwind_encoding [system] [extern_c] {
header "compact_unwind_encoding.h"
export *
}

View File

@ -1,45 +1,37 @@
/* -*- 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 <stdint.h>
#include <stddef.h>
#include <Availability.h>
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32)
#include <windows.h>
#include <ntverp.h>
#endif
#if defined(__APPLE__)
#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
#else
#define LIBUNWIND_UNAVAIL
#endif
typedef enum {
_URC_NO_REASON = 0,
_URC_OK = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
@ -47,7 +39,10 @@ typedef enum {
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
_URC_CONTINUE_UNWIND = 8,
#if defined(_LIBUNWIND_ARM_EHABI)
_URC_FAILURE = 9
#endif
} _Unwind_Reason_Code;
typedef enum {
@ -58,41 +53,106 @@ typedef enum {
_UA_END_OF_STACK = 16 // gcc extension to C++ ABI
} _Unwind_Action;
typedef struct _Unwind_Context _Unwind_Context; // opaque
#if defined(_LIBUNWIND_ARM_EHABI)
typedef uint32_t _Unwind_State;
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)
(_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;
struct _Unwind_Exception {
uint64_t exception_class;
void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
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
#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.
#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,
struct _Unwind_Exception* exceptionObject,
_Unwind_Exception* exceptionObject,
struct _Unwind_Context* context,
void* stop_parameter );
typedef _Unwind_Reason_Code (*__personality_routine)
(int version,
_Unwind_Action actions,
uint64_t exceptionClass,
struct _Unwind_Exception* exceptionObject,
struct _Unwind_Context* context);
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" {
@ -101,27 +161,120 @@ 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 __arm__
#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 <unwind.h> 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);
@ -131,63 +284,55 @@ extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context
// The following are semi-suppoted extensions to the C++ ABI
//
//
// 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_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*);
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.
//
// _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.
//
// __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
{
// 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;
@ -195,38 +340,56 @@ 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);
// 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__

View File

@ -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

View File

@ -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 = "<group>"; };
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 = "<group>"; };
F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "Unwind-sjlj.c"; path = "src/Unwind-sjlj.c"; sourceTree = "<group>"; };
F94138D00D1C7AC600B5EA0C /* dwarf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2.h; path = src/dwarf2.h; sourceTree = "<group>"; };
F94139850D25A12200B5EA0C /* UnwindCursor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = UnwindCursor.hpp; path = src/UnwindCursor.hpp; sourceTree = "<group>"; };
F9413A530D25D7E100B5EA0C /* AddressSpace.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = AddressSpace.hpp; path = src/AddressSpace.hpp; sourceTree = "<group>"; };
F9413A540D25D7E100B5EA0C /* Registers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Registers.hpp; path = src/Registers.hpp; sourceTree = "<group>"; };
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 = "<group>"; };
F95BE31A0D2EED80007E3672 /* CompactUnwinder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CompactUnwinder.hpp; path = src/CompactUnwinder.hpp; sourceTree = "<group>"; };
F95BE4DC0D343AB9007E3672 /* DwarfParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DwarfParser.hpp; path = src/DwarfParser.hpp; sourceTree = "<group>"; };
F95DF59A0DEDD12800B8DA7A /* InternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InternalMacros.h; path = src/InternalMacros.h; sourceTree = "<group>"; };
F98BE9080D0F3D7D00F298D0 /* libunwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libunwind.h; path = include/libunwind.h; sourceTree = "<group>"; };
F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = unw_getcontext.s; path = src/unw_getcontext.s; sourceTree = "<group>"; };
F98BEA710D10CC1700F298D0 /* Registers.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = Registers.s; path = src/Registers.s; sourceTree = "<group>"; };
F98BEABC0D121A4000F298D0 /* libuwind.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = libuwind.cxx; path = src/libuwind.cxx; sourceTree = "<group>"; };
F98BEAC40D121B7800F298D0 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/FileAbstraction.hpp; sourceTree = "<group>"; };
F98F98E311A475B300D21E1F /* libunwind.order */ = {isa = PBXFileReference; explicitFileType = sourcecode.exports; fileEncoding = 4; path = libunwind.order; sourceTree = "<group>"; };
F9AB4BC61194E18500F870C2 /* libunwind_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libunwind_priv.h; path = src/libunwind_priv.h; sourceTree = "<group>"; };
F9ABAAA91118B2BB00A06182 /* unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unwind.h; path = include/unwind.h; sourceTree = "<group>"; };
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 = "<group>"; };
/* 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 = "<group>";
};
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 = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */,
F9276F140E6E0B6100B731C9 /* libunwind.a */,
);
name = Products;
sourceTree = "<group>";
};
F90DFABC0D8A1E9B003302A1 /* include */ = {
isa = PBXGroup;
children = (
F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */,
F9ABAAA91118B2BB00A06182 /* unwind.h */,
F98BE9080D0F3D7D00F298D0 /* libunwind.h */,
);
name = include;
sourceTree = "<group>";
};
/* 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 */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>all.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>dyld-libunwind.a.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>libunwind.dylib.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
</dict>
</plist>

View File

@ -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,91 +15,200 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <mach-o/loader.h>
#include <mach-o/getsect.h>
#include <mach-o/dyld_priv.h>
#include <Availability.h>
#include <string.h>
#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 <dlfcn.h>
#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 <windows.h>
#include <psapi.h>
#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
#include <link.h>
#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;
/// 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
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); }
#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 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);
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);
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;
};
LocalAddressSpace sThisAddress;
inline uintptr_t LocalAddressSpace::getP(pint_t addr)
{
#if __LP64__
inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
#if __SIZEOF_POINTER__ == 8
return get64(addr);
#else
return get32(addr);
#endif
}
/* Read a ULEB128 into a 64-bit word. */
inline uint64_t
LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
{
inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
return get64(addr);
#else
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;
@ -125,14 +217,13 @@ LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
uint64_t b;
if (p == pend)
ABORT("truncated uleb128 expression");
_LIBUNWIND_ABORT("truncated uleb128 expression");
b = *p & 0x7f;
if (bit >= 64 || b << bit >> bit != b) {
ABORT("malformed uleb128 expression");
}
else {
_LIBUNWIND_ABORT("malformed uleb128 expression");
} else {
result |= b << bit;
bit += 7;
}
@ -141,29 +232,30 @@ LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
return result;
}
/* Read a SLEB128 into a 64-bit word. */
inline int64_t
LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
{
/// 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 |= ((byte & 0x7f) << bit);
result |= (uint64_t)(byte & 0x7f) << bit;
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
if ( (byte & 0x40) != 0 )
result |= (-1LL) << bit;
if ((byte & 0x40) != 0 && bit < 64)
result |= (-1ULL) << bit;
addr = (pint_t) p;
return result;
}
LocalAddressSpace::pint_t
LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
{
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;
@ -176,7 +268,7 @@ LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
addr = (pint_t) p;
break;
case DW_EH_PE_uleb128:
result = getULEB128(addr, end);
result = (pint_t)getULEB128(addr, end);
break;
case DW_EH_PE_udata2:
result = get16(addr);
@ -189,30 +281,32 @@ LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
addr = (pint_t) p;
break;
case DW_EH_PE_udata8:
result = get64(addr);
result = (pint_t)get64(addr);
p += 8;
addr = (pint_t) p;
break;
case DW_EH_PE_sleb128:
result = getSLEB128(addr, end);
result = (pint_t)getSLEB128(addr, end);
break;
case DW_EH_PE_sdata2:
result = (int16_t)get16(addr);
// 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:
result = (int32_t)get32(addr);
// 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 = get64(addr);
result = (pint_t)get64(addr);
p += 8;
addr = (pint_t) p;
break;
default:
ABORT("unknown pointer encoding");
_LIBUNWIND_ABORT("unknown pointer encoding");
}
// then add relative offset
@ -224,208 +318,329 @@ LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
result += startAddr;
break;
case DW_EH_PE_textrel:
ABORT("DW_EH_PE_textrel pointer encoding not supported");
_LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
break;
case DW_EH_PE_datarel:
ABORT("DW_EH_PE_datarel pointer encoding not supported");
// 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:
ABORT("DW_EH_PE_funcrel pointer encoding not supported");
_LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
break;
case DW_EH_PE_aligned:
ABORT("DW_EH_PE_aligned pointer encoding not supported");
_LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
break;
default:
ABORT("unknown pointer encoding");
_LIBUNWIND_ABORT("unknown pointer encoding");
break;
}
if ( encoding & DW_EH_PE_indirect )
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::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;
// The ElfW() macro for pointer-size independent ELF header traversal is not
// provided by <link.h> 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<Elf_Addr>(pinfo->dlpi_phdr) -
phdr->p_vaddr;
break;
}
}
}
#endif
return image_base;
}
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
#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;
}
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
size_t pinfo_size, void *data) {
auto cbdata = static_cast<dl_iterate_cb_data *>(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
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
{
dl_info dyldInfo;
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<LocalAddressSpace>::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<LocalAddressSpace>::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;
}
#elif defined(_LIBUNWIND_ARM_EHABI)
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t,
void *data) {
auto *cbdata = static_cast<dl_iterate_cb_data *>(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;
}
#endif
#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
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;
if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
DWORD err = GetLastError();
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
"returned error %d", (int)err);
return false;
}
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;
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<bool>(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;
}
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;
}
#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 <typename P>
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;
};
template <typename P>
uint8_t OtherAddressSpace<P>::get8(pint_t addr)
{
return *((uint8_t*)localCopy(addr));
}
template <typename P>
uint16_t OtherAddressSpace<P>::get16(pint_t addr)
{
return P::E::get16(*(uint16_t*)localCopy(addr));
}
template <typename P>
uint32_t OtherAddressSpace<P>::get32(pint_t addr)
{
return P::E::get32(*(uint32_t*)localCopy(addr));
}
template <typename P>
uint64_t OtherAddressSpace<P>::get64(pint_t addr)
{
return P::E::get64(*(uint64_t*)localCopy(addr));
}
template <typename P>
typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr)
{
return P::getP(*(uint64_t*)localCopy(addr));
}
template <typename P>
uint64_t OtherAddressSpace<P>::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;
}
template <typename P>
int64_t OtherAddressSpace<P>::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;
}
template <typename P>
void* OtherAddressSpace<P>::localCopy(pint_t addr)
{
// FIX ME
}
template <typename P>
bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
{
// FIX ME
}
///
/// 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<Pointer32<LittleEndian> > 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<Pointer64<LittleEndian> > 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<Pointer32<BigEndian> > oas;
};
#endif // UNW_REMOTE
} // namespace libunwind
#endif // __ADDRESSSPACE_HPP__

View File

@ -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()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <typename A> 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<A>::FDE_Info *fdeInfo,
typename CFI_Parser<A>::CIE_Info *cieInfo);
private:
static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
pint_t ehHdrStart, pint_t ehHdrEnd,
uint8_t tableEnc,
typename CFI_Parser<A>::FDE_Info *fdeInfo,
typename CFI_Parser<A>::CIE_Info *cieInfo);
static size_t getTableEntrySize(uint8_t tableEnc);
};
template <typename A>
bool EHHeaderParser<A>::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 <typename A>
bool EHHeaderParser<A>::decodeTableEntry(
A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
typename CFI_Parser<A>::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<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
if (message != NULL) {
_LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
message);
return false;
}
return true;
}
template <typename A>
bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
uint32_t sectionLength,
typename CFI_Parser<A>::FDE_Info *fdeInfo,
typename CFI_Parser<A>::CIE_Info *cieInfo) {
pint_t ehHdrEnd = ehHdrStart + sectionLength;
EHHeaderParser<A>::EHHeaderInfo hdrInfo;
if (!EHHeaderParser<A>::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 <typename A>
size_t EHHeaderParser<A>::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

View File

@ -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 <stdint.h>
#include <string.h>
#include <libkern/OSByteOrder.h>
#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<LittleEndian>
//
//
// 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<<bitCount)-1)); }
static void setBitsRaw(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
const uint32_t mask = ((1<<bitCount)-1);
temp &= ~(mask << (32-firstBit-bitCount));
temp |= ((value & mask) << (32-firstBit-bitCount));
into = temp; }
enum { little_endian = 0 };
};
class LittleEndian
{
public:
static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&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 >> firstBit) & ((1<<bitCount)-1)); }
static void setBitsRaw(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
const uint32_t mask = ((1<<bitCount)-1);
temp &= ~(mask << firstBit);
temp |= ((value & mask) << firstBit);
into = temp; }
enum { little_endian = 1 };
};
template <typename _E>
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 <typename _E>
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__

View File

@ -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 <limits.h>
#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<dl_iterate_cb_data *>(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__

View File

@ -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 <assert.h>
#include <Availability.h>
#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

114
libunwind/src/RWMutex.hpp Normal file
View File

@ -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 <windows.h>
#elif !defined(_LIBUNWIND_HAS_NO_THREADS)
#include <pthread.h>
#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__

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdint.h>
#include <unwind.h>
// 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__

View File

@ -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 <unwind.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <windef.h>
#include <excpt.h>
#include <winnt.h>
#include <ntstatus.h>
#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<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor))
UnwindCursor<LocalAddressSpace, Registers_x86_64>(
context, LocalAddressSpace::sThisAddressSpace);
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
co->setInfoBasedOnIPRegister();
return UNW_ESUCCESS;
#elif defined(_LIBUNWIND_TARGET_ARM)
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor))
UnwindCursor<LocalAddressSpace, Registers_arm>(
context, LocalAddressSpace::sThisAddressSpace);
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
co->setInfoBasedOnIPRegister();
return UNW_ESUCCESS;
#elif defined(_LIBUNWIND_TARGET_AARCH64)
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor))
UnwindCursor<LocalAddressSpace, Registers_arm64>(
context, LocalAddressSpace::sThisAddressSpace);
auto *co = reinterpret_cast<AbstractUnwindCursor *>(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<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext();
#elif defined(_LIBUNWIND_TARGET_ARM)
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext();
#elif defined(_LIBUNWIND_TARGET_AARCH64)
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(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<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp);
#elif defined(_LIBUNWIND_TARGET_ARM)
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp);
#elif defined(_LIBUNWIND_TARGET_AARCH64)
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp);
#endif
}
#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)

View File

@ -1,71 +1,45 @@
/* -*- 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 <unwind.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <setjmp.h>
#if !FOR_DYLD
#include <System/pthread_machdep.h>
#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
{
/// 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.
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
struct _Unwind_FunctionContext {
// next function in stack of handlers
struct _Unwind_FunctionContext *prev;
// set by calling function before registering to be the landing pad
uintptr_t resumeLocation;
uint32_t resumeLocation;
// set by personality handler to be parameters passed to landing pad function
uintptr_t resumeParameters[4];
uint32_t resumeParameters[4];
// set by calling function before registering
__personality_routine personality; // arm offset=24
_Unwind_Personality_Fn personality; // arm offset=24
uintptr_t lsda; // arm offset=28
// variable length array, contains registers to restore
@ -73,81 +47,115 @@ struct _Unwind_FunctionContext
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)
{
#if !defined(FOR_DYLD)
#if defined(__APPLE__)
#include <System/pthread_machdep.h>
#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)
{
/// 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)
{
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);
_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) {
// 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);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
"bottom => _URC_END_OF_STACK",
(void *)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
_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) {
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);
_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;
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
"_URC_HANDLER_FOUND",
(void *)exception_object);
return _URC_NO_REASON;
case _URC_CONTINUE_UNWIND:
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
"_URC_CONTINUE_UNWIND",
(void *)exception_object);
// continue unwinding
break;
default:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
}
@ -156,18 +164,23 @@ static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception* exception_obj
}
static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
static _Unwind_Reason_Code
unwind_phase2(struct _Unwind_Exception *exception_object) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
(void *)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);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
(void *)exception_object, (void *)c);
// 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);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
"bottom => _URC_END_OF_STACK",
(void *)exception_object);
return _URC_END_OF_STACK;
}
@ -175,111 +188,144 @@ static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_obj
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);
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);
_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...
ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
_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:
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT, will resume at landing pad %p\n", exception_object, c->jbuf[1]);
_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
// __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);
_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
// 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)
{
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);
_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 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,
_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);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
"stop function returned %d",
(void *)exception_object, stopResult);
if (stopResult != _URC_NO_REASON) {
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
_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) {
__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,
_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:
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
_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:
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
_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
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
exception_object, personalityResult);
_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
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);
// 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
// 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
// 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;
@ -293,199 +339,178 @@ EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception*
}
//
// 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);
/// 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);
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");
_LIBUNWIND_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
/// 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()
// 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
// 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");
_LIBUNWIND_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)
{
/// 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;
DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%0lX\n", context, ufc->lsda);
_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 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);
/// 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 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);
/// 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
//
EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
{
/// 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;
DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, ufc->resumeLocation+1);
_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.
//
EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
{
/// 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;
DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", context, ipBefore, ufc->resumeLocation+1);
_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
//
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);
/// 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
//
EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
{
/// 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
DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p)\n", context);
(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
//
EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
/// 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);
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
exception_object);
}
//
// Called by personality handler during phase 2 to get base address for data relative encodings
//
EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
{
/// 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
DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
ABORT("_Unwind_GetDataRelBase() not implemented");
(void)context;
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
_LIBUNWIND_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)
{
/// 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
DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
ABORT("_Unwind_GetTextRelBase() not implemented");
(void)context;
_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
}
//
// 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);
/// 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
// the SP in the jmpbuf is the closest approximation
// 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;
}
#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
#endif // __arm__
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)

File diff suppressed because it is too large Load Diff

View File

@ -1,223 +1,259 @@
/* -*- 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:
* <http://www.codesourcery.com/cxx-abi/abi-eh.html>
* using libunwind
*
*/
//===--------------------- 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 <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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
/// 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);
// should return if there is no catch clause, so that __cxa_rethrow can call std::terminate()
// 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
// 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");
_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");
}
/// 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");
}
//
// 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);
/// 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)(long)pc);
if ( unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS )
return (void*)(long)info.start_ip;
__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 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)
{
/// 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);
__unw_getcontext(&uc);
__unw_init_local(&cursor, &uc);
DEBUG_PRINT_API("_Unwind_Backtrace(callback=%p)\n", callback);
_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;
// 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);
#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 ( DEBUG_PRINT_UNWINDING_TEST ) {
if (_LIBUNWIND_TRACING_UNWINDING) {
char functionName[512];
unw_proc_info_t frameInfo;
unw_proc_info_t frame;
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);
__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
_Unwind_Reason_Code result = (*callback)((struct _Unwind_Context*)(&cursor), ref);
result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
if (result != _URC_NO_REASON) {
DEBUG_PRINT_UNWINDING(" _backtrace: ended because callback returned %d\n", result);
_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)
{
/// 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)(long)pc);
unw_get_proc_info(&cursor, &info);
bases->tbase = info.extra;
__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 = 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;
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;
}
EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
{
/// 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);
DEBUG_PRINT_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, (uint64_t)result);
return 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.
//
EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
{
DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p)\n", context);
/// 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);
}
#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
// 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 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 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);
/// 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);
}
//
// 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
@ -225,82 +261,66 @@ EXPORT void __deregister_frame(const void* fde)
// 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);
#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);
_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);
_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);
_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);
_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);
_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);
_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)

View File

@ -1,109 +1,128 @@
/* -*- 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:
* <http://www.codesourcery.com/cxx-abi/abi-eh.html>
* 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 <unwind.h>), thus we need
// to export these functions from libunwind.so as well.
#define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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);
#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
// walk each frame looking for a place to stop
for (bool handlerNotFound = true; handlerNotFound; ) {
#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
// ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
int stepResult = unw_step(&cursor1);
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) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
_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 ) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
} 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)
// 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);
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;
}
// debugging
if ( DEBUG_PRINT_UNWINDING_TEST ) {
char functionName[512];
// 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(&cursor1, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
strcpy(functionName, ".anonymous.");
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(&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);
__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 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));
_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(&cursor1, UNW_REG_SP, &sp);
exception_object->private_2 = sp;
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
__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:
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
(void *)exception_object);
// continue unwinding
break;
default:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
}
@ -112,344 +131,388 @@ static _Unwind_Reason_Code unwind_phase1(unw_context_t* uc, struct _Unwind_Excep
}
static _Unwind_Reason_Code unwind_phase2(unw_context_t* uc, struct _Unwind_Exception* exception_object)
{
unw_cursor_t cursor2;
unw_init_local(&cursor2, uc);
static _Unwind_Reason_Code
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
__unw_init_local(cursor, uc);
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
(void *)exception_object);
// walk each frame until we reach where search phase said to stop
// Walk each frame until we reach where search phase said to stop.
while (true) {
// ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
int stepResult = unw_step(&cursor2);
// Ask libunwind to get next frame (skip over first which is
// _Unwind_RaiseException).
int stepResult = __unw_step(cursor);
if (stepResult == 0) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
_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 ) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
} 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
// 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);
__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;
}
// debugging
if ( DEBUG_PRINT_UNWINDING_TEST ) {
char functionName[512];
// 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, 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 ((__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 there is a personality routine, tell it we are unwinding.
if (frameInfo.handler != 0) {
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
_Unwind_Personality_Fn p =
(_Unwind_Personality_Fn)(uintptr_t)(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");
// Tell personality this was the frame it marked in phase 1.
action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
}
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;
}
}
}
// 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));
_Unwind_Reason_Code personalityResult =
(*p)(1, action, exception_object->exception_class, exception_object,
(struct _Unwind_Context *)(cursor));
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
// 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:
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);
_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:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
exception_object, personalityResult);
// 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
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);
// 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
// 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_RaiseException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_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_RaiseException(_Unwind_Exception *exception_object) {
_LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
(void *)exception_object);
unw_context_t uc;
unw_getcontext(&uc);
unw_cursor_t cursor;
__unw_getcontext(&uc);
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
// 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);
_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, exception_object);
return unwind_phase2(&uc, &cursor, 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);
/// 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_getcontext(&uc);
unw_cursor_t cursor;
__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);
unwind_phase2_forced(&uc, &cursor, exception_object,
(_Unwind_Stop_Fn) exception_object->private_1,
(void *)exception_object->private_2);
else
unwind_phase2(&uc, exception_object);
unwind_phase2(&uc, &cursor, exception_object);
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
ABORT("_Unwind_Resume() can't return");
// 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().
//
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);
/// 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_getcontext(&uc);
unw_cursor_t cursor;
__unw_getcontext(&uc);
// mark that this is a forced unwind, so _Unwind_Resume() can do the right thing
// 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;
// do it
return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter);
}
//
// Called by personality handler during phase 2 to get LSDA for current frame
//
EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
{
/// 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 = frameInfo.lsda;
DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result);
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)
DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result);
_LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
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)
{
/// 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 = frameInfo.start_ip;
DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result);
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
//
EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
/// 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);
(*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;
}
//
// 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)
/// 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 // __ppc__ || __i386__ || __x86_64__
#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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)

165
libunwind/src/assembly.h Normal file
View File

@ -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 */

232
libunwind/src/config.h Normal file
View File

@ -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 <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#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 <typename _Type, typename _Mem>
struct check_fit {
template <typename T>
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

View File

@ -1,36 +1,22 @@
/*
* 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@
*/
//===------------------------------- 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
//
//===----------------------------------------------------------------------===//
/* 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.
*/
#ifndef __DWARF2__
#define __DWARF2__
// dwarf unwind instructions
// DWARF unwind instructions
enum {
DW_CFA_nop = 0x0,
DW_CFA_set_loc = 0x1,
@ -62,12 +48,15 @@ enum {
// GNU extensions
DW_CFA_GNU_window_save = 0x2D,
DW_CFA_GNU_args_size = 0x2E,
DW_CFA_GNU_negative_offset_extended = 0x2F
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
// Used in CFI augmentation by GCC
enum {
DW_EH_PE_ptr = 0x00,
DW_EH_PE_uleb128 = 0x01,
@ -247,9 +236,4 @@ enum {
};
#endif

340
libunwind/src/libunwind.cpp Normal file
View File

@ -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 <libunwind.h>
//
//===----------------------------------------------------------------------===//
#include <libunwind.h>
#include "libunwind_ext.h"
#include "config.h"
#include <stdlib.h>
#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<void *>(cursor),
static_cast<void *>(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<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor))
UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
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<void *>(cursor), regNum,
static_cast<void *>(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<void *>(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<void *>(cursor), regNum,
static_cast<void *>(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<void *>(cursor), regNum, value);
#else
_LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
static_cast<void *>(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<void *>(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<void *>(cursor), static_cast<void *>(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<void *>(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<void *>(cursor), static_cast<void *>(buf),
static_cast<unsigned long>(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<void *>(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<void *>(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<void *>(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<void *>(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<void *>(func));
DwarfFDECache<LocalAddressSpace>::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<LocalAddressSpace>::FDE_Info fdeInfo;
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
const char *message = CFI_Parser<LocalAddressSpace>::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<LocalAddressSpace>::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<LocalAddressSpace>::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 <stdlib.h>
_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

View File

@ -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 <libunwind.h>
#include <unwind.h>
#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__

View File

@ -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 <libunwind.h>
#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

View File

@ -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 <mach/mach_types.h>
#include <mach/machine.h>
#include <new>
#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<LocalAddressSpace,Registers_x86>(context, sThisAddressSpace);
#elif __x86_64__
new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86_64>(context, sThisAddressSpace);
#elif __ppc__
new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_ppc>(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<OtherAddressSpace<Pointer32<LittleEndian> >,
Registers_x86>(((unw_addr_space_i386*)as)->oas, thread);
break;
case CPU_TYPE_X86_64:
new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer64<LittleEndian> >,
Registers_x86_64>(((unw_addr_space_x86_64*)as)->oas, thread);
break;
case CPU_TYPE_POWERPC:
new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >,
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<LocalAddressSpace>::iterateCacheEntries(func);
}
#endif // !FOR_DYLD
#if !FOR_DYLD
//
// IPI: for __register_frame()
//
void _unw_add_dynamic_fde(unw_word_t fde)
{
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
const char* message = CFI_Parser<LocalAddressSpace>::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<LocalAddressSpace>::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<LocalAddressSpace>::removeAllIn(fde);
}
#endif
#endif // __ppc__ || __i386__ || __x86_64__

View File

@ -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

View File

@ -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})

View File

@ -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 <unwind.h>
// 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()
{
}

View File

@ -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 <link.h>
#include <stdio.h>
// 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

View File

Some files were not shown because too many files have changed in this diff Show More