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
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_DEBUGGER_H_
6#define RUNTIME_VM_DEBUGGER_H_
7
8#include <memory>
9
10#include "include/dart_tools_api.h"
11
12#include "vm/compiler/api/deopt_id.h"
13#include "vm/kernel_isolate.h"
14#include "vm/object.h"
15#include "vm/port.h"
16#include "vm/scopes.h"
17#include "vm/service_event.h"
18#include "vm/simulator.h"
19#include "vm/stack_frame.h"
20#include "vm/stack_trace.h"
21
22#if !defined(PRODUCT)
23
24DECLARE_FLAG(bool, verbose_debug);
25
26// 'Trace Debugger' TD_Print.
27#if defined(_MSC_VER)
28#define TD_Print(format, ...) \
29 if (FLAG_verbose_debug) Log::Current()->Print(format, __VA_ARGS__)
30#else
31#define TD_Print(format, ...) \
32 if (FLAG_verbose_debug) Log::Current()->Print(format, ##__VA_ARGS__)
33#endif
34
35namespace dart {
36
37class CodeBreakpoint;
38class Isolate;
39class JSONArray;
40class JSONStream;
41class ObjectPointerVisitor;
42class BreakpointLocation;
43class StackFrame;
44
45// A user-defined breakpoint, which can be set for a particular closure
46// (if |closure| is not |null|) and can fire one (|is_single_shot| is |true|)
47// or many times.
48class Breakpoint {
49 public:
50 Breakpoint(intptr_t id,
51 BreakpointLocation* bpt_location,
52 bool is_single_shot,
53 const Closure& closure)
54 : id_(id),
55 next_(nullptr),
56 closure_(closure.ptr()),
57 bpt_location_(bpt_location),
58 is_single_shot_(is_single_shot) {}
59
60 intptr_t id() const { return id_; }
61 Breakpoint* next() const { return next_; }
62 void set_next(Breakpoint* n) { next_ = n; }
63
64 BreakpointLocation* bpt_location() const { return bpt_location_; }
65 void set_bpt_location(BreakpointLocation* new_bpt_location);
66
67 bool is_single_shot() const { return is_single_shot_; }
68 ClosurePtr closure() const { return closure_; }
69
70 void Enable() {
71 ASSERT(!enabled_);
72 enabled_ = true;
73 }
74
75 void Disable() {
76 ASSERT(enabled_);
77 enabled_ = false;
78 }
79
80 bool is_enabled() const { return enabled_; }
81
82 void PrintJSON(JSONStream* stream);
83
84 private:
85 void VisitObjectPointers(ObjectPointerVisitor* visitor);
86
87 intptr_t id_;
88 Breakpoint* next_;
89 ClosurePtr closure_;
90 BreakpointLocation* bpt_location_;
91 bool is_single_shot_;
92 bool enabled_ = false;
93
94 friend class BreakpointLocation;
95 DISALLOW_COPY_AND_ASSIGN(Breakpoint);
96};
97
98// BreakpointLocation represents a collection of breakpoint conditions at the
99// same token position in Dart source. There may be more than one CodeBreakpoint
100// object per BreakpointLocation.
101// An unresolved breakpoint is one where the underlying code has not
102// been compiled yet. Since the code has not been compiled, we don't know
103// the definitive source location yet. The requested source location may
104// change when the underlying code gets compiled.
105// A latent breakpoint represents a breakpoint location in Dart source
106// that is not loaded in the VM when the breakpoint is requested.
107// When a script with matching url is loaded, a latent breakpoint
108// becomes an unresolved breakpoint.
109class BreakpointLocation {
110 public:
111 // Create a new unresolved breakpoint.
112 BreakpointLocation(Debugger* debugger,
113 const GrowableHandlePtrArray<const Script>& scripts,
114 TokenPosition token_pos,
115 TokenPosition end_token_pos,
116 intptr_t requested_line_number,
117 intptr_t requested_column_number);
118 // Create a new latent breakpoint.
119 BreakpointLocation(Debugger* debugger,
120 const String& url,
121 intptr_t requested_line_number,
122 intptr_t requested_column_number);
123
124 ~BreakpointLocation();
125
126 TokenPosition token_pos() const { return token_pos_.load(); }
127 intptr_t line_number();
128 TokenPosition end_token_pos() const { return end_token_pos_.load(); }
129
130 ScriptPtr script() const {
131 if (scripts_.length() == 0) {
132 return Script::null();
133 }
134 return scripts_.At(index: 0);
135 }
136 StringPtr url() const { return url_; }
137
138 intptr_t requested_line_number() const { return requested_line_number_; }
139 intptr_t requested_column_number() const { return requested_column_number_; }
140
141 void GetCodeLocation(Script* script, TokenPosition* token_pos) const;
142
143 Breakpoint* AddRepeated(Debugger* dbg);
144 Breakpoint* AddSingleShot(Debugger* dbg);
145 Breakpoint* AddBreakpoint(Debugger* dbg,
146 const Closure& closure,
147 bool single_shot);
148
149 bool AnyEnabled() const;
150 bool IsResolved() const { return code_token_pos_.IsReal(); }
151 bool IsLatent() const { return !token_pos().IsReal(); }
152
153 bool EnsureIsResolved(const Function& target_function,
154 TokenPosition exact_token_pos);
155
156 Debugger* debugger() { return debugger_; }
157
158 private:
159 void VisitObjectPointers(ObjectPointerVisitor* visitor);
160
161 void SetResolved(const Function& func, TokenPosition token_pos);
162
163 BreakpointLocation* next() const { return this->next_; }
164 void set_next(BreakpointLocation* value) { next_ = value; }
165
166 void AddBreakpoint(Breakpoint* bpt, Debugger* dbg);
167
168 Breakpoint* breakpoints() const { return this->conditions_; }
169 void set_breakpoints(Breakpoint* head) { this->conditions_ = head; }
170
171 // Finds the breakpoint we hit at |location|.
172 Breakpoint* FindHitBreakpoint(ActivationFrame* top_frame);
173
174 SafepointRwLock* line_number_lock() { return line_number_lock_.get(); }
175
176 Debugger* debugger_;
177 MallocGrowableArray<ScriptPtr> scripts_;
178 StringPtr url_;
179 std::unique_ptr<SafepointRwLock> line_number_lock_;
180 intptr_t line_number_; // lazily computed for token_pos_
181 std::atomic<TokenPosition> token_pos_;
182 std::atomic<TokenPosition> end_token_pos_;
183 BreakpointLocation* next_;
184 Breakpoint* conditions_;
185 intptr_t requested_line_number_;
186 intptr_t requested_column_number_;
187
188 // Valid for resolved breakpoints:
189 TokenPosition code_token_pos_;
190
191 friend class Debugger;
192 friend class GroupDebugger;
193 DISALLOW_COPY_AND_ASSIGN(BreakpointLocation);
194};
195
196// CodeBreakpoint represents a location in compiled code.
197// There may be more than one CodeBreakpoint for one BreakpointLocation,
198// e.g. when a function gets compiled as a regular function and as a closure.
199// There may be more than one BreakpointLocation associated with CodeBreakpoint,
200// one for every isolate in a group that sets a breakpoint at particular
201// code location represented by the CodeBreakpoint.
202// Each BreakpointLocation might be enabled/disabled based on whether it has
203// any actual breakpoints associated with it.
204// The CodeBreakpoint is enabled if it has any such BreakpointLocations
205// associated with it.
206// The class is not thread-safe - users of this class need to ensure the access
207// is synchronized, guarded by mutexes or run inside of a safepoint scope.
208class CodeBreakpoint {
209 public:
210 // Unless CodeBreakpoint is unlinked and is no longer used there should be at
211 // least one BreakpointLocation associated with CodeBreakpoint. If there are
212 // more BreakpointLocation added assumption is is that all of them point to
213 // the same source so have the same token pos.
214 CodeBreakpoint(const Code& code,
215 BreakpointLocation* loc,
216 uword pc,
217 UntaggedPcDescriptors::Kind kind);
218 ~CodeBreakpoint();
219
220 // Used by GroupDebugger to find CodeBreakpoint associated with
221 // particular function.
222 FunctionPtr function() const { return Code::Handle(ptr: code_).function(); }
223
224 uword pc() const { return pc_; }
225 bool HasBreakpointLocation(BreakpointLocation* breakpoint_location);
226 bool FindAndDeleteBreakpointLocation(BreakpointLocation* breakpoint_location);
227 bool HasNoBreakpointLocations() {
228 return breakpoint_locations_.length() == 0;
229 }
230
231 void Enable();
232 void Disable();
233 bool IsEnabled() const { return enabled_count_ > 0; }
234
235 CodePtr OrigStubAddress() const;
236
237 const char* ToCString() const;
238
239 private:
240 void VisitObjectPointers(ObjectPointerVisitor* visitor);
241
242 // Finds right BreakpointLocation for a given Isolate's debugger.
243 BreakpointLocation* FindBreakpointForDebugger(Debugger* debugger);
244 // Adds new BreakpointLocation for another isolate that wants to
245 // break at the same function/code location that this CodeBreakpoint
246 // represents.
247 void AddBreakpointLocation(BreakpointLocation* breakpoint_location) {
248 ASSERT(breakpoint_locations_.length() == 0 ||
249 (breakpoint_location->token_pos() ==
250 breakpoint_locations_.At(0)->token_pos() &&
251 breakpoint_location->url() == breakpoint_locations_.At(0)->url()));
252 breakpoint_locations_.Add(value: breakpoint_location);
253 }
254
255 void set_next(CodeBreakpoint* value) { next_ = value; }
256 CodeBreakpoint* next() const { return this->next_; }
257
258 void PatchCode();
259 void RestoreCode();
260
261 CodePtr code_;
262 uword pc_;
263 int enabled_count_; // incremented for every enabled breakpoint location
264
265 // Breakpoint locations from different debuggers/isolates that
266 // point to this code breakpoint.
267 MallocGrowableArray<BreakpointLocation*> breakpoint_locations_;
268 CodeBreakpoint* next_;
269
270 UntaggedPcDescriptors::Kind breakpoint_kind_;
271 CodePtr saved_value_;
272
273 friend class Debugger;
274 friend class GroupDebugger;
275 DISALLOW_COPY_AND_ASSIGN(CodeBreakpoint);
276};
277
278// ActivationFrame represents one dart function activation frame
279// on the call stack.
280class ActivationFrame : public ZoneAllocated {
281 public:
282 enum Kind {
283 kRegular,
284 kAsyncSuspensionMarker,
285 kAsyncAwaiter,
286 };
287
288 ActivationFrame(uword pc,
289 uword fp,
290 uword sp,
291 const Code& code,
292 const Array& deopt_frame,
293 intptr_t deopt_frame_offset);
294
295 // Create a |kAsyncAwaiter| frame representing asynchronous awaiter
296 // waiting for the completion of a |Future|.
297 //
298 // |closure| is the listener which will be invoked when awaited
299 // computation completes.
300 ActivationFrame(uword pc, const Code& code, const Closure& closure);
301
302 explicit ActivationFrame(Kind kind);
303
304 Kind kind() const { return kind_; }
305
306 uword pc() const { return pc_; }
307 uword fp() const { return fp_; }
308 uword sp() const { return sp_; }
309
310 uword GetCallerSp() const { return fp() + (kCallerSpSlotFromFp * kWordSize); }
311
312 // For |kAsyncAwaiter| frames this is the listener which will be invoked
313 // when the frame below (callee) completes.
314 const Closure& closure() const { return closure_; }
315
316 const Function& function() const {
317 return function_;
318 }
319 const Code& code() const {
320 ASSERT(!code_.IsNull());
321 return code_;
322 }
323
324 enum Relation {
325 kCallee,
326 kSelf,
327 kCaller,
328 };
329
330 Relation CompareTo(uword other_fp) const;
331
332 StringPtr QualifiedFunctionName();
333 StringPtr SourceUrl();
334 ScriptPtr SourceScript();
335 LibraryPtr Library();
336 TokenPosition TokenPos();
337 intptr_t LineNumber();
338 intptr_t ColumnNumber();
339
340 // Returns true if this frame is for a function that is visible
341 // to the user and can be debugged.
342 bool IsDebuggable() const;
343
344 // Returns true if it is possible to rewind the debugger to this frame.
345 bool IsRewindable() const;
346
347 // The context level of a frame is the context level at the
348 // PC/token index of the frame. It determines the depth of the context
349 // chain that belongs to the function of this activation frame.
350 intptr_t ContextLevel();
351
352 const char* ToCString();
353
354 intptr_t NumLocalVariables();
355
356 void VariableAt(intptr_t i,
357 String* name,
358 TokenPosition* declaration_token_pos,
359 TokenPosition* visible_start_token_pos,
360 TokenPosition* visible_end_token_pos,
361 Object* value);
362
363 ArrayPtr GetLocalVariables();
364 ObjectPtr GetParameter(intptr_t index);
365 ClosurePtr GetClosure();
366 ObjectPtr GetReceiver();
367
368 const Context& GetSavedCurrentContext();
369 ObjectPtr GetSuspendStateVar();
370 ObjectPtr GetSuspendableFunctionData();
371
372 TypeArgumentsPtr BuildParameters(
373 const GrowableObjectArray& param_names,
374 const GrowableObjectArray& param_values,
375 const GrowableObjectArray& type_params_names,
376 const GrowableObjectArray& type_params_bounds,
377 const GrowableObjectArray& type_params_defaults);
378
379 ObjectPtr EvaluateCompiledExpression(const ExternalTypedData& kernel_data,
380 const Array& arguments,
381 const Array& type_definitions,
382 const TypeArguments& type_arguments);
383
384 void PrintToJSONObject(JSONObject* jsobj);
385
386 bool HandlesException(const Instance& exc_obj);
387
388 bool has_catch_error() const { return has_catch_error_; }
389 void set_has_catch_error(bool value) { has_catch_error_ = value; }
390
391 private:
392 void PrintToJSONObjectRegular(JSONObject* jsobj);
393 void PrintToJSONObjectAsyncAwaiter(JSONObject* jsobj);
394 void PrintToJSONObjectAsyncSuspensionMarker(JSONObject* jsobj);
395 void PrintContextMismatchError(intptr_t ctx_slot,
396 intptr_t frame_ctx_level,
397 intptr_t var_ctx_level);
398 void PrintDescriptorsError(const char* message);
399
400 intptr_t TryIndex();
401 intptr_t DeoptId();
402 void GetPcDescriptors();
403 void GetVarDescriptors();
404 void GetDescIndices();
405
406 static const char* KindToCString(Kind kind) {
407 switch (kind) {
408 case kRegular:
409 return "Regular";
410 case kAsyncAwaiter:
411 // Keeping the legacy name in the protocol itself.
412 return "AsyncCausal";
413 case kAsyncSuspensionMarker:
414 return "AsyncSuspensionMarker";
415 default:
416 UNREACHABLE();
417 return "";
418 }
419 }
420
421 ObjectPtr GetStackVar(VariableIndex var_index);
422 ObjectPtr GetRelativeContextVar(intptr_t ctxt_level,
423 intptr_t slot_index,
424 intptr_t frame_ctx_level);
425 ObjectPtr GetContextVar(intptr_t ctxt_level, intptr_t slot_index);
426
427 uword pc_ = 0;
428 uword fp_ = 0;
429 uword sp_ = 0;
430
431 // The anchor of the context chain for this function.
432 Context& ctx_ = Context::ZoneHandle();
433 const Code& code_;
434 const Function& function_;
435 const Closure& closure_;
436
437 bool token_pos_initialized_ = false;
438 TokenPosition token_pos_ = TokenPosition::kNoSource;
439 intptr_t try_index_ = -1;
440 intptr_t deopt_id_ = dart::DeoptId::kNone;
441
442 intptr_t line_number_ = -1;
443 intptr_t column_number_ = -1;
444 intptr_t context_level_ = -1;
445
446 // Some frames are deoptimized into a side array in order to inspect them.
447 const Array& deopt_frame_;
448 const intptr_t deopt_frame_offset_;
449
450 Kind kind_;
451
452 bool vars_initialized_ = false;
453 LocalVarDescriptors& var_descriptors_ = LocalVarDescriptors::ZoneHandle();
454 ZoneGrowableArray<intptr_t> desc_indices_;
455 PcDescriptors& pc_desc_ = PcDescriptors::ZoneHandle();
456
457 bool has_catch_error_ = false;
458
459 friend class Debugger;
460 friend class DebuggerStackTrace;
461 DISALLOW_COPY_AND_ASSIGN(ActivationFrame);
462};
463
464// Array of function activations on the call stack.
465class DebuggerStackTrace : public ZoneAllocated {
466 public:
467 explicit DebuggerStackTrace(int capacity)
468 : thread_(Thread::Current()), zone_(thread_->zone()), trace_(capacity) {}
469
470 intptr_t Length() const { return trace_.length(); }
471
472 ActivationFrame* FrameAt(int i) const { return trace_[i]; }
473
474 ActivationFrame* GetHandlerFrame(const Instance& exc_obj) const;
475
476 static DebuggerStackTrace* Collect();
477 static DebuggerStackTrace* CollectAsyncAwaiters();
478
479 // Returns a debugger stack trace corresponding to a dart.core.StackTrace.
480 // Frames corresponding to invisible functions are omitted. It is not valid
481 // to query local variables in the returned stack.
482 static DebuggerStackTrace* From(const class StackTrace& ex_trace);
483
484 private:
485 void AddActivation(ActivationFrame* frame);
486 void AddAsyncSuspension(bool has_catch_error);
487 void AddAsyncAwaiterFrame(uword pc, const Code& code, const Closure& closure);
488
489 void AppendCodeFrames(StackFrame* frame, const Code& code);
490
491 Thread* thread_;
492 Zone* zone_;
493 Code& inlined_code_ = Code::Handle();
494 Array& deopt_frame_ = Array::Handle();
495 ZoneGrowableArray<ActivationFrame*> trace_;
496
497 friend class Debugger;
498
499 DISALLOW_COPY_AND_ASSIGN(DebuggerStackTrace);
500};
501
502// On which exceptions to pause.
503typedef enum {
504 kNoPauseOnExceptions = 1,
505 kPauseOnUnhandledExceptions,
506 kPauseOnAllExceptions,
507 kInvalidExceptionPauseInfo
508} Dart_ExceptionPauseInfo;
509
510class DebuggerKeyValueTrait : public AllStatic {
511 public:
512 typedef const Debugger* Key;
513 typedef bool Value;
514
515 struct Pair {
516 Key key;
517 Value value;
518 Pair() : key(nullptr), value(false) {}
519 Pair(const Key key, const Value& value) : key(key), value(value) {}
520 Pair(const Pair& other) : key(other.key), value(other.value) {}
521 Pair& operator=(const Pair&) = default;
522 };
523
524 static Key KeyOf(Pair kv) { return kv.key; }
525 static Value ValueOf(Pair kv) { return kv.value; }
526 static uword Hash(Key key) {
527 return Utils::WordHash(key: reinterpret_cast<intptr_t>(key));
528 }
529 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
530};
531
532class DebuggerSet : public MallocDirectChainedHashMap<DebuggerKeyValueTrait> {
533 public:
534 typedef DebuggerKeyValueTrait::Key Key;
535 typedef DebuggerKeyValueTrait::Value Value;
536 typedef DebuggerKeyValueTrait::Pair Pair;
537
538 virtual ~DebuggerSet() { Clear(); }
539
540 void Insert(const Key& key) {
541 Pair pair(key, /*value=*/true);
542 MallocDirectChainedHashMap<DebuggerKeyValueTrait>::Insert(kv: pair);
543 }
544
545 void Remove(const Key& key) {
546 MallocDirectChainedHashMap<DebuggerKeyValueTrait>::Remove(key);
547 }
548};
549
550class BoolCallable : public ValueObject {
551 public:
552 BoolCallable() {}
553 virtual ~BoolCallable() {}
554
555 virtual bool Call() = 0;
556
557 private:
558 DISALLOW_COPY_AND_ASSIGN(BoolCallable);
559};
560
561template <typename T>
562class LambdaBoolCallable : public BoolCallable {
563 public:
564 explicit LambdaBoolCallable(T& lambda) : lambda_(lambda) {}
565 bool Call() { return lambda_(); }
566
567 private:
568 T& lambda_;
569 DISALLOW_COPY_AND_ASSIGN(LambdaBoolCallable);
570};
571
572class GroupDebugger {
573 public:
574 explicit GroupDebugger(IsolateGroup* isolate_group);
575 ~GroupDebugger();
576
577 void MakeCodeBreakpointAt(const Function& func, BreakpointLocation* bpt);
578
579 // Returns [nullptr] if no breakpoint exists for the given address.
580 CodeBreakpoint* GetCodeBreakpoint(uword breakpoint_address);
581 BreakpointLocation* GetBreakpointLocationFor(Debugger* debugger,
582 uword breakpoint_address,
583 CodeBreakpoint** pcbpt);
584 CodePtr GetPatchedStubAddress(uword breakpoint_address);
585
586 void RegisterBreakpointLocation(BreakpointLocation* location);
587 void UnregisterBreakpointLocation(BreakpointLocation* location);
588
589 void RemoveBreakpointLocation(BreakpointLocation* bpt_location);
590 void UnlinkCodeBreakpoints(BreakpointLocation* bpt_location);
591
592 // Returns true if the call at address pc is patched to point to
593 // a debugger stub.
594 bool HasActiveBreakpoint(uword pc);
595 bool HasCodeBreakpointInFunction(const Function& func);
596 bool HasCodeBreakpointInCode(const Code& code);
597
598 bool HasBreakpointInFunction(const Function& func);
599 bool HasBreakpointInCode(const Code& code);
600
601 void SyncBreakpointLocation(BreakpointLocation* loc);
602
603 void Pause();
604
605 bool EnsureLocationIsInFunction(Zone* zone,
606 const Function& function,
607 BreakpointLocation* location);
608 void NotifyCompilation(const Function& func);
609
610 void VisitObjectPointers(ObjectPointerVisitor* visitor);
611
612 SafepointRwLock* code_breakpoints_lock() {
613 return code_breakpoints_lock_.get();
614 }
615
616 SafepointRwLock* breakpoint_locations_lock() {
617 return breakpoint_locations_lock_.get();
618 }
619
620 SafepointRwLock* single_stepping_set_lock() {
621 return single_stepping_set_lock_.get();
622 }
623 void RegisterSingleSteppingDebugger(Thread* thread, const Debugger* debugger);
624 void UnregisterSingleSteppingDebugger(Thread* thread,
625 const Debugger* debugger);
626
627 bool RunUnderReadLockIfNeededCallable(Thread* thread,
628 SafepointRwLock* rw_lock,
629 BoolCallable* callable);
630
631 template <typename T>
632 bool RunUnderReadLockIfNeeded(Thread* thread,
633 SafepointRwLock* rw_lock,
634 T function) {
635 LambdaBoolCallable<T> callable(function);
636 return RunUnderReadLockIfNeededCallable(thread, rw_lock, callable: &callable);
637 }
638
639 // Returns [true] if there is at least one breakpoint set in function or code.
640 // Checks for both user-defined and internal temporary breakpoints.
641 bool HasBreakpoint(Thread* thread, const Function& function);
642 bool IsDebugging(Thread* thread, const Function& function);
643
644 private:
645 IsolateGroup* isolate_group_;
646
647 std::unique_ptr<SafepointRwLock> code_breakpoints_lock_;
648 CodeBreakpoint* code_breakpoints_;
649
650 // Secondary list of all breakpoint_locations_(primary is in Debugger class).
651 // This list is kept in sync with all the lists in Isolate Debuggers and is
652 // used to quickly scan BreakpointLocations when new Function is compiled.
653 std::unique_ptr<SafepointRwLock> breakpoint_locations_lock_;
654 MallocGrowableArray<BreakpointLocation*> breakpoint_locations_;
655
656 std::unique_ptr<SafepointRwLock> single_stepping_set_lock_;
657 DebuggerSet single_stepping_set_;
658
659 void RemoveUnlinkedCodeBreakpoints();
660 void RegisterCodeBreakpoint(CodeBreakpoint* bpt);
661
662 bool needs_breakpoint_cleanup_;
663};
664
665class Debugger {
666 public:
667 enum ResumeAction {
668 kContinue,
669 kStepInto,
670 kStepOver,
671 kStepOut,
672 kStepRewind,
673 kStepOverAsyncSuspension,
674 };
675
676 explicit Debugger(Isolate* isolate);
677 ~Debugger();
678
679 Isolate* isolate() const { return isolate_; }
680
681 void NotifyIsolateCreated();
682 void Shutdown();
683
684 void NotifyDoneLoading();
685
686 // Set breakpoint at closest location to function entry.
687 Breakpoint* SetBreakpointAtEntry(const Function& target_function,
688 bool single_shot);
689 Breakpoint* SetBreakpointAtActivation(const Instance& closure,
690 bool single_shot);
691 Breakpoint* BreakpointAtActivation(const Instance& closure);
692
693 // TODO(turnidge): script_url may no longer be specific enough.
694 Breakpoint* SetBreakpointAtLine(const String& script_url,
695 intptr_t line_number);
696 Breakpoint* SetBreakpointAtLineCol(const String& script_url,
697 intptr_t line_number,
698 intptr_t column_number);
699
700 BreakpointLocation* BreakpointLocationAtLineCol(const String& script_url,
701 intptr_t line_number,
702 intptr_t column_number);
703
704 // Returns true if the breakpoint's state changed.
705 bool SetBreakpointState(Breakpoint* bpt, bool enable);
706
707 void RemoveBreakpoint(intptr_t bp_id);
708 Breakpoint* GetBreakpointById(intptr_t id);
709
710 void AsyncStepInto(const Closure& awaiter);
711
712 void Continue();
713
714 bool SetResumeAction(ResumeAction action,
715 intptr_t frame_index = 1,
716 const char** error = nullptr);
717
718 bool IsStepping() const { return resume_action_ != kContinue; }
719
720 bool IsSingleStepping() const { return resume_action_ == kStepInto; }
721
722 bool IsPaused() const { return pause_event_ != nullptr; }
723
724 bool ignore_breakpoints() const { return ignore_breakpoints_; }
725 void set_ignore_breakpoints(bool ignore_breakpoints) {
726 ignore_breakpoints_ = ignore_breakpoints;
727 }
728
729 // Put the isolate into single stepping mode when Dart code next runs.
730 //
731 // This is used by the vm service to allow the user to step while
732 // paused at isolate start.
733 void EnterSingleStepMode();
734
735 // Indicates why the debugger is currently paused. If the debugger
736 // is not paused, this returns nullptr. Note that the debugger can be
737 // paused for breakpoints, isolate interruption, and (sometimes)
738 // exceptions.
739 const ServiceEvent* PauseEvent() const { return pause_event_; }
740
741 void SetExceptionPauseInfo(Dart_ExceptionPauseInfo pause_info);
742 Dart_ExceptionPauseInfo GetExceptionPauseInfo() const;
743
744 void VisitObjectPointers(ObjectPointerVisitor* visitor);
745
746 // Returns a stack trace with frames corresponding to invisible functions
747 // omitted. CurrentStackTrace always returns a new trace on the current stack.
748 // The trace returned by StackTrace may have been cached; it is suitable for
749 // use when stepping, but otherwise may be out of sync with the current stack.
750 DebuggerStackTrace* StackTrace();
751
752 DebuggerStackTrace* AsyncAwaiterStackTrace();
753
754 // Pause execution for a breakpoint. Called from generated code.
755 ErrorPtr PauseBreakpoint();
756
757 // Pause execution due to stepping. Called from generated code.
758 ErrorPtr PauseStepping();
759
760 // Pause execution due to isolate interrupt.
761 ErrorPtr PauseInterrupted();
762
763 // Pause after a reload request.
764 ErrorPtr PausePostRequest();
765
766 // Pause execution due to an uncaught exception.
767 void PauseException(const Instance& exc);
768
769 // Pause execution due to a call to the debugger() function from
770 // Dart.
771 void PauseDeveloper(const String& msg);
772
773 void PrintBreakpointsToJSONArray(JSONArray* jsarr) const;
774 void PrintSettingsToJSONObject(JSONObject* jsobj) const;
775
776 static bool IsDebuggable(const Function& func);
777
778 intptr_t limitBreakpointId() { return next_id_; }
779
780 // Callback to the debugger to continue frame rewind, post-deoptimization.
781 void RewindPostDeopt();
782
783 // Sets breakpoint at resumption of a suspendable function
784 // with given function data (such as _Future or _AsyncStarStreamController).
785 void SetBreakpointAtResumption(const Object& function_data);
786
787 // Check breakpoints at frame resumption. Called from generated code.
788 void ResumptionBreakpoint();
789
790 private:
791 ErrorPtr PauseRequest(ServiceEvent::EventKind kind);
792
793 // Will return false if we are not at an await.
794 bool SetupStepOverAsyncSuspension(const char** error);
795
796 bool NeedsIsolateEvents();
797 bool NeedsDebugEvents();
798
799 void SendBreakpointEvent(ServiceEvent::EventKind kind, Breakpoint* bpt);
800
801 void FindCompiledFunctions(
802 const GrowableHandlePtrArray<const Script>& scripts,
803 TokenPosition start_pos,
804 TokenPosition end_pos,
805 GrowableObjectArray* code_function_list);
806 bool FindBestFit(const Script& script,
807 TokenPosition token_pos,
808 TokenPosition last_token_pos,
809 Function* best_fit);
810 void DeoptimizeWorld();
811 void NotifySingleStepping(bool value) const;
812 BreakpointLocation* SetCodeBreakpoints(
813 const GrowableHandlePtrArray<const Script>& scripts,
814 TokenPosition token_pos,
815 TokenPosition last_token_pos,
816 intptr_t requested_line,
817 intptr_t requested_column,
818 TokenPosition exact_token_pos,
819 const GrowableObjectArray& functions);
820 BreakpointLocation* SetBreakpoint(const Script& script,
821 TokenPosition token_pos,
822 TokenPosition last_token_pos,
823 intptr_t requested_line,
824 intptr_t requested_column,
825 const Function& function);
826 BreakpointLocation* SetBreakpoint(
827 const GrowableHandlePtrArray<const Script>& scripts,
828 TokenPosition token_pos,
829 TokenPosition last_token_pos,
830 intptr_t requested_line,
831 intptr_t requested_column,
832 const Function& function);
833 bool RemoveBreakpointFromTheList(intptr_t bp_id, BreakpointLocation** list);
834 Breakpoint* GetBreakpointByIdInTheList(intptr_t id, BreakpointLocation* list);
835 BreakpointLocation* GetLatentBreakpoint(const String& url,
836 intptr_t line,
837 intptr_t column);
838 void RegisterBreakpointLocation(BreakpointLocation* bpt);
839 BreakpointLocation* GetResolvedBreakpointLocation(
840 const String& script_url,
841 TokenPosition code_token_pos);
842 BreakpointLocation* GetBreakpointLocation(
843 const String& script_url,
844 TokenPosition token_pos,
845 intptr_t requested_line,
846 intptr_t requested_column,
847 TokenPosition code_token_pos = TokenPosition::kNoSource);
848
849 void PrintBreakpointsListToJSONArray(BreakpointLocation* sbpt,
850 JSONArray* jsarr) const;
851
852 void SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt);
853
854 intptr_t nextId() { return next_id_++; }
855
856 bool ShouldPauseOnException(DebuggerStackTrace* stack_trace,
857 const Instance& exc);
858
859 // Handles any events which pause vm execution. Breakpoints,
860 // interrupts, etc.
861 void Pause(ServiceEvent* event);
862
863 void HandleSteppingRequest(bool skip_next_step = false);
864
865 void CacheStackTraces(DebuggerStackTrace* stack_trace,
866 DebuggerStackTrace* async_awaiter_stack_trace);
867 void ClearCachedStackTraces();
868
869 void RewindToFrame(intptr_t frame_index);
870 void RewindToUnoptimizedFrame(StackFrame* frame, const Code& code);
871 void RewindToOptimizedFrame(StackFrame* frame,
872 const Code& code,
873 intptr_t post_deopt_frame_index);
874
875 void ResetSteppingFramePointer();
876 void SetSyncSteppingFramePointer(DebuggerStackTrace* stack_trace);
877
878 GroupDebugger* group_debugger() { return isolate_->group()->debugger(); }
879
880 Isolate* isolate_;
881
882 // ID number generator.
883 intptr_t next_id_;
884
885 BreakpointLocation* latent_locations_;
886 BreakpointLocation* breakpoint_locations_;
887
888 // Tells debugger what to do when resuming execution after a breakpoint.
889 ResumeAction resume_action_;
890 void set_resume_action(ResumeAction action);
891 intptr_t resume_frame_index_;
892 intptr_t post_deopt_frame_index_;
893
894 // Do not call back to breakpoint handler if this flag is set.
895 // Effectively this means ignoring breakpoints. Set when Dart code may
896 // be run as a side effect of getting values of fields.
897 bool ignore_breakpoints_;
898
899 // Indicates why the debugger is currently paused. If the debugger
900 // is not paused, this is nullptr. Note that the debugger can be
901 // paused for breakpoints, isolate interruption, and (sometimes)
902 // exceptions.
903 ServiceEvent* pause_event_;
904
905 // Current stack trace. Valid only while IsPaused().
906 DebuggerStackTrace* stack_trace_;
907 DebuggerStackTrace* async_awaiter_stack_trace_;
908
909 // When stepping through code, only pause the program if the top
910 // frame corresponds to this fp value, or if the top frame is
911 // lower on the stack.
912 uword stepping_fp_;
913
914 // When stepping through code, do not stop more than once in the same
915 // token position range.
916 uword last_stepping_fp_;
917 TokenPosition last_stepping_pos_;
918
919 // If we step while at a breakpoint, we would hit the same pc twice.
920 // We use this field to let us skip the next single-step after a
921 // breakpoint.
922 bool skip_next_step_;
923
924 Dart_ExceptionPauseInfo exc_pause_info_;
925
926 // Holds function data corresponding to suspendable
927 // function which should be stopped when resumed.
928 MallocGrowableArray<ObjectPtr> breakpoints_at_resumption_;
929
930 friend class Isolate;
931 friend class BreakpointLocation;
932 DISALLOW_COPY_AND_ASSIGN(Debugger);
933};
934
935class DisableBreakpointsScope : public ValueObject {
936 public:
937 DisableBreakpointsScope(Debugger* debugger, bool disable)
938 : debugger_(debugger) {
939 ASSERT(debugger_ != nullptr);
940 initial_state_ = debugger_->ignore_breakpoints();
941 debugger_->set_ignore_breakpoints(disable);
942 }
943
944 ~DisableBreakpointsScope() {
945 debugger_->set_ignore_breakpoints(initial_state_);
946 }
947
948 private:
949 Debugger* debugger_;
950 bool initial_state_;
951
952 DISALLOW_COPY_AND_ASSIGN(DisableBreakpointsScope);
953};
954
955} // namespace dart
956
957#endif // !defined(PRODUCT)
958
959#endif // RUNTIME_VM_DEBUGGER_H_
960

source code of flutter_engine/third_party/dart/runtime/vm/debugger.h