• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
40devtools.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 */
133devtools.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 */
145devtools.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 */
164devtools.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 */
197devtools.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 */
229devtools.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 */
240devtools.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 */
301devtools.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 */
341devtools.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 */
371devtools.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 */
380devtools.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 */
389devtools.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 */
399devtools.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 */
414devtools.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 */
432devtools.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 */
449devtools.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 */
468devtools.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 */
479devtools.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 */
491devtools.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 */
508devtools.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 */
535devtools.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 */
562devtools.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 */
614devtools.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 */
646devtools.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 */
656devtools.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 */
672devtools.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 */
687devtools.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 */
700devtools.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 */
710devtools.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 */
725devtools.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 */
740devtools.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 */
781devtools.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 */
820devtools.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 */
835devtools.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 */
855devtools.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 */
877devtools.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 */
900devtools.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 */
924devtools.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 */
946devtools.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 */
967devtools.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 */
977devtools.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 */
989devtools.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 */
1004devtools.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 */
1017devtools.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 */
1035devtools.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 */
1090devtools.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 */
1108devtools.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 */
1128devtools.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 */
1164devtools.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 */
1175devtools.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 */
1192devtools.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 */
1207devtools.ScriptInfo.prototype.getLineOffset = function()
1208{
1209    return this.lineOffset_;
1210};
1211
1212
1213/**
1214 * @return {string}
1215 */
1216devtools.ScriptInfo.prototype.getContextType = function()
1217{
1218    return this.contextType_;
1219};
1220
1221
1222/**
1223 * @return {?string}
1224 */
1225devtools.ScriptInfo.prototype.getUrl = function()
1226{
1227    return this.url_;
1228};
1229
1230
1231/**
1232 * @return {?bool}
1233 */
1234devtools.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 */
1246devtools.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 */
1256devtools.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 */
1265devtools.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 */
1277devtools.BreakpointInfo = function(line)
1278{
1279    this.line_ = line;
1280    this.v8id_ = -1;
1281    this.removed_ = false;
1282};
1283
1284
1285/**
1286 * @return {number}
1287 */
1288devtools.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 */
1297devtools.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 */
1307devtools.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 */
1316devtools.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 */
1326devtools.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 */
1342devtools.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 */
1360devtools.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 */
1388devtools.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 */
1402devtools.DebugCommand.nextSeq_ = 1;
1403
1404
1405/**
1406 * @return {number}
1407 */
1408devtools.DebugCommand.prototype.getSequenceNumber = function()
1409{
1410    return this.seq_;
1411};
1412
1413
1414/**
1415 * @return {string}
1416 */
1417devtools.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 */
1436devtools.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 */
1450devtools.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 */
1459devtools.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 */
1469devtools.DebuggerMessage.prototype.getCommand = function()
1470{
1471    return this.packet_.command;
1472};
1473
1474
1475/**
1476 * @return {number} The packet request sequence.
1477 */
1478devtools.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 */
1487devtools.DebuggerMessage.prototype.isRunning = function()
1488{
1489    return this.packet_.running ? true : false;
1490};
1491
1492
1493/**
1494 * @return {boolean} Whether the request succeeded.
1495 */
1496devtools.DebuggerMessage.prototype.isSuccess = function()
1497{
1498    return this.packet_.success ? true : false;
1499};
1500
1501
1502/**
1503 * @return {string}
1504 */
1505devtools.DebuggerMessage.prototype.getMessage = function()
1506{
1507    return this.packet_.message;
1508};
1509
1510
1511/**
1512 * @return {Object} Parsed message body json.
1513 */
1514devtools.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 */
1525devtools.DebuggerMessage.prototype.lookup = function(handle)
1526{
1527    return this.refs_[handle];
1528};
1529