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 // 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:async"; | 9 import "dart:async"; |
10 import "dart:io"; | 10 import "dart:io"; |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 debugger.error("Error: expected messaged id $id but got ${response["id"]}. "); | 179 debugger.error("Error: expected messaged id $id but got ${response["id"]}. "); |
180 } | 180 } |
181 } | 181 } |
182 } | 182 } |
183 | 183 |
184 | 184 |
185 class FrameMatcher extends Command { | 185 class FrameMatcher extends Command { |
186 int frameIndex; | 186 int frameIndex; |
187 List<String> functionNames; | 187 List<String> functionNames; |
188 | 188 |
189 Map locals = {}; | |
190 | |
189 FrameMatcher(this.frameIndex, this.functionNames) { | 191 FrameMatcher(this.frameIndex, this.functionNames) { |
190 template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}} ; | 192 template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}} ; |
191 } | 193 } |
192 | 194 |
195 void matchLocal(String localName, String localValue) { | |
196 locals[localName] = localValue; | |
197 } | |
198 | |
193 void matchResponse(Debugger debugger) { | 199 void matchResponse(Debugger debugger) { |
194 super.matchResponse(debugger); | 200 super.matchResponse(debugger); |
195 var msg = debugger.currentMessage; | 201 var msg = debugger.currentMessage; |
196 List frames = getJsonValue(msg, "result:callFrames"); | 202 List frames = getJsonValue(msg, "result:callFrames"); |
197 assert(frames != null); | 203 assert(frames != null); |
198 if (debugger.scriptUrl == null) { | 204 if (debugger.scriptUrl == null) { |
199 var name = frames[0]["functionName"]; | 205 var name = frames[0]["functionName"]; |
200 if (name == "main") { | 206 if (name == "main") { |
201 // Extract script url of debugged script. | 207 // Extract script url of debugged script. |
202 debugger.scriptUrl = frames[0]["location"]["url"]; | 208 debugger.scriptUrl = frames[0]["location"]["url"]; |
203 assert(debugger.scriptUrl != null); | 209 assert(debugger.scriptUrl != null); |
204 } | 210 } |
205 } | 211 } |
206 if (frames.length < functionNames.length) { | 212 if (frames.length < functionNames.length) { |
207 debugger.error("Error: stack trace not long enough " | 213 debugger.error("Error: stack trace not long enough " |
208 "to match ${functionNames.length} frames"); | 214 "to match ${functionNames.length} frames"); |
209 return; | 215 return; |
210 } | 216 } |
211 for (int i = 0; i < functionNames.length; i++) { | 217 for (int i = 0; i < functionNames.length; i++) { |
212 var idx = i + frameIndex; | 218 var idx = i + frameIndex; |
213 var name = frames[idx]["functionName"]; | 219 var name = frames[idx]["functionName"]; |
214 assert(name != null); | 220 assert(name != null); |
215 if (name != functionNames[i]) { | 221 if (name != functionNames[i]) { |
216 debugger.error("Error: call frame $idx: " | 222 debugger.error("Error: call frame $idx: " |
217 "expected function name '${functionNames[i]}' but found '$name'"); | 223 "expected function name '${functionNames[i]}' but found '$name'"); |
218 return; | 224 return; |
219 } | 225 } |
220 } | 226 } |
227 | |
228 // verify locals | |
229 String functionName = frames[frameIndex]['functionName']; | |
230 List localsList = frames[frameIndex]['locals']; | |
231 Map reportedLocals = {}; | |
232 localsList.forEach((local) => reportedLocals[local['name']] = local['value'] ); | |
233 for (String key in locals.keys) { | |
234 if (reportedLocals[key] == null) { | |
235 debugger.error("Error in $functionName(): no value reported for local " | |
236 "variable $key"); | |
237 return; | |
238 } | |
239 String expected = locals[key]; | |
240 String actual = reportedLocals[key]['text']; | |
241 if (expected != actual) { | |
242 debugger.error("Error in $functionName(): got '$actual' for local " | |
243 "variable $key, but expected '$expected'"); | |
244 return; | |
245 } | |
246 } | |
221 } | 247 } |
222 } | 248 } |
223 | 249 |
224 | 250 |
225 MatchFrame(int frameIndex, String functionName) { | 251 MatchFrame(int frameIndex, String functionName) { |
226 return new FrameMatcher(frameIndex, [ functionName ]); | 252 return new FrameMatcher(frameIndex, [ functionName ]); |
227 } | 253 } |
228 | 254 |
229 MatchFrames(List<String> functionNames) { | 255 MatchFrames(List<String> functionNames) { |
hausner
2013/06/18 17:30:25
How about an optional parameter here that takes a
| |
230 return new FrameMatcher(0, functionNames); | 256 return new FrameMatcher(0, functionNames); |
231 } | 257 } |
232 | 258 |
233 | 259 |
260 class EventMatcher { | |
261 String eventName; | |
262 | |
263 EventMatcher(this.eventName); | |
264 | |
265 void matchEvent(Debugger debugger, Map event) { | |
266 String actualName = event['event']; | |
267 | |
268 if (eventName != actualName) { | |
269 debugger.error("Error: got event $actualName but expected event $eventName "); | |
270 return; | |
271 } | |
272 } | |
273 } | |
274 | |
275 | |
276 ExpectEvent(String eventName) { | |
277 return new EventMatcher(eventName); | |
278 } | |
279 | |
280 | |
234 class RunCommand extends Command { | 281 class RunCommand extends Command { |
235 RunCommand.resume() { | 282 RunCommand.resume() { |
236 template = {"id": 0, "command": "resume", "params": {"isolateId": 0}}; | 283 template = {"id": 0, "command": "resume", "params": {"isolateId": 0}}; |
237 } | 284 } |
238 RunCommand.step() { | 285 RunCommand.step() { |
239 template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}}; | 286 template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}}; |
240 } | 287 } |
241 RunCommand.stepInto() { | 288 RunCommand.stepInto() { |
242 template = {"id": 0, "command": "stepInto", "params": {"isolateId": 0}}; | 289 template = {"id": 0, "command": "stepInto", "params": {"isolateId": 0}}; |
243 } | 290 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
278 | 325 |
279 | 326 |
280 // A debug script is a list of Command objects. | 327 // A debug script is a list of Command objects. |
281 class DebugScript { | 328 class DebugScript { |
282 List entries; | 329 List entries; |
283 DebugScript(List scriptEntries) { | 330 DebugScript(List scriptEntries) { |
284 entries = new List.from(scriptEntries.reversed); | 331 entries = new List.from(scriptEntries.reversed); |
285 entries.add(MatchFrame(0, "main")); | 332 entries.add(MatchFrame(0, "main")); |
286 } | 333 } |
287 bool get isEmpty => entries.isEmpty; | 334 bool get isEmpty => entries.isEmpty; |
335 bool get isNextEventMatcher => !isEmpty && currentEntry is EventMatcher; | |
288 get currentEntry => entries.last; | 336 get currentEntry => entries.last; |
289 advance() => entries.removeLast(); | 337 advance() => entries.removeLast(); |
290 add(entry) => entries.add(entry); | 338 add(entry) => entries.add(entry); |
291 } | 339 } |
292 | 340 |
293 | 341 |
294 class Debugger { | 342 class Debugger { |
295 // Debug target process properties. | 343 // Debug target process properties. |
296 Process targetProcess; | 344 Process targetProcess; |
297 Socket socket; | 345 Socket socket; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
354 var location = msg["params"]["location"]; | 402 var location = msg["params"]["location"]; |
355 assert(location != null); | 403 assert(location != null); |
356 print("Isolate $isolateId: breakpoint $bpId resolved" | 404 print("Isolate $isolateId: breakpoint $bpId resolved" |
357 " at location $location"); | 405 " at location $location"); |
358 // We may want to maintain a table of breakpoints in the future. | 406 // We may want to maintain a table of breakpoints in the future. |
359 } else if (msg["event"] == "paused") { | 407 } else if (msg["event"] == "paused") { |
360 isPaused = true; | 408 isPaused = true; |
361 } else { | 409 } else { |
362 error("Error: unknown debugger event received"); | 410 error("Error: unknown debugger event received"); |
363 } | 411 } |
412 | |
413 if (script.isNextEventMatcher) { | |
414 EventMatcher matcher = script.currentEntry; | |
415 script.advance(); | |
416 matcher.matchEvent(this, msg); | |
417 } | |
364 } | 418 } |
365 | 419 |
366 // Handle one JSON message object and match it to the | 420 // Handle one JSON message object and match it to the |
367 // expected events and responses in the debugging script. | 421 // expected events and responses in the debugging script. |
368 void handleMessage(Map<String,dynamic> receivedMsg) { | 422 void handleMessage(Map<String,dynamic> receivedMsg) { |
369 currentMessage = receivedMsg; | 423 currentMessage = receivedMsg; |
370 if (receivedMsg["event"] != null) { | 424 if (receivedMsg["event"] != null) { |
371 handleEvent(receivedMsg); | 425 handleEvent(receivedMsg); |
372 if (errorsDetected) { | 426 if (errorsDetected) { |
373 error("Error while handling debugger event"); | 427 error("Error while handling debugger event"); |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
525 targetOpts.add("--debuggee"); | 579 targetOpts.add("--debuggee"); |
526 print('args: ${targetOpts.join(" ")}'); | 580 print('args: ${targetOpts.join(" ")}'); |
527 | 581 |
528 Process.start(options.executable, targetOpts).then((Process process) { | 582 Process.start(options.executable, targetOpts).then((Process process) { |
529 print("Debug target process started, pid ${process.pid}."); | 583 print("Debug target process started, pid ${process.pid}."); |
530 process.stdin.close(); | 584 process.stdin.close(); |
531 var debugger = new Debugger(process, new DebugScript(script)); | 585 var debugger = new Debugger(process, new DebugScript(script)); |
532 }); | 586 }); |
533 return true; | 587 return true; |
534 } | 588 } |
OLD | NEW |