| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 debugger_page_element; | 5 library debugger_page_element; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'observatory_element.dart'; | 9 import 'observatory_element.dart'; |
| 10 import 'package:observatory/app.dart'; |
| 10 import 'package:observatory/cli.dart'; | 11 import 'package:observatory/cli.dart'; |
| 11 import 'package:observatory/debugger.dart'; | 12 import 'package:observatory/debugger.dart'; |
| 12 import 'package:observatory/service.dart'; | 13 import 'package:observatory/service.dart'; |
| 13 import 'package:logging/logging.dart'; | 14 import 'package:logging/logging.dart'; |
| 14 import 'package:polymer/polymer.dart'; | 15 import 'package:polymer/polymer.dart'; |
| 15 | 16 |
| 16 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. | 17 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. |
| 17 abstract class DebuggerCommand extends Command { | 18 abstract class DebuggerCommand extends Command { |
| 18 ObservatoryDebugger debugger; | 19 ObservatoryDebugger debugger; |
| 19 | 20 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 count = int.parse(args[0]); | 184 count = int.parse(args[0]); |
| 184 } else if (args.length > 1) { | 185 } else if (args.length > 1) { |
| 185 debugger.console.print('down expects 0 or 1 argument'); | 186 debugger.console.print('down expects 0 or 1 argument'); |
| 186 return new Future.value(null); | 187 return new Future.value(null); |
| 187 } | 188 } |
| 188 if (debugger.currentFrame == null) { | 189 if (debugger.currentFrame == null) { |
| 189 debugger.console.print('No stack'); | 190 debugger.console.print('No stack'); |
| 190 return new Future.value(null); | 191 return new Future.value(null); |
| 191 } | 192 } |
| 192 try { | 193 try { |
| 193 debugger.currentFrame += count; | 194 debugger.downFrame(count); |
| 194 debugger.console.print('frame = ${debugger.currentFrame}'); | 195 debugger.console.print('frame = ${debugger.currentFrame}'); |
| 195 } catch (e) { | 196 } catch (e) { |
| 196 debugger.console.print('frame must be in range [${e.start},${e.end-1}]'); | 197 debugger.console.print('frame must be in range [${e.start},${e.end-1}]'); |
| 197 } | 198 } |
| 198 return new Future.value(null); | 199 return new Future.value(null); |
| 199 } | 200 } |
| 200 | 201 |
| 201 String helpShort = 'Move down one or more frames (hotkey: [Page Down])'; | 202 String helpShort = 'Move down one or more frames (hotkey: [Page Down])'; |
| 202 | 203 |
| 203 String helpLong = | 204 String helpLong = |
| (...skipping 14 matching lines...) Expand all Loading... |
| 218 count = int.parse(args[0]); | 219 count = int.parse(args[0]); |
| 219 } else if (args.length > 1) { | 220 } else if (args.length > 1) { |
| 220 debugger.console.print('up expects 0 or 1 argument'); | 221 debugger.console.print('up expects 0 or 1 argument'); |
| 221 return new Future.value(null); | 222 return new Future.value(null); |
| 222 } | 223 } |
| 223 if (debugger.currentFrame == null) { | 224 if (debugger.currentFrame == null) { |
| 224 debugger.console.print('No stack'); | 225 debugger.console.print('No stack'); |
| 225 return new Future.value(null); | 226 return new Future.value(null); |
| 226 } | 227 } |
| 227 try { | 228 try { |
| 228 debugger.currentFrame -= count; | 229 debugger.upFrame(count); |
| 229 debugger.console.print('frame = ${debugger.currentFrame}'); | 230 debugger.console.print('frame = ${debugger.currentFrame}'); |
| 230 } on RangeError catch (e) { | 231 } on RangeError catch (e) { |
| 231 debugger.console.print('frame must be in range [${e.start},${e.end-1}]'); | 232 debugger.console.print('frame must be in range [${e.start},${e.end-1}]'); |
| 232 } | 233 } |
| 233 return new Future.value(null); | 234 return new Future.value(null); |
| 234 } | 235 } |
| 235 | 236 |
| 236 String helpShort = 'Move up one or more frames (hotkey: [Page Up])'; | 237 String helpShort = 'Move up one or more frames (hotkey: [Page Up])'; |
| 237 | 238 |
| 238 String helpLong = | 239 String helpLong = |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 String helpLong = | 490 String helpLong = |
| 490 'Continue running the isolate until the current function exits.\n' | 491 'Continue running the isolate until the current function exits.\n' |
| 491 '\n' | 492 '\n' |
| 492 'Syntax: finish\n'; | 493 'Syntax: finish\n'; |
| 493 } | 494 } |
| 494 | 495 |
| 495 class SetCommand extends DebuggerCommand { | 496 class SetCommand extends DebuggerCommand { |
| 496 SetCommand(Debugger debugger) | 497 SetCommand(Debugger debugger) |
| 497 : super(debugger, 'set', []); | 498 : super(debugger, 'set', []); |
| 498 | 499 |
| 500 static var _boeValues = ['all', 'none', 'unhandled']; |
| 501 static var _boolValues = ['false', 'true']; |
| 502 |
| 503 static var _options = { |
| 504 'break-on-exception': [_boeValues, |
| 505 _setBreakOnException, |
| 506 (debugger, _) => debugger.breakOnException], |
| 507 'up-is-down': [_boolValues, |
| 508 _setUpIsDown, |
| 509 (debugger, _) => debugger.upIsDown], |
| 510 }; |
| 511 |
| 512 static Future _setBreakOnException(debugger, name, value) async { |
| 513 var result = await debugger.isolate.setExceptionPauseInfo(value); |
| 514 if (result.isError) { |
| 515 debugger.console.print(result.toString()); |
| 516 } else { |
| 517 // Printing will occur elsewhere. |
| 518 debugger.breakOnException = value; |
| 519 } |
| 520 } |
| 521 |
| 522 static Future _setUpIsDown(debugger, name, value) async { |
| 523 if (value == 'true') { |
| 524 debugger.upIsDown = true; |
| 525 } else { |
| 526 debugger.upIsDown = false; |
| 527 } |
| 528 debugger.console.print('${name} = ${value}'); |
| 529 } |
| 530 |
| 499 Future run(List<String> args) async { | 531 Future run(List<String> args) async { |
| 532 if (args.length == 0) { |
| 533 for (var name in _options.keys) { |
| 534 var getHandler = _options[name][2]; |
| 535 var value = await getHandler(debugger, name); |
| 536 debugger.console.print("${name} = ${value}"); |
| 537 } |
| 538 } else if (args.length == 1) { |
| 539 var name = args[0].trim(); |
| 540 var optionInfo = _options[name]; |
| 541 if (optionInfo == null) { |
| 542 debugger.console.print("unrecognized option: $name"); |
| 543 return; |
| 544 } else { |
| 545 var getHandler = optionInfo[2]; |
| 546 var value = await getHandler(debugger, name); |
| 547 debugger.console.print("${name} = ${value}"); |
| 548 } |
| 549 } else if (args.length == 2) { |
| 550 var name = args[0].trim(); |
| 551 var value = args[1].trim(); |
| 552 var optionInfo = _options[name]; |
| 553 if (optionInfo == null) { |
| 554 debugger.console.print("unrecognized option: $name"); |
| 555 return; |
| 556 } |
| 557 var validValues = optionInfo[0]; |
| 558 if (!validValues.contains(value)) { |
| 559 debugger.console.print("'${value}' is not in ${validValues}"); |
| 560 return; |
| 561 } |
| 562 var setHandler = optionInfo[1]; |
| 563 await setHandler(debugger, name, value); |
| 564 } else { |
| 565 debugger.console.print("set expects 0, 1, or 2 arguments"); |
| 566 } |
| 567 } |
| 568 |
| 569 Future<List<String>> complete(List<String> args) { |
| 570 if (args.length < 1 || args.length > 2) { |
| 571 return new Future.value([args.join('')]); |
| 572 } |
| 573 var result = []; |
| 574 if (args.length == 1) { |
| 575 var prefix = args[0]; |
| 576 for (var option in _options.keys) { |
| 577 if (option.startsWith(prefix)) { |
| 578 result.add('${option} '); |
| 579 } |
| 580 } |
| 581 } |
| 500 if (args.length == 2) { | 582 if (args.length == 2) { |
| 501 var option = args[0].trim(); | 583 var name = args[0].trim(); |
| 502 if (option == 'break-on-exceptions') { | 584 var prefix = args[1]; |
| 503 var result = await debugger.isolate.setExceptionPauseInfo(args[1]); | 585 var optionInfo = _options[name]; |
| 504 if (result.isError) { | 586 if (optionInfo != null) { |
| 505 debugger.console.print(result.toString()); | 587 var validValues = optionInfo[0]; |
| 588 for (var value in validValues) { |
| 589 if (value.startsWith(prefix)) { |
| 590 result.add('${args[0]}${value} '); |
| 591 } |
| 506 } | 592 } |
| 507 } else { | |
| 508 debugger.console.print("unknown option '$option'"); | |
| 509 } | 593 } |
| 510 } else { | |
| 511 debugger.console.print("set expects 2 arguments"); | |
| 512 } | 594 } |
| 595 return new Future.value(result); |
| 513 } | 596 } |
| 514 | 597 |
| 515 String helpShort = | 598 String helpShort = |
| 516 'Set a debugger option'; | 599 'Set a debugger option'; |
| 517 | 600 |
| 518 String helpLong = | 601 String helpLong = |
| 519 'Set a debugger option' | 602 'Set a debugger option.\n' |
| 520 '\n' | 603 '\n' |
| 521 'Syntax: set break-on-exceptions "all" | "none" | "unhandled"\n'; | 604 'Known options:\n' |
| 605 ' break-on-exceptions # Should the debugger break on exceptions?\n' |
| 606 " # ${_boeValues}\n" |
| 607 ' up-is-down # Reverse meaning of up/down commands?\n' |
| 608 " # ${_boolValues}\n" |
| 609 '\n' |
| 610 'Syntax: set # Display all option settings\n' |
| 611 ' set <option> # Get current value for option\n' |
| 612 ' set <option> <value> # Set value for option'; |
| 522 } | 613 } |
| 523 | 614 |
| 524 class BreakCommand extends DebuggerCommand { | 615 class BreakCommand extends DebuggerCommand { |
| 525 BreakCommand(Debugger debugger) : super(debugger, 'break', []); | 616 BreakCommand(Debugger debugger) : super(debugger, 'break', []); |
| 526 | 617 |
| 527 Future run(List<String> args) async { | 618 Future run(List<String> args) async { |
| 528 if (args.length > 1) { | 619 if (args.length > 1) { |
| 529 debugger.console.print('not implemented'); | 620 debugger.console.print('not implemented'); |
| 530 return new Future.value(null); | 621 return new Future.value(null); |
| 531 } | 622 } |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 } | 1138 } |
| 1048 } | 1139 } |
| 1049 | 1140 |
| 1050 String _format(String isolateName, String streamName, String line) { | 1141 String _format(String isolateName, String streamName, String line) { |
| 1051 return '${isolateName}:${streamName}> ${line}'; | 1142 return '${isolateName}:${streamName}> ${line}'; |
| 1052 } | 1143 } |
| 1053 } | 1144 } |
| 1054 | 1145 |
| 1055 // Tracks the state for an isolate debugging session. | 1146 // Tracks the state for an isolate debugging session. |
| 1056 class ObservatoryDebugger extends Debugger { | 1147 class ObservatoryDebugger extends Debugger { |
| 1148 final SettingsGroup settings = new SettingsGroup('debugger'); |
| 1057 RootCommand cmd; | 1149 RootCommand cmd; |
| 1058 DebuggerPageElement page; | 1150 DebuggerPageElement page; |
| 1059 DebuggerConsoleElement console; | 1151 DebuggerConsoleElement console; |
| 1060 DebuggerInputElement input; | 1152 DebuggerInputElement input; |
| 1061 DebuggerStackElement stackElement; | 1153 DebuggerStackElement stackElement; |
| 1062 ServiceMap stack; | 1154 ServiceMap stack; |
| 1063 String exceptions = "none"; // Last known setting. | 1155 String breakOnException = "none"; // Last known setting. |
| 1064 | 1156 |
| 1065 int get currentFrame => _currentFrame; | 1157 int get currentFrame => _currentFrame; |
| 1158 |
| 1066 void set currentFrame(int value) { | 1159 void set currentFrame(int value) { |
| 1067 if (value != null && (value < 0 || value >= stackDepth)) { | 1160 if (value != null && (value < 0 || value >= stackDepth)) { |
| 1068 throw new RangeError.range(value, 0, stackDepth); | 1161 throw new RangeError.range(value, 0, stackDepth); |
| 1069 } | 1162 } |
| 1070 _currentFrame = value; | 1163 _currentFrame = value; |
| 1071 if (stackElement != null) { | 1164 if (stackElement != null) { |
| 1072 stackElement.setCurrentFrame(value); | 1165 stackElement.setCurrentFrame(value); |
| 1073 } | 1166 } |
| 1074 } | 1167 } |
| 1075 int _currentFrame = null; | 1168 int _currentFrame = null; |
| 1076 | 1169 |
| 1170 bool get upIsDown => _upIsDown; |
| 1171 void set upIsDown(bool value) { |
| 1172 settings.set('up-is-down', value); |
| 1173 _upIsDown = value; |
| 1174 } |
| 1175 bool _upIsDown; |
| 1176 |
| 1177 void upFrame(int count) { |
| 1178 if (_upIsDown) { |
| 1179 currentFrame += count; |
| 1180 } else { |
| 1181 currentFrame -= count; |
| 1182 } |
| 1183 } |
| 1184 |
| 1185 void downFrame(int count) { |
| 1186 if (_upIsDown) { |
| 1187 currentFrame -= count; |
| 1188 } else { |
| 1189 currentFrame += count; |
| 1190 } |
| 1191 } |
| 1192 |
| 1077 int get stackDepth => stack['frames'].length; | 1193 int get stackDepth => stack['frames'].length; |
| 1078 | 1194 |
| 1079 ObservatoryDebugger() { | 1195 ObservatoryDebugger() { |
| 1196 _loadSettings(); |
| 1080 cmd = new RootCommand([ | 1197 cmd = new RootCommand([ |
| 1081 new HelpCommand(this), | 1198 new HelpCommand(this), |
| 1082 new PrintCommand(this), | 1199 new PrintCommand(this), |
| 1083 new DownCommand(this), | 1200 new DownCommand(this), |
| 1084 new UpCommand(this), | 1201 new UpCommand(this), |
| 1085 new FrameCommand(this), | 1202 new FrameCommand(this), |
| 1086 new PauseCommand(this), | 1203 new PauseCommand(this), |
| 1087 new ContinueCommand(this), | 1204 new ContinueCommand(this), |
| 1088 new NextCommand(this), | 1205 new NextCommand(this), |
| 1089 new StepCommand(this), | 1206 new StepCommand(this), |
| 1090 new AsyncNextCommand(this), | 1207 new AsyncNextCommand(this), |
| 1091 new FinishCommand(this), | 1208 new FinishCommand(this), |
| 1092 new BreakCommand(this), | 1209 new BreakCommand(this), |
| 1093 new SetCommand(this), | 1210 new SetCommand(this), |
| 1094 new ClearCommand(this), | 1211 new ClearCommand(this), |
| 1095 new DeleteCommand(this), | 1212 new DeleteCommand(this), |
| 1096 new InfoCommand(this), | 1213 new InfoCommand(this), |
| 1097 new IsolateCommand(this), | 1214 new IsolateCommand(this), |
| 1098 new RefreshCommand(this), | 1215 new RefreshCommand(this), |
| 1099 new LogCommand(this), | 1216 new LogCommand(this), |
| 1100 new ClsCommand(this), | 1217 new ClsCommand(this), |
| 1101 ]); | 1218 ]); |
| 1102 _consolePrinter = new _ConsoleStreamPrinter(this); | 1219 _consolePrinter = new _ConsoleStreamPrinter(this); |
| 1103 } | 1220 } |
| 1104 | 1221 |
| 1222 void _loadSettings() { |
| 1223 _upIsDown = settings.get('up-is-down'); |
| 1224 } |
| 1225 |
| 1105 VM get vm => page.app.vm; | 1226 VM get vm => page.app.vm; |
| 1106 | 1227 |
| 1107 void updateIsolate(Isolate iso) { | 1228 void updateIsolate(Isolate iso) { |
| 1108 _isolate = iso; | 1229 _isolate = iso; |
| 1109 if (_isolate != null) { | 1230 if (_isolate != null) { |
| 1110 if ((exceptions != iso.exceptionsPauseInfo) && | 1231 if ((breakOnException != iso.exceptionsPauseInfo) && |
| 1111 (iso.exceptionsPauseInfo != null)) { | 1232 (iso.exceptionsPauseInfo != null)) { |
| 1112 exceptions = iso.exceptionsPauseInfo; | 1233 breakOnException = iso.exceptionsPauseInfo; |
| 1113 console.print("Now pausing for $exceptions exceptions"); | 1234 console.print("Now pausing for exceptions: $breakOnException"); |
| 1114 } | 1235 } |
| 1115 | 1236 |
| 1116 _isolate.reload().then((response) { | 1237 _isolate.reload().then((response) { |
| 1117 // TODO(turnidge): Currently the debugger relies on all libs | 1238 // TODO(turnidge): Currently the debugger relies on all libs |
| 1118 // being loaded. Fix this. | 1239 // being loaded. Fix this. |
| 1119 var pending = []; | 1240 var pending = []; |
| 1120 for (var lib in _isolate.libraries) { | 1241 for (var lib in _isolate.libraries) { |
| 1121 if (!lib.loaded) { | 1242 if (!lib.loaded) { |
| 1122 pending.add(lib.load()); | 1243 pending.add(lib.load()); |
| 1123 } | 1244 } |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1298 if (iso == isolate) { | 1419 if (iso == isolate) { |
| 1299 console.print("The current isolate has exited"); | 1420 console.print("The current isolate has exited"); |
| 1300 } else { | 1421 } else { |
| 1301 console.print( | 1422 console.print( |
| 1302 "Isolate ${iso.number} '${iso.name}' has exited"); | 1423 "Isolate ${iso.number} '${iso.name}' has exited"); |
| 1303 } | 1424 } |
| 1304 } | 1425 } |
| 1305 break; | 1426 break; |
| 1306 | 1427 |
| 1307 case ServiceEvent.kDebuggerSettingsUpdate: | 1428 case ServiceEvent.kDebuggerSettingsUpdate: |
| 1308 if (exceptions != event.exceptions) { | 1429 if (breakOnException != event.exceptions) { |
| 1309 exceptions = event.exceptions; | 1430 breakOnException = event.exceptions; |
| 1310 console.print("Now pausing for $exceptions exceptions"); | 1431 console.print("Now pausing for exceptions: $breakOnException"); |
| 1311 } | 1432 } |
| 1312 break; | 1433 break; |
| 1313 | 1434 |
| 1314 case ServiceEvent.kIsolateUpdate: | 1435 case ServiceEvent.kIsolateUpdate: |
| 1315 var iso = event.owner; | 1436 var iso = event.owner; |
| 1316 console.print("Isolate ${iso.number} renamed to '${iso.name}'"); | 1437 console.print("Isolate ${iso.number} renamed to '${iso.name}'"); |
| 1317 break; | 1438 break; |
| 1318 | 1439 |
| 1319 case ServiceEvent.kPauseStart: | 1440 case ServiceEvent.kPauseStart: |
| 1320 case ServiceEvent.kPauseExit: | 1441 case ServiceEvent.kPauseExit: |
| (...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2108 | 2229 |
| 2109 case KeyCode.DOWN: | 2230 case KeyCode.DOWN: |
| 2110 e.preventDefault(); | 2231 e.preventDefault(); |
| 2111 text = debugger.historyNext(text); | 2232 text = debugger.historyNext(text); |
| 2112 busy = false; | 2233 busy = false; |
| 2113 break; | 2234 break; |
| 2114 | 2235 |
| 2115 case KeyCode.PAGE_UP: | 2236 case KeyCode.PAGE_UP: |
| 2116 e.preventDefault(); | 2237 e.preventDefault(); |
| 2117 try { | 2238 try { |
| 2118 debugger.currentFrame -= 1; | 2239 debugger.upFrame(1); |
| 2119 } on RangeError catch (e) { | 2240 } on RangeError catch (e) { |
| 2120 // Ignore. | 2241 // Ignore. |
| 2121 } | 2242 } |
| 2122 busy = false; | 2243 busy = false; |
| 2123 break; | 2244 break; |
| 2124 | 2245 |
| 2125 case KeyCode.PAGE_DOWN: | 2246 case KeyCode.PAGE_DOWN: |
| 2126 e.preventDefault(); | 2247 e.preventDefault(); |
| 2127 try { | 2248 try { |
| 2128 debugger.currentFrame += 1; | 2249 debugger.downFrame(1); |
| 2129 } on RangeError catch (e) { | 2250 } on RangeError catch (e) { |
| 2130 // Ignore. | 2251 // Ignore. |
| 2131 } | 2252 } |
| 2132 busy = false; | 2253 busy = false; |
| 2133 break; | 2254 break; |
| 2134 | 2255 |
| 2135 case KeyCode.F7: | 2256 case KeyCode.F7: |
| 2136 e.preventDefault(); | 2257 e.preventDefault(); |
| 2137 debugger.resume().whenComplete(() { | 2258 debugger.resume().whenComplete(() { |
| 2138 busy = false; | 2259 busy = false; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2178 } | 2299 } |
| 2179 }); | 2300 }); |
| 2180 } | 2301 } |
| 2181 | 2302 |
| 2182 void focus() { | 2303 void focus() { |
| 2183 $['textBox'].focus(); | 2304 $['textBox'].focus(); |
| 2184 } | 2305 } |
| 2185 | 2306 |
| 2186 DebuggerInputElement.created() : super.created(); | 2307 DebuggerInputElement.created() : super.created(); |
| 2187 } | 2308 } |
| OLD | NEW |