Chromium Code Reviews| Index: tools/ddbg.dart |
| =================================================================== |
| --- tools/ddbg.dart (revision 0) |
| +++ tools/ddbg.dart (revision 0) |
| @@ -0,0 +1,194 @@ |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +// Simple interactive debugger shell that connects to the Dart VM's debugger |
| +// connection port. |
| + |
| +#import("dart:io"); |
| +#import("dart:json"); |
| + |
| +Map<int, Completer> outstandingCommands; |
| + |
| +Socket vmSock; |
| +OutputStream vmStream; |
| +int seqNum = 0; |
| + |
| +bool verbose = false; |
| + |
| + |
| +void printHelp() { |
| + print(""" |
| + q Quit debugger shell |
| + r Resume execution |
| + s Single step |
| + so Step over |
| + si Step into |
| + ll List loaded libraries |
| + ls <libname> List loaded scripts in library |
| +"""); |
| +} |
| + |
| + |
| +void quitShell() { |
| + vmStream.close(); |
| + vmSock.close(); |
| + stdin.close(); |
| +} |
| + |
| + |
| +Future sendCmd(Map<String, Dynamic> cmd) { |
| + var completer = new Completer(); |
| + assert(cmd["id"] != null); |
| + var id = cmd["id"]; |
| + outstandingCommands[id] = completer; |
| + if (verbose) print("sending: '${JSON.stringify(cmd)}'"); |
|
siva
2012/05/10 20:08:36
not sure what the Dart style guide says but we usu
hausner
2012/05/10 22:36:28
Done.
|
| + vmStream.writeString(JSON.stringify(cmd)); |
| + return completer.future; |
| +} |
| + |
| + |
| +void processCommand(String cmdLine) { |
| + seqNum++; |
| + var args = cmdLine.split(' '); |
| + if (args.length == 0) { |
| + return; |
| + } |
| + var cmd = args[0]; |
| + if (cmd == "r") { |
| + var cmd = { "id": seqNum, "command": "resume" }; |
| + sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| + } else if (cmd == "s") { |
| + var cmd = { "id": seqNum, "command": "stepOver" }; |
| + sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| + } else if (cmd == "si") { |
| + var cmd = { "id": seqNum, "command": "stepInto" }; |
| + sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| + } else if (cmd == "so") { |
| + var cmd = { "id": seqNum, "command": "stepOut" }; |
| + sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| + } else if (cmd == "ll") { |
| + var cmd = { "id": seqNum, "command": "getLibraryURLs" }; |
| + sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); |
| + } else if (cmd == "ls") { |
| + if (args.length < 2) { |
| + return; |
| + } |
| + var cmd = { "id": seqNum, "command": "getScriptURLs", |
| + "param": { "library": args[1] }}; |
| + sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); |
| + } else if (cmd == "q") { |
| + quitShell(); |
| + } else if (cmd == "h") { |
| + printHelp(); |
| + } else { |
| + print("Error: $cmd not understood"); |
| + } |
| +} |
| + |
| + |
| +void handleGetLibraryResponse(response) { |
| + var result = response["result"]; |
| + assert(result != null); |
| + var urls = result["urls"]; |
| + assert(urls != null); |
| + assert(urls is List); |
| + print("Loaded isolates:"); |
| + for (int i = 0; i < urls.length; i++) { |
| + print(" $i ${urls[i]}"); |
| + } |
| +} |
| + |
| + |
| +void handleGetScriptsResponse(response) { |
| + var result = response["result"]; |
| + assert(result != null); |
| + var urls = result["urls"]; |
| + assert(urls != null); |
| + assert(urls is List); |
| + print("Loaded scripts:"); |
| + for (int i = 0; i < urls.length; i++) { |
| + print(" $i ${urls[i]}"); |
| + } |
| +} |
| + |
| + |
| +void handleGenericResponse(response) { |
| + if (response["error"] != null) { |
| + print("Error: ${response["error"]}"); |
| + return; |
|
siva
2012/05/10 20:08:36
Is this return necessary?
hausner
2012/05/10 22:36:28
Um, no. It may have been at some time.
|
| + } |
| +} |
| + |
| + |
| +void printStackTrace(var trace) { |
| + if (trace == null) { |
| + return; |
| + } |
| + var frames = trace["callFrames"]; |
| + if (frames is !List) { |
| + print("unexpected type for frames parameter $frames"); |
| + return; |
| + } |
| + for (int i = 0; i < frames.length; i++) { |
| + var frame = frames[i]; |
| + var fname = frame["functionName"]; |
| + var url = frame["location"]["url"]; |
| + var line = frame["location"]["lineNumber"]; |
| + print("$i $fname ($url:$line)"); |
| + } |
| +} |
| + |
| + |
| +// TODO(hausner): Need to handle the case where we receive only a partial |
| +// message from the debugger, e.g. when the message is too big to fit in |
| +// one network packet. |
| +void processVmData(String s) { |
| + if (verbose) print("vm: $s"); |
| + var msg = JSON.parse(s); |
| + if (msg == null) { |
| + return; |
| + } |
| + var event = msg["event"]; |
| + if (event == "paused") { |
| + print("VM paused, stack trace:"); |
| + printStackTrace(msg["params"]); |
| + return; |
| + } |
| + if (msg["id"] != null) { |
| + var id = msg["id"]; |
| + if (outstandingCommands.containsKey(id)) { |
| + if (msg["error"] != null) { |
| + print("VM says: ${msg["error"]}"); |
| + } else { |
| + var completer = outstandingCommands[id]; |
| + completer.complete(msg); |
| + } |
| + outstandingCommands.remove(id); |
| + } |
| + } |
| +} |
| + |
| + |
| +void main() { |
| + outstandingCommands = new Map<int, Completer>(); |
| + vmSock = new Socket("127.0.0.1", 5858); |
| + vmStream = new SocketOutputStream(vmSock); |
| + StringInputStream stdinStream = new StringInputStream(stdin); |
|
siva
2012/05/10 20:08:36
var stdinStream = new ....
hausner
2012/05/10 22:36:28
Slowly weaning off of using types :)
|
| + stdinStream.onLine = () { |
| + processCommand(stdinStream.readLine()); |
| + }; |
| + var vmInStream = new SocketInputStream(vmSock); |
| + vmInStream.onData = () { |
| + var s = new String.fromCharCodes(vmInStream.read()); |
| + processVmData(s); |
| + }; |
| + vmInStream.onError = (err) { |
| + print("Error in debug connection: $err"); |
| + quitShell(); |
| + }; |
| + vmInStream.onClosed = () { |
| + print("VM debugger connection closed"); |
| + quitShell(); |
| + }; |
| +} |