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

Unified Diff: tools/ddbg.dart

Issue 1497033003: - Remove the legacy debug protocol. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address review comments. Created 5 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/coverage.dart ('k') | tools/ddbg/lib/commando.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/ddbg.dart
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
deleted file mode 100644
index f14a0170a93f82bf13f71bdfb1c1c99a6211697c..0000000000000000000000000000000000000000
--- a/tools/ddbg.dart
+++ /dev/null
@@ -1,1496 +0,0 @@
-// 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:convert";
-import "dart:io";
-import "dart:async";
-import "dart:math";
-
-import "ddbg/lib/commando.dart";
-
-class TargetScript {
- // The text of a script.
- String source = null;
-
- // A mapping from line number to source text.
- List<String> lineToSource = null;
-
- // A mapping from token offset to line number.
- Map<int,int> tokenToLine = null;
-}
-
-const UnknownLocation = const {};
-
-class TargetIsolate {
- int id;
- // The location of the last paused event.
- Map pausedLocation = null;
-
- TargetIsolate(this.id);
- bool get isPaused => pausedLocation != null;
- String get pausedUrl => pausedLocation != null ? pausedLocation["url"] : null;
-
- Map<String, TargetScript> scripts = {};
-}
-
-Map<int, TargetIsolate> targetIsolates= new Map<int, TargetIsolate>();
-
-Map<int, Completer> outstandingCommands;
-
-Socket vmSock;
-String vmData;
-var cmdSubscription;
-Commando cmdo;
-var vmSubscription;
-int seqNum = 0;
-
-bool isDebugging = false;
-Process targetProcess = null;
-bool suppressNextExitCode = false;
-
-final verbose = false;
-final printMessages = false;
-
-TargetIsolate currentIsolate;
-TargetIsolate mainIsolate;
-
-int debugPort = 5858;
-
-String formatLocation(Map location) {
- if (location == null) return "";
- var fileName = location["url"].split("/").last;
- return "file: $fileName lib: ${location['libraryId']} token: ${location['tokenOffset']}";
-}
-
-
-Future sendCmd(Map<String, dynamic> cmd) {
- var completer = new Completer.sync();
- int id = cmd["id"];
- outstandingCommands[id] = completer;
- if (verbose) {
- print("sending: '${JSON.encode(cmd)}'");
- }
- vmSock.write(JSON.encode(cmd));
- return completer.future;
-}
-
-
-bool checkCurrentIsolate() {
- if (vmSock == null) {
- print("There is no active script. Try 'help run'.");
- return false;
- }
- if (currentIsolate == null) {
- print('There is no current isolate.');
- return false;
- }
- return true;
-}
-
-
-void setCurrentIsolate(TargetIsolate isolate) {
- if (isolate != currentIsolate) {
- currentIsolate = isolate;
- if (mainIsolate == null) {
- print("Main isolate is ${isolate.id}");
- mainIsolate = isolate;
- }
- print("Current isolate is now ${isolate.id}");
- }
-}
-
-
-bool checkPaused() {
- if (!checkCurrentIsolate()) return false;
- if (currentIsolate.isPaused) return true;
- print("Current isolate must be paused");
- return false;
-}
-
-// These settings are allowed in the 'set' and 'show' debugger commands.
-var validSettings = ['vm', 'vmargs', 'script', 'args'];
-
-// The current values for all settings.
-var settings = new Map();
-
-String _leftJustify(text, int width) {
- StringBuffer buffer = new StringBuffer();
- buffer.write(text);
- while (buffer.length < width) {
- buffer.write(' ');
- }
- return buffer.toString();
-}
-
-// TODO(turnidge): Move all commands here.
-List<Command> commandList =
- [ new HelpCommand(),
- new QuitCommand(),
- new RunCommand(),
- new KillCommand(),
- new ConnectCommand(),
- new DisconnectCommand(),
- new SetCommand(),
- new ShowCommand() ];
-
-
-List<Command> matchCommand(String commandName, bool exactMatchWins) {
- List matches = [];
- for (var command in commandList) {
- if (command.name.startsWith(commandName)) {
- if (exactMatchWins && command.name == commandName) {
- // Exact match
- return [command];
- } else {
- matches.add(command);
- }
- }
- }
- return matches;
-}
-
-abstract class Command {
- String get name;
- Future run(List<String> args);
-}
-
-class HelpCommand extends Command {
- final name = 'help';
- final helpShort = 'Show a list of debugger commands';
- final helpLong ="""
-Show a list of debugger commands or get more information about a
-particular command.
-
-Usage:
- help
- help <command>
-""";
-
- Future run(List<String> args) {
- if (args.length == 1) {
- print("Debugger commands:\n");
- for (var command in commandList) {
- print(' ${_leftJustify(command.name, 11)} ${command.helpShort}');
- }
-
- // TODO(turnidge): Convert all commands to use the Command class.
- print("""
- bt Show backtrace
- r Resume execution
- s Single step
- so Step over
- si Step into
- sbp [<file>] <line> Set breakpoint
- rbp <id> Remove breakpoint with given id
- po <id> Print object info for given id
- eval fr <n> <expr> Evaluate expr on stack frame index n
- eval obj <id> <expr> Evaluate expr on object id
- eval cls <id> <expr> Evaluate expr on class id
- eval lib <id> <expr> Evaluate expr in toplevel of library id
- pl <id> <idx> [<len>] Print list element/slice
- pc <id> Print class info for given id
- ll List loaded libraries
- plib <id> Print library info for given library id
- slib <id> <true|false> Set library id debuggable
- pg <id> Print all global variables visible within given library id
- ls <lib_id> List loaded scripts in library
- gs <lib_id> <script_url> Get source text of script in library
- tok <lib_id> <script_url> Get line and token table of script in library
- epi <none|all|unhandled> Set exception pause info
- li List ids of all isolates in the VM
- sci <id> Set current target isolate
- i <id> Interrupt execution of given isolate id
-""");
-
- print("For more information about a particular command, type:\n\n"
- " help <command>\n");
-
- print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
- } else if (args.length == 2) {
- var commandName = args[1];
- var matches = matchCommand(commandName, true);
- if (matches.length == 0) {
- print("Command '$commandName' not recognized. "
- "Try 'help' for a list of commands.");
- } else {
- for (var command in matches) {
- print("---- ${command.name} ----\n${command.helpLong}");
- }
- }
- } else {
- print("Command '$command' not recognized. "
- "Try 'help' for a list of commands.");
- }
-
- return new Future.value();
- }
-}
-
-
-class QuitCommand extends Command {
- final name = 'quit';
- final helpShort = 'Quit the debugger.';
- final helpLong ="""
-Quit the debugger.
-
-Usage:
- quit
-""";
-
- Future run(List<String> args) {
- if (args.length > 1) {
- print("Unexpected arguments to $name command.");
- return new Future.value();
- }
- return debuggerQuit();
- }
-}
-
-class SetCommand extends Command {
- final name = 'set';
- final helpShort = 'Change the value of a debugger setting.';
- final helpLong ="""
-Change the value of a debugger setting.
-
-Usage:
- set <setting> <value>
-
-Valid settings are:
- ${validSettings.join('\n ')}.
-
-See also 'help show'.
-""";
-
- Future run(List<String> args) {
- if (args.length < 3 || !validSettings.contains(args[1])) {
- print("Undefined $name command. Try 'help $name'.");
- return new Future.value();
- }
- var option = args[1];
- var value = args.getRange(2, args.length).join(' ');
- settings[option] = value;
- return new Future.value();
- }
-}
-
-class ShowCommand extends Command {
- final name = 'show';
- final helpShort = 'Show the current value of a debugger setting.';
- final helpLong ="""
-Show the current value of a debugger setting.
-
-Usage:
- show
- show <setting>
-
-If no <setting> is specified, all current settings are shown.
-
-Valid settings are:
- ${validSettings.join('\n ')}.
-
-See also 'help set'.
-""";
-
- Future run(List<String> args) {
- if (args.length == 1) {
- for (var option in validSettings) {
- var value = settings[option];
- print("$option = '$value'");
- }
- } else if (args.length == 2 && validSettings.contains(args[1])) {
- var option = args[1];
- var value = settings[option];
- if (value == null) {
- print('$option has not been set.');
- } else {
- print("$option = '$value'");
- }
- return new Future.value();
- } else {
- print("Undefined $name command. Try 'help $name'.");
- }
- return new Future.value();
- }
-}
-
-class RunCommand extends Command {
- final name = 'run';
- final helpShort = "Run the currrent script.";
- final helpLong ="""
-Runs the current script.
-
-Usage:
- run
- run <args>
-
-The current script will be run on the current vm. The 'vm' and
-'vmargs' settings are used to specify the current vm and vm arguments.
-The 'script' and 'args' settings are used to specify the current
-script and script arguments.
-
-For more information on settings type 'help show' or 'help set'.
-
-If <args> are provided to the run command, it is the same as typing
-'set args <args>' followed by 'run'.
-""";
-
- Future run(List<String> cmdArgs) {
- if (isDebugging) {
- // TODO(turnidge): Implement modal y/n dialog to stop running script.
- print("There is already a running dart process. "
- "Try 'kill'.");
- return new Future.value();
- }
- assert(targetProcess == null);
- if (settings['script'] == null) {
- print("There is no script specified. "
- "Use 'set script' to set the current script.");
- return new Future.value();
- }
- if (cmdArgs.length > 1) {
- settings['args'] = cmdArgs.getRange(1, cmdArgs.length);
- }
-
- // Build the process arguments.
- var processArgs = ['--debug:$debugPort'];
- if (verbose) {
- processArgs.add('--verbose_debug');
- }
- if (settings['vmargs'] != null) {
- processArgs.addAll(settings['vmargs'].split(' '));
- }
- processArgs.add(settings['script']);
- if (settings['args'] != null) {
- processArgs.addAll(settings['args'].split(' '));
- }
- String vm = settings['vm'];
-
- isDebugging = true;
- cmdo.hide();
- return Process.start(vm, processArgs).then((process) {
- print("Started process ${process.pid} '$vm ${processArgs.join(' ')}'");
- targetProcess = process;
- process.stdin.close();
-
- // TODO(turnidge): For now we only show full lines of output
- // from the debugged process. Should show each character.
- process.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter())
- .listen((String line) {
- cmdo.hide();
- // TODO(turnidge): Escape output in any way?
- print(line);
- cmdo.show();
- });
-
- process.stderr
- .transform(UTF8.decoder)
- .transform(new LineSplitter())
- .listen((String line) {
- cmdo.hide();
- print(line);
- cmdo.show();
- });
-
- process.exitCode.then((int exitCode) {
- cmdo.hide();
- if (suppressNextExitCode) {
- suppressNextExitCode = false;
- } else {
- if (exitCode == 0) {
- print('Process exited normally.');
- } else {
- print('Process exited with code $exitCode.');
- }
- }
- targetProcess = null;
- cmdo.show();
- });
-
- // Wait for the vm to open the debugging port.
- return openVmSocket(0);
- });
- }
-}
-
-class KillCommand extends Command {
- final name = 'kill';
- final helpShort = 'Kill the currently executing script.';
- final helpLong ="""
-Kill the currently executing script.
-
-Usage:
- kill
-""";
-
- Future run(List<String> cmdArgs) {
- if (!isDebugging) {
- print('There is no running script.');
- return new Future.value();
- }
- if (targetProcess == null) {
- print("The active dart process was not started with 'run'. "
- "Try 'disconnect' instead.");
- return new Future.value();
- }
- assert(targetProcess != null);
- bool result = targetProcess.kill();
- if (result) {
- print('Process killed.');
- suppressNextExitCode = true;
- } else {
- print('Unable to kill process ${targetProcess.pid}');
- }
- return new Future.value();
- }
-}
-
-class ConnectCommand extends Command {
- final name = 'connect';
- final helpShort = "Connect to a running dart script.";
- final helpLong ="""
-Connect to a running dart script.
-
-Usage:
- connect
- connect <port>
-
-The debugger will connect to a dart script which has already been
-started with the --debug option. If no port is provided, the debugger
-will attempt to connect on the default debugger port.
-""";
-
- Future run(List<String> cmdArgs) {
- if (cmdArgs.length > 2) {
- print("Too many arguments to 'connect'.");
- }
- if (isDebugging) {
- // TODO(turnidge): Implement modal y/n dialog to stop running script.
- print("There is already a running dart process. "
- "Try 'kill'.");
- return new Future.value();
- }
- assert(targetProcess == null);
- if (cmdArgs.length == 2) {
- debugPort = int.parse(cmdArgs[1]);
- }
-
- isDebugging = true;
- cmdo.hide();
- return openVmSocket(0);
- }
-}
-
-class DisconnectCommand extends Command {
- final name = 'disconnect';
- final helpShort = "Disconnect from a running dart script.";
- final helpLong ="""
-Disconnect from a running dart script.
-
-Usage:
- disconnect
-
-The debugger will disconnect from a dart script's debugging port. The
-script must have been connected to earlier with the 'connect' command.
-""";
-
- Future run(List<String> cmdArgs) {
- if (cmdArgs.length > 1) {
- print("Too many arguments to 'disconnect'.");
- }
- if (!isDebugging) {
- // TODO(turnidge): Implement modal y/n dialog to stop running script.
- print("There is no active dart process. "
- "Try 'connect'.");
- return new Future.value();
- }
- if (targetProcess != null) {
- print("The active dart process was started with 'run'. "
- "Try 'kill'.");
- }
-
- cmdo.hide();
- return closeVmSocket();
- }
-}
-
-typedef void HandlerType(Map response);
-
-HandlerType showPromptAfter(void handler(Map response)) {
- return (response) {
- handler(response);
- cmdo.show();
- };
-}
-
-void processCommand(String cmdLine) {
- void huh() {
- print("'$cmdLine' not understood, try 'help' for help.");
- }
-
- cmdo.hide();
- seqNum++;
- cmdLine = cmdLine.trim();
- var args = cmdLine.split(' ');
- if (args.length == 0) {
- return;
- }
- var command = args[0];
-
- var resume_commands =
- { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'};
- if (resume_commands[command] != null) {
- if (!checkPaused()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": resume_commands[command],
- "params": { "isolateId" : currentIsolate.id } };
- sendCmd(cmd).then(showPromptAfter(handleResumedResponse));
- } else if (command == "bt") {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getStackTrace",
- "params": { "isolateId" : currentIsolate.id } };
- sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse));
- } else if (command == "ll") {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getLibraries",
- "params": { "isolateId" : currentIsolate.id } };
- sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse));
- } else if (command == "sbp" && args.length >= 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var url, line;
- if (args.length == 2 && currentIsolate.pausedUrl != null) {
- url = currentIsolate.pausedUrl;
- line = int.parse(args[1]);
- } else {
- url = args[1];
- line = int.parse(args[2]);
- }
- var cmd = { "id": seqNum,
- "command": "setBreakpoint",
- "params": { "isolateId" : currentIsolate.id,
- "url": url,
- "line": line }};
- sendCmd(cmd).then(showPromptAfter(handleSetBpResponse));
- } else if (command == "rbp" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "removeBreakpoint",
- "params": { "isolateId" : currentIsolate.id,
- "breakpointId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command == "ls" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getScriptURLs",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse));
- } else if (command == "eval" && args.length > 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var expr = args.getRange(3, args.length).join(" ");
- var target = args[1];
- if (target == "obj") {
- target = "objectId";
- } else if (target == "cls") {
- target = "classId";
- } else if (target == "lib") {
- target = "libraryId";
- } else if (target == "fr") {
- target = "frameId";
- } else {
- huh();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "evaluateExpr",
- "params": { "isolateId": currentIsolate.id,
- target: int.parse(args[2]),
- "expression": expr } };
- sendCmd(cmd).then(showPromptAfter(handleEvalResponse));
- } else if (command == "po" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getObjectProperties",
- "params": { "isolateId" : currentIsolate.id,
- "objectId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse));
- } else if (command == "pl" && args.length >= 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd;
- if (args.length == 3) {
- cmd = { "id": seqNum,
- "command": "getListElements",
- "params": { "isolateId" : currentIsolate.id,
- "objectId": int.parse(args[1]),
- "index": int.parse(args[2]) } };
- } else {
- cmd = { "id": seqNum,
- "command": "getListElements",
- "params": { "isolateId" : currentIsolate.id,
- "objectId": int.parse(args[1]),
- "index": int.parse(args[2]),
- "length": int.parse(args[3]) } };
- }
- sendCmd(cmd).then(showPromptAfter(handleGetListResponse));
- } else if (command == "pc" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getClassProperties",
- "params": { "isolateId" : currentIsolate.id,
- "classId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse));
- } else if (command == "plib" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getLibraryProperties",
- "params": {"isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse));
- } else if (command == "slib" && args.length == 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "setLibraryProperties",
- "params": {"isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]),
- "debuggingEnabled": args[2] } };
- sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse));
- } else if (command == "pg" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getGlobalVariables",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse));
- } else if (command == "gs" && args.length == 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getScriptSource",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]),
- "url": args[2] } };
- sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse));
- } else if (command == "tok" && args.length == 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getLineNumberTable",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]),
- "url": args[2] } };
- sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse));
- } else if (command == "epi" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "setPauseOnException",
- "params": { "isolateId" : currentIsolate.id,
- "exceptions": args[1] } };
- sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command == "li") {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum, "command": "getIsolateIds" };
- sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse));
- } else if (command == "sci" && args.length == 2) {
- var id = int.parse(args[1]);
- if (targetIsolates[id] != null) {
- setCurrentIsolate(targetIsolates[id]);
- } else {
- print("$id is not a valid isolate id");
- }
- cmdo.show();
- } else if (command == "i" && args.length == 2) {
- var cmd = { "id": seqNum,
- "command": "interrupt",
- "params": { "isolateId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command.length == 0) {
- huh();
- cmdo.show();
- } else {
- // TODO(turnidge): Use this for all commands.
- var matches = matchCommand(command, true);
- if (matches.length == 0) {
- huh();
- cmdo.show();
- } else if (matches.length == 1) {
- matches[0].run(args).then((_) {
- cmdo.show();
- });
- } else {
- var matchNames = matches.map((handler) => handler.name);
- print("Ambiguous command '$command' : ${matchNames.toList()}");
- cmdo.show();
- }
- }
-}
-
-
-void processError(error, trace) {
- cmdo.hide();
- print("\nInternal error:\n$error\n$trace");
- cmdo.show();
-}
-
-
-void processDone() {
- debuggerQuit();
-}
-
-
-String remoteObject(value) {
- var kind = value["kind"];
- var text = value["text"];
- var id = value["objectId"];
- if (kind == "string") {
- return "(string, id $id) '$text'";
- } else if (kind == "list") {
- var len = value["length"];
- return "(list, id $id, len $len) $text";
- } else if (kind == "object") {
- return "(obj, id $id) $text";
- } else if (kind == "function") {
- var location = formatLocation(value['location']);
- var name = value['name'];
- var signature = value['signature'];
- return "(closure ${name}${signature} $location)";
- } else {
- return "$text";
- }
-}
-
-
-printNamedObject(obj) {
- var name = obj["name"];
- var value = obj["value"];
- print(" $name = ${remoteObject(value)}");
-}
-
-
-handleGetObjPropsResponse(Map response) {
- Map props = response["result"];
- int class_id = props["classId"];
- if (class_id == -1) {
- print(" null");
- return;
- }
- List fields = props["fields"];
- print(" class id: $class_id");
- for (int i = 0; i < fields.length; i++) {
- printNamedObject(fields[i]);
- }
-}
-
-handleGetListResponse(Map response) {
- Map result = response["result"];
- if (result["elements"] != null) {
- // List slice.
- var index = result["index"];
- var length = result["length"];
- List elements = result["elements"];
- assert(length == elements.length);
- for (int i = 0; i < length; i++) {
- var kind = elements[i]["kind"];
- var text = elements[i]["text"];
- print(" ${index + i}: ($kind) $text");
- }
- } else {
- // One element, a remote object.
- print(result);
- print(" ${remoteObject(result)}");
- }
-}
-
-
-handleGetClassPropsResponse(Map response) {
- Map props = response["result"];
- assert(props["name"] != null);
- int libId = props["libraryId"];
- assert(libId != null);
- print(" class ${props["name"]} (library id: $libId)");
- List fields = props["fields"];
- if (fields.length > 0) {
- print(" static fields:");
- for (int i = 0; i < fields.length; i++) {
- printNamedObject(fields[i]);
- }
- }
-}
-
-
-handleGetLibraryPropsResponse(Map response) {
- Map props = response["result"];
- assert(props["url"] != null);
- print(" library url: ${props["url"]}");
- assert(props["debuggingEnabled"] != null);
- print(" debugging enabled: ${props["debuggingEnabled"]}");
- List imports = props["imports"];
- assert(imports != null);
- if (imports.length > 0) {
- print(" imports:");
- for (int i = 0; i < imports.length; i++) {
- print(" id ${imports[i]["libraryId"]} prefix ${imports[i]["prefix"]}");
- }
- }
- List globals = props["globals"];
- assert(globals != null);
- if (globals.length > 0) {
- print(" global variables:");
- for (int i = 0; i < globals.length; i++) {
- printNamedObject(globals[i]);
- }
- }
-}
-
-
-handleSetLibraryPropsResponse(Map response) {
- Map props = response["result"];
- assert(props["debuggingEnabled"] != null);
- print(" debugging enabled: ${props["debuggingEnabled"]}");
-}
-
-
-handleGetGlobalVarsResponse(Map response) {
- List globals = response["result"]["globals"];
- for (int i = 0; i < globals.length; i++) {
- printNamedObject(globals[i]);
- }
-}
-
-
-handleGetSourceResponse(Map response) {
- Map result = response["result"];
- String source = result["text"];
- print("Source text:\n$source\n--------");
-}
-
-
-handleGetLineTableResponse(Map response) {
- Map result = response["result"];
- var info = result["lines"];
- print("Line info table:\n$info");
-}
-
-
-void handleGetIsolatesResponse(Map response) {
- Map result = response["result"];
- List ids = result["isolateIds"];
- assert(ids != null);
- print("List of isolates:");
- for (int id in ids) {
- TargetIsolate isolate = targetIsolates[id];
- var state = (isolate != null) ? "running" : "<unknown isolate>";
- if (isolate != null && isolate.isPaused) {
- var loc = formatLocation(isolate.pausedLocation);
- state = "paused at $loc";
- }
- var marker = " ";
- if (currentIsolate != null && id == currentIsolate.id) {
- marker = "*";
- }
- print("$marker $id $state");
- }
-}
-
-
-void handleGetLibraryResponse(Map response) {
- Map result = response["result"];
- List libs = result["libraries"];
- print("Loaded libraries:");
- print(libs);
- for (int i = 0; i < libs.length; i++) {
- print(" ${libs[i]["id"]} ${libs[i]["url"]}");
- }
-}
-
-
-void handleGetScriptsResponse(Map response) {
- Map result = response["result"];
- List urls = result["urls"];
- print("Loaded scripts:");
- for (int i = 0; i < urls.length; i++) {
- print(" $i ${urls[i]}");
- }
-}
-
-
-void handleEvalResponse(Map response) {
- Map result = response["result"];
- print(remoteObject(result));
-}
-
-
-void handleSetBpResponse(Map response) {
- Map result = response["result"];
- var id = result["breakpointId"];
- assert(id != null);
- print("Set BP $id");
-}
-
-
-void handleGenericResponse(Map response) {
- if (response["error"] != null) {
- print("Error: ${response["error"]}");
- }
-}
-
-void handleResumedResponse(Map response) {
- if (response["error"] != null) {
- print("Error: ${response["error"]}");
- return;
- }
- assert(currentIsolate != null);
- currentIsolate.pausedLocation = null;
-}
-
-
-void handleStackTraceResponse(Map response) {
- Map result = response["result"];
- List callFrames = result["callFrames"];
- assert(callFrames != null);
- printStackTrace(callFrames);
-}
-
-
-void printStackFrame(frame_num, Map frame) {
- var fname = frame["functionName"];
- var loc = formatLocation(frame["location"]);
- print("#${_leftJustify(frame_num,2)} $fname at $loc");
- List locals = frame["locals"];
- for (int i = 0; i < locals.length; i++) {
- printNamedObject(locals[i]);
- }
-}
-
-
-void printStackTrace(List frames) {
- for (int i = 0; i < frames.length; i++) {
- printStackFrame(i, frames[i]);
- }
-}
-
-
-Map<int, int> parseLineNumberTable(List<List<int>> table) {
- Map tokenToLine = {};
- for (var line in table) {
- // Each entry begins with a line number...
- var lineNumber = line[0];
- for (var pos = 1; pos < line.length; pos += 2) {
- // ...and is followed by (token offset, col number) pairs.
- // We ignore the column numbers.
- var tokenOffset = line[pos];
- tokenToLine[tokenOffset] = lineNumber;
- }
- }
- return tokenToLine;
-}
-
-
-Future<TargetScript> getTargetScript(Map location) {
- var isolate = targetIsolates[currentIsolate.id];
- var url = location['url'];
- var script = isolate.scripts[url];
- if (script != null) {
- return new Future.value(script);
- }
- script = new TargetScript();
-
- // Ask the vm for the source and line number table.
- var sourceCmd = {
- "id": seqNum++,
- "command": "getScriptSource",
- "params": { "isolateId": currentIsolate.id,
- "libraryId": location['libraryId'],
- "url": url } };
-
- var lineNumberCmd = {
- "id": seqNum++,
- "command": "getLineNumberTable",
- "params": { "isolateId": currentIsolate.id,
- "libraryId": location['libraryId'],
- "url": url } };
-
- // Send the source command
- var sourceResponse = sendCmd(sourceCmd).then((response) {
- Map result = response["result"];
- script.source = result['text'];
- // Line numbers are 1-based so add a dummy for line 0.
- script.lineToSource = [''];
- script.lineToSource.addAll(script.source.split('\n'));
- });
-
- // Send the line numbers command
- var lineNumberResponse = sendCmd(lineNumberCmd).then((response) {
- Map result = response["result"];
- script.tokenToLine = parseLineNumberTable(result['lines']);
- });
-
- return Future.wait([sourceResponse, lineNumberResponse]).then((_) {
- // When both commands complete, cache the result.
- isolate.scripts[url] = script;
- return script;
- });
-}
-
-
-Future printLocation(String label, Map location) {
- // Figure out the line number.
- return getTargetScript(location).then((script) {
- var lineNumber = script.tokenToLine[location['tokenOffset']];
- var text = script.lineToSource[lineNumber];
- if (label != null) {
- var fileName = location['url'].split("/").last;
- print("$label \n"
- " at $fileName:$lineNumber");
- }
- print("${_leftJustify(lineNumber, 8)}$text");
- });
-}
-
-
-Future handlePausedEvent(msg) {
- assert(msg["params"] != null);
- var reason = msg["params"]["reason"];
- int isolateId = msg["params"]["isolateId"];
- assert(isolateId != null);
- var isolate = targetIsolates[isolateId];
- assert(isolate != null);
- assert(!isolate.isPaused);
- var location = msg["params"]["location"];;
- setCurrentIsolate(isolate);
- isolate.pausedLocation = (location == null) ? UnknownLocation : location;
- if (reason == "breakpoint") {
- assert(location != null);
- var bpId = (msg["params"]["breakpointId"]);
- var label = (bpId != null) ? "Breakpoint $bpId" : null;
- return printLocation(label, location);
- } else if (reason == "interrupted") {
- assert(location != null);
- return printLocation("Interrupted", location);
- } else {
- assert(reason == "exception");
- var excObj = msg["params"]["exception"];
- print("Isolate $isolateId paused on exception");
- print(remoteObject(excObj));
- return new Future.value();
- }
-}
-
-void handleIsolateEvent(msg) {
- Map params = msg["params"];
- assert(params != null);
- var isolateId = params["id"];
- var reason = params["reason"];
- if (reason == "created") {
- print("Isolate $isolateId has been created.");
- assert(targetIsolates[isolateId] == null);
- targetIsolates[isolateId] = new TargetIsolate(isolateId);
- } else {
- assert(reason == "shutdown");
- var isolate = targetIsolates.remove(isolateId);
- assert(isolate != null);
- if (isolate == mainIsolate) {
- mainIsolate = null;
- print("Main isolate ${isolate.id} has terminated.");
- } else {
- print("Isolate ${isolate.id} has terminated.");
- }
- if (isolate == currentIsolate) {
- currentIsolate = mainIsolate;
- if (currentIsolate == null && !targetIsolates.isEmpty) {
- currentIsolate = targetIsolates.values.first;
- }
- if (currentIsolate != null) {
- print("Setting current isolate to ${currentIsolate.id}.");
- } else {
- print("All isolates have terminated.");
- }
- }
- }
-}
-
-void processVmMessage(String jsonString) {
- var msg = JSON.decode(jsonString);
- if (msg == null) {
- return;
- }
- var event = msg["event"];
- if (event == "isolate") {
- cmdo.hide();
- handleIsolateEvent(msg);
- cmdo.show();
- return;
- }
- if (event == "paused") {
- cmdo.hide();
- handlePausedEvent(msg).then((_) {
- cmdo.show();
- });
- return;
- }
- if (event == "breakpointResolved") {
- Map params = msg["params"];
- assert(params != null);
- var isolateId = params["isolateId"];
- var location = formatLocation(params["location"]);
- cmdo.hide();
- print("Breakpoint ${params["breakpointId"]} resolved in isolate $isolateId"
- " at $location.");
- cmdo.show();
- return;
- }
- if (msg["id"] != null) {
- var id = msg["id"];
- if (outstandingCommands.containsKey(id)) {
- var completer = outstandingCommands.remove(id);
- if (msg["error"] != null) {
- print("VM says: ${msg["error"]}");
- // TODO(turnidge): Rework how hide/show happens. For now we
- // show here explicitly.
- cmdo.show();
- } else {
- completer.complete(msg);
- }
- }
- }
-}
-
-bool haveGarbageVmData() {
- if (vmData == null || vmData.length == 0) return false;
- var i = 0, char = " ";
- while (i < vmData.length) {
- char = vmData[i];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- i++;
- }
- if (i >= vmData.length) {
- return false;
- } else {
- return char != "{";
- }
-}
-
-
-void processVmData(String data) {
- if (vmData == null || vmData.length == 0) {
- vmData = data;
- } else {
- vmData = vmData + data;
- }
- if (haveGarbageVmData()) {
- print("Error: have garbage data from VM: '$vmData'");
- return;
- }
- int msg_len = jsonObjectLength(vmData);
- if (printMessages && msg_len == 0) {
- print("have partial or illegal json message"
- " of ${vmData.length} chars:\n'$vmData'");
- return;
- }
- while (msg_len > 0 && msg_len <= vmData.length) {
- if (msg_len == vmData.length) {
- if (printMessages) { print("have one full message:\n$vmData"); }
- processVmMessage(vmData);
- vmData = null;
- return;
- }
- if (printMessages) { print("at least one message: '$vmData'"); }
- var msg = vmData.substring(0, msg_len);
- if (printMessages) { print("first message: $msg"); }
- vmData = vmData.substring(msg_len);
- if (haveGarbageVmData()) {
- print("Error: garbage data after previous message: '$vmData'");
- print("Previous message was: '$msg'");
- return;
- }
- processVmMessage(msg);
- msg_len = jsonObjectLength(vmData);
- }
- if (printMessages) { print("leftover vm data '$vmData'"); }
-}
-
-/**
- * Skip past a JSON object value.
- * The object value must start with '{' and continues to the
- * matching '}'. No attempt is made to otherwise validate the contents
- * as JSON. If it is invalid, a later [parseJson] will fail.
- */
-int jsonObjectLength(String string) {
- int skipWhitespace(int index) {
- while (index < string.length) {
- String char = string[index];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- index++;
- }
- return index;
- }
- int skipString(int index) {
- assert(string[index - 1] == '"');
- while (index < string.length) {
- String char = string[index];
- if (char == '"') return index + 1;
- if (char == r'\') index++;
- if (index == string.length) return index;
- index++;
- }
- return index;
- }
- int index = 0;
- index = skipWhitespace(index);
- // Bail out if the first non-whitespace character isn't '{'.
- if (index == string.length || string[index] != '{') return 0;
- int nesting = 0;
- while (index < string.length) {
- String char = string[index++];
- if (char == '{') {
- nesting++;
- } else if (char == '}') {
- nesting--;
- if (nesting == 0) return index;
- } else if (char == '"') {
- // Strings can contain braces. Skip their content.
- index = skipString(index);
- }
- }
- return 0;
-}
-
-List<String> debuggerCommandCompleter(List<String> commandParts) {
- List<String> completions = new List<String>();
-
- // TODO(turnidge): Have a global command table and use it to for
- // help messages, command completion, and command dispatching. For now
- // we hardcode the list here.
- //
- // TODO(turnidge): Implement completion for arguments as well.
- List<String> oldCommands = ['bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
- 'po', 'eval', 'pl', 'pc', 'll', 'plib', 'slib',
- 'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i' ];
-
- // Completion of first word in the command.
- if (commandParts.length == 1) {
- String prefix = commandParts.last;
- for (var command in oldCommands) {
- if (command.startsWith(prefix)) {
- completions.add(command);
- }
- }
- for (var command in commandList) {
- if (command.name.startsWith(prefix)) {
- completions.add(command.name);
- }
- }
- }
-
- return completions;
-}
-
-Future closeCommando() {
- var subscription = cmdSubscription;
- cmdSubscription = null;
- cmdo = null;
-
- var future = subscription.cancel();
- if (future != null) {
- return future;
- } else {
- return new Future.value();
- }
-}
-
-
-Future openVmSocket(int attempt) {
- return Socket.connect("127.0.0.1", debugPort).then(
- setupVmSocket,
- onError: (e) {
- // We were unable to connect to the debugger's port. Try again.
- retryOpenVmSocket(e, attempt);
- });
-}
-
-
-void setupVmSocket(Socket s) {
- vmSock = s;
- vmSock.setOption(SocketOption.TCP_NODELAY, true);
- var stringStream = vmSock.transform(UTF8.decoder);
- outstandingCommands = new Map<int, Completer>();
- vmSubscription = stringStream.listen(
- (String data) {
- processVmData(data);
- },
- onDone: () {
- cmdo.hide();
- if (verbose) {
- print("VM debugger connection closed");
- }
- closeVmSocket().then((_) {
- cmdo.show();
- });
- },
- onError: (err) {
- cmdo.hide();
- // TODO(floitsch): do we want to print the stack trace?
- print("Error in debug connection: $err");
-
- // TODO(turnidge): Kill the debugged process here?
- closeVmSocket().then((_) {
- cmdo.show();
- });
- });
-}
-
-
-Future retryOpenVmSocket(error, int attempt) {
- var delay;
- if (attempt < 10) {
- delay = new Duration(milliseconds:10);
- } else if (attempt < 20) {
- delay = new Duration(seconds:1);
- } else {
- // Too many retries. Give up.
- //
- // TODO(turnidge): Kill the debugged process here?
- print('Timed out waiting for debugger to start.\nError: $e');
- return closeVmSocket();
- }
- // Wait and retry.
- return new Future.delayed(delay, () {
- openVmSocket(attempt + 1);
- });
-}
-
-
-Future closeVmSocket() {
- if (vmSubscription == null) {
- // Already closed, nothing to do.
- assert(vmSock == null);
- return new Future.value();
- }
-
- isDebugging = false;
- var subscription = vmSubscription;
- var sock = vmSock;
-
- // Wait for the socket to close and the subscription to be
- // cancelled. Perhaps overkill, but it means we know these will be
- // done.
- //
- // This is uglier than it needs to be since cancel can return null.
- var cleanupFutures = [sock.close()];
- var future = subscription.cancel();
- if (future != null) {
- cleanupFutures.add(future);
- }
-
- vmSubscription = null;
- vmSock = null;
- outstandingCommands = null;
- return Future.wait(cleanupFutures);
-}
-
-void debuggerError(self, parent, zone, error, StackTrace trace) {
- print('\n--------\nExiting due to unexpected error:\n'
- ' $error\n$trace\n');
- debuggerQuit();
-}
-
-Future debuggerQuit() {
- // Kill target process, if any.
- if (targetProcess != null) {
- if (!targetProcess.kill()) {
- print('Unable to kill process ${targetProcess.pid}');
- }
- }
-
- // Restore terminal settings, close connections.
- return Future.wait([closeCommando(), closeVmSocket()]).then((_) {
- exit(0);
-
- // Unreachable.
- return new Future.value();
- });
-}
-
-
-void parseArgs(List<String> args) {
- int pos = 0;
- settings['vm'] = Platform.executable;
- while (pos < args.length && args[pos].startsWith('-')) {
- pos++;
- }
- if (pos < args.length) {
- settings['vmargs'] = args.getRange(0, pos).join(' ');
- settings['script'] = args[pos];
- settings['args'] = args.getRange(pos + 1, args.length).join(' ');
- }
-}
-
-void main(List<String> args) {
- // Setup a zone which will exit the debugger cleanly on any uncaught
- // exception.
- var zone = Zone.ROOT.fork(specification:new ZoneSpecification(
- handleUncaughtError: debuggerError));
-
- zone.run(() {
- parseArgs(args);
- cmdo = new Commando(completer: debuggerCommandCompleter);
- cmdSubscription = cmdo.commands.listen(processCommand,
- onError: processError,
- onDone: processDone);
- });
-}
« no previous file with comments | « tools/coverage.dart ('k') | tools/ddbg/lib/commando.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698