Skip to content

Commit 00aafd4

Browse files
committed
Add multi-process support
1 parent f292348 commit 00aafd4

File tree

5 files changed

+72
-19
lines changed

5 files changed

+72
-19
lines changed

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@
130130
"description": "Prints all GDB calls to the console",
131131
"default": false
132132
},
133+
"multiProcess": {
134+
"type": "boolean",
135+
"description": "Allow multiple process debugging",
136+
"default": false
137+
},
133138
"showDevDebugOutput": {
134139
"type": "boolean",
135140
"description": "Prints all GDB responses to the console",

src/backend/backend.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export interface IBackend {
5656
start(): Thenable<boolean>;
5757
stop();
5858
detach();
59-
interrupt(): Thenable<boolean>;
59+
interrupt(all: boolean): Thenable<boolean>;
6060
continue(): Thenable<boolean>;
6161
next(): Thenable<boolean>;
6262
step(): Thenable<boolean>;

src/backend/mi2/mi2.ts

+20-6
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,18 @@ export class MI2 extends EventEmitter implements IBackend {
197197
cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
198198
if (this.prettyPrint)
199199
cmds.push(this.sendCommand("enable-pretty-printing"));
200+
if (this.multiProcess) {
201+
cmds.push(
202+
this.sendCommand("gdb-set follow-fork-mode parent"),
203+
this.sendCommand("gdb-set detach-on-fork off"),
204+
this.sendCommand("gdb-set non-stop on"),
205+
this.sendCommand("gdb-set schedule-multiple on"),
206+
207+
this.sendCommand("interpreter-exec console \"handle SIGSYS nostop noprint\"")
208+
);
209+
}
200210
for (let cmd of this.extraCommands) {
201211
cmds.push(this.sendCommand(cmd));
202-
}
203212

204213
return cmds;
205214
}
@@ -357,7 +366,7 @@ export class MI2 extends EventEmitter implements IBackend {
357366
else if (reason == "exited-normally")
358367
this.emit("exited-normally", parsed);
359368
else if (reason == "exited") { // exit with error code != 0
360-
this.log("stderr", "Program exited with code " + parsed.record("exit-code"));
369+
this.log("stderr", "Inferior exited with code " + parsed.record("exit-code"));
361370
this.emit("exited-normally", parsed);
362371
} else {
363372
this.log("console", "Not implemented stop reason (assuming exception): " + reason);
@@ -370,6 +379,10 @@ export class MI2 extends EventEmitter implements IBackend {
370379
this.emit("thread-created", parsed);
371380
} else if (record.asyncClass == "thread-exited") {
372381
this.emit("thread-exited", parsed);
382+
} else if (record.asyncClass == "thread-group-started") {
383+
this.emit("thread-group-started", parsed);
384+
} else if (record.asyncClass == "thread-group-exited") {
385+
this.emit("thread-group-exited", parsed);
373386
}
374387
}
375388
}
@@ -431,21 +444,21 @@ export class MI2 extends EventEmitter implements IBackend {
431444
this.sendRaw("-target-detach");
432445
}
433446

434-
interrupt(): Thenable<boolean> {
447+
interrupt(all: boolean = true): Thenable<boolean> {
435448
if (trace)
436449
this.log("stderr", "interrupt");
437450
return new Promise((resolve, reject) => {
438-
this.sendCommand("exec-interrupt").then((info) => {
451+
this.sendCommand("exec-interrupt" + (all ? " --all" : "")).then((info) => {
439452
resolve(info.resultRecords.resultClass == "done");
440453
}, reject);
441454
});
442455
}
443456

444-
continue(reverse: boolean = false): Thenable<boolean> {
457+
continue(reverse: boolean = false, all: boolean = true): Thenable<boolean> {
445458
if (trace)
446459
this.log("stderr", "continue");
447460
return new Promise((resolve, reject) => {
448-
this.sendCommand("exec-continue" + (reverse ? " --reverse" : "")).then((info) => {
461+
this.sendCommand("exec-continue" + (reverse ? " --reverse" : "") + (all ? " --all" : "")).then((info) => {
449462
resolve(info.resultRecords.resultClass == "running");
450463
}, reject);
451464
});
@@ -794,6 +807,7 @@ export class MI2 extends EventEmitter implements IBackend {
794807
}
795808

796809
prettyPrint: boolean = true;
810+
multiProcess: boolean = false;
797811
printCalls: boolean;
798812
debugOutput: boolean;
799813
public procEnv: any;

src/gdb.ts

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArgum
1717
ssh: SSHArguments;
1818
valuesFormatting: ValuesFormattingMode;
1919
printCalls: boolean;
20+
multiProcess: boolean;
2021
showDevDebugOutput: boolean;
2122
}
2223

@@ -33,6 +34,7 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum
3334
ssh: SSHArguments;
3435
valuesFormatting: ValuesFormattingMode;
3536
printCalls: boolean;
37+
multiProcess: boolean;
3638
showDevDebugOutput: boolean;
3739
}
3840

@@ -62,6 +64,7 @@ class GDBDebugSession extends MI2DebugSession {
6264
this.debugReady = false;
6365
this.setValuesFormattingMode(args.valuesFormatting);
6466
this.miDebugger.printCalls = !!args.printCalls;
67+
this.miDebugger.multiProcess = !!args.multiProcess;
6568
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
6669
if (args.ssh !== undefined) {
6770
if (args.ssh.forwardX11 === undefined)
@@ -130,6 +133,7 @@ class GDBDebugSession extends MI2DebugSession {
130133
this.debugReady = false;
131134
this.setValuesFormattingMode(args.valuesFormatting);
132135
this.miDebugger.printCalls = !!args.printCalls;
136+
this.miDebugger.multiProcess = !!args.multiProcess;
133137
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
134138
if (args.ssh !== undefined) {
135139
if (args.ssh.forwardX11 === undefined)

src/mibase.ts

+42-12
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export class MI2DebugSession extends DebugSession {
3838
protected miDebugger: MI2;
3939
protected commandServer: net.Server;
4040
protected serverPath: string;
41+
protected threadGroupPids = new Map<string, string>();
42+
protected threadToPid = new Map<number, string>();
4143

4244
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
4345
super(debuggerLinesStartAt1, isServer);
@@ -56,6 +58,8 @@ export class MI2DebugSession extends DebugSession {
5658
this.miDebugger.on("signal-stop", this.handlePause.bind(this));
5759
this.miDebugger.on("thread-created", this.threadCreatedEvent.bind(this));
5860
this.miDebugger.on("thread-exited", this.threadExitedEvent.bind(this));
61+
this.miDebugger.on("thread-group-started", this.threadGroupStartedEvent.bind(this));
62+
this.miDebugger.on("thread-group-exited", this.threadGroupExitedEvent.bind(this));
5963
this.sendEvent(new InitializedEvent());
6064
try {
6165
this.commandServer = net.createServer(c => {
@@ -140,21 +144,39 @@ export class MI2DebugSession extends DebugSession {
140144
}
141145

142146
protected threadCreatedEvent(info: MINode) {
143-
this.sendEvent(new ThreadEvent("started", info.record("id")));
147+
let threadId = parseInt(info.record("id"), 10);
148+
149+
let threadPid = this.threadGroupPids.get(info.record("group-id"));
150+
this.threadToPid.set(threadId, threadPid);
151+
152+
this.sendEvent(new ThreadEvent("started", threadId));
144153
}
145154

146155
protected threadExitedEvent(info: MINode) {
147-
this.sendEvent(new ThreadEvent("exited", info.record("id")));
156+
let threadId = parseInt(info.record("id"), 10);
157+
158+
this.threadToPid.delete(info.record("group-id"));
159+
160+
this.sendEvent(new ThreadEvent("exited", threadId));
148161
}
149162

150-
protected quitEvent() {
151-
this.quit = true;
152-
this.sendEvent(new TerminatedEvent());
163+
protected threadGroupStartedEvent(info: MINode) {
164+
this.threadGroupPids.set(info.record("id"), info.record("pid"));
165+
}
153166

154-
if (this.serverPath)
155-
fs.unlink(this.serverPath, (err) => {
156-
console.error("Failed to unlink debug server");
157-
});
167+
protected threadGroupExitedEvent(info: MINode) {
168+
this.threadGroupPids.delete(info.record("id"));
169+
}
170+
171+
protected quitEvent(info?: MINode) {
172+
if (this.threadGroupPids.size == 0) {
173+
this.quit = true;
174+
this.sendEvent(new TerminatedEvent());
175+
if (this.serverPath)
176+
fs.unlink(this.serverPath, (err) => {
177+
console.error("Failed to unlink debug server");
178+
});
179+
}
158180
}
159181

160182
protected launchError(err: any) {
@@ -274,8 +296,14 @@ export class MI2DebugSession extends DebugSession {
274296
threads: []
275297
};
276298
for (const thread of threads) {
277-
let threadName = thread.name || thread.targetId || "<unnamed>";
278-
response.body.threads.push(new Thread(thread.id, thread.id + ":" + threadName));
299+
let threadName = thread.name || thread.targetId || "<unnamed>";
300+
if (this.threadGroupPids.size > 1) {
301+
let pid = this.threadToPid.get(thread.id);
302+
threadName = `(${pid}) ${thread.id}:${threadName}`;
303+
} else {
304+
threadName = `${thread.id}:${threadName}`;
305+
}
306+
response.body.threads.push(new Thread(thread.id, threadName));
279307
}
280308
this.sendResponse(response);
281309
});
@@ -561,7 +589,7 @@ export class MI2DebugSession extends DebugSession {
561589
}
562590
}
563591

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

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

580609
protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
581610
this.miDebugger.continue().then(done => {
611+
response.body.allThreadsContinued = true;
582612
this.sendResponse(response);
583613
}, msg => {
584614
this.sendErrorResponse(response, 2, `Could not continue: ${msg}`);

0 commit comments

Comments
 (0)