Skip to content

Commit 96a1909

Browse files
committed
POC for multiple debug sessions
1 parent 92c61ff commit 96a1909

4 files changed

Lines changed: 287 additions & 21 deletions

File tree

src/backend/mi2/mi2inferior.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { Breakpoint, IBackend, SSHArguments, Stack, Thread, Variable } from "../backend";
2+
import { MI2 } from "./mi2";
3+
4+
export class MI2Inferior implements IBackend {
5+
load(cwd: string, target: string, procArgs: string, separateConsole: string, autorun: string[]): Thenable<any> {
6+
return this.superior.load(cwd, target, procArgs, separateConsole, autorun);
7+
}
8+
9+
ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string, attach: boolean, autorun: string[]): Thenable<any> {
10+
return this.superior.ssh(args, cwd, target, separateConsole, procArgs, attach, autorun);
11+
}
12+
13+
attach(cwd: string, executable: string, target: string, autorun: string[]): Thenable<any> {
14+
return this.superior.attach(cwd, executable, target, autorun);
15+
}
16+
17+
connect(cwd: string, executable: string, target: string, autorun: string[]): Thenable<any> {
18+
return this.superior.attach(cwd, executable, target, autorun);
19+
}
20+
21+
start(runToStart: boolean): Thenable<boolean> {
22+
return this.superior.start(runToStart);
23+
}
24+
25+
stop(): void {
26+
this.superior.stop();
27+
}
28+
29+
detach(): void {
30+
this.superior.detach();
31+
}
32+
33+
interrupt(threadId?: number): Thenable<boolean> {
34+
return this.superior.interrupt(threadId);
35+
}
36+
37+
continue(reverse?: boolean, threadId?: number): Thenable<boolean> {
38+
return this.superior.continue(reverse, threadId);
39+
}
40+
41+
next(): Thenable<boolean> {
42+
return this.superior.next();
43+
}
44+
step(): Thenable<boolean> {
45+
return this.superior.step();
46+
}
47+
48+
stepOut(): Thenable<boolean> {
49+
return this.superior.stepOut();
50+
}
51+
52+
loadBreakPoints(breakpoints: Breakpoint[]): Thenable<[boolean, Breakpoint][]> {
53+
return this.superior.loadBreakPoints(breakpoints);
54+
}
55+
56+
addBreakPoint(breakpoint: Breakpoint): Thenable<[boolean, Breakpoint]> {
57+
return this.superior.addBreakPoint(breakpoint);
58+
}
59+
60+
removeBreakPoint(breakpoint: Breakpoint): Thenable<boolean> {
61+
return this.superior.removeBreakPoint(breakpoint);
62+
}
63+
64+
clearBreakPoints(source?: string): Thenable<any> {
65+
return this.superior.clearBreakPoints(source);
66+
}
67+
68+
getThreads(): Thenable<Thread[]> {
69+
return this.superior.getThreads();
70+
}
71+
72+
getStack(startFrame: number, maxLevels: number, thread: number): Thenable<Stack[]> {
73+
return this.superior.getStack(startFrame, maxLevels, thread);
74+
}
75+
76+
getStackVariables(thread: number, frame: number): Thenable<Variable[]> {
77+
return this.superior.getStackVariables(thread, frame);
78+
}
79+
80+
evalExpression(name: string, thread: number, frame: number): Thenable<any> {
81+
return this.superior.evalExpression(name, thread, frame);
82+
}
83+
84+
isReady(): boolean {
85+
return this.superior.isReady();
86+
}
87+
88+
changeVariable(name: string, rawValue: string): Thenable<any> {
89+
return this.superior.changeVariable(name, rawValue);
90+
}
91+
92+
examineMemory(from: number, to: number): Thenable<any> {
93+
return this.superior.examineMemory(from, to);
94+
}
95+
96+
private superior: MI2;
97+
98+
contructor(superior: MI2) {
99+
this.superior = superior
100+
}
101+
};

src/gdb.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum
4545
registerLimit: string;
4646
}
4747

48-
class GDBDebugSession extends MI2DebugSession {
48+
export class GDBDebugSession extends MI2DebugSession {
4949
protected override initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
5050
response.body.supportsGotoTargetsRequest = true;
5151
response.body.supportsHitConditionalBreakpoints = true;

src/mibase.ts

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as DebugAdapter from 'vscode-debugadapter';
2+
import * as Net from 'net';
23
import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, ThreadEvent, OutputEvent, ContinuedEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
34
import { DebugProtocol } from 'vscode-debugprotocol';
45
import { Breakpoint, IBackend, Variable, VariableObject, ValuesFormattingMode, MIError } from './backend/backend';
@@ -11,6 +12,7 @@ import * as net from "net";
1112
import * as os from "os";
1213
import * as fs from "fs";
1314
import { SourceFileMap } from "./source_file_map";
15+
import { MI2InferiorSession } from "./miinferior"
1416

1517
class ExtendedVariable {
1618
constructor(public name: string, public options: { "arg": any }) {
@@ -41,11 +43,12 @@ export class MI2DebugSession extends DebugSession {
4143
protected sourceFileMap: SourceFileMap;
4244
protected started: boolean;
4345
protected crashed: boolean;
44-
protected miDebugger: MI2;
46+
public miDebugger: MI2;
4547
protected commandServer: net.Server;
4648
protected serverPath: string;
4749
protected threadGroupPids = new Map<string, string>();
4850
protected threadToPid = new Map<number, string>();
51+
protected inferiorServers = new Array();
4952

5053
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
5154
super(debuggerLinesStartAt1, isServer);
@@ -185,8 +188,55 @@ export class MI2DebugSession extends DebugSession {
185188
this.sendEvent(new ThreadEvent("exited", threadId));
186189
}
187190

191+
private openInferiorDebugServer(superiorServer: MI2DebugSession) {
192+
function randomIntFromInterval(min: number, max: number) { // min and max included
193+
return Math.floor(Math.random() * (max - min + 1) + min);
194+
}
195+
196+
const port = 1337 + randomIntFromInterval(1, 1000);
197+
198+
console.error(`waiting for debug protocol on port ${port}`);
199+
200+
const server = Net.createServer((socket) => {
201+
console.error('>> accepted connection from client');
202+
socket.on('end', () => {
203+
console.error('>> client connection closed\n');
204+
});
205+
const session = new MI2InferiorSession(superiorServer);
206+
session.setRunAsServer(true);
207+
session.start(socket, socket);
208+
}).listen(port);
209+
210+
this.inferiorServers.push(server);
211+
212+
return server;
213+
}
214+
188215
protected threadGroupStartedEvent(info: MINode) {
216+
let pid = parseInt(info.record("pid"), 10);
217+
218+
this.miDebugger.log("stdout", "threadGroupStartedEvent")
219+
this.miDebugger.log("stdout", pid.toString())
220+
189221
this.threadGroupPids.set(info.record("id"), info.record("pid"));
222+
223+
// If there are more than 1 threadgroups active, start a new debugger session in VSCode
224+
// This makes the UI all fancy with subprocesses and threads etc.
225+
if (this.threadGroupPids.size > 1) {
226+
// Open a new port for the new DebugSession to attach to
227+
const server = this.openInferiorDebugServer(this);
228+
const serverAddress = (server.address() as Net.AddressInfo).port;
229+
230+
this.startDebuggingRequest({
231+
request: "attach",
232+
configuration: {
233+
type: "gdb-inferior",
234+
target: info.record("pid"),
235+
cwd: "${workspaceRoot}",
236+
debugServer: serverAddress
237+
}
238+
}, 1000, () => {})
239+
}
190240
}
191241

192242
protected threadGroupExitedEvent(info: MINode) {
@@ -212,7 +262,7 @@ export class MI2DebugSession extends DebugSession {
212262
this.quitEvent();
213263
}
214264

215-
protected override disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments): void {
265+
public override disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments): void {
216266
if (this.attached)
217267
this.miDebugger.detach();
218268
else
@@ -222,7 +272,7 @@ export class MI2DebugSession extends DebugSession {
222272
this.sendResponse(response);
223273
}
224274

225-
protected override async setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): Promise<void> {
275+
public override async setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): Promise<void> {
226276
try {
227277
if (this.useVarObjects) {
228278
let name = args.name;
@@ -249,7 +299,7 @@ export class MI2DebugSession extends DebugSession {
249299
}
250300
}
251301

252-
protected override setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void {
302+
public override setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void {
253303
const all: Thenable<[boolean, Breakpoint]>[] = [];
254304
args.breakpoints.forEach(brk => {
255305
all.push(this.miDebugger.addBreakPoint({ raw: brk.name, condition: brk.condition, countCondition: brk.hitCondition }));
@@ -269,7 +319,7 @@ export class MI2DebugSession extends DebugSession {
269319
});
270320
}
271321

272-
protected override setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
322+
public override setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
273323
let path = args.source.path;
274324
if (this.isSSH) {
275325
// convert local path to ssh path
@@ -299,7 +349,7 @@ export class MI2DebugSession extends DebugSession {
299349
});
300350
}
301351

302-
protected override threadsRequest(response: DebugProtocol.ThreadsResponse): void {
352+
public override threadsRequest(response: DebugProtocol.ThreadsResponse): void {
303353
if (!this.miDebugger) {
304354
this.sendResponse(response);
305355
return;
@@ -336,7 +386,7 @@ export class MI2DebugSession extends DebugSession {
336386
return [frameId & 0xffff, frameId >> 16];
337387
}
338388

339-
protected override stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
389+
public override stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
340390
this.miDebugger.getStack(args.startFrame, args.levels, args.threadId).then(stack => {
341391
const ret: StackFrame[] = [];
342392
stack.forEach(element => {
@@ -370,7 +420,7 @@ export class MI2DebugSession extends DebugSession {
370420
});
371421
}
372422

373-
protected override configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): void {
423+
public override configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): void {
374424
const promises: Thenable<any>[] = [];
375425
let entryPoint: string | undefined = undefined;
376426
let runToStart: boolean = false;
@@ -439,7 +489,7 @@ export class MI2DebugSession extends DebugSession {
439489
});
440490
}
441491

442-
protected override scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
492+
public override scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
443493
const scopes = new Array<Scope>();
444494
const [threadId, level] = this.frameIdToThreadAndLevel(args.frameId);
445495

@@ -466,7 +516,7 @@ export class MI2DebugSession extends DebugSession {
466516
this.sendResponse(response);
467517
}
468518

469-
protected override async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise<void> {
519+
public override async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise<void> {
470520
const variables: DebugProtocol.Variable[] = [];
471521
const id: VariableScope | string | VariableObject | ExtendedVariable = this.variableHandles.get(args.variablesReference);
472522

@@ -692,15 +742,15 @@ export class MI2DebugSession extends DebugSession {
692742
}
693743
}
694744

695-
protected override pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments): void {
745+
public override pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments): void {
696746
this.miDebugger.interrupt(args.threadId).then(done => {
697747
this.sendResponse(response);
698748
}, msg => {
699749
this.sendErrorResponse(response, 3, `Could not pause: ${msg}`);
700750
});
701751
}
702752

703-
protected override reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments): void {
753+
public override reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments): void {
704754
this.miDebugger.continue(true, args.threadId).then(done => {
705755
if (!response.hasOwnProperty("body")) {
706756
response.body = Object();
@@ -713,7 +763,7 @@ export class MI2DebugSession extends DebugSession {
713763
});
714764
}
715765

716-
protected override continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
766+
public override continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
717767
this.miDebugger.continue(false, args.threadId).then(done => {
718768
if (!response.hasOwnProperty("body")) {
719769
response.body = Object();
@@ -727,39 +777,39 @@ export class MI2DebugSession extends DebugSession {
727777
});
728778
}
729779

730-
protected override stepBackRequest(response: DebugProtocol.StepBackResponse, args: DebugProtocol.StepBackArguments): void {
780+
public override stepBackRequest(response: DebugProtocol.StepBackResponse, args: DebugProtocol.StepBackArguments): void {
731781
this.miDebugger.step(true).then(done => {
732782
this.sendResponse(response);
733783
}, msg => {
734784
this.sendErrorResponse(response, 4, `Could not step back: ${msg} - Try running 'target record-full' before stepping back`);
735785
});
736786
}
737787

738-
protected override stepInRequest(response: DebugProtocol.StepInResponse, args: DebugProtocol.StepInArguments): void {
788+
public override stepInRequest(response: DebugProtocol.StepInResponse, args: DebugProtocol.StepInArguments): void {
739789
this.miDebugger.step().then(done => {
740790
this.sendResponse(response);
741791
}, msg => {
742792
this.sendErrorResponse(response, 4, `Could not step in: ${msg}`);
743793
});
744794
}
745795

746-
protected override stepOutRequest(response: DebugProtocol.StepOutResponse, args: DebugProtocol.StepOutArguments): void {
796+
public override stepOutRequest(response: DebugProtocol.StepOutResponse, args: DebugProtocol.StepOutArguments): void {
747797
this.miDebugger.stepOut().then(done => {
748798
this.sendResponse(response);
749799
}, msg => {
750800
this.sendErrorResponse(response, 5, `Could not step out: ${msg}`);
751801
});
752802
}
753803

754-
protected override nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void {
804+
public override nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void {
755805
this.miDebugger.next().then(done => {
756806
this.sendResponse(response);
757807
}, msg => {
758808
this.sendErrorResponse(response, 6, `Could not step over: ${msg}`);
759809
});
760810
}
761811

762-
protected override evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void {
812+
public override evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void {
763813
const [threadId, level] = this.frameIdToThreadAndLevel(args.frameId);
764814
if (args.context === "watch" || args.context === "hover") {
765815
this.miDebugger.evalExpression(args.expression, threadId, level).then((res) => {
@@ -795,7 +845,7 @@ export class MI2DebugSession extends DebugSession {
795845
}
796846
}
797847

798-
protected override gotoTargetsRequest(response: DebugProtocol.GotoTargetsResponse, args: DebugProtocol.GotoTargetsArguments): void {
848+
public override gotoTargetsRequest(response: DebugProtocol.GotoTargetsResponse, args: DebugProtocol.GotoTargetsArguments): void {
799849
const path: string = this.isSSH ? this.sourceFileMap.toRemotePath(args.source.path) : args.source.path;
800850
this.miDebugger.goto(path, args.line).then(done => {
801851
response.body = {
@@ -812,7 +862,7 @@ export class MI2DebugSession extends DebugSession {
812862
});
813863
}
814864

815-
protected override gotoRequest(response: DebugProtocol.GotoResponse, args: DebugProtocol.GotoArguments): void {
865+
public override gotoRequest(response: DebugProtocol.GotoResponse, args: DebugProtocol.GotoArguments): void {
816866
this.sendResponse(response);
817867
}
818868

0 commit comments

Comments
 (0)