Chromium Code Reviews| Index: runtime/vm/debugger.cc |
| =================================================================== |
| --- runtime/vm/debugger.cc (revision 0) |
| +++ runtime/vm/debugger.cc (revision 0) |
| @@ -0,0 +1,186 @@ |
| +// 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>"); |
|
siva
2011/11/30 00:00:47
I hope all these flags are just temporary stuff be
hausner
2011/11/30 01:17:05
Yes, only temporary.
|
| + |
| + |
| +class Breakpoint { |
| + public: |
| + Breakpoint(const Function& func, int pc_desc_index, uword pc) |
|
srdjan
2011/11/29 22:26:00
intptr_t pc_dec_index
hausner
2011/11/30 01:17:05
Done.
|
| + : 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: |
|
srdjan
2011/11/29 22:26:00
DISALLOW_....
hausner
2011/11/30 01:17:05
Done.
|
| + RawFunction* function_; |
| + int pc_desc_index_; |
|
srdjan
2011/11/29 22:26:00
intptr_t
hausner
2011/11/30 01:17:05
Done, but over the long run I would change this to
|
| + uword pc_; |
|
siva
2011/11/30 00:00:47
Don't you also need to store the original contents
hausner
2011/11/30 01:17:05
At this point I don't need to. To remove a BP I ju
|
| + Breakpoint* next_; |
| +}; |
| + |
| + |
| +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()); |
|
srdjan
2011/11/29 22:26:00
4 spaces indent.
hausner
2011/11/30 01:17:05
Done.
|
| + 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::SetBreakpoint(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()) { |
| + printf("could not find function '%s' in class '%s'\n", |
| + function_name.ToCString(), class_name.ToCString()); |
|
srdjan
2011/11/29 22:26:00
OS::Print
hausner
2011/11/30 01:17:05
Done.
|
| + return; |
| + } |
| + if (!func.HasCode()) { |
| + Compiler::CompileFunction(func); |
| + } |
|
siva
2011/11/30 00:00:47
If the function already has code and it is running
hausner
2011/11/30 01:17:05
Yes. For now I just assume the optimizing compiler
|
| + 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) { |
| + printf("patching dynamic call at %p\n", desc.PC(i)); |
|
srdjan
2011/11/29 22:26:00
ditto
Maybe add a tracing flag and hide the print
hausner
2011/11/30 01:17:05
As mentioned above, all these prints will go away
|
| + CodePatcher::PatchInstanceCallAt( |
| + desc.PC(i), StubCode::BreakpointDynamicEntryPoint()); |
| + AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); |
|
siva
2011/11/30 00:00:47
you probably need a return here too, otherwise the
hausner
2011/11/30 01:17:05
Good catch.
|
| + } else if (kind == PcDescriptors::kOther) { |
| + if (CodePatcher::IsDartCall(desc.PC(i))) { |
| + printf("patching static call at %p\n", desc.PC(i)); |
| + CodePatcher::PatchStaticCallAt( |
| + desc.PC(i), StubCode::BreakpointStaticEntryPoint()); |
| + AddBreakpoint(new Breakpoint(func, i, desc.PC(i))); |
|
srdjan
2011/11/29 22:26:00
Who deletes breakpoints? Do we need a ~Debugger()
hausner
2011/11/30 01:17:05
Nobody yet. I think it's ok to leave this for futu
|
| + return; |
| + } |
|
siva
2011/11/30 00:00:47
Why don't we want to set breakpoints on locations
hausner
2011/11/30 01:17:05
I had to leave some functionality for version 2 :)
|
| + } |
| + } |
| + printf("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(); |
|
siva
2011/11/30 00:00:47
We would need a library name too over here, may no
hausner
2011/11/30 01:17:05
Very true. To keep things simple for the beginning
|
| + 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); |
| + } |
| + |
| + SetBreakpoint(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 |