-
Notifications
You must be signed in to change notification settings - Fork 13
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
Support storing and applying of memory content #96
Support storing and applying of memory content #96
Conversation
src/common/debug-requests.ts
Outdated
@@ -0,0 +1,39 @@ | |||
/******************************************************************************** | |||
* Copyright (C) 2018 Red Hat, Inc. and others. |
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.
Never quite sure what to do with headers in copied code. Feels funny to have a header date older than the repo, though :-).
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.
Haha, that is a very interesting observation! I try to opt for the safest option but this really results in this slight repository paradox. If you want me to change it, let me know or maybe @planger knows whether there are any particular rules for the project.
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.
Now I'd say that you've rewritten fairly thoroughly, so it likely makes sense to put your company and the current date in here.
src/common/debug-requests.ts
Outdated
export interface DebugRequestTypes { | ||
'evaluate': [DebugProtocol.EvaluateArguments, DebugProtocol.EvaluateResponse['body']] | ||
'readMemory': [DebugProtocol.ReadMemoryArguments, DebugProtocol.ReadMemoryResponse['body']] | ||
'writeMemory': [DebugProtocol.WriteMemoryArguments, DebugProtocol.WriteMemoryResponse['body']] | ||
} |
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.
This sort of thing is maybe the only time I wish we had macros (and that the DAP had types for the body
of responses!).
It sounds like you don't like the idea of using the DebugProtocol
interfaces directly, but making this the primary declaration makes for ugly code in messaging.ts
where we refer to the things declared here by array index.
-
How strongly do you feel about not using the DAP types? We were already aliasing the
body
types for ergonomics, and we are in fact using them, so aliasing them doesn't change much. -
If you strongly prefer not using them directly anywhere but where we alias them, I think I'd prefer that we alias the types here for use elsewhere:
export interface DebugRequestTypes { | |
'evaluate': [DebugProtocol.EvaluateArguments, DebugProtocol.EvaluateResponse['body']] | |
'readMemory': [DebugProtocol.ReadMemoryArguments, DebugProtocol.ReadMemoryResponse['body']] | |
'writeMemory': [DebugProtocol.WriteMemoryArguments, DebugProtocol.WriteMemoryResponse['body']] | |
} | |
export type ReadMemoryArguments = DebugProtocol.ReadMemoryArguments; | |
export type ReadMemoryResult = DebugProtocol.ReadMemoryResponse['body']; | |
export type WriteMemoryArguments = DebugProtocol.WriteMemoryArguments; | |
export type WriteMemoryResult = DebugProtocol.WriteMemoryResponse['body']; | |
export type EvaluateArguments = DebugProtocol.EvaluateArguments; | |
export type EvaluateResult = DebugProtocol.EvaluateResponse['body']; | |
export interface DebugRequestTypes { | |
'evaluate': [EvaluateArguments, EvaluateResult] | |
'readMemory': [ReadMemoryArguments, ReadMemoryResult] | |
'writeMemory': [WriteMemoryArguments, WriteMemoryResult] | |
} |
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.
Absolutely true! I wonder if the VS Code people had a discussion about that because as soon as you actually start using it, you really see how accessing the body
of the responses makes for really long and really weird types ;-)
So my thought process in the split between the debug-requests.ts
and messaging.ts
is that the messaging is really the protocol between the extension's main side and the extension webview whereas the debug protocol messages are between the extension's main side and the debug adapter.
Therefore, bleeding any types from the debug protocol into the webview does not make much sense as it cannot directly access the debug adapter. Following that, it seemed logical to have a messaging layer in-between where we define the arguments and results of the main-webview communication. Sure, some of those types may be a 1:1 alias for a debug protocol message but we may also want to extend them at some point (like I do with the WriteMemoryArguments
), make parts required or optional (with a lot of the Partial
going around) or re-define them. So in a way, having all those DebugProtocol.ReadMemoryArguments
in the webview and the options is really more a "coincidence" because it obviously represents memory reading well but and also avoids giving some of the usages a more specific semantic imho.
Based on that, I'm absolutely not opposed to using the DebugProtocol
interfaces on the extension's main side within all the debug-related classes (which is why I also left them in the memory-provider
). Of course I wished for their names to be shorter, so we could alias them as in the debug-requests.ts
as you suggested but for me personally, that would not replace the type definitions that we do in messaging.ts
.
Long story short: I think we should distinguish between the types used in the main-debug communication and the ones in the main-webview communication. However, maybe I just overthought the whole thing so I don't plan to die on this hill ;-) I'd be very happy to get your thoughts on that though.
package.json
Outdated
@@ -92,19 +104,45 @@ | |||
{ | |||
"command": "memory-inspector.show-variable", | |||
"when": "false" | |||
}, | |||
{ | |||
"command": "memory-inspector.store-file", |
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 should disable the commands/buttons in the window if no debug session is active.
At the moment, I can click the buttons outside the debug session and get errors as expected.
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.
That is a very good point!
We can see that the command is already disabled as it does not show up in the command palette anymore (F1 + 'memory' because we can no longer read or write. I moved the enablement condition directly to the command but it seems that VS code still allows us to simply execute the command via code and I don't see any other way to determine whether our command is enabled or not. The documentation even states it like that:
(Optional) Condition which must be true to enable the command in the UI (menu and keybindings). Does not prevent executing the command by other means, like the `executeCommand`-api.
I added a new commit that now shares the current session state with the memory inspector so we can properly determine the read/write capabilities and disable our buttons accordingly.
100e9d0
to
9c497d1
Compare
@colin-grant-work Thank you for your detailed feedback! I tried to address everything in a follow up commit (after a rebase) and added another commit on top based on the feedback from Jens. Besides the type placement, I think I have addressed everything. |
c9f3c03
to
733088f
Compare
@martin-fleck-at , re-tested functionality. Did the ultimate test with storing memory from one of our existing debug tools to a hex file. And applying it with the Memory Inspector. And vice versa. Looks all healthy! :-) The recent change to connect a memory window instance to a debug session ID has the unfortunate side effect of not being able to reuse a memory window anymore. This was possible, would be good to get that back. Use case: I debug something and use the Memory Inspector, I make a code change, then restart debug, and would like to inspect related changes in the previously opened window instance. Some minor suggestions inline. One bigger change that may be required and is possibly out of scope for this one is to honor MS-DAP |
8cd7612
to
e945093
Compare
@jreineckearm Thank you very much for your feedback! I rebased the change and added the new functionality on top: The memory inspector should now properly refresh automatically and we also support the Furthermore, I added the missing context menu entries for #51. Could you please have another look at it? |
Quite a few changes since my last look - I'll read things over later today. |
@colin-grant-work Thank you very much! I added them as separate commits so it shouldn't be too bad, I hope! I'll do a quick rebase then. |
Add commands to store and apply memory content as Intel HEX file - Encapsulate behavior in new MemoryStorage class - Trigger 'store' from Memory view, Variables view and command palette - Trigger 'apply' from Memory view, Explorer view and command palette - Use nrf-intel-hex library for read/write file licensed under BSD-3 Use quick inputs to guide user through necessary input - Initialize as much of the input as possible through command args Communicate with webview through messenger requests and notifications -- Request to trigger store and apply from webview -- Notify webview about any written memory so it can update properly Minor improvements - Move some common types and functionality into 'common' area - Avoid bleeding Debug Adapter types into webview, use messaging types - Common style: 'getVariables' -> 'getVariablesType' - Provide utility functions and types for debug requests - Fix 'Enter' handling for numpad by checking key value of event Closes eclipse-cdt-cloud#50
- Move evaluation expression for addressOf and sizeOf to adapter - Make 'toHexStringWithRadixMarker' more flexible - Shorten validation messages for memory - Align props and method names with existing method names, no prefixes - Replace 'MemoryVariableNode' with 'IVariablesContext' - Add comment on overlap calculation - Make sure command enablement fails early
- VS Code always allows to execute a command programmatically -- There is no way to determine whether a command is enabled or not - Forward current session context to memory inspector
e945093
to
934e95e
Compare
- Integrate commands with context menu - React to 'memory' event from debug adapter - Use 'Store Memory to File' as proper storage label - Use workspace folder as default save location - Minor fix for numpad key enter on memory options
934e95e
to
4b0c003
Compare
@colin-grant-work @jreineckearm Everything should be good to review again ;-) |
Thanks, @martin-fleck-at ! From a functionality point of view, things work as outlined in your last comment. This is a really nice new feature!
Minor improvement for later (not this PR)
|
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.
Nice, thanks for incorporating the feedback! LGTM!
Sorry, wrong Github window. But applies here of course, too. :-)
(Anyone who has the power feel free to delete this comment, and please do not merge until @colin-grant-work had a chance to review).
src/common/debug-requests.ts
Outdated
@@ -0,0 +1,39 @@ | |||
/******************************************************************************** | |||
* Copyright (C) 2018 Red Hat, Inc. and others. |
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.
Now I'd say that you've rewritten fairly thoroughly, so it likely makes sense to put your company and the current date in here.
- Use short (PascalCase) names for generic arguments - Adapt copyright header in debug-requests - Remove optional 'count' parameter in messaging and memory-provider - Remove caching of session context and simply re-create if necessary - Execute variable queries in parallel instead of sequentially - Fix typo in comment
ef0e3b2
to
83c51b5
Compare
@colin-grant-work @jreineckearm I pushed an update that should address the latest concerns. |
@@ -42,13 +42,14 @@ export class CTracker extends AdapterVariableTracker { | |||
return undefined; | |||
} | |||
try { | |||
const variableAddress = await this.getAddressOfVariable(variable.name, session); | |||
const [variableAddress, variableSize] = await Promise.all([ | |||
variable.memoryReference && hexAddress.test(variable.memoryReference) ? variable.memoryReference : this.getAddressOfVariable(variable.name, session), |
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 consider different integer representations? Not sure if all debug adapters would always return a hex value for an address (although IMO the sensible thing to do).
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.
That is a good point! But I'd rather defer this discussion into a separate issue. The previous behavior also used the hexAddress
. I did add a commit that unifies that check but I still think it does not necessarily have to be part of this PR, do you agree?
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.
Fine with me. TBF, I'd expect addresses to be returned as hex values anyway.
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.
Since this isn't standardized, I'd probably prefer a check for any (easily parsed) number format so that 16
is valid in addition to 0x10
. That would follow the convention for things like the ReadMemoryResponse
and DisassembledInstruction
where at least hex and decimal are both considered acceptable formats.
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.
Fantastic, thank you! I added #107 to track this. It shouldn't be too much work but it needs to be discussed first (all formats vs "only" hexadecimal/decimal because they are mentioned in the DAP).
69c5c9d
to
8583bb8
Compare
8583bb8
to
175a330
Compare
protected async storeMemory(storeArguments: StoreMemoryArguments): Promise<void> { | ||
// Even if we disable the command in VS Code through enablement or when condition, programmatic execution is still possible. | ||
// However, we want to fail early in case the user tries to execute a disabled command | ||
if (!this.memoryProvider.createContext().canRead) { | ||
throw new Error('Cannot read memory, no valid debug session.'); | ||
} | ||
return vscode.commands.executeCommand(StoreCommandType, storeArguments); | ||
} | ||
|
||
protected async applyMemory(): Promise<MemoryOptions> { | ||
// Even if we disable the command in VS Code through enablement or when condition, programmatic execution is still possible. | ||
// However, we want to fail early in case the user tries to execute a disabled command | ||
if (!this.memoryProvider.createContext().canWrite) { | ||
throw new Error('Cannot write memory, no valid debug session.'); | ||
} | ||
return vscode.commands.executeCommand(ApplyCommandType); | ||
} |
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.
For a follow-up: since we're sending a context to the view that includes information about the session that that window is associated with, these requests could handle that association and check the relevant session, rather than defaulting to the active session. Re: #97.
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.
This is a very good point and I believe that should be handled as part of #97 as we definitely want to do this for all requests (read, write, store, apply, get variables).
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'm happy with the changes. Both of my last comments can be handled as a follow-up, though I'd like it if the address parsing were handled in this PR.
@colin-grant-work Thank you very much! I'll push an update for the decimal address support in a few minutes! |
- Provide decimal address regex and function to extract address - Ensure we can properly serialize bigints when logging data - Ensure we return a proper variable range if we only have the address
@colin-grant-work If you agree with the latest commit, please feel free to merge this PR. |
What it does
Add commands to store and apply memory content as Intel HEX file
Use quick inputs to guide user through necessary input
Communicate with webview through messenger requests and notifications
Minor improvements
memory-store-apply.mp4
Closes #50
How to test
Review checklist
Reminder for reviewers