| 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 "platform/address_sanitizer.h" | 9 #include "platform/address_sanitizer.h" |
| 10 | 10 |
| (...skipping 1886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1897 // the readability of the trace. | 1897 // the readability of the trace. |
| 1898 i++; | 1898 i++; |
| 1899 } else { | 1899 } else { |
| 1900 code = Code::RawCast(async_stack_trace.CodeAtFrame(i)); | 1900 code = Code::RawCast(async_stack_trace.CodeAtFrame(i)); |
| 1901 offset = Smi::RawCast(async_stack_trace.PcOffsetAtFrame(i)); | 1901 offset = Smi::RawCast(async_stack_trace.PcOffsetAtFrame(i)); |
| 1902 uword pc = code.PayloadStart() + offset.Value(); | 1902 uword pc = code.PayloadStart() + offset.Value(); |
| 1903 if (code.is_optimized()) { | 1903 if (code.is_optimized()) { |
| 1904 for (InlinedFunctionsIterator it(code, pc); !it.Done(); | 1904 for (InlinedFunctionsIterator it(code, pc); !it.Done(); |
| 1905 it.Advance()) { | 1905 it.Advance()) { |
| 1906 inlined_code = it.code(); | 1906 inlined_code = it.code(); |
| 1907 stack_trace->AddAsyncCausalFrame(pc, inlined_code); | 1907 stack_trace->AddAsyncCausalFrame(it.pc(), inlined_code); |
| 1908 } | 1908 } |
| 1909 } else { | 1909 } else { |
| 1910 stack_trace->AddAsyncCausalFrame(pc, code); | 1910 stack_trace->AddAsyncCausalFrame(pc, code); |
| 1911 } | 1911 } |
| 1912 } | 1912 } |
| 1913 } | 1913 } |
| 1914 // Follow the link. | 1914 // Follow the link. |
| 1915 async_stack_trace = async_stack_trace.async_link(); | 1915 async_stack_trace = async_stack_trace.async_link(); |
| 1916 } | 1916 } |
| 1917 | 1917 |
| 1918 return stack_trace; | 1918 return stack_trace; |
| 1919 } | 1919 } |
| 1920 | 1920 |
| 1921 | 1921 |
| 1922 DebuggerStackTrace* Debugger::CollectAwaiterReturnStackTrace() { | 1922 DebuggerStackTrace* Debugger::CollectAwaiterReturnStackTrace() { |
| 1923 if (!FLAG_causal_async_stacks) { | 1923 if (!FLAG_causal_async_stacks) { |
| 1924 return NULL; | 1924 return NULL; |
| 1925 } | 1925 } |
| 1926 // Causal async stacks are not supported in the AOT runtime. |
| 1927 ASSERT(!FLAG_precompiled_runtime); |
| 1928 |
| 1926 Thread* thread = Thread::Current(); | 1929 Thread* thread = Thread::Current(); |
| 1927 Zone* zone = thread->zone(); | 1930 Zone* zone = thread->zone(); |
| 1928 Isolate* isolate = thread->isolate(); | 1931 Isolate* isolate = thread->isolate(); |
| 1929 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 1932 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 1930 | 1933 |
| 1931 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); | 1934 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); |
| 1932 | 1935 |
| 1933 Code& code = Code::Handle(zone); | 1936 Code& code = Code::Handle(zone); |
| 1934 Function& function = Function::Handle(zone); | 1937 Function& function = Function::Handle(zone); |
| 1935 Code& inlined_code = Code::Handle(zone); | 1938 Code& inlined_code = Code::Handle(zone); |
| 1936 Closure& async_activation = Closure::Handle(zone); | 1939 Closure& async_activation = Closure::Handle(zone); |
| 1937 Array& deopt_frame = Array::Handle(zone); | 1940 Array& deopt_frame = Array::Handle(zone); |
| 1938 | 1941 |
| 1939 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; | 1942 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
| 1940 frame = iterator.NextFrame()) { | 1943 frame = iterator.NextFrame()) { |
| 1941 ASSERT(frame->IsValid()); | 1944 ASSERT(frame->IsValid()); |
| 1945 if (FLAG_trace_debugger_stacktrace) { |
| 1946 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", |
| 1947 frame->ToCString()); |
| 1948 } |
| 1942 if (frame->IsDartFrame()) { | 1949 if (frame->IsDartFrame()) { |
| 1943 code = frame->LookupDartCode(); | 1950 code = frame->LookupDartCode(); |
| 1944 function = code.function(); | 1951 if (code.is_optimized()) { |
| 1945 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { | 1952 deopt_frame = DeoptimizeToArray(thread, frame, code); |
| 1946 ActivationFrame* activation = CollectDartFrame( | 1953 bool found_async_awaiter = false; |
| 1947 isolate, frame->pc(), frame, code, Object::null_array(), 0, | 1954 for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); |
| 1948 ActivationFrame::kAsyncActivation); | 1955 it.Advance()) { |
| 1949 ASSERT(activation != NULL); | 1956 inlined_code = it.code(); |
| 1950 stack_trace->AddActivation(activation); | 1957 function = inlined_code.function(); |
| 1951 // Grab the awaiter. | 1958 if (FLAG_trace_debugger_stacktrace) { |
| 1952 async_activation ^= activation->GetAsyncAwaiter(); | 1959 ASSERT(!function.IsNull()); |
| 1953 break; | 1960 OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n", |
| 1961 function.ToFullyQualifiedCString()); |
| 1962 } |
| 1963 intptr_t deopt_frame_offset = it.GetDeoptFpOffset(); |
| 1964 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { |
| 1965 ActivationFrame* activation = CollectDartFrame( |
| 1966 isolate, it.pc(), frame, inlined_code, deopt_frame, |
| 1967 deopt_frame_offset, ActivationFrame::kAsyncActivation); |
| 1968 ASSERT(activation != NULL); |
| 1969 stack_trace->AddActivation(activation); |
| 1970 // Grab the awaiter. |
| 1971 async_activation ^= activation->GetAsyncAwaiter(); |
| 1972 found_async_awaiter = true; |
| 1973 break; |
| 1974 } else { |
| 1975 stack_trace->AddActivation( |
| 1976 CollectDartFrame(isolate, it.pc(), frame, inlined_code, |
| 1977 deopt_frame, deopt_frame_offset)); |
| 1978 } |
| 1979 } |
| 1980 // Break out of outer loop. |
| 1981 if (found_async_awaiter) { |
| 1982 break; |
| 1983 } |
| 1954 } else { | 1984 } else { |
| 1955 AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code, | 1985 function = code.function(); |
| 1956 &inlined_code, &deopt_frame); | 1986 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { |
| 1987 ActivationFrame* activation = CollectDartFrame( |
| 1988 isolate, frame->pc(), frame, code, Object::null_array(), 0, |
| 1989 ActivationFrame::kAsyncActivation); |
| 1990 ASSERT(activation != NULL); |
| 1991 stack_trace->AddActivation(activation); |
| 1992 // Grab the awaiter. |
| 1993 async_activation ^= activation->GetAsyncAwaiter(); |
| 1994 break; |
| 1995 } else { |
| 1996 stack_trace->AddActivation(CollectDartFrame( |
| 1997 isolate, frame->pc(), frame, code, Object::null_array(), 0)); |
| 1998 } |
| 1957 } | 1999 } |
| 1958 } | 2000 } |
| 1959 } | 2001 } |
| 1960 | 2002 |
| 1961 // Return NULL to indicate that there is no useful information in this stack | 2003 // Return NULL to indicate that there is no useful information in this stack |
| 1962 // trace because we never found an awaiter. | 2004 // trace because we never found an awaiter. |
| 1963 if (async_activation.IsNull()) { | 2005 if (async_activation.IsNull()) { |
| 1964 return NULL; | 2006 return NULL; |
| 1965 } | 2007 } |
| 1966 | 2008 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2069 (pause_info == kPauseOnAllExceptions)); | 2111 (pause_info == kPauseOnAllExceptions)); |
| 2070 exc_pause_info_ = pause_info; | 2112 exc_pause_info_ = pause_info; |
| 2071 } | 2113 } |
| 2072 | 2114 |
| 2073 | 2115 |
| 2074 Dart_ExceptionPauseInfo Debugger::GetExceptionPauseInfo() const { | 2116 Dart_ExceptionPauseInfo Debugger::GetExceptionPauseInfo() const { |
| 2075 return exc_pause_info_; | 2117 return exc_pause_info_; |
| 2076 } | 2118 } |
| 2077 | 2119 |
| 2078 | 2120 |
| 2079 bool Debugger::ShouldPauseOnAsyncException(DebuggerStackTrace* stack_trace, | |
| 2080 const Instance& exc) { | |
| 2081 if (exc_pause_info_ == kNoPauseOnExceptions) { | |
| 2082 return false; | |
| 2083 } | |
| 2084 if (exc_pause_info_ == kPauseOnAllExceptions) { | |
| 2085 return true; | |
| 2086 } | |
| 2087 ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions); | |
| 2088 for (intptr_t i = 0; i < stack_trace->Length(); i++) { | |
| 2089 ActivationFrame* frame = stack_trace->FrameAt(i); | |
| 2090 if (frame->HandlesException(exc)) { | |
| 2091 if (FLAG_verbose_debug) { | |
| 2092 OS::PrintErr("%s is caught by frame %s\n", exc.ToCString(), | |
| 2093 frame->ToCString()); | |
| 2094 } | |
| 2095 return false; | |
| 2096 } | |
| 2097 } | |
| 2098 return true; | |
| 2099 } | |
| 2100 | |
| 2101 | |
| 2102 bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace, | 2121 bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace, |
| 2103 const Instance& exception) { | 2122 const Instance& exception) { |
| 2104 if (exc_pause_info_ == kNoPauseOnExceptions) { | 2123 if (exc_pause_info_ == kNoPauseOnExceptions) { |
| 2105 return false; | 2124 return false; |
| 2106 } | 2125 } |
| 2107 if (exc_pause_info_ == kPauseOnAllExceptions) { | 2126 if (exc_pause_info_ == kPauseOnAllExceptions) { |
| 2108 return true; | 2127 return true; |
| 2109 } | 2128 } |
| 2110 ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions); | 2129 ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions); |
| 2111 ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception); | 2130 ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception); |
| 2112 if (handler_frame == NULL) { | 2131 if (handler_frame == NULL) { |
| 2113 // Did not find an exception handler that catches this exception. | 2132 // Did not find an exception handler that catches this exception. |
| 2114 // Note that this check is not precise, since we can't check | 2133 // Note that this check is not precise, since we can't check |
| 2115 // uninstantiated types, i.e. types containing type parameters. | 2134 // uninstantiated types, i.e. types containing type parameters. |
| 2116 // Thus, we may report an exception as unhandled when in fact | 2135 // Thus, we may report an exception as unhandled when in fact |
| 2117 // it will be caught once we unwind the stack. | 2136 // it will be caught once we unwind the stack. |
| 2118 return true; | 2137 return true; |
| 2119 } | 2138 } |
| 2120 return false; | 2139 return false; |
| 2121 } | 2140 } |
| 2122 | 2141 |
| 2123 | 2142 |
| 2124 void Debugger::PauseException(const Instance& exc) { | 2143 void Debugger::PauseException(const Instance& exc) { |
| 2144 if (FLAG_stress_async_stacks) { |
| 2145 CollectAwaiterReturnStackTrace(); |
| 2146 } |
| 2125 // We ignore this exception event when the VM is executing code invoked | 2147 // We ignore this exception event when the VM is executing code invoked |
| 2126 // by the debugger to evaluate variables values, when we see a nested | 2148 // by the debugger to evaluate variables values, when we see a nested |
| 2127 // breakpoint or exception event, or if the debugger is not | 2149 // breakpoint or exception event, or if the debugger is not |
| 2128 // interested in exception events. | 2150 // interested in exception events. |
| 2129 if (ignore_breakpoints_ || IsPaused() || | 2151 if (ignore_breakpoints_ || IsPaused() || |
| 2130 (exc_pause_info_ == kNoPauseOnExceptions)) { | 2152 (exc_pause_info_ == kNoPauseOnExceptions)) { |
| 2131 return; | 2153 return; |
| 2132 } | 2154 } |
| 2133 DebuggerStackTrace* awaiter_stack_trace = CollectAwaiterReturnStackTrace(); | 2155 DebuggerStackTrace* awaiter_stack_trace = CollectAwaiterReturnStackTrace(); |
| 2134 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2156 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 2135 if (awaiter_stack_trace != NULL) { | 2157 if (awaiter_stack_trace != NULL) { |
| 2136 if (!ShouldPauseOnAsyncException(awaiter_stack_trace, exc)) { | 2158 if (!ShouldPauseOnException(awaiter_stack_trace, exc)) { |
| 2137 return; | 2159 return; |
| 2138 } | 2160 } |
| 2139 } else { | 2161 } else { |
| 2140 if (!ShouldPauseOnException(stack_trace, exc)) { | 2162 if (!ShouldPauseOnException(stack_trace, exc)) { |
| 2141 return; | 2163 return; |
| 2142 } | 2164 } |
| 2143 } | 2165 } |
| 2144 ServiceEvent event(isolate_, ServiceEvent::kPauseException); | 2166 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
| 2145 event.set_exception(&exc); | 2167 event.set_exception(&exc); |
| 2146 if (stack_trace->Length() > 0) { | 2168 if (stack_trace->Length() > 0) { |
| (...skipping 1964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4111 | 4133 |
| 4112 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 4134 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 4113 ASSERT(bpt->next() == NULL); | 4135 ASSERT(bpt->next() == NULL); |
| 4114 bpt->set_next(code_breakpoints_); | 4136 bpt->set_next(code_breakpoints_); |
| 4115 code_breakpoints_ = bpt; | 4137 code_breakpoints_ = bpt; |
| 4116 } | 4138 } |
| 4117 | 4139 |
| 4118 #endif // !PRODUCT | 4140 #endif // !PRODUCT |
| 4119 | 4141 |
| 4120 } // namespace dart | 4142 } // namespace dart |
| OLD | NEW |