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 24 matching lines...) Expand all Loading... |
267 if (!cls.IsNull()) { | 283 if (!cls.IsNull()) { |
268 function = cls.LookupStaticFunction(function_name); | 284 function = cls.LookupStaticFunction(function_name); |
269 if (function.IsNull()) { | 285 if (function.IsNull()) { |
270 function = cls.LookupDynamicFunction(function_name); | 286 function = cls.LookupDynamicFunction(function_name); |
271 } | 287 } |
272 } | 288 } |
273 return function.raw(); | 289 return function.raw(); |
274 } | 290 } |
275 | 291 |
276 | 292 |
277 // TODO(hausner): Need to check whether a breakpoint for the | 293 // TODO(hausner): Distinguish between newly created breakpoints and |
278 // location already exists and either return the existing breakpoint | 294 // returning a breakpoint that already exists? |
279 // or return an error. | |
280 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, | 295 Breakpoint* Debugger::SetBreakpoint(const Function& target_function, |
281 intptr_t token_index) { | 296 intptr_t token_index) { |
282 if ((token_index < target_function.token_index()) || | 297 if ((token_index < target_function.token_index()) || |
283 (target_function.end_token_index() <= token_index)) { | 298 (target_function.end_token_index() <= token_index)) { |
284 // The given token position is not within the target function. | 299 // The given token position is not within the target function. |
285 return NULL; | 300 return NULL; |
286 } | 301 } |
287 if (!target_function.HasCode()) { | 302 if (!target_function.HasCode()) { |
288 Compiler::CompileFunction(target_function); | 303 Compiler::CompileFunction(target_function); |
289 } | 304 } |
290 Code& code = Code::Handle(target_function.code()); | 305 Code& code = Code::Handle(target_function.code()); |
291 ASSERT(!code.IsNull()); | 306 ASSERT(!code.IsNull()); |
292 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 307 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
293 for (int i = 0; i < desc.Length(); i++) { | 308 for (int i = 0; i < desc.Length(); i++) { |
294 if (desc.TokenIndex(i) < token_index) { | 309 if (desc.TokenIndex(i) < token_index) { |
295 continue; | 310 continue; |
296 } | 311 } |
297 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 312 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
298 Breakpoint* bpt = NULL; | 313 Breakpoint* bpt = NULL; |
299 if (kind == PcDescriptors::kIcCall) { | 314 if (kind == PcDescriptors::kIcCall) { |
| 315 bpt = GetBreakpoint(desc.PC(i)); |
| 316 if (bpt != NULL) { |
| 317 // There is an existing breakpoint at this token position. |
| 318 break; |
| 319 } |
| 320 bpt = new Breakpoint(target_function, i); |
| 321 String& func_name = String::Handle(); |
| 322 int num_args, num_named_args; |
| 323 CodePatcher::GetInstanceCallAt(desc.PC(i), |
| 324 &func_name, &num_args, &num_named_args, &bpt->saved_bytes_); |
300 CodePatcher::PatchInstanceCallAt( | 325 CodePatcher::PatchInstanceCallAt( |
301 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); | 326 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); |
302 bpt = new Breakpoint(target_function, i); | 327 RegisterBreakpoint(bpt); |
303 } else if (kind == PcDescriptors::kOther) { | 328 } else if (kind == PcDescriptors::kOther) { |
304 if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) { | 329 if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) { |
| 330 bpt = GetBreakpoint(desc.PC(i)); |
| 331 if (bpt != NULL) { |
| 332 // There is an existing breakpoint at this token position. |
| 333 break; |
| 334 } |
| 335 bpt = new Breakpoint(target_function, i); |
| 336 Function& func = Function::Handle(); |
| 337 CodePatcher::GetStaticCallAt(desc.PC(i), &func, &bpt->saved_bytes_); |
305 CodePatcher::PatchStaticCallAt( | 338 CodePatcher::PatchStaticCallAt( |
306 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); | 339 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); |
307 bpt = new Breakpoint(target_function, i); | 340 RegisterBreakpoint(bpt); |
308 } | 341 } |
309 } | 342 } |
310 if (bpt != NULL) { | 343 if (bpt != NULL) { |
311 if (verbose) { | 344 if (verbose) { |
312 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", | 345 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", |
313 String::Handle(bpt->SourceUrl()).ToCString(), | 346 String::Handle(bpt->SourceUrl()).ToCString(), |
314 bpt->LineNumber(), | 347 bpt->LineNumber(), |
315 bpt->pc()); | 348 bpt->pc()); |
316 } | 349 } |
317 AddBreakpoint(bpt); | |
318 return bpt; | 350 return bpt; |
319 } | 351 } |
320 } | 352 } |
321 return NULL; | 353 return NULL; |
322 } | 354 } |
323 | 355 |
324 | 356 |
| 357 void Debugger::UnsetBreakpoint(Breakpoint* bpt) { |
| 358 const Function& func = Function::Handle(bpt->function()); |
| 359 const Code& code = Code::Handle(func.code()); |
| 360 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 361 intptr_t desc_index = bpt->pc_desc_index(); |
| 362 ASSERT(desc_index < desc.Length()); |
| 363 ASSERT(bpt->pc() == desc.PC(desc_index)); |
| 364 PcDescriptors::Kind kind = desc.DescriptorKind(desc_index); |
| 365 if (kind == PcDescriptors::kIcCall) { |
| 366 CodePatcher::PatchInstanceCallAt(desc.PC(desc_index), bpt->saved_bytes_); |
| 367 } else { |
| 368 CodePatcher::PatchStaticCallAt(desc.PC(desc_index), bpt->saved_bytes_); |
| 369 } |
| 370 } |
| 371 |
| 372 |
325 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function) { | 373 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function) { |
326 ASSERT(!target_function.IsNull()); | 374 ASSERT(!target_function.IsNull()); |
327 return SetBreakpoint(target_function, target_function.token_index()); | 375 return SetBreakpoint(target_function, target_function.token_index()); |
328 } | 376 } |
329 | 377 |
330 | 378 |
331 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 379 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
332 intptr_t line_number) { | 380 intptr_t line_number) { |
333 Library& lib = Library::Handle(); | 381 Library& lib = Library::Handle(); |
334 Script& script = Script::Handle(); | 382 Script& script = Script::Handle(); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 while (bpt != NULL) { | 486 while (bpt != NULL) { |
439 if (bpt->pc() == breakpoint_address) { | 487 if (bpt->pc() == breakpoint_address) { |
440 return bpt; | 488 return bpt; |
441 } | 489 } |
442 bpt = bpt->next(); | 490 bpt = bpt->next(); |
443 } | 491 } |
444 return NULL; | 492 return NULL; |
445 } | 493 } |
446 | 494 |
447 | 495 |
448 void Debugger::AddBreakpoint(Breakpoint* bpt) { | 496 void Debugger::RemoveBreakpoint(Breakpoint* bpt) { |
| 497 ASSERT(breakpoints_ != NULL); |
| 498 Breakpoint* prev_bpt = NULL; |
| 499 Breakpoint* curr_bpt = breakpoints_; |
| 500 while (curr_bpt != NULL) { |
| 501 if (bpt == curr_bpt) { |
| 502 if (prev_bpt == NULL) { |
| 503 breakpoints_ = breakpoints_->next(); |
| 504 } else { |
| 505 prev_bpt->set_next(curr_bpt->next()); |
| 506 } |
| 507 UnsetBreakpoint(bpt); |
| 508 delete bpt; |
| 509 return; |
| 510 } |
| 511 prev_bpt = curr_bpt; |
| 512 curr_bpt = curr_bpt->next(); |
| 513 } |
| 514 // bpt is not a registered breakpoint, nothing to do. |
| 515 } |
| 516 |
| 517 |
| 518 Breakpoint* Debugger::GetBreakpointByFunction(const Function& func, |
| 519 intptr_t token_index) { |
| 520 Breakpoint* bpt = this->breakpoints_; |
| 521 while (bpt != NULL) { |
| 522 if ((bpt->function() == func.raw()) && |
| 523 (bpt->token_index() == token_index)) { |
| 524 return bpt; |
| 525 } |
| 526 bpt = bpt->next(); |
| 527 } |
| 528 return NULL; |
| 529 } |
| 530 |
| 531 |
| 532 void Debugger::RegisterBreakpoint(Breakpoint* bpt) { |
449 ASSERT(bpt->next() == NULL); | 533 ASSERT(bpt->next() == NULL); |
450 bpt->set_next(this->breakpoints_); | 534 bpt->set_next(this->breakpoints_); |
451 this->breakpoints_ = bpt; | 535 this->breakpoints_ = bpt; |
452 } | 536 } |
453 | 537 |
454 | 538 |
455 } // namespace dart | 539 } // namespace dart |
OLD | NEW |