Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-process support #133

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mixed indentation here

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