| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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" |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 intptr_t len = | 281 intptr_t len = |
| 282 OS::SNPrint(NULL, 0, kFormat, func_name, url.ToCString(), line); | 282 OS::SNPrint(NULL, 0, kFormat, func_name, url.ToCString(), line); |
| 283 len++; // String terminator. | 283 len++; // String terminator. |
| 284 char* chars = reinterpret_cast<char*>( | 284 char* chars = reinterpret_cast<char*>( |
| 285 Isolate::Current()->current_zone()->Allocate(len)); | 285 Isolate::Current()->current_zone()->Allocate(len)); |
| 286 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); | 286 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); |
| 287 return chars; | 287 return chars; |
| 288 } | 288 } |
| 289 | 289 |
| 290 | 290 |
| 291 void StackTrace::AddActivation(ActivationFrame* frame) { | 291 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
| 292 trace_.Add(frame); | 292 trace_.Add(frame); |
| 293 } | 293 } |
| 294 | 294 |
| 295 | 295 |
| 296 CodeBreakpoint::CodeBreakpoint(const Function& func, intptr_t pc_desc_index) | 296 CodeBreakpoint::CodeBreakpoint(const Function& func, intptr_t pc_desc_index) |
| 297 : function_(func.raw()), | 297 : function_(func.raw()), |
| 298 pc_desc_index_(pc_desc_index), | 298 pc_desc_index_(pc_desc_index), |
| 299 pc_(0), | 299 pc_(0), |
| 300 line_number_(-1), | 300 line_number_(-1), |
| 301 is_enabled_(false), | 301 is_enabled_(false), |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 (kind == PcDescriptors::kFuncCall) || | 507 (kind == PcDescriptors::kFuncCall) || |
| 508 (kind == PcDescriptors::kReturn)) { | 508 (kind == PcDescriptors::kReturn)) { |
| 509 bpt = new CodeBreakpoint(target_function, i); | 509 bpt = new CodeBreakpoint(target_function, i); |
| 510 RegisterCodeBreakpoint(bpt); | 510 RegisterCodeBreakpoint(bpt); |
| 511 bpt->Enable(); | 511 bpt->Enable(); |
| 512 } | 512 } |
| 513 } | 513 } |
| 514 } | 514 } |
| 515 | 515 |
| 516 | 516 |
| 517 CodeBreakpoint* Debugger::MakeCodeBreakpoint(SourceBreakpoint* src_bpt) { | 517 CodeBreakpoint* Debugger::MakeCodeBreakpoint(const Function& func, |
| 518 Function& func = Function::Handle(src_bpt->function()); | 518 intptr_t token_index) { |
| 519 ASSERT(func.HasCode()); | 519 ASSERT(func.HasCode()); |
| 520 ASSERT(!func.HasOptimizedCode()); | 520 ASSERT(!func.HasOptimizedCode()); |
| 521 Code& code = Code::Handle(func.unoptimized_code()); | 521 Code& code = Code::Handle(func.unoptimized_code()); |
| 522 ASSERT(!code.IsNull()); | 522 ASSERT(!code.IsNull()); |
| 523 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(); | |
| 525 for (int i = 0; i < desc.Length(); i++) { | 524 for (int i = 0; i < desc.Length(); i++) { |
| 526 if (desc.TokenIndex(i) < requested_token_index) { | 525 if (desc.TokenIndex(i) < token_index) { |
| 527 continue; | 526 continue; |
| 528 } | 527 } |
| 529 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i)); | 528 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i)); |
| 530 // We should only ever have one code breakpoint at the same address. | 529 // 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 | 530 // If we find an existing breakpoint, it must be an internal one which |
| 532 // is used for stepping. | 531 // is used for stepping. |
| 533 if (bpt != NULL) { | 532 if (bpt != NULL) { |
| 534 ASSERT(bpt->src_bpt() == NULL); | 533 ASSERT(bpt->src_bpt() == NULL); |
| 535 bpt->set_src_bpt(src_bpt); | |
| 536 return bpt; | 534 return bpt; |
| 537 } | 535 } |
| 538 | 536 |
| 539 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 537 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 540 if ((kind == PcDescriptors::kIcCall) || | 538 if ((kind == PcDescriptors::kIcCall) || |
| 541 (kind == PcDescriptors::kFuncCall) || | 539 (kind == PcDescriptors::kFuncCall) || |
| 542 (kind == PcDescriptors::kReturn)) { | 540 (kind == PcDescriptors::kReturn)) { |
| 543 bpt = new CodeBreakpoint(func, i); | 541 bpt = new CodeBreakpoint(func, i); |
| 544 bpt->set_src_bpt(src_bpt); | |
| 545 if (verbose) { | 542 if (verbose) { |
| 546 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n", | 543 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n", |
| 547 String::Handle(func.name()).ToCString(), | 544 String::Handle(func.name()).ToCString(), |
| 548 String::Handle(bpt->SourceUrl()).ToCString(), | 545 String::Handle(bpt->SourceUrl()).ToCString(), |
| 549 bpt->LineNumber(), | 546 bpt->LineNumber(), |
| 550 bpt->pc()); | 547 bpt->pc()); |
| 551 } | 548 } |
| 552 RegisterCodeBreakpoint(bpt); | 549 RegisterCodeBreakpoint(bpt); |
| 553 return bpt; | 550 return bpt; |
| 554 } | 551 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 573 RegisterSourceBreakpoint(bpt); | 570 RegisterSourceBreakpoint(bpt); |
| 574 if (verbose && !target_function.HasCode()) { | 571 if (verbose && !target_function.HasCode()) { |
| 575 OS::Print("Registering breakpoint for uncompiled function '%s'" | 572 OS::Print("Registering breakpoint for uncompiled function '%s'" |
| 576 " (%s:%d)\n", | 573 " (%s:%d)\n", |
| 577 String::Handle(target_function.name()).ToCString(), | 574 String::Handle(target_function.name()).ToCString(), |
| 578 String::Handle(bpt->SourceUrl()).ToCString(), | 575 String::Handle(bpt->SourceUrl()).ToCString(), |
| 579 bpt->LineNumber()); | 576 bpt->LineNumber()); |
| 580 } | 577 } |
| 581 | 578 |
| 582 if (target_function.HasCode()) { | 579 if (target_function.HasCode()) { |
| 583 CodeBreakpoint* cbpt = MakeCodeBreakpoint(bpt); | 580 CodeBreakpoint* cbpt = MakeCodeBreakpoint(target_function, token_index); |
| 584 if (cbpt == NULL) { | 581 if (cbpt != NULL) { |
| 582 ASSERT(cbpt->src_bpt() == NULL); |
| 583 cbpt->set_src_bpt(bpt); |
| 584 } else { |
| 585 if (verbose) { | 585 if (verbose) { |
| 586 OS::Print("Failed to set breakpoint at '%s' line %d\n", | 586 OS::Print("Failed to set breakpoint at '%s' line %d\n", |
| 587 String::Handle(bpt->SourceUrl()).ToCString(), | 587 String::Handle(bpt->SourceUrl()).ToCString(), |
| 588 bpt->LineNumber()); | 588 bpt->LineNumber()); |
| 589 } | 589 } |
| 590 } | 590 } |
| 591 } | 591 } |
| 592 bpt->Enable(); | 592 bpt->Enable(); |
| 593 return bpt; | 593 return bpt; |
| 594 } | 594 } |
| 595 | 595 |
| 596 | 596 |
| 597 // Synchronize the enabled/disabled state of all code breakpoints |
| 598 // associated with the source breakpoint bpt. |
| 597 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { | 599 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
| 598 CodeBreakpoint* cbpt = code_breakpoints_; | 600 CodeBreakpoint* cbpt = code_breakpoints_; |
| 599 while (cbpt != NULL) { | 601 while (cbpt != NULL) { |
| 600 if (bpt == cbpt->src_bpt()) { | 602 if (bpt == cbpt->src_bpt()) { |
| 601 if (bpt->IsEnabled()) { | 603 if (bpt->IsEnabled()) { |
| 602 cbpt->Enable(); | 604 cbpt->Enable(); |
| 603 } else { | 605 } else { |
| 604 cbpt->Disable(); | 606 cbpt->Disable(); |
| 605 } | 607 } |
| 606 } | 608 } |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 765 bpt = bpt->next(); | 767 bpt = bpt->next(); |
| 766 } | 768 } |
| 767 CodeBreakpoint* cbpt = code_breakpoints_; | 769 CodeBreakpoint* cbpt = code_breakpoints_; |
| 768 while (cbpt != NULL) { | 770 while (cbpt != NULL) { |
| 769 cbpt->VisitObjectPointers(visitor); | 771 cbpt->VisitObjectPointers(visitor); |
| 770 cbpt = cbpt->next(); | 772 cbpt = cbpt->next(); |
| 771 } | 773 } |
| 772 } | 774 } |
| 773 | 775 |
| 774 | 776 |
| 775 static void DefaultBreakpointHandler(SourceBreakpoint* bpt, StackTrace* stack) { | 777 static void DefaultBreakpointHandler(SourceBreakpoint* bpt, |
| 778 DebuggerStackTrace* stack) { |
| 776 String& var_name = String::Handle(); | 779 String& var_name = String::Handle(); |
| 777 Instance& value = Instance::Handle(); | 780 Instance& value = Instance::Handle(); |
| 778 for (intptr_t i = 0; i < stack->Length(); i++) { | 781 for (intptr_t i = 0; i < stack->Length(); i++) { |
| 779 ActivationFrame* frame = stack->ActivationFrameAt(i); | 782 ActivationFrame* frame = stack->ActivationFrameAt(i); |
| 780 OS::Print(" %d. %s\n", | 783 OS::Print(" %d. %s\n", |
| 781 i + 1, frame->ToCString()); | 784 i + 1, frame->ToCString()); |
| 782 intptr_t num_locals = frame->NumLocalVariables(); | 785 intptr_t num_locals = frame->NumLocalVariables(); |
| 783 for (intptr_t i = 0; i < num_locals; i++) { | 786 for (intptr_t i = 0; i < num_locals; i++) { |
| 784 intptr_t token_pos, end_pos; | 787 intptr_t token_pos, end_pos; |
| 785 frame->VariableAt(i, &var_name, &token_pos, &end_pos, &value); | 788 frame->VariableAt(i, &var_name, &token_pos, &end_pos, &value); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 805 ASSERT(frame != NULL); | 808 ASSERT(frame != NULL); |
| 806 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc()); | 809 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc()); |
| 807 ASSERT(bpt != NULL); | 810 ASSERT(bpt != NULL); |
| 808 if (verbose) { | 811 if (verbose) { |
| 809 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", | 812 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", |
| 810 bpt->IsInternal() ? "hit internal" : "hit user", | 813 bpt->IsInternal() ? "hit internal" : "hit user", |
| 811 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", | 814 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", |
| 812 bpt ? bpt->LineNumber() : 0, | 815 bpt ? bpt->LineNumber() : 0, |
| 813 frame->pc()); | 816 frame->pc()); |
| 814 } | 817 } |
| 815 StackTrace* stack_trace = new StackTrace(8); | 818 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 816 while (frame != NULL) { | 819 while (frame != NULL) { |
| 817 ASSERT(frame->IsValid()); | 820 ASSERT(frame->IsValid()); |
| 818 ASSERT(frame->IsDartFrame()); | 821 ASSERT(frame->IsDartFrame()); |
| 819 ActivationFrame* activation = | 822 ActivationFrame* activation = |
| 820 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); | 823 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); |
| 821 stack_trace->AddActivation(activation); | 824 stack_trace->AddActivation(activation); |
| 822 frame = iterator.NextFrame(); | 825 frame = iterator.NextFrame(); |
| 823 } | 826 } |
| 824 | 827 |
| 825 resume_action_ = kContinue; | 828 resume_action_ = kContinue; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 void Debugger::Initialize(Isolate* isolate) { | 888 void Debugger::Initialize(Isolate* isolate) { |
| 886 if (initialized_) { | 889 if (initialized_) { |
| 887 return; | 890 return; |
| 888 } | 891 } |
| 889 isolate_ = isolate; | 892 isolate_ = isolate; |
| 890 initialized_ = true; | 893 initialized_ = true; |
| 891 SetBreakpointHandler(DefaultBreakpointHandler); | 894 SetBreakpointHandler(DefaultBreakpointHandler); |
| 892 } | 895 } |
| 893 | 896 |
| 894 | 897 |
| 895 // TODO(hausner): handle closure functions. | |
| 896 void Debugger::NotifyCompilation(const Function& func) { | 898 void Debugger::NotifyCompilation(const Function& func) { |
| 899 if (src_breakpoints_ == NULL) { |
| 900 // Return with minimal overhead if there are no breakpoints. |
| 901 return; |
| 902 } |
| 903 Function& lookup_function = Function::Handle(func.raw()); |
| 904 if (func.IsClosureFunction()) { |
| 905 // If the newly compiled function is a closure, we need to use |
| 906 // the closure's parent function to see whether there are any |
| 907 // breakpoints. |
| 908 lookup_function = func.parent_function(); |
| 909 } |
| 897 SourceBreakpoint* bpt = src_breakpoints_; | 910 SourceBreakpoint* bpt = src_breakpoints_; |
| 898 while (bpt != NULL) { | 911 while (bpt != NULL) { |
| 899 if (func.raw() == bpt->function()) { | 912 if (lookup_function.raw() == bpt->function()) { |
| 900 if (verbose) { | 913 if (verbose) { |
| 901 OS::Print("Enable latent breakpoint for function '%s'\n", | 914 OS::Print("Enable latent breakpoint for function '%s'\n", |
| 902 String::Handle(func.name()).ToCString()); | 915 String::Handle(lookup_function.name()).ToCString()); |
| 903 } | 916 } |
| 904 MakeCodeBreakpoint(bpt); | 917 // Set breakpoint in newly compiled code of function func. |
| 918 CodeBreakpoint* cbpt = MakeCodeBreakpoint(func, bpt->token_index()); |
| 919 if (cbpt != NULL) { |
| 920 cbpt->set_src_bpt(bpt); |
| 921 } |
| 905 bpt->Enable(); // Enables the code breakpoint as well. | 922 bpt->Enable(); // Enables the code breakpoint as well. |
| 906 } | 923 } |
| 907 bpt = bpt->next(); | 924 bpt = bpt->next(); |
| 908 } | 925 } |
| 909 } | 926 } |
| 910 | 927 |
| 911 | 928 |
| 912 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 929 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
| 913 CodeBreakpoint* bpt = code_breakpoints_; | 930 CodeBreakpoint* bpt = code_breakpoints_; |
| 914 while (bpt != NULL) { | 931 while (bpt != NULL) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 } | 1015 } |
| 999 | 1016 |
| 1000 | 1017 |
| 1001 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1018 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1002 ASSERT(bpt->next() == NULL); | 1019 ASSERT(bpt->next() == NULL); |
| 1003 bpt->set_next(code_breakpoints_); | 1020 bpt->set_next(code_breakpoints_); |
| 1004 code_breakpoints_ = bpt; | 1021 code_breakpoints_ = bpt; |
| 1005 } | 1022 } |
| 1006 | 1023 |
| 1007 } // namespace dart | 1024 } // namespace dart |
| OLD | NEW |