Skip to content

Commit

Permalink
Add multi-process support
Browse files Browse the repository at this point in the history
  • Loading branch information
LeszekSwirski committed Jul 20, 2020
1 parent f292348 commit 00aafd4
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 19 deletions.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@
"description": "Prints all GDB calls to the console",
"default": false
},
"multiProcess": {
"type": "boolean",
"description": "Allow multiple process debugging",
"default": false
},
"showDevDebugOutput": {
"type": "boolean",
"description": "Prints all GDB responses to the console",
Expand Down
2 changes: 1 addition & 1 deletion src/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export interface IBackend {
start(): Thenable<boolean>;
stop();
detach();
interrupt(): Thenable<boolean>;
interrupt(all: boolean): Thenable<boolean>;
continue(): Thenable<boolean>;
next(): Thenable<boolean>;
step(): Thenable<boolean>;
Expand Down
26 changes: 20 additions & 6 deletions src/backend/mi2/mi2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,18 @@ export class MI2 extends EventEmitter implements IBackend {
cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
if (this.prettyPrint)
cmds.push(this.sendCommand("enable-pretty-printing"));
if (this.multiProcess) {
cmds.push(
this.sendCommand("gdb-set follow-fork-mode parent"),
this.sendCommand("gdb-set detach-on-fork off"),
this.sendCommand("gdb-set non-stop on"),
this.sendCommand("gdb-set schedule-multiple on"),

this.sendCommand("interpreter-exec console \"handle SIGSYS nostop noprint\"")
);
}
for (let cmd of this.extraCommands) {
cmds.push(this.sendCommand(cmd));
}

return cmds;
}
Expand Down Expand Up @@ -357,7 +366,7 @@ export class MI2 extends EventEmitter implements IBackend {
else if (reason == "exited-normally")
this.emit("exited-normally", parsed);
else if (reason == "exited") { // exit with error code != 0
this.log("stderr", "Program exited with code " + parsed.record("exit-code"));
this.log("stderr", "Inferior exited with code " + parsed.record("exit-code"));
this.emit("exited-normally", parsed);
} else {
this.log("console", "Not implemented stop reason (assuming exception): " + reason);
Expand All @@ -370,6 +379,10 @@ export class MI2 extends EventEmitter implements IBackend {
this.emit("thread-created", parsed);
} else if (record.asyncClass == "thread-exited") {
this.emit("thread-exited", parsed);
} else if (record.asyncClass == "thread-group-started") {
this.emit("thread-group-started", parsed);
} else if (record.asyncClass == "thread-group-exited") {
this.emit("thread-group-exited", parsed);
}
}
}
Expand Down Expand Up @@ -431,21 +444,21 @@ export class MI2 extends EventEmitter implements IBackend {
this.sendRaw("-target-detach");
}

interrupt(): Thenable<boolean> {
interrupt(all: boolean = true): Thenable<boolean> {
if (trace)
this.log("stderr", "interrupt");
return new Promise((resolve, reject) => {
this.sendCommand("exec-interrupt").then((info) => {
this.sendCommand("exec-interrupt" + (all ? " --all" : "")).then((info) => {
resolve(info.resultRecords.resultClass == "done");
}, reject);
});
}

continue(reverse: boolean = false): Thenable<boolean> {
continue(reverse: boolean = false, all: boolean = true): Thenable<boolean> {
if (trace)
this.log("stderr", "continue");
return new Promise((resolve, reject) => {
this.sendCommand("exec-continue" + (reverse ? " --reverse" : "")).then((info) => {
this.sendCommand("exec-continue" + (reverse ? " --reverse" : "") + (all ? " --all" : "")).then((info) => {
resolve(info.resultRecords.resultClass == "running");
}, reject);
});
Expand Down Expand Up @@ -794,6 +807,7 @@ export class MI2 extends EventEmitter implements IBackend {
}

prettyPrint: boolean = true;
multiProcess: boolean = false;
printCalls: boolean;
debugOutput: boolean;
public procEnv: any;
Expand Down
4 changes: 4 additions & 0 deletions src/gdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArgum
ssh: SSHArguments;
valuesFormatting: ValuesFormattingMode;
printCalls: boolean;
multiProcess: boolean;
showDevDebugOutput: boolean;
}

Expand All @@ -33,6 +34,7 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum
ssh: SSHArguments;
valuesFormatting: ValuesFormattingMode;
printCalls: boolean;
multiProcess: boolean;
showDevDebugOutput: boolean;
}

Expand Down Expand Up @@ -62,6 +64,7 @@ class GDBDebugSession extends MI2DebugSession {
this.debugReady = false;
this.setValuesFormattingMode(args.valuesFormatting);
this.miDebugger.printCalls = !!args.printCalls;
this.miDebugger.multiProcess = !!args.multiProcess;
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
if (args.ssh !== undefined) {
if (args.ssh.forwardX11 === undefined)
Expand Down Expand Up @@ -130,6 +133,7 @@ class GDBDebugSession extends MI2DebugSession {
this.debugReady = false;
this.setValuesFormattingMode(args.valuesFormatting);
this.miDebugger.printCalls = !!args.printCalls;
this.miDebugger.multiProcess = !!args.multiProcess;
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
if (args.ssh !== undefined) {
if (args.ssh.forwardX11 === undefined)
Expand Down
54 changes: 42 additions & 12 deletions src/mibase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export class MI2DebugSession extends DebugSession {
protected miDebugger: MI2;
protected commandServer: net.Server;
protected serverPath: string;
protected threadGroupPids = new Map<string, string>();
protected threadToPid = new Map<number, string>();

public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
super(debuggerLinesStartAt1, isServer);
Expand All @@ -56,6 +58,8 @@ export class MI2DebugSession extends DebugSession {
this.miDebugger.on("signal-stop", this.handlePause.bind(this));
this.miDebugger.on("thread-created", this.threadCreatedEvent.bind(this));
this.miDebugger.on("thread-exited", this.threadExitedEvent.bind(this));
this.miDebugger.on("thread-group-started", this.threadGroupStartedEvent.bind(this));
this.miDebugger.on("thread-group-exited", this.threadGroupExitedEvent.bind(this));
this.sendEvent(new InitializedEvent());
try {
this.commandServer = net.createServer(c => {
Expand Down Expand Up @@ -140,21 +144,39 @@ export class MI2DebugSession extends DebugSession {
}

protected threadCreatedEvent(info: MINode) {
this.sendEvent(new ThreadEvent("started", info.record("id")));
let threadId = parseInt(info.record("id"), 10);

let threadPid = this.threadGroupPids.get(info.record("group-id"));
this.threadToPid.set(threadId, threadPid);

this.sendEvent(new ThreadEvent("started", threadId));
}

protected threadExitedEvent(info: MINode) {
this.sendEvent(new ThreadEvent("exited", info.record("id")));
let threadId = parseInt(info.record("id"), 10);

this.threadToPid.delete(info.record("group-id"));

this.sendEvent(new ThreadEvent("exited", threadId));
}

protected quitEvent() {
this.quit = true;
this.sendEvent(new TerminatedEvent());
protected threadGroupStartedEvent(info: MINode) {
this.threadGroupPids.set(info.record("id"), info.record("pid"));
}

if (this.serverPath)
fs.unlink(this.serverPath, (err) => {
console.error("Failed to unlink debug server");
});
protected threadGroupExitedEvent(info: MINode) {
this.threadGroupPids.delete(info.record("id"));
}

protected quitEvent(info?: MINode) {
if (this.threadGroupPids.size == 0) {
this.quit = true;
this.sendEvent(new TerminatedEvent());
if (this.serverPath)
fs.unlink(this.serverPath, (err) => {
console.error("Failed to unlink debug server");
});
}
}

protected launchError(err: any) {
Expand Down Expand Up @@ -274,8 +296,14 @@ export class MI2DebugSession extends DebugSession {
threads: []
};
for (const thread of threads) {
let threadName = thread.name || thread.targetId || "<unnamed>";
response.body.threads.push(new Thread(thread.id, thread.id + ":" + threadName));
let threadName = thread.name || thread.targetId || "<unnamed>";
if (this.threadGroupPids.size > 1) {
let pid = this.threadToPid.get(thread.id);
threadName = `(${pid}) ${thread.id}:${threadName}`;
} else {
threadName = `${thread.id}:${threadName}`;
}
response.body.threads.push(new Thread(thread.id, threadName));
}
this.sendResponse(response);
});
Expand Down Expand Up @@ -561,7 +589,7 @@ export class MI2DebugSession extends DebugSession {
}
}

protected pauseRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments): void {
this.miDebugger.interrupt().then(done => {
this.sendResponse(response);
}, msg => {
Expand All @@ -571,6 +599,7 @@ export class MI2DebugSession extends DebugSession {

protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments): void {
this.miDebugger.continue(true).then(done => {
response.body.allThreadsContinued = true;
this.sendResponse(response);
}, msg => {
this.sendErrorResponse(response, 2, `Could not continue: ${msg}`);
Expand All @@ -579,6 +608,7 @@ export class MI2DebugSession extends DebugSession {

protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
this.miDebugger.continue().then(done => {
response.body.allThreadsContinued = true;
this.sendResponse(response);
}, msg => {
this.sendErrorResponse(response, 2, `Could not continue: ${msg}`);
Expand Down

0 comments on commit 00aafd4

Please sign in to comment.