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

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