-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Bugfix: Not showing the synthetic children of values behind pointers #117755
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
base: main
Are you sure you want to change the base?
Bugfix: Not showing the synthetic children of values behind pointers #117755
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-lldb Author: Sergey Kuznetsov (skuznetsov) ChangesThis bug fix for the situation that was extensively discussed at LLVM Discourse thread: https://discourse.llvm.org/t/synthetic-data-providers-and-lldb-dap/ Full diff: https://github.com/llvm/llvm-project/pull/117755.diff 1 Files Affected:
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 3bfc578806021e..b86994f60f04e5 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -4020,6 +4020,10 @@ void request_variables(DAP &dap, const llvm::json::Object &request) {
std::optional<std::string> custom_name = {}) {
if (!child.IsValid())
return;
+ if (child.IsSynthetic() && (child.GetType().IsPointerType() || child.GetType().IsReferenceType())) {
+ // Dereference to access synthetic children behind pointers/references
+ child = child.Dereference();
+ }
bool is_permanent =
dap.variables.IsPermanentVariableReference(variablesReference);
int64_t var_ref = dap.variables.InsertVariable(child, is_permanent);
@@ -4028,6 +4032,9 @@ void request_variables(DAP &dap, const llvm::json::Object &request) {
dap.enable_synthetic_child_debugging,
/*is_name_duplicated=*/false, custom_name));
};
+ if (variable.GetType().IsPointerType() || variable.GetType().IsReferenceType()) {
+ variable = variable.Dereference();
+ }
const int64_t num_children = variable.GetNumChildren();
int64_t end_idx = start + ((count == 0) ? num_children : count);
int64_t i = start;
|
@@ -4020,6 +4020,10 @@ void request_variables(DAP &dap, const llvm::json::Object &request) { | |||
std::optional<std::string> custom_name = {}) { | |||
if (!child.IsValid()) | |||
return; | |||
if (child.IsSynthetic() && (child.GetType().IsPointerType() || child.GetType().IsReferenceType())) { |
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.
@clayborg , what do you think about this? This pretty much matches the experience from CLI, i.e. the variable name is prepended with *
, but the synthetic value is displayed right away.
if (variable.GetType().IsPointerType() || variable.GetType().IsReferenceType()) { | ||
variable = variable.Dereference(); | ||
} |
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.
Do you know why you need this change and the one above is not enough?
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.
The first change is more than enough. To be on the safe side, I overcomplicated it a little. I will remove the second change.
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.
None of this should be needed. If we have a child value that is a pointer to a synthetic value, and we expand that value, we should be showing the synthetic children via the standard LLDB APIs.
In LLDB way back in the beginning, when we would expand a pointer, we would show the first child as the dereferenced value and its name would be "*". And then if you expanded that, then you would see the contents. So if we had this code:
struct Point { int x,y; };
int my_int = 12
Point pt = {1,2};
Point *pt_ptr = &pt;
int *my_int_ptr = &i;
Old LLDB would show this as:
pt_ptr
\_ *pt_ptr
|- x = 1
\- y = 2
my_int_ptr
\_ 12
Current LLDB, when you expand a pointer, will look at the type and see if the type has children, and if it does, it will auto dereference the type:
pt_ptr
|- x = 1
\- y = 2
my_int_ptr
\_ 12
And if the dereferenced value has a synthetic child provider, it should be grabbing that synthetic value and asking it for its children.
So this isn't the right fix for this. It works for C++. We need to figure out why it isn't working for your language

@clayborg This is what puzzles me, too. Also, in your example, vectors are on the top level (in the function scope). |
Can you post a copy of a the python code for the synthetic child provider you are creating and also how you are registering it with LLDB? |
You should be able to debug lldb and step through the code that tries to get the synthetic child provider for the type and watch if fail. You can also step through the C++ example code from my screen shot and see how it is working to see what is going wrong and how the two things differ. |
Here it is:
|
You don't have a "def update(self):" method in your data formatter. This is what causes the values to be refetched. I think if you rename "extract_entries" to be named "update" it will fix your synthetic child provider. |
You also are overwriting the original
You never want to do this because if your value is a pointer, that pointer can change, and now you have replaced the value that is the pointer value with the first dereference value and that value will never change. Now when you run this function again, you won't get the right value because you will have locked onto the first dereferenced pointer. So if you have code like:
You will always be showing You also don't need to dereference the type. So your
Should be:
if self.valobj.GetChildMemberWithName("size") fails, it will return an invalid lldb.SBValue and calling |
the |
Another thing that might not be abvious is that an instance of this class lives as long as the variable lives so as you are stepping in the same function, we will create one synthetic python instance per raw |
@clayborg Thank you, Greg! By some reason my provider works in CLI lldb, but not in lldb-dap, but I will check if your suggestions will help to fix that. |
Let me know if this fixes things. I believe it will. |
I tried your approach and your recommended code changes, but it does not work without my patch for some strange reason. :( |
This bug fix for the situation that was extensively discussed at LLVM Discourse thread: https://discourse.llvm.org/t/synthetic-data-providers-and-lldb-dap/