mirror of
https://github.com/darlinghq/darling-libunwind.git
synced 2024-11-23 04:29:39 +00:00
Update Source To libunwind-201
This commit is contained in:
parent
3644e77cbe
commit
15c82cd41b
49
Makefile
Normal file
49
Makefile
Normal 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)
|
20
apple-xbs-support/Libcompiler_rt.mk
Normal file
20
apple-xbs-support/Libcompiler_rt.mk
Normal 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
123
apple-xbs-support/clang.mk
Normal 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
|
4
apple-xbs-support/clang_compiler_rt.mk
Normal file
4
apple-xbs-support/clang_compiler_rt.mk
Normal file
@ -0,0 +1,4 @@
|
||||
# apple-xbs-support/clang_compiler_rt.mk
|
||||
# Redirect to the 'clang' base project.
|
||||
|
||||
include apple-xbs-support/clang.mk
|
4
apple-xbs-support/clang_compiler_rt_os.mk
Normal file
4
apple-xbs-support/clang_compiler_rt_os.mk
Normal 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
|
8
apple-xbs-support/clang_device.mk
Normal file
8
apple-xbs-support/clang_device.mk
Normal 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
|
4
apple-xbs-support/clang_libs_osx.mk
Normal file
4
apple-xbs-support/clang_libs_osx.mk
Normal file
@ -0,0 +1,4 @@
|
||||
# apple-xbs-support/clang_libs_osx.mk
|
||||
# Redirect to the 'clang' base project.
|
||||
|
||||
include apple-xbs-support/clang.mk
|
79
apple-xbs-support/clang_shims.mk
Normal file
79
apple-xbs-support/clang_shims.mk
Normal 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}
|
33
apple-xbs-support/helpers/installsrc.mk
Normal file
33
apple-xbs-support/helpers/installsrc.mk
Normal 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)"
|
79
apple-xbs-support/helpers/train_detection.mk
Normal file
79
apple-xbs-support/helpers/train_detection.mk
Normal 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
|
66
apple-xbs-support/libcxx.mk
Normal file
66
apple-xbs-support/libcxx.mk
Normal 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"
|
1
apple-xbs-support/libcxx_Sim.mk
Normal file
1
apple-xbs-support/libcxx_Sim.mk
Normal file
@ -0,0 +1 @@
|
||||
include apple-xbs-support/libcxx.mk
|
1
apple-xbs-support/libcxx_driverkit.mk
Normal file
1
apple-xbs-support/libcxx_driverkit.mk
Normal file
@ -0,0 +1 @@
|
||||
include apple-xbs-support/libcxx.mk
|
1
apple-xbs-support/libcxx_dyld.mk
Normal file
1
apple-xbs-support/libcxx_dyld.mk
Normal file
@ -0,0 +1 @@
|
||||
include apple-xbs-support/libcxx.mk
|
1
apple-xbs-support/libcxx_dyld_Sim.mk
Normal file
1
apple-xbs-support/libcxx_dyld_Sim.mk
Normal file
@ -0,0 +1 @@
|
||||
include apple-xbs-support/libcxx.mk
|
31
apple-xbs-support/libunwind.mk
Normal file
31
apple-xbs-support/libunwind.mk
Normal 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"
|
2
apple-xbs-support/libunwind_Sim.mk
Normal file
2
apple-xbs-support/libunwind_Sim.mk
Normal file
@ -0,0 +1,2 @@
|
||||
INSTALLFLAGS := --sim
|
||||
include apple-xbs-support/libunwind.mk
|
2
apple-xbs-support/libunwind_dyld.mk
Normal file
2
apple-xbs-support/libunwind_dyld.mk
Normal file
@ -0,0 +1,2 @@
|
||||
INSTALLFLAGS := --dyld
|
||||
include apple-xbs-support/libunwind.mk
|
2
apple-xbs-support/libunwind_dyld_Sim.mk
Normal file
2
apple-xbs-support/libunwind_dyld_Sim.mk
Normal file
@ -0,0 +1,2 @@
|
||||
INSTALLFLAGS := --sim --dyld
|
||||
include apple-xbs-support/libunwind.mk
|
168
apple-xbs-support/tapi.mk
Normal file
168
apple-xbs-support/tapi.mk
Normal 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 "$@"
|
12
apple-xbs-support/test/Libcompiler_rt/installsrc.test
Normal file
12
apple-xbs-support/test/Libcompiler_rt/installsrc.test
Normal 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
|
||||
|
23
apple-xbs-support/test/Makefile
Normal file
23
apple-xbs-support/test/Makefile
Normal 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
|
17
apple-xbs-support/test/clang/installsrc.test
Normal file
17
apple-xbs-support/test/clang/installsrc.test
Normal 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
|
7
apple-xbs-support/test/clang/installsrc_variant.test
Normal file
7
apple-xbs-support/test/clang/installsrc_variant.test
Normal 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/'
|
22
apple-xbs-support/test/clang/shims.test
Normal file
22
apple-xbs-support/test/clang/shims.test
Normal 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"
|
@ -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'
|
3
apple-xbs-support/test/generic/missing-SRCROOT.test
Normal file
3
apple-xbs-support/test/generic/missing-SRCROOT.test
Normal 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'
|
187
apple-xbs-support/test/generic/train_detection.test
Normal file
187
apple-xbs-support/test/generic/train_detection.test
Normal 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
|
27
apple-xbs-support/test/libcxx/install_libcxx.test
Normal file
27
apple-xbs-support/test/libcxx/install_libcxx.test
Normal 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"
|
27
apple-xbs-support/test/libcxx/install_libcxx_driverkit.test
Normal file
27
apple-xbs-support/test/libcxx/install_libcxx_driverkit.test
Normal 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"
|
27
apple-xbs-support/test/libcxx/install_libcxx_dyld.test
Normal file
27
apple-xbs-support/test/libcxx/install_libcxx_dyld.test
Normal 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"
|
@ -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"
|
65
apple-xbs-support/test/libcxx/installsrc.test
Normal file
65
apple-xbs-support/test/libcxx/installsrc.test
Normal 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
|
26
apple-xbs-support/test/libcxx/per_tu_guarantee.test
Normal file
26
apple-xbs-support/test/libcxx/per_tu_guarantee.test
Normal 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'
|
40
apple-xbs-support/test/libunwind/install.test
Normal file
40
apple-xbs-support/test/libunwind/install.test
Normal 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'
|
26
apple-xbs-support/test/libunwind/installsrc.test
Normal file
26
apple-xbs-support/test/libunwind/installsrc.test
Normal 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
|
25
apple-xbs-support/test/libunwind/installsrc_variant.test
Normal file
25
apple-xbs-support/test/libunwind/installsrc_variant.test
Normal 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'
|
43
apple-xbs-support/test/lit.cfg
Normal file
43
apple-xbs-support/test/lit.cfg
Normal 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)))
|
@ -0,0 +1 @@
|
||||
RUN: %src_root/apple-xbs-support/utils/find-clang-asan-version | grep "\d\d\d\d"
|
3
apple-xbs-support/utils/find-clang-asan-version
Executable file
3
apple-xbs-support/utils/find-clang-asan-version
Executable 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
2
libunwind/.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
409
libunwind/CMakeLists.txt.apple
Normal file
409
libunwind/CMakeLists.txt.apple
Normal 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
311
libunwind/LICENSE.TXT
Normal 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.
|
156
libunwind/apple-install-libunwind.sh
Executable file
156
libunwind/apple-install-libunwind.sh
Executable 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
|
64
libunwind/cmake/Modules/HandleCompilerRT.cmake
Normal file
64
libunwind/cmake/Modules/HandleCompilerRT.cmake
Normal 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()
|
272
libunwind/cmake/Modules/HandleLibunwindFlags.cmake
Normal file
272
libunwind/cmake/Modules/HandleLibunwindFlags.cmake
Normal 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()
|
6
libunwind/cmake/caches/Apple-shared.cmake
Normal file
6
libunwind/cmake/caches/Apple-shared.cmake
Normal 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 "")
|
5
libunwind/cmake/caches/Apple-static.cmake
Normal file
5
libunwind/cmake/caches/Apple-static.cmake
Normal 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 "")
|
11
libunwind/cmake/caches/Apple.cmake
Normal file
11
libunwind/cmake/caches/Apple.cmake
Normal 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 "")
|
95
libunwind/cmake/config-ix.cmake
Normal file
95
libunwind/cmake/config-ix.cmake
Normal 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()
|
47
libunwind/docs/AppleInternalTesting.md
Normal file
47
libunwind/docs/AppleInternalTesting.md
Normal 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.
|
161
libunwind/docs/BuildingLibunwind.rst
Normal file
161
libunwind/docs/BuildingLibunwind.rst
Normal 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
|
7
libunwind/docs/CMakeLists.txt
Normal file
7
libunwind/docs/CMakeLists.txt
Normal 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
13
libunwind/docs/README.txt
Normal 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
252
libunwind/docs/conf.py
Normal 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
104
libunwind/docs/index.rst
Normal 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/>`_
|
159
libunwind/include/__libunwind_config.h
Normal file
159
libunwind/include/__libunwind_config.h
Normal 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__
|
File diff suppressed because it is too large
Load Diff
@ -1,56 +1,41 @@
|
||||
/* -*- mode: C; c-basic-offset: 4; tab-width: 4 -*-
|
||||
*
|
||||
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
//===------------------ mach-o/compact_unwind_encoding.h ------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//
|
||||
// Darwin's alternative to DWARF based unwind encodings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef __COMPACT_UNWIND_ENCODING__
|
||||
#define __COMPACT_UNWIND_ENCODING__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section
|
||||
// of object files. Or compilers can emit compact unwind information in
|
||||
// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section
|
||||
// of object files. Or compilers can emit compact unwind information in
|
||||
// the __LD,__compact_unwind section.
|
||||
//
|
||||
// When the linker creates a final linked image, it will create a
|
||||
// __TEXT,__unwind_info section. This section is a small and fast way for the
|
||||
// runtime to access unwind info for any given function. If the compiler emitted
|
||||
// compact unwind info for the function, that compact unwind info will be encoded
|
||||
// in the __TEXT,__unwind_info section. If the compiler emitted dwarf unwind info,
|
||||
// the __TEXT,__unwind_info section will contain the offset of the FDE in the
|
||||
// __TEXT,__eh_frame section in the final linked image.
|
||||
// When the linker creates a final linked image, it will create a
|
||||
// __TEXT,__unwind_info section. This section is a small and fast way for the
|
||||
// runtime to access unwind info for any given function. If the compiler
|
||||
// emitted compact unwind info for the function, that compact unwind info will
|
||||
// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
|
||||
// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset
|
||||
// of the FDE in the __TEXT,__eh_frame section in the final linked image.
|
||||
//
|
||||
// Note: Previously, the linker would transform some dwarf unwind infos into
|
||||
// Note: Previously, the linker would transform some DWARF unwind infos into
|
||||
// compact unwind info. But that is fragile and no longer done.
|
||||
|
||||
|
||||
//
|
||||
// The compact unwind endoding is a 32-bit value which encoded in an architecture
|
||||
// specific way, which registers to restore from where, and how to unwind out
|
||||
// of the function.
|
||||
// The compact unwind endoding is a 32-bit value which encoded in an
|
||||
// architecture specific way, which registers to restore from where, and how
|
||||
// to unwind out of the function.
|
||||
//
|
||||
typedef uint32_t compact_unwind_encoding_t;
|
||||
|
||||
@ -72,7 +57,7 @@ enum {
|
||||
// 1-bit: has lsda
|
||||
// 2-bit: personality index
|
||||
//
|
||||
// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
|
||||
// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||
// ebp based:
|
||||
// 15-bits (5*3-bits per reg) register permutation
|
||||
// 8-bits for stack offset
|
||||
@ -88,15 +73,15 @@ enum {
|
||||
UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
|
||||
UNWIND_X86_MODE_STACK_IND = 0x03000000,
|
||||
UNWIND_X86_MODE_DWARF = 0x04000000,
|
||||
|
||||
|
||||
UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
|
||||
UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
|
||||
|
||||
|
||||
UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
|
||||
UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
|
||||
UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
|
||||
UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
|
||||
|
||||
|
||||
UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||
};
|
||||
|
||||
@ -113,26 +98,26 @@ enum {
|
||||
//
|
||||
// For x86 there are four modes for the compact unwind encoding:
|
||||
// UNWIND_X86_MODE_EBP_FRAME:
|
||||
// EBP based frame where EBP is push on stack immediately after return address,
|
||||
// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
|
||||
// EPB value, then EBP is restored by popping off the stack, and the return
|
||||
// EBP based frame where EBP is push on stack immediately after return address,
|
||||
// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
|
||||
// EPB value, then EBP is restored by popping off the stack, and the return
|
||||
// is done by popping the stack once more into the pc.
|
||||
// All non-volatile registers that need to be restored must have been saved
|
||||
// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
|
||||
// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
|
||||
// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved
|
||||
// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||
// Each entry contains which register to restore.
|
||||
// Each entry contains which register to restore.
|
||||
// UNWIND_X86_MODE_STACK_IMMD:
|
||||
// A "frameless" (EBP not used as frame pointer) function with a small
|
||||
// constant stack size. To return, a constant (encoded in the compact
|
||||
// unwind encoding) is added to the ESP. Then the return is done by
|
||||
// constant stack size. To return, a constant (encoded in the compact
|
||||
// unwind encoding) is added to the ESP. Then the return is done by
|
||||
// popping the stack into the pc.
|
||||
// All non-volatile registers that need to be restored must have been saved
|
||||
// on the stack immediately after the return address. The stack_size/4 is
|
||||
// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
|
||||
// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
|
||||
// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
|
||||
// saved and their order.
|
||||
// saved and their order.
|
||||
// UNWIND_X86_MODE_STACK_IND:
|
||||
// A "frameless" (EBP not used as frame pointer) function large constant
|
||||
// stack size. This case is like the previous, except the stack size is too
|
||||
@ -142,11 +127,15 @@ enum {
|
||||
// UNWIND_X86_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only dwarf unwind info for a
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
// The permutation encoding is a Lehmer code sequence encoded into a
|
||||
// single variable-base number so we can encode the ordering of up to
|
||||
// six registers in a 10-bit space.
|
||||
//
|
||||
// The following is the algorithm used to create the permutation encoding used
|
||||
// with frameless stacks. It is passed the number of registers to be saved and
|
||||
// an array of the register numbers saved.
|
||||
@ -165,21 +154,21 @@ enum {
|
||||
// uint32_t permutationEncoding = 0;
|
||||
// switch ( registerCount ) {
|
||||
// case 6:
|
||||
// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
|
||||
// + 6*renumregs[2] + 2*renumregs[3]
|
||||
// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
|
||||
// + 6*renumregs[2] + 2*renumregs[3]
|
||||
// + renumregs[4]);
|
||||
// break;
|
||||
// case 5:
|
||||
// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
|
||||
// + 6*renumregs[3] + 2*renumregs[4]
|
||||
// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
|
||||
// + 6*renumregs[3] + 2*renumregs[4]
|
||||
// + renumregs[5]);
|
||||
// break;
|
||||
// case 4:
|
||||
// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
|
||||
// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
|
||||
// + 3*renumregs[4] + renumregs[5]);
|
||||
// break;
|
||||
// case 3:
|
||||
// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
|
||||
// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
|
||||
// + renumregs[5]);
|
||||
// break;
|
||||
// case 2:
|
||||
@ -203,7 +192,7 @@ enum {
|
||||
// 1-bit: has lsda
|
||||
// 2-bit: personality index
|
||||
//
|
||||
// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
|
||||
// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||
// rbp based:
|
||||
// 15-bits (5*3-bits per reg) register permutation
|
||||
// 8-bits for stack offset
|
||||
@ -219,7 +208,7 @@ enum {
|
||||
UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
|
||||
UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
|
||||
UNWIND_X86_64_MODE_DWARF = 0x04000000,
|
||||
|
||||
|
||||
UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
|
||||
UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
|
||||
|
||||
@ -243,12 +232,12 @@ enum {
|
||||
//
|
||||
// For x86_64 there are four modes for the compact unwind encoding:
|
||||
// UNWIND_X86_64_MODE_RBP_FRAME:
|
||||
// RBP based frame where RBP is push on stack immediately after return address,
|
||||
// RBP based frame where RBP is push on stack immediately after return address,
|
||||
// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
|
||||
// EPB value, then RBP is restored by popping off the stack, and the return
|
||||
// is done by popping the stack once more into the pc.
|
||||
// All non-volatile registers that need to be restored must have been saved
|
||||
// in a small range in the stack that starts RBP-8 to RBP-1020. The offset/4
|
||||
// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8
|
||||
// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
|
||||
// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||
// Each entry contains which register to restore.
|
||||
@ -258,8 +247,8 @@ enum {
|
||||
// unwind encoding) is added to the RSP. Then the return is done by
|
||||
// popping the stack into the pc.
|
||||
// All non-volatile registers that need to be restored must have been saved
|
||||
// on the stack immediately after the return address. The stack_size/4 is
|
||||
// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 1024).
|
||||
// on the stack immediately after the return address. The stack_size/8 is
|
||||
// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
|
||||
// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
|
||||
// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
|
||||
// saved and their order.
|
||||
@ -272,13 +261,75 @@ enum {
|
||||
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
|
||||
// UNWIND_X86_64_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only dwarf unwind info for a
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
|
||||
|
||||
// ARM64
|
||||
//
|
||||
// 1-bit: start
|
||||
// 1-bit: has lsda
|
||||
// 2-bit: personality index
|
||||
//
|
||||
// 4-bits: 4=frame-based, 3=DWARF, 2=frameless
|
||||
// frameless:
|
||||
// 12-bits of stack size
|
||||
// frame-based:
|
||||
// 4-bits D reg pairs saved
|
||||
// 5-bits X reg pairs saved
|
||||
// DWARF:
|
||||
// 24-bits offset of DWARF FDE in __eh_frame section
|
||||
//
|
||||
enum {
|
||||
UNWIND_ARM64_MODE_MASK = 0x0F000000,
|
||||
UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
|
||||
UNWIND_ARM64_MODE_DWARF = 0x03000000,
|
||||
UNWIND_ARM64_MODE_FRAME = 0x04000000,
|
||||
|
||||
UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
|
||||
UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
|
||||
UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
|
||||
UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
|
||||
UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
|
||||
UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
|
||||
UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
|
||||
UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
|
||||
UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
|
||||
|
||||
UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
|
||||
UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||
};
|
||||
// For arm64 there are three modes for the compact unwind encoding:
|
||||
// UNWIND_ARM64_MODE_FRAME:
|
||||
// This is a standard arm64 prolog where FP/LR are immediately pushed on the
|
||||
// stack, then SP is copied to FP. If there are any non-volatile registers
|
||||
// saved, then are copied into the stack frame in pairs in a contiguous
|
||||
// range right below the saved FP/LR pair. Any subset of the five X pairs
|
||||
// and four D pairs can be saved, but the memory layout must be in register
|
||||
// number order.
|
||||
// UNWIND_ARM64_MODE_FRAMELESS:
|
||||
// A "frameless" leaf function, where FP/LR are not saved. The return address
|
||||
// remains in LR throughout the function. If any non-volatile registers
|
||||
// are saved, they must be pushed onto the stack before any stack space is
|
||||
// allocated for local variables. The stack sized (including any saved
|
||||
// non-volatile registers) divided by 16 is encoded in the bits
|
||||
// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
|
||||
// UNWIND_ARM64_MODE_DWARF:
|
||||
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||
// This mode is never used in object files. It is only generated by the
|
||||
// linker in final linked images which have only DWARF unwind info for a
|
||||
// function.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@ -294,7 +345,7 @@ enum {
|
||||
// This section is a table, initially with one row per function (that needs
|
||||
// unwind info). The table columns and some conceptual entries are:
|
||||
//
|
||||
// range-start pointer to start of function/range
|
||||
// range-start pointer to start of function/range
|
||||
// range-length
|
||||
// compact-unwind-encoding 32-bit encoding
|
||||
// personality-function or zero if no personality function
|
||||
@ -335,7 +386,7 @@ enum {
|
||||
// saved at that range of the function.
|
||||
//
|
||||
// If a particular function is so wacky that there is no compact unwind way
|
||||
// to encode it, then the compiler can emit traditional dwarf unwind info.
|
||||
// to encode it, then the compiler can emit traditional DWARF unwind info.
|
||||
// The runtime will use which ever is available.
|
||||
//
|
||||
// Runtime support for compact unwind encodings are only available on 10.6
|
||||
@ -367,19 +418,19 @@ struct unwind_info_section_header
|
||||
uint32_t indexSectionOffset;
|
||||
uint32_t indexCount;
|
||||
// compact_unwind_encoding_t[]
|
||||
// uintptr_t personalities[]
|
||||
// uint32_t personalities[]
|
||||
// unwind_info_section_header_index_entry[]
|
||||
// unwind_info_section_header_lsda_index_entry[]
|
||||
};
|
||||
|
||||
struct unwind_info_section_header_index_entry
|
||||
struct unwind_info_section_header_index_entry
|
||||
{
|
||||
uint32_t functionOffset;
|
||||
uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
|
||||
uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
|
||||
};
|
||||
|
||||
struct unwind_info_section_header_lsda_index_entry
|
||||
struct unwind_info_section_header_lsda_index_entry
|
||||
{
|
||||
uint32_t functionOffset;
|
||||
uint32_t lsdaOffset;
|
||||
@ -389,10 +440,10 @@ struct unwind_info_section_header_lsda_index_entry
|
||||
// There are two kinds of second level index pages: regular and compressed.
|
||||
// A compressed page can hold up to 1021 entries, but it cannot be used
|
||||
// if too many different encoding types are used. The regular page holds
|
||||
// 511 entries.
|
||||
// 511 entries.
|
||||
//
|
||||
|
||||
struct unwind_info_regular_second_level_entry
|
||||
struct unwind_info_regular_second_level_entry
|
||||
{
|
||||
uint32_t functionOffset;
|
||||
compact_unwind_encoding_t encoding;
|
||||
@ -415,7 +466,7 @@ struct unwind_info_compressed_second_level_page_header
|
||||
uint16_t entryCount;
|
||||
uint16_t encodingsPageOffset;
|
||||
uint16_t encodingsCount;
|
||||
// 32-bit entry array
|
||||
// 32-bit entry array
|
||||
// encodings array
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
module MachO.compact_unwind_encoding [system] [extern_c] {
|
||||
header "compact_unwind_encoding.h"
|
||||
export *
|
||||
}
|
@ -1,99 +1,159 @@
|
||||
/* -*- mode: C++; c-basic-offset: 4; -*-
|
||||
*
|
||||
* Copyright (c) 2010-2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
*
|
||||
* C interface to libuwind
|
||||
*
|
||||
* Source compatible with Level 1 Base ABI documented at:
|
||||
* http://www.codesourcery.com/public/cxx-abi/abi-eh.html
|
||||
*
|
||||
*/
|
||||
|
||||
//===------------------------------- unwind.h -----------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//
|
||||
// C++ ABI Level 1 ABI documented at:
|
||||
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __UNWIND_H__
|
||||
#define __UNWIND_H__
|
||||
|
||||
#include <__libunwind_config.h>
|
||||
|
||||
#include <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_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_OK = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8,
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
_URC_FAILURE = 9
|
||||
#endif
|
||||
} _Unwind_Reason_Code;
|
||||
|
||||
typedef enum {
|
||||
_UA_SEARCH_PHASE = 1,
|
||||
_UA_CLEANUP_PHASE = 2,
|
||||
_UA_HANDLER_FRAME = 4,
|
||||
_UA_FORCE_UNWIND = 8,
|
||||
_UA_END_OF_STACK = 16 // gcc extension to C++ ABI
|
||||
_UA_SEARCH_PHASE = 1,
|
||||
_UA_CLEANUP_PHASE = 2,
|
||||
_UA_HANDLER_FRAME = 4,
|
||||
_UA_FORCE_UNWIND = 8,
|
||||
_UA_END_OF_STACK = 16 // gcc extension to C++ ABI
|
||||
} _Unwind_Action;
|
||||
|
||||
typedef struct _Unwind_Context _Unwind_Context; // opaque
|
||||
|
||||
struct _Unwind_Context; // opaque
|
||||
struct _Unwind_Exception; // forward declaration
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
typedef uint32_t _Unwind_State;
|
||||
|
||||
struct _Unwind_Exception {
|
||||
uint64_t exception_class;
|
||||
void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
|
||||
uintptr_t private_1; // non-zero means forced unwind
|
||||
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
|
||||
#if !__LP64__
|
||||
// The gcc implementation of _Unwind_Exception used attribute mode on the above fields
|
||||
// which had the side effect of causing this whole struct to round up to 32 bytes in size.
|
||||
// To be more explicit, we add pad fields added for binary compatibility.
|
||||
uint32_t reserved[3];
|
||||
#endif
|
||||
};
|
||||
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
|
||||
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
|
||||
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
|
||||
static const _Unwind_State _US_ACTION_MASK = 3;
|
||||
/* Undocumented flag for force unwinding. */
|
||||
static const _Unwind_State _US_FORCE_UNWIND = 8;
|
||||
|
||||
typedef uint32_t _Unwind_EHT_Header;
|
||||
|
||||
struct _Unwind_Control_Block;
|
||||
typedef struct _Unwind_Control_Block _Unwind_Control_Block;
|
||||
typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
|
||||
|
||||
struct _Unwind_Control_Block {
|
||||
uint64_t exception_class;
|
||||
void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*);
|
||||
|
||||
/* Unwinder cache, private fields for the unwinder's use */
|
||||
struct {
|
||||
uint32_t reserved1; /* init reserved1 to 0, then don't touch */
|
||||
uint32_t reserved2;
|
||||
uint32_t reserved3;
|
||||
uint32_t reserved4;
|
||||
uint32_t reserved5;
|
||||
} unwinder_cache;
|
||||
|
||||
/* Propagation barrier cache (valid after phase 1): */
|
||||
struct {
|
||||
uint32_t sp;
|
||||
uint32_t bitpattern[5];
|
||||
} barrier_cache;
|
||||
|
||||
/* Cleanup cache (preserved over cleanup): */
|
||||
struct {
|
||||
uint32_t bitpattern[4];
|
||||
} cleanup_cache;
|
||||
|
||||
/* Pr cache (for pr's benefit): */
|
||||
struct {
|
||||
uint32_t fnstart; /* function start address */
|
||||
_Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */
|
||||
uint32_t additional;
|
||||
uint32_t reserved1;
|
||||
} pr_cache;
|
||||
|
||||
long long int :0; /* Enforce the 8-byte alignment */
|
||||
} __attribute__((__aligned__(8)));
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||
(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exceptionClass,
|
||||
struct _Unwind_Exception* exceptionObject,
|
||||
struct _Unwind_Context* context,
|
||||
void* stop_parameter );
|
||||
(_Unwind_State state,
|
||||
_Unwind_Exception* exceptionObject,
|
||||
struct _Unwind_Context* context);
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
|
||||
_Unwind_State state, _Unwind_Exception *exceptionObject,
|
||||
struct _Unwind_Context *context);
|
||||
#else
|
||||
struct _Unwind_Context; // opaque
|
||||
struct _Unwind_Exception; // forward declaration
|
||||
typedef struct _Unwind_Exception _Unwind_Exception;
|
||||
|
||||
typedef _Unwind_Reason_Code (*__personality_routine)
|
||||
(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exceptionClass,
|
||||
struct _Unwind_Exception* exceptionObject,
|
||||
struct _Unwind_Context* context);
|
||||
|
||||
struct _Unwind_Exception {
|
||||
uint64_t exception_class;
|
||||
void (*exception_cleanup)(_Unwind_Reason_Code reason,
|
||||
_Unwind_Exception *exc);
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
uintptr_t private_[6];
|
||||
#else
|
||||
uintptr_t private_1; // non-zero means forced unwind
|
||||
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
|
||||
#endif
|
||||
#if __SIZEOF_POINTER__ == 4
|
||||
// The implementation of _Unwind_Exception uses an attribute mode on the
|
||||
// above fields which has the side effect of causing this whole struct to
|
||||
// round up to 32 bytes in size (48 with SEH). To be more explicit, we add
|
||||
// pad fields added for binary compatibility.
|
||||
uint32_t reserved[3];
|
||||
#endif
|
||||
// The Itanium ABI requires that _Unwind_Exception objects are "double-word
|
||||
// aligned". GCC has interpreted this to mean "use the maximum useful
|
||||
// alignment for the target"; so do we.
|
||||
} __attribute__((__aligned__));
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||
(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exceptionClass,
|
||||
_Unwind_Exception* exceptionObject,
|
||||
struct _Unwind_Context* context,
|
||||
void* stop_parameter );
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
|
||||
int version, _Unwind_Action actions, uint64_t exceptionClass,
|
||||
_Unwind_Exception *exceptionObject, struct _Unwind_Context *context);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -101,132 +161,235 @@ extern "C" {
|
||||
//
|
||||
// The following are the base functions documented by the C++ ABI
|
||||
//
|
||||
#if __arm__
|
||||
extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object);
|
||||
extern void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object);
|
||||
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||
extern _Unwind_Reason_Code
|
||||
_Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object);
|
||||
extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object);
|
||||
#else
|
||||
extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object);
|
||||
extern void _Unwind_Resume(struct _Unwind_Exception* exception_object);
|
||||
extern _Unwind_Reason_Code
|
||||
_Unwind_RaiseException(_Unwind_Exception *exception_object);
|
||||
extern void _Unwind_Resume(_Unwind_Exception *exception_object);
|
||||
#endif
|
||||
extern void _Unwind_DeleteException(struct _Unwind_Exception* exception_object);
|
||||
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index);
|
||||
extern void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value);
|
||||
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
|
||||
extern void _Unwind_SetIP(struct _Unwind_Context*, uintptr_t new_value);
|
||||
extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context);
|
||||
extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context);
|
||||
#if __arm__
|
||||
extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
|
||||
#else
|
||||
extern _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
|
||||
extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
|
||||
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
typedef enum {
|
||||
_UVRSC_CORE = 0, /* integer register */
|
||||
_UVRSC_VFP = 1, /* vfp */
|
||||
_UVRSC_WMMXD = 3, /* Intel WMMX data register */
|
||||
_UVRSC_WMMXC = 4 /* Intel WMMX control register */
|
||||
} _Unwind_VRS_RegClass;
|
||||
|
||||
typedef enum {
|
||||
_UVRSD_UINT32 = 0,
|
||||
_UVRSD_VFPX = 1,
|
||||
_UVRSD_UINT64 = 3,
|
||||
_UVRSD_FLOAT = 4,
|
||||
_UVRSD_DOUBLE = 5
|
||||
} _Unwind_VRS_DataRepresentation;
|
||||
|
||||
typedef enum {
|
||||
_UVRSR_OK = 0,
|
||||
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||
_UVRSR_FAILED = 2
|
||||
} _Unwind_VRS_Result;
|
||||
|
||||
extern void _Unwind_Complete(_Unwind_Exception* exception_object);
|
||||
|
||||
extern _Unwind_VRS_Result
|
||||
_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
|
||||
void *valuep);
|
||||
|
||||
extern _Unwind_VRS_Result
|
||||
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
|
||||
void *valuep);
|
||||
|
||||
extern _Unwind_VRS_Result
|
||||
_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||
uint32_t discriminator,
|
||||
_Unwind_VRS_DataRepresentation representation);
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
|
||||
extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t new_value);
|
||||
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
|
||||
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
|
||||
|
||||
#else // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
|
||||
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
|
||||
#else
|
||||
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__
|
||||
#endif
|
||||
|
||||
// These are de facto helper functions for ARM, which delegate the function
|
||||
// calls to _Unwind_VRS_Get/Set(). These are not a part of ARM EHABI
|
||||
// specification, thus these function MUST be inlined. Please don't replace
|
||||
// these with the "extern" function declaration; otherwise, the program
|
||||
// including this <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);
|
||||
#endif
|
||||
|
||||
#if __arm__
|
||||
typedef struct _Unwind_FunctionContext* _Unwind_FunctionContext_t;
|
||||
extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
|
||||
extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
|
||||
#endif
|
||||
|
||||
//
|
||||
// The following are semi-suppoted extensions to the C++ ABI
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// called by __cxa_rethrow().
|
||||
// called by __cxa_rethrow().
|
||||
//
|
||||
#if __arm__
|
||||
extern _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
|
||||
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||
extern _Unwind_Reason_Code
|
||||
_Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object);
|
||||
#else
|
||||
extern _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
|
||||
extern _Unwind_Reason_Code
|
||||
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object);
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
|
||||
// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
|
||||
// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
|
||||
// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
|
||||
//
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
|
||||
extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
|
||||
void *);
|
||||
extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
|
||||
|
||||
// _Unwind_GetCFA is a gcc extension that can be called from within a
|
||||
// personality handler to get the CFA (stack pointer before call) of
|
||||
// current frame.
|
||||
extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
|
||||
|
||||
|
||||
//
|
||||
// _Unwind_GetCFA is a gcc extension that can be called from within a personality
|
||||
// handler to get the CFA (stack pointer before call) of current frame.
|
||||
//
|
||||
extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context*);
|
||||
// _Unwind_GetIPInfo is a gcc extension that can be called from within a
|
||||
// personality handler. Similar to _Unwind_GetIP() but also returns in
|
||||
// *ipBefore a non-zero value if the instruction pointer is at or before the
|
||||
// instruction causing the unwind. Normally, in a function call, the IP returned
|
||||
// is the return address which is after the call instruction and may be past the
|
||||
// end of the function containing the call instruction.
|
||||
extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||
int *ipBefore);
|
||||
|
||||
|
||||
//
|
||||
// _Unwind_GetIPInfo is a gcc extension that can be called from within a personality
|
||||
// handler. Similar to _Unwind_GetIP() but also returns in *ipBefore a non-zero
|
||||
// value if the instruction pointer is at or before the instruction causing
|
||||
// the unwind. Normally, in a function call, the IP returned is the return address
|
||||
// which is after the call instruction and may be past the end of the function
|
||||
// containing the call instruction.
|
||||
//
|
||||
extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore);
|
||||
// __register_frame() is used with dynamically generated code to register the
|
||||
// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point
|
||||
// to its function and optional LSDA.
|
||||
// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and
|
||||
// 10.5 it was buggy and did not actually register the FDE with the unwinder.
|
||||
// In 10.6 and later it does register properly.
|
||||
extern void __register_frame(const void *fde);
|
||||
extern void __deregister_frame(const void *fde);
|
||||
|
||||
|
||||
//
|
||||
// __register_frame() is used with dynamically generated code to register the FDE
|
||||
// for a generated (JIT) code. The FDE must use pc-rel addressing to point to its
|
||||
// function and optional LSDA. __register_frame() has existed in all versions of
|
||||
// Mac OS X, but in 10.4 and 10.5 it was buggy and did not actually register the
|
||||
// FDE with the unwinder. In 10.6 and later it does register properly.
|
||||
//
|
||||
extern void __register_frame(const void* fde);
|
||||
extern void __deregister_frame(const void* fde);
|
||||
|
||||
|
||||
//
|
||||
// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
|
||||
// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind info"
|
||||
// which the runtime uses in preference to dwarf unwind info. This function
|
||||
// will only work if the target function has an FDE but no compact unwind info.
|
||||
//
|
||||
struct dwarf_eh_bases
|
||||
{
|
||||
uintptr_t tbase;
|
||||
uintptr_t dbase;
|
||||
uintptr_t func;
|
||||
// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind
|
||||
// info" which the runtime uses in preference to DWARF unwind info. This
|
||||
// function will only work if the target function has an FDE but no compact
|
||||
// unwind info.
|
||||
struct dwarf_eh_bases {
|
||||
uintptr_t tbase;
|
||||
uintptr_t dbase;
|
||||
uintptr_t func;
|
||||
};
|
||||
extern const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases*);
|
||||
extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
|
||||
|
||||
|
||||
//
|
||||
// This function attempts to find the start (address of first instruction) of
|
||||
// a function given an address inside the function. It only works if the function
|
||||
// has an FDE (dwarf unwind info).
|
||||
// a function given an address inside the function. It only works if the
|
||||
// function has an FDE (DWARF unwind info).
|
||||
// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
|
||||
// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
|
||||
extern void* _Unwind_FindEnclosingFunction(void* pc);
|
||||
extern void *_Unwind_FindEnclosingFunction(void *pc);
|
||||
|
||||
// Mac OS X does not support text-rel and data-rel addressing so these functions
|
||||
// are unimplemented
|
||||
extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
|
||||
// Mac OS X does not support text-rel and data-rel addressing so these functions are unimplemented
|
||||
extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
|
||||
extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
|
||||
|
||||
|
||||
|
||||
// Mac OS X 10.4 and 10.5 had implementations of these functions in libgcc_s.dylib,
|
||||
// but they never worked. These functions are no longer available.
|
||||
extern void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db) __attribute__((unavailable));
|
||||
extern void __register_frame_info(const void* fde, void* ob) __attribute__((unavailable));
|
||||
extern void __register_frame_info_table_bases(const void* fde, void* ob,void* tb, void* db) __attribute__((unavailable));
|
||||
extern void __register_frame_info_table(const void* fde, void* ob) __attribute__((unavailable));
|
||||
extern void __register_frame_table(const void* fde) __attribute__((unavailable));
|
||||
extern void* __deregister_frame_info(const void* fde) __attribute__((unavailable));
|
||||
extern void* __deregister_frame_info_bases(const void* fde) __attribute__((unavailable));
|
||||
// Mac OS X 10.4 and 10.5 had implementations of these functions in
|
||||
// libgcc_s.dylib, but they never worked.
|
||||
/// These functions are no longer available on Mac OS X.
|
||||
extern void __register_frame_info_bases(const void *fde, void *ob, void *tb,
|
||||
void *db) LIBUNWIND_UNAVAIL;
|
||||
extern void __register_frame_info(const void *fde, void *ob)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
extern void __register_frame_info_table_bases(const void *fde, void *ob,
|
||||
void *tb, void *db)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
extern void __register_frame_info_table(const void *fde, void *ob)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
extern void __register_frame_table(const void *fde)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
extern void *__deregister_frame_info(const void *fde)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
extern void *__deregister_frame_info_bases(const void *fde)
|
||||
LIBUNWIND_UNAVAIL;
|
||||
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#ifndef _WIN32
|
||||
typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
|
||||
typedef struct _CONTEXT CONTEXT;
|
||||
typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
|
||||
#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
|
||||
typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
|
||||
#endif
|
||||
// This is the common wrapper for GCC-style personality functions with SEH.
|
||||
extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc,
|
||||
void *frame, CONTEXT *ctx,
|
||||
DISPATCHER_CONTEXT *disp,
|
||||
_Unwind_Personality_Fn pers);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // __UNWIND_H__
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
Binary file not shown.
@ -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>
|
File diff suppressed because it is too large
Load Diff
260
libunwind/src/CMakeLists.txt.apple
Normal file
260
libunwind/src/CMakeLists.txt.apple
Normal 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
169
libunwind/src/EHHeaderParser.hpp
Normal file
169
libunwind/src/EHHeaderParser.hpp
Normal 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
|
@ -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__
|
||||
|
||||
|
149
libunwind/src/FrameHeaderCache.hpp
Normal file
149
libunwind/src/FrameHeaderCache.hpp
Normal 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__
|
@ -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
114
libunwind/src/RWMutex.hpp
Normal 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__
|
@ -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
1003
libunwind/src/Unwind-EHABI.cpp
Normal file
1003
libunwind/src/Unwind-EHABI.cpp
Normal file
File diff suppressed because it is too large
Load Diff
50
libunwind/src/Unwind-EHABI.h
Normal file
50
libunwind/src/Unwind-EHABI.h
Normal 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__
|
501
libunwind/src/Unwind-seh.cpp
Normal file
501
libunwind/src/Unwind-seh.cpp
Normal 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)
|
@ -1,491 +1,516 @@
|
||||
/* -*- mode: C++; c-basic-offset: 4; -*-
|
||||
*
|
||||
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
*
|
||||
* Implements setjump-longjump based C++ exceptions
|
||||
*
|
||||
*/
|
||||
//===--------------------------- Unwind-sjlj.c ----------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//
|
||||
// Implements setjump-longjump based C++ exceptions
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <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
|
||||
{
|
||||
// next function in stack of handlers
|
||||
struct _Unwind_FunctionContext* prev;
|
||||
/// With SJLJ based exceptions, any function that has a catch clause or needs to
|
||||
/// do any clean up when an exception propagates through it, needs to call
|
||||
/// \c _Unwind_SjLj_Register at the start of the function and
|
||||
/// \c _Unwind_SjLj_Unregister at the end. The register function is called with
|
||||
/// the address of a block of memory in the function's stack frame. The runtime
|
||||
/// keeps a linked list (stack) of these blocks - one per thread. The calling
|
||||
/// function also sets the personality and lsda fields of the block.
|
||||
|
||||
// set by calling function before registering to be the landing pad
|
||||
uintptr_t resumeLocation;
|
||||
|
||||
// set by personality handler to be parameters passed to landing pad function
|
||||
uintptr_t resumeParameters[4];
|
||||
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
|
||||
// set by calling function before registering
|
||||
__personality_routine personality; // arm offset=24
|
||||
uintptr_t lsda; // arm offset=28
|
||||
struct _Unwind_FunctionContext {
|
||||
// next function in stack of handlers
|
||||
struct _Unwind_FunctionContext *prev;
|
||||
|
||||
// variable length array, contains registers to restore
|
||||
// 0 = r7, 1 = pc, 2 = sp
|
||||
void* jbuf[];
|
||||
// set by calling function before registering to be the landing pad
|
||||
uint32_t resumeLocation;
|
||||
|
||||
// set by personality handler to be parameters passed to landing pad function
|
||||
uint32_t resumeParameters[4];
|
||||
|
||||
// set by calling function before registering
|
||||
_Unwind_Personality_Fn personality; // arm offset=24
|
||||
uintptr_t lsda; // arm offset=28
|
||||
|
||||
// variable length array, contains registers to restore
|
||||
// 0 = r7, 1 = pc, 2 = sp
|
||||
void *jbuf[];
|
||||
};
|
||||
|
||||
|
||||
#if FOR_DYLD
|
||||
// implemented in dyld
|
||||
extern struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
extern void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc);
|
||||
#if defined(_LIBUNWIND_HAS_NO_THREADS)
|
||||
# define _LIBUNWIND_THREAD_LOCAL
|
||||
#else
|
||||
static struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
|
||||
{
|
||||
return (struct _Unwind_FunctionContext*)_pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
|
||||
}
|
||||
|
||||
static void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
|
||||
{
|
||||
_pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
|
||||
}
|
||||
# if __STDC_VERSION__ >= 201112L
|
||||
# define _LIBUNWIND_THREAD_LOCAL _Thread_local
|
||||
# elif defined(_MSC_VER)
|
||||
# define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define _LIBUNWIND_THREAD_LOCAL __thread
|
||||
# else
|
||||
# error Unable to create thread local storage
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Called at start of each function that catches exceptions
|
||||
//
|
||||
EXPORT void _Unwind_SjLj_Register(struct _Unwind_FunctionContext* fc)
|
||||
{
|
||||
fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(fc);
|
||||
#if !defined(FOR_DYLD)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <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)
|
||||
{
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
|
||||
/// Called at end of each function that catches exceptions
|
||||
_LIBUNWIND_EXPORT void
|
||||
_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
|
||||
}
|
||||
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1: initial function-context=%p\n", c);
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase1(struct _Unwind_Exception *exception_object) {
|
||||
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",
|
||||
(void *)c);
|
||||
|
||||
// walk each frame looking for a place to stop
|
||||
for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
|
||||
// walk each frame looking for a place to stop
|
||||
for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
|
||||
|
||||
// check for no more frames
|
||||
if ( c == NULL ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): reached bottom => _URC_END_OF_STACK\n", exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1: function-context=%p\n", c);
|
||||
// if there is a personality routine, ask it if it will want to stop at this frame
|
||||
if ( c->personality != NULL ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, c->personality);
|
||||
_Unwind_Reason_Code personalityResult = (*c->personality)(1, _UA_SEARCH_PHASE,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)c);
|
||||
switch ( personalityResult ) {
|
||||
case _URC_HANDLER_FOUND:
|
||||
// found a catch clause or locals that need destructing in this frame
|
||||
// stop search and remember function context
|
||||
handlerNotFound = false;
|
||||
exception_object->private_2 = (uintptr_t)c;
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
|
||||
return _URC_NO_REASON;
|
||||
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
|
||||
// continue unwinding
|
||||
break;
|
||||
|
||||
default:
|
||||
// something went wrong
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
// check for no more frames
|
||||
if (c == NULL) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
|
||||
"bottom => _URC_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);
|
||||
// if there is a personality routine, ask it if it will want to stop at this
|
||||
// frame
|
||||
if (c->personality != NULL) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
|
||||
"personality function %p",
|
||||
(void *)exception_object,
|
||||
(void *)c->personality);
|
||||
_Unwind_Reason_Code personalityResult = (*c->personality)(
|
||||
1, _UA_SEARCH_PHASE, exception_object->exception_class,
|
||||
exception_object, (struct _Unwind_Context *)c);
|
||||
switch (personalityResult) {
|
||||
case _URC_HANDLER_FOUND:
|
||||
// found a catch clause or locals that need destructing in this frame
|
||||
// stop search and remember function context
|
||||
handlerNotFound = false;
|
||||
exception_object->private_2 = (uintptr_t) c;
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
|
||||
"_URC_HANDLER_FOUND",
|
||||
(void *)exception_object);
|
||||
return _URC_NO_REASON;
|
||||
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
|
||||
"_URC_CONTINUE_UNWIND",
|
||||
(void *)exception_object);
|
||||
// continue unwinding
|
||||
break;
|
||||
|
||||
default:
|
||||
// something went wrong
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
|
||||
|
||||
// walk each frame until we reach where search phase said to stop
|
||||
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
while ( true ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2s(ex_ojb=%p): function-context=%p\n", exception_object, c);
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase2(struct _Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
|
||||
(void *)exception_object);
|
||||
|
||||
// check for no more frames
|
||||
if ( c == NULL ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
// if there is a personality routine, tell it we are unwinding
|
||||
if ( c->personality != NULL ) {
|
||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||
if ( (uintptr_t)c == exception_object->private_2 )
|
||||
action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
|
||||
_Unwind_Reason_Code personalityResult = (*c->personality)(1, action,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)c);
|
||||
switch ( personalityResult ) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// continue unwinding
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
|
||||
if ( (uintptr_t)c == exception_object->private_2 ) {
|
||||
// phase 1 said we would stop at this frame, but we did not...
|
||||
ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
|
||||
}
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT, will resume at landing pad %p\n", exception_object, c->jbuf[1]);
|
||||
// personality routine says to transfer control to landing pad
|
||||
// we may get control back if landing pad calls _Unwind_Resume()
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(c);
|
||||
__builtin_longjmp(c->jbuf, 1);
|
||||
// unw_resume() only returns if there was an error
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
default:
|
||||
// something went wrong
|
||||
DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
c = c->prev;
|
||||
}
|
||||
// walk each frame until we reach where search phase said to stop
|
||||
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
while (true) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
|
||||
(void *)exception_object, (void *)c);
|
||||
|
||||
// clean up phase did not resume at the frame that the search phase said it would
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
// check for no more frames
|
||||
if (c == NULL) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
|
||||
"bottom => _URC_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
// if there is a personality routine, tell it we are unwinding
|
||||
if (c->personality != NULL) {
|
||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||
if ((uintptr_t) c == exception_object->private_2)
|
||||
action = (_Unwind_Action)(
|
||||
_UA_CLEANUP_PHASE |
|
||||
_UA_HANDLER_FRAME); // tell personality this was the frame it marked
|
||||
// in phase 1
|
||||
_Unwind_Reason_Code personalityResult =
|
||||
(*c->personality)(1, action, exception_object->exception_class,
|
||||
exception_object, (struct _Unwind_Context *)c);
|
||||
switch (personalityResult) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// continue unwinding
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
|
||||
(void *)exception_object);
|
||||
if ((uintptr_t) c == exception_object->private_2) {
|
||||
// phase 1 said we would stop at this frame, but we did not...
|
||||
_LIBUNWIND_ABORT("during phase1 personality function said it would "
|
||||
"stop here, but now if phase2 it did not stop here");
|
||||
}
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
|
||||
"_URC_INSTALL_CONTEXT, will resume at "
|
||||
"landing pad %p",
|
||||
(void *)exception_object, c->jbuf[1]);
|
||||
// personality routine says to transfer control to landing pad
|
||||
// we may get control back if landing pad calls _Unwind_Resume()
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(c);
|
||||
__builtin_longjmp(c->jbuf, 1);
|
||||
// __unw_resume() only returns if there was an error
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
default:
|
||||
// something went wrong
|
||||
_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
|
||||
personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
c = c->prev;
|
||||
}
|
||||
|
||||
// clean up phase did not resume at the frame that the search phase said it
|
||||
// would
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase2_forced(struct _Unwind_Exception* exception_object,
|
||||
_Unwind_Stop_Fn stop, void* stop_parameter)
|
||||
{
|
||||
// walk each frame until we reach where search phase said to stop
|
||||
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
while ( true ) {
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase2_forced(struct _Unwind_Exception *exception_object,
|
||||
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||
// walk each frame until we reach where search phase said to stop
|
||||
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||
while (true) {
|
||||
|
||||
// get next frame (skip over first which is _Unwind_RaiseException)
|
||||
if ( c == NULL ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
// call stop function at each frame
|
||||
_Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
|
||||
_Unwind_Reason_Code stopResult = (*stop)(1, action,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)c, stop_parameter);
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
|
||||
if ( stopResult != _URC_NO_REASON ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// if there is a personality routine, tell it we are unwinding
|
||||
if ( c->personality != NULL ) {
|
||||
__personality_routine p = (__personality_routine)c->personality;
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
|
||||
_Unwind_Reason_Code personalityResult = (*p)(1, action,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)c);
|
||||
switch ( personalityResult ) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
|
||||
// destructors called, continue unwinding
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
|
||||
// we may get control back if landing pad calls _Unwind_Resume()
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(c);
|
||||
__builtin_longjmp(c->jbuf, 1);
|
||||
break;
|
||||
default:
|
||||
// something went wrong
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
|
||||
exception_object, personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
c = c->prev;
|
||||
}
|
||||
// get next frame (skip over first which is _Unwind_RaiseException)
|
||||
if (c == NULL) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
|
||||
"bottom => _URC_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
// call stop function one last time and tell it we've reached the end of the stack
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
|
||||
_Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
|
||||
(*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)c, stop_parameter);
|
||||
|
||||
// clean up phase did not resume at the frame that the search phase said it would
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
// call stop function at each frame
|
||||
_Unwind_Action action =
|
||||
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
|
||||
_Unwind_Reason_Code stopResult =
|
||||
(*stop)(1, action, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)c, stop_parameter);
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"stop function returned %d",
|
||||
(void *)exception_object, stopResult);
|
||||
if (stopResult != _URC_NO_REASON) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"stopped by stop function",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// if there is a personality routine, tell it we are unwinding
|
||||
if (c->personality != NULL) {
|
||||
_Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality;
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"calling personality function %p",
|
||||
(void *)exception_object, (void *)p);
|
||||
_Unwind_Reason_Code personalityResult =
|
||||
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)c);
|
||||
switch (personalityResult) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"personality returned _URC_CONTINUE_UNWIND",
|
||||
(void *)exception_object);
|
||||
// destructors called, continue unwinding
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"personality returned _URC_INSTALL_CONTEXT",
|
||||
(void *)exception_object);
|
||||
// we may get control back if landing pad calls _Unwind_Resume()
|
||||
__Unwind_SjLj_SetTopOfFunctionStack(c);
|
||||
__builtin_longjmp(c->jbuf, 1);
|
||||
break;
|
||||
default:
|
||||
// something went wrong
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"personality returned %d, "
|
||||
"_URC_FATAL_PHASE2_ERROR",
|
||||
(void *)exception_object, personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
c = c->prev;
|
||||
}
|
||||
|
||||
// call stop function one last time and tell it we've reached the end of the
|
||||
// stack
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
|
||||
"function with _UA_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
_Unwind_Action lastAction =
|
||||
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
|
||||
(*stop)(1, lastAction, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)c, stop_parameter);
|
||||
|
||||
// clean up phase did not resume at the frame that the search phase said it
|
||||
// would
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by __cxa_throw. Only returns if there is a fatal error
|
||||
//
|
||||
EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object);
|
||||
/// Called by __cxa_throw. Only returns if there is a fatal error
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",
|
||||
(void *)exception_object);
|
||||
|
||||
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
|
||||
exception_object->private_1 = 0;
|
||||
exception_object->private_2 = 0;
|
||||
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
|
||||
// thing
|
||||
exception_object->private_1 = 0;
|
||||
exception_object->private_2 = 0;
|
||||
|
||||
// phase 1: the search phase
|
||||
_Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
|
||||
if ( phase1 != _URC_NO_REASON )
|
||||
return phase1;
|
||||
|
||||
// phase 2: the clean up phase
|
||||
return unwind_phase2(exception_object);
|
||||
}
|
||||
// phase 1: the search phase
|
||||
_Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
|
||||
if (phase1 != _URC_NO_REASON)
|
||||
return phase1;
|
||||
|
||||
|
||||
//
|
||||
// When _Unwind_RaiseException() is in phase2, it hands control
|
||||
// to the personality function at each frame. The personality
|
||||
// may force a jump to a landing pad in that function, the landing
|
||||
// pad code may then call _Unwind_Resume() to continue with the
|
||||
// unwinding. Note: the call to _Unwind_Resume() is from compiler
|
||||
// geneated user code. All other _Unwind_* routines are called
|
||||
// by the C++ runtime __cxa_* routines.
|
||||
//
|
||||
// Re-throwing an exception is implemented by having the code call
|
||||
// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
|
||||
//
|
||||
EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object);
|
||||
|
||||
if ( exception_object->private_1 != 0 )
|
||||
unwind_phase2_forced(exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
|
||||
else
|
||||
unwind_phase2(exception_object);
|
||||
|
||||
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||
ABORT("_Unwind_SjLj_Resume() can't return");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by __cxa_rethrow()
|
||||
//
|
||||
EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
|
||||
// if this is non-forced and a stopping place was found, then this is a re-throw
|
||||
// call _Unwind_RaiseException() as if this was a new exception
|
||||
if ( exception_object->private_1 == 0 ) {
|
||||
return _Unwind_SjLj_RaiseException(exception_object);
|
||||
// should return if there is no catch clause, so that __cxa_rethrow can call std::terminate()
|
||||
}
|
||||
|
||||
// call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
|
||||
_Unwind_SjLj_Resume(exception_object);
|
||||
ABORT("__Unwind_SjLj_Resume_or_Rethrow() called _Unwind_SjLj_Resume() which unexpectedly returned");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get LSDA for current frame
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
|
||||
{
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%0lX\n", context, ufc->lsda);
|
||||
return ufc->lsda;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get register values
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d)\n", context, index);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
return ufc->resumeParameters[index];
|
||||
// phase 2: the clean up phase
|
||||
return unwind_phase2(exception_object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to alter register values
|
||||
//
|
||||
EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n", context, index, new_value);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
ufc->resumeParameters[index] = new_value;
|
||||
/// When _Unwind_RaiseException() is in phase2, it hands control
|
||||
/// to the personality function at each frame. The personality
|
||||
/// may force a jump to a landing pad in that function, the landing
|
||||
/// pad code may then call _Unwind_Resume() to continue with the
|
||||
/// unwinding. Note: the call to _Unwind_Resume() is from compiler
|
||||
/// geneated user code. All other _Unwind_* routines are called
|
||||
/// by the C++ runtime __cxa_* routines.
|
||||
///
|
||||
/// Re-throwing an exception is implemented by having the code call
|
||||
/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
|
||||
_LIBUNWIND_EXPORT void
|
||||
_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",
|
||||
(void *)exception_object);
|
||||
|
||||
if (exception_object->private_1 != 0)
|
||||
unwind_phase2_forced(exception_object,
|
||||
(_Unwind_Stop_Fn) exception_object->private_1,
|
||||
(void *)exception_object->private_2);
|
||||
else
|
||||
unwind_phase2(exception_object);
|
||||
|
||||
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||
_LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get instruction pointer
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
|
||||
{
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, ufc->resumeLocation+1);
|
||||
return ufc->resumeLocation+1;
|
||||
}
|
||||
/// Called by __cxa_rethrow().
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
|
||||
"private_1=%" PRIuPTR,
|
||||
(void *)exception_object, exception_object->private_1);
|
||||
// If this is non-forced and a stopping place was found, then this is a
|
||||
// re-throw.
|
||||
// Call _Unwind_RaiseException() as if this was a new exception.
|
||||
if (exception_object->private_1 == 0) {
|
||||
return _Unwind_SjLj_RaiseException(exception_object);
|
||||
// should return if there is no catch clause, so that __cxa_rethrow can call
|
||||
// std::terminate()
|
||||
}
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get instruction pointer
|
||||
// ipBefore is a boolean that says if IP is already adjusted to be the call
|
||||
// site address. Normally IP is the return address.
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
|
||||
{
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
*ipBefore = 0;
|
||||
DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", context, ipBefore, ufc->resumeLocation+1);
|
||||
return ufc->resumeLocation+1;
|
||||
// Call through to _Unwind_Resume() which distiguishes between forced and
|
||||
// regular exceptions.
|
||||
_Unwind_SjLj_Resume(exception_object);
|
||||
_LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
|
||||
"_Unwind_SjLj_Resume() which unexpectedly returned");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to alter instruction pointer
|
||||
//
|
||||
EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", context, new_value);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
ufc->resumeLocation = new_value-1;
|
||||
}
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to find the start of the function
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
|
||||
{
|
||||
// Not supported or needed for sjlj based unwinding
|
||||
DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p)\n", context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 if a foreign exception is caught
|
||||
//
|
||||
EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
|
||||
if ( exception_object->exception_cleanup != NULL )
|
||||
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
|
||||
/// Called by personality handler during phase 2 to get LSDA for current frame.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
|
||||
"=> 0x%" PRIuPTR,
|
||||
(void *)context, ufc->lsda);
|
||||
return ufc->lsda;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get base address for data relative encodings
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
|
||||
{
|
||||
// Not supported or needed for sjlj based unwinding
|
||||
DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
|
||||
ABORT("_Unwind_GetDataRelBase() not implemented");
|
||||
/// Called by personality handler during phase 2 to get register values.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
|
||||
int index) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,
|
||||
index);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
return ufc->resumeParameters[index];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get base address for text relative encodings
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
|
||||
{
|
||||
// Not supported or needed for sjlj based unwinding
|
||||
DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
|
||||
ABORT("_Unwind_GetTextRelBase() not implemented");
|
||||
/// Called by personality handler during phase 2 to alter register values.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t new_value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR
|
||||
")",
|
||||
(void *)context, index, new_value);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
ufc->resumeParameters[index] = new_value;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32,
|
||||
(void *)context, ufc->resumeLocation + 1);
|
||||
return ufc->resumeLocation + 1;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||
/// ipBefore is a boolean that says if IP is already adjusted to be the call
|
||||
/// site address. Normally IP is the return address.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||
int *ipBefore) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
*ipBefore = 0;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32,
|
||||
(void *)context, (void *)ipBefore,
|
||||
ufc->resumeLocation + 1);
|
||||
return ufc->resumeLocation + 1;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to alter instruction pointer.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||
uintptr_t new_value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")",
|
||||
(void *)context, new_value);
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
ufc->resumeLocation = new_value - 1;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to find the start of the
|
||||
/// function.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||
// Not supported or needed for sjlj based unwinding
|
||||
(void)context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 if a foreign exception
|
||||
/// is caught.
|
||||
_LIBUNWIND_EXPORT void
|
||||
_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
|
||||
(void *)exception_object);
|
||||
if (exception_object->exception_cleanup != NULL)
|
||||
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
|
||||
exception_object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler to get Call Frame Area for current frame
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_GetCFA(context=%p)\n", context);
|
||||
if ( context != NULL ) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
|
||||
// setjmp/longjmp based exceptions don't have a true CFA
|
||||
// the SP in the jmpbuf is the closest approximation
|
||||
return (uintptr_t)ufc->jbuf[2];
|
||||
}
|
||||
return 0;
|
||||
/// Called by personality handler during phase 2 to get base address for data
|
||||
/// relative encodings.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
|
||||
// Not supported or needed for sjlj based unwinding
|
||||
(void)context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
|
||||
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !FOR_DYLD && __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
//
|
||||
// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in earlier versions
|
||||
//
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_GetIP)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SetGR)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SetIP)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_DeleteException)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_GetGR)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_GetCFA)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
|
||||
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
|
||||
#endif // !FOR_DYLD
|
||||
/// Called by personality handler during phase 2 to get base address for text
|
||||
/// relative encodings.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
|
||||
// Not supported or needed for sjlj based unwinding
|
||||
(void)context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
|
||||
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
|
||||
}
|
||||
|
||||
|
||||
#endif // __arm__
|
||||
/// Called by personality handler to get "Call Frame Area" for current frame.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);
|
||||
if (context != NULL) {
|
||||
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||
// Setjmp/longjmp based exceptions don't have a true CFA.
|
||||
// Instead, the SP in the jmpbuf is the closest approximation.
|
||||
return (uintptr_t) ufc->jbuf[2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,306 +1,326 @@
|
||||
/* -*- mode: C++; c-basic-offset: 4; -*-
|
||||
*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Implements gcc extensions to the C++ ABI Exception Handling Level 1 as documented at:
|
||||
* <http://www.codesourcery.com/cxx-abi/abi-eh.html>
|
||||
* using libunwind
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
//===--------------------- 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 <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
|
||||
if ( exception_object->private_1 == 0 ) {
|
||||
return _Unwind_RaiseException(exception_object);
|
||||
// should return if there is no catch clause, so that __cxa_rethrow can call std::terminate()
|
||||
}
|
||||
|
||||
// call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
|
||||
_Unwind_Resume(exception_object);
|
||||
ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException() which unexpectedly returned");
|
||||
/// Called by __cxa_rethrow().
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
|
||||
(void *)exception_object,
|
||||
(long)exception_object->unwinder_cache.reserved1);
|
||||
#else
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
|
||||
(void *)exception_object,
|
||||
(intptr_t)exception_object->private_1);
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
// _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
|
||||
// which is in the same position as private_1 below.
|
||||
return _Unwind_RaiseException(exception_object);
|
||||
#else
|
||||
// If this is non-forced and a stopping place was found, then this is a
|
||||
// re-throw.
|
||||
// Call _Unwind_RaiseException() as if this was a new exception
|
||||
if (exception_object->private_1 == 0) {
|
||||
return _Unwind_RaiseException(exception_object);
|
||||
// Will return if there is no catch clause, so that __cxa_rethrow can call
|
||||
// std::terminate().
|
||||
}
|
||||
|
||||
// Call through to _Unwind_Resume() which distiguishes between forced and
|
||||
// regular exceptions.
|
||||
_Unwind_Resume(exception_object);
|
||||
_LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
|
||||
" which unexpectedly returned");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get base address for data relative encodings
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
|
||||
ABORT("_Unwind_GetDataRelBase() not implemented");
|
||||
}
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get base address for text relative encodings
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
|
||||
ABORT("_Unwind_GetTextRelBase() not implemented");
|
||||
/// Called by personality handler during phase 2 to get base address for data
|
||||
/// relative encodings.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
|
||||
(void)context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
|
||||
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Scans unwind information to find the function that contains the
|
||||
// specified code address "pc".
|
||||
//
|
||||
EXPORT void* _Unwind_FindEnclosingFunction(void* pc)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
|
||||
// This is slow, but works.
|
||||
// We create an unwind cursor then alter the IP to be pc
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
unw_proc_info_t info;
|
||||
unw_getcontext(&uc);
|
||||
unw_init_local(&cursor, &uc);
|
||||
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc);
|
||||
if ( unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS )
|
||||
return (void*)(long)info.start_ip;
|
||||
else
|
||||
return NULL;
|
||||
/// Called by personality handler during phase 2 to get base address for text
|
||||
/// relative encodings.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
|
||||
(void)context;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
|
||||
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Walk every frame and call trace function at each one. If trace function
|
||||
// returns anything other than _URC_NO_REASON, then walk is terminated.
|
||||
//
|
||||
EXPORT _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void* ref)
|
||||
{
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
unw_getcontext(&uc);
|
||||
unw_init_local(&cursor, &uc);
|
||||
|
||||
DEBUG_PRINT_API("_Unwind_Backtrace(callback=%p)\n", callback);
|
||||
/// Scans unwind information to find the function that contains the
|
||||
/// specified code address "pc".
|
||||
_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
|
||||
// This is slow, but works.
|
||||
// We create an unwind cursor then alter the IP to be pc
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
unw_proc_info_t info;
|
||||
__unw_getcontext(&uc);
|
||||
__unw_init_local(&cursor, &uc);
|
||||
__unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
|
||||
if (__unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
|
||||
return (void *)(intptr_t) info.start_ip;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// walk each frame
|
||||
while ( true ) {
|
||||
/// Walk every frame and call trace function at each one. If trace function
|
||||
/// returns anything other than _URC_NO_REASON, then walk is terminated.
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
__unw_getcontext(&uc);
|
||||
__unw_init_local(&cursor, &uc);
|
||||
|
||||
// ask libuwind to get next frame (skip over first frame which is _Unwind_Backtrace())
|
||||
if ( unw_step(&cursor) <= 0 ) {
|
||||
DEBUG_PRINT_UNWINDING(" _backtrace: ended because cursor reached bottom of stack, returning %d\n", _URC_END_OF_STACK);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
// debugging
|
||||
if ( DEBUG_PRINT_UNWINDING_TEST ) {
|
||||
char functionName[512];
|
||||
unw_proc_info_t frameInfo;
|
||||
unw_word_t offset;
|
||||
unw_get_proc_name(&cursor, functionName, 512, &offset);
|
||||
unw_get_proc_info(&cursor, &frameInfo);
|
||||
DEBUG_PRINT_UNWINDING(" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
|
||||
frameInfo.start_ip, functionName, frameInfo.lsda, &cursor);
|
||||
}
|
||||
|
||||
// call trace function with this frame
|
||||
_Unwind_Reason_Code result = (*callback)((struct _Unwind_Context*)(&cursor), ref);
|
||||
if ( result != _URC_NO_REASON ) {
|
||||
DEBUG_PRINT_UNWINDING(" _backtrace: ended because callback returned %d\n", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
|
||||
(void *)(uintptr_t)callback);
|
||||
|
||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||
// Create a mock exception object for force unwinding.
|
||||
_Unwind_Exception ex;
|
||||
memset(&ex, '\0', sizeof(ex));
|
||||
ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
|
||||
#endif
|
||||
|
||||
// walk each frame
|
||||
while (true) {
|
||||
_Unwind_Reason_Code result;
|
||||
|
||||
#if !defined(_LIBUNWIND_ARM_EHABI)
|
||||
// ask libunwind to get next frame (skip over first frame which is
|
||||
// _Unwind_Backtrace())
|
||||
if (__unw_step(&cursor) <= 0) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
|
||||
"bottom of stack, returning %d",
|
||||
_URC_END_OF_STACK);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
#else
|
||||
// Get the information for this frame.
|
||||
unw_proc_info_t frameInfo;
|
||||
if (__unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
// Update the pr_cache in the mock exception object.
|
||||
const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
|
||||
ex.pr_cache.fnstart = frameInfo.start_ip;
|
||||
ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
|
||||
ex.pr_cache.additional= frameInfo.flags;
|
||||
|
||||
struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
|
||||
// Get and call the personality function to unwind the frame.
|
||||
_Unwind_Personality_Fn handler = (_Unwind_Personality_Fn)frameInfo.handler;
|
||||
if (handler == NULL) {
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
|
||||
_URC_CONTINUE_UNWIND) {
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
// debugging
|
||||
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||
char functionName[512];
|
||||
unw_proc_info_t frame;
|
||||
unw_word_t offset;
|
||||
__unw_get_proc_name(&cursor, functionName, 512, &offset);
|
||||
__unw_get_proc_info(&cursor, &frame);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
" _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
|
||||
frame.start_ip, functionName, frame.lsda,
|
||||
(void *)&cursor);
|
||||
}
|
||||
|
||||
// call trace function with this frame
|
||||
result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
|
||||
if (result != _URC_NO_REASON) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
" _backtrace: ended because callback returned %d", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Find dwarf unwind info for an address 'pc' in some function.
|
||||
//
|
||||
EXPORT const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases* bases)
|
||||
{
|
||||
// This is slow, but works.
|
||||
// We create an unwind cursor then alter the IP to be pc
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
unw_proc_info_t info;
|
||||
unw_getcontext(&uc);
|
||||
unw_init_local(&cursor, &uc);
|
||||
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc);
|
||||
unw_get_proc_info(&cursor, &info);
|
||||
bases->tbase = info.extra;
|
||||
bases->dbase = 0; // dbase not used on Mac OS X
|
||||
bases->func = info.start_ip;
|
||||
DEBUG_PRINT_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, (void*)(long)info.unwind_info);
|
||||
return (void*)(long)info.unwind_info;
|
||||
/// Find DWARF unwind info for an address 'pc' in some function.
|
||||
_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
|
||||
struct dwarf_eh_bases *bases) {
|
||||
// This is slow, but works.
|
||||
// We create an unwind cursor then alter the IP to be pc
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
unw_proc_info_t info;
|
||||
__unw_getcontext(&uc);
|
||||
__unw_init_local(&cursor, &uc);
|
||||
__unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
|
||||
__unw_get_proc_info(&cursor, &info);
|
||||
bases->tbase = (uintptr_t)info.extra;
|
||||
bases->dbase = 0; // dbase not used on Mac OS X
|
||||
bases->func = (uintptr_t)info.start_ip;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
|
||||
(void *)(intptr_t) info.unwind_info);
|
||||
return (void *)(intptr_t) info.unwind_info;
|
||||
}
|
||||
|
||||
/// Returns the CFA (call frame area, or stack pointer at start of function)
|
||||
/// for the current context.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_word_t result;
|
||||
__unw_get_reg(cursor, UNW_REG_SP, &result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, result);
|
||||
return (uintptr_t)result;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||
/// ipBefore is a boolean that says if IP is already adjusted to be the call
|
||||
/// site address. Normally IP is the return address.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||
int *ipBefore) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context);
|
||||
int isSignalFrame = __unw_is_signal_frame((unw_cursor_t *)context);
|
||||
// Negative means some kind of error (probably UNW_ENOINFO), but we have no
|
||||
// good way to report that, and this maintains backward compatibility with the
|
||||
// implementation that hard-coded zero in every case, even signal frames.
|
||||
if (isSignalFrame <= 0)
|
||||
*ipBefore = 0;
|
||||
else
|
||||
*ipBefore = 1;
|
||||
return _Unwind_GetIP(context);
|
||||
}
|
||||
|
||||
EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
|
||||
{
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_word_t result;
|
||||
unw_get_reg(cursor, UNW_REG_SP, &result);
|
||||
DEBUG_PRINT_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, (uint64_t)result);
|
||||
return result;
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
||||
/// Called by programs with dynamic code generators that want
|
||||
/// to register a dynamically generated FDE.
|
||||
/// This function has existed on Mac OS X since 10.4, but
|
||||
/// was broken until 10.6.
|
||||
_LIBUNWIND_EXPORT void __register_frame(const void *fde) {
|
||||
_LIBUNWIND_TRACE_API("__register_frame(%p)", fde);
|
||||
__unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get instruction pointer.
|
||||
// ipBefore is a boolean that says if IP is already adjusted to be the call
|
||||
// site address. Normally IP is the return address.
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p)\n", context);
|
||||
*ipBefore = 0;
|
||||
return _Unwind_GetIP(context);
|
||||
/// Called by programs with dynamic code generators that want
|
||||
/// to unregister a dynamically generated FDE.
|
||||
/// This function has existed on Mac OS X since 10.4, but
|
||||
/// was broken until 10.6.
|
||||
_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
|
||||
_LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde);
|
||||
__unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by programs with dynamic code generators that want
|
||||
// to register a dynamically generated FDE.
|
||||
// This function has existed on Mac OS X since 10.4, but
|
||||
// never worked before.
|
||||
//
|
||||
EXPORT void __register_frame(const void* fde)
|
||||
{
|
||||
DEBUG_PRINT_API("__register_frame(%p)\n", fde);
|
||||
_unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by programs with dynamic code generators that want
|
||||
// to unregister a dynamically generated FDE.
|
||||
// This function has existed on Mac OS X since 10.4, but
|
||||
// never worked before.
|
||||
//
|
||||
EXPORT void __deregister_frame(const void* fde)
|
||||
{
|
||||
DEBUG_PRINT_API("__deregister_frame(%p)\n", fde);
|
||||
_unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The following register/deregister functions are gcc extensions.
|
||||
// The following register/deregister functions are gcc extensions.
|
||||
// They have existed on Mac OS X, but have never worked because Mac OS X
|
||||
// before 10.6 used keymgr to track known FDEs, but these functions
|
||||
// never got updated to use keymgr.
|
||||
// For now, we implement these as do-nothing functions to keep any existing
|
||||
// applications working. We also add the not in 10.6 symbol so that nwe
|
||||
// application won't be able to use them.
|
||||
//
|
||||
|
||||
EXPORT void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db)
|
||||
{
|
||||
DEBUG_PRINT_API("__register_frame_info_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
|
||||
_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
|
||||
void *tb, void *db) {
|
||||
(void)fde;
|
||||
(void)ob;
|
||||
(void)tb;
|
||||
(void)db;
|
||||
_LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",
|
||||
fde, ob, tb, db);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
}
|
||||
|
||||
EXPORT void __register_frame_info(const void* fde, void* ob)
|
||||
{
|
||||
DEBUG_PRINT_API("__register_frame_info(%p, %p)\n", fde, ob);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {
|
||||
(void)fde;
|
||||
(void)ob;
|
||||
_LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
}
|
||||
|
||||
|
||||
EXPORT void __register_frame_info_table_bases(const void* fde, void* ob, void* tb, void* db)
|
||||
{
|
||||
DEBUG_PRINT_API("__register_frame_info_table_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
|
||||
void *ob, void *tb,
|
||||
void *db) {
|
||||
(void)fde;
|
||||
(void)ob;
|
||||
(void)tb;
|
||||
(void)db;
|
||||
_LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
|
||||
"(%p,%p, %p, %p)", fde, ob, tb, db);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
}
|
||||
|
||||
EXPORT void __register_frame_info_table(const void* fde, void* ob)
|
||||
{
|
||||
DEBUG_PRINT_API("__register_frame_info_table(%p, %p)\n", fde, ob);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {
|
||||
(void)fde;
|
||||
(void)ob;
|
||||
_LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
}
|
||||
|
||||
EXPORT void __register_frame_table(const void* fde)
|
||||
{
|
||||
DEBUG_PRINT_API("__register_frame_table(%p)\n", fde);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {
|
||||
(void)fde;
|
||||
_LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
}
|
||||
|
||||
EXPORT void* __deregister_frame_info(const void* fde)
|
||||
{
|
||||
DEBUG_PRINT_API("__deregister_frame_info(%p)\n", fde);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
return NULL;
|
||||
_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {
|
||||
(void)fde;
|
||||
_LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT void* __deregister_frame_info_bases(const void* fde)
|
||||
{
|
||||
DEBUG_PRINT_API("__deregister_frame_info_bases(%p)\n", fde);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
return NULL;
|
||||
_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
|
||||
(void)fde;
|
||||
_LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde);
|
||||
// do nothing, this function never worked in Mac OS X
|
||||
return NULL;
|
||||
}
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
|
||||
|
||||
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
||||
|
||||
|
||||
//
|
||||
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
|
||||
//
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
|
||||
|
||||
NOT_HERE_BEFORE_10_6(__register_frame)
|
||||
NOT_HERE_BEFORE_10_6(__deregister_frame)
|
||||
|
||||
|
||||
//
|
||||
// symbols in libSystem.dylib for compatibility, but we don't want any new code using them
|
||||
//
|
||||
NEVER_HERE(__register_frame_info_bases)
|
||||
NEVER_HERE(__register_frame_info)
|
||||
NEVER_HERE(__register_frame_info_table_bases)
|
||||
NEVER_HERE(__register_frame_info_table)
|
||||
NEVER_HERE(__register_frame_table)
|
||||
NEVER_HERE(__deregister_frame_info)
|
||||
NEVER_HERE(__deregister_frame_info_bases)
|
||||
|
||||
|
||||
#endif // __ppc__ || __i386__ || __x86_64__
|
||||
|
||||
#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||
|
@ -1,455 +1,518 @@
|
||||
/* -*- mode: C++; c-basic-offset: 4; -*-
|
||||
*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
*
|
||||
* Implements C++ ABI Exception Handling Level 1 as documented at:
|
||||
* <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);
|
||||
|
||||
// walk each frame looking for a place to stop
|
||||
for (bool handlerNotFound = true; handlerNotFound; ) {
|
||||
#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
||||
// ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
|
||||
int stepResult = unw_step(&cursor1);
|
||||
if ( stepResult == 0 ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
else if ( stepResult < 0 ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
// see if frame has code to run (has personality routine)
|
||||
unw_proc_info_t frameInfo;
|
||||
unw_word_t sp;
|
||||
if ( unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
// debugging
|
||||
if ( DEBUG_PRINT_UNWINDING_TEST ) {
|
||||
char functionName[512];
|
||||
unw_word_t offset;
|
||||
if ( (unw_get_proc_name(&cursor1, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
|
||||
strcpy(functionName, ".anonymous.");
|
||||
unw_word_t pc;
|
||||
unw_get_reg(&cursor1, UNW_REG_IP, &pc);
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
|
||||
exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
|
||||
// if there is a personality routine, ask it if it will want to stop at this frame
|
||||
if ( frameInfo.handler != 0 ) {
|
||||
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, p);
|
||||
_Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)(&cursor1));
|
||||
switch ( personalityResult ) {
|
||||
case _URC_HANDLER_FOUND:
|
||||
// found a catch clause or locals that need destructing in this frame
|
||||
// stop search and remember stack pointer at the frame
|
||||
handlerNotFound = false;
|
||||
unw_get_reg(&cursor1, UNW_REG_SP, &sp);
|
||||
exception_object->private_2 = sp;
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
|
||||
return _URC_NO_REASON;
|
||||
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
|
||||
// continue unwinding
|
||||
break;
|
||||
|
||||
default:
|
||||
// something went wrong
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||
__unw_init_local(cursor, uc);
|
||||
|
||||
// Walk each frame looking for a place to stop.
|
||||
bool handlerNotFound = true;
|
||||
while (handlerNotFound) {
|
||||
// Ask libunwind to get next frame (skip over first which is
|
||||
// _Unwind_RaiseException).
|
||||
int stepResult = __unw_step(cursor);
|
||||
if (stepResult == 0) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): __unw_step() reached "
|
||||
"bottom => _URC_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
} else if (stepResult < 0) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): __unw_step failed => "
|
||||
"_URC_FATAL_PHASE1_ERROR",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
// See if frame has code to run (has personality routine).
|
||||
unw_proc_info_t frameInfo;
|
||||
unw_word_t sp;
|
||||
if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): __unw_get_proc_info "
|
||||
"failed => _URC_FATAL_PHASE1_ERROR",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
// When tracing, print state information.
|
||||
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||
char functionBuf[512];
|
||||
const char *functionName = functionBuf;
|
||||
unw_word_t offset;
|
||||
if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
|
||||
&offset) != UNW_ESUCCESS) ||
|
||||
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||
functionName = ".anonymous.";
|
||||
unw_word_t pc;
|
||||
__unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
|
||||
", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
|
||||
(void *)exception_object, pc, frameInfo.start_ip, functionName,
|
||||
frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
|
||||
// If there is a personality routine, ask it if it will want to stop at
|
||||
// this frame.
|
||||
if (frameInfo.handler != 0) {
|
||||
_Unwind_Personality_Fn p =
|
||||
(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): calling personality function %p",
|
||||
(void *)exception_object, (void *)(uintptr_t)p);
|
||||
_Unwind_Reason_Code personalityResult =
|
||||
(*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
|
||||
exception_object, (struct _Unwind_Context *)(cursor));
|
||||
switch (personalityResult) {
|
||||
case _URC_HANDLER_FOUND:
|
||||
// found a catch clause or locals that need destructing in this frame
|
||||
// stop search and remember stack pointer at the frame
|
||||
handlerNotFound = false;
|
||||
__unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||
exception_object->private_2 = (uintptr_t)sp;
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
|
||||
(void *)exception_object);
|
||||
return _URC_NO_REASON;
|
||||
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
|
||||
(void *)exception_object);
|
||||
// continue unwinding
|
||||
break;
|
||||
|
||||
default:
|
||||
// something went wrong
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase2(unw_context_t* uc, struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
unw_cursor_t cursor2;
|
||||
unw_init_local(&cursor2, uc);
|
||||
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
|
||||
|
||||
// walk each frame until we reach where search phase said to stop
|
||||
while ( true ) {
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||
__unw_init_local(cursor, uc);
|
||||
|
||||
// ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
|
||||
int stepResult = unw_step(&cursor2);
|
||||
if ( stepResult == 0 ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
else if ( stepResult < 0 ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// get info about this frame
|
||||
unw_word_t sp;
|
||||
unw_proc_info_t frameInfo;
|
||||
unw_get_reg(&cursor2, UNW_REG_SP, &sp);
|
||||
if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// debugging
|
||||
if ( DEBUG_PRINT_UNWINDING_TEST ) {
|
||||
char functionName[512];
|
||||
unw_word_t offset;
|
||||
if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
|
||||
strcpy(functionName, ".anonymous.");
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, lsda=0x%llX, personality=0x%llX\n",
|
||||
exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
|
||||
// if there is a personality routine, tell it we are unwinding
|
||||
if ( frameInfo.handler != 0 ) {
|
||||
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
|
||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||
if ( sp == exception_object->private_2 )
|
||||
action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
|
||||
_Unwind_Reason_Code personalityResult = (*p)(1, action,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)(&cursor2));
|
||||
switch ( personalityResult ) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// continue unwinding
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
|
||||
if ( sp == exception_object->private_2 ) {
|
||||
// phase 1 said we would stop at this frame, but we did not...
|
||||
ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
|
||||
}
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object);
|
||||
// personality routine says to transfer control to landing pad
|
||||
// we may get control back if landing pad calls _Unwind_Resume()
|
||||
if ( DEBUG_PRINT_UNWINDING_TEST ) {
|
||||
unw_word_t pc;
|
||||
unw_word_t sp;
|
||||
unw_get_reg(&cursor2, UNW_REG_IP, &pc);
|
||||
unw_get_reg(&cursor2, UNW_REG_SP, &sp);
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp);
|
||||
}
|
||||
unw_resume(&cursor2);
|
||||
// unw_resume() only returns if there was an error
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
default:
|
||||
// something went wrong
|
||||
DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
|
||||
(void *)exception_object);
|
||||
|
||||
// clean up phase did not resume at the frame that the search phase said it would
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
// Walk each frame until we reach where search phase said to stop.
|
||||
while (true) {
|
||||
|
||||
// Ask libunwind to get next frame (skip over first which is
|
||||
// _Unwind_RaiseException).
|
||||
int stepResult = __unw_step(cursor);
|
||||
if (stepResult == 0) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
|
||||
"bottom => _URC_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
return _URC_END_OF_STACK;
|
||||
} else if (stepResult < 0) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): __unw_step failed => "
|
||||
"_URC_FATAL_PHASE1_ERROR",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// Get info about this frame.
|
||||
unw_word_t sp;
|
||||
unw_proc_info_t frameInfo;
|
||||
__unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||
if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): __unw_get_proc_info "
|
||||
"failed => _URC_FATAL_PHASE1_ERROR",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// When tracing, print state information.
|
||||
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||
char functionBuf[512];
|
||||
const char *functionName = functionBuf;
|
||||
unw_word_t offset;
|
||||
if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
|
||||
&offset) != UNW_ESUCCESS) ||
|
||||
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||
functionName = ".anonymous.";
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
|
||||
", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
|
||||
", personality=0x%" PRIxPTR,
|
||||
(void *)exception_object, frameInfo.start_ip,
|
||||
functionName, sp, frameInfo.lsda,
|
||||
frameInfo.handler);
|
||||
}
|
||||
|
||||
// If there is a personality routine, tell it we are unwinding.
|
||||
if (frameInfo.handler != 0) {
|
||||
_Unwind_Personality_Fn p =
|
||||
(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
|
||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||
if (sp == exception_object->private_2) {
|
||||
// Tell personality this was the frame it marked in phase 1.
|
||||
action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
|
||||
}
|
||||
_Unwind_Reason_Code personalityResult =
|
||||
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)(cursor));
|
||||
switch (personalityResult) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
// Continue unwinding
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
|
||||
(void *)exception_object);
|
||||
if (sp == exception_object->private_2) {
|
||||
// Phase 1 said we would stop at this frame, but we did not...
|
||||
_LIBUNWIND_ABORT("during phase1 personality function said it would "
|
||||
"stop here, but now in phase2 it did not stop here");
|
||||
}
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
|
||||
(void *)exception_object);
|
||||
// Personality routine says to transfer control to landing pad.
|
||||
// We may get control back if landing pad calls _Unwind_Resume().
|
||||
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||
unw_word_t pc;
|
||||
__unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||
__unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
|
||||
"user code with ip=0x%" PRIxPTR
|
||||
", sp=0x%" PRIxPTR,
|
||||
(void *)exception_object, pc, sp);
|
||||
}
|
||||
__unw_resume(cursor);
|
||||
// __unw_resume() only returns if there was an error.
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
default:
|
||||
// Personality routine returned an unknown result code.
|
||||
_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
|
||||
personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up phase did not resume at the frame that the search phase
|
||||
// said it would...
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
|
||||
_Unwind_Exception *exception_object,
|
||||
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||
__unw_init_local(cursor, uc);
|
||||
|
||||
// Walk each frame until we reach where search phase said to stop
|
||||
while (__unw_step(cursor) > 0) {
|
||||
|
||||
// Update info about this frame.
|
||||
unw_proc_info_t frameInfo;
|
||||
if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step "
|
||||
"failed => _URC_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// When tracing, print state information.
|
||||
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||
char functionBuf[512];
|
||||
const char *functionName = functionBuf;
|
||||
unw_word_t offset;
|
||||
if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
|
||||
&offset) != UNW_ESUCCESS) ||
|
||||
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||
functionName = ".anonymous.";
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
|
||||
", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
|
||||
(void *)exception_object, frameInfo.start_ip, functionName,
|
||||
frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
|
||||
// Call stop function at each frame.
|
||||
_Unwind_Action action =
|
||||
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
|
||||
_Unwind_Reason_Code stopResult =
|
||||
(*stop)(1, action, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)(cursor), stop_parameter);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
|
||||
(void *)exception_object, stopResult);
|
||||
if (stopResult != _URC_NO_REASON) {
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
|
||||
(void *)exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// If there is a personality routine, tell it we are unwinding.
|
||||
if (frameInfo.handler != 0) {
|
||||
_Unwind_Personality_Fn p =
|
||||
(_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
|
||||
_LIBUNWIND_TRACE_UNWINDING(
|
||||
"unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
|
||||
(void *)exception_object, (void *)(uintptr_t)p);
|
||||
_Unwind_Reason_Code personalityResult =
|
||||
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)(cursor));
|
||||
switch (personalityResult) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"personality returned "
|
||||
"_URC_CONTINUE_UNWIND",
|
||||
(void *)exception_object);
|
||||
// Destructors called, continue unwinding
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"personality returned "
|
||||
"_URC_INSTALL_CONTEXT",
|
||||
(void *)exception_object);
|
||||
// We may get control back if landing pad calls _Unwind_Resume().
|
||||
__unw_resume(cursor);
|
||||
break;
|
||||
default:
|
||||
// Personality routine returned an unknown result code.
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||
"personality returned %d, "
|
||||
"_URC_FATAL_PHASE2_ERROR",
|
||||
(void *)exception_object, personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call stop function one last time and tell it we've reached the end
|
||||
// of the stack.
|
||||
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
|
||||
"function with _UA_END_OF_STACK",
|
||||
(void *)exception_object);
|
||||
_Unwind_Action lastAction =
|
||||
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
|
||||
(*stop)(1, lastAction, exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context *)(cursor), stop_parameter);
|
||||
|
||||
// Clean up phase did not resume at the frame that the search phase said it
|
||||
// would.
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t* uc, struct _Unwind_Exception* exception_object,
|
||||
_Unwind_Stop_Fn stop, void* stop_parameter)
|
||||
{
|
||||
unw_cursor_t cursor2;
|
||||
unw_init_local(&cursor2, uc);
|
||||
|
||||
// walk each frame until we reach where search phase said to stop
|
||||
while ( unw_step(&cursor2) > 0 ) {
|
||||
|
||||
// get info about this frame
|
||||
unw_proc_info_t frameInfo;
|
||||
if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step failed => _URC_END_OF_STACK\n", exception_object);
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
// debugging
|
||||
if ( DEBUG_PRINT_UNWINDING_TEST ) {
|
||||
char functionName[512];
|
||||
unw_word_t offset;
|
||||
if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
|
||||
strcpy(functionName, ".anonymous.");
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
|
||||
exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
|
||||
}
|
||||
|
||||
// call stop function at each frame
|
||||
_Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
|
||||
_Unwind_Reason_Code stopResult = (*stop)(1, action,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)(&cursor2), stop_parameter);
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
|
||||
if ( stopResult != _URC_NO_REASON ) {
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
// if there is a personality routine, tell it we are unwinding
|
||||
if ( frameInfo.handler != 0 ) {
|
||||
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
|
||||
_Unwind_Reason_Code personalityResult = (*p)(1, action,
|
||||
exception_object->exception_class, exception_object,
|
||||
(struct _Unwind_Context*)(&cursor2));
|
||||
switch ( personalityResult ) {
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
|
||||
// destructors called, continue unwinding
|
||||
break;
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
|
||||
// we may get control back if landing pad calls _Unwind_Resume()
|
||||
unw_resume(&cursor2);
|
||||
break;
|
||||
default:
|
||||
// something went wrong
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
|
||||
exception_object, personalityResult);
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Called by __cxa_throw. Only returns if there is a fatal error.
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_RaiseException(_Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
|
||||
(void *)exception_object);
|
||||
unw_context_t uc;
|
||||
unw_cursor_t cursor;
|
||||
__unw_getcontext(&uc);
|
||||
|
||||
// call stop function one last time and tell it we've reached the end of the stack
|
||||
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
|
||||
_Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
|
||||
(*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)(&cursor2), stop_parameter);
|
||||
|
||||
// clean up phase did not resume at the frame that the search phase said it would
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
// Mark that this is a non-forced unwind, so _Unwind_Resume()
|
||||
// can do the right thing.
|
||||
exception_object->private_1 = 0;
|
||||
exception_object->private_2 = 0;
|
||||
|
||||
// phase 1: the search phase
|
||||
_Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object);
|
||||
if (phase1 != _URC_NO_REASON)
|
||||
return phase1;
|
||||
|
||||
//
|
||||
// Called by __cxa_throw. Only returns if there is a fatal error
|
||||
//
|
||||
EXPORT _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_RaiseException(ex_obj=%p)\n", exception_object);
|
||||
unw_context_t uc;
|
||||
unw_getcontext(&uc);
|
||||
|
||||
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
|
||||
exception_object->private_1 = 0;
|
||||
exception_object->private_2 = 0;
|
||||
|
||||
// phase 1: the search phase
|
||||
_Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
|
||||
if ( phase1 != _URC_NO_REASON )
|
||||
return phase1;
|
||||
|
||||
// phase 2: the clean up phase
|
||||
return unwind_phase2(&uc, exception_object);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// When _Unwind_RaiseException() is in phase2, it hands control
|
||||
// to the personality function at each frame. The personality
|
||||
// may force a jump to a landing pad in that function, the landing
|
||||
// pad code may then call _Unwind_Resume() to continue with the
|
||||
// unwinding. Note: the call to _Unwind_Resume() is from compiler
|
||||
// geneated user code. All other _Unwind_* routines are called
|
||||
// by the C++ runtime __cxa_* routines.
|
||||
//
|
||||
// Re-throwing an exception is implemented by having the code call
|
||||
// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
|
||||
//
|
||||
EXPORT void _Unwind_Resume(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_Resume(ex_obj=%p)\n", exception_object);
|
||||
unw_context_t uc;
|
||||
unw_getcontext(&uc);
|
||||
|
||||
if ( exception_object->private_1 != 0 )
|
||||
unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
|
||||
else
|
||||
unwind_phase2(&uc, exception_object);
|
||||
|
||||
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||
ABORT("_Unwind_Resume() can't return");
|
||||
// phase 2: the clean up phase
|
||||
return unwind_phase2(&uc, &cursor, exception_object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Not used by C++.
|
||||
// Unwinds stack, calling "stop" function at each frame
|
||||
// Could be used to implement longjmp().
|
||||
//
|
||||
EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", exception_object, stop);
|
||||
unw_context_t uc;
|
||||
unw_getcontext(&uc);
|
||||
/// When _Unwind_RaiseException() is in phase2, it hands control
|
||||
/// to the personality function at each frame. The personality
|
||||
/// may force a jump to a landing pad in that function, the landing
|
||||
/// pad code may then call _Unwind_Resume() to continue with the
|
||||
/// unwinding. Note: the call to _Unwind_Resume() is from compiler
|
||||
/// geneated user code. All other _Unwind_* routines are called
|
||||
/// by the C++ runtime __cxa_* routines.
|
||||
///
|
||||
/// Note: re-throwing an exception (as opposed to continuing the unwind)
|
||||
/// is implemented by having the code call __cxa_rethrow() which
|
||||
/// in turn calls _Unwind_Resume_or_Rethrow().
|
||||
_LIBUNWIND_EXPORT void
|
||||
_Unwind_Resume(_Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
|
||||
unw_context_t uc;
|
||||
unw_cursor_t cursor;
|
||||
__unw_getcontext(&uc);
|
||||
|
||||
// mark that this is a forced unwind, so _Unwind_Resume() can do the right thing
|
||||
exception_object->private_1 = (uintptr_t)stop;
|
||||
exception_object->private_2 = (uintptr_t)stop_parameter;
|
||||
|
||||
// doit
|
||||
return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
|
||||
}
|
||||
if (exception_object->private_1 != 0)
|
||||
unwind_phase2_forced(&uc, &cursor, exception_object,
|
||||
(_Unwind_Stop_Fn) exception_object->private_1,
|
||||
(void *)exception_object->private_2);
|
||||
else
|
||||
unwind_phase2(&uc, &cursor, exception_object);
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get LSDA for current frame
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
|
||||
{
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
uintptr_t result = 0;
|
||||
if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
|
||||
result = frameInfo.lsda;
|
||||
DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result);
|
||||
if ( result != 0 ) {
|
||||
if ( *((uint8_t*)result) != 0xFF )
|
||||
DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get register values
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
|
||||
{
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_word_t result;
|
||||
unw_get_reg(cursor, index, &result);
|
||||
DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n", context, index, (uint64_t)result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to alter register values
|
||||
//
|
||||
EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0llX)\n", context, index, (uint64_t)new_value);
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_set_reg(cursor, index, new_value);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to get instruction pointer
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
|
||||
{
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_word_t result;
|
||||
unw_get_reg(cursor, UNW_REG_IP, &result);
|
||||
DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context, (uint64_t)result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to alter instruction pointer
|
||||
//
|
||||
EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", context, (uint64_t)new_value);
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_set_reg(cursor, UNW_REG_IP, new_value);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 to find the start of the function
|
||||
//
|
||||
EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
|
||||
{
|
||||
unw_cursor_t* cursor = (unw_cursor_t*)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
uintptr_t result = 0;
|
||||
if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
|
||||
result = frameInfo.start_ip;
|
||||
DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called by personality handler during phase 2 if a foreign exception is caught
|
||||
//
|
||||
EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
|
||||
{
|
||||
DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
|
||||
if ( exception_object->exception_cleanup != NULL )
|
||||
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
|
||||
// Clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||
_LIBUNWIND_ABORT("_Unwind_Resume() can't return");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Not used by C++.
|
||||
/// Unwinds stack, calling "stop" function at each frame.
|
||||
/// Could be used to implement longjmp().
|
||||
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||
_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
|
||||
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
|
||||
(void *)exception_object, (void *)(uintptr_t)stop);
|
||||
unw_context_t uc;
|
||||
unw_cursor_t cursor;
|
||||
__unw_getcontext(&uc);
|
||||
|
||||
//
|
||||
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
|
||||
//
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_Resume)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
|
||||
NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
|
||||
// Mark that this is a forced unwind, so _Unwind_Resume() can do
|
||||
// the right thing.
|
||||
exception_object->private_1 = (uintptr_t) stop;
|
||||
exception_object->private_2 = (uintptr_t) stop_parameter;
|
||||
|
||||
#endif // __ppc__ || __i386__ || __x86_64__
|
||||
// do it
|
||||
return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter);
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to get LSDA for current frame.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
uintptr_t result = 0;
|
||||
if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
|
||||
result = (uintptr_t)frameInfo.lsda;
|
||||
_LIBUNWIND_TRACE_API(
|
||||
"_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, result);
|
||||
if (result != 0) {
|
||||
if (*((uint8_t *)result) != 0xFF)
|
||||
_LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
|
||||
result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// Called by personality handler during phase 2 to find the start of the
|
||||
/// function.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_proc_info_t frameInfo;
|
||||
uintptr_t result = 0;
|
||||
if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
|
||||
result = (uintptr_t)frameInfo.start_ip;
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND
|
||||
|
||||
/// Called by personality handler during phase 2 if a foreign exception
|
||||
// is caught.
|
||||
_LIBUNWIND_EXPORT void
|
||||
_Unwind_DeleteException(_Unwind_Exception *exception_object) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
|
||||
(void *)exception_object);
|
||||
if (exception_object->exception_cleanup != NULL)
|
||||
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
|
||||
exception_object);
|
||||
}
|
||||
|
||||
/// Called by personality handler during phase 2 to get register values.
|
||||
_LIBUNWIND_EXPORT uintptr_t
|
||||
_Unwind_GetGR(struct _Unwind_Context *context, int index) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_word_t result;
|
||||
__unw_get_reg(cursor, index, &result);
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,
|
||||
(void *)context, index, result);
|
||||
return (uintptr_t)result;
|
||||
}
|
||||
|
||||
/// Called by personality handler during phase 2 to alter register values.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||
uintptr_t value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR
|
||||
")",
|
||||
(void *)context, index, value);
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
__unw_set_reg(cursor, index, value);
|
||||
}
|
||||
|
||||
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
unw_word_t result;
|
||||
__unw_get_reg(cursor, UNW_REG_IP, &result);
|
||||
|
||||
|
||||
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
|
||||
(void *)context, result);
|
||||
return (uintptr_t)result;
|
||||
}
|
||||
|
||||
/// Called by personality handler during phase 2 to alter instruction pointer,
|
||||
/// such as setting where the landing pad is, so _Unwind_Resume() will
|
||||
/// start executing in the landing pad.
|
||||
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||
uintptr_t value) {
|
||||
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",
|
||||
(void *)context, value);
|
||||
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||
__unw_set_reg(cursor, UNW_REG_IP, value);
|
||||
}
|
||||
|
||||
#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
1157
libunwind/src/UnwindRegistersRestore.S
Normal file
1157
libunwind/src/UnwindRegistersRestore.S
Normal file
File diff suppressed because it is too large
Load Diff
1109
libunwind/src/UnwindRegistersSave.S
Normal file
1109
libunwind/src/UnwindRegistersSave.S
Normal file
File diff suppressed because it is too large
Load Diff
119
libunwind/src/Unwind_AppleExtras.cpp
Normal file
119
libunwind/src/Unwind_AppleExtras.cpp
Normal 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
165
libunwind/src/assembly.h
Normal 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
232
libunwind/src/config.h
Normal 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
|
@ -1,255 +1,239 @@
|
||||
//===------------------------------- dwarf2.h -----------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007-2008 Apple, Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
/* These constants were taken from version 3 of the DWARF standard,
|
||||
These constants were taken from version 3 of the DWARF standard,
|
||||
which is Copyright (c) 2005 Free Standards Group, and
|
||||
Copyright (c) 1992, 1993 UNIX International, Inc.
|
||||
Copyright (c) 1992, 1993 UNIX International, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __DWARF2__
|
||||
#define __DWARF2__
|
||||
|
||||
// dwarf unwind instructions
|
||||
// DWARF unwind instructions
|
||||
enum {
|
||||
DW_CFA_nop = 0x0,
|
||||
DW_CFA_set_loc = 0x1,
|
||||
DW_CFA_advance_loc1 = 0x2,
|
||||
DW_CFA_advance_loc2 = 0x3,
|
||||
DW_CFA_advance_loc4 = 0x4,
|
||||
DW_CFA_offset_extended = 0x5,
|
||||
DW_CFA_restore_extended = 0x6,
|
||||
DW_CFA_undefined = 0x7,
|
||||
DW_CFA_same_value = 0x8,
|
||||
DW_CFA_register = 0x9,
|
||||
DW_CFA_remember_state = 0xA,
|
||||
DW_CFA_restore_state = 0xB,
|
||||
DW_CFA_def_cfa = 0xC,
|
||||
DW_CFA_def_cfa_register = 0xD,
|
||||
DW_CFA_def_cfa_offset = 0xE,
|
||||
DW_CFA_def_cfa_expression = 0xF,
|
||||
DW_CFA_expression = 0x10,
|
||||
DW_CFA_offset_extended_sf = 0x11,
|
||||
DW_CFA_def_cfa_sf = 0x12,
|
||||
DW_CFA_def_cfa_offset_sf = 0x13,
|
||||
DW_CFA_val_offset = 0x14,
|
||||
DW_CFA_val_offset_sf = 0x15,
|
||||
DW_CFA_val_expression = 0x16,
|
||||
DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
|
||||
DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
|
||||
DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
|
||||
|
||||
// GNU extensions
|
||||
DW_CFA_GNU_window_save = 0x2D,
|
||||
DW_CFA_GNU_args_size = 0x2E,
|
||||
DW_CFA_GNU_negative_offset_extended = 0x2F
|
||||
DW_CFA_nop = 0x0,
|
||||
DW_CFA_set_loc = 0x1,
|
||||
DW_CFA_advance_loc1 = 0x2,
|
||||
DW_CFA_advance_loc2 = 0x3,
|
||||
DW_CFA_advance_loc4 = 0x4,
|
||||
DW_CFA_offset_extended = 0x5,
|
||||
DW_CFA_restore_extended = 0x6,
|
||||
DW_CFA_undefined = 0x7,
|
||||
DW_CFA_same_value = 0x8,
|
||||
DW_CFA_register = 0x9,
|
||||
DW_CFA_remember_state = 0xA,
|
||||
DW_CFA_restore_state = 0xB,
|
||||
DW_CFA_def_cfa = 0xC,
|
||||
DW_CFA_def_cfa_register = 0xD,
|
||||
DW_CFA_def_cfa_offset = 0xE,
|
||||
DW_CFA_def_cfa_expression = 0xF,
|
||||
DW_CFA_expression = 0x10,
|
||||
DW_CFA_offset_extended_sf = 0x11,
|
||||
DW_CFA_def_cfa_sf = 0x12,
|
||||
DW_CFA_def_cfa_offset_sf = 0x13,
|
||||
DW_CFA_val_offset = 0x14,
|
||||
DW_CFA_val_offset_sf = 0x15,
|
||||
DW_CFA_val_expression = 0x16,
|
||||
DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
|
||||
DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
|
||||
DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
|
||||
|
||||
// GNU extensions
|
||||
DW_CFA_GNU_window_save = 0x2D,
|
||||
DW_CFA_GNU_args_size = 0x2E,
|
||||
DW_CFA_GNU_negative_offset_extended = 0x2F,
|
||||
|
||||
// AARCH64 extensions
|
||||
DW_CFA_AARCH64_negate_ra_state = 0x2D
|
||||
};
|
||||
|
||||
|
||||
// FSF exception handling Pointer-Encoding constants
|
||||
// Used in CFI augmentation by gcc compiler
|
||||
// FSF exception handling Pointer-Encoding constants
|
||||
// Used in CFI augmentation by GCC
|
||||
enum {
|
||||
DW_EH_PE_ptr = 0x00,
|
||||
DW_EH_PE_uleb128 = 0x01,
|
||||
DW_EH_PE_udata2 = 0x02,
|
||||
DW_EH_PE_udata4 = 0x03,
|
||||
DW_EH_PE_udata8 = 0x04,
|
||||
DW_EH_PE_signed = 0x08,
|
||||
DW_EH_PE_sleb128 = 0x09,
|
||||
DW_EH_PE_sdata2 = 0x0A,
|
||||
DW_EH_PE_sdata4 = 0x0B,
|
||||
DW_EH_PE_sdata8 = 0x0C,
|
||||
DW_EH_PE_absptr = 0x00,
|
||||
DW_EH_PE_pcrel = 0x10,
|
||||
DW_EH_PE_textrel = 0x20,
|
||||
DW_EH_PE_datarel = 0x30,
|
||||
DW_EH_PE_funcrel = 0x40,
|
||||
DW_EH_PE_aligned = 0x50,
|
||||
DW_EH_PE_indirect = 0x80,
|
||||
DW_EH_PE_omit = 0xFF
|
||||
DW_EH_PE_ptr = 0x00,
|
||||
DW_EH_PE_uleb128 = 0x01,
|
||||
DW_EH_PE_udata2 = 0x02,
|
||||
DW_EH_PE_udata4 = 0x03,
|
||||
DW_EH_PE_udata8 = 0x04,
|
||||
DW_EH_PE_signed = 0x08,
|
||||
DW_EH_PE_sleb128 = 0x09,
|
||||
DW_EH_PE_sdata2 = 0x0A,
|
||||
DW_EH_PE_sdata4 = 0x0B,
|
||||
DW_EH_PE_sdata8 = 0x0C,
|
||||
DW_EH_PE_absptr = 0x00,
|
||||
DW_EH_PE_pcrel = 0x10,
|
||||
DW_EH_PE_textrel = 0x20,
|
||||
DW_EH_PE_datarel = 0x30,
|
||||
DW_EH_PE_funcrel = 0x40,
|
||||
DW_EH_PE_aligned = 0x50,
|
||||
DW_EH_PE_indirect = 0x80,
|
||||
DW_EH_PE_omit = 0xFF
|
||||
};
|
||||
|
||||
|
||||
// DWARF expressions
|
||||
// DWARF expressions
|
||||
enum {
|
||||
DW_OP_addr = 0x03, // constant address (size target specific)
|
||||
DW_OP_deref = 0x06,
|
||||
DW_OP_const1u = 0x08, // 1-byte constant
|
||||
DW_OP_const1s = 0x09, // 1-byte constant
|
||||
DW_OP_const2u = 0x0A, // 2-byte constant
|
||||
DW_OP_const2s = 0x0B, // 2-byte constant
|
||||
DW_OP_const4u = 0x0C, // 4-byte constant
|
||||
DW_OP_const4s = 0x0D, // 4-byte constant
|
||||
DW_OP_const8u = 0x0E, // 8-byte constant
|
||||
DW_OP_const8s = 0x0F, // 8-byte constant
|
||||
DW_OP_constu = 0x10, // ULEB128 constant
|
||||
DW_OP_consts = 0x11, // SLEB128 constant
|
||||
DW_OP_dup = 0x12,
|
||||
DW_OP_drop = 0x13,
|
||||
DW_OP_over = 0x14,
|
||||
DW_OP_pick = 0x15, // 1-byte stack index
|
||||
DW_OP_swap = 0x16,
|
||||
DW_OP_rot = 0x17,
|
||||
DW_OP_xderef = 0x18,
|
||||
DW_OP_abs = 0x19,
|
||||
DW_OP_and = 0x1A,
|
||||
DW_OP_div = 0x1B,
|
||||
DW_OP_minus = 0x1C,
|
||||
DW_OP_mod = 0x1D,
|
||||
DW_OP_mul = 0x1E,
|
||||
DW_OP_neg = 0x1F,
|
||||
DW_OP_not = 0x20,
|
||||
DW_OP_or = 0x21,
|
||||
DW_OP_plus = 0x22,
|
||||
DW_OP_plus_uconst = 0x23, // ULEB128 addend
|
||||
DW_OP_shl = 0x24,
|
||||
DW_OP_shr = 0x25,
|
||||
DW_OP_shra = 0x26,
|
||||
DW_OP_xor = 0x27,
|
||||
DW_OP_skip = 0x2F, // signed 2-byte constant
|
||||
DW_OP_bra = 0x28, // signed 2-byte constant
|
||||
DW_OP_eq = 0x29,
|
||||
DW_OP_ge = 0x2A,
|
||||
DW_OP_gt = 0x2B,
|
||||
DW_OP_le = 0x2C,
|
||||
DW_OP_lt = 0x2D,
|
||||
DW_OP_ne = 0x2E,
|
||||
DW_OP_lit0 = 0x30, // Literal 0
|
||||
DW_OP_lit1 = 0x31, // Literal 1
|
||||
DW_OP_lit2 = 0x32, // Literal 2
|
||||
DW_OP_lit3 = 0x33, // Literal 3
|
||||
DW_OP_lit4 = 0x34, // Literal 4
|
||||
DW_OP_lit5 = 0x35, // Literal 5
|
||||
DW_OP_lit6 = 0x36, // Literal 6
|
||||
DW_OP_lit7 = 0x37, // Literal 7
|
||||
DW_OP_lit8 = 0x38, // Literal 8
|
||||
DW_OP_lit9 = 0x39, // Literal 9
|
||||
DW_OP_lit10 = 0x3A, // Literal 10
|
||||
DW_OP_lit11 = 0x3B, // Literal 11
|
||||
DW_OP_lit12 = 0x3C, // Literal 12
|
||||
DW_OP_lit13 = 0x3D, // Literal 13
|
||||
DW_OP_lit14 = 0x3E, // Literal 14
|
||||
DW_OP_lit15 = 0x3F, // Literal 15
|
||||
DW_OP_lit16 = 0x40, // Literal 16
|
||||
DW_OP_lit17 = 0x41, // Literal 17
|
||||
DW_OP_lit18 = 0x42, // Literal 18
|
||||
DW_OP_lit19 = 0x43, // Literal 19
|
||||
DW_OP_lit20 = 0x44, // Literal 20
|
||||
DW_OP_lit21 = 0x45, // Literal 21
|
||||
DW_OP_lit22 = 0x46, // Literal 22
|
||||
DW_OP_lit23 = 0x47, // Literal 23
|
||||
DW_OP_lit24 = 0x48, // Literal 24
|
||||
DW_OP_lit25 = 0x49, // Literal 25
|
||||
DW_OP_lit26 = 0x4A, // Literal 26
|
||||
DW_OP_lit27 = 0x4B, // Literal 27
|
||||
DW_OP_lit28 = 0x4C, // Literal 28
|
||||
DW_OP_lit29 = 0x4D, // Literal 29
|
||||
DW_OP_lit30 = 0x4E, // Literal 30
|
||||
DW_OP_lit31 = 0x4F, // Literal 31
|
||||
DW_OP_reg0 = 0x50, // Contents of reg0
|
||||
DW_OP_reg1 = 0x51, // Contents of reg1
|
||||
DW_OP_reg2 = 0x52, // Contents of reg2
|
||||
DW_OP_reg3 = 0x53, // Contents of reg3
|
||||
DW_OP_reg4 = 0x54, // Contents of reg4
|
||||
DW_OP_reg5 = 0x55, // Contents of reg5
|
||||
DW_OP_reg6 = 0x56, // Contents of reg6
|
||||
DW_OP_reg7 = 0x57, // Contents of reg7
|
||||
DW_OP_reg8 = 0x58, // Contents of reg8
|
||||
DW_OP_reg9 = 0x59, // Contents of reg9
|
||||
DW_OP_reg10 = 0x5A, // Contents of reg10
|
||||
DW_OP_reg11 = 0x5B, // Contents of reg11
|
||||
DW_OP_reg12 = 0x5C, // Contents of reg12
|
||||
DW_OP_reg13 = 0x5D, // Contents of reg13
|
||||
DW_OP_reg14 = 0x5E, // Contents of reg14
|
||||
DW_OP_reg15 = 0x5F, // Contents of reg15
|
||||
DW_OP_reg16 = 0x60, // Contents of reg16
|
||||
DW_OP_reg17 = 0x61, // Contents of reg17
|
||||
DW_OP_reg18 = 0x62, // Contents of reg18
|
||||
DW_OP_reg19 = 0x63, // Contents of reg19
|
||||
DW_OP_reg20 = 0x64, // Contents of reg20
|
||||
DW_OP_reg21 = 0x65, // Contents of reg21
|
||||
DW_OP_reg22 = 0x66, // Contents of reg22
|
||||
DW_OP_reg23 = 0x67, // Contents of reg23
|
||||
DW_OP_reg24 = 0x68, // Contents of reg24
|
||||
DW_OP_reg25 = 0x69, // Contents of reg25
|
||||
DW_OP_reg26 = 0x6A, // Contents of reg26
|
||||
DW_OP_reg27 = 0x6B, // Contents of reg27
|
||||
DW_OP_reg28 = 0x6C, // Contents of reg28
|
||||
DW_OP_reg29 = 0x6D, // Contents of reg29
|
||||
DW_OP_reg30 = 0x6E, // Contents of reg30
|
||||
DW_OP_reg31 = 0x6F, // Contents of reg31
|
||||
DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
|
||||
DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
|
||||
DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
|
||||
DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
|
||||
DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
|
||||
DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
|
||||
DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
|
||||
DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
|
||||
DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
|
||||
DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
|
||||
DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
|
||||
DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
|
||||
DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
|
||||
DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
|
||||
DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
|
||||
DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
|
||||
DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
|
||||
DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
|
||||
DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
|
||||
DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
|
||||
DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
|
||||
DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
|
||||
DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
|
||||
DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
|
||||
DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
|
||||
DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
|
||||
DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
|
||||
DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
|
||||
DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
|
||||
DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
|
||||
DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
|
||||
DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
|
||||
DW_OP_regx = 0x90, // ULEB128 register
|
||||
DW_OP_fbreg = 0x91, // SLEB128 offset
|
||||
DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
|
||||
DW_OP_piece = 0x93, // ULEB128 size of piece addressed
|
||||
DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
|
||||
DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
|
||||
DW_OP_nop = 0x96,
|
||||
DW_OP_push_object_addres = 0x97,
|
||||
DW_OP_call2 = 0x98, // 2-byte offset of DIE
|
||||
DW_OP_call4 = 0x99, // 4-byte offset of DIE
|
||||
DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
|
||||
DW_OP_lo_user = 0xE0,
|
||||
DW_OP_APPLE_uninit = 0xF0,
|
||||
DW_OP_hi_user = 0xFF
|
||||
DW_OP_addr = 0x03, // constant address (size target specific)
|
||||
DW_OP_deref = 0x06,
|
||||
DW_OP_const1u = 0x08, // 1-byte constant
|
||||
DW_OP_const1s = 0x09, // 1-byte constant
|
||||
DW_OP_const2u = 0x0A, // 2-byte constant
|
||||
DW_OP_const2s = 0x0B, // 2-byte constant
|
||||
DW_OP_const4u = 0x0C, // 4-byte constant
|
||||
DW_OP_const4s = 0x0D, // 4-byte constant
|
||||
DW_OP_const8u = 0x0E, // 8-byte constant
|
||||
DW_OP_const8s = 0x0F, // 8-byte constant
|
||||
DW_OP_constu = 0x10, // ULEB128 constant
|
||||
DW_OP_consts = 0x11, // SLEB128 constant
|
||||
DW_OP_dup = 0x12,
|
||||
DW_OP_drop = 0x13,
|
||||
DW_OP_over = 0x14,
|
||||
DW_OP_pick = 0x15, // 1-byte stack index
|
||||
DW_OP_swap = 0x16,
|
||||
DW_OP_rot = 0x17,
|
||||
DW_OP_xderef = 0x18,
|
||||
DW_OP_abs = 0x19,
|
||||
DW_OP_and = 0x1A,
|
||||
DW_OP_div = 0x1B,
|
||||
DW_OP_minus = 0x1C,
|
||||
DW_OP_mod = 0x1D,
|
||||
DW_OP_mul = 0x1E,
|
||||
DW_OP_neg = 0x1F,
|
||||
DW_OP_not = 0x20,
|
||||
DW_OP_or = 0x21,
|
||||
DW_OP_plus = 0x22,
|
||||
DW_OP_plus_uconst = 0x23, // ULEB128 addend
|
||||
DW_OP_shl = 0x24,
|
||||
DW_OP_shr = 0x25,
|
||||
DW_OP_shra = 0x26,
|
||||
DW_OP_xor = 0x27,
|
||||
DW_OP_skip = 0x2F, // signed 2-byte constant
|
||||
DW_OP_bra = 0x28, // signed 2-byte constant
|
||||
DW_OP_eq = 0x29,
|
||||
DW_OP_ge = 0x2A,
|
||||
DW_OP_gt = 0x2B,
|
||||
DW_OP_le = 0x2C,
|
||||
DW_OP_lt = 0x2D,
|
||||
DW_OP_ne = 0x2E,
|
||||
DW_OP_lit0 = 0x30, // Literal 0
|
||||
DW_OP_lit1 = 0x31, // Literal 1
|
||||
DW_OP_lit2 = 0x32, // Literal 2
|
||||
DW_OP_lit3 = 0x33, // Literal 3
|
||||
DW_OP_lit4 = 0x34, // Literal 4
|
||||
DW_OP_lit5 = 0x35, // Literal 5
|
||||
DW_OP_lit6 = 0x36, // Literal 6
|
||||
DW_OP_lit7 = 0x37, // Literal 7
|
||||
DW_OP_lit8 = 0x38, // Literal 8
|
||||
DW_OP_lit9 = 0x39, // Literal 9
|
||||
DW_OP_lit10 = 0x3A, // Literal 10
|
||||
DW_OP_lit11 = 0x3B, // Literal 11
|
||||
DW_OP_lit12 = 0x3C, // Literal 12
|
||||
DW_OP_lit13 = 0x3D, // Literal 13
|
||||
DW_OP_lit14 = 0x3E, // Literal 14
|
||||
DW_OP_lit15 = 0x3F, // Literal 15
|
||||
DW_OP_lit16 = 0x40, // Literal 16
|
||||
DW_OP_lit17 = 0x41, // Literal 17
|
||||
DW_OP_lit18 = 0x42, // Literal 18
|
||||
DW_OP_lit19 = 0x43, // Literal 19
|
||||
DW_OP_lit20 = 0x44, // Literal 20
|
||||
DW_OP_lit21 = 0x45, // Literal 21
|
||||
DW_OP_lit22 = 0x46, // Literal 22
|
||||
DW_OP_lit23 = 0x47, // Literal 23
|
||||
DW_OP_lit24 = 0x48, // Literal 24
|
||||
DW_OP_lit25 = 0x49, // Literal 25
|
||||
DW_OP_lit26 = 0x4A, // Literal 26
|
||||
DW_OP_lit27 = 0x4B, // Literal 27
|
||||
DW_OP_lit28 = 0x4C, // Literal 28
|
||||
DW_OP_lit29 = 0x4D, // Literal 29
|
||||
DW_OP_lit30 = 0x4E, // Literal 30
|
||||
DW_OP_lit31 = 0x4F, // Literal 31
|
||||
DW_OP_reg0 = 0x50, // Contents of reg0
|
||||
DW_OP_reg1 = 0x51, // Contents of reg1
|
||||
DW_OP_reg2 = 0x52, // Contents of reg2
|
||||
DW_OP_reg3 = 0x53, // Contents of reg3
|
||||
DW_OP_reg4 = 0x54, // Contents of reg4
|
||||
DW_OP_reg5 = 0x55, // Contents of reg5
|
||||
DW_OP_reg6 = 0x56, // Contents of reg6
|
||||
DW_OP_reg7 = 0x57, // Contents of reg7
|
||||
DW_OP_reg8 = 0x58, // Contents of reg8
|
||||
DW_OP_reg9 = 0x59, // Contents of reg9
|
||||
DW_OP_reg10 = 0x5A, // Contents of reg10
|
||||
DW_OP_reg11 = 0x5B, // Contents of reg11
|
||||
DW_OP_reg12 = 0x5C, // Contents of reg12
|
||||
DW_OP_reg13 = 0x5D, // Contents of reg13
|
||||
DW_OP_reg14 = 0x5E, // Contents of reg14
|
||||
DW_OP_reg15 = 0x5F, // Contents of reg15
|
||||
DW_OP_reg16 = 0x60, // Contents of reg16
|
||||
DW_OP_reg17 = 0x61, // Contents of reg17
|
||||
DW_OP_reg18 = 0x62, // Contents of reg18
|
||||
DW_OP_reg19 = 0x63, // Contents of reg19
|
||||
DW_OP_reg20 = 0x64, // Contents of reg20
|
||||
DW_OP_reg21 = 0x65, // Contents of reg21
|
||||
DW_OP_reg22 = 0x66, // Contents of reg22
|
||||
DW_OP_reg23 = 0x67, // Contents of reg23
|
||||
DW_OP_reg24 = 0x68, // Contents of reg24
|
||||
DW_OP_reg25 = 0x69, // Contents of reg25
|
||||
DW_OP_reg26 = 0x6A, // Contents of reg26
|
||||
DW_OP_reg27 = 0x6B, // Contents of reg27
|
||||
DW_OP_reg28 = 0x6C, // Contents of reg28
|
||||
DW_OP_reg29 = 0x6D, // Contents of reg29
|
||||
DW_OP_reg30 = 0x6E, // Contents of reg30
|
||||
DW_OP_reg31 = 0x6F, // Contents of reg31
|
||||
DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
|
||||
DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
|
||||
DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
|
||||
DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
|
||||
DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
|
||||
DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
|
||||
DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
|
||||
DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
|
||||
DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
|
||||
DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
|
||||
DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
|
||||
DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
|
||||
DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
|
||||
DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
|
||||
DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
|
||||
DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
|
||||
DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
|
||||
DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
|
||||
DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
|
||||
DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
|
||||
DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
|
||||
DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
|
||||
DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
|
||||
DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
|
||||
DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
|
||||
DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
|
||||
DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
|
||||
DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
|
||||
DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
|
||||
DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
|
||||
DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
|
||||
DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
|
||||
DW_OP_regx = 0x90, // ULEB128 register
|
||||
DW_OP_fbreg = 0x91, // SLEB128 offset
|
||||
DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
|
||||
DW_OP_piece = 0x93, // ULEB128 size of piece addressed
|
||||
DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
|
||||
DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
|
||||
DW_OP_nop = 0x96,
|
||||
DW_OP_push_object_addres = 0x97,
|
||||
DW_OP_call2 = 0x98, // 2-byte offset of DIE
|
||||
DW_OP_call4 = 0x99, // 4-byte offset of DIE
|
||||
DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
|
||||
DW_OP_lo_user = 0xE0,
|
||||
DW_OP_APPLE_uninit = 0xF0,
|
||||
DW_OP_hi_user = 0xFF
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
340
libunwind/src/libunwind.cpp
Normal file
340
libunwind/src/libunwind.cpp
Normal 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
|
||||
|
69
libunwind/src/libunwind_ext.h
Normal file
69
libunwind/src/libunwind_ext.h
Normal 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__
|
@ -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
|
||||
|
@ -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__
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
35
libunwind/test/CMakeLists.txt
Normal file
35
libunwind/test/CMakeLists.txt
Normal 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})
|
28
libunwind/test/alignment.pass.cpp
Normal file
28
libunwind/test/alignment.pass.cpp
Normal 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()
|
||||
{
|
||||
}
|
73
libunwind/test/frameheadercache_test.pass.cpp
Normal file
73
libunwind/test/frameheadercache_test.pass.cpp
Normal 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
|
0
libunwind/test/libunwind/__init__.py
Normal file
0
libunwind/test/libunwind/__init__.py
Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user