| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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:io"; | 9 import "dart:io"; |
| 10 import "dart:utf"; | 10 import "dart:utf"; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 | 35 |
| 36 String getNextMessage() { | 36 String getNextMessage() { |
| 37 if (buffer == null) return null; | 37 if (buffer == null) return null; |
| 38 int msgLen = objectLength(); | 38 int msgLen = objectLength(); |
| 39 if (msgLen == 0) return null; | 39 if (msgLen == 0) return null; |
| 40 String msg = null; | 40 String msg = null; |
| 41 if (msgLen == buffer.length) { | 41 if (msgLen == buffer.length) { |
| 42 msg = buffer; | 42 msg = buffer; |
| 43 buffer = null; | 43 buffer = null; |
| 44 } else { | 44 } else { |
| 45 assert(msgLen < buffer.length); |
| 45 msg = buffer.substring(0, msgLen); | 46 msg = buffer.substring(0, msgLen); |
| 46 buffer = buffer.substring(msgLen); | 47 buffer = buffer.substring(msgLen); |
| 47 } | 48 } |
| 48 return msg; | 49 return msg; |
| 49 } | 50 } |
| 50 | 51 |
| 51 // Skip past a JSON object value. | 52 // Returns the character length of the newxt json message in the |
| 53 // buffer, or 0 if there is only a partial message in the buffer. |
| 52 // The object value must start with '{' and continues to the | 54 // The object value must start with '{' and continues to the |
| 53 // matching '}'. No attempt is made to otherwise validate the contents | 55 // matching '}'. No attempt is made to otherwise validate the contents |
| 54 // as JSON. If it is invalid, a later JSON.parse() will fail. | 56 // as JSON. If it is invalid, a later JSON.parse() will fail. |
| 55 int objectLength() { | 57 int objectLength() { |
| 56 int skipWhitespace(int index) { | 58 int skipWhitespace(int index) { |
| 57 while (index < buffer.length) { | 59 while (index < buffer.length) { |
| 58 String char = buffer[index]; | 60 String char = buffer[index]; |
| 59 if (char != " " && char != "\n" && char != "\r" && char != "\t") break; | 61 if (char != " " && char != "\n" && char != "\r" && char != "\t") break; |
| 60 index++; | 62 index++; |
| 61 } | 63 } |
| 62 return index; | 64 return index; |
| 63 } | 65 } |
| 64 int skipString(int index) { | 66 int skipString(int index) { |
| 65 assert(buffer[index - 1] == '"'); | 67 assert(buffer[index - 1] == '"'); |
| 66 while (index < buffer.length) { | 68 while (index < buffer.length) { |
| 67 String char = buffer[index]; | 69 String char = buffer[index]; |
| 68 if (char == '"') return index + 1; | 70 if (char == '"') return index + 1; |
| 69 if (char == r'\') index++; | 71 if (char == r'\') index++; |
| 70 if (index == buffer.length) return index; | 72 if (index == buffer.length) return index; |
| 71 index++; | 73 index++; |
| 72 } | 74 } |
| 73 return index; | 75 return index; |
| 74 } | 76 } |
| 75 int index = 0; | 77 int index = 0; |
| 76 index = skipWhitespace(index); | 78 index = skipWhitespace(index); |
| 77 // Bail out if the first non-whitespace character isn't '{'. | 79 // Bail out if the first non-whitespace character isn't '{'. |
| 78 if (index == buffer.length || buffer[index] != '{') return 0; | 80 if (index == buffer.length || buffer[index] != '{') return 0; |
| 79 int nexting = 0; | 81 int nesting = 0; |
| 80 while (index < buffer.length) { | 82 while (index < buffer.length) { |
| 81 String char = buffer[index++]; | 83 String char = buffer[index++]; |
| 82 if (char == '{') { | 84 if (char == '{') { |
| 83 nexting++; | 85 nesting++; |
| 84 } else if (char == '}') { | 86 } else if (char == '}') { |
| 85 nexting--; | 87 nesting--; |
| 86 if (nexting == 0) return index; | 88 if (nesting == 0) return index; |
| 87 } else if (char == '"') { | 89 } else if (char == '"') { |
| 88 // Strings can contain braces. Skip their content. | 90 // Strings can contain braces. Skip their content. |
| 89 index = skipString(index); | 91 index = skipString(index); |
| 90 } | 92 } |
| 91 } | 93 } |
| 92 return 0; | 94 return 0; |
| 93 } | 95 } |
| 94 } | 96 } |
| 95 | 97 |
| 96 | 98 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 107 if (bracketPos <= 0) return null; | 109 if (bracketPos <= 0) return null; |
| 108 var indexStr = property.substring(bracketPos + 1, property.length - 1); | 110 var indexStr = property.substring(bracketPos + 1, property.length - 1); |
| 109 try { | 111 try { |
| 110 index = int.parse(indexStr); | 112 index = int.parse(indexStr); |
| 111 } on FormatException { | 113 } on FormatException { |
| 112 print("$indexStr is not a valid array index"); | 114 print("$indexStr is not a valid array index"); |
| 113 return null; | 115 return null; |
| 114 } | 116 } |
| 115 property = property.substring(0, bracketPos); | 117 property = property.substring(0, bracketPos); |
| 116 } | 118 } |
| 117 » if (node is Map) { | 119 if (node is Map) { |
| 118 node = node[property]; | 120 node = node[property]; |
| 119 } else { | 121 } else { |
| 120 return null; | 122 return null; |
| 121 } | 123 } |
| 122 if (index != null) { | 124 if (index != null) { |
| 123 if (node is List && node.length > index) { | 125 if (node is List && node.length > index) { |
| 124 node = node[index]; | 126 node = node[index]; |
| 125 } else { | 127 } else { |
| 126 return null; | 128 return null; |
| 127 } | 129 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 155 class BreakpointEvent { | 157 class BreakpointEvent { |
| 156 String functionName; | 158 String functionName; |
| 157 var template = { "event": "paused", "params": { "reason": "breakpoint" }}; | 159 var template = { "event": "paused", "params": { "reason": "breakpoint" }}; |
| 158 | 160 |
| 159 BreakpointEvent({String function: null}) { | 161 BreakpointEvent({String function: null}) { |
| 160 functionName = function; | 162 functionName = function; |
| 161 } | 163 } |
| 162 | 164 |
| 163 void match(Debugger debugger) { | 165 void match(Debugger debugger) { |
| 164 var msg = debugger.currentMessage; | 166 var msg = debugger.currentMessage; |
| 165 if (!matchMaps(template, msg)) debugger.error("message does not match $templ
ate"); | 167 if (!matchMaps(template, msg)) { |
| 168 debugger.error("message does not match $template"); |
| 169 } |
| 166 var name = getJsonValue(msg, "params:callFrames[0]:functionName"); | 170 var name = getJsonValue(msg, "params:callFrames[0]:functionName"); |
| 167 if (name == "main") { | 171 if (name == "main") { |
| 168 // Extract script url of debugged script. | 172 // Extract script url of debugged script. |
| 169 var scriptUrl = getJsonValue(msg, "params:callFrames[0]:location:url"); | 173 var scriptUrl = getJsonValue(msg, "params:callFrames[0]:location:url"); |
| 170 assert(scriptUrl != null); | 174 assert(scriptUrl != null); |
| 171 debugger.scriptUrl = scriptUrl; | 175 debugger.scriptUrl = scriptUrl; |
| 172 } | 176 } |
| 173 if (functionName != null) { | 177 if (functionName != null) { |
| 174 var name = getJsonValue(msg, "params:callFrames[0]:functionName"); | 178 var name = getJsonValue(msg, "params:callFrames[0]:functionName"); |
| 175 if (functionName != name) { | 179 if (functionName != name) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 191 int frameIndex; | 195 int frameIndex; |
| 192 List<String> functionNames; | 196 List<String> functionNames; |
| 193 | 197 |
| 194 FrameMatcher(this.frameIndex, this.functionNames); | 198 FrameMatcher(this.frameIndex, this.functionNames); |
| 195 | 199 |
| 196 void match(Debugger debugger) { | 200 void match(Debugger debugger) { |
| 197 var msg = debugger.currentMessage; | 201 var msg = debugger.currentMessage; |
| 198 List frames = getJsonValue(msg, "params:callFrames"); | 202 List frames = getJsonValue(msg, "params:callFrames"); |
| 199 assert(frames != null); | 203 assert(frames != null); |
| 200 if (frames.length < functionNames.length) { | 204 if (frames.length < functionNames.length) { |
| 201 debugger.error("stack trace not long enough to match ${functionNames.lengt
h} frames"); | 205 debugger.error("stack trace not long enough " |
| 206 "to match ${functionNames.length} frames"); |
| 202 return; | 207 return; |
| 203 } | 208 } |
| 204 for (int i = 0; i < functionNames.length; i++) { | 209 for (int i = 0; i < functionNames.length; i++) { |
| 205 var idx = i + frameIndex; | 210 var idx = i + frameIndex; |
| 206 var property = "params:callFrames[$idx]:functionName"; | 211 var property = "params:callFrames[$idx]:functionName"; |
| 207 var name = getJsonValue(msg, property); | 212 var name = getJsonValue(msg, property); |
| 208 if (name == null) { | 213 if (name == null) { |
| 209 debugger.error("property '$property' not found"); | 214 debugger.error("property '$property' not found"); |
| 210 return; | 215 return; |
| 211 } | 216 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 232 var template; | 237 var template; |
| 233 Command(); | 238 Command(); |
| 234 Command.resume() { | 239 Command.resume() { |
| 235 template = {"id": 0, "command": "resume", "params": {"isolateId": 0}}; | 240 template = {"id": 0, "command": "resume", "params": {"isolateId": 0}}; |
| 236 } | 241 } |
| 237 Command.step() { | 242 Command.step() { |
| 238 template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}}; | 243 template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}}; |
| 239 } | 244 } |
| 240 Map makeMsg(int cmdId, int isolateId) { | 245 Map makeMsg(int cmdId, int isolateId) { |
| 241 template["id"] = cmdId; | 246 template["id"] = cmdId; |
| 242 if ((template["params"] != null) && (template["params"]["isolateId"] != null
)) { | 247 if ((template["params"] != null) |
| 248 && (template["params"]["isolateId"] != null)) { |
| 243 template["params"]["isolateId"] = isolateId; | 249 template["params"]["isolateId"] = isolateId; |
| 244 } | 250 } |
| 245 return template; | 251 return template; |
| 246 } | 252 } |
| 247 | 253 |
| 248 void send(Debugger debugger) { | 254 void send(Debugger debugger) { |
| 249 template["id"] = debugger.seqNr; | 255 template["id"] = debugger.seqNr; |
| 250 template["params"]["isolateId"] = debugger.isolateId; | 256 template["params"]["isolateId"] = debugger.isolateId; |
| 251 debugger.sendMessage(template); | 257 debugger.sendMessage(template); |
| 252 } | 258 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 // shutdown events, breakpoint resolution events, etc. | 347 // shutdown events, breakpoint resolution events, etc. |
| 342 bool handleImplicitEvents(Map<String,dynamic> msg) { | 348 bool handleImplicitEvents(Map<String,dynamic> msg) { |
| 343 if (msg["event"] == "isolate") { | 349 if (msg["event"] == "isolate") { |
| 344 if (msg["params"]["reason"] == "created") { | 350 if (msg["params"]["reason"] == "created") { |
| 345 isolateId = msg["params"]["id"]; | 351 isolateId = msg["params"]["id"]; |
| 346 assert(isolateId != null); | 352 assert(isolateId != null); |
| 347 print("Debuggee isolate id $isolateId created."); | 353 print("Debuggee isolate id $isolateId created."); |
| 348 } else if (msg["params"]["reason"] == "shutdown") { | 354 } else if (msg["params"]["reason"] == "shutdown") { |
| 349 print("Debuggee isolate id ${msg["params"]["id"]} shut down."); | 355 print("Debuggee isolate id ${msg["params"]["id"]} shut down."); |
| 350 shutdownEventSeen = true; | 356 shutdownEventSeen = true; |
| 357 if (script.currentEntry != null) { |
| 358 error("Premature isolate shutdown event seen."); |
| 359 } |
| 351 } | 360 } |
| 352 return true; | 361 return true; |
| 353 } else if (msg["event"] == "breakpointResolved") { | 362 } else if (msg["event"] == "breakpointResolved") { |
| 354 // Ignore the event. We may want to maintain a table of | 363 // Ignore the event. We may want to maintain a table of |
| 355 // breakpoints in the future. | 364 // breakpoints in the future. |
| 356 return true; | 365 return true; |
| 357 } | 366 } |
| 358 return false; | 367 return false; |
| 359 } | 368 } |
| 360 | 369 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 verboseWire = options.arguments.contains("--wire"); | 509 verboseWire = options.arguments.contains("--wire"); |
| 501 | 510 |
| 502 var targetOpts = [ "--debug:$debugPort" ]; | 511 var targetOpts = [ "--debug:$debugPort" ]; |
| 503 if (showDebuggeeOutput) targetOpts.add("--verbose_debug"); | 512 if (showDebuggeeOutput) targetOpts.add("--verbose_debug"); |
| 504 targetOpts.add(options.script); | 513 targetOpts.add(options.script); |
| 505 targetOpts.add("--debuggee"); | 514 targetOpts.add("--debuggee"); |
| 506 | 515 |
| 507 Process.start(options.executable, targetOpts).then((Process process) { | 516 Process.start(options.executable, targetOpts).then((Process process) { |
| 508 print("Debug target process started"); | 517 print("Debug target process started"); |
| 509 process.stdin.close(); | 518 process.stdin.close(); |
| 519 process.stdout.onData = process.stdout.read; |
| 520 process.stderr.onData = process.stderr.read; |
| 510 process.onExit = (int exitCode) { | 521 process.onExit = (int exitCode) { |
| 511 print("Debug target process exited with exit code $exitCode"); | 522 print("Debug target process exited with exit code $exitCode"); |
| 512 }; | 523 }; |
| 513 var debugger = new Debugger(process, debugPort); | 524 var debugger = new Debugger(process, debugPort); |
| 514 stdin.onClosed = () => debugger.close(); | 525 stdin.onClosed = () => debugger.close(); |
| 515 stdin.onError = (error) => debugger.close(); | 526 stdin.onError = (error) => debugger.close(); |
| 516 debugger.runScript(script); | 527 debugger.runScript(script); |
| 517 }); | 528 }); |
| 518 return true; | 529 return true; |
| 519 } | 530 } |
| OLD | NEW |