Chromium Code Reviews| OLD | NEW |
|---|---|
| 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_patcher.h" | 9 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 11 #include "vm/flags.h" | 12 #include "vm/flags.h" |
| 12 #include "vm/globals.h" | 13 #include "vm/globals.h" |
| 13 #include "vm/longjump.h" | 14 #include "vm/longjump.h" |
| 14 #include "vm/object.h" | 15 #include "vm/object.h" |
| 15 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 16 #include "vm/os.h" | 17 #include "vm/os.h" |
| 17 #include "vm/stack_frame.h" | 18 #include "vm/stack_frame.h" |
| 18 #include "vm/stub_code.h" | 19 #include "vm/stub_code.h" |
| 19 #include "vm/visitor.h" | 20 #include "vm/visitor.h" |
| 20 | 21 |
| 21 | 22 |
| 22 namespace dart { | 23 namespace dart { |
| 23 | 24 |
| 24 static const bool verbose = false; | 25 static const bool verbose = false; |
| 25 | 26 |
| 26 | 27 |
| 27 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) | 28 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) |
| 28 : function_(func.raw()), | 29 : function_(func.raw()), |
| 29 pc_desc_index_(pc_desc_index), | 30 pc_desc_index_(pc_desc_index), |
| 30 pc_(0), | 31 pc_(0), |
| 31 saved_bytes_(0), | |
| 32 line_number_(-1), | 32 line_number_(-1), |
| 33 is_patched_(false), | |
| 33 next_(NULL) { | 34 next_(NULL) { |
| 34 Code& code = Code::Handle(func.code()); | 35 Code& code = Code::Handle(func.code()); |
| 35 ASSERT(!code.IsNull()); // Function must be compiled. | 36 ASSERT(!code.IsNull()); // Function must be compiled. |
| 36 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 37 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 37 ASSERT(pc_desc_index < desc.Length()); | 38 ASSERT(pc_desc_index < desc.Length()); |
| 38 this->token_index_ = desc.TokenIndex(pc_desc_index); | 39 this->token_index_ = desc.TokenIndex(pc_desc_index); |
| 39 ASSERT(this->token_index_ > 0); | 40 ASSERT(this->token_index_ > 0); |
| 40 this->pc_ = desc.PC(pc_desc_index); | 41 this->pc_ = desc.PC(pc_desc_index); |
| 41 ASSERT(this->pc_ != 0); | 42 ASSERT(this->pc_ != 0); |
| 43 this->breakpoint_kind_ = desc.DescriptorKind(pc_desc_index); | |
| 42 } | 44 } |
| 43 | 45 |
| 44 | 46 |
| 45 RawScript* Breakpoint::SourceCode() { | 47 RawScript* Breakpoint::SourceCode() { |
| 46 const Function& func = Function::Handle(this->function_); | 48 const Function& func = Function::Handle(this->function_); |
| 47 const Class& cls = Class::Handle(func.owner()); | 49 const Class& cls = Class::Handle(func.owner()); |
| 48 return cls.script(); | 50 return cls.script(); |
| 49 } | 51 } |
| 50 | 52 |
| 51 | 53 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 65 } | 67 } |
| 66 return this->line_number_; | 68 return this->line_number_; |
| 67 } | 69 } |
| 68 | 70 |
| 69 | 71 |
| 70 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 72 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 71 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 73 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 72 } | 74 } |
| 73 | 75 |
| 74 | 76 |
| 75 ActivationFrame::ActivationFrame(uword pc, uword fp) | 77 ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp) |
| 76 : pc_(pc), fp_(fp), | 78 : pc_(pc), fp_(fp), sp_(sp), |
| 77 function_(Function::ZoneHandle()), | 79 function_(Function::ZoneHandle()), |
| 78 token_index_(-1), | 80 token_index_(-1), |
| 79 line_number_(-1), | 81 line_number_(-1), |
| 80 var_descriptors_(NULL), | 82 var_descriptors_(NULL), |
| 81 desc_indices_(8) { | 83 desc_indices_(8) { |
| 82 } | 84 } |
| 83 | 85 |
| 84 | 86 |
| 85 const Function& ActivationFrame::DartFunction() { | 87 const Function& ActivationFrame::DartFunction() { |
| 86 if (function_.IsNull()) { | 88 if (function_.IsNull()) { |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); | 273 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); |
| 272 return chars; | 274 return chars; |
| 273 } | 275 } |
| 274 | 276 |
| 275 | 277 |
| 276 void StackTrace::AddActivation(ActivationFrame* frame) { | 278 void StackTrace::AddActivation(ActivationFrame* frame) { |
| 277 this->trace_.Add(frame); | 279 this->trace_.Add(frame); |
| 278 } | 280 } |
| 279 | 281 |
| 280 | 282 |
| 283 void Breakpoint::PatchCode() { | |
| 284 ASSERT(!is_patched_); | |
| 285 switch (breakpoint_kind_) { | |
| 286 case PcDescriptors::kIcCall: { | |
| 287 int num_args, num_named_args; | |
| 288 CodePatcher::GetInstanceCallAt(pc_, | |
| 289 NULL, &num_args, &num_named_args, | |
| 290 &saved_bytes_.target_address_); | |
| 291 CodePatcher::PatchInstanceCallAt( | |
| 292 pc_, StubCode::BreakpointDynamicEntryPoint()); | |
| 293 break; | |
| 294 } | |
| 295 case PcDescriptors::kFuncCall: { | |
| 296 Function& func = Function::Handle(); | |
| 297 CodePatcher::GetStaticCallAt(pc_, &func, &saved_bytes_.target_address_); | |
| 298 CodePatcher::PatchStaticCallAt(pc_, | |
|
regis
2012/02/24 23:32:37
pc_ on next line as above?
hausner
2012/02/27 22:03:57
Done.
| |
| 299 StubCode::BreakpointStaticEntryPoint()); | |
| 300 break; | |
| 301 } | |
| 302 case PcDescriptors::kReturn: | |
| 303 PatchFunctionReturn(); | |
| 304 break; | |
| 305 default: | |
| 306 UNREACHABLE(); | |
| 307 } | |
| 308 is_patched_ = true; | |
| 309 } | |
| 310 | |
| 311 | |
| 312 void Breakpoint::RestoreCode() { | |
| 313 ASSERT(is_patched_); | |
| 314 switch (breakpoint_kind_) { | |
| 315 case PcDescriptors::kIcCall: | |
| 316 CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_); | |
| 317 break; | |
| 318 case PcDescriptors::kFuncCall: | |
| 319 CodePatcher::PatchStaticCallAt(pc_, saved_bytes_.target_address_); | |
| 320 break; | |
| 321 case PcDescriptors::kReturn: | |
| 322 RestoreFunctionReturn(); | |
| 323 break; | |
| 324 default: | |
| 325 UNREACHABLE(); | |
| 326 } | |
| 327 is_patched_ = false; | |
| 328 } | |
| 329 | |
| 330 void Breakpoint::SetActive(bool value) { | |
| 331 if (value && !is_patched_) { | |
| 332 PatchCode(); | |
| 333 return; | |
| 334 } | |
| 335 if (!value && is_patched_) { | |
| 336 RestoreCode(); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 | |
| 341 bool Breakpoint::IsActive() { | |
| 342 return is_patched_; | |
| 343 } | |
| 344 | |
| 345 | |
| 281 Debugger::Debugger() | 346 Debugger::Debugger() |
| 282 : isolate_(NULL), | 347 : isolate_(NULL), |
| 283 initialized_(false), | 348 initialized_(false), |
| 284 bp_handler_(NULL), | 349 bp_handler_(NULL), |
| 285 breakpoints_(NULL) { | 350 breakpoints_(NULL), |
| 351 resume_action_(kContinue) { | |
| 286 } | 352 } |
| 287 | 353 |
| 288 | 354 |
| 289 Debugger::~Debugger() { | 355 Debugger::~Debugger() { |
| 290 ASSERT(breakpoints_ == NULL); | 356 ASSERT(breakpoints_ == NULL); |
| 291 } | 357 } |
| 292 | 358 |
| 293 | 359 |
| 294 void Debugger::Shutdown() { | 360 void Debugger::Shutdown() { |
| 295 while (breakpoints_ != NULL) { | 361 while (breakpoints_ != NULL) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 if (!cls.IsNull()) { | 404 if (!cls.IsNull()) { |
| 339 function = cls.LookupStaticFunction(function_name); | 405 function = cls.LookupStaticFunction(function_name); |
| 340 if (function.IsNull()) { | 406 if (function.IsNull()) { |
| 341 function = cls.LookupDynamicFunction(function_name); | 407 function = cls.LookupDynamicFunction(function_name); |
| 342 } | 408 } |
| 343 } | 409 } |
| 344 return function.raw(); | 410 return function.raw(); |
| 345 } | 411 } |
| 346 | 412 |
| 347 | 413 |
| 414 void Debugger::InstrumentForStepping(const Function &target_function) { | |
| 415 if (!target_function.HasCode()) { | |
| 416 Compiler::CompileFunction(target_function); | |
| 417 // If there were any errors, ignore them silently and return without | |
| 418 // adding breakpoints to target. | |
| 419 if (!target_function.HasCode()) { | |
| 420 return; | |
| 421 } | |
| 422 } | |
| 423 Code& code = Code::Handle(target_function.code()); | |
| 424 ASSERT(!code.IsNull()); | |
| 425 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | |
| 426 for (int i = 0; i < desc.Length(); i++) { | |
| 427 Breakpoint* bpt = GetBreakpoint(desc.PC(i)); | |
| 428 if (bpt != NULL) { | |
| 429 // There is already a breakpoint for this address. Leave it alone. | |
| 430 continue; | |
| 431 } | |
| 432 PcDescriptors::Kind kind = desc.DescriptorKind(i); | |
| 433 if ((kind == PcDescriptors::kIcCall) || | |
| 434 (kind == PcDescriptors::kFuncCall) || | |
| 435 (kind == PcDescriptors::kReturn)) { | |
| 436 bpt = new Breakpoint(target_function, i); | |
| 437 bpt->set_temporary(true); | |
| 438 bpt->PatchCode(); | |
| 439 RegisterBreakpoint(bpt); | |
| 440 } | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 | |
| 348 // TODO(hausner): Distinguish between newly created breakpoints and | 445 // TODO(hausner): Distinguish between newly created breakpoints and |
| 349 // returning a breakpoint that already exists? | 446 // returning a breakpoint that already exists? |
| 350 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, | 447 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, |
| 351 intptr_t token_index, | 448 intptr_t token_index, |
| 352 Error* error) { | 449 Error* error) { |
| 353 if ((token_index < target_function.token_index()) || | 450 if ((token_index < target_function.token_index()) || |
| 354 (target_function.end_token_index() <= token_index)) { | 451 (target_function.end_token_index() <= token_index)) { |
| 355 // The given token position is not within the target function. | 452 // The given token position is not within the target function. |
| 356 return NULL; | 453 return NULL; |
| 357 } | 454 } |
| 358 if (!target_function.HasCode()) { | 455 if (!target_function.HasCode()) { |
| 359 *error = Compiler::CompileFunction(target_function); | 456 *error = Compiler::CompileFunction(target_function); |
| 360 if (!error->IsNull()) { | 457 if (!error->IsNull()) { |
| 361 return NULL; | 458 return NULL; |
| 362 } | 459 } |
| 363 } | 460 } |
| 364 Code& code = Code::Handle(target_function.code()); | 461 Code& code = Code::Handle(target_function.code()); |
| 365 ASSERT(!code.IsNull()); | 462 ASSERT(!code.IsNull()); |
| 366 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 463 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 367 for (int i = 0; i < desc.Length(); i++) { | 464 for (int i = 0; i < desc.Length(); i++) { |
| 368 if (desc.TokenIndex(i) < token_index) { | 465 if (desc.TokenIndex(i) < token_index) { |
| 369 continue; | 466 continue; |
| 370 } | 467 } |
| 468 Breakpoint* bpt = GetBreakpoint(desc.PC(i)); | |
| 469 if (bpt != NULL) { | |
| 470 // Found existing breakpoint. | |
| 471 return bpt; | |
| 472 } | |
| 371 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 473 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 372 Breakpoint* bpt = NULL; | 474 if ((kind == PcDescriptors::kIcCall) || |
| 373 if (kind == PcDescriptors::kIcCall) { | 475 (kind == PcDescriptors::kFuncCall) || |
| 374 bpt = GetBreakpoint(desc.PC(i)); | 476 (kind == PcDescriptors::kReturn)) { |
| 375 if (bpt != NULL) { | |
| 376 // There is an existing breakpoint at this token position. | |
| 377 break; | |
| 378 } | |
| 379 bpt = new Breakpoint(target_function, i); | 477 bpt = new Breakpoint(target_function, i); |
| 380 String& func_name = String::Handle(); | 478 bpt->PatchCode(); |
| 381 int num_args, num_named_args; | |
| 382 CodePatcher::GetInstanceCallAt(desc.PC(i), | |
| 383 &func_name, &num_args, &num_named_args, &bpt->saved_bytes_); | |
| 384 CodePatcher::PatchInstanceCallAt( | |
| 385 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); | |
| 386 RegisterBreakpoint(bpt); | 479 RegisterBreakpoint(bpt); |
| 387 } else if (kind == PcDescriptors::kOther) { | |
| 388 if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) { | |
| 389 bpt = GetBreakpoint(desc.PC(i)); | |
| 390 if (bpt != NULL) { | |
| 391 // There is an existing breakpoint at this token position. | |
| 392 break; | |
| 393 } | |
| 394 bpt = new Breakpoint(target_function, i); | |
| 395 Function& func = Function::Handle(); | |
| 396 CodePatcher::GetStaticCallAt(desc.PC(i), &func, &bpt->saved_bytes_); | |
| 397 CodePatcher::PatchStaticCallAt( | |
| 398 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); | |
| 399 RegisterBreakpoint(bpt); | |
| 400 } | |
| 401 } | |
| 402 if (bpt != NULL) { | |
| 403 if (verbose) { | 480 if (verbose) { |
| 404 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", | 481 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", |
| 405 String::Handle(bpt->SourceUrl()).ToCString(), | 482 String::Handle(bpt->SourceUrl()).ToCString(), |
| 406 bpt->LineNumber(), | 483 bpt->LineNumber(), |
| 407 bpt->pc()); | 484 bpt->pc()); |
| 408 } | 485 } |
| 409 return bpt; | 486 return bpt; |
| 410 } | 487 } |
| 411 } | 488 } |
| 412 return NULL; | 489 return NULL; |
| 413 } | 490 } |
| 414 | 491 |
| 415 | 492 |
| 416 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { | 493 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { |
| 417 const Function& func = Function::Handle(bpt->function()); | 494 bpt->SetActive(false); |
| 418 const Code& code = Code::Handle(func.code()); | |
| 419 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | |
| 420 intptr_t desc_index = bpt->pc_desc_index(); | |
| 421 ASSERT(desc_index < desc.Length()); | |
| 422 ASSERT(bpt->pc() == desc.PC(desc_index)); | |
| 423 PcDescriptors::Kind kind = desc.DescriptorKind(desc_index); | |
| 424 if (kind == PcDescriptors::kIcCall) { | |
| 425 CodePatcher::PatchInstanceCallAt(desc.PC(desc_index), bpt->saved_bytes_); | |
| 426 } else { | |
| 427 CodePatcher::PatchStaticCallAt(desc.PC(desc_index), bpt->saved_bytes_); | |
| 428 } | |
| 429 } | 495 } |
| 430 | 496 |
| 431 | 497 |
| 432 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, | 498 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, |
| 433 Error* error) { | 499 Error* error) { |
| 434 ASSERT(!target_function.IsNull()); | 500 ASSERT(!target_function.IsNull()); |
| 435 return SetBreakpoint(target_function, target_function.token_index(), error); | 501 return SetBreakpoint(target_function, target_function.token_index(), error); |
| 436 } | 502 } |
| 437 | 503 |
| 438 | 504 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 603 | 669 |
| 604 | 670 |
| 605 void Debugger::BreakpointCallback() { | 671 void Debugger::BreakpointCallback() { |
| 606 ASSERT(initialized_); | 672 ASSERT(initialized_); |
| 607 DartFrameIterator iterator; | 673 DartFrameIterator iterator; |
| 608 DartFrame* frame = iterator.NextFrame(); | 674 DartFrame* frame = iterator.NextFrame(); |
| 609 ASSERT(frame != NULL); | 675 ASSERT(frame != NULL); |
| 610 Breakpoint* bpt = GetBreakpoint(frame->pc()); | 676 Breakpoint* bpt = GetBreakpoint(frame->pc()); |
| 611 ASSERT(bpt != NULL); | 677 ASSERT(bpt != NULL); |
| 612 if (verbose) { | 678 if (verbose) { |
| 613 OS::Print(">>> Breakpoint at %s:%d (Address %p)\n", | 679 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", |
| 680 bpt->is_temporary() ? "hit temp" : "hit user", | |
| 614 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", | 681 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", |
| 615 bpt ? bpt->LineNumber() : 0, | 682 bpt ? bpt->LineNumber() : 0, |
| 616 frame->pc()); | 683 frame->pc()); |
| 617 } | 684 } |
| 618 StackTrace* stack_trace = new StackTrace(8); | 685 StackTrace* stack_trace = new StackTrace(8); |
| 619 while (frame != NULL) { | 686 while (frame != NULL) { |
| 620 ASSERT(frame->IsValid()); | 687 ASSERT(frame->IsValid()); |
| 621 ASSERT(frame->IsDartFrame()); | 688 ASSERT(frame->IsDartFrame()); |
| 622 ActivationFrame* activation = | 689 ActivationFrame* activation = |
| 623 new ActivationFrame(frame->pc(), frame->fp()); | 690 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); |
| 624 stack_trace->AddActivation(activation); | 691 stack_trace->AddActivation(activation); |
| 625 frame = iterator.NextFrame(); | 692 frame = iterator.NextFrame(); |
| 626 } | 693 } |
| 627 | 694 |
| 695 resume_action_ = kContinue; | |
| 628 if (bp_handler_ != NULL) { | 696 if (bp_handler_ != NULL) { |
| 629 (*bp_handler_)(bpt, stack_trace); | 697 (*bp_handler_)(bpt, stack_trace); |
| 630 } | 698 } |
| 699 | |
| 700 if (resume_action_ == kContinue) { | |
| 701 RemoveTemporaryBreakpoints(); | |
| 702 } else if (resume_action_ == kStepOver) { | |
| 703 Function& func = Function::Handle(bpt->function()); | |
| 704 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { | |
| 705 // If we are at the function return, do a StepOut action. | |
| 706 if (stack_trace->Length() > 1) { | |
| 707 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); | |
| 708 func = caller->DartFunction().raw(); | |
| 709 RemoveTemporaryBreakpoints(); | |
| 710 } | |
| 711 } | |
| 712 InstrumentForStepping(func); | |
| 713 } else if (resume_action_ == kStepInto) { | |
| 714 RemoveTemporaryBreakpoints(); | |
| 715 if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) { | |
| 716 int num_args, num_named_args; | |
| 717 uword target; | |
| 718 CodePatcher::GetInstanceCallAt(bpt->pc_, NULL, | |
| 719 &num_args, &num_named_args, &target); | |
| 720 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); | |
| 721 Instance& receiver = Instance::Handle( | |
| 722 top_frame->GetInstanceCallReceiver(num_args)); | |
| 723 Code& code = Code::Handle( | |
| 724 ResolveCompileInstanceCallTarget(isolate_, receiver)); | |
| 725 if (!code.IsNull()) { | |
| 726 Function& callee = Function::Handle(code.function()); | |
| 727 InstrumentForStepping(callee); | |
|
regis
2012/02/24 23:32:37
Setting a breakpoint at the entry of the callee sh
hausner
2012/02/27 22:03:57
True. Added a todo to optimize later.
| |
| 728 } | |
| 729 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) { | |
| 730 Function& callee = Function::Handle(); | |
| 731 uword target; | |
| 732 CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target); | |
| 733 InstrumentForStepping(callee); | |
|
regis
2012/02/24 23:32:37
ditto
hausner
2012/02/27 22:03:57
ditto.
| |
| 734 } else { | |
| 735 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); | |
| 736 // Treat like stepping out to caller. | |
| 737 if (stack_trace->Length() > 1) { | |
| 738 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); | |
| 739 InstrumentForStepping(caller->DartFunction()); | |
| 740 } | |
| 741 } | |
| 742 } else { | |
| 743 ASSERT(resume_action_ == kStepOut); | |
| 744 // Set temporary breakpoints in the caller. | |
| 745 RemoveTemporaryBreakpoints(); | |
| 746 if (stack_trace->Length() > 1) { | |
| 747 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); | |
| 748 InstrumentForStepping(caller->DartFunction()); | |
| 749 } | |
| 750 } | |
| 631 } | 751 } |
| 632 | 752 |
| 633 | 753 |
| 634 void Debugger::Initialize(Isolate* isolate) { | 754 void Debugger::Initialize(Isolate* isolate) { |
| 635 if (initialized_) { | 755 if (initialized_) { |
| 636 return; | 756 return; |
| 637 } | 757 } |
| 638 isolate_ = isolate; | 758 isolate_ = isolate; |
| 639 initialized_ = true; | 759 initialized_ = true; |
| 640 SetBreakpointHandler(DefaultBreakpointHandler); | 760 SetBreakpointHandler(DefaultBreakpointHandler); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 668 delete bpt; | 788 delete bpt; |
| 669 return; | 789 return; |
| 670 } | 790 } |
| 671 prev_bpt = curr_bpt; | 791 prev_bpt = curr_bpt; |
| 672 curr_bpt = curr_bpt->next(); | 792 curr_bpt = curr_bpt->next(); |
| 673 } | 793 } |
| 674 // bpt is not a registered breakpoint, nothing to do. | 794 // bpt is not a registered breakpoint, nothing to do. |
| 675 } | 795 } |
| 676 | 796 |
| 677 | 797 |
| 798 void Debugger::RemoveTemporaryBreakpoints() { | |
| 799 Breakpoint* prev_bpt = NULL; | |
| 800 Breakpoint* curr_bpt = breakpoints_; | |
| 801 while (curr_bpt != NULL) { | |
| 802 if (curr_bpt->is_temporary()) { | |
| 803 if (prev_bpt == NULL) { | |
| 804 breakpoints_ = breakpoints_->next(); | |
| 805 } else { | |
| 806 prev_bpt->set_next(curr_bpt->next()); | |
| 807 } | |
| 808 Breakpoint* temp_bpt = curr_bpt; | |
| 809 curr_bpt = curr_bpt->next(); | |
| 810 UnsetBreakpoint(temp_bpt); | |
| 811 delete temp_bpt; | |
| 812 } else { | |
| 813 prev_bpt = curr_bpt; | |
| 814 curr_bpt = curr_bpt->next(); | |
| 815 } | |
| 816 } | |
| 817 } | |
| 818 | |
| 819 | |
| 678 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, | 820 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, |
| 679 intptr_t token_index) { | 821 intptr_t token_index) { |
| 680 Breakpoint* bpt = this->breakpoints_; | 822 Breakpoint* bpt = this->breakpoints_; |
| 681 while (bpt != NULL) { | 823 while (bpt != NULL) { |
| 682 if ((bpt->function() == func.raw()) && | 824 if ((bpt->function() == func.raw()) && |
| 683 (bpt->token_index() == token_index)) { | 825 (bpt->token_index() == token_index)) { |
| 684 return bpt; | 826 return bpt; |
| 685 } | 827 } |
| 686 bpt = bpt->next(); | 828 bpt = bpt->next(); |
| 687 } | 829 } |
| 688 return NULL; | 830 return NULL; |
| 689 } | 831 } |
| 690 | 832 |
| 691 | 833 |
| 692 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { | 834 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { |
| 693 ASSERT(bpt->next() == NULL); | 835 ASSERT(bpt->next() == NULL); |
| 694 bpt->set_next(this->breakpoints_); | 836 bpt->set_next(this->breakpoints_); |
| 695 this->breakpoints_ = bpt; | 837 this->breakpoints_ = bpt; |
| 696 } | 838 } |
| 697 | 839 |
| 698 | 840 |
| 699 } // namespace dart | 841 } // namespace dart |
| OLD | NEW |