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 /** 32 * @fileoverview Provides communication interface to remote v8 debugger. See 33 * protocol decription at http://code.google.com/p/v8/wiki/DebuggerProtocol 34 */ 35 36 /** 37 * FIXME: change field naming style to use trailing underscore. 38 * @constructor 39 */ 40 devtools.DebuggerAgent = function() 41 { 42 RemoteDebuggerAgent.debuggerOutput = this.handleDebuggerOutput_.bind(this); 43 RemoteDebuggerAgent.setContextId = this.setContextId_.bind(this); 44 45 /** 46 * Id of the inspected page global context. It is used for filtering scripts. 47 * @type {number} 48 */ 49 this.contextId_ = null; 50 51 /** 52 * Mapping from script id to script info. 53 * @type {Object} 54 */ 55 this.parsedScripts_ = null; 56 57 /** 58 * Mapping from the request id to the devtools.BreakpointInfo for the 59 * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for 60 * "setbreakpoint" responses to learn their ids in the v8 debugger. 61 * @see #handleSetBreakpointResponse_ 62 * @type {Object} 63 */ 64 this.requestNumberToBreakpointInfo_ = null; 65 66 /** 67 * Information on current stack frames. 68 * @type {Array.<devtools.CallFrame>} 69 */ 70 this.callFrames_ = []; 71 72 /** 73 * Whether to stop in the debugger on the exceptions. 74 * @type {boolean} 75 */ 76 this.pauseOnExceptions_ = false; 77 78 /** 79 * Mapping: request sequence number->callback. 80 * @type {Object} 81 */ 82 this.requestSeqToCallback_ = null; 83 84 /** 85 * Whether the scripts panel has been shown and initialilzed. 86 * @type {boolean} 87 */ 88 this.scriptsPanelInitialized_ = false; 89 90 /** 91 * Whether the scripts list should be requested next time when context id is 92 * set. 93 * @type {boolean} 94 */ 95 this.requestScriptsWhenContextIdSet_ = false; 96 97 /** 98 * Whether the agent is waiting for initial scripts response. 99 * @type {boolean} 100 */ 101 this.waitingForInitialScriptsResponse_ = false; 102 103 /** 104 * If backtrace response is received when initial scripts response 105 * is not yet processed the backtrace handling will be postponed until 106 * after the scripts response processing. The handler bound to its arguments 107 * and this agent will be stored in this field then. 108 * @type {?function()} 109 */ 110 this.pendingBacktraceResponseHandler_ = null; 111 112 /** 113 * Container of all breakpoints set using resource URL. These breakpoints 114 * survive page reload. Breakpoints set by script id(for scripts that don't 115 * have URLs) are stored in ScriptInfo objects. 116 * @type {Object} 117 */ 118 this.urlToBreakpoints_ = {}; 119 120 121 /** 122 * Exception message that is shown to user while on exception break. 123 * @type {WebInspector.ConsoleMessage} 124 */ 125 this.currentExceptionMessage_ = null; 126 }; 127 128 129 /** 130 * A copy of the scope types from v8/src/mirror-delay.js 131 * @enum {number} 132 */ 133 devtools.DebuggerAgent.ScopeType = { 134 Global: 0, 135 Local: 1, 136 With: 2, 137 Closure: 3, 138 Catch: 4 139 }; 140 141 142 /** 143 * Resets debugger agent to its initial state. 144 */ 145 devtools.DebuggerAgent.prototype.reset = function() 146 { 147 this.contextId_ = null; 148 // No need to request scripts since they all will be pushed in AfterCompile 149 // events. 150 this.requestScriptsWhenContextIdSet_ = false; 151 this.waitingForInitialScriptsResponse_ = false; 152 153 this.parsedScripts_ = {}; 154 this.requestNumberToBreakpointInfo_ = {}; 155 this.callFrames_ = []; 156 this.requestSeqToCallback_ = {}; 157 }; 158 159 160 /** 161 * Initializes scripts UI. This method is called every time Scripts panel 162 * is shown. It will send request for context id if it's not set yet. 163 */ 164 devtools.DebuggerAgent.prototype.initUI = function() 165 { 166 // Initialize scripts cache when Scripts panel is shown first time. 167 if (this.scriptsPanelInitialized_) 168 return; 169 this.scriptsPanelInitialized_ = true; 170 if (this.contextId_) { 171 // We already have context id. This means that we are here from the 172 // very beginning of the page load cycle and hence will get all scripts 173 // via after-compile events. No need to request scripts for this session. 174 // 175 // There can be a number of scripts from after-compile events that are 176 // pending addition into the UI. 177 for (var scriptId in this.parsedScripts_) { 178 var script = this.parsedScripts_[scriptId]; 179 WebInspector.parsedScriptSource(scriptId, script.getUrl(), undefined /* script source */, script.getLineOffset()); 180 } 181 return; 182 } 183 this.waitingForInitialScriptsResponse_ = true; 184 // Script list should be requested only when current context id is known. 185 RemoteDebuggerAgent.getContextId(); 186 this.requestScriptsWhenContextIdSet_ = true; 187 }; 188 189 190 /** 191 * Asynchronously requests the debugger for the script source. 192 * @param {number} scriptId Id of the script whose source should be resolved. 193 * @param {function(source:?string):void} callback Function that will be called 194 * when the source resolution is completed. "source" parameter will be null 195 * if the resolution fails. 196 */ 197 devtools.DebuggerAgent.prototype.resolveScriptSource = function(scriptId, callback) 198 { 199 var script = this.parsedScripts_[scriptId]; 200 if (!script || script.isUnresolved()) { 201 callback(null); 202 return; 203 } 204 205 var cmd = new devtools.DebugCommand("scripts", { 206 "ids": [scriptId], 207 "includeSource": true 208 }); 209 devtools.DebuggerAgent.sendCommand_(cmd); 210 // Force v8 execution so that it gets to processing the requested command. 211 RemoteDebuggerAgent.processDebugCommands(); 212 213 this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { 214 if (msg.isSuccess()) { 215 var scriptJson = msg.getBody()[0]; 216 if (scriptJson) 217 callback(scriptJson.source); 218 else 219 callback(null); 220 } else 221 callback(null); 222 }; 223 }; 224 225 226 /** 227 * Tells the v8 debugger to stop on as soon as possible. 228 */ 229 devtools.DebuggerAgent.prototype.pauseExecution = function() 230 { 231 RemoteDebuggerCommandExecutor.DebuggerPauseScript(); 232 }; 233 234 235 /** 236 * @param {number} sourceId Id of the script fot the breakpoint. 237 * @param {number} line Number of the line for the breakpoint. 238 * @param {?string} condition The breakpoint condition. 239 */ 240 devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line, condition) 241 { 242 var script = this.parsedScripts_[sourceId]; 243 if (!script) 244 return; 245 246 line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); 247 248 var commandArguments; 249 if (script.getUrl()) { 250 var breakpoints = this.urlToBreakpoints_[script.getUrl()]; 251 if (breakpoints && breakpoints[line]) 252 return; 253 if (!breakpoints) { 254 breakpoints = {}; 255 this.urlToBreakpoints_[script.getUrl()] = breakpoints; 256 } 257 258 var breakpointInfo = new devtools.BreakpointInfo(line); 259 breakpoints[line] = breakpointInfo; 260 261 commandArguments = { 262 "groupId": this.contextId_, 263 "type": "script", 264 "target": script.getUrl(), 265 "line": line, 266 "condition": condition 267 }; 268 } else { 269 var breakpointInfo = script.getBreakpointInfo(line); 270 if (breakpointInfo) 271 return; 272 273 breakpointInfo = new devtools.BreakpointInfo(line); 274 script.addBreakpointInfo(breakpointInfo); 275 276 commandArguments = { 277 "groupId": this.contextId_, 278 "type": "scriptId", 279 "target": sourceId, 280 "line": line, 281 "condition": condition 282 }; 283 } 284 285 var cmd = new devtools.DebugCommand("setbreakpoint", commandArguments); 286 287 this.requestNumberToBreakpointInfo_[cmd.getSequenceNumber()] = breakpointInfo; 288 289 devtools.DebuggerAgent.sendCommand_(cmd); 290 // Force v8 execution so that it gets to processing the requested command. 291 // It is necessary for being able to change a breakpoint just after it 292 // has been created (since we need an existing breakpoint id for that). 293 RemoteDebuggerAgent.processDebugCommands(); 294 }; 295 296 297 /** 298 * @param {number} sourceId Id of the script for the breakpoint. 299 * @param {number} line Number of the line for the breakpoint. 300 */ 301 devtools.DebuggerAgent.prototype.removeBreakpoint = function(sourceId, line) 302 { 303 var script = this.parsedScripts_[sourceId]; 304 if (!script) 305 return; 306 307 line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); 308 309 var breakpointInfo; 310 if (script.getUrl()) { 311 var breakpoints = this.urlToBreakpoints_[script.getUrl()]; 312 breakpointInfo = breakpoints[line]; 313 delete breakpoints[line]; 314 } else { 315 breakpointInfo = script.getBreakpointInfo(line); 316 if (breakpointInfo) 317 script.removeBreakpointInfo(breakpointInfo); 318 } 319 320 if (!breakpointInfo) 321 return; 322 323 breakpointInfo.markAsRemoved(); 324 325 var id = breakpointInfo.getV8Id(); 326 327 // If we don't know id of this breakpoint in the v8 debugger we cannot send 328 // "clearbreakpoint" request. In that case it will be removed in 329 // "setbreakpoint" response handler when we learn the id. 330 if (id !== -1) { 331 this.requestClearBreakpoint_(id); 332 } 333 }; 334 335 336 /** 337 * @param {number} sourceId Id of the script for the breakpoint. 338 * @param {number} line Number of the line for the breakpoint. 339 * @param {?string} condition New breakpoint condition. 340 */ 341 devtools.DebuggerAgent.prototype.updateBreakpoint = function(sourceId, line, condition) 342 { 343 var script = this.parsedScripts_[sourceId]; 344 if (!script) 345 return; 346 347 line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); 348 349 var breakpointInfo; 350 if (script.getUrl()) { 351 var breakpoints = this.urlToBreakpoints_[script.getUrl()]; 352 breakpointInfo = breakpoints[line]; 353 } else 354 breakpointInfo = script.getBreakpointInfo(line); 355 356 var id = breakpointInfo.getV8Id(); 357 358 // If we don't know id of this breakpoint in the v8 debugger we cannot send 359 // the "changebreakpoint" request. 360 if (id !== -1) { 361 // TODO(apavlov): make use of the real values for "enabled" and 362 // "ignoreCount" when appropriate. 363 this.requestChangeBreakpoint_(id, true, condition, null); 364 } 365 }; 366 367 368 /** 369 * Tells the v8 debugger to step into the next statement. 370 */ 371 devtools.DebuggerAgent.prototype.stepIntoStatement = function() 372 { 373 this.stepCommand_("in"); 374 }; 375 376 377 /** 378 * Tells the v8 debugger to step out of current function. 379 */ 380 devtools.DebuggerAgent.prototype.stepOutOfFunction = function() 381 { 382 this.stepCommand_("out"); 383 }; 384 385 386 /** 387 * Tells the v8 debugger to step over the next statement. 388 */ 389 devtools.DebuggerAgent.prototype.stepOverStatement = function() 390 { 391 this.stepCommand_("next"); 392 }; 393 394 395 /** 396 * Tells the v8 debugger to continue execution after it has been stopped on a 397 * breakpoint or an exception. 398 */ 399 devtools.DebuggerAgent.prototype.resumeExecution = function() 400 { 401 this.clearExceptionMessage_(); 402 var cmd = new devtools.DebugCommand("continue"); 403 devtools.DebuggerAgent.sendCommand_(cmd); 404 }; 405 406 407 /** 408 * Creates exception message and schedules it for addition to the resource upon 409 * backtrace availability. 410 * @param {string} url Resource url. 411 * @param {number} line Resource line number. 412 * @param {string} message Exception text. 413 */ 414 devtools.DebuggerAgent.prototype.createExceptionMessage_ = function(url, line, message) 415 { 416 this.currentExceptionMessage_ = new WebInspector.ConsoleMessage( 417 WebInspector.ConsoleMessage.MessageSource.JS, 418 WebInspector.ConsoleMessage.MessageType.Log, 419 WebInspector.ConsoleMessage.MessageLevel.Error, 420 line, 421 url, 422 0 /* group level */, 423 1 /* repeat count */, 424 "[Exception] " + message); 425 }; 426 427 428 /** 429 * Shows pending exception message that is created with createExceptionMessage_ 430 * earlier. 431 */ 432 devtools.DebuggerAgent.prototype.showPendingExceptionMessage_ = function() 433 { 434 if (!this.currentExceptionMessage_) 435 return; 436 var msg = this.currentExceptionMessage_; 437 var resource = WebInspector.resourceURLMap[msg.url]; 438 if (resource) { 439 msg.resource = resource; 440 WebInspector.panels.resources.addMessageToResource(resource, msg); 441 } else 442 this.currentExceptionMessage_ = null; 443 }; 444 445 446 /** 447 * Clears exception message from the resource. 448 */ 449 devtools.DebuggerAgent.prototype.clearExceptionMessage_ = function() 450 { 451 if (this.currentExceptionMessage_) { 452 var messageElement = this.currentExceptionMessage_._resourceMessageLineElement; 453 var bubble = messageElement.parentElement; 454 bubble.removeChild(messageElement); 455 if (!bubble.firstChild) { 456 // Last message in bubble removed. 457 bubble.parentElement.removeChild(bubble); 458 } 459 this.currentExceptionMessage_ = null; 460 } 461 }; 462 463 464 /** 465 * @return {boolean} True iff the debugger will pause execution on the 466 * exceptions. 467 */ 468 devtools.DebuggerAgent.prototype.pauseOnExceptions = function() 469 { 470 return this.pauseOnExceptions_; 471 }; 472 473 474 /** 475 * Tells whether to pause in the debugger on the exceptions or not. 476 * @param {boolean} value True iff execution should be stopped in the debugger 477 * on the exceptions. 478 */ 479 devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value) 480 { 481 this.pauseOnExceptions_ = value; 482 }; 483 484 485 /** 486 * Sends "evaluate" request to the debugger. 487 * @param {Object} arguments Request arguments map. 488 * @param {function(devtools.DebuggerMessage)} callback Callback to be called 489 * when response is received. 490 */ 491 devtools.DebuggerAgent.prototype.requestEvaluate = function(arguments, callback) 492 { 493 var cmd = new devtools.DebugCommand("evaluate", arguments); 494 devtools.DebuggerAgent.sendCommand_(cmd); 495 this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback; 496 }; 497 498 499 /** 500 * Sends "lookup" request for each unresolved property of the object. When 501 * response is received the properties will be changed with their resolved 502 * values. 503 * @param {Object} object Object whose properties should be resolved. 504 * @param {function(devtools.DebuggerMessage)} Callback to be called when all 505 * children are resolved. 506 * @param {boolean} noIntrinsic Whether intrinsic properties should be included. 507 */ 508 devtools.DebuggerAgent.prototype.resolveChildren = function(object, callback, noIntrinsic) 509 { 510 if ("handle" in object) { 511 var result = []; 512 devtools.DebuggerAgent.formatObjectProperties_(object, result, noIntrinsic); 513 callback(result); 514 } else { 515 this.requestLookup_([object.ref], function(msg) { 516 var result = []; 517 if (msg.isSuccess()) { 518 var handleToObject = msg.getBody(); 519 var resolved = handleToObject[object.ref]; 520 devtools.DebuggerAgent.formatObjectProperties_(resolved, result, noIntrinsic); 521 callback(result); 522 } else 523 callback([]); 524 }); 525 } 526 }; 527 528 529 /** 530 * Sends "scope" request for the scope object to resolve its variables. 531 * @param {Object} scope Scope to be resolved. 532 * @param {function(Array.<WebInspector.ObjectPropertyProxy>)} callback 533 * Callback to be called when all scope variables are resolved. 534 */ 535 devtools.DebuggerAgent.prototype.resolveScope = function(scope, callback) 536 { 537 var cmd = new devtools.DebugCommand("scope", { 538 "frameNumber": scope.frameNumber, 539 "number": scope.index, 540 "compactFormat": true 541 }); 542 devtools.DebuggerAgent.sendCommand_(cmd); 543 this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { 544 var result = []; 545 if (msg.isSuccess()) { 546 var scopeObjectJson = msg.getBody().object; 547 devtools.DebuggerAgent.formatObjectProperties_(scopeObjectJson, result, true /* no intrinsic */); 548 } 549 callback(result); 550 }; 551 }; 552 553 554 /** 555 * Sends "scopes" request for the frame object to resolve all variables 556 * available in the frame. 557 * @param {number} callFrameId Id of call frame whose variables need to 558 * be resolved. 559 * @param {function(Object)} callback Callback to be called when all frame 560 * variables are resolved. 561 */ 562 devtools.DebuggerAgent.prototype.resolveFrameVariables_ = function(callFrameId, callback) 563 { 564 var result = {}; 565 566 var frame = this.callFrames_[callFrameId]; 567 if (!frame) { 568 callback(result); 569 return; 570 } 571 572 var waitingResponses = 0; 573 function scopeResponseHandler(msg) { 574 waitingResponses--; 575 576 if (msg.isSuccess()) { 577 var properties = msg.getBody().object.properties; 578 for (var j = 0; j < properties.length; j++) 579 result[properties[j].name] = true; 580 } 581 582 // When all scopes are resolved invoke the callback. 583 if (waitingResponses === 0) 584 callback(result); 585 }; 586 587 for (var i = 0; i < frame.scopeChain.length; i++) { 588 var scope = frame.scopeChain[i].objectId; 589 if (scope.type === devtools.DebuggerAgent.ScopeType.Global) { 590 // Do not resolve global scope since it takes for too long. 591 // TODO(yurys): allow to send only property names in the response. 592 continue; 593 } 594 var cmd = new devtools.DebugCommand("scope", { 595 "frameNumber": scope.frameNumber, 596 "number": scope.index, 597 "compactFormat": true 598 }); 599 devtools.DebuggerAgent.sendCommand_(cmd); 600 this.requestSeqToCallback_[cmd.getSequenceNumber()] = scopeResponseHandler; 601 waitingResponses++; 602 } 603 }; 604 605 /** 606 * Evaluates the expressionString to an object in the call frame and reports 607 * all its properties. 608 * @param{string} expressionString Expression whose properties should be 609 * collected. 610 * @param{number} callFrameId The frame id. 611 * @param{function(Object result,bool isException)} reportCompletions Callback 612 * function. 613 */ 614 devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame = function(expressionString, callFrameId, reportCompletions) 615 { 616 if (expressionString) { 617 expressionString = "var obj = " + expressionString + 618 "; var names = {}; for (var n in obj) { names[n] = true; };" + 619 "names;"; 620 this.evaluateInCallFrame( 621 callFrameId, 622 expressionString, 623 function(result) { 624 var names = {}; 625 if (!result.isException) { 626 var props = result.value.objectId.properties; 627 // Put all object properties into the map. 628 for (var i = 0; i < props.length; i++) 629 names[props[i].name] = true; 630 } 631 reportCompletions(names, result.isException); 632 }); 633 } else { 634 this.resolveFrameVariables_(callFrameId, 635 function(result) { 636 reportCompletions(result, false /* isException */); 637 }); 638 } 639 }; 640 641 642 /** 643 * @param{number} scriptId 644 * @return {string} Type of the context of the script with specified id. 645 */ 646 devtools.DebuggerAgent.prototype.getScriptContextType = function(scriptId) 647 { 648 return this.parsedScripts_[scriptId].getContextType(); 649 }; 650 651 652 /** 653 * Removes specified breakpoint from the v8 debugger. 654 * @param {number} breakpointId Id of the breakpoint in the v8 debugger. 655 */ 656 devtools.DebuggerAgent.prototype.requestClearBreakpoint_ = function(breakpointId) 657 { 658 var cmd = new devtools.DebugCommand("clearbreakpoint", { 659 "breakpoint": breakpointId 660 }); 661 devtools.DebuggerAgent.sendCommand_(cmd); 662 }; 663 664 665 /** 666 * Changes breakpoint parameters in the v8 debugger. 667 * @param {number} breakpointId Id of the breakpoint in the v8 debugger. 668 * @param {boolean} enabled Whether to enable the breakpoint. 669 * @param {?string} condition New breakpoint condition. 670 * @param {number} ignoreCount New ignore count for the breakpoint. 671 */ 672 devtools.DebuggerAgent.prototype.requestChangeBreakpoint_ = function(breakpointId, enabled, condition, ignoreCount) 673 { 674 var cmd = new devtools.DebugCommand("changebreakpoint", { 675 "breakpoint": breakpointId, 676 "enabled": enabled, 677 "condition": condition, 678 "ignoreCount": ignoreCount 679 }); 680 devtools.DebuggerAgent.sendCommand_(cmd); 681 }; 682 683 684 /** 685 * Sends "backtrace" request to v8. 686 */ 687 devtools.DebuggerAgent.prototype.requestBacktrace_ = function() 688 { 689 var cmd = new devtools.DebugCommand("backtrace", { 690 "compactFormat":true 691 }); 692 devtools.DebuggerAgent.sendCommand_(cmd); 693 }; 694 695 696 /** 697 * Sends command to v8 debugger. 698 * @param {devtools.DebugCommand} cmd Command to execute. 699 */ 700 devtools.DebuggerAgent.sendCommand_ = function(cmd) 701 { 702 RemoteDebuggerCommandExecutor.DebuggerCommand(cmd.toJSONProtocol()); 703 }; 704 705 706 /** 707 * Tells the v8 debugger to make the next execution step. 708 * @param {string} action "in", "out" or "next" action. 709 */ 710 devtools.DebuggerAgent.prototype.stepCommand_ = function(action) 711 { 712 this.clearExceptionMessage_(); 713 var cmd = new devtools.DebugCommand("continue", { 714 "stepaction": action, 715 "stepcount": 1 716 }); 717 devtools.DebuggerAgent.sendCommand_(cmd); 718 }; 719 720 721 /** 722 * Sends "lookup" request to v8. 723 * @param {number} handle Handle to the object to lookup. 724 */ 725 devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback) 726 { 727 var cmd = new devtools.DebugCommand("lookup", { 728 "compactFormat":true, 729 "handles": handles 730 }); 731 devtools.DebuggerAgent.sendCommand_(cmd); 732 this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback; 733 }; 734 735 736 /** 737 * Sets debugger context id for scripts filtering. 738 * @param {number} contextId Id of the inspected page global context. 739 */ 740 devtools.DebuggerAgent.prototype.setContextId_ = function(contextId) 741 { 742 this.contextId_ = contextId; 743 744 // If it's the first time context id is set request scripts list. 745 if (this.requestScriptsWhenContextIdSet_) { 746 this.requestScriptsWhenContextIdSet_ = false; 747 var cmd = new devtools.DebugCommand("scripts", { 748 "includeSource": false 749 }); 750 devtools.DebuggerAgent.sendCommand_(cmd); 751 // Force v8 execution so that it gets to processing the requested command. 752 RemoteDebuggerAgent.processDebugCommands(); 753 754 var debuggerAgent = this; 755 this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { 756 // Handle the response iff the context id hasn't changed since the request 757 // was issued. Otherwise if the context id did change all up-to-date 758 // scripts will be pushed in after compile events and there is no need to 759 // handle the response. 760 if (contextId === debuggerAgent.contextId_) 761 debuggerAgent.handleScriptsResponse_(msg); 762 763 // We received initial scripts response so flush the flag and 764 // see if there is an unhandled backtrace response. 765 debuggerAgent.waitingForInitialScriptsResponse_ = false; 766 if (debuggerAgent.pendingBacktraceResponseHandler_) { 767 debuggerAgent.pendingBacktraceResponseHandler_(); 768 debuggerAgent.pendingBacktraceResponseHandler_ = null; 769 } 770 }; 771 } 772 }; 773 774 775 /** 776 * Handles output sent by v8 debugger. The output is either asynchronous event 777 * or response to a previously sent request. See protocol definitioun for more 778 * details on the output format. 779 * @param {string} output 780 */ 781 devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output) 782 { 783 var msg; 784 try { 785 msg = new devtools.DebuggerMessage(output); 786 } catch(e) { 787 debugPrint("Failed to handle debugger response:\n" + e); 788 throw e; 789 } 790 791 if (msg.getType() === "event") { 792 if (msg.getEvent() === "break") 793 this.handleBreakEvent_(msg); 794 else if (msg.getEvent() === "exception") 795 this.handleExceptionEvent_(msg); 796 else if (msg.getEvent() === "afterCompile") 797 this.handleAfterCompileEvent_(msg); 798 } else if (msg.getType() === "response") { 799 if (msg.getCommand() === "scripts") 800 this.invokeCallbackForResponse_(msg); 801 else if (msg.getCommand() === "setbreakpoint") 802 this.handleSetBreakpointResponse_(msg); 803 else if (msg.getCommand() === "clearbreakpoint") 804 this.handleClearBreakpointResponse_(msg); 805 else if (msg.getCommand() === "backtrace") 806 this.handleBacktraceResponse_(msg); 807 else if (msg.getCommand() === "lookup") 808 this.invokeCallbackForResponse_(msg); 809 else if (msg.getCommand() === "evaluate") 810 this.invokeCallbackForResponse_(msg); 811 else if (msg.getCommand() === "scope") 812 this.invokeCallbackForResponse_(msg); 813 } 814 }; 815 816 817 /** 818 * @param {devtools.DebuggerMessage} msg 819 */ 820 devtools.DebuggerAgent.prototype.handleBreakEvent_ = function(msg) 821 { 822 // Force scrips panel to be shown first. 823 WebInspector.currentPanel = WebInspector.panels.scripts; 824 825 var body = msg.getBody(); 826 827 var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); 828 this.requestBacktrace_(); 829 }; 830 831 832 /** 833 * @param {devtools.DebuggerMessage} msg 834 */ 835 devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) 836 { 837 // Force scrips panel to be shown first. 838 WebInspector.currentPanel = WebInspector.panels.scripts; 839 840 var body = msg.getBody(); 841 // No script field in the body means that v8 failed to parse the script. We 842 // resume execution on parser errors automatically. 843 if (this.pauseOnExceptions_ && body.script) { 844 var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); 845 this.createExceptionMessage_(body.script.name, line, body.exception.text); 846 this.requestBacktrace_(); 847 } else 848 this.resumeExecution(); 849 }; 850 851 852 /** 853 * @param {devtools.DebuggerMessage} msg 854 */ 855 devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg) 856 { 857 var scripts = msg.getBody(); 858 for (var i = 0; i < scripts.length; i++) { 859 var script = scripts[i]; 860 861 // Skip scripts from other tabs. 862 if (!this.isScriptFromInspectedContext_(script, msg)) 863 continue; 864 865 // We may already have received the info in an afterCompile event. 866 if (script.id in this.parsedScripts_) 867 continue; 868 this.addScriptInfo_(script, msg); 869 } 870 }; 871 872 873 /** 874 * @param {Object} script Json object representing script. 875 * @param {devtools.DebuggerMessage} msg Debugger response. 876 */ 877 devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_ = function(script, msg) 878 { 879 if (!script.context) { 880 // Always ignore scripts from the utility context. 881 return false; 882 } 883 var context = msg.lookup(script.context.ref); 884 var scriptContextId = context.data; 885 if (typeof scriptContextId === "undefined") 886 return false; // Always ignore scripts from the utility context. 887 if (this.contextId_ === null) 888 return true; 889 // Find the id from context data. The context data has the format "type,id". 890 var comma = context.data.indexOf(","); 891 if (comma < 0) 892 return false; 893 return (context.data.substring(comma + 1) == this.contextId_); 894 }; 895 896 897 /** 898 * @param {devtools.DebuggerMessage} msg 899 */ 900 devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg) 901 { 902 var requestSeq = msg.getRequestSeq(); 903 var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq]; 904 if (!breakpointInfo) { 905 // TODO(yurys): handle this case 906 return; 907 } 908 delete this.requestNumberToBreakpointInfo_[requestSeq]; 909 if (!msg.isSuccess()) { 910 // TODO(yurys): handle this case 911 return; 912 } 913 var idInV8 = msg.getBody().breakpoint; 914 breakpointInfo.setV8Id(idInV8); 915 916 if (breakpointInfo.isRemoved()) 917 this.requestClearBreakpoint_(idInV8); 918 }; 919 920 921 /** 922 * @param {devtools.DebuggerMessage} msg 923 */ 924 devtools.DebuggerAgent.prototype.handleAfterCompileEvent_ = function(msg) 925 { 926 if (!this.contextId_) { 927 // Ignore scripts delta if main request has not been issued yet. 928 return; 929 } 930 var script = msg.getBody().script; 931 932 // Ignore scripts from other tabs. 933 if (!this.isScriptFromInspectedContext_(script, msg)) 934 return; 935 this.addScriptInfo_(script, msg); 936 }; 937 938 939 /** 940 * Adds the script info to the local cache. This method assumes that the script 941 * is not in the cache yet. 942 * @param {Object} script Script json object from the debugger message. 943 * @param {devtools.DebuggerMessage} msg Debugger message containing the script 944 * data. 945 */ 946 devtools.DebuggerAgent.prototype.addScriptInfo_ = function(script, msg) 947 { 948 var context = msg.lookup(script.context.ref); 949 var contextType; 950 // Find the type from context data. The context data has the format 951 // "type,id". 952 var comma = context.data.indexOf(","); 953 if (comma < 0) 954 return 955 contextType = context.data.substring(0, comma); 956 this.parsedScripts_[script.id] = new devtools.ScriptInfo(script.id, script.name, script.lineOffset, contextType); 957 if (this.scriptsPanelInitialized_) { 958 // Only report script as parsed after scripts panel has been shown. 959 WebInspector.parsedScriptSource(script.id, script.name, script.source, script.lineOffset); 960 } 961 }; 962 963 964 /** 965 * @param {devtools.DebuggerMessage} msg 966 */ 967 devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_ = function(msg) 968 { 969 // Do nothing. 970 }; 971 972 973 /** 974 * Handles response to "backtrace" command. 975 * @param {devtools.DebuggerMessage} msg 976 */ 977 devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) 978 { 979 if (this.waitingForInitialScriptsResponse_) 980 this.pendingBacktraceResponseHandler_ = this.doHandleBacktraceResponse_.bind(this, msg); 981 else 982 this.doHandleBacktraceResponse_(msg); 983 }; 984 985 986 /** 987 * @param {devtools.DebuggerMessage} msg 988 */ 989 devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_ = function(msg) 990 { 991 var frames = msg.getBody().frames; 992 this.callFrames_ = []; 993 for (var i = 0; i < frames.length; ++i) 994 this.callFrames_.push(this.formatCallFrame_(frames[i])); 995 WebInspector.pausedScript(this.callFrames_); 996 this.showPendingExceptionMessage_(); 997 InspectorFrontendHost.activateWindow(); 998 }; 999 1000 1001 /** 1002 * Evaluates code on given callframe. 1003 */ 1004 devtools.DebuggerAgent.prototype.evaluateInCallFrame = function(callFrameId, code, callback) 1005 { 1006 var callFrame = this.callFrames_[callFrameId]; 1007 callFrame.evaluate_(code, callback); 1008 }; 1009 1010 1011 /** 1012 * Handles response to a command by invoking its callback (if any). 1013 * @param {devtools.DebuggerMessage} msg 1014 * @return {boolean} Whether a callback for the given message was found and 1015 * excuted. 1016 */ 1017 devtools.DebuggerAgent.prototype.invokeCallbackForResponse_ = function(msg) 1018 { 1019 var callback = this.requestSeqToCallback_[msg.getRequestSeq()]; 1020 if (!callback) { 1021 // It may happend if reset was called. 1022 return false; 1023 } 1024 delete this.requestSeqToCallback_[msg.getRequestSeq()]; 1025 callback(msg); 1026 return true; 1027 }; 1028 1029 1030 /** 1031 * @param {Object} stackFrame Frame json object from "backtrace" response. 1032 * @return {!devtools.CallFrame} Object containing information related to the 1033 * call frame in the format expected by ScriptsPanel and its panes. 1034 */ 1035 devtools.DebuggerAgent.prototype.formatCallFrame_ = function(stackFrame) 1036 { 1037 var func = stackFrame.func; 1038 var sourceId = func.scriptId; 1039 1040 // Add service script if it does not exist. 1041 var existingScript = this.parsedScripts_[sourceId]; 1042 if (!existingScript) { 1043 this.parsedScripts_[sourceId] = new devtools.ScriptInfo(sourceId, null /* name */, 0 /* line */, "unknown" /* type */, true /* unresolved */); 1044 WebInspector.parsedScriptSource(sourceId, null, null, 0); 1045 } 1046 1047 var funcName = func.name || func.inferredName || "(anonymous function)"; 1048 var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(stackFrame.line); 1049 1050 // Add basic scope chain info with scope variables. 1051 var scopeChain = []; 1052 var ScopeType = devtools.DebuggerAgent.ScopeType; 1053 for (var i = 0; i < stackFrame.scopes.length; i++) { 1054 var scope = stackFrame.scopes[i]; 1055 scope.frameNumber = stackFrame.index; 1056 var scopeObjectProxy = new WebInspector.ObjectProxy(0, scope, [], 0, "", true); 1057 scopeObjectProxy.isScope = true; 1058 switch(scope.type) { 1059 case ScopeType.Global: 1060 scopeObjectProxy.isDocument = true; 1061 break; 1062 case ScopeType.Local: 1063 scopeObjectProxy.isLocal = true; 1064 scopeObjectProxy.thisObject = devtools.DebuggerAgent.formatObjectProxy_(stackFrame.receiver); 1065 break; 1066 case ScopeType.With: 1067 // Catch scope is treated as a regular with scope by WebKit so we 1068 // also treat it this way. 1069 case ScopeType.Catch: 1070 scopeObjectProxy.isWithBlock = true; 1071 break; 1072 case ScopeType.Closure: 1073 scopeObjectProxy.isClosure = true; 1074 break; 1075 } 1076 scopeChain.push(scopeObjectProxy); 1077 } 1078 return new devtools.CallFrame(stackFrame.index, "function", funcName, sourceId, line, scopeChain); 1079 }; 1080 1081 1082 /** 1083 * Collects properties for an object from the debugger response. 1084 * @param {Object} object An object from the debugger protocol response. 1085 * @param {Array.<WebInspector.ObjectPropertyProxy>} result An array to put the 1086 * properties into. 1087 * @param {boolean} noIntrinsic Whether intrinsic properties should be 1088 * included. 1089 */ 1090 devtools.DebuggerAgent.formatObjectProperties_ = function(object, result, noIntrinsic) 1091 { 1092 devtools.DebuggerAgent.propertiesToProxies_(object.properties, result); 1093 if (noIntrinsic) 1094 return; 1095 1096 result.push(new WebInspector.ObjectPropertyProxy("__proto__", devtools.DebuggerAgent.formatObjectProxy_(object.protoObject))); 1097 result.push(new WebInspector.ObjectPropertyProxy("constructor", devtools.DebuggerAgent.formatObjectProxy_(object.constructorFunction))); 1098 // Don't add 'prototype' property since it is one of the regualar properties. 1099 }; 1100 1101 1102 /** 1103 * For each property in "properties" creates its proxy representative. 1104 * @param {Array.<Object>} properties Receiver properties or locals array from 1105 * "backtrace" response. 1106 * @param {Array.<WebInspector.ObjectPropertyProxy>} Results holder. 1107 */ 1108 devtools.DebuggerAgent.propertiesToProxies_ = function(properties, result) 1109 { 1110 var map = {}; 1111 for (var i = 0; i < properties.length; ++i) { 1112 var property = properties[i]; 1113 var name = String(property.name); 1114 if (name in map) 1115 continue; 1116 map[name] = true; 1117 var value = devtools.DebuggerAgent.formatObjectProxy_(property.value); 1118 var propertyProxy = new WebInspector.ObjectPropertyProxy(name, value); 1119 result.push(propertyProxy); 1120 } 1121 }; 1122 1123 1124 /** 1125 * @param {Object} v An object reference from the debugger response. 1126 * @return {*} The value representation expected by ScriptsPanel. 1127 */ 1128 devtools.DebuggerAgent.formatObjectProxy_ = function(v) 1129 { 1130 var description; 1131 var hasChildren = false; 1132 if (v.type === "object") { 1133 description = v.className; 1134 hasChildren = true; 1135 } else if (v.type === "function") { 1136 if (v.source) 1137 description = v.source; 1138 else 1139 description = "function " + v.name + "()"; 1140 hasChildren = true; 1141 } else if (v.type === "undefined") 1142 description = "undefined"; 1143 else if (v.type === "null") 1144 description = "null"; 1145 else if (typeof v.value !== "undefined") { 1146 // Check for undefined and null types before checking the value, otherwise 1147 // null/undefined may have blank value. 1148 description = v.value; 1149 } else 1150 description = "<unresolved ref: " + v.ref + ", type: " + v.type + ">"; 1151 1152 var proxy = new WebInspector.ObjectProxy(0, v, [], 0, description, hasChildren); 1153 proxy.type = v.type; 1154 proxy.isV8Ref = true; 1155 return proxy; 1156 }; 1157 1158 1159 /** 1160 * Converts line number from Web Inspector UI(1-based) to v8(0-based). 1161 * @param {number} line Resource line number in Web Inspector UI. 1162 * @return {number} The line number in v8. 1163 */ 1164 devtools.DebuggerAgent.webkitToV8LineNumber_ = function(line) 1165 { 1166 return line - 1; 1167 }; 1168 1169 1170 /** 1171 * Converts line number from v8(0-based) to Web Inspector UI(1-based). 1172 * @param {number} line Resource line number in v8. 1173 * @return {number} The line number in Web Inspector. 1174 */ 1175 devtools.DebuggerAgent.v8ToWwebkitLineNumber_ = function(line) 1176 { 1177 return line + 1; 1178 }; 1179 1180 1181 /** 1182 * @param {number} scriptId Id of the script. 1183 * @param {?string} url Script resource URL if any. 1184 * @param {number} lineOffset First line 0-based offset in the containing 1185 * document. 1186 * @param {string} contextType Type of the script's context: 1187 * "page" - regular script from html page 1188 * "injected" - extension content script 1189 * @param {bool} opt_isUnresolved If true, script will not be resolved. 1190 * @constructor 1191 */ 1192 devtools.ScriptInfo = function(scriptId, url, lineOffset, contextType, opt_isUnresolved) 1193 { 1194 this.scriptId_ = scriptId; 1195 this.lineOffset_ = lineOffset; 1196 this.contextType_ = contextType; 1197 this.url_ = url; 1198 this.isUnresolved_ = opt_isUnresolved; 1199 1200 this.lineToBreakpointInfo_ = {}; 1201 }; 1202 1203 1204 /** 1205 * @return {number} 1206 */ 1207 devtools.ScriptInfo.prototype.getLineOffset = function() 1208 { 1209 return this.lineOffset_; 1210 }; 1211 1212 1213 /** 1214 * @return {string} 1215 */ 1216 devtools.ScriptInfo.prototype.getContextType = function() 1217 { 1218 return this.contextType_; 1219 }; 1220 1221 1222 /** 1223 * @return {?string} 1224 */ 1225 devtools.ScriptInfo.prototype.getUrl = function() 1226 { 1227 return this.url_; 1228 }; 1229 1230 1231 /** 1232 * @return {?bool} 1233 */ 1234 devtools.ScriptInfo.prototype.isUnresolved = function() 1235 { 1236 return this.isUnresolved_; 1237 }; 1238 1239 1240 /** 1241 * @param {number} line 0-based line number in the script. 1242 * @return {?devtools.BreakpointInfo} Information on a breakpoint at the 1243 * specified line in the script or undefined if there is no breakpoint at 1244 * that line. 1245 */ 1246 devtools.ScriptInfo.prototype.getBreakpointInfo = function(line) 1247 { 1248 return this.lineToBreakpointInfo_[line]; 1249 }; 1250 1251 1252 /** 1253 * Adds breakpoint info to the script. 1254 * @param {devtools.BreakpointInfo} breakpoint 1255 */ 1256 devtools.ScriptInfo.prototype.addBreakpointInfo = function(breakpoint) 1257 { 1258 this.lineToBreakpointInfo_[breakpoint.getLine()] = breakpoint; 1259 }; 1260 1261 1262 /** 1263 * @param {devtools.BreakpointInfo} breakpoint Breakpoint info to be removed. 1264 */ 1265 devtools.ScriptInfo.prototype.removeBreakpointInfo = function(breakpoint) 1266 { 1267 var line = breakpoint.getLine(); 1268 delete this.lineToBreakpointInfo_[line]; 1269 }; 1270 1271 1272 1273 /** 1274 * @param {number} line Breakpoint 0-based line number in the containing script. 1275 * @constructor 1276 */ 1277 devtools.BreakpointInfo = function(line) 1278 { 1279 this.line_ = line; 1280 this.v8id_ = -1; 1281 this.removed_ = false; 1282 }; 1283 1284 1285 /** 1286 * @return {number} 1287 */ 1288 devtools.BreakpointInfo.prototype.getLine = function(n) 1289 { 1290 return this.line_; 1291 }; 1292 1293 1294 /** 1295 * @return {number} Unique identifier of this breakpoint in the v8 debugger. 1296 */ 1297 devtools.BreakpointInfo.prototype.getV8Id = function(n) 1298 { 1299 return this.v8id_; 1300 }; 1301 1302 1303 /** 1304 * Sets id of this breakpoint in the v8 debugger. 1305 * @param {number} id 1306 */ 1307 devtools.BreakpointInfo.prototype.setV8Id = function(id) 1308 { 1309 this.v8id_ = id; 1310 }; 1311 1312 1313 /** 1314 * Marks this breakpoint as removed from the front-end. 1315 */ 1316 devtools.BreakpointInfo.prototype.markAsRemoved = function() 1317 { 1318 this.removed_ = true; 1319 }; 1320 1321 1322 /** 1323 * @return {boolean} Whether this breakpoint has been removed from the 1324 * front-end. 1325 */ 1326 devtools.BreakpointInfo.prototype.isRemoved = function() 1327 { 1328 return this.removed_; 1329 }; 1330 1331 1332 /** 1333 * Call stack frame data. 1334 * @param {string} id CallFrame id. 1335 * @param {string} type CallFrame type. 1336 * @param {string} functionName CallFrame type. 1337 * @param {string} sourceID Source id. 1338 * @param {number} line Source line. 1339 * @param {Array.<Object>} scopeChain Array of scoped objects. 1340 * @construnctor 1341 */ 1342 devtools.CallFrame = function(id, type, functionName, sourceID, line, scopeChain) 1343 { 1344 this.id = id; 1345 this.type = type; 1346 this.functionName = functionName; 1347 this.sourceID = sourceID; 1348 this.line = line; 1349 this.scopeChain = scopeChain; 1350 }; 1351 1352 1353 /** 1354 * This method issues asynchronous evaluate request, reports result to the 1355 * callback. 1356 * @param {string} expression An expression to be evaluated in the context of 1357 * this call frame. 1358 * @param {function(Object):undefined} callback Callback to report result to. 1359 */ 1360 devtools.CallFrame.prototype.evaluate_ = function(expression, callback) 1361 { 1362 devtools.tools.getDebuggerAgent().requestEvaluate({ 1363 "expression": expression, 1364 "frame": this.id, 1365 "global": false, 1366 "disable_break": false, 1367 "compactFormat": true 1368 }, 1369 function(response) { 1370 var result = {}; 1371 if (response.isSuccess()) 1372 result.value = devtools.DebuggerAgent.formatObjectProxy_(response.getBody()); 1373 else { 1374 result.value = response.getMessage(); 1375 result.isException = true; 1376 } 1377 callback(result); 1378 }); 1379 }; 1380 1381 1382 /** 1383 * JSON based commands sent to v8 debugger. 1384 * @param {string} command Name of the command to execute. 1385 * @param {Object} opt_arguments Command-specific arguments map. 1386 * @constructor 1387 */ 1388 devtools.DebugCommand = function(command, opt_arguments) 1389 { 1390 this.command_ = command; 1391 this.type_ = "request"; 1392 this.seq_ = ++devtools.DebugCommand.nextSeq_; 1393 if (opt_arguments) 1394 this.arguments_ = opt_arguments; 1395 }; 1396 1397 1398 /** 1399 * Next unique number to be used as debugger request sequence number. 1400 * @type {number} 1401 */ 1402 devtools.DebugCommand.nextSeq_ = 1; 1403 1404 1405 /** 1406 * @return {number} 1407 */ 1408 devtools.DebugCommand.prototype.getSequenceNumber = function() 1409 { 1410 return this.seq_; 1411 }; 1412 1413 1414 /** 1415 * @return {string} 1416 */ 1417 devtools.DebugCommand.prototype.toJSONProtocol = function() 1418 { 1419 var json = { 1420 "seq": this.seq_, 1421 "type": this.type_, 1422 "command": this.command_ 1423 } 1424 if (this.arguments_) 1425 json.arguments = this.arguments_; 1426 return JSON.stringify(json); 1427 }; 1428 1429 1430 /** 1431 * JSON messages sent from v8 debugger. See protocol definition for more 1432 * details: http://code.google.com/p/v8/wiki/DebuggerProtocol 1433 * @param {string} msg Raw protocol packet as JSON string. 1434 * @constructor 1435 */ 1436 devtools.DebuggerMessage = function(msg) 1437 { 1438 this.packet_ = JSON.parse(msg); 1439 this.refs_ = []; 1440 if (this.packet_.refs) { 1441 for (var i = 0; i < this.packet_.refs.length; i++) 1442 this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i]; 1443 } 1444 }; 1445 1446 1447 /** 1448 * @return {string} The packet type. 1449 */ 1450 devtools.DebuggerMessage.prototype.getType = function() 1451 { 1452 return this.packet_.type; 1453 }; 1454 1455 1456 /** 1457 * @return {?string} The packet event if the message is an event. 1458 */ 1459 devtools.DebuggerMessage.prototype.getEvent = function() 1460 { 1461 return this.packet_.event; 1462 }; 1463 1464 1465 /** 1466 * @return {?string} The packet command if the message is a response to a 1467 * command. 1468 */ 1469 devtools.DebuggerMessage.prototype.getCommand = function() 1470 { 1471 return this.packet_.command; 1472 }; 1473 1474 1475 /** 1476 * @return {number} The packet request sequence. 1477 */ 1478 devtools.DebuggerMessage.prototype.getRequestSeq = function() 1479 { 1480 return this.packet_.request_seq; 1481 }; 1482 1483 1484 /** 1485 * @return {number} Whether the v8 is running after processing the request. 1486 */ 1487 devtools.DebuggerMessage.prototype.isRunning = function() 1488 { 1489 return this.packet_.running ? true : false; 1490 }; 1491 1492 1493 /** 1494 * @return {boolean} Whether the request succeeded. 1495 */ 1496 devtools.DebuggerMessage.prototype.isSuccess = function() 1497 { 1498 return this.packet_.success ? true : false; 1499 }; 1500 1501 1502 /** 1503 * @return {string} 1504 */ 1505 devtools.DebuggerMessage.prototype.getMessage = function() 1506 { 1507 return this.packet_.message; 1508 }; 1509 1510 1511 /** 1512 * @return {Object} Parsed message body json. 1513 */ 1514 devtools.DebuggerMessage.prototype.getBody = function() 1515 { 1516 return this.packet_.body; 1517 }; 1518 1519 1520 /** 1521 * @param {number} handle Object handle. 1522 * @return {?Object} Returns the object with the handle if it was sent in this 1523 * message(some objects referenced by handles may be missing in the message). 1524 */ 1525 devtools.DebuggerMessage.prototype.lookup = function(handle) 1526 { 1527 return this.refs_[handle]; 1528 }; 1529