1 //===-- Coroutines.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Coroutines.h" 10 11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 12 13 using namespace lldb; 14 using namespace lldb_private; 15 using namespace lldb_private::formatters; 16 17 static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject &valobj) { 18 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 19 if (!valobj_sp) 20 return nullptr; 21 22 // We expect a single pointer in the `coroutine_handle` class. 23 // We don't care about its name. 24 if (valobj_sp->GetNumChildren() != 1) 25 return nullptr; 26 ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0, true)); 27 if (!ptr_sp) 28 return nullptr; 29 if (!ptr_sp->GetCompilerType().IsPointerType()) 30 return nullptr; 31 32 return ptr_sp; 33 } 34 35 static CompilerType GetCoroutineFrameType(TypeSystemClang &ast_ctx, 36 CompilerType promise_type) { 37 CompilerType void_type = ast_ctx.GetBasicType(lldb::eBasicTypeVoid); 38 CompilerType coro_func_type = ast_ctx.CreateFunctionType( 39 /*result_type=*/void_type, /*args=*/&void_type, /*num_args=*/1, 40 /*is_variadic=*/false, /*qualifiers=*/0); 41 CompilerType coro_abi_type; 42 if (promise_type.IsVoidType()) { 43 coro_abi_type = ast_ctx.CreateStructForIdentifier( 44 ConstString(), {{"resume", coro_func_type.GetPointerType()}, 45 {"destroy", coro_func_type.GetPointerType()}}); 46 } else { 47 coro_abi_type = ast_ctx.CreateStructForIdentifier( 48 ConstString(), {{"resume", coro_func_type.GetPointerType()}, 49 {"destroy", coro_func_type.GetPointerType()}, 50 {"promise", promise_type}}); 51 } 52 return coro_abi_type; 53 } 54 55 bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider( 56 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 57 ValueObjectSP ptr_sp(GetCoroFramePtrFromHandle(valobj)); 58 if (!ptr_sp) 59 return false; 60 61 stream.Printf("coro frame = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 62 return true; 63 } 64 65 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: 66 StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 67 : SyntheticChildrenFrontEnd(*valobj_sp) { 68 if (valobj_sp) 69 Update(); 70 } 71 72 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: 73 ~StdlibCoroutineHandleSyntheticFrontEnd() = default; 74 75 size_t lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: 76 CalculateNumChildren() { 77 if (!m_frame_ptr_sp) 78 return 0; 79 80 return m_frame_ptr_sp->GetNumChildren(); 81 } 82 83 lldb::ValueObjectSP lldb_private::formatters:: 84 StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 85 if (!m_frame_ptr_sp) 86 return lldb::ValueObjectSP(); 87 88 return m_frame_ptr_sp->GetChildAtIndex(idx, true); 89 } 90 91 bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: 92 Update() { 93 m_frame_ptr_sp.reset(); 94 95 ValueObjectSP valobj_sp = m_backend.GetSP(); 96 if (!valobj_sp) 97 return false; 98 99 ValueObjectSP ptr_sp(GetCoroFramePtrFromHandle(m_backend)); 100 if (!ptr_sp) 101 return false; 102 103 TypeSystemClang *ast_ctx = llvm::dyn_cast_or_null<TypeSystemClang>( 104 valobj_sp->GetCompilerType().GetTypeSystem()); 105 if (!ast_ctx) 106 return false; 107 108 CompilerType promise_type( 109 valobj_sp->GetCompilerType().GetTypeTemplateArgument(0)); 110 if (!promise_type) 111 return false; 112 CompilerType coro_frame_type = GetCoroutineFrameType(*ast_ctx, promise_type); 113 114 m_frame_ptr_sp = ptr_sp->Cast(coro_frame_type.GetPointerType()); 115 116 return false; 117 } 118 119 bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: 120 MightHaveChildren() { 121 return true; 122 } 123 124 size_t StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName( 125 ConstString name) { 126 if (!m_frame_ptr_sp) 127 return UINT32_MAX; 128 129 return m_frame_ptr_sp->GetIndexOfChildWithName(name); 130 } 131 132 SyntheticChildrenFrontEnd * 133 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator( 134 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 135 return (valobj_sp ? new StdlibCoroutineHandleSyntheticFrontEnd(valobj_sp) 136 : nullptr); 137 } 138