| author | |
| committer | |
| log | e41b58ddc3e20144d30bba8c1387df5aa5fd6c5e |
| tree | 2aee9d8b7085704906f67e4e403bfaad29c06cf4 |
| parent | 1eaf180dd04efcf65ef981b1e1064658b5ec09c3 |
6 files changed, 138 insertions(+), 50 deletions(-)
lib/libcxxabi/src/aix_state_tab_eh.inc+42-8| ... | ... | @@ -14,6 +14,10 @@ |
| 14 | 14 | #include <stdio.h> |
| 15 | 15 | #include <sys/debug.h> |
| 16 | 16 | |
| 17 | #if !__has_cpp_attribute(clang::optnone) | |
| 18 | #error This file requires clang::optnone attribute support | |
| 19 | #endif | |
| 20 | ||
| 17 | 21 | /* |
| 18 | 22 | The legacy IBM xlC and xlclang++ compilers use the state table for EH |
| 19 | 23 | instead of the range table. Destructors, or addresses of the possible catch |
| ... | ... | @@ -183,10 +187,6 @@ enum FSMMagic : uint32_t { |
| 183 | 187 | number3 = 0x1cedbeef // State table generated by xlclang++ compiler. |
| 184 | 188 | }; |
| 185 | 189 | |
| 186 | constexpr uint32_t REG_EXCP_OBJ = 14; // Register to pass the address of the exception | |
| 187 | // object from the personality to xlclang++ | |
| 188 | // compiled code. | |
| 189 | ||
| 190 | 190 | constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free |
| 191 | 191 | // virtual bases, don't delete object. |
| 192 | 192 | |
| ... | ... | @@ -555,8 +555,16 @@ __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionCl |
| 555 | 555 | if (actions & _UA_CLEANUP_PHASE) { |
| 556 | 556 | // Phase 2 cleanup: |
| 557 | 557 | if (results.reason == _URC_HANDLER_FOUND) { |
| 558 | // Store the address of unwind_exception in the stack field | |
| 559 | // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of | |
| 560 | // the caller of the function containing the landing pad (within the link | |
| 561 | // area for the call to the latter) for __xlc_exception_handle() | |
| 562 | // to retrieve when it is called by the landing pad. | |
| 563 | uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1)); | |
| 564 | uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]); | |
| 565 | callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception); | |
| 566 | _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP)); | |
| 558 | 567 | // Jump to the handler. |
| 559 | _Unwind_SetGR(context, REG_EXCP_OBJ, reinterpret_cast<uintptr_t>(unwind_exception)); | |
| 560 | 568 | _Unwind_SetIP(context, results.landingPad); |
| 561 | 569 | return _URC_INSTALL_CONTEXT; |
| 562 | 570 | } |
| ... | ... | @@ -633,12 +641,38 @@ _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() { |
| 633 | 641 | __cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0); |
| 634 | 642 | } |
| 635 | 643 | |
| 644 | // force_a_stackframe | |
| 645 | // This function is called by __xlc_exception_handle() to ensure a stack frame | |
| 646 | // is created for __xlc_exception_handle(). | |
| 647 | __attribute__((noinline, optnone)) | |
| 648 | static void force_a_stackframe() {} | |
| 649 | ||
| 636 | 650 | // __xlc_exception_handle |
| 637 | 651 | // This function is for xlclang++. It returns the address of the exception |
| 638 | // object set in gpr14 by the personality routine for xlclang++ compiled code. | |
| 652 | // object stored in the reserved field in the stack of the caller of the | |
| 653 | // function that calls __xlc_exception_handle() (within the link area for the | |
| 654 | // call to the latter). The address is stored by the personality routine for | |
| 655 | // xlclang++ compiled code. The implementation of __xlc_exception_handle() | |
| 656 | // assumes a stack frame is created for it. The following ensures this | |
| 657 | // assumption holds true: 1) a call to force_a_stackframe() is made inside | |
| 658 | // __xlc_exception_handle() to make it non-leaf; and 2) optimizations are | |
| 659 | // disabled for this function with attribute 'optnone'. Note: this function | |
| 660 | // may not work as expected if these are changed. | |
| 661 | __attribute__((optnone)) | |
| 639 | 662 | _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { |
| 640 | uintptr_t exceptionObject; | |
| 641 | asm("mr %0, 14" : "=r"(exceptionObject)); | |
| 663 | // Make a call to force_a_stackframe() so that the compiler creates a stack | |
| 664 | // frame for this function. | |
| 665 | force_a_stackframe(); | |
| 666 | ||
| 667 | // Get the SP of this function, i.e., __xlc_exception_handle(). | |
| 668 | uintptr_t *lastStack; | |
| 669 | asm("mr %0, 1" : "=r"(lastStack)); | |
| 670 | // Get the SP of the caller of __xlc_exception_handle(). | |
| 671 | uintptr_t *callerStack = reinterpret_cast<uintptr_t*>(lastStack[0]); | |
| 672 | // Get the SP of the caller of the caller. | |
| 673 | uintptr_t *callerStack2 = reinterpret_cast<uintptr_t*>(callerStack[0]); | |
| 674 | uintptr_t exceptionObject = callerStack2[3]; | |
| 675 | _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack2)); | |
| 642 | 676 | return exceptionObject; |
| 643 | 677 | } |
| 644 | 678 |
lib/libcxxabi/src/cxa_demangle.cpp+1-4| ... | ... | @@ -386,15 +386,12 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { |
| 386 | 386 | |
| 387 | 387 | int InternalStatus = demangle_success; |
| 388 | 388 | Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); |
| 389 | OutputBuffer O; | |
| 390 | ||
| 391 | 389 | Node *AST = Parser.parse(); |
| 392 | 390 | |
| 393 | 391 | if (AST == nullptr) |
| 394 | 392 | InternalStatus = demangle_invalid_mangled_name; |
| 395 | else if (!initializeOutputBuffer(Buf, N, O, 1024)) | |
| 396 | InternalStatus = demangle_memory_alloc_failure; | |
| 397 | 393 | else { |
| 394 | OutputBuffer O(Buf, N); | |
| 398 | 395 | assert(Parser.ForwardTemplateRefs.empty()); |
| 399 | 396 | AST->print(O); |
| 400 | 397 | O += '\0'; |
lib/libcxxabi/src/cxa_guard_impl.h+5-1| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | 6 | // |
| 7 | 7 | //===----------------------------------------------------------------------===// |
| 8 | ||
| 8 | 9 | #ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H |
| 9 | 10 | #define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H |
| 10 | 11 | |
| ... | ... | @@ -54,9 +55,12 @@ |
| 54 | 55 | # endif |
| 55 | 56 | #endif |
| 56 | 57 | |
| 58 | #include <__threading_support> | |
| 59 | #include <cstdint> | |
| 60 | #include <cstring> | |
| 57 | 61 | #include <limits.h> |
| 58 | 62 | #include <stdlib.h> |
| 59 | #include <__threading_support> | |
| 63 | ||
| 60 | 64 | #ifndef _LIBCXXABI_HAS_NO_THREADS |
| 61 | 65 | # if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) |
| 62 | 66 | # pragma comment(lib, "pthread") |
lib/libcxxabi/src/demangle/ItaniumDemangle.h+26-6| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | #include <cstdlib> |
| 27 | 27 | #include <cstring> |
| 28 | 28 | #include <limits> |
| 29 | #include <new> | |
| 29 | 30 | #include <utility> |
| 30 | 31 | |
| 31 | 32 | DEMANGLE_NAMESPACE_BEGIN |
| ... | ... | @@ -369,6 +370,10 @@ public: |
| 369 | 370 | VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) |
| 370 | 371 | : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} |
| 371 | 372 | |
| 373 | const Node *getTy() const { return Ty; } | |
| 374 | StringView getExt() const { return Ext; } | |
| 375 | const Node *getTA() const { return TA; } | |
| 376 | ||
| 372 | 377 | template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); } |
| 373 | 378 | |
| 374 | 379 | void printLeft(OutputBuffer &OB) const override { |
| ... | ... | @@ -417,6 +422,9 @@ public: |
| 417 | 422 | Child_->ArrayCache, Child_->FunctionCache), |
| 418 | 423 | Quals(Quals_), Child(Child_) {} |
| 419 | 424 | |
| 425 | Qualifiers getQuals() const { return Quals; } | |
| 426 | const Node *getChild() const { return Child; } | |
| 427 | ||
| 420 | 428 | template<typename Fn> void match(Fn F) const { F(Child, Quals); } |
| 421 | 429 | |
| 422 | 430 | bool hasRHSComponentSlow(OutputBuffer &OB) const override { |
| ... | ... | @@ -585,6 +593,8 @@ public: |
| 585 | 593 | : Node(KPointerType, Pointee_->RHSComponentCache), |
| 586 | 594 | Pointee(Pointee_) {} |
| 587 | 595 | |
| 596 | const Node *getPointee() const { return Pointee; } | |
| 597 | ||
| 588 | 598 | template<typename Fn> void match(Fn F) const { F(Pointee); } |
| 589 | 599 | |
| 590 | 600 | bool hasRHSComponentSlow(OutputBuffer &OB) const override { |
| ... | ... | @@ -1070,6 +1080,9 @@ public: |
| 1070 | 1080 | VectorType(const Node *BaseType_, const Node *Dimension_) |
| 1071 | 1081 | : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} |
| 1072 | 1082 | |
| 1083 | const Node *getBaseType() const { return BaseType; } | |
| 1084 | const Node *getDimension() const { return Dimension; } | |
| 1085 | ||
| 1073 | 1086 | template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } |
| 1074 | 1087 | |
| 1075 | 1088 | void printLeft(OutputBuffer &OB) const override { |
| ... | ... | @@ -3019,14 +3032,21 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { |
| 3019 | 3032 | if (numLeft() < 2) |
| 3020 | 3033 | return nullptr; |
| 3021 | 3034 | |
| 3022 | auto Op = std::lower_bound( | |
| 3023 | &Ops[0], &Ops[NumOps], First, | |
| 3024 | [](const OperatorInfo &Op_, const char *Enc_) { return Op_ < Enc_; }); | |
| 3025 | if (Op == &Ops[NumOps] || *Op != First) | |
| 3035 | // We can't use lower_bound as that can link to symbols in the C++ library, | |
| 3036 | // and this must remain independant of that. | |
| 3037 | size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. | |
| 3038 | while (upper != lower) { | |
| 3039 | size_t middle = (upper + lower) / 2; | |
| 3040 | if (Ops[middle] < First) | |
| 3041 | lower = middle + 1; | |
| 3042 | else | |
| 3043 | upper = middle; | |
| 3044 | } | |
| 3045 | if (Ops[lower] != First) | |
| 3026 | 3046 | return nullptr; |
| 3027 | 3047 | |
| 3028 | 3048 | First += 2; |
| 3029 | return Op; | |
| 3049 | return &Ops[lower]; | |
| 3030 | 3050 | } |
| 3031 | 3051 | |
| 3032 | 3052 | // <operator-name> ::= See parseOperatorEncoding() |
| ... | ... | @@ -5099,7 +5119,7 @@ template <> |
| 5099 | 5119 | struct FloatData<long double> |
| 5100 | 5120 | { |
| 5101 | 5121 | #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ |
| 5102 | defined(__wasm__) || defined(__riscv) | |
| 5122 | defined(__wasm__) || defined(__riscv) || defined(__loongarch__) | |
| 5103 | 5123 | static const size_t mangled_size = 32; |
| 5104 | 5124 | #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) |
| 5105 | 5125 | static const size_t mangled_size = 16; |
lib/libcxxabi/src/demangle/Utility.h+3-22| ... | ... | @@ -69,7 +69,9 @@ class OutputBuffer { |
| 69 | 69 | |
| 70 | 70 | public: |
| 71 | 71 | OutputBuffer(char *StartBuf, size_t Size) |
| 72 | : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} | |
| 72 | : Buffer(StartBuf), BufferCapacity(Size) {} | |
| 73 | OutputBuffer(char *StartBuf, size_t *SizePtr) | |
| 74 | : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} | |
| 73 | 75 | OutputBuffer() = default; |
| 74 | 76 | // Non-copyable |
| 75 | 77 | OutputBuffer(const OutputBuffer &) = delete; |
| ... | ... | @@ -77,12 +79,6 @@ public: |
| 77 | 79 | |
| 78 | 80 | operator StringView() const { return StringView(Buffer, CurrentPosition); } |
| 79 | 81 | |
| 80 | void reset(char *Buffer_, size_t BufferCapacity_) { | |
| 81 | CurrentPosition = 0; | |
| 82 | Buffer = Buffer_; | |
| 83 | BufferCapacity = BufferCapacity_; | |
| 84 | } | |
| 85 | ||
| 86 | 82 | /// If a ParameterPackExpansion (or similar type) is encountered, the offset |
| 87 | 83 | /// into the pack that we're currently printing. |
| 88 | 84 | unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); |
| ... | ... | @@ -198,21 +194,6 @@ public: |
| 198 | 194 | ScopedOverride &operator=(const ScopedOverride &) = delete; |
| 199 | 195 | }; |
| 200 | 196 | |
| 201 | inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB, | |
| 202 | size_t InitSize) { | |
| 203 | size_t BufferSize; | |
| 204 | if (Buf == nullptr) { | |
| 205 | Buf = static_cast<char *>(std::malloc(InitSize)); | |
| 206 | if (Buf == nullptr) | |
| 207 | return false; | |
| 208 | BufferSize = InitSize; | |
| 209 | } else | |
| 210 | BufferSize = *N; | |
| 211 | ||
| 212 | OB.reset(Buf, BufferSize); | |
| 213 | return true; | |
| 214 | } | |
| 215 | ||
| 216 | 197 | DEMANGLE_NAMESPACE_END |
| 217 | 198 | |
| 218 | 199 | #endif |
lib/libcxxabi/src/fallback_malloc.cpp+61-9| ... | ... | @@ -15,6 +15,7 @@ |
| 15 | 15 | #endif |
| 16 | 16 | #endif |
| 17 | 17 | |
| 18 | #include <assert.h> | |
| 18 | 19 | #include <stdlib.h> // for malloc, calloc, free |
| 19 | 20 | #include <string.h> // for memset |
| 20 | 21 | #include <new> // for std::__libcpp_aligned_{alloc,free} |
| ... | ... | @@ -63,11 +64,28 @@ char heap[HEAP_SIZE] __attribute__((aligned)); |
| 63 | 64 | typedef unsigned short heap_offset; |
| 64 | 65 | typedef unsigned short heap_size; |
| 65 | 66 | |
| 67 | // On both 64 and 32 bit targets heap_node should have the following properties | |
| 68 | // Size: 4 | |
| 69 | // Alignment: 2 | |
| 66 | 70 | struct heap_node { |
| 67 | 71 | heap_offset next_node; // offset into heap |
| 68 | 72 | heap_size len; // size in units of "sizeof(heap_node)" |
| 69 | 73 | }; |
| 70 | 74 | |
| 75 | // All pointers returned by fallback_malloc must be at least aligned | |
| 76 | // as RequiredAligned. Note that RequiredAlignment can be greater than | |
| 77 | // alignof(std::max_align_t) on 64 bit systems compiling 32 bit code. | |
| 78 | struct FallbackMaxAlignType { | |
| 79 | } __attribute__((aligned)); | |
| 80 | const size_t RequiredAlignment = alignof(FallbackMaxAlignType); | |
| 81 | ||
| 82 | static_assert(alignof(FallbackMaxAlignType) % sizeof(heap_node) == 0, | |
| 83 | "The required alignment must be evenly divisible by the sizeof(heap_node)"); | |
| 84 | ||
| 85 | // The number of heap_node's that can fit in a chunk of memory with the size | |
| 86 | // of the RequiredAlignment. On 64 bit targets NodesPerAlignment should be 4. | |
| 87 | const size_t NodesPerAlignment = alignof(FallbackMaxAlignType) / sizeof(heap_node); | |
| 88 | ||
| 71 | 89 | static const heap_node* list_end = |
| 72 | 90 | (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap |
| 73 | 91 | static heap_node* freelist = NULL; |
| ... | ... | @@ -82,10 +100,23 @@ heap_offset offset_from_node(const heap_node* ptr) { |
| 82 | 100 | sizeof(heap_node)); |
| 83 | 101 | } |
| 84 | 102 | |
| 103 | // Return a pointer to the first address, 'A', in `heap` that can actually be | |
| 104 | // used to represent a heap_node. 'A' must be aligned so that | |
| 105 | // '(A + sizeof(heap_node)) % RequiredAlignment == 0'. On 64 bit systems this | |
| 106 | // address should be 12 bytes after the first 16 byte boundary. | |
| 107 | heap_node* getFirstAlignedNodeInHeap() { | |
| 108 | heap_node* node = (heap_node*)heap; | |
| 109 | const size_t alignNBytesAfterBoundary = RequiredAlignment - sizeof(heap_node); | |
| 110 | size_t boundaryOffset = reinterpret_cast<size_t>(node) % RequiredAlignment; | |
| 111 | size_t requiredOffset = alignNBytesAfterBoundary - boundaryOffset; | |
| 112 | size_t NElemOffset = requiredOffset / sizeof(heap_node); | |
| 113 | return node + NElemOffset; | |
| 114 | } | |
| 115 | ||
| 85 | 116 | void init_heap() { |
| 86 | freelist = (heap_node*)heap; | |
| 117 | freelist = getFirstAlignedNodeInHeap(); | |
| 87 | 118 | freelist->next_node = offset_from_node(list_end); |
| 88 | freelist->len = HEAP_SIZE / sizeof(heap_node); | |
| 119 | freelist->len = static_cast<heap_size>(list_end - freelist); | |
| 89 | 120 | } |
| 90 | 121 | |
| 91 | 122 | // How big a chunk we allocate |
| ... | ... | @@ -109,23 +140,44 @@ void* fallback_malloc(size_t len) { |
| 109 | 140 | for (p = freelist, prev = 0; p && p != list_end; |
| 110 | 141 | prev = p, p = node_from_offset(p->next_node)) { |
| 111 | 142 | |
| 112 | if (p->len > nelems) { // chunk is larger, shorten, and return the tail | |
| 113 | heap_node* q; | |
| 143 | // Check the invariant that all heap_nodes pointers 'p' are aligned | |
| 144 | // so that 'p + 1' has an alignment of at least RequiredAlignment | |
| 145 | assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0); | |
| 146 | ||
| 147 | // Calculate the number of extra padding elements needed in order | |
| 148 | // to split 'p' and create a properly aligned heap_node from the tail | |
| 149 | // of 'p'. We calculate aligned_nelems such that 'p->len - aligned_nelems' | |
| 150 | // will be a multiple of NodesPerAlignment. | |
| 151 | size_t aligned_nelems = nelems; | |
| 152 | if (p->len > nelems) { | |
| 153 | heap_size remaining_len = static_cast<heap_size>(p->len - nelems); | |
| 154 | aligned_nelems += remaining_len % NodesPerAlignment; | |
| 155 | } | |
| 114 | 156 | |
| 115 | p->len = static_cast<heap_size>(p->len - nelems); | |
| 157 | // chunk is larger and we can create a properly aligned heap_node | |
| 158 | // from the tail. In this case we shorten 'p' and return the tail. | |
| 159 | if (p->len > aligned_nelems) { | |
| 160 | heap_node* q; | |
| 161 | p->len = static_cast<heap_size>(p->len - aligned_nelems); | |
| 116 | 162 | q = p + p->len; |
| 117 | 163 | q->next_node = 0; |
| 118 | q->len = static_cast<heap_size>(nelems); | |
| 119 | return (void*)(q + 1); | |
| 164 | q->len = static_cast<heap_size>(aligned_nelems); | |
| 165 | void* ptr = q + 1; | |
| 166 | assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0); | |
| 167 | return ptr; | |
| 120 | 168 | } |
| 121 | 169 | |
| 122 | if (p->len == nelems) { // exact size match | |
| 170 | // The chunk is the exact size or the chunk is larger but not large | |
| 171 | // enough to split due to alignment constraints. | |
| 172 | if (p->len >= nelems) { | |
| 123 | 173 | if (prev == 0) |
| 124 | 174 | freelist = node_from_offset(p->next_node); |
| 125 | 175 | else |
| 126 | 176 | prev->next_node = p->next_node; |
| 127 | 177 | p->next_node = 0; |
| 128 | return (void*)(p + 1); | |
| 178 | void* ptr = p + 1; | |
| 179 | assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0); | |
| 180 | return ptr; | |
| 129 | 181 | } |
| 130 | 182 | } |
| 131 | 183 | return NULL; // couldn't find a spot big enough |