-
Notifications
You must be signed in to change notification settings - Fork 14.9k
lldb-dap: Stop using replicated variable ids #124232
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?
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. |
@Anthony-Eid could you rebase this PR, that'd be better to look at it |
@medismailben I just updated the branch by merging with main. I started a rebase but I don't have enough time to finish it until later tonight. I might see if I can cherry pick my changes instead of rebase because I think that would be easier to test |
cccddfc
to
30658e9
Compare
@medismailben I fixed most of extra lines being added in the PR, but it's not 100% working in the new version. I'll ping you when it's functional. I believe I'm mainly going to need help rewriting the tests once I get this functionality and following any llvm standards that I'm unaware of. |
Sounds good, let me know when you're ready 🙂 |
@medismailben lldb-dap is usable from Zed with my most recent commit now! Do you have time this week to pair on getting this mergable? I'm pretty sure using new variable ids is going to break some tests and idk if there's formatters or anything else I have to fix to get CICD passing |
Awesome! I've kicked the llvm PR testing for your patch and it looks like the formatter job passed however there is some DAP test failures:
You should be able to look at the logs here: https://github.com/llvm/llvm-project/actions/runs/17280350831/job/49047894529?pr=124232 You can run the It would be nice to add your own test to make sure this doesn't regress in the future. Also, make sure to turn your draft into a PR when it's ready for review. |
Looking at the logs:
|
The test and API changes now get scope references dynamically instead of using hardcoded values. This fixes the below tests: - testDAP_memory - TestDAP_variables - GetTopLevelScope_ReturnsCorrectScope
✅ With the latest revision this PR passed the Python code formatter. |
Variable reference 1 was hard coded to always be the local scope but since the var_ref of local scope is dynamic now it uses a helper function in the test
@Anthony-Eid Almost there! Looks like all the tests are passing now you just need to fix the formatting for the python changes (you can run |
@medismailben It's ready for review! Thank you for your guidance |
So I ran |
int64_t variable_reference = dap.variables.GetNewVariableReference(false); | ||
scopes.push_back(CreateScope("Locals", variable_reference, | ||
dap.variables.locals.GetSize(), false)); | ||
|
||
dap.variables.AddScopeKind(variable_reference, ScopeKind::Locals, frame_id); |
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.
Should AddScopeKind
make a new ref internally and return the ref?
Or when we ready a frame, should this be handled then?
if (name == "Locals") | ||
scope.presentationHint = Scope::eScopePresentationHintLocals; | ||
else if (variablesReference == VARREF_REGS) | ||
else if (name == "Registers") | ||
scope.presentationHint = Scope::eScopePresentationHintRegisters; |
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.
Should we move this up a layer and take the presentation hint as a paramter instead of checking for specific names?
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 passed ScopeKind in to the function instead of name now, and use ScopeKind variant to generate the correct presentation hint and name for the scope. Is that an adequate fix for this?
void Variables::ReadyFrame(uint32_t frame_id, lldb::SBFrame &frame) { | ||
if (m_frames.find(frame_id) == m_frames.end()) { | ||
|
||
auto locals = frame.GetVariables(/*arguments=*/true, | ||
/*locals=*/true, | ||
/*statics=*/false, | ||
/*in_scope_only=*/true); | ||
|
||
auto globals = frame.GetVariables(/*arguments=*/false, | ||
/*locals=*/false, | ||
/*statics=*/true, | ||
/*in_scope_only=*/true); | ||
|
||
auto registers = frame.GetRegisters(); | ||
|
||
m_frames.insert( | ||
std::make_pair(frame_id, std::make_tuple(locals, globals, registers))); | ||
} | ||
} |
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.
We may want to go ahead and make a variable reference for the locals, globals, registers here that we can use to keep track of the SBValueList.
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.
+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.
What exactly is an SBValueList
?
Would doing something like this work (under m_frames.insert())?
m_variables.insert(locals.var_ref, locals);
m_variables.insert(global.var_ref, global);
m_variables.insert(registers.var_ref, registers);
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.
A SBValueList
is the container for the variables, like the local or global or registers.
Would doing something like this work (under m_frames.insert())?
Yea
I am not too happy with the It may not work if we are changing scopes in a stopped state (have not tested this patch locally) from #147105. It seems we are storing redundant information. For example to get the we can either have separate maps for variables and scope. or merge them together. e.g // separate
struct ScopeData { // or something similar
ScopeKind kind ; // Global, Local, Register
SBValueList value; // variables in that scope.
};
// Map ref -> ScopeData
denseMap<uint32_t, ScopeData> scopes;
denseMap<uint32_t, SBValue> tempValues; struct ReferencesTypes { // or something similar
ReferenceType type ; // Global, Local, Register, TempVariable (skip Permanent Variable)
std::variant<SBValueList, SBValue> value; // variables for that scope or variable.
};
denseMap<uint32_t, ReferencesTypes> scopes_types; |
@da-viper Thank you for your feedback! To address some of it
This is one of the bugs I'm aiming to fix with this PR, specially because it's extremely noticeable in Zed's debugger. Zed caches most of the requests it makes, and because lldb-dap reuses scope/variable references it's only able to get correct scopes/variables for the first frame it requests from. After running lldb-dap with my current branch the issue is fixed. I think it's because the variables request handler gets the correct scope from
I'll see if I can implement this. I might need some help because I've been primarily programming in Rust for a while now and am quite rusty when it comes to C++ 😀 Edit: I removed Variables::global, local, registers and the struct ScopeData {
ScopeKind kind;
lldb::SBValueList scope;
};
std::optional<ScopeData> GetScopeKind(const int64_t variablesReference);
lldb::SBValueList *GetScope(const uint32_t frame_id, const ScopeKind kind); And the data is already stored in variable list via these mappings // Variable Reference, frame_id
std::map<int64_t, std::pair<ScopeKind, uint32_t>> m_scope_kinds;
/// Variables that are alive in this stop state.
/// Will be cleared when debuggee resumes.
llvm::DenseMap<int64_t, lldb::SBValue> m_referencedvariables;
/// Key = frame_id
/// Value = (locals, globals Registers) scopes
std::map<uint32_t,
std::tuple<lldb::SBValueList, lldb::SBValueList, lldb::SBValueList>>
m_frames; |
I got rid of a variables locals, globals, and register fields and added some helper methods to access scopes based on a var_ref or a frame_id and a ScopeKind variant
void Variables::AddScopeKind(int64_t variable_reference, ScopeKind kind, | ||
uint32_t frame_id) { | ||
|
||
m_scope_kinds[variable_reference] = std::make_pair(kind, frame_id); | ||
} |
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.
When we ReadyFrame we could go ahead and add the m_scope_kinds[]
for the frame local/globals/registers. No need to separate those out.
return nullptr; | ||
} | ||
|
||
void Variables::ReadyFrame(uint32_t frame_id, lldb::SBFrame &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.
We could have this return a std::vector<Scope>
for the local/global/register scope.
@@ -11,6 +11,7 @@ | |||
#include "ExceptionBreakpoint.h" | |||
#include "LLDBUtils.h" | |||
#include "ProtocolUtils.h" | |||
#include "Variables.h" |
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.
Is variables needed any here? I don't see any usage...
@@ -9,6 +9,7 @@ | |||
#ifndef LLDB_TOOLS_LLDB_DAP_JSONUTILS_H | |||
#define LLDB_TOOLS_LLDB_DAP_JSONUTILS_H | |||
|
|||
#include "DAP.h" |
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.
We have DAPForward on line 13, do we need the full DAP here?
Closes #119784
This PR fixes two bugs:
It does this by storing all variables in their respective scopes and using that mapping in request handlers that relied on the old mapping. It dynamically creates new variable/scope IDs instead of resetting IDs whenever a new scope is created.
I also removed some unused code as well.