Skip to content

Commit

Permalink
run w/o debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
haneefdm committed Sep 11, 2021
1 parent 2436b4d commit 2c73aa8
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 48 deletions.
30 changes: 21 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,28 @@ New Features
<img src=https://user-images.githubusercontent.com/41269583/132694054-e4a2e085-132c-4bac-9c79-f5fdbdd9b1f8.png width=200 />

* The only place we could put the `Reset` button was at the beginning. We would have rather put it closer to the end but there isn't an API to do that as far as we know. Note that the toolbar appears in docking and floating modes and it is the docking mode where this was not possible. Hopefully, it is not a hinderance.
* Some gdb-servers do not respond appropriately to being reset to be compatible with `gdb`. You will have to find out what set of gdb-server/gdb commands work for you and use appropriate options in the `launch.json`. For instance, just after 'reset halt' some versions of OpenOCD do not provide `gdb` the updated registers (SP, PC, LR, etc.). Some devices may have a more complicated, customized reset mechanism, boot-loaders, etc. To force a synchronization between `OpenOCD` and `gdb`, you can do the following in `launch.json`.
* `svdAddrGapThreshold` `launch.json` option. Normally adjacent register addresses with small gaps are combined to reduce the number of device memory reads. Default is 16 bytes. You can now control the number of bytes the gap can be including zero. Zero means strict reading of bytes but adjacent registers are still combined if there is no gap.

```
"postRestartSessionCommands": [
"monitor gdb_sync",
"stepi" // Because of the command above, this is a no-op. No code is actually executed
]
* `Restart` causes VSCode to clear the `Debug Console` but `Reset` does not do that as VSCode is not involved.
* Some gdb-servers do not respond appropriately to being reset and are not compatible with `gdb` expectations. You will have to find out what set of gdb-server/gdb commands work for you and use appropriate options in the `launch.json`. For instance, just after 'reset halt' some versions of OpenOCD do not provide `gdb` the updated registers (SP, PC, LR, etc.). Some devices may have a more complicated, customized reset mechanism, boot-loaders, etc. To force a synchronization between `OpenOCD` and `gdb`, you can do the following in `launch.json`.
```
* **Auto-continue**: Operations `Launch`, `Reset`, and `Restart` will issue a `continue` to gdb upon sussesful reset-halt. For `Launch` this is not done if `runToEntryPoint` has been enabled. It is also not done if the corresponding action has a post-session-start commands set (i.e., `postStartSessionCommands`, `postRestartSessionCommands`). This does not apply to `Attach` since that always stops on an successful `Attach`. You can disable the auto-continue behavior using `doNotContinueAfterReset`
"postRestartSessionCommands": [ // OpenOCD only
"monitor gdb_sync",
"stepi" // Because of the command above, this is a no-op. No code is actually executed
]
```
* **`Run Without Debugging (^F5)`**: Experimental. This will now work but VSCode does not clearly define what this button should do. In an embedded cases, that is even murkier because without GDB and a gdb-server, there is no way to start the program. Between VSCode and Cortex-Debug, the end result is as follows
* VSCode does not transmit any breakpoints to Cortex-Debug and hence no breakpoints
* VSCode does show a pause button in active mode but pressing on it does nothing because that action is not sent to Cortex-Debug
* `runToEntryPoint` is disregarded and there will not be a stop after a Reset either
* If however your program halts because of an exception or any other reason, it is handled normally and now you will enter the normal debugger
* You can still Restart/Reset and the program restarts and continues to run

* **Auto-continue**: New behavior. Operations `Launch`, `Reset`, and `Restart` will now issue a `continue` to gdb upon sussesful reset-halt. This is not done in the followin cases
* `runToEntryPoint` has been used for a `Launch` session or it is an `Attach` session
* If a post-session-start commands (i.e., `postStartSessionCommands`, `postRestartSessionCommands`) are used; you can insert the `continue` command in there.
* Or you have used the `"breakAfterReset" = true`

* `svdAddrGapThreshold` option in `launch.json` option. Normally adjacent register addresses with small gaps are combined to reduce the number of device memory reads. Default is 16 bytes. You can now control the number of bytes the gap can be including zero. Zero means strict reading of bytes but adjacent registers are still combined if there is no gap.

* JLinkGDBServer will no longer display a graphical progress bar at `Launch`. If you need it, you can use the `-gui` command-line option in `launch.json`'s `serverArgs`

# V0.4.3
Expand Down
2 changes: 1 addition & 1 deletion debug_attributes.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
| Attribute | Applies To | Description |
| --------- | ---------- | ----------- |
| breakAfterReset | Common | Applies to Restart/Reset/Launch, halt debugger after a reset. Ignored for `Launch` if `runToEntryPoint` is used
| cmsisPack | Common | Path to a CMSIS-Pack file. Use to add extra device support.
| cwd | Common | Path of project
| debuggerArgs | Common | Additional arguments to pass to GDB command line
| device | Common | Target Device Identifier
| doNotContinueAfterReset | Common | Do not 'continue' execution after a 'Launch', 'Reset' or 'Restart'. Program will stop at the reset-vector instead
| executable | Common | Path of executable
| gdbPath | Common | This setting can be used to overrride the GDB path user/workspace setting for a particular launch configuration. This should be the full pathname to the executable (or name of the executable if it is in your PATH). Note that other toolchain executables with the configured prefix must still be available.
| graphConfig | Common | (unknown)
Expand Down
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,10 @@
"items": "string",
"description": "Additional GDB Commands to be executed at the end of the re-start sequence, after a debug session has already started."
},
"doNotContinueAfterReset": {
"breakAfterReset": {
"default": false,
"type": "boolean",
"description": "Do not 'continue' execution after a 'Launch', 'Reset' or 'Restart'. Program will stop at the reset-vector instead"
"description": "Applies to Restart/Reset/Launch, halt debugger after a reset."
},
"overrideGDBServerStartedRegex": {
"description": "You can supply a regular expression (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) in the configuration property to override the output from the GDB server that is looked for to determine if the GDB server has started. Under most circumstances this will not be necessary - but could be needed as a result of a change in the output of a GDB server making it incompatible with cortex-debug. This property has no effect for bmp or external GDB server types.",
Expand Down Expand Up @@ -1160,10 +1160,10 @@
"items": "string",
"description": "Additional GDB Commands to be executed at the end of the re-start sequence, after a debug session has already started."
},
"doNotContinueAfterReset": {
"breakAfterReset": {
"default": false,
"type": "boolean",
"description": "Do not 'continue' execution after a 'Launch', 'Reset' or 'Restart'. Program will stop at the reset-vector instead"
"description": "Applies to Restart/Reset/Launch, halt debugger after a reset. Ignored for `Launch` if `runToEntryPoint` is used"
},
"overrideGDBServerStartedRegex": {
"description": "You can supply a regular expression (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) in the configuration property to override the output from the GDB server that is looked for to determine if the GDB server has started. Under most circumstances this will not be necessary - but could be needed as a result of a change in the output of a GDB server making it incompatible with cortex-debug. This property has no effect for bmp or external GDB server types.",
Expand Down Expand Up @@ -2053,6 +2053,10 @@
{
"command": "cortex-debug.setForceDisassembly",
"when": "debugType == cortex-debug"
},
{
"command": "cortex-debug.resetDevice",
"when": "debugType == cortex-debug"
}
],
"debug/toolBar": [
Expand Down
2 changes: 1 addition & 1 deletion src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export interface ConfigurationArguments extends DebugProtocol.LaunchRequestArgum
postStartSessionCommands: string[];
postRestartSessionCommands: string[];
overrideGDBServerStartedRegex: string;
doNotContinueAfterReset: boolean;
breakAfterReset: boolean;
svdFile: string;
svdAddrGapThreshold: number;
rttConfig: RTTConfiguration;
Expand Down
29 changes: 22 additions & 7 deletions src/frontend/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class CortexDebugExtension {
private SVDDirectory: SVDInfo[] = [];
private functionSymbols: SymbolInformation[] = null;
private debuggerStatus: 'started' | 'stopped' | 'running' | 'none';
private currentArgs: any = null;

constructor(private context: vscode.ExtensionContext) {
this.startServerConsole(context); // Make this the first thing we do so it is ready for the session
Expand Down Expand Up @@ -162,7 +163,9 @@ export class CortexDebugExtension {
if (this.debuggerStatus === 'running') {
vscode.window.showInformationMessage(msg);
} else {
this.registerProvider.refresh();
if (this.currentArgs && !this.currentArgs.noDebug) {
this.registerProvider.refresh();
}
}
}
}
Expand Down Expand Up @@ -437,7 +440,9 @@ export class CortexDebugExtension {
}

private registersRefresh(): void {
this.registerProvider.refresh();
if (this.currentArgs && !this.currentArgs.noDebug) {
this.registerProvider.refresh();
}
}

// Settings changes
Expand Down Expand Up @@ -485,6 +490,7 @@ export class CortexDebugExtension {
this.debuggerStatus = 'started';

session.customRequest('get-arguments').then((args) => {
this.currentArgs = args;
let svdfile = args.svdFile;
if (!svdfile) {
svdfile = this.getSVDFile(args.device);
Expand All @@ -495,8 +501,10 @@ export class CortexDebugExtension {
if (this.swoSource) { this.initializeSWO(args); }
if (Object.keys(this.rttPortMap).length > 0) { this.initializeRTT(args); }

this.registerProvider.debugSessionStarted();
this.peripheralProvider.debugSessionStarted(svdfile ? svdfile : null, args.svdAddrGapThreshold);
if (!this.currentArgs.noDebug) {
this.registerProvider.debugSessionStarted();
}
this.peripheralProvider.debugSessionStarted((svdfile && !args.noDebug) ? svdfile : null, args.svdAddrGapThreshold);
this.cleanupRTTTerminals();
}, (error) => {
// TODO: Error handling for unable to get arguments
Expand All @@ -510,7 +518,9 @@ export class CortexDebugExtension {
Reporting.endSession();

this.debuggerStatus = 'none';
this.registerProvider.debugSessionTerminated();
if (!this.currentArgs.noDebug) {
this.registerProvider.debugSessionTerminated();
}
this.peripheralProvider.debugSessionTerminated();
if (this.swo) {
this.swo.debugSessionTerminated();
Expand All @@ -534,6 +544,7 @@ export class CortexDebugExtension {
this.rttPortMap = {};

this.clearAdapterOutputChannel = true;
this.currentArgs = null;
}
catch (e) {
vscode.window.showInformationMessage(`Debug session did not terminate cleanly ${e}\n${e ? e.stackstrace : ''}. Please report this problem`);
Expand Down Expand Up @@ -570,7 +581,9 @@ export class CortexDebugExtension {
private receivedStopEvent(e) {
this.debuggerStatus = 'stopped';
this.peripheralProvider.debugStopped();
this.registerProvider.debugStopped();
if (this.currentArgs && !this.currentArgs.noDebug) {
this.registerProvider.debugStopped();
}
vscode.workspace.textDocuments.filter((td) => td.fileName.endsWith('.cdmem'))
.forEach((doc) => { this.memoryProvider.update(doc); });
if (this.swo) { this.swo.debugStopped(); }
Expand All @@ -580,7 +593,9 @@ export class CortexDebugExtension {
private receivedContinuedEvent(e) {
this.debuggerStatus = 'running';
this.peripheralProvider.debugContinued();
this.registerProvider.debugContinued();
if (this.currentArgs && !this.currentArgs.noDebug) {
this.registerProvider.debugContinued();
}
if (this.swo) { this.swo.debugContinued(); }
if (this.rtt) { this.rtt.debugContinued(); }
}
Expand Down
58 changes: 32 additions & 26 deletions src/gdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export class GDBDebugSession extends DebugSession {
protected trimCWD: string;
protected switchCWD: string;
protected started: boolean;
protected crashed: boolean;
protected debugReady: boolean;
protected miDebugger: MI2;
protected commandServer: net.Server;
Expand Down Expand Up @@ -293,7 +292,6 @@ export class GDBDebugSession extends DebugSession {
this.quit = false;
this.attached = false;
this.started = false;
this.crashed = false;
this.debugReady = false;
this.stopped = false;
this.activeThreadIds.clear();
Expand Down Expand Up @@ -458,7 +456,7 @@ export class GDBDebugSession extends DebugSession {
this.handleMsg('log', dbgMsg);
}

this.disableSendStoppedEvents = (!attach && this.args.runToEntryPoint) ? true : false;
this.disableSendStoppedEvents = (!attach && (this.args.runToEntryPoint || this.args.noDebug)) ? true : false;
this.miDebugger.connect(this.args.cwd, this.args.executable, commands).then(() => {
this.started = true;
this.serverController.debuggerLaunchCompleted();
Expand All @@ -467,13 +465,15 @@ export class GDBDebugSession extends DebugSession {

const launchComplete = () => {
this.disableSendStoppedEvents = false;
setTimeout(() => {
this.stopped = true;
this.stoppedReason = 'start';
this.stoppedThreadId = this.currentThreadId;
this.sendEvent(new StoppedEvent('start', this.currentThreadId, true));
this.sendEvent(new CustomStoppedEvent('start', this.currentThreadId));
}, 50);
if (!this.args.noDebug) {
setTimeout(() => {
this.stopped = true;
this.stoppedReason = 'start';
this.stoppedThreadId = this.currentThreadId;
this.sendEvent(new StoppedEvent('start', this.currentThreadId, true));
this.sendEvent(new CustomStoppedEvent('start', this.currentThreadId));
}, 50);
}
};

const runPostStartSession = () => {
Expand All @@ -486,7 +486,7 @@ export class GDBDebugSession extends DebugSession {
}
};

if (this.args.runToEntryPoint) {
if (!this.args.noDebug && this.args.runToEntryPoint) {
this.miDebugger.sendCommand(`break-insert -t --function ${this.args.runToEntryPoint}`).then(() => {
this.miDebugger.once('generic-stopped', launchComplete);
// To avoid race conditions between finishing configuration, we should stay
Expand Down Expand Up @@ -585,11 +585,12 @@ export class GDBDebugSession extends DebugSession {
break;
}

// Note that for commands, an empty array is totall valid. Meaning don't do anything. Not even a 'continue'
if (!this.args.doNotContinueAfterReset) {
if ((commands == null) && (mode !== SessionMode.ATTACH) && !((mode === SessionMode.LAUNCH) && this.args.runToEntryPoint)) {
commands = ['-exec-continue'];
}
if ((mode !== SessionMode.ATTACH) && this.args.noDebug) {
if (!commands) { commands = []; }
commands.push('-exec-continue');
} else if (!this.args.breakAfterReset && (mode !== SessionMode.ATTACH) && (!commands || (commands.length === 0))) {
// This function is not called if 'runToEntryPoint' was used
commands = ['-exec-continue'];
}

if (commands && (commands.length > 0)) {
Expand Down Expand Up @@ -989,13 +990,15 @@ export class GDBDebugSession extends DebugSession {
this.sendResponse(response);
setTimeout(() => {
const isReset = (args as any).isReset;
this.stopped = true; // This should aleady be true??
this.stoppedReason = isReset ? 'reset' : 'restart';
this.sendEvent(new ContinuedEvent(this.currentThreadId, true));
this.sendEvent(new StoppedEvent(this.stoppedReason, this.currentThreadId, true));
this.sendEvent(new CustomStoppedEvent(this.stoppedReason, this.currentThreadId));
this.runPostStartSessionCommands(isReset ? SessionMode.RESET : SessionMode.RESTART, 50);
}, 50);
if (!this.args.noDebug) {
this.stopped = true; // This should aleady be true??
this.stoppedReason = isReset ? 'reset' : 'restart';
this.sendEvent(new ContinuedEvent(this.currentThreadId, true));
this.sendEvent(new StoppedEvent(this.stoppedReason, this.currentThreadId, true));
this.sendEvent(new CustomStoppedEvent(this.stoppedReason, this.currentThreadId));
}
this.runPostStartSessionCommands(isReset ? SessionMode.RESET : SessionMode.RESTART);
}, 5);
}, (msg) => {
this.sendErrorResponse(response, 6, `Could not restart: ${msg}`);
});
Expand Down Expand Up @@ -1176,13 +1179,16 @@ export class GDBDebugSession extends DebugSession {
}

protected stopEvent(info: MINode, reason: string = 'exception') {
if (!this.started) { this.crashed = true; }
if (!this.quit) {
this.stopped = true;
this.stoppedReason = reason;
this.findPausedThread(info);
this.sendEvent(new StoppedEvent(reason, this.currentThreadId, true));
this.sendEvent(new CustomStoppedEvent(reason, this.currentThreadId));
if ((reason === 'entry') && this.args.noDebug) {
// Do not notify the front-end if no-debug is active and it is the entry point. Or else, pass it on
} else {
this.sendEvent(new StoppedEvent(reason, this.currentThreadId, true));
this.sendEvent(new CustomStoppedEvent(reason, this.currentThreadId));
}
}
}

Expand Down

0 comments on commit 2c73aa8

Please sign in to comment.