| Index: runtime/vm/debugger.cc | 
| =================================================================== | 
| --- runtime/vm/debugger.cc	(revision 0) | 
| +++ runtime/vm/debugger.cc	(revision 0) | 
| @@ -0,0 +1,187 @@ | 
| +// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
| +// for details. All rights reserved. Use of this source code is governed by a | 
| +// BSD-style license that can be found in the LICENSE file. | 
| + | 
| +#include "vm/debugger.h" | 
| + | 
| +#include "vm/code_patcher.h" | 
| +#include "vm/compiler.h" | 
| +#include "vm/flags.h" | 
| +#include "vm/globals.h" | 
| +#include "vm/object.h" | 
| +#include "vm/object_store.h" | 
| +#include "vm/os.h" | 
| +#include "vm/stub_code.h" | 
| +#include "vm/visitor.h" | 
| + | 
| + | 
| +namespace dart { | 
| + | 
| +DEFINE_FLAG(bool, debugger, false, "Debug breakpoint at main"); | 
| +DEFINE_FLAG(charp, bpt, NULL, "Debug breakpoint at <func>"); | 
| + | 
| + | 
| +class Breakpoint { | 
| + public: | 
| +  Breakpoint(const Function& func, intptr_t pc_desc_index, uword pc) | 
| +      : function_(func.raw()), | 
| +        pc_desc_index_(pc_desc_index), | 
| +        pc_(pc), | 
| +        next_(NULL) { | 
| +  } | 
| + | 
| +  RawFunction* function() const { return function_; } | 
| +  uword pc() const { return pc_; } | 
| + | 
| +  void set_next(Breakpoint* value) { next_ = value; } | 
| +  Breakpoint* next() const { return this->next_; } | 
| + | 
| +  void VisitObjectPointers(ObjectPointerVisitor* visitor) { | 
| +    visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 
| +  } | 
| + | 
| + private: | 
| +  RawFunction* function_; | 
| +  intptr_t pc_desc_index_; | 
| +  uword pc_; | 
| +  Breakpoint* next_; | 
| +  DISALLOW_COPY_AND_ASSIGN(Breakpoint); | 
| +}; | 
| + | 
| + | 
| +Debugger::Debugger() | 
| +    : initialized_(false), | 
| +      breakpoints_(NULL) { | 
| +} | 
| + | 
| + | 
| +static RawFunction* ResolveLibraryFunction(const String& fname) { | 
| +  Isolate* isolate = Isolate::Current(); | 
| +  const Library& root_lib = | 
| +      Library::Handle(isolate->object_store()->root_library()); | 
| +  ASSERT(!root_lib.IsNull()); | 
| +  Function& function = Function::Handle(); | 
| +  const Object& object = Object::Handle(root_lib.LookupObject(fname)); | 
| +  if (!object.IsNull() && object.IsFunction()) { | 
| +    function ^= object.raw(); | 
| +  } | 
| +  return function.raw(); | 
| +} | 
| + | 
| + | 
| +static RawFunction* ResolveFunction(const String& class_name, | 
| +                                    const String& function_name) { | 
| +  Isolate* isolate = Isolate::Current(); | 
| +  const Library& root_lib = | 
| +      Library::Handle(isolate->object_store()->root_library()); | 
| +  const Class& cls = Class::Handle(root_lib.LookupClass(class_name)); | 
| + | 
| +  Function& function = Function::Handle(); | 
| +  if (!cls.IsNull()) { | 
| +    function = cls.LookupStaticFunction(function_name); | 
| +    if (function.IsNull()) { | 
| +      function = cls.LookupDynamicFunction(function_name); | 
| +    } | 
| +  } | 
| +  return function.raw(); | 
| +} | 
| + | 
| + | 
| + | 
| +void Debugger::SetBreakpointAtEntry(const String& class_name, | 
| +                                    const String& function_name) { | 
| +  Function& func = Function::Handle(); | 
| +  if (class_name.IsNull() || (class_name.Length() == 0)) { | 
| +    func = ResolveLibraryFunction(function_name); | 
| +  } else { | 
| +    func = ResolveFunction(class_name, function_name); | 
| +  } | 
| +  if (func.IsNull()) { | 
| +    OS::Print("could not find function '%s' in class '%s'\n", | 
| +      function_name.ToCString(), class_name.ToCString()); | 
| +    return; | 
| +  } | 
| +  if (!func.HasCode()) { | 
| +    Compiler::CompileFunction(func); | 
| +  } | 
| +  Code& code = Code::Handle(func.code()); | 
| +  ASSERT(!code.IsNull()); | 
| +  PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 
| +  for (int i = 0; i < desc.Length(); i++) { | 
| +    PcDescriptors::Kind kind = desc.DescriptorKind(i); | 
| +    if (kind == PcDescriptors::kIcCall) { | 
| +      OS::Print("patching dynamic call at %p\n", desc.PC(i)); | 
| +      CodePatcher::PatchInstanceCallAt( | 
| +          desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); | 
| +      AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); | 
| +      return; | 
| +    } else if (kind == PcDescriptors::kOther) { | 
| +      if (CodePatcher::IsDartCall(desc.PC(i))) { | 
| +        OS::Print("patching static call at %p\n", desc.PC(i)); | 
| +        CodePatcher::PatchStaticCallAt( | 
| +            desc.PC(i), StubCode::BreakpointStaticEntryPoint()); | 
| +        AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); | 
| +        return; | 
| +      } | 
| +    } | 
| +  } | 
| +  OS::Print("no breakpoint location found in function '%s'\n", | 
| +         function_name.ToCString()); | 
| +} | 
| + | 
| + | 
| +void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 
| +  ASSERT(visitor != NULL); | 
| +  Breakpoint* bpt = this->breakpoints_; | 
| +  while (bpt != NULL) { | 
| +    bpt->VisitObjectPointers(visitor); | 
| +    bpt = bpt->next(); | 
| +  } | 
| +} | 
| + | 
| + | 
| +void Debugger::Initialize(Isolate* isolate) { | 
| +  if (initialized_) { | 
| +    return; | 
| +  } | 
| +  initialized_ = true; | 
| +  if (!FLAG_debugger) { | 
| +    return; | 
| +  } | 
| +  if (FLAG_bpt == NULL) { | 
| +    FLAG_bpt = "main"; | 
| +  } | 
| +  String& cname = String::Handle(); | 
| +  String& fname = String::Handle(); | 
| +  char* dot = strchr(FLAG_bpt, '.'); | 
| +  if (dot == NULL) { | 
| +    fname = String::New(FLAG_bpt); | 
| +  } else { | 
| +    fname = String::New(dot + 1); | 
| +    cname = String::New(reinterpret_cast<const uint8_t*>(FLAG_bpt), | 
| +                        dot - FLAG_bpt); | 
| +  } | 
| +  SetBreakpointAtEntry(cname, fname); | 
| +} | 
| + | 
| + | 
| +Breakpoint* Debugger::GetBreakpoint(uword breakpoint_address) { | 
| +  Breakpoint* bpt = this->breakpoints_; | 
| +  while (bpt != NULL) { | 
| +    if (bpt->pc() == breakpoint_address) { | 
| +      return bpt; | 
| +    } | 
| +    bpt = bpt->next(); | 
| +  } | 
| +  return NULL; | 
| +} | 
| + | 
| + | 
| +void Debugger::AddBreakpoint(Breakpoint* bpt) { | 
| +  ASSERT(bpt->next() == NULL); | 
| +  bpt->set_next(this->breakpoints_); | 
| +  this->breakpoints_ = bpt; | 
| +} | 
| + | 
| + | 
| +}  // namespace dart | 
|  |