Add LLVM libcxxabi (#1063)

* third_party: Add libcxxabi

Added libcxxabi from LLVM 17.0.6
The library implements the Itanium C++ exception handling ABI.

* third_party/libcxxabi: Enable __cxa_thread_atexit

Enable `__cxa_thread_atexit` from libcxxabi.
`__cxa_thread_atexit_impl` is still implemented by the cosmo libc.
The original `__cxa_thread_atexit` has been removed.

* third_party/libcxx: Build with exceptions

Build libcxx with exceptions enabled.

- Removed `_LIBCPP_NO_EXCEPTIONS` from `__config`.
- Switched the exception implementation to `libcxxabi`. These two files
are taken from the same `libcxx` version as mentioned in `README.cosmo`.
- Removed `new_handler_fallback` in favor of `libcxxabi` implementation.
- Enable `-fexceptions` and `-frtti` for `libcxx`.
- Removed `THIRD_PARTY_LIBCXX` dependency from `libcxxabi` and
`libunwind`. These libraries do not use any runtime `libcxx` functions,
just headers.

* libc: Remove remaining redundant cxa functions

- `__cxa_pure_virtual` in `libcxxabi` is also a stub similar to the
existing one.
- `__cxa_guard_*` from `libcxxabi` is used instead of the ones from
Android.

Now there should be no more duplicate implementations.
`__cxa_thread_atexit_impl`, `__cxa_atexit`, and related supporting
functions, are still left to other libraries as in `libcxxabi`.

`libcxxabi` is also now added to `cosmopolitan.a` to make up for the
removed functions.

Affected in-tree libraries (`third_party/double-conversion`) have been
updated.
This commit is contained in:
Trung Nguyen 2024-01-08 23:45:10 +07:00 committed by GitHub
parent 94bab1618d
commit 8b33204f37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 14606 additions and 372 deletions

View file

@ -249,7 +249,6 @@ include libc/calls/BUILD.mk #─┐
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
include third_party/nsync/BUILD.mk # │ You can issue system calls
include libc/runtime/BUILD.mk # │
include third_party/double-conversion/BUILD.mk # │
include libc/crt/BUILD.mk # │
include third_party/dlmalloc/BUILD.mk #─┘
include libc/mem/BUILD.mk #─┐
@ -284,7 +283,10 @@ include third_party/stb/BUILD.mk # │
include third_party/mbedtls/BUILD.mk # │
include third_party/ncurses/BUILD.mk # │
include third_party/readline/BUILD.mk # │
include third_party/libunwind/BUILD.mk # |
include third_party/libcxxabi/BUILD.mk # |
include third_party/libcxx/BUILD.mk # │
include third_party/double-conversion/BUILD.mk # │
include third_party/pcre/BUILD.mk # │
include third_party/less/BUILD.mk # │
include net/https/BUILD.mk # │
@ -328,7 +330,6 @@ include third_party/python/BUILD.mk
include tool/build/BUILD.mk
include tool/curl/BUILD.mk
include third_party/qemu/BUILD.mk
include third_party/libunwind/BUILD.mk
include examples/BUILD.mk
include examples/pyapp/BUILD.mk
include examples/pylife/BUILD.mk
@ -441,6 +442,7 @@ COSMOPOLITAN_OBJECTS = \
LIBC_TIME \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB_GZ \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
LIBC_STDIO \
THIRD_PARTY_GDTOA \

View file

@ -1,28 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
void __cxa_pure_virtual(void) {
#ifndef NDEBUG
kprintf("__cxa_pure_virtual() called\n"
"Did you call a virtual method from a destructor?\n");
#endif
abort();
}

View file

@ -1,115 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* 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.
*/
#include "libc/atomic.h"
#include "libc/cxxabi.h"
#include "libc/intrin/atomic.h"
#include "libc/limits.h"
#include "third_party/nsync/futex.internal.h"
// This file contains C++ ABI support functions for one time
// constructors as defined in the "Run-time ABI for the ARM Architecture"
// section 4.4.2
//
// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for
// one time construction:
//
// ARM C++ ABI defines the LSB of guard variable should be tested
// by compiler-generated code before calling __cxa_guard_acquire et al.
//
// The Itanium/x86 C++ ABI defines the low-order _byte_ should be
// tested instead.
//
// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit
// aligned for x86.
//
// Reference documentation:
//
// section 3.2.3 of ARM IHI 0041C (for ARM)
// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86).
//
// There is no C++ ABI available for other ARCH. But the gcc source
// shows all other ARCH follow the definition of Itanium/x86 C++ ABI.
// The Itanium/x86 C++ ABI (used by all architectures that aren't ARM32)
// mandates guard variables are 64-bit aligned, 64-bit values. The least
// significant byte is tested by the compiler-generated code before it's
// calling __cxa_guard_acquire.
union CxaGuardValue {
atomic_int state;
int64_t aligner;
};
// Set construction state values according to reference documentation. 0
// is the initialization value. Arm requires ((*gv & 1) == 1) after
// __cxa_guard_release, ((*gv & 3) == 0) after __cxa_guard_abort. X86
// requires first byte not modified by __cxa_guard_acquire, first byte
// is non-zero after __cxa_guard_release.
#define CONSTRUCTION_NOT_YET_STARTED 0
#define CONSTRUCTION_COMPLETE 1
#define CONSTRUCTION_UNDERWAY_WITHOUT_WAITER 0x100
#define CONSTRUCTION_UNDERWAY_WITH_WAITER 0x200
int __cxa_guard_acquire(union CxaGuardValue *gv) {
int old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
while (true) {
if (old_value == CONSTRUCTION_COMPLETE) {
// A load_acquire operation is needed before exiting with COMPLETE
// state, as we must ensure that all the stores performed by the
// construction function are observable on this CPU after we exit.
atomic_thread_fence(memory_order_acquire);
return 0;
} else if (old_value == CONSTRUCTION_NOT_YET_STARTED) {
if (!atomic_compare_exchange_weak_explicit(
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITHOUT_WAITER,
memory_order_relaxed, memory_order_relaxed)) {
continue;
}
// The acquire fence may not be needed. But as described in section 3.3.2
// of the Itanium C++ ABI specification, it probably has to behave like
// the acquisition of a mutex, which needs an acquire fence.
atomic_thread_fence(memory_order_acquire);
return 1;
} else if (old_value == CONSTRUCTION_UNDERWAY_WITHOUT_WAITER) {
if (!atomic_compare_exchange_weak_explicit(
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITH_WAITER,
memory_order_relaxed, memory_order_relaxed)) {
continue;
}
}
nsync_futex_wait_(&gv->state, CONSTRUCTION_UNDERWAY_WITH_WAITER, 0, 0);
old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
}
}
void __cxa_guard_release(union CxaGuardValue *gv) {
// Release fence is used to make all stores performed by the construction
// function visible in other threads.
int old_value = atomic_exchange_explicit(&gv->state, CONSTRUCTION_COMPLETE,
memory_order_release);
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
nsync_futex_wake_(&gv->state, INT_MAX, 0);
}
}
void __cxa_guard_abort(union CxaGuardValue *gv) {
// Release fence is used to make all stores performed by the construction
// function visible in other threads.
int old_value = atomic_exchange_explicit(
&gv->state, CONSTRUCTION_NOT_YET_STARTED, memory_order_release);
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
nsync_futex_wake_(&gv->state, INT_MAX, 0);
}
}

View file

@ -1,23 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/cxaatexit.internal.h"
int __cxa_thread_atexit(void *fun, void *arg, void *dso_symbol) {
return __cxa_thread_atexit_impl(fun, arg, dso_symbol);
}

View file

@ -41,6 +41,7 @@ TEST_LIBC_THREAD_DIRECTDEPS = \
LIBC_THREAD \
LIBC_TIME \
LIBC_X \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_NSYNC \
THIRD_PARTY_NSYNC_MEM

View file

@ -17,6 +17,7 @@ o/$(MODE)/third_party: \
o/$(MODE)/third_party/hiredis \
o/$(MODE)/third_party/less \
o/$(MODE)/third_party/libcxx \
o/$(MODE)/third_party/libcxxabi \
o/$(MODE)/third_party/libunwind \
o/$(MODE)/third_party/linenoise \
o/$(MODE)/third_party/lua \

View file

@ -31,10 +31,9 @@ THIRD_PARTY_DOUBLECONVERSION_A_CHECKS = \
THIRD_PARTY_DOUBLECONVERSION_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_TINYMATH
LIBC_TINYMATH \
THIRD_PARTY_LIBCXXABI
THIRD_PARTY_DOUBLECONVERSION_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_DOUBLECONVERSION_A_DIRECTDEPS),$($(x))))

View file

@ -70,8 +70,8 @@ THIRD_PARTY_LIBCXX_A_HDRS = \
third_party/libcxx/deque \
third_party/libcxx/errno.h \
third_party/libcxx/exception \
third_party/libcxx/exception_fallback.hh \
third_party/libcxx/exception_pointer_unimplemented.hh \
third_party/libcxx/exception_libcxxabi.hh \
third_party/libcxx/exception_pointer_cxxabi.hh \
third_party/libcxx/execution \
third_party/libcxx/experimental/__config \
third_party/libcxx/filesystem \
@ -99,7 +99,6 @@ THIRD_PARTY_LIBCXX_A_HDRS = \
third_party/libcxx/memory \
third_party/libcxx/mutex \
third_party/libcxx/new \
third_party/libcxx/new_handler_fallback.hh \
third_party/libcxx/numeric \
third_party/libcxx/optional \
third_party/libcxx/ostream \
@ -200,7 +199,9 @@ THIRD_PARTY_LIBCXX_A_DIRECTDEPS = \
LIBC_THREAD \
LIBC_TINYMATH \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_GDTOA
THIRD_PARTY_GDTOA \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND
THIRD_PARTY_LIBCXX_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBCXX_A_DIRECTDEPS),$($(x))))
@ -217,7 +218,10 @@ $(THIRD_PARTY_LIBCXX_A).pkg: \
$(THIRD_PARTY_LIBCXX_A_OBJS): private \
CXXFLAGS += \
-ffunction-sections \
-fdata-sections
-fdata-sections \
-fexceptions \
-frtti \
-DLIBCXX_BUILDING_LIBCXXABI
THIRD_PARTY_LIBCXX_LIBS = $(foreach x,$(THIRD_PARTY_LIBCXX_ARTIFACTS),$($(x)))
THIRD_PARTY_LIBCXX_SRCS = $(foreach x,$(THIRD_PARTY_LIBCXX_ARTIFACTS),$($(x)_SRCS))

View file

@ -12,7 +12,6 @@
#include "libc/isystem/features.h"
#define _LIBCPP_ABI_UNSTABLE
#define _LIBCPP_NO_EXCEPTIONS
#define _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS
#define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION

View file

@ -11,6 +11,11 @@
#include "third_party/libcxx/new"
#include "third_party/libcxx/typeinfo"
#include "third_party/libcxx/atomic_support.hh"
#include "third_party/libcxx/exception_fallback.hh"
#include "third_party/libcxx/exception_pointer_unimplemented.hh"
#if defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
#include "third_party/libcxxabi/include/cxxabi.h"
using namespace __cxxabiv1;
#define HAVE_DEPENDENT_EH_ABI 1
#endif
#include "third_party/libcxx/exception_libcxxabi.hh"
#include "third_party/libcxx/exception_pointer_cxxabi.hh"

View file

@ -1,111 +0,0 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/exception"
#include "third_party/libcxx/cstdio"
#include "third_party/libcxx/atomic_support.hh"
namespace std {
_LIBCPP_SAFE_STATIC static std::terminate_handler __terminate_handler;
#if _LIBCPP_STD_VER <= 14 || \
defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) || \
defined(_LIBCPP_BUILDING_LIBRARY)
_LIBCPP_SAFE_STATIC static std::unexpected_handler __unexpected_handler;
// libcxxrt provides implementations of these functions itself.
unexpected_handler set_unexpected(unexpected_handler func) _NOEXCEPT {
return __libcpp_atomic_exchange(&__unexpected_handler, func);
}
unexpected_handler get_unexpected() _NOEXCEPT {
return __libcpp_atomic_load(&__unexpected_handler);
}
_LIBCPP_NORETURN
void unexpected() {
(*get_unexpected())();
// unexpected handler should not return
terminate();
}
#endif
terminate_handler set_terminate(terminate_handler func) _NOEXCEPT {
return __libcpp_atomic_exchange(&__terminate_handler, func);
}
terminate_handler get_terminate() _NOEXCEPT {
return __libcpp_atomic_load(&__terminate_handler);
}
#ifndef __EMSCRIPTEN__ // We provide this in JS
_LIBCPP_NORETURN
void terminate() _NOEXCEPT {
#ifndef _LIBCPP_NO_EXCEPTIONS
try {
#endif // _LIBCPP_NO_EXCEPTIONS
(*get_terminate())();
// handler should not return
fprintf(stderr, "terminate_handler unexpectedly returned\n");
::abort();
#ifndef _LIBCPP_NO_EXCEPTIONS
} catch (...) {
// handler should not throw exception
fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
::abort();
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
#endif // !__EMSCRIPTEN__
#if !defined(__EMSCRIPTEN__)
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
int uncaught_exceptions() _NOEXCEPT {
// #warning uncaught_exception not yet implemented
fprintf(stderr, "uncaught_exceptions not yet implemented\n");
::abort();
}
#endif // !__EMSCRIPTEN__
exception::~exception() _NOEXCEPT {}
const char* exception::what() const _NOEXCEPT { return "std::exception"; }
bad_exception::~bad_exception() _NOEXCEPT {}
const char* bad_exception::what() const _NOEXCEPT {
return "std::bad_exception";
}
bad_alloc::bad_alloc() _NOEXCEPT {}
bad_alloc::~bad_alloc() _NOEXCEPT {}
const char* bad_alloc::what() const _NOEXCEPT { return "std::bad_alloc"; }
bad_array_new_length::bad_array_new_length() _NOEXCEPT {}
bad_array_new_length::~bad_array_new_length() _NOEXCEPT {}
const char* bad_array_new_length::what() const _NOEXCEPT {
return "bad_array_new_length";
}
bad_cast::bad_cast() _NOEXCEPT {}
bad_typeid::bad_typeid() _NOEXCEPT {}
bad_cast::~bad_cast() _NOEXCEPT {}
const char* bad_cast::what() const _NOEXCEPT { return "std::bad_cast"; }
bad_typeid::~bad_typeid() _NOEXCEPT {}
const char* bad_typeid::what() const _NOEXCEPT { return "std::bad_typeid"; }
} // namespace std

View file

@ -7,20 +7,21 @@
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/__config"
#include "third_party/libcxx/new"
#include "third_party/libcxx/atomic_support.hh"
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/exception"
using namespace __cxxabiv1;
namespace std {
_LIBCPP_SAFE_STATIC static std::new_handler __new_handler;
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
new_handler set_new_handler(new_handler handler) _NOEXCEPT {
return __libcpp_atomic_exchange(&__new_handler, handler);
}
new_handler get_new_handler() _NOEXCEPT {
return __libcpp_atomic_load(&__new_handler);
int uncaught_exceptions() _NOEXCEPT
{
# if _LIBCPPABI_VERSION > 1001
return __cxa_uncaught_exceptions();
# else
return __cxa_uncaught_exception() ? 1 : 0;
# endif
}
} // namespace std

View file

@ -0,0 +1,73 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/exception"
using namespace __cxxabiv1;
namespace std {
exception_ptr::~exception_ptr() _NOEXCEPT {
__cxa_decrement_exception_refcount(__ptr_);
}
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
: __ptr_(other.__ptr_)
{
__cxa_increment_exception_refcount(__ptr_);
}
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
if (__ptr_ != other.__ptr_)
{
__cxa_increment_exception_refcount(other.__ptr_);
__cxa_decrement_exception_refcount(__ptr_);
__ptr_ = other.__ptr_;
}
return *this;
}
nested_exception::nested_exception() _NOEXCEPT
: __ptr_(current_exception())
{
}
nested_exception::~nested_exception() _NOEXCEPT
{
}
_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
if (__ptr_ == nullptr)
terminate();
rethrow_exception(__ptr_);
}
exception_ptr current_exception() _NOEXCEPT
{
// be nicer if there was a constructor that took a ptr, then
// this whole function would be just:
// return exception_ptr(__cxa_current_primary_exception());
exception_ptr ptr;
ptr.__ptr_ = __cxa_current_primary_exception();
return ptr;
}
_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
__cxa_rethrow_primary_exception(p.__ptr_);
// if p.__ptr_ is NULL, above returns so we terminate
terminate();
}
} // namespace std

View file

@ -1,68 +0,0 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/stdio.h"
#include "third_party/libcxx/stdlib.h"
#include "third_party/libcxx/exception"
namespace std {
exception_ptr::~exception_ptr() _NOEXCEPT {
// #warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
: __ptr_(other.__ptr_) {
// #warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT {
// #warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
nested_exception::nested_exception() _NOEXCEPT : __ptr_(current_exception()) {}
#if !defined(__GLIBCXX__)
nested_exception::~nested_exception() _NOEXCEPT {}
#endif
_LIBCPP_NORETURN
void nested_exception::rethrow_nested() const {
// #warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
#if 0
if (__ptr_ == nullptr)
terminate();
rethrow_exception(__ptr_);
#endif // FIXME
}
exception_ptr current_exception() _NOEXCEPT {
// #warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p) {
// #warning exception_ptr not yet implemented
fprintf(stderr, "exception_ptr not yet implemented\n");
::abort();
}
} // namespace std

View file

@ -10,7 +10,7 @@
#include "third_party/libcxx/new"
#include "third_party/libcxx/atomic_support.hh"
#include "third_party/libcxx/new_handler_fallback.hh"
#include "third_party/libcxxabi/include/cxxabi.h"
namespace std {

112
third_party/libcxxabi/BUILD.mk vendored Normal file
View file

@ -0,0 +1,112 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
PKGS += THIRD_PARTY_LIBCXXABI
THIRD_PARTY_LIBCXXABI_ARTIFACTS += THIRD_PARTY_LIBCXXABI_A
THIRD_PARTY_LIBCXXABI = $(THIRD_PARTY_LIBCXXABI_A_DEPS) $(THIRD_PARTY_LIBCXXABI_A)
THIRD_PARTY_LIBCXXABI_A = o/$(MODE)/third_party/libcxxabi/libcxxabi.a
THIRD_PARTY_LIBCXXABI_A_INCS = \
third_party/libcxxabi/demangle/ItaniumNodes.def \
third_party/libcxxabi/aix_state_tab_eh.inc \
third_party/libcxxabi/cxa_exception.h \
third_party/libcxxabi/cxa_guard_impl.h \
third_party/libcxxabi/cxa_handlers.h
# TODO: Remove this aligned_alloc header when libcxx is updated
THIRD_PARTY_LIBCXXABI_A_HDRS = \
third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h \
third_party/libcxxabi/include/__cxxabi_config.h \
third_party/libcxxabi/include/cxxabi.h \
third_party/libcxxabi/demangle/DemangleConfig.h \
third_party/libcxxabi/demangle/ItaniumDemangle.h \
third_party/libcxxabi/demangle/StringViewExtras.h \
third_party/libcxxabi/demangle/Utility.h \
third_party/libcxxabi/abort_message.h \
third_party/libcxxabi/fallback_malloc.h \
third_party/libcxxabi/private_typeinfo.h
THIRD_PARTY_LIBCXXABI_A_SRCS_CC = \
third_party/libcxxabi/abort_message.cc \
third_party/libcxxabi/cxa_aux_runtime.cc \
third_party/libcxxabi/cxa_default_handlers.cc \
third_party/libcxxabi/cxa_demangle.cc \
third_party/libcxxabi/cxa_exception_storage.cc \
third_party/libcxxabi/cxa_exception.cc \
third_party/libcxxabi/cxa_guard.cc \
third_party/libcxxabi/cxa_handlers.cc \
third_party/libcxxabi/cxa_personality.cc \
third_party/libcxxabi/cxa_thread_atexit.cc \
third_party/libcxxabi/cxa_vector.cc \
third_party/libcxxabi/cxa_virtual.cc \
third_party/libcxxabi/fallback_malloc.cc \
third_party/libcxxabi/private_typeinfo.cc \
third_party/libcxxabi/stdlib_exception.cc \
third_party/libcxxabi/stdlib_new_delete.cc \
third_party/libcxxabi/stdlib_stdexcept.cc \
third_party/libcxxabi/stdlib_typeinfo.cc
THIRD_PARTY_LIBCXXABI_A_SRCS = \
$(THIRD_PARTY_LIBCXXABI_A_SRCS_CC)
THIRD_PARTY_LIBCXXABI_A_OBJS = \
$(THIRD_PARTY_LIBCXXABI_A_SRCS_CC:%.cc=o/$(MODE)/%.o)
THIRD_PARTY_LIBCXXABI_A_CHECKS = \
$(THIRD_PARTY_LIBCXXABI_A).pkg \
$(THIRD_PARTY_LIBCXXABI_A_HDRS:%=o/$(MODE)/%.okk)
THIRD_PARTY_LIBCXXABI_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_THREAD \
THIRD_PARTY_LIBUNWIND
THIRD_PARTY_LIBCXXABI_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBCXXABI_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_LIBCXXABI_A): \
third_party/libcxxabi/ \
$(THIRD_PARTY_LIBCXXABI_A).pkg \
$(THIRD_PARTY_LIBCXXABI_A_OBJS)
$(THIRD_PARTY_LIBCXXABI_A).pkg: \
$(THIRD_PARTY_LIBCXXABI_A_OBJS) \
$(foreach x,$(THIRD_PARTY_LIBCXXABI_A_DIRECTDEPS),$($(x)_A).pkg)
# TODO: Remove constinit hacks when we have C++20
$(THIRD_PARTY_LIBCXXABI_A_OBJS): private \
CXXFLAGS += \
-ffunction-sections \
-fdata-sections \
-fexceptions \
-frtti \
-D_LIBCXXABI_BUILDING_LIBRARY \
-D_LIBCPP_BUILDING_LIBRARY \
-DHAVE___CXA_THREAD_ATEXIT_IMPL \
-D_LIBCPP_CONSTINIT=__constinit \
-Dconstinit=__constinit
# ttypeIndex is initialized and used only when native_old_exception is true.
# GCC does not seem to allow this.
o/$(MODE)/third_party/libcxxabi/cxa_personality.o: private \
CXXFLAGS += \
-Wno-error=maybe-uninitialized
THIRD_PARTY_LIBCXXABI_LIBS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)))
THIRD_PARTY_LIBCXXABI_SRCS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_LIBCXXABI_HDRS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_LIBCXXABI_INCS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_INCS))
THIRD_PARTY_LIBCXXABI_CHECKS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_LIBCXXABI_OBJS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_OBJS))
.PHONY: o/$(MODE)/third_party/libcxxabi
o/$(MODE)/third_party/libcxxabi: \
$(THIRD_PARTY_LIBCXXABI_CHECKS) \
$(THIRD_PARTY_LIBCXXABI_A)

71
third_party/libcxxabi/CREDITS.TXT vendored Normal file
View file

@ -0,0 +1,71 @@
This file is a partial list of people who have contributed to the LLVM/libc++abi
project. If you have contributed a patch or made some other contribution to
LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be
done!
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Aaron Ballman
E: aaron@aaronballman.com
D: Minor patches
N: Logan Chien
E: logan.chien@mediatek.com
D: ARM EHABI Unwind & Exception Handling
N: Marshall Clow
E: mclow.lists@gmail.com
E: marshall@idio.com
D: Architect and primary coauthor of libc++abi
N: Matthew Dempsky
E: matthew@dempsky.org
D: Minor patches and bug fixes.
N: Nowar Gu
E: wenhan.gu@gmail.com
D: Minor patches and fixes
N: Howard Hinnant
E: hhinnant@apple.com
D: Architect and primary coauthor of libc++abi
N: Dana Jansens
E: danakj@chromium.org
D: ARM EHABI Unwind & Exception Handling
N: Nick Kledzik
E: kledzik@apple.com
N: Antoine Labour
E: piman@chromium.org
D: ARM EHABI Unwind & Exception Handling
N: Bruce Mitchener, Jr.
E: bruce.mitchener@gmail.com
D: Minor typo fixes
N: Andrew Morrow
E: andrew.c.morrow@gmail.com
D: Minor patches and fixes
N: Erik Olofsson
E: erik.olofsson@hansoft.se
E: erik@olofsson.info
D: Minor patches and fixes
N: Jon Roelofs
E: jroelofs@jroelofs.com
D: ARM EHABI Unwind & Exception Handling, Bare-metal
N: Nico Weber
E: thakis@chromium.org
D: ARM EHABI Unwind & Exception Handling
N: Albert J. Wong
E: ajwong@google.com
D: ARM EHABI Unwind & Exception Handling

311
third_party/libcxxabi/LICENSE.TXT vendored Normal file
View file

@ -0,0 +1,311 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
The libc++abi 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.

18
third_party/libcxxabi/README.cosmo vendored Normal file
View file

@ -0,0 +1,18 @@
DESCRIPTION
libcxxabi - C++ Standard Library Support
ORIGIN
Obtained from the LLVM monorepo, release 17.0.6.
https://github.com/llvm/llvm-project/tree/llvmorg-17.0.6/libunwind
commit 6009708b4367171ccdbf4b5905cb6a803753fe18
Author: Tobias Hieta <tobias@hieta.se>
Date: Tue, 28 Nov 2023 09:52:28 +0100
LOCAL CHANGES
- Add <__memory/aligned_alloc.h> (contains a few inline functions) from
upstream libcxx.
- Enable __cxa_thread_atexit for Cosmopolitan.

79
third_party/libcxxabi/abort_message.cc vendored Normal file
View file

@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// 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 "libc/isystem/stdlib.h"
#include "libc/stdio/stdio.h"
#include "libc/isystem/stdarg.h"
#include "third_party/libcxxabi/abort_message.h"
#ifdef __BIONIC__
# include <android/api-level.h>
# if __ANDROID_API__ >= 21
# include <syslog.h>
extern "C" void android_set_abort_message(const char* msg);
# else
# include <assert.h>
# endif // __ANDROID_API__ >= 21
#endif // __BIONIC__
#if defined(__APPLE__) && __has_include(<CrashReporterClient.h>)
# include <CrashReporterClient.h>
# define _LIBCXXABI_USE_CRASHREPORTER_CLIENT
#endif
void abort_message(const char* format, ...)
{
// Write message to stderr. We do this before formatting into a
// variable-size buffer so that we still get some information if
// formatting into the variable-sized buffer fails.
#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL)
{
fprintf(stderr, "libc++abi: ");
va_list list;
va_start(list, format);
vfprintf(stderr, format, list);
va_end(list);
fprintf(stderr, "\n");
}
#endif
// Format the arguments into an allocated buffer. We leak the buffer on
// purpose, since we're about to abort() anyway.
#if defined(_LIBCXXABI_USE_CRASHREPORTER_CLIENT)
char* buffer;
va_list list;
va_start(list, format);
vasprintf(&buffer, format, list);
va_end(list);
CRSetCrashLogMessage(buffer);
#elif defined(__BIONIC__)
char* buffer;
va_list list;
va_start(list, format);
vasprintf(&buffer, format, list);
va_end(list);
# if __ANDROID_API__ >= 21
// Show error in tombstone.
android_set_abort_message(buffer);
// Show error in logcat.
openlog("libc++abi", 0, 0);
syslog(LOG_CRIT, "%s", buffer);
closelog();
# else
// The good error reporting wasn't available in Android until L. Since we're
// about to abort anyway, just call __assert2, which will log _somewhere_
// (tombstone and/or logcat) in older releases.
__assert2(__FILE__, __LINE__, __func__, buffer);
# endif // __ANDROID_API__ >= 21
#endif // __BIONIC__
abort();
}

17
third_party/libcxxabi/abort_message.h vendored Normal file
View file

@ -0,0 +1,17 @@
//===----------------------------------------------------------------------===//
//
// 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 __ABORT_MESSAGE_H_
#define __ABORT_MESSAGE_H_
#include "third_party/libcxxabi/include/cxxabi.h"
extern "C" _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
#endif

View file

@ -0,0 +1,745 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the personality and helper functions for the state
// table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
//
//===----------------------------------------------------------------------===//
#include <new>
#include <stdio.h>
#include <sys/debug.h>
/*
The legacy IBM xlC and xlclang++ compilers use the state table for EH
instead of the range table. Destructors, or addresses of the possible catch
sites or cleanup code are specified in the state table which is a finite
state machine (FSM). Each function that has a state table also has an
autolocal state variable. The state variable represents the current state
of the function for EH and is found through the traceback table of the
function during unwinding, which is located at the end of each function.
The FSM is an array of state entries. Each state entry has the following
fields:
* offset/address/pointer - the offset used to locate the object, or the
address of a global object, or the address of the next state if it is an
old conditional state change entry;
* dtor/landing pad - address of the destructor function to invoke,
or address of the catch block or cleanup code in the user code to branch to;
* element count/action flag - the number of elements or the flag for actions;
* element size - if the object is an array this is the size of one element
of the array;
* flags - flags used to control how fields in the entry are interpreted;
* next state - the state to execute next after the action for this state is
performed. The value of zero indicates the end of the state for this
function.
The following is the description of 'element count/action flag' field.
+-----------------------------------------------------------------------------+
| value | description | action |
+-------+------------------------+--------------------------------------------+
| > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for |
| | | each member of the array |
+-------+------------------------+--------------------------------------------+
| 1, 0 | object is a scalar | calls dtor for the object |
+-------+------------------------+--------------------------------------------+
| -1 | begin catch | branches to the handler which performes |
| | | catch-match. If there is no catch that |
| | | matches the exception it will be rethrown |
+-------+------------------------+--------------------------------------------+
| -2 | end catch | ends current catch block and continues |
| | | attempting to catch the exception |
+-------+------------------------+--------------------------------------------+
| -3 | delete the object | calls the delete function of the object |
+-------+------------------------+--------------------------------------------+
| -4 | cleanup label | branches to the user code for cleaning up |
+-------+------------------------+--------------------------------------------+
*/
namespace __cxxabiv1 {
extern "C" {
// Macros for debugging the state table parsing.
#ifdef NDEBUG
# define _LIBCXXABI_TRACE_STATETAB(msg, ...)
# define _LIBCXXABI_TRACE_STATETAB0(msg)
# define _LIBCXXABI_TRACE_STATETAB1(msg)
# define _LIBCXXABI_TRACING_STATETAB 0
#else
static bool state_tab_dbg() {
static bool checked = false;
static bool log = false;
if (!checked) {
log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
checked = true;
}
return log;
}
# define _LIBCXXABI_TRACE_STATETAB(msg, ...) \
do { \
if (state_tab_dbg()) \
fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \
} while (0)
# define _LIBCXXABI_TRACE_STATETAB0(msg) \
do { \
if (state_tab_dbg()) \
fprintf(stderr, "libcxxabi: " msg); \
} while (0)
# define _LIBCXXABI_TRACE_STATETAB1(msg) \
do { \
if (state_tab_dbg()) \
fprintf(stderr, msg); \
} while (0)
# define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
#endif // NDEBUG
namespace __state_table_eh {
using destruct_f = void (*)(void*);
// Definition of flags for the state table entry field 'action flag'.
enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 };
// Definition of flags for the state table entry field 'flags'.
enum FSMEntryFlag : int16_t {
indirect = 0x100, // Object was thrown from a function where
// the return value optimization was used.
oldConditionalStateChange = 0x400, // State table entry is an indirect state
// change, dereference the address in
// offset as int for the target state.
// This is deprecated. This indicates
// the address is direct. (static local).
conditionalStateChange = 0x800, // State table entry is an indirect state
// change, dereference the address in
// offset as int for the target state.
// The temporary is an automatic. State
// change is used in cases such as
// (b?(T1(),foo()):(T2(),foo())),throw 42;
// which causes a conditional state change
// so that we know if T1 or T2 need to be
// destroyed.
thisFlag = 0x01, // The address of the object for the
// cleanup action is based on the
// StateVariable::thisValue.
vBaseFlag = 0x02, // The object is of a virtual base class.
globalObj = 0x04 // FSMEntry::address is the address of
// a global object.
};
namespace {
// The finite state machine to be walked.
struct FSMEntry {
union {
// Offset of the object within its stack frame or containing object.
intptr_t offset;
// Address of a global object.
intptr_t address;
// Address of the next state if it is an old conditional state change entry.
intptr_t nextStatePtr;
};
union {
// Address of the destructor function.
void (*destructor)(void*, size_t);
// The address of the catch block or cleanup code.
void* landingPad;
};
union {
// The flag for actions (when the value is negative).
FSMEntryCount actionFlag;
// The element count (when the value is positive or zero).
size_t elementCount;
};
size_t elemSize;
FSMEntryFlag flags;
uint16_t nextState;
};
struct FSM {
uint32_t magic; // Magic number of the state table.
int32_t numberOfStates;
FSMEntry table[1]; // Actually table[numberOfStates].
};
// The state variable on the stack.
struct StateVariable {
int32_t state;
struct FSM* table;
intptr_t thisValue;
int32_t ignoreVBasePtrs;
};
} // namespace
// State table magic number
enum FSMMagic : uint32_t {
number = 0xbeefdead, // State table generated by xlC compiler.
number2 = 0xbeeedead, // State table generated by early version xlC compiler.
number3 = 0x1cedbeef // State table generated by xlclang++ compiler.
};
constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free
// virtual bases, don't delete object.
static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
_LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast<void*>(fsmEntry));
try {
if (fsmEntry->elementCount == 1) {
_LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n");
(*fsmEntry->destructor)(addr, dtorArgument);
_LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
} else {
_LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
__cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
reinterpret_cast<destruct_f>(fsmEntry->destructor));
_LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
}
} catch (...) {
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
std::terminate();
}
}
static void invoke_delete(FSMEntry* fsmEntry, void* addr) {
char* objectAddress = *reinterpret_cast<char**>(addr);
_LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast<void*>(objectAddress),
reinterpret_cast<void*>(fsmEntry));
try {
_LIBCXXABI_TRACE_STATETAB0("..calling delete()\n");
// 'destructor' holds a function pointer to delete().
(*fsmEntry->destructor)(objectAddress, fsmEntry->elemSize);
_LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n");
} catch (...) {
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
std::terminate();
}
}
// Get the frame address of the current function from its traceback table
// which is at the end of each function.
static uintptr_t get_frame_addr(_Unwind_Context* context) {
int framePointerReg = 1; // default frame pointer == SP.
uint32_t* p = reinterpret_cast<uint32_t*>(_Unwind_GetIP(context));
// Keep looking forward until a word of 0 is found. The traceback
// table starts at the following word.
while (*p)
++p;
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext);
// Skip field parminfo if it exists.
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
++p;
// Skip field tb_offset if it exists.
if (TBTable->tb.has_tboff)
++p;
// Skip field hand_mask if it exists.
if (TBTable->tb.int_hndl)
++p;
// Skip fields ctl_info and ctl_info_disp if they exist.
if (TBTable->tb.has_ctl)
p += 1 + *p;
// Skip fields name_len and name if exist.
if (TBTable->tb.name_present) {
const uint16_t name_len = *reinterpret_cast<uint16_t*>(p);
p = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(p) + name_len + sizeof(uint16_t));
}
if (TBTable->tb.uses_alloca)
framePointerReg = *reinterpret_cast<char*>(p);
return _Unwind_GetGR(context, framePointerReg);
}
// Calculate the object address from the FSM entry.
static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) {
void* addr;
if (fsmEntry->flags & FSMEntryFlag::globalObj) {
addr = reinterpret_cast<void*>(fsmEntry->address);
_LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr);
} else if (fsmEntry->flags & FSMEntryFlag::thisFlag) {
addr = reinterpret_cast<void*>(state->thisValue + fsmEntry->offset);
_LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : "
"state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n",
fsmEntry->offset, state->thisValue, addr);
} else if (fsmEntry->flags & FSMEntryFlag::indirect) {
addr = reinterpret_cast<void*>(
*reinterpret_cast<char**>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset)));
_LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n",
addr, fsmEntry->offset);
} else {
addr = reinterpret_cast<void*>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset));
_LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n",
addr);
}
return addr;
}
static void scan_state_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
_Unwind_Exception* unwind_exception, _Unwind_Context* context) {
// Initialize results to found nothing but an error.
results.ttypeIndex = 0;
results.actionRecord = 0;
results.languageSpecificData = 0;
results.landingPad = 0;
results.adjustedPtr = 0;
results.reason = _URC_FATAL_PHASE1_ERROR;
// Check for consistent actions.
if (actions & _UA_SEARCH_PHASE) {
// Do Phase 1
if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
// None of these flags should be set during Phase 1.
// Client error
results.reason = _URC_FATAL_PHASE1_ERROR;
return;
}
} else if (actions & _UA_CLEANUP_PHASE) {
if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) {
// _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
// If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
// Client error
results.reason = _URC_FATAL_PHASE2_ERROR;
return;
}
} else {
// Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
// Client error
results.reason = _URC_FATAL_PHASE1_ERROR;
return;
}
if (_LIBCXXABI_TRACING_STATETAB) {
_LIBCXXABI_TRACE_STATETAB1("\n");
_LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions);
if (_UA_SEARCH_PHASE & actions)
_LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE ");
if (_UA_CLEANUP_PHASE & actions)
_LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE ");
if (_UA_HANDLER_FRAME & actions)
_LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME ");
if (_UA_FORCE_UNWIND & actions)
_LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND ");
_LIBCXXABI_TRACE_STATETAB1(")\n");
_LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast<void*>(unwind_exception),
reinterpret_cast<void*>(context));
}
// Start scan by getting state table address.
StateVariable* const state = reinterpret_cast<StateVariable* const>(_Unwind_GetLanguageSpecificData(context));
if (state->state <= 0) {
// The state is not correct - give up on this routine.
_LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state);
results.reason = _URC_CONTINUE_UNWIND;
return;
}
// Parse the state table.
FSM* const fsm = state->table;
FSMEntry* currFSMEntry;
if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) {
// Something is wrong with the state table we found.
if (_UA_SEARCH_PHASE & actions) {
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n");
results.reason = _URC_FATAL_PHASE1_ERROR;
} else if (_UA_CLEANUP_PHASE & actions) {
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n");
results.reason = _URC_FATAL_PHASE2_ERROR;
} else {
// We should never get here.
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n");
results.reason = _URC_FATAL_PHASE2_ERROR;
}
return;
}
if (_LIBCXXABI_TRACING_STATETAB) {
// Print the state table for debugging purposes.
_LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs);
_LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates);
// Print out the FSM table.
_LIBCXXABI_TRACE_STATETAB0("FSM table:\n");
_LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad",
"count", "el_size", "flags", "next");
for (int i = 0; i < fsm->numberOfStates; i++) {
currFSMEntry = &fsm->table[i];
_LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld "
"%7ld %#7x %7d\n",
reinterpret_cast<void*>(&currFSMEntry), i + 1, currFSMEntry->offset,
reinterpret_cast<void*>(currFSMEntry->destructor),
currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags,
currFSMEntry->nextState);
}
}
if (_UA_SEARCH_PHASE & actions) {
// Start walking the state table. Use a local copy of state->state so when
// we return from search phase we don't change the state number.
int currState = state->state;
while (currState > 0) {
currFSMEntry = &fsm->table[currState - 1];
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags);
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) {
// Found a catch handler.
if (fsm->magic == FSMMagic::number) {
_LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n");
// xlC catch handlers cannot be entered because they use a
// proprietary EH runtime that is not interoperable.
results.reason = _URC_FATAL_PHASE1_ERROR;
return;
}
// xlclang++ compiled frames use CXA-abi EH calls and any catch
// block will include a catch(...) block so it is safe to assume that
// the handler is found without checking the catch match. The
// catch(...) block will rethrow the exception if there isn't a
// match.
_LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
results.reason = _URC_HANDLER_FOUND;
return;
}
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
_LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n");
results.reason = _URC_HANDLER_FOUND;
return;
}
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
// Deprecated conditional expression.
currState = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
currFSMEntry->nextStatePtr, currState);
continue; // We are done this iteration of the loop, since
// we changed a state.
}
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
void* addr = compute_addr_from_table(currFSMEntry, state, context);
currState = *reinterpret_cast<int*>(addr);
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
"addr(%p), set state=%d\n", addr, currState);
continue; // We are done this iteration of the loop, since we
// changed the state.
}
// Go to the next state.
currState = currFSMEntry->nextState;
}
_LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
results.reason = _URC_CONTINUE_UNWIND;
return;
}
if (_UA_CLEANUP_PHASE & actions) {
// Start walking the state table.
while (state->state > 0) {
currFSMEntry = &fsm->table[state->state - 1];
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
_LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n");
std::terminate();
}
// Perform action according to the currFSMEntry->actionFlag,
// except when flag is FSMEntryFlag::conditionalStateChange or
// FSMEntryFlag::oldConditionalStateChange.
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags);
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
state->state = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
currFSMEntry->nextStatePtr, state->state);
continue; // We are done with this iteration of the loop, since we changed a state.
}
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
// A conditional state table entry holds the address of a local
// that holds the next state.
void* addr = compute_addr_from_table(currFSMEntry, state, context);
state->state = *reinterpret_cast<int*>(addr);
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
"addr(%p), set state=%d\n", addr, state->state);
continue; // We are done with this iteration of the loop, since we changed a state.
}
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch ||
currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) {
_LIBCXXABI_TRACE_STATETAB(
"FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n",
(currFSMEntry->actionFlag == FSMEntryCount::beginCatch
? "beginCatch"
: (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")),
currFSMEntry->landingPad, *reinterpret_cast<void**>(currFSMEntry->landingPad));
state->state = currFSMEntry->nextState;
results.landingPad = reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(currFSMEntry->landingPad));
results.reason = _URC_HANDLER_FOUND;
return;
}
if (currFSMEntry->elementCount > 0) {
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
_LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
} else {
// We need to invoke the virtual base destructor. This must be
// a frame from the legacy xlC compiler as the xlclang++ compiler
// generates inline cleanup code rather than specifying
// the destructor via the state table.
void* addr = compute_addr_from_table(currFSMEntry, state, context);
// An extra indirect to get to the object according to the object
// model used by the xlC compiler.
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
_LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr);
invoke_destructor(currFSMEntry, addr);
}
} else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) {
void* addr = compute_addr_from_table(currFSMEntry, state, context);
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) {
// We need to invoke the virtual base delete function. This must be
// a frame from the legacy xlC compiler as the xlclang++ compiler
// generates inline cleanup code rather than specifying
// the delete function via the state table.
// An extra indirect to get to the object according to the object
// model used by the xlC compiler.
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
}
_LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
invoke_delete(currFSMEntry, addr);
} else {
_LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
currFSMEntry->elementCount);
} // End of action switching.
// Go to next state.
state->state = currFSMEntry->nextState;
}
_LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
results.reason = _URC_CONTINUE_UNWIND;
return;
}
_LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n");
// It is possible that no state table entry specify how to handle
// this exception. By spec, terminate it immediately.
call_terminate(native_exception, unwind_exception);
}
// Personality routine for EH using the state table.
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
__xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
_Unwind_Exception* unwind_exception, _Unwind_Context* context) {
if (version != 1 || unwind_exception == 0 || context == 0)
return _URC_FATAL_PHASE1_ERROR;
bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language);
scan_results results;
scan_state_tab(results, actions, native_exception, unwind_exception, context);
if (actions & _UA_SEARCH_PHASE) {
// Phase 1 search: All we're looking for in phase 1 is a handler that
// halts unwinding
return results.reason;
}
if (actions & _UA_CLEANUP_PHASE) {
// Phase 2 cleanup:
if (results.reason == _URC_HANDLER_FOUND) {
// Store the address of unwind_exception in the stack field
// reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of
// the caller of the function containing the landing pad (within the link
// area for the call to the latter) for __xlc_exception_handle()
// to retrieve when it is called by the landing pad.
uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1));
uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]);
callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception);
_LIBCXXABI_TRACE_STATETAB("Handshake: save unwind_exception=%p in stack=%p\n",
reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP));
// Jump to the handler.
_Unwind_SetIP(context, results.landingPad);
return _URC_INSTALL_CONTEXT;
}
// Did not find a handler. Return the results of the scan. Normally
// _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR.
return results.reason;
}
// We were called improperly: neither a phase 1 or phase 2 search.
return _URC_FATAL_PHASE1_ERROR;
}
} // namespace __state_table_eh
// The following are EH helper functions for xlclang++ compiled code.
// __xlc_catch_matchv2
// Check whether the thrown object matches the catch handler's exception
// declaration. If there is a match, the function returns true with adjusted
// address of the thrown object. Otherwise, returns false.
_LIBCXXABI_FUNC_VIS bool
__xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) {
_LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast<void*>(exceptionObject));
if (!__isOurExceptionClass(exceptionObject)) {
_LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n");
return false;
}
__cxa_exception* exceptionHeader = 0;
if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) {
// Walk to the __cxa_dependent_exception primary exception for the
// exception object and its type_info.
__cxa_dependent_exception* dependentExceptionHeader =
reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1;
exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1;
_LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n",
reinterpret_cast<void*>(exceptionObject),
reinterpret_cast<void*>(&exceptionHeader->unwindHeader));
exceptionObject = &exceptionHeader->unwindHeader;
} else {
_LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
}
void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1);
std::type_info* throwTypeInfo = exceptionHeader->exceptionType;
// Get the type info for the thrown type and this catch clause and
// see if the catch caluse can catch that type.
__cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo);
__cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo);
_LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n",
reinterpret_cast<void*>(exceptionObject), thrownObject, reinterpret_cast<void*>(throwType),
throwType->name(), reinterpret_cast<void*>(catchType), catchType->name());
if (catchType->can_catch(throwType, thrownObject)) {
exceptionHeader->adjustedPtr = thrownObject;
obj = thrownObject;
_LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
return true;
}
_LIBCXXABI_TRACE_STATETAB0("No match\n");
return false;
}
// __xlc_throw_badexception
// This function is for xlclang++. It allocates and throws a bad_exception.
// During unwinding for this bad_exception, the previous exception which is
// not matching the throw spec will be cleaned up. Thus having the same
// effect as replace the top most exception (which is bad) with a bad_exception.
_LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() {
_LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__);
void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception;
__cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0);
}
// skip_non_cxx_eh_aware_frames
// This function skips non-C++ EH aware stack frames by unwinding from the
// stack frame pointed by 'Sp' and returns the first C++ EH aware stack frame
// found. 'Pc' is an instruction address inside the function that owns the
// stack frame pointed to by 'Sp'.
static uintptr_t* skip_non_cxx_eh_aware_frames(uint32_t* Pc, uintptr_t* Sp) {
uint32_t* currentPc = Pc;
uintptr_t* currentStack = Sp;
// Loop until a C++ EH aware frame is found or the return address is 0,
// which is the return address of the startup function '__start'.
while (currentPc != 0) {
uint32_t* p = currentPc;
// Keep looking forward until a word of 0 is found. The traceback
// table starts at the following word.
while (*p)
++p;
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
// A stack frame with a C++ state table is C++ EH aware.
if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl)
return currentStack;
// Move up one stack frame.
currentStack = reinterpret_cast<uintptr_t*>(currentStack[0]);
// Get the value of the LR (saved, prior to incrementing the SP, by the
// prolog of the function just inspected) from the frame.
currentPc = reinterpret_cast<uint32_t*>(currentStack[2]);
}
// This should not happen.
_LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n");
abort();
}
// __xlc_exception_handle
// This function is for xlclang++. It returns the address of the exception
// object stored in the reserved field in the stack of the caller of the
// function that calls __xlc_exception_handle() (within the link area for the
// call to the latter). The address is stored by the personality routine for
// xlclang++ compiled code. If __xlc_exception_handle() is called by
// non-C++ EH aware functions, their frames are skipped until a C++ EH aware
// frame is found.
// Note: make sure __xlc_excpetion_handle() is a non-leaf function. Currently
// it calls skip_non_cxx_eh_aware_frames(), which in turn calls abort().
_LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
// Get the SP of this function, i.e., __xlc_exception_handle().
uintptr_t* lastStack = reinterpret_cast<uintptr_t*>(__builtin_frame_address(0));
// Move one frame up to the frame of the caller of __xlc_exception_handle().
lastStack = reinterpret_cast<uintptr_t*>(lastStack[0]);
// Get the return address of this function, i.e., __xlc_exception_handle().
uint32_t* returnAddress = reinterpret_cast<uint32_t*>(__builtin_return_address(0));
// Skip non-C++ EH aware frames and get the first C++ EH aware frame.
uintptr_t* callerStack = skip_non_cxx_eh_aware_frames(returnAddress, lastStack);
// Get the SP of the caller of the C++ EH aware caller.
callerStack = reinterpret_cast<uintptr_t*>(callerStack[0]);
// Retrieve the exception object in the stack slot saved by the personality.
uintptr_t exceptionObject = callerStack[3];
_LIBCXXABI_TRACE_STATETAB("Handshake: retrieve exceptionObject=%p from stack=%p\n",
reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack));
return exceptionObject;
}
// xlclang++ may generate calls to __Deleted_Virtual.
_LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); }
// __catchThrownException is called during AIX library initialization and
// termination to handle exceptions. An implementation is also provided in
// libC.a(shrcore.o). This implementation is provided for applications that
// link with -lc++ (the xlclang++ or ibm-clang++ link default.)
_LIBCXXABI_FUNC_VIS int
__catchThrownException(void (*cdfunc)(void), // function which may fail
void (*cleanup)(void*), // cleanup function
void* cleanuparg, // parameter to cleanup function
int action) { // control exception throwing and termination
enum Action : int { None = 0, Rethrow = 1, Terminate = 2 };
if (!cdfunc)
return 0;
if (action == Action::Rethrow && !cleanup) {
// No cleanup and rethrow is effectively no-op.
// Avoid the catch handler when possible to allow exceptions generated
// from xlC binaries to flow through.
(*cdfunc)();
return 0;
}
try {
(*cdfunc)();
} catch (...) {
if (action == Action::Terminate)
std::terminate();
if (cleanup)
(*cleanup)(cleanuparg);
if (action == Action::Rethrow)
throw;
assert(action == Action::None);
return -1; // FAILED
}
return 0;
}
} // extern "C"
} // __cxxabiv1

View file

@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the "Auxiliary Runtime APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-aux
//===----------------------------------------------------------------------===//
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/exception"
#include "third_party/libcxx/new"
#include "third_party/libcxx/typeinfo"
namespace __cxxabiv1 {
extern "C" {
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_cast();
#else
std::terminate();
#endif
}
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_typeid();
#else
std::terminate();
#endif
}
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw_bad_array_new_length(void) {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_array_new_length();
#else
std::terminate();
#endif
}
} // extern "C"
} // abi

View file

@ -0,0 +1,141 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the default terminate_handler, unexpected_handler and
// new_handler.
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/exception"
#include "third_party/libcxx/memory"
#include "third_party/libcxx/stdlib.h"
#include "third_party/libcxxabi/abort_message.h"
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxxabi/cxa_handlers.h"
#include "third_party/libcxxabi/cxa_exception.h"
#include "third_party/libcxxabi/private_typeinfo.h"
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
#if !defined(LIBCXXABI_SILENT_TERMINATE)
static constinit const char* cause = "uncaught";
#ifndef _LIBCXXABI_NO_EXCEPTIONS
// Demangle the given string, or return the string as-is in case of an error.
static std::unique_ptr<char const, void (*)(char const*)> demangle(char const* str)
{
#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE)
if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr))
return {result, [](char const* p) { std::free(const_cast<char*>(p)); }};
#endif
return {str, [](char const*) { /* nothing to free */ }};
}
__attribute__((noreturn))
static void demangling_terminate_handler()
{
using namespace __cxxabiv1;
__cxa_eh_globals* globals = __cxa_get_globals_fast();
// If there is no uncaught exception, just note that we're terminating
if (!globals)
abort_message("terminating");
__cxa_exception* exception_header = globals->caughtExceptions;
if (!exception_header)
abort_message("terminating");
_Unwind_Exception* unwind_exception =
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
// If we're terminating due to a foreign exception
if (!__isOurExceptionClass(unwind_exception))
abort_message("terminating due to %s foreign exception", cause);
void* thrown_object =
__getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
((__cxa_dependent_exception*)exception_header)->primaryException :
exception_header + 1;
const __shim_type_info* thrown_type =
static_cast<const __shim_type_info*>(exception_header->exceptionType);
auto name = demangle(thrown_type->name());
// If the uncaught exception can be caught with std::exception&
const __shim_type_info* catch_type =
static_cast<const __shim_type_info*>(&typeid(std::exception));
if (catch_type->can_catch(thrown_type, thrown_object))
{
// Include the what() message from the exception
const std::exception* e = static_cast<const std::exception*>(thrown_object);
abort_message("terminating due to %s exception of type %s: %s", cause, name.get(), e->what());
}
else
{
// Else just note that we're terminating due to an exception
abort_message("terminating due to %s exception of type %s", cause, name.get());
}
}
#else // !_LIBCXXABI_NO_EXCEPTIONS
__attribute__((noreturn))
static void demangling_terminate_handler()
{
abort_message("terminating");
}
#endif // !_LIBCXXABI_NO_EXCEPTIONS
__attribute__((noreturn))
static void demangling_unexpected_handler()
{
cause = "unexpected";
std::terminate();
}
static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
#else // !LIBCXXABI_SILENT_TERMINATE
static constexpr std::terminate_handler default_terminate_handler = ::abort;
static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
#endif // !LIBCXXABI_SILENT_TERMINATE
//
// Global variables that hold the pointers to the current handler
//
_LIBCXXABI_DATA_VIS
constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
_LIBCXXABI_DATA_VIS
constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
_LIBCXXABI_DATA_VIS
constinit std::new_handler __cxa_new_handler = nullptr;
namespace std
{
unexpected_handler
set_unexpected(unexpected_handler func) noexcept
{
if (func == 0)
func = default_unexpected_handler;
return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
_AO_Acq_Rel);
}
terminate_handler
set_terminate(terminate_handler func) noexcept
{
if (func == 0)
func = default_terminate_handler;
return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
_AO_Acq_Rel);
}
new_handler
set_new_handler(new_handler handler) noexcept
{
return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
}
}

409
third_party/libcxxabi/cxa_demangle.cc vendored Normal file
View file

@ -0,0 +1,409 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// FIXME: (possibly) incomplete list of features that clang mangles that this
// file does not yet support:
// - C++ modules TS
#include "third_party/libcxxabi/demangle/DemangleConfig.h"
#include "third_party/libcxxabi/demangle/ItaniumDemangle.h"
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cctype"
#include "third_party/libcxx/cstdio"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/cstring"
#include "third_party/libcxx/functional"
#include "third_party/libcxx/numeric"
#include "third_party/libcxx/string_view"
#include "third_party/libcxx/utility"
using namespace itanium_demangle;
constexpr const char *itanium_demangle::FloatData<float>::spec;
constexpr const char *itanium_demangle::FloatData<double>::spec;
constexpr const char *itanium_demangle::FloatData<long double>::spec;
// <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+ # at the end of string
const char *itanium_demangle::parse_discriminator(const char *first,
const char *last) {
// parse but ignore discriminator
if (first != last) {
if (*first == '_') {
const char *t1 = first + 1;
if (t1 != last) {
if (std::isdigit(*t1))
first = t1 + 1;
else if (*t1 == '_') {
for (++t1; t1 != last && std::isdigit(*t1); ++t1)
;
if (t1 != last && *t1 == '_')
first = t1 + 1;
}
}
} else if (std::isdigit(*first)) {
const char *t1 = first + 1;
for (; t1 != last && std::isdigit(*t1); ++t1)
;
if (t1 == last)
first = last;
}
}
return first;
}
#ifndef NDEBUG
namespace {
struct DumpVisitor {
unsigned Depth = 0;
bool PendingNewline = false;
template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
return true;
}
static bool wantsNewline(NodeArray A) { return !A.empty(); }
static constexpr bool wantsNewline(...) { return false; }
template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
for (bool B : {wantsNewline(Vs)...})
if (B)
return true;
return false;
}
void printStr(const char *S) { fprintf(stderr, "%s", S); }
void print(std::string_view SV) {
fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin());
}
void print(const Node *N) {
if (N)
N->visit(std::ref(*this));
else
printStr("<null>");
}
void print(NodeArray A) {
++Depth;
printStr("{");
bool First = true;
for (const Node *N : A) {
if (First)
print(N);
else
printWithComma(N);
First = false;
}
printStr("}");
--Depth;
}
// Overload used when T is exactly 'bool', not merely convertible to 'bool'.
void print(bool B) { printStr(B ? "true" : "false"); }
template <class T>
typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
fprintf(stderr, "%llu", (unsigned long long)N);
}
template <class T>
typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
fprintf(stderr, "%lld", (long long)N);
}
void print(ReferenceKind RK) {
switch (RK) {
case ReferenceKind::LValue:
return printStr("ReferenceKind::LValue");
case ReferenceKind::RValue:
return printStr("ReferenceKind::RValue");
}
}
void print(FunctionRefQual RQ) {
switch (RQ) {
case FunctionRefQual::FrefQualNone:
return printStr("FunctionRefQual::FrefQualNone");
case FunctionRefQual::FrefQualLValue:
return printStr("FunctionRefQual::FrefQualLValue");
case FunctionRefQual::FrefQualRValue:
return printStr("FunctionRefQual::FrefQualRValue");
}
}
void print(Qualifiers Qs) {
if (!Qs) return printStr("QualNone");
struct QualName { Qualifiers Q; const char *Name; } Names[] = {
{QualConst, "QualConst"},
{QualVolatile, "QualVolatile"},
{QualRestrict, "QualRestrict"},
};
for (QualName Name : Names) {
if (Qs & Name.Q) {
printStr(Name.Name);
Qs = Qualifiers(Qs & ~Name.Q);
if (Qs) printStr(" | ");
}
}
}
void print(SpecialSubKind SSK) {
switch (SSK) {
case SpecialSubKind::allocator:
return printStr("SpecialSubKind::allocator");
case SpecialSubKind::basic_string:
return printStr("SpecialSubKind::basic_string");
case SpecialSubKind::string:
return printStr("SpecialSubKind::string");
case SpecialSubKind::istream:
return printStr("SpecialSubKind::istream");
case SpecialSubKind::ostream:
return printStr("SpecialSubKind::ostream");
case SpecialSubKind::iostream:
return printStr("SpecialSubKind::iostream");
}
}
void print(TemplateParamKind TPK) {
switch (TPK) {
case TemplateParamKind::Type:
return printStr("TemplateParamKind::Type");
case TemplateParamKind::NonType:
return printStr("TemplateParamKind::NonType");
case TemplateParamKind::Template:
return printStr("TemplateParamKind::Template");
}
}
void print(Node::Prec P) {
switch (P) {
case Node::Prec::Primary:
return printStr("Node::Prec::Primary");
case Node::Prec::Postfix:
return printStr("Node::Prec::Postfix");
case Node::Prec::Unary:
return printStr("Node::Prec::Unary");
case Node::Prec::Cast:
return printStr("Node::Prec::Cast");
case Node::Prec::PtrMem:
return printStr("Node::Prec::PtrMem");
case Node::Prec::Multiplicative:
return printStr("Node::Prec::Multiplicative");
case Node::Prec::Additive:
return printStr("Node::Prec::Additive");
case Node::Prec::Shift:
return printStr("Node::Prec::Shift");
case Node::Prec::Spaceship:
return printStr("Node::Prec::Spaceship");
case Node::Prec::Relational:
return printStr("Node::Prec::Relational");
case Node::Prec::Equality:
return printStr("Node::Prec::Equality");
case Node::Prec::And:
return printStr("Node::Prec::And");
case Node::Prec::Xor:
return printStr("Node::Prec::Xor");
case Node::Prec::Ior:
return printStr("Node::Prec::Ior");
case Node::Prec::AndIf:
return printStr("Node::Prec::AndIf");
case Node::Prec::OrIf:
return printStr("Node::Prec::OrIf");
case Node::Prec::Conditional:
return printStr("Node::Prec::Conditional");
case Node::Prec::Assign:
return printStr("Node::Prec::Assign");
case Node::Prec::Comma:
return printStr("Node::Prec::Comma");
case Node::Prec::Default:
return printStr("Node::Prec::Default");
}
}
void newLine() {
printStr("\n");
for (unsigned I = 0; I != Depth; ++I)
printStr(" ");
PendingNewline = false;
}
template<typename T> void printWithPendingNewline(T V) {
print(V);
if (wantsNewline(V))
PendingNewline = true;
}
template<typename T> void printWithComma(T V) {
if (PendingNewline || wantsNewline(V)) {
printStr(",");
newLine();
} else {
printStr(", ");
}
printWithPendingNewline(V);
}
struct CtorArgPrinter {
DumpVisitor &Visitor;
template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
if (Visitor.anyWantNewline(V, Vs...))
Visitor.newLine();
Visitor.printWithPendingNewline(V);
int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
(void)PrintInOrder;
}
};
template<typename NodeT> void operator()(const NodeT *Node) {
Depth += 2;
fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
Node->match(CtorArgPrinter{*this});
fprintf(stderr, ")");
Depth -= 2;
}
void operator()(const ForwardTemplateReference *Node) {
Depth += 2;
fprintf(stderr, "ForwardTemplateReference(");
if (Node->Ref && !Node->Printing) {
Node->Printing = true;
CtorArgPrinter{*this}(Node->Ref);
Node->Printing = false;
} else {
CtorArgPrinter{*this}(Node->Index);
}
fprintf(stderr, ")");
Depth -= 2;
}
};
}
void itanium_demangle::Node::dump() const {
DumpVisitor V;
visit(std::ref(V));
V.newLine();
}
#endif
namespace {
class BumpPointerAllocator {
struct BlockMeta {
BlockMeta* Next;
size_t Current;
};
static constexpr size_t AllocSize = 4096;
static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
alignas(long double) char InitialBuffer[AllocSize];
BlockMeta* BlockList = nullptr;
void grow() {
char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
if (NewMeta == nullptr)
std::terminate();
BlockList = new (NewMeta) BlockMeta{BlockList, 0};
}
void* allocateMassive(size_t NBytes) {
NBytes += sizeof(BlockMeta);
BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
if (NewMeta == nullptr)
std::terminate();
BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
return static_cast<void*>(NewMeta + 1);
}
public:
BumpPointerAllocator()
: BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
void* allocate(size_t N) {
N = (N + 15u) & ~15u;
if (N + BlockList->Current >= UsableAllocSize) {
if (N > UsableAllocSize)
return allocateMassive(N);
grow();
}
BlockList->Current += N;
return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
BlockList->Current - N);
}
void reset() {
while (BlockList) {
BlockMeta* Tmp = BlockList;
BlockList = BlockList->Next;
if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
std::free(Tmp);
}
BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
}
~BumpPointerAllocator() { reset(); }
};
class DefaultAllocator {
BumpPointerAllocator Alloc;
public:
void reset() { Alloc.reset(); }
template<typename T, typename ...Args> T *makeNode(Args &&...args) {
return new (Alloc.allocate(sizeof(T)))
T(std::forward<Args>(args)...);
}
void *allocateNodeArray(size_t sz) {
return Alloc.allocate(sizeof(Node *) * sz);
}
};
} // unnamed namespace
//===----------------------------------------------------------------------===//
// Code beyond this point should not be synchronized with LLVM.
//===----------------------------------------------------------------------===//
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
namespace {
enum : int {
demangle_invalid_args = -3,
demangle_invalid_mangled_name = -2,
demangle_memory_alloc_failure = -1,
demangle_success = 0,
};
}
namespace __cxxabiv1 {
extern "C" _LIBCXXABI_FUNC_VIS char *
__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
if (Status)
*Status = demangle_invalid_args;
return nullptr;
}
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
Node *AST = Parser.parse();
if (AST == nullptr)
InternalStatus = demangle_invalid_mangled_name;
else {
OutputBuffer O(Buf, N);
assert(Parser.ForwardTemplateRefs.empty());
AST->print(O);
O += '\0';
if (N != nullptr)
*N = O.getCurrentPosition();
Buf = O.getBuffer();
}
if (Status)
*Status = InternalStatus;
return InternalStatus == demangle_success ? Buf : nullptr;
}
} // __cxxabiv1

776
third_party/libcxxabi/cxa_exception.cc vendored Normal file
View file

@ -0,0 +1,776 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the "Exception Handling APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/exception" // for std::terminate
#include "libc/isystem/string.h" // for memset
#include "third_party/libcxxabi/cxa_exception.h"
#include "third_party/libcxxabi/cxa_handlers.h"
#include "third_party/libcxxabi/fallback_malloc.h"
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
#if __has_feature(address_sanitizer)
#include <sanitizer/asan_interface.h>
#endif
// +---------------------------+-----------------------------+---------------+
// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
// +---------------------------+-----------------------------+---------------+
// ^
// |
// +-------------------------------------------------------+
// |
// +---------------------------+-----------------------------+
// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
// +---------------------------+-----------------------------+
namespace __cxxabiv1 {
// Utility routines
static
inline
__cxa_exception*
cxa_exception_from_thrown_object(void* thrown_object)
{
return static_cast<__cxa_exception*>(thrown_object) - 1;
}
// Note: This is never called when exception_header is masquerading as a
// __cxa_dependent_exception.
static
inline
void*
thrown_object_from_cxa_exception(__cxa_exception* exception_header)
{
return static_cast<void*>(exception_header + 1);
}
// Get the exception object from the unwind pointer.
// Relies on the structure layout, where the unwind pointer is right in
// front of the user's exception object
static
inline
__cxa_exception*
cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
{
return cxa_exception_from_thrown_object(unwind_exception + 1 );
}
// Round s up to next multiple of a.
static inline
size_t aligned_allocation_size(size_t s, size_t a) {
return (s + a - 1) & ~(a - 1);
}
static inline
size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
return aligned_allocation_size(size + sizeof (__cxa_exception),
alignof(__cxa_exception));
}
void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) {
::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue));
}
static void setOurExceptionClass(_Unwind_Exception* unwind_exception) {
__setExceptionClass(unwind_exception, kOurExceptionClass);
}
static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
__setExceptionClass(unwind_exception, kOurDependentExceptionClass);
}
// Is it one of ours?
uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
// On x86 and some ARM unwinders, unwind_exception->exception_class is
// a uint64_t. On other ARM unwinders, it is a char[8].
// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
// So we just copy it into a uint64_t to be sure.
uint64_t exClass;
::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
return exClass;
}
bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
return (__getExceptionClass(unwind_exception) & get_vendor_and_language) ==
(kOurExceptionClass & get_vendor_and_language);
}
static bool isDependentException(_Unwind_Exception* unwind_exception) {
return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01;
}
// This does not need to be atomic
static inline int incrementHandlerCount(__cxa_exception *exception) {
return ++exception->handlerCount;
}
// This does not need to be atomic
static inline int decrementHandlerCount(__cxa_exception *exception) {
return --exception->handlerCount;
}
/*
If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
stored in exc is called. Otherwise the exceptionDestructor stored in
exc is called, and then the memory for the exception is deallocated.
This is never called for a __cxa_dependent_exception.
*/
static
void
exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
{
__cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception);
if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
std::__terminate(exception_header->terminateHandler);
// Just in case there exists a dependent exception that is pointing to this,
// check the reference count and only destroy this if that count goes to zero.
__cxa_decrement_exception_refcount(unwind_exception + 1);
}
static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) {
// Section 2.5.3 says:
// * For purposes of this ABI, several things are considered exception handlers:
// ** A terminate() call due to a throw.
// and
// * Upon entry, Following initialization of the catch parameter,
// a handler must call:
// * void *__cxa_begin_catch(void *exceptionObject );
(void) __cxa_begin_catch(&exception_header->unwindHeader);
std::__terminate(exception_header->terminateHandler);
}
// Return the offset of the __cxa_exception header from the start of the
// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
// useful alignment for the target machine, padding has to be inserted before
// the header to ensure the thrown object that follows the header is
// sufficiently aligned. This happens if _Unwind_exception isn't double-word
// aligned (on Darwin, for example).
static size_t get_cxa_exception_offset() {
struct S {
} __attribute__((aligned));
// Compute the maximum alignment for the target machine.
constexpr size_t alignment = alignof(S);
constexpr size_t excp_size = sizeof(__cxa_exception);
constexpr size_t aligned_size =
(excp_size + alignment - 1) / alignment * alignment;
constexpr size_t offset = aligned_size - excp_size;
static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment),
"offset is non-zero only if _Unwind_Exception isn't aligned");
return offset;
}
extern "C" {
// Allocate a __cxa_exception object, and zero-fill it.
// Reserve "thrown_size" bytes on the end for the user's exception
// object. Zero-fill the object. If memory can't be allocated, call
// std::terminate. Return a pointer to the memory to be used for the
// user's exception object.
void *__cxa_allocate_exception(size_t thrown_size) throw() {
size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
// Allocate extra space before the __cxa_exception header to ensure the
// start of the thrown object is sufficiently aligned.
size_t header_offset = get_cxa_exception_offset();
char *raw_buffer =
(char *)__aligned_malloc_with_fallback(header_offset + actual_size);
if (NULL == raw_buffer)
std::terminate();
__cxa_exception *exception_header =
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
::memset(exception_header, 0, actual_size);
return thrown_object_from_cxa_exception(exception_header);
}
// Free a __cxa_exception object allocated with __cxa_allocate_exception.
void __cxa_free_exception(void *thrown_object) throw() {
// Compute the size of the padding before the header.
size_t header_offset = get_cxa_exception_offset();
char *raw_buffer =
((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
__aligned_free_with_fallback((void *)raw_buffer);
}
// This function shall allocate a __cxa_dependent_exception and
// return a pointer to it. (Really to the object, not past its' end).
// Otherwise, it will work like __cxa_allocate_exception.
void * __cxa_allocate_dependent_exception () {
size_t actual_size = sizeof(__cxa_dependent_exception);
void *ptr = __aligned_malloc_with_fallback(actual_size);
if (NULL == ptr)
std::terminate();
::memset(ptr, 0, actual_size);
return ptr;
}
// This function shall free a dependent_exception.
// It does not affect the reference count of the primary exception.
void __cxa_free_dependent_exception (void * dependent_exception) {
__aligned_free_with_fallback(dependent_exception);
}
// 2.4.3 Throwing the Exception Object
/*
After constructing the exception object with the throw argument value,
the generated code calls the __cxa_throw runtime library routine. This
routine never returns.
The __cxa_throw routine will do the following:
* Obtain the __cxa_exception header from the thrown exception object address,
which can be computed as follows:
__cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
* Save the tinfo and dest arguments in the __cxa_exception header.
* Set the exception_class field in the unwind header. This is a 64-bit value
representing the ASCII string "XXXXC++\0", where "XXXX" is a
vendor-dependent string. That is, for implementations conforming to this
ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
* Increment the uncaught_exception flag.
* Call _Unwind_RaiseException in the system unwind library, Its argument is the
pointer to the thrown exception, which __cxa_throw itself received as an argument.
__Unwind_RaiseException begins the process of stack unwinding, described
in Section 2.5. In special cases, such as an inability to find a
handler, _Unwind_RaiseException may return. In that case, __cxa_throw
will call terminate, assuming that there was no handler for the
exception.
*/
void
__cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
__cxa_eh_globals *globals = __cxa_get_globals();
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
exception_header->unexpectedHandler = std::get_unexpected();
exception_header->terminateHandler = std::get_terminate();
exception_header->exceptionType = tinfo;
exception_header->exceptionDestructor = dest;
setOurExceptionClass(&exception_header->unwindHeader);
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
#if __has_feature(address_sanitizer)
// Inform the ASan runtime that now might be a good time to clean stuff up.
__asan_handle_no_return();
#endif
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
#else
_Unwind_RaiseException(&exception_header->unwindHeader);
#endif
// This only happens when there is no handler, or some unexpected unwinding
// error happens.
failed_throw(exception_header);
}
// 2.5.3 Exception Handlers
/*
The adjusted pointer is computed by the personality routine during phase 1
and saved in the exception header (either __cxa_exception or
__cxa_dependent_exception).
Requires: exception is native
*/
void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
#if defined(_LIBCXXABI_ARM_EHABI)
return reinterpret_cast<void*>(
static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
#else
return cxa_exception_from_exception_unwind_exception(
static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr;
#endif
}
#if defined(_LIBCXXABI_ARM_EHABI)
/*
The routine to be called before the cleanup. This will save __cxa_exception in
__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
*/
bool __cxa_begin_cleanup(void *unwind_arg) throw() {
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
__cxa_eh_globals* globals = __cxa_get_globals();
__cxa_exception* exception_header =
cxa_exception_from_exception_unwind_exception(unwind_exception);
if (__isOurExceptionClass(unwind_exception))
{
if (0 == exception_header->propagationCount)
{
exception_header->nextPropagatingException = globals->propagatingExceptions;
globals->propagatingExceptions = exception_header;
}
++exception_header->propagationCount;
}
else
{
// If the propagatingExceptions stack is not empty, since we can't
// chain the foreign exception, terminate it.
if (NULL != globals->propagatingExceptions)
std::terminate();
globals->propagatingExceptions = exception_header;
}
return true;
}
/*
The routine to be called after the cleanup has been performed. It will get the
propagating __cxa_exception from __cxa_eh_globals, and continue the stack
unwinding with _Unwind_Resume.
According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
register, thus we have to write this function in assembly so that we can save
{r1, r2, r3}. We don't have to save r0 because it is the return value and the
first argument to _Unwind_Resume(). The function also saves/restores r4 to
keep the stack aligned and to provide a temp register. _Unwind_Resume never
returns and we need to keep the original lr so just branch to it. When
targeting bare metal, the function also clobbers ip/r12 to hold the address of
_Unwind_Resume, which may be too far away for an ordinary branch.
*/
__attribute__((used)) static _Unwind_Exception *
__cxa_end_cleanup_impl()
{
__cxa_eh_globals* globals = __cxa_get_globals();
__cxa_exception* exception_header = globals->propagatingExceptions;
if (NULL == exception_header)
{
// It seems that __cxa_begin_cleanup() is not called properly.
// We have no choice but terminate the program now.
std::terminate();
}
if (__isOurExceptionClass(&exception_header->unwindHeader))
{
--exception_header->propagationCount;
if (0 == exception_header->propagationCount)
{
globals->propagatingExceptions = exception_header->nextPropagatingException;
exception_header->nextPropagatingException = NULL;
}
}
else
{
globals->propagatingExceptions = NULL;
}
return &exception_header->unwindHeader;
}
asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
" .globl __cxa_end_cleanup\n"
" .type __cxa_end_cleanup,%function\n"
"__cxa_end_cleanup:\n"
#if defined(__ARM_FEATURE_BTI_DEFAULT)
" bti\n"
#endif
" push {r1, r2, r3, r4}\n"
" mov r4, lr\n"
" bl __cxa_end_cleanup_impl\n"
" mov lr, r4\n"
#if defined(LIBCXXABI_BAREMETAL)
" ldr r4, =_Unwind_Resume\n"
" mov ip, r4\n"
#endif
" pop {r1, r2, r3, r4}\n"
#if defined(LIBCXXABI_BAREMETAL)
" bx ip\n"
#else
" b _Unwind_Resume\n"
#endif
" .popsection");
#endif // defined(_LIBCXXABI_ARM_EHABI)
/*
This routine can catch foreign or native exceptions. If native, the exception
can be a primary or dependent variety. This routine may remain blissfully
ignorant of whether the native exception is primary or dependent.
If the exception is native:
* Increment's the exception's handler count.
* Push the exception on the stack of currently-caught exceptions if it is not
already there (from a rethrow).
* Decrements the uncaught_exception count.
* Returns the adjusted pointer to the exception object, which is stored in
the __cxa_exception by the personality routine.
If the exception is foreign, this means it did not originate from one of throw
routines. The foreign exception does not necessarily have a __cxa_exception
header. However we can catch it here with a catch (...), or with a call
to terminate or unexpected during unwinding.
* Do not try to increment the exception's handler count, we don't know where
it is.
* Push the exception on the stack of currently-caught exceptions only if the
stack is empty. The foreign exception has no way to link to the current
top of stack. If the stack is not empty, call terminate. Even with an
empty stack, this is hacked in by pushing a pointer to an imaginary
__cxa_exception block in front of the foreign exception. It would be better
if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
doesn't. It has a stack of __cxa_exception (which has a next* in it).
* Do not decrement the uncaught_exception count because we didn't increment it
in __cxa_throw (or one of our rethrow functions).
* If we haven't terminated, assume the exception object is just past the
_Unwind_Exception and return a pointer to that.
*/
void*
__cxa_begin_catch(void* unwind_arg) throw()
{
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
bool native_exception = __isOurExceptionClass(unwind_exception);
__cxa_eh_globals* globals = __cxa_get_globals();
// exception_header is a hackish offset from a foreign exception, but it
// works as long as we're careful not to try to access any __cxa_exception
// parts.
__cxa_exception* exception_header =
cxa_exception_from_exception_unwind_exception
(
static_cast<_Unwind_Exception*>(unwind_exception)
);
#if defined(__MVS__)
// Remove the exception object from the linked list of exceptions that the z/OS unwinder
// maintains before adding it to the libc++abi list of caught exceptions.
// The libc++abi will manage the lifetime of the exception from this point forward.
_UnwindZOS_PopException();
#endif
if (native_exception)
{
// Increment the handler count, removing the flag about being rethrown
exception_header->handlerCount = exception_header->handlerCount < 0 ?
-exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
// place the exception on the top of the stack if it's not already
// there by a previous rethrow
if (exception_header != globals->caughtExceptions)
{
exception_header->nextException = globals->caughtExceptions;
globals->caughtExceptions = exception_header;
}
globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
#if defined(_LIBCXXABI_ARM_EHABI)
return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
#else
return exception_header->adjustedPtr;
#endif
}
// Else this is a foreign exception
// If the caughtExceptions stack is not empty, terminate
if (globals->caughtExceptions != 0)
std::terminate();
// Push the foreign exception on to the stack
globals->caughtExceptions = exception_header;
return unwind_exception + 1;
}
/*
Upon exit for any reason, a handler must call:
void __cxa_end_catch ();
This routine can be called for either a native or foreign exception.
For a native exception:
* Locates the most recently caught exception and decrements its handler count.
* Removes the exception from the caught exception stack, if the handler count goes to zero.
* If the handler count goes down to zero, and the exception was not re-thrown
by throw, it locates the primary exception (which may be the same as the one
it's handling) and decrements its reference count. If that reference count
goes to zero, the function destroys the exception. In any case, if the current
exception is a dependent exception, it destroys that.
For a foreign exception:
* If it has been rethrown, there is nothing to do.
* Otherwise delete the exception and pop the catch stack to empty.
*/
void __cxa_end_catch() {
static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
"sizeof(__cxa_exception) must be equal to "
"sizeof(__cxa_dependent_exception)");
static_assert(__builtin_offsetof(__cxa_exception, referenceCount) ==
__builtin_offsetof(__cxa_dependent_exception,
primaryException),
"the layout of __cxa_exception must match the layout of "
"__cxa_dependent_exception");
static_assert(__builtin_offsetof(__cxa_exception, handlerCount) ==
__builtin_offsetof(__cxa_dependent_exception, handlerCount),
"the layout of __cxa_exception must match the layout of "
"__cxa_dependent_exception");
__cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
__cxa_exception* exception_header = globals->caughtExceptions;
// If we've rethrown a foreign exception, then globals->caughtExceptions
// will have been made an empty stack by __cxa_rethrow() and there is
// nothing more to be done. Do nothing!
if (NULL != exception_header)
{
bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
if (native_exception)
{
// This is a native exception
if (exception_header->handlerCount < 0)
{
// The exception has been rethrown by __cxa_rethrow, so don't delete it
if (0 == incrementHandlerCount(exception_header))
{
// Remove from the chain of uncaught exceptions
globals->caughtExceptions = exception_header->nextException;
// but don't destroy
}
// Keep handlerCount negative in case there are nested catch's
// that need to be told that this exception is rethrown. Don't
// erase this rethrow flag until the exception is recaught.
}
else
{
// The native exception has not been rethrown
if (0 == decrementHandlerCount(exception_header))
{
// Remove from the chain of uncaught exceptions
globals->caughtExceptions = exception_header->nextException;
// Destroy this exception, being careful to distinguish
// between dependent and primary exceptions
if (isDependentException(&exception_header->unwindHeader))
{
// Reset exception_header to primaryException and deallocate the dependent exception
__cxa_dependent_exception* dep_exception_header =
reinterpret_cast<__cxa_dependent_exception*>(exception_header);
exception_header =
cxa_exception_from_thrown_object(dep_exception_header->primaryException);
__cxa_free_dependent_exception(dep_exception_header);
}
// Destroy the primary exception only if its referenceCount goes to 0
// (this decrement must be atomic)
__cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header));
}
}
}
else
{
// The foreign exception has not been rethrown. Pop the stack
// and delete it. If there are nested catch's and they try
// to touch a foreign exception in any way, that is undefined
// behavior. They likely can't since the only way to catch
// a foreign exception is with catch (...)!
_Unwind_DeleteException(&globals->caughtExceptions->unwindHeader);
globals->caughtExceptions = 0;
}
}
}
// Note: exception_header may be masquerading as a __cxa_dependent_exception
// and that's ok. exceptionType is there too.
// However watch out for foreign exceptions. Return null for them.
std::type_info *__cxa_current_exception_type() {
// get the current exception
__cxa_eh_globals *globals = __cxa_get_globals_fast();
if (NULL == globals)
return NULL; // If there have never been any exceptions, there are none now.
__cxa_exception *exception_header = globals->caughtExceptions;
if (NULL == exception_header)
return NULL; // No current exception
if (!__isOurExceptionClass(&exception_header->unwindHeader))
return NULL;
return exception_header->exceptionType;
}
// 2.5.4 Rethrowing Exceptions
/* This routine can rethrow native or foreign exceptions.
If the exception is native:
* marks the exception object on top of the caughtExceptions stack
(in an implementation-defined way) as being rethrown.
* If the caughtExceptions stack is empty, it calls terminate()
(see [C++FDIS] [except.throw], 15.1.8).
* It then calls _Unwind_RaiseException which should not return
(terminate if it does).
Note: exception_header may be masquerading as a __cxa_dependent_exception
and that's ok.
*/
void __cxa_rethrow() {
__cxa_eh_globals* globals = __cxa_get_globals();
__cxa_exception* exception_header = globals->caughtExceptions;
if (NULL == exception_header)
std::terminate(); // throw; called outside of a exception handler
bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
if (native_exception)
{
// Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
exception_header->handlerCount = -exception_header->handlerCount;
globals->uncaughtExceptions += 1;
// __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
}
else // this is a foreign exception
{
// The only way to communicate to __cxa_end_catch that we've rethrown
// a foreign exception, so don't delete us, is to pop the stack here
// which must be empty afterwards. Then __cxa_end_catch will do
// nothing
globals->caughtExceptions = 0;
}
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
#else
_Unwind_RaiseException(&exception_header->unwindHeader);
#endif
// If we get here, some kind of unwinding error has occurred.
// There is some weird code generation bug happening with
// Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
// If we call failed_throw here. Turns up with -O2 or higher, and -Os.
__cxa_begin_catch(&exception_header->unwindHeader);
if (native_exception)
std::__terminate(exception_header->terminateHandler);
// Foreign exception: can't get exception_header->terminateHandler
std::terminate();
}
/*
If thrown_object is not null, atomically increment the referenceCount field
of the __cxa_exception header associated with the thrown object referred to
by thrown_object.
Requires: If thrown_object is not NULL, it is a native exception.
*/
void
__cxa_increment_exception_refcount(void *thrown_object) throw() {
if (thrown_object != NULL )
{
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
}
}
/*
If thrown_object is not null, atomically decrement the referenceCount field
of the __cxa_exception header associated with the thrown object referred to
by thrown_object. If the referenceCount drops to zero, destroy and
deallocate the exception.
Requires: If thrown_object is not NULL, it is a native exception.
*/
_LIBCXXABI_NO_CFI
void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
if (thrown_object != NULL )
{
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
{
if (NULL != exception_header->exceptionDestructor)
exception_header->exceptionDestructor(thrown_object);
__cxa_free_exception(thrown_object);
}
}
}
/*
Returns a pointer to the thrown object (if any) at the top of the
caughtExceptions stack. Atomically increment the exception's referenceCount.
If there is no such thrown object or if the thrown object is foreign,
returns null.
We can use __cxa_get_globals_fast here to get the globals because if there have
been no exceptions thrown, ever, on this thread, we can return NULL without
the need to allocate the exception-handling globals.
*/
void *__cxa_current_primary_exception() throw() {
// get the current exception
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (NULL == globals)
return NULL; // If there are no globals, there is no exception
__cxa_exception* exception_header = globals->caughtExceptions;
if (NULL == exception_header)
return NULL; // No current exception
if (!__isOurExceptionClass(&exception_header->unwindHeader))
return NULL; // Can't capture a foreign exception (no way to refcount it)
if (isDependentException(&exception_header->unwindHeader)) {
__cxa_dependent_exception* dep_exception_header =
reinterpret_cast<__cxa_dependent_exception*>(exception_header);
exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException);
}
void* thrown_object = thrown_object_from_cxa_exception(exception_header);
__cxa_increment_exception_refcount(thrown_object);
return thrown_object;
}
/*
If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
stored in exc is called. Otherwise the referenceCount stored in the
primary exception is decremented, destroying the primary if necessary.
Finally the dependent exception is destroyed.
*/
static
void
dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
{
__cxa_dependent_exception* dep_exception_header =
reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1;
if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
std::__terminate(dep_exception_header->terminateHandler);
__cxa_decrement_exception_refcount(dep_exception_header->primaryException);
__cxa_free_dependent_exception(dep_exception_header);
}
/*
If thrown_object is not null, allocate, initialize and throw a dependent
exception.
*/
void
__cxa_rethrow_primary_exception(void* thrown_object)
{
if ( thrown_object != NULL )
{
// thrown_object guaranteed to be native because
// __cxa_current_primary_exception returns NULL for foreign exceptions
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
__cxa_dependent_exception* dep_exception_header =
static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
dep_exception_header->primaryException = thrown_object;
__cxa_increment_exception_refcount(thrown_object);
dep_exception_header->exceptionType = exception_header->exceptionType;
dep_exception_header->unexpectedHandler = std::get_unexpected();
dep_exception_header->terminateHandler = std::get_terminate();
setDependentExceptionClass(&dep_exception_header->unwindHeader);
__cxa_get_globals()->uncaughtExceptions += 1;
dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
#ifdef __USING_SJLJ_EXCEPTIONS__
_Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
#else
_Unwind_RaiseException(&dep_exception_header->unwindHeader);
#endif
// Some sort of unwinding error. Note that terminate is a handler.
__cxa_begin_catch(&dep_exception_header->unwindHeader);
}
// If we return client will call terminate()
}
bool
__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; }
unsigned int
__cxa_uncaught_exceptions() throw()
{
// This does not report foreign exceptions in flight
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (globals == 0)
return 0;
return globals->uncaughtExceptions;
}
} // extern "C"
} // abi

164
third_party/libcxxabi/cxa_exception.h vendored Normal file
View file

@ -0,0 +1,164 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the "Exception Handling APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
//
//===----------------------------------------------------------------------===//
#ifndef _CXA_EXCEPTION_H
#define _CXA_EXCEPTION_H
#include "third_party/libcxx/exception" // for std::unexpected_handler and std::terminate_handler
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libunwind/include/unwind.h"
namespace __cxxabiv1 {
static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++
_LIBCXXABI_HIDDEN uint64_t __getExceptionClass (const _Unwind_Exception*);
_LIBCXXABI_HIDDEN void __setExceptionClass ( _Unwind_Exception*, uint64_t);
_LIBCXXABI_HIDDEN bool __isOurExceptionClass(const _Unwind_Exception*);
struct _LIBCXXABI_HIDDEN __cxa_exception {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
// Now _Unwind_Exception is marked with __attribute__((aligned)),
// which implies __cxa_exception is also aligned. Insert padding
// in the beginning of the struct, rather than before unwindHeader.
void *reserve;
// This is a new field to support C++11 exception_ptr.
// For binary compatibility it is at the start of this
// struct which is prepended to the object thrown in
// __cxa_allocate_exception.
size_t referenceCount;
#endif
// Manage the exception object itself.
std::type_info *exceptionType;
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
__cxa_exception *nextException;
int handlerCount;
#if defined(_LIBCXXABI_ARM_EHABI)
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void *catchTemp;
void *adjustedPtr;
#endif
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
// This is a new field to support C++11 exception_ptr.
// For binary compatibility it is placed where the compiler
// previously added padding to 64-bit align unwindHeader.
size_t referenceCount;
#endif
_Unwind_Exception unwindHeader;
};
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
// The layout of this structure MUST match the layout of __cxa_exception, with
// primaryException instead of referenceCount.
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
void* reserve; // padding.
void* primaryException;
#endif
std::type_info *exceptionType;
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
__cxa_exception *nextException;
int handlerCount;
#if defined(_LIBCXXABI_ARM_EHABI)
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void * catchTemp;
void *adjustedPtr;
#endif
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
void* primaryException;
#endif
_Unwind_Exception unwindHeader;
};
// Verify the negative offsets of different fields.
static_assert(sizeof(_Unwind_Exception) +
offsetof(__cxa_exception, unwindHeader) ==
sizeof(__cxa_exception),
"unwindHeader has wrong negative offsets");
static_assert(sizeof(_Unwind_Exception) +
offsetof(__cxa_dependent_exception, unwindHeader) ==
sizeof(__cxa_dependent_exception),
"unwindHeader has wrong negative offsets");
#if defined(_LIBCXXABI_ARM_EHABI)
static_assert(offsetof(__cxa_exception, propagationCount) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_exception),
"propagationCount has wrong negative offset");
static_assert(offsetof(__cxa_dependent_exception, propagationCount) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_dependent_exception),
"propagationCount has wrong negative offset");
#elif defined(__LP64__) || defined(_WIN64)
static_assert(offsetof(__cxa_exception, adjustedPtr) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_exception),
"adjustedPtr has wrong negative offset");
static_assert(offsetof(__cxa_dependent_exception, adjustedPtr) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_dependent_exception),
"adjustedPtr has wrong negative offset");
#else
static_assert(offsetof(__cxa_exception, referenceCount) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_exception),
"referenceCount has wrong negative offset");
static_assert(offsetof(__cxa_dependent_exception, primaryException) +
sizeof(_Unwind_Exception) + sizeof(void*) ==
sizeof(__cxa_dependent_exception),
"primaryException has wrong negative offset");
#endif
struct _LIBCXXABI_HIDDEN __cxa_eh_globals {
__cxa_exception * caughtExceptions;
unsigned int uncaughtExceptions;
#if defined(_LIBCXXABI_ARM_EHABI)
__cxa_exception* propagatingExceptions;
#endif
};
extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals ();
extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast ();
extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception ();
extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception);
} // namespace __cxxabiv1
#endif // _CXA_EXCEPTION_H

View file

@ -0,0 +1,103 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the storage for the "Caught Exception Stack"
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxxabi/cxa_exception.h"
#include "third_party/libcxx/__threading_support"
#if defined(_LIBCXXABI_HAS_NO_THREADS)
namespace __cxxabiv1 {
extern "C" {
static __cxa_eh_globals eh_globals;
__cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
__cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
} // extern "C"
} // namespace __cxxabiv1
#elif defined(HAS_THREAD_LOCAL)
namespace __cxxabiv1 {
namespace {
__cxa_eh_globals *__globals() {
static thread_local __cxa_eh_globals eh_globals;
return &eh_globals;
}
} // namespace
extern "C" {
__cxa_eh_globals *__cxa_get_globals() { return __globals(); }
__cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); }
} // extern "C"
} // namespace __cxxabiv1
#else
#include "third_party/libcxxabi/abort_message.h"
#include "third_party/libcxxabi/fallback_malloc.h"
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
// In general, we treat all threading errors as fatal.
// We cannot call std::terminate() because that will in turn
// call __cxa_get_globals() and cause infinite recursion.
namespace __cxxabiv1 {
namespace {
std::__libcpp_tls_key key_;
std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) {
__free_with_fallback(p);
if (0 != std::__libcpp_tls_set(key_, NULL))
abort_message("cannot zero out thread value for __cxa_get_globals()");
}
void construct_() {
if (0 != std::__libcpp_tls_create(&key_, destruct_))
abort_message("cannot create thread specific key for __cxa_get_globals()");
}
} // namespace
extern "C" {
__cxa_eh_globals *__cxa_get_globals() {
// Try to get the globals for this thread
__cxa_eh_globals *retVal = __cxa_get_globals_fast();
// If this is the first time we've been asked for these globals, create them
if (NULL == retVal) {
retVal = static_cast<__cxa_eh_globals*>(
__calloc_with_fallback(1, sizeof(__cxa_eh_globals)));
if (NULL == retVal)
abort_message("cannot allocate __cxa_eh_globals");
if (0 != std::__libcpp_tls_set(key_, retVal))
abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()");
}
return retVal;
}
// Note that this implementation will reliably return NULL if not
// preceded by a call to __cxa_get_globals(). This is an extension
// to the Itanium ABI and is taken advantage of in several places in
// libc++abi.
__cxa_eh_globals *__cxa_get_globals_fast() {
// First time through, create the key.
if (0 != std::__libcpp_execute_once(&flag_, construct_))
abort_message("execute once failure in __cxa_get_globals_fast()");
return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
}
} // extern "C"
} // namespace __cxxabiv1
#endif

53
third_party/libcxxabi/cxa_guard.cc vendored Normal file
View file

@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxxabi/include/cxxabi.h"
// Tell the implementation that we're building the actual implementation
// (and not testing it)
#define BUILDING_CXA_GUARD
#include "third_party/libcxxabi/cxa_guard_impl.h"
/*
This implementation must be careful to not call code external to this file
which will turn around and try to call __cxa_guard_acquire reentrantly.
For this reason, the headers of this file are as restricted as possible.
Previous implementations of this code for __APPLE__ have used
std::__libcpp_mutex_lock and the abort_message utility without problem. This
implementation also uses std::__libcpp_condvar_wait which has tested
to not be a problem.
*/
namespace __cxxabiv1 {
#if defined(_LIBCXXABI_GUARD_ABI_ARM)
using guard_type = uint32_t;
#else
using guard_type = uint64_t;
#endif
extern "C"
{
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type* raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
return static_cast<int>(imp.cxa_guard_acquire());
}
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
imp.cxa_guard_release();
}
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
SelectedImplementation imp(raw_guard_object);
imp.cxa_guard_abort();
}
} // extern "C"
} // __cxxabiv1

674
third_party/libcxxabi/cxa_guard_impl.h vendored Normal file
View file

@ -0,0 +1,674 @@
//===----------------------------------------------------------------------===//
//
// 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 LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
#define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
/* cxa_guard_impl.h - Implements the C++ runtime support for function local
* static guards.
* The layout of the guard object is the same across ARM and Itanium.
*
* The first "guard byte" (which is checked by the compiler) is set only upon
* the completion of cxa release.
*
* The second "init byte" does the rest of the bookkeeping. It tracks if
* initialization is complete or pending, and if there are waiting threads.
*
* If the guard variable is 64-bits and the platforms supplies a 32-bit thread
* identifier, it is used to detect recursive initialization. The thread ID of
* the thread currently performing initialization is stored in the second word.
*
* Guard Object Layout:
* ---------------------------------------------------------------------------
* | a+0: guard byte | a+1: init byte | a+2: unused ... | a+4: thread-id ... |
* ---------------------------------------------------------------------------
*
* Note that we don't do what the ABI docs suggest (put a mutex in the guard
* object which we acquire in cxa_guard_acquire and release in
* cxa_guard_release). Instead we use the init byte to imitate that behaviour,
* but without actually holding anything mutex related between aquire and
* release/abort.
*
* Access Protocol:
* For each implementation the guard byte is checked and set before accessing
* the init byte.
*
* Overall Design:
* The implementation was designed to allow each implementation to be tested
* independent of the C++ runtime or platform support.
*
*/
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
#if defined(__has_include)
# if __has_include(<sys/syscall.h>)
# include <sys/syscall.h>
# endif
# if __has_include(<unistd.h>)
# include <unistd.h>
# endif
#endif
#include "third_party/libcxx/__threading_support"
#include "third_party/libcxx/cstdint"
#include "third_party/libcxx/cstring"
#include "libc/isystem/limits.h"
#include "libc/isystem/stdlib.h"
#ifndef _LIBCXXABI_HAS_NO_THREADS
# if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
# pragma comment(lib, "pthread")
# endif
#endif
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Waddress"
#endif
// To make testing possible, this header is included from both cxa_guard.cpp
// and a number of tests.
//
// For this reason we place everything in an anonymous namespace -- even though
// we're in a header. We want the actual implementation and the tests to have
// unique definitions of the types in this header (since the tests may depend
// on function local statics).
//
// To enforce this either `BUILDING_CXA_GUARD` or `TESTING_CXA_GUARD` must be
// defined when including this file. Only `src/cxa_guard.cpp` should define
// the former.
#ifdef BUILDING_CXA_GUARD
# include "third_party/libcxxabi/abort_message.h"
# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
#elif defined(TESTING_CXA_GUARD)
# define ABORT_WITH_MESSAGE(...) ::abort()
#else
# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
#endif
#if __has_feature(thread_sanitizer)
extern "C" void __tsan_acquire(void*);
extern "C" void __tsan_release(void*);
#else
# define __tsan_acquire(addr) ((void)0)
# define __tsan_release(addr) ((void)0)
#endif
namespace __cxxabiv1 {
// Use an anonymous namespace to ensure that the tests and actual implementation
// have unique definitions of these symbols.
namespace {
//===----------------------------------------------------------------------===//
// Misc Utilities
//===----------------------------------------------------------------------===//
template <class T, T (*Init)()>
struct LazyValue {
LazyValue() : is_init(false) {}
T& get() {
if (!is_init) {
value = Init();
is_init = true;
}
return value;
}
private:
T value;
bool is_init = false;
};
template <class IntType>
class AtomicInt {
public:
using MemoryOrder = std::__libcpp_atomic_order;
explicit AtomicInt(IntType* b) : b_(b) {}
AtomicInt(AtomicInt const&) = delete;
AtomicInt& operator=(AtomicInt const&) = delete;
IntType load(MemoryOrder ord) { return std::__libcpp_atomic_load(b_, ord); }
void store(IntType val, MemoryOrder ord) { std::__libcpp_atomic_store(b_, val, ord); }
IntType exchange(IntType new_val, MemoryOrder ord) { return std::__libcpp_atomic_exchange(b_, new_val, ord); }
bool compare_exchange(IntType* expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
return std::__libcpp_atomic_compare_exchange(b_, expected, desired, ord_success, ord_failure);
}
private:
IntType* b_;
};
//===----------------------------------------------------------------------===//
// PlatformGetThreadID
//===----------------------------------------------------------------------===//
#if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
uint32_t PlatformThreadID() {
static_assert(sizeof(mach_port_t) == sizeof(uint32_t), "");
return static_cast<uint32_t>(pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
}
#elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
uint32_t PlatformThreadID() {
static_assert(sizeof(pid_t) == sizeof(uint32_t), "");
return static_cast<uint32_t>(syscall(SYS_gettid));
}
#else
constexpr uint32_t (*PlatformThreadID)() = nullptr;
#endif
//===----------------------------------------------------------------------===//
// GuardByte
//===----------------------------------------------------------------------===//
static constexpr uint8_t UNSET = 0;
static constexpr uint8_t COMPLETE_BIT = (1 << 0);
static constexpr uint8_t PENDING_BIT = (1 << 1);
static constexpr uint8_t WAITING_BIT = (1 << 2);
/// Manages reads and writes to the guard byte.
struct GuardByte {
GuardByte() = delete;
GuardByte(GuardByte const&) = delete;
GuardByte& operator=(GuardByte const&) = delete;
explicit GuardByte(uint8_t* const guard_byte_address) : guard_byte(guard_byte_address) {}
public:
/// The guard byte portion of cxa_guard_acquire. Returns true if
/// initialization has already been completed.
bool acquire() {
// if guard_byte is non-zero, we have already completed initialization
// (i.e. release has been called)
return guard_byte.load(std::_AO_Acquire) != UNSET;
}
/// The guard byte portion of cxa_guard_release.
void release() { guard_byte.store(COMPLETE_BIT, std::_AO_Release); }
/// The guard byte portion of cxa_guard_abort.
void abort() {} // Nothing to do
private:
AtomicInt<uint8_t> guard_byte;
};
//===----------------------------------------------------------------------===//
// InitByte Implementations
//===----------------------------------------------------------------------===//
//
// Each initialization byte implementation supports the following methods:
//
// InitByte(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
// Construct the InitByte object, initializing our member variables
//
// bool acquire()
// Called before we start the initialization. Check if someone else has already started, and if
// not to signal our intent to start it ourselves. We determine the current status from the init
// byte, which is one of 4 possible values:
// COMPLETE: Initialization was finished by somebody else. Return true.
// PENDING: Somebody has started the initialization already, set the WAITING bit,
// then wait for the init byte to get updated with a new value.
// (PENDING|WAITING): Somebody has started the initialization already, and we're not the
// first one waiting. Wait for the init byte to get updated.
// UNSET: Initialization hasn't successfully completed, and nobody is currently
// performing the initialization. Set the PENDING bit to indicate our
// intention to start the initialization, and return false.
// The return value indicates whether initialization has already been completed.
//
// void release()
// Called after successfully completing the initialization. Update the init byte to reflect
// that, then if anybody else is waiting, wake them up.
//
// void abort()
// Called after an error is thrown during the initialization. Reset the init byte to UNSET to
// indicate that we're no longer performing the initialization, then if anybody is waiting, wake
// them up so they can try performing the initialization.
//
//===----------------------------------------------------------------------===//
// Single Threaded Implementation
//===----------------------------------------------------------------------===//
/// InitByteNoThreads - Doesn't use any inter-thread synchronization when
/// managing reads and writes to the init byte.
struct InitByteNoThreads {
InitByteNoThreads() = delete;
InitByteNoThreads(InitByteNoThreads const&) = delete;
InitByteNoThreads& operator=(InitByteNoThreads const&) = delete;
explicit InitByteNoThreads(uint8_t* _init_byte_address, uint32_t*) : init_byte_address(_init_byte_address) {}
/// The init byte portion of cxa_guard_acquire. Returns true if
/// initialization has already been completed.
bool acquire() {
if (*init_byte_address == COMPLETE_BIT)
return true;
if (*init_byte_address & PENDING_BIT)
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?");
*init_byte_address = PENDING_BIT;
return false;
}
/// The init byte portion of cxa_guard_release.
void release() { *init_byte_address = COMPLETE_BIT; }
/// The init byte portion of cxa_guard_abort.
void abort() { *init_byte_address = UNSET; }
private:
/// The address of the byte used during initialization.
uint8_t* const init_byte_address;
};
//===----------------------------------------------------------------------===//
// Global Mutex Implementation
//===----------------------------------------------------------------------===//
struct LibcppMutex;
struct LibcppCondVar;
#ifndef _LIBCXXABI_HAS_NO_THREADS
struct LibcppMutex {
LibcppMutex() = default;
LibcppMutex(LibcppMutex const&) = delete;
LibcppMutex& operator=(LibcppMutex const&) = delete;
bool lock() { return std::__libcpp_mutex_lock(&mutex); }
bool unlock() { return std::__libcpp_mutex_unlock(&mutex); }
private:
friend struct LibcppCondVar;
std::__libcpp_mutex_t mutex = _LIBCPP_MUTEX_INITIALIZER;
};
struct LibcppCondVar {
LibcppCondVar() = default;
LibcppCondVar(LibcppCondVar const&) = delete;
LibcppCondVar& operator=(LibcppCondVar const&) = delete;
bool wait(LibcppMutex& mut) { return std::__libcpp_condvar_wait(&cond, &mut.mutex); }
bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); }
private:
std::__libcpp_condvar_t cond = _LIBCPP_CONDVAR_INITIALIZER;
};
#else
struct LibcppMutex {};
struct LibcppCondVar {};
#endif // !defined(_LIBCXXABI_HAS_NO_THREADS)
/// InitByteGlobalMutex - Uses a global mutex and condition variable (common to
/// all static local variables) to manage reads and writes to the init byte.
template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
uint32_t (*GetThreadID)() = PlatformThreadID>
struct InitByteGlobalMutex {
explicit InitByteGlobalMutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
: init_byte_address(_init_byte_address), thread_id_address(_thread_id_address),
has_thread_id_support(_thread_id_address != nullptr && GetThreadID != nullptr) {}
public:
/// The init byte portion of cxa_guard_acquire. Returns true if
/// initialization has already been completed.
bool acquire() {
LockGuard g("__cxa_guard_acquire");
// Check for possible recursive initialization.
if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) {
if (*thread_id_address == current_thread_id.get())
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?");
}
// Wait until the pending bit is not set.
while (*init_byte_address & PENDING_BIT) {
*init_byte_address |= WAITING_BIT;
global_cond.wait(global_mutex);
}
if (*init_byte_address == COMPLETE_BIT)
return true;
if (has_thread_id_support)
*thread_id_address = current_thread_id.get();
*init_byte_address = PENDING_BIT;
return false;
}
/// The init byte portion of cxa_guard_release.
void release() {
bool has_waiting;
{
LockGuard g("__cxa_guard_release");
has_waiting = *init_byte_address & WAITING_BIT;
*init_byte_address = COMPLETE_BIT;
}
if (has_waiting) {
if (global_cond.broadcast()) {
ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_release");
}
}
}
/// The init byte portion of cxa_guard_abort.
void abort() {
bool has_waiting;
{
LockGuard g("__cxa_guard_abort");
if (has_thread_id_support)
*thread_id_address = 0;
has_waiting = *init_byte_address & WAITING_BIT;
*init_byte_address = UNSET;
}
if (has_waiting) {
if (global_cond.broadcast()) {
ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_abort");
}
}
}
private:
/// The address of the byte used during initialization.
uint8_t* const init_byte_address;
/// An optional address storing an identifier for the thread performing initialization.
/// It's used to detect recursive initialization.
uint32_t* const thread_id_address;
const bool has_thread_id_support;
LazyValue<uint32_t, GetThreadID> current_thread_id;
private:
struct LockGuard {
LockGuard() = delete;
LockGuard(LockGuard const&) = delete;
LockGuard& operator=(LockGuard const&) = delete;
explicit LockGuard(const char* calling_func) : calling_func_(calling_func) {
if (global_mutex.lock())
ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func_);
}
~LockGuard() {
if (global_mutex.unlock())
ABORT_WITH_MESSAGE("%s failed to release mutex", calling_func_);
}
private:
const char* const calling_func_;
};
};
//===----------------------------------------------------------------------===//
// Futex Implementation
//===----------------------------------------------------------------------===//
#if defined(SYS_futex)
void PlatformFutexWait(int* addr, int expect) {
constexpr int WAIT = 0;
syscall(SYS_futex, addr, WAIT, expect, 0);
__tsan_acquire(addr);
}
void PlatformFutexWake(int* addr) {
constexpr int WAKE = 1;
__tsan_release(addr);
syscall(SYS_futex, addr, WAKE, INT_MAX);
}
#else
constexpr void (*PlatformFutexWait)(int*, int) = nullptr;
constexpr void (*PlatformFutexWake)(int*) = nullptr;
#endif
constexpr bool PlatformSupportsFutex() { return +PlatformFutexWait != nullptr; }
/// InitByteFutex - Uses a futex to manage reads and writes to the init byte.
template <void (*Wait)(int*, int) = PlatformFutexWait, void (*Wake)(int*) = PlatformFutexWake,
uint32_t (*GetThreadIDArg)() = PlatformThreadID>
struct InitByteFutex {
explicit InitByteFutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
: init_byte(_init_byte_address),
has_thread_id_support(_thread_id_address != nullptr && GetThreadIDArg != nullptr),
thread_id(_thread_id_address),
base_address(reinterpret_cast<int*>(/*_init_byte_address & ~0x3*/ _init_byte_address - 1)) {}
public:
/// The init byte portion of cxa_guard_acquire. Returns true if
/// initialization has already been completed.
bool acquire() {
while (true) {
uint8_t last_val = UNSET;
if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel, std::_AO_Acquire)) {
if (has_thread_id_support) {
thread_id.store(current_thread_id.get(), std::_AO_Relaxed);
}
return false;
}
if (last_val == COMPLETE_BIT)
return true;
if (last_val & PENDING_BIT) {
// Check for recursive initialization
if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) {
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization: do you have a function-local static variable whose initialization depends on that function?");
}
if ((last_val & WAITING_BIT) == 0) {
// This compare exchange can fail for several reasons
// (1) another thread finished the whole thing before we got here
// (2) another thread set the waiting bit we were trying to thread
// (3) another thread had an exception and failed to finish
if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT, std::_AO_Acq_Rel, std::_AO_Release)) {
// (1) success, via someone else's work!
if (last_val == COMPLETE_BIT)
return true;
// (3) someone else, bailed on doing the work, retry from the start!
if (last_val == UNSET)
continue;
// (2) the waiting bit got set, so we are happy to keep waiting
}
}
wait_on_initialization();
}
}
}
/// The init byte portion of cxa_guard_release.
void release() {
uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel);
if (old & WAITING_BIT)
wake_all();
}
/// The init byte portion of cxa_guard_abort.
void abort() {
if (has_thread_id_support)
thread_id.store(0, std::_AO_Relaxed);
uint8_t old = init_byte.exchange(UNSET, std::_AO_Acq_Rel);
if (old & WAITING_BIT)
wake_all();
}
private:
/// Use the futex to wait on the current guard variable. Futex expects a
/// 32-bit 4-byte aligned address as the first argument, so we use the 4-byte
/// aligned address that encompasses the init byte (i.e. the address of the
/// raw guard object that was passed to __cxa_guard_acquire/release/abort).
void wait_on_initialization() { Wait(base_address, expected_value_for_futex(PENDING_BIT | WAITING_BIT)); }
void wake_all() { Wake(base_address); }
private:
AtomicInt<uint8_t> init_byte;
const bool has_thread_id_support;
// Unsafe to use unless has_thread_id_support
AtomicInt<uint32_t> thread_id;
LazyValue<uint32_t, GetThreadIDArg> current_thread_id;
/// the 4-byte-aligned address that encompasses the init byte (i.e. the
/// address of the raw guard object).
int* const base_address;
/// Create the expected integer value for futex `wait(int* addr, int expected)`.
/// We pass the base address as the first argument, So this function creates
/// an zero-initialized integer with `b` copied at the correct offset.
static int expected_value_for_futex(uint8_t b) {
int dest_val = 0;
std::memcpy(reinterpret_cast<char*>(&dest_val) + 1, &b, 1);
return dest_val;
}
static_assert(Wait != nullptr && Wake != nullptr, "");
};
//===----------------------------------------------------------------------===//
// GuardObject
//===----------------------------------------------------------------------===//
enum class AcquireResult {
INIT_IS_DONE,
INIT_IS_PENDING,
};
constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
/// Co-ordinates between GuardByte and InitByte.
template <class InitByteT>
struct GuardObject {
GuardObject() = delete;
GuardObject(GuardObject const&) = delete;
GuardObject& operator=(GuardObject const&) = delete;
private:
GuardByte guard_byte;
InitByteT init_byte;
public:
/// ARM Constructor
explicit GuardObject(uint32_t* raw_guard_object)
: guard_byte(reinterpret_cast<uint8_t*>(raw_guard_object)),
init_byte(reinterpret_cast<uint8_t*>(raw_guard_object) + 1, nullptr) {}
/// Itanium Constructor
explicit GuardObject(uint64_t* raw_guard_object)
: guard_byte(reinterpret_cast<uint8_t*>(raw_guard_object)),
init_byte(reinterpret_cast<uint8_t*>(raw_guard_object) + 1, reinterpret_cast<uint32_t*>(raw_guard_object) + 1) {
}
/// Implements __cxa_guard_acquire.
AcquireResult cxa_guard_acquire() {
// Use short-circuit evaluation to avoid calling init_byte.acquire when
// guard_byte.acquire returns true. (i.e. don't call it when we know from
// the guard byte that initialization has already been completed)
if (guard_byte.acquire() || init_byte.acquire())
return INIT_IS_DONE;
return INIT_IS_PENDING;
}
/// Implements __cxa_guard_release.
void cxa_guard_release() {
// Update guard byte first, so if somebody is woken up by init_byte.release
// and comes all the way back around to __cxa_guard_acquire again, they see
// it as having completed initialization.
guard_byte.release();
init_byte.release();
}
/// Implements __cxa_guard_abort.
void cxa_guard_abort() {
guard_byte.abort();
init_byte.abort();
}
};
//===----------------------------------------------------------------------===//
// Convenience Classes
//===----------------------------------------------------------------------===//
/// NoThreadsGuard - Manages initialization without performing any inter-thread
/// synchronization.
using NoThreadsGuard = GuardObject<InitByteNoThreads>;
/// GlobalMutexGuard - Manages initialization using a global mutex and
/// condition variable.
template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
uint32_t (*GetThreadID)() = PlatformThreadID>
using GlobalMutexGuard = GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond, GetThreadID>>;
/// FutexGuard - Manages initialization using atomics and the futex syscall for
/// waiting and waking.
template <void (*Wait)(int*, int) = PlatformFutexWait, void (*Wake)(int*) = PlatformFutexWake,
uint32_t (*GetThreadIDArg)() = PlatformThreadID>
using FutexGuard = GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>>;
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
template <class T>
struct GlobalStatic {
static T instance;
};
template <class T>
_LIBCPP_CONSTINIT T GlobalStatic<T>::instance = {};
enum class Implementation { NoThreads, GlobalMutex, Futex };
template <Implementation Impl>
struct SelectImplementation;
template <>
struct SelectImplementation<Implementation::NoThreads> {
using type = NoThreadsGuard;
};
template <>
struct SelectImplementation<Implementation::GlobalMutex> {
using type = GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
};
template <>
struct SelectImplementation<Implementation::Futex> {
using type = FutexGuard<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
};
// TODO(EricWF): We should prefer the futex implementation when available. But
// it should be done in a separate step from adding the implementation.
constexpr Implementation CurrentImplementation =
#if defined(_LIBCXXABI_HAS_NO_THREADS)
Implementation::NoThreads;
#elif defined(_LIBCXXABI_USE_FUTEX)
Implementation::Futex;
#else
Implementation::GlobalMutex;
#endif
static_assert(CurrentImplementation != Implementation::Futex || PlatformSupportsFutex(),
"Futex selected but not supported");
using SelectedImplementation = SelectImplementation<CurrentImplementation>::type;
} // end namespace
} // end namespace __cxxabiv1
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
#endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H

101
third_party/libcxxabi/cxa_handlers.cc vendored Normal file
View file

@ -0,0 +1,101 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the functionality associated with the terminate_handler,
// unexpected_handler, and new_handler.
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/stdexcept"
#include "third_party/libcxx/new"
#include "third_party/libcxx/exception"
#include "third_party/libcxxabi/abort_message.h"
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxxabi/cxa_handlers.h"
#include "third_party/libcxxabi/cxa_exception.h"
#include "third_party/libcxxabi/private_typeinfo.h"
#include "third_party/libcxx/include/atomic_support.hh" // from libc++
namespace std
{
unexpected_handler
get_unexpected() noexcept
{
return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire);
}
void
__unexpected(unexpected_handler func)
{
func();
// unexpected handler should not return
abort_message("unexpected_handler unexpectedly returned");
}
__attribute__((noreturn))
void
unexpected()
{
__unexpected(get_unexpected());
}
terminate_handler
get_terminate() noexcept
{
return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire);
}
void
__terminate(terminate_handler func) noexcept
{
#ifndef _LIBCXXABI_NO_EXCEPTIONS
try
{
#endif // _LIBCXXABI_NO_EXCEPTIONS
func();
// handler should not return
abort_message("terminate_handler unexpectedly returned");
#ifndef _LIBCXXABI_NO_EXCEPTIONS
}
catch (...)
{
// handler should not throw exception
abort_message("terminate_handler unexpectedly threw an exception");
}
#endif // _LIBCXXABI_NO_EXCEPTIONS
}
__attribute__((noreturn))
void
terminate() noexcept
{
#ifndef _LIBCXXABI_NO_EXCEPTIONS
// If there might be an uncaught exception
using namespace __cxxabiv1;
__cxa_eh_globals* globals = __cxa_get_globals_fast();
if (globals)
{
__cxa_exception* exception_header = globals->caughtExceptions;
if (exception_header)
{
_Unwind_Exception* unwind_exception =
reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
if (__isOurExceptionClass(unwind_exception))
__terminate(exception_header->terminateHandler);
}
}
#endif
__terminate(get_terminate());
}
new_handler
get_new_handler() noexcept
{
return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire);
}
} // std

55
third_party/libcxxabi/cxa_handlers.h vendored Normal file
View file

@ -0,0 +1,55 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the functionality associated with the terminate_handler,
// unexpected_handler, and new_handler.
//===----------------------------------------------------------------------===//
#ifndef _CXA_HANDLERS_H
#define _CXA_HANDLERS_H
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxx/exception"
namespace std
{
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
void
__unexpected(unexpected_handler func);
_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
void
__terminate(terminate_handler func) noexcept;
} // std
extern "C"
{
_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)();
_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)();
_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)();
/*
At some point in the future these three symbols will become
C++11 atomic variables:
extern std::atomic<std::terminate_handler> __cxa_terminate_handler;
extern std::atomic<std::unexpected_handler> __cxa_unexpected_handler;
extern std::atomic<std::new_handler> __cxa_new_handler;
This change will not impact their ABI. But it will allow for a
portable performance optimization.
*/
} // extern "C"
#endif // _CXA_HANDLERS_H

1315
third_party/libcxxabi/cxa_personality.cc vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,145 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxxabi/abort_message.h"
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/__threading_support"
#ifndef _LIBCXXABI_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
#include "libc/isystem/stdlib.h"
namespace __cxxabiv1 {
using Dtor = void(*)(void*);
extern "C"
#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
// A weak symbol is used to detect this function's presence in the C library
// at runtime, even if libc++ is built against an older libc
_LIBCXXABI_WEAK
#endif
int __cxa_thread_atexit_impl(Dtor, void*, void*);
#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
namespace {
// This implementation is used if the C library does not provide
// __cxa_thread_atexit_impl() for us. It has a number of limitations that are
// difficult to impossible to address without ..._impl():
//
// - dso_symbol is ignored. This means that a shared library may be unloaded
// (via dlclose()) before its thread_local destructors have run.
//
// - thread_local destructors for the main thread are run by the destructor of
// a static object. This is later than expected; they should run before the
// destructors of any objects with static storage duration.
//
// - thread_local destructors on non-main threads run on the first iteration
// through the __libccpp_tls_key destructors.
// std::notify_all_at_thread_exit() and similar functions must be careful to
// wait until the second iteration to provide their intended ordering
// guarantees.
//
// Another limitation, though one shared with ..._impl(), is that any
// thread_locals that are first initialized after non-thread_local global
// destructors begin to run will not be destroyed. [basic.start.term] states
// that all thread_local destructors are sequenced before the destruction of
// objects with static storage duration, resulting in a contradiction if a
// thread_local is constructed after that point. Thus we consider such
// programs ill-formed, and don't bother to run those destructors. (If the
// program terminates abnormally after such a thread_local is constructed,
// the destructor is not expected to run and thus there is no contradiction.
// So construction still has to work.)
struct DtorList {
Dtor dtor;
void* obj;
DtorList* next;
};
// The linked list of thread-local destructors to run
__thread DtorList* dtors = nullptr;
// True if the destructors are currently scheduled to run on this thread
__thread bool dtors_alive = false;
// Used to trigger destructors on thread exit; value is ignored
std::__libcpp_tls_key dtors_key;
void run_dtors(void*) {
while (auto head = dtors) {
dtors = head->next;
head->dtor(head->obj);
::free(head);
}
dtors_alive = false;
}
struct DtorsManager {
DtorsManager() {
// There is intentionally no matching std::__libcpp_tls_delete call, as
// __cxa_thread_atexit() may be called arbitrarily late (for example, from
// global destructors or atexit() handlers).
if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) {
abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()");
}
}
~DtorsManager() {
// std::__libcpp_tls_key destructors do not run on threads that call exit()
// (including when the main thread returns from main()), so we explicitly
// call the destructor here. This runs at exit time (potentially earlier
// if libc++abi is dlclose()'d). Any thread_locals initialized after this
// point will not be destroyed.
run_dtors(nullptr);
}
};
} // namespace
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
extern "C" {
_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
#else
if (__cxa_thread_atexit_impl) {
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
} else {
// Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
// one-time initialization and __cxa_atexit() for destruction)
static DtorsManager manager;
if (!dtors_alive) {
if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) {
return -1;
}
dtors_alive = true;
}
auto head = static_cast<DtorList*>(::malloc(sizeof(DtorList)));
if (!head) {
return -1;
}
head->dtor = dtor;
head->obj = obj;
head->next = dtors;
dtors = head;
return 0;
}
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
}
} // extern "C"
} // namespace __cxxabiv1

421
third_party/libcxxabi/cxa_vector.cc vendored Normal file
View file

@ -0,0 +1,421 @@
//===----------------------------------------------------------------------===//
//
// 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 implements the "Array Construction and Destruction APIs"
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxx/exception" // for std::terminate
#include "third_party/libcxx/new" // for std::bad_array_new_length
#include "third_party/libcxxabi/abort_message.h"
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
namespace __cxxabiv1 {
//
// Helper routines and classes
//
namespace {
inline static size_t __get_element_count ( void *p ) {
return static_cast <size_t *> (p)[-1];
}
inline static void __set_element_count ( void *p, size_t element_count ) {
static_cast <size_t *> (p)[-1] = element_count;
}
// A pair of classes to simplify exception handling and control flow.
// They get passed a block of memory in the constructor, and unless the
// 'release' method is called, they deallocate the memory in the destructor.
// Preferred usage is to allocate some memory, attach it to one of these objects,
// and then, when all the operations to set up the memory block have succeeded,
// call 'release'. If any of the setup operations fail, or an exception is
// thrown, then the block is automatically deallocated.
//
// The only difference between these two classes is the signature for the
// deallocation function (to match new2/new3 and delete2/delete3.
class st_heap_block2 {
public:
typedef void (*dealloc_f)(void *);
st_heap_block2 ( dealloc_f dealloc, void *ptr )
: dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
void release () { enabled_ = false; }
private:
dealloc_f dealloc_;
void *ptr_;
bool enabled_;
};
class st_heap_block3 {
public:
typedef void (*dealloc_f)(void *, size_t);
st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size )
: dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
void release () { enabled_ = false; }
private:
dealloc_f dealloc_;
void *ptr_;
size_t size_;
bool enabled_;
};
class st_cxa_cleanup {
public:
typedef void (*destruct_f)(void *);
st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
: ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ),
destructor_ ( destructor ), enabled_ ( true ) {}
~st_cxa_cleanup () {
if ( enabled_ )
__cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
}
void release () { enabled_ = false; }
private:
void *ptr_;
size_t &idx_;
size_t element_size_;
destruct_f destructor_;
bool enabled_;
};
class st_terminate {
public:
st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
~st_terminate () { if ( enabled_ ) std::terminate (); }
void release () { enabled_ = false; }
private:
bool enabled_ ;
};
}
//
// Externally visible routines
//
namespace {
_LIBCXXABI_NORETURN
void throw_bad_array_new_length() {
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_array_new_length();
#else
abort_message("__cxa_vec_new failed to allocate memory");
#endif
}
bool mul_overflow(size_t x, size_t y, size_t *res) {
#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \
|| defined(_LIBCXXABI_COMPILER_GCC)
return __builtin_mul_overflow(x, y, res);
#else
*res = x * y;
return x && ((*res / x) != y);
#endif
}
bool add_overflow(size_t x, size_t y, size_t *res) {
#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \
|| defined(_LIBCXXABI_COMPILER_GCC)
return __builtin_add_overflow(x, y, res);
#else
*res = x + y;
return *res < y;
#endif
}
size_t calculate_allocation_size_or_throw(size_t element_count,
size_t element_size,
size_t padding_size) {
size_t element_heap_size;
if (mul_overflow(element_count, element_size, &element_heap_size))
throw_bad_array_new_length();
size_t allocation_size;
if (add_overflow(element_heap_size, padding_size, &allocation_size))
throw_bad_array_new_length();
return allocation_size;
}
} // namespace
extern "C" {
// Equivalent to
//
// __cxa_vec_new2(element_count, element_size, padding_size, constructor,
// destructor, &::operator new[], &::operator delete[])
_LIBCXXABI_FUNC_VIS void *
__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *)) {
return __cxa_vec_new2 ( element_count, element_size, padding_size,
constructor, destructor, &::operator new [], &::operator delete [] );
}
// Given the number and size of elements for an array and the non-negative
// size of prefix padding for a cookie, allocate space (using alloc) for
// the array preceded by the specified padding, initialize the cookie if
// the padding is non-zero, and call the given constructor on each element.
// Return the address of the array proper, after the padding.
//
// If alloc throws an exception, rethrow the exception. If alloc returns
// NULL, return NULL. If the constructor throws an exception, call
// destructor for any already constructed elements, and rethrow the
// exception. If the destructor throws an exception, call std::terminate.
//
// The constructor may be NULL, in which case it must not be called. If the
// padding_size is zero, the destructor may be NULL; in that case it must
// not be called.
//
// Neither alloc nor dealloc may be NULL.
_LIBCXXABI_FUNC_VIS void *
__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *)) {
const size_t heap_size = calculate_allocation_size_or_throw(
element_count, element_size, padding_size);
char* const heap_block = static_cast<char*>(alloc(heap_size));
char* vec_base = heap_block;
if (NULL != vec_base) {
st_heap_block2 heap(dealloc, heap_block);
// put the padding before the array elements
if ( 0 != padding_size ) {
vec_base += padding_size;
__set_element_count ( vec_base, element_count );
}
// Construct the elements
__cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
heap.release (); // We're good!
}
return vec_base;
}
// Same as __cxa_vec_new2 except that the deallocation function takes both
// the object address and its size.
_LIBCXXABI_FUNC_VIS void *
__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) {
const size_t heap_size = calculate_allocation_size_or_throw(
element_count, element_size, padding_size);
char* const heap_block = static_cast<char*>(alloc(heap_size));
char* vec_base = heap_block;
if (NULL != vec_base) {
st_heap_block3 heap(dealloc, heap_block, heap_size);
// put the padding before the array elements
if ( 0 != padding_size ) {
vec_base += padding_size;
__set_element_count ( vec_base, element_count );
}
// Construct the elements
__cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
heap.release (); // We're good!
}
return vec_base;
}
// Given the (data) addresses of a destination and a source array, an
// element count and an element size, call the given copy constructor to
// copy each element from the source array to the destination array. The
// copy constructor's arguments are the destination address and source
// address, respectively. If an exception occurs, call the given destructor
// (if non-NULL) on each copied element and rethrow. If the destructor
// throws an exception, call terminate(). The constructor and or destructor
// pointers may be NULL. If either is NULL, no action is taken when it
// would have been called.
_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array,
size_t element_count,
size_t element_size,
void (*constructor)(void *, void *),
void (*destructor)(void *)) {
if ( NULL != constructor ) {
size_t idx = 0;
char *src_ptr = static_cast<char *>(src_array);
char *dest_ptr = static_cast<char *>(dest_array);
st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
for ( idx = 0; idx < element_count;
++idx, src_ptr += element_size, dest_ptr += element_size )
constructor ( dest_ptr, src_ptr );
cleanup.release (); // We're good!
}
}
// Given the (data) address of an array, not including any cookie padding,
// and the number and size of its elements, call the given constructor on
// each element. If the constructor throws an exception, call the given
// destructor for any already-constructed elements, and rethrow the
// exception. If the destructor throws an exception, call terminate(). The
// constructor and/or destructor pointers may be NULL. If either is NULL,
// no action is taken when it would have been called.
_LIBCXXABI_FUNC_VIS void
__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
void (*constructor)(void *), void (*destructor)(void *)) {
if ( NULL != constructor ) {
size_t idx;
char *ptr = static_cast <char *> ( array_address );
st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
// Construct the elements
for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
constructor ( ptr );
cleanup.release (); // We're good!
}
}
// Given the (data) address of an array, the number of elements, and the
// size of its elements, call the given destructor on each element. If the
// destructor throws an exception, rethrow after destroying the remaining
// elements if possible. If the destructor throws a second exception, call
// terminate(). The destructor pointer may be NULL, in which case this
// routine does nothing.
_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *)) {
if ( NULL != destructor ) {
char *ptr = static_cast <char *> (array_address);
size_t idx = element_count;
st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
{
st_terminate exception_guard (__cxa_uncaught_exception ());
ptr += element_count * element_size; // one past the last element
while ( idx-- > 0 ) {
ptr -= element_size;
destructor ( ptr );
}
exception_guard.release (); // We're good !
}
cleanup.release (); // We're still good!
}
}
// Given the (data) address of an array, the number of elements, and the
// size of its elements, call the given destructor on each element. If the
// destructor throws an exception, call terminate(). The destructor pointer
// may be NULL, in which case this routine does nothing.
_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *)) {
if ( NULL != destructor ) {
char *ptr = static_cast <char *> (array_address);
size_t idx = element_count;
st_terminate exception_guard;
ptr += element_count * element_size; // one past the last element
while ( idx-- > 0 ) {
ptr -= element_size;
destructor ( ptr );
}
exception_guard.release (); // We're done!
}
}
// If the array_address is NULL, return immediately. Otherwise, given the
// (data) address of an array, the non-negative size of prefix padding for
// the cookie, and the size of its elements, call the given destructor on
// each element, using the cookie to determine the number of elements, and
// then delete the space by calling ::operator delete[](void *). If the
// destructor throws an exception, rethrow after (a) destroying the
// remaining elements, and (b) deallocating the storage. If the destructor
// throws a second exception, call terminate(). If padding_size is 0, the
// destructor pointer must be NULL. If the destructor pointer is NULL, no
// destructor call is to be made.
//
// The intent of this function is to permit an implementation to call this
// function when confronted with an expression of the form delete[] p in
// the source code, provided that the default deallocation function can be
// used. Therefore, the semantics of this function are consistent with
// those required by the standard. The requirement that the deallocation
// function be called even if the destructor throws an exception derives
// from the resolution to DR 353 to the C++ standard, which was adopted in
// April, 2003.
_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
size_t element_size,
size_t padding_size,
void (*destructor)(void *)) {
__cxa_vec_delete2 ( array_address, element_size, padding_size,
destructor, &::operator delete [] );
}
// Same as __cxa_vec_delete, except that the given function is used for
// deallocation instead of the default delete function. If dealloc throws
// an exception, the result is undefined. The dealloc pointer may not be
// NULL.
_LIBCXXABI_FUNC_VIS void
__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
void (*destructor)(void *), void (*dealloc)(void *)) {
if ( NULL != array_address ) {
char *vec_base = static_cast <char *> (array_address);
char *heap_block = vec_base - padding_size;
st_heap_block2 heap ( dealloc, heap_block );
if ( 0 != padding_size && NULL != destructor ) // call the destructors
__cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
element_size, destructor );
}
}
// Same as __cxa_vec_delete, except that the given function is used for
// deallocation instead of the default delete function. The deallocation
// function takes both the object address and its size. If dealloc throws
// an exception, the result is undefined. The dealloc pointer may not be
// NULL.
_LIBCXXABI_FUNC_VIS void
__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
void (*destructor)(void *), void (*dealloc)(void *, size_t)) {
if ( NULL != array_address ) {
char *vec_base = static_cast <char *> (array_address);
char *heap_block = vec_base - padding_size;
const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
const size_t heap_block_size = element_size * element_count + padding_size;
st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
if ( 0 != padding_size && NULL != destructor ) // call the destructors
__cxa_vec_dtor ( array_address, element_count, element_size, destructor );
}
}
} // extern "C"
} // abi

24
third_party/libcxxabi/cxa_virtual.cc vendored Normal file
View file

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxxabi/abort_message.h"
namespace __cxxabiv1 {
extern "C" {
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN
void __cxa_pure_virtual(void) {
abort_message("Pure virtual function called!");
}
_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN
void __cxa_deleted_virtual(void) {
abort_message("Deleted virtual function called!");
}
} // extern "C"
} // abi

View file

@ -0,0 +1,105 @@
//===--- DemangleConfig.h --------------------------------------*- 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
//
// This file is contains a subset of macros copied from
// llvm/include/llvm/Demangle/DemangleConfig.h
//===----------------------------------------------------------------------===//
#ifndef LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
#define LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
// Must be defined before pulling in headers from libc++. Allow downstream
// build systems to override this value.
// https://libcxx.llvm.org/UsingLibcxx.html#enabling-the-safe-libc-mode
#ifndef _LIBCPP_VERBOSE_ABORT
#define _LIBCPP_VERBOSE_ABORT(...) abort_message(__VA_ARGS__)
#include "third_party/libcxxabi/abort_message.h"
#endif
#include "third_party/libcxx/ciso646"
#ifdef _MSC_VER
// snprintf is implemented in VS 2015
#if _MSC_VER < 1900
#define snprintf _snprintf_s
#endif
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#endif
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef DEMANGLE_GNUC_PREREQ
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
((maj) << 20) + ((min) << 10) + (patch))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
#else
#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
#endif
#endif
#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
#else
#define DEMANGLE_ATTRIBUTE_USED
#endif
#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
#define DEMANGLE_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define DEMANGLE_UNREACHABLE __assume(false)
#else
#define DEMANGLE_UNREACHABLE
#endif
#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if !defined(NDEBUG)
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
#else
#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
#endif
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#define DEMANGLE_FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define DEMANGLE_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
#else
#define DEMANGLE_FALLTHROUGH
#endif
#define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
#define DEMANGLE_NAMESPACE_END } }
#endif // LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,95 @@
//===------------------------- ItaniumNodes.def ----------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Define the demangler's node names
#ifndef NODE
#error Define NODE to handle nodes
#endif
NODE(NodeArrayNode)
NODE(DotSuffix)
NODE(VendorExtQualType)
NODE(QualType)
NODE(ConversionOperatorType)
NODE(PostfixQualifiedType)
NODE(ElaboratedTypeSpefType)
NODE(NameType)
NODE(AbiTagAttr)
NODE(EnableIfAttr)
NODE(ObjCProtoName)
NODE(PointerType)
NODE(ReferenceType)
NODE(PointerToMemberType)
NODE(ArrayType)
NODE(FunctionType)
NODE(NoexceptSpec)
NODE(DynamicExceptionSpec)
NODE(FunctionEncoding)
NODE(LiteralOperator)
NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
NODE(VectorType)
NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
NODE(TypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
NODE(ParameterPack)
NODE(TemplateArgumentPack)
NODE(ParameterPackExpansion)
NODE(TemplateArgs)
NODE(ForwardTemplateReference)
NODE(NameWithTemplateArgs)
NODE(GlobalQualifiedName)
NODE(ExpandedSpecialSubstitution)
NODE(SpecialSubstitution)
NODE(CtorDtorName)
NODE(DtorName)
NODE(UnnamedTypeName)
NODE(ClosureTypeName)
NODE(StructuredBindingName)
NODE(BinaryExpr)
NODE(ArraySubscriptExpr)
NODE(PostfixExpr)
NODE(ConditionalExpr)
NODE(MemberExpr)
NODE(SubobjectExpr)
NODE(EnclosingExpr)
NODE(CastExpr)
NODE(SizeofParamPackExpr)
NODE(CallExpr)
NODE(NewExpr)
NODE(DeleteExpr)
NODE(PrefixExpr)
NODE(FunctionParam)
NODE(ConversionExpr)
NODE(PointerToMemberConversionExpr)
NODE(InitListExpr)
NODE(FoldExpr)
NODE(ThrowExpr)
NODE(BoolExpr)
NODE(StringLiteral)
NODE(LambdaExpr)
NODE(EnumLiteral)
NODE(IntegerLiteral)
NODE(FloatLiteral)
NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
#undef NODE

View file

@ -0,0 +1,38 @@
//===--- StringViewExtras.h -------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// There are two copies of this file in the source tree. The one under
// libcxxabi is the original and the one under llvm is the copy. Use
// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "third_party/libcxxabi/demangle/DemangleConfig.h"
#include "third_party/libcxx/string_view"
DEMANGLE_NAMESPACE_BEGIN
inline bool starts_with(std::string_view self, char C) noexcept {
return !self.empty() && *self.begin() == C;
}
inline bool starts_with(std::string_view haystack,
std::string_view needle) noexcept {
if (needle.size() > haystack.size())
return false;
haystack.remove_suffix(haystack.size() - needle.size());
return haystack == needle;
}
DEMANGLE_NAMESPACE_END
#endif

205
third_party/libcxxabi/demangle/Utility.h vendored Normal file
View file

@ -0,0 +1,205 @@
//===--- Utility.h ----------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler.
// There are two copies of this file in the source tree. The one in libcxxabi
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
// the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "third_party/libcxxabi/demangle/DemangleConfig.h"
#include "third_party/libcxx/array"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstdint"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/cstring"
#include "third_party/libcxx/exception"
#include "third_party/libcxx/limits"
#include "third_party/libcxx/string_view"
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
char *Buffer = nullptr;
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
// Ensure there are at least N more positions in the buffer.
void grow(size_t N) {
size_t Need = N + CurrentPosition;
if (Need > BufferCapacity) {
// Reduce the number of reallocations, with a bit of hysteresis. The
// number here is chosen so the first allocation will more-than-likely not
// allocate more than 1K.
Need += 1024 - 32;
BufferCapacity *= 2;
if (BufferCapacity < Need)
BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
std::array<char, 21> Temp;
char *TempPtr = Temp.data() + Temp.size();
// Output at least one character.
do {
*--TempPtr = char('0' + N % 10);
N /= 10;
} while (N);
// Add negative sign.
if (isNeg)
*--TempPtr = '-';
return operator+=(
std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
}
public:
OutputBuffer(char *StartBuf, size_t Size)
: Buffer(StartBuf), BufferCapacity(Size) {}
OutputBuffer(char *StartBuf, size_t *SizePtr)
: OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
OutputBuffer() = default;
// Non-copyable
OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
operator std::string_view() const {
return std::string_view(Buffer, CurrentPosition);
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
/// When zero, we're printing template args and '>' needs to be parenthesized.
/// Use a counter so we can simply increment inside parentheses.
unsigned GtIsGt = 1;
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
void printOpen(char Open = '(') {
GtIsGt++;
*this += Open;
}
void printClose(char Close = ')') {
GtIsGt--;
*this += Close;
}
OutputBuffer &operator+=(std::string_view R) {
if (size_t Size = R.size()) {
grow(Size);
std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
CurrentPosition += Size;
}
return *this;
}
OutputBuffer &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputBuffer &prepend(std::string_view R) {
size_t Size = R.size();
grow(Size);
std::memmove(Buffer + Size, Buffer, CurrentPosition);
std::memcpy(Buffer, &*R.begin(), Size);
CurrentPosition += Size;
return *this;
}
OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
OutputBuffer &operator<<(char C) { return (*this += C); }
OutputBuffer &operator<<(long long N) {
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
}
OutputBuffer &operator<<(unsigned long long N) {
return writeUnsigned(N, false);
}
OutputBuffer &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputBuffer &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputBuffer &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputBuffer &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
void insert(size_t Pos, const char *S, size_t N) {
assert(Pos <= CurrentPosition);
if (N == 0)
return;
grow(N);
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
std::memcpy(Buffer + Pos, S, N);
CurrentPosition += N;
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
assert(CurrentPosition);
return Buffer[CurrentPosition - 1];
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() const { return BufferCapacity; }
};
template <class T> class ScopedOverride {
T &Loc;
T Original;
public:
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
Loc_ = std::move(NewVal);
}
~ScopedOverride() { Loc = std::move(Original); }
ScopedOverride(const ScopedOverride &) = delete;
ScopedOverride &operator=(const ScopedOverride &) = delete;
};
DEMANGLE_NAMESPACE_END
#endif

303
third_party/libcxxabi/fallback_malloc.cc vendored Normal file
View file

@ -0,0 +1,303 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxxabi/fallback_malloc.h"
#include "third_party/libcxx/__threading_support"
#ifndef _LIBCXXABI_HAS_NO_THREADS
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
#pragma comment(lib, "pthread")
#endif
#endif
#include "third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h"
#include "libc/isystem/assert.h"
#include "libc/isystem/stdlib.h" // for malloc, calloc, free
#include "libc/isystem/string.h" // for memset
// A small, simple heap manager based (loosely) on
// the startup heap manager from FreeBSD, optimized for space.
//
// Manages a fixed-size memory pool, supports malloc and free only.
// No support for realloc.
//
// Allocates chunks in multiples of four bytes, with a four byte header
// for each chunk. The overhead of each chunk is kept low by keeping pointers
// as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
namespace {
// When POSIX threads are not available, make the mutex operations a nop
#ifndef _LIBCXXABI_HAS_NO_THREADS
static _LIBCPP_CONSTINIT std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
#else
static _LIBCPP_CONSTINIT void* heap_mutex = 0;
#endif
class mutexor {
public:
#ifndef _LIBCXXABI_HAS_NO_THREADS
mutexor(std::__libcpp_mutex_t* m) : mtx_(m) {
std::__libcpp_mutex_lock(mtx_);
}
~mutexor() { std::__libcpp_mutex_unlock(mtx_); }
#else
mutexor(void*) {}
~mutexor() {}
#endif
private:
mutexor(const mutexor& rhs);
mutexor& operator=(const mutexor& rhs);
#ifndef _LIBCXXABI_HAS_NO_THREADS
std::__libcpp_mutex_t* mtx_;
#endif
};
static const size_t HEAP_SIZE = 512;
char heap[HEAP_SIZE] __attribute__((aligned));
typedef unsigned short heap_offset;
typedef unsigned short heap_size;
// On both 64 and 32 bit targets heap_node should have the following properties
// Size: 4
// Alignment: 2
struct heap_node {
heap_offset next_node; // offset into heap
heap_size len; // size in units of "sizeof(heap_node)"
};
// All pointers returned by fallback_malloc must be at least aligned
// as RequiredAligned. Note that RequiredAlignment can be greater than
// alignof(std::max_align_t) on 64 bit systems compiling 32 bit code.
struct FallbackMaxAlignType {
} __attribute__((aligned));
const size_t RequiredAlignment = alignof(FallbackMaxAlignType);
static_assert(alignof(FallbackMaxAlignType) % sizeof(heap_node) == 0,
"The required alignment must be evenly divisible by the sizeof(heap_node)");
// The number of heap_node's that can fit in a chunk of memory with the size
// of the RequiredAlignment. On 64 bit targets NodesPerAlignment should be 4.
const size_t NodesPerAlignment = alignof(FallbackMaxAlignType) / sizeof(heap_node);
static const heap_node* list_end =
(heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap
static heap_node* freelist = NULL;
heap_node* node_from_offset(const heap_offset offset) {
return (heap_node*)(heap + (offset * sizeof(heap_node)));
}
heap_offset offset_from_node(const heap_node* ptr) {
return static_cast<heap_offset>(
static_cast<size_t>(reinterpret_cast<const char*>(ptr) - heap) /
sizeof(heap_node));
}
// Return a pointer to the first address, 'A', in `heap` that can actually be
// used to represent a heap_node. 'A' must be aligned so that
// '(A + sizeof(heap_node)) % RequiredAlignment == 0'. On 64 bit systems this
// address should be 12 bytes after the first 16 byte boundary.
heap_node* getFirstAlignedNodeInHeap() {
heap_node* node = (heap_node*)heap;
const size_t alignNBytesAfterBoundary = RequiredAlignment - sizeof(heap_node);
size_t boundaryOffset = reinterpret_cast<size_t>(node) % RequiredAlignment;
size_t requiredOffset = alignNBytesAfterBoundary - boundaryOffset;
size_t NElemOffset = requiredOffset / sizeof(heap_node);
return node + NElemOffset;
}
void init_heap() {
freelist = getFirstAlignedNodeInHeap();
freelist->next_node = offset_from_node(list_end);
freelist->len = static_cast<heap_size>(list_end - freelist);
}
// How big a chunk we allocate
size_t alloc_size(size_t len) {
return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1;
}
bool is_fallback_ptr(void* ptr) {
return ptr >= heap && ptr < (heap + HEAP_SIZE);
}
void* fallback_malloc(size_t len) {
heap_node *p, *prev;
const size_t nelems = alloc_size(len);
mutexor mtx(&heap_mutex);
if (NULL == freelist)
init_heap();
// Walk the free list, looking for a "big enough" chunk
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
// Check the invariant that all heap_nodes pointers 'p' are aligned
// so that 'p + 1' has an alignment of at least RequiredAlignment
assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0);
// Calculate the number of extra padding elements needed in order
// to split 'p' and create a properly aligned heap_node from the tail
// of 'p'. We calculate aligned_nelems such that 'p->len - aligned_nelems'
// will be a multiple of NodesPerAlignment.
size_t aligned_nelems = nelems;
if (p->len > nelems) {
heap_size remaining_len = static_cast<heap_size>(p->len - nelems);
aligned_nelems += remaining_len % NodesPerAlignment;
}
// chunk is larger and we can create a properly aligned heap_node
// from the tail. In this case we shorten 'p' and return the tail.
if (p->len > aligned_nelems) {
heap_node* q;
p->len = static_cast<heap_size>(p->len - aligned_nelems);
q = p + p->len;
q->next_node = 0;
q->len = static_cast<heap_size>(aligned_nelems);
void* ptr = q + 1;
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
return ptr;
}
// The chunk is the exact size or the chunk is larger but not large
// enough to split due to alignment constraints.
if (p->len >= nelems) {
if (prev == 0)
freelist = node_from_offset(p->next_node);
else
prev->next_node = p->next_node;
p->next_node = 0;
void* ptr = p + 1;
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
return ptr;
}
}
return NULL; // couldn't find a spot big enough
}
// Return the start of the next block
heap_node* after(struct heap_node* p) { return p + p->len; }
void fallback_free(void* ptr) {
struct heap_node* cp = ((struct heap_node*)ptr) - 1; // retrieve the chunk
struct heap_node *p, *prev;
mutexor mtx(&heap_mutex);
#ifdef DEBUG_FALLBACK_MALLOC
std::printf("Freeing item at %d of size %d\n", offset_from_node(cp), cp->len);
#endif
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
#ifdef DEBUG_FALLBACK_MALLOC
std::printf(" p=%d, cp=%d, after(p)=%d, after(cp)=%d\n",
offset_from_node(p), offset_from_node(cp),
offset_from_node(after(p)), offset_from_node(after(cp)));
#endif
if (after(p) == cp) {
#ifdef DEBUG_FALLBACK_MALLOC
std::printf(" Appending onto chunk at %d\n", offset_from_node(p));
#endif
p->len = static_cast<heap_size>(
p->len + cp->len); // make the free heap_node larger
return;
} else if (after(cp) == p) { // there's a free heap_node right after
#ifdef DEBUG_FALLBACK_MALLOC
std::printf(" Appending free chunk at %d\n", offset_from_node(p));
#endif
cp->len = static_cast<heap_size>(cp->len + p->len);
if (prev == 0) {
freelist = cp;
cp->next_node = p->next_node;
} else
prev->next_node = offset_from_node(cp);
return;
}
}
// Nothing to merge with, add it to the start of the free list
#ifdef DEBUG_FALLBACK_MALLOC
std::printf(" Making new free list entry %d\n", offset_from_node(cp));
#endif
cp->next_node = offset_from_node(freelist);
freelist = cp;
}
#ifdef INSTRUMENT_FALLBACK_MALLOC
size_t print_free_list() {
struct heap_node *p, *prev;
heap_size total_free = 0;
if (NULL == freelist)
init_heap();
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
std::printf("%sOffset: %d\tsize: %d Next: %d\n",
(prev == 0 ? "" : " "), offset_from_node(p), p->len, p->next_node);
total_free += p->len;
}
std::printf("Total Free space: %d\n", total_free);
return total_free;
}
#endif
} // end unnamed namespace
namespace __cxxabiv1 {
struct __attribute__((aligned)) __aligned_type {};
void* __aligned_malloc_with_fallback(size_t size) {
#if defined(_WIN32)
if (void* dest = std::__libcpp_aligned_alloc(alignof(__aligned_type), size))
return dest;
#elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
if (void* dest = ::malloc(size))
return dest;
#else
if (size == 0)
size = 1;
if (void* dest = std::__libcpp_aligned_alloc(__alignof(__aligned_type), size))
return dest;
#endif
return fallback_malloc(size);
}
void* __calloc_with_fallback(size_t count, size_t size) {
void* ptr = ::calloc(count, size);
if (NULL != ptr)
return ptr;
// if calloc fails, fall back to emergency stash
ptr = fallback_malloc(size * count);
if (NULL != ptr)
::memset(ptr, 0, size * count);
return ptr;
}
void __aligned_free_with_fallback(void* ptr) {
if (is_fallback_ptr(ptr))
fallback_free(ptr);
else {
#if defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
::free(ptr);
#else
std::__libcpp_aligned_free(ptr);
#endif
}
}
void __free_with_fallback(void* ptr) {
if (is_fallback_ptr(ptr))
fallback_free(ptr);
else
::free(ptr);
}
} // namespace __cxxabiv1

28
third_party/libcxxabi/fallback_malloc.h vendored Normal file
View file

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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 _FALLBACK_MALLOC_H
#define _FALLBACK_MALLOC_H
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "libc/isystem/stddef.h" // for size_t
namespace __cxxabiv1 {
// Allocate some memory from _somewhere_
_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size);
// Allocate and zero-initialize memory from _somewhere_
_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size);
_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr);
_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr);
} // namespace __cxxabiv1
#endif

View file

@ -0,0 +1,106 @@
//===----------------------------------------------------------------------===//
//
// 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 ____CXXABI_CONFIG_H
#define ____CXXABI_CONFIG_H
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
!defined(__ARM_DWARF_EH__) && !defined(__SEH__)
#define _LIBCXXABI_ARM_EHABI
#endif
#if !defined(__has_attribute)
#define __has_attribute(_attribute_) 0
#endif
#if defined(__clang__)
# define _LIBCXXABI_COMPILER_CLANG
# ifndef __apple_build_version__
# define _LIBCXXABI_CLANG_VER (__clang_major__ * 100 + __clang_minor__)
# endif
#elif defined(__GNUC__)
# define _LIBCXXABI_COMPILER_GCC
#elif defined(_MSC_VER)
# define _LIBCXXABI_COMPILER_MSVC
#elif defined(__IBMCPP__)
# define _LIBCXXABI_COMPILER_IBM
#endif
#if defined(_WIN32)
#if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS
#define _LIBCXXABI_FUNC_VIS
#define _LIBCXXABI_TYPE_VIS
#elif defined(_LIBCXXABI_BUILDING_LIBRARY)
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS __declspec(dllexport)
#define _LIBCXXABI_FUNC_VIS __declspec(dllexport)
#define _LIBCXXABI_TYPE_VIS __declspec(dllexport)
#else
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS __declspec(dllimport)
#define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
#define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
#endif
#else
#if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
#define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
#define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default")))
#define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default")))
#if __has_attribute(__type_visibility__)
#define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default")))
#else
#define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default")))
#endif
#else
#define _LIBCXXABI_HIDDEN
#define _LIBCXXABI_DATA_VIS
#define _LIBCXXABI_FUNC_VIS
#define _LIBCXXABI_TYPE_VIS
#endif
#endif
#if defined(_LIBCXXABI_COMPILER_MSVC)
#define _LIBCXXABI_WEAK
#else
#define _LIBCXXABI_WEAK __attribute__((__weak__))
#endif
#if defined(__clang__)
#define _LIBCXXABI_COMPILER_CLANG
#elif defined(__GNUC__)
#define _LIBCXXABI_COMPILER_GCC
#endif
#if __has_attribute(__no_sanitize__) && defined(_LIBCXXABI_COMPILER_CLANG)
#define _LIBCXXABI_NO_CFI __attribute__((__no_sanitize__("cfi")))
#else
#define _LIBCXXABI_NO_CFI
#endif
// wasm32 follows the arm32 ABI convention of using 32-bit guard.
#if defined(__arm__) || defined(__wasm32__) || defined(__ARM64_ARCH_8_32__)
# define _LIBCXXABI_GUARD_ABI_ARM
#endif
#if defined(_LIBCXXABI_COMPILER_CLANG)
# if !__has_feature(cxx_exceptions)
# define _LIBCXXABI_NO_EXCEPTIONS
# endif
#elif defined(_LIBCXXABI_COMPILER_GCC) && !defined(__EXCEPTIONS)
# define _LIBCXXABI_NO_EXCEPTIONS
#endif
#if defined(_WIN32)
#define _LIBCXXABI_DTOR_FUNC __thiscall
#else
#define _LIBCXXABI_DTOR_FUNC
#endif
#endif // ____CXXABI_CONFIG_H

177
third_party/libcxxabi/include/cxxabi.h vendored Normal file
View file

@ -0,0 +1,177 @@
//===----------------------------------------------------------------------===//
//
// 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 __CXXABI_H
#define __CXXABI_H
/*
* This header provides the interface to the C++ ABI as defined at:
* https://itanium-cxx-abi.github.io/cxx-abi/
*/
#include "libc/isystem/stddef.h"
#include "libc/isystem/stdint.h"
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#define _LIBCPPABI_VERSION 15000
#define _LIBCXXABI_NORETURN __attribute__((noreturn))
#define _LIBCXXABI_ALWAYS_COLD __attribute__((cold))
#ifdef __cplusplus
namespace std {
#if defined(_WIN32)
class _LIBCXXABI_TYPE_VIS type_info; // forward declaration
#else
class type_info; // forward declaration
#endif
}
// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
namespace __cxxabiv1 {
extern "C" {
// 2.4.2 Allocating the Exception Object
extern _LIBCXXABI_FUNC_VIS void *
__cxa_allocate_exception(size_t thrown_size) throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_free_exception(void *thrown_exception) throw();
// 2.4.3 Throwing the Exception Object
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
void (_LIBCXXABI_DTOR_FUNC *dest)(void *));
// 2.5.3 Exception Handlers
extern _LIBCXXABI_FUNC_VIS void *
__cxa_get_exception_ptr(void *exceptionObject) throw();
extern _LIBCXXABI_FUNC_VIS void *
__cxa_begin_catch(void *exceptionObject) throw();
extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch();
#if defined(_LIBCXXABI_ARM_EHABI)
extern _LIBCXXABI_FUNC_VIS bool
__cxa_begin_cleanup(void *exceptionObject) throw();
extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup();
#endif
extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type();
// 2.5.4 Rethrowing Exceptions
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow();
// 2.6 Auxiliary Runtime APIs
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw_bad_array_new_length(void);
// 3.2.6 Pure Virtual Function API
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void);
// 3.2.7 Deleted Virtual Function API
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void);
// 3.3.2 One-time Construction API
#if defined(_LIBCXXABI_GUARD_ABI_ARM)
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint32_t *);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint32_t *);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint32_t *);
#else
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint64_t *);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint64_t *);
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint64_t *);
#endif
// 3.3.3 Array Construction and Destruction API
extern _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *));
extern _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
void (*constructor)(void *), void (*destructor)(void *),
void *(*alloc)(size_t), void (*dealloc)(void *, size_t));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
void (*constructor)(void *), void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
size_t element_count,
size_t element_size,
void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
size_t element_size,
size_t padding_size,
void (*destructor)(void *));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
void (*destructor)(void *), void (*dealloc)(void *));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_delete3(void *__array_address, size_t element_size,
size_t padding_size, void (*destructor)(void *),
void (*dealloc)(void *, size_t));
extern _LIBCXXABI_FUNC_VIS void
__cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count,
size_t element_size, void (*constructor)(void *, void *),
void (*destructor)(void *));
// 3.3.5.3 Runtime API
// These functions are part of the C++ ABI, but they are not defined in libc++abi:
// int __cxa_atexit(void (*)(void *), void *, void *);
// void __cxa_finalize(void *);
// 3.4 Demangler API
extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name,
char *output_buffer,
size_t *length, int *status);
// Apple additions to support C++ 0x exception_ptr class
// These are primitives to wrap a smart pointer around an exception object
extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_rethrow_primary_exception(void *primary_exception);
extern _LIBCXXABI_FUNC_VIS void
__cxa_increment_exception_refcount(void *primary_exception) throw();
extern _LIBCXXABI_FUNC_VIS void
__cxa_decrement_exception_refcount(void *primary_exception) throw();
// Apple extension to support std::uncaught_exception()
extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw();
extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw();
#if defined(__linux__) || defined(__Fuchsia__) || defined(__COSMOPOLITAN__)
// Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.
// https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
void *) throw();
#endif
} // extern "C"
} // namespace __cxxabiv1
namespace abi = __cxxabiv1;
#endif // __cplusplus
#endif // __CXXABI_H

View file

@ -0,0 +1,66 @@
//===----------------------------------------------------------------------===//
//
// 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 _LIBCPP___MEMORY_ALIGNED_ALLOC_H
#define _LIBCPP___MEMORY_ALIGNED_ALLOC_H
#include "third_party/libcxx/__config"
#include "third_party/libcxx/cstddef"
#include "third_party/libcxx/cstdlib"
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
// Low-level helpers to call the aligned allocation and deallocation functions
// on the target platform. This is used to implement libc++'s own memory
// allocation routines -- if you need to allocate memory inside the library,
// chances are that you want to use `__libcpp_allocate` instead.
//
// Returns the allocated memory, or `nullptr` on failure.
inline _LIBCPP_HIDE_FROM_ABI
void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) {
# if defined(_LIBCPP_MSVCRT_LIKE)
return ::_aligned_malloc(__size, __alignment);
# elif _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_C11_ALIGNED_ALLOC)
// aligned_alloc() requires that __size is a multiple of __alignment,
// but for C++ [new.delete.general], only states "if the value of an
// alignment argument passed to any of these functions is not a valid
// alignment value, the behavior is undefined".
// To handle calls such as ::operator new(1, std::align_val_t(128)), we
// round __size up to the next multiple of __alignment.
size_t __rounded_size = (__size + __alignment - 1) & ~(__alignment - 1);
// Rounding up could have wrapped around to zero, so we have to add another
// max() ternary to the actual call site to avoid succeeded in that case.
return ::aligned_alloc(__alignment, __size > __rounded_size ? __size : __rounded_size);
# else
void* __result = nullptr;
(void)::posix_memalign(&__result, __alignment, __size);
// If posix_memalign fails, __result is unmodified so we still return `nullptr`.
return __result;
# endif
}
inline _LIBCPP_HIDE_FROM_ABI
void __libcpp_aligned_free(void* __ptr) {
#if defined(_LIBCPP_MSVCRT_LIKE)
::_aligned_free(__ptr);
#else
::free(__ptr);
#endif
}
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___MEMORY_ALIGNED_ALLOC_H

1388
third_party/libcxxabi/private_typeinfo.cc vendored Normal file

File diff suppressed because it is too large Load diff

251
third_party/libcxxabi/private_typeinfo.h vendored Normal file
View file

@ -0,0 +1,251 @@
//===----------------------------------------------------------------------===//
//
// 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 __PRIVATE_TYPEINFO_H_
#define __PRIVATE_TYPEINFO_H_
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxx/typeinfo"
#include "libc/isystem/stddef.h"
namespace __cxxabiv1 {
class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__shim_type_info();
_LIBCXXABI_HIDDEN virtual void noop1() const;
_LIBCXXABI_HIDDEN virtual void noop2() const;
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *thrown_type,
void *&adjustedPtr) const = 0;
};
class _LIBCXXABI_TYPE_VIS __fundamental_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__fundamental_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __array_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__array_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __function_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__function_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__enum_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
enum
{
unknown = 0,
public_path,
not_public_path,
yes,
no
};
class _LIBCXXABI_TYPE_VIS __class_type_info;
struct _LIBCXXABI_HIDDEN __dynamic_cast_info
{
// const data supplied to the search:
const __class_type_info* dst_type;
const void* static_ptr;
const __class_type_info* static_type;
ptrdiff_t src2dst_offset;
// Data that represents the answer:
// pointer to a dst_type which has (static_ptr, static_type) above it
const void* dst_ptr_leading_to_static_ptr;
// pointer to a dst_type which does not have (static_ptr, static_type) above it
const void* dst_ptr_not_leading_to_static_ptr;
// The following three paths are either unknown, public_path or not_public_path.
// access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
int path_dst_ptr_to_static_ptr;
// access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
// when there is no dst_type along the path
int path_dynamic_ptr_to_static_ptr;
// access of path from (dynamic_ptr, dynamic_type) to dst_type
// (not used if there is a (static_ptr, static_type) above a dst_type).
int path_dynamic_ptr_to_dst_ptr;
// Number of dst_types below (static_ptr, static_type)
int number_to_static_ptr;
// Number of dst_types not below (static_ptr, static_type)
int number_to_dst_ptr;
// Data that helps stop the search before the entire tree is searched:
// is_dst_type_derived_from_static_type is either unknown, yes or no.
int is_dst_type_derived_from_static_type;
// Number of dst_type in tree. If 0, then that means unknown.
int number_of_dst_type;
// communicates to a dst_type node that (static_ptr, static_type) was found
// above it.
bool found_our_static_ptr;
// communicates to a dst_type node that a static_type was found
// above it, but it wasn't (static_ptr, static_type)
bool found_any_static_type;
// Set whenever a search can be stopped
bool search_done;
};
// Has no base class
class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__class_type_info();
_LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *,
const void *,
const void *, int) const;
_LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
const void *, int) const;
_LIBCXXABI_HIDDEN void process_found_base_class(__dynamic_cast_info *, void *,
int) const;
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
const void *, const void *,
int, bool) const;
_LIBCXXABI_HIDDEN virtual void
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
_LIBCXXABI_HIDDEN virtual void
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
};
// Has one non-virtual public base class at offset zero
class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info {
public:
const __class_type_info *__base_type;
_LIBCXXABI_HIDDEN virtual ~__si_class_type_info();
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
const void *, const void *,
int, bool) const;
_LIBCXXABI_HIDDEN virtual void
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
_LIBCXXABI_HIDDEN virtual void
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
};
struct _LIBCXXABI_HIDDEN __base_class_type_info
{
public:
const __class_type_info* __base_type;
long __offset_flags;
enum __offset_flags_masks
{
__virtual_mask = 0x1,
__public_mask = 0x2, // base is public
__offset_shift = 8
};
void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
};
// Has one or more base classes
class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info {
public:
unsigned int __flags;
unsigned int __base_count;
__base_class_type_info __base_info[1];
enum __flags_masks {
__non_diamond_repeat_mask = 0x1, // has two or more distinct base class
// objects of the same type
__diamond_shaped_mask = 0x2 // has base class object with two or
// more derived objects
};
_LIBCXXABI_HIDDEN virtual ~__vmi_class_type_info();
_LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
const void *, const void *,
int, bool) const;
_LIBCXXABI_HIDDEN virtual void
search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
_LIBCXXABI_HIDDEN virtual void
has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
};
class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {
public:
unsigned int __flags;
const __shim_type_info *__pointee;
enum __masks {
__const_mask = 0x1,
__volatile_mask = 0x2,
__restrict_mask = 0x4,
__incomplete_mask = 0x8,
__incomplete_class_mask = 0x10,
__transaction_safe_mask = 0x20,
// This implements the following proposal from cxx-abi-dev (not yet part of
// the ABI document):
//
// http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002986.html
//
// This is necessary for support of http://wg21.link/p0012, which permits
// throwing noexcept function and member function pointers and catching
// them as non-noexcept pointers.
__noexcept_mask = 0x40,
// Flags that cannot be removed by a standard conversion.
__no_remove_flags_mask = __const_mask | __volatile_mask | __restrict_mask,
// Flags that cannot be added by a standard conversion.
__no_add_flags_mask = __transaction_safe_mask | __noexcept_mask
};
_LIBCXXABI_HIDDEN virtual ~__pbase_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
};
class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info {
public:
_LIBCXXABI_HIDDEN virtual ~__pointer_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
_LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
};
class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info
: public __pbase_type_info {
public:
const __class_type_info *__context;
_LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info();
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
void *&) const;
_LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
};
} // __cxxabiv1
#endif // __PRIVATE_TYPEINFO_H_

View file

@ -0,0 +1,70 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxx/new"
#include "third_party/libcxx/exception"
namespace std
{
// exception
exception::~exception() noexcept
{
}
const char* exception::what() const noexcept
{
return "std::exception";
}
// bad_exception
bad_exception::~bad_exception() noexcept
{
}
const char* bad_exception::what() const noexcept
{
return "std::bad_exception";
}
// bad_alloc
bad_alloc::bad_alloc() noexcept
{
}
bad_alloc::~bad_alloc() noexcept
{
}
const char*
bad_alloc::what() const noexcept
{
return "std::bad_alloc";
}
// bad_array_new_length
bad_array_new_length::bad_array_new_length() noexcept
{
}
bad_array_new_length::~bad_array_new_length() noexcept
{
}
const char*
bad_array_new_length::what() const noexcept
{
return "bad_array_new_length";
}
} // std

View file

@ -0,0 +1,266 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libcxxabi/libcxx/include/__memory/aligned_alloc.h"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/new"
// Perform a few sanity checks on libc++ and libc++abi macros to ensure that
// the code below can be an exact copy of the code in libcxx/src/new.cpp.
#if !defined(_THROW_BAD_ALLOC)
# error The _THROW_BAD_ALLOC macro should be already defined by libc++
#endif
#ifndef _LIBCPP_WEAK
# error The _LIBCPP_WEAK macro should be already defined by libc++
#endif
#if defined(_LIBCXXABI_NO_EXCEPTIONS) != defined(_LIBCPP_HAS_NO_EXCEPTIONS)
# error libc++ and libc++abi seem to disagree on whether exceptions are enabled
#endif
// ------------------ BEGIN COPY ------------------
// Implement all new and delete operators as weak definitions
// in this shared library, so that they can be overridden by programs
// that define non-weak copies of the functions.
_LIBCPP_WEAK
void *
operator new(std::size_t size) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
void* p;
while ((p = std::malloc(size)) == nullptr)
{
// If malloc fails and there is a new_handler,
// call it to try free up memory.
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw std::bad_alloc();
#else
break;
#endif
}
return p;
}
_LIBCPP_WEAK
void*
operator new(size_t size, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new(size);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void*
operator new[](size_t size) _THROW_BAD_ALLOC
{
return ::operator new(size);
}
_LIBCPP_WEAK
void*
operator new[](size_t size, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new[](size);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void
operator delete(void* ptr) noexcept
{
std::free(ptr);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, const std::nothrow_t&) noexcept
{
::operator delete(ptr);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, size_t) noexcept
{
::operator delete(ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr) noexcept
{
::operator delete(ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, const std::nothrow_t&) noexcept
{
::operator delete[](ptr);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, size_t) noexcept
{
::operator delete[](ptr);
}
#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
_LIBCPP_WEAK
void *
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
if (size == 0)
size = 1;
if (static_cast<size_t>(alignment) < sizeof(void*))
alignment = std::align_val_t(sizeof(void*));
// Try allocating memory. If allocation fails and there is a new_handler,
// call it to try free up memory, and try again until it succeeds, or until
// the new_handler decides to terminate.
//
// If allocation fails and there is no new_handler, we throw bad_alloc
// (or return nullptr if exceptions are disabled).
void* p;
while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr)
{
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw std::bad_alloc();
#else
break;
#endif
}
}
return p;
}
_LIBCPP_WEAK
void*
operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new(size, alignment);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void*
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
{
return ::operator new(size, alignment);
}
_LIBCPP_WEAK
void*
operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
void* p = nullptr;
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
p = ::operator new[](size, alignment);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
return p;
}
_LIBCPP_WEAK
void
operator delete(void* ptr, std::align_val_t) noexcept
{
std::__libcpp_aligned_free(ptr);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept
{
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment) noexcept
{
::operator delete(ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
::operator delete[](ptr, alignment);
}
_LIBCPP_WEAK
void
operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept
{
::operator delete[](ptr, alignment);
}
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
// ------------------ END COPY ------------------

View file

@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxx/stdexcept"
#include "third_party/libcxx/new"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/cstring"
#include "third_party/libcxx/cstdint"
#include "third_party/libcxx/cstddef"
#include "third_party/libcxx/refstring.hh" // from libc++
static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
namespace std // purposefully not using versioning namespace
{
logic_error::~logic_error() noexcept {}
const char*
logic_error::what() const noexcept
{
return __imp_.c_str();
}
runtime_error::~runtime_error() noexcept {}
const char*
runtime_error::what() const noexcept
{
return __imp_.c_str();
}
domain_error::~domain_error() noexcept {}
invalid_argument::~invalid_argument() noexcept {}
length_error::~length_error() noexcept {}
out_of_range::~out_of_range() noexcept {}
range_error::~range_error() noexcept {}
overflow_error::~overflow_error() noexcept {}
underflow_error::~underflow_error() noexcept {}
} // std

View file

@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// 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 "third_party/libcxx/typeinfo"
namespace std
{
// type_info
type_info::~type_info()
{
}
// bad_cast
bad_cast::bad_cast() noexcept
{
}
bad_cast::~bad_cast() noexcept
{
}
const char*
bad_cast::what() const noexcept
{
return "std::bad_cast";
}
// bad_typeid
bad_typeid::bad_typeid() noexcept
{
}
bad_typeid::~bad_typeid() noexcept
{
}
const char*
bad_typeid::what() const noexcept
{
return "std::bad_typeid";
}
} // std

View file

@ -54,8 +54,7 @@ THIRD_PARTY_LIBUNWIND_A_CHECKS = \
THIRD_PARTY_LIBUNWIND_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_INTRIN \
LIBC_STDIO \
THIRD_PARTY_LIBCXX
LIBC_STDIO
THIRD_PARTY_LIBUNWIND_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBUNWIND_A_DIRECTDEPS),$($(x))))