Chromium Code Reviews| 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"; |
| 11 import "dart:math"; | 11 import "dart:math"; |
| 12 import "dart:utf"; | 12 import "dart:utf"; |
| 13 import "dart:json" as JSON; | 13 import "dart:json" as JSON; |
| 14 | 14 |
| 15 // Whether or not to print the debugger wire messages on the console. | 15 // Whether or not to print the debugger wire messages on the console. |
| 16 var verboseWire = false; | 16 var verboseWire = false; |
| 17 | 17 |
| 18 // The number of attempts made to find an unused debugger port. | |
| 19 var retries = 0; | |
| 20 | |
| 21 // Class to buffer wire protocol data from debug target and | 18 // Class to buffer wire protocol data from debug target and |
| 22 // break it down to individual json messages. | 19 // break it down to individual json messages. |
| 23 class JsonBuffer { | 20 class JsonBuffer { |
| 24 String buffer = null; | 21 String buffer = null; |
| 25 | 22 |
| 26 append(String s) { | 23 append(String s) { |
| 27 if (buffer == null || buffer.length == 0) { | 24 if (buffer == null || buffer.length == 0) { |
| 28 buffer = s; | 25 buffer = s; |
| 29 } else { | 26 } else { |
| 30 buffer += s; | 27 buffer += s; |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 bool get isEmpty => entries.isEmpty; | 287 bool get isEmpty => entries.isEmpty; |
| 291 get currentEntry => entries.last; | 288 get currentEntry => entries.last; |
| 292 advance() => entries.removeLast(); | 289 advance() => entries.removeLast(); |
| 293 add(entry) => entries.add(entry); | 290 add(entry) => entries.add(entry); |
| 294 } | 291 } |
| 295 | 292 |
| 296 | 293 |
| 297 class Debugger { | 294 class Debugger { |
| 298 // Debug target process properties. | 295 // Debug target process properties. |
| 299 Process targetProcess; | 296 Process targetProcess; |
| 300 int portNumber; | |
| 301 Socket socket; | 297 Socket socket; |
| 302 JsonBuffer responses = new JsonBuffer(); | 298 JsonBuffer responses = new JsonBuffer(); |
| 303 | 299 |
| 304 DebugScript script; | 300 DebugScript script; |
| 305 int seqNr = 0; // Sequence number of next debugger command message. | 301 int seqNr = 0; // Sequence number of next debugger command message. |
| 306 Command lastCommand = null; // Most recent command sent to target. | 302 Command lastCommand = null; // Most recent command sent to target. |
| 307 List<String> errors = new List(); | 303 List<String> errors = new List(); |
| 308 bool cleanupDone = false; | 304 bool cleanupDone = false; |
| 309 | 305 |
| 310 // Data collected from debug target. | 306 // Data collected from debug target. |
| 311 Map currentMessage = null; // Currently handled message sent by target. | 307 Map currentMessage = null; // Currently handled message sent by target. |
| 312 String scriptUrl = null; | 308 String scriptUrl = null; |
| 313 bool shutdownEventSeen = false; | 309 bool shutdownEventSeen = false; |
| 314 int isolateId = 0; | 310 int isolateId = 0; |
| 315 bool isPaused = false; | 311 bool isPaused = false; |
| 316 | 312 |
| 317 Debugger(this.targetProcess, this.portNumber, this.script) { | 313 Debugger(this.targetProcess, this.script) { |
| 318 stdin.listen((_) {}); | 314 stdin.listen((_) {}); |
|
Ivan Posva
2013/05/23 02:06:11
Why is this stdin even needed? This is the stdin o
kustermann
2013/05/23 07:22:32
Correct, this should not be necessary.
When have h
hausner
2013/05/23 17:41:40
Removed this line.
On 2013/05/23 07:22:32, kuster
| |
| 319 var stdoutStringStream = targetProcess.stdout | 315 var stdoutStringStream = targetProcess.stdout |
| 320 .transform(new StringDecoder()) | 316 .transform(new StringDecoder()) |
| 321 .transform(new LineTransformer()); | 317 .transform(new LineTransformer()); |
| 322 stdoutStringStream.listen((line) { | 318 stdoutStringStream.listen((line) { |
| 323 if (line == "Debugger initialized") { | 319 print("TARG: $line"); |
| 324 openConnection(); | 320 if (line.startsWith("Debugger listening")) { |
| 321 RegExp portExpr = new RegExp(r"\d+"); | |
| 322 var port = portExpr.stringMatch(line); | |
| 323 print("Debug target found listening at port '$port'"); | |
| 324 openConnection(int.parse(port)); | |
| 325 } | 325 } |
| 326 print("TARG: $line"); | |
| 327 }); | 326 }); |
| 328 | 327 |
| 329 var stderrStringStream = targetProcess.stderr | 328 var stderrStringStream = targetProcess.stderr |
| 330 .transform(new StringDecoder()) | 329 .transform(new StringDecoder()) |
| 331 .transform(new LineTransformer()); | 330 .transform(new LineTransformer()); |
| 332 stderrStringStream.listen((line) { | 331 stderrStringStream.listen((line) { |
| 333 print("TARG: $line"); | 332 print("TARG: $line"); |
| 334 }); | 333 }); |
| 335 } | 334 } |
| 336 | 335 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 socket.write(jsonMsg); | 447 socket.write(jsonMsg); |
| 449 } | 448 } |
| 450 | 449 |
| 451 bool get errorsDetected => errors.length > 0; | 450 bool get errorsDetected => errors.length > 0; |
| 452 | 451 |
| 453 // Record error message. | 452 // Record error message. |
| 454 void error(String s) { | 453 void error(String s) { |
| 455 errors.add(s); | 454 errors.add(s); |
| 456 } | 455 } |
| 457 | 456 |
| 458 void openConnection() { | 457 void openConnection(int portNumber) { |
| 459 Socket.connect("127.0.0.1", portNumber).then((s) { | 458 Socket.connect("127.0.0.1", portNumber).then((s) { |
| 460 this.socket = s; | 459 this.socket = s; |
| 461 var stringStream = socket.transform(new StringDecoder()); | 460 var stringStream = socket.transform(new StringDecoder()); |
| 462 stringStream.listen((str) { | 461 stringStream.listen((str) { |
| 463 try { | 462 try { |
| 464 responses.append(str); | 463 responses.append(str); |
| 465 handleMessages(); | 464 handleMessages(); |
| 466 } catch(e, trace) { | 465 } catch(e, trace) { |
| 467 print("Unexpected exception:\n$e\n$trace"); | 466 print("Unexpected exception:\n$e\n$trace"); |
| 468 cleanup(); | 467 cleanup(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 492 if (cleanupDone) return; | 491 if (cleanupDone) return; |
| 493 if (socket != null) { | 492 if (socket != null) { |
| 494 socket.close().catchError((error) { | 493 socket.close().catchError((error) { |
| 495 // Print this directly in addition to adding it to the | 494 // Print this directly in addition to adding it to the |
| 496 // error message queue, in case the error message queue | 495 // error message queue, in case the error message queue |
| 497 // gets printed before this error handler is called. | 496 // gets printed before this error handler is called. |
| 498 print("Error occurred while closing socket: $error"); | 497 print("Error occurred while closing socket: $error"); |
| 499 error("Error while closing socket: $error"); | 498 error("Error while closing socket: $error"); |
| 500 }); | 499 }); |
| 501 } | 500 } |
| 501 var targetPid = targetProcess.pid; | |
| 502 print("Sending kill signal to process $targetPid..."); | |
| 502 targetProcess.kill(); | 503 targetProcess.kill(); |
| 503 // If the process was already dead exitCode is already | 504 // If the process was already dead exitCode is already |
| 504 // available and we call exit() in the next event loop cycle. | 505 // available and we call exit() in the next event loop cycle. |
| 505 // Otherwise this will wait for the process to exit. | 506 // Otherwise this will wait for the process to exit. |
| 506 targetProcess.exitCode.then((exitCode) { | 507 targetProcess.exitCode.then((exitCode) { |
| 508 print("process $targetPid terminated with exit code $exitCode."); | |
| 507 if (errorsDetected) { | 509 if (errorsDetected) { |
| 508 print("\n===== Errors detected: ====="); | 510 print("\n===== Errors detected: ====="); |
| 509 for (int i = 0; i < errors.length; i++) print(errors[i]); | 511 for (int i = 0; i < errors.length; i++) print(errors[i]); |
| 510 print("============================\n"); | 512 print("============================\n"); |
| 511 } | 513 } |
| 512 exit(errors.length); | 514 exit(errors.length); |
| 513 }); | 515 }); |
| 514 cleanupDone = true; | 516 cleanupDone = true; |
| 515 } | 517 } |
| 516 } | 518 } |
| 517 | 519 |
| 518 | 520 |
| 519 bool RunScript(List script) { | 521 bool RunScript(List script) { |
| 520 var options = new Options(); | 522 var options = new Options(); |
| 521 if (options.arguments.contains("--debuggee")) { | 523 if (options.arguments.contains("--debuggee")) { |
| 522 return false; | 524 return false; |
| 523 } | 525 } |
| 524 verboseWire = options.arguments.contains("--wire"); | 526 verboseWire = options.arguments.contains("--wire"); |
| 525 | 527 |
| 526 // Pick a port in the upper half of the port number range. | 528 // Port number 0 means debug target picks a free port dynamically. |
| 527 var seed = new DateTime.now().millisecondsSinceEpoch; | 529 var targetOpts = [ "--debug:0" ]; |
| 528 Random random = new Random(seed); | 530 targetOpts.add(options.script); |
| 529 var debugPort = random.nextInt(32000) + 32000; | 531 targetOpts.add("--debuggee"); |
| 530 print('using debug port $debugPort ...'); | 532 print('args: ${targetOpts.join(" ")}'); |
| 531 ServerSocket.bind('127.0.0.1', debugPort).then((ServerSocket s) { | |
| 532 s.close(); | |
| 533 var targetOpts = [ "--debug:$debugPort" ]; | |
| 534 // --verbose_debug is necessary so the test knows when the debuggee | |
| 535 // is initialized. | |
| 536 targetOpts.add("--verbose_debug"); | |
| 537 targetOpts.add(options.script); | |
| 538 targetOpts.add("--debuggee"); | |
| 539 print('args: ${targetOpts.join(" ")}'); | |
| 540 | 533 |
| 541 Process.start(options.executable, targetOpts).then((Process process) { | 534 Process.start(options.executable, targetOpts).then((Process process) { |
| 542 print("Debug target process started"); | 535 print("Debug target process started, pid ${process.pid}."); |
| 543 process.stdin.close(); | 536 process.stdin.close(); |
| 544 process.exitCode.then((int exitCode) { | 537 var debugger = new Debugger(process, new DebugScript(script)); |
| 545 if (exitCode != 0) throw "bad exit code: $exitCode"; | 538 }); |
| 546 print("Debug target process exited with exit code $exitCode"); | |
| 547 }); | |
| 548 var debugger = | |
| 549 new Debugger(process, debugPort, new DebugScript(script)); | |
| 550 }); | |
| 551 }, | |
| 552 onError: (e) { | |
| 553 if (++retries >= 3) { | |
| 554 print('unable to find unused port: $e'); | |
| 555 var trace = getAttachedStackTrace(e); | |
| 556 if (trace != null) print("StackTrace: $trace"); | |
| 557 return -1; | |
| 558 } else { | |
| 559 // Retry with another random port. | |
| 560 RunScript(script); | |
| 561 } | |
| 562 }); | |
| 563 return true; | 539 return true; |
| 564 } | 540 } |
| OLD | NEW |