blob: 34eb0f0ec51a9390a209a7f6c47bd24d1cbaaf27 [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Default number of frames to include in the response to backtrace request.
29const kDefaultBacktraceLength = 10;
30
31const Debug = {};
32
33// Regular expression to skip "crud" at the beginning of a source line which is
34// not really code. Currently the regular expression matches whitespace and
35// comments.
36const sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
37
38// Debug events which can occour in the V8 JavaScript engine. These originate
39// from the API include file debug.h.
40Debug.DebugEvent = { Break: 1,
41 Exception: 2,
42 NewFunction: 3,
43 BeforeCompile: 4,
44 AfterCompile: 5,
45 ScriptCollected: 6 };
46
47// Types of exceptions that can be broken upon.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010048Debug.ExceptionBreak = { Caught : 0,
Andrei Popescu31002712010-02-23 13:46:05 +000049 Uncaught: 1 };
50
51// The different types of steps.
52Debug.StepAction = { StepOut: 0,
53 StepNext: 1,
54 StepIn: 2,
55 StepMin: 3,
56 StepInMin: 4 };
57
58// The different types of scripts matching enum ScriptType in objects.h.
59Debug.ScriptType = { Native: 0,
60 Extension: 1,
61 Normal: 2 };
62
63// The different types of script compilations matching enum
64// Script::CompilationType in objects.h.
65Debug.ScriptCompilationType = { Host: 0,
66 Eval: 1,
67 JSON: 2 };
68
69// The different script break point types.
70Debug.ScriptBreakPointType = { ScriptId: 0,
71 ScriptName: 1 };
72
73function ScriptTypeFlag(type) {
74 return (1 << type);
75}
76
77// Globals.
78var next_response_seq = 0;
79var next_break_point_number = 1;
80var break_points = [];
81var script_break_points = [];
Ben Murdochbb769b22010-08-11 14:56:33 +010082var debugger_flags = {
83 breakPointsActive: {
84 value: true,
85 getValue: function() { return this.value; },
86 setValue: function(value) {
87 this.value = !!value;
88 %SetDisableBreak(!this.value);
89 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010090 },
91 breakOnCaughtException: {
92 getValue: function() { return Debug.isBreakOnException(); },
93 setValue: function(value) {
94 if (value) {
95 Debug.setBreakOnException();
96 } else {
97 Debug.clearBreakOnException();
98 }
99 }
100 },
101 breakOnUncaughtException: {
102 getValue: function() { return Debug.isBreakOnUncaughtException(); },
103 setValue: function(value) {
104 if (value) {
105 Debug.setBreakOnUncaughtException();
106 } else {
107 Debug.clearBreakOnUncaughtException();
108 }
109 }
110 },
Ben Murdochbb769b22010-08-11 14:56:33 +0100111};
Andrei Popescu31002712010-02-23 13:46:05 +0000112
113
114// Create a new break point object and add it to the list of break points.
115function MakeBreakPoint(source_position, opt_line, opt_column, opt_script_break_point) {
116 var break_point = new BreakPoint(source_position, opt_line, opt_column, opt_script_break_point);
117 break_points.push(break_point);
118 return break_point;
119}
120
121
122// Object representing a break point.
123// NOTE: This object does not have a reference to the function having break
124// point as this would cause function not to be garbage collected when it is
125// not used any more. We do not want break points to keep functions alive.
126function BreakPoint(source_position, opt_line, opt_column, opt_script_break_point) {
127 this.source_position_ = source_position;
128 this.source_line_ = opt_line;
129 this.source_column_ = opt_column;
130 if (opt_script_break_point) {
131 this.script_break_point_ = opt_script_break_point;
132 } else {
133 this.number_ = next_break_point_number++;
134 }
135 this.hit_count_ = 0;
136 this.active_ = true;
137 this.condition_ = null;
138 this.ignoreCount_ = 0;
139}
140
141
142BreakPoint.prototype.number = function() {
143 return this.number_;
144};
145
146
147BreakPoint.prototype.func = function() {
148 return this.func_;
149};
150
151
152BreakPoint.prototype.source_position = function() {
153 return this.source_position_;
154};
155
156
157BreakPoint.prototype.hit_count = function() {
158 return this.hit_count_;
159};
160
161
162BreakPoint.prototype.active = function() {
163 if (this.script_break_point()) {
164 return this.script_break_point().active();
165 }
166 return this.active_;
167};
168
169
170BreakPoint.prototype.condition = function() {
171 if (this.script_break_point() && this.script_break_point().condition()) {
172 return this.script_break_point().condition();
173 }
174 return this.condition_;
175};
176
177
178BreakPoint.prototype.ignoreCount = function() {
179 return this.ignoreCount_;
180};
181
182
183BreakPoint.prototype.script_break_point = function() {
184 return this.script_break_point_;
185};
186
187
188BreakPoint.prototype.enable = function() {
189 this.active_ = true;
190};
191
192
193BreakPoint.prototype.disable = function() {
194 this.active_ = false;
195};
196
197
198BreakPoint.prototype.setCondition = function(condition) {
199 this.condition_ = condition;
200};
201
202
203BreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
204 this.ignoreCount_ = ignoreCount;
205};
206
207
208BreakPoint.prototype.isTriggered = function(exec_state) {
209 // Break point not active - not triggered.
210 if (!this.active()) return false;
211
212 // Check for conditional break point.
213 if (this.condition()) {
214 // If break point has condition try to evaluate it in the top frame.
215 try {
216 var mirror = exec_state.frame(0).evaluate(this.condition());
217 // If no sensible mirror or non true value break point not triggered.
218 if (!(mirror instanceof ValueMirror) || !%ToBoolean(mirror.value_)) {
219 return false;
220 }
221 } catch (e) {
222 // Exception evaluating condition counts as not triggered.
223 return false;
224 }
225 }
226
227 // Update the hit count.
228 this.hit_count_++;
229 if (this.script_break_point_) {
230 this.script_break_point_.hit_count_++;
231 }
232
233 // If the break point has an ignore count it is not triggered.
234 if (this.ignoreCount_ > 0) {
235 this.ignoreCount_--;
236 return false;
237 }
238
239 // Break point triggered.
240 return true;
241};
242
243
244// Function called from the runtime when a break point is hit. Returns true if
245// the break point is triggered and supposed to break execution.
246function IsBreakPointTriggered(break_id, break_point) {
247 return break_point.isTriggered(MakeExecutionState(break_id));
248}
249
250
251// Object representing a script break point. The script is referenced by its
252// script name or script id and the break point is represented as line and
253// column.
254function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
255 opt_groupId) {
256 this.type_ = type;
257 if (type == Debug.ScriptBreakPointType.ScriptId) {
258 this.script_id_ = script_id_or_name;
259 } else { // type == Debug.ScriptBreakPointType.ScriptName
260 this.script_name_ = script_id_or_name;
261 }
262 this.line_ = opt_line || 0;
263 this.column_ = opt_column;
264 this.groupId_ = opt_groupId;
265 this.hit_count_ = 0;
266 this.active_ = true;
267 this.condition_ = null;
268 this.ignoreCount_ = 0;
Steve Block8defd9f2010-07-08 12:39:36 +0100269 this.break_points_ = [];
Andrei Popescu31002712010-02-23 13:46:05 +0000270}
271
272
Steve Block6ded16b2010-05-10 14:33:55 +0100273//Creates a clone of script breakpoint that is linked to another script.
274ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
275 var copy = new ScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
276 other_script.id, this.line_, this.column_, this.groupId_);
277 copy.number_ = next_break_point_number++;
278 script_break_points.push(copy);
Ben Murdochbb769b22010-08-11 14:56:33 +0100279
Steve Block6ded16b2010-05-10 14:33:55 +0100280 copy.hit_count_ = this.hit_count_;
281 copy.active_ = this.active_;
282 copy.condition_ = this.condition_;
283 copy.ignoreCount_ = this.ignoreCount_;
284 return copy;
285}
286
287
Andrei Popescu31002712010-02-23 13:46:05 +0000288ScriptBreakPoint.prototype.number = function() {
289 return this.number_;
290};
291
292
293ScriptBreakPoint.prototype.groupId = function() {
294 return this.groupId_;
295};
296
297
298ScriptBreakPoint.prototype.type = function() {
299 return this.type_;
300};
301
302
303ScriptBreakPoint.prototype.script_id = function() {
304 return this.script_id_;
305};
306
307
308ScriptBreakPoint.prototype.script_name = function() {
309 return this.script_name_;
310};
311
312
313ScriptBreakPoint.prototype.line = function() {
314 return this.line_;
315};
316
317
318ScriptBreakPoint.prototype.column = function() {
319 return this.column_;
320};
321
322
Steve Block8defd9f2010-07-08 12:39:36 +0100323ScriptBreakPoint.prototype.actual_locations = function() {
324 var locations = [];
325 for (var i = 0; i < this.break_points_.length; i++) {
326 locations.push(this.break_points_[i].actual_location);
327 }
328 return locations;
329}
330
331
Steve Block6ded16b2010-05-10 14:33:55 +0100332ScriptBreakPoint.prototype.update_positions = function(line, column) {
333 this.line_ = line;
334 this.column_ = column;
335}
336
337
Andrei Popescu31002712010-02-23 13:46:05 +0000338ScriptBreakPoint.prototype.hit_count = function() {
339 return this.hit_count_;
340};
341
342
343ScriptBreakPoint.prototype.active = function() {
344 return this.active_;
345};
346
347
348ScriptBreakPoint.prototype.condition = function() {
349 return this.condition_;
350};
351
352
353ScriptBreakPoint.prototype.ignoreCount = function() {
354 return this.ignoreCount_;
355};
356
357
358ScriptBreakPoint.prototype.enable = function() {
359 this.active_ = true;
360};
361
362
363ScriptBreakPoint.prototype.disable = function() {
364 this.active_ = false;
365};
366
367
368ScriptBreakPoint.prototype.setCondition = function(condition) {
369 this.condition_ = condition;
370};
371
372
373ScriptBreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
374 this.ignoreCount_ = ignoreCount;
375
376 // Set ignore count on all break points created from this script break point.
Steve Block8defd9f2010-07-08 12:39:36 +0100377 for (var i = 0; i < this.break_points_.length; i++) {
378 this.break_points_[i].setIgnoreCount(ignoreCount);
Andrei Popescu31002712010-02-23 13:46:05 +0000379 }
380};
381
382
383// Check whether a script matches this script break point. Currently this is
384// only based on script name.
385ScriptBreakPoint.prototype.matchesScript = function(script) {
386 if (this.type_ == Debug.ScriptBreakPointType.ScriptId) {
387 return this.script_id_ == script.id;
388 } else { // this.type_ == Debug.ScriptBreakPointType.ScriptName
Steve Block6ded16b2010-05-10 14:33:55 +0100389 return this.script_name_ == script.nameOrSourceURL() &&
Andrei Popescu31002712010-02-23 13:46:05 +0000390 script.line_offset <= this.line_ &&
391 this.line_ < script.line_offset + script.lineCount();
392 }
393};
394
395
396// Set the script break point in a script.
397ScriptBreakPoint.prototype.set = function (script) {
398 var column = this.column();
399 var line = this.line();
400 // If the column is undefined the break is on the line. To help locate the
401 // first piece of breakable code on the line try to find the column on the
402 // line which contains some source.
403 if (IS_UNDEFINED(column)) {
404 var source_line = script.sourceLine(this.line());
405
406 // Allocate array for caching the columns where the actual source starts.
407 if (!script.sourceColumnStart_) {
408 script.sourceColumnStart_ = new Array(script.lineCount());
409 }
410
411 // Fill cache if needed and get column where the actual source starts.
412 if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
413 script.sourceColumnStart_[line] =
414 source_line.match(sourceLineBeginningSkip)[0].length;
415 }
416 column = script.sourceColumnStart_[line];
417 }
418
419 // Convert the line and column into an absolute position within the script.
Steve Block8defd9f2010-07-08 12:39:36 +0100420 var position = Debug.findScriptSourcePosition(script, this.line(), column);
Andrei Popescu31002712010-02-23 13:46:05 +0000421
422 // If the position is not found in the script (the script might be shorter
423 // than it used to be) just ignore it.
Steve Block8defd9f2010-07-08 12:39:36 +0100424 if (position === null) return;
Andrei Popescu31002712010-02-23 13:46:05 +0000425
426 // Create a break point object and set the break point.
Steve Block8defd9f2010-07-08 12:39:36 +0100427 break_point = MakeBreakPoint(position, this.line(), this.column(), this);
Andrei Popescu31002712010-02-23 13:46:05 +0000428 break_point.setIgnoreCount(this.ignoreCount());
Steve Block8defd9f2010-07-08 12:39:36 +0100429 var actual_position = %SetScriptBreakPoint(script, position, break_point);
430 if (IS_UNDEFINED(actual_position)) {
431 actual_position = position;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100432 }
Steve Block8defd9f2010-07-08 12:39:36 +0100433 var actual_location = script.locationFromPosition(actual_position, true);
434 break_point.actual_location = { line: actual_location.line,
435 column: actual_location.column };
436 this.break_points_.push(break_point);
Andrei Popescu31002712010-02-23 13:46:05 +0000437 return break_point;
438};
439
440
441// Clear all the break points created from this script break point
442ScriptBreakPoint.prototype.clear = function () {
443 var remaining_break_points = [];
444 for (var i = 0; i < break_points.length; i++) {
445 if (break_points[i].script_break_point() &&
446 break_points[i].script_break_point() === this) {
447 %ClearBreakPoint(break_points[i]);
448 } else {
449 remaining_break_points.push(break_points[i]);
450 }
451 }
452 break_points = remaining_break_points;
Steve Block8defd9f2010-07-08 12:39:36 +0100453 this.break_points_ = [];
Andrei Popescu31002712010-02-23 13:46:05 +0000454};
455
456
457// Function called from runtime when a new script is compiled to set any script
458// break points set in this script.
459function UpdateScriptBreakPoints(script) {
460 for (var i = 0; i < script_break_points.length; i++) {
461 if (script_break_points[i].type() == Debug.ScriptBreakPointType.ScriptName &&
462 script_break_points[i].matchesScript(script)) {
463 script_break_points[i].set(script);
464 }
465 }
466}
467
468
Steve Block6ded16b2010-05-10 14:33:55 +0100469function GetScriptBreakPoints(script) {
470 var result = [];
471 for (var i = 0; i < script_break_points.length; i++) {
472 if (script_break_points[i].matchesScript(script)) {
473 result.push(script_break_points[i]);
474 }
475 }
476 return result;
477}
478
479
Andrei Popescu31002712010-02-23 13:46:05 +0000480Debug.setListener = function(listener, opt_data) {
481 if (!IS_FUNCTION(listener) && !IS_UNDEFINED(listener) && !IS_NULL(listener)) {
482 throw new Error('Parameters have wrong types.');
483 }
484 %SetDebugEventListener(listener, opt_data);
485};
486
487
488Debug.breakExecution = function(f) {
489 %Break();
490};
491
492Debug.breakLocations = function(f) {
493 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
494 return %GetBreakLocations(f);
495};
496
497// Returns a Script object. If the parameter is a function the return value
498// is the script in which the function is defined. If the parameter is a string
499// the return value is the script for which the script name has that string
500// value. If it is a regexp and there is a unique script whose name matches
501// we return that, otherwise undefined.
502Debug.findScript = function(func_or_script_name) {
503 if (IS_FUNCTION(func_or_script_name)) {
504 return %FunctionGetScript(func_or_script_name);
505 } else if (IS_REGEXP(func_or_script_name)) {
506 var scripts = Debug.scripts();
507 var last_result = null;
508 var result_count = 0;
509 for (var i in scripts) {
510 var script = scripts[i];
511 if (func_or_script_name.test(script.name)) {
512 last_result = script;
513 result_count++;
514 }
515 }
516 // Return the unique script matching the regexp. If there are more
517 // than one we don't return a value since there is no good way to
518 // decide which one to return. Returning a "random" one, say the
519 // first, would introduce nondeterminism (or something close to it)
520 // because the order is the heap iteration order.
521 if (result_count == 1) {
522 return last_result;
523 } else {
524 return undefined;
525 }
526 } else {
527 return %GetScript(func_or_script_name);
528 }
529};
530
531// Returns the script source. If the parameter is a function the return value
532// is the script source for the script in which the function is defined. If the
533// parameter is a string the return value is the script for which the script
534// name has that string value.
535Debug.scriptSource = function(func_or_script_name) {
536 return this.findScript(func_or_script_name).source;
537};
538
539Debug.source = function(f) {
540 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
541 return %FunctionGetSourceCode(f);
542};
543
544Debug.disassemble = function(f) {
545 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
546 return %DebugDisassembleFunction(f);
547};
548
549Debug.disassembleConstructor = function(f) {
550 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
551 return %DebugDisassembleConstructor(f);
552};
553
Steve Block6ded16b2010-05-10 14:33:55 +0100554Debug.ExecuteInDebugContext = function(f, without_debugger) {
555 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
556 return %ExecuteInDebugContext(f, !!without_debugger);
557};
558
Andrei Popescu31002712010-02-23 13:46:05 +0000559Debug.sourcePosition = function(f) {
560 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
561 return %FunctionGetScriptSourcePosition(f);
562};
563
564
565Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
566 var script = %FunctionGetScript(func);
567 var script_offset = %FunctionGetScriptSourcePosition(func);
568 return script.locationFromLine(opt_line, opt_column, script_offset);
569}
570
571
572// Returns the character position in a script based on a line number and an
573// optional position within that line.
574Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
575 var location = script.locationFromLine(opt_line, opt_column);
576 return location ? location.position : null;
577}
578
579
580Debug.findBreakPoint = function(break_point_number, remove) {
581 var break_point;
582 for (var i = 0; i < break_points.length; i++) {
583 if (break_points[i].number() == break_point_number) {
584 break_point = break_points[i];
585 // Remove the break point from the list if requested.
586 if (remove) {
587 break_points.splice(i, 1);
588 }
589 break;
590 }
591 }
592 if (break_point) {
593 return break_point;
594 } else {
595 return this.findScriptBreakPoint(break_point_number, remove);
596 }
597};
598
Steve Block8defd9f2010-07-08 12:39:36 +0100599Debug.findBreakPointActualLocations = function(break_point_number) {
600 for (var i = 0; i < script_break_points.length; i++) {
601 if (script_break_points[i].number() == break_point_number) {
602 return script_break_points[i].actual_locations();
603 }
604 }
605 for (var i = 0; i < break_points.length; i++) {
606 if (break_points[i].number() == break_point_number) {
607 return [break_points[i].actual_location];
608 }
609 }
610 return [];
611}
Andrei Popescu31002712010-02-23 13:46:05 +0000612
613Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
614 if (!IS_FUNCTION(func)) throw new Error('Parameters have wrong types.');
615 // Break points in API functions are not supported.
616 if (%FunctionIsAPIFunction(func)) {
617 throw new Error('Cannot set break point in native code.');
618 }
619 // Find source position relative to start of the function
620 var break_position =
621 this.findFunctionSourceLocation(func, opt_line, opt_column).position;
622 var source_position = break_position - this.sourcePosition(func);
623 // Find the script for the function.
624 var script = %FunctionGetScript(func);
625 // Break in builtin JavaScript code is not supported.
626 if (script.type == Debug.ScriptType.Native) {
627 throw new Error('Cannot set break point in native code.');
628 }
629 // If the script for the function has a name convert this to a script break
630 // point.
631 if (script && script.id) {
632 // Adjust the source position to be script relative.
633 source_position += %FunctionGetScriptSourcePosition(func);
634 // Find line and column for the position in the script and set a script
635 // break point from that.
636 var location = script.locationFromPosition(source_position, false);
637 return this.setScriptBreakPointById(script.id,
638 location.line, location.column,
639 opt_condition);
640 } else {
641 // Set a break point directly on the function.
642 var break_point = MakeBreakPoint(source_position, opt_line, opt_column);
Steve Block8defd9f2010-07-08 12:39:36 +0100643 var actual_position =
644 %SetFunctionBreakPoint(func, source_position, break_point);
645 actual_position += this.sourcePosition(func);
646 var actual_location = script.locationFromPosition(actual_position, true);
647 break_point.actual_location = { line: actual_location.line,
648 column: actual_location.column };
Andrei Popescu31002712010-02-23 13:46:05 +0000649 break_point.setCondition(opt_condition);
650 return break_point.number();
651 }
652};
653
654
655Debug.enableBreakPoint = function(break_point_number) {
656 var break_point = this.findBreakPoint(break_point_number, false);
657 break_point.enable();
658};
659
660
661Debug.disableBreakPoint = function(break_point_number) {
662 var break_point = this.findBreakPoint(break_point_number, false);
663 break_point.disable();
664};
665
666
667Debug.changeBreakPointCondition = function(break_point_number, condition) {
668 var break_point = this.findBreakPoint(break_point_number, false);
669 break_point.setCondition(condition);
670};
671
672
673Debug.changeBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
674 if (ignoreCount < 0) {
675 throw new Error('Invalid argument');
676 }
677 var break_point = this.findBreakPoint(break_point_number, false);
678 break_point.setIgnoreCount(ignoreCount);
679};
680
681
682Debug.clearBreakPoint = function(break_point_number) {
683 var break_point = this.findBreakPoint(break_point_number, true);
684 if (break_point) {
685 return %ClearBreakPoint(break_point);
686 } else {
687 break_point = this.findScriptBreakPoint(break_point_number, true);
688 if (!break_point) {
689 throw new Error('Invalid breakpoint');
690 }
691 }
692};
693
694
695Debug.clearAllBreakPoints = function() {
696 for (var i = 0; i < break_points.length; i++) {
697 break_point = break_points[i];
698 %ClearBreakPoint(break_point);
699 }
700 break_points = [];
701};
702
703
704Debug.findScriptBreakPoint = function(break_point_number, remove) {
705 var script_break_point;
706 for (var i = 0; i < script_break_points.length; i++) {
707 if (script_break_points[i].number() == break_point_number) {
708 script_break_point = script_break_points[i];
709 // Remove the break point from the list if requested.
710 if (remove) {
711 script_break_point.clear();
712 script_break_points.splice(i,1);
713 }
714 break;
715 }
716 }
717 return script_break_point;
718}
719
720
721// Sets a breakpoint in a script identified through id or name at the
722// specified source line and column within that line.
723Debug.setScriptBreakPoint = function(type, script_id_or_name,
724 opt_line, opt_column, opt_condition,
725 opt_groupId) {
726 // Create script break point object.
727 var script_break_point =
728 new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
729 opt_groupId);
730
731 // Assign number to the new script break point and add it.
732 script_break_point.number_ = next_break_point_number++;
733 script_break_point.setCondition(opt_condition);
734 script_break_points.push(script_break_point);
735
736 // Run through all scripts to see if this script break point matches any
737 // loaded scripts.
738 var scripts = this.scripts();
739 for (var i = 0; i < scripts.length; i++) {
740 if (script_break_point.matchesScript(scripts[i])) {
741 script_break_point.set(scripts[i]);
742 }
743 }
744
745 return script_break_point.number();
746}
747
748
749Debug.setScriptBreakPointById = function(script_id,
750 opt_line, opt_column,
751 opt_condition, opt_groupId) {
752 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
753 script_id, opt_line, opt_column,
754 opt_condition, opt_groupId);
755}
756
757
758Debug.setScriptBreakPointByName = function(script_name,
759 opt_line, opt_column,
760 opt_condition, opt_groupId) {
761 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
762 script_name, opt_line, opt_column,
763 opt_condition, opt_groupId);
764}
765
766
767Debug.enableScriptBreakPoint = function(break_point_number) {
768 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
769 script_break_point.enable();
770};
771
772
773Debug.disableScriptBreakPoint = function(break_point_number) {
774 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
775 script_break_point.disable();
776};
777
778
779Debug.changeScriptBreakPointCondition = function(break_point_number, condition) {
780 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
781 script_break_point.setCondition(condition);
782};
783
784
785Debug.changeScriptBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
786 if (ignoreCount < 0) {
787 throw new Error('Invalid argument');
788 }
789 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
790 script_break_point.setIgnoreCount(ignoreCount);
791};
792
793
794Debug.scriptBreakPoints = function() {
795 return script_break_points;
796}
797
798
799Debug.clearStepping = function() {
800 %ClearStepping();
801}
802
803Debug.setBreakOnException = function() {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100804 return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true);
Andrei Popescu31002712010-02-23 13:46:05 +0000805};
806
807Debug.clearBreakOnException = function() {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100808 return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
809};
810
811Debug.isBreakOnException = function() {
812 return !!%IsBreakOnException(Debug.ExceptionBreak.Caught);
Andrei Popescu31002712010-02-23 13:46:05 +0000813};
814
815Debug.setBreakOnUncaughtException = function() {
816 return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, true);
817};
818
819Debug.clearBreakOnUncaughtException = function() {
820 return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
821};
822
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100823Debug.isBreakOnUncaughtException = function() {
824 return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
825};
826
Andrei Popescu31002712010-02-23 13:46:05 +0000827Debug.showBreakPoints = function(f, full) {
828 if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
829 var source = full ? this.scriptSource(f) : this.source(f);
830 var offset = full ? this.sourcePosition(f) : 0;
831 var locations = this.breakLocations(f);
832 if (!locations) return source;
833 locations.sort(function(x, y) { return x - y; });
834 var result = "";
835 var prev_pos = 0;
836 var pos;
837 for (var i = 0; i < locations.length; i++) {
838 pos = locations[i] - offset;
839 result += source.slice(prev_pos, pos);
840 result += "[B" + i + "]";
841 prev_pos = pos;
842 }
843 pos = source.length;
844 result += source.substring(prev_pos, pos);
845 return result;
846};
847
848
849// Get all the scripts currently loaded. Locating all the scripts is based on
850// scanning the heap.
851Debug.scripts = function() {
852 // Collect all scripts in the heap.
853 return %DebugGetLoadedScripts();
Ben Murdochbb769b22010-08-11 14:56:33 +0100854};
855
856
857Debug.debuggerFlags = function() {
858 return debugger_flags;
859};
860
Andrei Popescu31002712010-02-23 13:46:05 +0000861
862function MakeExecutionState(break_id) {
863 return new ExecutionState(break_id);
864}
865
866function ExecutionState(break_id) {
867 this.break_id = break_id;
868 this.selected_frame = 0;
869}
870
871ExecutionState.prototype.prepareStep = function(opt_action, opt_count) {
872 var action = Debug.StepAction.StepIn;
873 if (!IS_UNDEFINED(opt_action)) action = %ToNumber(opt_action);
874 var count = opt_count ? %ToNumber(opt_count) : 1;
875
876 return %PrepareStep(this.break_id, action, count);
877}
878
879ExecutionState.prototype.evaluateGlobal = function(source, disable_break) {
880 return MakeMirror(
881 %DebugEvaluateGlobal(this.break_id, source, Boolean(disable_break)));
882};
883
884ExecutionState.prototype.frameCount = function() {
885 return %GetFrameCount(this.break_id);
886};
887
888ExecutionState.prototype.threadCount = function() {
889 return %GetThreadCount(this.break_id);
890};
891
892ExecutionState.prototype.frame = function(opt_index) {
893 // If no index supplied return the selected frame.
894 if (opt_index == null) opt_index = this.selected_frame;
Steve Block6ded16b2010-05-10 14:33:55 +0100895 if (opt_index < 0 || opt_index >= this.frameCount())
896 throw new Error('Illegal frame index.');
Andrei Popescu31002712010-02-23 13:46:05 +0000897 return new FrameMirror(this.break_id, opt_index);
898};
899
900ExecutionState.prototype.cframesValue = function(opt_from_index, opt_to_index) {
901 return %GetCFrames(this.break_id);
902};
903
904ExecutionState.prototype.setSelectedFrame = function(index) {
905 var i = %ToNumber(index);
906 if (i < 0 || i >= this.frameCount()) throw new Error('Illegal frame index.');
907 this.selected_frame = i;
908};
909
910ExecutionState.prototype.selectedFrame = function() {
911 return this.selected_frame;
912};
913
914ExecutionState.prototype.debugCommandProcessor = function(opt_is_running) {
915 return new DebugCommandProcessor(this, opt_is_running);
916};
917
918
919function MakeBreakEvent(exec_state, break_points_hit) {
920 return new BreakEvent(exec_state, break_points_hit);
921}
922
923
924function BreakEvent(exec_state, break_points_hit) {
925 this.exec_state_ = exec_state;
926 this.break_points_hit_ = break_points_hit;
927}
928
929
930BreakEvent.prototype.executionState = function() {
931 return this.exec_state_;
932};
933
934
935BreakEvent.prototype.eventType = function() {
936 return Debug.DebugEvent.Break;
937};
938
939
940BreakEvent.prototype.func = function() {
941 return this.exec_state_.frame(0).func();
942};
943
944
945BreakEvent.prototype.sourceLine = function() {
946 return this.exec_state_.frame(0).sourceLine();
947};
948
949
950BreakEvent.prototype.sourceColumn = function() {
951 return this.exec_state_.frame(0).sourceColumn();
952};
953
954
955BreakEvent.prototype.sourceLineText = function() {
956 return this.exec_state_.frame(0).sourceLineText();
957};
958
959
960BreakEvent.prototype.breakPointsHit = function() {
961 return this.break_points_hit_;
962};
963
964
965BreakEvent.prototype.toJSONProtocol = function() {
966 var o = { seq: next_response_seq++,
967 type: "event",
968 event: "break",
969 body: { invocationText: this.exec_state_.frame(0).invocationText(),
970 }
971 };
972
973 // Add script related information to the event if available.
974 var script = this.func().script();
975 if (script) {
976 o.body.sourceLine = this.sourceLine(),
977 o.body.sourceColumn = this.sourceColumn(),
978 o.body.sourceLineText = this.sourceLineText(),
979 o.body.script = MakeScriptObject_(script, false);
980 }
981
982 // Add an Array of break points hit if any.
983 if (this.breakPointsHit()) {
984 o.body.breakpoints = [];
985 for (var i = 0; i < this.breakPointsHit().length; i++) {
986 // Find the break point number. For break points originating from a
987 // script break point supply the script break point number.
988 var breakpoint = this.breakPointsHit()[i];
989 var script_break_point = breakpoint.script_break_point();
990 var number;
991 if (script_break_point) {
992 number = script_break_point.number();
993 } else {
994 number = breakpoint.number();
995 }
996 o.body.breakpoints.push(number);
997 }
998 }
999 return JSON.stringify(ObjectToProtocolObject_(o));
1000};
1001
1002
1003function MakeExceptionEvent(exec_state, exception, uncaught) {
1004 return new ExceptionEvent(exec_state, exception, uncaught);
1005}
1006
1007
1008function ExceptionEvent(exec_state, exception, uncaught) {
1009 this.exec_state_ = exec_state;
1010 this.exception_ = exception;
1011 this.uncaught_ = uncaught;
1012}
1013
1014
1015ExceptionEvent.prototype.executionState = function() {
1016 return this.exec_state_;
1017};
1018
1019
1020ExceptionEvent.prototype.eventType = function() {
1021 return Debug.DebugEvent.Exception;
1022};
1023
1024
1025ExceptionEvent.prototype.exception = function() {
1026 return this.exception_;
1027}
1028
1029
1030ExceptionEvent.prototype.uncaught = function() {
1031 return this.uncaught_;
1032}
1033
1034
1035ExceptionEvent.prototype.func = function() {
1036 return this.exec_state_.frame(0).func();
1037};
1038
1039
1040ExceptionEvent.prototype.sourceLine = function() {
1041 return this.exec_state_.frame(0).sourceLine();
1042};
1043
1044
1045ExceptionEvent.prototype.sourceColumn = function() {
1046 return this.exec_state_.frame(0).sourceColumn();
1047};
1048
1049
1050ExceptionEvent.prototype.sourceLineText = function() {
1051 return this.exec_state_.frame(0).sourceLineText();
1052};
1053
1054
1055ExceptionEvent.prototype.toJSONProtocol = function() {
1056 var o = new ProtocolMessage();
1057 o.event = "exception";
1058 o.body = { uncaught: this.uncaught_,
1059 exception: MakeMirror(this.exception_)
1060 };
1061
1062 // Exceptions might happen whithout any JavaScript frames.
1063 if (this.exec_state_.frameCount() > 0) {
1064 o.body.sourceLine = this.sourceLine();
1065 o.body.sourceColumn = this.sourceColumn();
1066 o.body.sourceLineText = this.sourceLineText();
1067
1068 // Add script information to the event if available.
1069 var script = this.func().script();
1070 if (script) {
1071 o.body.script = MakeScriptObject_(script, false);
1072 }
1073 } else {
1074 o.body.sourceLine = -1;
1075 }
1076
1077 return o.toJSONProtocol();
1078};
1079
1080
1081function MakeCompileEvent(exec_state, script, before) {
1082 return new CompileEvent(exec_state, script, before);
1083}
1084
1085
1086function CompileEvent(exec_state, script, before) {
1087 this.exec_state_ = exec_state;
1088 this.script_ = MakeMirror(script);
1089 this.before_ = before;
1090}
1091
1092
1093CompileEvent.prototype.executionState = function() {
1094 return this.exec_state_;
1095};
1096
1097
1098CompileEvent.prototype.eventType = function() {
1099 if (this.before_) {
1100 return Debug.DebugEvent.BeforeCompile;
1101 } else {
1102 return Debug.DebugEvent.AfterCompile;
1103 }
1104};
1105
1106
1107CompileEvent.prototype.script = function() {
1108 return this.script_;
1109};
1110
1111
1112CompileEvent.prototype.toJSONProtocol = function() {
1113 var o = new ProtocolMessage();
1114 o.running = true;
1115 if (this.before_) {
1116 o.event = "beforeCompile";
1117 } else {
1118 o.event = "afterCompile";
1119 }
1120 o.body = {};
1121 o.body.script = this.script_;
1122
1123 return o.toJSONProtocol();
1124}
1125
1126
1127function MakeNewFunctionEvent(func) {
1128 return new NewFunctionEvent(func);
1129}
1130
1131
1132function NewFunctionEvent(func) {
1133 this.func = func;
1134}
1135
1136
1137NewFunctionEvent.prototype.eventType = function() {
1138 return Debug.DebugEvent.NewFunction;
1139};
1140
1141
1142NewFunctionEvent.prototype.name = function() {
1143 return this.func.name;
1144};
1145
1146
1147NewFunctionEvent.prototype.setBreakPoint = function(p) {
1148 Debug.setBreakPoint(this.func, p || 0);
1149};
1150
1151
1152function MakeScriptCollectedEvent(exec_state, id) {
1153 return new ScriptCollectedEvent(exec_state, id);
1154}
1155
1156
1157function ScriptCollectedEvent(exec_state, id) {
1158 this.exec_state_ = exec_state;
1159 this.id_ = id;
1160}
1161
1162
1163ScriptCollectedEvent.prototype.id = function() {
1164 return this.id_;
1165};
1166
1167
1168ScriptCollectedEvent.prototype.executionState = function() {
1169 return this.exec_state_;
1170};
1171
1172
1173ScriptCollectedEvent.prototype.toJSONProtocol = function() {
1174 var o = new ProtocolMessage();
1175 o.running = true;
1176 o.event = "scriptCollected";
1177 o.body = {};
1178 o.body.script = { id: this.id() };
1179 return o.toJSONProtocol();
1180}
1181
1182
1183function MakeScriptObject_(script, include_source) {
1184 var o = { id: script.id(),
1185 name: script.name(),
1186 lineOffset: script.lineOffset(),
1187 columnOffset: script.columnOffset(),
1188 lineCount: script.lineCount(),
1189 };
1190 if (!IS_UNDEFINED(script.data())) {
1191 o.data = script.data();
1192 }
1193 if (include_source) {
1194 o.source = script.source();
1195 }
1196 return o;
1197};
1198
1199
1200function DebugCommandProcessor(exec_state, opt_is_running) {
1201 this.exec_state_ = exec_state;
1202 this.running_ = opt_is_running || false;
1203};
1204
1205
1206DebugCommandProcessor.prototype.processDebugRequest = function (request) {
1207 return this.processDebugJSONRequest(request);
1208}
1209
1210
1211function ProtocolMessage(request) {
1212 // Update sequence number.
1213 this.seq = next_response_seq++;
1214
1215 if (request) {
1216 // If message is based on a request this is a response. Fill the initial
1217 // response from the request.
1218 this.type = 'response';
1219 this.request_seq = request.seq;
1220 this.command = request.command;
1221 } else {
1222 // If message is not based on a request it is a dabugger generated event.
1223 this.type = 'event';
1224 }
1225 this.success = true;
1226 // Handler may set this field to control debugger state.
1227 this.running = undefined;
1228}
1229
1230
1231ProtocolMessage.prototype.setOption = function(name, value) {
1232 if (!this.options_) {
1233 this.options_ = {};
1234 }
1235 this.options_[name] = value;
1236}
1237
1238
1239ProtocolMessage.prototype.failed = function(message) {
1240 this.success = false;
1241 this.message = message;
1242}
1243
1244
1245ProtocolMessage.prototype.toJSONProtocol = function() {
1246 // Encode the protocol header.
1247 var json = {};
1248 json.seq= this.seq;
1249 if (this.request_seq) {
1250 json.request_seq = this.request_seq;
1251 }
1252 json.type = this.type;
1253 if (this.event) {
1254 json.event = this.event;
1255 }
1256 if (this.command) {
1257 json.command = this.command;
1258 }
1259 if (this.success) {
1260 json.success = this.success;
1261 } else {
1262 json.success = false;
1263 }
1264 if (this.body) {
1265 // Encode the body part.
1266 var bodyJson;
1267 var serializer = MakeMirrorSerializer(true, this.options_);
1268 if (this.body instanceof Mirror) {
1269 bodyJson = serializer.serializeValue(this.body);
1270 } else if (this.body instanceof Array) {
1271 bodyJson = [];
1272 for (var i = 0; i < this.body.length; i++) {
1273 if (this.body[i] instanceof Mirror) {
1274 bodyJson.push(serializer.serializeValue(this.body[i]));
1275 } else {
1276 bodyJson.push(ObjectToProtocolObject_(this.body[i], serializer));
1277 }
1278 }
1279 } else {
1280 bodyJson = ObjectToProtocolObject_(this.body, serializer);
1281 }
1282 json.body = bodyJson;
1283 json.refs = serializer.serializeReferencedObjects();
1284 }
1285 if (this.message) {
1286 json.message = this.message;
1287 }
1288 json.running = this.running;
1289 return JSON.stringify(json);
1290}
1291
1292
1293DebugCommandProcessor.prototype.createResponse = function(request) {
1294 return new ProtocolMessage(request);
1295};
1296
1297
1298DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) {
1299 var request; // Current request.
1300 var response; // Generated response.
1301 try {
1302 try {
1303 // Convert the JSON string to an object.
1304 request = %CompileString('(' + json_request + ')', false)();
1305
1306 // Create an initial response.
1307 response = this.createResponse(request);
1308
1309 if (!request.type) {
1310 throw new Error('Type not specified');
1311 }
1312
1313 if (request.type != 'request') {
1314 throw new Error("Illegal type '" + request.type + "' in request");
1315 }
1316
1317 if (!request.command) {
1318 throw new Error('Command not specified');
1319 }
1320
Andrei Popescu402d9372010-02-26 13:31:12 +00001321 if (request.arguments) {
1322 var args = request.arguments;
1323 // TODO(yurys): remove request.arguments.compactFormat check once
1324 // ChromeDevTools are switched to 'inlineRefs'
1325 if (args.inlineRefs || args.compactFormat) {
1326 response.setOption('inlineRefs', true);
1327 }
1328 if (!IS_UNDEFINED(args.maxStringLength)) {
1329 response.setOption('maxStringLength', args.maxStringLength);
1330 }
Andrei Popescu31002712010-02-23 13:46:05 +00001331 }
1332
1333 if (request.command == 'continue') {
1334 this.continueRequest_(request, response);
1335 } else if (request.command == 'break') {
1336 this.breakRequest_(request, response);
1337 } else if (request.command == 'setbreakpoint') {
1338 this.setBreakPointRequest_(request, response);
1339 } else if (request.command == 'changebreakpoint') {
1340 this.changeBreakPointRequest_(request, response);
1341 } else if (request.command == 'clearbreakpoint') {
1342 this.clearBreakPointRequest_(request, response);
1343 } else if (request.command == 'clearbreakpointgroup') {
1344 this.clearBreakPointGroupRequest_(request, response);
Kristian Monsen25f61362010-05-21 11:50:48 +01001345 } else if (request.command == 'listbreakpoints') {
1346 this.listBreakpointsRequest_(request, response);
Andrei Popescu31002712010-02-23 13:46:05 +00001347 } else if (request.command == 'backtrace') {
1348 this.backtraceRequest_(request, response);
1349 } else if (request.command == 'frame') {
1350 this.frameRequest_(request, response);
1351 } else if (request.command == 'scopes') {
1352 this.scopesRequest_(request, response);
1353 } else if (request.command == 'scope') {
1354 this.scopeRequest_(request, response);
1355 } else if (request.command == 'evaluate') {
1356 this.evaluateRequest_(request, response);
1357 } else if (request.command == 'lookup') {
1358 this.lookupRequest_(request, response);
1359 } else if (request.command == 'references') {
1360 this.referencesRequest_(request, response);
1361 } else if (request.command == 'source') {
1362 this.sourceRequest_(request, response);
1363 } else if (request.command == 'scripts') {
1364 this.scriptsRequest_(request, response);
1365 } else if (request.command == 'threads') {
1366 this.threadsRequest_(request, response);
1367 } else if (request.command == 'suspend') {
1368 this.suspendRequest_(request, response);
1369 } else if (request.command == 'version') {
1370 this.versionRequest_(request, response);
1371 } else if (request.command == 'profile') {
Ben Murdochbb769b22010-08-11 14:56:33 +01001372 this.profileRequest_(request, response);
Steve Block6ded16b2010-05-10 14:33:55 +01001373 } else if (request.command == 'changelive') {
Ben Murdochbb769b22010-08-11 14:56:33 +01001374 this.changeLiveRequest_(request, response);
1375 } else if (request.command == 'flags') {
1376 this.debuggerFlagsRequest_(request, response);
Andrei Popescu31002712010-02-23 13:46:05 +00001377 } else {
1378 throw new Error('Unknown command "' + request.command + '" in request');
1379 }
1380 } catch (e) {
1381 // If there is no response object created one (without command).
1382 if (!response) {
1383 response = this.createResponse();
1384 }
1385 response.success = false;
1386 response.message = %ToString(e);
1387 }
1388
1389 // Return the response as a JSON encoded string.
1390 try {
1391 if (!IS_UNDEFINED(response.running)) {
1392 // Response controls running state.
1393 this.running_ = response.running;
1394 }
Steve Block6ded16b2010-05-10 14:33:55 +01001395 response.running = this.running_;
Andrei Popescu31002712010-02-23 13:46:05 +00001396 return response.toJSONProtocol();
1397 } catch (e) {
1398 // Failed to generate response - return generic error.
1399 return '{"seq":' + response.seq + ',' +
1400 '"request_seq":' + request.seq + ',' +
1401 '"type":"response",' +
1402 '"success":false,' +
1403 '"message":"Internal error: ' + %ToString(e) + '"}';
1404 }
1405 } catch (e) {
1406 // Failed in one of the catch blocks above - most generic error.
1407 return '{"seq":0,"type":"response","success":false,"message":"Internal error"}';
1408 }
1409};
1410
1411
1412DebugCommandProcessor.prototype.continueRequest_ = function(request, response) {
1413 // Check for arguments for continue.
1414 if (request.arguments) {
1415 var count = 1;
1416 var action = Debug.StepAction.StepIn;
1417
1418 // Pull out arguments.
1419 var stepaction = request.arguments.stepaction;
1420 var stepcount = request.arguments.stepcount;
1421
1422 // Get the stepcount argument if any.
1423 if (stepcount) {
1424 count = %ToNumber(stepcount);
1425 if (count < 0) {
1426 throw new Error('Invalid stepcount argument "' + stepcount + '".');
1427 }
1428 }
1429
1430 // Get the stepaction argument.
1431 if (stepaction) {
1432 if (stepaction == 'in') {
1433 action = Debug.StepAction.StepIn;
1434 } else if (stepaction == 'min') {
1435 action = Debug.StepAction.StepMin;
1436 } else if (stepaction == 'next') {
1437 action = Debug.StepAction.StepNext;
1438 } else if (stepaction == 'out') {
1439 action = Debug.StepAction.StepOut;
1440 } else {
1441 throw new Error('Invalid stepaction argument "' + stepaction + '".');
1442 }
1443 }
1444
1445 // Setup the VM for stepping.
1446 this.exec_state_.prepareStep(action, count);
1447 }
1448
1449 // VM should be running after executing this request.
1450 response.running = true;
1451};
1452
1453
1454DebugCommandProcessor.prototype.breakRequest_ = function(request, response) {
1455 // Ignore as break command does not do anything when broken.
1456};
1457
1458
1459DebugCommandProcessor.prototype.setBreakPointRequest_ =
1460 function(request, response) {
1461 // Check for legal request.
1462 if (!request.arguments) {
1463 response.failed('Missing arguments');
1464 return;
1465 }
1466
1467 // Pull out arguments.
1468 var type = request.arguments.type;
1469 var target = request.arguments.target;
1470 var line = request.arguments.line;
1471 var column = request.arguments.column;
1472 var enabled = IS_UNDEFINED(request.arguments.enabled) ?
1473 true : request.arguments.enabled;
1474 var condition = request.arguments.condition;
1475 var ignoreCount = request.arguments.ignoreCount;
1476 var groupId = request.arguments.groupId;
1477
1478 // Check for legal arguments.
1479 if (!type || IS_UNDEFINED(target)) {
1480 response.failed('Missing argument "type" or "target"');
1481 return;
1482 }
1483 if (type != 'function' && type != 'handle' &&
1484 type != 'script' && type != 'scriptId') {
1485 response.failed('Illegal type "' + type + '"');
1486 return;
1487 }
1488
1489 // Either function or script break point.
1490 var break_point_number;
1491 if (type == 'function') {
1492 // Handle function break point.
1493 if (!IS_STRING(target)) {
1494 response.failed('Argument "target" is not a string value');
1495 return;
1496 }
1497 var f;
1498 try {
1499 // Find the function through a global evaluate.
1500 f = this.exec_state_.evaluateGlobal(target).value();
1501 } catch (e) {
1502 response.failed('Error: "' + %ToString(e) +
1503 '" evaluating "' + target + '"');
1504 return;
1505 }
1506 if (!IS_FUNCTION(f)) {
1507 response.failed('"' + target + '" does not evaluate to a function');
1508 return;
1509 }
1510
1511 // Set function break point.
1512 break_point_number = Debug.setBreakPoint(f, line, column, condition);
1513 } else if (type == 'handle') {
1514 // Find the object pointed by the specified handle.
1515 var handle = parseInt(target, 10);
1516 var mirror = LookupMirror(handle);
1517 if (!mirror) {
1518 return response.failed('Object #' + handle + '# not found');
1519 }
1520 if (!mirror.isFunction()) {
1521 return response.failed('Object #' + handle + '# is not a function');
1522 }
1523
1524 // Set function break point.
1525 break_point_number = Debug.setBreakPoint(mirror.value(),
1526 line, column, condition);
1527 } else if (type == 'script') {
1528 // set script break point.
1529 break_point_number =
1530 Debug.setScriptBreakPointByName(target, line, column, condition,
1531 groupId);
1532 } else { // type == 'scriptId.
1533 break_point_number =
1534 Debug.setScriptBreakPointById(target, line, column, condition, groupId);
1535 }
1536
1537 // Set additional break point properties.
1538 var break_point = Debug.findBreakPoint(break_point_number);
1539 if (ignoreCount) {
1540 Debug.changeBreakPointIgnoreCount(break_point_number, ignoreCount);
1541 }
1542 if (!enabled) {
1543 Debug.disableBreakPoint(break_point_number);
1544 }
1545
1546 // Add the break point number to the response.
1547 response.body = { type: type,
1548 breakpoint: break_point_number }
1549
1550 // Add break point information to the response.
1551 if (break_point instanceof ScriptBreakPoint) {
1552 if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
1553 response.body.type = 'scriptId';
1554 response.body.script_id = break_point.script_id();
1555 } else {
1556 response.body.type = 'scriptName';
1557 response.body.script_name = break_point.script_name();
1558 }
1559 response.body.line = break_point.line();
1560 response.body.column = break_point.column();
Steve Block8defd9f2010-07-08 12:39:36 +01001561 response.body.actual_locations = break_point.actual_locations();
Andrei Popescu31002712010-02-23 13:46:05 +00001562 } else {
1563 response.body.type = 'function';
Steve Block8defd9f2010-07-08 12:39:36 +01001564 response.body.actual_locations = [break_point.actual_location];
Andrei Popescu31002712010-02-23 13:46:05 +00001565 }
1566};
1567
1568
1569DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(request, response) {
1570 // Check for legal request.
1571 if (!request.arguments) {
1572 response.failed('Missing arguments');
1573 return;
1574 }
1575
1576 // Pull out arguments.
1577 var break_point = %ToNumber(request.arguments.breakpoint);
1578 var enabled = request.arguments.enabled;
1579 var condition = request.arguments.condition;
1580 var ignoreCount = request.arguments.ignoreCount;
1581
1582 // Check for legal arguments.
1583 if (!break_point) {
1584 response.failed('Missing argument "breakpoint"');
1585 return;
1586 }
1587
1588 // Change enabled state if supplied.
1589 if (!IS_UNDEFINED(enabled)) {
1590 if (enabled) {
1591 Debug.enableBreakPoint(break_point);
1592 } else {
1593 Debug.disableBreakPoint(break_point);
1594 }
1595 }
1596
1597 // Change condition if supplied
1598 if (!IS_UNDEFINED(condition)) {
1599 Debug.changeBreakPointCondition(break_point, condition);
1600 }
1601
1602 // Change ignore count if supplied
1603 if (!IS_UNDEFINED(ignoreCount)) {
1604 Debug.changeBreakPointIgnoreCount(break_point, ignoreCount);
1605 }
1606}
1607
1608
1609DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(request, response) {
1610 // Check for legal request.
1611 if (!request.arguments) {
1612 response.failed('Missing arguments');
1613 return;
1614 }
1615
1616 // Pull out arguments.
1617 var group_id = request.arguments.groupId;
1618
1619 // Check for legal arguments.
1620 if (!group_id) {
1621 response.failed('Missing argument "groupId"');
1622 return;
1623 }
1624
1625 var cleared_break_points = [];
1626 var new_script_break_points = [];
1627 for (var i = 0; i < script_break_points.length; i++) {
1628 var next_break_point = script_break_points[i];
1629 if (next_break_point.groupId() == group_id) {
1630 cleared_break_points.push(next_break_point.number());
1631 next_break_point.clear();
1632 } else {
1633 new_script_break_points.push(next_break_point);
1634 }
1635 }
1636 script_break_points = new_script_break_points;
1637
1638 // Add the cleared break point numbers to the response.
1639 response.body = { breakpoints: cleared_break_points };
1640}
1641
1642
1643DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(request, response) {
1644 // Check for legal request.
1645 if (!request.arguments) {
1646 response.failed('Missing arguments');
1647 return;
1648 }
1649
1650 // Pull out arguments.
1651 var break_point = %ToNumber(request.arguments.breakpoint);
1652
1653 // Check for legal arguments.
1654 if (!break_point) {
1655 response.failed('Missing argument "breakpoint"');
1656 return;
1657 }
1658
1659 // Clear break point.
1660 Debug.clearBreakPoint(break_point);
1661
1662 // Add the cleared break point number to the response.
1663 response.body = { breakpoint: break_point }
1664}
1665
Ben Murdochbb769b22010-08-11 14:56:33 +01001666
Kristian Monsen25f61362010-05-21 11:50:48 +01001667DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, response) {
1668 var array = [];
1669 for (var i = 0; i < script_break_points.length; i++) {
1670 var break_point = script_break_points[i];
1671
1672 var description = {
1673 number: break_point.number(),
1674 line: break_point.line(),
1675 column: break_point.column(),
1676 groupId: break_point.groupId(),
1677 hit_count: break_point.hit_count(),
1678 active: break_point.active(),
1679 condition: break_point.condition(),
Steve Block8defd9f2010-07-08 12:39:36 +01001680 ignoreCount: break_point.ignoreCount(),
1681 actual_locations: break_point.actual_locations()
Kristian Monsen25f61362010-05-21 11:50:48 +01001682 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001683
Kristian Monsen25f61362010-05-21 11:50:48 +01001684 if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
1685 description.type = 'scriptId';
1686 description.script_id = break_point.script_id();
1687 } else {
1688 description.type = 'scriptName';
1689 description.script_name = break_point.script_name();
1690 }
1691 array.push(description);
1692 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001693
Kristian Monsen25f61362010-05-21 11:50:48 +01001694 response.body = { breakpoints: array }
1695}
1696
Andrei Popescu31002712010-02-23 13:46:05 +00001697
1698DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response) {
1699 // Get the number of frames.
1700 var total_frames = this.exec_state_.frameCount();
1701
1702 // Create simple response if there are no frames.
1703 if (total_frames == 0) {
1704 response.body = {
1705 totalFrames: total_frames
1706 }
1707 return;
1708 }
1709
1710 // Default frame range to include in backtrace.
1711 var from_index = 0
1712 var to_index = kDefaultBacktraceLength;
1713
1714 // Get the range from the arguments.
1715 if (request.arguments) {
1716 if (request.arguments.fromFrame) {
1717 from_index = request.arguments.fromFrame;
1718 }
1719 if (request.arguments.toFrame) {
1720 to_index = request.arguments.toFrame;
1721 }
1722 if (request.arguments.bottom) {
1723 var tmp_index = total_frames - from_index;
1724 from_index = total_frames - to_index
1725 to_index = tmp_index;
1726 }
1727 if (from_index < 0 || to_index < 0) {
1728 return response.failed('Invalid frame number');
1729 }
1730 }
1731
1732 // Adjust the index.
1733 to_index = Math.min(total_frames, to_index);
1734
1735 if (to_index <= from_index) {
1736 var error = 'Invalid frame range';
1737 return response.failed(error);
1738 }
1739
1740 // Create the response body.
1741 var frames = [];
1742 for (var i = from_index; i < to_index; i++) {
1743 frames.push(this.exec_state_.frame(i));
1744 }
1745 response.body = {
1746 fromFrame: from_index,
1747 toFrame: to_index,
1748 totalFrames: total_frames,
1749 frames: frames
1750 }
1751};
1752
1753
1754DebugCommandProcessor.prototype.backtracec = function(cmd, args) {
1755 return this.exec_state_.cframesValue();
1756};
1757
1758
1759DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
1760 // No frames no source.
1761 if (this.exec_state_.frameCount() == 0) {
1762 return response.failed('No frames');
1763 }
1764
1765 // With no arguments just keep the selected frame.
1766 if (request.arguments) {
1767 var index = request.arguments.number;
1768 if (index < 0 || this.exec_state_.frameCount() <= index) {
1769 return response.failed('Invalid frame number');
1770 }
1771
1772 this.exec_state_.setSelectedFrame(request.arguments.number);
1773 }
1774 response.body = this.exec_state_.frame();
1775};
1776
1777
1778DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
1779 // Get the frame for which the scope or scopes are requested. With no frameNumber
1780 // argument use the currently selected frame.
1781 if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
1782 frame_index = request.arguments.frameNumber;
1783 if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
1784 return response.failed('Invalid frame number');
1785 }
1786 return this.exec_state_.frame(frame_index);
1787 } else {
1788 return this.exec_state_.frame();
1789 }
1790}
1791
1792
1793DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
1794 // No frames no scopes.
1795 if (this.exec_state_.frameCount() == 0) {
1796 return response.failed('No scopes');
1797 }
1798
1799 // Get the frame for which the scopes are requested.
1800 var frame = this.frameForScopeRequest_(request);
1801
1802 // Fill all scopes for this frame.
1803 var total_scopes = frame.scopeCount();
1804 var scopes = [];
1805 for (var i = 0; i < total_scopes; i++) {
1806 scopes.push(frame.scope(i));
1807 }
1808 response.body = {
1809 fromScope: 0,
1810 toScope: total_scopes,
1811 totalScopes: total_scopes,
1812 scopes: scopes
1813 }
1814};
1815
1816
1817DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
1818 // No frames no scopes.
1819 if (this.exec_state_.frameCount() == 0) {
1820 return response.failed('No scopes');
1821 }
1822
1823 // Get the frame for which the scope is requested.
1824 var frame = this.frameForScopeRequest_(request);
1825
1826 // With no scope argument just return top scope.
1827 var scope_index = 0;
1828 if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
1829 scope_index = %ToNumber(request.arguments.number);
1830 if (scope_index < 0 || frame.scopeCount() <= scope_index) {
1831 return response.failed('Invalid scope number');
1832 }
1833 }
1834
1835 response.body = frame.scope(scope_index);
1836};
1837
1838
1839DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) {
1840 if (!request.arguments) {
1841 return response.failed('Missing arguments');
1842 }
1843
1844 // Pull out arguments.
1845 var expression = request.arguments.expression;
1846 var frame = request.arguments.frame;
1847 var global = request.arguments.global;
1848 var disable_break = request.arguments.disable_break;
1849
1850 // The expression argument could be an integer so we convert it to a
1851 // string.
1852 try {
1853 expression = String(expression);
1854 } catch(e) {
1855 return response.failed('Failed to convert expression argument to string');
1856 }
1857
1858 // Check for legal arguments.
1859 if (!IS_UNDEFINED(frame) && global) {
1860 return response.failed('Arguments "frame" and "global" are exclusive');
1861 }
1862
1863 // Global evaluate.
1864 if (global) {
1865 // Evaluate in the global context.
1866 response.body =
1867 this.exec_state_.evaluateGlobal(expression, Boolean(disable_break));
1868 return;
1869 }
1870
1871 // Default value for disable_break is true.
1872 if (IS_UNDEFINED(disable_break)) {
1873 disable_break = true;
1874 }
1875
1876 // No frames no evaluate in frame.
1877 if (this.exec_state_.frameCount() == 0) {
1878 return response.failed('No frames');
1879 }
1880
1881 // Check whether a frame was specified.
1882 if (!IS_UNDEFINED(frame)) {
1883 var frame_number = %ToNumber(frame);
1884 if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
1885 return response.failed('Invalid frame "' + frame + '"');
1886 }
1887 // Evaluate in the specified frame.
1888 response.body = this.exec_state_.frame(frame_number).evaluate(
1889 expression, Boolean(disable_break));
1890 return;
1891 } else {
1892 // Evaluate in the selected frame.
1893 response.body = this.exec_state_.frame().evaluate(
1894 expression, Boolean(disable_break));
1895 return;
1896 }
1897};
1898
1899
1900DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
1901 if (!request.arguments) {
1902 return response.failed('Missing arguments');
1903 }
1904
1905 // Pull out arguments.
1906 var handles = request.arguments.handles;
1907
1908 // Check for legal arguments.
1909 if (IS_UNDEFINED(handles)) {
1910 return response.failed('Argument "handles" missing');
1911 }
1912
1913 // Set 'includeSource' option for script lookup.
1914 if (!IS_UNDEFINED(request.arguments.includeSource)) {
1915 includeSource = %ToBoolean(request.arguments.includeSource);
1916 response.setOption('includeSource', includeSource);
1917 }
1918
1919 // Lookup handles.
1920 var mirrors = {};
1921 for (var i = 0; i < handles.length; i++) {
1922 var handle = handles[i];
1923 var mirror = LookupMirror(handle);
1924 if (!mirror) {
1925 return response.failed('Object #' + handle + '# not found');
1926 }
1927 mirrors[handle] = mirror;
1928 }
1929 response.body = mirrors;
1930};
1931
1932
1933DebugCommandProcessor.prototype.referencesRequest_ =
1934 function(request, response) {
1935 if (!request.arguments) {
1936 return response.failed('Missing arguments');
1937 }
1938
1939 // Pull out arguments.
1940 var type = request.arguments.type;
1941 var handle = request.arguments.handle;
1942
1943 // Check for legal arguments.
1944 if (IS_UNDEFINED(type)) {
1945 return response.failed('Argument "type" missing');
1946 }
1947 if (IS_UNDEFINED(handle)) {
1948 return response.failed('Argument "handle" missing');
1949 }
1950 if (type != 'referencedBy' && type != 'constructedBy') {
1951 return response.failed('Invalid type "' + type + '"');
1952 }
1953
1954 // Lookup handle and return objects with references the object.
1955 var mirror = LookupMirror(handle);
1956 if (mirror) {
1957 if (type == 'referencedBy') {
1958 response.body = mirror.referencedBy();
1959 } else {
1960 response.body = mirror.constructedBy();
1961 }
1962 } else {
1963 return response.failed('Object #' + handle + '# not found');
1964 }
1965};
1966
1967
1968DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
1969 // No frames no source.
1970 if (this.exec_state_.frameCount() == 0) {
1971 return response.failed('No source');
1972 }
1973
1974 var from_line;
1975 var to_line;
1976 var frame = this.exec_state_.frame();
1977 if (request.arguments) {
1978 // Pull out arguments.
1979 from_line = request.arguments.fromLine;
1980 to_line = request.arguments.toLine;
1981
1982 if (!IS_UNDEFINED(request.arguments.frame)) {
1983 var frame_number = %ToNumber(request.arguments.frame);
1984 if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
1985 return response.failed('Invalid frame "' + frame + '"');
1986 }
1987 frame = this.exec_state_.frame(frame_number);
1988 }
1989 }
1990
1991 // Get the script selected.
1992 var script = frame.func().script();
1993 if (!script) {
1994 return response.failed('No source');
1995 }
1996
1997 // Get the source slice and fill it into the response.
1998 var slice = script.sourceSlice(from_line, to_line);
1999 if (!slice) {
2000 return response.failed('Invalid line interval');
2001 }
2002 response.body = {};
2003 response.body.source = slice.sourceText();
2004 response.body.fromLine = slice.from_line;
2005 response.body.toLine = slice.to_line;
2006 response.body.fromPosition = slice.from_position;
2007 response.body.toPosition = slice.to_position;
2008 response.body.totalLines = script.lineCount();
2009};
2010
2011
2012DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
2013 var types = ScriptTypeFlag(Debug.ScriptType.Normal);
2014 var includeSource = false;
2015 var idsToInclude = null;
2016 if (request.arguments) {
2017 // Pull out arguments.
2018 if (!IS_UNDEFINED(request.arguments.types)) {
2019 types = %ToNumber(request.arguments.types);
2020 if (isNaN(types) || types < 0) {
2021 return response.failed('Invalid types "' + request.arguments.types + '"');
2022 }
2023 }
Steve Block6ded16b2010-05-10 14:33:55 +01002024
Andrei Popescu31002712010-02-23 13:46:05 +00002025 if (!IS_UNDEFINED(request.arguments.includeSource)) {
2026 includeSource = %ToBoolean(request.arguments.includeSource);
2027 response.setOption('includeSource', includeSource);
2028 }
Steve Block6ded16b2010-05-10 14:33:55 +01002029
Andrei Popescu31002712010-02-23 13:46:05 +00002030 if (IS_ARRAY(request.arguments.ids)) {
2031 idsToInclude = {};
2032 var ids = request.arguments.ids;
2033 for (var i = 0; i < ids.length; i++) {
2034 idsToInclude[ids[i]] = true;
2035 }
2036 }
2037 }
2038
2039 // Collect all scripts in the heap.
2040 var scripts = %DebugGetLoadedScripts();
2041
2042 response.body = [];
2043
2044 for (var i = 0; i < scripts.length; i++) {
2045 if (idsToInclude && !idsToInclude[scripts[i].id]) {
2046 continue;
2047 }
2048 if (types & ScriptTypeFlag(scripts[i].type)) {
2049 response.body.push(MakeMirror(scripts[i]));
2050 }
2051 }
2052};
2053
2054
2055DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
2056 // Get the number of threads.
2057 var total_threads = this.exec_state_.threadCount();
2058
2059 // Get information for all threads.
2060 var threads = [];
2061 for (var i = 0; i < total_threads; i++) {
2062 var details = %GetThreadDetails(this.exec_state_.break_id, i);
2063 var thread_info = { current: details[0],
2064 id: details[1]
2065 }
2066 threads.push(thread_info);
2067 }
2068
2069 // Create the response body.
2070 response.body = {
2071 totalThreads: total_threads,
2072 threads: threads
2073 }
2074};
2075
2076
2077DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
2078 response.running = false;
2079};
2080
2081
2082DebugCommandProcessor.prototype.versionRequest_ = function(request, response) {
2083 response.body = {
2084 V8Version: %GetV8Version()
2085 }
2086};
2087
2088
2089DebugCommandProcessor.prototype.profileRequest_ = function(request, response) {
2090 if (!request.arguments) {
2091 return response.failed('Missing arguments');
2092 }
2093 var modules = parseInt(request.arguments.modules);
2094 if (isNaN(modules)) {
2095 return response.failed('Modules is not an integer');
2096 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002097 var tag = parseInt(request.arguments.tag);
2098 if (isNaN(tag)) {
2099 tag = 0;
2100 }
Andrei Popescu31002712010-02-23 13:46:05 +00002101 if (request.arguments.command == 'resume') {
Andrei Popescu402d9372010-02-26 13:31:12 +00002102 %ProfilerResume(modules, tag);
Andrei Popescu31002712010-02-23 13:46:05 +00002103 } else if (request.arguments.command == 'pause') {
Andrei Popescu402d9372010-02-26 13:31:12 +00002104 %ProfilerPause(modules, tag);
Andrei Popescu31002712010-02-23 13:46:05 +00002105 } else {
2106 return response.failed('Unknown command');
2107 }
2108 response.body = {};
2109};
2110
2111
Steve Block6ded16b2010-05-10 14:33:55 +01002112DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) {
2113 if (!Debug.LiveEdit) {
2114 return response.failed('LiveEdit feature is not supported');
2115 }
2116 if (!request.arguments) {
2117 return response.failed('Missing arguments');
2118 }
2119 var script_id = request.arguments.script_id;
Steve Block8defd9f2010-07-08 12:39:36 +01002120 var preview_only = !!request.arguments.preview_only;
Steve Block6ded16b2010-05-10 14:33:55 +01002121
2122 var scripts = %DebugGetLoadedScripts();
2123
2124 var the_script = null;
2125 for (var i = 0; i < scripts.length; i++) {
2126 if (scripts[i].id == script_id) {
2127 the_script = scripts[i];
2128 }
2129 }
2130 if (!the_script) {
2131 response.failed('Script not found');
2132 return;
2133 }
2134
2135 var change_log = new Array();
Ben Murdochbb769b22010-08-11 14:56:33 +01002136
Steve Block6ded16b2010-05-10 14:33:55 +01002137 if (!IS_STRING(request.arguments.new_source)) {
2138 throw "new_source argument expected";
2139 }
2140
2141 var new_source = request.arguments.new_source;
2142
Steve Block8defd9f2010-07-08 12:39:36 +01002143 var result_description = Debug.LiveEdit.SetScriptSource(the_script,
2144 new_source, preview_only, change_log);
2145 response.body = {change_log: change_log, result: result_description};
Ben Murdochbb769b22010-08-11 14:56:33 +01002146
2147 if (!preview_only && !this.running_ && result_description.stack_modified) {
2148 response.body.stepin_recommended = true;
2149 }
Steve Block6ded16b2010-05-10 14:33:55 +01002150};
2151
2152
Ben Murdochbb769b22010-08-11 14:56:33 +01002153DebugCommandProcessor.prototype.debuggerFlagsRequest_ = function(request,
2154 response) {
2155 // Check for legal request.
2156 if (!request.arguments) {
2157 response.failed('Missing arguments');
2158 return;
2159 }
2160
2161 // Pull out arguments.
2162 var flags = request.arguments.flags;
2163
2164 response.body = { flags: [] };
2165 if (!IS_UNDEFINED(flags)) {
2166 for (var i = 0; i < flags.length; i++) {
2167 var name = flags[i].name;
2168 var debugger_flag = debugger_flags[name];
2169 if (!debugger_flag) {
2170 continue;
2171 }
2172 if ('value' in flags[i]) {
2173 debugger_flag.setValue(flags[i].value);
2174 }
2175 response.body.flags.push({ name: name, value: debugger_flag.getValue() });
2176 }
2177 } else {
2178 for (var name in debugger_flags) {
2179 var value = debugger_flags[name].getValue();
2180 response.body.flags.push({ name: name, value: value });
2181 }
2182 }
2183}
2184
2185
Andrei Popescu31002712010-02-23 13:46:05 +00002186// Check whether the previously processed command caused the VM to become
2187// running.
2188DebugCommandProcessor.prototype.isRunning = function() {
2189 return this.running_;
2190}
2191
2192
2193DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
2194 return %SystemBreak();
2195};
2196
2197
2198function NumberToHex8Str(n) {
2199 var r = "";
2200 for (var i = 0; i < 8; ++i) {
2201 var c = hexCharArray[n & 0x0F]; // hexCharArray is defined in uri.js
2202 r = c + r;
2203 n = n >>> 4;
2204 }
2205 return r;
2206};
2207
2208DebugCommandProcessor.prototype.formatCFrames = function(cframes_value) {
2209 var result = "";
2210 if (cframes_value == null || cframes_value.length == 0) {
2211 result += "(stack empty)";
2212 } else {
2213 for (var i = 0; i < cframes_value.length; ++i) {
2214 if (i != 0) result += "\n";
2215 result += this.formatCFrame(cframes_value[i]);
2216 }
2217 }
2218 return result;
2219};
2220
2221
2222DebugCommandProcessor.prototype.formatCFrame = function(cframe_value) {
2223 var result = "";
2224 result += "0x" + NumberToHex8Str(cframe_value.address);
2225 if (!IS_UNDEFINED(cframe_value.text)) {
2226 result += " " + cframe_value.text;
2227 }
2228 return result;
2229}
2230
2231
2232/**
2233 * Convert an Object to its debugger protocol representation. The representation
2234 * may be serilized to a JSON object using JSON.stringify().
2235 * This implementation simply runs through all string property names, converts
2236 * each property value to a protocol value and adds the property to the result
2237 * object. For type "object" the function will be called recursively. Note that
2238 * circular structures will cause infinite recursion.
2239 * @param {Object} object The object to format as protocol object.
2240 * @param {MirrorSerializer} mirror_serializer The serializer to use if any
2241 * mirror objects are encountered.
2242 * @return {Object} Protocol object value.
2243 */
2244function ObjectToProtocolObject_(object, mirror_serializer) {
2245 var content = {};
2246 for (var key in object) {
2247 // Only consider string keys.
2248 if (typeof key == 'string') {
2249 // Format the value based on its type.
2250 var property_value_json = ValueToProtocolValue_(object[key],
2251 mirror_serializer);
2252 // Add the property if relevant.
2253 if (!IS_UNDEFINED(property_value_json)) {
2254 content[key] = property_value_json;
2255 }
2256 }
2257 }
Steve Block6ded16b2010-05-10 14:33:55 +01002258
Andrei Popescu31002712010-02-23 13:46:05 +00002259 return content;
2260}
2261
2262
2263/**
2264 * Convert an array to its debugger protocol representation. It will convert
2265 * each array element to a protocol value.
2266 * @param {Array} array The array to format as protocol array.
2267 * @param {MirrorSerializer} mirror_serializer The serializer to use if any
2268 * mirror objects are encountered.
2269 * @return {Array} Protocol array value.
2270 */
2271function ArrayToProtocolArray_(array, mirror_serializer) {
2272 var json = [];
2273 for (var i = 0; i < array.length; i++) {
2274 json.push(ValueToProtocolValue_(array[i], mirror_serializer));
2275 }
2276 return json;
2277}
2278
2279
2280/**
Steve Block6ded16b2010-05-10 14:33:55 +01002281 * Convert a value to its debugger protocol representation.
Andrei Popescu31002712010-02-23 13:46:05 +00002282 * @param {*} value The value to format as protocol value.
2283 * @param {MirrorSerializer} mirror_serializer The serializer to use if any
2284 * mirror objects are encountered.
2285 * @return {*} Protocol value.
2286 */
2287function ValueToProtocolValue_(value, mirror_serializer) {
2288 // Format the value based on its type.
2289 var json;
2290 switch (typeof value) {
2291 case 'object':
2292 if (value instanceof Mirror) {
2293 json = mirror_serializer.serializeValue(value);
2294 } else if (IS_ARRAY(value)){
2295 json = ArrayToProtocolArray_(value, mirror_serializer);
2296 } else {
2297 json = ObjectToProtocolObject_(value, mirror_serializer);
2298 }
2299 break;
2300
2301 case 'boolean':
2302 case 'string':
2303 case 'number':
2304 json = value;
2305 break
2306
2307 default:
2308 json = null;
2309 }
2310 return json;
2311}