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 |