Rewild Your Web
web browser dweb
at main 120 lines 4.5 kB view raw
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});