| 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 "include/dart_debugger_api.h" | 5 #include "include/dart_debugger_api.h" |
| 6 #include "vm/dart_api_impl.h" | 6 #include "vm/dart_api_impl.h" |
| 7 #include "vm/dart_entry.h" | 7 #include "vm/dart_entry.h" |
| 8 #include "vm/debugger.h" | 8 #include "vm/debugger.h" |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 #include "vm/message_handler.h" | 10 #include "vm/message_handler.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 char* buffer = isolate->current_zone()->Alloc<char>(len + 1); | 65 char* buffer = isolate->current_zone()->Alloc<char>(len + 1); |
| 66 va_list args2; | 66 va_list args2; |
| 67 va_start(args2, fmt); | 67 va_start(args2, fmt); |
| 68 OS::VSNPrint(buffer, (len + 1), fmt, args2); | 68 OS::VSNPrint(buffer, (len + 1), fmt, args2); |
| 69 va_end(args2); | 69 va_end(args2); |
| 70 | 70 |
| 71 return Eval(lib, buffer); | 71 return Eval(lib, buffer); |
| 72 } | 72 } |
| 73 | 73 |
| 74 | 74 |
| 75 /* | |
| 76 static RawFunction* GetFunction(const Class& cls, const char* name) { | 75 static RawFunction* GetFunction(const Class& cls, const char* name) { |
| 77 const Function& result = Function::Handle(cls.LookupDynamicFunction( | 76 const Function& result = Function::Handle(cls.LookupDynamicFunction( |
| 78 String::Handle(String::New(name)))); | 77 String::Handle(String::New(name)))); |
| 79 EXPECT(!result.IsNull()); | 78 EXPECT(!result.IsNull()); |
| 80 return result.raw(); | 79 return result.raw(); |
| 81 } | 80 } |
| 82 | 81 |
| 83 | 82 |
| 84 static RawFunction* GetStaticFunction(const Class& cls, const char* name) { | |
| 85 const Function& result = Function::Handle(cls.LookupStaticFunction( | |
| 86 String::Handle(String::New(name)))); | |
| 87 EXPECT(!result.IsNull()); | |
| 88 return result.raw(); | |
| 89 } | |
| 90 | |
| 91 | |
| 92 static RawField* GetField(const Class& cls, const char* name) { | |
| 93 const Field& field = | |
| 94 Field::Handle(cls.LookupField(String::Handle(String::New(name)))); | |
| 95 EXPECT(!field.IsNull()); | |
| 96 return field.raw(); | |
| 97 } | |
| 98 */ | |
| 99 | |
| 100 | |
| 101 static RawClass* GetClass(const Library& lib, const char* name) { | 83 static RawClass* GetClass(const Library& lib, const char* name) { |
| 102 const Class& cls = Class::Handle( | 84 const Class& cls = Class::Handle( |
| 103 lib.LookupClass(String::Handle(Symbols::New(name)))); | 85 lib.LookupClass(String::Handle(Symbols::New(name)))); |
| 104 EXPECT(!cls.IsNull()); // No ambiguity error expected. | 86 EXPECT(!cls.IsNull()); // No ambiguity error expected. |
| 105 return cls.raw(); | 87 return cls.raw(); |
| 106 } | 88 } |
| 107 | 89 |
| 108 | 90 |
| 109 TEST_CASE(Service_DebugBreakpoints) { | 91 TEST_CASE(Service_DebugBreakpoints) { |
| 110 const char* kScript = | 92 const char* kScript = |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 | 260 |
| 279 // Request function 0 from class A. | 261 // Request function 0 from class A. |
| 280 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '0']," | 262 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '0']," |
| 281 "[], []]", cid); | 263 "[], []]", cid); |
| 282 Service::HandleServiceMessage(isolate, service_msg); | 264 Service::HandleServiceMessage(isolate, service_msg); |
| 283 handler.HandleNextMessage(); | 265 handler.HandleNextMessage(); |
| 284 EXPECT_STREQ( | 266 EXPECT_STREQ( |
| 285 "{\"type\":\"Function\",\"id\":\"classes\\/1009\\/functions\\/0\",\"name\":" | 267 "{\"type\":\"Function\",\"id\":\"classes\\/1009\\/functions\\/0\",\"name\":" |
| 286 "\"get:a\",\"user_name\":\"A.a\",\"is_static\":false,\"is_const\":false," | 268 "\"get:a\",\"user_name\":\"A.a\",\"is_static\":false,\"is_const\":false," |
| 287 "\"is_optimizable\":true,\"is_inlinable\":false,\"kind\":" | 269 "\"is_optimizable\":true,\"is_inlinable\":false,\"kind\":" |
| 288 "\"implicit getter\",\"unoptimized_code\":{\"type\":\"null\"}," | 270 "\"kImplicitGetter\",\"unoptimized_code\":{\"type\":\"null\"}," |
| 289 "\"usage_counter\":0,\"optimized_call_site_count\":0,\"code\":" | 271 "\"usage_counter\":0,\"optimized_call_site_count\":0,\"code\":" |
| 290 "{\"type\":\"null\"},\"deoptimizations\":0}", handler.msg()); | 272 "{\"type\":\"null\"},\"deoptimizations\":0}", handler.msg()); |
| 291 | 273 |
| 292 // Request field 0 from class A. | 274 // Request field 0 from class A. |
| 293 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '0']," | 275 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '0']," |
| 294 "[], []]", cid); | 276 "[], []]", cid); |
| 295 Service::HandleServiceMessage(isolate, service_msg); | 277 Service::HandleServiceMessage(isolate, service_msg); |
| 296 handler.HandleNextMessage(); | 278 handler.HandleNextMessage(); |
| 297 EXPECT_STREQ( | 279 EXPECT_STREQ( |
| 298 "{\"type\":\"Field\",\"id\":\"classes\\/1009\\/fields\\/0\",\"name\":\"a\"," | 280 "{\"type\":\"Field\",\"id\":\"classes\\/1009\\/fields\\/0\",\"name\":\"a\"," |
| (...skipping 14 matching lines...) Expand all Loading... |
| 313 "{\"type\":\"Error\",\"text\":\"Invalid sub collection huh\",\"message\":" | 295 "{\"type\":\"Error\",\"text\":\"Invalid sub collection huh\",\"message\":" |
| 314 "{\"arguments\":[\"classes\",\"1009\",\"huh\",\"0\"],\"option_keys\":[]," | 296 "{\"arguments\":[\"classes\",\"1009\",\"huh\",\"0\"],\"option_keys\":[]," |
| 315 "\"option_values\":[]}}", handler.msg()); | 297 "\"option_values\":[]}}", handler.msg()); |
| 316 | 298 |
| 317 // Invalid field request. | 299 // Invalid field request. |
| 318 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '9']," | 300 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '9']," |
| 319 "[], []]", cid); | 301 "[], []]", cid); |
| 320 Service::HandleServiceMessage(isolate, service_msg); | 302 Service::HandleServiceMessage(isolate, service_msg); |
| 321 handler.HandleNextMessage(); | 303 handler.HandleNextMessage(); |
| 322 EXPECT_STREQ( | 304 EXPECT_STREQ( |
| 323 "{\"type\":\"Error\",\"text\":\"fields id (9) must be in [0, 1).\"," | 305 "{\"type\":\"Error\",\"text\":\"Field 9 not found\"," |
| 324 "\"message\":{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\"]," | 306 "\"message\":{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\"]," |
| 325 "\"option_keys\":[],\"option_values\":[]}}", handler.msg()); | 307 "\"option_keys\":[],\"option_values\":[]}}", handler.msg()); |
| 326 | 308 |
| 327 // Invalid function request. | 309 // Invalid function request. |
| 328 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9']," | 310 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9']," |
| 329 "[], []]", cid); | 311 "[], []]", cid); |
| 330 Service::HandleServiceMessage(isolate, service_msg); | 312 Service::HandleServiceMessage(isolate, service_msg); |
| 331 handler.HandleNextMessage(); | 313 handler.HandleNextMessage(); |
| 332 EXPECT_STREQ( | 314 EXPECT_STREQ( |
| 333 "{\"type\":\"Error\",\"text\":\"functions id (9) must be in [0, 5).\"," | 315 "{\"type\":\"Error\",\"text\":\"Function 9 not found\"," |
| 334 "\"message\":{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\"]," | 316 "\"message\":{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\"]," |
| 335 "\"option_keys\":[],\"option_values\":[]}}", handler.msg()); | 317 "\"option_keys\":[],\"option_values\":[]}}", handler.msg()); |
| 336 | 318 |
| 337 | 319 |
| 338 // Invalid field subcommand. | 320 // Invalid field subcommand. |
| 339 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '9', 'x']" | 321 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '9', 'x']" |
| 340 ",[], []]", cid); | 322 ",[], []]", cid); |
| 341 Service::HandleServiceMessage(isolate, service_msg); | 323 Service::HandleServiceMessage(isolate, service_msg); |
| 342 handler.HandleNextMessage(); | 324 handler.HandleNextMessage(); |
| 343 EXPECT_STREQ( | 325 EXPECT_STREQ( |
| 344 "{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":" | 326 "{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":" |
| 345 "{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\",\"x\"]," | 327 "{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\",\"x\"]," |
| 346 "\"option_keys\":[],\"option_values\":[]}}", | 328 "\"option_keys\":[],\"option_values\":[]}}", |
| 347 handler.msg()); | 329 handler.msg()); |
| 348 | 330 |
| 349 // Invalid function request. | 331 // Invalid function request. |
| 350 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9'," | 332 service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9'," |
| 351 "'x'], [], []]", cid); | 333 "'x'], [], []]", cid); |
| 352 Service::HandleServiceMessage(isolate, service_msg); | 334 Service::HandleServiceMessage(isolate, service_msg); |
| 353 handler.HandleNextMessage(); | 335 handler.HandleNextMessage(); |
| 354 EXPECT_STREQ( | 336 EXPECT_STREQ( |
| 355 "{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":" | 337 "{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":" |
| 356 "{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\",\"x\"]," | 338 "{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\",\"x\"]," |
| 357 "\"option_keys\":[],\"option_values\":[]}}", | 339 "\"option_keys\":[],\"option_values\":[]}}", |
| 358 handler.msg()); | 340 handler.msg()); |
| 359 } | 341 } |
| 360 | 342 |
| 343 |
| 344 TEST_CASE(Service_Code) { |
| 345 const char* kScript = |
| 346 "var port;\n" // Set to our mock port by C++. |
| 347 "\n" |
| 348 "class A {\n" |
| 349 " var a;\n" |
| 350 " dynamic b() {}\n" |
| 351 " dynamic c() {\n" |
| 352 " var d = () { b(); };\n" |
| 353 " return d;\n" |
| 354 " }\n" |
| 355 "}\n" |
| 356 "main() {\n" |
| 357 " var z = new A();\n" |
| 358 " var x = z.c();\n" |
| 359 " x();\n" |
| 360 "}"; |
| 361 |
| 362 Isolate* isolate = Isolate::Current(); |
| 363 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL); |
| 364 EXPECT_VALID(h_lib); |
| 365 Library& lib = Library::Handle(); |
| 366 lib ^= Api::UnwrapHandle(h_lib); |
| 367 EXPECT(!lib.IsNull()); |
| 368 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL); |
| 369 EXPECT_VALID(result); |
| 370 const Class& class_a = Class::Handle(GetClass(lib, "A")); |
| 371 EXPECT(!class_a.IsNull()); |
| 372 const Function& function_c = Function::Handle(GetFunction(class_a, "c")); |
| 373 EXPECT(!function_c.IsNull()); |
| 374 const Code& code_c = Code::Handle(function_c.CurrentCode()); |
| 375 EXPECT(!code_c.IsNull()); |
| 376 // Use the entry of the code object as it's reference. |
| 377 uword entry = code_c.EntryPoint(); |
| 378 EXPECT_GT(code_c.Size(), 16); |
| 379 uword last = entry + code_c.Size(); |
| 380 |
| 381 // Build a mock message handler and wrap it in a dart port. |
| 382 ServiceTestMessageHandler handler; |
| 383 Dart_Port port_id = PortMap::CreatePort(&handler); |
| 384 Dart_Handle port = |
| 385 Api::NewHandle(isolate, DartLibraryCalls::NewSendPort(port_id)); |
| 386 EXPECT_VALID(port); |
| 387 EXPECT_VALID(Dart_SetField(h_lib, NewString("port"), port)); |
| 388 |
| 389 Instance& service_msg = Instance::Handle(); |
| 390 |
| 391 // Request an invalid code object. |
| 392 service_msg = Eval(h_lib, "[port, ['code', '0'], [], []]"); |
| 393 Service::HandleServiceMessage(isolate, service_msg); |
| 394 handler.HandleNextMessage(); |
| 395 EXPECT_STREQ( |
| 396 "{\"type\":\"Error\",\"text\":\"Could not find code at 0\",\"message\":" |
| 397 "{\"arguments\":[\"code\",\"0\"]," |
| 398 "\"option_keys\":[],\"option_values\":[]}}", handler.msg()); |
| 399 |
| 400 // The following four tests check that a code object can be found |
| 401 // inside the range: [code.EntryPoint(), code.EntryPoint() + code.Size()). |
| 402 // Request code object at code.EntryPoint() |
| 403 // Expect this to succeed as it is inside [entry, entry + size). |
| 404 service_msg = EvalF(h_lib, "[port, ['code', '%" Px "'], [], []]", entry); |
| 405 Service::HandleServiceMessage(isolate, service_msg); |
| 406 handler.HandleNextMessage(); |
| 407 { |
| 408 // Only perform a partial match. |
| 409 const intptr_t kBufferSize = 512; |
| 410 char buffer[kBufferSize]; |
| 411 OS::SNPrint(buffer, kBufferSize-1, |
| 412 "{\"type\":\"Code\",\"id\":\"code\\/%" Px "\",", entry); |
| 413 EXPECT_SUBSTRING(buffer, handler.msg()); |
| 414 } |
| 415 |
| 416 // Request code object at code.EntryPoint() + 16. |
| 417 // Expect this to succeed as it is inside [entry, entry + size). |
| 418 uintptr_t address = entry + 16; |
| 419 service_msg = EvalF(h_lib, "[port, ['code', '%" Px "'], [], []]", address); |
| 420 Service::HandleServiceMessage(isolate, service_msg); |
| 421 handler.HandleNextMessage(); |
| 422 { |
| 423 // Only perform a partial match. |
| 424 const intptr_t kBufferSize = 512; |
| 425 char buffer[kBufferSize]; |
| 426 OS::SNPrint(buffer, kBufferSize-1, |
| 427 "{\"type\":\"Code\",\"id\":\"code\\/%" Px "\",", entry); |
| 428 EXPECT_SUBSTRING(buffer, handler.msg()); |
| 429 } |
| 430 |
| 431 // Request code object at code.EntryPoint() + code.Size() - 1. |
| 432 // Expect this to succeed as it is inside [entry, entry + size). |
| 433 address = last - 1; |
| 434 service_msg = EvalF(h_lib, "[port, ['code', '%" Px "'], [], []]", address); |
| 435 Service::HandleServiceMessage(isolate, service_msg); |
| 436 handler.HandleNextMessage(); |
| 437 { |
| 438 // Only perform a partial match. |
| 439 const intptr_t kBufferSize = 512; |
| 440 char buffer[kBufferSize]; |
| 441 OS::SNPrint(buffer, kBufferSize-1, |
| 442 "{\"type\":\"Code\",\"id\":\"code\\/%" Px "\",", entry); |
| 443 EXPECT_SUBSTRING(buffer, handler.msg()); |
| 444 } |
| 445 |
| 446 // Request code object at code.EntryPoint() + code.Size(). Expect this |
| 447 // to fail as it's outside of [entry, entry + size). |
| 448 address = last; |
| 449 service_msg = EvalF(h_lib, "[port, ['code', '%" Px "'], [], []]", address); |
| 450 Service::HandleServiceMessage(isolate, service_msg); |
| 451 handler.HandleNextMessage(); |
| 452 { |
| 453 const intptr_t kBufferSize = 1024; |
| 454 char buffer[kBufferSize]; |
| 455 OS::SNPrint(buffer, kBufferSize-1, |
| 456 "{\"type\":\"Error\",\"text\":\"Could not find code at %" Px "\"," |
| 457 "\"message\":{\"arguments\":[\"code\",\"%" Px "\"]," |
| 458 "\"option_keys\":[],\"option_values\":[]}}", address, address); |
| 459 EXPECT_STREQ(buffer, handler.msg()); |
| 460 } |
| 461 } |
| 462 |
| 361 } // namespace dart | 463 } // namespace dart |
| OLD | NEW |