| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| add_flang_unittest(FlangRuntimeTests | ||
| AccessTest.cpp | ||
| Allocatable.cpp | ||
| ArrayConstructor.cpp | ||
| BufferTest.cpp | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| //===-- Definition of macros from fenv_t.h --------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_HDR_FENV_T_H | ||
| #define LLVM_LIBC_HDR_FENV_T_H | ||
|
|
||
| #ifdef LIBC_FULL_BUILD | ||
|
|
||
| #include "include/llvm-libc-types/fenv_t.h" | ||
|
|
||
| #else // Overlay mode | ||
|
|
||
| #include <fenv.h> | ||
|
|
||
| #endif // LLVM_LIBC_FULL_BUILD | ||
|
|
||
| #endif // LLVM_LIBC_HDR_FENV_T_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| //===-- Definition of macros from fexcept_t.h -----------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_HDR_FEXCEPT_T_H | ||
| #define LLVM_LIBC_HDR_FEXCEPT_T_H | ||
|
|
||
| #ifdef LIBC_FULL_BUILD | ||
|
|
||
| #include "include/llvm-libc-types/fexcept_t.h" | ||
|
|
||
| #else // Overlay mode | ||
|
|
||
| #include <fenv.h> | ||
|
|
||
| #endif // LLVM_LIBC_FULL_BUILD | ||
|
|
||
| #endif // LLVM_LIBC_HDR_FENV_T_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef _LIBCPP___PSTL_CPU_ALGOS_CPU_TRAITS_H | ||
| #define _LIBCPP___PSTL_CPU_ALGOS_CPU_TRAITS_H | ||
|
|
||
| #include <__config> | ||
| #include <cstddef> | ||
|
|
||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
| # pragma GCC system_header | ||
| #endif | ||
|
|
||
| _LIBCPP_PUSH_MACROS | ||
| #include <__undef_macros> | ||
|
|
||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||
| namespace __pstl { | ||
|
|
||
| // __cpu_traits | ||
| // | ||
| // This traits class encapsulates the basis operations for a CPU-based implementation of the PSTL. | ||
| // All the operations in the PSTL can be implemented from these basis operations, so a pure CPU backend | ||
| // only needs to customize these traits in order to get an implementation of the whole PSTL. | ||
| // | ||
| // Basis operations | ||
| // ================ | ||
| // | ||
| // template <class _RandomAccessIterator, class _Functor> | ||
| // optional<__empty> __for_each(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func); | ||
| // - __func must take a subrange of [__first, __last) that should be executed in serial | ||
| // | ||
| // template <class _Iterator, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduction> | ||
| // optional<_Tp> __transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction); | ||
| // | ||
| // template <class _RandomAccessIterator1, | ||
| // class _RandomAccessIterator2, | ||
| // class _RandomAccessIterator3, | ||
| // class _Compare, | ||
| // class _LeafMerge> | ||
| // optional<_RandomAccessIterator3> __merge(_RandomAccessIterator1 __first1, | ||
| // _RandomAccessIterator1 __last1, | ||
| // _RandomAccessIterator2 __first2, | ||
| // _RandomAccessIterator2 __last2, | ||
| // _RandomAccessIterator3 __outit, | ||
| // _Compare __comp, | ||
| // _LeafMerge __leaf_merge); | ||
| // | ||
| // template <class _RandomAccessIterator, class _Comp, class _LeafSort> | ||
| // optional<__empty> __stable_sort(_RandomAccessIterator __first, | ||
| // _RandomAccessIterator __last, | ||
| // _Comp __comp, | ||
| // _LeafSort __leaf_sort); | ||
| // | ||
| // void __cancel_execution(); | ||
| // Cancel the execution of other jobs - they aren't needed anymore. This is not a binding request, | ||
| // some backends may not actually be able to cancel jobs. | ||
| // | ||
| // constexpr size_t __lane_size; | ||
| // Size of SIMD lanes. | ||
| // TODO: Merge this with __native_vector_size from __algorithm/simd_utils.h | ||
| // | ||
| // | ||
| // Exception handling | ||
| // ================== | ||
| // | ||
| // CPU backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their | ||
| // implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are | ||
| // turned into a program termination at the front-end level. When a backend returns a disengaged `optional` to the | ||
| // frontend, the frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to | ||
| // the user. | ||
|
|
||
| template <class _Backend> | ||
| struct __cpu_traits; | ||
|
|
||
| } // namespace __pstl | ||
| _LIBCPP_END_NAMESPACE_STD | ||
|
|
||
| _LIBCPP_POP_MACROS | ||
|
|
||
| #endif // _LIBCPP___PSTL_CPU_ALGOS_CPU_TRAITS_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef _LIBCPP___UTILITY_IS_VALID_RANGE_H | ||
| #define _LIBCPP___UTILITY_IS_VALID_RANGE_H | ||
|
|
||
| #include <__algorithm/comp.h> | ||
| #include <__config> | ||
| #include <__type_traits/is_constant_evaluated.h> | ||
|
|
||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
| # pragma GCC system_header | ||
| #endif | ||
|
|
||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||
|
|
||
| template <class _Tp> | ||
| _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool | ||
| __is_valid_range(const _Tp* __first, const _Tp* __last) { | ||
| if (__libcpp_is_constant_evaluated()) { | ||
| // If this is not a constant during constant evaluation, that is because __first and __last are not | ||
| // part of the same allocation. If they are part of the same allocation, we must still make sure they | ||
| // are ordered properly. | ||
| return __builtin_constant_p(__first <= __last) && __first <= __last; | ||
| } | ||
|
|
||
| return !__less<>()(__last, __first); | ||
| } | ||
|
|
||
| _LIBCPP_END_NAMESPACE_STD | ||
|
|
||
| #endif // _LIBCPP___UTILITY_IS_VALID_RANGE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include <__utility/is_valid_range.h> | ||
| #include <cassert> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| template <class T, class TQualified> | ||
| TEST_CONSTEXPR_CXX14 void check_type() { | ||
| { | ||
| // We need to ensure that the addresses of i and j are ordered as &i < &j for | ||
| // the test below to work portably, so we define them in a struct. | ||
| struct { | ||
| T i = 0; | ||
| T j = 0; | ||
| } storage; | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(&storage.i), static_cast<TQualified*>(&storage.i))); | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(&storage.i), static_cast<TQualified*>(&storage.i + 1))); | ||
|
|
||
| assert(!std::__is_valid_range(static_cast<TQualified*>(&storage.j), static_cast<TQualified*>(&storage.i))); | ||
| assert(!std::__is_valid_range(static_cast<TQualified*>(&storage.i + 1), static_cast<TQualified*>(&storage.i))); | ||
|
|
||
| // We detect this as being a valid range even though it is not really valid. | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(&storage.i), static_cast<TQualified*>(&storage.j))); | ||
| } | ||
|
|
||
| { | ||
| T arr[3] = {1, 2, 3}; | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(&arr[0]), static_cast<TQualified*>(&arr[0]))); | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(&arr[0]), static_cast<TQualified*>(&arr[1]))); | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(&arr[0]), static_cast<TQualified*>(&arr[2]))); | ||
|
|
||
| assert(!std::__is_valid_range(static_cast<TQualified*>(&arr[1]), static_cast<TQualified*>(&arr[0]))); | ||
| assert(!std::__is_valid_range(static_cast<TQualified*>(&arr[2]), static_cast<TQualified*>(&arr[0]))); | ||
| } | ||
|
|
||
| #if TEST_STD_VER >= 20 | ||
| { | ||
| T* arr = new int[4]{1, 2, 3, 4}; | ||
| assert(std::__is_valid_range(static_cast<TQualified*>(arr), static_cast<TQualified*>(arr + 4))); | ||
| delete[] arr; | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| TEST_CONSTEXPR_CXX14 bool test() { | ||
| check_type<int, int>(); | ||
| check_type<int, int const>(); | ||
| check_type<int, int volatile>(); | ||
| check_type<int, int const volatile>(); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| #if TEST_STD_VER >= 14 | ||
| static_assert(test(), ""); | ||
| #endif | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # REQUIRES: x86 | ||
| # RUN: split-file %s %t.dir | ||
|
|
||
| # RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/lib.s -filetype=obj -o %t.dir/lib.obj | ||
| # RUN: lld-link -out:%t.dir/lib.dll -dll -entry:DllMainCRTStartup %t.dir/lib.obj -lldmingw -implib:%t.dir/lib.lib | ||
|
|
||
| # RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/main.s -filetype=obj -o %t.dir/main.obj | ||
| # RUN: lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/lib.lib -opt:ref -debug:dwarf | ||
|
|
||
| #--- main.s | ||
| .global main | ||
| .section .text$main,"xr",one_only,main | ||
| main: | ||
| ret | ||
|
|
||
| .global other | ||
| .section .text$other,"xr",one_only,other | ||
| other: | ||
| movq .refptr.variable(%rip), %rax | ||
| movl (%rax), %eax | ||
| ret | ||
|
|
||
| .section .rdata$.refptr.variable,"dr",discard,.refptr.variable | ||
| .global .refptr.variable | ||
| .refptr.variable: | ||
| .quad variable | ||
|
|
||
| .section .debug_info | ||
| .long 1 | ||
| .quad variable | ||
| .long 2 | ||
|
|
||
| #--- lib.s | ||
| .global variable | ||
| .global DllMainCRTStartup | ||
| .text | ||
| DllMainCRTStartup: | ||
| ret | ||
| .data | ||
| variable: | ||
| .long 42 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,5 +27,8 @@ | |
| .text | ||
| main: | ||
| movl data(%rip), %eax | ||
| ret | ||
| .global _pei386_runtime_relocator | ||
| _pei386_runtime_relocator: | ||
| ret | ||
| .data | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # REQUIRES: x86 | ||
| # RUN: split-file %s %t.dir | ||
|
|
||
| # RUN: llvm-dlltool -m i386:x86-64 -d %t.dir/lib.def -D lib.dll -l %t.dir/lib.lib | ||
|
|
||
| # RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/main.s -filetype=obj -o %t.dir/main.obj | ||
| # RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/func.s -filetype=obj -o %t.dir/func.obj | ||
| # RUN: env LLD_IN_TEST=1 not lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/lib.lib 2>&1 | FileCheck %s --check-prefix=ERR | ||
|
|
||
| # RUN: lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/func.obj %t.dir/lib.lib 2>&1 | FileCheck %s --check-prefix=NOERR --allow-empty | ||
|
|
||
| # ERR: error: output image has runtime pseudo relocations, but the function _pei386_runtime_relocator is missing; it is needed for fixing the relocations at runtime | ||
|
|
||
| # NOERR-NOT: error | ||
|
|
||
| #--- main.s | ||
| .global main | ||
| .text | ||
| main: | ||
| ret | ||
|
|
||
| .data | ||
| .long 1 | ||
| .quad variable | ||
| .long 2 | ||
|
|
||
| #--- func.s | ||
| .global _pei386_runtime_relocator | ||
| .text | ||
| _pei386_runtime_relocator: | ||
| ret | ||
|
|
||
| #--- lib.def | ||
| EXPORTS | ||
| variable DATA | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| //===-- LibCxxProxyArray.cpp-----------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "LibCxx.h" | ||
|
|
||
| #include "lldb/Core/ValueObject.h" | ||
| #include "lldb/DataFormatters/FormattersHelpers.h" | ||
| #include <optional> | ||
|
|
||
| using namespace lldb; | ||
| using namespace lldb_private; | ||
| using namespace lldb_private::formatters; | ||
|
|
||
| namespace lldb_private { | ||
| namespace formatters { | ||
|
|
||
| /// Data formatter for libc++'s std::"proxy_array". | ||
| /// | ||
| /// A proxy_array's are created by using: | ||
| /// std::gslice_array operator[](const std::gslice& gslicearr); | ||
| /// std::mask_array operator[](const std::valarray<bool>& boolarr); | ||
| /// std::indirect_array operator[](const std::valarray<std::size_t>& indarr); | ||
| /// | ||
| /// These arrays have the following members: | ||
| /// - __vp_ points to std::valarray::__begin_ | ||
| /// - __1d_ an array of offsets of the elements from @a __vp_ | ||
| class LibcxxStdProxyArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { | ||
| public: | ||
| LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); | ||
|
|
||
| ~LibcxxStdProxyArraySyntheticFrontEnd() override; | ||
|
|
||
| llvm::Expected<uint32_t> CalculateNumChildren() override; | ||
|
|
||
| lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; | ||
|
|
||
| lldb::ChildCacheState Update() override; | ||
|
|
||
| bool MightHaveChildren() override; | ||
|
|
||
| size_t GetIndexOfChildWithName(ConstString name) override; | ||
|
|
||
| private: | ||
| /// A non-owning pointer to the array's __vp_. | ||
| ValueObject *m_base = nullptr; | ||
| /// The type of the array's template argument T. | ||
| CompilerType m_element_type; | ||
| /// The sizeof the array's template argument T. | ||
| uint32_t m_element_size = 0; | ||
|
|
||
| /// A non-owning pointer to the array's __1d_.__begin_. | ||
| ValueObject *m_start = nullptr; | ||
| /// A non-owning pointer to the array's __1d_.__end_. | ||
| ValueObject *m_finish = nullptr; | ||
| /// The type of the __1d_ array's template argument T (size_t). | ||
| CompilerType m_element_type_size_t; | ||
| /// The sizeof the __1d_ array's template argument T (size_t) | ||
| uint32_t m_element_size_size_t = 0; | ||
| }; | ||
|
|
||
| } // namespace formatters | ||
| } // namespace lldb_private | ||
|
|
||
| lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: | ||
| LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) | ||
| : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { | ||
| if (valobj_sp) | ||
| Update(); | ||
| } | ||
|
|
||
| lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: | ||
| ~LibcxxStdProxyArraySyntheticFrontEnd() { | ||
| // these need to stay around because they are child objects who will follow | ||
| // their parent's life cycle | ||
| // delete m_base; | ||
| } | ||
|
|
||
| llvm::Expected<uint32_t> lldb_private::formatters:: | ||
| LibcxxStdProxyArraySyntheticFrontEnd::CalculateNumChildren() { | ||
|
|
||
| if (!m_start || !m_finish) | ||
| return 0; | ||
| uint64_t start_val = m_start->GetValueAsUnsigned(0); | ||
| uint64_t finish_val = m_finish->GetValueAsUnsigned(0); | ||
|
|
||
| if (start_val == 0 || finish_val == 0) | ||
| return 0; | ||
|
|
||
| if (start_val >= finish_val) | ||
| return 0; | ||
|
|
||
| size_t num_children = (finish_val - start_val); | ||
| if (num_children % m_element_size_size_t) | ||
| return 0; | ||
| return num_children / m_element_size_size_t; | ||
| } | ||
|
|
||
| lldb::ValueObjectSP | ||
| lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex( | ||
| uint32_t idx) { | ||
| if (!m_base) | ||
| return lldb::ValueObjectSP(); | ||
|
|
||
| uint64_t offset = idx * m_element_size_size_t; | ||
| offset = offset + m_start->GetValueAsUnsigned(0); | ||
|
|
||
| lldb::ValueObjectSP indirect = CreateValueObjectFromAddress( | ||
| "", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t); | ||
| if (!indirect) | ||
| return lldb::ValueObjectSP(); | ||
|
|
||
| const size_t value = indirect->GetValueAsUnsigned(0); | ||
| if (!value) | ||
| return lldb::ValueObjectSP(); | ||
|
|
||
| offset = value * m_element_size; | ||
| offset = offset + m_base->GetValueAsUnsigned(0); | ||
|
|
||
| StreamString name; | ||
| name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value); | ||
| return CreateValueObjectFromAddress(name.GetString(), offset, | ||
| m_backend.GetExecutionContextRef(), | ||
| m_element_type); | ||
| } | ||
|
|
||
| lldb::ChildCacheState | ||
| lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::Update() { | ||
| m_base = nullptr; | ||
| m_start = nullptr; | ||
| m_finish = nullptr; | ||
|
|
||
| CompilerType type = m_backend.GetCompilerType(); | ||
| if (type.GetNumTemplateArguments() == 0) | ||
| return ChildCacheState::eRefetch; | ||
|
|
||
| m_element_type = type.GetTypeTemplateArgument(0); | ||
| if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) | ||
| m_element_size = *size; | ||
|
|
||
| if (m_element_size == 0) | ||
| return ChildCacheState::eRefetch; | ||
|
|
||
| ValueObjectSP vector = m_backend.GetChildMemberWithName("__1d_"); | ||
| if (!vector) | ||
| return ChildCacheState::eRefetch; | ||
|
|
||
| type = vector->GetCompilerType(); | ||
| if (type.GetNumTemplateArguments() == 0) | ||
| return ChildCacheState::eRefetch; | ||
|
|
||
| m_element_type_size_t = type.GetTypeTemplateArgument(0); | ||
| if (std::optional<uint64_t> size = m_element_type_size_t.GetByteSize(nullptr)) | ||
| m_element_size_size_t = *size; | ||
|
|
||
| if (m_element_size_size_t == 0) | ||
| return ChildCacheState::eRefetch; | ||
|
|
||
| ValueObjectSP base = m_backend.GetChildMemberWithName("__vp_"); | ||
| ValueObjectSP start = vector->GetChildMemberWithName("__begin_"); | ||
| ValueObjectSP finish = vector->GetChildMemberWithName("__end_"); | ||
| if (!base || !start || !finish) | ||
| return ChildCacheState::eRefetch; | ||
|
|
||
| m_base = base.get(); | ||
| m_start = start.get(); | ||
| m_finish = finish.get(); | ||
|
|
||
| return ChildCacheState::eRefetch; | ||
| } | ||
|
|
||
| bool lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: | ||
| MightHaveChildren() { | ||
| return true; | ||
| } | ||
|
|
||
| size_t lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: | ||
| GetIndexOfChildWithName(ConstString name) { | ||
| if (!m_base) | ||
| return std::numeric_limits<size_t>::max(); | ||
| return ExtractIndexFromString(name.GetCString()); | ||
| } | ||
|
|
||
| lldb_private::SyntheticChildrenFrontEnd * | ||
| lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator( | ||
| CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { | ||
| if (!valobj_sp) | ||
| return nullptr; | ||
| return new LibcxxStdProxyArraySyntheticFrontEnd(valobj_sp); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,8 @@ | ||
| C_SOURCES := main.c | ||
| asan: CFLAGS_EXTRAS := -fsanitize=address -g -gcolumn-info | ||
| asan: all | ||
|
|
||
| libsanitizers: CFLAGS_EXTRAS := -fsanitize=address -fsanitize-stable-abi -g -gcolumn-info | ||
| libsanitizers: all | ||
|
|
||
| include Makefile.rules |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| def no_libsanitizers(testbase): | ||
| testbase.runCmd("image list libsystem_sanitizers.dylib", check=False) | ||
| return not "libsystem_sanitizers.dylib" in testbase.res.GetOutput() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| add_lldb_unittest(UnwindAssemblyX86ButNoX86TargetTests | ||
| Testx86AssemblyInspectionEngine.cpp | ||
| LINK_LIBS | ||
| lldbCore | ||
| lldbSymbol | ||
| lldbPluginUnwindAssemblyX86 | ||
| LINK_COMPONENTS | ||
| Support | ||
| ${LLVM_TARGETS_TO_BUILD} | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| //===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===// | ||
|
|
||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "gtest/gtest.h" | ||
|
|
||
| #include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h" | ||
| #include "lldb/Core/AddressRange.h" | ||
| #include "lldb/Symbol/UnwindPlan.h" | ||
| #include "lldb/Utility/ArchSpec.h" | ||
|
|
||
| #include "llvm/Support/TargetSelect.h" | ||
|
|
||
| #include <memory> | ||
| #include <vector> | ||
|
|
||
| using namespace lldb; | ||
| using namespace lldb_private; | ||
|
|
||
| class Testx86AssemblyInspectionEngine : public testing::Test { | ||
| public: | ||
| static void SetUpTestCase(); | ||
| }; | ||
|
|
||
| void Testx86AssemblyInspectionEngine::SetUpTestCase() { | ||
| llvm::InitializeAllTargets(); | ||
| llvm::InitializeAllAsmPrinters(); | ||
| llvm::InitializeAllTargetMCs(); | ||
| llvm::InitializeAllDisassemblers(); | ||
| } | ||
|
|
||
| // only defining the register names / numbers that the unwinder is actually | ||
| // using today | ||
|
|
||
| // names should match the constants below. These will be the eRegisterKindLLDB | ||
| // register numbers. | ||
|
|
||
| const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp", | ||
| "rsi", "rdi", "r8", "r9", "r10", "r11", | ||
| "r12", "r13", "r14", "r15", "rip"}; | ||
|
|
||
| enum x86_64_regs { | ||
| k_rax = 0, | ||
| k_rbx = 1, | ||
| k_rcx = 2, | ||
| k_rdx = 3, | ||
| k_rsp = 4, | ||
| k_rbp = 5, | ||
| k_rsi = 6, | ||
| k_rdi = 7, | ||
| k_r8 = 8, | ||
| k_r9 = 9, | ||
| k_r10 = 10, | ||
| k_r11 = 11, | ||
| k_r12 = 12, | ||
| k_r13 = 13, | ||
| k_r14 = 14, | ||
| k_r15 = 15, | ||
| k_rip = 16 | ||
| }; | ||
|
|
||
| std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() { | ||
|
|
||
| ArchSpec arch("x86_64-apple-macosx"); | ||
| std::unique_ptr<x86AssemblyInspectionEngine> engine( | ||
| new x86AssemblyInspectionEngine(arch)); | ||
|
|
||
| std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums; | ||
| int i = 0; | ||
| for (const auto &name : x86_64_reg_names) { | ||
| x86AssemblyInspectionEngine::lldb_reg_info ri; | ||
| ri.name = name; | ||
| ri.lldb_regnum = i++; | ||
| lldb_regnums.push_back(ri); | ||
| } | ||
|
|
||
| engine->Initialize(lldb_regnums); | ||
| return engine; | ||
| } | ||
|
|
||
| TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) { | ||
| std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); | ||
|
|
||
| // 'int main() { }' compiled for x86_64-apple-macosx with clang | ||
| uint8_t data[] = { | ||
| 0x55, // offset 0 -- pushq %rbp | ||
| 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp | ||
| 0x31, 0xc0, // offset 4 -- xorl %eax, %eax | ||
| 0x5d, // offset 6 -- popq %rbp | ||
| 0xc3 // offset 7 -- retq | ||
| }; | ||
|
|
||
| AddressRange sample_range(0x1000, sizeof(data)); | ||
|
|
||
| UnwindPlan unwind_plan(eRegisterKindLLDB); | ||
| EXPECT_FALSE(engine->GetNonCallSiteUnwindPlanFromAssembly( | ||
| data, sizeof(data), sample_range, unwind_plan)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| if(LLDB_TOOL_LLDB_SERVER_BUILD) | ||
| if (NOT LLVM_USE_SANITIZER MATCHES ".*Address.*") | ||
| add_subdirectory(lldb-server) | ||
| endif() | ||
| endif() |