Skip to content

Commit

Permalink
Add support for selecting a core to debug in PyOCD
Browse files Browse the repository at this point in the history
  • Loading branch information
thegecko committed Feb 12, 2020
1 parent 1241bca commit aea6e06
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 21 deletions.
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
"type": "array",
"default": []
},
"gdbCore": {
"description": "Core number gdb will connect to",
"type": "number",
"default": 0
},
"gdbServer": {
"type": "string",
"description": "Path to gdb server",
Expand Down Expand Up @@ -138,6 +143,11 @@
"type": "array",
"default": []
},
"gdbCore": {
"description": "Core number gdb will connect to",
"type": "number",
"default": 0
},
"gdbServer": {
"type": "string",
"description": "Path to gdb server",
Expand Down
14 changes: 11 additions & 3 deletions src/abstract-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,20 @@ export abstract class AbstractServer extends EventEmitter {
protected launchReject?: (error: any) => void;
protected timer?: NodeJS.Timer;

public spawn(args: CmsisRequestArguments): Promise<void> {
constructor(protected args: CmsisRequestArguments) {
super();
}

public spawn(): Promise<void> {
return new Promise(async (resolve, reject) => {
this.launchResolve = resolve;
this.launchReject = reject;

try {
this.timer = setTimeout(() => this.onSpawnError(new Error('Timeout waiting for gdb server to start')), TIMEOUT);

const command = args.gdbServer || 'gdb-server';
const serverArguments = await this.resolveServerArguments(args.gdbServerArguments);
const command = this.args.gdbServer || 'gdb-server';
const serverArguments = await this.resolveServerArguments(this.args.gdbServerArguments);
this.process = spawn(command, serverArguments, {
cwd: dirname(command),
});
Expand Down Expand Up @@ -80,6 +84,10 @@ export abstract class AbstractServer extends EventEmitter {
}
}

public resolveGdbPort(port: number): number {
return port;
}

protected async resolveServerArguments(serverArguments?: string[]): Promise<string[]> {
return serverArguments || [];
}
Expand Down
45 changes: 27 additions & 18 deletions src/cmsis-debug-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import * as mi from './mi';

export interface CmsisRequestArguments extends RequestArguments {
runToMain?: boolean;
gdbCore?: number;
gdbServer?: string;
gdbServerArguments?: string[];
objdump?: string;
Expand All @@ -47,7 +48,7 @@ const STATIC_HANDLES_FINISH = 0x01FFFF;

export class CmsisDebugSession extends GDBDebugSession {

protected gdbServer = new PyocdServer();
protected gdbServer: PyocdServer | undefined;
protected portScanner = new PortScanner();
protected symbolTable!: SymbolTable;
protected globalHandle!: number;
Expand Down Expand Up @@ -200,27 +201,20 @@ export class CmsisDebugSession extends GDBDebugSession {
this.gdb.on('execAsync', (resultClass, resultData) => this.handleGDBAsync(resultClass, resultData));
this.gdb.on('notifyAsync', (resultClass, resultData) => this.handleGDBNotify(resultClass, resultData));

// gdb server has main info channel on stderr
this.gdbServer.on('stderr', data => this.sendEvent(new OutputEvent(data, 'stdout')));
this.gdbServer.on('error', message => {
this.sendEvent(new TerminatedEvent());
throw message;
});

// Load debug symbols
try {
this.symbolTable = new SymbolTable(args.program, args.objdump);
await this.symbolTable.loadSymbols();
} catch (error) {
this.sendEvent(new OutputEvent(`Unable to load debug symbols: ${error.message}`));
}

const port = await this.portScanner.findFreePort();
if (!port) {
// Determine free port for gdb server
const serverPort = await this.portScanner.findFreePort();
if (!serverPort) {
throw new Error('Unable to find a free port to use for debugging');
}
this.sendEvent(new OutputEvent(`Selected port ${port} for debugging`));

const remote = `localhost:${port}`;
this.sendEvent(new OutputEvent(`Selected port ${serverPort} for debugging`));

// Set gdb arguments
if (!args.gdbArguments) {
Expand All @@ -232,18 +226,30 @@ export class CmsisDebugSession extends GDBDebugSession {
if (!args.gdbServerArguments) {
args.gdbServerArguments = [];
}
args.gdbServerArguments.push('--port', port.toString());
args.gdbServerArguments.push('--port', serverPort.toString());

// gdb server has main info channel on stderr
this.gdbServer = new PyocdServer(args);
this.gdbServer.on('stderr', data => this.sendEvent(new OutputEvent(data, 'stdout')));
this.gdbServer.on('error', message => {
this.sendEvent(new TerminatedEvent());
throw message;
});

// Start gdb client and server
// Start gdb server and client
this.progressEvent(0, 'Starting Debugger');
await this.gdbServer.spawn(args);
await this.gdbServer.spawn();
await this.spawn(args);

// Find correct debug client port
const clientPort = this.gdbServer.resolveGdbPort(serverPort);
const remote = `localhost:${clientPort}`;

// Send commands
await mi.sendTargetAsyncOn(this.gdb);
await mi.sendTargetSelectRemote(this.gdb, remote);
await mi.sendMonitorResetHalt(this.gdb);
this.sendEvent(new OutputEvent(`Attached to debugger on port ${port}`));
this.sendEvent(new OutputEvent(`Attached to debugger on port ${clientPort}`));

// Download image
const progressListener = (percent: number) => this.progressEvent(percent, 'Loading Image');
Expand Down Expand Up @@ -365,7 +371,10 @@ export class CmsisDebugSession extends GDBDebugSession {
} catch (e) {
// Need to catch here in case the connection has already been closed
}
this.gdbServer.kill();

if (this.gdbServer) {
this.gdbServer.kill();
}
}

public async shutdown() {
Expand Down
10 changes: 10 additions & 0 deletions src/pyocd-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ export class PyocdServer extends AbstractServer {
protected portScanner = new PortScanner();
protected progress = 0;

public resolveGdbPort(port: number): number {
if (this.args.gdbCore) {
// PyOCD starts each core on a subsequent port
// (e.g. core 0 on starting port, core 1 on starting port +1, etc.)
port += this.args.gdbCore;
}

return port;
}

protected async resolveServerArguments(serverArguments?: string[]): Promise<string[]> {
if (!serverArguments) {
serverArguments = [];
Expand Down

0 comments on commit aea6e06

Please sign in to comment.