Chromium Code Reviews| 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 = true; |
|
srdjan
2012/05/14 20:48:16
Do you really want it to be true?
hausner
2012/05/14 21:07:27
Changed to false.
| |
| 18 | 18 |
| 19 | 19 |
| 20 void printHelp() { | 20 void printHelp() { |
| 21 print(""" | 21 print(""" |
| 22 q Quit debugger shell | 22 q Quit debugger shell |
| 23 bt Show backtrace | |
| 23 r Resume execution | 24 r Resume execution |
| 24 s Single step | 25 s Single step |
| 25 so Step over | 26 so Step over |
| 26 si Step into | 27 si Step into |
| 28 sbp <file> <line> Set breakpoint | |
| 27 ll List loaded libraries | 29 ll List loaded libraries |
| 28 ls <libname> List loaded scripts in library | 30 ls <libname> List loaded scripts in library |
| 29 """); | 31 """); |
| 30 } | 32 } |
| 31 | 33 |
| 32 | 34 |
| 33 void quitShell() { | 35 void quitShell() { |
| 34 vmStream.close(); | 36 vmStream.close(); |
| 35 vmSock.close(); | 37 vmSock.close(); |
| 36 stdin.close(); | 38 stdin.close(); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 62 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 64 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 63 } else if (cmd == "s") { | 65 } else if (cmd == "s") { |
| 64 var cmd = { "id": seqNum, "command": "stepOver" }; | 66 var cmd = { "id": seqNum, "command": "stepOver" }; |
| 65 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 67 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 66 } else if (cmd == "si") { | 68 } else if (cmd == "si") { |
| 67 var cmd = { "id": seqNum, "command": "stepInto" }; | 69 var cmd = { "id": seqNum, "command": "stepInto" }; |
| 68 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 70 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 69 } else if (cmd == "so") { | 71 } else if (cmd == "so") { |
| 70 var cmd = { "id": seqNum, "command": "stepOut" }; | 72 var cmd = { "id": seqNum, "command": "stepOut" }; |
| 71 sendCmd(cmd).then((result) => handleGenericResponse(result)); | 73 sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| 74 } else if (cmd == "bt") { | |
| 75 var cmd = { "id": seqNum, "command": "getStackTrace" }; | |
| 76 sendCmd(cmd).then((result) => handleStackTraceResponse(result)); | |
| 72 } else if (cmd == "ll") { | 77 } else if (cmd == "ll") { |
| 73 var cmd = { "id": seqNum, "command": "getLibraryURLs" }; | 78 var cmd = { "id": seqNum, "command": "getLibraryURLs" }; |
| 74 sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); | 79 sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); |
| 80 } else if (cmd == "sbp") { | |
| 81 if (args.length < 3) { | |
| 82 return; | |
| 83 } | |
| 84 var cmd = { "id": seqNum, | |
| 85 "command": "setBreakpoint", | |
| 86 "params": { "url": args[1], "line": Math.parseInt(args[2]) }}; | |
| 87 sendCmd(cmd).then((result) => handleSetBpResponse(result)); | |
| 75 } else if (cmd == "ls") { | 88 } else if (cmd == "ls") { |
| 76 if (args.length < 2) { | 89 if (args.length < 2) { |
| 77 return; | 90 return; |
| 78 } | 91 } |
| 79 var cmd = { "id": seqNum, "command": "getScriptURLs", | 92 var cmd = { "id": seqNum, |
| 80 "param": { "library": args[1] }}; | 93 "command": "getScriptURLs", |
| 94 "params": { "library": args[1] }}; | |
| 81 sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); | 95 sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); |
| 82 } else if (cmd == "q") { | 96 } else if (cmd == "q") { |
| 83 quitShell(); | 97 quitShell(); |
| 84 } else if (cmd == "h") { | 98 } else if (cmd == "h") { |
| 85 printHelp(); | 99 printHelp(); |
| 86 } else { | 100 } else { |
| 87 print("Error: $cmd not understood"); | 101 print("command '$cmd' not understood, try h for help"); |
| 88 } | 102 } |
| 89 } | 103 } |
| 90 | 104 |
| 91 | 105 |
| 92 void handleGetLibraryResponse(response) { | 106 void handleGetLibraryResponse(response) { |
| 93 var result = response["result"]; | 107 var result = response["result"]; |
| 94 assert(result != null); | 108 assert(result != null); |
| 95 var urls = result["urls"]; | 109 var urls = result["urls"]; |
| 96 assert(urls != null); | 110 assert(urls != null); |
| 97 assert(urls is List); | 111 assert(urls is List); |
| 98 print("Loaded isolates:"); | 112 print("Loaded libraries:"); |
| 99 for (int i = 0; i < urls.length; i++) { | 113 for (int i = 0; i < urls.length; i++) { |
| 100 print(" $i ${urls[i]}"); | 114 print(" $i ${urls[i]}"); |
| 101 } | 115 } |
| 102 } | 116 } |
| 103 | 117 |
| 104 | 118 |
| 105 void handleGetScriptsResponse(response) { | 119 void handleGetScriptsResponse(response) { |
| 106 var result = response["result"]; | 120 var result = response["result"]; |
| 107 assert(result != null); | 121 assert(result != null); |
| 108 var urls = result["urls"]; | 122 var urls = result["urls"]; |
| 109 assert(urls != null); | 123 assert(urls != null); |
| 110 assert(urls is List); | 124 assert(urls is List); |
| 111 print("Loaded scripts:"); | 125 print("Loaded scripts:"); |
| 112 for (int i = 0; i < urls.length; i++) { | 126 for (int i = 0; i < urls.length; i++) { |
| 113 print(" $i ${urls[i]}"); | 127 print(" $i ${urls[i]}"); |
| 114 } | 128 } |
| 115 } | 129 } |
| 116 | 130 |
| 117 | 131 |
| 132 void handleSetBpResponse(response) { | |
| 133 var result = response["result"]; | |
| 134 assert(result != null); | |
| 135 var id = result["breakpointId"]; | |
| 136 assert(id != null); | |
| 137 print("Set BP $id"); | |
| 138 } | |
| 139 | |
| 140 | |
| 118 void handleGenericResponse(response) { | 141 void handleGenericResponse(response) { |
| 119 if (response["error"] != null) { | 142 if (response["error"] != null) { |
| 120 print("Error: ${response["error"]}"); | 143 print("Error: ${response["error"]}"); |
| 121 } | 144 } |
| 122 } | 145 } |
| 123 | 146 |
| 124 | 147 |
| 125 void printStackTrace(var trace) { | 148 void handleStackTraceResponse(response) { |
| 126 if (trace == null) { | 149 var result = response["result"]; |
| 127 return; | 150 assert(result != null); |
| 128 } | 151 var callFrames = result["callFrames"]; |
| 152 assert(callFrames != null); | |
| 153 printStackTrace(result); | |
| 154 } | |
| 155 | |
| 156 | |
| 157 void printStackTrace(trace) { | |
| 158 assert(trace != null); | |
| 129 var frames = trace["callFrames"]; | 159 var frames = trace["callFrames"]; |
| 130 if (frames is !List) { | 160 if (frames is !List) { |
| 131 print("unexpected type for frames parameter $frames"); | 161 print("unexpected type for frames parameter $frames"); |
| 132 return; | 162 return; |
| 133 } | 163 } |
| 134 for (int i = 0; i < frames.length; i++) { | 164 for (int i = 0; i < frames.length; i++) { |
| 135 var frame = frames[i]; | 165 var frame = frames[i]; |
| 136 var fname = frame["functionName"]; | 166 var fname = frame["functionName"]; |
| 137 var url = frame["location"]["url"]; | 167 var url = frame["location"]["url"]; |
| 138 var line = frame["location"]["lineNumber"]; | 168 var line = frame["location"]["lineNumber"]; |
| 139 print("$i $fname ($url:$line)"); | 169 print("$i $fname ($url:$line)"); |
| 140 } | 170 } |
| 141 } | 171 } |
| 142 | 172 |
| 143 | 173 |
| 144 // TODO(hausner): Need to handle the case where we receive only a partial | 174 void processVmMessage(String json) { |
| 145 // message from the debugger, e.g. when the message is too big to fit in | 175 var msg = JSON.parse(json); |
| 146 // one network packet. | |
| 147 void processVmData(String s) { | |
| 148 if (verbose) print("vm: $s"); | |
| 149 var msg = JSON.parse(s); | |
| 150 if (msg == null) { | 176 if (msg == null) { |
| 151 return; | 177 return; |
| 152 } | 178 } |
| 153 var event = msg["event"]; | 179 var event = msg["event"]; |
| 154 if (event == "paused") { | 180 if (event == "paused") { |
| 155 print("VM paused, stack trace:"); | 181 print("VM paused, stack trace:"); |
| 156 printStackTrace(msg["params"]); | 182 printStackTrace(msg["params"]); |
| 157 return; | 183 return; |
| 158 } | 184 } |
| 185 if (event == "breakpointResolved") { | |
| 186 var params = msg["params"]; | |
| 187 assert(params != null); | |
| 188 print("BP ${params["breakpointId"]} resolved and " | |
| 189 "set at line ${params["line"]}."); | |
| 190 return; | |
| 191 } | |
| 159 if (msg["id"] != null) { | 192 if (msg["id"] != null) { |
| 160 var id = msg["id"]; | 193 var id = msg["id"]; |
| 161 if (outstandingCommands.containsKey(id)) { | 194 if (outstandingCommands.containsKey(id)) { |
| 162 if (msg["error"] != null) { | 195 if (msg["error"] != null) { |
| 163 print("VM says: ${msg["error"]}"); | 196 print("VM says: ${msg["error"]}"); |
| 164 } else { | 197 } else { |
| 165 var completer = outstandingCommands[id]; | 198 var completer = outstandingCommands[id]; |
| 166 completer.complete(msg); | 199 completer.complete(msg); |
| 167 } | 200 } |
| 168 outstandingCommands.remove(id); | 201 outstandingCommands.remove(id); |
| 169 } | 202 } |
| 170 } | 203 } |
| 171 } | 204 } |
| 172 | 205 |
| 173 | 206 |
| 207 // TODO(hausner): Need to handle the case where we receive only a partial | |
| 208 // message from the debugger, e.g. when the message is too big to fit in | |
| 209 // one network packet. | |
| 210 void processVmData(String s) { | |
| 211 final printMessages = false; | |
| 212 int msg_len = JSON.length(s); | |
| 213 if (printMessages && msg_len == 0) { | |
| 214 print("vm sent illegal or partial json message '$s'"); | |
| 215 quitShell(); | |
| 216 return; | |
| 217 } | |
| 218 while (msg_len > 0 && msg_len <= s.length) { | |
| 219 if (msg_len == s.length) { | |
| 220 if (printMessages) { print("message: $s"); } | |
| 221 processVmMessage(s); | |
| 222 return; | |
| 223 } | |
| 224 if (printMessages) { print("at least one message: '$s'"); } | |
| 225 var msg = s.substring(0, msg_len); | |
| 226 if (printMessages) { print("first message: $msg"); } | |
| 227 processVmMessage(msg); | |
| 228 s = s.substring(msg_len); | |
| 229 msg_len = JSON.length(s); | |
| 230 } | |
| 231 if (printMessages) { print("leftover vm data '$s'"); } | |
| 232 } | |
| 233 | |
| 234 | |
| 174 void main() { | 235 void main() { |
| 175 outstandingCommands = new Map<int, Completer>(); | 236 outstandingCommands = new Map<int, Completer>(); |
| 176 vmSock = new Socket("127.0.0.1", 5858); | 237 vmSock = new Socket("127.0.0.1", 5858); |
| 177 vmStream = new SocketOutputStream(vmSock); | 238 vmStream = new SocketOutputStream(vmSock); |
| 178 var stdinStream = new StringInputStream(stdin); | 239 var stdinStream = new StringInputStream(stdin); |
| 179 stdinStream.onLine = () { | 240 stdinStream.onLine = () { |
| 180 processCommand(stdinStream.readLine()); | 241 processCommand(stdinStream.readLine()); |
| 181 }; | 242 }; |
| 182 var vmInStream = new SocketInputStream(vmSock); | 243 var vmInStream = new SocketInputStream(vmSock); |
| 183 vmInStream.onData = () { | 244 vmInStream.onData = () { |
| 184 var s = new String.fromCharCodes(vmInStream.read()); | 245 var s = new String.fromCharCodes(vmInStream.read()); |
| 185 processVmData(s); | 246 processVmData(s); |
| 186 }; | 247 }; |
| 187 vmInStream.onError = (err) { | 248 vmInStream.onError = (err) { |
| 188 print("Error in debug connection: $err"); | 249 print("Error in debug connection: $err"); |
| 189 quitShell(); | 250 quitShell(); |
| 190 }; | 251 }; |
| 191 vmInStream.onClosed = () { | 252 vmInStream.onClosed = () { |
| 192 print("VM debugger connection closed"); | 253 print("VM debugger connection closed"); |
| 193 quitShell(); | 254 quitShell(); |
| 194 }; | 255 }; |
| 195 } | 256 } |
| OLD | NEW |