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

Unified Diff: tests/standalone/debugger/debug_lib.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
Index: tests/standalone/debugger/debug_lib.dart
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
deleted file mode 100644
index 92a0d103c096dc47007b9ffcd15ee7c19844184d..0000000000000000000000000000000000000000
--- a/tests/standalone/debugger/debug_lib.dart
+++ /dev/null
@@ -1,749 +0,0 @@
-// Copyright (c) 2013, 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.
-
-// Library used by debugger wire protocol tests (standalone VM debugging).
-
-library DartDebugger;
-
-import "dart:async";
-import "dart:convert";
-import "dart:io";
-import "dart:math";
-
-// Whether or not to print the debugger wire messages on the console.
-var verboseWire = false;
-
-// Class to buffer wire protocol data from debug target and
-// break it down to individual json messages.
-class JsonBuffer {
- String buffer = null;
-
- append(String s) {
- if (buffer == null || buffer.length == 0) {
- buffer = s;
- } else {
- buffer += s;
- }
- }
-
- String getNextMessage() {
- if (buffer == null) return null;
- int msgLen = objectLength();
- if (msgLen == 0) return null;
- String msg = null;
- if (msgLen == buffer.length) {
- msg = buffer;
- buffer = null;
- } else {
- assert(msgLen < buffer.length);
- msg = buffer.substring(0, msgLen);
- buffer = buffer.substring(msgLen);
- }
- return msg;
- }
-
- bool haveGarbage() {
- if (buffer == null || buffer.length == 0) return false;
- var i = 0, char = " ";
- while (i < buffer.length) {
- char = buffer[i];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- i++;
- }
- if (i >= buffer.length) {
- return false;
- } else {
- return char != "{";
- }
- }
-
- // Returns the character length of the next json message in the
- // buffer, or 0 if there is only a partial message in the buffer.
- // 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 JSON.decode() will fail.
- int objectLength() {
- int skipWhitespace(int index) {
- while (index < buffer.length) {
- String char = buffer[index];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- index++;
- }
- return index;
- }
- int skipString(int index) {
- assert(buffer[index - 1] == '"');
- while (index < buffer.length) {
- String char = buffer[index];
- if (char == '"') return index + 1;
- if (char == r'\') index++;
- if (index == buffer.length) return index;
- index++;
- }
- return index;
- }
- int index = 0;
- index = skipWhitespace(index);
- // Bail out if the first non-whitespace character isn't '{'.
- if (index == buffer.length || buffer[index] != '{') return 0;
- int nesting = 0;
- while (index < buffer.length) {
- String char = buffer[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;
- }
-}
-
-
-getJsonValue(Map jsonMsg, String path) {
- List properties = path.split(new RegExp(":"));
- assert(properties.length >= 1);
- var node = jsonMsg;
- for (int i = 0; i < properties.length; i++) {
- if (node == null) return null;
- String property = properties[i];
- var index = null;
- if (property.endsWith("]")) {
- var bracketPos = property.lastIndexOf("[");
- if (bracketPos <= 0) return null;
- var indexStr = property.substring(bracketPos + 1, property.length - 1);
- try {
- index = int.parse(indexStr);
- } on FormatException {
- print("$indexStr is not a valid array index");
- return null;
- }
- property = property.substring(0, bracketPos);
- }
- if (node is Map) {
- node = node[property];
- } else {
- return null;
- }
- if (index != null) {
- if (node is List && node.length > index) {
- node = node[index];
- } else {
- return null;
- }
- }
- }
- return node;
-}
-
-
-// Returns true if [template] is a subset of [map].
-bool matchMaps(Map template, Map msg) {
- bool isMatch = true;
- template.forEach((k, v) {
- if (msg.containsKey(k)) {
- var receivedValue = msg[k];
- if ((v is Map) && (receivedValue is Map)) {
- if (!matchMaps(v, receivedValue)) isMatch = false;
- } else if (v == null) {
- // null in the template matches everything.
- } else if (v != receivedValue) {
- isMatch = false;
- }
- } else {
- isMatch = false;
- }
- });
- return isMatch;
-}
-
-
-class Command {
- var template;
-
- void send(Debugger debugger) {
- debugger.sendMessage(template);
- }
-
- void matchResponse(Debugger debugger) {
- Map response = debugger.currentMessage;
- var id = template["id"];
- assert(id != null && id >= 0);
- if (response["id"] != id) {
- debugger.error("Error: expected messaged id $id but got ${response["id"]}.");
- }
- }
-}
-
-class GetLineTableCmd extends Command {
- GetLineTableCmd() {
- template = {"id": 0,
- "command": "getLineNumberTable",
- "params": {"isolateId": 0, "libraryId": 0, "url": ""}};
- }
-
- void send(Debugger debugger) {
- assert(debugger.scriptUrl != null);
- template["params"]["url"] = debugger.scriptUrl;
- template["params"]["libraryId"] = debugger.libraryId;
- debugger.sendMessage(template);
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- List<List<int>> table = getJsonValue(debugger.currentMessage, "result:lines");
- debugger.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.
- var tokenOffset = line[pos];
- debugger.tokenToLine[tokenOffset] = lineNumber;
- }
- }
- }
-}
-
-
-class LineMatcher extends Command {
- int expectedLineNumber;
-
- LineMatcher(this.expectedLineNumber) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- assert(debugger.tokenToLine != null);
- super.matchResponse(debugger);
- var msg = debugger.currentMessage;
- List frames = getJsonValue(msg, "result:callFrames");
- assert(frames != null);
- var tokenOffset = frames[0]["location"]["tokenOffset"];
- assert(tokenOffset != null);
- var lineNumber = debugger.tokenToLine[tokenOffset];
- assert(lineNumber != null);
- if (expectedLineNumber != lineNumber) {
- debugger.error("Error: expected pause at line $expectedLineNumber "
- "but reported line is $lineNumber.");
- return;
- }
- print("Matched line number $lineNumber");
- }
-}
-
-MatchLine(lineNumber) {
- return new LineMatcher(lineNumber);
-}
-
-
-class FrameMatcher extends Command {
- int frameIndex;
- List<String> functionNames;
- bool exactMatch;
-
- FrameMatcher(this.frameIndex, this.functionNames, this.exactMatch) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- var msg = debugger.currentMessage;
- List frames = getJsonValue(msg, "result:callFrames");
- assert(frames != null);
- if (debugger.scriptUrl == null) {
- var name = frames[0]["functionName"];
- if (name == "main") {
- // Extract script url of debugged script.
- debugger.scriptUrl = frames[0]["location"]["url"];
- assert(debugger.scriptUrl != null);
- debugger.libraryId = frames[0]["location"]["libraryId"];
- assert(debugger.libraryId != null);
- }
- }
- if (frames.length < functionNames.length) {
- debugger.error("Error: stack trace not long enough "
- "to match ${functionNames.length} frames");
- return;
- }
- for (int i = 0; i < functionNames.length; i++) {
- var idx = i + frameIndex;
- var name = frames[idx]["functionName"];
- assert(name != null);
- bool isMatch = exactMatch ? name == functionNames[i]
- : name.contains(functionNames[i]);
- if (!isMatch) {
- debugger.error("Error: call frame $idx: "
- "expected function name '${functionNames[i]}' but found '$name'");
- return;
- }
- }
- print("Matched frames: $functionNames");
- }
-}
-
-
-MatchFrame(int frameIndex, String functionName, {exactMatch: false}) {
- return new FrameMatcher(frameIndex, [functionName], exactMatch);
-}
-
-MatchFrames(List<String> functionNames, {exactMatch: false}) {
- return new FrameMatcher(0, functionNames, exactMatch);
-}
-
-
-class LocalsMatcher extends Command {
- Map locals = {};
-
- LocalsMatcher(this.locals) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
-
- List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
- assert(frames != null);
-
- String functionName = frames[0]['functionName'];
- List localsList = frames[0]['locals'];
- Map reportedLocals = {};
- localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
- for (String key in locals.keys) {
- if (reportedLocals[key] == null) {
- debugger.error("Error in $functionName(): no value reported for local "
- "variable $key");
- return;
- }
- String expected = locals[key];
- String actual = reportedLocals[key]['text'];
- if (expected != actual) {
- debugger.error("Error in $functionName(): got '$actual' for local "
- "variable $key, but expected '$expected'");
- return;
- }
- }
- print("Matched locals ${locals.keys}");
- }
-}
-
-
-MatchLocals(Map localValues) {
- return new LocalsMatcher(localValues);
-}
-
-
-// Used to check if local variables are visible.
-class AssertLocalsNotVisibleMatcher extends Command {
- List<String> locals;
- int frame_index;
-
- AssertLocalsNotVisibleMatcher(this.locals, this.frame_index) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
-
- List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
- assert(frames != null);
-
- String functionName = frames[frame_index]['functionName'];
- List localsList = frames[frame_index]['locals'];
- Map reportedLocals = {};
- localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
- for (String key in locals) {
- if (reportedLocals[key] != null) {
- debugger.error("Error in $functionName(): local variable $key not "
- "expected in scope (reported value "
- "${reportedLocals[key]['text']})");
- return;
- }
- }
- print("Matched locals $locals");
- }
-}
-
-
-AssertLocalsNotVisible(List<String> locals, [int frame_index = 0]) {
- return new AssertLocalsNotVisibleMatcher(locals, frame_index);
-}
-
-
-class EventMatcher {
- String eventName;
- Map params;
-
- EventMatcher(this.eventName, this.params);
-
- void matchEvent(Debugger debugger) {
- for (Event event in debugger.events) {
- if (event.name == eventName) {
- if (params == null || matchMaps(params, event.params)) {
- // Remove the matched event, so we don't match against it in the future.
- debugger.events.remove(event);
- return;
- }
- }
- }
-
- String msg = params == null ? '' : params.toString();
- debugger.error("Error: could not match event $eventName $msg");
- }
-}
-
-
-ExpectEvent(String eventName, [Map params]) {
- return new EventMatcher(eventName, params);
-}
-
-
-class RunCommand extends Command {
- RunCommand.resume() {
- template = {"id": 0, "command": "resume", "params": {"isolateId": 0}};
- }
- RunCommand.step() {
- template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}};
- }
- RunCommand.stepInto() {
- template = {"id": 0, "command": "stepInto", "params": {"isolateId": 0}};
- }
- RunCommand.stepOut() {
- template = {"id": 0, "command": "stepOut", "params": {"isolateId": 0}};
- }
- void send(Debugger debugger) {
- debugger.sendMessage(template);
- debugger.isPaused = false;
- }
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- print("Command: ${template['command']}");
- }
-}
-
-
-Resume() => new RunCommand.resume();
-Step() => new RunCommand.step();
-StepInto() => new RunCommand.stepInto();
-StepOut() => new RunCommand.stepOut();
-
-class SetBreakpointCommand extends Command {
- int line;
- String url;
- SetBreakpointCommand(this.line, this.url) {
- template = {"id": 0,
- "command": "setBreakpoint",
- "params": { "isolateId": 0,
- "url": null,
- "line": null }};
- }
-
- void send(Debugger debugger) {
- assert(debugger.scriptUrl != null);
- if (url == null) {
- url = debugger.scriptUrl;
- }
- template["params"]["url"] = url;
- template["params"]["line"] = line;
- debugger.sendMessage(template);
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- print("Set breakpoint at line $line in $url");
- }
-}
-
-SetBreakpoint(int line, {String url}) => new SetBreakpointCommand(line, url);
-
-class Event {
- String name;
- Map params;
-
- Event(Map json) {
- name = json['event'];
- params = json['params'];
- }
-}
-
-
-// A debug script is a list of Command objects.
-class DebugScript {
- List entries;
- DebugScript(List scriptEntries) {
- entries = new List.from(scriptEntries.reversed);
- entries.add(new GetLineTableCmd());
- entries.add(MatchFrame(0, "main"));
- }
- bool get isEmpty => entries.isEmpty;
- bool get isNextEventMatcher => !isEmpty && currentEntry is EventMatcher;
- get currentEntry => entries.last;
- advance() => entries.removeLast();
- add(entry) => entries.add(entry);
-}
-
-
-class Debugger {
- // Debug target process properties.
- Process targetProcess;
- Socket socket;
- JsonBuffer responses = new JsonBuffer();
-
- DebugScript script;
- int seqNr = 0; // Sequence number of next debugger command message.
- Command lastCommand = null; // Most recent command sent to target.
- List<String> errors = new List();
- List<Event> events = new List();
- bool cleanupDone = false;
-
- // Data collected from debug target.
- Map currentMessage = null; // Currently handled message sent by target.
- String scriptUrl = null;
- int libraryId = null;
- Map<int,int> tokenToLine = null;
- bool shutdownEventSeen = false;
- int isolateId = 0;
- bool isPaused = false;
-
- Debugger(this.targetProcess, this.script) {
- var stdoutStringStream = targetProcess.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
- stdoutStringStream.listen((line) {
- print("TARG: $line");
- if (line.startsWith("Debugger listening")) {
- RegExp portExpr = new RegExp(r"\d+");
- var port = portExpr.stringMatch(line);
- print("Debug target found listening at port '$port'");
- openConnection(int.parse(port));
- }
- });
-
- var stderrStringStream = targetProcess.stderr
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
- stderrStringStream.listen((line) {
- print("TARG: $line");
- });
- }
-
- // Handle debugger events, updating the debugger state.
- void handleEvent(Map<String,dynamic> msg) {
- events.add(new Event(msg));
-
- if (msg["event"] == "isolate") {
- if (msg["params"]["reason"] == "created") {
- isolateId = msg["params"]["id"];
- assert(isolateId != null);
- print("Debuggee isolate id $isolateId created.");
- } else if (msg["params"]["reason"] == "shutdown") {
- print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
- shutdownEventSeen = true;
- if (!script.isEmpty) {
- error("Error: premature isolate shutdown event seen.");
- error("Next expected event: ${script.currentEntry}");
- }
- }
- } else if (msg["event"] == "breakpointResolved") {
- var bpId = msg["params"]["breakpointId"];
- assert(bpId != null);
- var isolateId = msg["params"]["isolateId"];
- assert(isolateId != null);
- var location = msg["params"]["location"];
- assert(location != null);
- print("Isolate $isolateId: breakpoint $bpId resolved"
- " at location $location");
- // We may want to maintain a table of breakpoints in the future.
- } else if (msg["event"] == "paused") {
- isPaused = true;
- } else {
- error("Error: unknown debugger event received");
- }
- }
-
- // Handle one JSON message object and match it to the
- // expected events and responses in the debugging script.
- void handleMessage(Map<String,dynamic> receivedMsg) {
- currentMessage = receivedMsg;
- if (receivedMsg["event"] != null) {
- handleEvent(receivedMsg);
- if (errorsDetected) {
- error("Error while handling debugger event");
- error("Event received from debug target: $receivedMsg");
- }
- } else if (receivedMsg["id"] != null) {
- // This is a response to the last command we sent.
- assert(lastCommand != null);
- lastCommand.matchResponse(this);
- lastCommand = null;
- if (errorsDetected) {
- error("Error while matching response to debugger command");
- error("Response received from debug target: $receivedMsg");
- }
- }
- }
-
- // Send next debugger command in the script, if a response
- // from the last command has been received and processed.
- void sendNextCommand() {
- while (script.isNextEventMatcher) {
- EventMatcher matcher = script.currentEntry;
- script.advance();
- matcher.matchEvent(this);
- }
-
- if (lastCommand == null) {
- if (script.currentEntry is Command) {
- script.currentEntry.send(this);
- lastCommand = script.currentEntry;
- seqNr++;
- script.advance();
- }
- }
- }
-
- // Handle data received over the wire from the debug target
- // process. Split input from JSON wire format into individual
- // message objects (maps).
- void handleMessages() {
- var msg = responses.getNextMessage();
- while (msg != null) {
- if (verboseWire) print("RECV: $msg");
- if (responses.haveGarbage()) {
- error("Error: leftover text after message: '${responses.buffer}'");
- error("Previous message may be malformed, was: '$msg'");
- cleanup();
- return;
- }
- var msgObj = JSON.decode(msg);
- handleMessage(msgObj);
- if (errorsDetected) {
- error("Error while handling script entry");
- error("Message received from debug target: $msg");
- cleanup();
- return;
- }
- if (shutdownEventSeen) {
- cleanup();
- return;
- }
- if (isPaused) sendNextCommand();
- msg = responses.getNextMessage();
- }
- }
-
- // Send a debugger command to the target VM.
- void sendMessage(Map<String,dynamic> msg) {
- if (msg["id"] != null) {
- msg["id"] = seqNr;
- }
- if (msg["params"] != null && msg["params"]["isolateId"] != null) {
- msg["params"]["isolateId"] = isolateId;
- }
- String jsonMsg = JSON.encode(msg);
- if (verboseWire) print("SEND: $jsonMsg");
- socket.write(jsonMsg);
- }
-
- bool get errorsDetected => errors.length > 0;
-
- // Record error message.
- void error(String s) {
- errors.add(s);
- }
-
- void openConnection(int portNumber) {
- Socket.connect("127.0.0.1", portNumber).then((s) {
- s.setOption(SocketOption.TCP_NODELAY, true);
- this.socket = s;
- var stringStream = socket.transform(UTF8.decoder);
- stringStream.listen((str) {
- try {
- responses.append(str);
- handleMessages();
- } catch(e, trace) {
- print("Unexpected exception:\n$e\n$trace");
- cleanup();
- }
- },
- onDone: () {
- print("Connection closed by debug target");
- cleanup();
- },
- onError: (e, trace) {
- print("Error '$e' detected in input stream from debug target");
- if (trace != null) print("StackTrace: $trace");
- cleanup();
- });
- },
- onError: (e, trace) {
- String msg = "Error while connecting to debugee: $e";
- if (trace != null) msg += "\nStackTrace: $trace";
- error(msg);
- cleanup();
- });
- }
-
- void cleanup() {
- if (cleanupDone) return;
- if (socket != null) {
- socket.close().catchError((error) {
- // Print this directly in addition to adding it to the
- // error message queue, in case the error message queue
- // gets printed before this error handler is called.
- print("Error occurred while closing socket: $error");
- error("Error while closing socket: $error");
- });
- }
- var targetPid = targetProcess.pid;
- if (errorsDetected || !shutdownEventSeen) {
- print("Sending kill signal to process $targetPid...");
- targetProcess.kill();
- }
- // If the process was already dead, exitCode is
- // available and we call exit() in the next event loop cycle.
- // Otherwise this will wait for the process to exit.
- targetProcess.exitCode.then((exitCode) {
- print("process $targetPid terminated with exit code $exitCode.");
- if (exitCode != 0) {
- error("Error: target process died with exit code $exitCode");
- }
- if (errorsDetected) {
- print("\n===== Errors detected: =====");
- for (int i = 0; i < errors.length; i++) print(errors[i]);
- print("============================\n");
- }
- exit(errors.length);
- });
- cleanupDone = true;
- }
-}
-
-
-bool RunScript(List script, List<String> arguments) {
- if (arguments.contains("--debuggee")) {
- return false;
- }
- verboseWire = arguments.contains("--wire");
-
- // Port number 0 means debug target picks a free port dynamically.
- var targetOpts = [ "--debug:0" ];
- if (arguments.contains("--verbose")) {
- targetOpts.add("--verbose_debug");
- }
- targetOpts.add(Platform.script.toFilePath());
- targetOpts.add("--debuggee");
- print('args: ${targetOpts.join(" ")}');
-
- Process.start(Platform.executable, targetOpts).then((Process process) {
- print("Debug target process started, pid ${process.pid}.");
- process.stdin.close();
- var debugger = new Debugger(process, new DebugScript(script));
- });
- return true;
-}
« no previous file with comments | « tests/standalone/debugger/closure_debugger_test.dart ('k') | tests/standalone/debugger/deferred_code_lib.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698