Chromium Code Reviews| 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 #include "vm/service.h" | 5 #include "vm/service.h" |
| 6 | 6 |
| 7 #include "vm/cpu.h" | 7 #include "vm/cpu.h" |
| 8 #include "vm/dart_entry.h" | 8 #include "vm/dart_entry.h" |
| 9 #include "vm/debugger.h" | 9 #include "vm/debugger.h" |
| 10 #include "vm/heap_histogram.h" | 10 #include "vm/heap_histogram.h" |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 | 232 |
| 233 | 233 |
| 234 // Print an error message if there is no ID argument. | 234 // Print an error message if there is no ID argument. |
| 235 #define REQUIRE_COLLECTION_ID(collection) \ | 235 #define REQUIRE_COLLECTION_ID(collection) \ |
| 236 if (js->num_arguments() == 1) { \ | 236 if (js->num_arguments() == 1) { \ |
| 237 PrintError(js, "Must specify collection object id: /%s/id", collection); \ | 237 PrintError(js, "Must specify collection object id: /%s/id", collection); \ |
| 238 return; \ | 238 return; \ |
| 239 } | 239 } |
| 240 | 240 |
| 241 | 241 |
| 242 #define CHECK_COLLECTION_ID_BOUNDS(collection, length, arg, id, js) \ | |
| 243 if (!GetIntegerId(arg, &id)) { \ | |
| 244 PrintError(js, "Must specify collection object id: %s/id", collection); \ | |
| 245 return; \ | |
| 246 } \ | |
| 247 if ((id < 0) || (id >= length)) { \ | |
| 248 PrintError(js, "%s id (%" Pd ") must be in [0, %" Pd ").", collection, id, \ | |
| 249 length); \ | |
|
turnidge
2013/12/20 17:44:45
For discussion only - this message exposes that we
| |
| 250 return; \ | |
| 251 } | |
| 252 | |
| 253 | |
| 254 static bool GetIntegerId(const char* s, intptr_t* id) { | |
| 255 if ((s == NULL) || (*s == '\0')) { | |
| 256 // Empty string. | |
| 257 return false; | |
| 258 } | |
| 259 if (id == NULL) { | |
| 260 // No id pointer. | |
| 261 return false; | |
| 262 } | |
| 263 intptr_t r = 0; | |
| 264 char* end_ptr = NULL; | |
| 265 r = strtol(s, &end_ptr, 10); | |
| 266 if (end_ptr == s) { | |
| 267 // String was not advanced at all, cannot be valid. | |
| 268 return false; | |
| 269 } | |
| 270 *id = r; | |
| 271 return true; | |
| 272 } | |
| 273 | |
| 274 | |
| 275 static void HandleClassesClosures(Isolate* isolate, const Class& cls, | |
| 276 JSONStream* js) { | |
| 277 const GrowableObjectArray& closures = | |
| 278 GrowableObjectArray::Handle(cls.closures()); | |
| 279 intptr_t id; | |
| 280 CHECK_COLLECTION_ID_BOUNDS("closures", closures.Length(), js->GetArgument(3), | |
| 281 id, js); | |
|
turnidge
2013/12/20 17:44:45
Add check that js->num_arguments() == 4 with nice
Cutch
2013/12/20 18:23:46
Done.
| |
| 282 Function& function = Function::Handle(); | |
| 283 function ^= closures.At(id); | |
| 284 ASSERT(!function.IsNull()); | |
| 285 function.PrintToJSONStream(js, false); | |
| 286 } | |
| 287 | |
| 288 | |
| 289 static void HandleClassesFunctions(Isolate* isolate, const Class& cls, | |
| 290 JSONStream* js) { | |
| 291 const Array& functions = | |
| 292 Array::Handle(cls.functions()); | |
| 293 intptr_t id; | |
| 294 CHECK_COLLECTION_ID_BOUNDS("functions", functions.Length(), | |
| 295 js->GetArgument(3), id, js); | |
| 296 Function& function = Function::Handle(); | |
| 297 function ^= functions.At(id); | |
| 298 ASSERT(!function.IsNull()); | |
| 299 function.PrintToJSONStream(js, false); | |
| 300 } | |
| 301 | |
| 302 | |
| 303 static void HandleClassesFields(Isolate* isolate, const Class& cls, | |
| 304 JSONStream* js) { | |
| 305 const Array& fields = | |
| 306 Array::Handle(cls.fields()); | |
| 307 intptr_t id; | |
| 308 CHECK_COLLECTION_ID_BOUNDS("fields", fields.Length(), js->GetArgument(3), | |
| 309 id, js); | |
| 310 Field& field = Field::Handle(); | |
| 311 field ^= fields.At(id); | |
| 312 ASSERT(!field.IsNull()); | |
| 313 field.PrintToJSONStream(js, false); | |
| 314 } | |
| 315 | |
| 316 | |
| 242 static void HandleClasses(Isolate* isolate, JSONStream* js) { | 317 static void HandleClasses(Isolate* isolate, JSONStream* js) { |
| 243 if (js->num_arguments() == 1) { | 318 if (js->num_arguments() == 1) { |
| 244 ClassTable* table = isolate->class_table(); | 319 ClassTable* table = isolate->class_table(); |
| 245 table->PrintToJSONStream(js); | 320 table->PrintToJSONStream(js); |
| 246 return; | 321 return; |
| 247 } | 322 } |
| 248 ASSERT(js->num_arguments() >= 2); | 323 ASSERT(js->num_arguments() >= 2); |
| 249 intptr_t id = atoi(js->GetArgument(1)); | 324 intptr_t id; |
| 325 if (!GetIntegerId(js->GetArgument(1), &id)) { | |
| 326 PrintError(js, "Must specify collection object id: /classes/id"); | |
| 327 return; | |
| 328 } | |
| 250 ClassTable* table = isolate->class_table(); | 329 ClassTable* table = isolate->class_table(); |
| 251 if (!table->IsValidIndex(id)) { | 330 if (!table->IsValidIndex(id)) { |
| 252 Object::null_object().PrintToJSONStream(js, false); | 331 PrintError(js, "%" Pd " is not a valid class id.", id);; |
| 253 } else { | 332 return; |
| 254 Class& cls = Class::Handle(table->At(id)); | 333 } |
| 334 Class& cls = Class::Handle(table->At(id)); | |
| 335 if (js->num_arguments() == 2) { | |
| 255 cls.PrintToJSONStream(js, false); | 336 cls.PrintToJSONStream(js, false); |
| 337 return; | |
| 338 } else if (js->num_arguments() >= 3) { | |
| 339 const char* second = js->GetArgument(2); | |
| 340 if (!strcmp(second, "closures")) { | |
| 341 HandleClassesClosures(isolate, cls, js); | |
| 342 } else if (!strcmp(second, "fields")) { | |
| 343 HandleClassesFields(isolate, cls, js); | |
| 344 } else if (!strcmp(second, "functions")) { | |
| 345 HandleClassesFunctions(isolate, cls, js); | |
| 346 } else { | |
| 347 PrintError(js, "Invalid sub collection %s", second); | |
| 348 } | |
| 349 return; | |
| 256 } | 350 } |
| 351 UNREACHABLE(); | |
| 257 } | 352 } |
| 258 | 353 |
| 259 | 354 |
| 260 static void HandleLibrary(Isolate* isolate, JSONStream* js) { | 355 static void HandleLibrary(Isolate* isolate, JSONStream* js) { |
| 261 if (js->num_arguments() == 1) { | 356 if (js->num_arguments() == 1) { |
| 262 const Library& lib = | 357 const Library& lib = |
| 263 Library::Handle(isolate->object_store()->root_library()); | 358 Library::Handle(isolate->object_store()->root_library()); |
| 264 lib.PrintToJSONStream(js, false); | 359 lib.PrintToJSONStream(js, false); |
| 265 return; | 360 return; |
| 266 } | 361 } |
| 267 PrintGenericError(js); | 362 PrintGenericError(js); |
| 268 } | 363 } |
| 269 | 364 |
| 270 | 365 |
| 366 static void HandleLibraries(Isolate* isolate, JSONStream* js) { | |
| 367 // TODO(johnmccutchan): Support fields and functions on libraries. | |
| 368 REQUIRE_COLLECTION_ID("libraries"); | |
| 369 const GrowableObjectArray& libs = | |
| 370 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | |
| 371 ASSERT(!libs.IsNull()); | |
| 372 intptr_t id = 0; | |
| 373 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1), | |
| 374 id, js); | |
| 375 Library& lib = Library::Handle(); | |
| 376 lib ^= libs.At(id); | |
| 377 ASSERT(!lib.IsNull()); | |
| 378 lib.PrintToJSONStream(js, false); | |
| 379 } | |
| 380 | |
| 381 | |
| 271 static void HandleObjects(Isolate* isolate, JSONStream* js) { | 382 static void HandleObjects(Isolate* isolate, JSONStream* js) { |
| 272 REQUIRE_COLLECTION_ID("objects"); | 383 REQUIRE_COLLECTION_ID("objects"); |
| 273 ASSERT(js->num_arguments() >= 2); | 384 ASSERT(js->num_arguments() >= 2); |
| 274 ObjectIdRing* ring = isolate->object_id_ring(); | 385 ObjectIdRing* ring = isolate->object_id_ring(); |
| 275 ASSERT(ring != NULL); | 386 ASSERT(ring != NULL); |
| 276 intptr_t id = atoi(js->GetArgument(1)); | 387 intptr_t id = -1; |
| 388 if (!GetIntegerId(js->GetArgument(1), &id)) { | |
| 389 Object::null_object().PrintToJSONStream(js, false); | |
| 390 return; | |
| 391 } | |
| 277 Object& obj = Object::Handle(ring->GetObjectForId(id)); | 392 Object& obj = Object::Handle(ring->GetObjectForId(id)); |
| 278 obj.PrintToJSONStream(js, false); | 393 obj.PrintToJSONStream(js, false); |
| 279 } | 394 } |
| 280 | 395 |
| 281 | 396 |
| 397 | |
| 398 static void HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { | |
| 399 JSONObject jsobj(js); | |
| 400 jsobj.AddProperty("type", "ScriptList"); | |
| 401 { | |
| 402 JSONArray members(&jsobj, "members"); | |
| 403 const GrowableObjectArray& libs = | |
| 404 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | |
| 405 int num_libs = libs.Length(); | |
| 406 Library &lib = Library::Handle(); | |
| 407 Script& script = Script::Handle(); | |
| 408 for (intptr_t i = 0; i < num_libs; i++) { | |
| 409 lib ^= libs.At(i); | |
| 410 ASSERT(!lib.IsNull()); | |
| 411 ASSERT(Smi::IsValid(lib.index())); | |
| 412 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); | |
| 413 ASSERT(!loaded_scripts.IsNull()); | |
| 414 intptr_t num_scripts = loaded_scripts.Length(); | |
| 415 for (intptr_t i = 0; i < num_scripts; i++) { | |
| 416 script ^= loaded_scripts.At(i); | |
| 417 members.AddValue(script); | |
| 418 } | |
| 419 } | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 | |
| 424 static void HandleScriptsFetch(Isolate* isolate, JSONStream* js) { | |
| 425 const GrowableObjectArray& libs = | |
| 426 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | |
| 427 int num_libs = libs.Length(); | |
| 428 Library &lib = Library::Handle(); | |
| 429 Script& script = Script::Handle(); | |
| 430 String& url = String::Handle(); | |
| 431 const String& id = String::Handle(String::New(js->GetArgument(1))); | |
| 432 ASSERT(!id.IsNull()); | |
| 433 // The id is the url of the script % encoded, decode it. | |
| 434 String& requested_url = String::Handle(String::DecodeURI(id)); | |
| 435 for (intptr_t i = 0; i < num_libs; i++) { | |
| 436 lib ^= libs.At(i); | |
| 437 ASSERT(!lib.IsNull()); | |
| 438 ASSERT(Smi::IsValid(lib.index())); | |
| 439 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); | |
| 440 ASSERT(!loaded_scripts.IsNull()); | |
| 441 intptr_t num_scripts = loaded_scripts.Length(); | |
| 442 for (intptr_t i = 0; i < num_scripts; i++) { | |
| 443 script ^= loaded_scripts.At(i); | |
| 444 ASSERT(!script.IsNull()); | |
| 445 url ^= script.url(); | |
| 446 if (url.Equals(requested_url)) { | |
| 447 script.PrintToJSONStream(js, false); | |
| 448 return; | |
| 449 } | |
| 450 } | |
| 451 } | |
| 452 PrintError(js, "Cannot find script %s\n", requested_url.ToCString()); | |
| 453 } | |
| 454 | |
| 455 | |
| 456 static void HandleScripts(Isolate* isolate, JSONStream* js) { | |
| 457 if (js->num_arguments() == 1) { | |
| 458 // Enumerate all scripts. | |
| 459 HandleScriptsEnumerate(isolate, js); | |
| 460 } else if (js->num_arguments() == 2) { | |
| 461 // Fetch specific script. | |
| 462 HandleScriptsFetch(isolate, js); | |
| 463 } else { | |
| 464 PrintError(js, "Command too long"); | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 | |
| 282 static void HandleDebug(Isolate* isolate, JSONStream* js) { | 469 static void HandleDebug(Isolate* isolate, JSONStream* js) { |
| 283 if (js->num_arguments() == 1) { | 470 if (js->num_arguments() == 1) { |
| 284 PrintError(js, "Must specify a subcommand"); | 471 PrintError(js, "Must specify a subcommand"); |
| 285 return; | 472 return; |
| 286 } | 473 } |
| 287 const char* command = js->GetArgument(1); | 474 const char* command = js->GetArgument(1); |
| 288 if (!strcmp(command, "breakpoints")) { | 475 if (!strcmp(command, "breakpoints")) { |
| 289 if (js->num_arguments() == 2) { | 476 if (js->num_arguments() == 2) { |
| 290 // Print breakpoint list. | 477 // Print breakpoint list. |
| 291 JSONObject jsobj(js); | 478 JSONObject jsobj(js); |
| 292 jsobj.AddProperty("type", "BreakpointList"); | 479 jsobj.AddProperty("type", "BreakpointList"); |
| 293 JSONArray jsarr(&jsobj, "breakpoints"); | 480 JSONArray jsarr(&jsobj, "breakpoints"); |
| 294 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); | 481 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); |
| 295 | 482 |
| 296 } else if (js->num_arguments() == 3) { | 483 } else if (js->num_arguments() == 3) { |
| 297 // Print individual breakpoint. | 484 // Print individual breakpoint. |
| 298 intptr_t id = atoi(js->GetArgument(2)); | 485 intptr_t id = 0; |
| 299 SourceBreakpoint* bpt = isolate->debugger()->GetBreakpointById(id); | 486 SourceBreakpoint* bpt = NULL; |
| 487 if (GetIntegerId(js->GetArgument(2), &id)) { | |
| 488 bpt = isolate->debugger()->GetBreakpointById(id); | |
| 489 } | |
| 300 if (bpt != NULL) { | 490 if (bpt != NULL) { |
| 301 bpt->PrintToJSONStream(js); | 491 bpt->PrintToJSONStream(js); |
| 302 } else { | 492 } else { |
| 303 PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2)); | 493 PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2)); |
| 304 } | 494 } |
| 305 | 495 |
| 306 } else { | 496 } else { |
| 307 PrintError(js, "Command too long"); | 497 PrintError(js, "Command too long"); |
| 308 } | 498 } |
| 309 } else { | 499 } else { |
| 310 PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1)); | 500 PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1)); |
| 311 } | 501 } |
| 312 } | 502 } |
| 313 | 503 |
| 314 | 504 |
| 315 static void HandleCpu(Isolate* isolate, JSONStream* js) { | 505 static void HandleCpu(Isolate* isolate, JSONStream* js) { |
| 316 JSONObject jsobj(js); | 506 JSONObject jsobj(js); |
| 317 jsobj.AddProperty("type", "CPU"); | 507 jsobj.AddProperty("type", "CPU"); |
| 318 jsobj.AddProperty("architecture", CPU::Id()); | 508 jsobj.AddProperty("architecture", CPU::Id()); |
| 319 } | 509 } |
| 320 | 510 |
| 321 | 511 |
| 322 static ServiceMessageHandlerEntry __message_handlers[] = { | 512 static ServiceMessageHandlerEntry __message_handlers[] = { |
| 323 { "_echo", HandleEcho }, | 513 { "_echo", HandleEcho }, |
| 324 { "classes", HandleClasses }, | 514 { "classes", HandleClasses }, |
| 325 { "cpu", HandleCpu }, | 515 { "cpu", HandleCpu }, |
| 326 { "debug", HandleDebug }, | 516 { "debug", HandleDebug }, |
| 517 { "libraries", HandleLibraries }, | |
| 327 { "library", HandleLibrary }, | 518 { "library", HandleLibrary }, |
| 328 { "name", HandleName }, | 519 { "name", HandleName }, |
| 329 { "objecthistogram", HandleObjectHistogram}, | 520 { "objecthistogram", HandleObjectHistogram}, |
| 330 { "objects", HandleObjects }, | 521 { "objects", HandleObjects }, |
| 522 { "scripts", HandleScripts }, | |
| 331 { "stacktrace", HandleStackTrace }, | 523 { "stacktrace", HandleStackTrace }, |
| 332 }; | 524 }; |
| 333 | 525 |
| 334 | 526 |
| 335 static void HandleFallthrough(Isolate* isolate, JSONStream* js) { | 527 static void HandleFallthrough(Isolate* isolate, JSONStream* js) { |
| 336 JSONObject jsobj(js); | 528 JSONObject jsobj(js); |
| 337 jsobj.AddProperty("type", "Error"); | 529 jsobj.AddProperty("type", "Error"); |
| 338 jsobj.AddProperty("text", "request not understood."); | 530 jsobj.AddProperty("text", "request not understood."); |
| 339 PrintArgumentsAndOptions(jsobj, js); | 531 PrintArgumentsAndOptions(jsobj, js); |
| 340 } | 532 } |
| 341 | 533 |
| 342 | 534 |
| 343 static ServiceMessageHandler FindServiceMessageHandler(const char* command) { | 535 static ServiceMessageHandler FindServiceMessageHandler(const char* command) { |
| 344 intptr_t num_message_handlers = sizeof(__message_handlers) / | 536 intptr_t num_message_handlers = sizeof(__message_handlers) / |
| 345 sizeof(__message_handlers[0]); | 537 sizeof(__message_handlers[0]); |
| 346 for (intptr_t i = 0; i < num_message_handlers; i++) { | 538 for (intptr_t i = 0; i < num_message_handlers; i++) { |
| 347 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; | 539 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; |
| 348 if (!strcmp(command, entry.command)) { | 540 if (!strcmp(command, entry.command)) { |
| 349 return entry.handler; | 541 return entry.handler; |
| 350 } | 542 } |
| 351 } | 543 } |
| 352 return HandleFallthrough; | 544 return HandleFallthrough; |
| 353 } | 545 } |
| 354 | 546 |
| 355 } // namespace dart | 547 } // namespace dart |
| OLD | NEW |