[Lldb-commits] [lldb] [LLDB] Don't ignore artificial variables and members for coroutines (PR #70779)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/70779 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Don't ignore artificial variables and members for coroutines (PR #70779)
@@ -41,7 +41,10 @@ CPPLanguageRuntime::CPPLanguageRuntime(Process *process) : LanguageRuntime(process) {} bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { - return name == g_this; + // FIXME: use a list when the list grows more. + return name == g_this || + name == ConstString("__promise") || + name == ConstString("__coro_frame"); vogelsgesang wrote: I am not sure if I would expose the `__coro_frame` variable. Maybe I would only expose the `__promise` variable by default. The `__coro_frame` is usually out-of-sync and does not hold the up-to-date coroutine state while the coroutine is in flight https://github.com/llvm/llvm-project/pull/70779 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Don't ignore artificial variables and members for coroutines (PR #70779)
https://github.com/vogelsgesang commented: I can't provide feedback on the lldb integration aspects, as I don't know the lldb code base well enough https://github.com/llvm/llvm-project/pull/70779 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 54d4a25 - [LLDB] Fix assertion failure by removing `CopyType` in `std::coroutine_handle` pretty printer
Author: Adrian Vogelsgesang Date: 2023-02-08T10:22:50-08:00 New Revision: 54d4a2550d3167d51a9d386d9823a06aca459531 URL: https://github.com/llvm/llvm-project/commit/54d4a2550d3167d51a9d386d9823a06aca459531 DIFF: https://github.com/llvm/llvm-project/commit/54d4a2550d3167d51a9d386d9823a06aca459531.diff LOG: [LLDB] Fix assertion failure by removing `CopyType` in `std::coroutine_handle` pretty printer The pretty printer for `std::coroutine_handle` was running into > Assertion failed: (target_ctx != source_ctx && "Can't import into itself") from ClangASTImporter.h, line 270. This commit fixes the issue by removing the `CopyType` call from the pretty printer. While this call was necessary in the past, it seems to be no longer required, at least all test cases are still passing. Maybe something changed in the meantime around the handling of `TypesystemClang` instances. I don't quite understand why `CopyType` was necessary earlier. I am not sure how to add a regression test for this, though. It seems the issue is already triggered by the exising `TestCoroutineHandle.py`, but API tests seem to ignore all violations of `lldbassert` and still report the test as "passed", even if assertions were triggered Differential Revision: https://reviews.llvm.org/D143127 Added: Modified: lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/source/Plugins/Language/CPlusPlus/Coroutines.h Removed: diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index bd428a812531a..c5170757496f1 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -8,7 +8,6 @@ #include "Coroutines.h" -#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/VariableList.h" @@ -97,8 +96,7 @@ bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider( lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) -: SyntheticChildrenFrontEnd(*valobj_sp), - m_ast_importer(std::make_unique()) { +: SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } @@ -174,8 +172,7 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: if (Function *destroy_func = ExtractDestroyFunction(target_sp, frame_ptr_addr)) { if (CompilerType inferred_type = InferPromiseType(*destroy_func)) { -// Copy the type over to the correct `TypeSystemClang` instance -promise_type = m_ast_importer->CopyType(*ast_ctx, inferred_type); +promise_type = inferred_type; } } } diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h index e2e640ab48430..b26cc9ed6132d 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h @@ -16,8 +16,6 @@ namespace lldb_private { -class ClangASTImporter; - namespace formatters { /// Summary provider for `std::coroutine_handle` from libc++, libstdc++ and @@ -50,7 +48,6 @@ class StdlibCoroutineHandleSyntheticFrontEnd lldb::ValueObjectSP m_resume_ptr_sp; lldb::ValueObjectSP m_destroy_ptr_sp; lldb::ValueObjectSP m_promise_ptr_sp; - std::unique_ptr m_ast_importer; }; SyntheticChildrenFrontEnd * ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 8aa3137 - [LLDB] Do not dereference promise pointer in `coroutine_handle` pretty printer
Author: Adrian Vogelsgesang Date: 2023-01-31T07:40:31-08:00 New Revision: 8aa313755118bf43c6042fb316b6c243b2c59be2 URL: https://github.com/llvm/llvm-project/commit/8aa313755118bf43c6042fb316b6c243b2c59be2 DIFF: https://github.com/llvm/llvm-project/commit/8aa313755118bf43c6042fb316b6c243b2c59be2.diff LOG: [LLDB] Do not dereference promise pointer in `coroutine_handle` pretty printer So far, the pretty printer for `std::coroutine_handle` internally dereferenced the contained frame pointer displayed the `promise` as a sub-value. As noticed in https://reviews.llvm.org/D132624 by @labath, this can lead to an endless loop in lldb during printing if the coroutine frame pointers form a cycle. This commit breaks the cycle by exposing the `promise` as a pointer type instead of a value type. The depth to which the `frame variable` and the `expression` commands dereference those pointers can be controlled using the `--ptr-depth` argument. Differential Revision: https://reviews.llvm.org/D132815 Added: Modified: lldb/packages/Python/lldbsuite/test/lldbtest.py lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/source/Plugins/Language/CPlusPlus/Coroutines.h lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py Removed: diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 97fe14e769cdd..e2c076132fc63 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -247,7 +247,7 @@ def which(program): class ValueCheck: def __init__(self, name=None, value=None, type=None, summary=None, - children=None): + children=None, dereference=None): """ :param name: The name that the SBValue should have. None if the summary should not be checked. @@ -262,12 +262,15 @@ def __init__(self, name=None, value=None, type=None, summary=None, The order of checks is the order of the checks in the list. The number of checks has to match the number of children. +:param dereference: A ValueCheck for the SBValue returned by the +`Dereference` function. """ self.expect_name = name self.expect_value = value self.expect_type = type self.expect_summary = summary self.children = children +self.dereference = dereference def check_value(self, test_base, val, error_msg=None): """ @@ -309,6 +312,9 @@ def check_value(self, test_base, val, error_msg=None): if self.children is not None: self.check_value_children(test_base, val, error_msg) +if self.dereference is not None: +self.dereference.check_value(test_base, val.Dereference(), error_msg) + def check_value_children(self, test_base, val, error_msg=None): """ Checks that the children of a SBValue match a certain structure and diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index bd9ff99db67b8..bd428a812531a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -17,38 +17,37 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; -static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject ) { - ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); +static lldb::addr_t GetCoroFramePtrFromHandle(ValueObjectSP valobj_sp) { if (!valobj_sp) -return nullptr; +return LLDB_INVALID_ADDRESS; // We expect a single pointer in the `coroutine_handle` class. // We don't care about its name. if (valobj_sp->GetNumChildren() != 1) -return nullptr; +return LLDB_INVALID_ADDRESS; ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0, true)); if (!ptr_sp) -return nullptr; +return LLDB_INVALID_ADDRESS; if (!ptr_sp->GetCompilerType().IsPointerType()) -return nullptr; - - return ptr_sp; -} - -static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { - lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP(); - lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP(); - auto ptr_size = process_sp->GetAddressByteSize(); +return LLDB_INVALID_ADDRESS; AddressType addr_type; - lldb::addr_t frame_ptr_addr = frame_ptr_sp->GetPointerValue(_type); + lldb::addr_t frame_ptr_addr = ptr_sp->GetPointerValue(_type); if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS) -return nullptr; +return LLDB_INVALID_ADDRESS; lldbassert(addr_type == AddressType::eAddressTypeLoad); + if (addr_type != AddressType::eAddressTypeLoad) +
Re: [Lldb-commits] green dragon testsuite crash on TestCoroutineHandle.py from coroutines formatter changes, temporarily revert?
> I don't know what tools are installed on the builder but I'll ask around the office on Monday, I know there are people who are more familiar with how these bots are set up. Sounds good. Thank you! > FWIW I could repo promise_type failure on my macOS desktop which has the current Xcode 14 tools installed You mean you were able to reproduce the crash? Or were you able to reproduce the test failure described in https://github.com/llvm/llvm-project/commit/2b2f2f66141d52dc0d3082ddd12805d36872a189 also on your macOS desktop? My current hypothesis is: 1. https://github.com/llvm/llvm-project/commit/4346318f5c700f4e85f866610fb8328fc429319b failed because - green dragon is using an outdated pre-release version of clang - as commented in the test case "clang version < 16 did not yet write debug info for the noop coroutines." - the test case hence uses the condition "if not (is_clang and self.expectedCompilerVersion(["<", "16"])):"" to only expect check this test expectation on recent enough compilers - my understanding is that "clang-16 development builds" would pass this version check, even if they did not yet include https://reviews.llvm.org/D132580 and then fail the test expectation - If it turns out to be true that green dragon uses an older clang-version, I would propose the following course of action: - Somebody should upgrades the version of clang used in green dragon - I resubmit this change unchanged 2. https://github.com/llvm/llvm-project/commit/cd3091a88f7c55c90d9b5fff372ce1cdfc71948d - was indeed buggy. This commit turned a "missing debug information" situation into a crash - I am pretty sure that Apple clang version 14.0.0 did not contain https://reviews.llvm.org/D132580, and is hence missing the debug information. This would explain the crash on your mac Desktop. - I would first wait after we resolved the issues around the first commit, though, because rebasing this commit so it can be applied before 4346318f5c700f4e85f866610fb8328fc429319b would be cumbersome - I will then add the additional `if (!promise_type.isVoid())` check, so we no longer crash on missing debug info, and then re-apply the patch Do you agree with that plan? Do you know somebody who can update clang on green dragon? Cheers, Adrian On Sat, Nov 26, 2022 at 3:24 AM Jason Molenda wrote: > FWIW I could repo promise_type failure on my macOS desktop which has the > current Xcode 14 tools installed, but I can't tell you exactly what this > corresponds to in github hash terms (it's "Apple clang version 14.0.0 > (clang-1400.0.29.100)"), I think it was originally branched 2021-10-26, > although there have been a lot of cherrypicks pulled in too, so it's not an > exact snapshot of October 26 sources. > > J > > > On Nov 25, 2022, at 2:22 PM, Adrian Vogelsgesang < > avogelsges...@salesforce.com> wrote: > > > > Hm... wait a second... > > > > Which clang-version is > https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/ using? Is it > using an older version of clang? Does that version already contain the > patch https://reviews.llvm.org/D132580? > > > > If not, that might explain things... > > > > On Fri, Nov 25, 2022 at 11:18 PM Adrian Vogelsgesang < > avogelsges...@salesforce.com> wrote: > > Hi Jason, > > > > Sorry for the late reply - your mail got caught in my spam filter, and I > just realized about the build breakage now after you reverted the commits. > Just to confirm: > > > > I looked at the original change again, and I think I know what's going > wrong here: Devirtualization fails, and `promise_type` stays `void`. > Obviously, `CreateValueObjectFromAddress` cannot create an object of type > `void` and fails. The previous version was robust against that scenario, > but https://reviews.llvm.org/D132815 accidentally regressed this. > > > > If a program has all the expected debug info, devirtualization should > never fail and `promise_type` never stays `void`. It seems something is > wrong/unexpected with the debug info on Darwin. Devirtualization relies on > being able to identify the function pointer of the `destroy` function and > inspects that function. So the root cause seems to be the same as for the > revert > https://github.com/llvm/llvm-project/commit/2b2f2f66141d52dc0d3082ddd12805d36872a189: > For some reason, the debugger cannot find debug info for the function > pointed to by the `destroy` function. > > > > However, I still don't quite understand what's wrong with the debug info > on Mac. > > > > Either way, the pretty printer should of course be robust against such > unexpected debug info. I think a simple additional check should be enough > to make this robust so we no longer crash: > > if (!promise_type.isVoid()) { // < additional check > > lldb::ValueObjectSP promise = CreateValueObjectFromAddress( > > "promise", frame_ptr_addr + 2 *
Re: [Lldb-commits] green dragon testsuite crash on TestCoroutineHandle.py from coroutines formatter changes, temporarily revert?
Hm... wait a second... Which clang-version is https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/ using? Is it using an older version of clang? Does that version already contain the patch https://reviews.llvm.org/D132580? If not, that might explain things... On Fri, Nov 25, 2022 at 11:18 PM Adrian Vogelsgesang < avogelsges...@salesforce.com> wrote: > Hi Jason, > > Sorry for the late reply - your mail got caught in my spam filter, and I > just realized about the build breakage now after you reverted the commits. > Just to confirm: > > I looked at the original change again, and I think I know what's going > wrong here: Devirtualization fails, and `promise_type` stays `void`. > Obviously, `CreateValueObjectFromAddress` cannot create an object of type > `void` and fails. The previous version was robust against that scenario, > but https://reviews.llvm.org/D132815 accidentally regressed this. > > If a program has all the expected debug info, devirtualization should > never fail and `promise_type` never stays `void`. It seems something is > wrong/unexpected with the debug info on Darwin. Devirtualization relies on > being able to identify the function pointer of the `destroy` function and > inspects that function. So the root cause seems to be the same as for the > revert > https://github.com/llvm/llvm-project/commit/2b2f2f66141d52dc0d3082ddd12805d36872a189: > For some reason, the debugger cannot find debug info for the function > pointed to by the `destroy` function. > > However, I still don't quite understand what's wrong with the debug info > on Mac. > > Either way, the pretty printer should of course be robust against such > unexpected debug info. I think a simple additional check should be enough > to make this robust so we no longer crash: > if (!promise_type.isVoid()) { // < additional check > lldb::ValueObjectSP promise = CreateValueObjectFromAddress( > "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type); > Status error; > lldb::ValueObjectSP promisePtr = promise->AddressOf(error); > if (error.Success()) > m_promise_ptr_sp = promisePtr->Clone(ConstString("promise")); > } > > Meta question: I am a bit confused about > https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/. I thought > LLVM's buildbots were set up to send an email in case somebody breaks the > build. Also, I made sure that all builds in > https://lab.llvm.org/buildbot/#/builders stayed green after my commit. So > what are the expectations around which CIs need to stay green after a > commit? Do I need to setup anything such that green.lab.llvm.org also > sends me an email if I break it? > > Cheers, > Adrian > > On Thu, Nov 24, 2022 at 10:50 PM Jason Molenda wrote: > >> Ah, little misstatement below. My first thought was that promise_type >> was null, but when I stepped through here with a debugger, it was not. I >> didn't know how to dig in to a CompilerType object but there was some >> reason why this CreateValueObjectFromAddress failed to return an actual >> ValueObject, and I assumed it's something to do with that CompilerType. >> But I didn't dig in far enough to understand what the issue in the type was. >> >> > On Nov 24, 2022, at 1:20 PM, Jason Molenda wrote: >> > >> > Hi Adrian, the green dragon Incremental CI bot has been failing the >> past couple of days after the changes for the coroutines formatter, most >> directly https://reviews.llvm.org/D132815 landed - >> TestCoroutineHandle.py results in a segfault on Darwin systems (both on the >> CI and on my mac desktop) consistently. >> https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/ >> > >> > It's crashing in formatters::StdlibCoroutineHandleSyntheticFrontEnd >> where you're doing >> > >> > ``` >> > // Add the `promise` member. We intentionally add `promise` as a >> pointer type >> > // instead of a value type, and don't automatically dereference this >> pointer. >> > // We do so to avoid potential very deep recursion in case there is a >> cycle in >> > // formed between `std::coroutine_handle`s and their promises. >> > lldb::ValueObjectSP promise = CreateValueObjectFromAddress( >> > "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type); >> > Status error; >> > lldb::ValueObjectSP promisePtr = promise->AddressOf(error); >> > ``` >> > >> > and the promise_type dose not have a CompilerType so promisePtr is >> nullptr and we crash on the method call to AddressOf. I looked briefly, but >> this isn't a part of lldb I know well and I'm not sure the nature of the >> problem. >> > >> > It's a long weekend in the US, so if you have a suggestion for >> addressing this that'd be great, or I can roll back the changes necessary >> to get the bot clean later today and we can look at this next week. >> > >> > Thanks! >> >> >> ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
Re: [Lldb-commits] green dragon testsuite crash on TestCoroutineHandle.py from coroutines formatter changes, temporarily revert?
Hi Jason, Sorry for the late reply - your mail got caught in my spam filter, and I just realized about the build breakage now after you reverted the commits. Just to confirm: I looked at the original change again, and I think I know what's going wrong here: Devirtualization fails, and `promise_type` stays `void`. Obviously, `CreateValueObjectFromAddress` cannot create an object of type `void` and fails. The previous version was robust against that scenario, but https://reviews.llvm.org/D132815 accidentally regressed this. If a program has all the expected debug info, devirtualization should never fail and `promise_type` never stays `void`. It seems something is wrong/unexpected with the debug info on Darwin. Devirtualization relies on being able to identify the function pointer of the `destroy` function and inspects that function. So the root cause seems to be the same as for the revert https://github.com/llvm/llvm-project/commit/2b2f2f66141d52dc0d3082ddd12805d36872a189: For some reason, the debugger cannot find debug info for the function pointed to by the `destroy` function. However, I still don't quite understand what's wrong with the debug info on Mac. Either way, the pretty printer should of course be robust against such unexpected debug info. I think a simple additional check should be enough to make this robust so we no longer crash: if (!promise_type.isVoid()) { // < additional check lldb::ValueObjectSP promise = CreateValueObjectFromAddress( "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type); Status error; lldb::ValueObjectSP promisePtr = promise->AddressOf(error); if (error.Success()) m_promise_ptr_sp = promisePtr->Clone(ConstString("promise")); } Meta question: I am a bit confused about https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/. I thought LLVM's buildbots were set up to send an email in case somebody breaks the build. Also, I made sure that all builds in https://lab.llvm.org/buildbot/#/builders stayed green after my commit. So what are the expectations around which CIs need to stay green after a commit? Do I need to setup anything such that green.lab.llvm.org also sends me an email if I break it? Cheers, Adrian On Thu, Nov 24, 2022 at 10:50 PM Jason Molenda wrote: > Ah, little misstatement below. My first thought was that promise_type was > null, but when I stepped through here with a debugger, it was not. I > didn't know how to dig in to a CompilerType object but there was some > reason why this CreateValueObjectFromAddress failed to return an actual > ValueObject, and I assumed it's something to do with that CompilerType. > But I didn't dig in far enough to understand what the issue in the type was. > > > On Nov 24, 2022, at 1:20 PM, Jason Molenda wrote: > > > > Hi Adrian, the green dragon Incremental CI bot has been failing the past > couple of days after the changes for the coroutines formatter, most > directly https://reviews.llvm.org/D132815 landed - > TestCoroutineHandle.py results in a segfault on Darwin systems (both on the > CI and on my mac desktop) consistently. > https://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/ > > > > It's crashing in formatters::StdlibCoroutineHandleSyntheticFrontEnd > where you're doing > > > > ``` > > // Add the `promise` member. We intentionally add `promise` as a > pointer type > > // instead of a value type, and don't automatically dereference this > pointer. > > // We do so to avoid potential very deep recursion in case there is a > cycle in > > // formed between `std::coroutine_handle`s and their promises. > > lldb::ValueObjectSP promise = CreateValueObjectFromAddress( > > "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type); > > Status error; > > lldb::ValueObjectSP promisePtr = promise->AddressOf(error); > > ``` > > > > and the promise_type dose not have a CompilerType so promisePtr is > nullptr and we crash on the method call to AddressOf. I looked briefly, but > this isn't a part of lldb I know well and I'm not sure the nature of the > problem. > > > > It's a long weekend in the US, so if you have a suggestion for > addressing this that'd be great, or I can roll back the changes necessary > to get the bot clean later today and we can look at this next week. > > > > Thanks! > > > ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
Re: [Lldb-commits] [PATCH] D132624: [LLDB] Devirtualize coroutine promise types for `std::coroutine_handle`
Thank you for that hint, Jim! This infrastructure indeed looks very interesting for my use case. I will most likely use the HistoryThread class to represent the backtrace of the logical coroutine threads. Is my understanding correct, that `GetExtendedBacktraceThreads` only allows me to append additional stack trace frames to existing, physical threads, though? I want to expose completely new threads instead. In a sense, I want to display each pending request inside my asynchronous multiplexer as its own thread, such that I can see not only the requests which an OS-level thread is currently working on, but also the onse which are currently queued/not yet processed/blocked on IO On Fri, Aug 26, 2022 at 6:38 PM Jim Ingham wrote: > > > > On Aug 26, 2022, at 7:05 AM, Adrian Vogelsgesang via Phabricator via > lldb-commits wrote: > > > > avogelsgesang added a comment. > > > >> I don't know much about coroutines, but it seems like your goal is to > format them like a linked list > > > > actually, my preferred goal would be to show them as a logical, > user-level thread. Such that you can type > > > > thread backtrace cxxcoro:0xb2a0 > > > > to get the backtrace of the logical coroutine thread routed at the > coroutine at address `0xb2a0`, or maybe even > > > > thread backtrace cxxcoro:hdl > > > > where `hdl` is evaluated as an expression to identify the coroutine > handle from where to dump the backtrace. > > > > Also, it would be neat if those logical threads show up in `thread > list`... > > > > But it seems there is currently no infrastructure yet in LLDB for > logical threads provided by `LanguageRuntime` plugins. > > > > I guess at some point, I will write an RFC about that on discourse. But > before that, I will first do some more exploration on how LLDB works and I > will first grab the low-hanging fruits (like a data formatter for > `std::coroutine_handle` and patching LLVM to emit the necessary debug info) > > lldb has the notion of "extended backtrace threads" - backed by lldb's > "History" threads - that it uses in a similar circumstance handling Darwin > dispatch queues. If you have a thread that is serving a Darwin "dispatch > queue" SBThread.GetExtendedBacktraceThreads will return the backtrace of > the thread that enqueued the work, at the point where the enqueuing is > done. I bet you could make the same setup work for these coroutines. > > Jim > > > > > > > > Repository: > > rG LLVM Github Monorepo > > > > CHANGES SINCE LAST ACTION > > https://reviews.llvm.org/D132624/new/ > > > > https://reviews.llvm.org/D132624 > > > > ___ > > lldb-commits mailing list > > lldb-commits@lists.llvm.org > > https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits > > ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] cd3091a - [LLDB] Do not dereference promise pointer in `coroutine_handle` pretty printer
Author: Adrian Vogelsgesang Date: 2022-11-20T14:26:36-08:00 New Revision: cd3091a88f7c55c90d9b5fff372ce1cdfc71948d URL: https://github.com/llvm/llvm-project/commit/cd3091a88f7c55c90d9b5fff372ce1cdfc71948d DIFF: https://github.com/llvm/llvm-project/commit/cd3091a88f7c55c90d9b5fff372ce1cdfc71948d.diff LOG: [LLDB] Do not dereference promise pointer in `coroutine_handle` pretty printer So far, the pretty printer for `std::coroutine_handle` internally dereferenced the contained frame pointer displayed the `promise` as a sub-value. As noticed in https://reviews.llvm.org/D132624 by @labath, this can lead to an endless loop in lldb during printing if the coroutine frame pointers form a cycle. This commit breaks the cycle by exposing the `promise` as a pointer type instead of a value type. The depth to which the `frame variable` and the `expression` commands dereference those pointers can be controlled using the `--ptr-depth` argument. Differential Revision: https://reviews.llvm.org/D132815 Added: Modified: lldb/packages/Python/lldbsuite/test/lldbtest.py lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/source/Plugins/Language/CPlusPlus/Coroutines.h lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py Removed: diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 63bad9d0241de..f579a0160b2b7 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -246,7 +246,7 @@ def which(program): class ValueCheck: def __init__(self, name=None, value=None, type=None, summary=None, - children=None): + children=None, dereference=None): """ :param name: The name that the SBValue should have. None if the summary should not be checked. @@ -261,12 +261,15 @@ def __init__(self, name=None, value=None, type=None, summary=None, The order of checks is the order of the checks in the list. The number of checks has to match the number of children. +:param dereference: A ValueCheck for the SBValue returned by the +`Dereference` function. """ self.expect_name = name self.expect_value = value self.expect_type = type self.expect_summary = summary self.children = children +self.dereference = dereference def check_value(self, test_base, val, error_msg=None): """ @@ -308,6 +311,9 @@ def check_value(self, test_base, val, error_msg=None): if self.children is not None: self.check_value_children(test_base, val, error_msg) +if self.dereference is not None: +self.dereference.check_value(test_base, val.Dereference(), error_msg) + def check_value_children(self, test_base, val, error_msg=None): """ Checks that the children of a SBValue match a certain structure and diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index aa6a6ef7e56ae..7e1302c7eb785 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -17,34 +17,35 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; -static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject ) { - ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); +static lldb::addr_t GetCoroFramePtrFromHandle(ValueObjectSP valobj_sp) { if (!valobj_sp) -return nullptr; +return LLDB_INVALID_ADDRESS; // We expect a single pointer in the `coroutine_handle` class. // We don't care about its name. if (valobj_sp->GetNumChildren() != 1) -return nullptr; +return LLDB_INVALID_ADDRESS; ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0, true)); if (!ptr_sp) -return nullptr; +return LLDB_INVALID_ADDRESS; if (!ptr_sp->GetCompilerType().IsPointerType()) -return nullptr; - - return ptr_sp; -} - -static Function *ExtractFunction(ValueObjectSP _ptr_sp, int offset) { - lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP(); - lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP(); - auto ptr_size = process_sp->GetAddressByteSize(); +return LLDB_INVALID_ADDRESS; AddressType addr_type; - lldb::addr_t frame_ptr_addr = frame_ptr_sp->GetPointerValue(_type); + lldb::addr_t frame_ptr_addr = ptr_sp->GetPointerValue(_type); if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS) -return nullptr; +return LLDB_INVALID_ADDRESS; lldbassert(addr_type == AddressType::eAddressTypeLoad); + if (addr_type !=
[Lldb-commits] [lldb] 4346318 - [LLDB] Recognize `std::noop_coroutine()` in `std::coroutine_handle` pretty printer
Author: Adrian Vogelsgesang Date: 2022-11-20T11:18:52-08:00 New Revision: 4346318f5c700f4e85f866610fb8328fc429319b URL: https://github.com/llvm/llvm-project/commit/4346318f5c700f4e85f866610fb8328fc429319b DIFF: https://github.com/llvm/llvm-project/commit/4346318f5c700f4e85f866610fb8328fc429319b.diff LOG: [LLDB] Recognize `std::noop_coroutine()` in `std::coroutine_handle` pretty printer With this commit, the `std::coroutine_handle` pretty printer now recognizes `std::noop_coroutine()` handles. For noop coroutine handles, we identify use the summary string `noop_coroutine` and we don't print children Instead of ``` (std::coroutine_handle) $3 = coro frame = 0x9058 { resume = 0x64f0 (a.out`std::__1::coroutine_handle::__noop_coroutine_frame_ty_::__dummy_resume_destroy_func() at noop_coroutine_handle.h:79) destroy = 0x64f0 (a.out`std::__1::coroutine_handle::__noop_coroutine_frame_ty_::__dummy_resume_destroy_func() at noop_coroutine_handle.h:79) } ``` we now print ``` (std::coroutine_handle) $3 = noop_coroutine ``` Differential Revision: https://reviews.llvm.org/D132735 Added: Modified: lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/main.cpp Removed: diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index bd9ff99db67b8..aa6a6ef7e56ae 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -35,7 +35,7 @@ static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject ) { return ptr_sp; } -static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { +static Function *ExtractFunction(ValueObjectSP _ptr_sp, int offset) { lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP(); lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP(); auto ptr_size = process_sp->GetAddressByteSize(); @@ -47,24 +47,64 @@ static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { lldbassert(addr_type == AddressType::eAddressTypeLoad); Status error; - // The destroy pointer is the 2nd pointer inside the compiler-generated - // `pair`. - auto destroy_func_ptr_addr = frame_ptr_addr + ptr_size; - lldb::addr_t destroy_func_addr = - process_sp->ReadPointerFromMemory(destroy_func_ptr_addr, error); + auto func_ptr_addr = frame_ptr_addr + offset * ptr_size; + lldb::addr_t func_addr = + process_sp->ReadPointerFromMemory(func_ptr_addr, error); if (error.Fail()) return nullptr; - Address destroy_func_address; - if (!target_sp->ResolveLoadAddress(destroy_func_addr, destroy_func_address)) + Address func_address; + if (!target_sp->ResolveLoadAddress(func_addr, func_address)) return nullptr; - Function *destroy_func = - destroy_func_address.CalculateSymbolContextFunction(); - if (!destroy_func) -return nullptr; + return func_address.CalculateSymbolContextFunction(); +} + +static Function *ExtractResumeFunction(ValueObjectSP _ptr_sp) { + return ExtractFunction(frame_ptr_sp, 0); +} + +static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { + return ExtractFunction(frame_ptr_sp, 1); +} + +static bool IsNoopCoroFunction(Function *f) { + if (!f) +return false; - return destroy_func; + // clang's `__builtin_coro_noop` gets lowered to + // `_NoopCoro_ResumeDestroy`. This is used by libc++ + // on clang. + auto mangledName = f->GetMangled().GetMangledName(); + if (mangledName == "__NoopCoro_ResumeDestroy") +return true; + + // libc++ uses the following name as a fallback on + // compilers without `__builtin_coro_noop`. + auto name = f->GetNameNoArguments(); + static RegularExpression libcxxRegex( + "^std::coroutine_handle::" + "__noop_coroutine_frame_ty_::__dummy_resume_destroy_func$"); + lldbassert(libcxxRegex.IsValid()); + if (libcxxRegex.Execute(name.GetStringRef())) +return true; + static RegularExpression libcxxRegexAbiNS( + "^std::__[[:alnum:]]+::coroutine_handle::__noop_coroutine_frame_ty_::" + "__dummy_resume_destroy_func$"); + lldbassert(libcxxRegexAbiNS.IsValid()); + if (libcxxRegexAbiNS.Execute(name.GetStringRef())) +return true; + + // libstdc++ uses the following name on both gcc and clang. + static RegularExpression libstdcppRegex( + "^std::__[[:alnum:]]+::coroutine_handle::__frame::__dummy_resume_destroy$"); + lldbassert(libstdcppRegex.IsValid()); + if (libstdcppRegex.Execute(name.GetStringRef())) +return true; + + return false; } static CompilerType InferPromiseType(Function _func) { @@ -113,9 +153,15 @@ bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider(
[Lldb-commits] [lldb] fb61dce - [lldb] Fix test expectation in `TestCoroutineHandle.py` for 32-bit systems
Author: Adrian Vogelsgesang Date: 2022-11-20T10:30:29-08:00 New Revision: fb61dce1adc4572e794e836861915d8ae372749d URL: https://github.com/llvm/llvm-project/commit/fb61dce1adc4572e794e836861915d8ae372749d DIFF: https://github.com/llvm/llvm-project/commit/fb61dce1adc4572e794e836861915d8ae372749d.diff LOG: [lldb] Fix test expectation in `TestCoroutineHandle.py` for 32-bit systems Added: Modified: lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py Removed: diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py index ed03fd0961cce..44e5e6451c10d 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py @@ -97,7 +97,7 @@ def do_test(self, stdlib_type): self.expect_expr("type_erased_hdl", result_summary=re.compile("^coro frame = 0x[0-9a-f]*$"), result_children=[ -ValueCheck(name="resume", value = "0x"), +ValueCheck(name="resume", value = re.compile("^0x0+$")), ValueCheck(name="destroy", summary = test_generator_func_ptr_re), ValueCheck(name="promise", children=[ ValueCheck(name="current_value", value = "42"), ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 01f4c30 - Reapply "[LLDB] Devirtualize coroutine promise types for `std::coroutine_handle`"
Author: Adrian Vogelsgesang Date: 2022-11-20T06:35:16-08:00 New Revision: 01f4c305fae9ff2f165ce0f635a90f8e2292308c URL: https://github.com/llvm/llvm-project/commit/01f4c305fae9ff2f165ce0f635a90f8e2292308c DIFF: https://github.com/llvm/llvm-project/commit/01f4c305fae9ff2f165ce0f635a90f8e2292308c.diff LOG: Reapply "[LLDB] Devirtualize coroutine promise types for `std::coroutine_handle`" The original commit was missing a `ClangASTImporter::CopyType` call. Original commit message: This commit teaches the `std::coroutine_handle` pretty-printer to devirtualize type-erased promise types. This is particularly useful to resonstruct call stacks, either of asynchronous control flow or of recursive invocations of `std::generator`. For the example recently introduced by https://reviews.llvm.org/D132451, printing the `__promise` variable now shows ``` (std::__coroutine_traits_sfinae::promise_type) __promise = { continuation = coro frame = 0x55562430 { resume = 0x6310 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) destroy = 0x6700 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) promise = { continuation = coro frame = 0x555623e0 { resume = 0x7070 (a.out`task detail::chain_fn<2>() at llvm-nested-example.cpp:66) destroy = 0x7460 (a.out`task detail::chain_fn<2>() at llvm-nested-example.cpp:66) promise = { ... } } result = 0 } } result = 0 } ``` (shortened to keep the commit message readable) instead of ``` (std::__coroutine_traits_sfinae::promise_type) __promise = { continuation = coro frame = 0x55562430 { resume = 0x6310 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) destroy = 0x6700 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) } result = 0 } ``` Note how the new debug output reveals the complete asynchronous call stack: our own function resumes `chain_fn<1>` which in turn will resume `chain_fn<2>` and so on. Thereby this change allows users of lldb to inspect the logical coroutine call stack without using any custom debug scripts (although the display is still a bit clumsy. It would be nicer to also integrate this into lldb's backtrace feature, but I don't know how to do so) The devirtualization currently works by introspecting the function pointed to by the `destroy` pointer. (The `resume` pointer is not worth much, given that for the final suspend point `resume` is set to a nullptr. We have to use the `destroy` pointer instead.) We then look for a `__promise` variable inside the `destroy` function. This `__promise` variable is synthetically generated by LLVM, and looking at its type reveals the type-erased promise_type. This approach only works for clang-generated code, though. While gcc also adds a `_Coro_promise` variable to the `resume` function, it does not do so for the `destroy` function. However, we can't use the `resume` function, as it will be reset to a nullptr at the final suspension point. For the time being, I am happy with de-virtualization only working for clang. A follow-up commit will further improve devirtualization and also expose the variables spilled to the coroutine frame. As part of this, I will also revisit gcc support. Differential Revision: https://reviews.llvm.org/D132624 Added: Modified: lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/source/Plugins/Language/CPlusPlus/Coroutines.h lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/main.cpp Removed: diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index de5d1831c01ef..bd9ff99db67b8 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -8,7 +8,10 @@ #include "Coroutines.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/VariableList.h" using namespace lldb; using namespace lldb_private; @@ -32,6 +35,56 @@ static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject ) { return ptr_sp; } +static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { + lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP(); + lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP(); + auto ptr_size = process_sp->GetAddressByteSize(); + + AddressType addr_type; + lldb::addr_t frame_ptr_addr = frame_ptr_sp->GetPointerValue(_type); + if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS) +return nullptr; +
[Lldb-commits] [lldb] d7e1c27 - Revert "[LLDB] Devirtualize coroutine promise types for `std::coroutine_handle`"
Author: Adrian Vogelsgesang Date: 2022-11-11T10:00:58-08:00 New Revision: d7e1c2770fa57fb8df2f09f74d433ac9cf80a595 URL: https://github.com/llvm/llvm-project/commit/d7e1c2770fa57fb8df2f09f74d433ac9cf80a595 DIFF: https://github.com/llvm/llvm-project/commit/d7e1c2770fa57fb8df2f09f74d433ac9cf80a595.diff LOG: Revert "[LLDB] Devirtualize coroutine promise types for `std::coroutine_handle`" This reverts commit 558db7787005348e2efaabb628ec36f1c461a741 due to buildbot failures on ARM * https://lab.llvm.org/buildbot/#/builders/96/builds/31416 * https://lab.llvm.org/buildbot/#/builders/17/builds/30086 Added: Modified: lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/main.cpp Removed: diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index 89ee4bb67f931..5427a7a2b7850 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -9,8 +9,6 @@ #include "Coroutines.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/VariableList.h" using namespace lldb; using namespace lldb_private; @@ -34,57 +32,6 @@ static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject ) { return ptr_sp; } -static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { - lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP(); - lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP(); - auto ptr_size = process_sp->GetAddressByteSize(); - - AddressType addr_type; - lldb::addr_t frame_ptr_addr = frame_ptr_sp->GetPointerValue(_type); - if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS) -return nullptr; - lldbassert(addr_type == AddressType::eAddressTypeLoad); - - Status error; - // The destroy pointer is the 2nd pointer inside the compiler-generated - // `pair`. - auto destroy_func_ptr_addr = frame_ptr_addr + ptr_size; - lldb::addr_t destroy_func_addr = - process_sp->ReadPointerFromMemory(destroy_func_ptr_addr, error); - if (error.Fail()) -return nullptr; - - Address destroy_func_address; - if (!target_sp->ResolveLoadAddress(destroy_func_addr, destroy_func_address)) -return nullptr; - - Function *destroy_func = - destroy_func_address.CalculateSymbolContextFunction(); - if (!destroy_func) -return nullptr; - - return destroy_func; -} - -static CompilerType InferPromiseType(Function _func) { - SymbolContext sc; - Block = destroy_func.GetBlock(true); - auto variable_list = block.GetBlockVariableList(true); - - // clang generates an artificial `__promise` variable inside the - // `destroy` function. Look for it. - auto promise_var = variable_list->FindVariable(ConstString("__promise")); - if (!promise_var) -return {}; - if (!promise_var->IsArtificial()) -return {}; - - Type *promise_type = promise_var->GetType(); - if (!promise_type) -return {}; - return promise_type->GetForwardCompilerType(); -} - static CompilerType GetCoroutineFrameType(TypeSystemClang _ctx, CompilerType promise_type) { CompilerType void_type = ast_ctx.GetBasicType(lldb::eBasicTypeVoid); @@ -111,11 +58,7 @@ bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider( if (!ptr_sp) return false; - if (!ptr_sp->GetValueAsUnsigned(0)) { -stream << "nullptr"; - } else { -stream.Printf("coro frame = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); - } + stream.Printf("coro frame = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); return true; } @@ -157,26 +100,15 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: if (!ptr_sp) return false; - // Get the `promise_type` from the template argument + TypeSystemClang *ast_ctx = llvm::dyn_cast_or_null( + valobj_sp->GetCompilerType().GetTypeSystem()); + if (!ast_ctx) +return false; + CompilerType promise_type( valobj_sp->GetCompilerType().GetTypeTemplateArgument(0)); if (!promise_type) return false; - - // Try to infer the promise_type if it was type-erased - if (promise_type.IsVoidType()) { -if (Function *destroy_func = ExtractDestroyFunction(ptr_sp)) { - if (CompilerType inferred_type = InferPromiseType(*destroy_func)) { -promise_type = inferred_type; - } -} - } - - // Build the coroutine frame type - TypeSystemClang *ast_ctx = llvm::dyn_cast_or_null( - ptr_sp->GetCompilerType().GetTypeSystem()); - if (!ast_ctx) -return {}; CompilerType coro_frame_type = GetCoroutineFrameType(*ast_ctx, promise_type); m_frame_ptr_sp =
[Lldb-commits] [lldb] 558db77 - [LLDB] Devirtualize coroutine promise types for `std::coroutine_handle`
Author: Adrian Vogelsgesang Date: 2022-11-11T09:37:08-08:00 New Revision: 558db7787005348e2efaabb628ec36f1c461a741 URL: https://github.com/llvm/llvm-project/commit/558db7787005348e2efaabb628ec36f1c461a741 DIFF: https://github.com/llvm/llvm-project/commit/558db7787005348e2efaabb628ec36f1c461a741.diff LOG: [LLDB] Devirtualize coroutine promise types for `std::coroutine_handle` This commit teaches the `std::coroutine_handle` pretty-printer to devirtualize type-erased promise types. This is particularly useful to resonstruct call stacks, either of asynchronous control flow or of recursive invocations of `std::generator`. For the example recently introduced by https://reviews.llvm.org/D132451, printing the `__promise` variable now shows ``` (std::__coroutine_traits_sfinae::promise_type) __promise = { continuation = coro frame = 0x55562430 { resume = 0x6310 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) destroy = 0x6700 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) promise = { continuation = coro frame = 0x555623e0 { resume = 0x7070 (a.out`task detail::chain_fn<2>() at llvm-nested-example.cpp:66) destroy = 0x7460 (a.out`task detail::chain_fn<2>() at llvm-nested-example.cpp:66) promise = { ... } } result = 0 } } result = 0 } ``` (shortened to keep the commit message readable) instead of ``` (std::__coroutine_traits_sfinae::promise_type) __promise = { continuation = coro frame = 0x55562430 { resume = 0x6310 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) destroy = 0x6700 (a.out`task detail::chain_fn<1>() at llvm-nested-example.cpp:66) } result = 0 } ``` Note how the new debug output reveals the complete asynchronous call stack: our own function resumes `chain_fn<1>` which in turn will resume `chain_fn<2>` and so on. Thereby this change allows users of lldb to inspect the logical coroutine call stack without using any custom debug scripts (although the display is still a bit clumsy. It would be nicer to also integrate this into lldb's backtrace feature, but I don't know how to do so) The devirtualization currently works by introspecting the function pointed to by the `destroy` pointer. (The `resume` pointer is not worth much, given that for the final suspend point `resume` is set to a nullptr. We have to use the `destroy` pointer instead.) We then look for a `__promise` variable inside the `destroy` function. This `__promise` variable is synthetically generated by LLVM, and looking at its type reveals the type-erased promise_type. This approach only works for clang-generated code, though. While gcc also adds a `_Coro_promise` variable to the `resume` function, it does not do so for the `destroy` function. However, we can't use the `resume` function, as it will be reset to a nullptr at the final suspension point. For the time being, I am happy with de-virtualization only working for clang. A follow-up commit will further improve devirtualization and also expose the variables spilled to the coroutine frame. As part of this, I will also revisit gcc support. Differential Revision: https://reviews.llvm.org/D132624 Added: Modified: lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/main.cpp Removed: diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index 5427a7a2b7850..89ee4bb67f931 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -9,6 +9,8 @@ #include "Coroutines.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/VariableList.h" using namespace lldb; using namespace lldb_private; @@ -32,6 +34,57 @@ static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject ) { return ptr_sp; } +static Function *ExtractDestroyFunction(ValueObjectSP _ptr_sp) { + lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP(); + lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP(); + auto ptr_size = process_sp->GetAddressByteSize(); + + AddressType addr_type; + lldb::addr_t frame_ptr_addr = frame_ptr_sp->GetPointerValue(_type); + if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS) +return nullptr; + lldbassert(addr_type == AddressType::eAddressTypeLoad); + + Status error; + // The destroy pointer is the 2nd pointer inside the compiler-generated + // `pair`. + auto destroy_func_ptr_addr = frame_ptr_addr + ptr_size; +
[Lldb-commits] [lldb] 6f88388 - [lldb][test] Fix nullptr test expctation for 32-bit system
Author: Adrian Vogelsgesang Date: 2022-08-25T17:11:57-07:00 New Revision: 6f88388f61327b375112e76ff4b80741a1b349cb URL: https://github.com/llvm/llvm-project/commit/6f88388f61327b375112e76ff4b80741a1b349cb DIFF: https://github.com/llvm/llvm-project/commit/6f88388f61327b375112e76ff4b80741a1b349cb.diff LOG: [lldb][test] Fix nullptr test expctation for 32-bit system Follow-up to https://reviews.llvm.org/D132415 Fixes https://lab.llvm.org/buildbot/#/builders/17/builds/26630 Added: Modified: lldb/packages/Python/lldbsuite/test/lldbtest.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py Removed: diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 1c090395e6c4c..0d449737cfd0b 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -286,8 +286,12 @@ def check_value(self, test_base, val, error_msg=None): test_base.assertEqual(self.expect_name, val.GetName(), this_error_msg) if self.expect_value: -test_base.assertEqual(self.expect_value, val.GetValue(), - this_error_msg) +if isinstance(self.expect_value, re.Pattern): +test_base.assertRegex(val.GetValue(), self.expect_value, + this_error_msg) +else: +test_base.assertEqual(self.expect_value, val.GetValue(), + this_error_msg) if self.expect_type: test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(), this_error_msg) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py index 33d580d98df61..50cac6ebff7fd 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py @@ -63,7 +63,7 @@ def do_test(self, stdlib_type): # Check that we still show the remaining data correctly. self.expect_expr("gen.hdl", result_children=[ -ValueCheck(name="resume", value = "0x"), +ValueCheck(name="resume", value = re.compile("^0x0+$")), ValueCheck(name="destroy", summary = test_generator_func_ptr_re), ValueCheck(name="promise", children=[ ValueCheck(name="current_value", value = "42"), ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 9138900 - [LLDB] Add data formatter for std::coroutine_handle
Author: Adrian Vogelsgesang Date: 2022-08-24T14:40:53-07:00 New Revision: 91389000abe8ef5d06d98cbbefd3fa03ac7e4480 URL: https://github.com/llvm/llvm-project/commit/91389000abe8ef5d06d98cbbefd3fa03ac7e4480 DIFF: https://github.com/llvm/llvm-project/commit/91389000abe8ef5d06d98cbbefd3fa03ac7e4480.diff LOG: [LLDB] Add data formatter for std::coroutine_handle This patch adds a formatter for `std::coroutine_handle`, both for libc++ and libstdc++. For the type-erased `coroutine_handle<>`, it shows the `resume` and `destroy` function pointers. For a non-type-erased `coroutine_handle` it also shows the `promise` value. With this change, executing the `v t` command on the example from https://clang.llvm.org/docs/DebuggingCoroutines.html now outputs ``` (task) t = { handle = coro frame = 0xb2a0 { resume = 0x5a10 (a.out`coro_task(int, int) at llvm-example.cpp:36) destroy = 0x6090 (a.out`coro_task(int, int) at llvm-example.cpp:36) } } ``` instead of just ``` (task) t = { handle = { __handle_ = 0xb2a0 } } ``` Note, how the symbols for the `resume` and `destroy` function pointer reveal which coroutine is stored inside the `std::coroutine_handle`. A follow-up commit will use this fact to infer the coroutine's promise type and the representation of its internal coroutine state based on the `resume` and `destroy` pointers. The same formatter is used for both libc++ and libstdc++. It would also work for MSVC's standard library, however it is not registered for MSVC, given that lldb does not provide pretty printers for other MSVC types, either. The formatter is in a newly added `Coroutines.{h,cpp}` file because there does not seem to be an already existing place where we could share formatters across libc++ and libstdc++. Also, I expect this code to grow as we improve debugging experience for coroutines further. **Testing** * Added API test Differential Revision: https://reviews.llvm.org/D132415 Added: lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp lldb/source/Plugins/Language/CPlusPlus/Coroutines.h lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/Makefile lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/TestCoroutineHandle.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/coroutine_handle/main.cpp Modified: clang/docs/tools/clang-formatted-files.txt lldb/packages/Python/lldbsuite/test/lldbtest.py lldb/packages/Python/lldbsuite/test/lldbutil.py lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp Removed: diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index f89e19ca7cd3a..c49acfaec58aa 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -4180,6 +4180,8 @@ lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h +lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +lldb/source/Plugins/Language/CPlusPlus/Coroutines.h lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 69bb5ac5629e4..1c090395e6c4c 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -292,8 +292,12 @@ def check_value(self, test_base, val, error_msg=None): test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(), this_error_msg) if self.expect_summary: -test_base.assertEqual(self.expect_summary, val.GetSummary(), - this_error_msg) +if isinstance(self.expect_summary, re.Pattern): +test_base.assertRegex(val.GetSummary(), self.expect_summary, + this_error_msg) +else: +test_base.assertEqual(self.expect_summary, val.GetSummary(), + this_error_msg) if self.children is not None: self.check_value_children(test_base, val, error_msg) diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py index 8bd49c742cb04..7e64afb3639cd 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -988,6 +988,21 @@ def