Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(477)

Side by Side Diff: pkg/fletchc/lib/src/verbs/debug_verb.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE.md file.
4
5 library fletchc.verbs.debug_verb;
6
7 import 'dart:core' hide
8 StackTrace;
9
10 import 'infrastructure.dart';
11
12 import 'dart:async' show
13 Stream,
14 StreamController,
15 StreamIterator;
16
17 import 'dart:convert' show
18 UTF8,
19 LineSplitter;
20
21 import 'documentation.dart' show
22 debugDocumentation;
23
24 import '../diagnostic.dart' show
25 throwInternalError;
26
27 import '../worker/developer.dart' show
28 ClientEventHandler,
29 handleSignal,
30 compileAndAttachToVmThen,
31 setupClientInOut;
32
33 import '../hub/client_commands.dart' show
34 ClientCommandCode;
35
36 import 'package:fletchc/debug_state.dart' show
37 Breakpoint;
38
39 import '../../debug_state.dart' show
40 RemoteObject,
41 RemoteValue,
42 BackTrace;
43
44 import '../../vm_commands.dart' show
45 VmCommand;
46
47 const Action debugAction =
48 const Action(
49 debug,
50 debugDocumentation,
51 requiresSession: true,
52 supportedTargets: const [
53 TargetKind.APPLY,
54 TargetKind.BACKTRACE,
55 TargetKind.BREAK,
56 TargetKind.CONTINUE,
57 TargetKind.DELETE_BREAKPOINT,
58 TargetKind.DISASM,
59 TargetKind.FIBERS,
60 TargetKind.FILE,
61 TargetKind.FINISH,
62 TargetKind.FRAME,
63 TargetKind.LIST,
64 TargetKind.LIST_BREAKPOINTS,
65 TargetKind.PRINT,
66 TargetKind.PRINT_ALL,
67 TargetKind.RESTART,
68 TargetKind.RUN_TO_MAIN,
69 TargetKind.STEP,
70 TargetKind.STEP_BYTECODE,
71 TargetKind.STEP_OVER,
72 TargetKind.STEP_OVER_BYTECODE,
73 TargetKind.TOGGLE,
74 ]);
75
76 const int sigQuit = 3;
77
78 Future debug(AnalyzedSentence sentence, VerbContext context) async {
79 Uri base = sentence.base;
80 if (sentence.target == null) {
81 return context.performTaskInWorker(
82 new InteractiveDebuggerTask(base));
83 }
84
85 DebuggerTask task;
86 switch (sentence.target.kind) {
87 case TargetKind.APPLY:
88 task = new DebuggerTask(TargetKind.APPLY.index, base);
89 break;
90 case TargetKind.RUN_TO_MAIN:
91 task = new DebuggerTask(TargetKind.RUN_TO_MAIN.index, base);
92 break;
93 case TargetKind.BACKTRACE:
94 task = new DebuggerTask(TargetKind.BACKTRACE.index, base);
95 break;
96 case TargetKind.CONTINUE:
97 task = new DebuggerTask(TargetKind.CONTINUE.index, base);
98 break;
99 case TargetKind.BREAK:
100 task = new DebuggerTask(TargetKind.BREAK.index, base,
101 sentence.targetName);
102 break;
103 case TargetKind.LIST:
104 task = new DebuggerTask(TargetKind.LIST.index, base);
105 break;
106 case TargetKind.DISASM:
107 task = new DebuggerTask(TargetKind.DISASM.index, base);
108 break;
109 case TargetKind.FRAME:
110 task = new DebuggerTask(TargetKind.FRAME.index, base,
111 sentence.targetName);
112 break;
113 case TargetKind.DELETE_BREAKPOINT:
114 task = new DebuggerTask(TargetKind.DELETE_BREAKPOINT.index,
115 base,
116 sentence.targetName);
117 break;
118 case TargetKind.LIST_BREAKPOINTS:
119 task = new DebuggerTask(TargetKind.LIST_BREAKPOINTS.index, base);
120 break;
121 case TargetKind.STEP:
122 task = new DebuggerTask(TargetKind.STEP.index, base);
123 break;
124 case TargetKind.STEP_OVER:
125 task = new DebuggerTask(TargetKind.STEP_OVER.index, base);
126 break;
127 case TargetKind.FIBERS:
128 task = new DebuggerTask(TargetKind.FIBERS.index, base);
129 break;
130 case TargetKind.FINISH:
131 task = new DebuggerTask(TargetKind.FINISH.index, base);
132 break;
133 case TargetKind.RESTART:
134 task = new DebuggerTask(TargetKind.RESTART.index, base);
135 break;
136 case TargetKind.STEP_BYTECODE:
137 task = new DebuggerTask(TargetKind.STEP_BYTECODE.index, base);
138 break;
139 case TargetKind.STEP_OVER_BYTECODE:
140 task = new DebuggerTask(TargetKind.STEP_OVER_BYTECODE.index, base);
141 break;
142 case TargetKind.PRINT:
143 task = new DebuggerTask(TargetKind.PRINT.index, base,
144 sentence.targetName);
145 break;
146 case TargetKind.PRINT_ALL:
147 task = new DebuggerTask(TargetKind.PRINT_ALL.index, base);
148 break;
149 case TargetKind.TOGGLE:
150 task = new DebuggerTask(TargetKind.TOGGLE.index, base,
151 sentence.targetName);
152 break;
153 case TargetKind.FILE:
154 task = new DebuggerTask(TargetKind.FILE.index, base,
155 sentence.targetUri);
156 break;
157 default:
158 throwInternalError("Unimplemented ${sentence.target}");
159 }
160
161 return context.performTaskInWorker(task);
162 }
163
164 // Returns a debug client event handler that is bound to the current session.
165 ClientEventHandler debugClientEventHandler(
166 SessionState state,
167 StreamIterator<ClientCommand> commandIterator,
168 StreamController stdinController) {
169 // TODO(zerny): Take the correct session explicitly because it will be cleared
170 // later to ensure against possible reuse. Restructure the code to avoid this.
171 return (Session session) async {
172 while (await commandIterator.moveNext()) {
173 ClientCommand command = commandIterator.current;
174 switch (command.code) {
175 case ClientCommandCode.Stdin:
176 if (command.data.length == 0) {
177 await stdinController.close();
178 } else {
179 stdinController.add(command.data);
180 }
181 break;
182
183 case ClientCommandCode.Signal:
184 int signalNumber = command.data;
185 if (signalNumber == sigQuit) {
186 await session.interrupt();
187 } else {
188 handleSignal(state, signalNumber);
189 }
190 break;
191
192 default:
193 throwInternalError("Unexpected command from client: $command");
194 }
195 }
196 };
197 }
198
199 class InteractiveDebuggerTask extends SharedTask {
200 // Keep this class simple, see note in superclass.
201
202 final Uri base;
203
204 const InteractiveDebuggerTask(this.base);
205
206 Future<int> call(
207 CommandSender commandSender,
208 StreamIterator<ClientCommand> commandIterator) {
209
210 // Setup a more advanced client input handler for the interactive debug task
211 // that also handles the input and forwards it to the debug input handler.
212 StreamController stdinController = new StreamController();
213 SessionState state = SessionState.current;
214 setupClientInOut(
215 state,
216 commandSender,
217 debugClientEventHandler(state, commandIterator, stdinController));
218
219 return interactiveDebuggerTask(state, base, stdinController);
220 }
221 }
222
223 Future<int> runInteractiveDebuggerTask(
224 CommandSender commandSender,
225 StreamIterator<ClientCommand> commandIterator,
226 SessionState state,
227 Uri script,
228 Uri base) {
229
230 // Setup a more advanced client input handler for the interactive debug task
231 // that also handles the input and forwards it to the debug input handler.
232 StreamController stdinController = new StreamController();
233 return compileAndAttachToVmThen(
234 commandSender,
235 commandIterator,
236 state,
237 script,
238 base,
239 true,
240 () => interactiveDebuggerTask(state, base, stdinController),
241 eventHandler:
242 debugClientEventHandler(state, commandIterator, stdinController));
243 }
244
245 Future<int> interactiveDebuggerTask(
246 SessionState state,
247 Uri base,
248 StreamController stdinController) async {
249 Session session = state.session;
250 if (session == null) {
251 throwFatalError(DiagnosticKind.attachToVmBeforeRun);
252 }
253 List<FletchDelta> compilationResult = state.compilationResults;
254 if (compilationResult.isEmpty) {
255 throwFatalError(DiagnosticKind.compileBeforeRun);
256 }
257
258 // Make sure current state's session is not reused if invoked again.
259 state.session = null;
260
261 for (FletchDelta delta in compilationResult) {
262 await session.applyDelta(delta);
263 }
264
265 Stream<String> inputStream = stdinController.stream
266 .transform(UTF8.decoder)
267 .transform(new LineSplitter());
268
269 return await session.debug(inputStream, base, state);
270 }
271
272 class DebuggerTask extends SharedTask {
273 // Keep this class simple, see note in superclass.
274 final int kind;
275 final argument;
276 final Uri base;
277
278 DebuggerTask(this.kind, this.base, [this.argument]);
279
280 Future<int> call(
281 CommandSender commandSender,
282 StreamIterator<ClientCommand> commandIterator) {
283 switch (TargetKind.values[kind]) {
284 case TargetKind.APPLY:
285 return apply(commandSender, SessionState.current);
286 case TargetKind.RUN_TO_MAIN:
287 return runToMainDebuggerTask(commandSender, SessionState.current);
288 case TargetKind.BACKTRACE:
289 return backtraceDebuggerTask(commandSender, SessionState.current);
290 case TargetKind.CONTINUE:
291 return continueDebuggerTask(commandSender, SessionState.current);
292 case TargetKind.BREAK:
293 return breakDebuggerTask(
294 commandSender, SessionState.current, argument, base);
295 case TargetKind.LIST:
296 return listDebuggerTask(commandSender, SessionState.current);
297 case TargetKind.DISASM:
298 return disasmDebuggerTask(commandSender, SessionState.current);
299 case TargetKind.FRAME:
300 return frameDebuggerTask(commandSender, SessionState.current, argument);
301 case TargetKind.DELETE_BREAKPOINT:
302 return deleteBreakpointDebuggerTask(
303 commandSender, SessionState.current, argument);
304 case TargetKind.LIST_BREAKPOINTS:
305 return listBreakpointsDebuggerTask(commandSender, SessionState.current);
306 case TargetKind.STEP:
307 return stepDebuggerTask(commandSender, SessionState.current);
308 case TargetKind.STEP_OVER:
309 return stepOverDebuggerTask(commandSender, SessionState.current);
310 case TargetKind.FIBERS:
311 return fibersDebuggerTask(commandSender, SessionState.current);
312 case TargetKind.FINISH:
313 return finishDebuggerTask(commandSender, SessionState.current);
314 case TargetKind.RESTART:
315 return restartDebuggerTask(commandSender, SessionState.current);
316 case TargetKind.STEP_BYTECODE:
317 return stepBytecodeDebuggerTask(commandSender, SessionState.current);
318 case TargetKind.STEP_OVER_BYTECODE:
319 return stepOverBytecodeDebuggerTask(
320 commandSender, SessionState.current);
321 case TargetKind.PRINT:
322 return printDebuggerTask(commandSender, SessionState.current, argument);
323 case TargetKind.PRINT_ALL:
324 return printAllDebuggerTask(commandSender, SessionState.current);
325 case TargetKind.TOGGLE:
326 return toggleDebuggerTask(
327 commandSender, SessionState.current, argument);
328 case TargetKind.FILE:
329 return runInteractiveDebuggerTask(
330 commandSender, commandIterator, SessionState.current, argument,
331 base);
332
333 default:
334 throwInternalError("Unimplemented ${TargetKind.values[kind]}");
335 }
336 return null;
337 }
338 }
339
340 Session attachToSession(SessionState state, CommandSender commandSender) {
341 Session session = state.session;
342 if (session == null) {
343 throwFatalError(DiagnosticKind.attachToVmBeforeRun);
344 }
345 state.attachCommandSender(commandSender);
346 return session;
347 }
348
349 Future<int> runToMainDebuggerTask(
350 CommandSender commandSender,
351 SessionState state) async {
352 List<FletchDelta> compilationResults = state.compilationResults;
353 Session session = state.session;
354 if (session == null) {
355 throwFatalError(DiagnosticKind.attachToVmBeforeRun);
356 }
357 if (session.loaded) {
358 // We cannot reuse a session that has already been loaded. Loading
359 // currently implies that some of the code has been run.
360 throwFatalError(DiagnosticKind.sessionInvalidState,
361 sessionName: state.name);
362 }
363 if (compilationResults.isEmpty) {
364 throwFatalError(DiagnosticKind.compileBeforeRun);
365 }
366
367 state.attachCommandSender(commandSender);
368 for (FletchDelta delta in compilationResults) {
369 await session.applyDelta(delta);
370 }
371
372 await session.enableDebugger();
373 await session.spawnProcess();
374 await session.setBreakpoint(methodName: "main", bytecodeIndex: 0);
375 await session.debugRun();
376
377 return 0;
378 }
379
380 Future<int> backtraceDebuggerTask(
381 CommandSender commandSender,
382 SessionState state) async {
383 Session session = attachToSession(state, commandSender);
384
385 if (!session.loaded) {
386 throwInternalError('### process not loaded, cannot show backtrace');
387 }
388 BackTrace trace = await session.backTrace();
389 print(trace.format());
390
391 return 0;
392 }
393
394 Future<int> continueDebuggerTask(
395 CommandSender commandSender,
396 SessionState state) async {
397 Session session = attachToSession(state, commandSender);
398
399 if (!session.running) {
400 // TODO(ager, lukechurch): Fix error reporting.
401 throwInternalError('### process not running, cannot continue');
402 }
403 VmCommand response = await session.cont();
404 print(await session.processStopResponseToString(response, state));
405
406 if (session.terminated) state.session = null;
407
408 return 0;
409 }
410
411 Future<int> breakDebuggerTask(
412 CommandSender commandSender,
413 SessionState state,
414 String breakpointSpecification,
415 Uri base) async {
416 Session session = attachToSession(state, commandSender);
417
418 if (breakpointSpecification.contains('@')) {
419 List<String> parts = breakpointSpecification.split('@');
420
421 if (parts.length > 2) {
422 // TODO(ager, lukechurch): Fix error reporting.
423 throwInternalError('Invalid breakpoint format');
424 }
425
426 String name = parts[0];
427 int index = 0;
428
429 if (parts.length == 2) {
430 index = int.parse(parts[1], onError: (_) => -1);
431 if (index == -1) {
432 // TODO(ager, lukechurch): Fix error reporting.
433 throwInternalError('Invalid bytecode index');
434 }
435 }
436
437 List<Breakpoint> breakpoints =
438 await session.setBreakpoint(methodName: name, bytecodeIndex: index);
439 for (Breakpoint breakpoint in breakpoints) {
440 print("Breakpoint set: $breakpoint");
441 }
442 } else if (breakpointSpecification.contains(':')) {
443 List<String> parts = breakpointSpecification.split(':');
444
445 if (parts.length != 3) {
446 // TODO(ager, lukechurch): Fix error reporting.
447 throwInternalError('Invalid breakpoint format');
448 }
449
450 String file = parts[0];
451 int line = int.parse(parts[1], onError: (_) => -1);
452 int column = int.parse(parts[2], onError: (_) => -1);
453
454 if (line < 1 || column < 1) {
455 // TODO(ager, lukechurch): Fix error reporting.
456 throwInternalError('Invalid line or column number');
457 }
458
459 // TODO(ager): Refactor session so that setFileBreakpoint
460 // does not print automatically but gives us information about what
461 // happened.
462 Breakpoint breakpoint =
463 await session.setFileBreakpoint(base.resolve(file), line, column);
464 if (breakpoint != null) {
465 print("Breakpoint set: $breakpoint");
466 } else {
467 // TODO(ager, lukechurch): Fix error reporting.
468 throwInternalError('Failed to set breakpoint');
469 }
470 } else {
471 List<Breakpoint> breakpoints =
472 await session.setBreakpoint(
473 methodName: breakpointSpecification, bytecodeIndex: 0);
474 for (Breakpoint breakpoint in breakpoints) {
475 print("Breakpoint set: $breakpoint");
476 }
477 }
478
479 return 0;
480 }
481
482 Future<int> listDebuggerTask(
483 CommandSender commandSender, SessionState state) async {
484 Session session = attachToSession(state, commandSender);
485
486 if (!session.loaded) {
487 throwInternalError('### process not loaded, nothing to list');
488 }
489 BackTrace trace = await session.backTrace();
490 if (trace == null) {
491 // TODO(ager,lukechurch): Fix error reporting.
492 throwInternalError('Source listing failed');
493 }
494 print(trace.list(state));
495
496 return 0;
497 }
498
499 Future<int> disasmDebuggerTask(
500 CommandSender commandSender, SessionState state) async {
501 Session session = attachToSession(state, commandSender);
502
503 if (!session.loaded) {
504 throwInternalError('### process not loaded, nothing to disassemble');
505 }
506 BackTrace trace = await session.backTrace();
507 if (trace == null) {
508 // TODO(ager,lukechurch): Fix error reporting.
509 throwInternalError('Bytecode disassembly failed');
510 }
511 print(trace.disasm());
512
513 return 0;
514 }
515
516 Future<int> frameDebuggerTask(
517 CommandSender commandSender, SessionState state, String frame) async {
518 Session session = attachToSession(state, commandSender);
519
520 int frameNumber = int.parse(frame, onError: (_) => -1);
521 if (frameNumber == -1) {
522 // TODO(ager,lukechurch): Fix error reporting.
523 throwInternalError('Invalid frame number');
524 }
525
526 bool frameSelected = await session.selectFrame(frameNumber);
527 if (!frameSelected) {
528 // TODO(ager,lukechurch): Fix error reporting.
529 throwInternalError('Frame selection failed');
530 }
531
532 return 0;
533 }
534
535 Future<int> deleteBreakpointDebuggerTask(
536 CommandSender commandSender, SessionState state, String breakpoint) async {
537 Session session = attachToSession(state, commandSender);
538
539 int id = int.parse(breakpoint, onError: (_) => -1);
540 if (id == -1) {
541 // TODO(ager,lukechurch): Fix error reporting.
542 throwInternalError('Invalid breakpoint id: $breakpoint');
543 }
544
545 Breakpoint bp = await session.deleteBreakpoint(id);
546 if (bp == null) {
547 throwInternalError('Invalid breakpoint id: $id');
548 }
549 print('Deleted breakpoint: $bp');
550 return 0;
551 }
552
553 Future<int> listBreakpointsDebuggerTask(
554 CommandSender commandSender, SessionState state) async {
555 Session session = attachToSession(state, commandSender);
556 List<Breakpoint> breakpoints = session.breakpoints();
557 if (breakpoints == null || breakpoints.isEmpty) {
558 print('No breakpoints');
559 } else {
560 print('Breakpoints:');
561 for (Breakpoint bp in breakpoints) {
562 print(bp);
563 }
564 }
565 return 0;
566 }
567
568 Future<int> stepDebuggerTask(
569 CommandSender commandSender, SessionState state) async {
570 Session session = attachToSession(state, commandSender);
571 if (!session.running) {
572 throwInternalError(
573 '### process not running, cannot step to next expression');
574 }
575 VmCommand response = await session.step();
576 print(await session.processStopResponseToString(response, state));
577 return 0;
578 }
579
580 Future<int> stepOverDebuggerTask(
581 CommandSender commandSender, SessionState state) async {
582 Session session = attachToSession(state, commandSender);
583 if (!session.running) {
584 throwInternalError('### process not running, cannot go to next expression');
585 }
586 VmCommand response = await session.stepOver();
587 print(await session.processStopResponseToString(response, state));
588 return 0;
589 }
590
591 Future<int> fibersDebuggerTask(
592 CommandSender commandSender, SessionState state) async {
593 Session session = attachToSession(state, commandSender);
594 if (!session.running) {
595 throwInternalError('### process not running, cannot show fibers');
596 }
597 List<BackTrace> traces = await session.fibers();
598 print('');
599 for (int fiber = 0; fiber < traces.length; ++fiber) {
600 print('fiber $fiber');
601 print(traces[fiber].format());
602 }
603 return 0;
604 }
605
606 Future<int> finishDebuggerTask(
607 CommandSender commandSender, SessionState state) async {
608 Session session = attachToSession(state, commandSender);
609 if (!session.running) {
610 throwInternalError('### process not running, cannot finish method');
611 }
612 VmCommand response = await session.stepOut();
613 print(await session.processStopResponseToString(response, state));
614 return 0;
615 }
616
617 Future<int> restartDebuggerTask(
618 CommandSender commandSender, SessionState state) async {
619 Session session = attachToSession(state, commandSender);
620 if (!session.loaded) {
621 throwInternalError('### process not loaded, cannot restart');
622 }
623 BackTrace trace = await session.backTrace();
624 if (trace == null) {
625 throwInternalError("### cannot restart when nothing is executing.");
626 }
627 if (trace.length <= 1) {
628 throwInternalError("### cannot restart entry frame.");
629 }
630 VmCommand response = await session.restart();
631 print(await session.processStopResponseToString(response, state));
632 return 0;
633 }
634
635 Future<int> apply(
636 CommandSender commandSender, SessionState state) async {
637 Session session = attachToSession(state, commandSender);
638 await session.applyDelta(state.compilationResults.last);
639 return 0;
640 }
641
642 Future<int> stepBytecodeDebuggerTask(
643 CommandSender commandSender, SessionState state) async {
644 Session session = attachToSession(state, commandSender);
645 if (!session.running) {
646 throwInternalError('### process not running, cannot step bytecode');
647 }
648 VmCommand response = await session.stepBytecode();
649 assert(response != null); // stepBytecode cannot return null
650 print(await session.processStopResponseToString(response, state));
651 return 0;
652 }
653
654 Future<int> stepOverBytecodeDebuggerTask(
655 CommandSender commandSender, SessionState state) async {
656 Session session = attachToSession(state, commandSender);
657 if (!session.running) {
658 throwInternalError('### process not running, cannot step over bytecode');
659 }
660 VmCommand response = await session.stepOverBytecode();
661 assert(response != null); // stepOverBytecode cannot return null
662 print(await session.processStopResponseToString(response, state));
663 return 0;
664 }
665
666 Future<int> printDebuggerTask(
667 CommandSender commandSender, SessionState state, String name) async {
668 Session session = attachToSession(state, commandSender);
669
670 RemoteObject variable;
671 if (name.startsWith("*")) {
672 name = name.substring(1);
673 variable = await session.processVariableStructure(name);
674 } else {
675 variable = await session.processVariable(name);
676 }
677 if (variable == null) {
678 print('### No such variable: $name');
679 } else {
680 print(session.remoteObjectToString(variable));
681 }
682
683 return 0;
684 }
685
686 Future<int> printAllDebuggerTask(
687 CommandSender commandSender, SessionState state) async {
688 Session session = attachToSession(state, commandSender);
689 List<RemoteObject> variables = await session.processAllVariables();
690 if (variables.isEmpty) {
691 print('### No variables in scope');
692 } else {
693 for (RemoteObject variable in variables) {
694 print(session.remoteObjectToString(variable));
695 }
696 }
697 return 0;
698 }
699
700 Future<int> toggleDebuggerTask(
701 CommandSender commandSender, SessionState state, String argument) async {
702 Session session = attachToSession(state, commandSender);
703
704 if (argument != 'internal') {
705 // TODO(ager, lukechurch): Fix error reporting.
706 throwInternalError("Invalid argument to toggle. "
707 "Valid arguments: 'internal'.");
708 }
709 await session.toggleInternal();
710
711 return 0;
712 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/src/verbs/create_verb.dart ('k') | pkg/fletchc/lib/src/verbs/documentation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698