OLD | NEW |
1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2008 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 "use strict"; | 5 "use strict"; |
6 | 6 |
7 String.prototype.startsWith = function (str) { | 7 String.prototype.startsWith = function (str) { |
8 if (str.length > this.length) { | 8 if (str.length > this.length) { |
9 return false; | 9 return false; |
10 } | 10 } |
11 return this.substr(0, str.length) == str; | 11 return this.substr(0, str.length) == str; |
12 }; | 12 }; |
13 | 13 |
14 function log10(num) { | |
15 return Math.log(num)/Math.log(10); | |
16 } | |
17 | |
18 function ToInspectableObject(obj) { | 14 function ToInspectableObject(obj) { |
19 if (!obj && typeof obj === 'object') { | 15 if (!obj && typeof obj === 'object') { |
20 return UNDEFINED; | 16 return UNDEFINED; |
21 } else { | 17 } else { |
22 return Object(obj); | 18 return Object(obj); |
23 } | 19 } |
24 } | 20 } |
25 | 21 |
26 function GetCompletions(global, last, full) { | 22 function GetCompletions(global, last, full) { |
27 var full_tokens = full.split(); | 23 var full_tokens = full.split(); |
(...skipping 18 matching lines...) Expand all Loading... |
46 var name = properties[i].name(); | 42 var name = properties[i].name(); |
47 if (typeof name === 'string' && name.startsWith(last)) { | 43 if (typeof name === 'string' && name.startsWith(last)) { |
48 result.push(name); | 44 result.push(name); |
49 } | 45 } |
50 } | 46 } |
51 current = ToInspectableObject(Object.getPrototypeOf(current)); | 47 current = ToInspectableObject(Object.getPrototypeOf(current)); |
52 } | 48 } |
53 return result; | 49 return result; |
54 } | 50 } |
55 | 51 |
56 | |
57 // Global object holding debugger related constants and state. | |
58 var Debug = {}; | |
59 | |
60 | |
61 // Debug events which can occour in the V8 JavaScript engine. These originate | |
62 // from the API include file v8-debug.h. | |
63 Debug.DebugEvent = { Break: 1, | |
64 Exception: 2, | |
65 NewFunction: 3, | |
66 BeforeCompile: 4, | |
67 AfterCompile: 5 }; | |
68 | |
69 | |
70 // The different types of scripts matching enum ScriptType in objects.h. | |
71 Debug.ScriptType = { Native: 0, | |
72 Extension: 1, | |
73 Normal: 2 }; | |
74 | |
75 | |
76 // The different types of script compilations matching enum | |
77 // Script::CompilationType in objects.h. | |
78 Debug.ScriptCompilationType = { Host: 0, | |
79 Eval: 1, | |
80 JSON: 2 }; | |
81 | |
82 | |
83 // The different types of scopes matching constants runtime.cc. | |
84 Debug.ScopeType = { Global: 0, | |
85 Local: 1, | |
86 With: 2, | |
87 Closure: 3, | |
88 Catch: 4, | |
89 Block: 5 }; | |
90 | |
91 | |
92 // Current debug state. | |
93 var kNoFrame = -1; | |
94 Debug.State = { | |
95 currentFrame: kNoFrame, | |
96 displaySourceStartLine: -1, | |
97 displaySourceEndLine: -1, | |
98 currentSourceLine: -1 | |
99 }; | |
100 var trace_compile = false; // Tracing all compile events? | |
101 var trace_debug_json = false; // Tracing all debug json packets? | |
102 var last_cmd = ''; | |
103 var repeat_cmd_line = ''; | |
104 var is_running = true; | |
105 // Global variable used to store whether a handle was requested. | |
106 var lookup_handle = null; | |
107 | |
108 // Copied from debug-delay.js. This is needed below: | |
109 function ScriptTypeFlag(type) { | |
110 return (1 << type); | |
111 } | |
112 | |
113 | |
114 // Process a debugger JSON message into a display text and a running status. | |
115 // This function returns an object with properties "text" and "running" holding | |
116 // this information. | |
117 function DebugMessageDetails(message) { | |
118 if (trace_debug_json) { | |
119 print("received: '" + message + "'"); | |
120 } | |
121 // Convert the JSON string to an object. | |
122 var response = new ProtocolPackage(message); | |
123 is_running = response.running(); | |
124 | |
125 if (response.type() == 'event') { | |
126 return DebugEventDetails(response); | |
127 } else { | |
128 return DebugResponseDetails(response); | |
129 } | |
130 } | |
131 | |
132 function DebugEventDetails(response) { | |
133 var details = {text:'', running:false}; | |
134 | |
135 // Get the running state. | |
136 details.running = response.running(); | |
137 | |
138 var body = response.body(); | |
139 var result = ''; | |
140 switch (response.event()) { | |
141 case 'break': | |
142 if (body.breakpoints) { | |
143 result += 'breakpoint'; | |
144 if (body.breakpoints.length > 1) { | |
145 result += 's'; | |
146 } | |
147 result += ' #'; | |
148 for (var i = 0; i < body.breakpoints.length; i++) { | |
149 if (i > 0) { | |
150 result += ', #'; | |
151 } | |
152 result += body.breakpoints[i]; | |
153 } | |
154 } else { | |
155 result += 'break'; | |
156 } | |
157 result += ' in '; | |
158 result += body.invocationText; | |
159 result += ', '; | |
160 result += SourceInfo(body); | |
161 result += '\n'; | |
162 result += SourceUnderline(body.sourceLineText, body.sourceColumn); | |
163 Debug.State.currentSourceLine = body.sourceLine; | |
164 Debug.State.displaySourceStartLine = -1; | |
165 Debug.State.displaySourceEndLine = -1; | |
166 Debug.State.currentFrame = 0; | |
167 details.text = result; | |
168 break; | |
169 | |
170 case 'exception': | |
171 if (body.uncaught) { | |
172 result += 'Uncaught: '; | |
173 } else { | |
174 result += 'Exception: '; | |
175 } | |
176 result += '"'; | |
177 result += body.exception.text; | |
178 result += '"'; | |
179 if (body.sourceLine >= 0) { | |
180 result += ', '; | |
181 result += SourceInfo(body); | |
182 result += '\n'; | |
183 result += SourceUnderline(body.sourceLineText, body.sourceColumn); | |
184 Debug.State.currentSourceLine = body.sourceLine; | |
185 Debug.State.displaySourceStartLine = -1; | |
186 Debug.State.displaySourceEndLine = -1; | |
187 Debug.State.currentFrame = 0; | |
188 } else { | |
189 result += ' (empty stack)'; | |
190 Debug.State.currentSourceLine = -1; | |
191 Debug.State.displaySourceStartLine = -1; | |
192 Debug.State.displaySourceEndLine = -1; | |
193 Debug.State.currentFrame = kNoFrame; | |
194 } | |
195 details.text = result; | |
196 break; | |
197 | |
198 case 'afterCompile': | |
199 if (trace_compile) { | |
200 result = 'Source ' + body.script.name + ' compiled:\n'; | |
201 var source = body.script.source; | |
202 if (!(source[source.length - 1] == '\n')) { | |
203 result += source; | |
204 } else { | |
205 result += source.substring(0, source.length - 1); | |
206 } | |
207 } | |
208 details.text = result; | |
209 break; | |
210 | |
211 default: | |
212 details.text = 'Unknown debug event ' + response.event(); | |
213 } | |
214 | |
215 return details; | |
216 } | |
217 | |
218 | |
219 function SourceInfo(body) { | |
220 var result = ''; | |
221 | |
222 if (body.script) { | |
223 if (body.script.name) { | |
224 result += body.script.name; | |
225 } else { | |
226 result += '[unnamed]'; | |
227 } | |
228 } | |
229 result += ' line '; | |
230 result += body.sourceLine + 1; | |
231 result += ' column '; | |
232 result += body.sourceColumn + 1; | |
233 | |
234 return result; | |
235 } | |
236 | |
237 | |
238 function SourceUnderline(source_text, position) { | |
239 if (!source_text) { | |
240 return; | |
241 } | |
242 | |
243 // Create an underline with a caret pointing to the source position. If the | |
244 // source contains a tab character the underline will have a tab character in | |
245 // the same place otherwise the underline will have a space character. | |
246 var underline = ''; | |
247 for (var i = 0; i < position; i++) { | |
248 if (source_text[i] == '\t') { | |
249 underline += '\t'; | |
250 } else { | |
251 underline += ' '; | |
252 } | |
253 } | |
254 underline += '^'; | |
255 | |
256 // Return the source line text with the underline beneath. | |
257 return source_text + '\n' + underline; | |
258 } | |
259 | |
260 | |
261 // Converts a text command to a JSON request. | |
262 function DebugCommandToJSONRequest(cmd_line) { | |
263 var result = new DebugRequest(cmd_line).JSONRequest(); | |
264 if (trace_debug_json && result) { | |
265 print("sending: '" + result + "'"); | |
266 } | |
267 return result; | |
268 } | |
269 | |
270 | |
271 function DebugRequest(cmd_line) { | |
272 // If the very first character is a { assume that a JSON request have been | |
273 // entered as a command. Converting that to a JSON request is trivial. | |
274 if (cmd_line && cmd_line.length > 0 && cmd_line.charAt(0) == '{') { | |
275 this.request_ = cmd_line; | |
276 return; | |
277 } | |
278 | |
279 // Check for a simple carriage return to repeat the last command: | |
280 var is_repeating = false; | |
281 if (cmd_line == '\n') { | |
282 if (is_running) { | |
283 cmd_line = 'break'; // Not in debugger mode, break with a frame request. | |
284 } else { | |
285 cmd_line = repeat_cmd_line; // use command to repeat. | |
286 is_repeating = true; | |
287 } | |
288 } | |
289 if (!is_running) { // Only save the command if in debugger mode. | |
290 repeat_cmd_line = cmd_line; // save last command. | |
291 } | |
292 | |
293 // Trim string for leading and trailing whitespace. | |
294 cmd_line = cmd_line.replace(/^\s+|\s+$/g, ''); | |
295 | |
296 // Find the command. | |
297 var pos = cmd_line.indexOf(' '); | |
298 var cmd; | |
299 var args; | |
300 if (pos == -1) { | |
301 cmd = cmd_line; | |
302 args = ''; | |
303 } else { | |
304 cmd = cmd_line.slice(0, pos); | |
305 args = cmd_line.slice(pos).replace(/^\s+|\s+$/g, ''); | |
306 } | |
307 | |
308 if ((cmd === undefined) || !cmd) { | |
309 this.request_ = UNDEFINED; | |
310 return; | |
311 } | |
312 | |
313 last_cmd = cmd; | |
314 | |
315 // Switch on command. | |
316 switch (cmd) { | |
317 case 'continue': | |
318 case 'c': | |
319 this.request_ = this.continueCommandToJSONRequest_(args); | |
320 break; | |
321 | |
322 case 'step': | |
323 case 's': | |
324 this.request_ = this.stepCommandToJSONRequest_(args, 'in'); | |
325 break; | |
326 | |
327 case 'stepi': | |
328 case 'si': | |
329 this.request_ = this.stepCommandToJSONRequest_(args, 'min'); | |
330 break; | |
331 | |
332 case 'next': | |
333 case 'n': | |
334 this.request_ = this.stepCommandToJSONRequest_(args, 'next'); | |
335 break; | |
336 | |
337 case 'finish': | |
338 case 'fin': | |
339 this.request_ = this.stepCommandToJSONRequest_(args, 'out'); | |
340 break; | |
341 | |
342 case 'backtrace': | |
343 case 'bt': | |
344 this.request_ = this.backtraceCommandToJSONRequest_(args); | |
345 break; | |
346 | |
347 case 'frame': | |
348 case 'f': | |
349 this.request_ = this.frameCommandToJSONRequest_(args); | |
350 break; | |
351 | |
352 case 'scopes': | |
353 this.request_ = this.scopesCommandToJSONRequest_(args); | |
354 break; | |
355 | |
356 case 'scope': | |
357 this.request_ = this.scopeCommandToJSONRequest_(args); | |
358 break; | |
359 | |
360 case 'disconnect': | |
361 case 'exit': | |
362 case 'quit': | |
363 this.request_ = this.disconnectCommandToJSONRequest_(args); | |
364 break; | |
365 | |
366 case 'up': | |
367 this.request_ = | |
368 this.frameCommandToJSONRequest_('' + | |
369 (Debug.State.currentFrame + 1)); | |
370 break; | |
371 | |
372 case 'down': | |
373 case 'do': | |
374 this.request_ = | |
375 this.frameCommandToJSONRequest_('' + | |
376 (Debug.State.currentFrame - 1)); | |
377 break; | |
378 | |
379 case 'set': | |
380 case 'print': | |
381 case 'p': | |
382 this.request_ = this.printCommandToJSONRequest_(args); | |
383 break; | |
384 | |
385 case 'dir': | |
386 this.request_ = this.dirCommandToJSONRequest_(args); | |
387 break; | |
388 | |
389 case 'references': | |
390 this.request_ = this.referencesCommandToJSONRequest_(args); | |
391 break; | |
392 | |
393 case 'instances': | |
394 this.request_ = this.instancesCommandToJSONRequest_(args); | |
395 break; | |
396 | |
397 case 'list': | |
398 case 'l': | |
399 this.request_ = this.listCommandToJSONRequest_(args); | |
400 break; | |
401 case 'source': | |
402 this.request_ = this.sourceCommandToJSONRequest_(args); | |
403 break; | |
404 | |
405 case 'scripts': | |
406 case 'script': | |
407 case 'scr': | |
408 this.request_ = this.scriptsCommandToJSONRequest_(args); | |
409 break; | |
410 | |
411 case 'break': | |
412 case 'b': | |
413 this.request_ = this.breakCommandToJSONRequest_(args); | |
414 break; | |
415 | |
416 case 'breakpoints': | |
417 case 'bb': | |
418 this.request_ = this.breakpointsCommandToJSONRequest_(args); | |
419 break; | |
420 | |
421 case 'clear': | |
422 case 'delete': | |
423 case 'd': | |
424 this.request_ = this.clearCommandToJSONRequest_(args); | |
425 break; | |
426 | |
427 case 'threads': | |
428 this.request_ = this.threadsCommandToJSONRequest_(args); | |
429 break; | |
430 | |
431 case 'cond': | |
432 this.request_ = this.changeBreakpointCommandToJSONRequest_(args, 'cond'); | |
433 break; | |
434 | |
435 case 'enable': | |
436 case 'en': | |
437 this.request_ = | |
438 this.changeBreakpointCommandToJSONRequest_(args, 'enable'); | |
439 break; | |
440 | |
441 case 'disable': | |
442 case 'dis': | |
443 this.request_ = | |
444 this.changeBreakpointCommandToJSONRequest_(args, 'disable'); | |
445 break; | |
446 | |
447 case 'ignore': | |
448 this.request_ = | |
449 this.changeBreakpointCommandToJSONRequest_(args, 'ignore'); | |
450 break; | |
451 | |
452 case 'info': | |
453 case 'inf': | |
454 this.request_ = this.infoCommandToJSONRequest_(args); | |
455 break; | |
456 | |
457 case 'flags': | |
458 this.request_ = this.v8FlagsToJSONRequest_(args); | |
459 break; | |
460 | |
461 case 'gc': | |
462 this.request_ = this.gcToJSONRequest_(args); | |
463 break; | |
464 | |
465 case 'trace': | |
466 case 'tr': | |
467 // Return undefined to indicate command handled internally (no JSON). | |
468 this.request_ = UNDEFINED; | |
469 this.traceCommand_(args); | |
470 break; | |
471 | |
472 case 'help': | |
473 case '?': | |
474 this.helpCommand_(args); | |
475 // Return undefined to indicate command handled internally (no JSON). | |
476 this.request_ = UNDEFINED; | |
477 break; | |
478 | |
479 default: | |
480 throw new Error('Unknown command "' + cmd + '"'); | |
481 } | |
482 } | |
483 | |
484 DebugRequest.prototype.JSONRequest = function() { | |
485 return this.request_; | |
486 }; | |
487 | |
488 | |
489 function RequestPacket(command) { | |
490 this.seq = 0; | |
491 this.type = 'request'; | |
492 this.command = command; | |
493 } | |
494 | |
495 | |
496 RequestPacket.prototype.toJSONProtocol = function() { | |
497 // Encode the protocol header. | |
498 var json = '{'; | |
499 json += '"seq":' + this.seq; | |
500 json += ',"type":"' + this.type + '"'; | |
501 if (this.command) { | |
502 json += ',"command":' + JSON.stringify(this.command); | |
503 } | |
504 if (this.arguments) { | |
505 json += ',"arguments":'; | |
506 // Encode the arguments part. | |
507 if (this.arguments.toJSONProtocol) { | |
508 json += this.arguments.toJSONProtocol(); | |
509 } else { | |
510 json += JSON.stringify(this.arguments); | |
511 } | |
512 } | |
513 json += '}'; | |
514 return json; | |
515 }; | |
516 | |
517 | |
518 DebugRequest.prototype.createRequest = function(command) { | |
519 return new RequestPacket(command); | |
520 }; | |
521 | |
522 | |
523 // Create a JSON request for the evaluation command. | |
524 DebugRequest.prototype.makeEvaluateJSONRequest_ = function(expression) { | |
525 lookup_handle = null; | |
526 | |
527 // Check if the expression is a handle id in the form #<handle>#. | |
528 var handle_match = expression.match(/^#([0-9]*)#$/); | |
529 if (handle_match) { | |
530 // Remember the handle requested in a global variable. | |
531 lookup_handle = parseInt(handle_match[1]); | |
532 // Build a lookup request. | |
533 var request = this.createRequest('lookup'); | |
534 request.arguments = {}; | |
535 request.arguments.handles = [ lookup_handle ]; | |
536 return request.toJSONProtocol(); | |
537 } else { | |
538 // Build an evaluate request. | |
539 var request = this.createRequest('evaluate'); | |
540 request.arguments = {}; | |
541 request.arguments.expression = expression; | |
542 // Request a global evaluation if there is no current frame. | |
543 if (Debug.State.currentFrame == kNoFrame) { | |
544 request.arguments.global = true; | |
545 } | |
546 return request.toJSONProtocol(); | |
547 } | |
548 }; | |
549 | |
550 | |
551 // Create a JSON request for the references/instances command. | |
552 DebugRequest.prototype.makeReferencesJSONRequest_ = function(handle, type) { | |
553 // Build a references request. | |
554 var handle_match = handle.match(/^#([0-9]*)#$/); | |
555 if (handle_match) { | |
556 var request = this.createRequest('references'); | |
557 request.arguments = {}; | |
558 request.arguments.type = type; | |
559 request.arguments.handle = parseInt(handle_match[1]); | |
560 return request.toJSONProtocol(); | |
561 } else { | |
562 throw new Error('Invalid object id.'); | |
563 } | |
564 }; | |
565 | |
566 | |
567 // Create a JSON request for the continue command. | |
568 DebugRequest.prototype.continueCommandToJSONRequest_ = function(args) { | |
569 var request = this.createRequest('continue'); | |
570 return request.toJSONProtocol(); | |
571 }; | |
572 | |
573 | |
574 // Create a JSON request for the step command. | |
575 DebugRequest.prototype.stepCommandToJSONRequest_ = function(args, type) { | |
576 // Requesting a step is through the continue command with additional | |
577 // arguments. | |
578 var request = this.createRequest('continue'); | |
579 request.arguments = {}; | |
580 | |
581 // Process arguments if any. | |
582 | |
583 // Only process args if the command is 'step' which is indicated by type being | |
584 // set to 'in'. For all other commands, ignore the args. | |
585 if (args && args.length > 0) { | |
586 args = args.split(/\s+/g); | |
587 | |
588 if (args.length > 2) { | |
589 throw new Error('Invalid step arguments.'); | |
590 } | |
591 | |
592 if (args.length > 0) { | |
593 // Check if we have a gdb stype step command. If so, the 1st arg would | |
594 // be the step count. If it's not a number, then assume that we're | |
595 // parsing for the legacy v8 step command. | |
596 var stepcount = Number(args[0]); | |
597 if (stepcount == Number.NaN) { | |
598 // No step count at arg 1. Process as legacy d8 step command: | |
599 if (args.length == 2) { | |
600 var stepcount = parseInt(args[1]); | |
601 if (isNaN(stepcount) || stepcount <= 0) { | |
602 throw new Error('Invalid step count argument "' + args[0] + '".'); | |
603 } | |
604 request.arguments.stepcount = stepcount; | |
605 } | |
606 | |
607 // Get the step action. | |
608 switch (args[0]) { | |
609 case 'in': | |
610 case 'i': | |
611 request.arguments.stepaction = 'in'; | |
612 break; | |
613 | |
614 case 'min': | |
615 case 'm': | |
616 request.arguments.stepaction = 'min'; | |
617 break; | |
618 | |
619 case 'next': | |
620 case 'n': | |
621 request.arguments.stepaction = 'next'; | |
622 break; | |
623 | |
624 case 'out': | |
625 case 'o': | |
626 request.arguments.stepaction = 'out'; | |
627 break; | |
628 | |
629 default: | |
630 throw new Error('Invalid step argument "' + args[0] + '".'); | |
631 } | |
632 | |
633 } else { | |
634 // gdb style step commands: | |
635 request.arguments.stepaction = type; | |
636 request.arguments.stepcount = stepcount; | |
637 } | |
638 } | |
639 } else { | |
640 // Default is step of the specified type. | |
641 request.arguments.stepaction = type; | |
642 } | |
643 | |
644 return request.toJSONProtocol(); | |
645 }; | |
646 | |
647 | |
648 // Create a JSON request for the backtrace command. | |
649 DebugRequest.prototype.backtraceCommandToJSONRequest_ = function(args) { | |
650 // Build a backtrace request from the text command. | |
651 var request = this.createRequest('backtrace'); | |
652 | |
653 // Default is to show top 10 frames. | |
654 request.arguments = {}; | |
655 request.arguments.fromFrame = 0; | |
656 request.arguments.toFrame = 10; | |
657 | |
658 args = args.split(/\s*[ ]+\s*/g); | |
659 if (args.length == 1 && args[0].length > 0) { | |
660 var frameCount = parseInt(args[0]); | |
661 if (frameCount > 0) { | |
662 // Show top frames. | |
663 request.arguments.fromFrame = 0; | |
664 request.arguments.toFrame = frameCount; | |
665 } else { | |
666 // Show bottom frames. | |
667 request.arguments.fromFrame = 0; | |
668 request.arguments.toFrame = -frameCount; | |
669 request.arguments.bottom = true; | |
670 } | |
671 } else if (args.length == 2) { | |
672 var fromFrame = parseInt(args[0]); | |
673 var toFrame = parseInt(args[1]); | |
674 if (isNaN(fromFrame) || fromFrame < 0) { | |
675 throw new Error('Invalid start frame argument "' + args[0] + '".'); | |
676 } | |
677 if (isNaN(toFrame) || toFrame < 0) { | |
678 throw new Error('Invalid end frame argument "' + args[1] + '".'); | |
679 } | |
680 if (fromFrame > toFrame) { | |
681 throw new Error('Invalid arguments start frame cannot be larger ' + | |
682 'than end frame.'); | |
683 } | |
684 // Show frame range. | |
685 request.arguments.fromFrame = fromFrame; | |
686 request.arguments.toFrame = toFrame + 1; | |
687 } else if (args.length > 2) { | |
688 throw new Error('Invalid backtrace arguments.'); | |
689 } | |
690 | |
691 return request.toJSONProtocol(); | |
692 }; | |
693 | |
694 | |
695 // Create a JSON request for the frame command. | |
696 DebugRequest.prototype.frameCommandToJSONRequest_ = function(args) { | |
697 // Build a frame request from the text command. | |
698 var request = this.createRequest('frame'); | |
699 args = args.split(/\s*[ ]+\s*/g); | |
700 if (args.length > 0 && args[0].length > 0) { | |
701 request.arguments = {}; | |
702 request.arguments.number = args[0]; | |
703 } | |
704 return request.toJSONProtocol(); | |
705 }; | |
706 | |
707 | |
708 // Create a JSON request for the scopes command. | |
709 DebugRequest.prototype.scopesCommandToJSONRequest_ = function(args) { | |
710 // Build a scopes request from the text command. | |
711 var request = this.createRequest('scopes'); | |
712 return request.toJSONProtocol(); | |
713 }; | |
714 | |
715 | |
716 // Create a JSON request for the scope command. | |
717 DebugRequest.prototype.scopeCommandToJSONRequest_ = function(args) { | |
718 // Build a scope request from the text command. | |
719 var request = this.createRequest('scope'); | |
720 args = args.split(/\s*[ ]+\s*/g); | |
721 if (args.length > 0 && args[0].length > 0) { | |
722 request.arguments = {}; | |
723 request.arguments.number = args[0]; | |
724 } | |
725 return request.toJSONProtocol(); | |
726 }; | |
727 | |
728 | |
729 // Create a JSON request for the print command. | |
730 DebugRequest.prototype.printCommandToJSONRequest_ = function(args) { | |
731 // Build an evaluate request from the text command. | |
732 if (args.length == 0) { | |
733 throw new Error('Missing expression.'); | |
734 } | |
735 return this.makeEvaluateJSONRequest_(args); | |
736 }; | |
737 | |
738 | |
739 // Create a JSON request for the dir command. | |
740 DebugRequest.prototype.dirCommandToJSONRequest_ = function(args) { | |
741 // Build an evaluate request from the text command. | |
742 if (args.length == 0) { | |
743 throw new Error('Missing expression.'); | |
744 } | |
745 return this.makeEvaluateJSONRequest_(args); | |
746 }; | |
747 | |
748 | |
749 // Create a JSON request for the references command. | |
750 DebugRequest.prototype.referencesCommandToJSONRequest_ = function(args) { | |
751 // Build an evaluate request from the text command. | |
752 if (args.length == 0) { | |
753 throw new Error('Missing object id.'); | |
754 } | |
755 | |
756 return this.makeReferencesJSONRequest_(args, 'referencedBy'); | |
757 }; | |
758 | |
759 | |
760 // Create a JSON request for the instances command. | |
761 DebugRequest.prototype.instancesCommandToJSONRequest_ = function(args) { | |
762 // Build an evaluate request from the text command. | |
763 if (args.length == 0) { | |
764 throw new Error('Missing object id.'); | |
765 } | |
766 | |
767 // Build a references request. | |
768 return this.makeReferencesJSONRequest_(args, 'constructedBy'); | |
769 }; | |
770 | |
771 | |
772 // Create a JSON request for the list command. | |
773 DebugRequest.prototype.listCommandToJSONRequest_ = function(args) { | |
774 | |
775 // Default is ten lines starting five lines before the current location. | |
776 if (Debug.State.displaySourceEndLine == -1) { | |
777 // If we list forwards, we will start listing after the last source end | |
778 // line. Set it to start from 5 lines before the current location. | |
779 Debug.State.displaySourceEndLine = Debug.State.currentSourceLine - 5; | |
780 // If we list backwards, we will start listing backwards from the last | |
781 // source start line. Set it to start from 1 lines before the current | |
782 // location. | |
783 Debug.State.displaySourceStartLine = Debug.State.currentSourceLine + 1; | |
784 } | |
785 | |
786 var from = Debug.State.displaySourceEndLine + 1; | |
787 var lines = 10; | |
788 | |
789 // Parse the arguments. | |
790 args = args.split(/\s*,\s*/g); | |
791 if (args == '') { | |
792 } else if ((args.length == 1) && (args[0] == '-')) { | |
793 from = Debug.State.displaySourceStartLine - lines; | |
794 } else if (args.length == 2) { | |
795 from = parseInt(args[0]); | |
796 lines = parseInt(args[1]) - from + 1; // inclusive of the ending line. | |
797 } else { | |
798 throw new Error('Invalid list arguments.'); | |
799 } | |
800 Debug.State.displaySourceStartLine = from; | |
801 Debug.State.displaySourceEndLine = from + lines - 1; | |
802 var sourceArgs = '' + from + ' ' + lines; | |
803 return this.sourceCommandToJSONRequest_(sourceArgs); | |
804 }; | |
805 | |
806 | |
807 // Create a JSON request for the source command. | |
808 DebugRequest.prototype.sourceCommandToJSONRequest_ = function(args) { | |
809 // Build a evaluate request from the text command. | |
810 var request = this.createRequest('source'); | |
811 | |
812 // Default is ten lines starting five lines before the current location. | |
813 var from = Debug.State.currentSourceLine - 5; | |
814 var lines = 10; | |
815 | |
816 // Parse the arguments. | |
817 args = args.split(/\s*[ ]+\s*/g); | |
818 if (args.length > 1 && args[0].length > 0 && args[1].length > 0) { | |
819 from = parseInt(args[0]) - 1; | |
820 lines = parseInt(args[1]); | |
821 } else if (args.length > 0 && args[0].length > 0) { | |
822 from = parseInt(args[0]) - 1; | |
823 } | |
824 | |
825 if (from < 0) from = 0; | |
826 if (lines < 0) lines = 10; | |
827 | |
828 // Request source arround current source location. | |
829 request.arguments = {}; | |
830 request.arguments.fromLine = from; | |
831 request.arguments.toLine = from + lines; | |
832 | |
833 return request.toJSONProtocol(); | |
834 }; | |
835 | |
836 | |
837 // Create a JSON request for the scripts command. | |
838 DebugRequest.prototype.scriptsCommandToJSONRequest_ = function(args) { | |
839 // Build a evaluate request from the text command. | |
840 var request = this.createRequest('scripts'); | |
841 | |
842 // Process arguments if any. | |
843 if (args && args.length > 0) { | |
844 args = args.split(/\s*[ ]+\s*/g); | |
845 | |
846 if (args.length > 1) { | |
847 throw new Error('Invalid scripts arguments.'); | |
848 } | |
849 | |
850 request.arguments = {}; | |
851 switch (args[0]) { | |
852 case 'natives': | |
853 request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Native); | |
854 break; | |
855 | |
856 case 'extensions': | |
857 request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Extension); | |
858 break; | |
859 | |
860 case 'all': | |
861 request.arguments.types = | |
862 ScriptTypeFlag(Debug.ScriptType.Normal) | | |
863 ScriptTypeFlag(Debug.ScriptType.Native) | | |
864 ScriptTypeFlag(Debug.ScriptType.Extension); | |
865 break; | |
866 | |
867 default: | |
868 // If the arg is not one of the know one aboves, then it must be a | |
869 // filter used for filtering the results: | |
870 request.arguments.filter = args[0]; | |
871 break; | |
872 } | |
873 } | |
874 | |
875 return request.toJSONProtocol(); | |
876 }; | |
877 | |
878 | |
879 // Create a JSON request for the break command. | |
880 DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) { | |
881 // Build a evaluate request from the text command. | |
882 // Process arguments if any. | |
883 if (args && args.length > 0) { | |
884 var target = args; | |
885 var type = 'function'; | |
886 var line; | |
887 var column; | |
888 var condition; | |
889 var pos; | |
890 | |
891 var request = this.createRequest('setbreakpoint'); | |
892 | |
893 // Break the args into target spec and condition if appropriate. | |
894 | |
895 // Check for breakpoint condition. | |
896 pos = args.indexOf(' '); | |
897 if (pos > 0) { | |
898 target = args.substring(0, pos); | |
899 condition = args.substring(pos + 1, args.length); | |
900 } | |
901 | |
902 // Check for script breakpoint (name:line[:column]). If no ':' in break | |
903 // specification it is considered a function break point. | |
904 pos = target.indexOf(':'); | |
905 if (pos > 0) { | |
906 var tmp = target.substring(pos + 1, target.length); | |
907 target = target.substring(0, pos); | |
908 if (target[0] == '/' && target[target.length - 1] == '/') { | |
909 type = 'scriptRegExp'; | |
910 target = target.substring(1, target.length - 1); | |
911 } else { | |
912 type = 'script'; | |
913 } | |
914 | |
915 // Check for both line and column. | |
916 pos = tmp.indexOf(':'); | |
917 if (pos > 0) { | |
918 column = parseInt(tmp.substring(pos + 1, tmp.length)) - 1; | |
919 line = parseInt(tmp.substring(0, pos)) - 1; | |
920 } else { | |
921 line = parseInt(tmp) - 1; | |
922 } | |
923 } else if (target[0] == '#' && target[target.length - 1] == '#') { | |
924 type = 'handle'; | |
925 target = target.substring(1, target.length - 1); | |
926 } else { | |
927 type = 'function'; | |
928 } | |
929 | |
930 request.arguments = {}; | |
931 request.arguments.type = type; | |
932 request.arguments.target = target; | |
933 request.arguments.line = line; | |
934 request.arguments.column = column; | |
935 request.arguments.condition = condition; | |
936 } else { | |
937 var request = this.createRequest('suspend'); | |
938 } | |
939 | |
940 return request.toJSONProtocol(); | |
941 }; | |
942 | |
943 | |
944 DebugRequest.prototype.breakpointsCommandToJSONRequest_ = function(args) { | |
945 if (args && args.length > 0) { | |
946 throw new Error('Unexpected arguments.'); | |
947 } | |
948 var request = this.createRequest('listbreakpoints'); | |
949 return request.toJSONProtocol(); | |
950 }; | |
951 | |
952 | |
953 // Create a JSON request for the clear command. | |
954 DebugRequest.prototype.clearCommandToJSONRequest_ = function(args) { | |
955 // Build a evaluate request from the text command. | |
956 var request = this.createRequest('clearbreakpoint'); | |
957 | |
958 // Process arguments if any. | |
959 if (args && args.length > 0) { | |
960 request.arguments = {}; | |
961 request.arguments.breakpoint = parseInt(args); | |
962 } else { | |
963 throw new Error('Invalid break arguments.'); | |
964 } | |
965 | |
966 return request.toJSONProtocol(); | |
967 }; | |
968 | |
969 | |
970 // Create a JSON request for the change breakpoint command. | |
971 DebugRequest.prototype.changeBreakpointCommandToJSONRequest_ = | |
972 function(args, command) { | |
973 | |
974 var request; | |
975 | |
976 // Check for exception breaks first: | |
977 // en[able] exc[eptions] [all|unc[aught]] | |
978 // en[able] [all|unc[aught]] exc[eptions] | |
979 // dis[able] exc[eptions] [all|unc[aught]] | |
980 // dis[able] [all|unc[aught]] exc[eptions] | |
981 if ((command == 'enable' || command == 'disable') && | |
982 args && args.length > 1) { | |
983 var nextPos = args.indexOf(' '); | |
984 var arg1 = (nextPos > 0) ? args.substring(0, nextPos) : args; | |
985 var excType = null; | |
986 | |
987 // Check for: | |
988 // en[able] exc[eptions] [all|unc[aught]] | |
989 // dis[able] exc[eptions] [all|unc[aught]] | |
990 if (arg1 == 'exc' || arg1 == 'exception' || arg1 == 'exceptions') { | |
991 | |
992 var arg2 = (nextPos > 0) ? | |
993 args.substring(nextPos + 1, args.length) : 'all'; | |
994 if (!arg2) { | |
995 arg2 = 'all'; // if unspecified, set for all. | |
996 } else if (arg2 == 'unc') { // check for short cut. | |
997 arg2 = 'uncaught'; | |
998 } | |
999 excType = arg2; | |
1000 | |
1001 // Check for: | |
1002 // en[able] [all|unc[aught]] exc[eptions] | |
1003 // dis[able] [all|unc[aught]] exc[eptions] | |
1004 } else if (arg1 == 'all' || arg1 == 'unc' || arg1 == 'uncaught') { | |
1005 | |
1006 var arg2 = (nextPos > 0) ? | |
1007 args.substring(nextPos + 1, args.length) : null; | |
1008 if (arg2 == 'exc' || arg1 == 'exception' || arg1 == 'exceptions') { | |
1009 excType = arg1; | |
1010 if (excType == 'unc') { | |
1011 excType = 'uncaught'; | |
1012 } | |
1013 } | |
1014 } | |
1015 | |
1016 // If we matched one of the command formats, then excType will be non-null: | |
1017 if (excType) { | |
1018 // Build a evaluate request from the text command. | |
1019 request = this.createRequest('setexceptionbreak'); | |
1020 | |
1021 request.arguments = {}; | |
1022 request.arguments.type = excType; | |
1023 request.arguments.enabled = (command == 'enable'); | |
1024 | |
1025 return request.toJSONProtocol(); | |
1026 } | |
1027 } | |
1028 | |
1029 // Build a evaluate request from the text command. | |
1030 request = this.createRequest('changebreakpoint'); | |
1031 | |
1032 // Process arguments if any. | |
1033 if (args && args.length > 0) { | |
1034 request.arguments = {}; | |
1035 var pos = args.indexOf(' '); | |
1036 var breakpointArg = args; | |
1037 var otherArgs; | |
1038 if (pos > 0) { | |
1039 breakpointArg = args.substring(0, pos); | |
1040 otherArgs = args.substring(pos + 1, args.length); | |
1041 } | |
1042 | |
1043 request.arguments.breakpoint = parseInt(breakpointArg); | |
1044 | |
1045 switch(command) { | |
1046 case 'cond': | |
1047 request.arguments.condition = otherArgs ? otherArgs : null; | |
1048 break; | |
1049 case 'enable': | |
1050 request.arguments.enabled = true; | |
1051 break; | |
1052 case 'disable': | |
1053 request.arguments.enabled = false; | |
1054 break; | |
1055 case 'ignore': | |
1056 request.arguments.ignoreCount = parseInt(otherArgs); | |
1057 break; | |
1058 default: | |
1059 throw new Error('Invalid arguments.'); | |
1060 } | |
1061 } else { | |
1062 throw new Error('Invalid arguments.'); | |
1063 } | |
1064 | |
1065 return request.toJSONProtocol(); | |
1066 }; | |
1067 | |
1068 | |
1069 // Create a JSON request for the disconnect command. | |
1070 DebugRequest.prototype.disconnectCommandToJSONRequest_ = function(args) { | |
1071 var request; | |
1072 request = this.createRequest('disconnect'); | |
1073 return request.toJSONProtocol(); | |
1074 }; | |
1075 | |
1076 | |
1077 // Create a JSON request for the info command. | |
1078 DebugRequest.prototype.infoCommandToJSONRequest_ = function(args) { | |
1079 var request; | |
1080 if (args && (args == 'break' || args == 'br')) { | |
1081 // Build a evaluate request from the text command. | |
1082 request = this.createRequest('listbreakpoints'); | |
1083 last_cmd = 'info break'; | |
1084 } else if (args && (args == 'locals' || args == 'lo')) { | |
1085 // Build a evaluate request from the text command. | |
1086 request = this.createRequest('frame'); | |
1087 last_cmd = 'info locals'; | |
1088 } else if (args && (args == 'args' || args == 'ar')) { | |
1089 // Build a evaluate request from the text command. | |
1090 request = this.createRequest('frame'); | |
1091 last_cmd = 'info args'; | |
1092 } else { | |
1093 throw new Error('Invalid info arguments.'); | |
1094 } | |
1095 | |
1096 return request.toJSONProtocol(); | |
1097 }; | |
1098 | |
1099 | |
1100 DebugRequest.prototype.v8FlagsToJSONRequest_ = function(args) { | |
1101 var request; | |
1102 request = this.createRequest('v8flags'); | |
1103 request.arguments = {}; | |
1104 request.arguments.flags = args; | |
1105 return request.toJSONProtocol(); | |
1106 }; | |
1107 | |
1108 | |
1109 DebugRequest.prototype.gcToJSONRequest_ = function(args) { | |
1110 var request; | |
1111 if (!args) { | |
1112 args = 'all'; | |
1113 } | |
1114 var args = args.split(/\s+/g); | |
1115 var cmd = args[0]; | |
1116 | |
1117 switch(cmd) { | |
1118 case 'all': | |
1119 case 'quick': | |
1120 case 'full': | |
1121 case 'young': | |
1122 case 'old': | |
1123 case 'compact': | |
1124 case 'sweep': | |
1125 case 'scavenge': { | |
1126 if (cmd == 'young') { cmd = 'quick'; } | |
1127 else if (cmd == 'old') { cmd = 'full'; } | |
1128 | |
1129 request = this.createRequest('gc'); | |
1130 request.arguments = {}; | |
1131 request.arguments.type = cmd; | |
1132 break; | |
1133 } | |
1134 // Else fall thru to the default case below to report the error. | |
1135 default: | |
1136 throw new Error('Missing arguments after ' + cmd + '.'); | |
1137 } | |
1138 return request.toJSONProtocol(); | |
1139 }; | |
1140 | |
1141 | |
1142 // Create a JSON request for the threads command. | |
1143 DebugRequest.prototype.threadsCommandToJSONRequest_ = function(args) { | |
1144 // Build a threads request from the text command. | |
1145 var request = this.createRequest('threads'); | |
1146 return request.toJSONProtocol(); | |
1147 }; | |
1148 | |
1149 | |
1150 // Handle the trace command. | |
1151 DebugRequest.prototype.traceCommand_ = function(args) { | |
1152 // Process arguments. | |
1153 if (args && args.length > 0) { | |
1154 if (args == 'compile') { | |
1155 trace_compile = !trace_compile; | |
1156 print('Tracing of compiled scripts ' + (trace_compile ? 'on' : 'off')); | |
1157 } else if (args === 'debug json' || args === 'json' || args === 'packets') { | |
1158 trace_debug_json = !trace_debug_json; | |
1159 print('Tracing of debug json packets ' + | |
1160 (trace_debug_json ? 'on' : 'off')); | |
1161 } else { | |
1162 throw new Error('Invalid trace arguments.'); | |
1163 } | |
1164 } else { | |
1165 throw new Error('Invalid trace arguments.'); | |
1166 } | |
1167 }; | |
1168 | |
1169 // Handle the help command. | |
1170 DebugRequest.prototype.helpCommand_ = function(args) { | |
1171 // Help os quite simple. | |
1172 if (args && args.length > 0) { | |
1173 print('warning: arguments to \'help\' are ignored'); | |
1174 } | |
1175 | |
1176 print('Note: <> denotes symbollic values to be replaced with real values.'); | |
1177 print('Note: [] denotes optional parts of commands, or optional options / argu
ments.'); | |
1178 print(' e.g. d[elete] - you get the same command if you type d or delete.
'); | |
1179 print(''); | |
1180 print('[break] - break as soon as possible'); | |
1181 print('b[reak] location [condition]'); | |
1182 print(' - break on named function: location is a function name'); | |
1183 print(' - break on function: location is #<id>#'); | |
1184 print(' - break on script position: location is name:line[:column]'); | |
1185 print(''); | |
1186 print('clear <breakpoint #> - deletes the specified user defined breakpo
int'); | |
1187 print('d[elete] <breakpoint #> - deletes the specified user defined breakpo
int'); | |
1188 print('dis[able] <breakpoint #> - disables the specified user defined breakp
oint'); | |
1189 print('dis[able] exc[eptions] [[all] | unc[aught]]'); | |
1190 print(' - disables breaking on exceptions'); | |
1191 print('en[able] <breakpoint #> - enables the specified user defined breakpo
int'); | |
1192 print('en[able] exc[eptions] [[all] | unc[aught]]'); | |
1193 print(' - enables breaking on exceptions'); | |
1194 print(''); | |
1195 print('b[ack]t[race] [n] | [-n] | [from to]'); | |
1196 print(' - prints the stack back trace'); | |
1197 print('f[rame] - prints info about the current frame contex
t'); | |
1198 print('f[rame] <frame #> - set context to specified frame #'); | |
1199 print('scopes'); | |
1200 print('scope <scope #>'); | |
1201 print(''); | |
1202 print('up - set context to caller of current frame'); | |
1203 print('do[wn] - set context to callee of current frame'); | |
1204 print('inf[o] br[eak] - prints info about breakpoints in use'); | |
1205 print('inf[o] ar[gs] - prints info about arguments of the current
function'); | |
1206 print('inf[o] lo[cals] - prints info about locals in the current fu
nction'); | |
1207 print(''); | |
1208 print('step [in | next | out| min [step count]]'); | |
1209 print('c[ontinue] - continue executing after a breakpoint'); | |
1210 print('s[tep] [<N>] - step into the next N callees (default N is
1)'); | |
1211 print('s[tep]i [<N>] - step into the next N callees (default N is
1)'); | |
1212 print('n[ext] [<N>] - step over the next N callees (default N is
1)'); | |
1213 print('fin[ish] [<N>] - step out of N frames (default N is 1)'); | |
1214 print(''); | |
1215 print('p[rint] <expression> - prints the result of the specified express
ion'); | |
1216 print('dir <expression> - prints the object structure of the result'
); | |
1217 print('set <var> = <expression> - executes the specified statement'); | |
1218 print(''); | |
1219 print('l[ist] - list the source code around for the curren
t pc'); | |
1220 print('l[ist] [- | <start>,<end>] - list the specified range of source code'); | |
1221 print('source [from line [num lines]]'); | |
1222 print('scr[ipts] [native|extensions|all]'); | |
1223 print('scr[ipts] [<filter text>] - list scripts with the specified text in it
s description'); | |
1224 print(''); | |
1225 print('gc - runs the garbage collector'); | |
1226 print(''); | |
1227 print('trace compile'); | |
1228 // hidden command: trace debug json - toggles tracing of debug json packets | |
1229 print(''); | |
1230 print('disconnect|exit|quit - disconnects and quits the debugger'); | |
1231 print('help - prints this help information'); | |
1232 }; | |
1233 | |
1234 | |
1235 function formatHandleReference_(value) { | |
1236 if (value.handle() >= 0) { | |
1237 return '#' + value.handle() + '#'; | |
1238 } else { | |
1239 return '#Transient#'; | |
1240 } | |
1241 } | |
1242 | |
1243 | |
1244 function formatObject_(value, include_properties) { | |
1245 var result = ''; | |
1246 result += formatHandleReference_(value); | |
1247 result += ', type: object'; | |
1248 result += ', constructor '; | |
1249 var ctor = value.constructorFunctionValue(); | |
1250 result += formatHandleReference_(ctor); | |
1251 result += ', __proto__ '; | |
1252 var proto = value.protoObjectValue(); | |
1253 result += formatHandleReference_(proto); | |
1254 result += ', '; | |
1255 result += value.propertyCount(); | |
1256 result += ' properties.'; | |
1257 if (include_properties) { | |
1258 result += '\n'; | |
1259 for (var i = 0; i < value.propertyCount(); i++) { | |
1260 result += ' '; | |
1261 result += value.propertyName(i); | |
1262 result += ': '; | |
1263 var property_value = value.propertyValue(i); | |
1264 if (property_value instanceof ProtocolReference) { | |
1265 result += '<no type>'; | |
1266 } else { | |
1267 if (property_value && property_value.type()) { | |
1268 result += property_value.type(); | |
1269 } else { | |
1270 result += '<no type>'; | |
1271 } | |
1272 } | |
1273 result += ' '; | |
1274 result += formatHandleReference_(property_value); | |
1275 result += '\n'; | |
1276 } | |
1277 } | |
1278 return result; | |
1279 } | |
1280 | |
1281 | |
1282 function formatScope_(scope) { | |
1283 var result = ''; | |
1284 var index = scope.index; | |
1285 result += '#' + (index <= 9 ? '0' : '') + index; | |
1286 result += ' '; | |
1287 switch (scope.type) { | |
1288 case Debug.ScopeType.Global: | |
1289 result += 'Global, '; | |
1290 result += '#' + scope.object.ref + '#'; | |
1291 break; | |
1292 case Debug.ScopeType.Local: | |
1293 result += 'Local'; | |
1294 break; | |
1295 case Debug.ScopeType.With: | |
1296 result += 'With, '; | |
1297 result += '#' + scope.object.ref + '#'; | |
1298 break; | |
1299 case Debug.ScopeType.Catch: | |
1300 result += 'Catch, '; | |
1301 result += '#' + scope.object.ref + '#'; | |
1302 break; | |
1303 case Debug.ScopeType.Closure: | |
1304 result += 'Closure'; | |
1305 break; | |
1306 default: | |
1307 result += 'UNKNOWN'; | |
1308 } | |
1309 return result; | |
1310 } | |
1311 | |
1312 | |
1313 function refObjectToString_(protocolPackage, handle) { | |
1314 var value = protocolPackage.lookup(handle); | |
1315 var result = ''; | |
1316 if (value.isString()) { | |
1317 result = '"' + value.value() + '"'; | |
1318 } else if (value.isPrimitive()) { | |
1319 result = value.valueString(); | |
1320 } else if (value.isObject()) { | |
1321 result += formatObject_(value, true); | |
1322 } | |
1323 return result; | |
1324 } | |
1325 | |
1326 | |
1327 // Rounds number 'num' to 'length' decimal places. | |
1328 function roundNumber(num, length) { | |
1329 var factor = Math.pow(10, length); | |
1330 return Math.round(num * factor) / factor; | |
1331 } | |
1332 | |
1333 | |
1334 // Convert a JSON response to text for display in a text based debugger. | |
1335 function DebugResponseDetails(response) { | |
1336 var details = { text: '', running: false }; | |
1337 | |
1338 try { | |
1339 if (!response.success()) { | |
1340 details.text = response.message(); | |
1341 return details; | |
1342 } | |
1343 | |
1344 // Get the running state. | |
1345 details.running = response.running(); | |
1346 | |
1347 var body = response.body(); | |
1348 var result = ''; | |
1349 switch (response.command()) { | |
1350 case 'suspend': | |
1351 details.text = 'stopped'; | |
1352 break; | |
1353 | |
1354 case 'setbreakpoint': | |
1355 result = 'set breakpoint #'; | |
1356 result += body.breakpoint; | |
1357 details.text = result; | |
1358 break; | |
1359 | |
1360 case 'clearbreakpoint': | |
1361 result = 'cleared breakpoint #'; | |
1362 result += body.breakpoint; | |
1363 details.text = result; | |
1364 break; | |
1365 | |
1366 case 'changebreakpoint': | |
1367 result = 'successfully changed breakpoint'; | |
1368 details.text = result; | |
1369 break; | |
1370 | |
1371 case 'listbreakpoints': | |
1372 result = 'breakpoints: (' + body.breakpoints.length + ')'; | |
1373 for (var i = 0; i < body.breakpoints.length; i++) { | |
1374 var breakpoint = body.breakpoints[i]; | |
1375 result += '\n id=' + breakpoint.number; | |
1376 result += ' type=' + breakpoint.type; | |
1377 if (breakpoint.script_id) { | |
1378 result += ' script_id=' + breakpoint.script_id; | |
1379 } | |
1380 if (breakpoint.script_name) { | |
1381 result += ' script_name=' + breakpoint.script_name; | |
1382 } | |
1383 if (breakpoint.script_regexp) { | |
1384 result += ' script_regexp=' + breakpoint.script_regexp; | |
1385 } | |
1386 result += ' line=' + (breakpoint.line + 1); | |
1387 if (breakpoint.column != null) { | |
1388 result += ' column=' + (breakpoint.column + 1); | |
1389 } | |
1390 if (breakpoint.groupId) { | |
1391 result += ' groupId=' + breakpoint.groupId; | |
1392 } | |
1393 if (breakpoint.ignoreCount) { | |
1394 result += ' ignoreCount=' + breakpoint.ignoreCount; | |
1395 } | |
1396 if (breakpoint.active === false) { | |
1397 result += ' inactive'; | |
1398 } | |
1399 if (breakpoint.condition) { | |
1400 result += ' condition=' + breakpoint.condition; | |
1401 } | |
1402 result += ' hit_count=' + breakpoint.hit_count; | |
1403 } | |
1404 if (body.breakpoints.length === 0) { | |
1405 result = "No user defined breakpoints\n"; | |
1406 } else { | |
1407 result += '\n'; | |
1408 } | |
1409 if (body.breakOnExceptions) { | |
1410 result += '* breaking on ALL exceptions is enabled\n'; | |
1411 } else if (body.breakOnUncaughtExceptions) { | |
1412 result += '* breaking on UNCAUGHT exceptions is enabled\n'; | |
1413 } else { | |
1414 result += '* all exception breakpoints are disabled\n'; | |
1415 } | |
1416 details.text = result; | |
1417 break; | |
1418 | |
1419 case 'setexceptionbreak': | |
1420 result = 'Break on ' + body.type + ' exceptions: '; | |
1421 result += body.enabled ? 'enabled' : 'disabled'; | |
1422 details.text = result; | |
1423 break; | |
1424 | |
1425 case 'backtrace': | |
1426 if (body.totalFrames == 0) { | |
1427 result = '(empty stack)'; | |
1428 } else { | |
1429 var result = 'Frames #' + body.fromFrame + ' to #' + | |
1430 (body.toFrame - 1) + ' of ' + body.totalFrames + '\n'; | |
1431 for (i = 0; i < body.frames.length; i++) { | |
1432 if (i != 0) result += '\n'; | |
1433 result += body.frames[i].text; | |
1434 } | |
1435 } | |
1436 details.text = result; | |
1437 break; | |
1438 | |
1439 case 'frame': | |
1440 if (last_cmd === 'info locals') { | |
1441 var locals = body.locals; | |
1442 if (locals.length === 0) { | |
1443 result = 'No locals'; | |
1444 } else { | |
1445 for (var i = 0; i < locals.length; i++) { | |
1446 var local = locals[i]; | |
1447 result += local.name + ' = '; | |
1448 result += refObjectToString_(response, local.value.ref); | |
1449 result += '\n'; | |
1450 } | |
1451 } | |
1452 } else if (last_cmd === 'info args') { | |
1453 var args = body.arguments; | |
1454 if (args.length === 0) { | |
1455 result = 'No arguments'; | |
1456 } else { | |
1457 for (var i = 0; i < args.length; i++) { | |
1458 var arg = args[i]; | |
1459 result += arg.name + ' = '; | |
1460 result += refObjectToString_(response, arg.value.ref); | |
1461 result += '\n'; | |
1462 } | |
1463 } | |
1464 } else { | |
1465 result = SourceUnderline(body.sourceLineText, | |
1466 body.column); | |
1467 Debug.State.currentSourceLine = body.line; | |
1468 Debug.State.currentFrame = body.index; | |
1469 Debug.State.displaySourceStartLine = -1; | |
1470 Debug.State.displaySourceEndLine = -1; | |
1471 } | |
1472 details.text = result; | |
1473 break; | |
1474 | |
1475 case 'scopes': | |
1476 if (body.totalScopes == 0) { | |
1477 result = '(no scopes)'; | |
1478 } else { | |
1479 result = 'Scopes #' + body.fromScope + ' to #' + | |
1480 (body.toScope - 1) + ' of ' + body.totalScopes + '\n'; | |
1481 for (i = 0; i < body.scopes.length; i++) { | |
1482 if (i != 0) { | |
1483 result += '\n'; | |
1484 } | |
1485 result += formatScope_(body.scopes[i]); | |
1486 } | |
1487 } | |
1488 details.text = result; | |
1489 break; | |
1490 | |
1491 case 'scope': | |
1492 result += formatScope_(body); | |
1493 result += '\n'; | |
1494 var scope_object_value = response.lookup(body.object.ref); | |
1495 result += formatObject_(scope_object_value, true); | |
1496 details.text = result; | |
1497 break; | |
1498 | |
1499 case 'evaluate': | |
1500 case 'lookup': | |
1501 case 'getobj': | |
1502 if (last_cmd == 'p' || last_cmd == 'print') { | |
1503 result = body.text; | |
1504 } else { | |
1505 var value; | |
1506 if (lookup_handle) { | |
1507 value = response.bodyValue(lookup_handle); | |
1508 } else { | |
1509 value = response.bodyValue(); | |
1510 } | |
1511 if (value.isObject()) { | |
1512 result += formatObject_(value, true); | |
1513 } else { | |
1514 result += 'type: '; | |
1515 result += value.type(); | |
1516 if (!value.isUndefined() && !value.isNull()) { | |
1517 result += ', '; | |
1518 if (value.isString()) { | |
1519 result += '"'; | |
1520 } | |
1521 result += value.value(); | |
1522 if (value.isString()) { | |
1523 result += '"'; | |
1524 } | |
1525 } | |
1526 result += '\n'; | |
1527 } | |
1528 } | |
1529 details.text = result; | |
1530 break; | |
1531 | |
1532 case 'references': | |
1533 var count = body.length; | |
1534 result += 'found ' + count + ' objects'; | |
1535 result += '\n'; | |
1536 for (var i = 0; i < count; i++) { | |
1537 var value = response.bodyValue(i); | |
1538 result += formatObject_(value, false); | |
1539 result += '\n'; | |
1540 } | |
1541 details.text = result; | |
1542 break; | |
1543 | |
1544 case 'source': | |
1545 // Get the source from the response. | |
1546 var source = body.source; | |
1547 var from_line = body.fromLine + 1; | |
1548 var lines = source.split('\n'); | |
1549 var maxdigits = 1 + Math.floor(log10(from_line + lines.length)); | |
1550 if (maxdigits < 3) { | |
1551 maxdigits = 3; | |
1552 } | |
1553 var result = ''; | |
1554 for (var num = 0; num < lines.length; num++) { | |
1555 // Check if there's an extra newline at the end. | |
1556 if (num == (lines.length - 1) && lines[num].length == 0) { | |
1557 break; | |
1558 } | |
1559 | |
1560 var current_line = from_line + num; | |
1561 var spacer = maxdigits - (1 + Math.floor(log10(current_line))); | |
1562 if (current_line == Debug.State.currentSourceLine + 1) { | |
1563 for (var i = 0; i < maxdigits; i++) { | |
1564 result += '>'; | |
1565 } | |
1566 result += ' '; | |
1567 } else { | |
1568 for (var i = 0; i < spacer; i++) { | |
1569 result += ' '; | |
1570 } | |
1571 result += current_line + ': '; | |
1572 } | |
1573 result += lines[num]; | |
1574 result += '\n'; | |
1575 } | |
1576 details.text = result; | |
1577 break; | |
1578 | |
1579 case 'scripts': | |
1580 var result = ''; | |
1581 for (i = 0; i < body.length; i++) { | |
1582 if (i != 0) result += '\n'; | |
1583 if (body[i].id) { | |
1584 result += body[i].id; | |
1585 } else { | |
1586 result += '[no id]'; | |
1587 } | |
1588 result += ', '; | |
1589 if (body[i].name) { | |
1590 result += body[i].name; | |
1591 } else { | |
1592 if (body[i].compilationType == Debug.ScriptCompilationType.Eval | |
1593 && body[i].evalFromScript | |
1594 ) { | |
1595 result += 'eval from '; | |
1596 var script_value = response.lookup(body[i].evalFromScript.ref); | |
1597 result += ' ' + script_value.field('name'); | |
1598 result += ':' + (body[i].evalFromLocation.line + 1); | |
1599 result += ':' + body[i].evalFromLocation.column; | |
1600 } else if (body[i].compilationType == | |
1601 Debug.ScriptCompilationType.JSON) { | |
1602 result += 'JSON '; | |
1603 } else { // body[i].compilation == Debug.ScriptCompilationType.Host | |
1604 result += '[unnamed] '; | |
1605 } | |
1606 } | |
1607 result += ' (lines: '; | |
1608 result += body[i].lineCount; | |
1609 result += ', length: '; | |
1610 result += body[i].sourceLength; | |
1611 if (body[i].type == Debug.ScriptType.Native) { | |
1612 result += ', native'; | |
1613 } else if (body[i].type == Debug.ScriptType.Extension) { | |
1614 result += ', extension'; | |
1615 } | |
1616 result += '), ['; | |
1617 var sourceStart = body[i].sourceStart; | |
1618 if (sourceStart.length > 40) { | |
1619 sourceStart = sourceStart.substring(0, 37) + '...'; | |
1620 } | |
1621 result += sourceStart; | |
1622 result += ']'; | |
1623 } | |
1624 if (body.length == 0) { | |
1625 result = "no matching scripts found"; | |
1626 } | |
1627 details.text = result; | |
1628 break; | |
1629 | |
1630 case 'threads': | |
1631 var result = 'Active V8 threads: ' + body.totalThreads + '\n'; | |
1632 body.threads.sort(function(a, b) { return a.id - b.id; }); | |
1633 for (i = 0; i < body.threads.length; i++) { | |
1634 result += body.threads[i].current ? '*' : ' '; | |
1635 result += ' '; | |
1636 result += body.threads[i].id; | |
1637 result += '\n'; | |
1638 } | |
1639 details.text = result; | |
1640 break; | |
1641 | |
1642 case 'continue': | |
1643 details.text = "(running)"; | |
1644 break; | |
1645 | |
1646 case 'v8flags': | |
1647 details.text = "flags set"; | |
1648 break; | |
1649 | |
1650 case 'gc': | |
1651 details.text = "GC " + body.before + " => " + body.after; | |
1652 if (body.after > (1024*1024)) { | |
1653 details.text += | |
1654 " (" + roundNumber(body.before/(1024*1024), 1) + "M => " + | |
1655 roundNumber(body.after/(1024*1024), 1) + "M)"; | |
1656 } else if (body.after > 1024) { | |
1657 details.text += | |
1658 " (" + roundNumber(body.before/1024, 1) + "K => " + | |
1659 roundNumber(body.after/1024, 1) + "K)"; | |
1660 } | |
1661 break; | |
1662 | |
1663 default: | |
1664 details.text = | |
1665 'Response for unknown command \'' + response.command() + '\'' + | |
1666 ' (' + response.raw_json() + ')'; | |
1667 } | |
1668 } catch (e) { | |
1669 details.text = 'Error: "' + e + '" formatting response'; | |
1670 } | |
1671 | |
1672 return details; | |
1673 } | |
1674 | |
1675 | |
1676 /** | |
1677 * Protocol packages send from the debugger. | |
1678 * @param {string} json - raw protocol packet as JSON string. | |
1679 * @constructor | |
1680 */ | |
1681 function ProtocolPackage(json) { | |
1682 this.raw_json_ = json; | |
1683 this.packet_ = JSON.parse(json); | |
1684 this.refs_ = []; | |
1685 if (this.packet_.refs) { | |
1686 for (var i = 0; i < this.packet_.refs.length; i++) { | |
1687 this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i]; | |
1688 } | |
1689 } | |
1690 } | |
1691 | |
1692 | |
1693 /** | |
1694 * Get the packet type. | |
1695 * @return {String} the packet type | |
1696 */ | |
1697 ProtocolPackage.prototype.type = function() { | |
1698 return this.packet_.type; | |
1699 }; | |
1700 | |
1701 | |
1702 /** | |
1703 * Get the packet event. | |
1704 * @return {Object} the packet event | |
1705 */ | |
1706 ProtocolPackage.prototype.event = function() { | |
1707 return this.packet_.event; | |
1708 }; | |
1709 | |
1710 | |
1711 /** | |
1712 * Get the packet request sequence. | |
1713 * @return {number} the packet request sequence | |
1714 */ | |
1715 ProtocolPackage.prototype.requestSeq = function() { | |
1716 return this.packet_.request_seq; | |
1717 }; | |
1718 | |
1719 | |
1720 /** | |
1721 * Get the packet request sequence. | |
1722 * @return {number} the packet request sequence | |
1723 */ | |
1724 ProtocolPackage.prototype.running = function() { | |
1725 return this.packet_.running ? true : false; | |
1726 }; | |
1727 | |
1728 | |
1729 ProtocolPackage.prototype.success = function() { | |
1730 return this.packet_.success ? true : false; | |
1731 }; | |
1732 | |
1733 | |
1734 ProtocolPackage.prototype.message = function() { | |
1735 return this.packet_.message; | |
1736 }; | |
1737 | |
1738 | |
1739 ProtocolPackage.prototype.command = function() { | |
1740 return this.packet_.command; | |
1741 }; | |
1742 | |
1743 | |
1744 ProtocolPackage.prototype.body = function() { | |
1745 return this.packet_.body; | |
1746 }; | |
1747 | |
1748 | |
1749 ProtocolPackage.prototype.bodyValue = function(index) { | |
1750 if (index != null) { | |
1751 return new ProtocolValue(this.packet_.body[index], this); | |
1752 } else { | |
1753 return new ProtocolValue(this.packet_.body, this); | |
1754 } | |
1755 }; | |
1756 | |
1757 | |
1758 ProtocolPackage.prototype.body = function() { | |
1759 return this.packet_.body; | |
1760 }; | |
1761 | |
1762 | |
1763 ProtocolPackage.prototype.lookup = function(handle) { | |
1764 var value = this.refs_[handle]; | |
1765 if (value) { | |
1766 return new ProtocolValue(value, this); | |
1767 } else { | |
1768 return new ProtocolReference(handle); | |
1769 } | |
1770 }; | |
1771 | |
1772 | |
1773 ProtocolPackage.prototype.raw_json = function() { | |
1774 return this.raw_json_; | |
1775 }; | |
1776 | |
1777 | |
1778 function ProtocolValue(value, packet) { | |
1779 this.value_ = value; | |
1780 this.packet_ = packet; | |
1781 } | |
1782 | |
1783 | |
1784 /** | |
1785 * Get the value type. | |
1786 * @return {String} the value type | |
1787 */ | |
1788 ProtocolValue.prototype.type = function() { | |
1789 return this.value_.type; | |
1790 }; | |
1791 | |
1792 | |
1793 /** | |
1794 * Get a metadata field from a protocol value. | |
1795 * @return {Object} the metadata field value | |
1796 */ | |
1797 ProtocolValue.prototype.field = function(name) { | |
1798 return this.value_[name]; | |
1799 }; | |
1800 | |
1801 | |
1802 /** | |
1803 * Check is the value is a primitive value. | |
1804 * @return {boolean} true if the value is primitive | |
1805 */ | |
1806 ProtocolValue.prototype.isPrimitive = function() { | |
1807 return this.isUndefined() || this.isNull() || this.isBoolean() || | |
1808 this.isNumber() || this.isString(); | |
1809 }; | |
1810 | |
1811 | |
1812 /** | |
1813 * Get the object handle. | |
1814 * @return {number} the value handle | |
1815 */ | |
1816 ProtocolValue.prototype.handle = function() { | |
1817 return this.value_.handle; | |
1818 }; | |
1819 | |
1820 | |
1821 /** | |
1822 * Check is the value is undefined. | |
1823 * @return {boolean} true if the value is undefined | |
1824 */ | |
1825 ProtocolValue.prototype.isUndefined = function() { | |
1826 return this.value_.type == 'undefined'; | |
1827 }; | |
1828 | |
1829 | |
1830 /** | |
1831 * Check is the value is null. | |
1832 * @return {boolean} true if the value is null | |
1833 */ | |
1834 ProtocolValue.prototype.isNull = function() { | |
1835 return this.value_.type == 'null'; | |
1836 }; | |
1837 | |
1838 | |
1839 /** | |
1840 * Check is the value is a boolean. | |
1841 * @return {boolean} true if the value is a boolean | |
1842 */ | |
1843 ProtocolValue.prototype.isBoolean = function() { | |
1844 return this.value_.type == 'boolean'; | |
1845 }; | |
1846 | |
1847 | |
1848 /** | |
1849 * Check is the value is a number. | |
1850 * @return {boolean} true if the value is a number | |
1851 */ | |
1852 ProtocolValue.prototype.isNumber = function() { | |
1853 return this.value_.type == 'number'; | |
1854 }; | |
1855 | |
1856 | |
1857 /** | |
1858 * Check is the value is a string. | |
1859 * @return {boolean} true if the value is a string | |
1860 */ | |
1861 ProtocolValue.prototype.isString = function() { | |
1862 return this.value_.type == 'string'; | |
1863 }; | |
1864 | |
1865 | |
1866 /** | |
1867 * Check is the value is an object. | |
1868 * @return {boolean} true if the value is an object | |
1869 */ | |
1870 ProtocolValue.prototype.isObject = function() { | |
1871 return this.value_.type == 'object' || this.value_.type == 'function' || | |
1872 this.value_.type == 'error' || this.value_.type == 'regexp'; | |
1873 }; | |
1874 | |
1875 | |
1876 /** | |
1877 * Get the constructor function | |
1878 * @return {ProtocolValue} constructor function | |
1879 */ | |
1880 ProtocolValue.prototype.constructorFunctionValue = function() { | |
1881 var ctor = this.value_.constructorFunction; | |
1882 return this.packet_.lookup(ctor.ref); | |
1883 }; | |
1884 | |
1885 | |
1886 /** | |
1887 * Get the __proto__ value | |
1888 * @return {ProtocolValue} __proto__ value | |
1889 */ | |
1890 ProtocolValue.prototype.protoObjectValue = function() { | |
1891 var proto = this.value_.protoObject; | |
1892 return this.packet_.lookup(proto.ref); | |
1893 }; | |
1894 | |
1895 | |
1896 /** | |
1897 * Get the number og properties. | |
1898 * @return {number} the number of properties | |
1899 */ | |
1900 ProtocolValue.prototype.propertyCount = function() { | |
1901 return this.value_.properties ? this.value_.properties.length : 0; | |
1902 }; | |
1903 | |
1904 | |
1905 /** | |
1906 * Get the specified property name. | |
1907 * @return {string} property name | |
1908 */ | |
1909 ProtocolValue.prototype.propertyName = function(index) { | |
1910 var property = this.value_.properties[index]; | |
1911 return property.name; | |
1912 }; | |
1913 | |
1914 | |
1915 /** | |
1916 * Return index for the property name. | |
1917 * @param name The property name to look for | |
1918 * @return {number} index for the property name | |
1919 */ | |
1920 ProtocolValue.prototype.propertyIndex = function(name) { | |
1921 for (var i = 0; i < this.propertyCount(); i++) { | |
1922 if (this.value_.properties[i].name == name) { | |
1923 return i; | |
1924 } | |
1925 } | |
1926 return null; | |
1927 }; | |
1928 | |
1929 | |
1930 /** | |
1931 * Get the specified property value. | |
1932 * @return {ProtocolValue} property value | |
1933 */ | |
1934 ProtocolValue.prototype.propertyValue = function(index) { | |
1935 var property = this.value_.properties[index]; | |
1936 return this.packet_.lookup(property.ref); | |
1937 }; | |
1938 | |
1939 | |
1940 /** | |
1941 * Check is the value is a string. | |
1942 * @return {boolean} true if the value is a string | |
1943 */ | |
1944 ProtocolValue.prototype.value = function() { | |
1945 return this.value_.value; | |
1946 }; | |
1947 | |
1948 | |
1949 ProtocolValue.prototype.valueString = function() { | |
1950 return this.value_.text; | |
1951 }; | |
1952 | |
1953 | |
1954 function ProtocolReference(handle) { | |
1955 this.handle_ = handle; | |
1956 } | |
1957 | |
1958 | |
1959 ProtocolReference.prototype.handle = function() { | |
1960 return this.handle_; | |
1961 }; | |
1962 | |
1963 | |
1964 // A more universal stringify that supports more types than JSON. | 52 // A more universal stringify that supports more types than JSON. |
1965 // Used by the d8 shell to output results. | 53 // Used by the d8 shell to output results. |
1966 var stringifyDepthLimit = 4; // To avoid crashing on cyclic objects | 54 var stringifyDepthLimit = 4; // To avoid crashing on cyclic objects |
1967 | 55 |
1968 function Stringify(x, depth) { | 56 function Stringify(x, depth) { |
1969 if (depth === undefined) | 57 if (depth === undefined) |
1970 depth = stringifyDepthLimit; | 58 depth = stringifyDepthLimit; |
1971 else if (depth === 0) | 59 else if (depth === 0) |
1972 return "*"; | 60 return "*"; |
1973 switch (typeof x) { | 61 switch (typeof x) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2010 var getter = Stringify(desc.get); | 98 var getter = Stringify(desc.get); |
2011 props.push("get " + name + getter.slice(getter.indexOf('('))); | 99 props.push("get " + name + getter.slice(getter.indexOf('('))); |
2012 } | 100 } |
2013 if (desc.set) { | 101 if (desc.set) { |
2014 var setter = Stringify(desc.set); | 102 var setter = Stringify(desc.set); |
2015 props.push("set " + name + setter.slice(setter.indexOf('('))); | 103 props.push("set " + name + setter.slice(setter.indexOf('('))); |
2016 } | 104 } |
2017 } | 105 } |
2018 return "{" + props.join(", ") + "}"; | 106 return "{" + props.join(", ") + "}"; |
2019 default: | 107 default: |
2020 return "[crazy non-standard shit]"; | 108 return "[crazy non-standard value]"; |
2021 } | 109 } |
2022 } | 110 } |
OLD | NEW |