| 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:io"); | 8 #import("dart:io"); |
| 9 #import("dart:json"); | 9 #import("dart:json"); |
| 10 | 10 |
| 11 Map<int, Completer> outstandingCommands; | 11 Map<int, Completer> outstandingCommands; |
| 12 | 12 |
| 13 Socket vmSock; | 13 Socket vmSock; |
| 14 OutputStream vmStream; | 14 OutputStream vmStream; |
| 15 int seqNum = 0; | 15 int seqNum = 0; |
| 16 | 16 |
| 17 bool verbose = false; | 17 bool verbose = false; |
| 18 | 18 |
| 19 // The current stack trace, while the VM is paused. It's a list |
| 20 // of activation frames. |
| 21 List stackTrace; |
| 22 |
| 23 // The current activation frame, while the VM is paused. |
| 24 Map curFrame; |
| 25 |
| 19 | 26 |
| 20 void printHelp() { | 27 void printHelp() { |
| 21 print(""" | 28 print(""" |
| 22 q Quit debugger shell | 29 q Quit debugger shell |
| 23 bt Show backtrace | 30 bt Show backtrace |
| 24 r Resume execution | 31 r Resume execution |
| 25 s Single step | 32 s Single step |
| 26 so Step over | 33 so Step over |
| 27 si Step into | 34 si Step into |
| 28 sbp <file> <line> Set breakpoint | 35 sbp [<file>] <line> Set breakpoint |
| 36 po <id> Print object info for given id |
| 37 pc <id> Print class info for given id |
| 29 ll List loaded libraries | 38 ll List loaded libraries |
| 30 ls <libname> List loaded scripts in library | 39 ls <libname> List loaded scripts in library |
| 40 h Print help |
| 31 """); | 41 """); |
| 32 } | 42 } |
| 33 | 43 |
| 34 | 44 |
| 35 void quitShell() { | 45 void quitShell() { |
| 36 vmStream.close(); | 46 vmStream.close(); |
| 37 vmSock.close(); | 47 vmSock.close(); |
| 38 stdin.close(); | 48 stdin.close(); |
| 39 } | 49 } |
| 40 | 50 |
| 41 | 51 |
| 42 Future sendCmd(Map<String, Dynamic> cmd) { | 52 Future sendCmd(Map<String, Dynamic> cmd) { |
| 43 var completer = new Completer(); | 53 var completer = new Completer(); |
| 44 assert(cmd["id"] != null); | 54 int id = cmd["id"]; |
| 45 var id = cmd["id"]; | |
| 46 outstandingCommands[id] = completer; | 55 outstandingCommands[id] = completer; |
| 47 if (verbose) { | 56 if (verbose) { |
| 48 print("sending: '${JSON.stringify(cmd)}'"); | 57 print("sending: '${JSON.stringify(cmd)}'"); |
| 49 } | 58 } |
| 50 vmStream.writeString(JSON.stringify(cmd)); | 59 vmStream.writeString(JSON.stringify(cmd)); |
| 51 return completer.future; | 60 return completer.future; |
| 52 } | 61 } |
| 53 | 62 |
| 54 | 63 |
| 55 void processCommand(String cmdLine) { | 64 void processCommand(String cmdLine) { |
| 56 seqNum++; | 65 seqNum++; |
| 57 var args = cmdLine.split(' '); | 66 var args = cmdLine.split(' '); |
| 58 if (args.length == 0) { | 67 if (args.length == 0) { |
| 59 return; | 68 return; |
| 60 } | 69 } |
| 61 var cmd = args[0]; | 70 var cmd = args[0]; |
| 62 if (cmd == "r") { | 71 if (cmd == "r") { |
| 63 var cmd = { "id": seqNum, "command": "resume" }; | 72 var cmd = { "id": seqNum, "command": "resume" }; |
| 64 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 73 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 74 stackTrace = curFrame = null; |
| 65 } else if (cmd == "s") { | 75 } else if (cmd == "s") { |
| 66 var cmd = { "id": seqNum, "command": "stepOver" }; | 76 var cmd = { "id": seqNum, "command": "stepOver" }; |
| 67 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 77 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 78 stackTrace = curFrame = null; |
| 68 } else if (cmd == "si") { | 79 } else if (cmd == "si") { |
| 69 var cmd = { "id": seqNum, "command": "stepInto" }; | 80 var cmd = { "id": seqNum, "command": "stepInto" }; |
| 70 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 81 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 82 stackTrace = curFrame = null; |
| 71 } else if (cmd == "so") { | 83 } else if (cmd == "so") { |
| 72 var cmd = { "id": seqNum, "command": "stepOut" }; | 84 var cmd = { "id": seqNum, "command": "stepOut" }; |
| 73 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 85 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 86 stackTrace = curFrame = null; |
| 74 } else if (cmd == "bt") { | 87 } else if (cmd == "bt") { |
| 75 var cmd = { "id": seqNum, "command": "getStackTrace" }; | 88 var cmd = { "id": seqNum, "command": "getStackTrace" }; |
| 76 sendCmd(cmd).then((result) => handleStackTraceResponse(result)); | 89 sendCmd(cmd).then((result) => handleStackTraceResponse(result)); |
| 77 } else if (cmd == "ll") { | 90 } else if (cmd == "ll") { |
| 78 var cmd = { "id": seqNum, "command": "getLibraryURLs" }; | 91 var cmd = { "id": seqNum, "command": "getLibraryURLs" }; |
| 79 sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); | 92 sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); |
| 80 } else if (cmd == "sbp") { | 93 } else if (cmd == "sbp" && args.length >= 2) { |
| 81 if (args.length < 3) { | 94 var url, line; |
| 82 return; | 95 if (args.length == 2) { |
| 96 url = stackTrace[0]["location"]["url"]; |
| 97 line = Math.parseInt(args[1]); |
| 98 } else { |
| 99 url = args[1]; |
| 100 line = Math.parseInt(args[2]); |
| 83 } | 101 } |
| 84 var cmd = { "id": seqNum, | 102 var cmd = { "id": seqNum, |
| 85 "command": "setBreakpoint", | 103 "command": "setBreakpoint", |
| 86 "params": { "url": args[1], "line": Math.parseInt(args[2]) }}; | 104 "params": { "url": url, "line": line }}; |
| 87 sendCmd(cmd).then((result) => handleSetBpResponse(result)); | 105 sendCmd(cmd).then((result) => handleSetBpResponse(result)); |
| 88 } else if (cmd == "ls") { | 106 } else if (cmd == "ls" && args.length == 2) { |
| 89 if (args.length < 2) { | |
| 90 return; | |
| 91 } | |
| 92 var cmd = { "id": seqNum, | 107 var cmd = { "id": seqNum, |
| 93 "command": "getScriptURLs", | 108 "command": "getScriptURLs", |
| 94 "params": { "library": args[1] }}; | 109 "params": { "library": args[1] }}; |
| 95 sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); | 110 sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); |
| 111 } else if (cmd == "po" && args.length == 2) { |
| 112 var cmd = { "id": seqNum, "command": "getObjectProperties", |
| 113 "params": {"objectId": Math.parseInt(args[1]) }}; |
| 114 sendCmd(cmd).then((result) => handleGetObjPropsResponse(result)); |
| 115 } else if (cmd == "pc" && args.length == 2) { |
| 116 var cmd = { "id": seqNum, "command": "getClassProperties", |
| 117 "params": {"classId": Math.parseInt(args[1]) }}; |
| 118 sendCmd(cmd).then((result) => handleGetClassPropsResponse(result)); |
| 96 } else if (cmd == "q") { | 119 } else if (cmd == "q") { |
| 97 quitShell(); | 120 quitShell(); |
| 98 } else if (cmd == "h") { | 121 } else if (cmd == "h") { |
| 99 printHelp(); | 122 printHelp(); |
| 100 } else { | 123 } else { |
| 101 print("command '$cmd' not understood, try h for help"); | 124 print("command '$cmd' not understood, try h for help"); |
| 102 } | 125 } |
| 103 } | 126 } |
| 104 | 127 |
| 105 | 128 |
| 129 printNamedObject(obj) { |
| 130 var name = obj["name"]; |
| 131 var value = obj["value"]; |
| 132 var kind = value["kind"]; |
| 133 var text = value["text"]; |
| 134 var id = value["objectId"]; |
| 135 if (kind == "string") { |
| 136 print(" $name = '$text'"); |
| 137 } else if (kind == "object") { |
| 138 print(" $name (id:$id) = $text"); |
| 139 } else { |
| 140 print(" $name = $text"); |
| 141 } |
| 142 } |
| 143 |
| 144 |
| 145 handleGetObjPropsResponse(response) { |
| 146 Map props = response["result"]; |
| 147 int class_id = props["classId"]; |
| 148 List fields = props["fields"]; |
| 149 print(" class id: $class_id"); |
| 150 for (int i = 0; i < fields.length; i++) { |
| 151 printNamedObject(fields[i]); |
| 152 } |
| 153 } |
| 154 |
| 155 |
| 156 handleGetClassPropsResponse(response) { |
| 157 Map props = response["result"]; |
| 158 assert(props["name"] != null); |
| 159 int libId = props["libraryId"]; |
| 160 assert(libId != null); |
| 161 print(" class ${props["name"]} (library id: $libId)"); |
| 162 List fields = props["fields"]; |
| 163 if (fields.length > 0) { |
| 164 print(" static fields:"); |
| 165 for (int i = 0; i < fields.length; i++) { |
| 166 printNamedObject(fields[i]); |
| 167 } |
| 168 } |
| 169 } |
| 170 |
| 171 |
| 106 void handleGetLibraryResponse(response) { | 172 void handleGetLibraryResponse(response) { |
| 107 var result = response["result"]; | 173 Map result = response["result"]; |
| 108 assert(result != null); | 174 List urls = result["urls"]; |
| 109 var urls = result["urls"]; | |
| 110 assert(urls != null); | |
| 111 assert(urls is List); | |
| 112 print("Loaded libraries:"); | 175 print("Loaded libraries:"); |
| 113 for (int i = 0; i < urls.length; i++) { | 176 for (int i = 0; i < urls.length; i++) { |
| 114 print(" $i ${urls[i]}"); | 177 print(" $i ${urls[i]}"); |
| 115 } | 178 } |
| 116 } | 179 } |
| 117 | 180 |
| 118 | 181 |
| 119 void handleGetScriptsResponse(response) { | 182 void handleGetScriptsResponse(response) { |
| 120 var result = response["result"]; | 183 Map result = response["result"]; |
| 121 assert(result != null); | 184 List urls = result["urls"]; |
| 122 var urls = result["urls"]; | |
| 123 assert(urls != null); | |
| 124 assert(urls is List); | |
| 125 print("Loaded scripts:"); | 185 print("Loaded scripts:"); |
| 126 for (int i = 0; i < urls.length; i++) { | 186 for (int i = 0; i < urls.length; i++) { |
| 127 print(" $i ${urls[i]}"); | 187 print(" $i ${urls[i]}"); |
| 128 } | 188 } |
| 129 } | 189 } |
| 130 | 190 |
| 131 | 191 |
| 132 void handleSetBpResponse(response) { | 192 void handleSetBpResponse(response) { |
| 133 var result = response["result"]; | 193 Map result = response["result"]; |
| 134 assert(result != null); | |
| 135 var id = result["breakpointId"]; | 194 var id = result["breakpointId"]; |
| 136 assert(id != null); | 195 assert(id != null); |
| 137 print("Set BP $id"); | 196 print("Set BP $id"); |
| 138 } | 197 } |
| 139 | 198 |
| 140 | 199 |
| 141 void handleGenericResponse(response) { | 200 void handleGenericResponse(response) { |
| 142 if (response["error"] != null) { | 201 if (response["error"] != null) { |
| 143 print("Error: ${response["error"]}"); | 202 print("Error: ${response["error"]}"); |
| 144 } | 203 } |
| 145 } | 204 } |
| 146 | 205 |
| 147 | 206 |
| 148 void handleStackTraceResponse(response) { | 207 void handleStackTraceResponse(response) { |
| 149 var result = response["result"]; | 208 Map result = response["result"]; |
| 150 assert(result != null); | 209 List callFrames = result["callFrames"]; |
| 151 var callFrames = result["callFrames"]; | |
| 152 assert(callFrames != null); | 210 assert(callFrames != null); |
| 153 printStackTrace(result); | 211 printStackTrace(callFrames); |
| 154 } | 212 } |
| 155 | 213 |
| 156 | 214 |
| 157 void printStackTrace(trace) { | 215 void printStackFrame(frame_num, Map frame) { |
| 158 assert(trace != null); | 216 var fname = frame["functionName"]; |
| 159 var frames = trace["callFrames"]; | 217 var url = frame["location"]["url"]; |
| 160 if (frames is !List) { | 218 var line = frame["location"]["lineNumber"]; |
| 161 print("unexpected type for frames parameter $frames"); | 219 print("$frame_num $fname ($url:$line)"); |
| 162 return; | 220 List locals = frame["locals"]; |
| 221 for (int i = 0; i < locals.length; i++) { |
| 222 printNamedObject(locals[i]); |
| 163 } | 223 } |
| 224 } |
| 225 |
| 226 |
| 227 void printStackTrace(List frames) { |
| 164 for (int i = 0; i < frames.length; i++) { | 228 for (int i = 0; i < frames.length; i++) { |
| 165 var frame = frames[i]; | 229 printStackFrame(i, frames[i]); |
| 166 var fname = frame["functionName"]; | |
| 167 var url = frame["location"]["url"]; | |
| 168 var line = frame["location"]["lineNumber"]; | |
| 169 print("$i $fname ($url:$line)"); | |
| 170 } | 230 } |
| 171 } | 231 } |
| 172 | 232 |
| 173 | 233 |
| 234 void handlePausedEvent(msg) { |
| 235 assert(msg["params"] != null); |
| 236 stackTrace = msg["params"]["callFrames"]; |
| 237 assert(stackTrace != null); |
| 238 assert(stackTrace.length >= 1); |
| 239 curFrame = stackTrace[0]; |
| 240 print("VM paused, stack trace:"); |
| 241 printStackTrace(stackTrace); |
| 242 } |
| 243 |
| 244 |
| 174 void processVmMessage(String json) { | 245 void processVmMessage(String json) { |
| 175 var msg = JSON.parse(json); | 246 var msg = JSON.parse(json); |
| 176 if (msg == null) { | 247 if (msg == null) { |
| 177 return; | 248 return; |
| 178 } | 249 } |
| 179 var event = msg["event"]; | 250 var event = msg["event"]; |
| 180 if (event == "paused") { | 251 if (event == "paused") { |
| 181 print("VM paused, stack trace:"); | 252 handlePausedEvent(msg); |
| 182 printStackTrace(msg["params"]); | |
| 183 return; | 253 return; |
| 184 } | 254 } |
| 185 if (event == "breakpointResolved") { | 255 if (event == "breakpointResolved") { |
| 186 var params = msg["params"]; | 256 Map params = msg["params"]; |
| 187 assert(params != null); | 257 assert(params != null); |
| 188 print("BP ${params["breakpointId"]} resolved and " | 258 print("BP ${params["breakpointId"]} resolved and " |
| 189 "set at line ${params["line"]}."); | 259 "set at line ${params["line"]}."); |
| 190 return; | 260 return; |
| 191 } | 261 } |
| 192 if (msg["id"] != null) { | 262 if (msg["id"] != null) { |
| 193 var id = msg["id"]; | 263 var id = msg["id"]; |
| 194 if (outstandingCommands.containsKey(id)) { | 264 if (outstandingCommands.containsKey(id)) { |
| 195 if (msg["error"] != null) { | 265 if (msg["error"] != null) { |
| 196 print("VM says: ${msg["error"]}"); | 266 print("VM says: ${msg["error"]}"); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 }; | 317 }; |
| 248 vmInStream.onError = (err) { | 318 vmInStream.onError = (err) { |
| 249 print("Error in debug connection: $err"); | 319 print("Error in debug connection: $err"); |
| 250 quitShell(); | 320 quitShell(); |
| 251 }; | 321 }; |
| 252 vmInStream.onClosed = () { | 322 vmInStream.onClosed = () { |
| 253 print("VM debugger connection closed"); | 323 print("VM debugger connection closed"); |
| 254 quitShell(); | 324 quitShell(); |
| 255 }; | 325 }; |
| 256 } | 326 } |
| OLD | NEW |