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

Side by Side Diff: tools/ddbg_service/lib/debugger.dart

Issue 575853002: Add tools/ddbg_service. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: add test Created 6 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « tools/ddbg_service/lib/commando.dart ('k') | tools/ddbg_service/lib/terminfo.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart 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 file.
4
5 library debugger;
6
7 import "dart:async";
8 import "dart:io";
9
10 import "package:ddbg/commando.dart";
11 import "package:observatory/service_io.dart";
12
13 class Debugger {
14 Commando _cmdo;
15 var _cmdoSubscription;
16
17 VM _vm;
18 VM get vm => _vm;
19 set vm(VM vm) {
20 if (_vm == vm) {
21 // Do nothing.
22 return;
23 }
24 if (_vm != null) {
25 _vm.disconnect();
26 }
27 if (vm != null) {
28 vm.onConnect.then(_vmConnected);
29 vm.onDisconnect.then(_vmDisconnected);
30 vm.errors.stream.listen(_onServiceError);
31 vm.exceptions.stream.listen(_onServiceException);
32 vm.events.stream.listen(_onServiceEvent);
33 }
34 _vm = vm;
35 }
36
37 _vmConnected(VM vm) {
38 _cmdo.hide();
39 print('Connected to vm');
Cutch 2014/09/16 17:33:37 Should these messages go through some abstraction
turnidge 2014/09/16 17:52:34 Done.
40 _cmdo.show();
41 }
42
43 _vmDisconnected(VM vm) {
44 _cmdo.hide();
45 print('Disconnected from vm');
46 _cmdo.show();
47 }
48
49 _onServiceError(ServiceError error) {
50 _cmdo.hide();
51 print('error $error');
52 _cmdo.show();
53 }
54
55 _onServiceException(ServiceException exception) {
56 _cmdo.hide();
57 print('${exception.message}');
58 _cmdo.show();
59 }
60
61 _onServiceEvent(ServiceEvent event) {
62 switch (event.eventType) {
63 case 'GC':
64 // Ignore GC events for now.
65 break;
66 default:
67 _cmdo.hide();
68 print('event $event');
69 _cmdo.show();
70 break;
71 }
72 }
73
74 VM _isolate;
75 VM get isolate => _isolate;
76 set isolate(Isolate isolate) {
77 _isolate = isolate;
78 _cmdo.hide();
79 print('Current isolate is now isolate ${getIsolateIndex(_isolate)}');
80 _cmdo.show();
81 }
82
83 Map _isolateIndexMap = new Map();
84 int _nextIsolateIndex = 0;
85 int getIsolateIndex(Isolate isolate) {
86 var index = _isolateIndexMap[isolate.id];
87 if (index == null) {
88 index = _nextIsolateIndex++;
89 _isolateIndexMap[isolate.id] = index;
90 }
91 return index;
92 }
93
94 void onUncaughtError(error, StackTrace trace) {
95 if (error is ServiceException ||
96 error is ServiceError) {
97 // These are handled elsewhere. Ignore.
98 return;
99 }
100 print('\n--------\nExiting due to unexpected error:\n'
101 ' $error\n$trace\n');
102 quit();
103 }
104
105 Debugger() {
106 _cmdo = new Commando(completer: completeCommand);
107 _cmdoSubscription = _cmdo.commands.listen(_processCommand,
108 onError: _cmdoError,
109 onDone: _cmdoDone);
110 }
111
112 Future _closeCmdo() {
113 var sub = _cmdoSubscription;
114 _cmdoSubscription = null;
115 _cmdo = null;
116
117 var future = sub.cancel();
118 if (future != null) {
119 return future;
120 } else {
121 return new Future.value();
122 }
123 }
124
125 Future quit() {
126 return Future.wait([_closeCmdo()]).then((_) {
127 exit(0);
128 });
129 }
130
131 void _cmdoError(self, parent, zone, error, StackTrace trace) {
132 print('\n--------\nExiting due to unexpected error:\n'
133 ' $error\n$trace\n');
134 quit();
135 }
136
137 void _cmdoDone() {
138 quit();
139 }
140
141 void _processCommand(String cmdLine) {
142 void huh() {
143 print("'$cmdLine' not understood, try 'help' for help.");
144 }
145
146 _cmdo.hide();
147 cmdLine = cmdLine.trim();
148 var args = cmdLine.split(' ');
149 if (args.length == 0) {
150 return;
151 }
152 var command = args[0];
153 var matches = matchCommand(command, true);
154 if (matches.length == 0) {
155 huh();
156 _cmdo.show();
157 } else if (matches.length == 1) {
158 matches[0].run(this, args).then((_) {
159 _cmdo.show();
160 });
161 } else {
162 var matchNames = matches.map((handler) => handler.name);
163 print("Ambigous command '$command' : ${matchNames.toList()}");
164 _cmdo.show();
165 }
166 }
167
168 }
169
170 // Every debugger command extends this base class.
171 abstract class Command {
172 String get name;
173 String get helpShort;
174 void printHelp(List<String> args);
175 Future run(Debugger debugger, List<String> args);
176 }
177
178 class AttachCommand extends Command {
179 final name = 'attach';
180 final helpShort = 'Attach to a running Dart VM';
181 void printHelp(List<String> args) {
182 print("""
Cutch 2014/09/16 17:33:37 Typically, Dart code uses ' over "
turnidge 2014/09/16 17:52:34 Done.
183 ----- attach -----
184
185 Attach to the Dart VM running at the indicated host:port. If no
186 host:port is provided, attach to the VM running on the default port.
187
188 Usage:
189 attach
190 attach <host:port>
191 """);
192 }
193
194 Future run(Debugger debugger, List<String> args) {
195 if (args.length > 2) {
196 print('$name expects 0 or 1 arguments');
197 return new Future.value();
198 }
199 String hostPort = 'localhost:8181';
200 if (args.length > 1) {
201 hostPort = args[1];
202 }
203
204 debugger.vm = new WebSocketVM(new WebSocketVMTarget('ws://${hostPort}/ws'));
205 return debugger.vm.load().then((vm) {
206 if (debugger.isolate == null) {
207 for (var isolate in vm.isolates) {
208 if (isolate.name == 'root') {
209 debugger.isolate = isolate;
210 }
211 }
212 }
213 });
214 }
215 }
216
217 class DetachCommand extends Command {
218 final name = 'detach';
219 final helpShort = 'Detach from a running Dart VM';
220 void printHelp(List<String> args) {
221 print("""
222 ----- detach -----
223
224 Detach from the Dart VM.
225
226 Usage:
227 detach
228 """);
229 }
230
231 Future run(Debugger debugger, List<String> args) {
232 if (args.length > 1) {
233 print('$name expects no arguments');
234 return new Future.value();
235 }
236 if (debugger.vm == null) {
237 print('No VM is attached');
238 } else {
239 debugger.vm = null;
240 }
241 return new Future.value();
242 }
243 }
244
245 class HelpCommand extends Command {
246 final name = 'help';
247 final helpShort = 'Show a list of debugger commands';
248 void printHelp(List<String> args) {
249 print("""
250 ----- help -----
251
252 Show a list of debugger commands or get more information about a
253 particular command.
254
255 Usage:
256 help
257 help <command>
258 """);
259 }
260
261 Future run(Debugger debugger, List<String> args) {
262 if (args.length <= 1) {
263 print("\nDebugger commands:\n");
264 for (var command in commandList) {
265 print(' ${command.name.padRight(11)} ${command.helpShort}');
266 }
267 print("For more information about a particular command, type:\n\n"
268 " help <command>\n");
269
270 print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
271 } else {
272 var commandName = args[1];
273 var matches = matchCommand(commandName, true);
274 if (matches.length == 0) {
275 print("Command '$commandName' not recognized. "
276 "Try 'help' for a list of commands.");
277 } else {
278 for (var command in matches) {
279 command.printHelp(args);
280 }
281 }
282 }
283
284 return new Future.value();
285 }
286 }
287
288 class IsolateCommand extends Command {
289 final name = 'isolate';
290 final helpShort = 'Isolate control';
291 void printHelp(List<String> args) {
292 print("""
293 ----- isolate -----
294
295 List all isolates.
296
297 Usage:
298 isolate
299 isolate list
300
301 Set current isolate.
302
303 Usage:
304 isolate <id>
305 """);
306 }
307
308 Future run(Debugger debugger, List<String> args) {
309 if (args.length == 1 ||
310 (args.length == 2 && args[1] == 'list')) {
311 return _listIsolates(debugger);
312 } else if (args.length == 2) {
313 print('UNIMPLEMENTED');
314 return new Future.value();
315 } else {
316 if (args.length > 1) {
317 print('Unrecognized isolate command');
318 printHelp([]);
319 return new Future.value();
320 }
321 }
322 }
323
324 Future _listIsolates(Debugger debugger) {
325 if (debugger.vm == null) {
326 print('No VM is attached');
327 return new Future.value();
328 }
329 return debugger.vm.reload().then((vm) {
330 // Sort the isolates by their indices.
331 var isolates = vm.isolates.toList();
332 isolates.sort((iso1, iso2) {
333 return (debugger.getIsolateIndex(iso1) -
334 debugger.getIsolateIndex(iso2));
335 });
336
337 StringBuffer sb = new StringBuffer();
338 print(' ID NAME STATE');
339 print('-----------------------------------------------');
340 for (var isolate in isolates) {
341 if (isolate == debugger.isolate) {
342 sb.write('* ');
343 } else {
344 sb.write(' ');
345 }
346 sb.write(debugger.getIsolateIndex(isolate).toString().padRight(8));
347 sb.write(' ');
348 sb.write(isolate.name.padRight(12));
349 sb.write(' ');
350 if (isolate.pauseEvent != null) {
351 switch (isolate.pauseEvent.eventType) {
352 case 'IsolateCreated':
353 sb.write('paused at isolate start');
354 break;
355 case 'IsolateShutdown':
356 sb.write('paused at isolate exit');
357 break;
358 case 'IsolateInterrupted':
359 sb.write('paused');
360 break;
361 case 'BreakpointReached':
362 sb.write('paused by breakpoint');
363 break;
364 case 'ExceptionThrown':
365 sb.write('paused by exception');
366 break;
367 default:
368 sb.write('paused by unknown cause');
369 break;
370 }
371 } else if (isolate.running) {
372 sb.write('running');
373 } else if (isolate.idle) {
374 sb.write('idle');
375 } else if (isolate.loading) {
376 // TODO(turnidge): This is weird in a command line debugger.
377 sb.write('(not available)');
378 }
379 sb.write('\n');
380 }
381 print(sb);
382 });
383 return new Future.value();
384 }
385 }
386
387 class QuitCommand extends Command {
388 final name = 'quit';
389 final helpShort = 'Quit the debugger.';
390 void printHelp(List<String> args) {
391 print("""
392 ----- quit -----
393
394 Quit the debugger.
395
396 Usage:
397 quit
398 """);
399 }
400
401 Future run(Debugger debugger, List<String> args) {
402 if (args.length > 1) {
403 print("Unexpected arguments to $name command.");
404 return new Future.value();
405 }
406 return debugger.quit();
407 }
408 }
409
410 List<Command> commandList =
411 [ new AttachCommand(),
412 new DetachCommand(),
413 new HelpCommand(),
414 new IsolateCommand(),
415 new QuitCommand() ];
416
417 List<Command> matchCommand(String commandName, bool exactMatchWins) {
418 var matches = [];
419 for (var command in commandList) {
420 if (command.name.startsWith(commandName)) {
421 if (exactMatchWins && command.name == commandName) {
422 // Exact match
423 return [command];
424 } else {
425 matches.add(command);
426 }
427 }
428 }
429 return matches;
430 }
431
432 List<String> completeCommand(List<String> commandParts) {
433 var completions = new List<String>();
434 if (commandParts.length == 1) {
435 String prefix = commandParts[0];
436 for (var command in commandList) {
437 if (command.name.startsWith(prefix)) {
438 completions.add(command.name);
439 }
440 }
441 }
442 return completions;
443 }
OLDNEW
« no previous file with comments | « tools/ddbg_service/lib/commando.dart ('k') | tools/ddbg_service/lib/terminfo.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698