Chromium Code Reviews| 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_patcher.h" | 8 #include "vm/code_patcher.h" |
| 8 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 9 #include "vm/flags.h" | 10 #include "vm/flags.h" |
| 10 #include "vm/globals.h" | 11 #include "vm/globals.h" |
| 11 #include "vm/object.h" | 12 #include "vm/object.h" |
| 12 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 13 #include "vm/os.h" | 14 #include "vm/os.h" |
| 15 #include "vm/stack_frame.h" | |
| 14 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
| 15 #include "vm/visitor.h" | 17 #include "vm/visitor.h" |
| 16 | 18 |
| 17 | 19 |
| 18 namespace dart { | 20 namespace dart { |
| 19 | 21 |
| 20 DEFINE_FLAG(bool, debugger, false, "Debug breakpoint at main"); | 22 DEFINE_FLAG(bool, debugger, false, "Debug breakpoint at main"); |
| 21 DEFINE_FLAG(charp, bpt, NULL, "Debug breakpoint at <func>"); | 23 DEFINE_FLAG(charp, bpt, NULL, "Debug breakpoint at <func>"); |
| 22 | 24 |
| 23 | 25 |
| 24 class Breakpoint { | 26 |
| 25 public: | 27 Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index) |
| 26 Breakpoint(const Function& func, intptr_t pc_desc_index, uword pc) | 28 : function_(func.raw()), |
| 27 : function_(func.raw()), | 29 pc_desc_index_(pc_desc_index), |
| 28 pc_desc_index_(pc_desc_index), | 30 token_index_(0), |
| 29 pc_(pc), | 31 pc_(0), |
| 30 next_(NULL) { | 32 line_number_(-1), |
| 33 next_(NULL) { | |
| 34 Code& code = Code::Handle(func.code()); | |
| 35 ASSERT(!code.IsNull()); // Function must be compiled. | |
| 36 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | |
| 37 ASSERT(pc_desc_index < desc.Length()); | |
| 38 this->token_index_ = desc.TokenIndex(pc_desc_index); | |
| 39 ASSERT(this->token_index_ > 0); | |
| 40 this->pc_ = desc.PC(pc_desc_index); | |
| 41 ASSERT(this->token_index_ != 0); | |
|
siva
2011/12/05 19:21:44
Storing the pc_ and token_index_ in this structure
hausner
2011/12/05 21:11:23
I tried to cache some data so it would not have to
| |
| 42 } | |
| 43 | |
| 44 | |
| 45 RawScript* Breakpoint::SourceCode() { | |
| 46 const Function& func = Function::Handle(this->function_); | |
| 47 const Class& cls = Class::Handle(func.owner()); | |
| 48 return cls.script(); | |
| 49 } | |
| 50 | |
| 51 | |
| 52 RawString* Breakpoint::SourceUrl() { | |
| 53 const Script& script = Script::Handle(this->SourceCode()); | |
| 54 return script.url(); | |
| 55 } | |
| 56 | |
| 57 | |
| 58 intptr_t Breakpoint::LineNumber() { | |
| 59 // Compute line number lazily since it causes scanning of the script. | |
| 60 if (this->line_number_ < 0) { | |
| 61 const Script& script = Script::Handle(this->SourceCode()); | |
| 62 intptr_t ignore_column; | |
| 63 script.GetTokenLocation(this->token_index_, | |
| 64 &this->line_number_, &ignore_column); | |
| 31 } | 65 } |
| 66 return this->line_number_; | |
| 67 } | |
| 32 | 68 |
| 33 RawFunction* function() const { return function_; } | |
| 34 uword pc() const { return pc_; } | |
| 35 | 69 |
| 36 void set_next(Breakpoint* value) { next_ = value; } | 70 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 37 Breakpoint* next() const { return this->next_; } | 71 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 72 } | |
| 38 | 73 |
| 39 void VisitObjectPointers(ObjectPointerVisitor* visitor) { | 74 |
| 40 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 75 ActivationFrame::ActivationFrame(uword pc) |
| 76 : pc_(pc), | |
| 77 function_(Function::null()), | |
| 78 token_index_(-1), | |
| 79 line_number_(-1) { | |
| 80 } | |
| 81 | |
| 82 | |
| 83 RawFunction* ActivationFrame::DartFunction() { | |
| 84 if (function_ == Function::null()) { | |
| 85 ASSERT(Isolate::Current() != NULL); | |
| 86 CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); | |
| 87 ASSERT(code_index_table != NULL); | |
| 88 function_ = code_index_table->LookupFunction(pc_); | |
| 41 } | 89 } |
| 90 return function_; | |
| 91 } | |
| 42 | 92 |
| 43 private: | 93 |
| 44 RawFunction* function_; | 94 RawString* ActivationFrame::SourceUrl() { |
| 45 intptr_t pc_desc_index_; | 95 const Script& script = Script::Handle(SourceScript()); |
| 46 uword pc_; | 96 return script.url(); |
| 47 Breakpoint* next_; | 97 } |
| 48 DISALLOW_COPY_AND_ASSIGN(Breakpoint); | 98 |
| 49 }; | 99 |
| 100 RawScript* ActivationFrame::SourceScript() { | |
| 101 const Function& func = Function::Handle(DartFunction()); | |
| 102 const Class& cls = Class::Handle(func.owner()); | |
| 103 return cls.script(); | |
| 104 } | |
| 105 | |
| 106 | |
| 107 intptr_t ActivationFrame::TokenIndex() { | |
| 108 if (token_index_ < 0) { | |
| 109 const Function& func = Function::Handle(DartFunction()); | |
| 110 Code& code = Code::Handle(func.code()); | |
| 111 ASSERT(!code.IsNull()); | |
| 112 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | |
| 113 for (int i = 0; i < desc.Length(); i++) { | |
| 114 if (desc.PC(i) == pc_) { | |
| 115 token_index_ = desc.TokenIndex(i); | |
| 116 break; | |
| 117 } | |
| 118 } | |
| 119 ASSERT(token_index_ >= 0); | |
| 120 } | |
| 121 return token_index_; | |
| 122 } | |
| 123 | |
| 124 | |
| 125 intptr_t ActivationFrame::LineNumber() { | |
| 126 // Compute line number lazily since it causes scanning of the script. | |
| 127 if (line_number_ < 0) { | |
| 128 const Script& script = Script::Handle(SourceScript()); | |
| 129 intptr_t ignore_column; | |
| 130 script.GetTokenLocation(TokenIndex(), &line_number_, &ignore_column); | |
| 131 } | |
|
siva
2011/12/05 19:21:44
The line number computation code is duplicated her
hausner
2011/12/05 21:11:23
I noticed that too, but I could really only factor
| |
| 132 return line_number_; | |
| 133 } | |
| 134 | |
| 135 | |
| 136 RawArray* ActivationFrame::Variables() { | |
| 137 UNIMPLEMENTED(); | |
| 138 } | |
| 139 | |
| 140 | |
| 141 RawInstance* ActivationFrame::Value(const String& variable_name) { | |
| 142 UNIMPLEMENTED(); | |
| 143 } | |
| 144 | |
| 145 | |
| 146 char* ActivationFrame::ToCString() { | |
| 147 const char* kFormat = "Function: '%s%s%s' url: '%s' line: %d"; | |
| 148 | |
| 149 Function& func = Function::Handle(DartFunction()); | |
| 150 String& func_name = String::Handle(func.name()); | |
| 151 Class& func_class = Class::Handle(func.owner()); | |
| 152 String& class_name = String::Handle(func_class.Name()); | |
| 153 String& url = String::Handle(SourceUrl()); | |
| 154 intptr_t line = LineNumber(); | |
| 155 | |
| 156 intptr_t len = OS::SNPrint(NULL, 0, kFormat, | |
| 157 class_name.ToCString(), | |
| 158 func_class.IsTopLevel() ? "" : ".", | |
| 159 func_name.ToCString(), | |
| 160 url.ToCString(), | |
| 161 line); | |
| 162 len++; // String terminator. | |
| 163 char* chars = reinterpret_cast<char*>( | |
| 164 Isolate::Current()->current_zone()->Allocate(len)); | |
| 165 OS::SNPrint(chars, len, kFormat, | |
| 166 class_name.ToCString(), | |
| 167 func_class.IsTopLevel() ? "" : ".", | |
| 168 func_name.ToCString(), | |
| 169 url.ToCString(), | |
| 170 line); | |
| 171 return chars; | |
| 172 } | |
| 173 | |
| 174 | |
| 175 void StackTrace::AddActivation(ActivationFrame* frame) { | |
| 176 this->trace_.Add(frame); | |
| 177 } | |
| 50 | 178 |
| 51 | 179 |
| 52 Debugger::Debugger() | 180 Debugger::Debugger() |
| 53 : initialized_(false), | 181 : initialized_(false), |
| 182 bp_handler_(NULL), | |
| 54 breakpoints_(NULL) { | 183 breakpoints_(NULL) { |
| 55 } | 184 } |
| 56 | 185 |
| 57 | 186 |
| 58 static RawFunction* ResolveLibraryFunction(const String& fname) { | 187 static RawFunction* ResolveLibraryFunction(const String& fname) { |
| 59 Isolate* isolate = Isolate::Current(); | 188 Isolate* isolate = Isolate::Current(); |
| 60 const Library& root_lib = | 189 const Library& root_lib = |
| 61 Library::Handle(isolate->object_store()->root_library()); | 190 Library::Handle(isolate->object_store()->root_library()); |
| 62 ASSERT(!root_lib.IsNull()); | 191 ASSERT(!root_lib.IsNull()); |
| 63 Function& function = Function::Handle(); | 192 Function& function = Function::Handle(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 80 if (!cls.IsNull()) { | 209 if (!cls.IsNull()) { |
| 81 function = cls.LookupStaticFunction(function_name); | 210 function = cls.LookupStaticFunction(function_name); |
| 82 if (function.IsNull()) { | 211 if (function.IsNull()) { |
| 83 function = cls.LookupDynamicFunction(function_name); | 212 function = cls.LookupDynamicFunction(function_name); |
| 84 } | 213 } |
| 85 } | 214 } |
| 86 return function.raw(); | 215 return function.raw(); |
| 87 } | 216 } |
| 88 | 217 |
| 89 | 218 |
| 90 | |
| 91 void Debugger::SetBreakpointAtEntry(const String& class_name, | 219 void Debugger::SetBreakpointAtEntry(const String& class_name, |
| 92 const String& function_name) { | 220 const String& function_name) { |
| 93 Function& func = Function::Handle(); | 221 Function& func = Function::Handle(); |
| 94 if (class_name.IsNull() || (class_name.Length() == 0)) { | 222 if (class_name.IsNull() || (class_name.Length() == 0)) { |
| 95 func = ResolveLibraryFunction(function_name); | 223 func = ResolveLibraryFunction(function_name); |
| 96 } else { | 224 } else { |
| 97 func = ResolveFunction(class_name, function_name); | 225 func = ResolveFunction(class_name, function_name); |
| 98 } | 226 } |
| 99 if (func.IsNull()) { | 227 if (func.IsNull()) { |
| 100 OS::Print("could not find function '%s' in class '%s'\n", | 228 OS::Print("could not find function '%s'\n", function_name.ToCString()); |
| 101 function_name.ToCString(), class_name.ToCString()); | |
| 102 return; | 229 return; |
| 103 } | 230 } |
| 104 if (!func.HasCode()) { | 231 if (!func.HasCode()) { |
| 105 Compiler::CompileFunction(func); | 232 Compiler::CompileFunction(func); |
| 106 } | 233 } |
| 107 Code& code = Code::Handle(func.code()); | 234 Code& code = Code::Handle(func.code()); |
| 108 ASSERT(!code.IsNull()); | 235 ASSERT(!code.IsNull()); |
| 109 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 236 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 110 for (int i = 0; i < desc.Length(); i++) { | 237 for (int i = 0; i < desc.Length(); i++) { |
| 111 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 238 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 239 Breakpoint* bpt = NULL; | |
| 112 if (kind == PcDescriptors::kIcCall) { | 240 if (kind == PcDescriptors::kIcCall) { |
| 113 OS::Print("patching dynamic call at %p\n", desc.PC(i)); | |
| 114 CodePatcher::PatchInstanceCallAt( | 241 CodePatcher::PatchInstanceCallAt( |
| 115 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); | 242 desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); |
| 116 AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); | 243 bpt = new Breakpoint(func, i); |
| 117 return; | |
| 118 } else if (kind == PcDescriptors::kOther) { | 244 } else if (kind == PcDescriptors::kOther) { |
| 119 if (CodePatcher::IsDartCall(desc.PC(i))) { | 245 if (CodePatcher::IsDartCall(desc.PC(i))) { |
| 120 OS::Print("patching static call at %p\n", desc.PC(i)); | |
| 121 CodePatcher::PatchStaticCallAt( | 246 CodePatcher::PatchStaticCallAt( |
| 122 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); | 247 desc.PC(i), StubCode::BreakpointStaticEntryPoint()); |
| 123 AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); | 248 bpt = new Breakpoint(func, i); |
| 124 return; | |
| 125 } | 249 } |
| 126 } | 250 } |
| 251 if (bpt != NULL) { | |
| 252 OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n", | |
| 253 String::Handle(bpt->SourceUrl()).ToCString(), | |
| 254 bpt->LineNumber(), | |
| 255 bpt->pc()); | |
| 256 AddBreakpoint(bpt); | |
| 257 return; | |
| 258 } | |
| 127 } | 259 } |
| 128 OS::Print("no breakpoint location found in function '%s'\n", | 260 OS::Print("no breakpoint location found in function '%s'\n", |
| 129 function_name.ToCString()); | 261 function_name.ToCString()); |
| 130 } | 262 } |
| 131 | 263 |
| 132 | 264 |
| 265 void Debugger::SetBreakpointHandler(BreakpointHandler* handler) { | |
| 266 bp_handler_ = handler; | |
| 267 } | |
| 268 | |
| 269 | |
| 133 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 270 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 134 ASSERT(visitor != NULL); | 271 ASSERT(visitor != NULL); |
| 135 Breakpoint* bpt = this->breakpoints_; | 272 Breakpoint* bpt = this->breakpoints_; |
| 136 while (bpt != NULL) { | 273 while (bpt != NULL) { |
| 137 bpt->VisitObjectPointers(visitor); | 274 bpt->VisitObjectPointers(visitor); |
| 138 bpt = bpt->next(); | 275 bpt = bpt->next(); |
| 139 } | 276 } |
| 140 } | 277 } |
| 141 | 278 |
| 142 | 279 |
| 280 static void DefaultBreakpointHandler(Breakpoint* bpt, StackTrace* stack) { | |
| 281 for (int i = 0; i < stack->Length(); i++) { | |
|
siva
2011/12/05 19:21:44
stack->Length() returns an intptr_t so should i al
hausner
2011/12/05 21:11:23
Done.
| |
| 282 OS::Print(" %d. %s\n", | |
| 283 i + 1, stack->ActivationFrameAt(i)->ToCString()); | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 | |
| 288 void Debugger::BreakpointCallback() { | |
| 289 ASSERT(initialized_); | |
| 290 DartFrameIterator iterator; | |
| 291 DartFrame* frame = iterator.NextFrame(); | |
| 292 Function& func = Function::Handle(); | |
| 293 ASSERT(frame != NULL); | |
| 294 Breakpoint* bpt = GetBreakpoint(frame->pc()); | |
| 295 ASSERT(bpt != NULL); | |
| 296 OS::Print(">>> Breakpoint at %s:%d (Address %p)\n", | |
| 297 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", | |
| 298 bpt ? bpt->LineNumber() : 0, | |
| 299 frame->pc()); | |
| 300 StackTrace* stack_trace = new StackTrace(8); | |
| 301 while (frame != NULL) { | |
| 302 ASSERT(frame->IsValid()); | |
| 303 ASSERT(frame->IsDartFrame()); | |
| 304 ActivationFrame* activation = new ActivationFrame(frame->pc()); | |
| 305 stack_trace->AddActivation(activation); | |
| 306 frame = iterator.NextFrame(); | |
| 307 } | |
| 308 | |
| 309 if (bp_handler_ != NULL) { | |
| 310 (*bp_handler_)(bpt, stack_trace); | |
| 311 } else { | |
| 312 DefaultBreakpointHandler(bpt, stack_trace); | |
| 313 } | |
|
siva
2011/12/05 19:21:44
Why not register DefaultBreakpointHandler as the d
hausner
2011/12/05 21:11:23
Yes. Done.
| |
| 314 } | |
| 315 | |
| 316 | |
| 143 void Debugger::Initialize(Isolate* isolate) { | 317 void Debugger::Initialize(Isolate* isolate) { |
| 144 if (initialized_) { | 318 if (initialized_) { |
| 145 return; | 319 return; |
| 146 } | 320 } |
| 147 initialized_ = true; | 321 initialized_ = true; |
| 148 if (!FLAG_debugger) { | 322 if (!FLAG_debugger) { |
| 149 return; | 323 return; |
| 150 } | 324 } |
| 151 if (FLAG_bpt == NULL) { | 325 if (FLAG_bpt == NULL) { |
| 152 FLAG_bpt = "main"; | 326 FLAG_bpt = "main"; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 178 | 352 |
| 179 | 353 |
| 180 void Debugger::AddBreakpoint(Breakpoint* bpt) { | 354 void Debugger::AddBreakpoint(Breakpoint* bpt) { |
| 181 ASSERT(bpt->next() == NULL); | 355 ASSERT(bpt->next() == NULL); |
| 182 bpt->set_next(this->breakpoints_); | 356 bpt->set_next(this->breakpoints_); |
| 183 this->breakpoints_ = bpt; | 357 this->breakpoints_ = bpt; |
| 184 } | 358 } |
| 185 | 359 |
| 186 | 360 |
| 187 } // namespace dart | 361 } // namespace dart |
| OLD | NEW |