| 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 // Simple interactive debugger shell that connects to the Dart VM's debugger | 5 // Simple interactive debugger shell that connects to the Dart VM's debugger |
| 6 // connection port. | 6 // connection port. |
| 7 | 7 |
| 8 import "dart:convert"; | 8 import "dart:convert"; |
| 9 import "dart:io"; | 9 import "dart:io"; |
| 10 import "dart:async"; | 10 import "dart:async"; |
| 11 | 11 |
| 12 import "ddbg/lib/commando.dart"; |
| 13 |
| 12 | 14 |
| 13 Map<int, Completer> outstandingCommands; | 15 Map<int, Completer> outstandingCommands; |
| 14 | 16 |
| 15 Socket vmSock; | 17 Socket vmSock; |
| 16 String vmData; | 18 String vmData; |
| 17 var stdinSubscription; | 19 Commando cmdo; |
| 18 var vmSubscription; | 20 var vmSubscription; |
| 19 int seqNum = 0; | 21 int seqNum = 0; |
| 20 int isolate_id = -1; | 22 int isolate_id = -1; |
| 21 | 23 |
| 24 Process targetProcess; |
| 25 |
| 22 final verbose = false; | 26 final verbose = false; |
| 23 final printMessages = false; | 27 final printMessages = false; |
| 24 | 28 |
| 25 // The location of the last paused event. | 29 // The location of the last paused event. |
| 26 Map pausedLocation = null; | 30 Map pausedLocation = null; |
| 27 | 31 |
| 28 | 32 |
| 29 void printHelp() { | 33 void printHelp() { |
| 30 print(""" | 34 print(""" |
| 31 q Quit debugger shell | 35 q Quit debugger shell |
| (...skipping 21 matching lines...) Expand all Loading... |
| 53 li List ids of all isolates in the VM | 57 li List ids of all isolates in the VM |
| 54 i <id> Interrupt execution of given isolate id | 58 i <id> Interrupt execution of given isolate id |
| 55 h Print help | 59 h Print help |
| 56 """); | 60 """); |
| 57 } | 61 } |
| 58 | 62 |
| 59 | 63 |
| 60 void quitShell() { | 64 void quitShell() { |
| 61 vmSubscription.cancel(); | 65 vmSubscription.cancel(); |
| 62 vmSock.close(); | 66 vmSock.close(); |
| 63 stdinSubscription.cancel(); | 67 cmdo.done(); |
| 64 } | 68 } |
| 65 | 69 |
| 66 | 70 |
| 67 Future sendCmd(Map<String, dynamic> cmd) { | 71 Future sendCmd(Map<String, dynamic> cmd) { |
| 68 var completer = new Completer(); | 72 var completer = new Completer(); |
| 69 int id = cmd["id"]; | 73 int id = cmd["id"]; |
| 70 outstandingCommands[id] = completer; | 74 outstandingCommands[id] = completer; |
| 71 if (verbose) { | 75 if (verbose) { |
| 72 print("sending: '${JSON.encode(cmd)}'"); | 76 print("sending: '${JSON.encode(cmd)}'"); |
| 73 } | 77 } |
| 74 vmSock.write(JSON.encode(cmd)); | 78 vmSock.write(JSON.encode(cmd)); |
| 75 return completer.future; | 79 return completer.future; |
| 76 } | 80 } |
| 77 | 81 |
| 82 |
| 83 typedef void HandlerType(Map response); |
| 84 |
| 85 HandlerType showPromptAfter(void handler(Map response)) { |
| 86 // Hide the command prompt immediately. |
| 87 return (response) { |
| 88 handler(response); |
| 89 cmdo.show(); |
| 90 }; |
| 91 } |
| 92 |
| 93 |
| 78 void processCommand(String cmdLine) { | 94 void processCommand(String cmdLine) { |
| 79 | 95 |
| 80 void huh() { | 96 void huh() { |
| 81 print("'$cmdLine' not understood, try h for help"); | 97 print("'$cmdLine' not understood, try h for help"); |
| 82 } | 98 } |
| 83 | 99 |
| 84 seqNum++; | 100 seqNum++; |
| 101 cmdLine = cmdLine.trim(); |
| 85 var args = cmdLine.split(' '); | 102 var args = cmdLine.split(' '); |
| 86 if (args.length == 0) { | 103 if (args.length == 0) { |
| 87 return; | 104 return; |
| 88 } | 105 } |
| 89 var command = args[0]; | 106 var command = args[0]; |
| 90 var simple_commands = | 107 var simple_commands = |
| 91 { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'}; | 108 { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'}; |
| 92 if (simple_commands[command] != null) { | 109 if (simple_commands[command] != null) { |
| 93 var cmd = { "id": seqNum, | 110 var cmd = { "id": seqNum, |
| 94 "command": simple_commands[command], | 111 "command": simple_commands[command], |
| 95 "params": { "isolateId" : isolate_id } }; | 112 "params": { "isolateId" : isolate_id } }; |
| 96 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 113 cmdo.hide(); |
| 114 sendCmd(cmd).then(showPromptAfter(handleGenericResponse)); |
| 97 } else if (command == "bt") { | 115 } else if (command == "bt") { |
| 98 var cmd = { "id": seqNum, | 116 var cmd = { "id": seqNum, |
| 99 "command": "getStackTrace", | 117 "command": "getStackTrace", |
| 100 "params": { "isolateId" : isolate_id } }; | 118 "params": { "isolateId" : isolate_id } }; |
| 101 sendCmd(cmd).then((result) => handleStackTraceResponse(result)); | 119 cmdo.hide(); |
| 120 sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse)); |
| 102 } else if (command == "ll") { | 121 } else if (command == "ll") { |
| 103 var cmd = { "id": seqNum, | 122 var cmd = { "id": seqNum, |
| 104 "command": "getLibraries", | 123 "command": "getLibraries", |
| 105 "params": { "isolateId" : isolate_id } }; | 124 "params": { "isolateId" : isolate_id } }; |
| 106 sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); | 125 cmdo.hide(); |
| 126 sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse)); |
| 107 } else if (command == "sbp" && args.length >= 2) { | 127 } else if (command == "sbp" && args.length >= 2) { |
| 108 var url, line; | 128 var url, line; |
| 109 if (args.length == 2 && pausedLocation != null) { | 129 if (args.length == 2 && pausedLocation != null) { |
| 110 url = pausedLocation["url"]; | 130 url = pausedLocation["url"]; |
| 111 assert(url != null); | 131 assert(url != null); |
| 112 line = int.parse(args[1]); | 132 line = int.parse(args[1]); |
| 113 } else { | 133 } else { |
| 114 url = args[1]; | 134 url = args[1]; |
| 115 line = int.parse(args[2]); | 135 line = int.parse(args[2]); |
| 116 } | 136 } |
| 117 var cmd = { "id": seqNum, | 137 var cmd = { "id": seqNum, |
| 118 "command": "setBreakpoint", | 138 "command": "setBreakpoint", |
| 119 "params": { "isolateId" : isolate_id, | 139 "params": { "isolateId" : isolate_id, |
| 120 "url": url, | 140 "url": url, |
| 121 "line": line }}; | 141 "line": line }}; |
| 122 sendCmd(cmd).then((result) => handleSetBpResponse(result)); | 142 cmdo.hide(); |
| 143 sendCmd(cmd).then(showPromptAfter(handleSetBpResponse)); |
| 123 } else if (command == "rbp" && args.length == 2) { | 144 } else if (command == "rbp" && args.length == 2) { |
| 124 var cmd = { "id": seqNum, | 145 var cmd = { "id": seqNum, |
| 125 "command": "removeBreakpoint", | 146 "command": "removeBreakpoint", |
| 126 "params": { "isolateId" : isolate_id, | 147 "params": { "isolateId" : isolate_id, |
| 127 "breakpointId": int.parse(args[1]) } }; | 148 "breakpointId": int.parse(args[1]) } }; |
| 128 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 149 cmdo.hide(); |
| 150 sendCmd(cmd).then(showPromptAfter(handleGenericResponse)); |
| 129 } else if (command == "ls" && args.length == 2) { | 151 } else if (command == "ls" && args.length == 2) { |
| 130 var cmd = { "id": seqNum, | 152 var cmd = { "id": seqNum, |
| 131 "command": "getScriptURLs", | 153 "command": "getScriptURLs", |
| 132 "params": { "isolateId" : isolate_id, | 154 "params": { "isolateId" : isolate_id, |
| 133 "libraryId": int.parse(args[1]) } }; | 155 "libraryId": int.parse(args[1]) } }; |
| 134 sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); | 156 cmdo.hide(); |
| 157 sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse)); |
| 135 } else if (command == "eval" && args.length > 3) { | 158 } else if (command == "eval" && args.length > 3) { |
| 136 var expr = args.getRange(3, args.length).join(" "); | 159 var expr = args.getRange(3, args.length).join(" "); |
| 137 var target = args[1]; | 160 var target = args[1]; |
| 138 if (target == "obj") { | 161 if (target == "obj") { |
| 139 target = "objectId"; | 162 target = "objectId"; |
| 140 } else if (target == "cls") { | 163 } else if (target == "cls") { |
| 141 target = "classId"; | 164 target = "classId"; |
| 142 } else if (target == "lib") { | 165 } else if (target == "lib") { |
| 143 target = "libraryId"; | 166 target = "libraryId"; |
| 144 } else { | 167 } else { |
| 145 huh(); | 168 huh(); |
| 146 return; | 169 return; |
| 147 } | 170 } |
| 148 var cmd = { "id": seqNum, | 171 var cmd = { "id": seqNum, |
| 149 "command": "evaluateExpr", | 172 "command": "evaluateExpr", |
| 150 "params": { "isolateId": isolate_id, | 173 "params": { "isolateId": isolate_id, |
| 151 target: int.parse(args[2]), | 174 target: int.parse(args[2]), |
| 152 "expression": expr } }; | 175 "expression": expr } }; |
| 153 sendCmd(cmd).then((result) => handleEvalResponse(result)); | 176 cmdo.hide(); |
| 177 sendCmd(cmd).then(showPromptAfter(handleEvalResponse)); |
| 154 } else if (command == "po" && args.length == 2) { | 178 } else if (command == "po" && args.length == 2) { |
| 155 var cmd = { "id": seqNum, | 179 var cmd = { "id": seqNum, |
| 156 "command": "getObjectProperties", | 180 "command": "getObjectProperties", |
| 157 "params": { "isolateId" : isolate_id, | 181 "params": { "isolateId" : isolate_id, |
| 158 "objectId": int.parse(args[1]) } }; | 182 "objectId": int.parse(args[1]) } }; |
| 159 sendCmd(cmd).then((result) => handleGetObjPropsResponse(result)); | 183 cmdo.hide(); |
| 184 sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse)); |
| 160 } else if (command == "pl" && args.length >= 3) { | 185 } else if (command == "pl" && args.length >= 3) { |
| 161 var cmd; | 186 var cmd; |
| 162 if (args.length == 3) { | 187 if (args.length == 3) { |
| 163 cmd = { "id": seqNum, | 188 cmd = { "id": seqNum, |
| 164 "command": "getListElements", | 189 "command": "getListElements", |
| 165 "params": { "isolateId" : isolate_id, | 190 "params": { "isolateId" : isolate_id, |
| 166 "objectId": int.parse(args[1]), | 191 "objectId": int.parse(args[1]), |
| 167 "index": int.parse(args[2]) } }; | 192 "index": int.parse(args[2]) } }; |
| 168 } else { | 193 } else { |
| 169 cmd = { "id": seqNum, | 194 cmd = { "id": seqNum, |
| 170 "command": "getListElements", | 195 "command": "getListElements", |
| 171 "params": { "isolateId" : isolate_id, | 196 "params": { "isolateId" : isolate_id, |
| 172 "objectId": int.parse(args[1]), | 197 "objectId": int.parse(args[1]), |
| 173 "index": int.parse(args[2]), | 198 "index": int.parse(args[2]), |
| 174 "length": int.parse(args[3]) } }; | 199 "length": int.parse(args[3]) } }; |
| 175 } | 200 } |
| 176 sendCmd(cmd).then((result) => handleGetListResponse(result)); | 201 cmdo.hide(); |
| 202 sendCmd(cmd).then(showPromptAfter(handleGetListResponse)); |
| 177 } else if (command == "pc" && args.length == 2) { | 203 } else if (command == "pc" && args.length == 2) { |
| 178 var cmd = { "id": seqNum, | 204 var cmd = { "id": seqNum, |
| 179 "command": "getClassProperties", | 205 "command": "getClassProperties", |
| 180 "params": { "isolateId" : isolate_id, | 206 "params": { "isolateId" : isolate_id, |
| 181 "classId": int.parse(args[1]) } }; | 207 "classId": int.parse(args[1]) } }; |
| 182 sendCmd(cmd).then((result) => handleGetClassPropsResponse(result)); | 208 cmdo.hide(); |
| 209 sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse)); |
| 183 } else if (command == "plib" && args.length == 2) { | 210 } else if (command == "plib" && args.length == 2) { |
| 184 var cmd = { "id": seqNum, | 211 var cmd = { "id": seqNum, |
| 185 "command": "getLibraryProperties", | 212 "command": "getLibraryProperties", |
| 186 "params": {"isolateId" : isolate_id, | 213 "params": {"isolateId" : isolate_id, |
| 187 "libraryId": int.parse(args[1]) } }; | 214 "libraryId": int.parse(args[1]) } }; |
| 188 sendCmd(cmd).then((result) => handleGetLibraryPropsResponse(result)); | 215 cmdo.hide(); |
| 216 sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse)); |
| 189 } else if (command == "slib" && args.length == 3) { | 217 } else if (command == "slib" && args.length == 3) { |
| 190 var cmd = { "id": seqNum, | 218 var cmd = { "id": seqNum, |
| 191 "command": "setLibraryProperties", | 219 "command": "setLibraryProperties", |
| 192 "params": {"isolateId" : isolate_id, | 220 "params": {"isolateId" : isolate_id, |
| 193 "libraryId": int.parse(args[1]), | 221 "libraryId": int.parse(args[1]), |
| 194 "debuggingEnabled": args[2] } }; | 222 "debuggingEnabled": args[2] } }; |
| 195 sendCmd(cmd).then((result) => handleSetLibraryPropsResponse(result)); | 223 cmdo.hide(); |
| 224 sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse)); |
| 196 } else if (command == "pg" && args.length == 2) { | 225 } else if (command == "pg" && args.length == 2) { |
| 197 var cmd = { "id": seqNum, | 226 var cmd = { "id": seqNum, |
| 198 "command": "getGlobalVariables", | 227 "command": "getGlobalVariables", |
| 199 "params": { "isolateId" : isolate_id, | 228 "params": { "isolateId" : isolate_id, |
| 200 "libraryId": int.parse(args[1]) } }; | 229 "libraryId": int.parse(args[1]) } }; |
| 201 sendCmd(cmd).then((result) => handleGetGlobalVarsResponse(result)); | 230 cmdo.hide(); |
| 231 sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse)); |
| 202 } else if (command == "gs" && args.length == 3) { | 232 } else if (command == "gs" && args.length == 3) { |
| 203 var cmd = { "id": seqNum, | 233 var cmd = { "id": seqNum, |
| 204 "command": "getScriptSource", | 234 "command": "getScriptSource", |
| 205 "params": { "isolateId" : isolate_id, | 235 "params": { "isolateId" : isolate_id, |
| 206 "libraryId": int.parse(args[1]), | 236 "libraryId": int.parse(args[1]), |
| 207 "url": args[2] } }; | 237 "url": args[2] } }; |
| 208 sendCmd(cmd).then((result) => handleGetSourceResponse(result)); | 238 cmdo.hide(); |
| 239 sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse)); |
| 209 } else if (command == "tok" && args.length == 3) { | 240 } else if (command == "tok" && args.length == 3) { |
| 210 var cmd = { "id": seqNum, | 241 var cmd = { "id": seqNum, |
| 211 "command": "getLineNumberTable", | 242 "command": "getLineNumberTable", |
| 212 "params": { "isolateId" : isolate_id, | 243 "params": { "isolateId" : isolate_id, |
| 213 "libraryId": int.parse(args[1]), | 244 "libraryId": int.parse(args[1]), |
| 214 "url": args[2] } }; | 245 "url": args[2] } }; |
| 215 sendCmd(cmd).then((result) => handleGetLineTableResponse(result)); | 246 cmdo.hide(); |
| 247 sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse)); |
| 216 } else if (command == "epi" && args.length == 2) { | 248 } else if (command == "epi" && args.length == 2) { |
| 217 var cmd = { "id": seqNum, | 249 var cmd = { "id": seqNum, |
| 218 "command": "setPauseOnException", | 250 "command": "setPauseOnException", |
| 219 "params": { "isolateId" : isolate_id, | 251 "params": { "isolateId" : isolate_id, |
| 220 "exceptions": args[1] } }; | 252 "exceptions": args[1] } }; |
| 221 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 253 cmdo.hide(); |
| 254 sendCmd(cmd).then(showPromptAfter(handleGenericResponse)); |
| 222 } else if (command == "li") { | 255 } else if (command == "li") { |
| 223 var cmd = { "id": seqNum, "command": "getIsolateIds" }; | 256 var cmd = { "id": seqNum, "command": "getIsolateIds" }; |
| 224 sendCmd(cmd).then((result) => handleGetIsolatesResponse(result)); | 257 cmdo.hide(); |
| 258 sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse)); |
| 225 } else if (command == "i" && args.length == 2) { | 259 } else if (command == "i" && args.length == 2) { |
| 226 var cmd = { "id": seqNum, | 260 var cmd = { "id": seqNum, |
| 227 "command": "interrupt", | 261 "command": "interrupt", |
| 228 "params": { "isolateId": int.parse(args[1]) } }; | 262 "params": { "isolateId": int.parse(args[1]) } }; |
| 229 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 263 cmdo.hide(); |
| 264 sendCmd(cmd).then(showPromptAfter(handleGenericResponse)); |
| 230 } else if (command == "q") { | 265 } else if (command == "q") { |
| 231 quitShell(); | 266 quitShell(); |
| 232 } else if (command == "h") { | 267 } else if (command == "h") { |
| 233 printHelp(); | 268 printHelp(); |
| 234 } else { | 269 } else { |
| 235 huh(); | 270 huh(); |
| 236 } | 271 } |
| 237 } | 272 } |
| 238 | 273 |
| 239 | 274 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 262 } | 297 } |
| 263 | 298 |
| 264 | 299 |
| 265 printNamedObject(obj) { | 300 printNamedObject(obj) { |
| 266 var name = obj["name"]; | 301 var name = obj["name"]; |
| 267 var value = obj["value"]; | 302 var value = obj["value"]; |
| 268 print(" $name = ${remoteObject(value)}"); | 303 print(" $name = ${remoteObject(value)}"); |
| 269 } | 304 } |
| 270 | 305 |
| 271 | 306 |
| 272 handleGetObjPropsResponse(response) { | 307 handleGetObjPropsResponse(Map response) { |
| 273 Map props = response["result"]; | 308 Map props = response["result"]; |
| 274 int class_id = props["classId"]; | 309 int class_id = props["classId"]; |
| 275 if (class_id == -1) { | 310 if (class_id == -1) { |
| 276 print(" null"); | 311 print(" null"); |
| 277 return; | 312 return; |
| 278 } | 313 } |
| 279 List fields = props["fields"]; | 314 List fields = props["fields"]; |
| 280 print(" class id: $class_id"); | 315 print(" class id: $class_id"); |
| 281 for (int i = 0; i < fields.length; i++) { | 316 for (int i = 0; i < fields.length; i++) { |
| 282 printNamedObject(fields[i]); | 317 printNamedObject(fields[i]); |
| 283 } | 318 } |
| 284 } | 319 } |
| 285 | 320 |
| 286 handleGetListResponse(response) { | 321 handleGetListResponse(Map response) { |
| 287 Map result = response["result"]; | 322 Map result = response["result"]; |
| 288 if (result["elements"] != null) { | 323 if (result["elements"] != null) { |
| 289 // List slice. | 324 // List slice. |
| 290 var index = result["index"]; | 325 var index = result["index"]; |
| 291 var length = result["length"]; | 326 var length = result["length"]; |
| 292 List elements = result["elements"]; | 327 List elements = result["elements"]; |
| 293 assert(length == elements.length); | 328 assert(length == elements.length); |
| 294 for (int i = 0; i < length; i++) { | 329 for (int i = 0; i < length; i++) { |
| 295 var kind = elements[i]["kind"]; | 330 var kind = elements[i]["kind"]; |
| 296 var text = elements[i]["text"]; | 331 var text = elements[i]["text"]; |
| 297 print(" ${index + i}: ($kind) $text"); | 332 print(" ${index + i}: ($kind) $text"); |
| 298 } | 333 } |
| 299 } else { | 334 } else { |
| 300 // One element, a remote object. | 335 // One element, a remote object. |
| 301 print(result); | 336 print(result); |
| 302 print(" ${remoteObject(result)}"); | 337 print(" ${remoteObject(result)}"); |
| 303 } | 338 } |
| 304 } | 339 } |
| 305 | 340 |
| 306 | 341 |
| 307 handleGetClassPropsResponse(response) { | 342 handleGetClassPropsResponse(Map response) { |
| 308 Map props = response["result"]; | 343 Map props = response["result"]; |
| 309 assert(props["name"] != null); | 344 assert(props["name"] != null); |
| 310 int libId = props["libraryId"]; | 345 int libId = props["libraryId"]; |
| 311 assert(libId != null); | 346 assert(libId != null); |
| 312 print(" class ${props["name"]} (library id: $libId)"); | 347 print(" class ${props["name"]} (library id: $libId)"); |
| 313 List fields = props["fields"]; | 348 List fields = props["fields"]; |
| 314 if (fields.length > 0) { | 349 if (fields.length > 0) { |
| 315 print(" static fields:"); | 350 print(" static fields:"); |
| 316 for (int i = 0; i < fields.length; i++) { | 351 for (int i = 0; i < fields.length; i++) { |
| 317 printNamedObject(fields[i]); | 352 printNamedObject(fields[i]); |
| 318 } | 353 } |
| 319 } | 354 } |
| 320 } | 355 } |
| 321 | 356 |
| 322 | 357 |
| 323 handleGetLibraryPropsResponse(response) { | 358 handleGetLibraryPropsResponse(Map response) { |
| 324 Map props = response["result"]; | 359 Map props = response["result"]; |
| 325 assert(props["url"] != null); | 360 assert(props["url"] != null); |
| 326 print(" library url: ${props["url"]}"); | 361 print(" library url: ${props["url"]}"); |
| 327 assert(props["debuggingEnabled"] != null); | 362 assert(props["debuggingEnabled"] != null); |
| 328 print(" debugging enabled: ${props["debuggingEnabled"]}"); | 363 print(" debugging enabled: ${props["debuggingEnabled"]}"); |
| 329 List imports = props["imports"]; | 364 List imports = props["imports"]; |
| 330 assert(imports != null); | 365 assert(imports != null); |
| 331 if (imports.length > 0) { | 366 if (imports.length > 0) { |
| 332 print(" imports:"); | 367 print(" imports:"); |
| 333 for (int i = 0; i < imports.length; i++) { | 368 for (int i = 0; i < imports.length; i++) { |
| 334 print(" id ${imports[i]["libraryId"]} prefix ${imports[i]["prefix"]}"); | 369 print(" id ${imports[i]["libraryId"]} prefix ${imports[i]["prefix"]}"); |
| 335 } | 370 } |
| 336 } | 371 } |
| 337 List globals = props["globals"]; | 372 List globals = props["globals"]; |
| 338 assert(globals != null); | 373 assert(globals != null); |
| 339 if (globals.length > 0) { | 374 if (globals.length > 0) { |
| 340 print(" global variables:"); | 375 print(" global variables:"); |
| 341 for (int i = 0; i < globals.length; i++) { | 376 for (int i = 0; i < globals.length; i++) { |
| 342 printNamedObject(globals[i]); | 377 printNamedObject(globals[i]); |
| 343 } | 378 } |
| 344 } | 379 } |
| 345 } | 380 } |
| 346 | 381 |
| 347 | 382 |
| 348 handleSetLibraryPropsResponse(response) { | 383 handleSetLibraryPropsResponse(Map response) { |
| 349 Map props = response["result"]; | 384 Map props = response["result"]; |
| 350 assert(props["debuggingEnabled"] != null); | 385 assert(props["debuggingEnabled"] != null); |
| 351 print(" debugging enabled: ${props["debuggingEnabled"]}"); | 386 print(" debugging enabled: ${props["debuggingEnabled"]}"); |
| 352 } | 387 } |
| 353 | 388 |
| 354 | 389 |
| 355 handleGetGlobalVarsResponse(response) { | 390 handleGetGlobalVarsResponse(Map response) { |
| 356 List globals = response["result"]["globals"]; | 391 List globals = response["result"]["globals"]; |
| 357 for (int i = 0; i < globals.length; i++) { | 392 for (int i = 0; i < globals.length; i++) { |
| 358 printNamedObject(globals[i]); | 393 printNamedObject(globals[i]); |
| 359 } | 394 } |
| 360 } | 395 } |
| 361 | 396 |
| 362 | 397 |
| 363 handleGetSourceResponse(response) { | 398 handleGetSourceResponse(Map response) { |
| 364 Map result = response["result"]; | 399 Map result = response["result"]; |
| 365 String source = result["text"]; | 400 String source = result["text"]; |
| 366 print("Source text:\n$source\n--------"); | 401 print("Source text:\n$source\n--------"); |
| 367 } | 402 } |
| 368 | 403 |
| 369 | 404 |
| 370 handleGetLineTableResponse(response) { | 405 handleGetLineTableResponse(Map response) { |
| 371 Map result = response["result"]; | 406 Map result = response["result"]; |
| 372 var info = result["lines"]; | 407 var info = result["lines"]; |
| 373 print("Line info table:\n$info"); | 408 print("Line info table:\n$info"); |
| 374 } | 409 } |
| 375 | 410 |
| 376 | 411 |
| 377 handleGetIsolatesResponse(response) { | 412 void handleGetIsolatesResponse(Map response) { |
| 378 Map result = response["result"]; | 413 Map result = response["result"]; |
| 379 print("Isolates: ${result["isolateIds"]}"); | 414 print("Isolates: ${result["isolateIds"]}"); |
| 380 } | 415 } |
| 381 | 416 |
| 382 | 417 |
| 383 void handleGetLibraryResponse(response) { | 418 void handleGetLibraryResponse(Map response) { |
| 384 Map result = response["result"]; | 419 Map result = response["result"]; |
| 385 List libs = result["libraries"]; | 420 List libs = result["libraries"]; |
| 386 print("Loaded libraries:"); | 421 print("Loaded libraries:"); |
| 387 print(libs); | 422 print(libs); |
| 388 for (int i = 0; i < libs.length; i++) { | 423 for (int i = 0; i < libs.length; i++) { |
| 389 print(" ${libs[i]["id"]} ${libs[i]["url"]}"); | 424 print(" ${libs[i]["id"]} ${libs[i]["url"]}"); |
| 390 } | 425 } |
| 391 } | 426 } |
| 392 | 427 |
| 393 | 428 |
| 394 void handleGetScriptsResponse(response) { | 429 void handleGetScriptsResponse(Map response) { |
| 395 Map result = response["result"]; | 430 Map result = response["result"]; |
| 396 List urls = result["urls"]; | 431 List urls = result["urls"]; |
| 397 print("Loaded scripts:"); | 432 print("Loaded scripts:"); |
| 398 for (int i = 0; i < urls.length; i++) { | 433 for (int i = 0; i < urls.length; i++) { |
| 399 print(" $i ${urls[i]}"); | 434 print(" $i ${urls[i]}"); |
| 400 } | 435 } |
| 401 } | 436 } |
| 402 | 437 |
| 403 | 438 |
| 404 void handleEvalResponse(response) { | 439 void handleEvalResponse(Map response) { |
| 405 Map result = response["result"]; | 440 Map result = response["result"]; |
| 406 print(remoteObject(result)); | 441 print(remoteObject(result)); |
| 407 } | 442 } |
| 408 | 443 |
| 409 | 444 |
| 410 void handleSetBpResponse(response) { | 445 void handleSetBpResponse(Map response) { |
| 411 Map result = response["result"]; | 446 Map result = response["result"]; |
| 412 var id = result["breakpointId"]; | 447 var id = result["breakpointId"]; |
| 413 assert(id != null); | 448 assert(id != null); |
| 414 print("Set BP $id"); | 449 print("Set BP $id"); |
| 415 } | 450 } |
| 416 | 451 |
| 417 | 452 |
| 418 void handleGenericResponse(response) { | 453 void handleGenericResponse(Map response) { |
| 419 if (response["error"] != null) { | 454 if (response["error"] != null) { |
| 420 print("Error: ${response["error"]}"); | 455 print("Error: ${response["error"]}"); |
| 421 } | 456 } |
| 422 } | 457 } |
| 423 | 458 |
| 424 | 459 |
| 425 void handleStackTraceResponse(response) { | 460 void handleStackTraceResponse(Map response) { |
| 426 Map result = response["result"]; | 461 Map result = response["result"]; |
| 427 List callFrames = result["callFrames"]; | 462 List callFrames = result["callFrames"]; |
| 428 assert(callFrames != null); | 463 assert(callFrames != null); |
| 429 printStackTrace(callFrames); | 464 printStackTrace(callFrames); |
| 430 } | 465 } |
| 431 | 466 |
| 432 | 467 |
| 433 void printStackFrame(frame_num, Map frame) { | 468 void printStackFrame(frame_num, Map frame) { |
| 434 var fname = frame["functionName"]; | 469 var fname = frame["functionName"]; |
| 435 var libId = frame["location"]["libraryId"]; | 470 var libId = frame["location"]["libraryId"]; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 } | 506 } |
| 472 | 507 |
| 473 | 508 |
| 474 void processVmMessage(String jsonString) { | 509 void processVmMessage(String jsonString) { |
| 475 var msg = JSON.decode(jsonString); | 510 var msg = JSON.decode(jsonString); |
| 476 if (msg == null) { | 511 if (msg == null) { |
| 477 return; | 512 return; |
| 478 } | 513 } |
| 479 var event = msg["event"]; | 514 var event = msg["event"]; |
| 480 if (event == "paused") { | 515 if (event == "paused") { |
| 516 cmdo.hide(); |
| 481 handlePausedEvent(msg); | 517 handlePausedEvent(msg); |
| 518 cmdo.show(); |
| 482 return; | 519 return; |
| 483 } | 520 } |
| 484 if (event == "breakpointResolved") { | 521 if (event == "breakpointResolved") { |
| 485 Map params = msg["params"]; | 522 Map params = msg["params"]; |
| 486 assert(params != null); | 523 assert(params != null); |
| 524 cmdo.hide(); |
| 487 print("BP ${params["breakpointId"]} resolved and " | 525 print("BP ${params["breakpointId"]} resolved and " |
| 488 "set at line ${params["line"]}."); | 526 "set at line ${params["line"]}."); |
| 527 cmdo.show(); |
| 489 return; | 528 return; |
| 490 } | 529 } |
| 491 if (event == "isolate") { | 530 if (event == "isolate") { |
| 492 Map params = msg["params"]; | 531 Map params = msg["params"]; |
| 493 assert(params != null); | 532 assert(params != null); |
| 533 cmdo.hide(); |
| 494 print("Isolate ${params["id"]} has been ${params["reason"]}."); | 534 print("Isolate ${params["id"]} has been ${params["reason"]}."); |
| 535 cmdo.show(); |
| 495 return; | 536 return; |
| 496 } | 537 } |
| 497 if (msg["id"] != null) { | 538 if (msg["id"] != null) { |
| 498 var id = msg["id"]; | 539 var id = msg["id"]; |
| 499 if (outstandingCommands.containsKey(id)) { | 540 if (outstandingCommands.containsKey(id)) { |
| 541 var completer = outstandingCommands.remove(id); |
| 500 if (msg["error"] != null) { | 542 if (msg["error"] != null) { |
| 501 print("VM says: ${msg["error"]}"); | 543 print("VM says: ${msg["error"]}"); |
| 544 // TODO(turnidge): Rework how hide/show happens. For now we |
| 545 // show here explicitly. |
| 546 cmdo.show(); |
| 502 } else { | 547 } else { |
| 503 var completer = outstandingCommands[id]; | |
| 504 completer.complete(msg); | 548 completer.complete(msg); |
| 505 } | 549 } |
| 506 outstandingCommands.remove(id); | |
| 507 } | 550 } |
| 508 } | 551 } |
| 509 } | 552 } |
| 510 | 553 |
| 511 bool haveGarbageVmData() { | 554 bool haveGarbageVmData() { |
| 512 if (vmData == null || vmData.length == 0) return false; | 555 if (vmData == null || vmData.length == 0) return false; |
| 513 var i = 0, char = " "; | 556 var i = 0, char = " "; |
| 514 while (i < vmData.length) { | 557 while (i < vmData.length) { |
| 515 char = vmData[i]; | 558 char = vmData[i]; |
| 516 if (char != " " && char != "\n" && char != "\r" && char != "\t") break; | 559 if (char != " " && char != "\n" && char != "\r" && char != "\t") break; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 nesting--; | 644 nesting--; |
| 602 if (nesting == 0) return index; | 645 if (nesting == 0) return index; |
| 603 } else if (char == '"') { | 646 } else if (char == '"') { |
| 604 // Strings can contain braces. Skip their content. | 647 // Strings can contain braces. Skip their content. |
| 605 index = skipString(index); | 648 index = skipString(index); |
| 606 } | 649 } |
| 607 } | 650 } |
| 608 return 0; | 651 return 0; |
| 609 } | 652 } |
| 610 | 653 |
| 654 List<String> debuggerCommandCompleter(List<String> commandParts) { |
| 655 List<String> completions = new List<String>(); |
| 656 |
| 657 // TODO(turnidge): Have a global command table and use it to for |
| 658 // help messages, command completion, and command dispatching. For now |
| 659 // we hardcode the list here. |
| 660 // |
| 661 // TODO(turnidge): Implement completion for arguments as well. |
| 662 List<String> allCommands = ['q', 'bt', 'r', 's', 'so', 'si', 'sbp', 'rbp', |
| 663 'po', 'eval', 'pl', 'pc', 'll', 'plib', 'slib', |
| 664 'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i', 'h']; |
| 665 |
| 666 // Completion of first word in the command. |
| 667 if (commandParts.length == 1) { |
| 668 String prefix = commandParts.last; |
| 669 for (String command in allCommands) { |
| 670 if (command.startsWith(prefix)) { |
| 671 completions.add(command); |
| 672 } |
| 673 } |
| 674 } |
| 675 |
| 676 return completions; |
| 677 } |
| 611 | 678 |
| 612 void debuggerMain() { | 679 void debuggerMain() { |
| 613 outstandingCommands = new Map<int, Completer>(); | 680 outstandingCommands = new Map<int, Completer>(); |
| 614 Socket.connect("127.0.0.1", 5858).then((s) { | 681 Socket.connect("127.0.0.1", 5858).then((s) { |
| 615 vmSock = s; | 682 vmSock = s; |
| 616 vmSock.setOption(SocketOption.TCP_NODELAY, true); | 683 vmSock.setOption(SocketOption.TCP_NODELAY, true); |
| 617 var stringStream = vmSock.transform(UTF8.decoder); | 684 var stringStream = vmSock.transform(UTF8.decoder); |
| 618 vmSubscription = stringStream.listen( | 685 vmSubscription = stringStream.listen( |
| 619 (String data) { | 686 (String data) { |
| 620 processVmData(data); | 687 processVmData(data); |
| 621 }, | 688 }, |
| 622 onDone: () { | 689 onDone: () { |
| 623 print("VM debugger connection closed"); | 690 print("VM debugger connection closed"); |
| 624 quitShell(); | 691 quitShell(); |
| 625 }, | 692 }, |
| 626 onError: (err) { | 693 onError: (err) { |
| 627 print("Error in debug connection: $err"); | 694 print("Error in debug connection: $err"); |
| 628 // TODO(floitsch): do we want to print the stack trace? | 695 // TODO(floitsch): do we want to print the stack trace? |
| 629 quitShell(); | 696 quitShell(); |
| 630 }); | 697 }); |
| 631 stdinSubscription = stdin.transform(UTF8.decoder) | 698 cmdo = new Commando(stdin, stdout, processCommand, |
| 632 .transform(new LineSplitter()) | 699 completer : debuggerCommandCompleter); |
| 633 .listen((String line) => processCommand(line)); | |
| 634 }); | 700 }); |
| 635 } | 701 } |
| 636 | 702 |
| 637 void main(List<String> arguments) { | 703 void main(List<String> args) { |
| 638 if (arguments.length > 0) { | 704 if (args.length > 0) { |
| 639 arguments = <String>['--debug', '--verbose_debug']..addAll(arguments); | 705 if (verbose) { |
| 640 Process.start(Platform.executable, arguments).then((Process process) { | 706 args = <String>['--debug', '--verbose_debug']..addAll(args); |
| 641 process.stdin.close(); | 707 } else { |
| 642 process.exitCode.then((int exitCode) { | 708 args = <String>['--debug']..addAll(args); |
| 643 print('${arguments.join(" ")} exited with $exitCode'); | 709 } |
| 644 }); | 710 Process.start(Platform.executable, args).then((Process process) { |
| 711 targetProcess = process; |
| 712 process.stdin.close(); |
| 713 |
| 714 // TODO(turnidge): For now we only show full lines of output |
| 715 // from the debugged process. Should show each character. |
| 716 process.stdout |
| 717 .transform(UTF8.decoder) |
| 718 .transform(new LineSplitter()) |
| 719 .listen((String line) { |
| 720 // Hide/show command prompt across asynchronous output. |
| 721 if (cmdo != null) { |
| 722 cmdo.hide(); |
| 723 } |
| 724 print("$line"); |
| 725 if (cmdo != null) { |
| 726 cmdo.show(); |
| 727 } |
| 728 }); |
| 729 |
| 730 process.exitCode.then((int exitCode) { |
| 731 if (exitCode == 0) { |
| 732 print('Program exited normally.'); |
| 733 } else { |
| 734 print('Program exited with code $exitCode.'); |
| 735 } |
| 736 }); |
| 737 |
| 645 debuggerMain(); | 738 debuggerMain(); |
| 646 }); | 739 }); |
| 647 } else { | 740 } else { |
| 648 debuggerMain(); | 741 debuggerMain(); |
| 649 } | 742 } |
| 650 } | 743 } |
| OLD | NEW |