Rewild Your Web
web
browser
dweb
1if ("dbg" in this) {
2 throw new Error("Debugger script must not run more than once!");
3}
4
5const dbg = new Debugger;
6const debuggeesToPipelineIds = new Map;
7const debuggeesToWorkerIds = new Map;
8const sourceIdsToScripts = new Map;
9
10dbg.uncaughtExceptionHook = function(error) {
11 console.error(`[debugger] Uncaught exception at ${error.fileName}:${error.lineNumber}:${error.columnNumber}: ${error.name}: ${error.message}`);
12};
13
14dbg.onNewScript = function(script, /* undefined; seems to be `script.global` now */ global) {
15 // TODO: handle wasm (`script.source.introductionType == wasm`)
16 sourceIdsToScripts.set(script.source.id, script);
17 notifyNewSource({
18 pipelineId: debuggeesToPipelineIds.get(script.global),
19 workerId: debuggeesToWorkerIds.get(script.global),
20 spidermonkeyId: script.source.id,
21 url: script.source.url,
22 urlOverride: script.source.displayURL,
23 text: script.source.text,
24 introductionType: script.source.introductionType ?? null,
25 });
26};
27
28addEventListener("addDebuggee", event => {
29 const {global, pipelineId: {namespaceId, index}, workerId} = event;
30 dbg.addDebuggee(global);
31 const debuggerObject = dbg.addDebuggee(global);
32 debuggeesToPipelineIds.set(debuggerObject, {
33 namespaceId,
34 index,
35 });
36 debuggeesToWorkerIds.set(debuggerObject, workerId);
37});
38
39addEventListener("getPossibleBreakpoints", event => {
40 const {spidermonkeyId} = event;
41 const script = sourceIdsToScripts.get(spidermonkeyId);
42 let result = [];
43
44 function getPossibleBreakpointsRecursive(script) {
45 for (const location of script.getPossibleBreakpoints()) {
46 location["scriptId"] = script.sourceStart;
47 result.push(location);
48 }
49 for (const child of script.getChildScripts()) {
50 getPossibleBreakpointsRecursive(child);
51 }
52 }
53 getPossibleBreakpointsRecursive(script);
54
55 getPossibleBreakpointsResult(event, result);
56});
57
58addEventListener("setBreakpoint", event => {
59 const {spidermonkeyId, scriptId, offset} = event;
60 const script = sourceIdsToScripts.get(spidermonkeyId);
61
62 // <https://firefox-source-docs.mozilla.org/js/Debugger/Conventions.html#resumption-values>
63 function breakpointHandler(...args) {
64 // TODO: notify script to pause
65 // tell spidermonkey to pause
66 return {throw: "1"}
67 }
68
69 function setBreakpointRecursive(script) {
70 if (script.sourceStart == scriptId) {
71 script.setBreakpoint(offset, { hit: breakpointHandler });
72 return;
73 }
74 for (const child of script.getChildScripts()) {
75 setBreakpointRecursive(child);
76 }
77 }
78 setBreakpointRecursive(script);
79});
80
81// <https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Frame.html>
82addEventListener("pause", event => {
83 dbg.onEnterFrame = function(frame) {
84 dbg.onEnterFrame = undefined;
85 // TODO: Some properties throw if terminated is true
86 // TODO: Check if start line / column is correct or we need the proper breakpoint
87 let result = {
88 // TODO: arguments: frame.arguments,
89 column: frame.script.startColumn,
90 displayName: frame.script.displayName,
91 line: frame.script.startLine,
92 onStack: frame.onStack,
93 oldest: frame.older == null,
94 terminated: frame.terminated,
95 type_: frame.type,
96 url: frame.script.url,
97 };
98 getFrameResult(event, result);
99 };
100});
101
102// <https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Script.html#clearbreakpoint-handler-offset>
103// There may be more than one breakpoint at the same offset with different handlers, but we don’t handle that case for now.
104addEventListener("clearBreakpoint", event => {
105 const {spidermonkeyId, scriptId, offset} = event;
106 const script = sourceIdsToScripts.get(spidermonkeyId);
107
108 function setClearBreakpointRecursive(script) {
109 if (script.sourceStart == scriptId) {
110 // <https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Script.html#clearallbreakpoints-offset>
111 // If the instance refers to a JSScript, remove all breakpoints set in this script at that offset.
112 script.clearAllBreakpoints(offset);
113 return;
114 }
115 for (const child of script.getChildScripts()) {
116 setClearBreakpointRecursive(child);
117 }
118 }
119 setClearBreakpointRecursive(script);
120});