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 |