| 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 |