bugs 119827 and 100677, a=drivers Disable debug target, enable debugger for all execution hooks. git-svn-id: svn://10.0.0.236/trunk@116459 18797224-902f-48f8-a5cc-f745e15eee43
935 lines
27 KiB
JavaScript
935 lines
27 KiB
JavaScript
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is The JavaScript Debugger
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation
|
|
* Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation.
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU Public License (the "GPL"), in which case the
|
|
* provisions of the GPL are applicable instead of those above.
|
|
* If you wish to allow use of your version of this file only
|
|
* under the terms of the GPL and not to allow others to use your
|
|
* version of this file under the MPL, indicate your decision by
|
|
* deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this
|
|
* file under either the MPL or the GPL.
|
|
*
|
|
* Contributor(s):
|
|
* Robert Ginda, <rginda@netscape.com>, original author
|
|
*
|
|
*/
|
|
|
|
const JSD_CTRID = "@mozilla.org/js/jsd/debugger-service;1";
|
|
const jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
|
|
const jsdIExecutionHook = Components.interfaces.jsdIExecutionHook;
|
|
const jsdIErrorHook = Components.interfaces.jsdIErrorHook;
|
|
const jsdICallHook = Components.interfaces.jsdICallHook;
|
|
const jsdIValue = Components.interfaces.jsdIValue;
|
|
const jsdIProperty = Components.interfaces.jsdIProperty;
|
|
const jsdIScript = Components.interfaces.jsdIScript;
|
|
const jsdIStackFrame = Components.interfaces.jsdIStackFrame;
|
|
const jsdIFilter = Components.interfaces.jsdIFilter;
|
|
|
|
const COLLECT_PROFILE_DATA = jsdIDebuggerService.COLLECT_PROFILE_DATA;
|
|
|
|
const PCMAP_SOURCETEXT = jsdIScript.PCMAP_SOURCETEXT;
|
|
const PCMAP_PRETTYPRINT = jsdIScript.PCMAP_PRETTYPRINT;
|
|
|
|
const FTYPE_STD = 0;
|
|
const FTYPE_SUMMARY = 1;
|
|
const FTYPE_ARRAY = 2;
|
|
|
|
const FILTER_ENABLED = jsdIFilter.FLAG_ENABLED;
|
|
const FILTER_DISABLED = ~jsdIFilter.FLAG_ENABLED;
|
|
const FILTER_PASS = jsdIFilter.FLAG_PASS;
|
|
const FILTER_SYSTEM = 0x100; /* system filter, do not show in UI */
|
|
|
|
var $ = new Array(); /* array to store results from evals in debug frames */
|
|
|
|
console._scriptHook = {
|
|
onScriptCreated: realizeScript,
|
|
onScriptDestroyed: unrealizeScript
|
|
};
|
|
|
|
console._executionHook = {onExecute: vnk_exehook};
|
|
function vnk_exehook (frame, type, rv)
|
|
{
|
|
var hookReturn = jsdIExecutionHook.RETURN_CONTINUE;
|
|
|
|
if (!ASSERT(!("frames" in console), "Execution hook called while stopped") ||
|
|
frame.isNative ||
|
|
!ASSERT(frame.script, "Execution hook called with no script") ||
|
|
frame.script.fileName == MSG_VAL_CONSOLE)
|
|
{
|
|
return hookReturn;
|
|
}
|
|
|
|
var targetWindow = null;
|
|
var wasModal = false;
|
|
var ex;
|
|
var cx;
|
|
|
|
try
|
|
{
|
|
cx = frame.executionContext;
|
|
}
|
|
catch (ex)
|
|
{
|
|
dd ("no context");
|
|
cx = null;
|
|
}
|
|
|
|
var targetWasEnabled = true;
|
|
var debuggerWasEnabled = console.debuggerWindow.enabled;
|
|
console.debuggerWindow.enabled = true;
|
|
|
|
if (cx)
|
|
{
|
|
cx.scriptsEnabled = false;
|
|
var glob = cx.globalObject;
|
|
if (glob)
|
|
{
|
|
console.targetWindow =
|
|
getBaseWindowFromWindow(glob.getWrappedValue());
|
|
targetWasEnabled = console.targetWindow.enabled;
|
|
console.targetWindow.enabled = false;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
hookReturn = debugTrap(frame, type, rv);
|
|
}
|
|
catch (ex)
|
|
{
|
|
display (MSG_ERR_INTERNAL_BPT, MT_ERROR);
|
|
display (formatException(ex), MT_ERROR);
|
|
}
|
|
|
|
if (cx)
|
|
{
|
|
cx.scriptsEnabled = true;
|
|
if (0 && targetWindow)
|
|
{
|
|
targetWindow.enabled = true;
|
|
if (wasModal)
|
|
targetWindow.modalMien = true;
|
|
}
|
|
}
|
|
|
|
if (console.targetWindow)
|
|
console.targetWindow.enabled = targetWasEnabled;
|
|
console.debuggerWindow.enabled = debuggerWasEnabled;
|
|
delete console.frames;
|
|
delete console.targetWindow;
|
|
if ("__exitAfterContinue__" in console)
|
|
window.close();
|
|
|
|
return hookReturn;
|
|
}
|
|
|
|
console._callHook = {
|
|
onCall: function callhook (frame, type) {
|
|
if (type == jsdICallHook.TYPE_FUNCTION_CALL)
|
|
{
|
|
setStopState(false);
|
|
++console._stepOverLevel;
|
|
}
|
|
else if (type == jsdICallHook.TYPE_FUNCTION_RETURN)
|
|
{
|
|
if (--console._stepOverLevel <= 0)
|
|
{
|
|
setStopState(true);
|
|
console.jsds.functionHook = null;
|
|
}
|
|
}
|
|
dd ("Call Hook: " + frame.functionName + ", type " +
|
|
type + " callCount: " + console._stepOverLevel);
|
|
}
|
|
};
|
|
|
|
console._errorHook = {
|
|
onError: function errorhook (message, fileName, line, pos, flags,
|
|
exception) {
|
|
try {
|
|
var flagstr;
|
|
flagstr =
|
|
(flags && jsdIErrorHook.REPORT_EXCEPTION) ? "x" : "-";
|
|
flagstr +=
|
|
(flags && jsdIErrorHook.REPORT_STRICT) ? "s" : "-";
|
|
|
|
//dd ("===\n" + message + "\n" + fileName + "@" +
|
|
// line + ":" + pos + "; " + flagstr);
|
|
var msn = (flags & jsdIErrorHook.REPORT_WARNING) ?
|
|
MSN_ERPT_WARN : MSN_ERPT_ERROR;
|
|
|
|
if (console.errorMode != EMODE_IGNORE)
|
|
display (getMsg(msn, [message, flagstr, fileName,
|
|
line, pos]), MT_ETRACE);
|
|
|
|
if (console.errorMode == EMODE_BREAK)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
catch (ex)
|
|
{
|
|
dd ("error in error hook: " + ex);
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
function initDebugger()
|
|
{
|
|
dd ("initDebugger {");
|
|
|
|
console._continueCodeStack = new Array(); /* top of stack is the default */
|
|
/* return code for the most */
|
|
/* recent debugTrap(). */
|
|
console.scripts = new Object();
|
|
|
|
/* create the debugger instance */
|
|
if (!Components.classes[JSD_CTRID])
|
|
throw new BadMojo (ERR_NO_DEBUGGER);
|
|
|
|
console.jsds = Components.classes[JSD_CTRID].getService(jsdIDebuggerService);
|
|
console.jsds.on();
|
|
console.jsds.breakpointHook = console._executionHook;
|
|
console.jsds.debuggerHook = console._executionHook;
|
|
console.jsds.debugHook = console._executionHook;
|
|
console.jsds.errorHook = console._errorHook;
|
|
console.jsds.scriptHook = console._scriptHook;
|
|
console.jsds.flags = jsdIDebuggerService.ENABLE_NATIVE_FRAMES;
|
|
|
|
console.chromeFilter = {
|
|
globalObject: null,
|
|
flags: FILTER_SYSTEM | FILTER_ENABLED,
|
|
urlPattern: "chrome:*",
|
|
startLine: 0,
|
|
endLine: 0
|
|
};
|
|
|
|
if (console.prefs["enableChromeFilter"])
|
|
{
|
|
console.enableChromeFilter = true;
|
|
console.jsds.appendFilter(console.chromeFilter);
|
|
}
|
|
else
|
|
console.enableChromeFilter = false;
|
|
|
|
var venkmanFilter1 = { /* glob based filter goes first, because it's the */
|
|
globalObject: this, /* easiest to match. */
|
|
flags: FILTER_SYSTEM | FILTER_ENABLED,
|
|
urlPattern: null,
|
|
startLine: 0,
|
|
endLine: 0
|
|
};
|
|
var venkmanFilter2 = { /* url based filter for XPCOM callbacks that may */
|
|
globalObject: null, /* not happen under our glob. */
|
|
flags: FILTER_SYSTEM | FILTER_ENABLED,
|
|
urlPattern: "chrome://venkman/*",
|
|
startLine: 0,
|
|
endLine: 0
|
|
};
|
|
console.jsds.appendFilter (venkmanFilter1);
|
|
console.jsds.appendFilter (venkmanFilter2);
|
|
|
|
console.throwMode = TMODE_IGNORE;
|
|
console.errorMode = EMODE_IGNORE;
|
|
|
|
var enumer = {
|
|
enumerateScript: function _es (script) {
|
|
realizeScript(script);
|
|
}
|
|
};
|
|
|
|
console.scriptsView.freeze();
|
|
console.jsds.enumerateScripts(enumer);
|
|
console.scriptsView.thaw();
|
|
|
|
dd ("} initDebugger");
|
|
}
|
|
|
|
function detachDebugger()
|
|
{
|
|
if ("frames" in console)
|
|
console.jsds.exitNestedEventLoop();
|
|
|
|
console.jsds.topLevelHook = null;
|
|
console.jsds.functionHook = null;
|
|
console.jsds.breakpointHook = null;
|
|
console.jsds.debuggerHook = null;
|
|
console.jsds.errorHook = null;
|
|
console.jsds.scriptHook = null;
|
|
console.jsds.interruptHook = null;
|
|
console.jsds.clearAllBreakpoints();
|
|
console.jsds.clearFilters();
|
|
if (!console.jsds.initAtStartup)
|
|
console.jsds.off();
|
|
}
|
|
|
|
function isURLFiltered (url)
|
|
{
|
|
return (!url || url == MSG_VAL_CONSOLE ||
|
|
(console.enableChromeFilter && url.indexOf ("chrome:") == 0) ||
|
|
url.indexOf ("x-jsd:internal") == 0);
|
|
}
|
|
|
|
function realizeScript(script)
|
|
{
|
|
var container;
|
|
if (script.fileName in console.scripts)
|
|
{
|
|
container = console.scripts[script.fileName];
|
|
if (!("parentRecord" in container))
|
|
{
|
|
/* container record exists but is not inserted in the scripts view,
|
|
* either we are reloading it, or the user added it manually */
|
|
if (!isURLFiltered(script.fileName))
|
|
console.scriptsView.childData.appendChild(container);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
container = console.scripts[script.fileName] =
|
|
new ScriptContainerRecord (script.fileName);
|
|
container.reserveChildren();
|
|
if (!isURLFiltered(script.fileName))
|
|
console.scriptsView.childData.appendChild(container);
|
|
}
|
|
|
|
var scriptRec = new ScriptRecord (script);
|
|
if ("dbgRealize" in console && console.dbgRealize)
|
|
{
|
|
dd ("new scriptrecord: " + formatScript(script) + "\n" +
|
|
script.functionSource);
|
|
}
|
|
|
|
container.appendScriptRecord (scriptRec);
|
|
/* check to see if this script contains a breakpoint */
|
|
for (var i = 0; i < console.breakpoints.childData.length; ++i)
|
|
{
|
|
var bpr = console.breakpoints.childData[i];
|
|
if (bpr.matchesScriptRecord(scriptRec))
|
|
{
|
|
if (bpr.fileName == scriptRec.script.fileName)
|
|
{
|
|
/* if the names match exactly, piggyback the new script record
|
|
* on the existing breakpoint record. */
|
|
bpr.addScriptRecord(scriptRec);
|
|
}
|
|
else
|
|
{
|
|
/* otherwise, we only matched a pattern, create a new breakpoint
|
|
* record. */
|
|
setBreakpoint (scriptRec.script.fileName, bpr.line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function unrealizeScript(script)
|
|
{
|
|
var container = console.scripts[script.fileName];
|
|
if (!container)
|
|
{
|
|
dd ("unrealizeScript: unknown file ``" +
|
|
script.fileName + "''");
|
|
return;
|
|
}
|
|
|
|
if ("dbgRealize" in console && console.dbgRealize)
|
|
dd ("remove scriptrecord: " + formatScript(script));
|
|
|
|
var scriptRec = container.locateChildByScript (script);
|
|
if (!scriptRec)
|
|
{
|
|
dd ("unrealizeScript: unable to locate script record");
|
|
return;
|
|
}
|
|
|
|
if (console.sourceView.provider == scriptRec)
|
|
console.sourceView.setCurrentSourceProvider(scriptRec.parentRecord);
|
|
|
|
var bplist = console.breakpoints.childData;
|
|
for (var i = 0; i < bplist.length; ++i)
|
|
{
|
|
if (bplist[i].fileName == script.fileName)
|
|
{
|
|
var bpr = bplist[i];
|
|
for (var j = 0; j < bpr.scriptRecords.length; ++j)
|
|
{
|
|
if (bpr.scriptRecords[j] == scriptRec)
|
|
{
|
|
arrayRemoveAt(bpr.scriptRecords, j);
|
|
--scriptRec.bpcount;
|
|
bpr.invalidate();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
container.removeChildAtIndex (scriptRec.childIndex);
|
|
if (container.childData.length == 0 && "parentRecord" in container)
|
|
{
|
|
console.scriptsView.childData.removeChildAtIndex(container.childIndex);
|
|
}
|
|
}
|
|
|
|
const EMODE_IGNORE = 0;
|
|
const EMODE_TRACE = 1;
|
|
const EMODE_BREAK = 2;
|
|
|
|
const TMODE_IGNORE = 0;
|
|
const TMODE_TRACE = 1;
|
|
const TMODE_BREAK = 2;
|
|
|
|
function debugTrap (frame, type, rv)
|
|
{
|
|
var tn = "";
|
|
var retcode = jsdIExecutionHook.RETURN_CONTINUE;
|
|
|
|
$ = new Array();
|
|
|
|
switch (type)
|
|
{
|
|
case jsdIExecutionHook.TYPE_BREAKPOINT:
|
|
tn = MSG_WORD_BREAKPOINT;
|
|
break;
|
|
case jsdIExecutionHook.TYPE_DEBUG_REQUESTED:
|
|
tn = MSG_WORD_DEBUG;
|
|
break;
|
|
case jsdIExecutionHook.TYPE_DEBUGGER_KEYWORD:
|
|
tn = MSG_WORD_DEBUGGER;
|
|
break;
|
|
case jsdIExecutionHook.TYPE_THROW:
|
|
display (getMsg(MSN_EXCP_TRACE, [formatValue(rv.value),
|
|
formatFrame(frame)]), MT_ETRACE);
|
|
if (rv.value.jsClassName == "Error")
|
|
display (formatProperty(rv.value.getProperty("message")));
|
|
|
|
if (console.throwMode != TMODE_BREAK)
|
|
return jsdIExecutionHook.RETURN_CONTINUE_THROW;
|
|
|
|
$[0] = rv.value;
|
|
retcode = jsdIExecutionHook.RETURN_CONTINUE_THROW;
|
|
tn = MSG_WORD_THROW;
|
|
break;
|
|
case jsdIExecutionHook.TYPE_INTERRUPTED:
|
|
var line;
|
|
if (console.sourceView.prettyPrint)
|
|
line = frame.script.pcToLine (frame.pc, PCMAP_PRETTYPRINT);
|
|
else
|
|
line = frame.line;
|
|
if (console._stepPast == frame.script.fileName + line)
|
|
return jsdIExecutionHook.RETURN_CONTINUE;
|
|
delete console._stepPast;
|
|
setStopState(false);
|
|
break;
|
|
default:
|
|
/* don't print stop/cont messages for other types */
|
|
}
|
|
|
|
console.jsds.functionHook = null;
|
|
|
|
/* set our default return value */
|
|
console._continueCodeStack.push (retcode);
|
|
|
|
if (tn)
|
|
display (getMsg(MSN_STOP, tn), MT_STOP);
|
|
if (0 in $)
|
|
display (getMsg(MSN_FMT_TMP_ASSIGN, [0, formatValue ($[0])]),
|
|
MT_FEVAL_OUT);
|
|
|
|
/* build an array of frames */
|
|
console.frames = new Array(frame);
|
|
|
|
console.stackView.stack.unHide();
|
|
console.stackView.stack.open();
|
|
var frameRec = new FrameRecord(frame);
|
|
console.stackView.stack.appendChild (frameRec);
|
|
|
|
while ((frame = frame.callingFrame))
|
|
{
|
|
console.stackView.stack.appendChild (new FrameRecord(frame));
|
|
console.frames.push(frame);
|
|
}
|
|
|
|
console.trapType = type;
|
|
window.focus();
|
|
window.getAttention();
|
|
|
|
console.jsds.enterNestedEventLoop({onNest: console.onDebugTrap});
|
|
|
|
/* execution pauses here until someone calls
|
|
* console.dbg.exitNestedEventLoop()
|
|
*/
|
|
|
|
clearCurrentFrame();
|
|
delete console.frames;
|
|
delete console.trapType;
|
|
rv.value = (0 in $) ? $[0] : null;
|
|
$ = new Array();
|
|
|
|
console.onDebugContinue();
|
|
|
|
if (tn)
|
|
display (getMsg(MSN_CONT, tn), MT_CONT);
|
|
|
|
return console._continueCodeStack.pop();
|
|
}
|
|
|
|
function getCurrentFrame()
|
|
{
|
|
return console.frames[console._currentFrameIndex];
|
|
}
|
|
|
|
function getCurrentFrameIndex()
|
|
{
|
|
if (typeof console._currentFrameIndex == "undefined")
|
|
return -1;
|
|
|
|
return console._currentFrameIndex;
|
|
}
|
|
|
|
function setCurrentFrameByIndex (index)
|
|
{
|
|
if (!console.frames)
|
|
throw new BadMojo (ERR_NO_STACK);
|
|
|
|
ASSERT (index >= 0 && index < console.frames.length, "index out of range");
|
|
|
|
console._currentFrameIndex = index;
|
|
var cf = console.frames[console._currentFrameIndex];
|
|
console.stopFile = (cf.isNative) ? MSG_URL_NATIVE : cf.script.fileName;
|
|
console.stopLine = cf.line;
|
|
delete console._pp_stopLine;
|
|
console.onFrameChanged (cf, console._currentFrameIndex);
|
|
|
|
return cf;
|
|
}
|
|
|
|
function clearCurrentFrame ()
|
|
{
|
|
if (!console.frames)
|
|
throw new BadMojo (ERR_NO_STACK);
|
|
|
|
delete console.stopLine;
|
|
delete console._pp_stopLine;
|
|
delete console.stopFile;
|
|
delete console._currentFrameIndex;
|
|
console.onFrameChanged (null, 0);
|
|
}
|
|
|
|
function findNextExecutableLine (script, line)
|
|
{
|
|
var pc = script.lineToPc (line + 1, PCMAP_SOURCETEXT);
|
|
|
|
}
|
|
|
|
function formatArguments (v)
|
|
{
|
|
if (!v)
|
|
return "";
|
|
|
|
var ary = new Array();
|
|
var p = new Object();
|
|
v.getProperties (p, {});
|
|
p = p.value;
|
|
for (var i = 0; i < p.length; ++i)
|
|
{
|
|
if (p[i].flags & jsdIProperty.FLAG_ARGUMENT)
|
|
ary.push (getMsg(MSN_FMT_ARGUMENT,
|
|
[p[i].name.stringValue,
|
|
formatValue(p[i].value, FTYPE_SUMMARY)]));
|
|
}
|
|
|
|
return ary.join (MSG_COMMASP);
|
|
}
|
|
|
|
function formatFlags (flags)
|
|
{
|
|
var s = "";
|
|
|
|
if (flags & jsdIProperty.FLAG_ENUMERATE)
|
|
s += MSG_VF_ENUMERABLE;
|
|
if (flags & jsdIProperty.FLAG_READONLY)
|
|
s += MSG_VF_READONLY;
|
|
if (flags & jsdIProperty.FLAG_PERMANENT)
|
|
s += MSG_VF_PERMANENT;
|
|
if (flags & jsdIProperty.FLAG_ALIAS)
|
|
s += MSG_VF_ALIAS;
|
|
if (flags & jsdIProperty.FLAG_ARGUMENT)
|
|
s += MSG_VF_ARGUMENT;
|
|
if (flags & jsdIProperty.FLAG_VARIABLE)
|
|
s += MSG_VF_VARIABLE;
|
|
if (flags & jsdIProperty.FLAG_HINTED)
|
|
s += MSG_VF_HINTED;
|
|
|
|
return s;
|
|
}
|
|
|
|
function formatProperty (p, formatType)
|
|
{
|
|
if (!p)
|
|
throw new BadMojo (ERR_REQUIRED_PARAM, "p");
|
|
|
|
var s = formatFlags (p.flags);
|
|
|
|
if (formatType == FTYPE_ARRAY)
|
|
{
|
|
var rv = formatValue (p.value, FTYPE_ARRAY);
|
|
return [p.name.stringValue, rv[1] ? rv[1] : rv[0], rv[2], s];
|
|
}
|
|
|
|
return getMsg(MSN_FMT_PROPERTY, [s, p.name.stringValue,
|
|
formatValue(p.value)]);
|
|
}
|
|
|
|
function formatScript (script)
|
|
{
|
|
if (!script)
|
|
throw new BadMojo (ERR_REQUIRED_PARAM, "script");
|
|
|
|
return getMsg (MSN_FMT_SCRIPT, [script.functionName, script.fileName]);
|
|
}
|
|
|
|
function formatFrame (f)
|
|
{
|
|
if (!f)
|
|
throw new BadMojo (ERR_REQUIRED_PARAM, "f");
|
|
var url = (f.isNative) ? MSG_URL_NATIVE : f.script.fileName;
|
|
return getMsg (MSN_FMT_FRAME,
|
|
[f.functionName, formatArguments(f.scope), url, f.line]);
|
|
}
|
|
|
|
function formatValue (v, formatType)
|
|
{
|
|
if (!v)
|
|
throw new BadMojo (ERR_REQUIRED_PARAM, "v");
|
|
|
|
if (!(v instanceof jsdIValue))
|
|
throw new BadMojo (ERR_INVALID_PARAM, "v", String(v));
|
|
|
|
var type;
|
|
var value;
|
|
|
|
switch (v.jsType)
|
|
{
|
|
case jsdIValue.TYPE_BOOLEAN:
|
|
type = MSG_TYPE_BOOLEAN;
|
|
value = String(v.booleanValue);
|
|
break;
|
|
case jsdIValue.TYPE_DOUBLE:
|
|
type = MSG_TYPE_DOUBLE;
|
|
value = v.doubleValue;
|
|
break;
|
|
case jsdIValue.TYPE_INT:
|
|
type = MSG_TYPE_INT;
|
|
value = v.intValue;
|
|
break;
|
|
case jsdIValue.TYPE_FUNCTION:
|
|
type = MSG_TYPE_FUNCTION;
|
|
value = v.jsFunctionName;
|
|
break;
|
|
case jsdIValue.TYPE_NULL:
|
|
type = MSG_TYPE_NULL;
|
|
value = MSG_TYPE_NULL;
|
|
break;
|
|
case jsdIValue.TYPE_OBJECT:
|
|
if (formatType == FTYPE_STD)
|
|
{
|
|
type = MSG_TYPE_OBJECT;
|
|
value = getMsg(MSN_FMT_OBJECT, String(v.propertyCount));
|
|
}
|
|
else
|
|
{
|
|
if (v.jsClassName)
|
|
if (v.jsClassName == "XPCWrappedNative_NoHelper")
|
|
type = MSG_CLASS_XPCOBJ;
|
|
else
|
|
type = v.jsClassName;
|
|
else
|
|
type = MSG_TYPE_OBJECT;
|
|
value = "{" + String(v.propertyCount) + "}";
|
|
}
|
|
break;
|
|
case jsdIValue.TYPE_STRING:
|
|
type = MSG_TYPE_STRING;
|
|
value = v.stringValue.quote();
|
|
break;
|
|
case jsdIValue.TYPE_VOID:
|
|
type = MSG_TYPE_VOID;
|
|
value = MSG_TYPE_VOID;
|
|
break;
|
|
default:
|
|
type = MSG_TYPE_UNKNOWN;
|
|
value = MSG_TYPE_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
if (formatType == FTYPE_SUMMARY)
|
|
return getMsg (MSN_FMT_VALUE_SHORT, [type, value]);
|
|
|
|
var className;
|
|
if (v.jsClassName)
|
|
if (v.jsClassName == "XPCWrappedNative_NoHelper")
|
|
/* translate this long, unintuitive, and common class name into
|
|
* something more palatable. */
|
|
className = MSG_CLASS_XPCOBJ;
|
|
else
|
|
className = v.jsClassName;
|
|
|
|
if (formatType == FTYPE_ARRAY)
|
|
return [type, className, value];
|
|
|
|
if (className)
|
|
return getMsg (MSN_FMT_VALUE_LONG, [type, v.jsClassName, value]);
|
|
|
|
return getMsg (MSN_FMT_VALUE_MED, [type, value]);
|
|
|
|
}
|
|
|
|
function displayCallStack ()
|
|
{
|
|
for (var i = 0; i < console.frames.length; ++i)
|
|
displayFrame (console.frames[i], i);
|
|
}
|
|
|
|
function displayProperties (v)
|
|
{
|
|
if (!v)
|
|
throw new BadMojo (ERR_REQUIRED_PARAM, "v");
|
|
|
|
if (!(v instanceof jsdIValue))
|
|
throw new BadMojo (ERR_INVALID_PARAM, "v", String(v));
|
|
|
|
var p = new Object();
|
|
v.getProperties (p, {});
|
|
for (var i in p.value) display(formatProperty (p.value[i]));
|
|
}
|
|
|
|
function displaySource (url, line, contextLines)
|
|
{
|
|
function onSourceLoaded (status)
|
|
{
|
|
if (status == Components.results.NS_OK)
|
|
displaySource (url, line, contextLines);
|
|
}
|
|
|
|
var rec = console.scripts[url];
|
|
|
|
if (!rec)
|
|
{
|
|
display (getMsg(MSN_ERR_NO_SCRIPT, url), MT_ERROR);
|
|
return;
|
|
}
|
|
|
|
var sourceText = rec.sourceText;
|
|
|
|
if (sourceText.isLoaded)
|
|
for (var i = line - contextLines; i <= line + contextLines; ++i)
|
|
{
|
|
if (i > 0 && i < sourceText.lines.length)
|
|
{
|
|
display (getMsg(MSN_SOURCE_LINE, [zeroPad (i, 3),
|
|
sourceText.lines[i - 1]]),
|
|
i == line ? MT_STEP : MT_SOURCE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sourceText.loadSource (onSourceLoaded);
|
|
}
|
|
}
|
|
|
|
function displayFrame (f, idx, showSource)
|
|
{
|
|
if (!f)
|
|
throw new BadMojo (ERR_REQUIRED_PARAM, "f");
|
|
|
|
if (typeof idx == "undefined")
|
|
{
|
|
for (idx = 0; idx < console.frames.length; ++idx)
|
|
if (f == console.frames[idx])
|
|
break;
|
|
|
|
if (idx >= console.frames.length)
|
|
idx = MSG_VAL_UNKNOWN;
|
|
}
|
|
|
|
if (typeof idx == "number")
|
|
idx = "#" + idx;
|
|
|
|
display(idx + ": " + formatFrame (f));
|
|
if (!f.isNative && f.script.fileName && showSource)
|
|
displaySource (f.script.fileName, f.line, 2);
|
|
}
|
|
|
|
function getBreakpoint (fileName, line)
|
|
{
|
|
return console.breakpoints.locateChildByFileLine (fileName, line);
|
|
}
|
|
|
|
function disableBreakpoint (fileName, line)
|
|
{
|
|
var bpr = console.breakpoints.locateChildByFileLine (fileName, line);
|
|
if (!bpr)
|
|
{
|
|
display (getMsg(MSN_ERR_BP_NODICE, [fileName, line]), MT_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
return disableBreakpointByNumber (bpr.childIndex);
|
|
}
|
|
|
|
function disableBreakpointByNumber (number)
|
|
{
|
|
var bpr = console.breakpoints.childData[number];
|
|
if (!bpr)
|
|
{
|
|
display (getMsg(MSN_ERR_BP_NOINDEX, number, MT_ERROR));
|
|
return;
|
|
}
|
|
|
|
bpr.enabled = false;
|
|
display (getMsg(MSN_BP_DISABLED, [bpr.fileName, bpr.line,
|
|
bpr.scriptMatches]));
|
|
}
|
|
|
|
function clearBreakpoint (fileName, line)
|
|
{
|
|
var bpr = console.breakpoints.locateChildByFileLine (fileName, line);
|
|
if (!bpr)
|
|
{
|
|
display (getMsg(MSN_ERR_BP_NODICE, [fileName, line]), MT_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
return clearBreakpointByNumber (bpr.childIndex);
|
|
}
|
|
|
|
function clearBreakpointByNumber (number)
|
|
{
|
|
var bpr = console.breakpoints.childData[number];
|
|
if (!bpr)
|
|
{
|
|
display (getMsg(MSN_ERR_BP_NOINDEX, number, MT_ERROR));
|
|
return null;
|
|
}
|
|
|
|
bpr.enabled = false;
|
|
|
|
var fileName = bpr.fileName;
|
|
var line = bpr.line;
|
|
|
|
var sourceText;
|
|
|
|
if (fileName in console.scripts)
|
|
sourceText = console.scripts[fileName].sourceText;
|
|
else if (fileName in console.files)
|
|
sourceText = console.files[fileName];
|
|
|
|
if (sourceText && sourceText.isLoaded && sourceText.lines[line - 1])
|
|
{
|
|
delete sourceText.lines[line - 1].bpRecord;
|
|
if (console.sourceView.childData.fileName == fileName)
|
|
console.sourceView.outliner.invalidateRow (line - 1);
|
|
}
|
|
|
|
console.breakpoints.removeChildAtIndex(number);
|
|
return bpr;
|
|
}
|
|
|
|
function setBreakpoint (fileName, line)
|
|
{
|
|
var scriptRec = console.scripts[fileName];
|
|
|
|
if (!scriptRec)
|
|
{
|
|
display (getMsg(MSN_ERR_NOSCRIPT, fileName), MT_ERROR);
|
|
return null;
|
|
}
|
|
|
|
var bpr = console.breakpoints.locateChildByFileLine (fileName, line);
|
|
if (bpr)
|
|
{
|
|
display (getMsg(MSN_BP_EXISTS, [fileName, line]), MT_INFO);
|
|
return null;
|
|
}
|
|
|
|
bpr = new BPRecord (fileName, line);
|
|
|
|
var ary = scriptRec.childData;
|
|
var found = false;
|
|
|
|
for (var i = 0; i < ary.length; ++i)
|
|
{
|
|
if (ary[i].containsLine(line) &&
|
|
ary[i].script.isLineExecutable(line, PCMAP_SOURCETEXT))
|
|
{
|
|
found = true;
|
|
bpr.addScriptRecord(ary[i]);
|
|
}
|
|
}
|
|
|
|
var matches = bpr.scriptMatches;
|
|
if (!matches)
|
|
{
|
|
display (getMsg(MSN_ERR_BP_NOLINE, [fileName, line]), MT_ERROR);
|
|
return null;
|
|
}
|
|
|
|
if (scriptRec.sourceText.isLoaded &&
|
|
scriptRec.sourceText.lines[line - 1])
|
|
{
|
|
scriptRec.sourceText.lines[line - 1].bpRecord = bpr;
|
|
if (console.sourceView.childData.fileName == fileName)
|
|
console.sourceView.outliner.invalidateRow (line - 1);
|
|
}
|
|
|
|
console.breakpoints.appendChild (bpr);
|
|
return bpr;
|
|
}
|
|
|
|
function setFutureBreakpoint (filePattern, line)
|
|
{
|
|
var bpr = console.breakpoints.locateChildByFileLine (filePattern, line);
|
|
if (bpr)
|
|
{
|
|
display (getMsg(MSN_BP_EXISTS, [filePattern, line]), MT_INFO);
|
|
return null;
|
|
}
|
|
|
|
bpr = new BPRecord (filePattern, line);
|
|
|
|
if (filePattern in console.files)
|
|
{
|
|
var sourceText = console.files[filePattern];
|
|
if (sourceText.isLoaded)
|
|
{
|
|
sourceText.lines[line - 1].bpRecord = bpr;
|
|
if (console.sourceView.childData.fileName == filePattern)
|
|
console.sourceView.outliner.invalidateRow (line - 1);
|
|
}
|
|
}
|
|
|
|
console.breakpoints.appendChild (bpr);
|
|
return bpr;
|
|
}
|