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 33 var DebuggerScript = {}; 34 35 DebuggerScript.PauseOnExceptionsState = { 36 DontPauseOnExceptions : 0, 37 PauseOnAllExceptions : 1, 38 PauseOnUncaughtExceptions: 2 39 }; 40 41 DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions; 42 Debug.clearBreakOnException(); 43 Debug.clearBreakOnUncaughtException(); 44 45 DebuggerScript.getAfterCompileScript = function(eventData) 46 { 47 return DebuggerScript._formatScript(eventData.script_.script_); 48 } 49 50 DebuggerScript.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 65 DebuggerScript.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 87 DebuggerScript._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 99 DebuggerScript.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 111 DebuggerScript.removeBreakpoint = function(execState, args) 112 { 113 Debug.findBreakPoint(args.breakpointId, true); 114 } 115 116 DebuggerScript.pauseOnExceptionsState = function() 117 { 118 return DebuggerScript._pauseOnExceptionsState; 119 } 120 121 DebuggerScript.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 136 DebuggerScript.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 150 DebuggerScript.stepIntoStatement = function(execState) 151 { 152 execState.prepareStep(Debug.StepAction.StepIn, 1); 153 } 154 155 DebuggerScript.stepOverStatement = function(execState) 156 { 157 execState.prepareStep(Debug.StepAction.StepNext, 1); 158 } 159 160 DebuggerScript.stepOutOfFunction = function(execState) 161 { 162 execState.prepareStep(Debug.StepAction.StepOut, 1); 163 } 164 165 DebuggerScript.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 183 DebuggerScript.clearBreakpoints = function(execState, args) 184 { 185 Debug.clearAllBreakPoints(); 186 } 187 188 DebuggerScript.setBreakpointsActivated = function(execState, args) 189 { 190 Debug.debuggerFlags().breakPointsActive.setValue(args.enabled); 191 } 192 193 DebuggerScript._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 268 return DebuggerScript; 269 })(); 270