| Index: tests/standalone/debugger/debug_lib.dart
|
| ===================================================================
|
| --- tests/standalone/debugger/debug_lib.dart (revision 20832)
|
| +++ tests/standalone/debugger/debug_lib.dart (working copy)
|
| @@ -154,53 +154,50 @@
|
| }
|
|
|
|
|
| -class BreakpointEvent {
|
| - String functionName;
|
| - var template = { "event": "paused", "params": { "reason": "breakpoint" }};
|
| +class Matcher {
|
| + void match(Debugger debugger);
|
| +}
|
|
|
| - BreakpointEvent({String function: null}) {
|
| - functionName = function;
|
| +
|
| +class Command {
|
| + var template;
|
| +
|
| + void send(Debugger debugger) {
|
| + debugger.sendMessage(template);
|
| }
|
|
|
| - void match(Debugger debugger) {
|
| - var msg = debugger.currentMessage;
|
| - if (!matchMaps(template, msg)) {
|
| - debugger.error("message does not match $template");
|
| + void matchResponse(Debugger debugger) {
|
| + Map response = debugger.currentMessage;
|
| + var id = template["id"];
|
| + assert(id != null && id >= 0);
|
| + if (response["id"] != id) {
|
| + debugger.error("Expected messaged id $id but got ${response["id"]}.");
|
| }
|
| - var name = getJsonValue(msg, "params:callFrames[0]:functionName");
|
| - if (name == "main") {
|
| - // Extract script url of debugged script.
|
| - var scriptUrl = getJsonValue(msg, "params:callFrames[0]:location:url");
|
| - assert(scriptUrl != null);
|
| - debugger.scriptUrl = scriptUrl;
|
| - }
|
| - if (functionName != null) {
|
| - var name = getJsonValue(msg, "params:callFrames[0]:functionName");
|
| - if (functionName != name) {
|
| - debugger.error("expected function name $functionName but got $name");
|
| - }
|
| - }
|
| }
|
| }
|
|
|
| -Breakpoint({String function}) {
|
| - return new BreakpointEvent(function: function);
|
| -}
|
|
|
| -class Matcher {
|
| - void match(Debugger debugger);
|
| -}
|
| -
|
| -class FrameMatcher extends Matcher {
|
| +class FrameMatcher extends Command {
|
| int frameIndex;
|
| List<String> functionNames;
|
|
|
| - FrameMatcher(this.frameIndex, this.functionNames);
|
| + FrameMatcher(this.frameIndex, this.functionNames) {
|
| + template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
|
| + }
|
|
|
| - void match(Debugger debugger) {
|
| + void matchResponse(Debugger debugger) {
|
| + super.matchResponse(debugger);
|
| var msg = debugger.currentMessage;
|
| - List frames = getJsonValue(msg, "params:callFrames");
|
| + 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);
|
| + }
|
| + }
|
| if (frames.length < functionNames.length) {
|
| debugger.error("stack trace not long enough "
|
| "to match ${functionNames.length} frames");
|
| @@ -208,12 +205,8 @@
|
| }
|
| for (int i = 0; i < functionNames.length; i++) {
|
| var idx = i + frameIndex;
|
| - var property = "params:callFrames[$idx]:functionName";
|
| - var name = getJsonValue(msg, property);
|
| - if (name == null) {
|
| - debugger.error("property '$property' not found");
|
| - return;
|
| - }
|
| + var name = frames[idx]["functionName"];
|
| + assert(name != null);
|
| if (name != functionNames[i]) {
|
| debugger.error("call frame $idx: "
|
| "expected function name '${functionNames[i]}' but found '$name'");
|
| @@ -233,43 +226,24 @@
|
| }
|
|
|
|
|
| -class Command {
|
| - var template;
|
| - Command();
|
| - Command.resume() {
|
| +class RunCommand extends Command {
|
| + RunCommand.resume() {
|
| template = {"id": 0, "command": "resume", "params": {"isolateId": 0}};
|
| }
|
| - Command.step() {
|
| + RunCommand.step() {
|
| template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}};
|
| }
|
| - Map makeMsg(int cmdId, int isolateId) {
|
| - template["id"] = cmdId;
|
| - if ((template["params"] != null)
|
| - && (template["params"]["isolateId"] != null)) {
|
| - template["params"]["isolateId"] = isolateId;
|
| - }
|
| - return template;
|
| - }
|
| -
|
| void send(Debugger debugger) {
|
| - template["id"] = debugger.seqNr;
|
| - template["params"]["isolateId"] = debugger.isolateId;
|
| debugger.sendMessage(template);
|
| + debugger.isPaused = false;
|
| }
|
| -
|
| - void matchResponse(Debugger debugger) {
|
| - Map response = debugger.currentMessage;
|
| - var id = template["id"];
|
| - assert(id != null && id >= 0);
|
| - if (response["id"] != id) {
|
| - debugger.error("Expected messaged id $id but got ${response["id"]}.");
|
| - }
|
| - }
|
| }
|
|
|
| -Resume() => new Command.resume();
|
| -Step() => new Command.step();
|
|
|
| +Resume() => new RunCommand.resume();
|
| +Step() => new RunCommand.step();
|
| +
|
| +
|
| class SetBreakpointCommand extends Command {
|
| int line;
|
| SetBreakpointCommand(int this.line) {
|
| @@ -279,29 +253,29 @@
|
| "url": null,
|
| "line": null }};
|
| }
|
| +
|
| void send(Debugger debugger) {
|
| assert(debugger.scriptUrl != null);
|
| template["params"]["url"] = debugger.scriptUrl;
|
| template["params"]["line"] = line;
|
| - super.send(debugger);
|
| + debugger.sendMessage(template);
|
| }
|
| }
|
|
|
| SetBreakpoint(int line) => new SetBreakpointCommand(line);
|
|
|
|
|
| -// A debug script is a list of Event, Matcher and Command objects.
|
| +// A debug script is a list of Command objects.
|
| class DebugScript {
|
| List entries;
|
| - int currentIndex;
|
| - DebugScript(List this.entries) : currentIndex = 0;
|
| - get currentEntry {
|
| - if (currentIndex < entries.length) return entries[currentIndex];
|
| - return null;
|
| + DebugScript(List scriptEntries) {
|
| + entries = new List.from(scriptEntries.reversed);
|
| + entries.add(MatchFrame(0, "main"));
|
| }
|
| - advance() {
|
| - currentIndex++;
|
| - }
|
| + bool get isEmpty => entries.isEmpty;
|
| + get currentEntry => entries.last;
|
| + advance() => entries.removeLast();
|
| + add(entry) => entries.add(entry);
|
| }
|
|
|
|
|
| @@ -322,6 +296,7 @@
|
| String scriptUrl = null;
|
| bool shutdownEventSeen = false;
|
| int isolateId = 0;
|
| + bool isPaused = false;
|
|
|
| Debugger(this.targetProcess, this.portNumber) {
|
| stdin.listen((_) {});
|
| @@ -344,10 +319,8 @@
|
| });
|
| }
|
|
|
| - // Handle debugger events for which there is no explicit
|
| - // entry in the debug script, for example isolate create and
|
| - // shutdown events, breakpoint resolution events, etc.
|
| - bool handleImplicitEvents(Map<String,dynamic> msg) {
|
| + // Handle debugger events, updating the debugger state.
|
| + void handleEvent(Map<String,dynamic> msg) {
|
| if (msg["event"] == "isolate") {
|
| if (msg["params"]["reason"] == "created") {
|
| isolateId = msg["params"]["id"];
|
| @@ -356,27 +329,31 @@
|
| } else if (msg["params"]["reason"] == "shutdown") {
|
| print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
|
| shutdownEventSeen = true;
|
| - if (script.currentEntry != null) {
|
| + if (!script.isEmpty) {
|
| error("Premature isolate shutdown event seen.");
|
| }
|
| }
|
| - return true;
|
| } else if (msg["event"] == "breakpointResolved") {
|
| // Ignore the event. We may want to maintain a table of
|
| // breakpoints in the future.
|
| - return true;
|
| + } else if (msg["event"] == "paused") {
|
| + isPaused = true;
|
| + } else {
|
| + error("unknown debugger event received");
|
| }
|
| - return false;
|
| }
|
|
|
| // 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;
|
| - var isHandled = handleImplicitEvents(receivedMsg);
|
| - if (isHandled) return;
|
| -
|
| - if (receivedMsg["id"] != null) {
|
| + 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);
|
| @@ -385,26 +362,7 @@
|
| error("Error while matching response to debugger command");
|
| error("Response received from debug target: $receivedMsg");
|
| }
|
| - return;
|
| }
|
| -
|
| - // This message must be an event that is expected by the script.
|
| - assert(receivedMsg["event"] != null);
|
| - if ((script.currentEntry == null) || (script.currentEntry is Command)) {
|
| - // Error: unexpected event received.
|
| - error("unexpected event received: $receivedMsg");
|
| - return;
|
| - } else {
|
| - // Match received message with expected event.
|
| - script.currentEntry.match(this);
|
| - if (errorsDetected) return;
|
| - script.advance();
|
| - while (script.currentEntry is Matcher) {
|
| - script.currentEntry.match(this);
|
| - if (errorsDetected) return;
|
| - script.advance();
|
| - }
|
| - }
|
| }
|
|
|
| // Send next debugger command in the script, if a response
|
| @@ -430,7 +388,7 @@
|
| var msgObj = JSON.parse(msg);
|
| handleMessage(msgObj);
|
| if (errorsDetected) {
|
| - error("Error while handling script entry ${script.currentIndex}");
|
| + error("Error while handling script entry");
|
| error("Message received from debug target: $msg");
|
| close(killDebugee: true);
|
| return;
|
| @@ -439,7 +397,7 @@
|
| close();
|
| return;
|
| }
|
| - sendNextCommand();
|
| + if (isPaused) sendNextCommand();
|
| msg = responses.getNextMessage();
|
| }
|
| }
|
| @@ -451,6 +409,12 @@
|
|
|
| // 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.stringify(msg);
|
| if (verboseWire) print("SEND: $jsonMsg");
|
| socket.write(jsonMsg);
|
|
|