-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLDB] Ignore actual-needed artificial members in DWARFASTParserClang::ParseSingleMember #70779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't provide feedback on the lldb integration aspects, as I don't know the lldb code base well enough
// FIXME: use a list when the list grows more. | ||
return name == g_this || | ||
name == ConstString("__promise") || | ||
name == ConstString("__coro_frame"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any chance we can get the Type
from the Variable
in CommandObjectFrameVariable
and can re-use the IsCoroutineFrameType
check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if I would expose the __coro_frame variable.
For completeness, I'm leaning towards exposing__coro_frame
as well, even though it is not that useful.
Any chance we can get the Type from the Variable in CommandObjectFrameVariable and can re-use the IsCoroutineFrameType check?
Yes, we can get the Type in CommandObjectFrameVariable
by calling valobj_sp->GetCompilerType();
.
However it only works for the coroutine-frame variables, other variables like __promise
(whose type is a user-defined promise_type) are still not available. One idea is to make the IsCoroutineFrameType
more generic to check coroutine-relevant types (promise_type, coroutine_frame_type).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this change from this pull request now (will sent as a followup). Let's focus on addressing the ignore-artificial-fields issue in DWARFASTParserClang.cpp
.
@@ -3061,7 +3061,8 @@ void DWARFASTParserClang::ParseSingleMember( | |||
// artificial member with (unnamed bitfield) padding. | |||
// FIXME: This check should verify that this is indeed an artificial member | |||
// we are supposed to ignore. | |||
if (attrs.is_artificial) { | |||
if (attrs.is_artificial && | |||
!TypeSystemClang::IsCoroutineFrameType(class_clang_type)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do still wonder if we should just make a ShouldIgnoreArtificialField
API that returns true
for known fields we want to skip. The only ones that comes to mind are artificial variables that start with _vptr$
Not sure if there are some Objective-C artificial vars we want to skip. Maybe @jimingham or @adrian-prantl would know
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed to ShouldIgnoreArtificialField
per suggest (unite tests are passed). It looks like the vtable pointer is the only case for C/C++.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review.
// FIXME: use a list when the list grows more. | ||
return name == g_this || | ||
name == ConstString("__promise") || | ||
name == ConstString("__coro_frame"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if I would expose the __coro_frame variable.
For completeness, I'm leaning towards exposing__coro_frame
as well, even though it is not that useful.
Any chance we can get the Type from the Variable in CommandObjectFrameVariable and can re-use the IsCoroutineFrameType check?
Yes, we can get the Type in CommandObjectFrameVariable
by calling valobj_sp->GetCompilerType();
.
However it only works for the coroutine-frame variables, other variables like __promise
(whose type is a user-defined promise_type) are still not available. One idea is to make the IsCoroutineFrameType
more generic to check coroutine-relevant types (promise_type, coroutine_frame_type).
@@ -3061,7 +3061,8 @@ void DWARFASTParserClang::ParseSingleMember( | |||
// artificial member with (unnamed bitfield) padding. | |||
// FIXME: This check should verify that this is indeed an artificial member | |||
// we are supposed to ignore. | |||
if (attrs.is_artificial) { | |||
if (attrs.is_artificial && | |||
!TypeSystemClang::IsCoroutineFrameType(class_clang_type)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed to ShouldIgnoreArtificialField
per suggest (unite tests are passed). It looks like the vtable pointer is the only case for C/C++.
@@ -771,6 +771,10 @@ TypeSystemClang *TypeSystemClang::GetASTContext(clang::ASTContext *ast) { | |||
return clang_ast; | |||
} | |||
|
|||
bool TypeSystemClang::ShouldIgnoreArtificialField(llvm::StringRef Name) { | |||
return Name.starts_with("_vptr$"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On GCC I see we get a slightly different name:
< 2><0x00000166> DW_TAG_member
DW_AT_name _vptr.Base
DW_AT_type <0x000001cc>
DW_AT_data_member_location 0
DW_AT_artificial yes(1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, good catch. Handled the gdb case and added a test case (I thought the Clang name in the filename and path name indicates that these part of code only cares about clang-generated code, but it looks like we use Clang type system to parse the DWARF debug info).
Do we care about the msvc-built program as well? I think? probably not, as we use a different debug info format PDB
on Windows. And this class is only used in parsing DWARF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeSystemClang
should be agnostic to the debug-info format. The various debug-info->AST parsers (e.g., DWARFASTParserClang
/PDBASTParser
/npdb::PdbAstBuilder
, the latter two being the MSVC debug-info parsers) use TypeSystemClang
after they've parsed debug-info to construct clang AST nodes. But I'm not sure how the PDB parsers handle the vptr case and artificial variables. From a brief glance it doesn't look like it cares about artificial member variables at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you still planning on using this API from the CPPLanguageRuntime
? If not, you could just put it inside of DWARFASTParserClang.cpp
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeSystemClang should be agnostic to the debug-info format. The various debug-info->AST parsers (e.g., DWARFASTParserClang/PDBASTParser/npdb::PdbAstBuilder, the latter two being the MSVC debug-info parsers) use TypeSystemClang after they've parsed debug-info to construct clang AST nodes.
Thanks for the clarification.
That makes sense. I don't have any plan to use this API. It is better to move DWARFASTParserClang.cpp (better layering).
* always populate all fields for the generated coroutine frame type; * make the artificial variables `__promise`, `__coro_frame` visible, so that they are present in the `frame var` command;
…tificial members we should ignore.
and remove the change in CPPLanguageRuntim.cpp.
c145045
to
e74494c
Compare
@llvm/pr-subscribers-lldb Author: Haojian Wu (hokein) ChangesPart of the fixes #69309. Address the FIXME, this will allow the lldb print all fields of the generated coroutine frame structure. Full diff: https://github.com/llvm/llvm-project/pull/70779.diff 4 Files Affected:
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 3174c18c97d888c..63260f28a7da85d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -3059,9 +3059,8 @@ void DWARFASTParserClang::ParseSingleMember(
// This needs to be done after updating FieldInfo which keeps track of where
// field start/end so we don't later try to fill the space of this
// artificial member with (unnamed bitfield) padding.
- // FIXME: This check should verify that this is indeed an artificial member
- // we are supposed to ignore.
- if (attrs.is_artificial) {
+ if (attrs.is_artificial &&
+ TypeSystemClang::ShouldIgnoreArtificialField(attrs.name)) {
last_field_info.SetIsArtificial(true);
return;
}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 6f65587c4acedd1..e81fdc7bdfd8e40 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -771,6 +771,12 @@ TypeSystemClang *TypeSystemClang::GetASTContext(clang::ASTContext *ast) {
return clang_ast;
}
+bool TypeSystemClang::ShouldIgnoreArtificialField(llvm::StringRef Name) {
+ return Name.starts_with("_vptr$")
+ // gdb emit vtable pointer as "_vptr.classname"
+ || Name.starts_with("_vptr.");
+}
+
clang::MangleContext *TypeSystemClang::getMangleContext() {
if (m_mangle_ctx_up == nullptr)
m_mangle_ctx_up.reset(getASTContext().createMangleContext());
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 0ec2d026e996105..477b655bb7c86ea 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -154,6 +154,10 @@ class TypeSystemClang : public TypeSystem {
static TypeSystemClang *GetASTContext(clang::ASTContext *ast_ctx);
+ // Returns true if the given artificial field name should be ignored when
+ // parsing the DWARF.
+ static bool ShouldIgnoreArtificialField(llvm::StringRef FieldName);
+
/// Returns the display name of this TypeSystemClang that indicates what
/// purpose it serves in LLDB. Used for example in logs.
llvm::StringRef getDisplayName() const { return m_display_name; }
diff --git a/lldb/test/Shell/SymbolFile/DWARF/ignored_artificial_fields.test b/lldb/test/Shell/SymbolFile/DWARF/ignored_artificial_fields.test
new file mode 100644
index 000000000000000..e7d3bc4b796224a
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/ignored_artificial_fields.test
@@ -0,0 +1,17 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# Make sure the artifical field `vptr.ClassName` from gcc debug info is ignored.
+# RUN: %build --compiler=gcc %S/Inputs/debug-types-expressions.cpp -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+breakpoint set -n foo
+process launch
+
+# CHECK: Process {{.*}} stopped
+
+frame variable *a
+# CHECK-LABEL: frame variable *a
+# CHECK: (B) *a = {
+# CHECK-NEXT: A = (i = 47)
+# CHECK-NEXT: j = 42
+# CHECK-NEXT: }
|
Thanks for the comment, I updated the patch, this is ready for another round of review. |
DWARFASTParserClang.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Are you still going to make the change to CommandObjectFrame
such that frame var
doesn't hide the artificial fields?
Thank you very much for the review!
Yes, that's my next step. |
Hi, this is failing on Linaro's Linux LLDB bots: https://lab.llvm.org/buildbot/#/builders/96/builds/48277 Looks like the |
I think I have a fix for this, will commit it soon. |
Sorry for the breakage. I removed this test temporarily in 343eb4b to make the builtbots happy again while doing the investigation. |
Ah, I just saw your new message. If you can fix that, that would be fantastic (I don't know too much about lldb). |
I just pushed a fix for the build script (7c3603e), I'll put the test case back once I know the script change is good. |
Thank you very much for the fix! |
All fixed now. |
Hi @hokein - ignored_artificial_fields.test breaks if gcc is unavailable. For ex we purposely exclude gcc on our downstream bots so as not to implicitly depend on it. Maybe all that is needed is adding something like Would you be able to revert the test and/or patch it to only run when gcc is present? |
…::ParseSingleMember (llvm#70779) Address the FIXME, this will allow lldb to print all fields of the generated coroutine frame structure. Fixes llvm#69309.
Address the FIXME, this will allow lldb to print all fields of the generated coroutine frame structure.
Fixes #69309.