1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31(function () { 32 33var DebuggerScript = {}; 34 35DebuggerScript.PauseOnExceptionsState = { 36 DontPauseOnExceptions : 0, 37 PauseOnAllExceptions : 1, 38 PauseOnUncaughtExceptions: 2 39}; 40 41DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions; 42Debug.clearBreakOnException(); 43Debug.clearBreakOnUncaughtException(); 44 45DebuggerScript.getAfterCompileScript = function(eventData) 46{ 47 return DebuggerScript._formatScript(eventData.script_.script_); 48} 49 50DebuggerScript.getWorkerScripts = function() 51{ 52 var result = []; 53 var scripts = Debug.scripts(); 54 for (var i = 0; i < scripts.length; ++i) { 55 var script = scripts[i]; 56 // Workers don't share same V8 heap now so there is no need to complicate stuff with 57 // the context id like we do to discriminate between scripts from different pages. 58 // However we need to filter out v8 native scripts. 59 if (script.context_data && script.context_data === "worker") 60 result.push(DebuggerScript._formatScript(script)); 61 } 62 return result; 63} 64 65DebuggerScript.getScripts = function(contextData) 66{ 67 var result = []; 68 69 if (!contextData) 70 return result; 71 var comma = contextData.indexOf(","); 72 if (comma === -1) 73 return result; 74 // Context data is a string in the following format: 75 // ("page"|"injected")","<page id> 76 var idSuffix = contextData.substring(comma); // including the comma 77 78 var scripts = Debug.scripts(); 79 for (var i = 0; i < scripts.length; ++i) { 80 var script = scripts[i]; 81 if (script.context_data && script.context_data.lastIndexOf(idSuffix) != -1) 82 result.push(DebuggerScript._formatScript(script)); 83 } 84 return result; 85} 86 87DebuggerScript._formatScript = function(script) 88{ 89 return { 90 id: script.id, 91 name: script.nameOrSourceURL(), 92 source: script.source, 93 lineOffset: script.line_offset, 94 columnOffset: script.column_offset, 95 isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0 96 }; 97} 98 99DebuggerScript.setBreakpoint = function(execState, args) 100{ 101 var breakId = Debug.setScriptBreakPointById(args.sourceID, args.lineNumber, args.columnNumber, args.condition); 102 103 var locations = Debug.findBreakPointActualLocations(breakId); 104 if (!locations.length) 105 return undefined; 106 args.lineNumber = locations[0].line; 107 args.columnNumber = locations[0].column; 108 return breakId.toString(); 109} 110 111DebuggerScript.removeBreakpoint = function(execState, args) 112{ 113 Debug.findBreakPoint(args.breakpointId, true); 114} 115 116DebuggerScript.pauseOnExceptionsState = function() 117{ 118 return DebuggerScript._pauseOnExceptionsState; 119} 120 121DebuggerScript.setPauseOnExceptionsState = function(newState) 122{ 123 DebuggerScript._pauseOnExceptionsState = newState; 124 125 if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState) 126 Debug.setBreakOnException(); 127 else 128 Debug.clearBreakOnException(); 129 130 if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState) 131 Debug.setBreakOnUncaughtException(); 132 else 133 Debug.clearBreakOnUncaughtException(); 134} 135 136DebuggerScript.currentCallFrame = function(execState, args) 137{ 138 var frameCount = execState.frameCount(); 139 if (frameCount === 0) 140 return undefined; 141 142 var topFrame; 143 for (var i = frameCount - 1; i >= 0; i--) { 144 var frameMirror = execState.frame(i); 145 topFrame = DebuggerScript._frameMirrorToJSCallFrame(frameMirror, topFrame); 146 } 147 return topFrame; 148} 149 150DebuggerScript.stepIntoStatement = function(execState) 151{ 152 execState.prepareStep(Debug.StepAction.StepIn, 1); 153} 154 155DebuggerScript.stepOverStatement = function(execState) 156{ 157 execState.prepareStep(Debug.StepAction.StepNext, 1); 158} 159 160DebuggerScript.stepOutOfFunction = function(execState) 161{ 162 execState.prepareStep(Debug.StepAction.StepOut, 1); 163} 164 165DebuggerScript.editScriptSource = function(scriptId, newSource) 166{ 167 var scripts = Debug.scripts(); 168 var scriptToEdit = null; 169 for (var i = 0; i < scripts.length; i++) { 170 if (scripts[i].id == scriptId) { 171 scriptToEdit = scripts[i]; 172 break; 173 } 174 } 175 if (!scriptToEdit) 176 throw("Script not found"); 177 178 var changeLog = []; 179 Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, false, changeLog); 180 return scriptToEdit.source; 181} 182 183DebuggerScript.clearBreakpoints = function(execState, args) 184{ 185 Debug.clearAllBreakPoints(); 186} 187 188DebuggerScript.setBreakpointsActivated = function(execState, args) 189{ 190 Debug.debuggerFlags().breakPointsActive.setValue(args.enabled); 191} 192 193DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame) 194{ 195 // Get function name. 196 var func; 197 try { 198 func = frameMirror.func(); 199 } catch(e) { 200 } 201 var functionName; 202 if (func) 203 functionName = func.name() || func.inferredName(); 204 205 // Get script ID. 206 var script = func.script(); 207 var sourceID = script && script.id(); 208 209 // Get location. 210 var location = frameMirror.sourceLocation(); 211 212 // Get this object. 213 var thisObject = frameMirror.details_.receiver(); 214 215 // Get scope chain array in format: [<scope type>, <scope object>, <scope type>, <scope object>,...] 216 var scopeChain = []; 217 var scopeType = []; 218 for (var i = 0; i < frameMirror.scopeCount(); i++) { 219 var scopeMirror = frameMirror.scope(i); 220 var scopeObjectMirror = scopeMirror.scopeObject(); 221 222 var scopeObject; 223 switch (scopeMirror.scopeType()) { 224 case ScopeType.Local: 225 case ScopeType.Closure: 226 // For transient objects we create a "persistent" copy that contains 227 // the same properties. 228 scopeObject = {}; 229 // Reset scope object prototype to null so that the proto properties 230 // don't appear in the local scope section. 231 scopeObject.__proto__ = null; 232 var properties = scopeObjectMirror.properties(); 233 for (var j = 0; j < properties.length; j++) { 234 var name = properties[j].name(); 235 if (name.charAt(0) === ".") 236 continue; // Skip internal variables like ".arguments" 237 scopeObject[name] = properties[j].value_; 238 } 239 break; 240 case ScopeType.Global: 241 case ScopeType.With: 242 case ScopeType.Catch: 243 scopeObject = scopeMirror.details_.object(); 244 break; 245 } 246 247 scopeType.push(scopeMirror.scopeType()); 248 scopeChain.push(scopeObject); 249 } 250 251 function evaluate(expression) { 252 return frameMirror.evaluate(expression, false).value(); 253 } 254 255 return { 256 "sourceID": sourceID, 257 "line": location.line, 258 "column": location.column, 259 "functionName": functionName, 260 "thisObject": thisObject, 261 "scopeChain": scopeChain, 262 "scopeType": scopeType, 263 "evaluate": evaluate, 264 "caller": callerFrame 265 }; 266} 267 268return DebuggerScript; 269})(); 270