Skip to content

Proposal: Support for reading registers #41

Closed

Description

We propose that adapters can present a set of CPU registers to the frontend by returning an additional scope in response to the scopes request. The name of this scope would be provided in the adapter's Capabilities to support frontends such as VS that show registers in a separate window. This allows adapters to localize the scope's name for display in VSCode while still allowing VS to find it:

export interface Capabilities {
    // ....

    /** Name of the scope that contains register variables. */
    registersScopeName?: string;
}

In the simplest form, the scope would contain one variable for each register, e.g.:

  • [Scope] Registers
    • [Variable] EAX = ...
    • [Variable] EBX = ...
    • [Variable] XMM0 = ...
    • [Variable] XMM1 = ...
    • ...

Additionally, VS supports categorization of registers, and allows individual categories to be shown / hidden. This could be supported via nesting, where the intermediate level variable provides the category name and contains the actual register values as children, e.g.:

  • [Scope] Registers
    • [Variable] CPU
      • [Variable] EAX = ...
      • [Variable] EBX = ...
      • ...
    • [Variable] SSE
      • [Variable] XMM0 = ...
      • [Variable] XMM1 = ...
      • ...

CC: Gregg Miskelly (@gregg-miskelly)

Activity

  1. haneefdm commented on May 19, 2019

    @haneefdm
    Contributor

    Andrew Crawley (@andrewcrawley), Gregg Miskelly (@gregg-miskelly) Pierson Lee (@pieandcakes)

    This is great. Can I help to implement/prototype this in MIEngine? Not sure how to proceed

  2. PavelSosin commented on May 19, 2019

    @PavelSosin

    I vote No ! Debug Adapter Protocol means High Level Language Debug Adapter protocol. High Level language is abstraction which allows to write code without dealing with architecture. Reading registers breaks this abstraction. Even Cuda is abstraction. I know that I can use java to program Arm. I have very little interest in where registers are in Arm, how GPU memory is addressed and which elements of CPU participate in hardware acceleration. There are better places to discuss driver debugging protocol

  3. puremourning commented on May 19, 2019

    @puremourning
    Contributor

    Pavel Sosin (@PavelSosin) I totally disagree. All applications run on real hardware, and pretty much all real hardware has registers, memory and a processor. Debuggers are for real applications, not "high level languages". How does preventing viewing registers aid debugging?

    I think this proposal is very sensible.

  4. haneefdm commented on May 19, 2019

    @haneefdm
    Contributor

    Pavel Sosin (@PavelSosin) Perhaps you misunderstand. This is an optional capability that only makes sense for certain Debug Adapters and only those adapters will advertise it. Clients GUIs do not even have to use it. No one else is affected. For instance, the Scripts window in VSCode is not for everyone and is not shown when debugging C/C++. Nothing to do with driver development. Some (millions) of us still have to use C/C++ but even those have little interest in seeing registers. But, when something goes wrong, or we need the absolute best performance, this is needed -- sometimes to give you those high-level abstracted languages. Rust is another language that can use it.

    Final note: There are millions of embedded/IoT developers who would just love VStudio/VSCode besides desktop developers.

    I noticed you also posted similar views in issue #42 Same deal.

  5. haneefdm commented on May 19, 2019

    @haneefdm
    Contributor

    Btw, I have my own experimental extension to see registers. It is ugly and not performant. A hack really. But it works.

    I recently submitted a patch to MIEngine debug adapter, so somewhat familiar with the code and thus offering to help. It is still a proposal stage, we need a prototype to make sure.

    CC: Gregg Miskelly (@gregg-miskelly) Pierson Lee (@pieandcakes)

  6. haneefdm commented on May 20, 2019

    @haneefdm
    Contributor

    Andrew Crawley (@andrewcrawley) Trying to understand a bit. Gregg Miskelly (@gregg-miskelly) his idea was that registers simply show up in the Variables window as a separate scope regardless of what part of the stack/frame you are looking at. So this proposal says simply what name a DA has decided to use/implement? If a client (UI) wants to know where registers exist and how to display them, this is the name they would look for.

    As of today, a DA can already add scopes/nesting (real or made-up). This proposal simply says the DA can advertise the root-name of a scope meant for 'processor' registers. Totally innocuous.

  7. PavelSosin commented on May 20, 2019

    @PavelSosin

    Unfortunately, something ugly ans not aligned with other debuggers behavior can't pass through our UX. As it is known to me nobody in our Debugger team knows C++ and we have only one team responsible on Debugging features for all languages. We have only one team responsible on Editors too. They work strictly by Protocol definition. Everything has to be encapsulated in Protocol itself and client and server capabilities. Every debugger UI inherits 90% of capabilities from "abstract" debugger UI. Protocol standard should reflect abstract debugger UI communication with abstract debugging server. I don't expect that people developing Java debugging core jdt are specialists in WebUI. DAP for C++, DAP for Go and DAP for typescript are nonsense. We have only one LSP protocol which serves all languages and all editors. Language specific extensions are allowed but UI should be decoupled from server anyway.

  8. gregg-miskelly commented on May 20, 2019

    @gregg-miskelly
    Member

    Pavel Sosin (@PavelSosin) I think you misunderstand this very modest proposal. Also, please pick a more open tone in the future.

    This proposal has the following impact: if you have a debug adapter, such as C++ debug adapter, where showing register values would be useful, AND if you want to plug into a debugger UI, such as Visual Studio, where there is a special window for showing registers, then this proposal is how the debug adapter and UI can communicate over which scope contains registers. This is all this does. If you own a debug adapter and you don't want to provide registers - not a problem. If you own a debugger UI and you don't want to display registers in a special way - not a problem either.

  9. gregg-miskelly commented on May 20, 2019

    @gregg-miskelly
    Member

    Haneef Mohammed (@haneefdm) this idea is a slight refinement to my original idea -- instead of showing it as a pseudo-variable, we can instead display them as a pseudo-scope. We can create the scope with the `expensive = true;`` to it will just show up in VS Code in an unobtrusive way. This proposal just lets us hookup to the registers Window in VS.

  10. puremourning commented on May 20, 2019

    @puremourning
    Contributor

    Yes the scopes are a good choice for this IMO.

    Indeed, I seem to recall that one existing debug adapter that uses lldb already does exactly this.

  11. haneefdm commented on May 20, 2019

    @haneefdm
    Contributor

    Gregg Miskelly (@gregg-miskelly) Yes, I understood as that. For some reason, I thought you also said scopes or thats how I took it. Thank you for the specific line link to the schema. You all are awesome.

    This proposal just lets us hookup to the registers Window in VS.

    Did you mean the existing variables window? Looking to clarify.

  12. andrewcrawley commented on May 20, 2019

    @andrewcrawley
    Author

    Haneef Mohammed (@haneefdm): VS has a "Registers" window that is separate from the "Variables" window - look at Debug -> Windows -> Registers. Here's an example:
    image

    In this case, the window was populated via the following requests (I've snipped out the irrelevant messages):

     1> --> C (scopes-30): {"command":"scopes","arguments":{"frameId":1000},"seq":30,"type":"request"}
     1> <--   R (scopes-30) [9 ms]: {"seq":51,"type":"response","request_seq":30,"success":true,"command":"scopes","message":"","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false},{"name":"Registers","variablesReference":1001,"expensive":true}]}}
    
     1> --> C (variables-32): {"command":"variables","arguments":{"variablesReference":1001,"format":{"hex":true},"timeout":2000},"seq":32,"type":"request"}
     1> <--   R (variables-32) [15 ms]: {"seq":53,"type":"response","request_seq":32,"success":true,"command":"variables","message":"","body":{"variables":[{"name":"CPU","value":"","variablesReference":1006},{"name":"CPU Segments","value":"","variablesReference":1007},{"name":"Floating Point","value":"","variablesReference":1008},{"name":"MMX","value":"","variablesReference":1009},{"name":"SSE","value":"","variablesReference":1010},{"name":"AVX","value":"","variablesReference":1011},{"name":"MPX","value":"","variablesReference":1012},{"name":"Flags","value":"","variablesReference":1013}]}}
    
     1> --> C (variables-35): {"command":"variables","arguments":{"variablesReference":1006,"format":{"hex":true},"timeout":2000},"seq":35,"type":"request"}
     1> <--   R (variables-35) [5 ms]: {"seq":56,"type":"response","request_seq":35,"success":true,"command":"variables","message":"","body":{"variables":[{"name":"EAX","value":"00000001","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EBX","value":"011AF000","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"ECX","value":"1FB80000","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EDX","value":"00000000","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"ESI","value":"0133F5DC","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EDI","value":"0133F720","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EIP","value":"00A81F68","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"ESP","value":"0133F5DC","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EBP","value":"0133F720","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EFL","value":"00000246","presentationHint":{"attributes":["readOnly"]},"variablesReference":0}]}}
    
     1> --> C (variables-42): {"command":"variables","arguments":{"variablesReference":1013,"format":{"hex":true},"timeout":2000},"seq":42,"type":"request"}
     1> <--   R (variables-42) [5 ms]: {"seq":63,"type":"response","request_seq":42,"success":true,"command":"variables","message":"","body":{"variables":[{"name":"OV","value":"0","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"UP","value":"0","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"EI","value":"1","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"PL","value":"0","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"ZR","value":"1","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"AC","value":"0","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"PE","value":"1","presentationHint":{"attributes":["readOnly"]},"variablesReference":0},{"name":"CY","value":"0","presentationHint":{"attributes":["readOnly"]},"variablesReference":0}]}}
    
    

    You can see the extra "Registers" scope being returned in the first response.

  13. 14 remaining items

  14. isidorn commented on May 23, 2019

    @isidorn

    For me the capabilities is something that the debug adapter is capable of doing. Specifying the registerScopeName feels like it does not belong there.
    Since this information is more scope specific it makes sense to me to live in the Scope as Andre Weinand (@weinand) suggests.

    As for having multiple scopes of kind = regsiters, I feel like it is up to the debug adapter to make sure this does not happen and that it is emitting proper scope data.

  15. weinand commented on May 23, 2019

    @weinand
    Contributor

    Andrew Crawley (@andrewcrawley) if it's OK with you, I will implement the kind based approach because it avoids the problem that clients have to interpret localisable UI values (which is not done anywhere else in DAP).

    IMO the issue of having multiple scopes flagged as "registers" is minor in comparison and I will address it in the attribute's documentation.

    As you suggested I will also add values for "arguments" and "locals".

  16. haneefdm commented on May 23, 2019

    @haneefdm
    Contributor

    Andre Weinand (@weinand) Andrew Crawley (@andrewcrawley) I must be missing something. Yes, the value of registersScopeName has to be localized. But as a client as in the UI, I probably do not worry what the value is. If I want the registers, I simply query the DA using the value of registersScopeName. If I query for a list of scopes, and if a scope name matches the value of registersScopeName, I know that that scope is for registers.

    If you do the kind based approach, there are so many of those for all kinds of languages, I am not even sure how to enumerate them all. Locals/Globals/Arguments/Closures/Block/File-Static/Other.

    Either approach is fine but just wanted to bring it up. I am not worried of duplicates either

  17. weinand commented on May 23, 2019

    @weinand
    Contributor

    Haneef Mohammed (@haneefdm) you are correct that a client does not have to worry about the value of the registersScopeName capability.

    However, DAP's approach to conveying "semantics" vs. "just strings" is as follows:

    • as long as we expect that clients have no need to understand the semantics of specific UI strings, we just send strings (which can be modified (e.g. through localisation) without danger).
    • if we see a need for clients to understand the semantics of specific strings, we introduce an additional attribute to convey the semantics. One past example was the introduction of the description attribute for the StoppedEvent which only had a reason attribute initially (and people were starting to "scrape" those strings to understand the semantics of the event).

    Introducing an additional attribute is less error prone than using the registersScopeName approach, because it does not require that two strings are changed in a consistent way in two source locations.

    The scope "kind" is what I call an "open-ended enum". That means it is not a fixed set of all possible values but it only contains those few values that we can all agree on and we can add more values to it in the future.

    So for this proposal it would be sufficient to just have "registers" in the enum.
    "arguments" and "locals" were only included because they are already part of the Scope's documentation. But there is no need for an exhaustive set of values.

  18. gregg-miskelly commented on May 23, 2019

    @gregg-miskelly
    Member

    One additional note -- we only need to add a new 'kind' value when there exists at least one client that has special handling of a particular scope type. For example, Visual Studio has a registers window so we need that one. If, in the future, some other debugger UI that wants to become a DAP client has a Globals window, we could add that kind value for that. But there is no reason to do so now since the enum can always be extended.

  19. andrewcrawley commented on May 23, 2019

    @andrewcrawley
    Author

    Alright, sounds good to me!

  20. PavelSosin commented on May 24, 2019

    @PavelSosin

    I think that Andre Weinand has real experience with application development for Arm architecture. Arm architecture is not similar to Intel architecture. Arm memory structure differs from Intel memory structure. Arm assembler is not like Intel assembler. Every high level language has own abstraction. Every programming language assumes own run-time with own low-level debugging protocol. I suppose it is not good idea to build Debugger client-server communication on Server-Client capabilities exchange. Debugger UI and Debugger Server simply know the language semantics and all language and architecture specific information could be sent via qualifiers. Function can be qualified as "function". Memory addresses can be qualified as "memory", Registers can be qualified as "register" or "register of kind". Operations - display, set, step, step-into, step-over, run, continue-to, set-breakpoint, clear-breakpoint, watch are universal. Stack and stack frame are also universal. It is strange to think how debugger can not to support them and every Server implementation must support them. validity of certain operation and qualifier combinations should be enabled or disabled by UI based on its knowledge of context and accepted or rejected by server based on its knowledge of context in run-time. UI displays values provided by server based
    of its interpretation of qualifiers. Implementations of UI and server are based on Language context and low-level debugging protocol capabilities. All kinds of UIs and Server extend abstract UI and abstract server.

  21. haneefdm commented on May 24, 2019

    @haneefdm
    Contributor

    Andre Weinand (@weinand) I got ya, about scope kind enum stuff.

    Non-technical stuff below...

    Pavel Sosin (@PavelSosin) I will never ever claim to be an expert in anything. But I have some real experience with these things from bare metal (various CPUs) to high-level programming and their tools. Or else, I wouldn't be in this thread. I don't understand your characterization about what we are trying to do. I see it as a real-world need that I don't see changing anytime soon. When it does, everyone will adapt. Tools first. I hope you really look into the ecosystem these features serve, user profiles, CPUs/MCUs, IoT -- significant # of developers/products. Sorry, I can't quote numbers but just look around you and think about how those things were developed and debugged.

    If DAP and/or VSCode+extensions have no interest in including this class of users, then we are done. End of conversation. But, I see hope. VSCode is awesome and other tools can also leverage from this work on the DAP.

  22. added a commit that references this issue on May 27, 2019
    bed6768
  23. weinand commented on May 27, 2019

    @weinand
    Contributor

    Andrew Crawley (@andrewcrawley) Gregg Miskelly (@gregg-miskelly) I've created PR #49 for the complete DAP change.

  24. PavelSosin commented on May 30, 2019

    @PavelSosin

    Andre Weinand (@weinand)
    I think that Product Vscode IDE is so popular among developers because it is easily extensible and developers can find many very usable extensions which fulfill their requirements. I'm wondering when we finally agree what we are discussing - design proposal of Vscode extension which can be offered via marketplace channel or backbone protocol which is used by various IDE products and has implementation cost which allows to place debugger implementation at the head of team's backlog. In SAP and RedHat teams involved into IDE development means dozens of employers - POs, UX, UI designers, developers, DevOps, etc. If implementation cost is too high and added value is not so high the feature will never reach GA. I think your proposal is falls into category of extension proposal. It is absolutely valid that extension is designed and developed by single developer and consumed by 5 users over the world from product marketplace. It is absolutely unacceptable when proposal fits to 5 developers need but makes product inconsistent and miss-lead 100 developers. Such proposal is not even considered for implementation. I feel that your proposal can be implemented according existing Vscode extensibility model and without costly for implementation protocol changes. Please, argue what are benefits it gives to other Vscode extensions developers and how its implementation can be consumed by users.

  25. PavelSosin commented on Jun 11, 2019

    @PavelSosin

    The requested feature has been implemented in VisualStudio 2019: VS2019- registers window. Implementation in VSCode will be redundant.

  26. weinand commented on Jun 11, 2019

    @weinand
    Contributor

    So your statement is: every DAP feature that is implemented in more than one client is redundant, right?

  27. locked as resolved and limited conversation to collaborators on Jun 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

feature-requestRequest for new features or functionality

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions