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_patcher.h" | 8 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/flags.h" | 10 #include "vm/flags.h" |
| 11 #include "vm/globals.h" | 11 #include "vm/globals.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/os.h" | 14 #include "vm/os.h" |
| 15 #include "vm/stack_frame.h" | 15 #include "vm/stack_frame.h" |
| 16 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
| 17 #include "vm/visitor.h" | 17 #include "vm/visitor.h" |
| 18 | 18 |
| 19 | 19 |
| 20 namespace dart { | 20 namespace dart { |
| 21 | 21 |
| 22 static const bool verbose = false; | 22 static const bool verbose = false; |
| 23 | 23 |
| 24 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) | 24 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) |
| 25 : function_(func.raw()), | 25 : function_(func.raw()), |
| 26 pc_desc_index_(pc_desc_index), | 26 pc_desc_index_(pc_desc_index), |
| 27 pc_(0), | 27 pc_(0), |
| 28 saved_bytes_(0), | |
| 28 line_number_(-1), | 29 line_number_(-1), |
| 29 next_(NULL) { | 30 next_(NULL) { |
| 30 Code& code = Code::Handle(func.code()); | 31 Code& code = Code::Handle(func.code()); |
| 31 ASSERT(!code.IsNull()); // Function must be compiled. | 32 ASSERT(!code.IsNull()); // Function must be compiled. |
| 32 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 33 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 33 ASSERT(pc_desc_index < desc.Length()); | 34 ASSERT(pc_desc_index < desc.Length()); |
| 34 this->token_index_ = desc.TokenIndex(pc_desc_index); | 35 this->token_index_ = desc.TokenIndex(pc_desc_index); |
| 35 ASSERT(this->token_index_ > 0); | 36 ASSERT(this->token_index_ > 0); |
| 36 this->pc_ = desc.PC(pc_desc_index); | 37 this->pc_ = desc.PC(pc_desc_index); |
| 37 ASSERT(this->pc_ != 0); | 38 ASSERT(this->pc_ != 0); |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 } | 224 } |
| 224 | 225 |
| 225 | 226 |
| 226 Debugger::Debugger() | 227 Debugger::Debugger() |
| 227 : initialized_(false), | 228 : initialized_(false), |
| 228 bp_handler_(NULL), | 229 bp_handler_(NULL), |
| 229 breakpoints_(NULL) { | 230 breakpoints_(NULL) { |
| 230 } | 231 } |
| 231 | 232 |
| 232 | 233 |
| 234 Debugger::~Debugger() { | |
| 235 ASSERT(breakpoints_ == NULL); | |
| 236 } | |
| 237 | |
| 238 | |
| 239 void Debugger::Shutdown() { | |
| 240 while (breakpoints_ != NULL) { | |
| 241 Breakpoint* bpt = breakpoints_; | |
| 242 breakpoints_ = breakpoints_->next(); | |
| 243 UnsetBreakpoint(bpt); | |
| 244 delete bpt; | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 | |
| 233 bool Debugger::IsActive() { | 249 bool Debugger::IsActive() { |
| 234 // TODO(hausner): The code generator uses this function to prevent | 250 // TODO(hausner): The code generator uses this function to prevent |
| 235 // generation of optimized code when Dart code is being debugged. | 251 // generation of optimized code when Dart code is being debugged. |
| 236 // This is probably not conservative enough (we could set the first | 252 // This is probably not conservative enough (we could set the first |
| 237 // breakpoint after optimized code has already been produced). | 253 // breakpoint after optimized code has already been produced). |
| 238 // Long-term, we need to be able to de-optimize code. | 254 // Long-term, we need to be able to de-optimize code. |
| 239 return breakpoints_ != NULL; | 255 return breakpoints_ != NULL; |
| 240 } | 256 } |
| 241 | 257 |
| 242 | 258 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 Code& code = Code::Handle(target_function.code()); | 306 Code& code = Code::Handle(target_function.code()); |
| 291 ASSERT(!code.IsNull()); | 307 ASSERT(!code.IsNull()); |
| 292 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 308 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 293 for (int i = 0; i < desc.Length(); i++) { | 309 for (int i = 0; i < desc.Length(); i++) { |
| 294 if (desc.TokenIndex(i) < token_index) { | 310 if (desc.TokenIndex(i) < token_index) { |
| 295 continue; | 311 continue; |
| 296 } | 312 } |
| 297 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 313 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 298 Breakpoint* bpt = NULL; | 314 Breakpoint* bpt = NULL; |
| 299 if (kind == PcDescriptors::kIcCall) { | 315 if (kind == PcDescriptors::kIcCall) { |
| 316 bpt = GetBreakpoint(desc.PC(i)); | |
| 317 if (bpt != NULL) { | |
| 318 // There is an existing breakpoint at this token position. | |
| 319 break; | |
| 320 } | |
| 321 bpt = new Breakpoint(target_function, i); | |
| 322 RegisterBreakpoint(bpt); | |
|
siva
2012/01/20 21:26:29
Should the register happen after the code patching
hausner
2012/01/20 22:20:32
Done.
| |
| 323 String& func_name = String::Handle(); | |
| 324 int num_args, num_named_args; | |
| 325 CodePatcher::GetInstanceCallAt(desc.PC(i), | |
| 326 &func_name, &num_args, &num_named_args, &bpt->saved_bytes_); | |
| 300 CodePatcher::PatchInstanceCallAt( | 327 CodePatcher::PatchInstanceCallAt( |
| 301 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); | 328 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); |
| 302 bpt = new Breakpoint(target_function, i); | |
| 303 } else if (kind == PcDescriptors::kOther) { | 329 } else if (kind == PcDescriptors::kOther) { |
| 304 if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) { | 330 if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) { |
| 331 bpt = GetBreakpoint(desc.PC(i)); | |
| 332 if (bpt != NULL) { | |
| 333 // There is an existing breakpoint at this token position. | |
| 334 break; | |
| 335 } | |
| 336 bpt = new Breakpoint(target_function, i); | |
| 337 RegisterBreakpoint(bpt); | |
| 338 Function& func = Function::Handle(); | |
| 339 CodePatcher::GetStaticCallAt(desc.PC(i), &func, &bpt->saved_bytes_); | |
| 305 CodePatcher::PatchStaticCallAt( | 340 CodePatcher::PatchStaticCallAt( |
| 306 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); | 341 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); |
| 307 bpt = new Breakpoint(target_function, i); | |
| 308 } | 342 } |
| 309 } | 343 } |
| 310 if (bpt != NULL) { | 344 if (bpt != NULL) { |
| 311 if (verbose) { | 345 if (verbose) { |
| 312 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", | 346 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", |
| 313 String::Handle(bpt->SourceUrl()).ToCString(), | 347 String::Handle(bpt->SourceUrl()).ToCString(), |
| 314 bpt->LineNumber(), | 348 bpt->LineNumber(), |
| 315 bpt->pc()); | 349 bpt->pc()); |
|
siva
2012/01/20 21:26:29
Both newly set breakpoints and existing breakpoint
hausner
2012/01/20 22:20:32
Added a todo to determine later. The idea sounds r
| |
| 316 } | 350 } |
| 317 AddBreakpoint(bpt); | |
| 318 return bpt; | 351 return bpt; |
| 319 } | 352 } |
| 320 } | 353 } |
| 321 return NULL; | 354 return NULL; |
| 322 } | 355 } |
| 323 | 356 |
| 324 | 357 |
| 358 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { | |
| 359 const Function& func = Function::Handle(bpt->function()); | |
| 360 const Code& code = Code::Handle(func.code()); | |
| 361 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | |
| 362 intptr_t desc_index = bpt->pc_desc_index(); | |
| 363 ASSERT(desc_index < desc.Length()); | |
| 364 ASSERT(bpt->pc() == desc.PC(desc_index)); | |
| 365 PcDescriptors::Kind kind = desc.DescriptorKind(desc_index); | |
| 366 if (kind == PcDescriptors::kIcCall) { | |
| 367 CodePatcher::PatchInstanceCallAt(desc.PC(desc_index), bpt->saved_bytes_); | |
| 368 } else { | |
| 369 CodePatcher::PatchStaticCallAt(desc.PC(desc_index), bpt->saved_bytes_); | |
| 370 } | |
| 371 } | |
| 372 | |
| 373 | |
| 325 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function) { | 374 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function) { |
| 326 ASSERT(!target_function.IsNull()); | 375 ASSERT(!target_function.IsNull()); |
| 327 return SetBreakpoint(target_function, target_function.token_index()); | 376 return SetBreakpoint(target_function, target_function.token_index()); |
| 328 } | 377 } |
| 329 | 378 |
| 330 | 379 |
| 331 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 380 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 332 intptr_t line_number) { | 381 intptr_t line_number) { |
| 333 Library& lib = Library::Handle(); | 382 Library& lib = Library::Handle(); |
| 334 Script& script = Script::Handle(); | 383 Script& script = Script::Handle(); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 438 while (bpt != NULL) { | 487 while (bpt != NULL) { |
| 439 if (bpt->pc() == breakpoint_address) { | 488 if (bpt->pc() == breakpoint_address) { |
| 440 return bpt; | 489 return bpt; |
| 441 } | 490 } |
| 442 bpt = bpt->next(); | 491 bpt = bpt->next(); |
| 443 } | 492 } |
| 444 return NULL; | 493 return NULL; |
| 445 } | 494 } |
| 446 | 495 |
| 447 | 496 |
| 448 void Debugger::AddBreakpoint(Breakpoint* bpt) { | 497 bool Debugger::IsRegisteredBreakpoint(Breakpoint* bpt) { |
|
siva
2012/01/20 21:26:29
Where is this function used?
hausner
2012/01/20 22:20:32
Not used at the moment. At first I wanted to make
| |
| 498 Breakpoint* known_bpt = this->breakpoints_; | |
| 499 while (known_bpt != NULL) { | |
| 500 if (bpt == known_bpt) { | |
| 501 return true; | |
| 502 } | |
| 503 known_bpt = known_bpt->next(); | |
| 504 } | |
| 505 return false; | |
| 506 } | |
| 507 | |
| 508 | |
| 509 void Debugger::RemoveBreakpoint(Breakpoint* bpt) { | |
| 510 ASSERT(breakpoints_ != NULL); | |
| 511 if (breakpoints_ == NULL) { | |
| 512 return; | |
| 513 } | |
|
siva
2012/01/20 21:26:29
There is an assertion that breakpoints_ is not NUL
hausner
2012/01/20 22:20:32
Similar to the above comment: Most likely it is an
| |
| 514 if (bpt == breakpoints_) { | |
| 515 breakpoints_ = breakpoints_->next(); | |
| 516 UnsetBreakpoint(bpt); | |
| 517 delete bpt; | |
| 518 return; | |
| 519 } | |
| 520 // There is at least one breakpoint in the list, and the one we're | |
| 521 // looking for is not at the head of the list. | |
| 522 Breakpoint* prev_bpt = this->breakpoints_; | |
| 523 Breakpoint* curr_bpt = prev_bpt->next(); | |
| 524 while (curr_bpt != NULL) { | |
| 525 if (bpt == curr_bpt) { | |
| 526 // Unlink curr_bpt from list and delete the breakpoint. | |
|
siva
2012/01/20 21:26:29
Can we roll the two delete points you have into th
hausner
2012/01/20 22:20:32
Ok, done. I thought the code would be easier to un
| |
| 527 prev_bpt->set_next(curr_bpt->next()); | |
| 528 UnsetBreakpoint(bpt); | |
| 529 delete bpt; | |
| 530 return; | |
| 531 } | |
| 532 prev_bpt = curr_bpt; | |
| 533 curr_bpt = curr_bpt->next(); | |
| 534 } | |
| 535 // bpt is not a registered breakpoint, nothing to do. | |
| 536 } | |
| 537 | |
| 538 | |
| 539 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, | |
| 540 intptr_t token_index) { | |
| 541 Breakpoint* bpt = this->breakpoints_; | |
| 542 while (bpt != NULL) { | |
| 543 if ((bpt->function() == func.raw()) && | |
| 544 (bpt->token_index() == token_index)) { | |
| 545 return bpt; | |
| 546 } | |
| 547 bpt = bpt->next(); | |
| 548 } | |
| 549 return NULL; | |
| 550 } | |
| 551 | |
| 552 | |
| 553 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { | |
| 449 ASSERT(bpt->next() == NULL); | 554 ASSERT(bpt->next() == NULL); |
| 450 bpt->set_next(this->breakpoints_); | 555 bpt->set_next(this->breakpoints_); |
| 451 this->breakpoints_ = bpt; | 556 this->breakpoints_ = bpt; |
| 452 } | 557 } |
| 453 | 558 |
| 454 | 559 |
| 455 } // namespace dart | 560 } // namespace dart |
| OLD | NEW |