blob: a4dd1f658ab47580445d72157efaf7f17bea268a [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
var TRACE_NONE = 0x0000;
var TRACE_COMMANDS = 0x001;
var TRACE_DIAG_OUTPUT = 0x002;
var TRACE_INTERNAL_FUNCTIONS = 0x004;
var TRACE_DEBUG_EVENTS = 0x008;
var TRACE_ALL = TRACE_COMMANDS | TRACE_DIAG_OUTPUT | TRACE_INTERNAL_FUNCTIONS | TRACE_DEBUG_EVENTS;
// Have all JsDiag* functions installed on it by Debugger.cpp
var hostDebugObject = {};
var controllerObj = (function () {
var _commandList = [];
var _commandCompletions = [];
var _wasResumed = false;
var _currentStackFrameIndex = 0;
var _trace = TRACE_NONE;
var _eventLog = [];
var _baseline = undefined;
var _exceptionCommands = undefined;
var _onasyncbreakCommands = undefined;
var _inspectMaxStringLength = 16;
function internalPrint(str) {
WScript.Echo(str);
}
function isTracing(traceFlag) {
return _trace & traceFlag;
}
function internalTrace(traceFlag, ...varArgs) {
if (isTracing(traceFlag)) {
var str = "";
varArgs.map(function (element) {
str += (typeof element != "string") ? JSON.stringify(element, undefined, " ") : element;
});
internalPrint(str);
}
}
function printError(str) {
internalPrint("Error: " + str);
}
function callHostFunction(fn) {
var result = fn.apply(undefined, [].slice.call(arguments, 1));
var obj = {};
obj[fn.name] = result;
internalTrace(TRACE_DIAG_OUTPUT, obj);
return result;
}
filterLog = (function () {
var parentFilter = { "this": 1, "locals": 1, "globals": 1 };
var filter = {};
// Discard all known globals to reduce baseline noise.
[
"#__proto__",
"globalThis",
"Array",
"ArrayBuffer",
"Atomics",
"Boolean",
"chWriteTraceEvent",
"CollectGarbage",
"console",
"DataView",
"Date",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"Error",
"escape",
"eval",
"EvalError",
"Float32Array",
"Float64Array",
"Function",
"Infinity",
"Int16Array",
"Int32Array",
"Int8Array",
"Intl",
"isFinite",
"isNaN",
"JSON",
"Map",
"Math",
"NaN",
"Number",
"Object",
"parseFloat",
"parseInt",
"print",
"Promise",
"Proxy",
"RangeError",
"read",
"readbuffer",
"readline",
"ReferenceError",
"Reflect",
"RegExp",
"Set",
"SharedArrayBuffer",
"String",
"Symbol",
"SyntaxError",
"TypeError",
"Uint16Array",
"Uint32Array",
"Uint8Array",
"Uint8ClampedArray",
"undefined",
"unescape",
"URIError",
"WeakMap",
"WeakSet",
"WebAssembly",
"WScript",
].forEach(function (name) {
filter[name] = 1;
});
function filterInternal(parentName, obj, depth) {
for (var p in obj) {
if (parentFilter[parentName] == 1 && filter[p] == 1) {
delete obj[p];
} else if (typeof obj[p] == "object") {
filterInternal(p.trim(), obj[p], depth + 1);
}
}
}
return function (obj) {
try {
filterInternal("this"/*filter root*/, obj, 0);
} catch (ex) {
printError("exception during filter: " + ex);
}
};
})();
function recordEvent(json) {
filterLog(json);
_eventLog.push(json);
}
// remove path from file name and just have the filename with extension
function filterFileName(fileName) {
try {
var index = fileName.lastIndexOf("\\");
if (index >= 0) {
return fileName.substring(index + 1);
}
} catch (ex) { }
return "";
}
var bpManager = (function () {
var _bpMap = [];
var _locBpId = -1;
function getBpFromName(name) {
for (var i in _bpMap) {
if (_bpMap[i].name === name) {
return _bpMap[i];
}
}
printError("Breakpoint named '" + name + "' was not found");
}
function internalSetBp(name, scriptId, line, column, execStr) {
var bpObject = callHostFunction(hostDebugObject.JsDiagSetBreakpoint, scriptId, line, column);
return {
id: bpObject.breakpointId,
scriptId: scriptId,
name: name,
line: bpObject.line,
column: bpObject.column,
execStr: execStr,
enabled: true
};
}
function addBpObject(bpObj) {
internalTrace(TRACE_INTERNAL_FUNCTIONS, "addBpObject: ", bpObj);
_bpMap[bpObj.id] = bpObj;
}
return {
setBreakpoint: function (name, scriptId, line, column, execStr) {
var bpObj = internalSetBp(name, scriptId, line, column, execStr);
addBpObject(bpObj);
},
setLocationBreakpoint: function (name, scriptId, line, column, execStr) {
var bpObj = {
id: _locBpId--,
scriptId: scriptId,
name: name,
line: line,
column: column,
execStr: execStr,
enabled: false
}
addBpObject(bpObj);
},
enableBreakpoint: function (name) {
var bpObj = getBpFromName(name);
if (bpObj) {
delete _bpMap[bpObj.id];
internalTrace(TRACE_INTERNAL_FUNCTIONS, "enableBreakpoint: ", name, " bpObj: ", bpObj);
bpObj = internalSetBp(bpObj.name, bpObj.scriptId, bpObj.line, bpObj.column, bpObj.execStr);
addBpObject(bpObj);
}
},
deleteBreakpoint: function (name) {
var bpObj = getBpFromName(name);
if (bpObj && bpObj.enabled) {
internalTrace(TRACE_INTERNAL_FUNCTIONS, "deleteBreakpoint: ", name, " bpObj: ", bpObj);
callHostFunction(hostDebugObject.JsDiagRemoveBreakpoint, bpObj.id);
delete _bpMap[bpObj.id];
}
},
disableBreakpoint: function (name) {
var bpObj = getBpFromName(name);
if (bpObj && bpObj.enabled) {
internalTrace(TRACE_INTERNAL_FUNCTIONS, "disableBreakpoint: ", name, " bpObj: ", bpObj);
callHostFunction(hostDebugObject.JsDiagRemoveBreakpoint, bpObj.id);
_bpMap[bpObj.id].enabled = false;
}
},
getExecStr: function (id) {
for (var i in _bpMap) {
if (_bpMap[i].id === id) {
return _bpMap[i].execStr;
}
}
printError("Breakpoint '" + id + "' was not found");
},
setExecStr: function (id, newExecStr) {
for (var i in _bpMap) {
if (_bpMap[i].id === id) {
_bpMap[i].execStr = newExecStr;
}
}
},
clearAllBreakpoints: function () {
_bpMap = [];
_locBpId = -1;
}
}
})();
function addSourceFile(text, srcId) {
try {
// Split the text into lines. Note this doesn't take into account block comments, but that's probably okay.
var lines = text.split(/\n/);
// /**bp <-- a breakpoint
// /**loc <-- a named source location used for enabling bp at later stage
// /**exception <-- set exception handling, catch all or only uncaught exception
// /**onasyncbreak <-- set what happens on async break
var bpStartToken = "/**";
var bpStartStrings = ["bp", "loc", "exception", "onasyncbreak"];
var bpEnd = "**/";
// Iterate through each source line, setting any breakpoints.
for (var i = 0; i < lines.length; ++i) {
var line = lines[i];
for (var startString in bpStartStrings) {
var bpStart = bpStartToken + bpStartStrings[startString];
var isLocationBreakpoint = (bpStart.indexOf("loc") != -1);
var isExceptionBreakpoint = (bpStart.indexOf("exception") != -1);
var isOnAsyncBreak = (bpStart.indexOf("onasyncbreak") != -1);
var startIdx = -1;
while ((startIdx = line.indexOf(bpStart, startIdx + 1)) != -1) {
var endIdx;
var currLine = i;
var bpLine = i;
var currBpLineString = "";
// Gather up any lines within the breakpoint comment.
do {
var currentStartIdx = 0;
if (currLine == i) {
currentStartIdx = startIdx;
}
currBpLineString += lines[currLine++];
endIdx = currBpLineString.indexOf(bpEnd, currentStartIdx);
} while (endIdx == -1 && currLine < lines.length && lines[currLine].indexOf(bpStartToken) == -1);
// Move the line cursor forward, allowing the current line to be re-checked
i = currLine - 1;
// Do some checking
if (endIdx == -1) {
printError("Unterminated breakpoint expression");
return;
}
var bpStrStartIdx = startIdx + bpStart.length;
var bpStr = currBpLineString.substring(bpStrStartIdx, endIdx);
var bpFullStr = currBpLineString.substring(startIdx, endIdx);
// Quick check to make sure the breakpoint is not within a
// quoted string (such as an eval). If it is within an eval, the
// eval will cause a separate call to have its breakpoints parsed.
// This check can be defeated, but it should cover the useful scenarios.
var quoteCount = 0;
var escapeCount = 0;
for (var j = 0; j < bpStrStartIdx; ++j) {
switch (currBpLineString[j]) {
case '\\':
escapeCount++;
continue;
case '"':
case '\'':
if (escapeCount % 2 == 0)
quoteCount++;
/* fall through */
default:
escapeCount = 0;
}
}
if (quoteCount % 2 == 1) {
// The breakpoint was in a quoted string.
continue;
}
// Only support strings like:
// /**bp**/
// /**bp(name)**/
// /**bp(columnoffset)**/ takes an integer
// /**bp:locals();stack()**/
// /**bp(name):locals();stack()**/
// /**loc(name)**/
// /**loc(name):locals();stack()**/
//
// Parse the breakpoint name (if it exists)
var bpName = undefined;
var bpColumnOffset = 0;
var bpExecStr = undefined;
var parseIdx = 0;
if (bpStr[parseIdx] == '(') {
// The name and offset is overloaded with the same parameter.
// if that is int (determined by parseInt), then it is column offset otherwise left as name.
bpName = bpStr.match(/\(([\w,]+?)\)/)[1];
parseIdx = bpName.length + 2;
bpColumnOffset = parseInt(bpName);
if (isNaN(bpColumnOffset)) {
bpColumnOffset = 0;
} else {
bpName = undefined;
if (bpColumnOffset > line.length) {
bpColumnOffset = line.length - 1;
} else if (bpColumnOffset < 0) {
bpColumnOffset = 0;
}
}
} else if (isLocationBreakpoint) {
printError("'loc' sites require a label, for example /**loc(myFunc)**/");
return;
}
// Process the exception label:
// exception(none)
// exception(uncaught)
// exception(all)
if (isExceptionBreakpoint) {
var exceptionAttributes = -1;
if (bpName !== undefined) {
if (bpName == "none") {
exceptionAttributes = 0; // JsDiagBreakOnExceptionAttributeNone
} else if (bpName == "uncaught") {
exceptionAttributes = 0x1; // JsDiagBreakOnExceptionAttributeUncaught
} else if (bpName == "firstchance") {
exceptionAttributes = 0x2; // JsDiagBreakOnExceptionAttributeFirstChance
} else if (bpName == "all") {
exceptionAttributes = 0x1 | 0x2; // JsDiagBreakOnExceptionAttributeUncaught | JsDiagBreakOnExceptionAttributeFirstChance
}
} else {
// throw "No exception type specified";
}
callHostFunction(hostDebugObject.JsDiagSetBreakOnException, exceptionAttributes);
}
// Parse the breakpoint execution string
if (bpStr[parseIdx] == ':') {
bpExecStr = bpStr.substring(parseIdx + 1);
} else if (parseIdx != bpStr.length) {
printError("Invalid breakpoint string: " + bpStr);
return;
}
// Insert the breakpoint.
if (isExceptionBreakpoint) {
if (_exceptionCommands != undefined) {
printError("More than one 'exception' annotation found");
return;
}
_exceptionCommands = bpExecStr;
}
if (isOnAsyncBreak) {
if (_onasyncbreakCommands != undefined) {
printError("More than one 'onasyncbreak' annotation found");
return;
}
_onasyncbreakCommands = bpExecStr;
}
if (!isExceptionBreakpoint && !isOnAsyncBreak) {
if (!isLocationBreakpoint) {
bpManager.setBreakpoint(bpName, srcId, bpLine, bpColumnOffset, bpExecStr);
} else {
bpManager.setLocationBreakpoint(bpName, srcId, bpLine, bpColumnOffset, bpExecStr);
}
}
}
}
}
} catch (ex) {
printError(ex);
}
}
function handleBreakpoint(id) {
internalTrace(TRACE_INTERNAL_FUNCTIONS, "handleBreakpoint id: ", id)
_wasResumed = false;
if (id != -1) {
try {
var execStr = "";
if (id === "exception") {
execStr = _exceptionCommands;
if (execStr && execStr.toString().search("removeExpr()") != -1) {
_exceptionCommands = undefined;
}
} else if (id === "asyncbreak") {
execStr = _onasyncbreakCommands;
if (execStr && execStr.toString().search("removeExpr()") != -1) {
_onasyncbreakCommands = undefined;
}
} else if (id === "debuggerStatement") {
execStr = "dumpBreak();locals();stack();"
} else {
// Retrieve this breakpoint's execution string
execStr = bpManager.getExecStr(id);
if (execStr.toString().search("removeExpr()") != -1) {
// A hack to remove entire expression, so that it will not run again.
bpManager.setExecStr(id, null);
}
}
internalTrace(TRACE_INTERNAL_FUNCTIONS, "handleBreakpoint execStr: ", execStr)
if (execStr != null) {
eval(execStr);
}
} catch (ex) {
printError(ex);
}
}
internalTrace(TRACE_INTERNAL_FUNCTIONS, "_commandList length: ", _commandList.length, " _wasResumed: ", _wasResumed);
// Continue processing the command list.
while (_commandList.length > 0 && !_wasResumed) {
var cmd = _commandList.shift();
internalTrace(TRACE_INTERNAL_FUNCTIONS, "cmd: ", cmd);
var completion = cmd.fn.apply(this, cmd.args);
if (typeof completion === "function") {
_commandCompletions.push(completion);
}
}
while (_commandCompletions.length > 0) {
var completion = _commandCompletions.shift();
completion();
}
if (!_wasResumed) {
_currentStackFrameIndex = 0;
_wasResumed = true;
}
}
function GetObjectDisplay(obj) {
var objectDisplay = ("className" in obj) ? obj["className"] : obj["type"];
var value = ("value" in obj) ? obj["value"] : obj["display"];
if (value && value.length > _inspectMaxStringLength) {
objectDisplay += " <large string>";
} else {
objectDisplay += " " + value;
}
return objectDisplay;
}
var stringToArrayBuffer = function stringToArrayBuffer(str) {
var arr = [];
for (var i = 0, len = str.length; i < len; i++) {
arr[i] = str.charCodeAt(i) & 0xFF;
}
return new Uint8Array(arr).buffer;
}
function GetChild(obj, level) {
function GetChildrens(obj, level) {
var retArray = {};
for (var i = 0; i < obj.length; ++i) {
var propName = (obj[i].name == "__proto__") ? "#__proto__" : obj[i].name;
retArray[propName] = GetChild(obj[i], level);
}
return retArray;
}
var retValue = {};
if ("handle" in obj) {
if (level >= 0) {
var childProps = callHostFunction(hostDebugObject.JsDiagGetProperties, obj["handle"], 0, 1000);
var properties = childProps["properties"];
var debuggerOnlyProperties = childProps["debuggerOnlyProperties"];
Array.prototype.push.apply(properties, debuggerOnlyProperties);
if (properties.length > 0) {
retValue = GetChildrens(properties, level - 1);
} else {
retValue = GetObjectDisplay(obj);
}
} else {
retValue = GetObjectDisplay(obj);
}
delete obj["handle"];
}
if ("propertyAttributes" in obj) {
delete obj["propertyAttributes"];
}
return retValue;
}
function compareWithBaseline() {
function compareObjects(a, b, obj_namespace) {
var objectsEqual = true;
// This is a basic object comparison function, primarily to be used for JSON data.
// It doesn't handle cyclical objects.
function fail(step, message) {
if (message == undefined) {
message = "diff baselines for details";
}
printError("Step " + step + "; on: " + obj_namespace + ": " + message);
objectsEqual = false;
}
function failNonObj(step, a, b, message) {
if (message == undefined) {
message = "";
}
printError("Step " + step + "; Local Diff on: " + obj_namespace + ": " + message);
printError("Value 1:" + JSON.stringify(a));
printError("Value 2:" + JSON.stringify(b));
print("");
objectsEqual = false;
}
// (1) Check strict equality.
if (a === b)
return true;
// (2) non-Objects must have passed the strict equality comparison in (1)
if ((typeof a != "object") || (typeof b != "object")) {
failNonObj(2, a, b);
return false;
}
// (3) check all properties
for (var p in a) {
// (4) check the property
if (a[p] === b[p])
continue;
// (5) non-Objects must have passed the strict equality comparison in (4)
if (typeof (a[p]) != "object") {
failNonObj(5, a[p], b[p], "Property " + p);
continue;
}
// (6) recursively check objects or arrays
if (!compareObjects(a[p], b[p], obj_namespace + "." + p)) {
// Don't need to report error message as it'll be reported inside nested call
objectsEqual = false;
continue;
}
}
// (7) check any properties not in the previous enumeration
var hasOwnProperty = Object.prototype.hasOwnProperty;
for (var p in b) {
if (hasOwnProperty.call(b, p) && !hasOwnProperty.call(a, p)) {
fail(7, "Property missing: " + p + ", value: " + JSON.stringify(b[p]));
continue;
}
}
return objectsEqual;
}
var PASSED = 0;
var FAILED = 1;
if (_baseline == undefined) {
return PASSED;
}
try {
if (compareObjects(_baseline, _eventLog, "baseline")) {
return PASSED;
}
}
catch (ex) {
printError("EXCEPTION: " + ex);
}
printError("TEST FAILED");
return FAILED;
}
return {
pushCommand: function pushCommand(fn, args) {
_commandList.push({
fn: fn,
args: args
});
},
debuggerCommands: {
log: function (str) {
internalPrint("LOG: " + str);
},
logJson: function (str) {
recordEvent({ log: str });
},
resume: function (kind) {
if (_wasResumed) {
printError("Breakpoint resumed twice");
} else {
var stepType = -1;
if (kind == "step_into") {
stepType = 0;
} else if (kind == "step_out") {
stepType = 1;
} else if (kind == "step_over") {
stepType = 2;
} else if (kind == "step_document") {
stepType = 0;
}
if (stepType != -1) {
callHostFunction(hostDebugObject.JsDiagSetStepType, stepType);
} else if (kind != "continue") {
throw new Error("Unhandled step type - " + kind);
}
_wasResumed = true;
_currentStackFrameIndex = 0;
}
},
locals: function (expandLevel, flags) {
if (expandLevel == undefined || expandLevel < 0) {
expandLevel = 0;
}
var stackProperties = callHostFunction(hostDebugObject.JsDiagGetStackProperties, _currentStackFrameIndex);
if (expandLevel >= 0) {
var localsJSON = {};
["thisObject", "exception", "arguments", "returnValue"].forEach(function (name) {
if (name in stackProperties) {
var stackObject = stackProperties[name];
localsJSON[stackObject.name] = GetChild(stackObject, expandLevel - 1);
}
});
["functionCallsReturn", "locals"].forEach(function (name) {
if (name in stackProperties) {
var stackObject = stackProperties[name];
if (stackObject.length > 0) {
localsJSON[name] = {};
for (var i = 0; i < stackObject.length; ++i) {
localsJSON[name][stackObject[i].name] = GetChild(stackObject[i], expandLevel - 1);
}
}
}
});
if ("scopes" in stackProperties) {
var scopesArray = stackProperties["scopes"];
for (var i = 0; i < scopesArray.length; ++i) {
localsJSON["scopes" + i] = GetChild(scopesArray[i], expandLevel - 1);
}
}
if ("globals" in stackProperties && expandLevel > 0) {
localsJSON["globals"] = GetChild(stackProperties["globals"], expandLevel - 1);
}
recordEvent(localsJSON);
}
},
stack: function (flags) {
if (flags === undefined) {
flags = 0;
}
var stackTrace = callHostFunction(hostDebugObject.JsDiagGetStackTrace);
var stackTraceArray = [];
for (var i = 0; i < stackTrace.length; ++i) {
var stack = {};
stack["line"] = stackTrace[i].line;
stack["column"] = stackTrace[i].column;
stack["sourceText"] = stackTrace[i].sourceText;
var functionObject = callHostFunction(hostDebugObject.JsDiagGetObjectFromHandle, stackTrace[i].functionHandle);
stack["function"] = functionObject.name;
stackTraceArray.push(stack);
}
recordEvent({
'callStack': stackTraceArray
});
},
evaluate: function (expression, expandLevel, flags) {
if (expression != undefined) {
if (typeof expandLevel != "number" || expandLevel <= 0) {
expandLevel = 0;
}
if (WScript && typeof expression == 'string' && WScript.forceDebugArrayBuffer)
expression = stringToArrayBuffer(expression);
var evalResult = callHostFunction(hostDebugObject.JsDiagEvaluate, _currentStackFrameIndex, expression);
var evaluateOutput = {};
evaluateOutput[evalResult.name] = GetChild(evalResult, expandLevel - 1);
recordEvent({
'evaluate': evaluateOutput
});
}
},
enableBp: function (name) {
bpManager.enableBreakpoint(name);
},
disableBp: function (name) {
bpManager.disableBreakpoint(name);
},
deleteBp: function (name) {
bpManager.deleteBreakpoint(name);
},
setFrame: function (depth) {
var stackTrace = callHostFunction(hostDebugObject.JsDiagGetStackTrace);
for (var i = 0; i < stackTrace.length; ++i) {
if (stackTrace[i].index == depth) {
_currentStackFrameIndex = depth;
break;
}
}
},
dumpBreak: function () {
var breakpoints = callHostFunction(hostDebugObject.JsDiagGetBreakpoints);
recordEvent({
'breakpoints': breakpoints
});
},
dumpSourceList: function () {
var sources = callHostFunction(hostDebugObject.JsDiagGetScripts);
sources.forEach(function (source) {
if ("fileName" in source) {
source["fileName"] = filterFileName(source["fileName"]);
}
});
recordEvent({
'sources': sources
});
},
dumpFunctionProperties: function (frameIdOrArrayOfIds = [0], expandLevel = 0) {
if (typeof frameIdOrArrayOfIds != "number" && !(frameIdOrArrayOfIds instanceof Array)) {
frameIdOrArrayOfIds = [0];
}
if (typeof expandLevel != "number" || expandLevel < 0) {
expandLevel = 0;
}
let stackTrace = callHostFunction(hostDebugObject.JsDiagGetStackTrace);
let functionHandles = [];
let requestedFrameIndexes = [];
if (typeof frameIdOrArrayOfIds === "number") {
requestedFrameIndexes.push(frameIdOrArrayOfIds);
} else if (frameIdOrArrayOfIds instanceof Array) {
frameIdOrArrayOfIds.forEach((s) => {
if (typeof s === "number") {
requestedFrameIndexes.push(s);
}
});
}
if (requestedFrameIndexes.length == 0) {
requestedFrameIndexes.push(0);
}
stackTrace.forEach((stackFrame) => {
let stackFrameIndex = stackFrame.index;
if (requestedFrameIndexes.includes(stackFrameIndex) && !functionHandles.includes(stackFrame.functionHandle)) {
functionHandles.push(stackFrame.functionHandle);
}
});
let functionProperties = [];
functionHandles.forEach((handle) => {
functionProperties.push(GetChild({ handle: handle }, expandLevel));
});
recordEvent({
'functionProperties': functionProperties
});
},
trace: function (traceFlag) {
_trace |= traceFlag;
}
},
setBaseline: function (baseline) {
try {
_baseline = JSON.parse(baseline);
} catch (ex) {
printError("Invalid JSON passed to setBaseline: " + ex);
internalPrint(baseline);
}
},
dumpFunctionPosition: function (functionPosition) {
if (!functionPosition) {
functionPosition = {};
}
else {
functionPosition["fileName"] = filterFileName(functionPosition["fileName"]);
}
recordEvent({
'functionPosition': functionPosition
});
},
setInspectMaxStringLength: function (value) {
_inspectMaxStringLength = value;
},
getOutputJson: function () {
return JSON.stringify(_eventLog, undefined, " ");
},
verify: function () {
return compareWithBaseline();
},
handleDebugEvent: function (debugEvent, eventData) {
function debugEventToString(debugEvent) {
switch (debugEvent) {
case 0:
return "JsDiagDebugEventSourceCompile";
case 1:
return "JsDiagDebugEventCompileError";
case 2:
return "JsDiagDebugEventBreakpoint";
case 3:
return "JsDiagDebugEventStepComplete";
case 4:
return "JsDiagDebugEventDebuggerStatement";
case 5:
return "JsDiagDebugEventAsyncBreak";
case 6:
return "JsDiagDebugEventRuntimeException";
default:
return "UnKnown";
}
}
internalTrace(TRACE_DEBUG_EVENTS, {
'debugEvent': debugEventToString(debugEvent),
'eventData': eventData
});
switch (debugEvent) {
case 0:
/*JsDiagDebugEventSourceCompile*/
var source = callHostFunction(hostDebugObject.JsDiagGetSource, eventData.scriptId);
addSourceFile(source.source, source.scriptId);
break;
case 1:
/*JsDiagDebugEventCompileError*/
var stackTrace = callHostFunction(hostDebugObject.JsDiagGetScripts);
break;
case 2:
/*JsDiagDebugEventBreakpoint*/
case 3:
/*JsDiagDebugEventStepComplete*/
handleBreakpoint(("breakpointId" in eventData) ? eventData.breakpointId : -1);
break;
case 4:
/*JsDiagDebugEventDebuggerStatement*/
handleBreakpoint("debuggerStatement");
break;
case 5:
/*JsDiagDebugEventAsyncBreak*/
handleBreakpoint("asyncbreak");
break;
case 6:
/*JsDiagDebugEventRuntimeException*/
handleBreakpoint("exception");
break;
default:
throw "Unhandled JsDiagDebugEvent value " + debugEvent;
break;
}
},
handleSourceRunDown: function (sources) {
bpManager.clearAllBreakpoints();
for (var len = 0; len < sources.length; ++len) {
var source = callHostFunction(hostDebugObject.JsDiagGetSource, sources[len].scriptId);
addSourceFile(source.source, source.scriptId);
};
},
}
})();
// Commands for use from the breakpoint execution string in test files
function log(str) {
// Prints given string as 'LOG: <given string>' on console
controllerObj.pushCommand(controllerObj.debuggerCommands.log, arguments);
}
function logJson(str) {
// Prints given string on console
controllerObj.pushCommand(controllerObj.debuggerCommands.logJson, arguments);
}
function resume(kind) {
// Resume exceution after a break, kinds - step_into, step_out, step_over
controllerObj.pushCommand(controllerObj.debuggerCommands.resume, arguments);
}
function locals(expandLevel, flags) {
// Dumps locals tree, expand till expandLevel with given flags
controllerObj.pushCommand(controllerObj.debuggerCommands.locals, arguments);
}
function stack() {
controllerObj.pushCommand(controllerObj.debuggerCommands.stack, arguments);
}
function removeExpr(bpId) {
// A workaround to remove the current expression
}
function evaluate(expression, expandLevel, flags) {
controllerObj.pushCommand(controllerObj.debuggerCommands.evaluate, arguments);
}
function enableBp(name) {
controllerObj.pushCommand(controllerObj.debuggerCommands.enableBp, arguments);
}
function disableBp(name) {
controllerObj.pushCommand(controllerObj.debuggerCommands.disableBp, arguments);
}
function deleteBp(name) {
controllerObj.pushCommand(controllerObj.debuggerCommands.deleteBp, arguments);
}
function setFrame(name) {
controllerObj.pushCommand(controllerObj.debuggerCommands.setFrame, arguments);
}
function dumpBreak() {
controllerObj.pushCommand(controllerObj.debuggerCommands.dumpBreak, arguments);
}
function dumpSourceList() {
controllerObj.pushCommand(controllerObj.debuggerCommands.dumpSourceList, arguments);
}
function dumpFunctionProperties() {
controllerObj.pushCommand(controllerObj.debuggerCommands.dumpFunctionProperties, arguments);
}
// Start internal tracing. E.g.: /**bp:trace(TRACE_COMMANDS)**/
function trace() {
controllerObj.pushCommand(controllerObj.debuggerCommands.trace, arguments);
}
// Non Supported - TO BE REMOVED
function setExceptionResume() { }
function setnext() { }
function evaluateAsync() { }
function trackProjectionCall() { }
function mbp() { }
function deleteMbp() { }
// APIs exposed to Debugger.cpp
function GetOutputJson() {
return controllerObj.getOutputJson.apply(controllerObj, arguments);
}
function Verify() {
return controllerObj.verify.apply(controllerObj, arguments);
}
function SetBaseline() {
return controllerObj.setBaseline.apply(controllerObj, arguments);
}
function SetInspectMaxStringLength() {
return controllerObj.setInspectMaxStringLength.apply(controllerObj, arguments);
}
function DumpFunctionPosition() {
return controllerObj.dumpFunctionPosition.apply(controllerObj, arguments);
}
// Called from Debugger.cpp to handle JsDiagDebugEvent
function HandleDebugEvent() {
return controllerObj.handleDebugEvent.apply(controllerObj, arguments);
}
// Called from Debugger.cpp when debugger is attached using WScript.Attach
function HandleSourceRunDown() {
return controllerObj.handleSourceRunDown.apply(controllerObj, arguments);
}