Skip to content
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

Integrate Memory Inspector in Theia repository #11394

Merged

Conversation

colin-grant-work
Copy link
Contributor

What it does

This PR transfers the Memory Inspector functionality from the Theia CPP Extensions to the Theia repository. Relative to the current state of that repository, this PR makes some minor changes necessary to operate with [email protected] and transfers some functionality that is not fully determined by the Debug Adapter Protocol into the MemoryProviderService, where it can be more easily adjusted for adapters with specific known properties.

How to test

  1. With the CDT-GDB adapter, the instructions from this PR still apply
  2. To demonstrate the functionality with another debug adapter: (less convenient than GDB, because it supports fewer reference options)
  3. Create and open a new Rust project or use this one
  4. In your workspace, make sure that the preference lldb.rpcServer is set to null to work around Incorrect conversions from null to undefined in new RPC #11392
  5. Install Rust Analyzer and CodeLLDB
  6. (If using the example project linked above) open main.rs and put a breakpoint on line 12.
  7. Use the code lenses provided by Rust Analyzer to start a debug session from the testson lines 16-25.
  8. When you hit the breakpoint, the terminal in which the program is running will have printed two addresses.
  9. Open the memory inspector from the right panel and input one of the addresses into the address selector and hit Go. The memory location should load, and it should match the data of the struct whose address you entered.

Review checklist

Reminder for reviewers

@colin-grant-work colin-grant-work added debug issues that related to debug functionality proposal feature proposals (potential future features) labels Jul 7, 2022
@colin-grant-work colin-grant-work marked this pull request as draft July 7, 2022 22:32
@JonasHelming
Copy link
Contributor

Just out of interest: Did you consider moving this to CDT.cloud instead of the Theia main repo?

@colin-grant-work
Copy link
Contributor Author

@JonasHelming, I've made this PR for two reasons: I believe that having the code in this repo will make it easier to ensure its compatibility with latest Theia, and I believe that it's advantageous with respect to the features requested in #10841. What would be the benefit of placing it in CDT.cloud?

@colin-grant-work colin-grant-work force-pushed the feature/memory-inspector branch from ab0ec7f to b6db786 Compare July 12, 2022 21:56
@colin-grant-work colin-grant-work marked this pull request as ready for review July 12, 2022 23:27
@JonasHelming
Copy link
Contributor

Basically to keep the core Theia project as slim as possible. Most components would benefit from beeing moved to the core project/repo in terms of ensuring compatibility. Are the people maintaining this component the same team that are core Theia developers? Again: I am not opposed to move this to Theia core, I just wanted to raise the question as we had a tendency to try to keep the core repo as small as possible.

One example that you could aim at when hosting it at CDT.cloud would be to ensure compatibility for community releases only.
Again, up to you!

@JonasHelming
Copy link
Contributor

Thinking about this again: the memory inspector is not necessarily bound to C/C++, correct? This would be an argument in favor to keep it in Theia.

@colin-grant-work
Copy link
Contributor Author

@JonasHelming, exactly. I've been waiting till I could get it working on at least one non-C(++) debug adapter before trying to move it here, and I was finally able to get it working for Rust. :-)

Copy link
Member

@vince-fugnitto vince-fugnitto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a second commit to localize everything I could find, and cleaned up the code slightly.
I still have some comments however.

"@theia/core": "1.27.0",
"@theia/debug": "1.27.0",
"long": "^4.0.0",
"vscode-debugprotocol": "^1.48.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to also update vscode-debugprotocol in @theia/debug and @theia/plugin-ext to follow this version:

"vscode-debugprotocol": "^1.32.0"

"vscode-debugprotocol": "^1.32.0",

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because they're both caret versions, we're currently getting a high-enough version (1.51) in our yarn.lock, but it's probably best to be explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the entries in our various package.json. They've deprecated this package name, so I've updated that, as well, with the unfortunate consequence that the new package name isn't part of the 3PP baseline, apparently.

Comment on lines 31 to 37
render(): React.ReactNode {
return (
<div className='t-mv-memory-fetch-error'>
Click the
{' '}
<i className='memory-view-icon toolbar' />
{' '}
icon to add a new memory view or the
{' '}
<i className='register-view-icon toolbar' />
{' '}
icon to add a register view.
</div>
);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably clean up this method and localize if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up, but not localized. Not quite sure what to do with the fact that it's broken up by the icons - the pieces in between aren't meaningful enough to pass to an automated translation tool. @msujew, any suggestions?

Copy link
Member

@msujew msujew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it yet, but here are my obligatory i18n comments :)

Also please rebase on latest master to get access to automatic translations for your changes.

while (currentLevel.parent instanceof DebugVariable) {
currentLevel = currentLevel.parent;
}
return currentLevel.parent instanceof DebugScope && currentLevel.parent['raw'].name === 'Local';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Are Local or Registers localized values? I'm feeling queasy about the comparison.

Copy link
Contributor Author

@colin-grant-work colin-grant-work Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair observation. This class is intended to be tightly coupled to CDT-GDB adapter, and at the moment, it does not localize any of its text, and adapter returns are mapped fairly directly into the display in the Variables widget, so this should work, but it's certainly not as robust as might be ideal. To my knowledge, there aren't hard conventions about the naming of variable scopes - an adapter could return any labels it wants - so I don't see a very good way around this, at the moment. The DAP does specifically mention both that the name of a scope returned by an adapter should be displayed as is, and that that text may be translated (on the adapter's side, presumably).

@colin-grant-work colin-grant-work force-pushed the feature/memory-inspector branch from 167ec32 to d8f1b57 Compare August 4, 2022 16:31
@JonasHelming
Copy link
Contributor

@colin-grant-work Is this ready for a re-review?

@vince-fugnitto vince-fugnitto self-requested a review August 17, 2022 14:08
Copy link
Contributor

@martin-fleck-at martin-fleck-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @colin-grant-work and everyone, thank you for the great work!

I had a look at this PR for an adopter where we customized the memory view to stick on a particular thread. The design of this component is really thought-out and it was easy to do most of the necessary customizations. Still, I thought I'd share some of my observations with you - mostly about making things a bit easier to override. Please note that my comments are just some minor things that should not prevent this PR from being merged.

async createNewMemoryWidget<T extends MemoryWidget>(kind: 'register' | 'memory' = 'memory'): Promise<T> {
this.widgetDisplayId = this._availableWidgets.size !== 0 ? this.widgetDisplayId + 1 : 1;
const options: MemoryWidgetOptions = { identifier: this.createdWidgetCount += 1, displayId: this.widgetDisplayId };
const widgetId = kind === 'memory'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand that correctly that the only way to plug in a custom memory or widget view is to re-bind the manager and override this method? At least the README seems to suggest so. If that is true, it would be really create if this mapping from kind to widget id could be in a separate overridable/protected method for easier customization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is reasonable, but doing it right would require a bit of a refactor - I'll leave this one out for now.

Copy link
Contributor

@martin-fleck-at martin-fleck-at Aug 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, you can keep the effort as low as possible. I just thought something simple along the lines of:

protected mapKindToWidgetId(kind: 'register' | 'memory' = 'memory') {
   return kind === 'memory' ? MemoryWidget.ID : RegisterWidget.ID;
}

So in case you want the editable memory widget you could simply do:

protected override mapKindToWidgetId(kind: 'register' | 'memory' = 'memory') {
   return kind === 'memory' ? EditableMemoryWidget.ID : RegisterWidget.ID;
}

But we can also keep it as is for now.

console.log('Problem writing memory with arguments', edit, '\n', e);
}
}
this.memoryEditsCompleted.resolve();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that when I submit edits there is no update on the view by default. We do resolve the edits which means that the next time the memory is changed it will update accordingly and the pending edits are cleared (handleMemoryChange). But this requires a specific user action. At the moment, the pending changes just remain in the UI. Should we trigger an explicit update from here or what is the expected flow after the user submits the edits?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit tricky because the debug session doesn't emit any events when memory changes - we just get a response. When we implemented this internally, we just had the debug adapter send a StoppedEvent after successfully updating memory, but that was a bit of a workaround, and I didn't include it when implementing the write memory request upstream in the CDT-GDB adapter. I think your suggestion of triggering a refresh cycle is probably the best way to handle it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've modified the code here so that if a write succeeds we refresh the memory, but we don't clear any pending edits.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really, really like this solution! I tested it and it works and looks great! I think it is a great solution to clear the edits one by one if there is no error. Thank you, Colin!

@martin-fleck-at
Copy link
Contributor

@vince-fugnitto @colin-grant-work: Thanks again for the great work! Is there any chance this PR can make it in the upcoming release? If there is any way I can help out, please let me know.

@colin-grant-work
Copy link
Contributor Author

@martin-fleck-at, I'll devote some time to this today to address the outstanding comments.

@colin-grant-work colin-grant-work force-pushed the feature/memory-inspector branch 2 times, most recently from ae1d582 to a3785f8 Compare August 23, 2022 21:04
@colin-grant-work
Copy link
Contributor Author

@vince-fugnitto, @martin-fleck-at, I've addressed most of y'all's comments - since there's some interest in getting this into the release, would you mind taking another look?

Copy link
Contributor

@martin-fleck-at martin-fleck-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Colin, I retested our customization with the new commits and everything still works great and I definitely saved a couple of lines of copied code ;-) I really appreciate the time you are taking for this, so thank you very much!

I found a few minors in the new code that again do not a affect the functionality so if you have some time you could fix them but otherwise I'd rather see this change merged than delayed for the next release.

console.log('Problem writing memory with arguments', edit, '\n', e);
}
}
this.memoryEditsCompleted.resolve();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really, really like this solution! I tested it and it works and looks great! I think it is a great solution to clear the edits one by one if there is no error. Thank you, Colin!

packages/memory-inspector/package.json Outdated Show resolved Hide resolved
async createNewMemoryWidget<T extends MemoryWidget>(kind: 'register' | 'memory' = 'memory'): Promise<T> {
this.widgetDisplayId = this._availableWidgets.size !== 0 ? this.widgetDisplayId + 1 : 1;
const options: MemoryWidgetOptions = { identifier: this.createdWidgetCount += 1, displayId: this.widgetDisplayId };
const widgetId = kind === 'memory'
Copy link
Contributor

@martin-fleck-at martin-fleck-at Aug 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, you can keep the effort as low as possible. I just thought something simple along the lines of:

protected mapKindToWidgetId(kind: 'register' | 'memory' = 'memory') {
   return kind === 'memory' ? MemoryWidget.ID : RegisterWidget.ID;
}

So in case you want the editable memory widget you could simply do:

protected override mapKindToWidgetId(kind: 'register' | 'memory' = 'memory') {
   return kind === 'memory' ? EditableMemoryWidget.ID : RegisterWidget.ID;
}

But we can also keep it as is for now.

@colin-grant-work
Copy link
Contributor Author

@martin-fleck-at, I've pushed commits that I hope should address your concerns and requests.

Copy link
Contributor

@martin-fleck-at martin-fleck-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, everything has been done, thank you very much, Colin! I really appreciate it!

I re-tested the latest version with our customizations and everything works and looks great. It is really an awesome feature, thank you to everyone involved.

@martin-fleck-at
Copy link
Contributor

@vince-fugnitto Do you want to have another look at it or do you think we can merge this?

@colin-grant-work colin-grant-work force-pushed the feature/memory-inspector branch from b355a0d to 64c8047 Compare August 25, 2022 14:15
@colin-grant-work colin-grant-work merged commit 9331b9b into eclipse-theia:master Aug 25, 2022
@colin-grant-work colin-grant-work deleted the feature/memory-inspector branch August 25, 2022 14:38
@colin-grant-work colin-grant-work added this to the 1.29.0 milestone Aug 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
debug issues that related to debug functionality proposal feature proposals (potential future features)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants