2025-05-29 20:40:33 -07:00
|
|
|
import { logger } from 'tools/dap/logger.js';
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
export class JsDebugger
|
|
|
|
|
{
|
|
|
|
|
constructor()
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this.debugger = new Debugger();
|
|
|
|
|
this.logger = logger.getLogger("SpiderDebugger");
|
|
|
|
|
this.events = [];
|
|
|
|
|
this.sourcesReferences = [];
|
|
|
|
|
this.currentFrame = null;
|
|
|
|
|
this.hooks = {
|
|
|
|
|
'onDebuggerAttached': [],
|
|
|
|
|
'onDebuggerDetached': [],
|
|
|
|
|
'onNewGlobalObject': [],
|
|
|
|
|
'onDebuggerStatement': [],
|
|
|
|
|
'onNewScript': [],
|
|
|
|
|
'onEnterFrame': [],
|
|
|
|
|
'onUncaughtException': [],
|
|
|
|
|
'onStopInFrame': [],
|
|
|
|
|
'onRsumeInFrame': [],
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
this.debugger.uncaughtExceptionHook = (e) =>
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this._runHooks('onUncaughtException', e);
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
this.debugger.onNewGlobalObject = (global) =>
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this._runHooks('onNewGlobalObject', global);
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
this.debugger.onDebuggerStatement = (frame) =>
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this._runHooks('onDebuggerStatement', frame);
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
this.debugger.onNewScript = (script, global) =>
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this._runHooks('onNewScript', { script, global });
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
this.debugger.onEnterFrame = (frame) =>
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this._runHooks('onEnterFrame', frame);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.debuggerAttached = false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
_runHooks(event, data)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this.logger.trace(`Running hook for ${event}`);
|
|
|
|
|
for (const hookInfo of this.hooks[event])
|
|
|
|
|
{
|
|
|
|
|
this.logger.trace(`Running hook for ${hookInfo.source}-${event}`);
|
|
|
|
|
if (typeof hookInfo.callback !== 'function')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn(`Hook for ${event} is not a function: ${hook.source}`);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
try
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
hookInfo.callback(data);
|
2025-12-30 00:57:37 -08:00
|
|
|
}
|
|
|
|
|
catch(e)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this.logger.error(`Error in hook for ${hookInfo.source}-${event}: ${e.message}`);
|
|
|
|
|
this.logger.error(uneval(e.stack));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
on(event, callback, source)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
if (!event || typeof event !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn('Invalid event name');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.hooks[event])
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn(`No hooks registered for event: ${event}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!source || typeof source !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn(`Invalid source name for event ${event}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (typeof callback !== 'function')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn(`Callback for event ${source}:${event} is not a function`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.hooks[event].push({ callback, source });
|
|
|
|
|
this.logger.debug(`Hook added for event: ${event}`);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
get instance()
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
return this.debugger;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
setAttached(attached)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
this.debuggerAttached = attached;
|
|
|
|
|
if (attached)
|
|
|
|
|
{
|
|
|
|
|
this.logger.debug("Debugger attached");
|
|
|
|
|
this._runHooks('onDebuggerAttached', {});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this.logger.debug("Debugger detached");
|
|
|
|
|
this._runHooks('onDebuggerDetached', {});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
pushEvent(eventName, eventData, source)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
if (!eventName || typeof eventName !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn('Invalid event name');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (source && typeof source !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn('Invalid source name');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.logger.debug(`Pushing event: ${source}-${eventName}`);
|
|
|
|
|
this.events.push({
|
|
|
|
|
'type': 'event',
|
|
|
|
|
'event': eventName,
|
|
|
|
|
'body': eventData
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
stopInframe(frame, onHandler)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
if (!frame || !(frame instanceof Debugger.Frame))
|
|
|
|
|
{
|
|
|
|
|
this.logger.error('Invalid frame provided to stopInframe');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.currentFrame = frame;
|
|
|
|
|
frame.currentLocation = frame.script.getOffsetLocation(frame.offset);
|
|
|
|
|
this.logger.debug(`Stop at ${frame.script.url}:${frame.currentLocation.lineNumber}:${frame.currentLocation.columnNumber}`);
|
|
|
|
|
this.logger.debug(`Frame type: ${frame.type}`);
|
|
|
|
|
|
|
|
|
|
if (onHandler && typeof onHandler === 'function')
|
|
|
|
|
onHandler();
|
|
|
|
|
|
|
|
|
|
this._runHooks('onStopInFrame', frame);
|
|
|
|
|
Engine.WaitForMessage();
|
|
|
|
|
this._runHooks('onRsumeInFrame', frame);
|
|
|
|
|
|
|
|
|
|
this.logger.debug("Client continue");
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
registerHookName(event, source)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
if (!event || typeof event !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn('Invalid event name');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!source || typeof source !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn(`Invalid source name for ${event}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.hooks[event])
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn(`Hooks already registered for event: ${event}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.hooks[event] = [];
|
|
|
|
|
this.logger.debug(`Hook registered for event: ${event} from source: ${source}`);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 00:57:37 -08:00
|
|
|
triggerHook(event, data)
|
|
|
|
|
{
|
2025-05-29 20:40:33 -07:00
|
|
|
if (!event || typeof event !== 'string')
|
|
|
|
|
{
|
|
|
|
|
this.logger.warn('Invalid event name');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._runHooks(event, data);
|
|
|
|
|
}
|
|
|
|
|
}
|