Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, 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 "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 | 8 |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 } | 55 } |
| 56 | 56 |
| 57 private: | 57 private: |
| 58 GrowableObjectArray* objs_; | 58 GrowableObjectArray* objs_; |
| 59 | 59 |
| 60 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 60 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 | 63 |
| 64 // Create an unresolved breakpoint in given token range and script. | 64 // Create an unresolved breakpoint in given token range and script. |
| 65 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 65 SourceBreakpoint::SourceBreakpoint(const Script& script, |
| 66 const Script& script, | |
| 67 intptr_t token_pos, | 66 intptr_t token_pos, |
| 68 intptr_t end_token_pos) | 67 intptr_t end_token_pos) |
| 69 : id_(id), | 68 : script_(script.raw()), |
| 70 script_(script.raw()), | |
| 71 url_(script.url()), | 69 url_(script.url()), |
| 72 token_pos_(token_pos), | 70 token_pos_(token_pos), |
| 73 end_token_pos_(end_token_pos), | 71 end_token_pos_(end_token_pos), |
| 74 is_resolved_(false), | 72 is_resolved_(false), |
| 75 is_enabled_(false), | 73 is_enabled_(false), |
| 76 is_one_shot_(false), | |
| 77 next_(NULL), | 74 next_(NULL), |
| 75 conditions_(NULL), | |
| 78 function_(Function::null()), | 76 function_(Function::null()), |
| 79 line_number_(-1) { | 77 line_number_(-1) { |
| 80 ASSERT(id_ > 0); | |
| 81 ASSERT(!script.IsNull()); | 78 ASSERT(!script.IsNull()); |
| 82 ASSERT(token_pos_ >= 0); | 79 ASSERT(token_pos_ >= 0); |
| 83 } | 80 } |
| 84 | 81 |
| 85 // Create a latent breakpoint at given url and line number. | 82 // Create a latent breakpoint at given url and line number. |
| 86 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 83 SourceBreakpoint::SourceBreakpoint(const String& url, |
| 87 const String& url, | |
| 88 intptr_t line_number) | 84 intptr_t line_number) |
| 89 : id_(id), | 85 : script_(Script::null()), |
| 90 script_(Script::null()), | |
| 91 url_(url.raw()), | 86 url_(url.raw()), |
| 92 token_pos_(-1), | 87 token_pos_(-1), |
| 93 end_token_pos_(-1), | 88 end_token_pos_(-1), |
| 94 is_resolved_(false), | 89 is_resolved_(false), |
| 95 is_enabled_(false), | 90 is_enabled_(false), |
| 96 is_one_shot_(false), | |
| 97 next_(NULL), | 91 next_(NULL), |
| 92 conditions_(NULL), | |
| 98 function_(Function::null()), | 93 function_(Function::null()), |
| 99 line_number_(line_number) { | 94 line_number_(line_number) { |
| 100 ASSERT(id >= 0); | |
| 101 ASSERT(line_number_ >= 0); | 95 ASSERT(line_number_ >= 0); |
| 102 } | 96 } |
| 103 | 97 |
| 104 void SourceBreakpoint::Enable() { | 98 void SourceBreakpoint::Enable() { |
| 105 is_enabled_ = true; | 99 is_enabled_ = true; |
| 106 Isolate::Current()->debugger()->SyncBreakpoint(this); | 100 Isolate::Current()->debugger()->SyncBreakpoint(this); |
| 107 } | 101 } |
| 108 | 102 |
| 109 | 103 |
| 110 void SourceBreakpoint::Disable() { | 104 void SourceBreakpoint::Disable() { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 ASSERT(!IsLatent() || line_number_ >= 0); | 151 ASSERT(!IsLatent() || line_number_ >= 0); |
| 158 // Compute line number lazily since it causes scanning of the script. | 152 // Compute line number lazily since it causes scanning of the script. |
| 159 if (line_number_ < 0) { | 153 if (line_number_ < 0) { |
| 160 const Script& script = Script::Handle(this->script()); | 154 const Script& script = Script::Handle(this->script()); |
| 161 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 155 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
| 162 } | 156 } |
| 163 return line_number_; | 157 return line_number_; |
| 164 } | 158 } |
| 165 | 159 |
| 166 | 160 |
| 161 void BreakpointCondition::set_src_bpt(SourceBreakpoint* new_src_bpt) { | |
| 162 ASSERT(src_bpt_->IsLatent()); // Only reason to move. | |
| 163 src_bpt_ = new_src_bpt; | |
| 164 } | |
| 165 | |
| 166 | |
| 167 void BreakpointCondition::VisitObjectPointers(ObjectPointerVisitor* visitor) { | |
| 168 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); | |
| 169 } | |
| 170 | |
| 171 | |
| 167 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 172 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 168 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | 173 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
| 169 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); | 174 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); |
| 170 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 175 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 176 | |
| 177 BreakpointCondition* cond = conditions_; | |
| 178 while (cond != NULL) { | |
| 179 cond -> VisitObjectPointers(visitor); | |
| 180 cond = cond->next(); | |
| 181 } | |
| 171 } | 182 } |
| 172 | 183 |
| 173 | 184 |
| 174 void SourceBreakpoint::PrintJSON(JSONStream* stream) { | 185 void BreakpointCondition::PrintJSON(JSONStream* stream) { |
| 175 Isolate* isolate = Isolate::Current(); | 186 Isolate* isolate = Isolate::Current(); |
| 176 | 187 |
| 177 JSONObject jsobj(stream); | 188 JSONObject jsobj(stream); |
| 178 jsobj.AddProperty("type", "Breakpoint"); | 189 jsobj.AddProperty("type", "Breakpoint"); |
| 179 | 190 |
| 180 jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id()); | 191 jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id()); |
| 181 jsobj.AddProperty("breakpointNumber", id()); | 192 jsobj.AddProperty("breakpointNumber", id()); |
| 182 jsobj.AddProperty("resolved", IsResolved()); | 193 jsobj.AddProperty("resolved", src_bpt_->IsResolved()); |
| 183 | 194 |
| 184 Library& library = Library::Handle(isolate); | 195 Library& library = Library::Handle(isolate); |
| 185 Script& script = Script::Handle(isolate); | 196 Script& script = Script::Handle(isolate); |
| 186 intptr_t token_pos; | 197 intptr_t token_pos; |
| 187 GetCodeLocation(&library, &script, &token_pos); | 198 src_bpt_->GetCodeLocation(&library, &script, &token_pos); |
| 188 { | 199 { |
| 189 JSONObject location(&jsobj, "location"); | 200 JSONObject location(&jsobj, "location"); |
| 190 location.AddProperty("type", "Location"); | 201 location.AddProperty("type", "Location"); |
| 191 location.AddProperty("script", script); | 202 location.AddProperty("script", script); |
| 192 location.AddProperty("tokenPos", token_pos); | 203 location.AddProperty("tokenPos", token_pos); |
| 193 } | 204 } |
| 194 } | 205 } |
| 195 | 206 |
| 196 | 207 |
| 197 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 208 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 Debugger* debugger = Isolate::Current()->debugger(); | 297 Debugger* debugger = Isolate::Current()->debugger(); |
| 287 ASSERT(debugger != NULL); | 298 ASSERT(debugger != NULL); |
| 288 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); | 299 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); |
| 289 } | 300 } |
| 290 } | 301 } |
| 291 | 302 |
| 292 | 303 |
| 293 // The vm service handles breakpoint notifications in a different way | 304 // The vm service handles breakpoint notifications in a different way |
| 294 // than the regular debugger breakpoint notifications. | 305 // than the regular debugger breakpoint notifications. |
| 295 static void SendServiceBreakpointEvent(ServiceEvent::EventType type, | 306 static void SendServiceBreakpointEvent(ServiceEvent::EventType type, |
| 296 SourceBreakpoint* bpt) { | 307 BreakpointCondition* bpt) { |
| 297 if (Service::NeedsEvents()) { | 308 if (Service::NeedsEvents()) { |
| 298 ServiceEvent service_event(Isolate::Current(), type); | 309 ServiceEvent service_event(Isolate::Current(), type); |
| 299 service_event.set_breakpoint(bpt); | 310 service_event.set_breakpoint(bpt); |
| 300 Service::HandleEvent(&service_event); | 311 Service::HandleEvent(&service_event); |
| 301 } | 312 } |
| 302 } | 313 } |
| 303 | 314 |
| 304 | 315 |
| 316 BreakpointCondition* SourceBreakpoint::AddRepeated(Debugger* dbg) { | |
| 317 BreakpointCondition* cond = conditions(); | |
| 318 while (cond != NULL) { | |
| 319 if (cond->IsRepeated()) break; | |
| 320 cond = cond->next(); | |
| 321 } | |
| 322 if (cond == NULL) { | |
| 323 cond = new BreakpointCondition(dbg->nextId(), this); | |
| 324 cond->SetIsRepeated(); | |
| 325 cond->set_next(conditions()); | |
| 326 set_conditions(cond); | |
| 327 | |
| 328 if (IsResolved()) { | |
| 329 dbg->SignalBpResolved(cond); | |
| 330 } | |
| 331 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond); | |
| 332 } | |
| 333 return cond; | |
| 334 } | |
| 335 | |
| 336 | |
| 337 BreakpointCondition* SourceBreakpoint::AddSingleShot(Debugger* dbg) { | |
| 338 BreakpointCondition* cond = conditions(); | |
| 339 while (cond != NULL) { | |
| 340 if (cond->IsSingleShot()) break; | |
| 341 cond = cond->next(); | |
| 342 } | |
| 343 if (cond == NULL) { | |
| 344 cond = new BreakpointCondition(dbg->nextId(), this); | |
| 345 cond->SetIsSingleShot(); | |
| 346 cond->set_next(conditions()); | |
| 347 set_conditions(cond); | |
| 348 | |
| 349 if (IsResolved()) { | |
| 350 dbg->SignalBpResolved(cond); | |
| 351 } | |
| 352 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond); | |
| 353 } | |
| 354 return cond; | |
| 355 } | |
| 356 | |
| 357 | |
| 358 BreakpointCondition* SourceBreakpoint::AddPerClosure(Debugger* dbg, | |
| 359 const Instance& closure) { | |
| 360 BreakpointCondition* cond = conditions(); | |
| 361 while (cond != NULL) { | |
| 362 if (cond->IsPerClosure() && cond->closure() == closure.raw()) break; | |
| 363 cond = cond->next(); | |
| 364 } | |
| 365 if (cond == NULL) { | |
| 366 cond = new BreakpointCondition(dbg->nextId(), this); | |
| 367 cond->SetIsPerClosure(closure); | |
| 368 cond->set_next(conditions()); | |
| 369 set_conditions(cond); | |
| 370 | |
| 371 if (IsResolved()) { | |
| 372 dbg->SignalBpResolved(cond); | |
| 373 } | |
| 374 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond); | |
| 375 } | |
| 376 return cond; | |
| 377 } | |
| 378 | |
| 379 | |
| 305 const char* Debugger::QualifiedFunctionName(const Function& func) { | 380 const char* Debugger::QualifiedFunctionName(const Function& func) { |
| 306 const String& func_name = String::Handle(func.name()); | 381 const String& func_name = String::Handle(func.name()); |
| 307 Class& func_class = Class::Handle(func.Owner()); | 382 Class& func_class = Class::Handle(func.Owner()); |
| 308 String& class_name = String::Handle(func_class.Name()); | 383 String& class_name = String::Handle(func_class.Name()); |
| 309 | 384 |
| 310 const char* kFormat = "%s%s%s"; | 385 const char* kFormat = "%s%s%s"; |
| 311 intptr_t len = OS::SNPrint(NULL, 0, kFormat, | 386 intptr_t len = OS::SNPrint(NULL, 0, kFormat, |
| 312 func_class.IsTopLevel() ? "" : class_name.ToCString(), | 387 func_class.IsTopLevel() ? "" : class_name.ToCString(), |
| 313 func_class.IsTopLevel() ? "" : ".", | 388 func_class.IsTopLevel() ? "" : ".", |
| 314 func_name.ToCString()); | 389 func_name.ToCString()); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 } | 446 } |
| 372 cbpt = cbpt->next_; | 447 cbpt = cbpt->next_; |
| 373 } | 448 } |
| 374 return false; | 449 return false; |
| 375 } | 450 } |
| 376 | 451 |
| 377 | 452 |
| 378 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { | 453 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { |
| 379 SourceBreakpoint* sbpt = src_breakpoints_; | 454 SourceBreakpoint* sbpt = src_breakpoints_; |
| 380 while (sbpt != NULL) { | 455 while (sbpt != NULL) { |
| 381 jsarr->AddValue(sbpt); | 456 BreakpointCondition* cond = sbpt->conditions(); |
| 457 while (cond != NULL) { | |
| 458 jsarr->AddValue(cond); | |
| 459 cond = cond->next(); | |
| 460 } | |
| 382 sbpt = sbpt->next_; | 461 sbpt = sbpt->next_; |
| 383 } | 462 } |
| 384 } | 463 } |
| 385 | 464 |
| 386 | 465 |
| 387 RawString* ActivationFrame::QualifiedFunctionName() { | 466 RawString* ActivationFrame::QualifiedFunctionName() { |
| 388 return String::New(Debugger::QualifiedFunctionName(function())); | 467 return String::New(Debugger::QualifiedFunctionName(function())); |
| 389 } | 468 } |
| 390 | 469 |
| 391 | 470 |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 668 vars_initialized_ = true; | 747 vars_initialized_ = true; |
| 669 } | 748 } |
| 670 | 749 |
| 671 | 750 |
| 672 intptr_t ActivationFrame::NumLocalVariables() { | 751 intptr_t ActivationFrame::NumLocalVariables() { |
| 673 GetDescIndices(); | 752 GetDescIndices(); |
| 674 return desc_indices_.length(); | 753 return desc_indices_.length(); |
| 675 } | 754 } |
| 676 | 755 |
| 677 | 756 |
| 757 RawObject* ActivationFrame::GetParameter(intptr_t index) { | |
| 758 intptr_t num_parameters = function().num_fixed_parameters(); | |
| 759 ASSERT(0 <= index && index < num_parameters); | |
| 760 intptr_t reverse_index = num_parameters - index; | |
| 761 | |
| 762 if (function().NumOptionalParameters() > 0) { | |
| 763 // If the function has optional parameters, the first positional parameter | |
| 764 // can be in a number of places in the caller's frame depending on how many | |
| 765 // were actually supplied at the call site, but they are copied to a fixed | |
| 766 // place in the callee's frame. | |
| 767 uword var_address = fp() + ((kFirstLocalSlotFromFp - index) * kWordSize); | |
| 768 return reinterpret_cast<RawObject*>( | |
| 769 *reinterpret_cast<uword*>(var_address)); | |
| 770 } else { | |
| 771 uword var_address = fp() + (kParamEndSlotFromFp * kWordSize) | |
| 772 + (reverse_index * kWordSize); | |
| 773 return reinterpret_cast<RawObject*>( | |
| 774 *reinterpret_cast<uword*>(var_address)); | |
| 775 } | |
| 776 } | |
| 777 | |
| 778 | |
| 779 RawObject* ActivationFrame::GetClosure() { | |
| 780 ASSERT(function().IsClosureFunction()); | |
| 781 return GetParameter(0); | |
| 782 } | |
| 783 | |
| 784 | |
| 678 RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) { | 785 RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) { |
| 679 if (deopt_frame_.IsNull()) { | 786 if (deopt_frame_.IsNull()) { |
| 680 uword var_address = fp() + slot_index * kWordSize; | 787 uword var_address = fp() + slot_index * kWordSize; |
| 681 return reinterpret_cast<RawObject*>( | 788 return reinterpret_cast<RawObject*>( |
| 682 *reinterpret_cast<uword*>(var_address)); | 789 *reinterpret_cast<uword*>(var_address)); |
| 683 } else { | 790 } else { |
| 684 return deopt_frame_.At(deopt_frame_offset_ + slot_index); | 791 return deopt_frame_.At(deopt_frame_offset_ + slot_index); |
| 685 } | 792 } |
| 686 } | 793 } |
| 687 | 794 |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1185 if (function.HasOptimizedCode()) { | 1292 if (function.HasOptimizedCode()) { |
| 1186 function.SwitchToUnoptimizedCode(); | 1293 function.SwitchToUnoptimizedCode(); |
| 1187 } | 1294 } |
| 1188 } | 1295 } |
| 1189 } | 1296 } |
| 1190 } | 1297 } |
| 1191 } | 1298 } |
| 1192 } | 1299 } |
| 1193 | 1300 |
| 1194 | 1301 |
| 1195 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { | 1302 void Debugger::SignalBpResolved(BreakpointCondition* cond) { |
| 1196 if (HasEventHandler() && !bpt->IsOneShot()) { | 1303 if (HasEventHandler()) { |
| 1197 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); | 1304 if (!cond->IsSingleShot()) { |
| 1198 event.set_breakpoint(bpt); | 1305 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); |
| 1199 InvokeEventHandler(&event); | 1306 event.set_breakpoint(cond); |
| 1307 InvokeEventHandler(&event); | |
| 1308 } | |
| 1200 } | 1309 } |
| 1201 } | 1310 } |
| 1202 | 1311 |
| 1203 | 1312 |
| 1204 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1313 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
| 1205 uword pc, | 1314 uword pc, |
| 1206 StackFrame* frame, | 1315 StackFrame* frame, |
| 1207 const Code& code, | 1316 const Code& code, |
| 1208 const Array& deopt_frame, | 1317 const Array& deopt_frame, |
| 1209 intptr_t deopt_frame_offset) { | 1318 intptr_t deopt_frame_offset) { |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1721 DeoptimizeWorld(); | 1830 DeoptimizeWorld(); |
| 1722 func ^= functions.At(0); | 1831 func ^= functions.At(0); |
| 1723 intptr_t breakpoint_pos = | 1832 intptr_t breakpoint_pos = |
| 1724 ResolveBreakpointPos(func, token_pos, last_token_pos); | 1833 ResolveBreakpointPos(func, token_pos, last_token_pos); |
| 1725 if (breakpoint_pos >= 0) { | 1834 if (breakpoint_pos >= 0) { |
| 1726 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); | 1835 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); |
| 1727 if (bpt != NULL) { | 1836 if (bpt != NULL) { |
| 1728 // A source breakpoint for this location already exists. | 1837 // A source breakpoint for this location already exists. |
| 1729 return bpt; | 1838 return bpt; |
| 1730 } | 1839 } |
| 1731 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos); | 1840 bpt = new SourceBreakpoint(script, token_pos, last_token_pos); |
| 1732 bpt->SetResolved(func, breakpoint_pos); | 1841 bpt->SetResolved(func, breakpoint_pos); |
| 1733 RegisterSourceBreakpoint(bpt); | 1842 RegisterSourceBreakpoint(bpt); |
| 1734 | 1843 |
| 1735 // Create code breakpoints for all compiled functions we found. | 1844 // Create code breakpoints for all compiled functions we found. |
| 1736 const intptr_t num_functions = functions.Length(); | 1845 const intptr_t num_functions = functions.Length(); |
| 1737 for (intptr_t i = 0; i < num_functions; i++) { | 1846 for (intptr_t i = 0; i < num_functions; i++) { |
| 1738 func ^= functions.At(i); | 1847 func ^= functions.At(i); |
| 1739 ASSERT(func.HasCode()); | 1848 ASSERT(func.HasCode()); |
| 1740 MakeCodeBreakpointAt(func, bpt); | 1849 MakeCodeBreakpointAt(func, bpt); |
| 1741 } | 1850 } |
| 1742 bpt->Enable(); | 1851 bpt->Enable(); |
| 1743 if (FLAG_verbose_debug) { | 1852 if (FLAG_verbose_debug) { |
| 1744 intptr_t line_number; | 1853 intptr_t line_number; |
| 1745 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); | 1854 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); |
| 1746 OS::Print("Resolved BP for " | 1855 OS::Print("Resolved BP for " |
| 1747 "function '%s' at line %" Pd "\n", | 1856 "function '%s' at line %" Pd "\n", |
| 1748 func.ToFullyQualifiedCString(), | 1857 func.ToFullyQualifiedCString(), |
| 1749 line_number); | 1858 line_number); |
| 1750 } | 1859 } |
| 1751 SignalBpResolved(bpt); | |
| 1752 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
| 1753 return bpt; | 1860 return bpt; |
| 1754 } | 1861 } |
| 1755 } | 1862 } |
| 1756 // There is no compiled function at this token position. | 1863 // There is no compiled function at this token position. |
| 1757 // Register an unresolved breakpoint. | 1864 // Register an unresolved breakpoint. |
| 1758 if (FLAG_verbose_debug && !func.IsNull()) { | 1865 if (FLAG_verbose_debug && !func.IsNull()) { |
| 1759 intptr_t line_number; | 1866 intptr_t line_number; |
| 1760 script.GetTokenLocation(token_pos, &line_number, NULL); | 1867 script.GetTokenLocation(token_pos, &line_number, NULL); |
| 1761 OS::Print("Registering pending breakpoint for " | 1868 OS::Print("Registering pending breakpoint for " |
| 1762 "uncompiled function '%s' at line %" Pd "\n", | 1869 "uncompiled function '%s' at line %" Pd "\n", |
| 1763 func.ToFullyQualifiedCString(), | 1870 func.ToFullyQualifiedCString(), |
| 1764 line_number); | 1871 line_number); |
| 1765 } | 1872 } |
| 1766 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); | 1873 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); |
| 1767 if (bpt == NULL) { | 1874 if (bpt == NULL) { |
| 1768 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos); | 1875 bpt = new SourceBreakpoint(script, token_pos, last_token_pos); |
| 1769 RegisterSourceBreakpoint(bpt); | 1876 RegisterSourceBreakpoint(bpt); |
| 1770 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
| 1771 } | 1877 } |
| 1772 bpt->Enable(); | 1878 bpt->Enable(); |
| 1773 return bpt; | 1879 return bpt; |
| 1774 } | 1880 } |
| 1775 | 1881 |
| 1776 | 1882 |
| 1777 // Synchronize the enabled/disabled state of all code breakpoints | 1883 // Synchronize the enabled/disabled state of all code breakpoints |
| 1778 // associated with the source breakpoint bpt. | 1884 // associated with the source breakpoint bpt. |
| 1779 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { | 1885 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
| 1780 CodeBreakpoint* cbpt = code_breakpoints_; | 1886 CodeBreakpoint* cbpt = code_breakpoints_; |
| 1781 while (cbpt != NULL) { | 1887 while (cbpt != NULL) { |
| 1782 if (bpt == cbpt->src_bpt()) { | 1888 if (bpt == cbpt->src_bpt()) { |
| 1783 if (bpt->IsEnabled()) { | 1889 if (bpt->IsEnabled()) { |
| 1784 cbpt->Enable(); | 1890 cbpt->Enable(); |
| 1785 } else { | 1891 } else { |
| 1786 cbpt->Disable(); | 1892 cbpt->Disable(); |
| 1787 } | 1893 } |
| 1788 } | 1894 } |
| 1789 cbpt = cbpt->next(); | 1895 cbpt = cbpt->next(); |
| 1790 } | 1896 } |
| 1791 } | 1897 } |
| 1792 | 1898 |
| 1793 | 1899 |
| 1794 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { | 1900 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { |
| 1795 LongJumpScope jump; | 1901 LongJumpScope jump; |
| 1796 if (setjmp(*jump.Set()) == 0) { | 1902 if (setjmp(*jump.Set()) == 0) { |
| 1797 SourceBreakpoint* bpt = SetBreakpointAtEntry(target_function); | 1903 SetBreakpointAtEntry(target_function, true); |
| 1798 if (bpt != NULL) { | |
| 1799 bpt->SetIsOneShot(); | |
| 1800 } | |
| 1801 return Error::null(); | 1904 return Error::null(); |
| 1802 } else { | 1905 } else { |
| 1803 return isolate_->object_store()->sticky_error(); | 1906 return isolate_->object_store()->sticky_error(); |
| 1804 } | 1907 } |
| 1805 } | 1908 } |
| 1806 | 1909 |
| 1807 | 1910 |
| 1808 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 1911 BreakpointCondition* Debugger::SetBreakpointAtEntry( |
| 1809 const Function& target_function) { | 1912 const Function& target_function, |
| 1913 bool single_shot) { | |
| 1810 ASSERT(!target_function.IsNull()); | 1914 ASSERT(!target_function.IsNull()); |
| 1811 if (!target_function.is_debuggable()) { | 1915 if (!target_function.is_debuggable()) { |
| 1812 return NULL; | 1916 return NULL; |
| 1813 } | 1917 } |
| 1814 const Script& script = Script::Handle(target_function.script()); | 1918 const Script& script = Script::Handle(target_function.script()); |
| 1815 return SetBreakpoint(script, | 1919 SourceBreakpoint* src_bpt = SetBreakpoint(script, |
| 1816 target_function.token_pos(), | 1920 target_function.token_pos(), |
| 1817 target_function.end_token_pos()); | 1921 target_function.end_token_pos()); |
| 1922 if (single_shot) { | |
| 1923 return src_bpt->AddSingleShot(this); | |
| 1924 } else { | |
| 1925 return src_bpt->AddRepeated(this); | |
| 1926 } | |
| 1818 } | 1927 } |
| 1819 | 1928 |
| 1820 | 1929 |
| 1821 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 1930 BreakpointCondition* Debugger::SetBreakpointAtActivation( |
| 1822 intptr_t line_number) { | 1931 const Instance& closure) { |
| 1932 if (!closure.IsClosure()) { | |
| 1933 return NULL; | |
| 1934 } | |
| 1935 const Function& func = Function::Handle(Closure::function(closure)); | |
| 1936 const Script& script = Script::Handle(func.script()); | |
| 1937 SourceBreakpoint* bpt = SetBreakpoint(script, | |
| 1938 func.token_pos(), | |
| 1939 func.end_token_pos()); | |
| 1940 return bpt->AddPerClosure(this, closure); | |
| 1941 } | |
| 1942 | |
| 1943 | |
| 1944 BreakpointCondition* Debugger::SetBreakpointAtLine(const String& script_url, | |
| 1945 intptr_t line_number) { | |
| 1946 SourceBreakpoint* bpt = SourceBreakpointAtLine(script_url, line_number); | |
| 1947 return bpt->AddRepeated(this); | |
| 1948 } | |
| 1949 | |
| 1950 | |
| 1951 SourceBreakpoint* Debugger::SourceBreakpointAtLine(const String& script_url, | |
| 1952 intptr_t line_number) { | |
| 1823 Library& lib = Library::Handle(isolate_); | 1953 Library& lib = Library::Handle(isolate_); |
| 1824 Script& script = Script::Handle(isolate_); | 1954 Script& script = Script::Handle(isolate_); |
| 1825 const GrowableObjectArray& libs = | 1955 const GrowableObjectArray& libs = |
| 1826 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 1956 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 1827 const GrowableObjectArray& scripts = | 1957 const GrowableObjectArray& scripts = |
| 1828 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); | 1958 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); |
| 1829 for (intptr_t i = 0; i < libs.Length(); i++) { | 1959 for (intptr_t i = 0; i < libs.Length(); i++) { |
| 1830 lib ^= libs.At(i); | 1960 lib ^= libs.At(i); |
| 1831 script = lib.LookupScript(script_url); | 1961 script = lib.LookupScript(script_url); |
| 1832 if (!script.IsNull()) { | 1962 if (!script.IsNull()) { |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2159 if (ServiceIsolate::IsRunning()) { | 2289 if (ServiceIsolate::IsRunning()) { |
| 2160 return true; | 2290 return true; |
| 2161 } | 2291 } |
| 2162 const Class& cls = Class::Handle(func.Owner()); | 2292 const Class& cls = Class::Handle(func.Owner()); |
| 2163 const Library& lib = Library::Handle(cls.library()); | 2293 const Library& lib = Library::Handle(cls.library()); |
| 2164 return lib.IsDebuggable(); | 2294 return lib.IsDebuggable(); |
| 2165 } | 2295 } |
| 2166 | 2296 |
| 2167 | 2297 |
| 2168 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, | 2298 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, |
| 2169 SourceBreakpoint* bpt) { | 2299 BreakpointCondition* bpt) { |
| 2170 resume_action_ = kContinue; | 2300 resume_action_ = kContinue; |
| 2171 stepping_fp_ = 0; | 2301 stepping_fp_ = 0; |
| 2172 isolate_->set_single_step(false); | 2302 isolate_->set_single_step(false); |
| 2173 ASSERT(!IsPaused()); | 2303 ASSERT(!IsPaused()); |
| 2174 ASSERT(obj_cache_ == NULL); | 2304 ASSERT(obj_cache_ == NULL); |
| 2175 if ((bpt != NULL) && bpt->IsOneShot()) { | 2305 if ((bpt != NULL) && bpt->IsSingleShot()) { |
| 2176 RemoveBreakpoint(bpt->id()); | 2306 RemoveBreakpoint(bpt->id()); |
| 2177 bpt = NULL; | 2307 bpt = NULL; |
| 2178 } | 2308 } |
| 2179 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2309 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); |
| 2180 event.set_top_frame(top_frame); | 2310 event.set_top_frame(top_frame); |
| 2181 event.set_breakpoint(bpt); | 2311 event.set_breakpoint(bpt); |
| 2182 Pause(&event); | 2312 Pause(&event); |
| 2183 } | 2313 } |
| 2184 | 2314 |
| 2185 | 2315 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2250 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { | 2380 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { |
| 2251 return; | 2381 return; |
| 2252 } | 2382 } |
| 2253 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2383 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 2254 ASSERT(stack_trace->Length() > 0); | 2384 ASSERT(stack_trace->Length() > 0); |
| 2255 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 2385 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
| 2256 ASSERT(top_frame != NULL); | 2386 ASSERT(top_frame != NULL); |
| 2257 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); | 2387 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); |
| 2258 ASSERT(bpt != NULL); | 2388 ASSERT(bpt != NULL); |
| 2259 | 2389 |
| 2390 SourceBreakpoint* src_bpt = bpt->src_bpt_; | |
| 2391 BreakpointCondition* condition_met = NULL; | |
| 2392 if (src_bpt != NULL) { | |
| 2393 BreakpointCondition* cond = src_bpt->conditions(); | |
| 2394 while (cond != NULL) { | |
| 2395 if (cond->IsPerClosure()) { | |
| 2396 Object& closure = Object::Handle(top_frame->GetClosure()); | |
| 2397 ASSERT(closure.IsInstance()); | |
| 2398 ASSERT(Instance::Cast(closure).IsClosure()); | |
| 2399 if (closure.raw() == cond->closure()) { | |
| 2400 condition_met = cond; | |
| 2401 break; | |
| 2402 } | |
| 2403 } else { | |
| 2404 condition_met = cond; | |
|
hausner
2015/05/21 18:23:55
This is subtly wrong. If you have a one-shot break
rmacnak
2015/05/21 21:59:35
As discussed, we should not send a series of break
| |
| 2405 break; | |
| 2406 } | |
| 2407 cond = cond->next(); | |
| 2408 } | |
| 2409 } | |
| 2410 if (condition_met == NULL) { | |
| 2411 return; | |
| 2412 } | |
| 2413 | |
| 2414 | |
| 2260 if (FLAG_verbose_debug) { | 2415 if (FLAG_verbose_debug) { |
| 2261 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " | 2416 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
| 2262 "(token %" Pd ") (address %#" Px ")\n", | 2417 "(token %" Pd ") (address %#" Px ")\n", |
| 2263 bpt->IsInternal() ? "internal" : "user", | 2418 bpt->IsInternal() ? "internal" : "user", |
| 2264 String::Handle(bpt->SourceUrl()).ToCString(), | 2419 String::Handle(bpt->SourceUrl()).ToCString(), |
| 2265 bpt->LineNumber(), | 2420 bpt->LineNumber(), |
| 2266 bpt->token_pos(), | 2421 bpt->token_pos(), |
| 2267 top_frame->pc()); | 2422 top_frame->pc()); |
| 2268 } | 2423 } |
| 2269 | 2424 |
| 2270 ASSERT(stack_trace_ == NULL); | 2425 ASSERT(stack_trace_ == NULL); |
| 2271 stack_trace_ = stack_trace; | 2426 stack_trace_ = stack_trace; |
| 2272 SignalPausedEvent(top_frame, bpt->src_bpt_); | 2427 SignalPausedEvent(top_frame, condition_met); |
| 2273 HandleSteppingRequest(stack_trace_); | 2428 HandleSteppingRequest(stack_trace_); |
| 2274 stack_trace_ = NULL; | 2429 stack_trace_ = NULL; |
| 2275 if (bpt->IsInternal()) { | 2430 if (bpt->IsInternal()) { |
| 2276 RemoveInternalBreakpoints(); | 2431 RemoveInternalBreakpoints(); |
| 2277 } | 2432 } |
| 2278 } | 2433 } |
| 2279 | 2434 |
| 2280 | 2435 |
| 2281 void Debugger::BreakHere(const String& msg) { | 2436 void Debugger::BreakHere(const String& msg) { |
| 2282 // We ignore this breakpoint when the VM is executing code invoked | 2437 // We ignore this breakpoint when the VM is executing code invoked |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2403 if (bp_pos < 0) { | 2558 if (bp_pos < 0) { |
| 2404 if (FLAG_verbose_debug) { | 2559 if (FLAG_verbose_debug) { |
| 2405 OS::Print("Failed resolving breakpoint for function '%s'\n", | 2560 OS::Print("Failed resolving breakpoint for function '%s'\n", |
| 2406 String::Handle(func.name()).ToCString()); | 2561 String::Handle(func.name()).ToCString()); |
| 2407 } | 2562 } |
| 2408 continue; | 2563 continue; |
| 2409 } | 2564 } |
| 2410 intptr_t requested_pos = bpt->token_pos(); | 2565 intptr_t requested_pos = bpt->token_pos(); |
| 2411 intptr_t requested_end_pos = bpt->end_token_pos(); | 2566 intptr_t requested_end_pos = bpt->end_token_pos(); |
| 2412 bpt->SetResolved(func, bp_pos); | 2567 bpt->SetResolved(func, bp_pos); |
| 2413 if (FLAG_verbose_debug) { | 2568 BreakpointCondition* cond = bpt->conditions(); |
| 2414 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " | 2569 while (cond != NULL) { |
| 2415 "function '%s' (requested range %" Pd "-%" Pd ")\n", | 2570 if (FLAG_verbose_debug) { |
| 2416 bpt->id(), | 2571 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " |
| 2417 bpt->token_pos(), | 2572 "function '%s' (requested range %" Pd "-%" Pd ")\n", |
| 2418 bpt->LineNumber(), | 2573 cond->id(), |
| 2419 func.ToFullyQualifiedCString(), | 2574 bpt->token_pos(), |
| 2420 requested_pos, | 2575 bpt->LineNumber(), |
| 2421 requested_end_pos); | 2576 func.ToFullyQualifiedCString(), |
| 2577 requested_pos, | |
| 2578 requested_end_pos); | |
| 2579 } | |
| 2580 SignalBpResolved(cond); | |
| 2581 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, cond); | |
| 2582 cond = cond->next(); | |
| 2422 } | 2583 } |
| 2423 SignalBpResolved(bpt); | |
| 2424 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); | |
| 2425 } | 2584 } |
| 2426 ASSERT(bpt->IsResolved()); | 2585 ASSERT(bpt->IsResolved()); |
| 2427 if (FLAG_verbose_debug) { | 2586 if (FLAG_verbose_debug) { |
| 2428 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", | 2587 BreakpointCondition* cond = bpt->conditions(); |
| 2429 bpt->id(), | 2588 while (cond != NULL) { |
| 2430 bpt->LineNumber(), | 2589 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", |
| 2431 func.IsClosureFunction() ? "closure" : "function", | 2590 cond->id(), |
| 2432 String::Handle(func.name()).ToCString()); | 2591 bpt->LineNumber(), |
| 2592 func.IsClosureFunction() ? "closure" : "function", | |
| 2593 String::Handle(func.name()).ToCString()); | |
| 2594 cond = cond->next(); | |
| 2595 } | |
| 2433 } | 2596 } |
| 2434 MakeCodeBreakpointAt(func, bpt); | 2597 MakeCodeBreakpointAt(func, bpt); |
| 2435 } | 2598 } |
| 2436 } | 2599 } |
| 2437 } | 2600 } |
| 2438 | 2601 |
| 2439 | 2602 |
| 2440 void Debugger::NotifyDoneLoading() { | 2603 void Debugger::NotifyDoneLoading() { |
| 2441 if (latent_breakpoints_ == NULL) { | 2604 if (latent_breakpoints_ == NULL) { |
| 2442 // Common, fast path. | 2605 // Common, fast path. |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 2469 // Now find the token range at the requested line and make a | 2632 // Now find the token range at the requested line and make a |
| 2470 // new unresolved source breakpoint. | 2633 // new unresolved source breakpoint. |
| 2471 intptr_t line_number = matched_bpt->LineNumber(); | 2634 intptr_t line_number = matched_bpt->LineNumber(); |
| 2472 ASSERT(line_number >= 0); | 2635 ASSERT(line_number >= 0); |
| 2473 intptr_t first_token_pos, last_token_pos; | 2636 intptr_t first_token_pos, last_token_pos; |
| 2474 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); | 2637 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); |
| 2475 if ((first_token_pos < 0) || | 2638 if ((first_token_pos < 0) || |
| 2476 (last_token_pos < 0)) { | 2639 (last_token_pos < 0)) { |
| 2477 // Script does not contain the given line number or there are no | 2640 // Script does not contain the given line number or there are no |
| 2478 // tokens on the line. Drop the breakpoint silently. | 2641 // tokens on the line. Drop the breakpoint silently. |
| 2479 if (FLAG_verbose_debug) { | 2642 BreakpointCondition* cond = matched_bpt->conditions(); |
| 2480 OS::Print("No code found at line %" Pd ": " | 2643 while (cond != NULL) { |
| 2481 "dropping latent breakpoint %" Pd " in '%s'\n", | 2644 if (FLAG_verbose_debug) { |
| 2482 line_number, | 2645 OS::Print("No code found at line %" Pd ": " |
| 2483 matched_bpt->id(), | 2646 "dropping latent breakpoint %" Pd " in '%s'\n", |
| 2484 url.ToCString()); | 2647 line_number, |
| 2648 cond->id(), | |
| 2649 url.ToCString()); | |
| 2650 } | |
| 2651 BreakpointCondition* prev = cond; | |
| 2652 cond = cond->next(); | |
| 2653 delete prev; | |
| 2485 } | 2654 } |
| 2486 delete matched_bpt; | 2655 delete matched_bpt; |
| 2487 } else { | 2656 } else { |
| 2488 // We don't expect to already have a breakpoint for this location. | 2657 // We don't expect to already have a breakpoint for this location. |
| 2489 // If there is one, assert in debug build but silently drop | 2658 // If there is one, assert in debug build but silently drop |
| 2490 // the latent breakpoint in release build. | 2659 // the latent breakpoint in release build. |
| 2491 SourceBreakpoint* existing_bpt = | 2660 SourceBreakpoint* existing_bpt = |
| 2492 GetSourceBreakpoint(script, first_token_pos); | 2661 GetSourceBreakpoint(script, first_token_pos); |
| 2493 ASSERT(existing_bpt == NULL); | 2662 ASSERT(existing_bpt == NULL); |
| 2494 if (existing_bpt == NULL) { | 2663 if (existing_bpt == NULL) { |
| 2495 // Create and register a new source breakpoint for the | 2664 // Create and register a new source breakpoint for the |
| 2496 // latent breakpoint. | 2665 // latent breakpoint. |
| 2497 SourceBreakpoint* unresolved_bpt = | 2666 SourceBreakpoint* unresolved_bpt = |
| 2498 new SourceBreakpoint(matched_bpt->id(), | 2667 new SourceBreakpoint(script, |
| 2499 script, | |
| 2500 first_token_pos, | 2668 first_token_pos, |
| 2501 last_token_pos); | 2669 last_token_pos); |
| 2502 RegisterSourceBreakpoint(unresolved_bpt); | 2670 RegisterSourceBreakpoint(unresolved_bpt); |
| 2503 unresolved_bpt->Enable(); | 2671 unresolved_bpt->Enable(); |
| 2504 if (FLAG_verbose_debug) { | 2672 |
| 2505 OS::Print("Converted latent breakpoint " | 2673 // Move conditions over. |
| 2506 "%" Pd " in '%s' at line %" Pd "\n", | 2674 BreakpointCondition* cond = existing_bpt->conditions(); |
| 2507 matched_bpt->id(), | 2675 unresolved_bpt->set_conditions(cond); |
| 2508 url.ToCString(), | 2676 existing_bpt->set_conditions(NULL); |
| 2509 line_number); | 2677 while (cond != NULL) { |
| 2678 cond->set_src_bpt(unresolved_bpt); | |
| 2679 if (FLAG_verbose_debug) { | |
| 2680 OS::Print("Converted latent breakpoint " | |
| 2681 "%" Pd " in '%s' at line %" Pd "\n", | |
| 2682 cond->id(), | |
| 2683 url.ToCString(), | |
| 2684 line_number); | |
| 2685 } | |
| 2686 cond = cond->next(); | |
| 2510 } | 2687 } |
| 2511 } | 2688 } |
| 2512 delete matched_bpt; | 2689 delete matched_bpt; |
| 2513 // Break out of the iteration over loaded libraries. If the | 2690 // Break out of the iteration over loaded libraries. If the |
| 2514 // same url has been loaded into more than one library, we | 2691 // same url has been loaded into more than one library, we |
| 2515 // only set a breakpoint in the first one. | 2692 // only set a breakpoint in the first one. |
| 2516 // TODO(hausner): There is one possible pitfall here. | 2693 // TODO(hausner): There is one possible pitfall here. |
| 2517 // If the user sets a latent breakpoint using a partial url that | 2694 // If the user sets a latent breakpoint using a partial url that |
| 2518 // ends up matching more than one script, the breakpoint might | 2695 // ends up matching more than one script, the breakpoint might |
| 2519 // get set in the wrong script. | 2696 // get set in the wrong script. |
| 2520 // It would be better if we could warn the user if multiple | 2697 // It would be better if we could warn the user if multiple |
| 2521 // scripts are matching. | 2698 // scripts are matching. |
| 2522 break; | 2699 break; |
| 2523 } | 2700 } |
| 2524 } | 2701 } |
| 2525 } | 2702 } |
| 2526 if (!found_match) { | 2703 if (!found_match) { |
| 2527 // No matching url found in any of the libraries. | 2704 // No matching url found in any of the libraries. |
| 2528 if (FLAG_verbose_debug) { | 2705 if (FLAG_verbose_debug) { |
| 2529 OS::Print("No match found for latent breakpoint id " | 2706 BreakpointCondition* cond = bpt->conditions(); |
| 2530 "%" Pd " with url '%s'\n", | 2707 while (cond != NULL) { |
| 2531 bpt->id(), | 2708 OS::Print("No match found for latent breakpoint id " |
| 2532 url.ToCString()); | 2709 "%" Pd " with url '%s'\n", |
| 2710 cond->id(), | |
| 2711 url.ToCString()); | |
| 2712 cond = cond->next(); | |
| 2713 } | |
| 2533 } | 2714 } |
| 2534 bpt = bpt->next(); | 2715 bpt = bpt->next(); |
| 2535 } | 2716 } |
| 2536 } | 2717 } |
| 2537 } | 2718 } |
| 2538 | 2719 |
| 2539 | 2720 |
| 2540 // TODO(hausner): Could potentially make this faster by checking | 2721 // TODO(hausner): Could potentially make this faster by checking |
| 2541 // whether the call target at pc is a debugger stub. | 2722 // whether the call target at pc is a debugger stub. |
| 2542 bool Debugger::HasActiveBreakpoint(uword pc) { | 2723 bool Debugger::HasActiveBreakpoint(uword pc) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 2566 return 0L; | 2747 return 0L; |
| 2567 } | 2748 } |
| 2568 | 2749 |
| 2569 | 2750 |
| 2570 // Remove and delete the source breakpoint bpt and its associated | 2751 // Remove and delete the source breakpoint bpt and its associated |
| 2571 // code breakpoints. | 2752 // code breakpoints. |
| 2572 void Debugger::RemoveBreakpoint(intptr_t bp_id) { | 2753 void Debugger::RemoveBreakpoint(intptr_t bp_id) { |
| 2573 SourceBreakpoint* prev_bpt = NULL; | 2754 SourceBreakpoint* prev_bpt = NULL; |
| 2574 SourceBreakpoint* curr_bpt = src_breakpoints_; | 2755 SourceBreakpoint* curr_bpt = src_breakpoints_; |
| 2575 while (curr_bpt != NULL) { | 2756 while (curr_bpt != NULL) { |
| 2576 if (curr_bpt->id() == bp_id) { | 2757 BreakpointCondition* prev_cond = NULL; |
| 2758 BreakpointCondition* curr_cond = curr_bpt->conditions(); | |
| 2759 while (curr_cond != NULL) { | |
| 2760 if (curr_cond->id() == bp_id) { | |
| 2761 if (prev_cond == NULL) { | |
| 2762 curr_bpt->set_conditions(curr_cond->next()); | |
| 2763 } else { | |
| 2764 prev_cond->set_next(curr_cond->next()); | |
| 2765 } | |
| 2766 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_cond); | |
| 2767 | |
| 2768 // Remove references from the current debugger pause event. | |
| 2769 if (pause_event_ != NULL && | |
| 2770 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
| 2771 pause_event_->breakpoint() == curr_cond) { | |
| 2772 pause_event_->set_breakpoint(NULL); | |
| 2773 } | |
| 2774 return; | |
| 2775 } | |
| 2776 | |
| 2777 prev_cond = curr_cond; | |
| 2778 curr_cond = curr_cond->next(); | |
| 2779 } | |
| 2780 | |
| 2781 if (curr_bpt->conditions() == NULL) { | |
| 2577 if (prev_bpt == NULL) { | 2782 if (prev_bpt == NULL) { |
| 2578 src_breakpoints_ = src_breakpoints_->next(); | 2783 src_breakpoints_ = src_breakpoints_->next(); |
| 2579 } else { | 2784 } else { |
| 2580 prev_bpt->set_next(curr_bpt->next()); | 2785 prev_bpt->set_next(curr_bpt->next()); |
| 2581 } | 2786 } |
| 2582 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); | |
| 2583 | 2787 |
| 2584 // Remove references from code breakpoints to this source breakpoint, | 2788 // Remove references from code breakpoints to this source breakpoint, |
| 2585 // and disable the code breakpoints. | 2789 // and disable the code breakpoints. |
| 2586 UnlinkCodeBreakpoints(curr_bpt); | 2790 UnlinkCodeBreakpoints(curr_bpt); |
| 2587 delete curr_bpt; | 2791 delete curr_bpt; |
| 2792 } | |
| 2588 | 2793 |
| 2589 // Remove references from the current debugger pause event. | |
| 2590 if (pause_event_ != NULL && | |
| 2591 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
| 2592 pause_event_->breakpoint() == curr_bpt) { | |
| 2593 pause_event_->set_breakpoint(NULL); | |
| 2594 } | |
| 2595 return; | |
| 2596 } | |
| 2597 prev_bpt = curr_bpt; | 2794 prev_bpt = curr_bpt; |
| 2598 curr_bpt = curr_bpt->next(); | 2795 curr_bpt = curr_bpt->next(); |
| 2599 } | 2796 } |
| 2600 // bpt is not a registered breakpoint, nothing to do. | 2797 // bpt is not a registered breakpoint, nothing to do. |
| 2601 } | 2798 } |
| 2602 | 2799 |
| 2603 | 2800 |
| 2604 // Turn code breakpoints associated with the given source breakpoint into | 2801 // Turn code breakpoints associated with the given source breakpoint into |
| 2605 // internal breakpoints. They will later be deleted when control | 2802 // internal breakpoints. They will later be deleted when control |
| 2606 // returns from the user-defined breakpoint callback. Also, disable the | 2803 // returns from the user-defined breakpoint callback. Also, disable the |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2649 while (bpt != NULL) { | 2846 while (bpt != NULL) { |
| 2650 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { | 2847 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { |
| 2651 return bpt; | 2848 return bpt; |
| 2652 } | 2849 } |
| 2653 bpt = bpt->next(); | 2850 bpt = bpt->next(); |
| 2654 } | 2851 } |
| 2655 return NULL; | 2852 return NULL; |
| 2656 } | 2853 } |
| 2657 | 2854 |
| 2658 | 2855 |
| 2659 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { | 2856 BreakpointCondition* Debugger::GetBreakpointById(intptr_t id) { |
| 2660 SourceBreakpoint* bpt = src_breakpoints_; | 2857 SourceBreakpoint* bpt = src_breakpoints_; |
| 2661 while (bpt != NULL) { | 2858 while (bpt != NULL) { |
| 2662 if (bpt->id() == id) { | 2859 BreakpointCondition* cond = bpt->conditions(); |
| 2663 return bpt; | 2860 while (cond != NULL) { |
| 2861 if (cond->id() == id) { | |
| 2862 return cond; | |
| 2863 } | |
| 2864 cond = cond->next(); | |
| 2664 } | 2865 } |
| 2665 bpt = bpt->next(); | 2866 bpt = bpt->next(); |
| 2666 } | 2867 } |
| 2667 return NULL; | 2868 return NULL; |
| 2668 } | 2869 } |
| 2669 | 2870 |
| 2670 | 2871 |
| 2671 SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url, | 2872 SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url, |
| 2672 intptr_t line) { | 2873 intptr_t line) { |
| 2673 SourceBreakpoint* bpt = latent_breakpoints_; | 2874 SourceBreakpoint* bpt = latent_breakpoints_; |
| 2674 String& bpt_url = String::Handle(isolate_); | 2875 String& bpt_url = String::Handle(isolate_); |
| 2675 while (bpt != NULL) { | 2876 while (bpt != NULL) { |
| 2676 bpt_url = bpt->url(); | 2877 bpt_url = bpt->url(); |
| 2677 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { | 2878 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { |
| 2678 return bpt; | 2879 return bpt; |
| 2679 } | 2880 } |
| 2680 bpt = bpt->next(); | 2881 bpt = bpt->next(); |
| 2681 } | 2882 } |
| 2682 // No breakpint for this url and line requested. Allocate new one. | 2883 // No breakpint for this url and line requested. Allocate new one. |
| 2683 bpt = new SourceBreakpoint(nextId(), url, line); | 2884 bpt = new SourceBreakpoint(url, line); |
| 2684 bpt->set_next(latent_breakpoints_); | 2885 bpt->set_next(latent_breakpoints_); |
| 2685 latent_breakpoints_ = bpt; | 2886 latent_breakpoints_ = bpt; |
| 2686 return bpt; | 2887 return bpt; |
| 2687 } | 2888 } |
| 2688 | 2889 |
| 2689 | 2890 |
| 2690 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { | 2891 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { |
| 2691 ASSERT(bpt->next() == NULL); | 2892 ASSERT(bpt->next() == NULL); |
| 2692 bpt->set_next(src_breakpoints_); | 2893 bpt->set_next(src_breakpoints_); |
| 2693 src_breakpoints_ = bpt; | 2894 src_breakpoints_ = bpt; |
| 2694 } | 2895 } |
| 2695 | 2896 |
| 2696 | 2897 |
| 2697 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2898 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 2698 ASSERT(bpt->next() == NULL); | 2899 ASSERT(bpt->next() == NULL); |
| 2699 bpt->set_next(code_breakpoints_); | 2900 bpt->set_next(code_breakpoints_); |
| 2700 code_breakpoints_ = bpt; | 2901 code_breakpoints_ = bpt; |
| 2701 } | 2902 } |
| 2702 | 2903 |
| 2703 } // namespace dart | 2904 } // namespace dart |
| OLD | NEW |