Skip to content

Commit

Permalink
Issue #539, some perf gains with gdb-mi, always demangle
Browse files Browse the repository at this point in the history
  • Loading branch information
haneefdm committed Dec 7, 2021
1 parent 5fd7e05 commit 8bb6321
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 162 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ChangeLog
#V0.4.11
* Issue #538: Fixed bug SVD internal debug verification. Not supposed to be for production but got released and caused false errors. This in turn resulted in SVD load failure.
* `launch.json` option `demangle` is removed. We always demangle. Its default value was true for quite some time. There is quite a bit of C++ now coming in and Rust as well. I appears there is no harm in always enabling it.

#V0.4.9
* Issue #536. Typo in code for os-specific paths
Expand Down
1 change: 0 additions & 1 deletion debug_attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
| toolchainPrefix | Common | This setting can be used to override the toolchainPrefix user setting for a particular launch configuration.
| BMPGDBSerialPort | BMP Specific | The serial port for the Black Magic Probe GDB Server. On Windows this will be "COM<num>", on Linux this will be something similar to /dev/ttyACM0, on OS X something like /dev/cu.usbmodemE2C0C4C6 (do not use tty versions on OS X)
| powerOverBMP | BMP Specific | Power up the board over Black Magic Probe. "powerOverBMP" : "enable" or "powerOverBMP" : "disable". If not set it will use the last power state.
| demangle | C++ specific | Experimental: If enabled the debugger will demangle C++ names.
| gdbTarget | External | For externally controlled GDB Servers you must specify the GDB target to connect to. This can either be a "hostname:port" combination or path to a serial port
| ipAddress | J-Link Specific | IP Address for networked J-Link Adapter
| jlinkscript | J-Link Specific | J-Link script file - optional input file for customizing J-Link actions.
Expand Down
10 changes: 0 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,6 @@
"description": "For externally controlled GDB Servers you must specify the GDB target to connect to. This can either be a \"hostname:port\" combination or path to a serial port",
"type": "string"
},
"demangle": {
"description": "Experimental: If enabled the debugger will demangle C++ names.",
"type": "boolean",
"default": true
},
"numberOfProcessors": {
"description": "Number of processors/cores in the target device.",
"type": "number",
Expand Down Expand Up @@ -1493,11 +1488,6 @@
"type": "string",
"default": "main"
},
"demangle": {
"description": "Experimental: If enabled the debugger will demangle C++ names.",
"type": "boolean",
"default": true
},
"numberOfProcessors": {
"description": "Number of processors/cores in the target device.",
"type": "number",
Expand Down
3 changes: 2 additions & 1 deletion src/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export interface Variable {
}

export interface IBackend {
connect(cwd: string, executable: string, target: string[]): Thenable<any>;
start(cwd: string, executable: string, init: string[]): Thenable<any>;
connect(target: string[]): Thenable<any>;
stop();
detach();
interrupt(arg: string): Thenable<boolean>;
Expand Down
70 changes: 61 additions & 9 deletions src/backend/mi2/mi2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { Breakpoint, DataBreakpoint, IBackend, Stack, Variable, VariableObject,
import * as ChildProcess from 'child_process';
import { EventEmitter } from 'events';
import { parseMI, MINode } from '../mi_parse';
import * as linuxTerm from '../linux/console';
import * as net from 'net';
import * as fs from 'fs';
import { posix } from 'path';
import * as nativePath from 'path';
import { ServerConsoleLog } from '../server';
Expand Down Expand Up @@ -38,12 +35,16 @@ export class MI2 extends EventEmitter implements IBackend {
protected stream;
protected firstStop: boolean = true;
protected exited: boolean = false;
protected captureConsole: boolean = false;
protected capturedConsole: string = '';
public gdbMajorVersion: number | undefined;
public gdbMinorVersion: number | undefined;

constructor(public application: string, public args: string[]) {
super();
}

public connect(cwd: string, executable: string, commands: string[]): Thenable<any> {
public start(cwd: string, executable: string, init: string[]): Thenable<any> {
if (!nativePath.isAbsolute(executable)) {
executable = nativePath.join(cwd, executable);
}
Expand All @@ -56,17 +57,64 @@ export class MI2 extends EventEmitter implements IBackend {
this.process.on('exit', this.onExit.bind(this));
this.process.on('error', ((err) => { this.emit('launcherror', err); }).bind(this));

const asyncPromise = this.sendCommand('gdb-set target-async on', true);
this.sendCommand('gdb-set target-async on', true).then(() => {
this.startCaptureConsole();
this.sendCommand('gdb-version').then((v: MINode) => {
const str = this.endCaptureConsole();
this.parseVersionInfo(str);
// const asyncPromise = this.sendCommand('gdb-set target-async on', true);
const promises = init.map((c) => this.sendCommand(c));
Promise.all(promises).then(() => {
this.emit('debug-ready');
resolve();
}, reject);
}, () => {
reject();
});
}, () => {
reject();
});
});
}

private startCaptureConsole(): void {
this.captureConsole = true;
this.capturedConsole = '';
}

private endCaptureConsole(): string {
const ret = this.capturedConsole;
this.captureConsole = false;
this.capturedConsole = '';
return ret;
}

private parseVersionInfo(str: string) {
const regex = RegExp(/^GNU gdb\s\(.*\)\s?(\d+)\.(\d+)\.[^\r\n]*/gm);
const match = regex.exec(str);
if (match !== null) {
str = str.substr(0, match.index);
this.gdbMajorVersion = parseInt(match[1]);
this.gdbMinorVersion = parseInt(match[2]);
if (this.gdbMajorVersion < 9) {
this.log('stderr', 'WARNING: Cortex-Debug will deprecate use of GDB version 8. Please upgrade to version 9+\n');
}
}
if (str) {
this.log('console', str);
}
}

public connect(commands: string[]): Thenable<any> {
return new Promise<void>((resolve, reject) => {
const promises = commands.map((c) => this.sendCommand(c));
promises.push(asyncPromise);

Promise.all(promises).then(() => {
this.emit('debug-ready');
resolve();
}, reject);
});
}

private onExit() {
console.log('GDB: exited');
this.exited = true;
Expand Down Expand Up @@ -162,7 +210,11 @@ export class MI2 extends EventEmitter implements IBackend {
if (parsed.outOfBandRecord) {
parsed.outOfBandRecord.forEach((record) => {
if (record.isStream) {
this.log(record.type, record.content);
if (this.captureConsole && (record.type === 'console')) {
this.capturedConsole += record.content;
} else {
this.log(record.type, record.content);
}
}
else {
if (record.type === 'exec') {
Expand Down
84 changes: 34 additions & 50 deletions src/backend/mi_parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ export interface MIInfo {
}

const octalMatch = /^[0-7]{3}/;
const escapeMap = {
'\\': '\\',
'"': '"',
'\'': '\'',
'n': '\n',
'r': '\r',
't': '\t',
'b': '\b',
'f': '\f',
'v': '\v',
'0': '\0'
};

function parseString(str: string): string {
const ret = Buffer.alloc(str.length * 4);
let bufIndex = 0;
Expand All @@ -13,61 +26,32 @@ function parseString(str: string): string {
throw new Error('Not a valid string');
}
str = str.slice(1, -1);
let escaped = false;
for (let i = 0; i < str.length; i++) {
if (escaped) {
let m;
if (str[i] === '\\') {
bufIndex += ret.write('\\', bufIndex);
}
else if (str[i] === '"') {
bufIndex += ret.write('"', bufIndex);
}
else if (str[i] === '\'') {
bufIndex += ret.write('\'', bufIndex);
}
else if (str[i] === 'n') {
bufIndex += ret.write('\n', bufIndex);
}
else if (str[i] === 'r') {
bufIndex += ret.write('\r', bufIndex);
}
else if (str[i] === 't') {
bufIndex += ret.write('\t', bufIndex);
}
else if (str[i] === 'b') {
bufIndex += ret.write('\b', bufIndex);
}
else if (str[i] === 'f') {
bufIndex += ret.write('\f', bufIndex);
}
else if (str[i] === 'v') {
bufIndex += ret.write('\v', bufIndex);
}
else if (str[i] === '0') {
bufIndex += ret.write('\0', bufIndex);
}
else if (m = octalMatch.exec(str.substr(i))) {
ret.writeUInt8(parseInt(m[0], 8), bufIndex++);
i += 2;
if (str[i] === '\\') {
if (++i >= str.length) {
throw new Error('Not a valid escape sequence');
}
else {
bufIndex += ret.write(str[i], bufIndex);
}
escaped = false;
} else {
if (str[i] === '\\') {
escaped = true;
}
else if (str[i] === '"') {
throw new Error('Not a valid string');
}
else {
bufIndex += ret.write(str[i], bufIndex);
const sub = escapeMap[str[i]];
if (sub) {
bufIndex += ret.write(sub, bufIndex);
} else {
const m = octalMatch.exec(str.substr(i));
if (m) {
ret.writeUInt8(parseInt(m[0], 8), bufIndex++);
i += 2;
}
else {
bufIndex += ret.write(str[i], bufIndex);
}
}
} else if (str[i] === '"') {
throw new Error('Not a valid string');
}
else {
bufIndex += ret.write(str[i], bufIndex);
}
}
return ret.slice(0, bufIndex).toString('utf8');
return ret.toString('utf8', 0, bufIndex);
}

export class MINode implements MIInfo {
Expand Down
Loading

0 comments on commit 8bb6321

Please sign in to comment.