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 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 context_level_(-1), | 256 context_level_(-1), |
| 257 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), | 257 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), |
| 258 deopt_frame_offset_(deopt_frame_offset), | 258 deopt_frame_offset_(deopt_frame_offset), |
| 259 vars_initialized_(false), | 259 vars_initialized_(false), |
| 260 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | 260 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 261 desc_indices_(8), | 261 desc_indices_(8), |
| 262 pc_desc_(PcDescriptors::ZoneHandle()) { | 262 pc_desc_(PcDescriptors::ZoneHandle()) { |
| 263 } | 263 } |
| 264 | 264 |
| 265 | 265 |
| 266 void DebuggerEvent::UpdateTimestamp() { | 266 bool Debugger::NeedsIsolateEvents() { |
| 267 timestamp_ = OS::GetCurrentTimeMillis(); | 267 return ((isolate_ != Dart::vm_isolate()) && |
| 268 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && | |
| 269 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); | |
| 268 } | 270 } |
| 269 | 271 |
| 270 | 272 |
| 271 bool Debugger::HasAnyEventHandler() { | 273 bool Debugger::NeedsDebugEvents() { |
| 272 return ((event_handler_ != NULL) || | 274 ASSERT(isolate_ != Dart::vm_isolate() && |
| 273 Service::isolate_stream.enabled() || | 275 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); |
| 276 return (FLAG_warn_on_pause_with_no_debugger || | |
| 277 (event_handler_ != NULL) || | |
| 274 Service::debug_stream.enabled()); | 278 Service::debug_stream.enabled()); |
| 275 } | 279 } |
| 276 | 280 |
| 277 | 281 |
| 278 bool Debugger::HasDebugEventHandler() { | 282 void Debugger::InvokeEventHandler(ServiceEvent* event) { |
| 279 return ((event_handler_ != NULL) || | 283 ASSERT(!event->IsPause()); // For pause events, call Pause instead. |
| 280 Service::debug_stream.enabled()); | 284 Service::HandleEvent(event); |
| 281 } | |
| 282 | 285 |
| 283 | 286 // Call the embedder's event handler, if it exists. |
| 284 static bool ServiceNeedsDebuggerEvent(DebuggerEvent::EventType type) { | 287 if (event_handler_ != NULL) { |
| 285 switch (type) { | 288 TransitionVMToNative transition(Thread::Current()); |
| 286 case DebuggerEvent::kBreakpointResolved: | 289 (*event_handler_)(event); |
| 287 // kBreakpointResolved events are handled differently in the vm | |
| 288 // service, so suppress them here. | |
| 289 return false; | |
| 290 | |
| 291 case DebuggerEvent::kBreakpointReached: | |
| 292 case DebuggerEvent::kExceptionThrown: | |
| 293 case DebuggerEvent::kIsolateInterrupted: | |
| 294 return (Service::debug_stream.enabled() || | |
| 295 FLAG_warn_on_pause_with_no_debugger); | |
| 296 | |
| 297 case DebuggerEvent::kIsolateCreated: | |
| 298 case DebuggerEvent::kIsolateShutdown: | |
| 299 return Service::isolate_stream.enabled(); | |
| 300 | |
| 301 default: | |
| 302 UNREACHABLE(); | |
| 303 return false; | |
| 304 } | 290 } |
| 305 } | 291 } |
| 306 | 292 |
| 307 | 293 |
| 308 void Debugger::InvokeEventHandler(DebuggerEvent* event) { | 294 RawError* Debugger::PauseInterrupted() { |
| 309 // Give the event to the Service first, as the debugger event handler | 295 if (ignore_breakpoints_ || IsPaused()) { |
| 310 // may go into a message loop and the Service will not. | 296 // We don't let the isolate get interrupted if we are already |
| 311 // | 297 // paused or ignoring breakpoints. |
| 312 // kBreakpointResolved events are handled differently in the vm | 298 return Error::null(); |
| 313 // service, so suppress them here. | |
| 314 if (ServiceNeedsDebuggerEvent(event->type())) { | |
| 315 ServiceEvent service_event(event); | |
| 316 Service::HandleEvent(&service_event); | |
| 317 } | 299 } |
| 318 | 300 ServiceEvent event(isolate_, ServiceEvent::kPauseInterrupted); |
| 319 { | 301 DebuggerStackTrace* trace = CollectStackTrace(); |
| 320 TransitionVMToNative transition(Thread::Current()); | 302 if (trace->Length() > 0) { |
| 321 if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) && | 303 event.set_top_frame(trace->FrameAt(0)); |
| 322 event->IsPauseEvent()) { | |
| 323 // We allow the embedder's default breakpoint handler to be overridden. | |
| 324 isolate_->PauseEventHandler(); | |
| 325 } else if (event_handler_ != NULL) { | |
| 326 (*event_handler_)(event); | |
| 327 } | |
| 328 } | 304 } |
| 329 | 305 ASSERT(stack_trace_ == NULL); |
| 330 if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) { | 306 stack_trace_ = trace; |
| 331 // If we were paused, notify the service that we have resumed. | 307 resume_action_ = kContinue; |
| 332 const Error& error = | 308 Pause(&event); |
| 333 Error::Handle(Thread::Current()->sticky_error()); | 309 HandleSteppingRequest(trace); |
| 334 ASSERT(error.IsNull() || | 310 stack_trace_ = NULL; |
| 335 error.IsUnwindError() || | |
| 336 error.IsUnhandledException()); | |
| 337 | |
| 338 // Only send a resume event when the isolate is not unwinding. | |
| 339 if (!error.IsUnwindError()) { | |
| 340 ServiceEvent service_event(event->isolate(), ServiceEvent::kResume); | |
| 341 service_event.set_top_frame(event->top_frame()); | |
| 342 Service::HandleEvent(&service_event); | |
| 343 } | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 | |
| 348 void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) { | |
| 349 if (HasAnyEventHandler()) { | |
| 350 DebuggerEvent event(isolate_, type); | |
| 351 ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID); | |
| 352 if (type == DebuggerEvent::kIsolateInterrupted) { | |
| 353 DebuggerStackTrace* trace = CollectStackTrace(); | |
| 354 if (trace->Length() > 0) { | |
| 355 event.set_top_frame(trace->FrameAt(0)); | |
| 356 } | |
| 357 ASSERT(stack_trace_ == NULL); | |
| 358 stack_trace_ = trace; | |
| 359 resume_action_ = kContinue; | |
| 360 Pause(&event); | |
| 361 HandleSteppingRequest(trace); | |
| 362 stack_trace_ = NULL; | |
| 363 } else { | |
| 364 InvokeEventHandler(&event); | |
| 365 } | |
| 366 } | |
| 367 } | |
| 368 | |
| 369 | |
| 370 RawError* Debugger::SignalIsolateInterrupted() { | |
| 371 if (HasDebugEventHandler()) { | |
| 372 SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); | |
| 373 } | |
| 374 | 311 |
| 375 // If any error occurred while in the debug message loop, return it here. | 312 // If any error occurred while in the debug message loop, return it here. |
| 376 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 313 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 377 ASSERT(error.IsNull() || error.IsUnwindError()); | 314 ASSERT(error.IsNull() || error.IsUnwindError()); |
| 378 Thread::Current()->clear_sticky_error(); | 315 Thread::Current()->clear_sticky_error(); |
| 379 return error.raw(); | 316 return error.raw(); |
| 380 } | 317 } |
| 381 | 318 |
| 382 | 319 |
| 383 // The vm service handles breakpoint notifications in a different way | 320 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, |
| 384 // than the regular debugger breakpoint notifications. | 321 Breakpoint* bpt) { |
| 385 static void SendServiceBreakpointEvent(ServiceEvent::EventKind kind, | 322 if (NeedsDebugEvents()) { |
| 386 Breakpoint* bpt) { | 323 // TODO(turnidge): Currently we send single-shot breakpoint events |
| 387 if (Service::debug_stream.enabled()) { | 324 // to the vm service. Do we want to change this? |
| 388 ServiceEvent service_event(Isolate::Current(), kind); | 325 ServiceEvent event(isolate_, kind); |
| 389 service_event.set_breakpoint(bpt); | 326 event.set_breakpoint(bpt); |
| 390 Service::HandleEvent(&service_event); | 327 InvokeEventHandler(&event); |
| 391 } | 328 } |
| 392 } | 329 } |
| 393 | 330 |
| 394 | 331 |
| 332 | |
|
hausner
2016/05/12 20:54:07
Nit: extra blank line.
turnidge
2016/05/13 15:29:32
Done.
| |
| 395 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { | 333 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { |
| 396 bpt->set_next(breakpoints()); | 334 bpt->set_next(breakpoints()); |
| 397 set_breakpoints(bpt); | 335 set_breakpoints(bpt); |
| 398 | 336 |
| 399 dbg->SyncBreakpointLocation(this); | 337 dbg->SyncBreakpointLocation(this); |
| 400 | 338 dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); |
| 401 if (IsResolved()) { | |
| 402 dbg->SignalBpResolved(bpt); | |
| 403 } | |
| 404 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
| 405 } | 339 } |
| 406 | 340 |
| 407 | 341 |
| 408 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { | 342 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { |
| 409 Breakpoint* bpt = breakpoints(); | 343 Breakpoint* bpt = breakpoints(); |
| 410 while (bpt != NULL) { | 344 while (bpt != NULL) { |
| 411 if (bpt->IsRepeated()) break; | 345 if (bpt->IsRepeated()) break; |
| 412 bpt = bpt->next(); | 346 bpt = bpt->next(); |
| 413 } | 347 } |
| 414 if (bpt == NULL) { | 348 if (bpt == NULL) { |
| (...skipping 848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1263 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { | 1197 RawObject* RemoteObjectCache::GetObj(intptr_t obj_id) const { |
| 1264 ASSERT(IsValidId(obj_id)); | 1198 ASSERT(IsValidId(obj_id)); |
| 1265 return objs_->At(obj_id); | 1199 return objs_->At(obj_id); |
| 1266 } | 1200 } |
| 1267 | 1201 |
| 1268 | 1202 |
| 1269 Debugger::Debugger() | 1203 Debugger::Debugger() |
| 1270 : isolate_(NULL), | 1204 : isolate_(NULL), |
| 1271 isolate_id_(ILLEGAL_ISOLATE_ID), | 1205 isolate_id_(ILLEGAL_ISOLATE_ID), |
| 1272 initialized_(false), | 1206 initialized_(false), |
| 1273 creation_message_sent_(false), | |
| 1274 next_id_(1), | 1207 next_id_(1), |
| 1275 latent_locations_(NULL), | 1208 latent_locations_(NULL), |
| 1276 breakpoint_locations_(NULL), | 1209 breakpoint_locations_(NULL), |
| 1277 code_breakpoints_(NULL), | 1210 code_breakpoints_(NULL), |
| 1278 resume_action_(kContinue), | 1211 resume_action_(kContinue), |
| 1279 ignore_breakpoints_(false), | 1212 ignore_breakpoints_(false), |
| 1280 pause_event_(NULL), | 1213 pause_event_(NULL), |
| 1281 obj_cache_(NULL), | 1214 obj_cache_(NULL), |
| 1282 stack_trace_(NULL), | 1215 stack_trace_(NULL), |
| 1283 stepping_fp_(0), | 1216 stepping_fp_(0), |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1315 BreakpointLocation* bpt = latent_locations_; | 1248 BreakpointLocation* bpt = latent_locations_; |
| 1316 latent_locations_ = latent_locations_->next(); | 1249 latent_locations_ = latent_locations_->next(); |
| 1317 delete bpt; | 1250 delete bpt; |
| 1318 } | 1251 } |
| 1319 while (code_breakpoints_ != NULL) { | 1252 while (code_breakpoints_ != NULL) { |
| 1320 CodeBreakpoint* bpt = code_breakpoints_; | 1253 CodeBreakpoint* bpt = code_breakpoints_; |
| 1321 code_breakpoints_ = code_breakpoints_->next(); | 1254 code_breakpoints_ = code_breakpoints_->next(); |
| 1322 bpt->Disable(); | 1255 bpt->Disable(); |
| 1323 delete bpt; | 1256 delete bpt; |
| 1324 } | 1257 } |
| 1325 // Signal isolate shutdown event, but only if we previously sent the creation | 1258 if (NeedsIsolateEvents()) { |
| 1326 // event. | 1259 ServiceEvent event(isolate_, ServiceEvent::kIsolateExit); |
| 1327 if (creation_message_sent_) { | 1260 InvokeEventHandler(&event); |
| 1328 SignalIsolateEvent(DebuggerEvent::kIsolateShutdown); | |
| 1329 } | 1261 } |
| 1330 } | 1262 } |
| 1331 | 1263 |
| 1332 | 1264 |
| 1333 static RawFunction* ResolveLibraryFunction( | 1265 static RawFunction* ResolveLibraryFunction( |
| 1334 const Library& library, | 1266 const Library& library, |
| 1335 const String& fname) { | 1267 const String& fname) { |
| 1336 ASSERT(!library.IsNull()); | 1268 ASSERT(!library.IsNull()); |
| 1337 const Object& object = Object::Handle(library.ResolveName(fname)); | 1269 const Object& object = Object::Handle(library.ResolveName(fname)); |
| 1338 if (!object.IsNull() && object.IsFunction()) { | 1270 if (!object.IsNull() && object.IsFunction()) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1444 for (intptr_t pos = 0; pos < num_closures; pos++) { | 1376 for (intptr_t pos = 0; pos < num_closures; pos++) { |
| 1445 function ^= closures.At(pos); | 1377 function ^= closures.At(pos); |
| 1446 ASSERT(!function.IsNull()); | 1378 ASSERT(!function.IsNull()); |
| 1447 if (function.HasOptimizedCode()) { | 1379 if (function.HasOptimizedCode()) { |
| 1448 function.SwitchToUnoptimizedCode(); | 1380 function.SwitchToUnoptimizedCode(); |
| 1449 } | 1381 } |
| 1450 } | 1382 } |
| 1451 } | 1383 } |
| 1452 | 1384 |
| 1453 | 1385 |
| 1454 void Debugger::SignalBpResolved(Breakpoint* bpt) { | |
| 1455 if (HasDebugEventHandler() && !bpt->IsSingleShot()) { | |
| 1456 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); | |
| 1457 event.set_breakpoint(bpt); | |
| 1458 InvokeEventHandler(&event); | |
| 1459 } | |
| 1460 } | |
| 1461 | |
| 1462 | |
| 1463 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1386 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
| 1464 uword pc, | 1387 uword pc, |
| 1465 StackFrame* frame, | 1388 StackFrame* frame, |
| 1466 const Code& code, | 1389 const Code& code, |
| 1467 const Array& deopt_frame, | 1390 const Array& deopt_frame, |
| 1468 intptr_t deopt_frame_offset) { | 1391 intptr_t deopt_frame_offset) { |
| 1469 ASSERT(code.ContainsInstructionAt(pc)); | 1392 ASSERT(code.ContainsInstructionAt(pc)); |
| 1470 ActivationFrame* activation = | 1393 ActivationFrame* activation = |
| 1471 new ActivationFrame(pc, frame->fp(), frame->sp(), code, | 1394 new ActivationFrame(pc, frame->fp(), frame->sp(), code, |
| 1472 deopt_frame, deopt_frame_offset); | 1395 deopt_frame, deopt_frame_offset); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1660 // Note that this check is not precise, since we can't check | 1583 // Note that this check is not precise, since we can't check |
| 1661 // uninstantiated types, i.e. types containing type parameters. | 1584 // uninstantiated types, i.e. types containing type parameters. |
| 1662 // Thus, we may report an exception as unhandled when in fact | 1585 // Thus, we may report an exception as unhandled when in fact |
| 1663 // it will be caught once we unwind the stack. | 1586 // it will be caught once we unwind the stack. |
| 1664 return true; | 1587 return true; |
| 1665 } | 1588 } |
| 1666 return false; | 1589 return false; |
| 1667 } | 1590 } |
| 1668 | 1591 |
| 1669 | 1592 |
| 1670 void Debugger::SignalExceptionThrown(const Instance& exc) { | 1593 void Debugger::PauseException(const Instance& exc) { |
| 1671 // We ignore this exception event when the VM is executing code invoked | 1594 // We ignore this exception event when the VM is executing code invoked |
| 1672 // by the debugger to evaluate variables values, when we see a nested | 1595 // by the debugger to evaluate variables values, when we see a nested |
| 1673 // breakpoint or exception event, or if the debugger is not | 1596 // breakpoint or exception event, or if the debugger is not |
| 1674 // interested in exception events. | 1597 // interested in exception events. |
| 1675 if (ignore_breakpoints_ || | 1598 if (ignore_breakpoints_ || |
| 1676 IsPaused() || | 1599 IsPaused() || |
| 1677 (exc_pause_info_ == kNoPauseOnExceptions)) { | 1600 (exc_pause_info_ == kNoPauseOnExceptions)) { |
| 1678 return; | 1601 return; |
| 1679 } | 1602 } |
| 1680 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1603 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 1681 if (!ShouldPauseOnException(stack_trace, exc)) { | 1604 if (!ShouldPauseOnException(stack_trace, exc)) { |
| 1682 return; | 1605 return; |
| 1683 } | 1606 } |
| 1684 DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown); | 1607 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
| 1685 event.set_exception(&exc); | 1608 event.set_exception(&exc); |
| 1686 if (stack_trace->Length() > 0) { | 1609 if (stack_trace->Length() > 0) { |
| 1687 event.set_top_frame(stack_trace->FrameAt(0)); | 1610 event.set_top_frame(stack_trace->FrameAt(0)); |
| 1688 } | 1611 } |
| 1689 ASSERT(stack_trace_ == NULL); | 1612 ASSERT(stack_trace_ == NULL); |
| 1690 stack_trace_ = stack_trace; | 1613 stack_trace_ = stack_trace; |
| 1691 Pause(&event); | 1614 Pause(&event); |
| 1692 stack_trace_ = NULL; | 1615 stack_trace_ = NULL; |
| 1693 } | 1616 } |
| 1694 | 1617 |
| (...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2229 } | 2152 } |
| 2230 loc = loc->next(); | 2153 loc = loc->next(); |
| 2231 } | 2154 } |
| 2232 | 2155 |
| 2233 return NULL; | 2156 return NULL; |
| 2234 } | 2157 } |
| 2235 | 2158 |
| 2236 | 2159 |
| 2237 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 2160 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 2238 intptr_t line_number) { | 2161 intptr_t line_number) { |
| 2162 // Prevent future tests from calling this function in the wrong | |
| 2163 // execution state. If you hit this assert, consider using | |
| 2164 // Dart_SetBreakpoint instead. | |
| 2165 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); | |
|
Cutch
2016/05/12 21:12:22
Nice catch! How did you find this?
turnidge
2016/05/13 15:29:32
We used to call Debugger::AddBreapointAtLine() dir
| |
| 2166 | |
| 2239 BreakpointLocation* loc = | 2167 BreakpointLocation* loc = |
| 2240 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); | 2168 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); |
| 2241 if (loc != NULL) { | 2169 if (loc != NULL) { |
| 2242 return loc->AddRepeated(this); | 2170 return loc->AddRepeated(this); |
| 2243 } | 2171 } |
| 2244 return NULL; | 2172 return NULL; |
| 2245 } | 2173 } |
| 2246 | 2174 |
| 2247 | 2175 |
| 2248 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, | 2176 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, |
| 2249 intptr_t line_number, | 2177 intptr_t line_number, |
| 2250 intptr_t column_number) { | 2178 intptr_t column_number) { |
| 2179 // Prevent future tests from calling this function in the wrong | |
| 2180 // execution state. If you hit this assert, consider using | |
| 2181 // Dart_SetBreakpoint instead. | |
| 2182 ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM); | |
| 2183 | |
| 2251 BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url, | 2184 BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url, |
| 2252 line_number, | 2185 line_number, |
| 2253 column_number); | 2186 column_number); |
| 2254 if (loc != NULL) { | 2187 if (loc != NULL) { |
| 2255 return loc->AddRepeated(this); | 2188 return loc->AddRepeated(this); |
| 2256 } | 2189 } |
| 2257 return NULL; | 2190 return NULL; |
| 2258 } | 2191 } |
| 2259 | 2192 |
| 2260 | 2193 |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2551 } | 2484 } |
| 2552 } | 2485 } |
| 2553 | 2486 |
| 2554 | 2487 |
| 2555 // static | 2488 // static |
| 2556 void Debugger::SetEventHandler(EventHandler* handler) { | 2489 void Debugger::SetEventHandler(EventHandler* handler) { |
| 2557 event_handler_ = handler; | 2490 event_handler_ = handler; |
| 2558 } | 2491 } |
| 2559 | 2492 |
| 2560 | 2493 |
| 2561 void Debugger::Pause(DebuggerEvent* event) { | 2494 void Debugger::Pause(ServiceEvent* event) { |
| 2562 ASSERT(!IsPaused()); // No recursive pausing. | 2495 ASSERT(event->IsPause()); // Should call InvokeEventHandler instead. |
| 2496 ASSERT(!ignore_breakpoints_); // We shouldn't get here when ignoring bpts. | |
| 2497 ASSERT(!IsPaused()); // No recursive pausing. | |
| 2563 ASSERT(obj_cache_ == NULL); | 2498 ASSERT(obj_cache_ == NULL); |
| 2564 | 2499 |
| 2565 pause_event_ = event; | 2500 pause_event_ = event; |
| 2566 pause_event_->UpdateTimestamp(); | 2501 pause_event_->UpdateTimestamp(); |
| 2567 obj_cache_ = new RemoteObjectCache(64); | 2502 obj_cache_ = new RemoteObjectCache(64); |
| 2568 | 2503 |
| 2569 // We are about to invoke the debuggers event handler. Disable interrupts | 2504 // We are about to invoke the debugger's event handler. Disable |
| 2570 // for this thread while waiting for debug commands over the service protocol. | 2505 // interrupts for this thread while waiting for debug commands over |
| 2506 // the service protocol. | |
| 2571 { | 2507 { |
| 2572 Thread* thread = Thread::Current(); | 2508 Thread* thread = Thread::Current(); |
| 2573 DisableThreadInterruptsScope dtis(thread); | 2509 DisableThreadInterruptsScope dtis(thread); |
| 2574 TimelineDurationScope tds(thread, | 2510 TimelineDurationScope tds(thread, |
| 2575 Timeline::GetDebuggerStream(), | 2511 Timeline::GetDebuggerStream(), |
| 2576 "Debugger Pause"); | 2512 "Debugger Pause"); |
| 2577 InvokeEventHandler(event); | 2513 |
| 2514 // Send the pause event. | |
| 2515 Service::HandleEvent(event); | |
| 2516 | |
| 2517 { | |
| 2518 TransitionVMToNative transition(Thread::Current()); | |
| 2519 if (FLAG_steal_breakpoints || (event_handler_ == NULL)) { | |
| 2520 // We allow the embedder's default breakpoint handler to be overridden. | |
| 2521 isolate_->PauseEventHandler(); | |
| 2522 } else if (event_handler_ != NULL) { | |
| 2523 (*event_handler_)(event); | |
| 2524 } | |
| 2525 } | |
| 2526 | |
| 2527 // Notify the service that we have resumed. | |
| 2528 const Error& error = | |
| 2529 Error::Handle(Thread::Current()->sticky_error()); | |
| 2530 ASSERT(error.IsNull() || | |
| 2531 error.IsUnwindError() || | |
| 2532 error.IsUnhandledException()); | |
| 2533 | |
| 2534 // Only send a resume event when the isolate is not unwinding. | |
| 2535 if (!error.IsUnwindError()) { | |
| 2536 ServiceEvent resume_event(event->isolate(), ServiceEvent::kResume); | |
| 2537 resume_event.set_top_frame(event->top_frame()); | |
| 2538 Service::HandleEvent(&resume_event); | |
| 2539 } | |
| 2578 } | 2540 } |
| 2579 | 2541 |
| 2580 pause_event_ = NULL; | 2542 pause_event_ = NULL; |
| 2581 obj_cache_ = NULL; // Zone allocated | 2543 obj_cache_ = NULL; // Zone allocated |
| 2582 } | 2544 } |
| 2583 | 2545 |
| 2584 | 2546 |
| 2585 void Debugger::EnterSingleStepMode() { | 2547 void Debugger::EnterSingleStepMode() { |
| 2586 stepping_fp_ = 0; | 2548 stepping_fp_ = 0; |
| 2587 DeoptimizeWorld(); | 2549 DeoptimizeWorld(); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2650 resume_action_ = kContinue; | 2612 resume_action_ = kContinue; |
| 2651 stepping_fp_ = 0; | 2613 stepping_fp_ = 0; |
| 2652 isolate_->set_single_step(false); | 2614 isolate_->set_single_step(false); |
| 2653 ASSERT(!IsPaused()); | 2615 ASSERT(!IsPaused()); |
| 2654 ASSERT(obj_cache_ == NULL); | 2616 ASSERT(obj_cache_ == NULL); |
| 2655 if ((bpt != NULL) && bpt->IsSingleShot()) { | 2617 if ((bpt != NULL) && bpt->IsSingleShot()) { |
| 2656 RemoveBreakpoint(bpt->id()); | 2618 RemoveBreakpoint(bpt->id()); |
| 2657 bpt = NULL; | 2619 bpt = NULL; |
| 2658 } | 2620 } |
| 2659 | 2621 |
| 2660 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2622 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); |
| 2661 event.set_top_frame(top_frame); | 2623 event.set_top_frame(top_frame); |
| 2662 event.set_breakpoint(bpt); | 2624 event.set_breakpoint(bpt); |
| 2663 event.set_at_async_jump(IsAtAsyncJump(top_frame)); | 2625 event.set_at_async_jump(IsAtAsyncJump(top_frame)); |
| 2664 Pause(&event); | 2626 Pause(&event); |
| 2665 } | 2627 } |
| 2666 | 2628 |
| 2667 | 2629 |
| 2668 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { | 2630 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { |
| 2669 Zone* zone = Thread::Current()->zone(); | 2631 Zone* zone = Thread::Current()->zone(); |
| 2670 Object& closure_or_null = | 2632 Object& closure_or_null = |
| 2671 Object::Handle(zone, top_frame->GetAsyncOperation()); | 2633 Object::Handle(zone, top_frame->GetAsyncOperation()); |
| 2672 if (!closure_or_null.IsNull()) { | 2634 if (!closure_or_null.IsNull()) { |
| 2673 ASSERT(closure_or_null.IsInstance()); | 2635 ASSERT(closure_or_null.IsInstance()); |
| 2674 ASSERT(Instance::Cast(closure_or_null).IsClosure()); | 2636 ASSERT(Instance::Cast(closure_or_null).IsClosure()); |
| 2675 const Script& script = Script::Handle(zone, top_frame->SourceScript()); | 2637 const Script& script = Script::Handle(zone, top_frame->SourceScript()); |
| 2676 const TokenStream& tokens = TokenStream::Handle(zone, script.tokens()); | 2638 const TokenStream& tokens = TokenStream::Handle(zone, script.tokens()); |
| 2677 TokenStream::Iterator iter(zone, tokens, top_frame->TokenPos()); | 2639 TokenStream::Iterator iter(zone, tokens, top_frame->TokenPos()); |
| 2678 if ((iter.CurrentTokenKind() == Token::kIDENT) && | 2640 if ((iter.CurrentTokenKind() == Token::kIDENT) && |
| 2679 ((iter.CurrentLiteral() == Symbols::Await().raw()) || | 2641 ((iter.CurrentLiteral() == Symbols::Await().raw()) || |
| 2680 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { | 2642 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { |
| 2681 return true; | 2643 return true; |
| 2682 } | 2644 } |
| 2683 } | 2645 } |
| 2684 return false; | 2646 return false; |
| 2685 } | 2647 } |
| 2686 | 2648 |
| 2687 RawError* Debugger::DebuggerStepCallback() { | 2649 RawError* Debugger::PauseStepping() { |
| 2688 ASSERT(isolate_->single_step()); | 2650 ASSERT(isolate_->single_step()); |
| 2689 // Don't pause recursively. | 2651 // Don't pause recursively. |
| 2690 if (IsPaused()) { | 2652 if (IsPaused()) { |
| 2691 return Error::null(); | 2653 return Error::null(); |
| 2692 } | 2654 } |
| 2693 if (skip_next_step_) { | 2655 if (skip_next_step_) { |
| 2694 skip_next_step_ = false; | 2656 skip_next_step_ = false; |
| 2695 return Error::null(); | 2657 return Error::null(); |
| 2696 } | 2658 } |
| 2697 | 2659 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2734 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 2696 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
| 2735 String::Handle(frame->SourceUrl()).ToCString(), | 2697 String::Handle(frame->SourceUrl()).ToCString(), |
| 2736 frame->LineNumber(), | 2698 frame->LineNumber(), |
| 2737 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 2699 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
| 2738 frame->TokenPos().ToCString()); | 2700 frame->TokenPos().ToCString()); |
| 2739 } | 2701 } |
| 2740 | 2702 |
| 2741 ASSERT(stack_trace_ == NULL); | 2703 ASSERT(stack_trace_ == NULL); |
| 2742 stack_trace_ = CollectStackTrace(); | 2704 stack_trace_ = CollectStackTrace(); |
| 2743 // If this step callback is part of stepping over an await statement, | 2705 // If this step callback is part of stepping over an await statement, |
| 2744 // we saved the synthetic async breakpoint in SignalBpReached. We report | 2706 // we saved the synthetic async breakpoint in PauseBreakpoint. We report |
| 2745 // that we are paused at that breakpoint and then delete it after continuing. | 2707 // that we are paused at that breakpoint and then delete it after continuing. |
| 2746 SignalPausedEvent(frame, synthetic_async_breakpoint_); | 2708 SignalPausedEvent(frame, synthetic_async_breakpoint_); |
| 2747 if (synthetic_async_breakpoint_ != NULL) { | 2709 if (synthetic_async_breakpoint_ != NULL) { |
| 2748 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | 2710 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
| 2749 synthetic_async_breakpoint_ = NULL; | 2711 synthetic_async_breakpoint_ = NULL; |
| 2750 } | 2712 } |
| 2751 HandleSteppingRequest(stack_trace_); | 2713 HandleSteppingRequest(stack_trace_); |
| 2752 stack_trace_ = NULL; | 2714 stack_trace_ = NULL; |
| 2753 | 2715 |
| 2754 // If any error occurred while in the debug message loop, return it here. | 2716 // If any error occurred while in the debug message loop, return it here. |
| 2755 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 2717 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 2756 Thread::Current()->clear_sticky_error(); | 2718 Thread::Current()->clear_sticky_error(); |
| 2757 return error.raw(); | 2719 return error.raw(); |
| 2758 } | 2720 } |
| 2759 | 2721 |
| 2760 | 2722 |
| 2761 RawError* Debugger::SignalBpReached() { | 2723 RawError* Debugger::PauseBreakpoint() { |
| 2762 // We ignore this breakpoint when the VM is executing code invoked | 2724 // We ignore this breakpoint when the VM is executing code invoked |
| 2763 // by the debugger to evaluate variables values, or when we see a nested | 2725 // by the debugger to evaluate variables values, or when we see a nested |
| 2764 // breakpoint or exception event. | 2726 // breakpoint or exception event. |
| 2765 if (ignore_breakpoints_ || IsPaused()) { | 2727 if (ignore_breakpoints_ || IsPaused()) { |
| 2766 return Error::null(); | 2728 return Error::null(); |
| 2767 } | 2729 } |
| 2768 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2730 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 2769 ASSERT(stack_trace->Length() > 0); | 2731 ASSERT(stack_trace->Length() > 0); |
| 2770 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 2732 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
| 2771 ASSERT(top_frame != NULL); | 2733 ASSERT(top_frame != NULL); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2871 RemoveInternalBreakpoints(); | 2833 RemoveInternalBreakpoints(); |
| 2872 } | 2834 } |
| 2873 | 2835 |
| 2874 // If any error occurred while in the debug message loop, return it here. | 2836 // If any error occurred while in the debug message loop, return it here. |
| 2875 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 2837 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 2876 Thread::Current()->clear_sticky_error(); | 2838 Thread::Current()->clear_sticky_error(); |
| 2877 return error.raw(); | 2839 return error.raw(); |
| 2878 } | 2840 } |
| 2879 | 2841 |
| 2880 | 2842 |
| 2881 void Debugger::BreakHere(const String& msg) { | 2843 void Debugger::PauseDeveloper(const String& msg) { |
| 2882 // We ignore this breakpoint when the VM is executing code invoked | 2844 // We ignore this breakpoint when the VM is executing code invoked |
| 2883 // by the debugger to evaluate variables values, or when we see a nested | 2845 // by the debugger to evaluate variables values, or when we see a nested |
| 2884 // breakpoint or exception event. | 2846 // breakpoint or exception event. |
| 2885 if (ignore_breakpoints_ || IsPaused()) { | 2847 if (ignore_breakpoints_ || IsPaused()) { |
| 2886 return; | 2848 return; |
| 2887 } | 2849 } |
| 2888 | 2850 |
| 2889 if (!HasDebugEventHandler()) { | 2851 if (!NeedsDebugEvents()) { |
| 2890 OS::Print("Hit debugger!"); | 2852 OS::Print("Hit debugger!"); |
| 2891 } | 2853 } |
| 2892 | 2854 |
| 2893 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2855 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 2894 ASSERT(stack_trace->Length() > 0); | 2856 ASSERT(stack_trace->Length() > 0); |
| 2895 ASSERT(stack_trace_ == NULL); | 2857 ASSERT(stack_trace_ == NULL); |
| 2896 stack_trace_ = stack_trace; | 2858 stack_trace_ = stack_trace; |
| 2897 | 2859 |
| 2898 // TODO(johnmccutchan): Send |msg| to Observatory. | 2860 // TODO(johnmccutchan): Send |msg| to Observatory. |
| 2899 | 2861 |
| 2900 // We are in the native call to Debugger_breakHere or Debugger_breakHereIf, | 2862 // We are in the native call to Developer_debugger. the developer |
| 2901 // the developer gets a better experience by not seeing this call. To | 2863 // gets a better experience by not seeing this call. To accomplish |
| 2902 // accomplish this, we continue execution until the call exits (step out). | 2864 // this, we continue execution until the call exits (step out). |
| 2903 SetStepOut(); | 2865 SetStepOut(); |
| 2904 HandleSteppingRequest(stack_trace_); | 2866 HandleSteppingRequest(stack_trace_); |
| 2905 | 2867 |
| 2906 stack_trace_ = NULL; | 2868 stack_trace_ = NULL; |
| 2907 } | 2869 } |
| 2908 | 2870 |
| 2909 | 2871 |
| 2910 void Debugger::Initialize(Isolate* isolate) { | 2872 void Debugger::Initialize(Isolate* isolate) { |
| 2911 if (initialized_) { | 2873 if (initialized_) { |
| 2912 return; | 2874 return; |
| 2913 } | 2875 } |
| 2914 isolate_ = isolate; | 2876 isolate_ = isolate; |
| 2915 | 2877 |
| 2916 // Use the isolate's control port as the isolate_id for debugging. | 2878 // Use the isolate's control port as the isolate_id for debugging. |
| 2917 // This port will be used as a unique ID to represent the isolate in the | 2879 // This port will be used as a unique ID to represent the isolate in |
| 2918 // debugger wire protocol messages. | 2880 // the debugger embedder api. |
| 2919 isolate_id_ = isolate_->main_port(); | 2881 isolate_id_ = isolate_->main_port(); |
| 2920 initialized_ = true; | 2882 initialized_ = true; |
| 2921 } | 2883 } |
| 2922 | 2884 |
| 2923 | 2885 |
| 2924 void Debugger::NotifyIsolateCreated() { | 2886 void Debugger::NotifyIsolateCreated() { |
| 2925 // Signal isolate creation event. | 2887 if (NeedsIsolateEvents()) { |
| 2926 if ((isolate_ != Dart::vm_isolate()) && | 2888 ServiceEvent event(isolate_, ServiceEvent::kIsolateStart); |
| 2927 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 2889 InvokeEventHandler(&event); |
| 2928 SignalIsolateEvent(DebuggerEvent::kIsolateCreated); | |
| 2929 creation_message_sent_ = true; | |
| 2930 } | 2890 } |
| 2931 } | 2891 } |
| 2932 | 2892 |
| 2933 | 2893 |
| 2934 // Return innermost closure contained in 'function' that contains | 2894 // Return innermost closure contained in 'function' that contains |
| 2935 // the given token position. | 2895 // the given token position. |
| 2936 RawFunction* Debugger::FindInnermostClosure(const Function& function, | 2896 RawFunction* Debugger::FindInnermostClosure(const Function& function, |
| 2937 TokenPosition token_pos) { | 2897 TokenPosition token_pos) { |
| 2938 Zone* zone = Thread::Current()->zone(); | 2898 Zone* zone = Thread::Current()->zone(); |
| 2939 const Script& outer_origin = Script::Handle(zone, function.script()); | 2899 const Script& outer_origin = Script::Handle(zone, function.script()); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3021 "requested col %" Pd ")\n", | 2981 "requested col %" Pd ")\n", |
| 3022 bpt->id(), | 2982 bpt->id(), |
| 3023 loc->token_pos().ToCString(), | 2983 loc->token_pos().ToCString(), |
| 3024 loc->LineNumber(), | 2984 loc->LineNumber(), |
| 3025 loc->ColumnNumber(), | 2985 loc->ColumnNumber(), |
| 3026 func.ToFullyQualifiedCString(), | 2986 func.ToFullyQualifiedCString(), |
| 3027 requested_pos.ToCString(), | 2987 requested_pos.ToCString(), |
| 3028 requested_end_pos.ToCString(), | 2988 requested_end_pos.ToCString(), |
| 3029 loc->requested_column_number()); | 2989 loc->requested_column_number()); |
| 3030 } | 2990 } |
| 3031 SignalBpResolved(bpt); | 2991 SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); |
| 3032 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); | |
| 3033 bpt = bpt->next(); | 2992 bpt = bpt->next(); |
| 3034 } | 2993 } |
| 3035 } | 2994 } |
| 3036 ASSERT(loc->IsResolved()); | 2995 ASSERT(loc->IsResolved()); |
| 3037 if (FLAG_verbose_debug) { | 2996 if (FLAG_verbose_debug) { |
| 3038 Breakpoint* bpt = loc->breakpoints(); | 2997 Breakpoint* bpt = loc->breakpoints(); |
| 3039 while (bpt != NULL) { | 2998 while (bpt != NULL) { |
| 3040 OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd "" | 2999 OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd "" |
| 3041 " for %s '%s'\n", | 3000 " for %s '%s'\n", |
| 3042 bpt->id(), | 3001 bpt->id(), |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3211 Breakpoint* prev_bpt = NULL; | 3170 Breakpoint* prev_bpt = NULL; |
| 3212 Breakpoint* curr_bpt = curr_loc->breakpoints(); | 3171 Breakpoint* curr_bpt = curr_loc->breakpoints(); |
| 3213 while (curr_bpt != NULL) { | 3172 while (curr_bpt != NULL) { |
| 3214 if (curr_bpt->id() == bp_id) { | 3173 if (curr_bpt->id() == bp_id) { |
| 3215 if (prev_bpt == NULL) { | 3174 if (prev_bpt == NULL) { |
| 3216 curr_loc->set_breakpoints(curr_bpt->next()); | 3175 curr_loc->set_breakpoints(curr_bpt->next()); |
| 3217 } else { | 3176 } else { |
| 3218 prev_bpt->set_next(curr_bpt->next()); | 3177 prev_bpt->set_next(curr_bpt->next()); |
| 3219 } | 3178 } |
| 3220 | 3179 |
| 3221 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); | 3180 SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); |
| 3222 | 3181 |
| 3223 // Remove references from the current debugger pause event. | 3182 // Remove references from the current debugger pause event. |
| 3224 if (pause_event_ != NULL && | 3183 if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) { |
| 3225 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
| 3226 pause_event_->breakpoint() == curr_bpt) { | |
| 3227 pause_event_->set_breakpoint(NULL); | 3184 pause_event_->set_breakpoint(NULL); |
| 3228 } | 3185 } |
| 3229 break; | 3186 break; |
| 3230 } | 3187 } |
| 3231 | 3188 |
| 3232 prev_bpt = curr_bpt; | 3189 prev_bpt = curr_bpt; |
| 3233 curr_bpt = curr_bpt->next(); | 3190 curr_bpt = curr_bpt->next(); |
| 3234 } | 3191 } |
| 3235 | 3192 |
| 3236 if (curr_loc->breakpoints() == NULL) { | 3193 if (curr_loc->breakpoints() == NULL) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3360 | 3317 |
| 3361 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3318 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 3362 ASSERT(bpt->next() == NULL); | 3319 ASSERT(bpt->next() == NULL); |
| 3363 bpt->set_next(code_breakpoints_); | 3320 bpt->set_next(code_breakpoints_); |
| 3364 code_breakpoints_ = bpt; | 3321 code_breakpoints_ = bpt; |
| 3365 } | 3322 } |
| 3366 | 3323 |
| 3367 #endif // !PRODUCT | 3324 #endif // !PRODUCT |
| 3368 | 3325 |
| 3369 } // namespace dart | 3326 } // namespace dart |
| OLD | NEW |