| OLD | NEW | 
|---|
| 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 // Library used by debugger wire protocol tests (standalone VM debugging). | 5 // Library used by debugger wire protocol tests (standalone VM debugging). | 
| 6 | 6 | 
| 7 library DartDebugger; | 7 library DartDebugger; | 
| 8 | 8 | 
| 9 import "dart:async"; | 9 import "dart:async"; | 
| 10 import "dart:io"; | 10 import "dart:io"; | 
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 172 | 172 | 
| 173   void send(Debugger debugger) { | 173   void send(Debugger debugger) { | 
| 174     debugger.sendMessage(template); | 174     debugger.sendMessage(template); | 
| 175   } | 175   } | 
| 176 | 176 | 
| 177   void matchResponse(Debugger debugger) { | 177   void matchResponse(Debugger debugger) { | 
| 178     Map response = debugger.currentMessage; | 178     Map response = debugger.currentMessage; | 
| 179     var id = template["id"]; | 179     var id = template["id"]; | 
| 180     assert(id != null && id >= 0); | 180     assert(id != null && id >= 0); | 
| 181     if (response["id"] != id) { | 181     if (response["id"] != id) { | 
| 182       debugger.error("Expected messaged id $id but got ${response["id"]}."); | 182       debugger.error("Error: expected messaged id $id but got ${response["id"]}.
     "); | 
| 183     } | 183     } | 
| 184   } | 184   } | 
| 185 } | 185 } | 
| 186 | 186 | 
| 187 | 187 | 
| 188 class FrameMatcher extends Command { | 188 class FrameMatcher extends Command { | 
| 189   int frameIndex; | 189   int frameIndex; | 
| 190   List<String> functionNames; | 190   List<String> functionNames; | 
| 191 | 191 | 
| 192   FrameMatcher(this.frameIndex, this.functionNames) { | 192   FrameMatcher(this.frameIndex, this.functionNames) { | 
| 193     template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}}
     ; | 193     template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}}
     ; | 
| 194   } | 194   } | 
| 195 | 195 | 
| 196   void matchResponse(Debugger debugger) { | 196   void matchResponse(Debugger debugger) { | 
| 197     super.matchResponse(debugger); | 197     super.matchResponse(debugger); | 
| 198     var msg = debugger.currentMessage; | 198     var msg = debugger.currentMessage; | 
| 199     List frames = getJsonValue(msg, "result:callFrames"); | 199     List frames = getJsonValue(msg, "result:callFrames"); | 
| 200     assert(frames != null); | 200     assert(frames != null); | 
| 201     if (debugger.scriptUrl == null) { | 201     if (debugger.scriptUrl == null) { | 
| 202       var name = frames[0]["functionName"]; | 202       var name = frames[0]["functionName"]; | 
| 203       if (name == "main") { | 203       if (name == "main") { | 
| 204         // Extract script url of debugged script. | 204         // Extract script url of debugged script. | 
| 205         debugger.scriptUrl = frames[0]["location"]["url"]; | 205         debugger.scriptUrl = frames[0]["location"]["url"]; | 
| 206         assert(debugger.scriptUrl != null); | 206         assert(debugger.scriptUrl != null); | 
| 207       } | 207       } | 
| 208     } | 208     } | 
| 209     if (frames.length < functionNames.length) { | 209     if (frames.length < functionNames.length) { | 
| 210       debugger.error("stack trace not long enough " | 210       debugger.error("Error: stack trace not long enough " | 
| 211                      "to match ${functionNames.length} frames"); | 211                      "to match ${functionNames.length} frames"); | 
| 212       return; | 212       return; | 
| 213     } | 213     } | 
| 214     for (int i = 0; i < functionNames.length; i++) { | 214     for (int i = 0; i < functionNames.length; i++) { | 
| 215       var idx = i + frameIndex; | 215       var idx = i + frameIndex; | 
| 216       var name = frames[idx]["functionName"]; | 216       var name = frames[idx]["functionName"]; | 
| 217       assert(name != null); | 217       assert(name != null); | 
| 218       if (name != functionNames[i]) { | 218       if (name != functionNames[i]) { | 
| 219         debugger.error("call frame $idx: " | 219         debugger.error("Error: call frame $idx: " | 
| 220           "expected function name '${functionNames[i]}' but found '$name'"); | 220           "expected function name '${functionNames[i]}' but found '$name'"); | 
| 221         return; | 221         return; | 
| 222       } | 222       } | 
| 223     } | 223     } | 
| 224   } | 224   } | 
| 225 } | 225 } | 
| 226 | 226 | 
| 227 | 227 | 
| 228 MatchFrame(int frameIndex, String functionName) { | 228 MatchFrame(int frameIndex, String functionName) { | 
| 229   return new FrameMatcher(frameIndex, [ functionName ]); | 229   return new FrameMatcher(frameIndex, [ functionName ]); | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 298   // Debug target process properties. | 298   // Debug target process properties. | 
| 299   Process targetProcess; | 299   Process targetProcess; | 
| 300   int portNumber; | 300   int portNumber; | 
| 301   Socket socket; | 301   Socket socket; | 
| 302   JsonBuffer responses = new JsonBuffer(); | 302   JsonBuffer responses = new JsonBuffer(); | 
| 303 | 303 | 
| 304   DebugScript script; | 304   DebugScript script; | 
| 305   int seqNr = 0;  // Sequence number of next debugger command message. | 305   int seqNr = 0;  // Sequence number of next debugger command message. | 
| 306   Command lastCommand = null;  // Most recent command sent to target. | 306   Command lastCommand = null;  // Most recent command sent to target. | 
| 307   List<String> errors = new List(); | 307   List<String> errors = new List(); | 
|  | 308   bool cleanupDone = false; | 
| 308 | 309 | 
| 309   // Data collected from debug target. | 310   // Data collected from debug target. | 
| 310   Map currentMessage = null;  // Currently handled message sent by target. | 311   Map currentMessage = null;  // Currently handled message sent by target. | 
| 311   String scriptUrl = null; | 312   String scriptUrl = null; | 
| 312   bool shutdownEventSeen = false; | 313   bool shutdownEventSeen = false; | 
| 313   int isolateId = 0; | 314   int isolateId = 0; | 
| 314   bool isPaused = false; | 315   bool isPaused = false; | 
| 315 | 316 | 
| 316   Debugger(this.targetProcess, this.portNumber, this.script) { | 317   Debugger(this.targetProcess, this.portNumber, this.script) { | 
| 317     stdin.listen((_) {}); | 318     stdin.listen((_) {}); | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 337   void handleEvent(Map<String,dynamic> msg) { | 338   void handleEvent(Map<String,dynamic> msg) { | 
| 338     if (msg["event"] == "isolate") { | 339     if (msg["event"] == "isolate") { | 
| 339       if (msg["params"]["reason"] == "created") { | 340       if (msg["params"]["reason"] == "created") { | 
| 340         isolateId = msg["params"]["id"]; | 341         isolateId = msg["params"]["id"]; | 
| 341         assert(isolateId != null); | 342         assert(isolateId != null); | 
| 342         print("Debuggee isolate id $isolateId created."); | 343         print("Debuggee isolate id $isolateId created."); | 
| 343       } else if (msg["params"]["reason"] == "shutdown") { | 344       } else if (msg["params"]["reason"] == "shutdown") { | 
| 344         print("Debuggee isolate id ${msg["params"]["id"]} shut down."); | 345         print("Debuggee isolate id ${msg["params"]["id"]} shut down."); | 
| 345         shutdownEventSeen = true; | 346         shutdownEventSeen = true; | 
| 346         if (!script.isEmpty) { | 347         if (!script.isEmpty) { | 
| 347           error("Premature isolate shutdown event seen."); | 348           error("Error: premature isolate shutdown event seen."); | 
| 348         } | 349         } | 
| 349       } | 350       } | 
| 350     } else if (msg["event"] == "breakpointResolved") { | 351     } else if (msg["event"] == "breakpointResolved") { | 
| 351       var bpId = msg["params"]["breakpointId"]; | 352       var bpId = msg["params"]["breakpointId"]; | 
| 352       assert(bpId != null); | 353       assert(bpId != null); | 
| 353       var isolateId = msg["params"]["isolateId"]; | 354       var isolateId = msg["params"]["isolateId"]; | 
| 354       assert(isolateId != null); | 355       assert(isolateId != null); | 
| 355       var location = msg["params"]["location"]; | 356       var location = msg["params"]["location"]; | 
| 356       assert(location != null); | 357       assert(location != null); | 
| 357       print("Isolate $isolateId: breakpoint $bpId resolved" | 358       print("Isolate $isolateId: breakpoint $bpId resolved" | 
| 358             " at location $location"); | 359             " at location $location"); | 
| 359       // We may want to maintain a table of breakpoints in the future. | 360       // We may want to maintain a table of breakpoints in the future. | 
| 360     } else if (msg["event"] == "paused") { | 361     } else if (msg["event"] == "paused") { | 
| 361       isPaused = true; | 362       isPaused = true; | 
| 362     } else { | 363     } else { | 
| 363       error("unknown debugger event received"); | 364       error("Error: unknown debugger event received"); | 
| 364     } | 365     } | 
| 365   } | 366   } | 
| 366 | 367 | 
| 367   // Handle one JSON message object and match it to the | 368   // Handle one JSON message object and match it to the | 
| 368   // expected events and responses in the debugging script. | 369   // expected events and responses in the debugging script. | 
| 369   void handleMessage(Map<String,dynamic> receivedMsg) { | 370   void handleMessage(Map<String,dynamic> receivedMsg) { | 
| 370     currentMessage = receivedMsg; | 371     currentMessage = receivedMsg; | 
| 371     if (receivedMsg["event"] != null) { | 372     if (receivedMsg["event"] != null) { | 
| 372       handleEvent(receivedMsg); | 373       handleEvent(receivedMsg); | 
| 373       if (errorsDetected) { | 374       if (errorsDetected) { | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
| 402   // Handle data received over the wire from the debug target | 403   // Handle data received over the wire from the debug target | 
| 403   // process. Split input from JSON wire format into individual | 404   // process. Split input from JSON wire format into individual | 
| 404   // message objects (maps). | 405   // message objects (maps). | 
| 405   void handleMessages() { | 406   void handleMessages() { | 
| 406     var msg = responses.getNextMessage(); | 407     var msg = responses.getNextMessage(); | 
| 407     while (msg != null) { | 408     while (msg != null) { | 
| 408       if (verboseWire) print("RECV: $msg"); | 409       if (verboseWire) print("RECV: $msg"); | 
| 409       if (responses.haveGarbage()) { | 410       if (responses.haveGarbage()) { | 
| 410         error("Error: leftover text after message: '${responses.buffer}'"); | 411         error("Error: leftover text after message: '${responses.buffer}'"); | 
| 411         error("Previous message may be malformed, was: '$msg'"); | 412         error("Previous message may be malformed, was: '$msg'"); | 
| 412         close(killDebugee: true); | 413         cleanup(); | 
| 413         return; | 414         return; | 
| 414       } | 415       } | 
| 415       var msgObj = JSON.parse(msg); | 416       var msgObj = JSON.parse(msg); | 
| 416       handleMessage(msgObj); | 417       handleMessage(msgObj); | 
| 417       if (errorsDetected) { | 418       if (errorsDetected) { | 
| 418         error("Error while handling script entry"); | 419         error("Error while handling script entry"); | 
| 419         error("Message received from debug target: $msg"); | 420         error("Message received from debug target: $msg"); | 
| 420         close(killDebugee: true); | 421         cleanup(); | 
| 421         return; | 422         return; | 
| 422       } | 423       } | 
| 423       if (shutdownEventSeen) { | 424       if (shutdownEventSeen) { | 
| 424         close(); | 425         cleanup(); | 
| 425         return; | 426         return; | 
| 426       } | 427       } | 
| 427       if (isPaused) sendNextCommand(); | 428       if (isPaused) sendNextCommand(); | 
| 428       msg = responses.getNextMessage(); | 429       msg = responses.getNextMessage(); | 
| 429     } | 430     } | 
| 430   } | 431   } | 
| 431 | 432 | 
| 432   runScript(List entries) { | 433   runScript(List entries) { | 
| 433     script = new DebugScript(entries); | 434     script = new DebugScript(entries); | 
| 434     openConnection(); | 435     openConnection(); | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 457   void openConnection() { | 458   void openConnection() { | 
| 458     Socket.connect("127.0.0.1", portNumber).then((s) { | 459     Socket.connect("127.0.0.1", portNumber).then((s) { | 
| 459         this.socket = s; | 460         this.socket = s; | 
| 460         var stringStream = socket.transform(new StringDecoder()); | 461         var stringStream = socket.transform(new StringDecoder()); | 
| 461         stringStream.listen((str) { | 462         stringStream.listen((str) { | 
| 462             try { | 463             try { | 
| 463               responses.append(str); | 464               responses.append(str); | 
| 464               handleMessages(); | 465               handleMessages(); | 
| 465             } catch(e, trace) { | 466             } catch(e, trace) { | 
| 466               print("Unexpected exception:\n$e\n$trace"); | 467               print("Unexpected exception:\n$e\n$trace"); | 
| 467               close(killDebugee: true); | 468               cleanup(); | 
| 468             } | 469             } | 
| 469           }, | 470           }, | 
| 470           onDone: () { | 471           onDone: () { | 
| 471             print("Connection closed by debug target"); | 472             print("Connection closed by debug target"); | 
| 472             close(killDebugee: true); | 473             cleanup(); | 
| 473           }, | 474           }, | 
| 474           onError: (e) { | 475           onError: (e) { | 
| 475             print("Error '$e' detected in input stream from debug target"); | 476             print("Error '$e' detected in input stream from debug target"); | 
| 476             var trace = getAttachedStackTrace(e); | 477             var trace = getAttachedStackTrace(e); | 
| 477             if (trace != null) print("StackTrace: $trace"); | 478             if (trace != null) print("StackTrace: $trace"); | 
| 478             close(killDebugee: true); | 479             cleanup(); | 
| 479           }); | 480           }); | 
| 480       }, | 481       }, | 
| 481       onError: (e) { | 482       onError: (e) { | 
| 482         String msg = "Error while connecting to debugee: $e"; | 483         String msg = "Error while connecting to debugee: $e"; | 
| 483         var trace = getAttachedStackTrace(e); | 484         var trace = getAttachedStackTrace(e); | 
| 484         if (trace != null) msg += "\nStackTrace: $trace"; | 485         if (trace != null) msg += "\nStackTrace: $trace"; | 
| 485         error(msg); | 486         error(msg); | 
| 486         close(killDebugee: true); | 487         cleanup(); | 
| 487       }); | 488       }); | 
| 488   } | 489   } | 
| 489 | 490 | 
| 490   void close({killDebugee: false}) { | 491   void cleanup() { | 
| 491     void printErrorsAndExit() { | 492     if (cleanupDone) return; | 
| 492       if (errorsDetected) throw "Errors detected"; |  | 
| 493       exit(errors.length); |  | 
| 494     } |  | 
| 495     if (errorsDetected) { |  | 
| 496       for (int i = 0; i < errors.length; i++) print(errors[i]); |  | 
| 497     } |  | 
| 498     if (socket != null) { | 493     if (socket != null) { | 
| 499       socket.close().catchError((error) { | 494       socket.close().catchError((error) { | 
| 500         print("Error occured while closing socket: $error"); | 495         // Print this directly in addition to adding it to the | 
|  | 496         // error message queue, in case the error message queue | 
|  | 497         // gets printed before this error handler is called. | 
|  | 498         print("Error occurred while closing socket: $error"); | 
|  | 499         error("Error while closing socket: $error"); | 
| 501       }); | 500       }); | 
| 502     } | 501     } | 
| 503     if (killDebugee) { | 502     targetProcess.kill(); | 
| 504       if (!targetProcess.kill()) { | 503     // If the process was already dead exitCode is already | 
| 505         print("Could not send kill signal to target process."); | 504     // available and we call exit() in the next event loop cycle. | 
| 506       } else { | 505     // Otherwise this will wait for the process to exit. | 
| 507         print("Successfully sent kill signal to target process."); | 506     targetProcess.exitCode.then((exitCode) { | 
|  | 507       if (errorsDetected) { | 
|  | 508         print("\n===== Errors detected: ====="); | 
|  | 509         for (int i = 0; i < errors.length; i++) print(errors[i]); | 
|  | 510         print("============================\n"); | 
| 508       } | 511       } | 
| 509       // If the process was already dead exitCode is already | 512       exit(errors.length); | 
| 510       // available and we call exit() in the next event loop cycle. | 513     }); | 
| 511       // Otherwise this will wait for the process to exit. | 514     cleanupDone = true; | 
| 512       targetProcess.exitCode.then((exitCode) { |  | 
| 513         printErrorsAndExit(); |  | 
| 514       }); |  | 
| 515     } else { |  | 
| 516       printErrorsAndExit(); |  | 
| 517     } |  | 
| 518   } | 515   } | 
| 519 } | 516 } | 
| 520 | 517 | 
| 521 | 518 | 
| 522 bool RunScript(List script) { | 519 bool RunScript(List script) { | 
| 523   var options = new Options(); | 520   var options = new Options(); | 
| 524   if (options.arguments.contains("--debuggee")) { | 521   if (options.arguments.contains("--debuggee")) { | 
| 525     return false; | 522     return false; | 
| 526   } | 523   } | 
| 527   verboseWire = options.arguments.contains("--wire"); | 524   verboseWire = options.arguments.contains("--wire"); | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 558         var trace = getAttachedStackTrace(e); | 555         var trace = getAttachedStackTrace(e); | 
| 559         if (trace != null) print("StackTrace: $trace"); | 556         if (trace != null) print("StackTrace: $trace"); | 
| 560         return -1; | 557         return -1; | 
| 561       } else { | 558       } else { | 
| 562         // Retry with another random port. | 559         // Retry with another random port. | 
| 563         RunScript(script); | 560         RunScript(script); | 
| 564       } | 561       } | 
| 565     }); | 562     }); | 
| 566   return true; | 563   return true; | 
| 567 } | 564 } | 
| OLD | NEW | 
|---|