Files
sdk/runtime/vm/debugger.h
T
hausner@google.com e58b6e4d4c Splitting debugger breakpoints into two parts
Splitting breakpoints into SourceBreakpoint that represent
a user-defined source location of a breakpoint, and
CodeBreakpoint, which represents a code location. There can
be more than one CodeBreakpoint per SourceBreakpoint, e.g.
for functions that are also called as closures (and are thus
compiled twice.)

Functions are no longer compiled as a side effect of setting
a breakpoint. When they eventually get compiled, the previously
recorded SourceBreakpoint is found and a CodeBreakpoint is set.
Review URL: https://chromiumcodereview.appspot.com//9581013

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4891 260f80e4-7a28-3924-810f-c04153c831b5
2012-03-02 18:01:38 +00:00

271 lines
7.2 KiB
C++

// 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.
#ifndef VM_DEBUGGER_H_
#define VM_DEBUGGER_H_
#include "vm/object.h"
namespace dart {
class SourceBreakpoint;
class CodeBreakpoint;
class Isolate;
class ObjectPointerVisitor;
class ActiveVariables;
// SourceBreakpoint represents a user-specified breakpoint location in
// Dart source. There may be more than one CodeBreakpoint object per
// SourceBreakpoint.
class SourceBreakpoint {
public:
SourceBreakpoint(const Function& func, intptr_t token_index);
RawFunction* function() const { return function_; }
intptr_t token_index() const { return token_index_; }
RawScript* SourceCode();
RawString* SourceUrl();
intptr_t LineNumber();
void Enable();
void Disable();
bool IsEnabled() const { return is_enabled_; }
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
void set_next(SourceBreakpoint* value) { next_ = value; }
SourceBreakpoint* next() const { return this->next_; }
RawFunction* function_;
intptr_t token_index_;
intptr_t line_number_;
bool is_enabled_;
SourceBreakpoint* next_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(SourceBreakpoint);
};
// CodeBreakpoint represents a location in compiled code. There may be
// more than one CodeBreakpoint for one SourceBreakpoint, e.g. when a
// function gets compiled as a regular function and as a closure.
class CodeBreakpoint {
public:
CodeBreakpoint(const Function& func, intptr_t pc_desc_index);
~CodeBreakpoint();
RawFunction* function() const { return function_; }
uword pc() const { return pc_; }
intptr_t token_index() const { return token_index_; }
bool IsInternal() const { return src_bpt_ == NULL; }
RawScript* SourceCode();
RawString* SourceUrl();
intptr_t LineNumber();
void Enable();
void Disable();
bool IsEnabled() const { return is_enabled_; }
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
SourceBreakpoint* src_bpt() const { return src_bpt_; }
void set_src_bpt(SourceBreakpoint* value) { src_bpt_ = value; }
void set_next(CodeBreakpoint* value) { next_ = value; }
CodeBreakpoint* next() const { return this->next_; }
intptr_t pc_desc_index() const { return pc_desc_index_; }
void PatchCode();
void RestoreCode();
void PatchFunctionReturn();
void RestoreFunctionReturn();
RawFunction* function_;
intptr_t pc_desc_index_;
intptr_t token_index_;
uword pc_;
intptr_t line_number_;
bool is_enabled_;
SourceBreakpoint* src_bpt_;
CodeBreakpoint* next_;
PcDescriptors::Kind breakpoint_kind_;
union {
uword target_address_;
uint8_t raw[2 * sizeof(uword)];
} saved_bytes_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(CodeBreakpoint);
};
// ActivationFrame represents one dart function activation frame
// on the call stack.
class ActivationFrame : public ZoneAllocated {
public:
explicit ActivationFrame(uword pc, uword fp, uword sp);
uword pc() const { return pc_; }
uword fp() const { return fp_; }
uword sp() const { return sp_; }
const Function& DartFunction();
RawString* QualifiedFunctionName();
RawString* SourceUrl();
RawScript* SourceScript();
intptr_t TokenIndex();
intptr_t LineNumber();
const char* ToCString();
intptr_t NumLocalVariables();
void VariableAt(intptr_t i,
String* name,
intptr_t* token_pos,
intptr_t* end_pos,
Instance* value);
RawArray* GetLocalVariables();
private:
void GetDescIndices();
RawInstance* GetLocalVarValue(intptr_t slot_index);
RawInstance* GetInstanceCallReceiver(intptr_t num_actual_args);
uword pc_;
uword fp_;
uword sp_;
Function& function_;
intptr_t token_index_;
intptr_t line_number_;
LocalVarDescriptors* var_descriptors_;
ZoneGrowableArray<intptr_t> desc_indices_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(ActivationFrame);
};
// Array of function activations on the call stack.
class StackTrace : public ZoneAllocated {
public:
explicit StackTrace(int capacity) : trace_(capacity) { }
intptr_t Length() const { return trace_.length(); }
ActivationFrame* ActivationFrameAt(int i) const {
ASSERT(i < trace_.length());
return trace_[i];
}
private:
void AddActivation(ActivationFrame* frame);
ZoneGrowableArray<ActivationFrame*> trace_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(StackTrace);
};
typedef void BreakpointHandler(SourceBreakpoint* bpt, StackTrace* stack);
class Debugger {
public:
Debugger();
~Debugger();
void Initialize(Isolate* isolate);
void Shutdown();
bool IsActive();
void NotifyCompilation(const Function& func);
void SetBreakpointHandler(BreakpointHandler* handler);
RawFunction* ResolveFunction(const Library& library,
const String& class_name,
const String& function_name);
// Set breakpoint at closest location to function entry.
SourceBreakpoint* SetBreakpointAtEntry(const Function& target_function);
SourceBreakpoint* SetBreakpointAtLine(const String& script_url,
intptr_t line_number);
void RemoveBreakpoint(SourceBreakpoint* bpt);
void SetStepOver() { resume_action_ = kStepOver; }
void SetStepInto() { resume_action_ = kStepInto; }
void SetStepOut() { resume_action_ = kStepOut; }
void VisitObjectPointers(ObjectPointerVisitor* visitor);
// Called from Runtime when a breakpoint in Dart code is reached.
void BreakpointCallback();
RawArray* GetInstanceFields(const Instance& obj);
RawArray* GetStaticFields(const Class& cls);
// Utility functions.
static const char* QualifiedFunctionName(const Function& func);
RawObject* GetInstanceField(const Class& cls,
const String& field_name,
const Instance& object);
RawObject* GetStaticField(const Class& cls,
const String& field_name);
private:
enum ResumeAction {
kContinue,
kStepOver,
kStepInto,
kStepOut
};
void InstrumentForStepping(const Function &target_function);
SourceBreakpoint* SetBreakpoint(const Function& target_function,
intptr_t token_index);
void RemoveInternalBreakpoints();
void RemoveCodeBreakpoints(SourceBreakpoint* src_bpt);
void RegisterSourceBreakpoint(SourceBreakpoint* bpt);
void RegisterCodeBreakpoint(CodeBreakpoint* bpt);
SourceBreakpoint* GetSourceBreakpoint(const Function& func,
intptr_t token_index);
CodeBreakpoint* MakeCodeBreakpoint(SourceBreakpoint* src_bpt);
// Returns NULL if no breakpoint exists for the given address.
CodeBreakpoint* GetCodeBreakpoint(uword breakpoint_address);
void SyncBreakpoint(SourceBreakpoint* bpt);
Isolate* isolate_;
bool initialized_;
BreakpointHandler* bp_handler_;
SourceBreakpoint* src_breakpoints_;
CodeBreakpoint* code_breakpoints_;
// Tells debugger what to do when resuming execution after a breakpoint.
ResumeAction resume_action_;
friend class SourceBreakpoint;
DISALLOW_COPY_AND_ASSIGN(Debugger);
};
} // namespace dart
#endif // VM_DEBUGGER_H_