Marus / cortex-debug

Visual Studio Code extension for enhancing debug capabilities for Cortex-M Microcontrollers
MIT License
1.02k stars 240 forks source link

OpenOCD stdout not showing up in the DEBUG CONSOLE #1030

Closed RolfNoot closed 4 months ago

RolfNoot commented 4 months ago

OpenOCD stdout / programming information is not showing up in / forwarded to the DEBUG CONSOLE when using internal launchcommands.

Steps to reproduce the behavior:

  1. Start a debug session (named "Debug") with the provided 'launch.json'
  2. Click on the DEBUG CONSOLE tab
  3. Check the information provided to the DEBUG CONSOLE

Expected behavior

Information from OpenOCD after an established GDB connection should be visible in the DEBUG CONSOLE

Screenshots Scherm­afbeelding 2024-07-04 om 12 41 56

Environment:

Cortex - Debug: v1.12.1 VS Code: 1.90.2 (Universal) Electron: 29.4.0 ElectronBuildId: 9728852 Chromium: 122.0.6261.156 Node.js: 20.9.0 V8: 12.2.281.27-electron.0 OS: Darwin x64 23.5.0

Please include launch.json

launch.json OpenOCD config files.zip

Attach text from Debug Console

SWD DPIDR 0x6ba02477
psoc6.cm4: Ran after reset and before halt...
psoc6.cm4 halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x100065c6 msp: 0x0803efa0
Note: automatically using hardware breakpoints for read-only addresses.

Temporary breakpoint 1, main () at ../source/main.c:248
248     __enable_irq();

Please enable debug output in your launch.json ("showDevDebugOutput": "raw"). It this is too large, please attach it as a file Cortex-Debug: VSCode debugger extension.txt

Additional context After overriding the internal launch commands, the programming info is visible. Scherm­afbeelding 2024-07-04 om 12 59 01

Not 100% sure about the expected behaviour but to me it seems the programming info is communicated over TCP but suppressed from being visible when using the internal launch commands. It would be nice / consistent with other debuggers when the full stdout of the debugging server would show up in the DEBUG CONSOLE. This would also solve the need to switch to the TERMINAL tab when the gdb-server fails (and the need for the message OpenOCD: GDB Server Quit Unexpectedly. See gdb-server output in TERMINAL tab for more details.).

haneefdm commented 4 months ago

Now, we are getting somewhere. You are using the monitor command to directly talk to the gdb-server. We use gdb for the same and we don't care how/what they communicate. You can see the difference between the default launch commands vs yours if you had enabled cortex-debug debug output like we recommend.

We always output what is on gdb-server stdout to the Debug Console. We don't filter or make stuff up. So, when gdb asks the gdb-server to program/erase something ... and your gdb-server is not putting anything to stdout (maybe it is using stderr), then we can't help it. The gdb-server and its config files belong to you. Maybe you create a wrapper script/program to merge stdout/stderr -- trivial to do on Mac/Linux. Maybe you can add event handlers to output additional messages. Like for gdb-flash-write-end. See all events. Please understand the underlying tools

OpenOCD: GDB Server Quit Unexpectedly. See gdb-server output in TERMINAL tab for more details.

This message is from us. When something unexpected happens (gdb or the server can crash, abort, have other issues), we report the first one that bails. We have no idea why. Again, we are mixing issues and assuming solutions may do not apply.

And, no we are NOT going to output the entire server output to the Debug Console. We designed it this way for multiple reasons and I already explained in #1012. I don't want duplication of information, allow bidirectional communication, do proper terminal like processing for carriage returns, ANSI codes, etc. None of that is possible if we move everything to the Debug Console. You can see that already... the programming messages in Debug Console are coming as several lines. But not in TERMINAL. There is a reason for that!!!

It would be nice / consistent with other debuggers when the full stdout of the debugging server would show up in the DEBUG CONSOLE

When in Rome... comes to mind. Like what though? VSCode has a particular usage pattern in mind hwen they designed the Debug Console. In fact, I like it. If you like some other debugger, then you know my answer. The gdb-server output (especially stderr) is rarely interesting to many. Some servers are especially chatty (JLink is medium chatty and even that is too much).

Please think through your suggestions for improvements and more globally.

RolfNoot commented 4 months ago

I understand the way gdb communicates with the gdb-server and it's underlying monitor commands to talk directly to the gdb-server. I know the internal launch commands differ from the ones I provide, and the monitor commands may provide different information than the gdb commands (eg. monitor program vs -target-download).

I was assuming the stdout wasn't routed to DEBUG CONSOLE as I don't see the gdb-server's output there. I was also assuming that the programming messages are going to OpenOCD's stdout (and not to stderr, which would be weird to me). And my assumptions seem to be correct (see my findings below).

However, I am still puzzled about the behaviour of the extension:

We always output what is on gdb-server stdout to the Debug Console.

and

no we are NOT going to output the entire server output to the Debug Console.

While my question is:

It would be nice ... when the full stdout of the debugging server would show up in the DEBUG CONSOLE.

Can you please clarify what you meant with We always output what is on gdb-server stdout to the Debug Console. and the expected behavior of the extension is? Is it always routing stdout to the DEBUG CONSOLE or not?

I did some tests and simply put: stdout nor stderr are being routed to the DEBUG CONSOLE: Scherm­afbeelding 2024-07-04 om 17 50 55

I've made stderr to output in red and as the screenshot shows, NONE of the gdb-server output is being shown.

That said, I did monitor the loopback traffic and noticed the TCP messages are being shown on the Debug Console and it's true that 'monitor program' would provide more information than '-target-download'.

Either way, it's or an issue (when the expected behaviour is routing stdout to the DEBUG CONSOLE), or a feature request (to have stdout routed to the DEBUG CONSOLE). And again, I am not saying that it ALWAYS should route stdout, but an OPTION would be nice (eg. 'off', 'stdout', 'stderr', 'both'). That way the user can decide.

Like what though?

.NET MAUI for VS Code for example. It starts forwarding stdout and stderr as soon as the debugger starts: afbeelding

RolfNoot commented 4 months ago

And adding to that: I am not looking for a complete update of the extension, especially when there's not much interest or time for it. Any pointers or suggestions which brings me closer to a solution or maybe even contributing to this nice extension would be great!

haneefdm commented 4 months ago

We always output what is on gdb-server stdout to the Debug Console

output means stderr and stdout. You should be seeing all of stdout in Debug Console. If that is routed via gdb or by us, I don't remember. I don't have a board to test it. And, we don't want to see duplicates either. Since you are seeing some but not all is a bit confusing and we should focus on that. What I see below are messages from the server. Whatever is happening now, was designed like this well before (2019) I inherited this extension. Unless we can establish a defect, the design is not going to change, especially because I agree with it. See below

image

Btw, you keep mentioning TCP. There is no TCP that we use. It is all stdio to both gdb and the server. TCP (or serial port) is used by gdb to talk to the server and we use TCP for things like SWO, RTT. Both gdb and us cannot use TCP for basic debug as that will confuse the hell out of all parties.

I usually debug stuff like this on the command line where I can split the streams

.NET MAUI for VS Code for example. It starts forwarding stdout and stderr as soon as the debugger starts:

I don't know what that debugger is and if it uses a server. Remember the distinction between debugger output from server output. Should never confuse the two.

Also, when you use multi-core/multi-board debug this can blow out of proportion. There are cases where you have multiple Debug Consoles and one or more gdb-servers. We got TONS of users in this situation. There are cases where even with a single core you can have multiple elf files. Boot, secure, non-secure, etc. We support all of that and I have to consider those use cases.

And again, I am not saying that it ALWAYS should route stdout, but an OPTION would be nice (eg. 'off', 'stdout', 'stderr', 'both'). That way the user can decide.

For all of the reasons mentioned above, I have to decline.

RolfNoot commented 4 months ago

Sorry, excuse me for my previous reply, i was agitated because of the misunderstanding. I will revise my reply. I realize you don't interact with the tcp messages itself but use gdb stdio which in turn use tcp to communicate with the server. I will follow up later.

RolfNoot commented 4 months ago

I was able to forward stdout and stderr to the debug console, providing what I essentially needed: Scherm­afbeelding 2024-07-06 om 23 01 36

I am not an expert on js/ts so it may not be the best code, however for me it works.

  1. Adding EventEmitter to server.ts export const serverEmitter = new EventEmitter(); and implementing it into sendToConsole:
    private sendToConsole(data: string|Buffer, source: string) {
        if (this.consoleSocket) {
            this.consoleSocket.write(data);
            serverEmitter.emit('consoleData', { source, data: data.toString() });
        } else {
    .... 
  2. Importing the EventEmitter into gdb.ts import { serverEmitter } from './backend/server';
  3. And finally adding the event listener to the constructor:
    public constructor(debuggerLinesStartAt1: boolean, public readonly isServer: boolean = false, threadID: number = 1) {
        super(undefined, debuggerLinesStartAt1, isServer);     // Use if deriving from LogDebugSession
        // Listen for events from the server
        serverEmitter.on('consoleData', ({ type, data }: { type: string, data: string }) => {
            this.handleMsg(type, data); 
        });
    ...

I guess there will be remarks from the experts, I am open for suggestions!

haneefdm commented 4 months ago

Like I said, I will not accept this change. Not even as an option. I know how to forward from the server stdio to anywhere I want to and I am already doing that. See the following lines. I added and removed support for them for a reason. Forgot to removed those lines.

https://github.com/Marus/cortex-debug/blob/17ad3b4914ef2650c30c09716219126ffe696ac0/src/backend/server.ts#L160

https://github.com/Marus/cortex-debug/blob/17ad3b4914ef2650c30c09716219126ffe696ac0/src/backend/server.ts#L181

I am exhausted trying to explain.

RolfNoot commented 4 months ago

My only intention was/is to make the extension a little better, or at least share possible improvements the way I (and our users) look at it. There may be plenty of reasons why it's (technically) not a good idea, like duplicates (some messages from the server and GDB are identical), different servers, different formats, inconsistencies and probably more.

At least for me and our customers, it's good to have the server stdout and stderr visible in the debug console and I will change and fork the extension. I might as well decide to add an option to include only the messages up and until debugging starts.

I am sure your reasons are solid and I don't want to bother. I am just sharing the information as it may be valuable for others.

Thanks for showing me the original code though.

Best, Rolf

RolfNoot commented 4 months ago

As my suggestion is not accepted, I've 'forked' this extension to https://github.com/onethinx/cortex-gdb. Added the stdout and stderr to the Debug Console. Super convenient, all programming / debugging info in one place, no more switching between TERMINAL and DEBUG CONSOLE 🥇

One comment about the current extension regarding this matter. Stdout and stderr are not properly buffered which can cause entangling of server's stderr and stdout. See: Scherm­afbeelding 2024-07-09 om 14 15 33

As both outputs are async, a buffer might be needed...

const lines = (this.stdOutBuffer + msg).split(/\r?\n|\r/);
this.stdOutBuffer = lines.pop();
lines.forEach((line) => {
    this.sendEvent(.... line + '/n');
});