Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: runtime/vm/debugger.cc

Issue 9581013: Splitting debugger breakpoints into two parts (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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/debugger.h" 5 #include "vm/debugger.h"
6 6
7 #include "vm/code_index_table.h" 7 #include "vm/code_index_table.h"
8 #include "vm/code_generator.h" 8 #include "vm/code_generator.h"
9 #include "vm/code_patcher.h" 9 #include "vm/code_patcher.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
11 #include "vm/dart_entry.h" 11 #include "vm/dart_entry.h"
12 #include "vm/flags.h" 12 #include "vm/flags.h"
13 #include "vm/globals.h" 13 #include "vm/globals.h"
14 #include "vm/longjump.h" 14 #include "vm/longjump.h"
15 #include "vm/object.h" 15 #include "vm/object.h"
16 #include "vm/object_store.h" 16 #include "vm/object_store.h"
17 #include "vm/os.h" 17 #include "vm/os.h"
18 #include "vm/stack_frame.h" 18 #include "vm/stack_frame.h"
19 #include "vm/stub_code.h" 19 #include "vm/stub_code.h"
20 #include "vm/visitor.h" 20 #include "vm/visitor.h"
21 21
22 22
23 namespace dart { 23 namespace dart {
24 24
25 static const bool verbose = false; 25 static const bool verbose = false;
26 26
27 27
28 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) 28 SourceBreakpoint::SourceBreakpoint(const Function& func, intptr_t token_index)
29 : function_(func.raw()), 29 : function_(func.raw()),
30 pc_desc_index_(pc_desc_index), 30 token_index_(token_index),
31 pc_(0),
32 line_number_(-1), 31 line_number_(-1),
33 is_temporary_(false), 32 is_enabled_(false),
34 is_patched_(false),
35 next_(NULL) { 33 next_(NULL) {
36 ASSERT(!func.HasOptimizedCode()); 34 ASSERT(!func.IsNull());
37 Code& code = Code::Handle(func.unoptimized_code()); 35 ASSERT((func.token_index() <= token_index_) &&
38 ASSERT(!code.IsNull()); // Function must be compiled. 36 (token_index_ < func.end_token_index()));
39 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
40 ASSERT(pc_desc_index < desc.Length());
41 this->token_index_ = desc.TokenIndex(pc_desc_index);
42 ASSERT(this->token_index_ > 0);
43 this->pc_ = desc.PC(pc_desc_index);
44 ASSERT(this->pc_ != 0);
45 this->breakpoint_kind_ = desc.DescriptorKind(pc_desc_index);
46 } 37 }
47 38
48 39
49 RawScript* Breakpoint::SourceCode() { 40 void SourceBreakpoint::Enable() {
50 const Function& func = Function::Handle(this->function_); 41 is_enabled_ = true;
42 Isolate::Current()->debugger()->SyncBreakpoint(this);
43 }
44
45
46 void SourceBreakpoint::Disable() {
47 is_enabled_ = false;
48 Isolate::Current()->debugger()->SyncBreakpoint(this);
49 }
50
51
52 RawScript* SourceBreakpoint::SourceCode() {
53 const Function& func = Function::Handle(function_);
51 const Class& cls = Class::Handle(func.owner()); 54 const Class& cls = Class::Handle(func.owner());
52 return cls.script(); 55 return cls.script();
53 } 56 }
54 57
55 58
56 RawString* Breakpoint::SourceUrl() { 59 RawString* SourceBreakpoint::SourceUrl() {
57 const Script& script = Script::Handle(this->SourceCode()); 60 const Script& script = Script::Handle(SourceCode());
58 return script.url(); 61 return script.url();
59 } 62 }
60 63
61 64
62 intptr_t Breakpoint::LineNumber() { 65 intptr_t SourceBreakpoint::LineNumber() {
63 // Compute line number lazily since it causes scanning of the script. 66 // Compute line number lazily since it causes scanning of the script.
64 if (this->line_number_ < 0) { 67 if (line_number_ < 0) {
65 const Script& script = Script::Handle(this->SourceCode()); 68 const Script& script = Script::Handle(SourceCode());
66 intptr_t ignore_column; 69 intptr_t ignore_column;
67 script.GetTokenLocation(this->token_index_, 70 script.GetTokenLocation(token_index_, &line_number_, &ignore_column);
68 &this->line_number_, &ignore_column);
69 } 71 }
70 return this->line_number_; 72 return line_number_;
71 } 73 }
72 74
73 75
74 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { 76 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
77 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
78 }
79
80
81
82 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
75 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); 83 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
76 } 84 }
77 85
78 86
79 ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp) 87 ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp)
80 : pc_(pc), fp_(fp), sp_(sp), 88 : pc_(pc), fp_(fp), sp_(sp),
81 function_(Function::ZoneHandle()), 89 function_(Function::ZoneHandle()),
82 token_index_(-1), 90 token_index_(-1),
83 line_number_(-1), 91 line_number_(-1),
84 var_descriptors_(NULL), 92 var_descriptors_(NULL),
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 OS::SNPrint(NULL, 0, kFormat, func_name, url.ToCString(), line); 282 OS::SNPrint(NULL, 0, kFormat, func_name, url.ToCString(), line);
275 len++; // String terminator. 283 len++; // String terminator.
276 char* chars = reinterpret_cast<char*>( 284 char* chars = reinterpret_cast<char*>(
277 Isolate::Current()->current_zone()->Allocate(len)); 285 Isolate::Current()->current_zone()->Allocate(len));
278 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); 286 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line);
279 return chars; 287 return chars;
280 } 288 }
281 289
282 290
283 void StackTrace::AddActivation(ActivationFrame* frame) { 291 void StackTrace::AddActivation(ActivationFrame* frame) {
284 this->trace_.Add(frame); 292 trace_.Add(frame);
285 } 293 }
286 294
287 295
288 void Breakpoint::PatchCode() { 296 CodeBreakpoint::CodeBreakpoint(const Function& func, intptr_t pc_desc_index)
289 ASSERT(!is_patched_); 297 : function_(func.raw()),
298 pc_desc_index_(pc_desc_index),
299 pc_(0),
300 line_number_(-1),
301 is_enabled_(false),
302 src_bpt_(NULL),
303 next_(NULL) {
304 ASSERT(!func.HasOptimizedCode());
305 Code& code = Code::Handle(func.unoptimized_code());
306 ASSERT(!code.IsNull()); // Function must be compiled.
307 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
308 ASSERT(pc_desc_index < desc.Length());
309 token_index_ = desc.TokenIndex(pc_desc_index);
310 ASSERT(token_index_ > 0);
311 pc_ = desc.PC(pc_desc_index);
312 ASSERT(pc_ != 0);
313 breakpoint_kind_ = desc.DescriptorKind(pc_desc_index);
314 }
315
316
317 CodeBreakpoint::~CodeBreakpoint() {
318 // Make sure we don't leave patched code behind.
319 ASSERT(!IsEnabled());
320 }
321
322
323 RawScript* CodeBreakpoint::SourceCode() {
324 const Function& func = Function::Handle(function_);
325 const Class& cls = Class::Handle(func.owner());
326 return cls.script();
327 }
328
329
330 RawString* CodeBreakpoint::SourceUrl() {
331 const Script& script = Script::Handle(SourceCode());
332 return script.url();
333 }
334
335
336 intptr_t CodeBreakpoint::LineNumber() {
337 // Compute line number lazily since it causes scanning of the script.
338 if (line_number_ < 0) {
339 const Script& script = Script::Handle(SourceCode());
340 intptr_t ignore_column;
341 script.GetTokenLocation(token_index_, &line_number_, &ignore_column);
342 }
343 return line_number_;
344 }
345
346
347 void CodeBreakpoint::PatchCode() {
348 ASSERT(!is_enabled_);
290 switch (breakpoint_kind_) { 349 switch (breakpoint_kind_) {
291 case PcDescriptors::kIcCall: { 350 case PcDescriptors::kIcCall: {
292 int num_args, num_named_args; 351 int num_args, num_named_args;
293 CodePatcher::GetInstanceCallAt(pc_, 352 CodePatcher::GetInstanceCallAt(pc_,
294 NULL, &num_args, &num_named_args, 353 NULL, &num_args, &num_named_args,
295 &saved_bytes_.target_address_); 354 &saved_bytes_.target_address_);
296 CodePatcher::PatchInstanceCallAt( 355 CodePatcher::PatchInstanceCallAt(
297 pc_, StubCode::BreakpointDynamicEntryPoint()); 356 pc_, StubCode::BreakpointDynamicEntryPoint());
298 break; 357 break;
299 } 358 }
300 case PcDescriptors::kFuncCall: { 359 case PcDescriptors::kFuncCall: {
301 Function& func = Function::Handle(); 360 Function& func = Function::Handle();
302 CodePatcher::GetStaticCallAt(pc_, &func, &saved_bytes_.target_address_); 361 CodePatcher::GetStaticCallAt(pc_, &func, &saved_bytes_.target_address_);
303 CodePatcher::PatchStaticCallAt(pc_, 362 CodePatcher::PatchStaticCallAt(pc_,
304 StubCode::BreakpointStaticEntryPoint()); 363 StubCode::BreakpointStaticEntryPoint());
305 break; 364 break;
306 } 365 }
307 case PcDescriptors::kReturn: 366 case PcDescriptors::kReturn:
308 PatchFunctionReturn(); 367 PatchFunctionReturn();
309 break; 368 break;
310 default: 369 default:
311 UNREACHABLE(); 370 UNREACHABLE();
312 } 371 }
313 is_patched_ = true; 372 is_enabled_ = true;
314 } 373 }
315 374
316 375
317 void Breakpoint::RestoreCode() { 376 void CodeBreakpoint::RestoreCode() {
318 ASSERT(is_patched_); 377 ASSERT(is_enabled_);
319 switch (breakpoint_kind_) { 378 switch (breakpoint_kind_) {
320 case PcDescriptors::kIcCall: 379 case PcDescriptors::kIcCall:
321 CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_); 380 CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_);
322 break; 381 break;
323 case PcDescriptors::kFuncCall: 382 case PcDescriptors::kFuncCall:
324 CodePatcher::PatchStaticCallAt(pc_, saved_bytes_.target_address_); 383 CodePatcher::PatchStaticCallAt(pc_, saved_bytes_.target_address_);
325 break; 384 break;
326 case PcDescriptors::kReturn: 385 case PcDescriptors::kReturn:
327 RestoreFunctionReturn(); 386 RestoreFunctionReturn();
328 break; 387 break;
329 default: 388 default:
330 UNREACHABLE(); 389 UNREACHABLE();
331 } 390 }
332 is_patched_ = false; 391 is_enabled_ = false;
333 }
334
335 void Breakpoint::SetActive(bool value) {
336 if (value && !is_patched_) {
337 PatchCode();
338 return;
339 }
340 if (!value && is_patched_) {
341 RestoreCode();
342 }
343 } 392 }
344 393
345 394
346 bool Breakpoint::IsActive() { 395 void CodeBreakpoint::Enable() {
347 return is_patched_; 396 if (!is_enabled_) {
397 PatchCode();
398 }
399 ASSERT(is_enabled_);
348 } 400 }
349 401
350 402
403 void CodeBreakpoint::Disable() {
404 if (is_enabled_) {
405 RestoreCode();
406 }
407 ASSERT(!is_enabled_);
408 }
409
410
351 Debugger::Debugger() 411 Debugger::Debugger()
352 : isolate_(NULL), 412 : isolate_(NULL),
353 initialized_(false), 413 initialized_(false),
354 bp_handler_(NULL), 414 bp_handler_(NULL),
355 breakpoints_(NULL), 415 src_breakpoints_(NULL),
416 code_breakpoints_(NULL),
356 resume_action_(kContinue) { 417 resume_action_(kContinue) {
357 } 418 }
358 419
359 420
360 Debugger::~Debugger() { 421 Debugger::~Debugger() {
361 ASSERT(breakpoints_ == NULL); 422 ASSERT(src_breakpoints_ == NULL);
423 ASSERT(code_breakpoints_ == NULL);
362 } 424 }
363 425
364 426
365 void Debugger::Shutdown() { 427 void Debugger::Shutdown() {
366 while (breakpoints_ != NULL) { 428 while (src_breakpoints_ != NULL) {
367 Breakpoint* bpt = breakpoints_; 429 SourceBreakpoint* bpt = src_breakpoints_;
368 breakpoints_ = breakpoints_->next(); 430 src_breakpoints_ = src_breakpoints_->next();
369 UnsetBreakpoint(bpt); 431 delete bpt;
432 }
433 while (code_breakpoints_ != NULL) {
434 CodeBreakpoint* bpt = code_breakpoints_;
435 code_breakpoints_ = code_breakpoints_->next();
436 bpt->Disable();
370 delete bpt; 437 delete bpt;
371 } 438 }
372 } 439 }
373 440
374 441
375 bool Debugger::IsActive() { 442 bool Debugger::IsActive() {
376 // TODO(hausner): The code generator uses this function to prevent 443 // TODO(hausner): The code generator uses this function to prevent
377 // generation of optimized code when Dart code is being debugged. 444 // generation of optimized code when Dart code is being debugged.
378 // This is probably not conservative enough (we could set the first 445 // This is probably not conservative enough (we could set the first
379 // breakpoint after optimized code has already been produced). 446 // breakpoint after optimized code has already been produced).
380 // Long-term, we need to be able to de-optimize code. 447 // Long-term, we need to be able to de-optimize code.
381 return breakpoints_ != NULL; 448 return (src_breakpoints_ != NULL) || (code_breakpoints_ != NULL);
382 } 449 }
383 450
384 451
385 static RawFunction* ResolveLibraryFunction( 452 static RawFunction* ResolveLibraryFunction(
386 const Library& library, 453 const Library& library,
387 const String& fname) { 454 const String& fname) {
388 ASSERT(!library.IsNull()); 455 ASSERT(!library.IsNull());
389 Function& function = Function::Handle(); 456 Function& function = Function::Handle();
390 const Object& object = Object::Handle(library.LookupObject(fname)); 457 const Object& object = Object::Handle(library.LookupObject(fname));
391 if (!object.IsNull() && object.IsFunction()) { 458 if (!object.IsNull() && object.IsFunction()) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 // adding breakpoints to target. 490 // adding breakpoints to target.
424 if (!target_function.HasCode()) { 491 if (!target_function.HasCode()) {
425 return; 492 return;
426 } 493 }
427 } 494 }
428 ASSERT(!target_function.HasOptimizedCode()); 495 ASSERT(!target_function.HasOptimizedCode());
429 Code& code = Code::Handle(target_function.unoptimized_code()); 496 Code& code = Code::Handle(target_function.unoptimized_code());
430 ASSERT(!code.IsNull()); 497 ASSERT(!code.IsNull());
431 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); 498 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
432 for (int i = 0; i < desc.Length(); i++) { 499 for (int i = 0; i < desc.Length(); i++) {
433 Breakpoint* bpt = GetBreakpoint(desc.PC(i)); 500 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
434 if (bpt != NULL) { 501 if (bpt != NULL) {
435 // There is already a breakpoint for this address. Leave it alone. 502 // There is already a breakpoint for this address. Leave it alone.
436 continue; 503 continue;
437 } 504 }
438 PcDescriptors::Kind kind = desc.DescriptorKind(i); 505 PcDescriptors::Kind kind = desc.DescriptorKind(i);
439 if ((kind == PcDescriptors::kIcCall) || 506 if ((kind == PcDescriptors::kIcCall) ||
440 (kind == PcDescriptors::kFuncCall) || 507 (kind == PcDescriptors::kFuncCall) ||
441 (kind == PcDescriptors::kReturn)) { 508 (kind == PcDescriptors::kReturn)) {
442 bpt = new Breakpoint(target_function, i); 509 bpt = new CodeBreakpoint(target_function, i);
443 bpt->set_temporary(true); 510 RegisterCodeBreakpoint(bpt);
444 bpt->PatchCode(); 511 bpt->Enable();
445 RegisterBreakpoint(bpt);
446 } 512 }
447 } 513 }
448 } 514 }
449 515
450 516
451 // TODO(hausner): Distinguish between newly created breakpoints and 517 CodeBreakpoint* Debugger::MakeCodeBreakpoint(SourceBreakpoint* src_bpt) {
452 // returning a breakpoint that already exists? 518 Function& func = Function::Handle(src_bpt->function());
453 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, 519 ASSERT(func.HasCode());
454 intptr_t token_index, 520 ASSERT(!func.HasOptimizedCode());
455 Error* error) { 521 Code& code = Code::Handle(func.unoptimized_code());
456 if ((token_index < target_function.token_index()) ||
457 (target_function.end_token_index() <= token_index)) {
458 // The given token position is not within the target function.
459 return NULL;
460 }
461 if (!target_function.HasCode()) {
462 *error = Compiler::CompileFunction(target_function);
463 if (!error->IsNull()) {
464 return NULL;
465 }
466 }
467 ASSERT(!target_function.HasOptimizedCode());
468 Code& code = Code::Handle(target_function.unoptimized_code());
469 ASSERT(!code.IsNull()); 522 ASSERT(!code.IsNull());
470 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); 523 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
524 intptr_t requested_token_index = src_bpt->token_index();
471 for (int i = 0; i < desc.Length(); i++) { 525 for (int i = 0; i < desc.Length(); i++) {
472 if (desc.TokenIndex(i) < token_index) { 526 if (desc.TokenIndex(i) < requested_token_index) {
473 continue; 527 continue;
474 } 528 }
475 Breakpoint* bpt = GetBreakpoint(desc.PC(i)); 529 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
530 // We should only ever have one code breakpoint at the same address.
531 // If we find an existing breakpoint, it must be an internal one which
532 // is used for stepping.
476 if (bpt != NULL) { 533 if (bpt != NULL) {
477 // Found existing breakpoint. 534 ASSERT(bpt->src_bpt() == NULL);
535 bpt->set_src_bpt(src_bpt);
478 return bpt; 536 return bpt;
479 } 537 }
538
480 PcDescriptors::Kind kind = desc.DescriptorKind(i); 539 PcDescriptors::Kind kind = desc.DescriptorKind(i);
481 if ((kind == PcDescriptors::kIcCall) || 540 if ((kind == PcDescriptors::kIcCall) ||
482 (kind == PcDescriptors::kFuncCall) || 541 (kind == PcDescriptors::kFuncCall) ||
483 (kind == PcDescriptors::kReturn)) { 542 (kind == PcDescriptors::kReturn)) {
484 bpt = new Breakpoint(target_function, i); 543 bpt = new CodeBreakpoint(func, i);
485 bpt->PatchCode(); 544 bpt->set_src_bpt(src_bpt);
486 RegisterBreakpoint(bpt);
487 if (verbose) { 545 if (verbose) {
488 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", 546 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n",
547 String::Handle(func.name()).ToCString(),
489 String::Handle(bpt->SourceUrl()).ToCString(), 548 String::Handle(bpt->SourceUrl()).ToCString(),
490 bpt->LineNumber(), 549 bpt->LineNumber(),
491 bpt->pc()); 550 bpt->pc());
492 } 551 }
552 RegisterCodeBreakpoint(bpt);
493 return bpt; 553 return bpt;
494 } 554 }
495 } 555 }
496 return NULL; 556 return NULL;
497 } 557 }
498 558
499 559
500 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { 560 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function,
501 bpt->SetActive(false); 561 intptr_t token_index) {
562 if ((token_index < target_function.token_index()) ||
563 (target_function.end_token_index() <= token_index)) {
564 // The given token position is not within the target function.
565 return NULL;
566 }
567 SourceBreakpoint* bpt = GetSourceBreakpoint(target_function, token_index);
568 if (bpt != NULL) {
569 // A breakpoint for this location already exists, return it.
570 return bpt;
571 }
572 bpt = new SourceBreakpoint(target_function, token_index);
573 RegisterSourceBreakpoint(bpt);
574 if (verbose && !target_function.HasCode()) {
575 OS::Print("Registering breakpoint for uncompiled function '%s'"
576 " (%s:%d)\n",
577 String::Handle(target_function.name()).ToCString(),
578 String::Handle(bpt->SourceUrl()).ToCString(),
579 bpt->LineNumber());
580 }
581
582 if (target_function.HasCode()) {
583 CodeBreakpoint* cbpt = MakeCodeBreakpoint(bpt);
584 if (cbpt == NULL) {
585 if (verbose) {
586 OS::Print("Failed to set breakpoint at '%s' line %d\n",
587 String::Handle(bpt->SourceUrl()).ToCString(),
588 bpt->LineNumber());
589 }
590 }
591 }
592 bpt->Enable();
593 return bpt;
502 } 594 }
503 595
504 596
505 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, 597 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) {
506 Error* error) { 598 CodeBreakpoint* cbpt = code_breakpoints_;
507 ASSERT(!target_function.IsNull()); 599 while (cbpt != NULL) {
508 return SetBreakpoint(target_function, target_function.token_index(), error); 600 if (bpt == cbpt->src_bpt()) {
601 if (bpt->IsEnabled()) {
602 cbpt->Enable();
603 } else {
604 cbpt->Disable();
605 }
606 }
607 cbpt = cbpt->next();
608 }
509 } 609 }
510 610
511 611
512 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, 612 SourceBreakpoint* Debugger::SetBreakpointAtEntry(
513 intptr_t line_number, 613 const Function& target_function) {
514 Error* error) { 614 ASSERT(!target_function.IsNull());
615 return SetBreakpoint(target_function, target_function.token_index());
616 }
617
618
619 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
620 intptr_t line_number) {
515 Library& lib = Library::Handle(); 621 Library& lib = Library::Handle();
516 Script& script = Script::Handle(); 622 Script& script = Script::Handle();
517 lib = isolate_->object_store()->registered_libraries(); 623 lib = isolate_->object_store()->registered_libraries();
518 while (!lib.IsNull()) { 624 while (!lib.IsNull()) {
519 script = lib.LookupScript(script_url); 625 script = lib.LookupScript(script_url);
520 if (!script.IsNull()) { 626 if (!script.IsNull()) {
521 break; 627 break;
522 } 628 }
523 lib = lib.next_registered(); 629 lib = lib.next_registered();
524 } 630 }
525 if (script.IsNull()) { 631 if (script.IsNull()) {
632 if (verbose) {
633 OS::Print("Failed to find script with url '%s'\n",
634 script_url.ToCString());
635 }
526 return NULL; 636 return NULL;
527 } 637 }
528 intptr_t token_index_at_line = script.TokenIndexAtLine(line_number); 638 intptr_t token_index_at_line = script.TokenIndexAtLine(line_number);
529 if (token_index_at_line < 0) { 639 if (token_index_at_line < 0) {
530 // Script does not contain the given line number. 640 // Script does not contain the given line number.
641 if (verbose) {
642 OS::Print("Script '%s' does not contain line number %d\n",
643 script_url.ToCString(), line_number);
644 }
531 return NULL; 645 return NULL;
532 } 646 }
533 const Function& func = 647 const Function& func =
534 Function::Handle(lib.LookupFunctionInScript(script, token_index_at_line)); 648 Function::Handle(lib.LookupFunctionInScript(script, token_index_at_line));
535 if (func.IsNull()) { 649 if (func.IsNull()) {
650 if (verbose) {
651 OS::Print("No executable code at line %d in '%s'\n",
652 line_number, script_url.ToCString());
653 }
536 return NULL; 654 return NULL;
537 } 655 }
538 return SetBreakpoint(func, token_index_at_line, error); 656 return SetBreakpoint(func, token_index_at_line);
539 } 657 }
540 658
541 659
542 static RawArray* MakeNameValueList(const GrowableArray<Object*>& pairs) { 660 static RawArray* MakeNameValueList(const GrowableArray<Object*>& pairs) {
543 int pairs_len = pairs.length(); 661 int pairs_len = pairs.length();
544 ASSERT(pairs_len % 2 == 0); 662 ASSERT(pairs_len % 2 == 0);
545 const Array& list = Array::Handle(Array::New(pairs_len)); 663 const Array& list = Array::Handle(Array::New(pairs_len));
546 for (int i = 0; i < pairs_len; i++) { 664 for (int i = 0; i < pairs_len; i++) {
547 list.SetAt(i, *pairs[i]); 665 list.SetAt(i, *pairs[i]);
548 } 666 }
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 field_list.Add(&field_name); 752 field_list.Add(&field_name);
635 field_list.Add(&field_value); 753 field_list.Add(&field_value);
636 } 754 }
637 } 755 }
638 return MakeNameValueList(field_list); 756 return MakeNameValueList(field_list);
639 } 757 }
640 758
641 759
642 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { 760 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) {
643 ASSERT(visitor != NULL); 761 ASSERT(visitor != NULL);
644 Breakpoint* bpt = this->breakpoints_; 762 SourceBreakpoint* bpt = src_breakpoints_;
645 while (bpt != NULL) { 763 while (bpt != NULL) {
646 bpt->VisitObjectPointers(visitor); 764 bpt->VisitObjectPointers(visitor);
647 bpt = bpt->next(); 765 bpt = bpt->next();
648 } 766 }
767 CodeBreakpoint* cbpt = code_breakpoints_;
768 while (cbpt != NULL) {
769 cbpt->VisitObjectPointers(visitor);
770 cbpt = cbpt->next();
771 }
649 } 772 }
650 773
651 774
652 static void DefaultBreakpointHandler(Breakpoint* bpt, StackTrace* stack) { 775 static void DefaultBreakpointHandler(SourceBreakpoint* bpt, StackTrace* stack) {
653 String& var_name = String::Handle(); 776 String& var_name = String::Handle();
654 Instance& value = Instance::Handle(); 777 Instance& value = Instance::Handle();
655 for (intptr_t i = 0; i < stack->Length(); i++) { 778 for (intptr_t i = 0; i < stack->Length(); i++) {
656 ActivationFrame* frame = stack->ActivationFrameAt(i); 779 ActivationFrame* frame = stack->ActivationFrameAt(i);
657 OS::Print(" %d. %s\n", 780 OS::Print(" %d. %s\n",
658 i + 1, frame->ToCString()); 781 i + 1, frame->ToCString());
659 intptr_t num_locals = frame->NumLocalVariables(); 782 intptr_t num_locals = frame->NumLocalVariables();
660 for (intptr_t i = 0; i < num_locals; i++) { 783 for (intptr_t i = 0; i < num_locals; i++) {
661 intptr_t token_pos, end_pos; 784 intptr_t token_pos, end_pos;
662 frame->VariableAt(i, &var_name, &token_pos, &end_pos, &value); 785 frame->VariableAt(i, &var_name, &token_pos, &end_pos, &value);
(...skipping 10 matching lines...) Expand all
673 bp_handler_ = &DefaultBreakpointHandler; 796 bp_handler_ = &DefaultBreakpointHandler;
674 } 797 }
675 } 798 }
676 799
677 800
678 void Debugger::BreakpointCallback() { 801 void Debugger::BreakpointCallback() {
679 ASSERT(initialized_); 802 ASSERT(initialized_);
680 DartFrameIterator iterator; 803 DartFrameIterator iterator;
681 DartFrame* frame = iterator.NextFrame(); 804 DartFrame* frame = iterator.NextFrame();
682 ASSERT(frame != NULL); 805 ASSERT(frame != NULL);
683 Breakpoint* bpt = GetBreakpoint(frame->pc()); 806 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc());
684 ASSERT(bpt != NULL); 807 ASSERT(bpt != NULL);
685 if (verbose) { 808 if (verbose) {
686 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", 809 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n",
687 bpt->is_temporary() ? "hit temp" : "hit user", 810 bpt->IsInternal() ? "hit internal" : "hit user",
688 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", 811 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?",
689 bpt ? bpt->LineNumber() : 0, 812 bpt ? bpt->LineNumber() : 0,
690 frame->pc()); 813 frame->pc());
691 } 814 }
692 StackTrace* stack_trace = new StackTrace(8); 815 StackTrace* stack_trace = new StackTrace(8);
693 while (frame != NULL) { 816 while (frame != NULL) {
694 ASSERT(frame->IsValid()); 817 ASSERT(frame->IsValid());
695 ASSERT(frame->IsDartFrame()); 818 ASSERT(frame->IsDartFrame());
696 ActivationFrame* activation = 819 ActivationFrame* activation =
697 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); 820 new ActivationFrame(frame->pc(), frame->fp(), frame->sp());
698 stack_trace->AddActivation(activation); 821 stack_trace->AddActivation(activation);
699 frame = iterator.NextFrame(); 822 frame = iterator.NextFrame();
700 } 823 }
701 824
702 resume_action_ = kContinue; 825 resume_action_ = kContinue;
703 if (bp_handler_ != NULL) { 826 if (bp_handler_ != NULL) {
704 (*bp_handler_)(bpt, stack_trace); 827 SourceBreakpoint* src_bpt = bpt->src_bpt();
828 (*bp_handler_)(src_bpt, stack_trace);
705 } 829 }
706 830
707 if (resume_action_ == kContinue) { 831 if (resume_action_ == kContinue) {
708 RemoveTemporaryBreakpoints(); 832 RemoveInternalBreakpoints();
709 } else if (resume_action_ == kStepOver) { 833 } else if (resume_action_ == kStepOver) {
710 Function& func = Function::Handle(bpt->function()); 834 Function& func = Function::Handle(bpt->function());
711 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { 835 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) {
712 // If we are at the function return, do a StepOut action. 836 // If we are at the function return, do a StepOut action.
713 if (stack_trace->Length() > 1) { 837 if (stack_trace->Length() > 1) {
714 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); 838 ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
715 func = caller->DartFunction().raw(); 839 func = caller->DartFunction().raw();
716 RemoveTemporaryBreakpoints(); 840 RemoveInternalBreakpoints();
717 } 841 }
718 } 842 }
719 InstrumentForStepping(func); 843 InstrumentForStepping(func);
720 } else if (resume_action_ == kStepInto) { 844 } else if (resume_action_ == kStepInto) {
721 RemoveTemporaryBreakpoints(); 845 RemoveInternalBreakpoints();
722 if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) { 846 if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) {
723 int num_args, num_named_args; 847 int num_args, num_named_args;
724 uword target; 848 uword target;
725 CodePatcher::GetInstanceCallAt(bpt->pc_, NULL, 849 CodePatcher::GetInstanceCallAt(bpt->pc_, NULL,
726 &num_args, &num_named_args, &target); 850 &num_args, &num_named_args, &target);
727 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); 851 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0);
728 Instance& receiver = Instance::Handle( 852 Instance& receiver = Instance::Handle(
729 top_frame->GetInstanceCallReceiver(num_args)); 853 top_frame->GetInstanceCallReceiver(num_args));
730 Code& code = Code::Handle( 854 Code& code = Code::Handle(
731 ResolveCompileInstanceCallTarget(isolate_, receiver)); 855 ResolveCompileInstanceCallTarget(isolate_, receiver));
732 if (!code.IsNull()) { 856 if (!code.IsNull()) {
733 Function& callee = Function::Handle(code.function()); 857 Function& callee = Function::Handle(code.function());
734 InstrumentForStepping(callee); 858 InstrumentForStepping(callee);
735 } 859 }
736 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) { 860 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) {
737 Function& callee = Function::Handle(); 861 Function& callee = Function::Handle();
738 uword target; 862 uword target;
739 CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target); 863 CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target);
740 InstrumentForStepping(callee); 864 InstrumentForStepping(callee);
741 } else { 865 } else {
742 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); 866 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn);
743 // Treat like stepping out to caller. 867 // Treat like stepping out to caller.
744 if (stack_trace->Length() > 1) { 868 if (stack_trace->Length() > 1) {
745 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); 869 ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
746 InstrumentForStepping(caller->DartFunction()); 870 InstrumentForStepping(caller->DartFunction());
747 } 871 }
748 } 872 }
749 } else { 873 } else {
750 ASSERT(resume_action_ == kStepOut); 874 ASSERT(resume_action_ == kStepOut);
751 // Set temporary breakpoints in the caller. 875 // Set stepping breakpoints in the caller.
752 RemoveTemporaryBreakpoints(); 876 RemoveInternalBreakpoints();
753 if (stack_trace->Length() > 1) { 877 if (stack_trace->Length() > 1) {
754 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); 878 ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
755 InstrumentForStepping(caller->DartFunction()); 879 InstrumentForStepping(caller->DartFunction());
756 } 880 }
757 } 881 }
758 } 882 }
759 883
760 884
761 void Debugger::Initialize(Isolate* isolate) { 885 void Debugger::Initialize(Isolate* isolate) {
762 if (initialized_) { 886 if (initialized_) {
763 return; 887 return;
764 } 888 }
765 isolate_ = isolate; 889 isolate_ = isolate;
766 initialized_ = true; 890 initialized_ = true;
767 SetBreakpointHandler(DefaultBreakpointHandler); 891 SetBreakpointHandler(DefaultBreakpointHandler);
768 } 892 }
769 893
770 894
771 Breakpoint* Debugger::GetBreakpoint(uword breakpoint_address) { 895 // TODO(hausner): handle closure functions.
772 Breakpoint* bpt = this->breakpoints_; 896 void Debugger::NotifyCompilation(const Function& func) {
897 SourceBreakpoint* bpt = src_breakpoints_;
898 while (bpt != NULL) {
899 if (func.raw() == bpt->function()) {
900 if (verbose) {
901 OS::Print("Enable latent breakpoint for function '%s'\n",
902 String::Handle(func.name()).ToCString());
903 }
904 CodeBreakpoint* cbpt = MakeCodeBreakpoint(bpt);
905 bpt->Enable();
906 }
907 bpt = bpt->next();
908 }
909 }
910
911
912 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) {
913 CodeBreakpoint* bpt = code_breakpoints_;
773 while (bpt != NULL) { 914 while (bpt != NULL) {
774 if (bpt->pc() == breakpoint_address) { 915 if (bpt->pc() == breakpoint_address) {
775 return bpt; 916 return bpt;
776 } 917 }
777 bpt = bpt->next(); 918 bpt = bpt->next();
778 } 919 }
779 return NULL; 920 return NULL;
780 } 921 }
781 922
782 923
783 void Debugger::RemoveBreakpoint(Breakpoint* bpt) { 924 // Remove and delete the source breakpoint bpt and its associated
784 ASSERT(breakpoints_ != NULL); 925 // code breakpoints.
785 Breakpoint* prev_bpt = NULL; 926 void Debugger::RemoveBreakpoint(SourceBreakpoint* bpt) {
786 Breakpoint* curr_bpt = breakpoints_; 927 ASSERT(src_breakpoints_ != NULL);
928 SourceBreakpoint* prev_bpt = NULL;
929 SourceBreakpoint* curr_bpt = src_breakpoints_;
787 while (curr_bpt != NULL) { 930 while (curr_bpt != NULL) {
788 if (bpt == curr_bpt) { 931 if (bpt == curr_bpt) {
789 if (prev_bpt == NULL) { 932 if (prev_bpt == NULL) {
790 breakpoints_ = breakpoints_->next(); 933 src_breakpoints_ = src_breakpoints_->next();
791 } else { 934 } else {
792 prev_bpt->set_next(curr_bpt->next()); 935 prev_bpt->set_next(curr_bpt->next());
793 } 936 }
794 UnsetBreakpoint(bpt); 937 // Remove the code breakpoints associated with the source breakpoint.
938 RemoveCodeBreakpoints(bpt);
795 delete bpt; 939 delete bpt;
796 return; 940 return;
797 } 941 }
798 prev_bpt = curr_bpt; 942 prev_bpt = curr_bpt;
799 curr_bpt = curr_bpt->next(); 943 curr_bpt = curr_bpt->next();
800 } 944 }
801 // bpt is not a registered breakpoint, nothing to do. 945 // bpt is not a registered breakpoint, nothing to do.
802 } 946 }
803 947
804 948
805 void Debugger::RemoveTemporaryBreakpoints() { 949 // Remove and delete the code breakpoints that are associated with given
806 Breakpoint* prev_bpt = NULL; 950 // source breakpoint bpt. If bpt is null, remove the internal breakpoints.
807 Breakpoint* curr_bpt = breakpoints_; 951 void Debugger::RemoveCodeBreakpoints(SourceBreakpoint* src_bpt) {
952 CodeBreakpoint* prev_bpt = NULL;
953 CodeBreakpoint* curr_bpt = code_breakpoints_;
808 while (curr_bpt != NULL) { 954 while (curr_bpt != NULL) {
809 if (curr_bpt->is_temporary()) { 955 if (curr_bpt->src_bpt() == src_bpt) {
810 if (prev_bpt == NULL) { 956 if (prev_bpt == NULL) {
811 breakpoints_ = breakpoints_->next(); 957 code_breakpoints_ = code_breakpoints_->next();
812 } else { 958 } else {
813 prev_bpt->set_next(curr_bpt->next()); 959 prev_bpt->set_next(curr_bpt->next());
814 } 960 }
815 Breakpoint* temp_bpt = curr_bpt; 961 CodeBreakpoint* temp_bpt = curr_bpt;
816 curr_bpt = curr_bpt->next(); 962 curr_bpt = curr_bpt->next();
817 UnsetBreakpoint(temp_bpt); 963 temp_bpt->Disable();
818 delete temp_bpt; 964 delete temp_bpt;
819 } else { 965 } else {
820 prev_bpt = curr_bpt; 966 prev_bpt = curr_bpt;
821 curr_bpt = curr_bpt->next(); 967 curr_bpt = curr_bpt->next();
822 } 968 }
823 } 969 }
824 } 970 }
825 971
826 972
827 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, 973 // Remove and delete all breakpoints that are not associated with a
828 intptr_t token_index) { 974 // user-defined source breakpoint.
829 Breakpoint* bpt = this->breakpoints_; 975 void Debugger::RemoveInternalBreakpoints() {
976 RemoveCodeBreakpoints(NULL);
977 }
978
979
980 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func,
981 intptr_t token_index) {
982 SourceBreakpoint* bpt = src_breakpoints_;
830 while (bpt != NULL) { 983 while (bpt != NULL) {
831 if ((bpt->function() == func.raw()) && 984 if ((bpt->function() == func.raw()) &&
832 (bpt->token_index() == token_index)) { 985 (bpt->token_index() == token_index)) {
833 return bpt; 986 return bpt;
834 } 987 }
835 bpt = bpt->next(); 988 bpt = bpt->next();
836 } 989 }
837 return NULL; 990 return NULL;
838 } 991 }
839 992
840 993
841 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { 994 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) {
842 ASSERT(bpt->next() == NULL); 995 ASSERT(bpt->next() == NULL);
843 bpt->set_next(this->breakpoints_); 996 bpt->set_next(src_breakpoints_);
844 this->breakpoints_ = bpt; 997 src_breakpoints_ = bpt;
845 } 998 }
846 999
847 1000
1001 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
1002 ASSERT(bpt->next() == NULL);
1003 bpt->set_next(code_breakpoints_);
1004 code_breakpoints_ = bpt;
1005 }
1006
848 } // namespace dart 1007 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698