| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 | 8 |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| (...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 isolate_id_(ILLEGAL_ISOLATE_ID), | 826 isolate_id_(ILLEGAL_ISOLATE_ID), |
| 827 initialized_(false), | 827 initialized_(false), |
| 828 next_id_(1), | 828 next_id_(1), |
| 829 src_breakpoints_(NULL), | 829 src_breakpoints_(NULL), |
| 830 code_breakpoints_(NULL), | 830 code_breakpoints_(NULL), |
| 831 resume_action_(kContinue), | 831 resume_action_(kContinue), |
| 832 ignore_breakpoints_(false), | 832 ignore_breakpoints_(false), |
| 833 pause_event_(NULL), | 833 pause_event_(NULL), |
| 834 obj_cache_(NULL), | 834 obj_cache_(NULL), |
| 835 stack_trace_(NULL), | 835 stack_trace_(NULL), |
| 836 stepping_fp_(0), |
| 836 exc_pause_info_(kNoPauseOnExceptions) { | 837 exc_pause_info_(kNoPauseOnExceptions) { |
| 837 } | 838 } |
| 838 | 839 |
| 839 | 840 |
| 840 Debugger::~Debugger() { | 841 Debugger::~Debugger() { |
| 841 isolate_id_ = ILLEGAL_ISOLATE_ID; | 842 isolate_id_ = ILLEGAL_ISOLATE_ID; |
| 842 ASSERT(!IsPaused()); | 843 ASSERT(!IsPaused()); |
| 843 ASSERT(src_breakpoints_ == NULL); | 844 ASSERT(src_breakpoints_ == NULL); |
| 844 ASSERT(code_breakpoints_ == NULL); | 845 ASSERT(code_breakpoints_ == NULL); |
| 845 ASSERT(stack_trace_ == NULL); | 846 ASSERT(stack_trace_ == NULL); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 868 const Library& library, | 869 const Library& library, |
| 869 const String& fname) { | 870 const String& fname) { |
| 870 ASSERT(!library.IsNull()); | 871 ASSERT(!library.IsNull()); |
| 871 const Object& object = Object::Handle(library.LookupObject(fname)); | 872 const Object& object = Object::Handle(library.LookupObject(fname)); |
| 872 if (!object.IsNull() && object.IsFunction()) { | 873 if (!object.IsNull() && object.IsFunction()) { |
| 873 return Function::Cast(object).raw(); | 874 return Function::Cast(object).raw(); |
| 874 } | 875 } |
| 875 return Function::null(); | 876 return Function::null(); |
| 876 } | 877 } |
| 877 | 878 |
| 879 |
| 878 void Debugger::SetSingleStep() { | 880 void Debugger::SetSingleStep() { |
| 879 isolate_->set_single_step(true); | |
| 880 resume_action_ = kSingleStep; | 881 resume_action_ = kSingleStep; |
| 881 } | 882 } |
| 882 | 883 |
| 884 |
| 883 void Debugger::SetStepOver() { | 885 void Debugger::SetStepOver() { |
| 884 isolate_->set_single_step(false); | |
| 885 resume_action_ = kStepOver; | 886 resume_action_ = kStepOver; |
| 886 } | 887 } |
| 887 | 888 |
| 889 |
| 888 void Debugger::SetStepOut() { | 890 void Debugger::SetStepOut() { |
| 889 isolate_->set_single_step(false); | |
| 890 resume_action_ = kStepOut; | 891 resume_action_ = kStepOut; |
| 891 } | 892 } |
| 892 | 893 |
| 893 RawFunction* Debugger::ResolveFunction(const Library& library, | 894 RawFunction* Debugger::ResolveFunction(const Library& library, |
| 894 const String& class_name, | 895 const String& class_name, |
| 895 const String& function_name) { | 896 const String& function_name) { |
| 896 ASSERT(!library.IsNull()); | 897 ASSERT(!library.IsNull()); |
| 897 ASSERT(!class_name.IsNull()); | 898 ASSERT(!class_name.IsNull()); |
| 898 ASSERT(!function_name.IsNull()); | 899 ASSERT(!function_name.IsNull()); |
| 899 if (class_name.Length() == 0) { | 900 if (class_name.Length() == 0) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 960 if (function.HasOptimizedCode()) { | 961 if (function.HasOptimizedCode()) { |
| 961 function.SwitchToUnoptimizedCode(); | 962 function.SwitchToUnoptimizedCode(); |
| 962 } | 963 } |
| 963 } | 964 } |
| 964 } | 965 } |
| 965 } | 966 } |
| 966 } | 967 } |
| 967 } | 968 } |
| 968 | 969 |
| 969 | 970 |
| 970 void Debugger::InstrumentForStepping(const Function& target_function) { | 971 void Debugger::SetInternalBreakpoints(const Function& target_function) { |
| 971 if (target_function.is_native()) { | 972 if (target_function.is_native()) { |
| 972 // Can't instrument native functions. | 973 // Can't instrument native functions. |
| 973 return; | 974 return; |
| 974 } | 975 } |
| 975 if (!target_function.HasCode()) { | 976 if (!target_function.HasCode()) { |
| 976 Compiler::CompileFunction(target_function); | 977 Compiler::CompileFunction(target_function); |
| 977 // If there were any errors, ignore them silently and return without | 978 // If there were any errors, ignore them silently and return without |
| 978 // adding breakpoints to target. | 979 // adding breakpoints to target. |
| 979 if (!target_function.HasCode()) { | 980 if (!target_function.HasCode()) { |
| 980 return; | 981 return; |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1558 } else { | 1559 } else { |
| 1559 cbpt->Disable(); | 1560 cbpt->Disable(); |
| 1560 } | 1561 } |
| 1561 } | 1562 } |
| 1562 cbpt = cbpt->next(); | 1563 cbpt = cbpt->next(); |
| 1563 } | 1564 } |
| 1564 } | 1565 } |
| 1565 | 1566 |
| 1566 | 1567 |
| 1567 void Debugger::OneTimeBreakAtEntry(const Function& target_function) { | 1568 void Debugger::OneTimeBreakAtEntry(const Function& target_function) { |
| 1568 InstrumentForStepping(target_function); | 1569 SetInternalBreakpoints(target_function); |
| 1569 if (target_function.HasImplicitClosureFunction()) { | 1570 if (target_function.HasImplicitClosureFunction()) { |
| 1570 const Function& closure_func = | 1571 const Function& closure_func = |
| 1571 Function::Handle(target_function.ImplicitClosureFunction()); | 1572 Function::Handle(target_function.ImplicitClosureFunction()); |
| 1572 InstrumentForStepping(closure_func); | 1573 SetInternalBreakpoints(closure_func); |
| 1573 } | 1574 } |
| 1574 } | 1575 } |
| 1575 | 1576 |
| 1576 | 1577 |
| 1577 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 1578 SourceBreakpoint* Debugger::SetBreakpointAtEntry( |
| 1578 const Function& target_function) { | 1579 const Function& target_function) { |
| 1579 ASSERT(!target_function.IsNull()); | 1580 ASSERT(!target_function.IsNull()); |
| 1580 const Script& script = Script::Handle(target_function.script()); | 1581 const Script& script = Script::Handle(target_function.script()); |
| 1581 return SetBreakpoint(script, target_function.token_pos()); | 1582 return SetBreakpoint(script, target_function.token_pos()); |
| 1582 } | 1583 } |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1878 } | 1879 } |
| 1879 const Class& cls = Class::Handle(func.Owner()); | 1880 const Class& cls = Class::Handle(func.Owner()); |
| 1880 const Library& lib = Library::Handle(cls.library()); | 1881 const Library& lib = Library::Handle(cls.library()); |
| 1881 return lib.IsDebuggable(); | 1882 return lib.IsDebuggable(); |
| 1882 } | 1883 } |
| 1883 | 1884 |
| 1884 | 1885 |
| 1885 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, | 1886 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, |
| 1886 SourceBreakpoint* bpt) { | 1887 SourceBreakpoint* bpt) { |
| 1887 resume_action_ = kContinue; | 1888 resume_action_ = kContinue; |
| 1889 stepping_fp_ = 0; |
| 1888 isolate_->set_single_step(false); | 1890 isolate_->set_single_step(false); |
| 1889 ASSERT(!IsPaused()); | 1891 ASSERT(!IsPaused()); |
| 1890 ASSERT(obj_cache_ == NULL); | 1892 ASSERT(obj_cache_ == NULL); |
| 1891 DebuggerEvent event(kBreakpointReached); | 1893 DebuggerEvent event(kBreakpointReached); |
| 1892 event.top_frame = top_frame; | 1894 event.top_frame = top_frame; |
| 1893 event.breakpoint = bpt; | 1895 event.breakpoint = bpt; |
| 1894 Pause(&event); | 1896 Pause(&event); |
| 1895 } | 1897 } |
| 1896 | 1898 |
| 1897 | 1899 |
| 1898 void Debugger::SingleStepCallback() { | 1900 static uword DebuggableCallerFP(DebuggerStackTrace* stack_trace) { |
| 1899 ASSERT(resume_action_ == kSingleStep); | 1901 for (intptr_t i = 1; i < stack_trace->Length(); i++) { |
| 1902 ActivationFrame* frame = stack_trace->FrameAt(i); |
| 1903 if (frame->IsDebuggable()) { |
| 1904 return frame->fp(); |
| 1905 } |
| 1906 } |
| 1907 return 0; |
| 1908 } |
| 1909 |
| 1910 |
| 1911 void Debugger::DebuggerStepCallback() { |
| 1900 ASSERT(isolate_->single_step()); | 1912 ASSERT(isolate_->single_step()); |
| 1901 // We can't get here unless the debugger event handler enabled | 1913 // We can't get here unless the debugger event handler enabled |
| 1902 // single stepping. | 1914 // single stepping. |
| 1903 ASSERT(event_handler_ != NULL); | 1915 ASSERT(event_handler_ != NULL); |
| 1904 // Don't pause recursively. | 1916 // Don't pause recursively. |
| 1905 if (IsPaused()) return; | 1917 if (IsPaused()) return; |
| 1906 | 1918 |
| 1907 // Check whether we are in a Dart function that the user is | 1919 // Check whether we are in a Dart function that the user is |
| 1908 // interested in. | 1920 // interested in. If we saved the frame pointer of a stack frame |
| 1921 // the user is interested in, we ignore the single step if we are |
| 1922 // in a callee of that frame. Note that we assume that the stack |
| 1923 // grows towards lower addresses. |
| 1909 ActivationFrame* frame = TopDartFrame(); | 1924 ActivationFrame* frame = TopDartFrame(); |
| 1910 ASSERT(frame != NULL); | 1925 ASSERT(frame != NULL); |
| 1911 const Function& func = frame->function(); | 1926 if ((stepping_fp_ != 0) && (stepping_fp_ > frame->fp())) { |
| 1912 if (!IsDebuggable(func)) { | 1927 return; |
| 1928 } |
| 1929 // If an "interesting" frame is set, we are either in that frame |
| 1930 // or the program has returned from that frame. Let the user set |
| 1931 // the "interesting" frame again next time we pause. |
| 1932 stepping_fp_ = 0; |
| 1933 |
| 1934 if (!frame->IsDebuggable()) { |
| 1913 return; | 1935 return; |
| 1914 } | 1936 } |
| 1915 if (frame->TokenPos() == Scanner::kNoSourcePos) { | 1937 if (frame->TokenPos() == Scanner::kNoSourcePos) { |
| 1916 return; | 1938 return; |
| 1917 } | 1939 } |
| 1940 |
| 1918 // Don't pause for a single step if there is a breakpoint set | 1941 // Don't pause for a single step if there is a breakpoint set |
| 1919 // at this location. | 1942 // at this location. |
| 1920 if (HasActiveBreakpoint(frame->pc())) { | 1943 if (HasActiveBreakpoint(frame->pc())) { |
| 1921 return; | 1944 return; |
| 1922 } | 1945 } |
| 1923 | 1946 |
| 1924 if (FLAG_verbose_debug) { | 1947 if (FLAG_verbose_debug) { |
| 1925 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", | 1948 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", |
| 1926 String::Handle(frame->SourceUrl()).ToCString(), | 1949 String::Handle(frame->SourceUrl()).ToCString(), |
| 1927 frame->LineNumber(), | 1950 frame->LineNumber(), |
| 1928 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 1951 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
| 1929 frame->TokenPos()); | 1952 frame->TokenPos()); |
| 1930 } | 1953 } |
| 1931 | 1954 |
| 1932 ASSERT(stack_trace_ == NULL); | 1955 ASSERT(stack_trace_ == NULL); |
| 1933 stack_trace_ = CollectStackTrace(); | 1956 stack_trace_ = CollectStackTrace(); |
| 1934 SignalPausedEvent(frame, NULL); | 1957 SignalPausedEvent(frame, NULL); |
| 1935 | 1958 |
| 1936 RemoveInternalBreakpoints(); | 1959 if (resume_action_ == kSingleStep) { |
| 1937 if (resume_action_ == kStepOver) { | 1960 isolate_->set_single_step(true); |
| 1938 InstrumentForStepping(func); | 1961 stepping_fp_ = 0; |
| 1962 } else if (resume_action_ == kStepOver) { |
| 1963 isolate_->set_single_step(true); |
| 1964 stepping_fp_ = frame->fp(); |
| 1939 } else if (resume_action_ == kStepOut) { | 1965 } else if (resume_action_ == kStepOut) { |
| 1940 if (stack_trace_->Length() > 1) { | 1966 isolate_->set_single_step(true); |
| 1941 ActivationFrame* caller_frame = stack_trace_->FrameAt(1); | 1967 stepping_fp_ = DebuggableCallerFP(stack_trace_); |
| 1942 InstrumentForStepping(caller_frame->function()); | |
| 1943 } | |
| 1944 } | 1968 } |
| 1945 stack_trace_ = NULL; | 1969 stack_trace_ = NULL; |
| 1946 } | 1970 } |
| 1947 | 1971 |
| 1948 | 1972 |
| 1949 void Debugger::SignalBpReached() { | 1973 void Debugger::SignalBpReached() { |
| 1950 // We ignore this breakpoint when the VM is executing code invoked | 1974 // We ignore this breakpoint when the VM is executing code invoked |
| 1951 // by the debugger to evaluate variables values, or when we see a nested | 1975 // by the debugger to evaluate variables values, or when we see a nested |
| 1952 // breakpoint or exception event. | 1976 // breakpoint or exception event. |
| 1953 if (ignore_breakpoints_ || IsPaused()) { | 1977 if (ignore_breakpoints_ || IsPaused() || (event_handler_ == NULL)) { |
| 1954 return; | 1978 return; |
| 1955 } | 1979 } |
| 1956 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1980 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 1957 ASSERT(stack_trace->Length() > 0); | 1981 ASSERT(stack_trace->Length() > 0); |
| 1958 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 1982 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
| 1959 ASSERT(top_frame != NULL); | 1983 ASSERT(top_frame != NULL); |
| 1960 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); | 1984 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); |
| 1961 ASSERT(bpt != NULL); | 1985 ASSERT(bpt != NULL); |
| 1962 | 1986 |
| 1963 bool report_bp = true; | |
| 1964 if (bpt->IsInternal() && !IsDebuggable(top_frame->function())) { | |
| 1965 report_bp = false; | |
| 1966 } | |
| 1967 if (FLAG_verbose_debug) { | 1987 if (FLAG_verbose_debug) { |
| 1968 OS::Print(">>> %s %s breakpoint at %s:%" Pd " " | 1988 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
| 1969 "(token %" Pd ") (address %#" Px ")\n", | 1989 "(token %" Pd ") (address %#" Px ")\n", |
| 1970 report_bp ? "hit" : "ignore", | |
| 1971 bpt->IsInternal() ? "internal" : "user", | 1990 bpt->IsInternal() ? "internal" : "user", |
| 1972 String::Handle(bpt->SourceUrl()).ToCString(), | 1991 String::Handle(bpt->SourceUrl()).ToCString(), |
| 1973 bpt->LineNumber(), | 1992 bpt->LineNumber(), |
| 1974 bpt->token_pos(), | 1993 bpt->token_pos(), |
| 1975 top_frame->pc()); | 1994 top_frame->pc()); |
| 1976 } | 1995 } |
| 1977 | 1996 |
| 1978 if (report_bp && (event_handler_ != NULL)) { | 1997 ASSERT(stack_trace_ == NULL); |
| 1979 ASSERT(stack_trace_ == NULL); | 1998 stack_trace_ = stack_trace; |
| 1980 stack_trace_ = stack_trace; | 1999 SignalPausedEvent(top_frame, bpt->src_bpt_); |
| 1981 SignalPausedEvent(top_frame, bpt->src_bpt_); | 2000 stack_trace_ = NULL; |
| 1982 stack_trace_ = NULL; | 2001 |
| 2002 if (resume_action_ == kSingleStep) { |
| 2003 isolate_->set_single_step(true); |
| 2004 stepping_fp_ = 0; |
| 2005 } else if (resume_action_ == kStepOver) { |
| 2006 isolate_->set_single_step(true); |
| 2007 stepping_fp_ = top_frame->fp(); |
| 2008 } else if (resume_action_ == kStepOut) { |
| 2009 isolate_->set_single_step(true); |
| 2010 stepping_fp_ = DebuggableCallerFP(stack_trace); |
| 1983 } | 2011 } |
| 1984 | 2012 if (bpt->IsInternal()) { |
| 1985 Function& func_to_instrument = Function::Handle(); | 2013 RemoveInternalBreakpoints(); |
| 1986 if ((resume_action_ == kStepOver) && | |
| 1987 (bpt->breakpoint_kind_ == PcDescriptors::kReturn)) { | |
| 1988 resume_action_ = kStepOut; | |
| 1989 } | |
| 1990 if (resume_action_ == kStepOver) { | |
| 1991 ASSERT(bpt->breakpoint_kind_ != PcDescriptors::kReturn); | |
| 1992 func_to_instrument = bpt->function(); | |
| 1993 } else if (resume_action_ == kStepOut) { | |
| 1994 if (stack_trace->Length() > 1) { | |
| 1995 ActivationFrame* caller_frame = stack_trace->FrameAt(1); | |
| 1996 func_to_instrument = caller_frame->function().raw(); | |
| 1997 } | |
| 1998 } else { | |
| 1999 ASSERT((resume_action_ == kContinue) || (resume_action_ == kSingleStep)); | |
| 2000 // Nothing to do here. Any potential instrumentation will be removed | |
| 2001 // below. Single stepping is handled by the single step callback. | |
| 2002 } | |
| 2003 | |
| 2004 if (func_to_instrument.IsNull() || | |
| 2005 (func_to_instrument.raw() != bpt->function())) { | |
| 2006 RemoveInternalBreakpoints(); // *bpt is now invalid. | |
| 2007 } | |
| 2008 if (!func_to_instrument.IsNull()) { | |
| 2009 InstrumentForStepping(func_to_instrument); | |
| 2010 } | 2014 } |
| 2011 } | 2015 } |
| 2012 | 2016 |
| 2013 | 2017 |
| 2014 void Debugger::Initialize(Isolate* isolate) { | 2018 void Debugger::Initialize(Isolate* isolate) { |
| 2015 if (initialized_) { | 2019 if (initialized_) { |
| 2016 return; | 2020 return; |
| 2017 } | 2021 } |
| 2018 isolate_ = isolate; | 2022 isolate_ = isolate; |
| 2019 // Use the isolate's control port as the isolate_id for debugging. | 2023 // Use the isolate's control port as the isolate_id for debugging. |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2258 } | 2262 } |
| 2259 | 2263 |
| 2260 | 2264 |
| 2261 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2265 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 2262 ASSERT(bpt->next() == NULL); | 2266 ASSERT(bpt->next() == NULL); |
| 2263 bpt->set_next(code_breakpoints_); | 2267 bpt->set_next(code_breakpoints_); |
| 2264 code_breakpoints_ = bpt; | 2268 code_breakpoints_ = bpt; |
| 2265 } | 2269 } |
| 2266 | 2270 |
| 2267 } // namespace dart | 2271 } // namespace dart |
| OLD | NEW |