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