191389000SAdrian Vogelsgesang //===-- Coroutines.cpp ----------------------------------------------------===//
291389000SAdrian Vogelsgesang //
391389000SAdrian Vogelsgesang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
491389000SAdrian Vogelsgesang // See https://llvm.org/LICENSE.txt for license information.
591389000SAdrian Vogelsgesang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
691389000SAdrian Vogelsgesang //
791389000SAdrian Vogelsgesang //===----------------------------------------------------------------------===//
891389000SAdrian Vogelsgesang
991389000SAdrian Vogelsgesang #include "Coroutines.h"
1091389000SAdrian Vogelsgesang
1191389000SAdrian Vogelsgesang #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1201f4c305SAdrian Vogelsgesang #include "lldb/Symbol/Function.h"
1301f4c305SAdrian Vogelsgesang #include "lldb/Symbol/VariableList.h"
14*624ea68cSAdrian Prantl #include "lldb/Utility/LLDBLog.h"
15*624ea68cSAdrian Prantl #include "lldb/Utility/Log.h"
1691389000SAdrian Vogelsgesang
1791389000SAdrian Vogelsgesang using namespace lldb;
1891389000SAdrian Vogelsgesang using namespace lldb_private;
1991389000SAdrian Vogelsgesang using namespace lldb_private::formatters;
2091389000SAdrian Vogelsgesang
GetCoroFramePtrFromHandle(ValueObjectSP valobj_sp)218aa31375SAdrian Vogelsgesang static lldb::addr_t GetCoroFramePtrFromHandle(ValueObjectSP valobj_sp) {
2291389000SAdrian Vogelsgesang if (!valobj_sp)
238aa31375SAdrian Vogelsgesang return LLDB_INVALID_ADDRESS;
2491389000SAdrian Vogelsgesang
2591389000SAdrian Vogelsgesang // We expect a single pointer in the `coroutine_handle` class.
2691389000SAdrian Vogelsgesang // We don't care about its name.
27*624ea68cSAdrian Prantl if (valobj_sp->GetNumChildrenIgnoringErrors() != 1)
288aa31375SAdrian Vogelsgesang return LLDB_INVALID_ADDRESS;
29a1a74f7cSDave Lee ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0));
3091389000SAdrian Vogelsgesang if (!ptr_sp)
318aa31375SAdrian Vogelsgesang return LLDB_INVALID_ADDRESS;
3291389000SAdrian Vogelsgesang if (!ptr_sp->GetCompilerType().IsPointerType())
338aa31375SAdrian Vogelsgesang return LLDB_INVALID_ADDRESS;
3401f4c305SAdrian Vogelsgesang
35f6d4e687SJason Molenda AddressType addr_type;
368aa31375SAdrian Vogelsgesang lldb::addr_t frame_ptr_addr = ptr_sp->GetPointerValue(&addr_type);
37f6d4e687SJason Molenda if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS)
388aa31375SAdrian Vogelsgesang return LLDB_INVALID_ADDRESS;
39f6d4e687SJason Molenda lldbassert(addr_type == AddressType::eAddressTypeLoad);
408aa31375SAdrian Vogelsgesang if (addr_type != AddressType::eAddressTypeLoad)
418aa31375SAdrian Vogelsgesang return LLDB_INVALID_ADDRESS;
428aa31375SAdrian Vogelsgesang
438aa31375SAdrian Vogelsgesang return frame_ptr_addr;
448aa31375SAdrian Vogelsgesang }
458aa31375SAdrian Vogelsgesang
ExtractDestroyFunction(lldb::TargetSP target_sp,lldb::addr_t frame_ptr_addr)468aa31375SAdrian Vogelsgesang static Function *ExtractDestroyFunction(lldb::TargetSP target_sp,
478aa31375SAdrian Vogelsgesang lldb::addr_t frame_ptr_addr) {
488aa31375SAdrian Vogelsgesang lldb::ProcessSP process_sp = target_sp->GetProcessSP();
498aa31375SAdrian Vogelsgesang auto ptr_size = process_sp->GetAddressByteSize();
50f6d4e687SJason Molenda
5101f4c305SAdrian Vogelsgesang Status error;
522b2f2f66SJason Molenda auto destroy_func_ptr_addr = frame_ptr_addr + ptr_size;
532b2f2f66SJason Molenda lldb::addr_t destroy_func_addr =
542b2f2f66SJason Molenda process_sp->ReadPointerFromMemory(destroy_func_ptr_addr, error);
5501f4c305SAdrian Vogelsgesang if (error.Fail())
5601f4c305SAdrian Vogelsgesang return nullptr;
5701f4c305SAdrian Vogelsgesang
582b2f2f66SJason Molenda Address destroy_func_address;
592b2f2f66SJason Molenda if (!target_sp->ResolveLoadAddress(destroy_func_addr, destroy_func_address))
6001f4c305SAdrian Vogelsgesang return nullptr;
6101f4c305SAdrian Vogelsgesang
628aa31375SAdrian Vogelsgesang return destroy_func_address.CalculateSymbolContextFunction();
6301f4c305SAdrian Vogelsgesang }
6401f4c305SAdrian Vogelsgesang
InferPromiseType(Function & destroy_func)6501f4c305SAdrian Vogelsgesang static CompilerType InferPromiseType(Function &destroy_func) {
6601f4c305SAdrian Vogelsgesang Block &block = destroy_func.GetBlock(true);
6701f4c305SAdrian Vogelsgesang auto variable_list = block.GetBlockVariableList(true);
6801f4c305SAdrian Vogelsgesang
6901f4c305SAdrian Vogelsgesang // clang generates an artificial `__promise` variable inside the
7001f4c305SAdrian Vogelsgesang // `destroy` function. Look for it.
7101f4c305SAdrian Vogelsgesang auto promise_var = variable_list->FindVariable(ConstString("__promise"));
7201f4c305SAdrian Vogelsgesang if (!promise_var)
7301f4c305SAdrian Vogelsgesang return {};
7401f4c305SAdrian Vogelsgesang if (!promise_var->IsArtificial())
7501f4c305SAdrian Vogelsgesang return {};
7601f4c305SAdrian Vogelsgesang
7701f4c305SAdrian Vogelsgesang Type *promise_type = promise_var->GetType();
7801f4c305SAdrian Vogelsgesang if (!promise_type)
7901f4c305SAdrian Vogelsgesang return {};
8001f4c305SAdrian Vogelsgesang return promise_type->GetForwardCompilerType();
8101f4c305SAdrian Vogelsgesang }
8201f4c305SAdrian Vogelsgesang
StdlibCoroutineHandleSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)8391389000SAdrian Vogelsgesang bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider(
8491389000SAdrian Vogelsgesang ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
858aa31375SAdrian Vogelsgesang lldb::addr_t frame_ptr_addr =
868aa31375SAdrian Vogelsgesang GetCoroFramePtrFromHandle(valobj.GetNonSyntheticValue());
878aa31375SAdrian Vogelsgesang if (frame_ptr_addr == LLDB_INVALID_ADDRESS)
8891389000SAdrian Vogelsgesang return false;
8991389000SAdrian Vogelsgesang
908aa31375SAdrian Vogelsgesang if (frame_ptr_addr == 0) {
9101f4c305SAdrian Vogelsgesang stream << "nullptr";
922b2f2f66SJason Molenda } else {
938aa31375SAdrian Vogelsgesang stream.Printf("coro frame = 0x%" PRIx64, frame_ptr_addr);
942b2f2f66SJason Molenda }
958aa31375SAdrian Vogelsgesang
9691389000SAdrian Vogelsgesang return true;
9791389000SAdrian Vogelsgesang }
9891389000SAdrian Vogelsgesang
9991389000SAdrian Vogelsgesang lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)10091389000SAdrian Vogelsgesang StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
10154d4a255SAdrian Vogelsgesang : SyntheticChildrenFrontEnd(*valobj_sp) {
10291389000SAdrian Vogelsgesang if (valobj_sp)
10391389000SAdrian Vogelsgesang Update();
10491389000SAdrian Vogelsgesang }
10591389000SAdrian Vogelsgesang
10691389000SAdrian Vogelsgesang lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
10791389000SAdrian Vogelsgesang ~StdlibCoroutineHandleSyntheticFrontEnd() = default;
10891389000SAdrian Vogelsgesang
109*624ea68cSAdrian Prantl llvm::Expected<uint32_t> lldb_private::formatters::
CalculateNumChildren()110*624ea68cSAdrian Prantl StdlibCoroutineHandleSyntheticFrontEnd::CalculateNumChildren() {
1118aa31375SAdrian Vogelsgesang if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
11291389000SAdrian Vogelsgesang return 0;
11391389000SAdrian Vogelsgesang
1148aa31375SAdrian Vogelsgesang return m_promise_ptr_sp ? 3 : 2;
11591389000SAdrian Vogelsgesang }
11691389000SAdrian Vogelsgesang
11791389000SAdrian Vogelsgesang lldb::ValueObjectSP lldb_private::formatters::
GetChildAtIndex(uint32_t idx)118e710523eSAdrian Prantl StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
1198aa31375SAdrian Vogelsgesang switch (idx) {
1208aa31375SAdrian Vogelsgesang case 0:
1218aa31375SAdrian Vogelsgesang return m_resume_ptr_sp;
1228aa31375SAdrian Vogelsgesang case 1:
1238aa31375SAdrian Vogelsgesang return m_destroy_ptr_sp;
1248aa31375SAdrian Vogelsgesang case 2:
1258aa31375SAdrian Vogelsgesang return m_promise_ptr_sp;
1268aa31375SAdrian Vogelsgesang }
12791389000SAdrian Vogelsgesang return lldb::ValueObjectSP();
12891389000SAdrian Vogelsgesang }
12991389000SAdrian Vogelsgesang
130d7fb94b6SMichael Buch lldb::ChildCacheState
Update()131d7fb94b6SMichael Buch lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
1328aa31375SAdrian Vogelsgesang m_resume_ptr_sp.reset();
1338aa31375SAdrian Vogelsgesang m_destroy_ptr_sp.reset();
1348aa31375SAdrian Vogelsgesang m_promise_ptr_sp.reset();
13591389000SAdrian Vogelsgesang
1368aa31375SAdrian Vogelsgesang ValueObjectSP valobj_sp = m_backend.GetNonSyntheticValue();
13791389000SAdrian Vogelsgesang if (!valobj_sp)
138d7fb94b6SMichael Buch return lldb::ChildCacheState::eRefetch;
13991389000SAdrian Vogelsgesang
1408aa31375SAdrian Vogelsgesang lldb::addr_t frame_ptr_addr = GetCoroFramePtrFromHandle(valobj_sp);
1418aa31375SAdrian Vogelsgesang if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS)
142d7fb94b6SMichael Buch return lldb::ChildCacheState::eRefetch;
14391389000SAdrian Vogelsgesang
1448aa31375SAdrian Vogelsgesang auto ts = valobj_sp->GetCompilerType().GetTypeSystem();
1458aa31375SAdrian Vogelsgesang auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>();
1468aa31375SAdrian Vogelsgesang if (!ast_ctx)
147d7fb94b6SMichael Buch return lldb::ChildCacheState::eRefetch;
1488aa31375SAdrian Vogelsgesang
1498aa31375SAdrian Vogelsgesang // Create the `resume` and `destroy` children.
1508aa31375SAdrian Vogelsgesang lldb::TargetSP target_sp = m_backend.GetTargetSP();
1518aa31375SAdrian Vogelsgesang auto &exe_ctx = m_backend.GetExecutionContextRef();
1528aa31375SAdrian Vogelsgesang lldb::ProcessSP process_sp = target_sp->GetProcessSP();
1538aa31375SAdrian Vogelsgesang auto ptr_size = process_sp->GetAddressByteSize();
1548aa31375SAdrian Vogelsgesang CompilerType void_type = ast_ctx->GetBasicType(lldb::eBasicTypeVoid);
1558aa31375SAdrian Vogelsgesang CompilerType coro_func_type = ast_ctx->CreateFunctionType(
1568aa31375SAdrian Vogelsgesang /*result_type=*/void_type, /*args=*/&void_type, /*num_args=*/1,
1578aa31375SAdrian Vogelsgesang /*is_variadic=*/false, /*qualifiers=*/0);
1588aa31375SAdrian Vogelsgesang CompilerType coro_func_ptr_type = coro_func_type.GetPointerType();
1598aa31375SAdrian Vogelsgesang m_resume_ptr_sp = CreateValueObjectFromAddress(
1608aa31375SAdrian Vogelsgesang "resume", frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
1618aa31375SAdrian Vogelsgesang lldbassert(m_resume_ptr_sp);
1628aa31375SAdrian Vogelsgesang m_destroy_ptr_sp = CreateValueObjectFromAddress(
1638aa31375SAdrian Vogelsgesang "destroy", frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
1648aa31375SAdrian Vogelsgesang lldbassert(m_destroy_ptr_sp);
1658aa31375SAdrian Vogelsgesang
16601f4c305SAdrian Vogelsgesang // Get the `promise_type` from the template argument
16791389000SAdrian Vogelsgesang CompilerType promise_type(
16891389000SAdrian Vogelsgesang valobj_sp->GetCompilerType().GetTypeTemplateArgument(0));
16991389000SAdrian Vogelsgesang if (!promise_type)
170d7fb94b6SMichael Buch return lldb::ChildCacheState::eRefetch;
17101f4c305SAdrian Vogelsgesang
17201f4c305SAdrian Vogelsgesang // Try to infer the promise_type if it was type-erased
1732b2f2f66SJason Molenda if (promise_type.IsVoidType()) {
1748aa31375SAdrian Vogelsgesang if (Function *destroy_func =
1758aa31375SAdrian Vogelsgesang ExtractDestroyFunction(target_sp, frame_ptr_addr)) {
17601f4c305SAdrian Vogelsgesang if (CompilerType inferred_type = InferPromiseType(*destroy_func)) {
17754d4a255SAdrian Vogelsgesang promise_type = inferred_type;
17801f4c305SAdrian Vogelsgesang }
17901f4c305SAdrian Vogelsgesang }
1802b2f2f66SJason Molenda }
18101f4c305SAdrian Vogelsgesang
1828aa31375SAdrian Vogelsgesang // If we don't know the promise type, we don't display the `promise` member.
1838aa31375SAdrian Vogelsgesang // `CreateValueObjectFromAddress` below would fail for `void` types.
1848aa31375SAdrian Vogelsgesang if (promise_type.IsVoidType()) {
185d7fb94b6SMichael Buch return lldb::ChildCacheState::eRefetch;
1868aa31375SAdrian Vogelsgesang }
187f6d4e687SJason Molenda
1888aa31375SAdrian Vogelsgesang // Add the `promise` member. We intentionally add `promise` as a pointer type
1898aa31375SAdrian Vogelsgesang // instead of a value type, and don't automatically dereference this pointer.
1908aa31375SAdrian Vogelsgesang // We do so to avoid potential very deep recursion in case there is a cycle
1918aa31375SAdrian Vogelsgesang // formed between `std::coroutine_handle`s and their promises.
1928aa31375SAdrian Vogelsgesang lldb::ValueObjectSP promise = CreateValueObjectFromAddress(
1938aa31375SAdrian Vogelsgesang "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type);
1948aa31375SAdrian Vogelsgesang Status error;
1958aa31375SAdrian Vogelsgesang lldb::ValueObjectSP promisePtr = promise->AddressOf(error);
1968aa31375SAdrian Vogelsgesang if (error.Success())
1978aa31375SAdrian Vogelsgesang m_promise_ptr_sp = promisePtr->Clone(ConstString("promise"));
19891389000SAdrian Vogelsgesang
199d7fb94b6SMichael Buch return lldb::ChildCacheState::eRefetch;
20091389000SAdrian Vogelsgesang }
20191389000SAdrian Vogelsgesang
20291389000SAdrian Vogelsgesang bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
MightHaveChildren()20391389000SAdrian Vogelsgesang MightHaveChildren() {
20491389000SAdrian Vogelsgesang return true;
20591389000SAdrian Vogelsgesang }
20691389000SAdrian Vogelsgesang
GetIndexOfChildWithName(ConstString name)20791389000SAdrian Vogelsgesang size_t StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName(
20891389000SAdrian Vogelsgesang ConstString name) {
2098aa31375SAdrian Vogelsgesang if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
21091389000SAdrian Vogelsgesang return UINT32_MAX;
21191389000SAdrian Vogelsgesang
2128aa31375SAdrian Vogelsgesang if (name == ConstString("resume"))
2138aa31375SAdrian Vogelsgesang return 0;
2148aa31375SAdrian Vogelsgesang if (name == ConstString("destroy"))
2158aa31375SAdrian Vogelsgesang return 1;
2168aa31375SAdrian Vogelsgesang if (name == ConstString("promise_ptr") && m_promise_ptr_sp)
2178aa31375SAdrian Vogelsgesang return 2;
2188aa31375SAdrian Vogelsgesang
2198aa31375SAdrian Vogelsgesang return UINT32_MAX;
22091389000SAdrian Vogelsgesang }
22191389000SAdrian Vogelsgesang
22291389000SAdrian Vogelsgesang SyntheticChildrenFrontEnd *
StdlibCoroutineHandleSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)22391389000SAdrian Vogelsgesang lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator(
22491389000SAdrian Vogelsgesang CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
22591389000SAdrian Vogelsgesang return (valobj_sp ? new StdlibCoroutineHandleSyntheticFrontEnd(valobj_sp)
22691389000SAdrian Vogelsgesang : nullptr);
22791389000SAdrian Vogelsgesang }
228