Chromium Code Reviews| Index: tools/ddbg.dart |
| =================================================================== |
| --- tools/ddbg.dart (revision 30580) |
| +++ tools/ddbg.dart (working copy) |
| @@ -10,6 +10,16 @@ |
| import "dart:async"; |
| +class TargetIsolate { |
| + int id; |
| + // The location of the last paused event. |
| + Map pausedLocation = null; |
| + |
| + TargetIsolate(this.id); |
| + bool get isPaused => pausedLocation != null; |
| +} |
| + |
| +Map<int, TargetIsolate> targetIsolates= new Map<int, TargetIsolate>(); |
| Map<int, Completer> outstandingCommands; |
| Socket vmSock; |
| @@ -17,13 +27,12 @@ |
| var stdinSubscription; |
| var vmSubscription; |
| int seqNum = 0; |
| -int isolate_id = -1; |
| final verbose = false; |
| final printMessages = false; |
| -// The location of the last paused event. |
| -Map pausedLocation = null; |
| +TargetIsolate currentIsolate; |
| +TargetIsolate mainIsolate; |
| void printHelp() { |
| @@ -51,12 +60,20 @@ |
| tok <lib_id> <script_url> Get line and token table of script in library |
| epi <none|all|unhandled> Set exception pause info |
| li List ids of all isolates in the VM |
| + sci <id> Set current target isolate |
| i <id> Interrupt execution of given isolate id |
| h Print help |
| """); |
| } |
| +String formatLocation(Map location) { |
| + if (location == null) return ""; |
| + var fileName = location["url"].split("/").last; |
| + return "file: $fileName lib: ${location['libraryId']} token: ${location['tokenOffset']}"; |
| +} |
| + |
| + |
| void quitShell() { |
| vmSubscription.cancel(); |
| vmSock.close(); |
| @@ -75,6 +92,21 @@ |
| return completer.future; |
| } |
| +bool checkCurrentIsolate() { |
| + if (currentIsolate != null) { |
| + return true; |
| + } |
| + print("Need valid current isolate"); |
| + return false; |
| +} |
| + |
| +bool checkPaused() { |
| + if (!checkCurrentIsolate()) return false; |
| + if (currentIsolate.isPaused) return true; |
| + print("Current isolate must be paused"); |
| + return false; |
| +} |
| + |
| void processCommand(String cmdLine) { |
| void huh() { |
| @@ -87,27 +119,29 @@ |
| return; |
| } |
| var command = args[0]; |
| - var simple_commands = |
| + var resume_commands = |
| { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'}; |
| - if (simple_commands[command] != null) { |
| + if (resume_commands[command] != null) { |
| + if (!checkPaused()) return; |
| var cmd = { "id": seqNum, |
| - "command": simple_commands[command], |
| - "params": { "isolateId" : isolate_id } }; |
| + "command": resume_commands[command], |
| + "params": { "isolateId" : currentIsolate.id } }; |
| sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| + currentIsolate.pausedLocation = null; |
|
turnidge
2013/11/22 19:24:00
I know that the sendCmd cannot complete immediatel
hausner
2013/11/22 22:54:42
Good point. Created a new handler that sets the pa
|
| } else if (command == "bt") { |
| var cmd = { "id": seqNum, |
| "command": "getStackTrace", |
| - "params": { "isolateId" : isolate_id } }; |
| + "params": { "isolateId" : currentIsolate.id } }; |
| sendCmd(cmd).then((result) => handleStackTraceResponse(result)); |
| } else if (command == "ll") { |
| var cmd = { "id": seqNum, |
| "command": "getLibraries", |
| - "params": { "isolateId" : isolate_id } }; |
| + "params": { "isolateId" : currentIsolate.id } }; |
| sendCmd(cmd).then((result) => handleGetLibraryResponse(result)); |
| } else if (command == "sbp" && args.length >= 2) { |
| var url, line; |
| - if (args.length == 2 && pausedLocation != null) { |
| - url = pausedLocation["url"]; |
| + if (args.length == 2 && currentIsolate.pausedLocation != null) { |
| + url = currentIsolate.pausedLocation["url"]; |
| assert(url != null); |
| line = int.parse(args[1]); |
| } else { |
| @@ -116,20 +150,20 @@ |
| } |
| var cmd = { "id": seqNum, |
| "command": "setBreakpoint", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "url": url, |
| "line": line }}; |
| sendCmd(cmd).then((result) => handleSetBpResponse(result)); |
| } else if (command == "rbp" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "removeBreakpoint", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "breakpointId": int.parse(args[1]) } }; |
| sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| } else if (command == "ls" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "getScriptURLs", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "libraryId": int.parse(args[1]) } }; |
| sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); |
| } else if (command == "eval" && args.length > 3) { |
| @@ -147,14 +181,14 @@ |
| } |
| var cmd = { "id": seqNum, |
| "command": "evaluateExpr", |
| - "params": { "isolateId": isolate_id, |
| + "params": { "isolateId": currentIsolate.id, |
| target: int.parse(args[2]), |
| "expression": expr } }; |
| sendCmd(cmd).then((result) => handleEvalResponse(result)); |
| } else if (command == "po" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "getObjectProperties", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "objectId": int.parse(args[1]) } }; |
| sendCmd(cmd).then((result) => handleGetObjPropsResponse(result)); |
| } else if (command == "pl" && args.length >= 3) { |
| @@ -162,13 +196,13 @@ |
| if (args.length == 3) { |
| cmd = { "id": seqNum, |
| "command": "getListElements", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "objectId": int.parse(args[1]), |
| "index": int.parse(args[2]) } }; |
| } else { |
| cmd = { "id": seqNum, |
| "command": "getListElements", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "objectId": int.parse(args[1]), |
| "index": int.parse(args[2]), |
| "length": int.parse(args[3]) } }; |
| @@ -177,51 +211,59 @@ |
| } else if (command == "pc" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "getClassProperties", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "classId": int.parse(args[1]) } }; |
| sendCmd(cmd).then((result) => handleGetClassPropsResponse(result)); |
| } else if (command == "plib" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "getLibraryProperties", |
| - "params": {"isolateId" : isolate_id, |
| + "params": {"isolateId" : currentIsolate.id, |
| "libraryId": int.parse(args[1]) } }; |
| sendCmd(cmd).then((result) => handleGetLibraryPropsResponse(result)); |
| } else if (command == "slib" && args.length == 3) { |
| var cmd = { "id": seqNum, |
| "command": "setLibraryProperties", |
| - "params": {"isolateId" : isolate_id, |
| + "params": {"isolateId" : currentIsolate.id, |
| "libraryId": int.parse(args[1]), |
| "debuggingEnabled": args[2] } }; |
| sendCmd(cmd).then((result) => handleSetLibraryPropsResponse(result)); |
| } else if (command == "pg" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "getGlobalVariables", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "libraryId": int.parse(args[1]) } }; |
| sendCmd(cmd).then((result) => handleGetGlobalVarsResponse(result)); |
| } else if (command == "gs" && args.length == 3) { |
| var cmd = { "id": seqNum, |
| "command": "getScriptSource", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "libraryId": int.parse(args[1]), |
| "url": args[2] } }; |
| sendCmd(cmd).then((result) => handleGetSourceResponse(result)); |
| } else if (command == "tok" && args.length == 3) { |
| var cmd = { "id": seqNum, |
| "command": "getLineNumberTable", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "libraryId": int.parse(args[1]), |
| "url": args[2] } }; |
| sendCmd(cmd).then((result) => handleGetLineTableResponse(result)); |
| } else if (command == "epi" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "setPauseOnException", |
| - "params": { "isolateId" : isolate_id, |
| + "params": { "isolateId" : currentIsolate.id, |
| "exceptions": args[1] } }; |
| sendCmd(cmd).then((result) => handleGenericResponse(result)); |
| } else if (command == "li") { |
| var cmd = { "id": seqNum, "command": "getIsolateIds" }; |
| sendCmd(cmd).then((result) => handleGetIsolatesResponse(result)); |
| + } else if (command == "sci" && args.length == 2) { |
| + var id = int.parse(args[1]); |
| + if (targetIsolates[id] != null) { |
| + currentIsolate = targetIsolates[id]; |
| + print("Setting current target isolate to $id"); |
| + } else { |
| + print("$id is not a valid isolate id"); |
| + } |
| } else if (command == "i" && args.length == 2) { |
| var cmd = { "id": seqNum, |
| "command": "interrupt", |
| @@ -249,10 +291,7 @@ |
| } else if (kind == "object") { |
| return "(obj, id $id) $text"; |
| } else if (kind == "function") { |
| - var location = value['location'] != null |
| - ? ", file '${value['location']['url']}'" |
| - ", token pos ${value['location']['tokenOffset']}" |
| - : ""; |
| + var location = formatLocation(value['location']); |
| var name = value['name']; |
| var signature = value['signature']; |
| return "(closure ${name}${signature} $location)"; |
| @@ -376,7 +415,22 @@ |
| handleGetIsolatesResponse(response) { |
| Map result = response["result"]; |
| - print("Isolates: ${result["isolateIds"]}"); |
| + List ids = result["isolateIds"]; |
| + assert(ids != null); |
| + print("List of isolates:"); |
| + for (int id in ids) { |
| + TargetIsolate isolate = targetIsolates[id]; |
| + var state = (isolate != null) ? "running" : "<unknown isolate>"; |
| + if (isolate != null && isolate.isPaused) { |
| + var loc = formatLocation(isolate.pausedLocation); |
| + state = "paused at $loc"; |
| + } |
| + var marker = " "; |
| + if (currentIsolate != null && id == currentIsolate.id) { |
| + marker = "*"; |
| + } |
| + print("$marker $id $state"); |
| + } |
| } |
| @@ -432,10 +486,8 @@ |
| void printStackFrame(frame_num, Map frame) { |
| var fname = frame["functionName"]; |
| - var libId = frame["location"]["libraryId"]; |
| - var url = frame["location"]["url"]; |
| - var toff = frame["location"]["tokenOffset"]; |
| - print("$frame_num $fname (url: $url token: $toff lib: $libId)"); |
| + var loc = formatLocation(frame["location"]); |
| + print("$frame_num $fname ($loc)"); |
| List locals = frame["locals"]; |
| for (int i = 0; i < locals.length; i++) { |
| printNamedObject(locals[i]); |
| @@ -453,23 +505,60 @@ |
| void handlePausedEvent(msg) { |
| assert(msg["params"] != null); |
| var reason = msg["params"]["reason"]; |
| - isolate_id = msg["params"]["isolateId"]; |
| - assert(isolate_id != null); |
| - pausedLocation = msg["params"]["location"]; |
| - assert(pausedLocation != null); |
| + int isolateId = msg["params"]["isolateId"]; |
| + assert(isolateId != null); |
| + var isolate = targetIsolates[isolateId]; |
| + assert(isolate != null); |
| + assert(!isolate.isPaused); |
| + var location = msg["params"]["location"];; |
| + assert(location != null); |
| + isolate.pausedLocation = location; |
| if (reason == "breakpoint") { |
| - print("Isolate $isolate_id paused on breakpoint"); |
| - print("location: $pausedLocation"); |
| + print("Isolate $isolateId paused on breakpoint"); |
| + print("location: ${formatLocation(location)}"); |
| } else if (reason == "interrupted") { |
| - print("Isolate $isolate_id paused due to an interrupt"); |
| + print("Isolate $isolateId paused due to an interrupt"); |
| + print("location: ${formatLocation(location)}"); |
| } else { |
| assert(reason == "exception"); |
| var excObj = msg["params"]["exception"]; |
| - print("Isolate $isolate_id paused on exception"); |
| + print("Isolate $isolateId paused on exception"); |
| print(remoteObject(excObj)); |
| } |
| } |
| +void handleIsolateEvent(msg) { |
| + Map params = msg["params"]; |
| + assert(params != null); |
| + var isolateId = params["id"]; |
| + var reason = params["reason"]; |
| + if (reason == "created") { |
| + print("Isolate $isolateId has been created."); |
| + assert(targetIsolates[isolateId] == null); |
| + targetIsolates[isolateId] = new TargetIsolate(isolateId); |
| + if (mainIsolate == null) { |
| + mainIsolate = targetIsolates[isolateId]; |
| + currentIsolate = mainIsolate; |
| + print("Current isolate set to ${currentIsolate.id}."); |
| + } |
| + } else { |
| + assert(reason == "shutdown"); |
| + var isolate = targetIsolates.remove(isolateId); |
| + assert(isolate != null); |
| + if (isolate == currentIsolate) { |
| + currentIsolate == mainIsolate; |
| + } |
| + if (isolate == mainIsolate) { |
| + mainIsolate = currentIsolate = null; |
|
turnidge
2013/11/22 19:24:00
So terminating the main isolate always sets curren
hausner
2013/11/22 22:54:42
Probably not. The main isolate can terminate and t
|
| + print("Main isolate has terminated."); |
| + } else { |
| + print("Isolate ${isolate.id} has terminated."); |
| + } |
| + if (currentIsolate != null) { |
| + print("Setting current isolate to ${currentIsolate.id}."); |
| + } |
| + } |
| +} |
| void processVmMessage(String jsonString) { |
| var msg = JSON.decode(jsonString); |
| @@ -477,6 +566,10 @@ |
| return; |
| } |
| var event = msg["event"]; |
| + if (event == "isolate") { |
| + handleIsolateEvent(msg); |
| + return; |
| + } |
| if (event == "paused") { |
| handlePausedEvent(msg); |
| return; |
| @@ -484,16 +577,12 @@ |
| if (event == "breakpointResolved") { |
| Map params = msg["params"]; |
| assert(params != null); |
| - print("BP ${params["breakpointId"]} resolved and " |
| - "set at line ${params["line"]}."); |
| + var isolateId = params["isolateId"]; |
| + var location = formatLocation(params["location"]); |
| + print("BP ${params["breakpointId"]} resolved in isolate $isolateId" |
| + " at $location."); |
| return; |
| } |
| - if (event == "isolate") { |
| - Map params = msg["params"]; |
| - assert(params != null); |
| - print("Isolate ${params["id"]} has been ${params["reason"]}."); |
| - return; |
| - } |
| if (msg["id"] != null) { |
| var id = msg["id"]; |
| if (outstandingCommands.containsKey(id)) { |