microsoft / vscode-debugadapter-node

Debug adapter protocol and implementation for VS Code.
Other
273 stars 79 forks source link

Add support for registers, disassembly, and memory #212

Closed andrewcrawley closed 5 years ago

andrewcrawley commented 5 years ago

Extends the debug adapter protocol to support reading arbitrary memory, disassembling code, and accessing registers.

CC: @weinand @gregg-miskelly

haneefdm commented 5 years ago

Pardon my intrusion. My understanding is that there can be a registers scope per frame on the stack. Yes, only one registers scope (which can have sub-scopes) per frame but in the context of that frame. The global registers values are really in the context of the leaf frame for the thread that got interrupted. Debuggers know which registers are saved on the stack according to the ABI and how to retrieve those values when queried. Am I making sense?

Happy to research it and point to docs if you want.

haneefdm commented 5 years ago

@andrewcrawley You said having an offset from a memoryReference was useful/helped based on your some recent work. I am 110% positive you found that to be case. May I ask how it was useful? I ask because the DA client can easily do that calculation and the DA implementation becomes more complicated.

haneefdm commented 5 years ago

About Disassembly: OMG, sorry to be so annoying. cringe. I am sure this was already thought out and I hope I am not wasting your time.

As of today, the protocol does not expose querying symbols and their current (relocated) addresses. How is a DA client supposed to figure out what an address of anything is to make a query? With Windows/PE, they can/will be rebased so reading the dll/exe is useless. ELF may not have absolute addresses -- virtualized or not.

But generally, the debugger knows. Or could memoryReference also support a symbol reference. My head hurts but if you give some time, I can figure it out.

andrewcrawley commented 5 years ago

@haneefdm:

Pardon my intrusion. My understanding is that there can be a registers scope per frame on the stack. Yes, only one registers scope (which can have sub-scopes) per frame but in the context of that frame. The global registers values are really in the context of the leaf frame for the thread that got interrupted. Debuggers know which registers are saved on the stack according to the ABI and how to retrieve those values when queried. Am I making sense?

Happy to research it and point to docs if you want.

Correct. You'd get the registers for whichever frame's frameId you pass when making the scopes request.

@andrewcrawley You said having an offset from a memoryReference was useful/helped based on your some recent work. I am 110% positive you found that to be case. May I ask how it was useful? I ask because the DA client can easily do that calculation and the DA implementation becomes more complicated.

Certain use cases for the VS disassembly window required the ability to say "go to this address and disassemble N instructions", and the way to represent an arbitrary address in the protocol is via a memoryReference + offset value.

About Disassembly: OMG, sorry to be so annoying. cringe. I am sure this was already thought out and I hope I am not wasting your time.

As of today, the protocol does not expose querying symbols and their current (relocated) addresses. How is a DA client supposed to figure out what an address of anything is to make a query? With Windows/PE, they can/will be rebased so reading the dll/exe is useless. ELF may not have absolute addresses -- virtualized or not.

But generally, the debugger knows. Or could memoryReference also support a symbol reference. My head hurts but if you give some time, I can figure it out.

If I understand correctly, you're asking how to get the address of "my_func" to use as (for example) the start point for disassembly? VS handles this by issuing an evaluate request for "my_func", then uses the memoryReference provided on the response as the start point for disassembly.

haneefdm commented 5 years ago

Okay, thanks.

gregg-miskelly commented 5 years ago

@haneefdm in case you didn't see, this PR was superseded by:

https://github.com/microsoft/debug-adapter-protocol/pull/49 https://github.com/microsoft/debug-adapter-protocol/pull/50

haneefdm commented 5 years ago

@gregg-miskelly Yup, I saw that, somehow I got notified. Cracked me up when @weinand said "where the truth lives" microsoft/debug-adapter-protocol#49

gregg-miskelly commented 5 years ago

As of today, the protocol does not expose querying symbols and their current (relocated) addresses. How is a DA client supposed to figure out what an address of anything is to make a query? With Windows/PE, they can/will be rebased so reading the dll/exe is useless. ELF may not have absolute addresses -- virtualized or not.

Are you talking about a scenario where the user wants to navigate to the disassembly of a function by inputting the function's name? If so, the way that would work would be to issue an evaluate request, using the text of the function name. The response from that should contain a memory reference which could then be used to issue a disassembly request.

If you are asking more about how a native debugger actually implements this feature - a native debugger needs to be aware of what modules are loaded into the target process and what base address the module is loaded at (or addresses on platforms where the loaded is allowed to relocate different sections of the image). Then it can use the base address of the module combined with the relative virtual address (RVA) that it obtained from the dll/pdb/elf/dwarf info to decide what address(es) the function is at.

haneefdm commented 5 years ago

@gregg-miskelly Less worried about how the debugger figures it out.

From a DA clients perspective, it needs to be a fully qualified name right? Which module dll/so/elf-section/etc because there can be duplicates without fully qualified names. To get a proper memory reference for a DA client, I was trying to figure out how that is done for an arbitrary function.

What helps is that all evaluate's happen in the context of frame/scope. Perhaps this is all that is needed.

gregg-miskelly commented 5 years ago

What helps is that all evaluate's happen in the context of frame/scope. Perhaps this is all that is needed.

Correct. The DA could also require qualification in cases where things are ambiguous. For example, the native VS debugger supports 'module.dll!Function', and even stranger syntax's for static functions.

weinand commented 5 years ago

I've released support for registers and "experimental" support for disassembly and memory access to the DAP in both the "debug-adapter-protocol" and in the "vscode-debugadapter-node" repositories.

haneefdm commented 5 years ago

You people are awesome. I did not add anything to what you already had thought through and your constraints. Wasted your time.

As punishment and for posterity, do you want me to document the clarifications and use cases as a summary? Once it is approved.

gregg-miskelly commented 5 years ago

@haneefdm if you have some clarifications which you think help - I would suggest opening a PR against microsoft/debug-adapter-protocol. If you are talking about a longer document for the disassembly API - I am not sure where to put it. So its up to you if you think it is worth your effort to find a place.

haneefdm commented 5 years ago

@gregg-miskelly may I ask what the next steps are? and where I can help? my first wish is 'registers'

andrewcrawley commented 5 years ago

@haneefdm: We should probably stop using this defunct PR as a discussion forum : ) I've replied to you on the MIEngine issue here: https://github.com/microsoft/MIEngine/issues/816

weinand commented 5 years ago

Yes please, this repo is only for the node.js based client library for DAP. If you are not using these npm modules (or if you do not have issues with it :-), please don't use this repo.