OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "vm/debugger.h" |
| 6 |
| 7 #include "vm/code_patcher.h" |
| 8 #include "vm/compiler.h" |
| 9 #include "vm/flags.h" |
| 10 #include "vm/globals.h" |
| 11 #include "vm/object.h" |
| 12 #include "vm/object_store.h" |
| 13 #include "vm/os.h" |
| 14 #include "vm/stub_code.h" |
| 15 #include "vm/visitor.h" |
| 16 |
| 17 |
| 18 namespace dart { |
| 19 |
| 20 DEFINE_FLAG(bool, debugger, false, "Debug breakpoint at main"); |
| 21 DEFINE_FLAG(charp, bpt, NULL, "Debug breakpoint at <func>"); |
| 22 |
| 23 |
| 24 class Breakpoint { |
| 25 public: |
| 26 Breakpoint(const Function& func, intptr_t pc_desc_index, uword pc) |
| 27 : function_(func.raw()), |
| 28 pc_desc_index_(pc_desc_index), |
| 29 pc_(pc), |
| 30 next_(NULL) { |
| 31 } |
| 32 |
| 33 RawFunction* function() const { return function_; } |
| 34 uword pc() const { return pc_; } |
| 35 |
| 36 void set_next(Breakpoint* value) { next_ = value; } |
| 37 Breakpoint* next() const { return this->next_; } |
| 38 |
| 39 void VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 40 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 41 } |
| 42 |
| 43 private: |
| 44 RawFunction* function_; |
| 45 intptr_t pc_desc_index_; |
| 46 uword pc_; |
| 47 Breakpoint* next_; |
| 48 DISALLOW_COPY_AND_ASSIGN(Breakpoint); |
| 49 }; |
| 50 |
| 51 |
| 52 Debugger::Debugger() |
| 53 : initialized_(false), |
| 54 breakpoints_(NULL) { |
| 55 } |
| 56 |
| 57 |
| 58 static RawFunction* ResolveLibraryFunction(const String& fname) { |
| 59 Isolate* isolate = Isolate::Current(); |
| 60 const Library& root_lib = |
| 61 Library::Handle(isolate->object_store()->root_library()); |
| 62 ASSERT(!root_lib.IsNull()); |
| 63 Function& function = Function::Handle(); |
| 64 const Object& object = Object::Handle(root_lib.LookupObject(fname)); |
| 65 if (!object.IsNull() && object.IsFunction()) { |
| 66 function ^= object.raw(); |
| 67 } |
| 68 return function.raw(); |
| 69 } |
| 70 |
| 71 |
| 72 static RawFunction* ResolveFunction(const String& class_name, |
| 73 const String& function_name) { |
| 74 Isolate* isolate = Isolate::Current(); |
| 75 const Library& root_lib = |
| 76 Library::Handle(isolate->object_store()->root_library()); |
| 77 const Class& cls = Class::Handle(root_lib.LookupClass(class_name)); |
| 78 |
| 79 Function& function = Function::Handle(); |
| 80 if (!cls.IsNull()) { |
| 81 function = cls.LookupStaticFunction(function_name); |
| 82 if (function.IsNull()) { |
| 83 function = cls.LookupDynamicFunction(function_name); |
| 84 } |
| 85 } |
| 86 return function.raw(); |
| 87 } |
| 88 |
| 89 |
| 90 |
| 91 void Debugger::SetBreakpointAtEntry(const String& class_name, |
| 92 const String& function_name) { |
| 93 Function& func = Function::Handle(); |
| 94 if (class_name.IsNull() || (class_name.Length() == 0)) { |
| 95 func = ResolveLibraryFunction(function_name); |
| 96 } else { |
| 97 func = ResolveFunction(class_name, function_name); |
| 98 } |
| 99 if (func.IsNull()) { |
| 100 OS::Print("could not find function '%s' in class '%s'\n", |
| 101 function_name.ToCString(), class_name.ToCString()); |
| 102 return; |
| 103 } |
| 104 if (!func.HasCode()) { |
| 105 Compiler::CompileFunction(func); |
| 106 } |
| 107 Code& code = Code::Handle(func.code()); |
| 108 ASSERT(!code.IsNull()); |
| 109 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 110 for (int i = 0; i < desc.Length(); i++) { |
| 111 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 112 if (kind == PcDescriptors::kIcCall) { |
| 113 OS::Print("patching dynamic call at %p\n", desc.PC(i)); |
| 114 CodePatcher::PatchInstanceCallAt( |
| 115 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); |
| 116 AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); |
| 117 return; |
| 118 } else if (kind == PcDescriptors::kOther) { |
| 119 if (CodePatcher::IsDartCall(desc.PC(i))) { |
| 120 OS::Print("patching static call at %p\n", desc.PC(i)); |
| 121 CodePatcher::PatchStaticCallAt( |
| 122 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); |
| 123 AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); |
| 124 return; |
| 125 } |
| 126 } |
| 127 } |
| 128 OS::Print("no breakpoint location found in function '%s'\n", |
| 129 function_name.ToCString()); |
| 130 } |
| 131 |
| 132 |
| 133 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 134 ASSERT(visitor != NULL); |
| 135 Breakpoint* bpt = this->breakpoints_; |
| 136 while (bpt != NULL) { |
| 137 bpt->VisitObjectPointers(visitor); |
| 138 bpt = bpt->next(); |
| 139 } |
| 140 } |
| 141 |
| 142 |
| 143 void Debugger::Initialize(Isolate* isolate) { |
| 144 if (initialized_) { |
| 145 return; |
| 146 } |
| 147 initialized_ = true; |
| 148 if (!FLAG_debugger) { |
| 149 return; |
| 150 } |
| 151 if (FLAG_bpt == NULL) { |
| 152 FLAG_bpt = "main"; |
| 153 } |
| 154 String& cname = String::Handle(); |
| 155 String& fname = String::Handle(); |
| 156 char* dot = strchr(FLAG_bpt, '.'); |
| 157 if (dot == NULL) { |
| 158 fname = String::New(FLAG_bpt); |
| 159 } else { |
| 160 fname = String::New(dot + 1); |
| 161 cname = String::New(reinterpret_cast<const uint8_t*>(FLAG_bpt), |
| 162 dot - FLAG_bpt); |
| 163 } |
| 164 SetBreakpointAtEntry(cname, fname); |
| 165 } |
| 166 |
| 167 |
| 168 Breakpoint* Debugger::GetBreakpoint(uword breakpoint_address) { |
| 169 Breakpoint* bpt = this->breakpoints_; |
| 170 while (bpt != NULL) { |
| 171 if (bpt->pc() == breakpoint_address) { |
| 172 return bpt; |
| 173 } |
| 174 bpt = bpt->next(); |
| 175 } |
| 176 return NULL; |
| 177 } |
| 178 |
| 179 |
| 180 void Debugger::AddBreakpoint(Breakpoint* bpt) { |
| 181 ASSERT(bpt->next() == NULL); |
| 182 bpt->set_next(this->breakpoints_); |
| 183 this->breakpoints_ = bpt; |
| 184 } |
| 185 |
| 186 |
| 187 } // namespace dart |
OLD | NEW |