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 // This test forks a second vm process that runs a dart script as | 5 // This test forks a second vm process that runs a dart script as |
| 6 // a debug target, single stepping through the entire program, and | 6 // a debug target, single stepping through the entire program, and |
| 7 // recording each breakpoint. At the end, a coverage map of the source | 7 // recording each breakpoint. At the end, a coverage map of the source |
| 8 // is printed. | 8 // is printed. |
| 9 // | 9 // |
| 10 // Usage: dart coverage.dart [--wire] [--verbose] target_script.dart | 10 // Usage: dart coverage.dart [--wire] [--verbose] target_script.dart |
| 11 // | 11 // |
| 12 // --wire see json messages sent between the processes. | 12 // --wire see json messages sent between the processes. |
| 13 // --verbose see the stdout and stderr output of the debug | 13 // --verbose see the stdout and stderr output of the debug |
| 14 // target process. | 14 // target process. |
| 15 | 15 |
| 16 import "dart:io"; | 16 import "dart:io"; |
| 17 import "dart:utf"; | 17 import "dart:utf"; |
| 18 import "dart:json" as JSON; | 18 import "dart:json" as JSON; |
| 19 | 19 |
| 20 | 20 |
| 21 // Whether or not to print debug target process on the console. | 21 // Whether or not to print debug target process on the console. |
| 22 var showDebuggeeOutput = false; | 22 var showDebuggeeOutput = false; |
| 23 | 23 |
| 24 // Whether or not to print the debugger wire messages on the console. | 24 // Whether or not to print the debugger wire messages on the console. |
| 25 var verboseWire = false; | 25 var verboseWire = false; |
| 26 | 26 |
| 27 var debugger = null; | |
| 27 | 28 |
| 28 class Program { | 29 class Program { |
| 29 static int numBps = 0; | 30 static int numBps = 0; |
| 30 | 31 |
| 31 // Maps source code url to source. | 32 // Maps source code url to source. |
| 32 static var sources = new Map<String, Source>(); | 33 static var sources = new Map<String, Source>(); |
| 33 | 34 |
| 34 // Takes a JSON Debugger response and increments the count for | 35 // Takes a JSON Debugger response and increments the count for |
| 35 // the source position. | 36 // the source position. |
| 36 static void recordBp(Debugger debugger, Map<String,dynamic> msg) { | 37 static void recordBp(Map<String,dynamic> msg) { |
| 37 // Progress indicator. | 38 // Progress indicator. |
| 38 if (++numBps % 1000 == 0) print(numBps); | 39 if (++numBps % 1000 == 0) print(numBps); |
| 39 var location = msg["params"]["location"]; | 40 var location = msg["params"]["location"]; |
| 40 if (location == null) return; | 41 if (location == null) return; |
| 41 String url = location["url"]; | 42 String url = location["url"]; |
| 42 assert(url != null); | 43 assert(url != null); |
| 44 int libId = location["libraryId"]; | |
| 45 assert(libId != null); | |
| 43 int tokenPos = location["tokenOffset"];; | 46 int tokenPos = location["tokenOffset"];; |
| 44 Source s = sources[url]; | 47 Source s = sources[url]; |
| 45 if (s == null) { | 48 if (s == null) { |
| 46 debugger.GetLineNumberTable(url); | 49 debugger.getLineNumberTable(url, libId); |
| 47 s = new Source(url); | 50 s = new Source(url); |
| 48 sources[url] = s; | 51 sources[url] = s; |
| 49 } | 52 } |
| 50 s.recordBp(tokenPos); | 53 s.recordBp(tokenPos); |
| 51 } | 54 } |
| 52 | 55 |
| 53 // Prints the annotated source code. | 56 // Prints the annotated source code. |
| 54 static void printCoverage() { | 57 static void printCoverage() { |
| 55 print("Coverage info collected from $numBps breakpoints:"); | 58 print("Coverage info collected from $numBps breakpoints:"); |
| 56 for(Source s in sources.values) s.printCoverage(); | 59 for(Source s in sources.values) s.printCoverage(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 | 142 |
| 140 void handleResponse(Map response) { | 143 void handleResponse(Map response) { |
| 141 var url = msg["params"]["url"]; | 144 var url = msg["params"]["url"]; |
| 142 Source s = Program.sources[url]; | 145 Source s = Program.sources[url]; |
| 143 assert(s != null); | 146 assert(s != null); |
| 144 s.SetLineInfo(response["result"]["lines"]); | 147 s.SetLineInfo(response["result"]["lines"]); |
| 145 } | 148 } |
| 146 } | 149 } |
| 147 | 150 |
| 148 | 151 |
| 152 class GetLibrariesCmd { | |
| 153 Map msg; | |
| 154 GetLibrariesCmd(int isolateId) { | |
| 155 msg = { "id": 0, | |
| 156 "command": "getLibraries", | |
| 157 "params": { "isolateId" : isolateId } }; | |
| 158 } | |
| 159 | |
| 160 void handleResponse(Map response) { | |
| 161 List libs = response["result"]["libraries"]; | |
| 162 for (var lib in libs) { | |
| 163 String url = lib["url"]; | |
| 164 int libraryId = lib["id"]; | |
| 165 bool enable = !url.startsWith("dart:") && !url.startsWith("package:"); | |
| 166 if (enable) { | |
| 167 print("Enable stepping for '$url'"); | |
|
srdjan
2013/07/18 18:51:12
Is that a debugging print?
hausner
2013/07/18 19:00:26
I thought it might be a helpful indicator on what
| |
| 168 debugger.enableDebugging(libraryId, true); | |
| 169 } | |
| 170 } | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 | |
| 175 class SetLibraryPropertiesCmd { | |
| 176 Map msg; | |
| 177 SetLibraryPropertiesCmd(int isolateId, int libraryId, bool enableDebugging) { | |
| 178 msg = { "id": 0, | |
| 179 "command": "setLibraryProperties", | |
| 180 "params": { "isolateId" : isolateId, | |
| 181 "libraryId": libraryId, | |
| 182 "debuggingEnabled": "$enableDebugging" } }; | |
| 183 } | |
| 184 | |
| 185 void handleResponse(Map response) { | |
| 186 // Nothing to do. | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 | |
| 149 class Debugger { | 191 class Debugger { |
| 150 // Debug target process properties. | 192 // Debug target process properties. |
| 151 Process targetProcess; | 193 Process targetProcess; |
| 152 Socket socket; | 194 Socket socket; |
| 153 bool cleanupDone = false; | 195 bool cleanupDone = false; |
| 154 JsonBuffer responses = new JsonBuffer(); | 196 JsonBuffer responses = new JsonBuffer(); |
| 155 List<String> errors = new List(); | 197 List<String> errors = new List(); |
| 156 | 198 |
| 157 // Data collected from debug target. | 199 // Data collected from debug target. |
| 158 Map currentMessage = null; // Currently handled message sent by target. | 200 Map currentMessage = null; // Currently handled message sent by target. |
| 159 var outstandingCommand = null; | 201 var outstandingCommand = null; |
| 160 var queuedCommand = null; | 202 var queuedCommands = new List(); |
| 161 String scriptUrl = null; | 203 String scriptUrl = null; |
| 162 bool shutdownEventSeen = false; | 204 bool shutdownEventSeen = false; |
| 163 int isolateId = 0; | 205 int isolateId = 0; |
| 164 int libraryId = null; | 206 int libraryId = null; |
| 165 | 207 |
| 166 int nextMessageId = 0; | 208 int nextMessageId = 0; |
| 167 bool isPaused = false; | 209 bool isPaused = false; |
| 168 bool pendingAck = false; | 210 bool pendingAck = false; |
| 169 | 211 |
| 170 Debugger(this.targetProcess) { | 212 Debugger(this.targetProcess) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 var location = msg["params"]["location"]; | 256 var location = msg["params"]["location"]; |
| 215 assert(location != null); | 257 assert(location != null); |
| 216 print("Isolate $isolateId: breakpoint $bpId resolved" | 258 print("Isolate $isolateId: breakpoint $bpId resolved" |
| 217 " at location $location"); | 259 " at location $location"); |
| 218 // We may want to maintain a table of breakpoints in the future. | 260 // We may want to maintain a table of breakpoints in the future. |
| 219 } else if (msg["event"] == "paused") { | 261 } else if (msg["event"] == "paused") { |
| 220 isPaused = true; | 262 isPaused = true; |
| 221 if (libraryId == null) { | 263 if (libraryId == null) { |
| 222 libraryId = msg["params"]["location"]["libraryId"]; | 264 libraryId = msg["params"]["location"]["libraryId"]; |
| 223 assert(libraryId != null); | 265 assert(libraryId != null); |
| 266 // This is the first paused event we got. Get all libraries from | |
| 267 // the debugger so we can turn on debugging events for them. | |
| 268 getLibraries(); | |
| 224 } | 269 } |
| 225 if (msg["params"]["reason"] == "breakpoint") { | 270 if (msg["params"]["reason"] == "breakpoint") { |
| 226 Program.recordBp(this, msg); | 271 Program.recordBp(msg); |
| 227 } | 272 } |
| 228 } else { | 273 } else { |
| 229 error("Error: unknown debugger event received"); | 274 error("Error: unknown debugger event received"); |
| 230 } | 275 } |
| 231 } | 276 } |
| 232 | 277 |
| 233 // Handle one JSON message object. | 278 // Handle one JSON message object. |
| 234 void handleMessage(Map<String,dynamic> receivedMsg) { | 279 void handleMessage(Map<String,dynamic> receivedMsg) { |
| 235 currentMessage = receivedMsg; | 280 currentMessage = receivedMsg; |
| 236 if (receivedMsg["event"] != null) { | 281 if (receivedMsg["event"] != null) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 return; | 318 return; |
| 274 } | 319 } |
| 275 if (shutdownEventSeen) { | 320 if (shutdownEventSeen) { |
| 276 if (outstandingCommand != null) { | 321 if (outstandingCommand != null) { |
| 277 error("Error: outstanding command when shutdown received"); | 322 error("Error: outstanding command when shutdown received"); |
| 278 } | 323 } |
| 279 cleanup(); | 324 cleanup(); |
| 280 return; | 325 return; |
| 281 } | 326 } |
| 282 if (isPaused && (outstandingCommand == null)) { | 327 if (isPaused && (outstandingCommand == null)) { |
| 283 var cmd = queuedCommand; | 328 var cmd = queuedCommands.length > 0 ? queuedCommands.removeAt(0) : null; |
| 284 queuedCommand = null; | |
| 285 if (cmd == null) { | 329 if (cmd == null) { |
| 286 cmd = new StepCmd(isolateId); | 330 cmd = new StepCmd(isolateId); |
| 287 isPaused = false; | 331 isPaused = false; |
| 288 } | 332 } |
| 289 sendMessage(cmd.msg); | 333 sendMessage(cmd.msg); |
| 290 outstandingCommand = cmd; | 334 outstandingCommand = cmd; |
| 291 } | 335 } |
| 292 msg = responses.getNextMessage(); | 336 msg = responses.getNextMessage(); |
| 293 } | 337 } |
| 294 } | 338 } |
| 295 | 339 |
| 296 // Send a debugger command to the target VM. | 340 // Send a debugger command to the target VM. |
| 297 void sendMessage(Map<String,dynamic> msg) { | 341 void sendMessage(Map<String,dynamic> msg) { |
| 298 assert(msg["id"] != null); | 342 assert(msg["id"] != null); |
| 299 msg["id"] = nextMessageId++; | 343 msg["id"] = nextMessageId++; |
| 300 String jsonMsg = JSON.stringify(msg); | 344 String jsonMsg = JSON.stringify(msg); |
| 301 if (verboseWire) print("SEND: $jsonMsg"); | 345 if (verboseWire) print("SEND: $jsonMsg"); |
| 302 socket.write(jsonMsg); | 346 socket.write(jsonMsg); |
| 303 } | 347 } |
| 304 | 348 |
| 305 void GetLineNumberTable(String url) { | 349 void getLineNumberTable(String url, int libId) { |
| 306 assert(queuedCommand == null); | 350 queuedCommands.add(new GetLineTableCmd(isolateId, libId, url)); |
| 307 queuedCommand = new GetLineTableCmd(isolateId, libraryId, url); | 351 } |
| 352 | |
| 353 void getLibraries() { | |
| 354 queuedCommands.add(new GetLibrariesCmd(isolateId)); | |
| 308 } | 355 } |
| 309 | 356 |
| 357 void enableDebugging(libraryId, enable) { | |
| 358 queuedCommands.add(new SetLibraryPropertiesCmd(isolateId, libraryId, enable) ); | |
| 359 } | |
| 360 | |
| 310 bool get errorsDetected => errors.length > 0; | 361 bool get errorsDetected => errors.length > 0; |
| 311 | 362 |
| 312 // Record error message. | 363 // Record error message. |
| 313 void error(String s) { | 364 void error(String s) { |
| 314 errors.add(s); | 365 errors.add(s); |
| 315 } | 366 } |
| 316 | 367 |
| 317 void openConnection(int portNumber) { | 368 void openConnection(int portNumber) { |
| 318 Socket.connect("127.0.0.1", portNumber).then((s) { | 369 Socket.connect("127.0.0.1", portNumber).then((s) { |
| 319 socket = s; | 370 socket = s; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 483 verboseWire = true; | 534 verboseWire = true; |
| 484 break; | 535 break; |
| 485 default: | 536 default: |
| 486 targetOpts.add(str); | 537 targetOpts.add(str); |
| 487 break; | 538 break; |
| 488 } | 539 } |
| 489 } | 540 } |
| 490 | 541 |
| 491 Process.start(options.executable, targetOpts).then((Process process) { | 542 Process.start(options.executable, targetOpts).then((Process process) { |
| 492 process.stdin.close(); | 543 process.stdin.close(); |
| 493 var debugger = new Debugger(process); | 544 debugger = new Debugger(process); |
| 494 }); | 545 }); |
| 495 } | 546 } |
| OLD | NEW |