Compare commits

...

8 Commits

Author SHA1 Message Date
joerg 224744e92e Import libcxxrt 47661d00cd4d6cd728ae31b0bb29a49a6c06272a
The repository moved to https://github.com/libcxxrt/libcxxrt in the mean
time, but keep it on the same branch as before. This primarily brings
C++14 support.
2021-05-30 00:08:19 +00:00
pooka effaea5059 Import libcxxrt e64e93fe5bba67a6d52cbe5a97f8770c054bfa65
Implements __cxa_throw_bad_array_new_length, which is generated by gcc
4.9 and later.  Also, some demangle support and fixes.
2015-09-11 11:19:58 +00:00
joerg 85868bff6a Define guard_lock_t on 32bit Big Endian platforms too. 2014-07-25 16:25:24 +00:00
joerg 62f1f69df8 Use correct type encoding for DWARF EH on ARM 2014-07-20 15:50:36 +00:00
joerg 43f1659e3a Import libcxxrt revision 4eb349088dda15d2de9a8c7b144c3f2d5f390269.
Restore support for 32bit architectures without 64bit CAS.
Support DWARF exception handling on ARM.
2014-05-15 23:56:01 +00:00
joerg 70614fb158 Import new snapshot of libcxxrt. Fixes demangling of anonymous
namespaces. Avoid use of old style (C) casts.
2013-12-25 20:19:45 +00:00
joerg 2caecc44fa Import revision c61efa043b14378efbd69c9a2686d44ed46ae179 of libcxxrt.
This adds __cxa_deleted_virtual, some explicit store barriers before
lock releases and fixes ARM guard variable initialisation.
2013-07-04 22:29:29 +00:00
joerg f07b9bbdf5 Import libcxxrt b2396b5945d7a2697c4762c3e52dc6f732b2eebd from
https://github.com/pathscale/libcxxrt/.
2013-05-17 23:04:37 +00:00
32 changed files with 9356 additions and 0 deletions

View File

@ -0,0 +1,2 @@
David Chisnall
PathScale engineers

View File

@ -0,0 +1,3 @@
PathScale Inc
NetBSD Foundation
FreeBSD Foundation

View File

@ -0,0 +1,14 @@
The BSD License
Copyright 2010-2011 PathScale, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of PathScale, Inc.

View File

@ -0,0 +1,50 @@
libcxxabi
=========
This library implements the Code Sourcery C++ ABI, as documented here:
http://www.codesourcery.com/public/cxx-abi/abi.html
It is intended to sit below an STL implementation, and provide features required by the compiler for implementation of the C++ language.
Current Status
--------------
At present, the library implements the following parts of the ABI specification:
- RTTI classes and support for the dynamic_cast<> operator.
- Exception handling.
- Thread-safe initializers.
Exception handling requires the assistance of a stack-unwinding library
implementing the low-level parts of the ABI. Either libgcc_s or libunwind
should work for this purpose.
The library depends on various libc features, but does not depend on any C++
features not implemented purely in the compiler or in the library itself.
Supported Platforms
-------------------
This code was initially developed on FreeBSD/x86, and has also been tested on FreeBSD/x86-64. It should work on other platforms that use the Code Sourcery ABI, for example Itanium, however this is untested.
This library also supports the ARM EH ABI.
Installation
------------
The default build system does not perform any installation. It is expected that this will be done by at a higher level. The exact installation steps depend on how you plan on deploying libcxxrt.
There are three files that you may consider installing:
- cxxabi.h (and unwind.h and either unwind-arm.h or unwind-itanium.h)
- libcxxrt.a
- libcxxrt.so
The first describes the contract between this library and the compiler / STL implementation (lib[std]{cxx,c++}). Its contents should be considered semi-private, as it is probably not a good idea to encourage any code above the STL implementation to depend on it. Doing so will introduce portability issues. You may install this file but I recommend simply copying or linking it into your STL implementation's build directory.
In general, I recommend against installing both the .a and the .so file. For static linking, the .a file should be linked against the static and dynamic versions of your STL implementation. Statically linking libcxxrt into your STL implementation means that users who dynamically link against the STL implementation can have libcxxrt upgraded automatically when you ship a new version of your STL implementation.
The other option, installing the .so, is recommended for situations where you have two or more STL implementations and wish to be able to link against both (e.g. where an application links one library using libstdc++ and another using libc++). To support this case, you should link both STL implementations against libcxxrt.so.
Supporting all of these options in the CMake build system is not practical - the amount of effort required to select the one that you want would be more than the effort required to perform the installation from an external script or build system.

View File

@ -0,0 +1,5 @@
/**
* The namespace used for the ABI declarations. This is currently defined to
* be the same as GNU libsupc++, however this may change in the future.
*/
#define ABI_NAMESPACE __cxxabiv1

View File

@ -0,0 +1,30 @@
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
/**
* Swap macro that enforces a happens-before relationship with a corresponding
* ATOMIC_LOAD.
*/
#if __has_builtin(__c11_atomic_exchange)
#define ATOMIC_SWAP(addr, val)\
__c11_atomic_exchange(reinterpret_cast<_Atomic(__typeof__(val))*>(addr), val, __ATOMIC_ACQ_REL)
#elif __has_builtin(__sync_swap)
#define ATOMIC_SWAP(addr, val)\
__sync_swap(addr, val)
#else
#define ATOMIC_SWAP(addr, val)\
__sync_lock_test_and_set(addr, val)
#endif
#if __has_builtin(__c11_atomic_load)
#define ATOMIC_LOAD(addr)\
__c11_atomic_load(reinterpret_cast<_Atomic(__typeof__(*addr))*>(addr), __ATOMIC_ACQUIRE)
#else
#define ATOMIC_LOAD(addr)\
(__sync_synchronize(), *addr)
#endif

View File

@ -0,0 +1,82 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* aux.cc - Compiler helper functions.
*
* The functions declared in this file are intended to be called only by code
* that is automatically generated by C++ compilers for some common cases.
*/
#include <stdlib.h>
#include "stdexcept.h"
/**
* Called to generate a bad cast exception. This function is intended to allow
* compilers to insert code generating this exception without needing to
* duplicate the code for throwing the exception in every call site.
*/
extern "C" void __cxa_bad_cast()
{
throw std::bad_cast();
}
/**
* Called to generate a bad typeid exception. This function is intended to
* allow compilers to insert code generating this exception without needing to
* duplicate the code for throwing the exception in every call site.
*/
extern "C" void __cxa_bad_typeid()
{
throw std::bad_typeid();
}
/**
* Compilers may (but are not required to) set any pure-virtual function's
* vtable entry to this function. This makes debugging slightly easier, as
* users can add a breakpoint on this function to tell if they've accidentally
* called a pure-virtual function.
*/
extern "C" void __cxa_pure_virtual()
{
abort();
}
/**
* Compilers may (but are not required to) set any deleted-virtual function's
* vtable entry to this function. This makes debugging slightly easier, as
* users can add a breakpoint on this function to tell if they've accidentally
* called a deleted-virtual function.
*/
extern "C" void __cxa_deleted_virtual()
{
abort();
}
extern "C" void __cxa_throw_bad_array_new_length()
{
throw std::bad_array_new_length();
}

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2012 David Chisnall.
*
* 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.
*
*/
/* Special thanks to TBricks for partially funding this work */
#ifdef __sun__
#include <pthread.h>
#include <stdlib.h>
static struct atexit_handler {
void (*f)(void *);
void *p;
void *d;
struct atexit_handler *next;
} *head;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int __cxa_atexit( void (*f)(void *), void *p, void *d) {
pthread_mutex_lock(&lock);
struct atexit_handler *h = malloc(sizeof(*h));
if (!h) {
pthread_mutex_unlock(&lock);
return 1;
}
h->f = f;
h->p = p;
h->d = d;
h->next = head;
head = h;
pthread_mutex_unlock(&lock);
return 0;
}
void __cxa_finalize(void *d ) {
pthread_mutex_lock(&lock);
struct atexit_handler **last = &head;
for (struct atexit_handler *h = head ; h ; h = h->next) {
if ((h->d == d) || (d == 0)) {
*last = h->next;
h->f(h->p);
free(h);
} else {
last = &h->next;
}
}
pthread_mutex_unlock(&lock);
}
#endif

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2012 David Chisnall.
*
* 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.
*
*/
void __cxa_finalize(void *d );
extern void *__dso_handle;
__attribute__((__destructor__, __used__))
static void cleanup(void) {
__cxa_finalize(&__dso_handle);
}

View File

@ -0,0 +1,244 @@
/*
* Copyright 2012 David Chisnall. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __CXXABI_H_
#define __CXXABI_H_
#include <stddef.h>
#include <stdint.h>
#include "unwind.h"
namespace std
{
class type_info;
}
/*
* The cxxabi.h header provides a set of public definitions for types and
* functions defined by the Itanium C++ ABI specification. For reference, see
* the ABI specification here:
*
* http://sourcery.mentor.com/public/cxx-abi/abi.html
*
* All deviations from this specification, unless otherwise noted, are
* accidental.
*/
#ifdef __cplusplus
namespace __cxxabiv1 {
extern "C" {
#endif
/**
* Function type to call when an unexpected exception is encountered.
*/
typedef void (*unexpected_handler)();
/**
* Function type to call when an unrecoverable condition is encountered.
*/
typedef void (*terminate_handler)();
/**
* Structure used as a header on thrown exceptions. This is the same layout as
* defined by the Itanium ABI spec, so should be interoperable with any other
* implementation of this spec, such as GNU libsupc++.
*
* This structure is allocated when an exception is thrown. Unwinding happens
* in two phases, the first looks for a handler and the second installs the
* context. This structure stores a cache of the handler location between
* phase 1 and phase 2. Unfortunately, cleanup information is not cached, so
* must be looked up in both phases. This happens for two reasons. The first
* is that we don't know how many frames containing cleanups there will be, and
* we should avoid dynamic allocation during unwinding (the exception may be
* reporting that we've run out of memory). The second is that finding
* cleanups is much cheaper than finding handlers, because we don't have to
* look at the type table at all.
*
* Note: Several fields of this structure have not-very-informative names.
* These are taken from the ABI spec and have not been changed to make it
* easier for people referring to to the spec while reading this code.
*/
struct __cxa_exception
{
#if __LP64__
/**
* Reference count. Used to support the C++11 exception_ptr class. This
* is prepended to the structure in 64-bit mode and squeezed in to the
* padding left before the 64-bit aligned _Unwind_Exception at the end in
* 32-bit mode.
*
* Note that it is safe to extend this structure at the beginning, rather
* than the end, because the public API for creating it returns the address
* of the end (where the exception object can be stored).
*/
uintptr_t referenceCount;
#endif
/** Type info for the thrown object. */
std::type_info *exceptionType;
/** Destructor for the object, if one exists. */
void (*exceptionDestructor) (void *);
/** Handler called when an exception specification is violated. */
unexpected_handler unexpectedHandler;
/** Hander called to terminate. */
terminate_handler terminateHandler;
/**
* Next exception in the list. If an exception is thrown inside a catch
* block and caught in a nested catch, this points to the exception that
* will be handled after the inner catch block completes.
*/
__cxa_exception *nextException;
/**
* The number of handlers that currently have references to this
* exception. The top (non-sign) bit of this is used as a flag to indicate
* that the exception is being rethrown, so should not be deleted when its
* handler count reaches 0 (which it doesn't with the top bit set).
*/
int handlerCount;
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
/**
* The ARM EH ABI requires the unwind library to keep track of exceptions
* during cleanups. These support nesting, so we need to keep a list of
* them.
*/
_Unwind_Exception *nextCleanup;
/**
* The number of cleanups that are currently being run on this exception.
*/
int cleanupCount;
#endif
/**
* The selector value to be returned when installing the catch handler.
* Used at the call site to determine which catch() block should execute.
* This is found in phase 1 of unwinding then installed in phase 2.
*/
int handlerSwitchValue;
/**
* The action record for the catch. This is cached during phase 1
* unwinding.
*/
const char *actionRecord;
/**
* Pointer to the language-specific data area (LSDA) for the handler
* frame. This is unused in this implementation, but set for ABI
* compatibility in case we want to mix code in very weird ways.
*/
const char *languageSpecificData;
/** The cached landing pad for the catch handler.*/
void *catchTemp;
/**
* The pointer that will be returned as the pointer to the object. When
* throwing a class and catching a virtual superclass (for example), we
* need to adjust the thrown pointer to make it all work correctly.
*/
void *adjustedPtr;
#if !__LP64__
/**
* Reference count. Used to support the C++11 exception_ptr class. This
* is prepended to the structure in 64-bit mode and squeezed in to the
* padding left before the 64-bit aligned _Unwind_Exception at the end in
* 32-bit mode.
*
* Note that it is safe to extend this structure at the beginning, rather
* than the end, because the public API for creating it returns the address
* of the end (where the exception object can be stored)
*/
uintptr_t referenceCount;
#endif
/** The language-agnostic part of the exception header. */
_Unwind_Exception unwindHeader;
};
/**
* ABI-specified globals structure. Returned by the __cxa_get_globals()
* function and its fast variant. This is a per-thread structure - every
* thread will have one lazily allocated.
*
* This structure is defined by the ABI, so may be used outside of this
* library.
*/
struct __cxa_eh_globals
{
/**
* A linked list of exceptions that are currently caught. There may be
* several of these in nested catch() blocks.
*/
__cxa_exception *caughtExceptions;
/**
* The number of uncaught exceptions.
*/
unsigned int uncaughtExceptions;
};
/**
* ABI function returning the __cxa_eh_globals structure.
*/
__cxa_eh_globals *__cxa_get_globals(void);
/**
* Version of __cxa_get_globals() assuming that __cxa_get_globals() has already
* been called at least once by this thread.
*/
__cxa_eh_globals *__cxa_get_globals_fast(void);
std::type_info * __cxa_current_exception_type();
/**
* Throws an exception returned by __cxa_current_primary_exception(). This
* exception may have been caught in another thread.
*/
void __cxa_rethrow_primary_exception(void* thrown_exception);
/**
* Returns the current exception in a form that can be stored in an
* exception_ptr object and then rethrown by a call to
* __cxa_rethrow_primary_exception().
*/
void *__cxa_current_primary_exception(void);
/**
* Increments the reference count of an exception. Called when an
* exception_ptr is copied.
*/
void __cxa_increment_exception_refcount(void* thrown_exception);
/**
* Decrements the reference count of an exception. Called when an
* exception_ptr is deleted.
*/
void __cxa_decrement_exception_refcount(void* thrown_exception);
/**
* Demangles a C++ symbol or type name. The buffer, if non-NULL, must be
* allocated with malloc() and must be *n bytes or more long. This function
* may call realloc() on the value pointed to by buf, and will return the
* length of the string via *n.
*
* The value pointed to by status is set to one of the following:
*
* 0: success
* -1: memory allocation failure
* -2: invalid mangled name
* -3: invalid arguments
*/
char* __cxa_demangle(const char* mangled_name,
char* buf,
size_t* n,
int* status);
#ifdef __cplusplus
} // extern "C"
} // namespace
namespace abi = __cxxabiv1;
#endif /* __cplusplus */
#endif /* __CXXABI_H_ */

View File

@ -0,0 +1,477 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* dwarf_eh.h - Defines some helper functions for parsing DWARF exception
* handling tables.
*
* This file contains various helper functions that are independent of the
* language-specific code. It can be used in any personality function for the
* Itanium ABI.
*/
#include <assert.h>
// TODO: Factor out Itanium / ARM differences. We probably want an itanium.h
// and arm.h that can be included by this file depending on the target ABI.
// _GNU_SOURCE must be defined for unwind.h to expose some of the functions
// that we want. If it isn't, then we define it and undefine it to make sure
// that it doesn't impact the rest of the program.
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
# include "unwind.h"
# undef _GNU_SOURCE
#else
# include "unwind.h"
#endif
#include <stdint.h>
/// Type used for pointers into DWARF data
typedef unsigned char *dw_eh_ptr_t;
// Flag indicating a signed quantity
#define DW_EH_PE_signed 0x08
/// DWARF data encoding types.
enum dwarf_data_encoding
{
/// Absolute pointer value
DW_EH_PE_absptr = 0x00,
/// Unsigned, little-endian, base 128-encoded (variable length).
DW_EH_PE_uleb128 = 0x01,
/// Unsigned 16-bit integer.
DW_EH_PE_udata2 = 0x02,
/// Unsigned 32-bit integer.
DW_EH_PE_udata4 = 0x03,
/// Unsigned 64-bit integer.
DW_EH_PE_udata8 = 0x04,
/// Signed, little-endian, base 128-encoded (variable length)
DW_EH_PE_sleb128 = DW_EH_PE_uleb128 | DW_EH_PE_signed,
/// Signed 16-bit integer.
DW_EH_PE_sdata2 = DW_EH_PE_udata2 | DW_EH_PE_signed,
/// Signed 32-bit integer.
DW_EH_PE_sdata4 = DW_EH_PE_udata4 | DW_EH_PE_signed,
/// Signed 32-bit integer.
DW_EH_PE_sdata8 = DW_EH_PE_udata8 | DW_EH_PE_signed
};
/**
* Returns the encoding for a DWARF EH table entry. The encoding is stored in
* the low four of an octet. The high four bits store the addressing mode.
*/
static inline enum dwarf_data_encoding get_encoding(unsigned char x)
{
return static_cast<enum dwarf_data_encoding>(x & 0xf);
}
/**
* DWARF addressing mode constants. When reading a pointer value from a DWARF
* exception table, you must know how it is stored and what the addressing mode
* is. The low four bits tell you the encoding, allowing you to decode a
* number. The high four bits tell you the addressing mode, allowing you to
* turn that number into an address in memory.
*/
enum dwarf_data_relative
{
/// Value is omitted
DW_EH_PE_omit = 0xff,
/// Value relative to program counter
DW_EH_PE_pcrel = 0x10,
/// Value relative to the text segment
DW_EH_PE_textrel = 0x20,
/// Value relative to the data segment
DW_EH_PE_datarel = 0x30,
/// Value relative to the start of the function
DW_EH_PE_funcrel = 0x40,
/// Aligned pointer (Not supported yet - are they actually used?)
DW_EH_PE_aligned = 0x50,
/// Pointer points to address of real value
DW_EH_PE_indirect = 0x80
};
/**
* Returns the addressing mode component of this encoding.
*/
static inline enum dwarf_data_relative get_base(unsigned char x)
{
return static_cast<enum dwarf_data_relative>(x & 0x70);
}
/**
* Returns whether an encoding represents an indirect address.
*/
static int is_indirect(unsigned char x)
{
return ((x & DW_EH_PE_indirect) == DW_EH_PE_indirect);
}
/**
* Returns the size of a fixed-size encoding. This function will abort if
* called with a value that is not a fixed-size encoding.
*/
static inline int dwarf_size_of_fixed_size_field(unsigned char type)
{
switch (get_encoding(type))
{
default: abort();
case DW_EH_PE_sdata2:
case DW_EH_PE_udata2: return 2;
case DW_EH_PE_sdata4:
case DW_EH_PE_udata4: return 4;
case DW_EH_PE_sdata8:
case DW_EH_PE_udata8: return 8;
case DW_EH_PE_absptr: return sizeof(void*);
}
}
/**
* Read an unsigned, little-endian, base-128, DWARF value. Updates *data to
* point to the end of the value. Stores the number of bits read in the value
* pointed to by b, allowing you to determine the value of the highest bit, and
* therefore the sign of a signed value.
*
* This function is not intended to be called directly. Use read_sleb128() or
* read_uleb128() for reading signed and unsigned versions, respectively.
*/
static uint64_t read_leb128(dw_eh_ptr_t *data, int *b)
{
uint64_t uleb = 0;
unsigned int bit = 0;
unsigned char digit = 0;
// We have to read at least one octet, and keep reading until we get to one
// with the high bit unset
do
{
// This check is a bit too strict - we should also check the highest
// bit of the digit.
assert(bit < sizeof(uint64_t) * 8);
// Get the base 128 digit
digit = (**data) & 0x7f;
// Add it to the current value
uleb += digit << bit;
// Increase the shift value
bit += 7;
// Proceed to the next octet
(*data)++;
// Terminate when we reach a value that does not have the high bit set
// (i.e. which was not modified when we mask it with 0x7f)
} while ((*(*data - 1)) != digit);
*b = bit;
return uleb;
}
/**
* Reads an unsigned little-endian base-128 value starting at the address
* pointed to by *data. Updates *data to point to the next byte after the end
* of the variable-length value.
*/
static int64_t read_uleb128(dw_eh_ptr_t *data)
{
int b;
return read_leb128(data, &b);
}
/**
* Reads a signed little-endian base-128 value starting at the address pointed
* to by *data. Updates *data to point to the next byte after the end of the
* variable-length value.
*/
static int64_t read_sleb128(dw_eh_ptr_t *data)
{
int bits;
// Read as if it's signed
uint64_t uleb = read_leb128(data, &bits);
// If the most significant bit read is 1, then we need to sign extend it
if ((uleb >> (bits-1)) == 1)
{
// Sign extend by setting all bits in front of it to 1
uleb |= static_cast<int64_t>(-1) << bits;
}
return static_cast<int64_t>(uleb);
}
/**
* Reads a value using the specified encoding from the address pointed to by
* *data. Updates the value of *data to point to the next byte after the end
* of the data.
*/
static uint64_t read_value(char encoding, dw_eh_ptr_t *data)
{
enum dwarf_data_encoding type = get_encoding(encoding);
switch (type)
{
// Read fixed-length types
#define READ(dwarf, type) \
case dwarf:\
{\
type t;\
memcpy(&t, *data, sizeof t);\
*data += sizeof t;\
return static_cast<uint64_t>(t);\
}
READ(DW_EH_PE_udata2, uint16_t)
READ(DW_EH_PE_udata4, uint32_t)
READ(DW_EH_PE_udata8, uint64_t)
READ(DW_EH_PE_sdata2, int16_t)
READ(DW_EH_PE_sdata4, int32_t)
READ(DW_EH_PE_sdata8, int64_t)
READ(DW_EH_PE_absptr, intptr_t)
#undef READ
// Read variable-length types
case DW_EH_PE_sleb128:
return read_sleb128(data);
case DW_EH_PE_uleb128:
return read_uleb128(data);
default: abort();
}
}
/**
* Resolves an indirect value. This expects an unwind context, an encoding, a
* decoded value, and the start of the region as arguments. The returned value
* is a pointer to the address identified by the encoded value.
*
* If the encoding does not specify an indirect value, then this returns v.
*/
static uint64_t resolve_indirect_value(_Unwind_Context *c,
unsigned char encoding,
int64_t v,
dw_eh_ptr_t start)
{
switch (get_base(encoding))
{
case DW_EH_PE_pcrel:
v += reinterpret_cast<uint64_t>(start);
break;
case DW_EH_PE_textrel:
v += static_cast<uint64_t>(static_cast<uintptr_t>(_Unwind_GetTextRelBase(c)));
break;
case DW_EH_PE_datarel:
v += static_cast<uint64_t>(static_cast<uintptr_t>(_Unwind_GetDataRelBase(c)));
break;
case DW_EH_PE_funcrel:
v += static_cast<uint64_t>(static_cast<uintptr_t>(_Unwind_GetRegionStart(c)));
default:
break;
}
// If this is an indirect value, then it is really the address of the real
// value
// TODO: Check whether this should really always be a pointer - it seems to
// be a GCC extensions, so not properly documented...
if (is_indirect(encoding))
{
v = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(v)));
}
return v;
}
/**
* Reads an encoding and a value, updating *data to point to the next byte.
*/
static inline void read_value_with_encoding(_Unwind_Context *context,
dw_eh_ptr_t *data,
uint64_t *out)
{
dw_eh_ptr_t start = *data;
unsigned char encoding = *((*data)++);
// If this value is omitted, skip it and don't touch the output value
if (encoding == DW_EH_PE_omit) { return; }
*out = read_value(encoding, data);
*out = resolve_indirect_value(context, encoding, *out, start);
}
/**
* Structure storing a decoded language-specific data area. Use parse_lsda()
* to generate an instance of this structure from the address returned by the
* generic unwind library.
*
* You should not need to inspect the fields of this structure directly if you
* are just using this header. The structure stores the locations of the
* various tables used for unwinding exceptions and is used by the functions
* for reading values from these tables.
*/
struct dwarf_eh_lsda
{
/// The start of the region. This is a cache of the value returned by
/// _Unwind_GetRegionStart().
dw_eh_ptr_t region_start;
/// The start of the landing pads table.
dw_eh_ptr_t landing_pads;
/// The start of the type table.
dw_eh_ptr_t type_table;
/// The encoding used for entries in the type tables.
unsigned char type_table_encoding;
/// The location of the call-site table.
dw_eh_ptr_t call_site_table;
/// The location of the action table.
dw_eh_ptr_t action_table;
/// The encoding used for entries in the call-site table.
unsigned char callsite_encoding;
};
/**
* Parse the header on the language-specific data area and return a structure
* containing the addresses and encodings of the various tables.
*/
static inline struct dwarf_eh_lsda parse_lsda(_Unwind_Context *context,
unsigned char *data)
{
struct dwarf_eh_lsda lsda;
lsda.region_start = reinterpret_cast<dw_eh_ptr_t>(_Unwind_GetRegionStart(context));
// If the landing pads are relative to anything other than the start of
// this region, find out where. This is @LPStart in the spec, although the
// encoding that GCC uses does not quite match the spec.
uint64_t v = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(lsda.region_start));
read_value_with_encoding(context, &data, &v);
lsda.landing_pads = reinterpret_cast<dw_eh_ptr_t>(static_cast<uintptr_t>(v));
// If there is a type table, find out where it is. This is @TTBase in the
// spec. Note: we find whether there is a type table pointer by checking
// whether the leading byte is DW_EH_PE_omit (0xff), which is not what the
// spec says, but does seem to be how G++ indicates this.
lsda.type_table = 0;
lsda.type_table_encoding = *data++;
if (lsda.type_table_encoding != DW_EH_PE_omit)
{
v = read_uleb128(&data);
dw_eh_ptr_t type_table = data;
type_table += v;
lsda.type_table = type_table;
//lsda.type_table = (uintptr_t*)(data + v);
}
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
lsda.type_table_encoding = (DW_EH_PE_pcrel | DW_EH_PE_indirect);
#endif
lsda.callsite_encoding = static_cast<enum dwarf_data_encoding>(*(data++));
// Action table is immediately after the call site table
lsda.action_table = data;
uintptr_t callsite_size = static_cast<uintptr_t>(read_uleb128(&data));
lsda.action_table = data + callsite_size;
// Call site table is immediately after the header
lsda.call_site_table = static_cast<dw_eh_ptr_t>(data);
return lsda;
}
/**
* Structure representing an action to be performed while unwinding. This
* contains the address that should be unwound to and the action record that
* provoked this action.
*/
struct dwarf_eh_action
{
/**
* The address that this action directs should be the new program counter
* value after unwinding.
*/
dw_eh_ptr_t landing_pad;
/// The address of the action record.
dw_eh_ptr_t action_record;
};
/**
* Look up the landing pad that corresponds to the current invoke.
* Returns true if record exists. The context is provided by the generic
* unwind library and the lsda should be the result of a call to parse_lsda().
*
* The action record is returned via the result parameter.
*/
static bool dwarf_eh_find_callsite(struct _Unwind_Context *context,
struct dwarf_eh_lsda *lsda,
struct dwarf_eh_action *result)
{
result->action_record = 0;
result->landing_pad = 0;
// The current instruction pointer offset within the region
uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context);
unsigned char *callsite_table = static_cast<unsigned char*>(lsda->call_site_table);
while (callsite_table <= lsda->action_table)
{
// Once again, the layout deviates from the spec.
uint64_t call_site_start, call_site_size, landing_pad, action;
call_site_start = read_value(lsda->callsite_encoding, &callsite_table);
call_site_size = read_value(lsda->callsite_encoding, &callsite_table);
// Call site entries are sorted, so if we find a call site that's after
// the current instruction pointer then there is no action associated
// with this call and we should unwind straight through this frame
// without doing anything.
if (call_site_start > ip) { break; }
// Read the address of the landing pad and the action from the call
// site table.
landing_pad = read_value(lsda->callsite_encoding, &callsite_table);
action = read_uleb128(&callsite_table);
// We should not include the call_site_start (beginning of the region)
// address in the ip range. For each call site:
//
// address1: call proc
// address2: next instruction
//
// The call stack contains address2 and not address1, address1 can be
// at the end of another EH region.
if (call_site_start < ip && ip <= call_site_start + call_site_size)
{
if (action)
{
// Action records are 1-biased so both no-record and zeroth
// record can be stored.
result->action_record = lsda->action_table + action - 1;
}
// No landing pad means keep unwinding.
if (landing_pad)
{
// Landing pad is the offset from the value in the header
result->landing_pad = lsda->landing_pads + landing_pad;
}
return true;
}
}
return false;
}
/// Defines an exception class from 8 bytes (endian independent)
#define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) \
((static_cast<uint64_t>(a) << 56) +\
(static_cast<uint64_t>(b) << 48) +\
(static_cast<uint64_t>(c) << 40) +\
(static_cast<uint64_t>(d) << 32) +\
(static_cast<uint64_t>(e) << 24) +\
(static_cast<uint64_t>(f) << 16) +\
(static_cast<uint64_t>(g) << 8) +\
(static_cast<uint64_t>(h)))
#define GENERIC_EXCEPTION_CLASS(e,f,g,h) \
(static_cast<uint32_t>(e) << 24) +\
(static_cast<uint32_t>(f) << 16) +\
(static_cast<uint32_t>(g) << 8) +\
(static_cast<uint32_t>(h))

View File

@ -0,0 +1,210 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "typeinfo.h"
#include <stdio.h>
using namespace ABI_NAMESPACE;
/**
* Vtable header.
*/
struct vtable_header
{
/** Offset of the leaf object. */
ptrdiff_t leaf_offset;
/** Type of the object. */
const __class_type_info *type;
};
/**
* Simple macro that does pointer arithmetic in bytes but returns a value of
* the same type as the original.
*/
#define ADD_TO_PTR(x, off) reinterpret_cast<__typeof__(x)>(reinterpret_cast<char*>(x) + off)
bool std::type_info::__do_catch(std::type_info const *ex_type,
void **exception_object,
unsigned int outer) const
{
const type_info *type = this;
if (type == ex_type)
{
return true;
}
if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type))
{
return ex_type->__do_upcast(cti, exception_object);
}
return false;
}
bool __pbase_type_info::__do_catch(std::type_info const *ex_type,
void **exception_object,
unsigned int outer) const
{
if (ex_type == this)
{
return true;
}
if (!ex_type->__is_pointer_p())
{
// Can't catch a non-pointer type in a pointer catch
return false;
}
if (!(outer & 1))
{
// If the low bit is cleared on this means that we've gone
// through a pointer that is not const qualified.
return false;
}
// Clear the low bit on outer if we're not const qualified.
if (!(__flags & __const_mask))
{
outer &= ~1;
}
const __pbase_type_info *ptr_type =
static_cast<const __pbase_type_info*>(ex_type);
if (ptr_type->__flags & ~__flags)
{
// Handler pointer is less qualified
return false;
}
// Special case for void* handler.
if(*__pointee == typeid(void))
{
return true;
}
return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer);
}
void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
if (this == other)
{
return obj;
}
return 0;
}
void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
if (this == other)
{
return obj;
}
return __base_type->cast_to(obj, other);
}
bool __si_class_type_info::__do_upcast(const __class_type_info *target,
void **thrown_object) const
{
if (this == target)
{
return true;
}
return __base_type->__do_upcast(target, thrown_object);
}
void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
if (__do_upcast(other, &obj))
{
return obj;
}
return 0;
}
bool __vmi_class_type_info::__do_upcast(const __class_type_info *target,
void **thrown_object) const
{
if (this == target)
{
return true;
}
for (unsigned int i=0 ; i<__base_count ; i++)
{
const __base_class_type_info *info = &__base_info[i];
ptrdiff_t offset = info->offset();
// If this is a virtual superclass, the offset is stored in the
// object's vtable at the offset requested; 2.9.5.6.c:
//
// 'For a non-virtual base, this is the offset in the object of the
// base subobject. For a virtual base, this is the offset in the
// virtual table of the virtual base offset for the virtual base
// referenced (negative).'
void *obj = *thrown_object;
if (info->isVirtual())
{
// Object's vtable
ptrdiff_t *off = *static_cast<ptrdiff_t**>(obj);
// Offset location in vtable
off = ADD_TO_PTR(off, offset);
offset = *off;
}
void *cast = ADD_TO_PTR(obj, offset);
if (info->__base_type == target ||
(info->__base_type->__do_upcast(target, &cast)))
{
*thrown_object = cast;
return true;
}
}
return 0;
}
/**
* ABI function used to implement the dynamic_cast<> operator. Some cases of
* this operator are implemented entirely in the compiler (e.g. to void*).
* This function implements the dynamic casts of the form dynamic_cast<T>(v).
* This will be translated to a call to this function with the value v as the
* first argument. The type id of the static type of v is the second argument
* and the type id of the destination type (T) is the third argument.
*
* The third argument is a hint about the compiler's guess at the correct
* pointer offset. If this value is negative, then -1 indicates no hint, -2
* that src is not a public base of dst, and -3 that src is a multiple public
* base type but never a virtual base type
*/
extern "C" void* __dynamic_cast(const void *sub,
const __class_type_info *src,
const __class_type_info *dst,
ptrdiff_t src2dst_offset)
{
const char *vtable_location = *static_cast<const char * const *>(sub);
const vtable_header *header =
reinterpret_cast<const vtable_header*>(vtable_location - sizeof(vtable_header));
void *leaf = ADD_TO_PTR(const_cast<void *>(sub), header->leaf_offset);
return header->type->cast_to(leaf, dst);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
/*
* Copyright 2010-2012 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* guard.cc: Functions for thread-safe static initialisation.
*
* Static values in C++ can be initialised lazily their first use. This file
* contains functions that are used to ensure that two threads attempting to
* initialize the same static do not call the constructor twice. This is
* important because constructors can have side effects, so calling the
* constructor twice may be very bad.
*
* Statics that require initialisation are protected by a 64-bit value. Any
* platform that can do 32-bit atomic test and set operations can use this
* value as a low-overhead lock. Because statics (in most sane code) are
* accessed far more times than they are initialised, this lock implementation
* is heavily optimised towards the case where the static has already been
* initialised.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include "atomic.h"
// Older GCC doesn't define __LITTLE_ENDIAN__
#ifndef __LITTLE_ENDIAN__
// If __BYTE_ORDER__ is defined, use that instead
# ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define __LITTLE_ENDIAN__
# endif
// x86 and ARM are the most common little-endian CPUs, so let's have a
// special case for them (ARM is already special cased). Assume everything
// else is big endian.
# elif defined(__x86_64) || defined(__i386)
# define __LITTLE_ENDIAN__
# endif
#endif
/*
* The least significant bit of the guard variable indicates that the object
* has been initialised, the most significant bit is used for a spinlock.
*/
#ifdef __arm__
// ARM ABI - 32-bit guards.
typedef uint32_t guard_t;
typedef uint32_t guard_lock_t;
static const uint32_t LOCKED = static_cast<guard_t>(1) << 31;
static const uint32_t INITIALISED = 1;
#define LOCK_PART(guard) (guard)
#define INIT_PART(guard) (guard)
#elif defined(_LP64)
typedef uint64_t guard_t;
typedef uint64_t guard_lock_t;
# if defined(__LITTLE_ENDIAN__)
static const guard_t LOCKED = static_cast<guard_t>(1) << 63;
static const guard_t INITIALISED = 1;
# else
static const guard_t LOCKED = 1;
static const guard_t INITIALISED = static_cast<guard_t>(1) << 56;
# endif
#define LOCK_PART(guard) (guard)
#define INIT_PART(guard) (guard)
#else
typedef uint32_t guard_lock_t;
# if defined(__LITTLE_ENDIAN__)
typedef struct {
uint32_t init_half;
uint32_t lock_half;
} guard_t;
static const uint32_t LOCKED = static_cast<guard_lock_t>(1) << 31;
static const uint32_t INITIALISED = 1;
# else
typedef struct {
uint32_t init_half;
uint32_t lock_half;
} guard_t;
static_assert(sizeof(guard_t) == sizeof(uint64_t), "");
static const uint32_t LOCKED = 1;
static const uint32_t INITIALISED = static_cast<guard_lock_t>(1) << 24;
# endif
#define LOCK_PART(guard) (&(guard)->lock_half)
#define INIT_PART(guard) (&(guard)->init_half)
#endif
static const guard_lock_t INITIAL = 0;
/**
* Acquires a lock on a guard, returning 0 if the object has already been
* initialised, and 1 if it has not. If the object is already constructed then
* this function just needs to read a byte from memory and return.
*/
extern "C" int __cxa_guard_acquire(volatile guard_t *guard_object)
{
guard_lock_t old;
// Not an atomic read, doesn't establish a happens-before relationship, but
// if one is already established and we end up seeing an initialised state
// then it's a fast path, otherwise we'll do something more expensive than
// this test anyway...
if (INITIALISED == *INIT_PART(guard_object))
return 0;
// Spin trying to do the initialisation
for (;;)
{
// Loop trying to move the value of the guard from 0 (not
// locked, not initialised) to the locked-uninitialised
// position.
old = __sync_val_compare_and_swap(LOCK_PART(guard_object),
INITIAL, LOCKED);
if (old == INITIAL) {
// Lock obtained. If lock and init bit are
// in separate words, check for init race.
if (INIT_PART(guard_object) == LOCK_PART(guard_object))
return 1;
if (INITIALISED != *INIT_PART(guard_object))
return 1;
// No need for a memory barrier here,
// see first comment.
*LOCK_PART(guard_object) = INITIAL;
return 0;
}
// If lock and init bit are in the same word, check again
// if we are done.
if (INIT_PART(guard_object) == LOCK_PART(guard_object) &&
old == INITIALISED)
return 0;
assert(old == LOCKED);
// Another thread holds the lock.
// If lock and init bit are in different words, check
// if we are done before yielding and looping.
if (INIT_PART(guard_object) != LOCK_PART(guard_object) &&
INITIALISED == *INIT_PART(guard_object))
return 0;
sched_yield();
}
}
/**
* Releases the lock without marking the object as initialised. This function
* is called if initialising a static causes an exception to be thrown.
*/
extern "C" void __cxa_guard_abort(volatile guard_t *guard_object)
{
__attribute__((unused))
bool reset = __sync_bool_compare_and_swap(LOCK_PART(guard_object),
LOCKED, INITIAL);
assert(reset);
}
/**
* Releases the guard and marks the object as initialised. This function is
* called after successful initialisation of a static.
*/
extern "C" void __cxa_guard_release(volatile guard_t *guard_object)
{
guard_lock_t old;
if (INIT_PART(guard_object) == LOCK_PART(guard_object))
old = LOCKED;
else
old = INITIAL;
__attribute__((unused))
bool reset = __sync_bool_compare_and_swap(INIT_PART(guard_object),
old, INITIALISED);
assert(reset);
if (INIT_PART(guard_object) != LOCK_PART(guard_object))
*LOCK_PART(guard_object) = INITIAL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,171 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* memory.cc - Contains stub definition of C++ new/delete operators.
*
* These definitions are intended to be used for testing and are weak symbols
* to allow them to be replaced by definitions from a STL implementation.
* These versions simply wrap malloc() and free(), they do not provide a
* C++-specific allocator.
*/
#include <stddef.h>
#include <stdlib.h>
#include "stdexcept.h"
#include "atomic.h"
namespace std
{
struct nothrow_t {};
}
/// The type of the function called when allocation fails.
typedef void (*new_handler)();
/**
* The function to call when allocation fails. By default, there is no
* handler and a bad allocation exception is thrown if an allocation fails.
*/
static new_handler new_handl;
namespace std
{
/**
* Sets a function to be called when there is a failure in new.
*/
__attribute__((weak))
new_handler set_new_handler(new_handler handler)
{
return ATOMIC_SWAP(&new_handl, handler);
}
__attribute__((weak))
new_handler get_new_handler(void)
{
return ATOMIC_LOAD(&new_handl);
}
}
#if __cplusplus < 201103L
#define NOEXCEPT throw()
#define BADALLOC throw(std::bad_alloc)
#else
#define NOEXCEPT noexcept
#define BADALLOC
#endif
__attribute__((weak))
void* operator new(size_t size) BADALLOC
{
if (0 == size)
{
size = 1;
}
void * mem = malloc(size);
while (0 == mem)
{
new_handler h = std::get_new_handler();
if (0 != h)
{
h();
}
else
{
throw std::bad_alloc();
}
mem = malloc(size);
}
return mem;
}
__attribute__((weak))
void* operator new(size_t size, const std::nothrow_t &) NOEXCEPT
{
try {
return :: operator new(size);
} catch (...) {
// nothrow operator new should return NULL in case of
// std::bad_alloc exception in new handler
return NULL;
}
}
__attribute__((weak))
void operator delete(void * ptr) NOEXCEPT
{
free(ptr);
}
__attribute__((weak))
void * operator new[](size_t size) BADALLOC
{
return ::operator new(size);
}
__attribute__((weak))
void * operator new[](size_t size, const std::nothrow_t &) NOEXCEPT
{
try {
return ::operator new[](size);
} catch (...) {
// nothrow operator new should return NULL in case of
// std::bad_alloc exception in new handler
return NULL;
}
}
__attribute__((weak))
void operator delete[](void * ptr) NOEXCEPT
{
::operator delete(ptr);
}
// C++14 additional delete operators
#if __cplusplus >= 201402L
__attribute__((weak))
void operator delete(void * ptr, size_t) NOEXCEPT
{
::operator delete(ptr);
}
__attribute__((weak))
void operator delete[](void * ptr, size_t) NOEXCEPT
{
::operator delete(ptr);
}
#endif

View File

@ -0,0 +1,99 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* stdexcept.cc - provides stub implementations of the exceptions required by the runtime.
*/
#include "stdexcept.h"
namespace std {
exception::exception() throw() {}
exception::~exception() {}
exception::exception(const exception&) throw() {}
exception& exception::operator=(const exception&) throw()
{
return *this;
}
const char* exception::what() const throw()
{
return "std::exception";
}
bad_alloc::bad_alloc() throw() {}
bad_alloc::~bad_alloc() {}
bad_alloc::bad_alloc(const bad_alloc&) throw() {}
bad_alloc& bad_alloc::operator=(const bad_alloc&) throw()
{
return *this;
}
const char* bad_alloc::what() const throw()
{
return "cxxrt::bad_alloc";
}
bad_cast::bad_cast() throw() {}
bad_cast::~bad_cast() {}
bad_cast::bad_cast(const bad_cast&) throw() {}
bad_cast& bad_cast::operator=(const bad_cast&) throw()
{
return *this;
}
const char* bad_cast::what() const throw()
{
return "std::bad_cast";
}
bad_typeid::bad_typeid() throw() {}
bad_typeid::~bad_typeid() {}
bad_typeid::bad_typeid(const bad_typeid &__rhs) throw() {}
bad_typeid& bad_typeid::operator=(const bad_typeid &__rhs) throw()
{
return *this;
}
const char* bad_typeid::what() const throw()
{
return "std::bad_typeid";
}
bad_array_new_length::bad_array_new_length() throw() {}
bad_array_new_length::~bad_array_new_length() {}
bad_array_new_length::bad_array_new_length(const bad_array_new_length&) throw() {}
bad_array_new_length& bad_array_new_length::operator=(const bad_array_new_length&) throw()
{
return *this;
}
const char* bad_array_new_length::what() const throw()
{
return "std::bad_array_new_length";
}
} // namespace std

View File

@ -0,0 +1,96 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* stdexcept.h - provides a stub version of <stdexcept>, which defines enough
* of the exceptions for the runtime to use.
*/
namespace std
{
class exception
{
public:
exception() throw();
exception(const exception&) throw();
exception& operator=(const exception&) throw();
virtual ~exception();
virtual const char* what() const throw();
};
/**
* Bad allocation exception. Thrown by ::operator new() if it fails.
*/
class bad_alloc: public exception
{
public:
bad_alloc() throw();
bad_alloc(const bad_alloc&) throw();
bad_alloc& operator=(const bad_alloc&) throw();
~bad_alloc();
virtual const char* what() const throw();
};
/**
* Bad cast exception. Thrown by the __cxa_bad_cast() helper function.
*/
class bad_cast: public exception {
public:
bad_cast() throw();
bad_cast(const bad_cast&) throw();
bad_cast& operator=(const bad_cast&) throw();
virtual ~bad_cast();
virtual const char* what() const throw();
};
/**
* Bad typeidexception. Thrown by the __cxa_bad_typeid() helper function.
*/
class bad_typeid: public exception
{
public:
bad_typeid() throw();
bad_typeid(const bad_typeid &__rhs) throw();
virtual ~bad_typeid();
bad_typeid& operator=(const bad_typeid &__rhs) throw();
virtual const char* what() const throw();
};
class bad_array_new_length: public bad_alloc
{
public:
bad_array_new_length() throw();
bad_array_new_length(const bad_array_new_length&) throw();
bad_array_new_length& operator=(const bad_array_new_length&) throw();
virtual ~bad_array_new_length();
virtual const char *what() const throw();
};
} // namespace std

View File

@ -0,0 +1,40 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
namespace std
{
/**
* Stub implementation of std::terminate. Used when the STL implementation
* doesn't provide one.
*/
__attribute__((weak))
void terminate()
{
abort();
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright 2010-2012 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "typeinfo.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using std::type_info;
type_info::~type_info() {}
bool type_info::operator==(const type_info &other) const
{
return __type_name == other.__type_name;
}
bool type_info::operator!=(const type_info &other) const
{
return __type_name != other.__type_name;
}
bool type_info::before(const type_info &other) const
{
return __type_name < other.__type_name;
}
const char* type_info::name() const
{
return __type_name;
}
type_info::type_info (const type_info& rhs)
{
__type_name = rhs.__type_name;
}
type_info& type_info::operator= (const type_info& rhs)
{
return *new type_info(rhs);
}
ABI_NAMESPACE::__fundamental_type_info::~__fundamental_type_info() {}
ABI_NAMESPACE::__array_type_info::~__array_type_info() {}
ABI_NAMESPACE::__function_type_info::~__function_type_info() {}
ABI_NAMESPACE::__enum_type_info::~__enum_type_info() {}
ABI_NAMESPACE::__class_type_info::~__class_type_info() {}
ABI_NAMESPACE::__si_class_type_info::~__si_class_type_info() {}
ABI_NAMESPACE::__vmi_class_type_info::~__vmi_class_type_info() {}
ABI_NAMESPACE::__pbase_type_info::~__pbase_type_info() {}
ABI_NAMESPACE::__pointer_type_info::~__pointer_type_info() {}
ABI_NAMESPACE::__pointer_to_member_type_info::~__pointer_to_member_type_info() {}
// From libelftc
extern "C" char *__cxa_demangle_gnu3(const char *);
extern "C" char* __cxa_demangle(const char* mangled_name,
char* buf,
size_t* n,
int* status)
{
// TODO: We should probably just be linking against libelf-tc, rather than
// copying their code. This requires them to do an actual release,
// however, and for our changes to be pushed upstream. We also need to
// call a different demangling function here depending on the ABI (e.g.
// ARM).
char *demangled = __cxa_demangle_gnu3(mangled_name);
if (NULL != demangled)
{
size_t len = strlen(demangled);
if (!buf || (*n < len+1))
{
buf = static_cast<char*>(realloc(buf, len+1));
}
if (0 != buf)
{
memcpy(buf, demangled, len);
buf[len] = 0;
if (n)
{
*n = len;
}
if (status)
{
*status = 0;
}
}
else
{
if (status)
{
*status = -1;
}
}
free(demangled);
}
else
{
if (status)
{
*status = -2;
}
return NULL;
}
return buf;
}

View File

@ -0,0 +1,313 @@
/*
* Copyright 2010-2011 PathScale, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include "abi_namespace.h"
namespace ABI_NAMESPACE
{
struct __class_type_info;
}
namespace std
{
/**
* Standard type info class. The layout of this class is specified by the
* ABI. The layout of the vtable is not, but is intended to be
* compatible with the GNU ABI.
*
* Unlike the GNU version, the vtable layout is considered semi-private.
*/
class type_info
{
public:
/**
* Virtual destructor. This class must have one virtual function to
* ensure that it has a vtable.
*/
virtual ~type_info();
bool operator==(const type_info &) const;
bool operator!=(const type_info &) const;
bool before(const type_info &) const;
const char* name() const;
type_info();
private:
type_info(const type_info& rhs);
type_info& operator= (const type_info& rhs);
const char *__type_name;
/*
* The following functions are in this order to match the
* vtable layout of libsupc++. This allows libcxxrt to be used
* with libraries that depend on this.
*
* These functions are in the public headers for libstdc++, so
* we have to assume that someone will probably call them and
* expect them to work. Their names must also match the names used in
* libsupc++, so that code linking against this library can subclass
* type_info and correctly fill in the values in the vtables.
*/
public:
/**
* Returns true if this is some pointer type, false otherwise.
*/
virtual bool __is_pointer_p() const { return false; }
/**
* Returns true if this is some function type, false otherwise.
*/
virtual bool __is_function_p() const { return false; }
/**
* Catch function. Allows external libraries to implement
* their own basic types. This is used, for example, in the
* GNUstep Objective-C runtime to allow Objective-C types to be
* caught in G++ catch blocks.
*
* The outer parameter indicates the number of outer pointers
* in the high bits. The low bit indicates whether the
* pointers are const qualified.
*/
virtual bool __do_catch(const type_info *thrown_type,
void **thrown_object,
unsigned outer) const;
/**
* Performs an upcast. This is used in exception handling to
* cast from subclasses to superclasses. If the upcast is
* possible, it returns true and adjusts the pointer. If the
* upcast is not possible, it returns false and does not adjust
* the pointer.
*/
virtual bool __do_upcast(
const ABI_NAMESPACE::__class_type_info *target,
void **thrown_object) const
{
return false;
}
};
}
namespace ABI_NAMESPACE
{
/**
* Primitive type info, for intrinsic types.
*/
struct __fundamental_type_info : public std::type_info
{
virtual ~__fundamental_type_info();
};
/**
* Type info for arrays.
*/
struct __array_type_info : public std::type_info
{
virtual ~__array_type_info();
};
/**
* Type info for functions.
*/
struct __function_type_info : public std::type_info
{
virtual ~__function_type_info();
virtual bool __is_function_p() const { return true; }
};
/**
* Type info for enums.
*/
struct __enum_type_info : public std::type_info
{
virtual ~__enum_type_info();
};
/**
* Base class for class type info. Used only for tentative definitions.
*/
struct __class_type_info : public std::type_info
{
virtual ~__class_type_info();
/**
* Function implementing dynamic casts.
*/
virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
virtual bool __do_upcast(const __class_type_info *target,
void **thrown_object) const
{
return this == target;
}
};
/**
* Single-inheritance class type info. This is used for classes containing
* a single non-virtual base class at offset 0.
*/
struct __si_class_type_info : public __class_type_info
{
virtual ~__si_class_type_info();
const __class_type_info *__base_type;
virtual bool __do_upcast(
const ABI_NAMESPACE::__class_type_info *target,
void **thrown_object) const;
virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
};
/**
* Type info for base classes. Classes with multiple bases store an array
* of these, one for each superclass.
*/
struct __base_class_type_info
{
const __class_type_info *__base_type;
private:
/**
* The high __offset_shift bits of this store the (signed) offset
* of the base class. The low bits store flags from
* __offset_flags_masks.
*/
long __offset_flags;
/**
* Flags used in the low bits of __offset_flags.
*/
enum __offset_flags_masks
{
/** This base class is virtual. */
__virtual_mask = 0x1,
/** This base class is public. */
__public_mask = 0x2,
/** The number of bits reserved for flags. */
__offset_shift = 8
};
public:
/**
* Returns the offset of the base class.
*/
long offset() const
{
return __offset_flags >> __offset_shift;
}
/**
* Returns the flags.
*/
long flags() const
{
return __offset_flags & ((1 << __offset_shift) - 1);
}
/**
* Returns whether this is a public base class.
*/
bool isPublic() const { return flags() & __public_mask; }
/**
* Returns whether this is a virtual base class.
*/
bool isVirtual() const { return flags() & __virtual_mask; }
};
/**
* Type info for classes with virtual bases or multiple superclasses.
*/
struct __vmi_class_type_info : public __class_type_info
{
virtual ~__vmi_class_type_info();
/** Flags describing this class. Contains values from __flags_masks. */
unsigned int __flags;
/** The number of base classes. */
unsigned int __base_count;
/**
* Array of base classes - this actually has __base_count elements, not
* 1.
*/
__base_class_type_info __base_info[1];
/**
* Flags used in the __flags field.
*/
enum __flags_masks
{
/** The class has non-diamond repeated inheritance. */
__non_diamond_repeat_mask = 0x1,
/** The class is diamond shaped. */
__diamond_shaped_mask = 0x2
};
virtual bool __do_upcast(
const ABI_NAMESPACE::__class_type_info *target,
void **thrown_object) const;
virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
};
/**
* Base class used for both pointer and pointer-to-member type info.
*/
struct __pbase_type_info : public std::type_info
{
virtual ~__pbase_type_info();
/**
* Flags. Values from __masks.
*/
unsigned int __flags;
/**
* The type info for the pointee.
*/
const std::type_info *__pointee;
/**
* Masks used for qualifiers on the pointer.
*/
enum __masks
{
/** Pointer has const qualifier. */
__const_mask = 0x1,
/** Pointer has volatile qualifier. */
__volatile_mask = 0x2,
/** Pointer has restrict qualifier. */
__restrict_mask = 0x4,
/** Pointer points to an incomplete type. */
__incomplete_mask = 0x8,
/** Pointer is a pointer to a member of an incomplete class. */
__incomplete_class_mask = 0x10
};
virtual bool __do_catch(const type_info *thrown_type,
void **thrown_object,
unsigned outer) const;
};
/**
* Pointer type info.
*/
struct __pointer_type_info : public __pbase_type_info
{
virtual ~__pointer_type_info();
virtual bool __is_pointer_p() const { return true; }
};
/**
* Pointer to member type info.
*/
struct __pointer_to_member_type_info : public __pbase_type_info
{
virtual ~__pointer_to_member_type_info();
/**
* Pointer to the class containing this member.
*/
const __class_type_info *__context;
};
}

View File

@ -0,0 +1,229 @@
/*
* Copyright 2012 David Chisnall. All rights reserved.
*
* 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.
*/
/* For uint32_t and uint64_t */
#include <stdint.h>
/**
* ARM-specific unwind definitions. These are taken from the ARM EHABI
* specification.
*/
typedef enum
{
_URC_NO_REASON = 0,
_URC_OK = 0, /* operation completed successfully */
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8,
_URC_FAILURE = 9, /* unspecified failure of some kind */
_URC_FATAL_PHASE1_ERROR = _URC_FAILURE
} _Unwind_Reason_Code;
typedef uint32_t _Unwind_State;
#ifdef __clang__
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
static const _Unwind_State _US_ACTION_MASK = 3;
#else // GCC fails at knowing what a constant expression is
# define _US_VIRTUAL_UNWIND_FRAME 0
# define _US_UNWIND_FRAME_STARTING 1
# define _US_UNWIND_FRAME_RESUME 2
# define _US_ACTION_MASK 3
#endif
typedef struct _Unwind_Context _Unwind_Context;
typedef uint32_t _Unwind_EHT_Header;
struct _Unwind_Exception
{
uint64_t exception_class;
void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
/* Unwinder cache, private fields for the unwinder's use */
struct
{
uint32_t reserved1;
uint32_t reserved2;
uint32_t reserved3;
uint32_t reserved4;
uint32_t reserved5;
/* init reserved1 to 0, then don't touch */
} unwinder_cache;
/* Propagation barrier cache (valid after phase 1): */
struct
{
uint32_t sp;
uint32_t bitpattern[5];
} barrier_cache;
/* Cleanup cache (preserved over cleanup): */
struct
{
uint32_t bitpattern[4];
} cleanup_cache;
/* Pr cache (for pr's benefit): */
struct
{
/** function start address */
uint32_t fnstart;
/** pointer to EHT entry header word */
_Unwind_EHT_Header *ehtp;
/** additional data */
uint32_t additional;
uint32_t reserved1;
} pr_cache;
/** Force alignment of next item to 8-byte boundary */
long long int :0;
} __attribute__((__aligned__(8)));
/* Unwinding functions */
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
void _Unwind_Resume(struct _Unwind_Exception *ucbp);
void _Unwind_Complete(struct _Unwind_Exception *ucbp);
void _Unwind_DeleteException(struct _Unwind_Exception *ucbp);
void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context*);
typedef enum
{
_UVRSR_OK = 0,
_UVRSR_NOT_IMPLEMENTED = 1,
_UVRSR_FAILED = 2
} _Unwind_VRS_Result;
typedef enum
{
_UVRSC_CORE = 0,
_UVRSC_VFP = 1,
_UVRSC_WMMXD = 3,
_UVRSC_WMMXC = 4
} _Unwind_VRS_RegClass;
typedef enum
{
_UVRSD_UINT32 = 0,
_UVRSD_VFPX = 1,
_UVRSD_UINT64 = 3,
_UVRSD_FLOAT = 4,
_UVRSD_DOUBLE = 5
} _Unwind_VRS_DataRepresentation;
_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
_Unwind_VRS_RegClass regclass,
uint32_t regno,
_Unwind_VRS_DataRepresentation representation,
void *valuep);
_Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
_Unwind_VRS_RegClass regclass,
uint32_t regno,
_Unwind_VRS_DataRepresentation representation,
void *valuep);
/* Return the base-address for data references. */
extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *);
/* Return the base-address for text references. */
extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *);
extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *);
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
void *);
extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
extern _Unwind_Reason_Code
_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
/**
* The next set of functions are compatibility extensions, implementing Itanium
* ABI functions on top of ARM ones.
*/
#define _UA_SEARCH_PHASE 1
#define _UA_CLEANUP_PHASE 2
#define _UA_HANDLER_FRAME 4
#define _UA_FORCE_UNWIND 8
static inline unsigned long _Unwind_GetGR(struct _Unwind_Context *context, int reg)
{
unsigned long val;
_Unwind_VRS_Get(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
return val;
}
static inline void _Unwind_SetGR(struct _Unwind_Context *context, int reg, unsigned long val)
{
_Unwind_VRS_Set(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
}
static inline unsigned long _Unwind_GetIP(_Unwind_Context *context)
{
// Low bit store the thumb state - discard it
return _Unwind_GetGR(context, 15) & ~1;
}
static inline void _Unwind_SetIP(_Unwind_Context *context, unsigned long val)
{
// The lowest bit of the instruction pointer indicates whether we're in
// thumb or ARM mode. This is assumed to be fixed throughout a function,
// so must be propagated when setting the program counter.
unsigned long thumbState = _Unwind_GetGR(context, 15) & 1;
_Unwind_SetGR(context, 15, (val | thumbState));
}
/** GNU API function that unwinds the frame */
_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception*, struct _Unwind_Context*);
#define DECLARE_PERSONALITY_FUNCTION(name) \
_Unwind_Reason_Code name(_Unwind_State state,\
struct _Unwind_Exception *exceptionObject,\
struct _Unwind_Context *context);
#define BEGIN_PERSONALITY_FUNCTION(name) \
_Unwind_Reason_Code name(_Unwind_State state,\
struct _Unwind_Exception *exceptionObject,\
struct _Unwind_Context *context)\
{\
int version = 1;\
uint64_t exceptionClass = exceptionObject->exception_class;\
int actions;\
switch (state)\
{\
default: return _URC_FAILURE;\
case _US_VIRTUAL_UNWIND_FRAME:\
{\
actions = _UA_SEARCH_PHASE;\
break;\
}\
case _US_UNWIND_FRAME_STARTING:\
{\
actions = _UA_CLEANUP_PHASE;\
if (exceptionObject->barrier_cache.sp == _Unwind_GetGR(context, 13))\
{\
actions |= _UA_HANDLER_FRAME;\
}\
break;\
}\
case _US_UNWIND_FRAME_RESUME:\
{\
return continueUnwinding(exceptionObject, context);\
break;\
}\
}\
_Unwind_SetGR (context, 12, reinterpret_cast<unsigned long>(exceptionObject));\
#define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context)

View File

@ -0,0 +1,174 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef _UNWIND_H
#define _UNWIND_H
/* For uint64_t */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Minimal interface as per C++ ABI draft standard:
http://www.codesourcery.com/cxx-abi/abi-eh.html */
typedef enum
{
_URC_NO_REASON = 0,
_URC_OK = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
}
_Unwind_Reason_Code;
typedef int _Unwind_Action;
#define _UA_SEARCH_PHASE 1
#define _UA_CLEANUP_PHASE 2
#define _UA_HANDLER_FRAME 4
#define _UA_FORCE_UNWIND 8
struct _Unwind_Context; /* opaque data-structure */
struct _Unwind_Exception; /* forward-declaration */
typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
struct _Unwind_Exception *);
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int, _Unwind_Action,
uint64_t,
struct _Unwind_Exception *,
struct _Unwind_Context *,
void *);
/* The C++ ABI requires exception_class, private_1, and private_2 to
be of type uint64 and the entire structure to be
double-word-aligned. Please note that exception_class stays 64-bit
even on 32-bit machines for gcc compatibility. */
struct _Unwind_Exception
{
uint64_t exception_class;
_Unwind_Exception_Cleanup_Fn exception_cleanup;
uintptr_t private_1;
uintptr_t private_2;
#if __SIZEOF_POINTER__ == 4
uint32_t reserved[3];
#endif
} __attribute__((__aligned__));
extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,
_Unwind_Stop_Fn, void *);
extern void _Unwind_Resume (struct _Unwind_Exception *);
extern void _Unwind_DeleteException (struct _Unwind_Exception *);
extern unsigned long _Unwind_GetGR (struct _Unwind_Context *, int);
extern void _Unwind_SetGR (struct _Unwind_Context *, int, unsigned long);
extern unsigned long _Unwind_GetIP (struct _Unwind_Context *);
extern unsigned long _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
extern void _Unwind_SetIP (struct _Unwind_Context *, unsigned long);
extern unsigned long _Unwind_GetLanguageSpecificData (struct _Unwind_Context*);
extern unsigned long _Unwind_GetRegionStart (struct _Unwind_Context *);
#ifdef _GNU_SOURCE
/* Callback for _Unwind_Backtrace(). The backtrace stops immediately
if the callback returns any value other than _URC_NO_REASON. */
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
void *);
/* See http://gcc.gnu.org/ml/gcc-patches/2001-09/msg00082.html for why
_UA_END_OF_STACK exists. */
# define _UA_END_OF_STACK 16
/* If the unwind was initiated due to a forced unwind, resume that
operation, else re-raise the exception. This is used by
__cxa_rethrow(). */
extern _Unwind_Reason_Code
_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
/* See http://gcc.gnu.org/ml/gcc-patches/2003-09/msg00154.html for why
_Unwind_GetBSP() exists. */
extern unsigned long _Unwind_GetBSP (struct _Unwind_Context *);
/* Return the "canonical frame address" for the given context.
This is used by NPTL... */
extern unsigned long _Unwind_GetCFA (struct _Unwind_Context *);
/* Return the base-address for data references. */
extern unsigned long _Unwind_GetDataRelBase (struct _Unwind_Context *);
/* Return the base-address for text references. */
extern unsigned long _Unwind_GetTextRelBase (struct _Unwind_Context *);
/* Call _Unwind_Trace_Fn once for each stack-frame, without doing any
cleanup. The first frame for which the callback is invoked is the
one for the caller of _Unwind_Backtrace(). _Unwind_Backtrace()
returns _URC_END_OF_STACK when the backtrace stopped due to
reaching the end of the call-chain or _URC_FATAL_PHASE1_ERROR if it
stops for any other reason. */
extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
/* Find the start-address of the procedure containing the specified IP
or NULL if it cannot be found (e.g., because the function has no
unwind info). Note: there is not necessarily a one-to-one
correspondence between source-level functions and procedures: some
functions don't have unwind-info and others are split into multiple
procedures. */
extern void *_Unwind_FindEnclosingFunction (void *);
/* See also Linux Standard Base Spec:
http://www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB/libgcc-s.html */
#endif /* _GNU_SOURCE */
#define DECLARE_PERSONALITY_FUNCTION(name) \
_Unwind_Reason_Code name(int version,\
_Unwind_Action actions,\
uint64_t exceptionClass,\
struct _Unwind_Exception *exceptionObject,\
struct _Unwind_Context *context);
#define BEGIN_PERSONALITY_FUNCTION(name) \
_Unwind_Reason_Code name(int version,\
_Unwind_Action actions,\
uint64_t exceptionClass,\
struct _Unwind_Exception *exceptionObject,\
struct _Unwind_Context *context)\
{
#define CALL_PERSONALITY_FUNCTION(name) name(version, actions, exceptionClass, exceptionObject, context)
#ifdef __cplusplus
}
#endif
#endif /* _UNWIND_H */

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012 David Chisnall. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef UNWIND_H_INCLUDED
#define UNWIND_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
#include "unwind-arm.h"
#else
#include "unwind-itanium.h"
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,5 @@
test_command=$1
expected_output=$2
test_log=$3
$test_command > $test_log 2>&1
diff $test_log $expected_output

View File

@ -0,0 +1,58 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int succeeded;
static int failed;
static bool verbose;
void log_test(bool predicate, const char *file, int line, const char *message)
{
if (predicate)
{
if (verbose)
{
printf("Test passed: %s:%d: %s\n", file, line, message);
}
succeeded++;
return;
}
failed++;
printf("Test failed: %s:%d: %s\n", file, line, message);
}
static void log_totals(void)
{
printf("\n%d tests, %d passed, %d failed\n", succeeded+failed, succeeded, failed);
}
static void __attribute__((constructor)) init(void)
{
atexit(log_totals);
}
void test_type_info(void);
void test_exceptions();
void test_guards(void);
void test_demangle(void);
int main(int argc, char **argv)
{
int ch;
while ((ch = getopt(argc, argv, "v")) != -1)
{
switch (ch)
{
case 'v':
verbose = true;
default: break;
}
}
test_type_info();
test_guards();
test_exceptions();
test_demangle();
return 0;
}

View File

@ -0,0 +1,5 @@
void log_test(bool predicate, const char *file, int line, const char *message);
#define TEST(p, m) log_test(p, __FILE__, __LINE__, m)
#define TEST_LOC(p, m, file, line) log_test(p, file, line, m)

View File

@ -0,0 +1,46 @@
#include "test.h"
#include <cxxabi.h>
#include <stdio.h>
#include <stdlib.h>
#include <list>
template <typename T> void test(const char* expected, int line) {
const char *mangled = typeid(T).name();
int status = 0;
using abi::__cxa_demangle;
char* demangled = __cxa_demangle(mangled, 0, 0, &status);
printf("mangled='%s' demangled='%s', status=%d\n", mangled, demangled,
status);
free(demangled);
TEST_LOC(status == 0, "should be able to demangle", __FILE__, line);
TEST_LOC(demangled != 0, "should be able to demangle", __FILE__, line);
if (!demangled) {
/* Don't dereference NULL in strcmp() */
return;
}
TEST_LOC(strcmp(expected, demangled) == 0, "should be able to demangle",
__FILE__, line);
TEST_LOC(strcmp(mangled, demangled) != 0, "should be able to demangle",
__FILE__, line);
}
namespace N {
template<typename T, int U>
class Templated {
virtual ~Templated() {};
};
}
void test_demangle(void)
{
using namespace N;
test<int>("int", __LINE__);
test<char[4]>("char [4]", __LINE__);
test<char[]>("char []", __LINE__);
test<Templated<Templated<long, 7>, 8> >(
"N::Templated<N::Templated<long, 7>, 8>", __LINE__);
test<Templated<void(long), -1> >(
"N::Templated<void (long), -1>", __LINE__);
}

View File

@ -0,0 +1,378 @@
#include "test.h"
#include "unwind.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <exception>
#define fprintf(...)
void log_cleanup(void* ignored)
{
//printf("Cleanup called on %s\n", *(char**)ignored);
}
#define CLEANUP\
__attribute__((cleanup(log_cleanup))) __attribute__((unused))\
const char *f = __func__;
/**
* Simple struct to test throwing.
*/
struct foo
{
int i;
};
struct bar : foo
{
float bar;
};
/**
* Non-pod type to test throwing
*/
class non_pod {
public:
non_pod(int i): x(i) {}
int x;
};
static int cleanup_count;
/**
* Simple structure declared with a destructor. Destroying this object will
* increment cleanup count. The destructor should be called automatically if
* an instance of cl is allocated with automatic storage.
*/
struct cl
{
int i;
~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
};
/**
* Test that one cl was destroyed when running the argument.
*/
#define TEST_CLEANUP(x) do {\
int cleanups = cleanup_count;\
{ x; }\
TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
} while(0)
int inner(int i)
{
CLEANUP
switch (i)
{
case 0: throw (int)1.0;
case 1: throw (float)1.0;
case 2: fprintf(stderr, "Throwing int64_t\n");throw (int64_t)1;
case 3: { foo f = {2} ; throw f; }
case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
case 5: throw non_pod(3);
}
return -1;
}
int outer(int i) throw(float, int, foo, non_pod)
{
//CLEANUP
inner(i);
return 1;
}
static void test_const(void)
{
int a = 1;
try
{
throw a;
}
catch (const int b)
{
TEST(a == b, "Caught int as const int");
}
catch(...)
{
TEST(0, "Failed to catch int as const int");
}
try
{
throw &a;
}
catch (const int *b)
{
TEST(&a == b, "Caught int* as const int*");
}
catch(...)
{
TEST(0, "Failed to catch int* as const int*");
}
}
static void test_catch(int s)
{
cl c;
c.i = 12;
fprintf(stderr, "Entering try\n");
try
{
outer(s);
}
catch(int i)
{
fprintf(stderr, "Caught int %d in test %d\n", i, s);
TEST((s == 0 && i == 1) || (s == 2 && i == 0), "Caught int");
return;
}
catch (float f)
{
fprintf(stderr, "Caught float %f!\n", f);
TEST(s == 1 && f == 1, "Caught float");
return;
}
catch (foo f)
{
fprintf(stderr, "Caught struct {%d}!\n", f.i);
TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
return;
}
catch (non_pod np) {
fprintf(stderr, "Caught non_pod {%d}!\n", np.x);
TEST(s == 5 && np.x == 3, "Caught non_pod");
return;
}
//abort();
TEST(0, "Unreachable line reached");
}
void test_nested1(void)
{
CLEANUP;
cl c;
c.i = 123;
try
{
outer(0);
}
catch (int a)
{
try
{
TEST(a == 1, "Caught int");
outer(1);
}
catch (float f)
{
TEST(f == 1, "Caught float inside outer catch block");
throw;
}
}
}
void test_nested()
{
try
{
test_nested1();
}
catch (float f)
{
fprintf(stderr, "Caught re-thrown float\n");
TEST(f == 1, "Caught re-thrown float");
}
}
static int violations = 0;
static void throw_zero()
{
violations++;
fprintf(stderr, "Throwing 0\n");
throw 0;
}
struct uncaught_exception_checker
{
uncaught_exception_checker(bool uncaught) : m_uncaught(uncaught) {}
~uncaught_exception_checker() {
if (std::uncaught_exception())
TEST(m_uncaught, "At least one uncaught exception is in flight");
else
TEST(!m_uncaught, "No uncaught exceptions are in flight");
}
bool m_uncaught;
};
void test_rethrown_uncaught_exception()
{
uncaught_exception_checker outer(false);
try
{
try
{
throw 42;
}
catch (int)
{
uncaught_exception_checker inner(true);
throw;
}
}
catch (...) {}
}
static void exception_cleanup(_Unwind_Reason_Code, struct _Unwind_Exception *ex)
{
delete ex;
}
void test_rethrown_uncaught_foreign_exception()
{
uncaught_exception_checker outer(false);
try
{
try
{
// Throw a foreign exception.
_Unwind_Exception *ex = new _Unwind_Exception;
ex->exception_class = 1234;
ex->exception_cleanup = exception_cleanup;
_Unwind_RaiseException(ex);
}
catch (...)
{
// Note: Uncaught exceptions doesn't report foreign exceptions,
// because we have no way of receiving a report that the other
// language has caught it.
uncaught_exception_checker inner(false);
throw;
}
}
catch (...) {}
}
void test_uncaught_exception()
{
uncaught_exception_checker outer(false);
try {
uncaught_exception_checker inner(true);
throw 42;
}
catch (...) {}
}
struct uncaught_exceptions_checker
{
uncaught_exceptions_checker(int uncaught) : m_uncaught(uncaught) {}
~uncaught_exceptions_checker() {
char msg[128];
int uncaught = std::uncaught_exceptions();
snprintf(msg, sizeof msg, "%d uncaught exception%s in flight",
uncaught, uncaught == 1 ? " is" : "s are");
TEST(uncaught == m_uncaught, msg);
}
int m_uncaught;
};
class top {
public:
~top() {
try {
uncaught_exceptions_checker uec(4);
throw "top";
}
catch (...) {}
}
};
class middle {
public:
~middle() {
try {
top f;
uncaught_exceptions_checker uec(3);
throw "middle";
}
catch (...) {}
}
};
class bottom {
public:
~bottom() {
try {
middle f;
uncaught_exceptions_checker uec(2);
throw "bottom";
}
catch (...) {}
}
};
void test_uncaught_exceptions()
{
uncaught_exceptions_checker outer(0);
try {
bottom b;
uncaught_exceptions_checker inner(1);
throw "test";
}
catch (...) {}
}
extern "C" void __cxa_bad_cast();
void test_exceptions(void)
{
std::set_unexpected(throw_zero);
TEST_CLEANUP(test_catch(0));
TEST_CLEANUP(test_catch(1));
TEST_CLEANUP(test_catch(3));
TEST_CLEANUP(test_catch(4));
TEST_CLEANUP(test_catch(5));
TEST_CLEANUP(test_nested());
try{
test_catch(2);
TEST(violations == 1, "Exactly one exception spec violation");
}
catch (int64_t i) {
TEST(0, "Caught int64_t, but that violates an exception spec");
}
int a;
try {
throw &a;
}
catch (const int *b)
{
TEST(&a==b, "Caught const int from thrown int");
}
try {
throw &a;
}
catch (int *b)
{
TEST(&a==b, "Caught int from thrown int");
}
try
{
__cxa_bad_cast();
}
catch (std::exception b)
{
TEST(1, "Caught bad cast");
}
catch (...)
{
TEST(0, "Bad cast was not caught correctly");
}
test_const();
test_uncaught_exception();
test_rethrown_uncaught_exception();
test_rethrown_uncaught_foreign_exception();
test_uncaught_exceptions();
//printf("Test: %s\n",
}

View File

@ -0,0 +1,125 @@
#include <cstdio>
#include <cstdlib>
#include "unwind.h"
#define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) \
((static_cast<uint64_t>(a) << 56) +\
(static_cast<uint64_t>(b) << 48) +\
(static_cast<uint64_t>(c) << 40) +\
(static_cast<uint64_t>(d) << 32) +\
(static_cast<uint64_t>(e) << 24) +\
(static_cast<uint64_t>(f) << 16) +\
(static_cast<uint64_t>(g) << 8) +\
(static_cast<uint64_t>(h)))
// using ld --wrap=_Unwind_RaiseException hook feature
extern "C" _Unwind_Reason_Code __real__Unwind_RaiseException (_Unwind_Exception *e);
extern "C" _Unwind_Reason_Code __wrap__Unwind_RaiseException (_Unwind_Exception *e);
extern "C" _Unwind_Reason_Code __wrap__Unwind_RaiseException (_Unwind_Exception *e)
{
// clobber exception class forcing libcxx own exceptions to be treated
// as foreign exception within libcxx itself
e->exception_class = EXCEPTION_CLASS('F','O','R','E','I','G','N','\0');
__real__Unwind_RaiseException(e);
}
_Unwind_Exception global_e;
enum test_status {
PENDING, PASSED, FAILED
};
const char test_status_str[][8] = {
"PENDING", "PASSED", "FAILED"
};
test_status test1_status = PENDING;
test_status test2_status = PENDING;
test_status test3_status = PENDING;
void test2_exception_cleanup(_Unwind_Reason_Code code, _Unwind_Exception *e)
{
fputs("(2) exception_cleanup called\n", stderr);
if (e != &global_e) {
fprintf(stderr, "(2) ERROR: unexpected ptr: expecting %p, got %p\n", &global_e, e);
test2_status = FAILED;
}
if (test2_status == PENDING)
test2_status = PASSED;
}
struct test3_exception
{
static int counter;
~test3_exception()
{
counter++;
fputs("(3) exception dtor\n", stderr);
}
};
int test3_exception::counter = 0;
int main()
{
///////////////////////////////////////////////////////////////
fputs("(1) foreign exception, exception_cleanup=nullptr\n", stderr);
try
{
global_e.exception_class = 0;
global_e.exception_cleanup = 0;
__real__Unwind_RaiseException(&global_e);
}
catch (...)
{
}
test1_status = PASSED;
fputs("(1) PASS\n", stderr);
///////////////////////////////////////////////////////////////
fputs("(2) foreign exception, exception_cleanup present\n", stderr);
try
{
global_e.exception_class = 0;
global_e.exception_cleanup = test2_exception_cleanup;
__real__Unwind_RaiseException(&global_e);
}
catch (...)
{
}
fprintf(stderr, "(2) %s\n", test_status_str[test2_status]);
///////////////////////////////////////////////////////////////
fputs("(3) C++ exception in foreign environment\n", stderr);
int counter_expected;
try
{
// throw was rigged such that the runtime treats C++ exceptions
// as foreign ones
throw test3_exception();
}
catch (test3_exception&)
{
fputs("(3) ERROR: wrong catch\n", stderr);
test3_status = FAILED;
}
catch (...)
{
fputs("(3) catch(...)\n", stderr);
counter_expected = test3_exception::counter + 1;
// one more dtor immediately after we leave catch
}
if (test3_status == PENDING && test3_exception::counter != counter_expected) {
fputs("(3) ERROR: exception dtor didn't run\n", stderr);
test3_status = FAILED;
}
if (test3_status == PENDING)
test3_status = PASSED;
fprintf(stderr, "(3) %s\n", test_status_str[test3_status]);
///////////////////////////////////////////////////////////////
if (test1_status == PASSED && test2_status == PASSED && test3_status == PASSED)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}

View File

@ -0,0 +1,29 @@
#include <stdio.h>
#include "test.h"
static int static_count;
struct static_struct
{
int i;
static_struct()
{
static_count++;
i = 12;
};
};
static static_struct ss;
int init_static(void)
{
static static_struct s;
return s.i;
}
void test_guards(void)
{
init_static();
int i = init_static();
TEST(i == 12, "Static initialized");
TEST(static_count == 2, "Each static only initialized once");
}

View File

@ -0,0 +1,112 @@
#include "../src/typeinfo.h"
#include "test.h"
#include <stdio.h>
struct Virt1;
struct Virt2;
struct Diamond;
struct Virt1a;
struct Virt2a;
struct Diamond2;
struct Root
{
int test;
void * foo;
virtual Virt1 *as_v1() { return 0; }
virtual Virt2 *as_v2() { return 0; }
virtual Diamond *as_diamond() { return 0; }
virtual Virt1a *as_v1a() { return 0; }
virtual Virt2a *as_v2a() { return 0; }
virtual Diamond2 *as_diamond2() { return 0; }
};
struct Sub1 : public Root
{
double a;
};
struct Sub2 : public Sub1
{
float ignored;
};
struct Virt1a : public virtual Root
{
int b;
virtual Virt1a *as_v1a() { return this; }
};
struct Virt2a : public virtual Root
{
int b;
virtual Virt2a *as_v2a() { return this; }
};
struct Virt1 : public virtual Virt1a
{
double a;
virtual Virt1 *as_v1() { return this; }
};
struct Virt2 : public virtual Virt2a
{
double b;
virtual Virt2 *as_v2() { return this; }
};
struct Diamond : public virtual Virt1, public virtual Virt2
{
int c;
virtual Diamond *as_diamond() { return this; }
};
struct Diamond2 : public virtual Virt1a, public virtual Virt2a
{
int c;
virtual Diamond2 *as_diamond2() { return this; }
};
void test_type_info(void)
{
Sub2 sub2;
Root root;
Virt1 virt1;
Diamond diamond;
Root *b = &sub2;
Root *f = &sub2;
Root *s2 = &sub2;
Root *b2 = &root;
Root *v1 = &virt1;
Virt1 *d1 = &diamond;
Root *up = &diamond;
b->test = 12;
f->test = 12;
b2->test = 12;
s2->test = 12;
TEST(12 == b->test, "Setting field");
b = dynamic_cast<Root*>(f);
TEST(12 == b->test, "Casting Sub1 to superclass");
((Sub1*)(s2))->a = 12;
TEST(12 == dynamic_cast<Sub1*>(s2)->a, "Casting Sub2 -> Sub1");
v1->as_v1()->a = 12;
TEST(12 == dynamic_cast<Virt1*>(v1)->a, "Casting Root (Virt1) -> Virt1");
d1->as_v1()->test = 12;
TEST(12 == d1->as_v2()->test, "Accessing virt2 via vtable method");
TEST(12 == dynamic_cast<Virt2*>(d1)->test, "Casting diamond to virt2");
TEST(12 == dynamic_cast<Diamond*>(d1)->test, "casting diamond to diamond");
Diamond2 diamond2;
Root *d2 = &diamond2;
d2->test = 12;
TEST(12 == dynamic_cast<Diamond2*>(d2)->test, "Casting Diamond2 to Diamond2");
TEST(12 == dynamic_cast<Virt2a*>(d2)->test, "Casting Diamond2 to Virt2a");
TEST(&diamond == dynamic_cast<Diamond*>(up), "Downcasting root-pointer to diamond");
TEST(0 == dynamic_cast<Diamond*>(&root), "Downcasting root to diamond");
TEST(0 == dynamic_cast<Sub1*>(b2), "Casting Root to Sub1 (0 expected)");
}