Skip to content

Commit 54262e5

Browse files
authored
Merge pull request #1 from A-Kovalev-Playrix/dev/breakpoins-pulling
PF from tomblind: Pull support for breakpoints update
2 parents d51ee29 + b6b2b13 commit 54262e5

8 files changed

Lines changed: 181 additions & 16 deletions

File tree

debugger/debugger.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,27 @@ export namespace Debugger {
7676
inputFile = io.stdin;
7777
}
7878

79+
const pullFileEnv: LuaDebug.PullFileEnv = "LOCAL_LUA_DEBUGGER_PULL_FILE";
80+
const pullFilePath = os.getenv(pullFileEnv);
81+
let lastPullSeek = 0;
82+
let pullFile: LuaFile | null;
83+
if (pullFilePath && pullFilePath.length > 0) {
84+
const [file, err] = io.open(pullFilePath, "r+");
85+
if (!file) {
86+
luaError(`Failed to open pull file "${pullFilePath}": ${err}\n`);
87+
}
88+
pullFile = file as LuaFile;
89+
pullFile.setvbuf("no");
90+
const [fileSize, errorSeek] = pullFile.seek("end");
91+
if (!fileSize) {
92+
luaError(`Failed to read pull file "${pullFilePath}": ${errorSeek}\n`);
93+
} else {
94+
lastPullSeek = fileSize;
95+
}
96+
} else {
97+
pullFile = null;
98+
}
99+
79100
let skipNextBreak = false;
80101

81102
const enum HookType {
@@ -475,6 +496,7 @@ export namespace Debugger {
475496
let breakAtDepth = -1;
476497
let breakInThread: Thread | undefined;
477498
let updateHook: { (): void };
499+
let isDebugHookDisabled = true;
478500
let ignorePatterns: string[] | undefined;
479501
let inDebugBreak = false;
480502

@@ -848,6 +870,10 @@ export namespace Debugger {
848870
const skipUnmappedLines = (os.getenv(stepUnmappedLinesEnv) !== "1");
849871

850872
function debugHook(event: "call" | "return" | "tail return" | "count" | "line", line?: number) {
873+
if (isDebugHookDisabled) {
874+
return;
875+
}
876+
851877
//Stepping
852878
if (breakAtDepth >= 0) {
853879
const activeThread = getActiveThread();
@@ -1143,7 +1169,10 @@ export namespace Debugger {
11431169
}
11441170

11451171
updateHook = function() {
1146-
if (breakAtDepth < 0 && Breakpoint.getCount() === 0) {
1172+
isDebugHookDisabled = breakAtDepth < 0 && Breakpoint.getCount() === 0;
1173+
// Do not disable debugging in luajit environment with pull breakpoints support enabled
1174+
// or functions will be jitted and will lose debug info of lines and files
1175+
if (isDebugHookDisabled && (_G["jit"] === null || pullFile === null)) {
11471176
debug.sethook();
11481177

11491178
for (const [thread] of pairs(threadIds)) {
@@ -1173,6 +1202,7 @@ export namespace Debugger {
11731202
coroutine.wrap = luaCoroutineWrap;
11741203
coroutine.resume = luaCoroutineResume;
11751204

1205+
isDebugHookDisabled = true;
11761206
debug.sethook();
11771207

11781208
for (const [thread] of pairs(threadIds)) {
@@ -1251,4 +1281,14 @@ export namespace Debugger {
12511281
return luaError(message, 2);
12521282
}
12531283
}
1284+
1285+
export function pullBreakpoints(): void {
1286+
if (pullFile) {
1287+
const newPullSeek = pullFile.seek("end")[0] as number;
1288+
if (newPullSeek > lastPullSeek) {
1289+
lastPullSeek = newPullSeek;
1290+
triggerBreak();
1291+
}
1292+
}
1293+
}
12541294
}

debugger/lldebugger.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ export function stop(): void {
5555
Debugger.clearHook();
5656
}
5757

58+
//Pull breakpoints change
59+
export function pullBreakpoints(): void {
60+
Debugger.pullBreakpoints();
61+
}
62+
5863
//Load and debug the specified file
5964
export function runFile(filePath: unknown, breakImmediately?: boolean, arg?: unknown[]): LuaMultiReturn<unknown[]> {
6065
if (typeof filePath !== "string") {

debugger/protocol.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,5 @@ declare namespace LuaDebug {
119119
type StepUnmappedLinesEnv = "LOCAL_LUA_DEBUGGER_STEP_UNMAPPED_LINES";
120120
type InputFileEnv = "LOCAL_LUA_DEBUGGER_INPUT_FILE";
121121
type OutputFileEnv = "LOCAL_LUA_DEBUGGER_OUTPUT_FILE";
122+
type PullFileEnv = "LOCAL_LUA_DEBUGGER_PULL_FILE";
122123
}

extension/debugPipe.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,34 @@ import * as crypto from "crypto";
22
import * as net from "net";
33
import * as childProcess from "child_process";
44
import * as fs from "fs";
5+
import * as os from "os";
6+
import * as path from "path";
57

68
export interface DebugPipe {
79
open: (onData: (data: unknown) => void, onError: (err: unknown) => void) => void;
810
close: () => void;
911
write: (data: string) => void;
12+
openPull: (onError: (err: unknown) => void) => void;
13+
requestPull: () => void;
1014
getOutputPipePath: () => string;
1115
getInputPipePath: () => string;
16+
getPullPipePath: () => string;
1217
}
1318

1419
export function createNamedPipe(): DebugPipe {
1520
const pipeId = crypto.randomBytes(16).toString("hex");
1621
const outputPipePath = `\\\\.\\pipe\\lldbg_out_${pipeId}`;
1722
const inputPipePath = `\\\\.\\pipe\\lldbg_in_${pipeId}`;
23+
const pullPipePath = `\\\\.\\pipe\\lldbg_pull_${pipeId}`;
1824
let outputPipe: net.Server | null = null;
1925
let inputPipe: net.Server | null = null;
26+
let pullPipe: net.Server | null = null;
2027
let inputStream: net.Socket | null;
28+
let pullStream: net.Socket | null;
29+
let onErrorCallback: ((err: unknown) => void) | null = null;
2130
return {
2231
open: (onData, onError) => {
32+
onErrorCallback = onError;
2333
outputPipe = net.createServer(
2434
stream => {
2535
stream.on("data", onData);
@@ -35,31 +45,56 @@ export function createNamedPipe(): DebugPipe {
3545
);
3646
inputPipe.listen(inputPipePath);
3747
},
48+
openPull: (onError: (err: unknown) => void) => {
49+
if (!onErrorCallback) {
50+
onErrorCallback = onError;
51+
}
52+
53+
pullPipe = net.createServer(
54+
stream => {
55+
stream.on("error", err => {
56+
onError(`error on pull pipe: ${err}`);
57+
});
58+
pullStream = stream;
59+
}
60+
);
61+
pullPipe.listen(pullPipePath);
62+
},
3863

3964
close: () => {
4065
outputPipe?.close();
4166
outputPipe = null;
4267
inputPipe?.close();
4368
inputPipe = null;
4469
inputStream = null;
70+
pullPipe = null;
71+
pullStream = null;
4572
},
4673

4774
write: data => {
4875
inputStream?.write(data);
4976
},
77+
requestPull: () => {
78+
pullStream?.write("pull|\n");
79+
},
5080

5181
getOutputPipePath: () => outputPipePath,
5282
getInputPipePath: () => inputPipePath,
83+
getPullPipePath: () => pullPipePath,
5384
};
5485
}
5586

5687
export function createFifoPipe(): DebugPipe {
5788
const pipeId = crypto.randomBytes(16).toString("hex");
5889
const outputPipePath = `/tmp/lldbg_out_${pipeId}`;
5990
const inputPipePath = `/tmp/lldbg_in_${pipeId}`;
60-
let outputFd: number | null;
61-
let inputFd: number | null;
91+
let pullPipePath = "";
92+
let debuggerTmpDir = "";
93+
let outputFd: number | null = null;
94+
let inputFd: number | null = null;
95+
let pullFd: number | null = null;
6296
let inputStream: fs.WriteStream | null = null;
97+
let pullStream: fs.WriteStream | null = null;
6398
let onErrorCallback: ((err: unknown) => void) | null = null;
6499
return {
65100
open: (onData, onError) => {
@@ -113,7 +148,27 @@ export function createFifoPipe(): DebugPipe {
113148
);
114149
}
115150
);
151+
},
116152

153+
openPull: (onError: (err: unknown) => void) => {
154+
if (!onErrorCallback) {
155+
onErrorCallback = onError;
156+
}
157+
158+
const appPrefix = "lldebugger";
159+
try {
160+
debuggerTmpDir = fs.mkdtempSync(path.join(os.tmpdir(), appPrefix));
161+
pullPipePath = path.join(debuggerTmpDir, "pull.txt");
162+
163+
const fd = fs.openSync(
164+
pullPipePath,
165+
fs.constants.O_WRONLY | fs.constants.O_CREAT
166+
);
167+
pullFd = fd;
168+
pullStream = fs.createWriteStream(null as unknown as fs.PathLike, {fd});
169+
} catch (e: unknown) {
170+
onErrorCallback(e);
171+
}
117172
},
118173

119174
close: () => {
@@ -141,13 +196,31 @@ export function createFifoPipe(): DebugPipe {
141196
}
142197
);
143198
}
199+
inputStream = null;
200+
try {
201+
if (pullFd !== null) {
202+
fs.close(pullFd);
203+
fs.rmSync(pullPipePath);
204+
pullFd = null;
205+
}
206+
pullStream = null;
207+
if (debuggerTmpDir.length > 0) {
208+
fs.rmdirSync(debuggerTmpDir);
209+
}
210+
} catch (e: unknown) {
211+
onErrorCallback?.(e);
212+
}
144213
},
145214

146215
write: data => {
147216
inputStream?.write(data);
148217
},
218+
requestPull: () => {
219+
pullStream?.write("pull|\n");
220+
},
149221

150222
getOutputPipePath: () => outputPipePath,
151223
getInputPipePath: () => inputPipePath,
224+
getPullPipePath: () => pullPipePath,
152225
};
153226
}

extension/launchConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export interface LaunchConfig {
4242
verbose?: boolean;
4343
stopOnEntry?: boolean;
4444
breakInCoroutines?: boolean;
45+
pullBreakpointsSupport?: boolean;
4546
stepUnmappedLines?: boolean;
4647
scriptFiles?: string[];
4748
ignorePatterns?: string[];

0 commit comments

Comments
 (0)