Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Unified Diff: runtime/vm/debugger.cc

Issue 9484002: StepOver, StepInto, StepOut (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/debugger_api_impl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/debugger.cc
===================================================================
--- runtime/vm/debugger.cc (revision 4638)
+++ runtime/vm/debugger.cc (working copy)
@@ -5,6 +5,7 @@
#include "vm/debugger.h"
#include "vm/code_index_table.h"
+#include "vm/code_generator.h"
#include "vm/code_patcher.h"
#include "vm/compiler.h"
#include "vm/dart_entry.h"
@@ -28,8 +29,8 @@
: function_(func.raw()),
pc_desc_index_(pc_desc_index),
pc_(0),
- saved_bytes_(0),
line_number_(-1),
+ is_patched_(false),
next_(NULL) {
Code& code = Code::Handle(func.code());
ASSERT(!code.IsNull()); // Function must be compiled.
@@ -39,6 +40,7 @@
ASSERT(this->token_index_ > 0);
this->pc_ = desc.PC(pc_desc_index);
ASSERT(this->pc_ != 0);
+ this->breakpoint_kind_ = desc.DescriptorKind(pc_desc_index);
}
@@ -72,8 +74,8 @@
}
-ActivationFrame::ActivationFrame(uword pc, uword fp)
- : pc_(pc), fp_(fp),
+ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp)
+ : pc_(pc), fp_(fp), sp_(sp),
function_(Function::ZoneHandle()),
token_index_(-1),
line_number_(-1),
@@ -278,11 +280,75 @@
}
+void Breakpoint::PatchCode() {
+ ASSERT(!is_patched_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ int num_args, num_named_args;
+ CodePatcher::GetInstanceCallAt(pc_,
+ NULL, &num_args, &num_named_args,
+ &saved_bytes_.target_address_);
+ CodePatcher::PatchInstanceCallAt(
+ pc_, StubCode::BreakpointDynamicEntryPoint());
+ break;
+ }
+ case PcDescriptors::kFuncCall: {
+ Function& func = Function::Handle();
+ CodePatcher::GetStaticCallAt(pc_, &func, &saved_bytes_.target_address_);
+ CodePatcher::PatchStaticCallAt(pc_,
+ StubCode::BreakpointStaticEntryPoint());
+ break;
+ }
+ case PcDescriptors::kReturn:
+ PatchFunctionReturn();
+ break;
+ default:
+ UNREACHABLE();
+ }
+ is_patched_ = true;
+}
+
+
+void Breakpoint::RestoreCode() {
+ ASSERT(is_patched_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall:
+ CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_);
+ break;
+ case PcDescriptors::kFuncCall:
+ CodePatcher::PatchStaticCallAt(pc_, saved_bytes_.target_address_);
+ break;
+ case PcDescriptors::kReturn:
+ RestoreFunctionReturn();
+ break;
+ default:
+ UNREACHABLE();
+ }
+ is_patched_ = false;
+}
+
+void Breakpoint::SetActive(bool value) {
+ if (value && !is_patched_) {
+ PatchCode();
+ return;
+ }
+ if (!value && is_patched_) {
+ RestoreCode();
+ }
+}
+
+
+bool Breakpoint::IsActive() {
+ return is_patched_;
+}
+
+
Debugger::Debugger()
: isolate_(NULL),
initialized_(false),
bp_handler_(NULL),
- breakpoints_(NULL) {
+ breakpoints_(NULL),
+ resume_action_(kContinue) {
}
@@ -345,6 +411,37 @@
}
+void Debugger::InstrumentForStepping(const Function &target_function) {
+ if (!target_function.HasCode()) {
+ Compiler::CompileFunction(target_function);
+ // If there were any errors, ignore them silently and return without
+ // adding breakpoints to target.
+ if (!target_function.HasCode()) {
+ return;
+ }
+ }
+ Code& code = Code::Handle(target_function.code());
+ ASSERT(!code.IsNull());
+ PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
+ for (int i = 0; i < desc.Length(); i++) {
+ Breakpoint* bpt = GetBreakpoint(desc.PC(i));
+ if (bpt != NULL) {
+ // There is already a breakpoint for this address. Leave it alone.
+ continue;
+ }
+ PcDescriptors::Kind kind = desc.DescriptorKind(i);
+ if ((kind == PcDescriptors::kIcCall) ||
+ (kind == PcDescriptors::kFuncCall) ||
+ (kind == PcDescriptors::kReturn)) {
+ bpt = new Breakpoint(target_function, i);
+ bpt->set_temporary(true);
+ bpt->PatchCode();
+ RegisterBreakpoint(bpt);
+ }
+ }
+}
+
+
// TODO(hausner): Distinguish between newly created breakpoints and
// returning a breakpoint that already exists?
Breakpoint* Debugger::SetBreakpoint(const Function& target_function,
@@ -368,38 +465,18 @@
if (desc.TokenIndex(i) < token_index) {
continue;
}
+ Breakpoint* bpt = GetBreakpoint(desc.PC(i));
+ if (bpt != NULL) {
+ // Found existing breakpoint.
+ return bpt;
+ }
PcDescriptors::Kind kind = desc.DescriptorKind(i);
- Breakpoint* bpt = NULL;
- if (kind == PcDescriptors::kIcCall) {
- bpt = GetBreakpoint(desc.PC(i));
- if (bpt != NULL) {
- // There is an existing breakpoint at this token position.
- break;
- }
+ if ((kind == PcDescriptors::kIcCall) ||
+ (kind == PcDescriptors::kFuncCall) ||
+ (kind == PcDescriptors::kReturn)) {
bpt = new Breakpoint(target_function, i);
- String& func_name = String::Handle();
- int num_args, num_named_args;
- CodePatcher::GetInstanceCallAt(desc.PC(i),
- &func_name, &num_args, &num_named_args, &bpt->saved_bytes_);
- CodePatcher::PatchInstanceCallAt(
- desc.PC(i), StubCode::BreakpointDynamicEntryPoint());
+ bpt->PatchCode();
RegisterBreakpoint(bpt);
- } else if (kind == PcDescriptors::kOther) {
- if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) {
- bpt = GetBreakpoint(desc.PC(i));
- if (bpt != NULL) {
- // There is an existing breakpoint at this token position.
- break;
- }
- bpt = new Breakpoint(target_function, i);
- Function& func = Function::Handle();
- CodePatcher::GetStaticCallAt(desc.PC(i), &func, &bpt->saved_bytes_);
- CodePatcher::PatchStaticCallAt(
- desc.PC(i), StubCode::BreakpointStaticEntryPoint());
- RegisterBreakpoint(bpt);
- }
- }
- if (bpt != NULL) {
if (verbose) {
OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n",
String::Handle(bpt->SourceUrl()).ToCString(),
@@ -414,18 +491,7 @@
void Debugger::UnsetBreakpoint(Breakpoint* bpt) {
- const Function& func = Function::Handle(bpt->function());
- const Code& code = Code::Handle(func.code());
- PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
- intptr_t desc_index = bpt->pc_desc_index();
- ASSERT(desc_index < desc.Length());
- ASSERT(bpt->pc() == desc.PC(desc_index));
- PcDescriptors::Kind kind = desc.DescriptorKind(desc_index);
- if (kind == PcDescriptors::kIcCall) {
- CodePatcher::PatchInstanceCallAt(desc.PC(desc_index), bpt->saved_bytes_);
- } else {
- CodePatcher::PatchStaticCallAt(desc.PC(desc_index), bpt->saved_bytes_);
- }
+ bpt->SetActive(false);
}
@@ -610,7 +676,8 @@
Breakpoint* bpt = GetBreakpoint(frame->pc());
ASSERT(bpt != NULL);
if (verbose) {
- OS::Print(">>> Breakpoint at %s:%d (Address %p)\n",
+ OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n",
+ bpt->is_temporary() ? "hit temp" : "hit user",
bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?",
bpt ? bpt->LineNumber() : 0,
frame->pc());
@@ -620,14 +687,67 @@
ASSERT(frame->IsValid());
ASSERT(frame->IsDartFrame());
ActivationFrame* activation =
- new ActivationFrame(frame->pc(), frame->fp());
+ new ActivationFrame(frame->pc(), frame->fp(), frame->sp());
stack_trace->AddActivation(activation);
frame = iterator.NextFrame();
}
+ resume_action_ = kContinue;
if (bp_handler_ != NULL) {
(*bp_handler_)(bpt, stack_trace);
}
+
+ if (resume_action_ == kContinue) {
+ RemoveTemporaryBreakpoints();
+ } else if (resume_action_ == kStepOver) {
+ Function& func = Function::Handle(bpt->function());
+ if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) {
+ // If we are at the function return, do a StepOut action.
+ if (stack_trace->Length() > 1) {
+ ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
+ func = caller->DartFunction().raw();
+ RemoveTemporaryBreakpoints();
+ }
+ }
+ InstrumentForStepping(func);
+ } else if (resume_action_ == kStepInto) {
+ RemoveTemporaryBreakpoints();
+ if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) {
+ int num_args, num_named_args;
+ uword target;
+ CodePatcher::GetInstanceCallAt(bpt->pc_, NULL,
+ &num_args, &num_named_args, &target);
+ ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0);
+ Instance& receiver = Instance::Handle(
+ top_frame->GetInstanceCallReceiver(num_args));
+ Code& code = Code::Handle(
+ ResolveCompileInstanceCallTarget(isolate_, receiver));
+ if (!code.IsNull()) {
+ Function& callee = Function::Handle(code.function());
+ InstrumentForStepping(callee);
+ }
+ } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) {
+ Function& callee = Function::Handle();
+ uword target;
+ CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target);
+ InstrumentForStepping(callee);
+ } else {
+ ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn);
+ // Treat like stepping out to caller.
+ if (stack_trace->Length() > 1) {
+ ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
+ InstrumentForStepping(caller->DartFunction());
+ }
+ }
+ } else {
+ ASSERT(resume_action_ == kStepOut);
+ // Set temporary breakpoints in the caller.
+ RemoveTemporaryBreakpoints();
+ if (stack_trace->Length() > 1) {
+ ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
+ InstrumentForStepping(caller->DartFunction());
+ }
+ }
}
@@ -675,6 +795,28 @@
}
+void Debugger::RemoveTemporaryBreakpoints() {
+ Breakpoint* prev_bpt = NULL;
+ Breakpoint* curr_bpt = breakpoints_;
+ while (curr_bpt != NULL) {
+ if (curr_bpt->is_temporary()) {
+ if (prev_bpt == NULL) {
+ breakpoints_ = breakpoints_->next();
+ } else {
+ prev_bpt->set_next(curr_bpt->next());
+ }
+ Breakpoint* temp_bpt = curr_bpt;
+ curr_bpt = curr_bpt->next();
+ UnsetBreakpoint(temp_bpt);
+ delete temp_bpt;
+ } else {
+ prev_bpt = curr_bpt;
+ curr_bpt = curr_bpt->next();
+ }
+ }
+}
+
+
Breakpoint* Debugger::GetBreakpointByFunction(const Function& func,
intptr_t token_index) {
Breakpoint* bpt = this->breakpoints_;
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/debugger_api_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698