Chromium Code Reviews| 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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 181 void Debugger::SignalIsolateEvent(EventType type) { | 181 void Debugger::SignalIsolateEvent(EventType type) { |
| 182 if (event_handler_ != NULL) { | 182 if (event_handler_ != NULL) { |
| 183 Debugger* debugger = Isolate::Current()->debugger(); | 183 Debugger* debugger = Isolate::Current()->debugger(); |
| 184 ASSERT(debugger != NULL); | 184 ASSERT(debugger != NULL); |
| 185 DebuggerEvent event(type); | 185 DebuggerEvent event(type); |
| 186 event.isolate_id = debugger->GetIsolateId(); | 186 event.isolate_id = debugger->GetIsolateId(); |
| 187 ASSERT(event.isolate_id != ILLEGAL_ISOLATE_ID); | 187 ASSERT(event.isolate_id != ILLEGAL_ISOLATE_ID); |
| 188 if (type == kIsolateInterrupted) { | 188 if (type == kIsolateInterrupted) { |
| 189 DebuggerStackTrace* stack_trace = debugger->CollectStackTrace(); | 189 DebuggerStackTrace* stack_trace = debugger->CollectStackTrace(); |
| 190 ASSERT(stack_trace->Length() > 0); | 190 ASSERT(stack_trace->Length() > 0); |
| 191 ASSERT(debugger->stack_trace_ == NULL); | 191 ASSERT(debugger->stack_trace_ == NULL); |
|
turnidge
2013/12/18 21:27:58
in_event_handler_ was missing here before. I thin
| |
| 192 ASSERT(debugger->obj_cache_ == NULL); | |
| 193 debugger->obj_cache_ = new RemoteObjectCache(64); | |
| 194 debugger->stack_trace_ = stack_trace; | 192 debugger->stack_trace_ = stack_trace; |
| 195 (*event_handler_)(&event); | 193 debugger->Pause(&event); |
| 196 debugger->stack_trace_ = NULL; | 194 debugger->stack_trace_ = NULL; |
| 197 debugger->obj_cache_ = NULL; // Remote object cache is zone allocated. | |
| 198 // TODO(asiva): Need some work here to be able to single step after | 195 // TODO(asiva): Need some work here to be able to single step after |
| 199 // an interrupt. | 196 // an interrupt. |
| 200 } else { | 197 } else { |
| 201 (*event_handler_)(&event); | 198 (*event_handler_)(&event); |
| 202 } | 199 } |
| 203 } | 200 } |
| 204 } | 201 } |
| 205 | 202 |
| 206 | 203 |
| 207 const char* Debugger::QualifiedFunctionName(const Function& func) { | 204 const char* Debugger::QualifiedFunctionName(const Function& func) { |
| (...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 848 ASSERT(IsValidId(obj_id)); | 845 ASSERT(IsValidId(obj_id)); |
| 849 return objs_->At(obj_id); | 846 return objs_->At(obj_id); |
| 850 } | 847 } |
| 851 | 848 |
| 852 | 849 |
| 853 Debugger::Debugger() | 850 Debugger::Debugger() |
| 854 : isolate_(NULL), | 851 : isolate_(NULL), |
| 855 isolate_id_(ILLEGAL_ISOLATE_ID), | 852 isolate_id_(ILLEGAL_ISOLATE_ID), |
| 856 initialized_(false), | 853 initialized_(false), |
| 857 next_id_(1), | 854 next_id_(1), |
| 858 stack_trace_(NULL), | |
| 859 obj_cache_(NULL), | |
| 860 src_breakpoints_(NULL), | 855 src_breakpoints_(NULL), |
| 861 code_breakpoints_(NULL), | 856 code_breakpoints_(NULL), |
| 862 resume_action_(kContinue), | 857 resume_action_(kContinue), |
| 863 ignore_breakpoints_(false), | 858 ignore_breakpoints_(false), |
| 864 in_event_notification_(false), | 859 pause_event_(NULL), |
| 860 obj_cache_(NULL), | |
| 861 stack_trace_(NULL), | |
| 865 exc_pause_info_(kNoPauseOnExceptions) { | 862 exc_pause_info_(kNoPauseOnExceptions) { |
| 866 } | 863 } |
| 867 | 864 |
| 868 | 865 |
| 869 Debugger::~Debugger() { | 866 Debugger::~Debugger() { |
| 870 isolate_id_ = ILLEGAL_ISOLATE_ID; | 867 isolate_id_ = ILLEGAL_ISOLATE_ID; |
| 871 ASSERT(!in_event_notification_); | 868 ASSERT(!IsPaused()); |
| 872 ASSERT(src_breakpoints_ == NULL); | 869 ASSERT(src_breakpoints_ == NULL); |
| 873 ASSERT(code_breakpoints_ == NULL); | 870 ASSERT(code_breakpoints_ == NULL); |
| 874 ASSERT(stack_trace_ == NULL); | 871 ASSERT(stack_trace_ == NULL); |
| 875 ASSERT(obj_cache_ == NULL); | 872 ASSERT(obj_cache_ == NULL); |
| 876 } | 873 } |
| 877 | 874 |
| 878 | 875 |
| 879 void Debugger::Shutdown() { | 876 void Debugger::Shutdown() { |
| 880 while (src_breakpoints_ != NULL) { | 877 while (src_breakpoints_ != NULL) { |
| 881 SourceBreakpoint* bpt = src_breakpoints_; | 878 SourceBreakpoint* bpt = src_breakpoints_; |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1263 return false; | 1260 return false; |
| 1264 } | 1261 } |
| 1265 | 1262 |
| 1266 | 1263 |
| 1267 void Debugger::SignalExceptionThrown(const Instance& exc) { | 1264 void Debugger::SignalExceptionThrown(const Instance& exc) { |
| 1268 // We ignore this exception event when the VM is executing code invoked | 1265 // We ignore this exception event when the VM is executing code invoked |
| 1269 // by the debugger to evaluate variables values, when we see a nested | 1266 // by the debugger to evaluate variables values, when we see a nested |
| 1270 // breakpoint or exception event, or if the debugger is not | 1267 // breakpoint or exception event, or if the debugger is not |
| 1271 // interested in exception events. | 1268 // interested in exception events. |
| 1272 if (ignore_breakpoints_ || | 1269 if (ignore_breakpoints_ || |
| 1273 in_event_notification_ || | 1270 IsPaused() || |
| 1274 (event_handler_ == NULL) || | 1271 (event_handler_ == NULL) || |
| 1275 (exc_pause_info_ == kNoPauseOnExceptions)) { | 1272 (exc_pause_info_ == kNoPauseOnExceptions)) { |
| 1276 return; | 1273 return; |
| 1277 } | 1274 } |
| 1278 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1275 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 1279 if (!ShouldPauseOnException(stack_trace, exc)) { | 1276 if (!ShouldPauseOnException(stack_trace, exc)) { |
| 1280 return; | 1277 return; |
| 1281 } | 1278 } |
| 1279 DebuggerEvent event(kExceptionThrown); | |
| 1280 event.exception = &exc; | |
| 1282 ASSERT(stack_trace_ == NULL); | 1281 ASSERT(stack_trace_ == NULL); |
| 1283 stack_trace_ = stack_trace; | 1282 stack_trace_ = stack_trace; |
| 1284 ASSERT(obj_cache_ == NULL); | 1283 Pause(&event); |
| 1285 in_event_notification_ = true; | |
| 1286 obj_cache_ = new RemoteObjectCache(64); | |
| 1287 DebuggerEvent event(kExceptionThrown); | |
| 1288 event.exception = &exc; | |
| 1289 (*event_handler_)(&event); | |
| 1290 in_event_notification_ = false; | |
| 1291 stack_trace_ = NULL; | 1284 stack_trace_ = NULL; |
| 1292 obj_cache_ = NULL; // Remote object cache is zone allocated. | |
| 1293 } | 1285 } |
| 1294 | 1286 |
| 1295 | 1287 |
| 1296 // Given a function and a token position range, return the best fit | 1288 // Given a function and a token position range, return the best fit |
| 1297 // token position to set a breakpoint. | 1289 // token position to set a breakpoint. |
| 1298 // If multiple possible breakpoint positions are within the given range, | 1290 // If multiple possible breakpoint positions are within the given range, |
| 1299 // the one with the lowest machine code address is picked. | 1291 // the one with the lowest machine code address is picked. |
| 1300 // If no possible breakpoint location exists in the given range, the closest | 1292 // If no possible breakpoint location exists in the given range, the closest |
| 1301 // token position after the range is returned. | 1293 // token position after the range is returned. |
| 1302 intptr_t Debugger::ResolveBreakpointPos(const Function& func, | 1294 intptr_t Debugger::ResolveBreakpointPos(const Function& func, |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1752 cbpt = cbpt->next(); | 1744 cbpt = cbpt->next(); |
| 1753 } | 1745 } |
| 1754 } | 1746 } |
| 1755 | 1747 |
| 1756 | 1748 |
| 1757 void Debugger::SetEventHandler(EventHandler* handler) { | 1749 void Debugger::SetEventHandler(EventHandler* handler) { |
| 1758 event_handler_ = handler; | 1750 event_handler_ = handler; |
| 1759 } | 1751 } |
| 1760 | 1752 |
| 1761 | 1753 |
| 1754 void Debugger::Pause(DebuggerEvent* event) { | |
| 1755 ASSERT(!IsPaused()); // No recursive pausing. | |
| 1756 ASSERT(obj_cache_ == NULL); | |
| 1757 | |
| 1758 pause_event_ = event; | |
| 1759 obj_cache_ = new RemoteObjectCache(64); | |
| 1760 | |
| 1761 (*event_handler_)(event); | |
| 1762 | |
| 1763 pause_event_ = NULL; | |
| 1764 obj_cache_ = NULL; // Zone allocated | |
| 1765 } | |
| 1766 | |
| 1767 | |
| 1762 bool Debugger::IsDebuggable(const Function& func) { | 1768 bool Debugger::IsDebuggable(const Function& func) { |
| 1763 RawFunction::Kind fkind = func.kind(); | 1769 RawFunction::Kind fkind = func.kind(); |
| 1764 if ((fkind == RawFunction::kImplicitGetter) || | 1770 if ((fkind == RawFunction::kImplicitGetter) || |
| 1765 (fkind == RawFunction::kImplicitSetter) || | 1771 (fkind == RawFunction::kImplicitSetter) || |
| 1766 (fkind == RawFunction::kImplicitStaticFinalGetter) || | 1772 (fkind == RawFunction::kImplicitStaticFinalGetter) || |
| 1767 (fkind == RawFunction::kStaticInitializer) || | 1773 (fkind == RawFunction::kStaticInitializer) || |
| 1768 (fkind == RawFunction::kMethodExtractor) || | 1774 (fkind == RawFunction::kMethodExtractor) || |
| 1769 (fkind == RawFunction::kNoSuchMethodDispatcher) || | 1775 (fkind == RawFunction::kNoSuchMethodDispatcher) || |
| 1770 (fkind == RawFunction::kInvokeFieldDispatcher)) { | 1776 (fkind == RawFunction::kInvokeFieldDispatcher)) { |
| 1771 return false; | 1777 return false; |
| 1772 } | 1778 } |
| 1773 const Class& cls = Class::Handle(func.Owner()); | 1779 const Class& cls = Class::Handle(func.Owner()); |
| 1774 const Library& lib = Library::Handle(cls.library()); | 1780 const Library& lib = Library::Handle(cls.library()); |
| 1775 return lib.IsDebuggable(); | 1781 return lib.IsDebuggable(); |
| 1776 } | 1782 } |
| 1777 | 1783 |
| 1778 | 1784 |
| 1779 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, | 1785 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, |
| 1780 SourceBreakpoint* bpt) { | 1786 SourceBreakpoint* bpt) { |
| 1781 resume_action_ = kContinue; | 1787 resume_action_ = kContinue; |
| 1782 isolate_->set_single_step(false); | 1788 isolate_->set_single_step(false); |
| 1783 ASSERT(!in_event_notification_); | 1789 ASSERT(!IsPaused()); |
| 1784 ASSERT(obj_cache_ == NULL); | 1790 ASSERT(obj_cache_ == NULL); |
| 1785 in_event_notification_ = true; | |
| 1786 obj_cache_ = new RemoteObjectCache(64); | |
| 1787 DebuggerEvent event(kBreakpointReached); | 1791 DebuggerEvent event(kBreakpointReached); |
| 1788 event.top_frame = top_frame; | 1792 event.top_frame = top_frame; |
| 1789 event.breakpoint = bpt; | 1793 event.breakpoint = bpt; |
| 1790 (*event_handler_)(&event); | 1794 Pause(&event); |
| 1791 in_event_notification_ = false; | |
| 1792 obj_cache_ = NULL; // Remote object cache is zone allocated. | |
| 1793 } | 1795 } |
| 1794 | 1796 |
| 1795 | 1797 |
| 1796 void Debugger::SingleStepCallback() { | 1798 void Debugger::SingleStepCallback() { |
| 1797 ASSERT(resume_action_ == kSingleStep); | 1799 ASSERT(resume_action_ == kSingleStep); |
| 1798 ASSERT(isolate_->single_step()); | 1800 ASSERT(isolate_->single_step()); |
| 1799 // We can't get here unless the debugger event handler enabled | 1801 // We can't get here unless the debugger event handler enabled |
| 1800 // single stepping. | 1802 // single stepping. |
| 1801 ASSERT(event_handler_ != NULL); | 1803 ASSERT(event_handler_ != NULL); |
| 1802 // Don't pause recursively. | 1804 // Don't pause recursively. |
| 1803 if (in_event_notification_) return; | 1805 if (IsPaused()) return; |
| 1804 | 1806 |
| 1805 // Check whether we are in a Dart function that the user is | 1807 // Check whether we are in a Dart function that the user is |
| 1806 // interested in. | 1808 // interested in. |
| 1807 ActivationFrame* frame = TopDartFrame(); | 1809 ActivationFrame* frame = TopDartFrame(); |
| 1808 ASSERT(frame != NULL); | 1810 ASSERT(frame != NULL); |
| 1809 const Function& func = frame->function(); | 1811 const Function& func = frame->function(); |
| 1810 if (!IsDebuggable(func)) { | 1812 if (!IsDebuggable(func)) { |
| 1811 return; | 1813 return; |
| 1812 } | 1814 } |
| 1813 if (frame->TokenPos() == Scanner::kDummyTokenIndex) { | 1815 if (frame->TokenPos() == Scanner::kDummyTokenIndex) { |
| 1814 return; | 1816 return; |
| 1815 } | 1817 } |
| 1816 | 1818 |
| 1817 if (FLAG_verbose_debug) { | 1819 if (FLAG_verbose_debug) { |
| 1818 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", | 1820 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", |
| 1819 String::Handle(frame->SourceUrl()).ToCString(), | 1821 String::Handle(frame->SourceUrl()).ToCString(), |
| 1820 frame->LineNumber(), | 1822 frame->LineNumber(), |
| 1821 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 1823 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
| 1822 frame->TokenPos()); | 1824 frame->TokenPos()); |
| 1823 } | 1825 } |
| 1824 | 1826 |
| 1827 ASSERT(stack_trace_ == NULL); | |
| 1825 stack_trace_ = CollectStackTrace(); | 1828 stack_trace_ = CollectStackTrace(); |
| 1826 SignalPausedEvent(frame, NULL); | 1829 SignalPausedEvent(frame, NULL); |
| 1827 | 1830 |
| 1828 RemoveInternalBreakpoints(); | 1831 RemoveInternalBreakpoints(); |
| 1829 if (resume_action_ == kStepOver) { | 1832 if (resume_action_ == kStepOver) { |
| 1830 InstrumentForStepping(func); | 1833 InstrumentForStepping(func); |
| 1831 } else if (resume_action_ == kStepOut) { | 1834 } else if (resume_action_ == kStepOut) { |
| 1832 if (stack_trace_->Length() > 1) { | 1835 if (stack_trace_->Length() > 1) { |
| 1833 ActivationFrame* caller_frame = stack_trace_->FrameAt(1); | 1836 ActivationFrame* caller_frame = stack_trace_->FrameAt(1); |
| 1834 InstrumentForStepping(caller_frame->function()); | 1837 InstrumentForStepping(caller_frame->function()); |
| 1835 } | 1838 } |
| 1836 } | 1839 } |
| 1837 stack_trace_ = NULL; | 1840 stack_trace_ = NULL; |
| 1838 } | 1841 } |
| 1839 | 1842 |
| 1840 | 1843 |
| 1841 void Debugger::SignalBpReached() { | 1844 void Debugger::SignalBpReached() { |
| 1842 // We ignore this breakpoint when the VM is executing code invoked | 1845 // We ignore this breakpoint when the VM is executing code invoked |
| 1843 // by the debugger to evaluate variables values, or when we see a nested | 1846 // by the debugger to evaluate variables values, or when we see a nested |
| 1844 // breakpoint or exception event. | 1847 // breakpoint or exception event. |
| 1845 if (ignore_breakpoints_ || in_event_notification_) { | 1848 if (ignore_breakpoints_ || IsPaused()) { |
| 1846 return; | 1849 return; |
| 1847 } | 1850 } |
| 1848 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1851 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 1849 ASSERT(stack_trace->Length() > 0); | 1852 ASSERT(stack_trace->Length() > 0); |
| 1850 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 1853 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
| 1851 ASSERT(top_frame != NULL); | 1854 ASSERT(top_frame != NULL); |
| 1852 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); | 1855 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); |
| 1853 ASSERT(bpt != NULL); | 1856 ASSERT(bpt != NULL); |
| 1854 | 1857 |
| 1855 bool report_bp = true; | 1858 bool report_bp = true; |
| 1856 if (bpt->IsInternal() && !IsDebuggable(top_frame->function())) { | 1859 if (bpt->IsInternal() && !IsDebuggable(top_frame->function())) { |
| 1857 report_bp = false; | 1860 report_bp = false; |
| 1858 } | 1861 } |
| 1859 if (FLAG_verbose_debug) { | 1862 if (FLAG_verbose_debug) { |
| 1860 OS::Print(">>> %s %s breakpoint at %s:%" Pd " " | 1863 OS::Print(">>> %s %s breakpoint at %s:%" Pd " " |
| 1861 "(token %" Pd ") (address %#" Px ")\n", | 1864 "(token %" Pd ") (address %#" Px ")\n", |
| 1862 report_bp ? "hit" : "ignore", | 1865 report_bp ? "hit" : "ignore", |
| 1863 bpt->IsInternal() ? "internal" : "user", | 1866 bpt->IsInternal() ? "internal" : "user", |
| 1864 String::Handle(bpt->SourceUrl()).ToCString(), | 1867 String::Handle(bpt->SourceUrl()).ToCString(), |
| 1865 bpt->LineNumber(), | 1868 bpt->LineNumber(), |
| 1866 bpt->token_pos(), | 1869 bpt->token_pos(), |
| 1867 top_frame->pc()); | 1870 top_frame->pc()); |
| 1868 } | 1871 } |
| 1869 | 1872 |
| 1870 if (report_bp && (event_handler_ != NULL)) { | 1873 if (report_bp && (event_handler_ != NULL)) { |
| 1874 ASSERT(stack_trace_ == NULL); | |
| 1871 stack_trace_ = stack_trace; | 1875 stack_trace_ = stack_trace; |
| 1872 SignalPausedEvent(top_frame, bpt->src_bpt_); | 1876 SignalPausedEvent(top_frame, bpt->src_bpt_); |
| 1873 stack_trace_ = NULL; | 1877 stack_trace_ = NULL; |
| 1874 } | 1878 } |
| 1875 | 1879 |
| 1876 Function& func_to_instrument = Function::Handle(); | 1880 Function& func_to_instrument = Function::Handle(); |
| 1877 if (resume_action_ == kStepOver) { | 1881 if (resume_action_ == kStepOver) { |
| 1878 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { | 1882 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { |
| 1879 // Step over return is converted into a single step so we break at | 1883 // Step over return is converted into a single step so we break at |
| 1880 // the caller. | 1884 // the caller. |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2134 } | 2138 } |
| 2135 | 2139 |
| 2136 | 2140 |
| 2137 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2141 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 2138 ASSERT(bpt->next() == NULL); | 2142 ASSERT(bpt->next() == NULL); |
| 2139 bpt->set_next(code_breakpoints_); | 2143 bpt->set_next(code_breakpoints_); |
| 2140 code_breakpoints_ = bpt; | 2144 code_breakpoints_ = bpt; |
| 2141 } | 2145 } |
| 2142 | 2146 |
| 2143 } // namespace dart | 2147 } // namespace dart |
| OLD | NEW |