blob: 7f06ca1be15e15f4f909fe7dd26d43e63866365d [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5(function (global, utils) {
6"use strict";
7
8// ----------------------------------------------------------------------------
9// Imports
10
11var FrameMirror = global.FrameMirror;
12var GlobalArray = global.Array;
13var GlobalRegExp = global.RegExp;
14var IsNaN = global.isNaN;
15var JSONParse = global.JSON.parse;
16var JSONStringify = global.JSON.stringify;
17var LookupMirror = global.LookupMirror;
18var MakeError;
19var MakeTypeError;
20var MakeMirror = global.MakeMirror;
21var MakeMirrorSerializer = global.MakeMirrorSerializer;
22var MathMin = global.Math.min;
23var Mirror = global.Mirror;
24var MirrorType;
25var ParseInt = global.parseInt;
26var ValueMirror = global.ValueMirror;
27
28utils.Import(function(from) {
29 MakeError = from.MakeError;
30 MakeTypeError = from.MakeTypeError;
31 MirrorType = from.MirrorType;
32});
33
34//----------------------------------------------------------------------------
35
36// Default number of frames to include in the response to backtrace request.
37var kDefaultBacktraceLength = 10;
38
39var Debug = {};
40
41// Regular expression to skip "crud" at the beginning of a source line which is
42// not really code. Currently the regular expression matches whitespace and
43// comments.
44var sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
45
46// Debug events which can occour in the V8 JavaScript engine. These originate
47// from the API include file debug.h.
48Debug.DebugEvent = { Break: 1,
49 Exception: 2,
50 NewFunction: 3,
51 BeforeCompile: 4,
52 AfterCompile: 5,
53 CompileError: 6,
Ben Murdochda12d292016-06-02 14:46:10 +010054 AsyncTaskEvent: 7 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055
56// Types of exceptions that can be broken upon.
57Debug.ExceptionBreak = { Caught : 0,
58 Uncaught: 1 };
59
60// The different types of steps.
61Debug.StepAction = { StepOut: 0,
62 StepNext: 1,
63 StepIn: 2,
64 StepFrame: 3 };
65
66// The different types of scripts matching enum ScriptType in objects.h.
67Debug.ScriptType = { Native: 0,
68 Extension: 1,
69 Normal: 2 };
70
71// The different types of script compilations matching enum
72// Script::CompilationType in objects.h.
73Debug.ScriptCompilationType = { Host: 0,
74 Eval: 1,
75 JSON: 2 };
76
77// The different script break point types.
78Debug.ScriptBreakPointType = { ScriptId: 0,
79 ScriptName: 1,
80 ScriptRegExp: 2 };
81
82// The different types of breakpoint position alignments.
83// Must match BreakPositionAlignment in debug.h.
84Debug.BreakPositionAlignment = {
85 Statement: 0,
86 BreakPosition: 1
87};
88
89function ScriptTypeFlag(type) {
90 return (1 << type);
91}
92
93// Globals.
94var next_response_seq = 0;
95var next_break_point_number = 1;
96var break_points = [];
97var script_break_points = [];
98var debugger_flags = {
99 breakPointsActive: {
100 value: true,
101 getValue: function() { return this.value; },
102 setValue: function(value) {
103 this.value = !!value;
104 %SetBreakPointsActive(this.value);
105 }
106 },
107 breakOnCaughtException: {
108 getValue: function() { return Debug.isBreakOnException(); },
109 setValue: function(value) {
110 if (value) {
111 Debug.setBreakOnException();
112 } else {
113 Debug.clearBreakOnException();
114 }
115 }
116 },
117 breakOnUncaughtException: {
118 getValue: function() { return Debug.isBreakOnUncaughtException(); },
119 setValue: function(value) {
120 if (value) {
121 Debug.setBreakOnUncaughtException();
122 } else {
123 Debug.clearBreakOnUncaughtException();
124 }
125 }
126 },
127};
128
129
130// Create a new break point object and add it to the list of break points.
131function MakeBreakPoint(source_position, opt_script_break_point) {
132 var break_point = new BreakPoint(source_position, opt_script_break_point);
133 break_points.push(break_point);
134 return break_point;
135}
136
137
138// Object representing a break point.
139// NOTE: This object does not have a reference to the function having break
140// point as this would cause function not to be garbage collected when it is
141// not used any more. We do not want break points to keep functions alive.
142function BreakPoint(source_position, opt_script_break_point) {
143 this.source_position_ = source_position;
144 if (opt_script_break_point) {
145 this.script_break_point_ = opt_script_break_point;
146 } else {
147 this.number_ = next_break_point_number++;
148 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 this.active_ = true;
150 this.condition_ = null;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151}
152
153
154BreakPoint.prototype.number = function() {
155 return this.number_;
156};
157
158
159BreakPoint.prototype.func = function() {
160 return this.func_;
161};
162
163
164BreakPoint.prototype.source_position = function() {
165 return this.source_position_;
166};
167
168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169BreakPoint.prototype.active = function() {
170 if (this.script_break_point()) {
171 return this.script_break_point().active();
172 }
173 return this.active_;
174};
175
176
177BreakPoint.prototype.condition = function() {
178 if (this.script_break_point() && this.script_break_point().condition()) {
179 return this.script_break_point().condition();
180 }
181 return this.condition_;
182};
183
184
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185BreakPoint.prototype.script_break_point = function() {
186 return this.script_break_point_;
187};
188
189
190BreakPoint.prototype.enable = function() {
191 this.active_ = true;
192};
193
194
195BreakPoint.prototype.disable = function() {
196 this.active_ = false;
197};
198
199
200BreakPoint.prototype.setCondition = function(condition) {
201 this.condition_ = condition;
202};
203
204
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205BreakPoint.prototype.isTriggered = function(exec_state) {
206 // Break point not active - not triggered.
207 if (!this.active()) return false;
208
209 // Check for conditional break point.
210 if (this.condition()) {
211 // If break point has condition try to evaluate it in the top frame.
212 try {
213 var mirror = exec_state.frame(0).evaluate(this.condition());
214 // If no sensible mirror or non true value break point not triggered.
215 if (!(mirror instanceof ValueMirror) || !mirror.value_) {
216 return false;
217 }
218 } catch (e) {
219 // Exception evaluating condition counts as not triggered.
220 return false;
221 }
222 }
223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 // Break point triggered.
225 return true;
226};
227
228
229// Function called from the runtime when a break point is hit. Returns true if
230// the break point is triggered and supposed to break execution.
231function IsBreakPointTriggered(break_id, break_point) {
232 return break_point.isTriggered(MakeExecutionState(break_id));
233}
234
235
236// Object representing a script break point. The script is referenced by its
237// script name or script id and the break point is represented as line and
238// column.
239function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
240 opt_groupId, opt_position_alignment) {
241 this.type_ = type;
242 if (type == Debug.ScriptBreakPointType.ScriptId) {
243 this.script_id_ = script_id_or_name;
244 } else if (type == Debug.ScriptBreakPointType.ScriptName) {
245 this.script_name_ = script_id_or_name;
246 } else if (type == Debug.ScriptBreakPointType.ScriptRegExp) {
247 this.script_regexp_object_ = new GlobalRegExp(script_id_or_name);
248 } else {
249 throw MakeError(kDebugger, "Unexpected breakpoint type " + type);
250 }
251 this.line_ = opt_line || 0;
252 this.column_ = opt_column;
253 this.groupId_ = opt_groupId;
254 this.position_alignment_ = IS_UNDEFINED(opt_position_alignment)
255 ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 this.active_ = true;
257 this.condition_ = null;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 this.break_points_ = [];
259}
260
261
262// Creates a clone of script breakpoint that is linked to another script.
263ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
264 var copy = new ScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
265 other_script.id, this.line_, this.column_, this.groupId_,
266 this.position_alignment_);
267 copy.number_ = next_break_point_number++;
268 script_break_points.push(copy);
269
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270 copy.active_ = this.active_;
271 copy.condition_ = this.condition_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272 return copy;
273};
274
275
276ScriptBreakPoint.prototype.number = function() {
277 return this.number_;
278};
279
280
281ScriptBreakPoint.prototype.groupId = function() {
282 return this.groupId_;
283};
284
285
286ScriptBreakPoint.prototype.type = function() {
287 return this.type_;
288};
289
290
291ScriptBreakPoint.prototype.script_id = function() {
292 return this.script_id_;
293};
294
295
296ScriptBreakPoint.prototype.script_name = function() {
297 return this.script_name_;
298};
299
300
301ScriptBreakPoint.prototype.script_regexp_object = function() {
302 return this.script_regexp_object_;
303};
304
305
306ScriptBreakPoint.prototype.line = function() {
307 return this.line_;
308};
309
310
311ScriptBreakPoint.prototype.column = function() {
312 return this.column_;
313};
314
315
316ScriptBreakPoint.prototype.actual_locations = function() {
317 var locations = [];
318 for (var i = 0; i < this.break_points_.length; i++) {
319 locations.push(this.break_points_[i].actual_location);
320 }
321 return locations;
322};
323
324
325ScriptBreakPoint.prototype.update_positions = function(line, column) {
326 this.line_ = line;
327 this.column_ = column;
328};
329
330
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331ScriptBreakPoint.prototype.active = function() {
332 return this.active_;
333};
334
335
336ScriptBreakPoint.prototype.condition = function() {
337 return this.condition_;
338};
339
340
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341ScriptBreakPoint.prototype.enable = function() {
342 this.active_ = true;
343};
344
345
346ScriptBreakPoint.prototype.disable = function() {
347 this.active_ = false;
348};
349
350
351ScriptBreakPoint.prototype.setCondition = function(condition) {
352 this.condition_ = condition;
353};
354
355
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000356// Check whether a script matches this script break point. Currently this is
357// only based on script name.
358ScriptBreakPoint.prototype.matchesScript = function(script) {
359 if (this.type_ == Debug.ScriptBreakPointType.ScriptId) {
360 return this.script_id_ == script.id;
361 } else {
362 // We might want to account columns here as well.
363 if (!(script.line_offset <= this.line_ &&
364 this.line_ < script.line_offset + script.lineCount())) {
365 return false;
366 }
367 if (this.type_ == Debug.ScriptBreakPointType.ScriptName) {
368 return this.script_name_ == script.nameOrSourceURL();
369 } else if (this.type_ == Debug.ScriptBreakPointType.ScriptRegExp) {
370 return this.script_regexp_object_.test(script.nameOrSourceURL());
371 } else {
372 throw MakeError(kDebugger, "Unexpected breakpoint type " + this.type_);
373 }
374 }
375};
376
377
378// Set the script break point in a script.
379ScriptBreakPoint.prototype.set = function (script) {
380 var column = this.column();
381 var line = this.line();
382 // If the column is undefined the break is on the line. To help locate the
383 // first piece of breakable code on the line try to find the column on the
384 // line which contains some source.
385 if (IS_UNDEFINED(column)) {
386 var source_line = script.sourceLine(this.line());
387
388 // Allocate array for caching the columns where the actual source starts.
389 if (!script.sourceColumnStart_) {
390 script.sourceColumnStart_ = new GlobalArray(script.lineCount());
391 }
392
393 // Fill cache if needed and get column where the actual source starts.
394 if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
395 script.sourceColumnStart_[line] =
396 source_line.match(sourceLineBeginningSkip)[0].length;
397 }
398 column = script.sourceColumnStart_[line];
399 }
400
401 // Convert the line and column into an absolute position within the script.
402 var position = Debug.findScriptSourcePosition(script, this.line(), column);
403
404 // If the position is not found in the script (the script might be shorter
405 // than it used to be) just ignore it.
406 if (IS_NULL(position)) return;
407
408 // Create a break point object and set the break point.
409 var break_point = MakeBreakPoint(position, this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 var actual_position = %SetScriptBreakPoint(script, position,
411 this.position_alignment_,
412 break_point);
413 if (IS_UNDEFINED(actual_position)) {
414 actual_position = position;
415 }
416 var actual_location = script.locationFromPosition(actual_position, true);
417 break_point.actual_location = { line: actual_location.line,
418 column: actual_location.column,
419 script_id: script.id };
420 this.break_points_.push(break_point);
421 return break_point;
422};
423
424
425// Clear all the break points created from this script break point
426ScriptBreakPoint.prototype.clear = function () {
427 var remaining_break_points = [];
428 for (var i = 0; i < break_points.length; i++) {
429 if (break_points[i].script_break_point() &&
430 break_points[i].script_break_point() === this) {
431 %ClearBreakPoint(break_points[i]);
432 } else {
433 remaining_break_points.push(break_points[i]);
434 }
435 }
436 break_points = remaining_break_points;
437 this.break_points_ = [];
438};
439
440
441// Function called from runtime when a new script is compiled to set any script
442// break points set in this script.
443function UpdateScriptBreakPoints(script) {
444 for (var i = 0; i < script_break_points.length; i++) {
445 var break_point = script_break_points[i];
446 if ((break_point.type() == Debug.ScriptBreakPointType.ScriptName ||
447 break_point.type() == Debug.ScriptBreakPointType.ScriptRegExp) &&
448 break_point.matchesScript(script)) {
449 break_point.set(script);
450 }
451 }
452}
453
454
455function GetScriptBreakPoints(script) {
456 var result = [];
457 for (var i = 0; i < script_break_points.length; i++) {
458 if (script_break_points[i].matchesScript(script)) {
459 result.push(script_break_points[i]);
460 }
461 }
462 return result;
463}
464
465
466Debug.setListener = function(listener, opt_data) {
467 if (!IS_FUNCTION(listener) && !IS_UNDEFINED(listener) && !IS_NULL(listener)) {
468 throw MakeTypeError(kDebuggerType);
469 }
470 %SetDebugEventListener(listener, opt_data);
471};
472
473
474Debug.breakLocations = function(f, opt_position_aligment) {
475 if (!IS_FUNCTION(f)) throw MakeTypeError(kDebuggerType);
476 var position_aligment = IS_UNDEFINED(opt_position_aligment)
477 ? Debug.BreakPositionAlignment.Statement : opt_position_aligment;
478 return %GetBreakLocations(f, position_aligment);
479};
480
481// Returns a Script object. If the parameter is a function the return value
482// is the script in which the function is defined. If the parameter is a string
483// the return value is the script for which the script name has that string
484// value. If it is a regexp and there is a unique script whose name matches
485// we return that, otherwise undefined.
486Debug.findScript = function(func_or_script_name) {
487 if (IS_FUNCTION(func_or_script_name)) {
488 return %FunctionGetScript(func_or_script_name);
489 } else if (IS_REGEXP(func_or_script_name)) {
490 var scripts = Debug.scripts();
491 var last_result = null;
492 var result_count = 0;
493 for (var i in scripts) {
494 var script = scripts[i];
495 if (func_or_script_name.test(script.name)) {
496 last_result = script;
497 result_count++;
498 }
499 }
500 // Return the unique script matching the regexp. If there are more
501 // than one we don't return a value since there is no good way to
502 // decide which one to return. Returning a "random" one, say the
503 // first, would introduce nondeterminism (or something close to it)
504 // because the order is the heap iteration order.
505 if (result_count == 1) {
506 return last_result;
507 } else {
508 return UNDEFINED;
509 }
510 } else {
511 return %GetScript(func_or_script_name);
512 }
513};
514
515// Returns the script source. If the parameter is a function the return value
516// is the script source for the script in which the function is defined. If the
517// parameter is a string the return value is the script for which the script
518// name has that string value.
519Debug.scriptSource = function(func_or_script_name) {
520 return this.findScript(func_or_script_name).source;
521};
522
523
524Debug.source = function(f) {
525 if (!IS_FUNCTION(f)) throw MakeTypeError(kDebuggerType);
526 return %FunctionGetSourceCode(f);
527};
528
529
530Debug.sourcePosition = function(f) {
531 if (!IS_FUNCTION(f)) throw MakeTypeError(kDebuggerType);
532 return %FunctionGetScriptSourcePosition(f);
533};
534
535
536Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
537 var script = %FunctionGetScript(func);
538 var script_offset = %FunctionGetScriptSourcePosition(func);
539 return script.locationFromLine(opt_line, opt_column, script_offset);
540};
541
542
543// Returns the character position in a script based on a line number and an
544// optional position within that line.
545Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
546 var location = script.locationFromLine(opt_line, opt_column);
547 return location ? location.position : null;
548};
549
550
551Debug.findBreakPoint = function(break_point_number, remove) {
552 var break_point;
553 for (var i = 0; i < break_points.length; i++) {
554 if (break_points[i].number() == break_point_number) {
555 break_point = break_points[i];
556 // Remove the break point from the list if requested.
557 if (remove) {
558 break_points.splice(i, 1);
559 }
560 break;
561 }
562 }
563 if (break_point) {
564 return break_point;
565 } else {
566 return this.findScriptBreakPoint(break_point_number, remove);
567 }
568};
569
570Debug.findBreakPointActualLocations = function(break_point_number) {
571 for (var i = 0; i < script_break_points.length; i++) {
572 if (script_break_points[i].number() == break_point_number) {
573 return script_break_points[i].actual_locations();
574 }
575 }
576 for (var i = 0; i < break_points.length; i++) {
577 if (break_points[i].number() == break_point_number) {
578 return [break_points[i].actual_location];
579 }
580 }
581 return [];
582};
583
584Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
585 if (!IS_FUNCTION(func)) throw MakeTypeError(kDebuggerType);
586 // Break points in API functions are not supported.
587 if (%FunctionIsAPIFunction(func)) {
588 throw MakeError(kDebugger, 'Cannot set break point in native code.');
589 }
590 // Find source position relative to start of the function
591 var break_position =
592 this.findFunctionSourceLocation(func, opt_line, opt_column).position;
593 var source_position = break_position - this.sourcePosition(func);
594 // Find the script for the function.
595 var script = %FunctionGetScript(func);
596 // Break in builtin JavaScript code is not supported.
597 if (script.type == Debug.ScriptType.Native) {
598 throw MakeError(kDebugger, 'Cannot set break point in native code.');
599 }
600 // If the script for the function has a name convert this to a script break
601 // point.
602 if (script && script.id) {
603 // Adjust the source position to be script relative.
604 source_position += %FunctionGetScriptSourcePosition(func);
605 // Find line and column for the position in the script and set a script
606 // break point from that.
607 var location = script.locationFromPosition(source_position, false);
608 return this.setScriptBreakPointById(script.id,
609 location.line, location.column,
610 opt_condition);
611 } else {
612 // Set a break point directly on the function.
613 var break_point = MakeBreakPoint(source_position);
614 var actual_position =
615 %SetFunctionBreakPoint(func, source_position, break_point);
616 actual_position += this.sourcePosition(func);
617 var actual_location = script.locationFromPosition(actual_position, true);
618 break_point.actual_location = { line: actual_location.line,
619 column: actual_location.column,
620 script_id: script.id };
621 break_point.setCondition(opt_condition);
622 return break_point.number();
623 }
624};
625
626
627Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
628 condition, enabled,
629 opt_position_alignment)
630{
631 var break_point = MakeBreakPoint(position);
632 break_point.setCondition(condition);
633 if (!enabled) {
634 break_point.disable();
635 }
636 var scripts = this.scripts();
637 var position_alignment = IS_UNDEFINED(opt_position_alignment)
638 ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
639 for (var i = 0; i < scripts.length; i++) {
640 if (script_id == scripts[i].id) {
641 break_point.actual_position = %SetScriptBreakPoint(scripts[i], position,
642 position_alignment, break_point);
643 break;
644 }
645 }
646 return break_point;
647};
648
649
650Debug.enableBreakPoint = function(break_point_number) {
651 var break_point = this.findBreakPoint(break_point_number, false);
652 // Only enable if the breakpoint hasn't been deleted:
653 if (break_point) {
654 break_point.enable();
655 }
656};
657
658
659Debug.disableBreakPoint = function(break_point_number) {
660 var break_point = this.findBreakPoint(break_point_number, false);
661 // Only enable if the breakpoint hasn't been deleted:
662 if (break_point) {
663 break_point.disable();
664 }
665};
666
667
668Debug.changeBreakPointCondition = function(break_point_number, condition) {
669 var break_point = this.findBreakPoint(break_point_number, false);
670 break_point.setCondition(condition);
671};
672
673
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000674Debug.clearBreakPoint = function(break_point_number) {
675 var break_point = this.findBreakPoint(break_point_number, true);
676 if (break_point) {
677 return %ClearBreakPoint(break_point);
678 } else {
679 break_point = this.findScriptBreakPoint(break_point_number, true);
680 if (!break_point) throw MakeError(kDebugger, 'Invalid breakpoint');
681 }
682};
683
684
685Debug.clearAllBreakPoints = function() {
686 for (var i = 0; i < break_points.length; i++) {
687 var break_point = break_points[i];
688 %ClearBreakPoint(break_point);
689 }
690 break_points = [];
691};
692
693
694Debug.disableAllBreakPoints = function() {
695 // Disable all user defined breakpoints:
696 for (var i = 1; i < next_break_point_number; i++) {
697 Debug.disableBreakPoint(i);
698 }
699 // Disable all exception breakpoints:
700 %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
701 %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
702};
703
704
705Debug.findScriptBreakPoint = function(break_point_number, remove) {
706 var script_break_point;
707 for (var i = 0; i < script_break_points.length; i++) {
708 if (script_break_points[i].number() == break_point_number) {
709 script_break_point = script_break_points[i];
710 // Remove the break point from the list if requested.
711 if (remove) {
712 script_break_point.clear();
713 script_break_points.splice(i,1);
714 }
715 break;
716 }
717 }
718 return script_break_point;
719};
720
721
722// Sets a breakpoint in a script identified through id or name at the
723// specified source line and column within that line.
724Debug.setScriptBreakPoint = function(type, script_id_or_name,
725 opt_line, opt_column, opt_condition,
726 opt_groupId, opt_position_alignment) {
727 // Create script break point object.
728 var script_break_point =
729 new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
730 opt_groupId, opt_position_alignment);
731
732 // Assign number to the new script break point and add it.
733 script_break_point.number_ = next_break_point_number++;
734 script_break_point.setCondition(opt_condition);
735 script_break_points.push(script_break_point);
736
737 // Run through all scripts to see if this script break point matches any
738 // loaded scripts.
739 var scripts = this.scripts();
740 for (var i = 0; i < scripts.length; i++) {
741 if (script_break_point.matchesScript(scripts[i])) {
742 script_break_point.set(scripts[i]);
743 }
744 }
745
746 return script_break_point.number();
747};
748
749
750Debug.setScriptBreakPointById = function(script_id,
751 opt_line, opt_column,
752 opt_condition, opt_groupId,
753 opt_position_alignment) {
754 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
755 script_id, opt_line, opt_column,
756 opt_condition, opt_groupId,
757 opt_position_alignment);
758};
759
760
761Debug.setScriptBreakPointByName = function(script_name,
762 opt_line, opt_column,
763 opt_condition, opt_groupId) {
764 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
765 script_name, opt_line, opt_column,
766 opt_condition, opt_groupId);
767};
768
769
770Debug.setScriptBreakPointByRegExp = function(script_regexp,
771 opt_line, opt_column,
772 opt_condition, opt_groupId) {
773 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptRegExp,
774 script_regexp, opt_line, opt_column,
775 opt_condition, opt_groupId);
776};
777
778
779Debug.enableScriptBreakPoint = function(break_point_number) {
780 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
781 script_break_point.enable();
782};
783
784
785Debug.disableScriptBreakPoint = function(break_point_number) {
786 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
787 script_break_point.disable();
788};
789
790
791Debug.changeScriptBreakPointCondition = function(
792 break_point_number, condition) {
793 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
794 script_break_point.setCondition(condition);
795};
796
797
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798Debug.scriptBreakPoints = function() {
799 return script_break_points;
800};
801
802
803Debug.clearStepping = function() {
804 %ClearStepping();
805};
806
807Debug.setBreakOnException = function() {
808 return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true);
809};
810
811Debug.clearBreakOnException = function() {
812 return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
813};
814
815Debug.isBreakOnException = function() {
816 return !!%IsBreakOnException(Debug.ExceptionBreak.Caught);
817};
818
819Debug.setBreakOnUncaughtException = function() {
820 return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, true);
821};
822
823Debug.clearBreakOnUncaughtException = function() {
824 return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
825};
826
827Debug.isBreakOnUncaughtException = function() {
828 return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
829};
830
831Debug.showBreakPoints = function(f, full, opt_position_alignment) {
832 if (!IS_FUNCTION(f)) throw MakeError(kDebuggerType);
833 var source = full ? this.scriptSource(f) : this.source(f);
834 var offset = full ? this.sourcePosition(f) : 0;
835 var locations = this.breakLocations(f, opt_position_alignment);
836 if (!locations) return source;
837 locations.sort(function(x, y) { return x - y; });
838 var result = "";
839 var prev_pos = 0;
840 var pos;
841 for (var i = 0; i < locations.length; i++) {
842 pos = locations[i] - offset;
843 result += source.slice(prev_pos, pos);
844 result += "[B" + i + "]";
845 prev_pos = pos;
846 }
847 pos = source.length;
848 result += source.substring(prev_pos, pos);
849 return result;
850};
851
852
853// Get all the scripts currently loaded. Locating all the scripts is based on
854// scanning the heap.
855Debug.scripts = function() {
856 // Collect all scripts in the heap.
857 return %DebugGetLoadedScripts();
858};
859
860
861Debug.debuggerFlags = function() {
862 return debugger_flags;
863};
864
865Debug.MakeMirror = MakeMirror;
866
867function MakeExecutionState(break_id) {
868 return new ExecutionState(break_id);
869}
870
871function ExecutionState(break_id) {
872 this.break_id = break_id;
873 this.selected_frame = 0;
874}
875
876ExecutionState.prototype.prepareStep = function(action) {
877 if (action === Debug.StepAction.StepIn ||
878 action === Debug.StepAction.StepOut ||
879 action === Debug.StepAction.StepNext ||
880 action === Debug.StepAction.StepFrame) {
881 return %PrepareStep(this.break_id, action);
882 }
883 throw MakeTypeError(kDebuggerType);
884};
885
886ExecutionState.prototype.evaluateGlobal = function(source, disable_break,
887 opt_additional_context) {
888 return MakeMirror(%DebugEvaluateGlobal(this.break_id, source,
889 TO_BOOLEAN(disable_break),
890 opt_additional_context));
891};
892
893ExecutionState.prototype.frameCount = function() {
894 return %GetFrameCount(this.break_id);
895};
896
897ExecutionState.prototype.threadCount = function() {
898 return %GetThreadCount(this.break_id);
899};
900
901ExecutionState.prototype.frame = function(opt_index) {
902 // If no index supplied return the selected frame.
903 if (opt_index == null) opt_index = this.selected_frame;
904 if (opt_index < 0 || opt_index >= this.frameCount()) {
905 throw MakeTypeError(kDebuggerFrame);
906 }
907 return new FrameMirror(this.break_id, opt_index);
908};
909
910ExecutionState.prototype.setSelectedFrame = function(index) {
911 var i = TO_NUMBER(index);
912 if (i < 0 || i >= this.frameCount()) {
913 throw MakeTypeError(kDebuggerFrame);
914 }
915 this.selected_frame = i;
916};
917
918ExecutionState.prototype.selectedFrame = function() {
919 return this.selected_frame;
920};
921
922ExecutionState.prototype.debugCommandProcessor = function(opt_is_running) {
923 return new DebugCommandProcessor(this, opt_is_running);
924};
925
926
927function MakeBreakEvent(break_id, break_points_hit) {
928 return new BreakEvent(break_id, break_points_hit);
929}
930
931
932function BreakEvent(break_id, break_points_hit) {
933 this.frame_ = new FrameMirror(break_id, 0);
934 this.break_points_hit_ = break_points_hit;
935}
936
937
938BreakEvent.prototype.eventType = function() {
939 return Debug.DebugEvent.Break;
940};
941
942
943BreakEvent.prototype.func = function() {
944 return this.frame_.func();
945};
946
947
948BreakEvent.prototype.sourceLine = function() {
949 return this.frame_.sourceLine();
950};
951
952
953BreakEvent.prototype.sourceColumn = function() {
954 return this.frame_.sourceColumn();
955};
956
957
958BreakEvent.prototype.sourceLineText = function() {
959 return this.frame_.sourceLineText();
960};
961
962
963BreakEvent.prototype.breakPointsHit = function() {
964 return this.break_points_hit_;
965};
966
967
968BreakEvent.prototype.toJSONProtocol = function() {
969 var o = { seq: next_response_seq++,
970 type: "event",
971 event: "break",
972 body: { invocationText: this.frame_.invocationText() }
973 };
974
975 // Add script related information to the event if available.
976 var script = this.func().script();
977 if (script) {
978 o.body.sourceLine = this.sourceLine(),
979 o.body.sourceColumn = this.sourceColumn(),
980 o.body.sourceLineText = this.sourceLineText(),
981 o.body.script = MakeScriptObject_(script, false);
982 }
983
984 // Add an Array of break points hit if any.
985 if (this.breakPointsHit()) {
986 o.body.breakpoints = [];
987 for (var i = 0; i < this.breakPointsHit().length; i++) {
988 // Find the break point number. For break points originating from a
989 // script break point supply the script break point number.
990 var breakpoint = this.breakPointsHit()[i];
991 var script_break_point = breakpoint.script_break_point();
992 var number;
993 if (script_break_point) {
994 number = script_break_point.number();
995 } else {
996 number = breakpoint.number();
997 }
998 o.body.breakpoints.push(number);
999 }
1000 }
1001 return JSONStringify(ObjectToProtocolObject_(o));
1002};
1003
1004
1005function MakeExceptionEvent(break_id, exception, uncaught, promise) {
1006 return new ExceptionEvent(break_id, exception, uncaught, promise);
1007}
1008
1009
1010function ExceptionEvent(break_id, exception, uncaught, promise) {
1011 this.exec_state_ = new ExecutionState(break_id);
1012 this.exception_ = exception;
1013 this.uncaught_ = uncaught;
1014 this.promise_ = promise;
1015}
1016
1017
1018ExceptionEvent.prototype.eventType = function() {
1019 return Debug.DebugEvent.Exception;
1020};
1021
1022
1023ExceptionEvent.prototype.exception = function() {
1024 return this.exception_;
1025};
1026
1027
1028ExceptionEvent.prototype.uncaught = function() {
1029 return this.uncaught_;
1030};
1031
1032
1033ExceptionEvent.prototype.promise = function() {
1034 return this.promise_;
1035};
1036
1037
1038ExceptionEvent.prototype.func = function() {
1039 return this.exec_state_.frame(0).func();
1040};
1041
1042
1043ExceptionEvent.prototype.sourceLine = function() {
1044 return this.exec_state_.frame(0).sourceLine();
1045};
1046
1047
1048ExceptionEvent.prototype.sourceColumn = function() {
1049 return this.exec_state_.frame(0).sourceColumn();
1050};
1051
1052
1053ExceptionEvent.prototype.sourceLineText = function() {
1054 return this.exec_state_.frame(0).sourceLineText();
1055};
1056
1057
1058ExceptionEvent.prototype.toJSONProtocol = function() {
1059 var o = new ProtocolMessage();
1060 o.event = "exception";
1061 o.body = { uncaught: this.uncaught_,
1062 exception: MakeMirror(this.exception_)
1063 };
1064
1065 // Exceptions might happen whithout any JavaScript frames.
1066 if (this.exec_state_.frameCount() > 0) {
1067 o.body.sourceLine = this.sourceLine();
1068 o.body.sourceColumn = this.sourceColumn();
1069 o.body.sourceLineText = this.sourceLineText();
1070
1071 // Add script information to the event if available.
1072 var script = this.func().script();
1073 if (script) {
1074 o.body.script = MakeScriptObject_(script, false);
1075 }
1076 } else {
1077 o.body.sourceLine = -1;
1078 }
1079
1080 return o.toJSONProtocol();
1081};
1082
1083
1084function MakeCompileEvent(script, type) {
1085 return new CompileEvent(script, type);
1086}
1087
1088
1089function CompileEvent(script, type) {
1090 this.script_ = MakeMirror(script);
1091 this.type_ = type;
1092}
1093
1094
1095CompileEvent.prototype.eventType = function() {
1096 return this.type_;
1097};
1098
1099
1100CompileEvent.prototype.script = function() {
1101 return this.script_;
1102};
1103
1104
1105CompileEvent.prototype.toJSONProtocol = function() {
1106 var o = new ProtocolMessage();
1107 o.running = true;
1108 switch (this.type_) {
1109 case Debug.DebugEvent.BeforeCompile:
1110 o.event = "beforeCompile";
1111 break;
1112 case Debug.DebugEvent.AfterCompile:
1113 o.event = "afterCompile";
1114 break;
1115 case Debug.DebugEvent.CompileError:
1116 o.event = "compileError";
1117 break;
1118 }
1119 o.body = {};
1120 o.body.script = this.script_;
1121
1122 return o.toJSONProtocol();
1123};
1124
1125
1126function MakeScriptObject_(script, include_source) {
1127 var o = { id: script.id(),
1128 name: script.name(),
1129 lineOffset: script.lineOffset(),
1130 columnOffset: script.columnOffset(),
1131 lineCount: script.lineCount(),
1132 };
1133 if (!IS_UNDEFINED(script.data())) {
1134 o.data = script.data();
1135 }
1136 if (include_source) {
1137 o.source = script.source();
1138 }
1139 return o;
1140}
1141
1142
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143function MakeAsyncTaskEvent(event_data) {
1144 return new AsyncTaskEvent(event_data);
1145}
1146
1147
1148function AsyncTaskEvent(event_data) {
1149 this.type_ = event_data.type;
1150 this.name_ = event_data.name;
1151 this.id_ = event_data.id;
1152}
1153
1154
1155AsyncTaskEvent.prototype.type = function() {
1156 return this.type_;
1157}
1158
1159
1160AsyncTaskEvent.prototype.name = function() {
1161 return this.name_;
1162}
1163
1164
1165AsyncTaskEvent.prototype.id = function() {
1166 return this.id_;
1167}
1168
1169
1170function DebugCommandProcessor(exec_state, opt_is_running) {
1171 this.exec_state_ = exec_state;
1172 this.running_ = opt_is_running || false;
1173}
1174
1175
1176DebugCommandProcessor.prototype.processDebugRequest = function (request) {
1177 return this.processDebugJSONRequest(request);
1178};
1179
1180
1181function ProtocolMessage(request) {
1182 // Update sequence number.
1183 this.seq = next_response_seq++;
1184
1185 if (request) {
1186 // If message is based on a request this is a response. Fill the initial
1187 // response from the request.
1188 this.type = 'response';
1189 this.request_seq = request.seq;
1190 this.command = request.command;
1191 } else {
1192 // If message is not based on a request it is a dabugger generated event.
1193 this.type = 'event';
1194 }
1195 this.success = true;
1196 // Handler may set this field to control debugger state.
1197 this.running = UNDEFINED;
1198}
1199
1200
1201ProtocolMessage.prototype.setOption = function(name, value) {
1202 if (!this.options_) {
1203 this.options_ = {};
1204 }
1205 this.options_[name] = value;
1206};
1207
1208
1209ProtocolMessage.prototype.failed = function(message, opt_details) {
1210 this.success = false;
1211 this.message = message;
1212 if (IS_OBJECT(opt_details)) {
1213 this.error_details = opt_details;
1214 }
1215};
1216
1217
1218ProtocolMessage.prototype.toJSONProtocol = function() {
1219 // Encode the protocol header.
1220 var json = {};
1221 json.seq= this.seq;
1222 if (this.request_seq) {
1223 json.request_seq = this.request_seq;
1224 }
1225 json.type = this.type;
1226 if (this.event) {
1227 json.event = this.event;
1228 }
1229 if (this.command) {
1230 json.command = this.command;
1231 }
1232 if (this.success) {
1233 json.success = this.success;
1234 } else {
1235 json.success = false;
1236 }
1237 if (this.body) {
1238 // Encode the body part.
1239 var bodyJson;
1240 var serializer = MakeMirrorSerializer(true, this.options_);
1241 if (this.body instanceof Mirror) {
1242 bodyJson = serializer.serializeValue(this.body);
1243 } else if (this.body instanceof GlobalArray) {
1244 bodyJson = [];
1245 for (var i = 0; i < this.body.length; i++) {
1246 if (this.body[i] instanceof Mirror) {
1247 bodyJson.push(serializer.serializeValue(this.body[i]));
1248 } else {
1249 bodyJson.push(ObjectToProtocolObject_(this.body[i], serializer));
1250 }
1251 }
1252 } else {
1253 bodyJson = ObjectToProtocolObject_(this.body, serializer);
1254 }
1255 json.body = bodyJson;
1256 json.refs = serializer.serializeReferencedObjects();
1257 }
1258 if (this.message) {
1259 json.message = this.message;
1260 }
1261 if (this.error_details) {
1262 json.error_details = this.error_details;
1263 }
1264 json.running = this.running;
1265 return JSONStringify(json);
1266};
1267
1268
1269DebugCommandProcessor.prototype.createResponse = function(request) {
1270 return new ProtocolMessage(request);
1271};
1272
1273
1274DebugCommandProcessor.prototype.processDebugJSONRequest = function(
1275 json_request) {
1276 var request; // Current request.
1277 var response; // Generated response.
1278 try {
1279 try {
1280 // Convert the JSON string to an object.
1281 request = JSONParse(json_request);
1282
1283 // Create an initial response.
1284 response = this.createResponse(request);
1285
1286 if (!request.type) {
1287 throw MakeError(kDebugger, 'Type not specified');
1288 }
1289
1290 if (request.type != 'request') {
1291 throw MakeError(kDebugger,
1292 "Illegal type '" + request.type + "' in request");
1293 }
1294
1295 if (!request.command) {
1296 throw MakeError(kDebugger, 'Command not specified');
1297 }
1298
1299 if (request.arguments) {
1300 var args = request.arguments;
1301 // TODO(yurys): remove request.arguments.compactFormat check once
1302 // ChromeDevTools are switched to 'inlineRefs'
1303 if (args.inlineRefs || args.compactFormat) {
1304 response.setOption('inlineRefs', true);
1305 }
1306 if (!IS_UNDEFINED(args.maxStringLength)) {
1307 response.setOption('maxStringLength', args.maxStringLength);
1308 }
1309 }
1310
1311 var key = request.command.toLowerCase();
1312 var handler = DebugCommandProcessor.prototype.dispatch_[key];
1313 if (IS_FUNCTION(handler)) {
1314 %_Call(handler, this, request, response);
1315 } else {
1316 throw MakeError(kDebugger,
1317 'Unknown command "' + request.command + '" in request');
1318 }
1319 } catch (e) {
1320 // If there is no response object created one (without command).
1321 if (!response) {
1322 response = this.createResponse();
1323 }
1324 response.success = false;
1325 response.message = TO_STRING(e);
1326 }
1327
1328 // Return the response as a JSON encoded string.
1329 try {
1330 if (!IS_UNDEFINED(response.running)) {
1331 // Response controls running state.
1332 this.running_ = response.running;
1333 }
1334 response.running = this.running_;
1335 return response.toJSONProtocol();
1336 } catch (e) {
1337 // Failed to generate response - return generic error.
1338 return '{"seq":' + response.seq + ',' +
1339 '"request_seq":' + request.seq + ',' +
1340 '"type":"response",' +
1341 '"success":false,' +
1342 '"message":"Internal error: ' + TO_STRING(e) + '"}';
1343 }
1344 } catch (e) {
1345 // Failed in one of the catch blocks above - most generic error.
1346 return '{"seq":0,"type":"response","success":false,"message":"Internal error"}';
1347 }
1348};
1349
1350
1351DebugCommandProcessor.prototype.continueRequest_ = function(request, response) {
1352 // Check for arguments for continue.
1353 if (request.arguments) {
1354 var action = Debug.StepAction.StepIn;
1355
1356 // Pull out arguments.
1357 var stepaction = request.arguments.stepaction;
1358
1359 // Get the stepaction argument.
1360 if (stepaction) {
1361 if (stepaction == 'in') {
1362 action = Debug.StepAction.StepIn;
1363 } else if (stepaction == 'next') {
1364 action = Debug.StepAction.StepNext;
1365 } else if (stepaction == 'out') {
1366 action = Debug.StepAction.StepOut;
1367 } else {
1368 throw MakeError(kDebugger,
1369 'Invalid stepaction argument "' + stepaction + '".');
1370 }
1371 }
1372
1373 // Set up the VM for stepping.
1374 this.exec_state_.prepareStep(action);
1375 }
1376
1377 // VM should be running after executing this request.
1378 response.running = true;
1379};
1380
1381
1382DebugCommandProcessor.prototype.breakRequest_ = function(request, response) {
1383 // Ignore as break command does not do anything when broken.
1384};
1385
1386
1387DebugCommandProcessor.prototype.setBreakPointRequest_ =
1388 function(request, response) {
1389 // Check for legal request.
1390 if (!request.arguments) {
1391 response.failed('Missing arguments');
1392 return;
1393 }
1394
1395 // Pull out arguments.
1396 var type = request.arguments.type;
1397 var target = request.arguments.target;
1398 var line = request.arguments.line;
1399 var column = request.arguments.column;
1400 var enabled = IS_UNDEFINED(request.arguments.enabled) ?
1401 true : request.arguments.enabled;
1402 var condition = request.arguments.condition;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 var groupId = request.arguments.groupId;
1404
1405 // Check for legal arguments.
1406 if (!type || IS_UNDEFINED(target)) {
1407 response.failed('Missing argument "type" or "target"');
1408 return;
1409 }
1410
1411 // Either function or script break point.
1412 var break_point_number;
1413 if (type == 'function') {
1414 // Handle function break point.
1415 if (!IS_STRING(target)) {
1416 response.failed('Argument "target" is not a string value');
1417 return;
1418 }
1419 var f;
1420 try {
1421 // Find the function through a global evaluate.
1422 f = this.exec_state_.evaluateGlobal(target).value();
1423 } catch (e) {
1424 response.failed('Error: "' + TO_STRING(e) +
1425 '" evaluating "' + target + '"');
1426 return;
1427 }
1428 if (!IS_FUNCTION(f)) {
1429 response.failed('"' + target + '" does not evaluate to a function');
1430 return;
1431 }
1432
1433 // Set function break point.
1434 break_point_number = Debug.setBreakPoint(f, line, column, condition);
1435 } else if (type == 'handle') {
1436 // Find the object pointed by the specified handle.
1437 var handle = ParseInt(target, 10);
1438 var mirror = LookupMirror(handle);
1439 if (!mirror) {
1440 return response.failed('Object #' + handle + '# not found');
1441 }
1442 if (!mirror.isFunction()) {
1443 return response.failed('Object #' + handle + '# is not a function');
1444 }
1445
1446 // Set function break point.
1447 break_point_number = Debug.setBreakPoint(mirror.value(),
1448 line, column, condition);
1449 } else if (type == 'script') {
1450 // set script break point.
1451 break_point_number =
1452 Debug.setScriptBreakPointByName(target, line, column, condition,
1453 groupId);
1454 } else if (type == 'scriptId') {
1455 break_point_number =
1456 Debug.setScriptBreakPointById(target, line, column, condition, groupId);
1457 } else if (type == 'scriptRegExp') {
1458 break_point_number =
1459 Debug.setScriptBreakPointByRegExp(target, line, column, condition,
1460 groupId);
1461 } else {
1462 response.failed('Illegal type "' + type + '"');
1463 return;
1464 }
1465
1466 // Set additional break point properties.
1467 var break_point = Debug.findBreakPoint(break_point_number);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 if (!enabled) {
1469 Debug.disableBreakPoint(break_point_number);
1470 }
1471
1472 // Add the break point number to the response.
1473 response.body = { type: type,
1474 breakpoint: break_point_number };
1475
1476 // Add break point information to the response.
1477 if (break_point instanceof ScriptBreakPoint) {
1478 if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
1479 response.body.type = 'scriptId';
1480 response.body.script_id = break_point.script_id();
1481 } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptName) {
1482 response.body.type = 'scriptName';
1483 response.body.script_name = break_point.script_name();
1484 } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptRegExp) {
1485 response.body.type = 'scriptRegExp';
1486 response.body.script_regexp = break_point.script_regexp_object().source;
1487 } else {
1488 throw MakeError(kDebugger,
1489 "Unexpected breakpoint type: " + break_point.type());
1490 }
1491 response.body.line = break_point.line();
1492 response.body.column = break_point.column();
1493 response.body.actual_locations = break_point.actual_locations();
1494 } else {
1495 response.body.type = 'function';
1496 response.body.actual_locations = [break_point.actual_location];
1497 }
1498};
1499
1500
1501DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(
1502 request, response) {
1503 // Check for legal request.
1504 if (!request.arguments) {
1505 response.failed('Missing arguments');
1506 return;
1507 }
1508
1509 // Pull out arguments.
1510 var break_point = TO_NUMBER(request.arguments.breakpoint);
1511 var enabled = request.arguments.enabled;
1512 var condition = request.arguments.condition;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001513
1514 // Check for legal arguments.
1515 if (!break_point) {
1516 response.failed('Missing argument "breakpoint"');
1517 return;
1518 }
1519
1520 // Change enabled state if supplied.
1521 if (!IS_UNDEFINED(enabled)) {
1522 if (enabled) {
1523 Debug.enableBreakPoint(break_point);
1524 } else {
1525 Debug.disableBreakPoint(break_point);
1526 }
1527 }
1528
1529 // Change condition if supplied
1530 if (!IS_UNDEFINED(condition)) {
1531 Debug.changeBreakPointCondition(break_point, condition);
1532 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001533};
1534
1535
1536DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(
1537 request, response) {
1538 // Check for legal request.
1539 if (!request.arguments) {
1540 response.failed('Missing arguments');
1541 return;
1542 }
1543
1544 // Pull out arguments.
1545 var group_id = request.arguments.groupId;
1546
1547 // Check for legal arguments.
1548 if (!group_id) {
1549 response.failed('Missing argument "groupId"');
1550 return;
1551 }
1552
1553 var cleared_break_points = [];
1554 var new_script_break_points = [];
1555 for (var i = 0; i < script_break_points.length; i++) {
1556 var next_break_point = script_break_points[i];
1557 if (next_break_point.groupId() == group_id) {
1558 cleared_break_points.push(next_break_point.number());
1559 next_break_point.clear();
1560 } else {
1561 new_script_break_points.push(next_break_point);
1562 }
1563 }
1564 script_break_points = new_script_break_points;
1565
1566 // Add the cleared break point numbers to the response.
1567 response.body = { breakpoints: cleared_break_points };
1568};
1569
1570
1571DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(
1572 request, response) {
1573 // Check for legal request.
1574 if (!request.arguments) {
1575 response.failed('Missing arguments');
1576 return;
1577 }
1578
1579 // Pull out arguments.
1580 var break_point = TO_NUMBER(request.arguments.breakpoint);
1581
1582 // Check for legal arguments.
1583 if (!break_point) {
1584 response.failed('Missing argument "breakpoint"');
1585 return;
1586 }
1587
1588 // Clear break point.
1589 Debug.clearBreakPoint(break_point);
1590
1591 // Add the cleared break point number to the response.
1592 response.body = { breakpoint: break_point };
1593};
1594
1595
1596DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(
1597 request, response) {
1598 var array = [];
1599 for (var i = 0; i < script_break_points.length; i++) {
1600 var break_point = script_break_points[i];
1601
1602 var description = {
1603 number: break_point.number(),
1604 line: break_point.line(),
1605 column: break_point.column(),
1606 groupId: break_point.groupId(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001607 active: break_point.active(),
1608 condition: break_point.condition(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001609 actual_locations: break_point.actual_locations()
1610 };
1611
1612 if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
1613 description.type = 'scriptId';
1614 description.script_id = break_point.script_id();
1615 } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptName) {
1616 description.type = 'scriptName';
1617 description.script_name = break_point.script_name();
1618 } else if (break_point.type() == Debug.ScriptBreakPointType.ScriptRegExp) {
1619 description.type = 'scriptRegExp';
1620 description.script_regexp = break_point.script_regexp_object().source;
1621 } else {
1622 throw MakeError(kDebugger,
1623 "Unexpected breakpoint type: " + break_point.type());
1624 }
1625 array.push(description);
1626 }
1627
1628 response.body = {
1629 breakpoints: array,
1630 breakOnExceptions: Debug.isBreakOnException(),
1631 breakOnUncaughtExceptions: Debug.isBreakOnUncaughtException()
1632 };
1633};
1634
1635
1636DebugCommandProcessor.prototype.disconnectRequest_ =
1637 function(request, response) {
1638 Debug.disableAllBreakPoints();
1639 this.continueRequest_(request, response);
1640};
1641
1642
1643DebugCommandProcessor.prototype.setExceptionBreakRequest_ =
1644 function(request, response) {
1645 // Check for legal request.
1646 if (!request.arguments) {
1647 response.failed('Missing arguments');
1648 return;
1649 }
1650
1651 // Pull out and check the 'type' argument:
1652 var type = request.arguments.type;
1653 if (!type) {
1654 response.failed('Missing argument "type"');
1655 return;
1656 }
1657
1658 // Initialize the default value of enable:
1659 var enabled;
1660 if (type == 'all') {
1661 enabled = !Debug.isBreakOnException();
1662 } else if (type == 'uncaught') {
1663 enabled = !Debug.isBreakOnUncaughtException();
1664 }
1665
1666 // Pull out and check the 'enabled' argument if present:
1667 if (!IS_UNDEFINED(request.arguments.enabled)) {
1668 enabled = request.arguments.enabled;
1669 if ((enabled != true) && (enabled != false)) {
1670 response.failed('Illegal value for "enabled":"' + enabled + '"');
1671 }
1672 }
1673
1674 // Now set the exception break state:
1675 if (type == 'all') {
1676 %ChangeBreakOnException(Debug.ExceptionBreak.Caught, enabled);
1677 } else if (type == 'uncaught') {
1678 %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, enabled);
1679 } else {
1680 response.failed('Unknown "type":"' + type + '"');
1681 }
1682
1683 // Add the cleared break point number to the response.
1684 response.body = { 'type': type, 'enabled': enabled };
1685};
1686
1687
1688DebugCommandProcessor.prototype.backtraceRequest_ = function(
1689 request, response) {
1690 // Get the number of frames.
1691 var total_frames = this.exec_state_.frameCount();
1692
1693 // Create simple response if there are no frames.
1694 if (total_frames == 0) {
1695 response.body = {
1696 totalFrames: total_frames
1697 };
1698 return;
1699 }
1700
1701 // Default frame range to include in backtrace.
1702 var from_index = 0;
1703 var to_index = kDefaultBacktraceLength;
1704
1705 // Get the range from the arguments.
1706 if (request.arguments) {
1707 if (request.arguments.fromFrame) {
1708 from_index = request.arguments.fromFrame;
1709 }
1710 if (request.arguments.toFrame) {
1711 to_index = request.arguments.toFrame;
1712 }
1713 if (request.arguments.bottom) {
1714 var tmp_index = total_frames - from_index;
1715 from_index = total_frames - to_index;
1716 to_index = tmp_index;
1717 }
1718 if (from_index < 0 || to_index < 0) {
1719 return response.failed('Invalid frame number');
1720 }
1721 }
1722
1723 // Adjust the index.
1724 to_index = MathMin(total_frames, to_index);
1725
1726 if (to_index <= from_index) {
1727 var error = 'Invalid frame range';
1728 return response.failed(error);
1729 }
1730
1731 // Create the response body.
1732 var frames = [];
1733 for (var i = from_index; i < to_index; i++) {
1734 frames.push(this.exec_state_.frame(i));
1735 }
1736 response.body = {
1737 fromFrame: from_index,
1738 toFrame: to_index,
1739 totalFrames: total_frames,
1740 frames: frames
1741 };
1742};
1743
1744
1745DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
1746 // No frames no source.
1747 if (this.exec_state_.frameCount() == 0) {
1748 return response.failed('No frames');
1749 }
1750
1751 // With no arguments just keep the selected frame.
1752 if (request.arguments) {
1753 var index = request.arguments.number;
1754 if (index < 0 || this.exec_state_.frameCount() <= index) {
1755 return response.failed('Invalid frame number');
1756 }
1757
1758 this.exec_state_.setSelectedFrame(request.arguments.number);
1759 }
1760 response.body = this.exec_state_.frame();
1761};
1762
1763
1764DebugCommandProcessor.prototype.resolveFrameFromScopeDescription_ =
1765 function(scope_description) {
1766 // Get the frame for which the scope or scopes are requested.
1767 // With no frameNumber argument use the currently selected frame.
1768 if (scope_description && !IS_UNDEFINED(scope_description.frameNumber)) {
1769 var frame_index = scope_description.frameNumber;
1770 if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
1771 throw MakeTypeError(kDebuggerFrame);
1772 }
1773 return this.exec_state_.frame(frame_index);
1774 } else {
1775 return this.exec_state_.frame();
1776 }
1777};
1778
1779
1780// Gets scope host object from request. It is either a function
1781// ('functionHandle' argument must be specified) or a stack frame
1782// ('frameNumber' may be specified and the current frame is taken by default).
1783DebugCommandProcessor.prototype.resolveScopeHolder_ =
1784 function(scope_description) {
1785 if (scope_description && "functionHandle" in scope_description) {
1786 if (!IS_NUMBER(scope_description.functionHandle)) {
1787 throw MakeError(kDebugger, 'Function handle must be a number');
1788 }
1789 var function_mirror = LookupMirror(scope_description.functionHandle);
1790 if (!function_mirror) {
1791 throw MakeError(kDebugger, 'Failed to find function object by handle');
1792 }
1793 if (!function_mirror.isFunction()) {
1794 throw MakeError(kDebugger,
1795 'Value of non-function type is found by handle');
1796 }
1797 return function_mirror;
1798 } else {
1799 // No frames no scopes.
1800 if (this.exec_state_.frameCount() == 0) {
1801 throw MakeError(kDebugger, 'No scopes');
1802 }
1803
1804 // Get the frame for which the scopes are requested.
1805 var frame = this.resolveFrameFromScopeDescription_(scope_description);
1806 return frame;
1807 }
1808}
1809
1810
1811DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
1812 var scope_holder = this.resolveScopeHolder_(request.arguments);
1813
1814 // Fill all scopes for this frame or function.
1815 var total_scopes = scope_holder.scopeCount();
1816 var scopes = [];
1817 for (var i = 0; i < total_scopes; i++) {
1818 scopes.push(scope_holder.scope(i));
1819 }
1820 response.body = {
1821 fromScope: 0,
1822 toScope: total_scopes,
1823 totalScopes: total_scopes,
1824 scopes: scopes
1825 };
1826};
1827
1828
1829DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
1830 // Get the frame or function for which the scope is requested.
1831 var scope_holder = this.resolveScopeHolder_(request.arguments);
1832
1833 // With no scope argument just return top scope.
1834 var scope_index = 0;
1835 if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
1836 scope_index = TO_NUMBER(request.arguments.number);
1837 if (scope_index < 0 || scope_holder.scopeCount() <= scope_index) {
1838 return response.failed('Invalid scope number');
1839 }
1840 }
1841
1842 response.body = scope_holder.scope(scope_index);
1843};
1844
1845
1846// Reads value from protocol description. Description may be in form of type
1847// (for singletons), raw value (primitive types supported in JSON),
1848// string value description plus type (for primitive values) or handle id.
1849// Returns raw value or throws exception.
1850DebugCommandProcessor.resolveValue_ = function(value_description) {
1851 if ("handle" in value_description) {
1852 var value_mirror = LookupMirror(value_description.handle);
1853 if (!value_mirror) {
1854 throw MakeError(kDebugger, "Failed to resolve value by handle, ' #" +
1855 value_description.handle + "# not found");
1856 }
1857 return value_mirror.value();
1858 } else if ("stringDescription" in value_description) {
1859 if (value_description.type == MirrorType.BOOLEAN_TYPE) {
1860 return TO_BOOLEAN(value_description.stringDescription);
1861 } else if (value_description.type == MirrorType.NUMBER_TYPE) {
1862 return TO_NUMBER(value_description.stringDescription);
1863 } if (value_description.type == MirrorType.STRING_TYPE) {
1864 return TO_STRING(value_description.stringDescription);
1865 } else {
1866 throw MakeError(kDebugger, "Unknown type");
1867 }
1868 } else if ("value" in value_description) {
1869 return value_description.value;
1870 } else if (value_description.type == MirrorType.UNDEFINED_TYPE) {
1871 return UNDEFINED;
1872 } else if (value_description.type == MirrorType.NULL_TYPE) {
1873 return null;
1874 } else {
1875 throw MakeError(kDebugger, "Failed to parse value description");
1876 }
1877};
1878
1879
1880DebugCommandProcessor.prototype.setVariableValueRequest_ =
1881 function(request, response) {
1882 if (!request.arguments) {
1883 response.failed('Missing arguments');
1884 return;
1885 }
1886
1887 if (IS_UNDEFINED(request.arguments.name)) {
1888 response.failed('Missing variable name');
1889 }
1890 var variable_name = request.arguments.name;
1891
1892 var scope_description = request.arguments.scope;
1893
1894 // Get the frame or function for which the scope is requested.
1895 var scope_holder = this.resolveScopeHolder_(scope_description);
1896
1897 if (IS_UNDEFINED(scope_description.number)) {
1898 response.failed('Missing scope number');
1899 }
1900 var scope_index = TO_NUMBER(scope_description.number);
1901
1902 var scope = scope_holder.scope(scope_index);
1903
1904 var new_value =
1905 DebugCommandProcessor.resolveValue_(request.arguments.newValue);
1906
1907 scope.setVariableValue(variable_name, new_value);
1908
1909 var new_value_mirror = MakeMirror(new_value);
1910
1911 response.body = {
1912 newValue: new_value_mirror
1913 };
1914};
1915
1916
1917DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) {
1918 if (!request.arguments) {
1919 return response.failed('Missing arguments');
1920 }
1921
1922 // Pull out arguments.
1923 var expression = request.arguments.expression;
1924 var frame = request.arguments.frame;
1925 var global = request.arguments.global;
1926 var disable_break = request.arguments.disable_break;
1927 var additional_context = request.arguments.additional_context;
1928
1929 // The expression argument could be an integer so we convert it to a
1930 // string.
1931 try {
1932 expression = TO_STRING(expression);
1933 } catch(e) {
1934 return response.failed('Failed to convert expression argument to string');
1935 }
1936
1937 // Check for legal arguments.
1938 if (!IS_UNDEFINED(frame) && global) {
1939 return response.failed('Arguments "frame" and "global" are exclusive');
1940 }
1941
1942 var additional_context_object;
1943 if (additional_context) {
1944 additional_context_object = {};
1945 for (var i = 0; i < additional_context.length; i++) {
1946 var mapping = additional_context[i];
1947
1948 if (!IS_STRING(mapping.name)) {
1949 return response.failed("Context element #" + i +
1950 " doesn't contain name:string property");
1951 }
1952
1953 var raw_value = DebugCommandProcessor.resolveValue_(mapping);
1954 additional_context_object[mapping.name] = raw_value;
1955 }
1956 }
1957
1958 // Global evaluate.
1959 if (global) {
1960 // Evaluate in the native context.
1961 response.body = this.exec_state_.evaluateGlobal(
1962 expression, TO_BOOLEAN(disable_break), additional_context_object);
1963 return;
1964 }
1965
1966 // Default value for disable_break is true.
1967 if (IS_UNDEFINED(disable_break)) {
1968 disable_break = true;
1969 }
1970
1971 // No frames no evaluate in frame.
1972 if (this.exec_state_.frameCount() == 0) {
1973 return response.failed('No frames');
1974 }
1975
1976 // Check whether a frame was specified.
1977 if (!IS_UNDEFINED(frame)) {
1978 var frame_number = TO_NUMBER(frame);
1979 if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
1980 return response.failed('Invalid frame "' + frame + '"');
1981 }
1982 // Evaluate in the specified frame.
1983 response.body = this.exec_state_.frame(frame_number).evaluate(
1984 expression, TO_BOOLEAN(disable_break), additional_context_object);
1985 return;
1986 } else {
1987 // Evaluate in the selected frame.
1988 response.body = this.exec_state_.frame().evaluate(
1989 expression, TO_BOOLEAN(disable_break), additional_context_object);
1990 return;
1991 }
1992};
1993
1994
1995DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
1996 if (!request.arguments) {
1997 return response.failed('Missing arguments');
1998 }
1999
2000 // Pull out arguments.
2001 var handles = request.arguments.handles;
2002
2003 // Check for legal arguments.
2004 if (IS_UNDEFINED(handles)) {
2005 return response.failed('Argument "handles" missing');
2006 }
2007
2008 // Set 'includeSource' option for script lookup.
2009 if (!IS_UNDEFINED(request.arguments.includeSource)) {
2010 var includeSource = TO_BOOLEAN(request.arguments.includeSource);
2011 response.setOption('includeSource', includeSource);
2012 }
2013
2014 // Lookup handles.
2015 var mirrors = {};
2016 for (var i = 0; i < handles.length; i++) {
2017 var handle = handles[i];
2018 var mirror = LookupMirror(handle);
2019 if (!mirror) {
2020 return response.failed('Object #' + handle + '# not found');
2021 }
2022 mirrors[handle] = mirror;
2023 }
2024 response.body = mirrors;
2025};
2026
2027
2028DebugCommandProcessor.prototype.referencesRequest_ =
2029 function(request, response) {
2030 if (!request.arguments) {
2031 return response.failed('Missing arguments');
2032 }
2033
2034 // Pull out arguments.
2035 var type = request.arguments.type;
2036 var handle = request.arguments.handle;
2037
2038 // Check for legal arguments.
2039 if (IS_UNDEFINED(type)) {
2040 return response.failed('Argument "type" missing');
2041 }
2042 if (IS_UNDEFINED(handle)) {
2043 return response.failed('Argument "handle" missing');
2044 }
2045 if (type != 'referencedBy' && type != 'constructedBy') {
2046 return response.failed('Invalid type "' + type + '"');
2047 }
2048
2049 // Lookup handle and return objects with references the object.
2050 var mirror = LookupMirror(handle);
2051 if (mirror) {
2052 if (type == 'referencedBy') {
2053 response.body = mirror.referencedBy();
2054 } else {
2055 response.body = mirror.constructedBy();
2056 }
2057 } else {
2058 return response.failed('Object #' + handle + '# not found');
2059 }
2060};
2061
2062
2063DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
2064 // No frames no source.
2065 if (this.exec_state_.frameCount() == 0) {
2066 return response.failed('No source');
2067 }
2068
2069 var from_line;
2070 var to_line;
2071 var frame = this.exec_state_.frame();
2072 if (request.arguments) {
2073 // Pull out arguments.
2074 from_line = request.arguments.fromLine;
2075 to_line = request.arguments.toLine;
2076
2077 if (!IS_UNDEFINED(request.arguments.frame)) {
2078 var frame_number = TO_NUMBER(request.arguments.frame);
2079 if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
2080 return response.failed('Invalid frame "' + frame + '"');
2081 }
2082 frame = this.exec_state_.frame(frame_number);
2083 }
2084 }
2085
2086 // Get the script selected.
2087 var script = frame.func().script();
2088 if (!script) {
2089 return response.failed('No source');
2090 }
2091
2092 // Get the source slice and fill it into the response.
2093 var slice = script.sourceSlice(from_line, to_line);
2094 if (!slice) {
2095 return response.failed('Invalid line interval');
2096 }
2097 response.body = {};
2098 response.body.source = slice.sourceText();
2099 response.body.fromLine = slice.from_line;
2100 response.body.toLine = slice.to_line;
2101 response.body.fromPosition = slice.from_position;
2102 response.body.toPosition = slice.to_position;
2103 response.body.totalLines = script.lineCount();
2104};
2105
2106
2107DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
2108 var types = ScriptTypeFlag(Debug.ScriptType.Normal);
2109 var includeSource = false;
2110 var idsToInclude = null;
2111 if (request.arguments) {
2112 // Pull out arguments.
2113 if (!IS_UNDEFINED(request.arguments.types)) {
2114 types = TO_NUMBER(request.arguments.types);
2115 if (IsNaN(types) || types < 0) {
2116 return response.failed('Invalid types "' +
2117 request.arguments.types + '"');
2118 }
2119 }
2120
2121 if (!IS_UNDEFINED(request.arguments.includeSource)) {
2122 includeSource = TO_BOOLEAN(request.arguments.includeSource);
2123 response.setOption('includeSource', includeSource);
2124 }
2125
2126 if (IS_ARRAY(request.arguments.ids)) {
2127 idsToInclude = {};
2128 var ids = request.arguments.ids;
2129 for (var i = 0; i < ids.length; i++) {
2130 idsToInclude[ids[i]] = true;
2131 }
2132 }
2133
2134 var filterStr = null;
2135 var filterNum = null;
2136 if (!IS_UNDEFINED(request.arguments.filter)) {
2137 var num = TO_NUMBER(request.arguments.filter);
2138 if (!IsNaN(num)) {
2139 filterNum = num;
2140 }
2141 filterStr = request.arguments.filter;
2142 }
2143 }
2144
2145 // Collect all scripts in the heap.
2146 var scripts = %DebugGetLoadedScripts();
2147
2148 response.body = [];
2149
2150 for (var i = 0; i < scripts.length; i++) {
2151 if (idsToInclude && !idsToInclude[scripts[i].id]) {
2152 continue;
2153 }
2154 if (filterStr || filterNum) {
2155 var script = scripts[i];
2156 var found = false;
2157 if (filterNum && !found) {
2158 if (script.id && script.id === filterNum) {
2159 found = true;
2160 }
2161 }
2162 if (filterStr && !found) {
2163 if (script.name && script.name.indexOf(filterStr) >= 0) {
2164 found = true;
2165 }
2166 }
2167 if (!found) continue;
2168 }
2169 if (types & ScriptTypeFlag(scripts[i].type)) {
2170 response.body.push(MakeMirror(scripts[i]));
2171 }
2172 }
2173};
2174
2175
2176DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
2177 // Get the number of threads.
2178 var total_threads = this.exec_state_.threadCount();
2179
2180 // Get information for all threads.
2181 var threads = [];
2182 for (var i = 0; i < total_threads; i++) {
2183 var details = %GetThreadDetails(this.exec_state_.break_id, i);
2184 var thread_info = { current: details[0],
2185 id: details[1]
2186 };
2187 threads.push(thread_info);
2188 }
2189
2190 // Create the response body.
2191 response.body = {
2192 totalThreads: total_threads,
2193 threads: threads
2194 };
2195};
2196
2197
2198DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
2199 response.running = false;
2200};
2201
2202
2203DebugCommandProcessor.prototype.versionRequest_ = function(request, response) {
2204 response.body = {
2205 V8Version: %GetV8Version()
2206 };
2207};
2208
2209
2210DebugCommandProcessor.prototype.changeLiveRequest_ = function(
2211 request, response) {
2212 if (!request.arguments) {
2213 return response.failed('Missing arguments');
2214 }
2215 var script_id = request.arguments.script_id;
2216 var preview_only = !!request.arguments.preview_only;
2217
2218 var scripts = %DebugGetLoadedScripts();
2219
2220 var the_script = null;
2221 for (var i = 0; i < scripts.length; i++) {
2222 if (scripts[i].id == script_id) {
2223 the_script = scripts[i];
2224 }
2225 }
2226 if (!the_script) {
2227 response.failed('Script not found');
2228 return;
2229 }
2230
2231 var change_log = new GlobalArray();
2232
2233 if (!IS_STRING(request.arguments.new_source)) {
2234 throw "new_source argument expected";
2235 }
2236
2237 var new_source = request.arguments.new_source;
2238
2239 var result_description;
2240 try {
2241 result_description = Debug.LiveEdit.SetScriptSource(the_script,
2242 new_source, preview_only, change_log);
2243 } catch (e) {
2244 if (e instanceof Debug.LiveEdit.Failure && "details" in e) {
2245 response.failed(e.message, e.details);
2246 return;
2247 }
2248 throw e;
2249 }
2250 response.body = {change_log: change_log, result: result_description};
2251
2252 if (!preview_only && !this.running_ && result_description.stack_modified) {
2253 response.body.stepin_recommended = true;
2254 }
2255};
2256
2257
2258DebugCommandProcessor.prototype.restartFrameRequest_ = function(
2259 request, response) {
2260 if (!request.arguments) {
2261 return response.failed('Missing arguments');
2262 }
2263 var frame = request.arguments.frame;
2264
2265 // No frames to evaluate in frame.
2266 if (this.exec_state_.frameCount() == 0) {
2267 return response.failed('No frames');
2268 }
2269
2270 var frame_mirror;
2271 // Check whether a frame was specified.
2272 if (!IS_UNDEFINED(frame)) {
2273 var frame_number = TO_NUMBER(frame);
2274 if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
2275 return response.failed('Invalid frame "' + frame + '"');
2276 }
2277 // Restart specified frame.
2278 frame_mirror = this.exec_state_.frame(frame_number);
2279 } else {
2280 // Restart selected frame.
2281 frame_mirror = this.exec_state_.frame();
2282 }
2283
Ben Murdoch097c5b22016-05-18 11:27:45 +01002284 var result_description = frame_mirror.restart();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002285 response.body = {result: result_description};
2286};
2287
2288
2289DebugCommandProcessor.prototype.debuggerFlagsRequest_ = function(request,
2290 response) {
2291 // Check for legal request.
2292 if (!request.arguments) {
2293 response.failed('Missing arguments');
2294 return;
2295 }
2296
2297 // Pull out arguments.
2298 var flags = request.arguments.flags;
2299
2300 response.body = { flags: [] };
2301 if (!IS_UNDEFINED(flags)) {
2302 for (var i = 0; i < flags.length; i++) {
2303 var name = flags[i].name;
2304 var debugger_flag = debugger_flags[name];
2305 if (!debugger_flag) {
2306 continue;
2307 }
2308 if ('value' in flags[i]) {
2309 debugger_flag.setValue(flags[i].value);
2310 }
2311 response.body.flags.push({ name: name, value: debugger_flag.getValue() });
2312 }
2313 } else {
2314 for (var name in debugger_flags) {
2315 var value = debugger_flags[name].getValue();
2316 response.body.flags.push({ name: name, value: value });
2317 }
2318 }
2319};
2320
2321
2322DebugCommandProcessor.prototype.v8FlagsRequest_ = function(request, response) {
2323 var flags = request.arguments.flags;
2324 if (!flags) flags = '';
2325 %SetFlags(flags);
2326};
2327
2328
2329DebugCommandProcessor.prototype.gcRequest_ = function(request, response) {
2330 var type = request.arguments.type;
2331 if (!type) type = 'all';
2332
2333 var before = %GetHeapUsage();
2334 %CollectGarbage(type);
2335 var after = %GetHeapUsage();
2336
2337 response.body = { "before": before, "after": after };
2338};
2339
2340
2341DebugCommandProcessor.prototype.dispatch_ = (function() {
2342 var proto = DebugCommandProcessor.prototype;
2343 return {
2344 "continue": proto.continueRequest_,
2345 "break" : proto.breakRequest_,
2346 "setbreakpoint" : proto.setBreakPointRequest_,
2347 "changebreakpoint": proto.changeBreakPointRequest_,
2348 "clearbreakpoint": proto.clearBreakPointRequest_,
2349 "clearbreakpointgroup": proto.clearBreakPointGroupRequest_,
2350 "disconnect": proto.disconnectRequest_,
2351 "setexceptionbreak": proto.setExceptionBreakRequest_,
2352 "listbreakpoints": proto.listBreakpointsRequest_,
2353 "backtrace": proto.backtraceRequest_,
2354 "frame": proto.frameRequest_,
2355 "scopes": proto.scopesRequest_,
2356 "scope": proto.scopeRequest_,
2357 "setvariablevalue": proto.setVariableValueRequest_,
2358 "evaluate": proto.evaluateRequest_,
2359 "lookup": proto.lookupRequest_,
2360 "references": proto.referencesRequest_,
2361 "source": proto.sourceRequest_,
2362 "scripts": proto.scriptsRequest_,
2363 "threads": proto.threadsRequest_,
2364 "suspend": proto.suspendRequest_,
2365 "version": proto.versionRequest_,
2366 "changelive": proto.changeLiveRequest_,
2367 "restartframe": proto.restartFrameRequest_,
2368 "flags": proto.debuggerFlagsRequest_,
2369 "v8flag": proto.v8FlagsRequest_,
2370 "gc": proto.gcRequest_,
2371 };
2372})();
2373
2374
2375// Check whether the previously processed command caused the VM to become
2376// running.
2377DebugCommandProcessor.prototype.isRunning = function() {
2378 return this.running_;
2379};
2380
2381
2382DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
2383 return %SystemBreak();
2384};
2385
2386
2387/**
2388 * Convert an Object to its debugger protocol representation. The representation
2389 * may be serilized to a JSON object using JSON.stringify().
2390 * This implementation simply runs through all string property names, converts
2391 * each property value to a protocol value and adds the property to the result
2392 * object. For type "object" the function will be called recursively. Note that
2393 * circular structures will cause infinite recursion.
2394 * @param {Object} object The object to format as protocol object.
2395 * @param {MirrorSerializer} mirror_serializer The serializer to use if any
2396 * mirror objects are encountered.
2397 * @return {Object} Protocol object value.
2398 */
2399function ObjectToProtocolObject_(object, mirror_serializer) {
2400 var content = {};
2401 for (var key in object) {
2402 // Only consider string keys.
2403 if (typeof key == 'string') {
2404 // Format the value based on its type.
2405 var property_value_json = ValueToProtocolValue_(object[key],
2406 mirror_serializer);
2407 // Add the property if relevant.
2408 if (!IS_UNDEFINED(property_value_json)) {
2409 content[key] = property_value_json;
2410 }
2411 }
2412 }
2413
2414 return content;
2415}
2416
2417
2418/**
2419 * Convert an array to its debugger protocol representation. It will convert
2420 * each array element to a protocol value.
2421 * @param {Array} array The array to format as protocol array.
2422 * @param {MirrorSerializer} mirror_serializer The serializer to use if any
2423 * mirror objects are encountered.
2424 * @return {Array} Protocol array value.
2425 */
2426function ArrayToProtocolArray_(array, mirror_serializer) {
2427 var json = [];
2428 for (var i = 0; i < array.length; i++) {
2429 json.push(ValueToProtocolValue_(array[i], mirror_serializer));
2430 }
2431 return json;
2432}
2433
2434
2435/**
2436 * Convert a value to its debugger protocol representation.
2437 * @param {*} value The value to format as protocol value.
2438 * @param {MirrorSerializer} mirror_serializer The serializer to use if any
2439 * mirror objects are encountered.
2440 * @return {*} Protocol value.
2441 */
2442function ValueToProtocolValue_(value, mirror_serializer) {
2443 // Format the value based on its type.
2444 var json;
2445 switch (typeof value) {
2446 case 'object':
2447 if (value instanceof Mirror) {
2448 json = mirror_serializer.serializeValue(value);
2449 } else if (IS_ARRAY(value)){
2450 json = ArrayToProtocolArray_(value, mirror_serializer);
2451 } else {
2452 json = ObjectToProtocolObject_(value, mirror_serializer);
2453 }
2454 break;
2455
2456 case 'boolean':
2457 case 'string':
2458 case 'number':
2459 json = value;
2460 break;
2461
2462 default:
2463 json = null;
2464 }
2465 return json;
2466}
2467
2468
2469// -------------------------------------------------------------------
2470// Exports
2471
2472utils.InstallConstants(global, [
2473 "Debug", Debug,
2474 "DebugCommandProcessor", DebugCommandProcessor,
2475 "BreakEvent", BreakEvent,
2476 "CompileEvent", CompileEvent,
2477 "BreakPoint", BreakPoint,
2478]);
2479
2480// Functions needed by the debugger runtime.
2481utils.InstallFunctions(utils, DONT_ENUM, [
2482 "MakeExecutionState", MakeExecutionState,
2483 "MakeExceptionEvent", MakeExceptionEvent,
2484 "MakeBreakEvent", MakeBreakEvent,
2485 "MakeCompileEvent", MakeCompileEvent,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002486 "MakeAsyncTaskEvent", MakeAsyncTaskEvent,
2487 "IsBreakPointTriggered", IsBreakPointTriggered,
2488 "UpdateScriptBreakPoints", UpdateScriptBreakPoints,
2489]);
2490
2491// Export to liveedit.js
2492utils.Export(function(to) {
2493 to.GetScriptBreakPoints = GetScriptBreakPoints;
2494});
2495
2496})