Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef vm_Debugger_h
8 : #define vm_Debugger_h
9 :
10 : #include "mozilla/DoublyLinkedList.h"
11 : #include "mozilla/GuardObjects.h"
12 : #include "mozilla/LinkedList.h"
13 : #include "mozilla/Range.h"
14 : #include "mozilla/TimeStamp.h"
15 : #include "mozilla/Vector.h"
16 :
17 : #include "jscntxt.h"
18 : #include "jscompartment.h"
19 : #include "jsweakmap.h"
20 : #include "jswrapper.h"
21 :
22 : #include "builtin/Promise.h"
23 : #include "ds/TraceableFifo.h"
24 : #include "gc/Barrier.h"
25 : #include "js/Debug.h"
26 : #include "js/GCVariant.h"
27 : #include "js/HashTable.h"
28 : #include "vm/GlobalObject.h"
29 : #include "vm/SavedStacks.h"
30 : #include "wasm/WasmJS.h"
31 :
32 : enum JSTrapStatus {
33 : JSTRAP_ERROR,
34 : JSTRAP_CONTINUE,
35 : JSTRAP_RETURN,
36 : JSTRAP_THROW,
37 : JSTRAP_LIMIT
38 : };
39 :
40 :
41 : namespace js {
42 :
43 : class Breakpoint;
44 : class DebuggerMemory;
45 : class ScriptedOnStepHandler;
46 : class ScriptedOnPopHandler;
47 : class WasmInstanceObject;
48 :
49 : typedef HashSet<ReadBarrieredGlobalObject,
50 : MovableCellHasher<ReadBarrieredGlobalObject>,
51 : RuntimeAllocPolicy> WeakGlobalObjectSet;
52 :
53 : /*
54 : * A weakmap from GC thing keys to JSObject values that supports the keys being
55 : * in different compartments to the values. All values must be in the same
56 : * compartment.
57 : *
58 : * The purpose of this is to allow the garbage collector to easily find edges
59 : * from debuggee object compartments to debugger compartments when calculating
60 : * the compartment groups. Note that these edges are the inverse of the edges
61 : * stored in the cross compartment map.
62 : *
63 : * The current implementation results in all debuggee object compartments being
64 : * swept in the same group as the debugger. This is a conservative approach,
65 : * and compartments may be unnecessarily grouped, however it results in a
66 : * simpler and faster implementation.
67 : *
68 : * If InvisibleKeysOk is true, then the map can have keys in invisible-to-
69 : * debugger compartments. If it is false, we assert that such entries are never
70 : * created.
71 : *
72 : * Also note that keys in these weakmaps can be in any compartment, debuggee or
73 : * not, because they cannot be deleted when a compartment is no longer a
74 : * debuggee: the values need to maintain object identity across add/remove/add
75 : * transitions.
76 : */
77 : template <class UnbarrieredKey, bool InvisibleKeysOk=false>
78 0 : class DebuggerWeakMap : private WeakMap<HeapPtr<UnbarrieredKey>, HeapPtr<JSObject*>,
79 : MovableCellHasher<HeapPtr<UnbarrieredKey>>>
80 : {
81 : private:
82 : typedef HeapPtr<UnbarrieredKey> Key;
83 : typedef HeapPtr<JSObject*> Value;
84 :
85 : typedef HashMap<JS::Zone*,
86 : uintptr_t,
87 : DefaultHasher<JS::Zone*>,
88 : RuntimeAllocPolicy> CountMap;
89 :
90 : CountMap zoneCounts;
91 : JSCompartment* compartment;
92 :
93 : public:
94 : typedef WeakMap<Key, Value, MovableCellHasher<Key>> Base;
95 :
96 0 : explicit DebuggerWeakMap(JSContext* cx)
97 : : Base(cx),
98 : zoneCounts(cx->runtime()),
99 0 : compartment(cx->compartment())
100 0 : { }
101 :
102 : public:
103 : /* Expose those parts of HashMap public interface that are used by Debugger methods. */
104 :
105 : typedef typename Base::Entry Entry;
106 : typedef typename Base::Ptr Ptr;
107 : typedef typename Base::AddPtr AddPtr;
108 : typedef typename Base::Range Range;
109 : typedef typename Base::Enum Enum;
110 : typedef typename Base::Lookup Lookup;
111 :
112 : /* Expose WeakMap public interface */
113 :
114 : using Base::lookupForAdd;
115 : using Base::all;
116 : using Base::trace;
117 :
118 0 : MOZ_MUST_USE bool init(uint32_t len = 16) {
119 0 : return Base::init(len) && zoneCounts.init();
120 : }
121 :
122 : template<typename KeyInput, typename ValueInput>
123 0 : bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) {
124 0 : MOZ_ASSERT(v->compartment() == this->compartment);
125 0 : MOZ_ASSERT(!k->compartment()->creationOptions().mergeable());
126 0 : MOZ_ASSERT_IF(!InvisibleKeysOk,
127 : !k->compartment()->creationOptions().invisibleToDebugger());
128 0 : MOZ_ASSERT(!Base::has(k));
129 0 : if (!incZoneCount(k->zone()))
130 0 : return false;
131 0 : bool ok = Base::relookupOrAdd(p, k, v);
132 0 : if (!ok)
133 0 : decZoneCount(k->zone());
134 0 : return ok;
135 : }
136 :
137 0 : void remove(const Lookup& l) {
138 0 : MOZ_ASSERT(Base::has(l));
139 0 : Base::remove(l);
140 0 : decZoneCount(l->zone());
141 0 : }
142 :
143 : public:
144 : template <void (traceValueEdges)(JSTracer*, JSObject*)>
145 0 : void traceCrossCompartmentEdges(JSTracer* tracer) {
146 0 : for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
147 0 : traceValueEdges(tracer, e.front().value());
148 0 : Key key = e.front().key();
149 0 : TraceEdge(tracer, &key, "Debugger WeakMap key");
150 0 : if (key != e.front().key())
151 0 : e.rekeyFront(key);
152 0 : key.unsafeSet(nullptr);
153 : }
154 0 : }
155 :
156 0 : bool hasKeyInZone(JS::Zone* zone) {
157 0 : CountMap::Ptr p = zoneCounts.lookup(zone);
158 0 : MOZ_ASSERT_IF(p.found(), p->value() > 0);
159 0 : return p.found();
160 : }
161 :
162 : private:
163 : /* Override sweep method to also update our edge cache. */
164 0 : void sweep() {
165 0 : MOZ_ASSERT(CurrentThreadIsPerformingGC());
166 0 : for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
167 0 : if (gc::IsAboutToBeFinalized(&e.front().mutableKey())) {
168 0 : decZoneCount(e.front().key()->zoneFromAnyThread());
169 0 : e.removeFront();
170 : }
171 : }
172 0 : Base::assertEntriesNotAboutToBeFinalized();
173 0 : }
174 :
175 0 : MOZ_MUST_USE bool incZoneCount(JS::Zone* zone) {
176 0 : CountMap::Ptr p = zoneCounts.lookupWithDefault(zone, 0);
177 0 : if (!p)
178 0 : return false;
179 0 : ++p->value();
180 0 : return true;
181 : }
182 :
183 0 : void decZoneCount(JS::Zone* zone) {
184 0 : CountMap::Ptr p = zoneCounts.lookup(zone);
185 0 : MOZ_ASSERT(p);
186 0 : MOZ_ASSERT(p->value() > 0);
187 0 : --p->value();
188 0 : if (p->value() == 0)
189 0 : zoneCounts.remove(zone);
190 0 : }
191 : };
192 :
193 : class LeaveDebuggeeNoExecute;
194 :
195 : // Suppresses all debuggee NX checks, i.e., allow all execution. Used to allow
196 : // certain whitelisted operations to execute code.
197 : //
198 : // WARNING
199 : // WARNING Do not use this unless you know what you are doing!
200 : // WARNING
201 : class AutoSuppressDebuggeeNoExecuteChecks
202 : {
203 : EnterDebuggeeNoExecute** stack_;
204 : EnterDebuggeeNoExecute* prev_;
205 :
206 : public:
207 1709 : explicit AutoSuppressDebuggeeNoExecuteChecks(JSContext* cx) {
208 1709 : stack_ = &cx->noExecuteDebuggerTop.ref();
209 1709 : prev_ = *stack_;
210 1709 : *stack_ = nullptr;
211 1709 : }
212 :
213 3420 : ~AutoSuppressDebuggeeNoExecuteChecks() {
214 1710 : MOZ_ASSERT(!*stack_);
215 1710 : *stack_ = prev_;
216 1710 : }
217 : };
218 :
219 : class MOZ_RAII EvalOptions {
220 : const char* filename_;
221 : unsigned lineno_;
222 :
223 : public:
224 0 : EvalOptions() : filename_(nullptr), lineno_(1) {}
225 : ~EvalOptions();
226 0 : const char* filename() const { return filename_; }
227 0 : unsigned lineno() const { return lineno_; }
228 : MOZ_MUST_USE bool setFilename(JSContext* cx, const char* filename);
229 0 : void setLineno(unsigned lineno) { lineno_ = lineno; }
230 : };
231 :
232 : /*
233 : * Env is the type of what ES5 calls "lexical environments" (runtime activations
234 : * of lexical scopes). This is currently just JSObject, and is implemented by
235 : * CallObject, LexicalEnvironmentObject, and WithEnvironmentObject, among
236 : * others--but environments and objects are really two different concepts.
237 : */
238 : typedef JSObject Env;
239 :
240 : // Either a real JSScript or synthesized.
241 : //
242 : // If synthesized, the referent is one of the following:
243 : //
244 : // 1. A WasmInstanceObject, denoting a synthesized toplevel wasm module
245 : // script.
246 : // 2. A wasm JSFunction, denoting a synthesized wasm function script.
247 : // NYI!
248 : typedef mozilla::Variant<JSScript*, WasmInstanceObject*> DebuggerScriptReferent;
249 :
250 : // Either a ScriptSourceObject, for ordinary JS, or a WasmInstanceObject,
251 : // denoting the synthesized source of a wasm module.
252 : typedef mozilla::Variant<ScriptSourceObject*, WasmInstanceObject*> DebuggerSourceReferent;
253 :
254 : // Either a AbstractFramePtr, for ordinary JS, or a wasm::DebugFrame,
255 : // for synthesized frame of a wasm code.
256 : typedef mozilla::Variant<AbstractFramePtr, wasm::DebugFrame*> DebuggerFrameReferent;
257 :
258 : class Debugger : private mozilla::LinkedListElement<Debugger>
259 : {
260 : friend class Breakpoint;
261 : friend class DebuggerMemory;
262 : friend struct JSRuntime::GlobalObjectWatchersSiblingAccess<Debugger>;
263 : friend class SavedStacks;
264 : friend class ScriptedOnStepHandler;
265 : friend class ScriptedOnPopHandler;
266 : friend class mozilla::LinkedListElement<Debugger>;
267 : friend class mozilla::LinkedList<Debugger>;
268 : friend bool (::JS_DefineDebuggerObject)(JSContext* cx, JS::HandleObject obj);
269 : friend bool (::JS::dbg::IsDebugger)(JSObject&);
270 : friend bool (::JS::dbg::GetDebuggeeGlobals)(JSContext*, JSObject&, AutoObjectVector&);
271 : friend void JS::dbg::onNewPromise(JSContext* cx, HandleObject promise);
272 : friend void JS::dbg::onPromiseSettled(JSContext* cx, HandleObject promise);
273 : friend bool JS::dbg::FireOnGarbageCollectionHookRequired(JSContext* cx);
274 : friend bool JS::dbg::FireOnGarbageCollectionHook(JSContext* cx,
275 : JS::dbg::GarbageCollectionEvent::Ptr&& data);
276 :
277 : public:
278 : enum Hook {
279 : OnDebuggerStatement,
280 : OnExceptionUnwind,
281 : OnNewScript,
282 : OnEnterFrame,
283 : OnNewGlobalObject,
284 : OnNewPromise,
285 : OnPromiseSettled,
286 : OnGarbageCollection,
287 : HookCount
288 : };
289 : enum {
290 : JSSLOT_DEBUG_PROTO_START,
291 : JSSLOT_DEBUG_FRAME_PROTO = JSSLOT_DEBUG_PROTO_START,
292 : JSSLOT_DEBUG_ENV_PROTO,
293 : JSSLOT_DEBUG_OBJECT_PROTO,
294 : JSSLOT_DEBUG_SCRIPT_PROTO,
295 : JSSLOT_DEBUG_SOURCE_PROTO,
296 : JSSLOT_DEBUG_MEMORY_PROTO,
297 : JSSLOT_DEBUG_PROTO_STOP,
298 : JSSLOT_DEBUG_HOOK_START = JSSLOT_DEBUG_PROTO_STOP,
299 : JSSLOT_DEBUG_HOOK_STOP = JSSLOT_DEBUG_HOOK_START + HookCount,
300 : JSSLOT_DEBUG_MEMORY_INSTANCE = JSSLOT_DEBUG_HOOK_STOP,
301 : JSSLOT_DEBUG_COUNT
302 : };
303 :
304 0 : class ExecutionObservableSet
305 : {
306 : public:
307 : typedef HashSet<Zone*>::Range ZoneRange;
308 :
309 0 : virtual Zone* singleZone() const { return nullptr; }
310 0 : virtual JSScript* singleScriptForZoneInvalidation() const { return nullptr; }
311 0 : virtual const HashSet<Zone*>* zones() const { return nullptr; }
312 :
313 : virtual bool shouldRecompileOrInvalidate(JSScript* script) const = 0;
314 : virtual bool shouldMarkAsDebuggee(FrameIter& iter) const = 0;
315 : };
316 :
317 : // This enum is converted to and compare with bool values; NotObserving
318 : // must be 0 and Observing must be 1.
319 : enum IsObserving {
320 : NotObserving = 0,
321 : Observing = 1
322 : };
323 :
324 : // Return true if the given compartment is a debuggee of this debugger,
325 : // false otherwise.
326 : bool isDebuggeeUnbarriered(const JSCompartment* compartment) const;
327 :
328 : // Return true if this Debugger observed a debuggee that participated in the
329 : // GC identified by the given GC number. Return false otherwise.
330 : // May return false negatives if we have hit OOM.
331 0 : bool observedGC(uint64_t majorGCNumber) const {
332 0 : return observedGCs.has(majorGCNumber);
333 : }
334 :
335 : // Notify this Debugger that one or more of its debuggees is participating
336 : // in the GC identified by the given GC number.
337 0 : bool debuggeeIsBeingCollected(uint64_t majorGCNumber) {
338 0 : return observedGCs.put(majorGCNumber);
339 : }
340 :
341 0 : bool isEnabled() const {
342 0 : return enabled;
343 : }
344 :
345 : static SavedFrame* getObjectAllocationSite(JSObject& obj);
346 :
347 0 : struct AllocationsLogEntry
348 : {
349 0 : AllocationsLogEntry(HandleObject frame, mozilla::TimeStamp when, const char* className,
350 : HandleAtom ctorName, size_t size, bool inNursery)
351 0 : : frame(frame),
352 : when(when),
353 : className(className),
354 : ctorName(ctorName),
355 : size(size),
356 0 : inNursery(inNursery)
357 : {
358 0 : MOZ_ASSERT_IF(frame, UncheckedUnwrap(frame)->is<SavedFrame>());
359 0 : };
360 :
361 : HeapPtr<JSObject*> frame;
362 : mozilla::TimeStamp when;
363 : const char* className;
364 : HeapPtr<JSAtom*> ctorName;
365 : size_t size;
366 : bool inNursery;
367 :
368 0 : void trace(JSTracer* trc) {
369 0 : TraceNullableEdge(trc, &frame, "Debugger::AllocationsLogEntry::frame");
370 0 : TraceNullableEdge(trc, &ctorName, "Debugger::AllocationsLogEntry::ctorName");
371 0 : }
372 : };
373 :
374 : // Barrier methods so we can have ReadBarriered<Debugger*>.
375 0 : static void readBarrier(Debugger* dbg) {
376 0 : InternalBarrierMethods<JSObject*>::readBarrier(dbg->object);
377 0 : }
378 0 : static void writeBarrierPost(Debugger** vp, Debugger* prev, Debugger* next) {}
379 :
380 : private:
381 : GCPtrNativeObject object; /* The Debugger object. Strong reference. */
382 : WeakGlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */
383 : JS::ZoneSet debuggeeZones; /* Set of zones that we have debuggees in. */
384 : js::GCPtrObject uncaughtExceptionHook; /* Strong reference. */
385 : bool enabled;
386 : bool allowUnobservedAsmJS;
387 : bool allowWasmBinarySource;
388 :
389 : // Whether to enable code coverage on the Debuggee.
390 : bool collectCoverageInfo;
391 :
392 : template<typename T>
393 : struct DebuggerSiblingAccess {
394 0 : static T* GetNext(T* elm) {
395 0 : return elm->debuggerLink.mNext;
396 : }
397 0 : static void SetNext(T* elm, T* next) {
398 0 : elm->debuggerLink.mNext = next;
399 0 : }
400 0 : static T* GetPrev(T* elm) {
401 0 : return elm->debuggerLink.mPrev;
402 : }
403 0 : static void SetPrev(T* elm, T* prev) {
404 0 : elm->debuggerLink.mPrev = prev;
405 0 : }
406 : };
407 :
408 : // List of all js::Breakpoints in this debugger.
409 : using BreakpointList =
410 : mozilla::DoublyLinkedList<js::Breakpoint,
411 : DebuggerSiblingAccess<js::Breakpoint>>;
412 : BreakpointList breakpoints;
413 :
414 : // The set of GC numbers for which one or more of this Debugger's observed
415 : // debuggees participated in.
416 : using GCNumberSet = HashSet<uint64_t, DefaultHasher<uint64_t>, RuntimeAllocPolicy>;
417 : GCNumberSet observedGCs;
418 :
419 : using AllocationsLog = js::TraceableFifo<AllocationsLogEntry>;
420 :
421 : AllocationsLog allocationsLog;
422 : bool trackingAllocationSites;
423 : double allocationSamplingProbability;
424 : size_t maxAllocationsLogLength;
425 : bool allocationsLogOverflowed;
426 :
427 : static const size_t DEFAULT_MAX_LOG_LENGTH = 5000;
428 :
429 : MOZ_MUST_USE bool appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame,
430 : mozilla::TimeStamp when);
431 :
432 : /*
433 : * Recompute the set of debuggee zones based on the set of debuggee globals.
434 : */
435 : void recomputeDebuggeeZoneSet();
436 :
437 : /*
438 : * Return true if there is an existing object metadata callback for the
439 : * given global's compartment that will prevent our instrumentation of
440 : * allocations.
441 : */
442 : static bool cannotTrackAllocations(const GlobalObject& global);
443 :
444 : /*
445 : * Return true if the given global is being observed by at least one
446 : * Debugger that is tracking allocations.
447 : */
448 : static bool isObservedByDebuggerTrackingAllocations(const GlobalObject& global);
449 :
450 : /*
451 : * Add allocations tracking for objects allocated within the given
452 : * debuggee's compartment. The given debuggee global must be observed by at
453 : * least one Debugger that is enabled and tracking allocations.
454 : */
455 : static MOZ_MUST_USE bool addAllocationsTracking(JSContext* cx, Handle<GlobalObject*> debuggee);
456 :
457 : /*
458 : * Remove allocations tracking for objects allocated within the given
459 : * global's compartment. This is a no-op if there are still Debuggers
460 : * observing this global and who are tracking allocations.
461 : */
462 : static void removeAllocationsTracking(GlobalObject& global);
463 :
464 : /*
465 : * Add or remove allocations tracking for all debuggees.
466 : */
467 : MOZ_MUST_USE bool addAllocationsTrackingForAllDebuggees(JSContext* cx);
468 : void removeAllocationsTrackingForAllDebuggees();
469 :
470 : /*
471 : * If this Debugger is enabled, and has a onNewGlobalObject handler, then
472 : * this link is inserted into the list headed by
473 : * JSRuntime::onNewGlobalObjectWatchers.
474 : */
475 : mozilla::DoublyLinkedListElement<Debugger> onNewGlobalObjectWatchersLink;
476 :
477 : /*
478 : * Map from stack frames that are currently on the stack to Debugger.Frame
479 : * instances.
480 : *
481 : * The keys are always live stack frames. We drop them from this map as
482 : * soon as they leave the stack (see slowPathOnLeaveFrame) and in
483 : * removeDebuggee.
484 : *
485 : * We don't trace the keys of this map (the frames are on the stack and
486 : * thus necessarily live), but we do trace the values. It's like a WeakMap
487 : * that way, but since stack frames are not gc-things, the implementation
488 : * has to be different.
489 : */
490 : typedef HashMap<AbstractFramePtr,
491 : HeapPtr<DebuggerFrame*>,
492 : DefaultHasher<AbstractFramePtr>,
493 : RuntimeAllocPolicy> FrameMap;
494 : FrameMap frames;
495 :
496 : /* An ephemeral map from JSScript* to Debugger.Script instances. */
497 : typedef DebuggerWeakMap<JSScript*> ScriptWeakMap;
498 : ScriptWeakMap scripts;
499 :
500 : /* The map from debuggee source script objects to their Debugger.Source instances. */
501 : typedef DebuggerWeakMap<JSObject*, true> SourceWeakMap;
502 : SourceWeakMap sources;
503 :
504 : /* The map from debuggee objects to their Debugger.Object instances. */
505 : typedef DebuggerWeakMap<JSObject*> ObjectWeakMap;
506 : ObjectWeakMap objects;
507 :
508 : /* The map from debuggee Envs to Debugger.Environment instances. */
509 : ObjectWeakMap environments;
510 :
511 : /* The map from WasmInstanceObjects to synthesized Debugger.Script instances. */
512 : typedef DebuggerWeakMap<WasmInstanceObject*> WasmInstanceWeakMap;
513 : WasmInstanceWeakMap wasmInstanceScripts;
514 :
515 : /* The map from WasmInstanceObjects to synthesized Debugger.Source instances. */
516 : WasmInstanceWeakMap wasmInstanceSources;
517 :
518 : /*
519 : * Keep track of tracelogger last drained identifiers to know if there are
520 : * lost events.
521 : */
522 : #ifdef NIGHTLY_BUILD
523 : uint32_t traceLoggerLastDrainedSize;
524 : uint32_t traceLoggerLastDrainedIteration;
525 : #endif
526 : uint32_t traceLoggerScriptedCallsLastDrainedSize;
527 : uint32_t traceLoggerScriptedCallsLastDrainedIteration;
528 :
529 : class ScriptQuery;
530 : class ObjectQuery;
531 :
532 : MOZ_MUST_USE bool addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> obj);
533 : void removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
534 : WeakGlobalObjectSet::Enum* debugEnum);
535 :
536 : /*
537 : * Report and clear the pending exception on ac.context, if any, and return
538 : * JSTRAP_ERROR.
539 : */
540 : JSTrapStatus reportUncaughtException(mozilla::Maybe<AutoCompartment>& ac);
541 :
542 : /*
543 : * Cope with an error or exception in a debugger hook.
544 : *
545 : * If callHook is true, then call the uncaughtExceptionHook, if any. If, in
546 : * addition, vp is given, then parse the value returned by
547 : * uncaughtExceptionHook as a resumption value.
548 : *
549 : * If there is no uncaughtExceptionHook, or if it fails, report and clear
550 : * the pending exception on ac.context and return JSTRAP_ERROR.
551 : *
552 : * This always calls ac.leave(); ac is a parameter because this method must
553 : * do some things in the debugger compartment and some things in the
554 : * debuggee compartment.
555 : */
556 : JSTrapStatus handleUncaughtException(mozilla::Maybe<AutoCompartment>& ac);
557 : JSTrapStatus handleUncaughtException(mozilla::Maybe<AutoCompartment>& ac,
558 : MutableHandleValue vp,
559 : const mozilla::Maybe<HandleValue>& thisVForCheck = mozilla::Nothing(),
560 : AbstractFramePtr frame = NullFramePtr());
561 :
562 : JSTrapStatus handleUncaughtExceptionHelper(mozilla::Maybe<AutoCompartment>& ac,
563 : MutableHandleValue* vp,
564 : const mozilla::Maybe<HandleValue>& thisVForCheck,
565 : AbstractFramePtr frame);
566 :
567 : /*
568 : * Handle the result of a hook that is expected to return a resumption
569 : * value <https://wiki.mozilla.org/Debugger#Resumption_Values>. This is called
570 : * when we return from a debugging hook to debuggee code. The interpreter wants
571 : * a (JSTrapStatus, Value) pair telling it how to proceed.
572 : *
573 : * Precondition: ac is entered. We are in the debugger compartment.
574 : *
575 : * Postcondition: This called ac.leave(). See handleUncaughtException.
576 : *
577 : * If ok is false, the hook failed. If an exception is pending in
578 : * ac.context(), return handleUncaughtException(ac, vp, callhook).
579 : * Otherwise just return JSTRAP_ERROR.
580 : *
581 : * If ok is true, there must be no exception pending in ac.context(). rv may be:
582 : * undefined - Return JSTRAP_CONTINUE to continue execution normally.
583 : * {return: value} or {throw: value} - Call unwrapDebuggeeValue to
584 : * unwrap value. Store the result in *vp and return JSTRAP_RETURN
585 : * or JSTRAP_THROW. The interpreter will force the current frame to
586 : * return or throw an exception.
587 : * null - Return JSTRAP_ERROR to terminate the debuggee with an
588 : * uncatchable error.
589 : * anything else - Make a new TypeError the pending exception and
590 : * return handleUncaughtException(ac, vp, callHook).
591 : */
592 : JSTrapStatus processHandlerResult(mozilla::Maybe<AutoCompartment>& ac, bool OK, const Value& rv,
593 : AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp);
594 :
595 : JSTrapStatus processParsedHandlerResult(mozilla::Maybe<AutoCompartment>& ac,
596 : AbstractFramePtr frame, jsbytecode* pc,
597 : bool success, JSTrapStatus status,
598 : MutableHandleValue vp);
599 :
600 : JSTrapStatus processParsedHandlerResultHelper(mozilla::Maybe<AutoCompartment>& ac,
601 : AbstractFramePtr frame,
602 : const mozilla::Maybe<HandleValue>& maybeThisv,
603 : bool success, JSTrapStatus status,
604 : MutableHandleValue vp);
605 :
606 : bool processResumptionValue(mozilla::Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
607 : const mozilla::Maybe<HandleValue>& maybeThis, HandleValue rval,
608 : JSTrapStatus& statusp, MutableHandleValue vp);
609 :
610 : GlobalObject* unwrapDebuggeeArgument(JSContext* cx, const Value& v);
611 :
612 : static void traceObject(JSTracer* trc, JSObject* obj);
613 :
614 : void trace(JSTracer* trc);
615 : friend struct js::GCManagedDeletePolicy<Debugger>;
616 :
617 : void traceForMovingGC(JSTracer* trc);
618 : void traceCrossCompartmentEdges(JSTracer* tracer);
619 :
620 : static const ClassOps classOps_;
621 :
622 : public:
623 : static const Class class_;
624 :
625 : private:
626 : static MOZ_MUST_USE bool getHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which);
627 : static MOZ_MUST_USE bool setHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which);
628 :
629 : static bool getEnabled(JSContext* cx, unsigned argc, Value* vp);
630 : static bool setEnabled(JSContext* cx, unsigned argc, Value* vp);
631 : static bool getOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp);
632 : static bool setOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp);
633 : static bool getOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp);
634 : static bool setOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp);
635 : static bool getOnNewScript(JSContext* cx, unsigned argc, Value* vp);
636 : static bool setOnNewScript(JSContext* cx, unsigned argc, Value* vp);
637 : static bool getOnEnterFrame(JSContext* cx, unsigned argc, Value* vp);
638 : static bool setOnEnterFrame(JSContext* cx, unsigned argc, Value* vp);
639 : static bool getOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp);
640 : static bool setOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp);
641 : static bool getOnNewPromise(JSContext* cx, unsigned argc, Value* vp);
642 : static bool setOnNewPromise(JSContext* cx, unsigned argc, Value* vp);
643 : static bool getOnPromiseSettled(JSContext* cx, unsigned argc, Value* vp);
644 : static bool setOnPromiseSettled(JSContext* cx, unsigned argc, Value* vp);
645 : static bool getUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp);
646 : static bool setUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp);
647 : static bool getAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp);
648 : static bool setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp);
649 : static bool getAllowWasmBinarySource(JSContext* cx, unsigned argc, Value* vp);
650 : static bool setAllowWasmBinarySource(JSContext* cx, unsigned argc, Value* vp);
651 : static bool getCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp);
652 : static bool setCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp);
653 : static bool getMemory(JSContext* cx, unsigned argc, Value* vp);
654 : static bool addDebuggee(JSContext* cx, unsigned argc, Value* vp);
655 : static bool addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp);
656 : static bool removeDebuggee(JSContext* cx, unsigned argc, Value* vp);
657 : static bool removeAllDebuggees(JSContext* cx, unsigned argc, Value* vp);
658 : static bool hasDebuggee(JSContext* cx, unsigned argc, Value* vp);
659 : static bool getDebuggees(JSContext* cx, unsigned argc, Value* vp);
660 : static bool getNewestFrame(JSContext* cx, unsigned argc, Value* vp);
661 : static bool clearAllBreakpoints(JSContext* cx, unsigned argc, Value* vp);
662 : static bool findScripts(JSContext* cx, unsigned argc, Value* vp);
663 : static bool findObjects(JSContext* cx, unsigned argc, Value* vp);
664 : static bool findAllGlobals(JSContext* cx, unsigned argc, Value* vp);
665 : static bool makeGlobalObjectReference(JSContext* cx, unsigned argc, Value* vp);
666 : static bool setupTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp);
667 : static bool drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp);
668 : static bool startTraceLogger(JSContext* cx, unsigned argc, Value* vp);
669 : static bool endTraceLogger(JSContext* cx, unsigned argc, Value* vp);
670 : static bool isCompilableUnit(JSContext* cx, unsigned argc, Value* vp);
671 : #ifdef NIGHTLY_BUILD
672 : static bool setupTraceLogger(JSContext* cx, unsigned argc, Value* vp);
673 : static bool drainTraceLogger(JSContext* cx, unsigned argc, Value* vp);
674 : #endif
675 : static bool adoptDebuggeeValue(JSContext* cx, unsigned argc, Value* vp);
676 : static bool construct(JSContext* cx, unsigned argc, Value* vp);
677 : static const JSPropertySpec properties[];
678 : static const JSFunctionSpec methods[];
679 : static const JSFunctionSpec static_methods[];
680 :
681 : static void removeFromFrameMapsAndClearBreakpointsIn(JSContext* cx, AbstractFramePtr frame);
682 : static bool updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObservableSet& obs,
683 : IsObserving observing);
684 : static bool updateExecutionObservabilityOfScripts(JSContext* cx, const ExecutionObservableSet& obs,
685 : IsObserving observing);
686 : static bool updateExecutionObservability(JSContext* cx, ExecutionObservableSet& obs,
687 : IsObserving observing);
688 :
689 : template <typename FrameFn /* void (NativeObject*) */>
690 : static void forEachDebuggerFrame(AbstractFramePtr frame, FrameFn fn);
691 :
692 : /*
693 : * Return a vector containing all Debugger.Frame instances referring to
694 : * |frame|. |global| is |frame|'s global object; if nullptr or omitted, we
695 : * compute it ourselves from |frame|.
696 : */
697 : using DebuggerFrameVector = GCVector<DebuggerFrame*>;
698 : static MOZ_MUST_USE bool getDebuggerFrames(AbstractFramePtr frame,
699 : MutableHandle<DebuggerFrameVector> frames);
700 :
701 : public:
702 : static MOZ_MUST_USE bool ensureExecutionObservabilityOfOsrFrame(JSContext* cx,
703 : InterpreterFrame* frame);
704 :
705 : // Public for DebuggerScript_setBreakpoint.
706 : static MOZ_MUST_USE bool ensureExecutionObservabilityOfScript(JSContext* cx, JSScript* script);
707 :
708 : // Whether the Debugger instance needs to observe all non-AOT JS
709 : // execution of its debugees.
710 : IsObserving observesAllExecution() const;
711 :
712 : // Whether the Debugger instance needs to observe AOT-compiled asm.js
713 : // execution of its debuggees.
714 : IsObserving observesAsmJS() const;
715 :
716 : // Whether the Debugger instance needs to observe coverage of any JavaScript
717 : // execution.
718 : IsObserving observesCoverage() const;
719 :
720 : IsObserving observesBinarySource() const;
721 :
722 : private:
723 : static MOZ_MUST_USE bool ensureExecutionObservabilityOfFrame(JSContext* cx,
724 : AbstractFramePtr frame);
725 : static MOZ_MUST_USE bool ensureExecutionObservabilityOfCompartment(JSContext* cx,
726 : JSCompartment* comp);
727 :
728 : static bool hookObservesAllExecution(Hook which);
729 :
730 : MOZ_MUST_USE bool updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving observing);
731 : MOZ_MUST_USE bool updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing);
732 : void updateObservesAsmJSOnDebuggees(IsObserving observing);
733 : void updateObservesBinarySourceDebuggees(IsObserving observing);
734 :
735 : JSObject* getHook(Hook hook) const;
736 : bool hasAnyLiveHooks(JSRuntime* rt) const;
737 :
738 : static MOZ_MUST_USE bool slowPathCheckNoExecute(JSContext* cx, HandleScript script);
739 : static JSTrapStatus slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame);
740 : static MOZ_MUST_USE bool slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame,
741 : jsbytecode* pc, bool ok);
742 : static JSTrapStatus slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame);
743 : static JSTrapStatus slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame);
744 : static void slowPathOnNewScript(JSContext* cx, HandleScript script);
745 : static void slowPathOnNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
746 : static void slowPathOnNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global);
747 : static MOZ_MUST_USE bool slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj,
748 : HandleSavedFrame frame,
749 : mozilla::TimeStamp when,
750 : GlobalObject::DebuggerVector& dbgs);
751 : static void slowPathPromiseHook(JSContext* cx, Hook hook, HandleObject promise);
752 :
753 : template <typename HookIsEnabledFun /* bool (Debugger*) */,
754 : typename FireHookFun /* JSTrapStatus (Debugger*) */>
755 : static JSTrapStatus dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled,
756 : FireHookFun fireHook);
757 :
758 : JSTrapStatus fireDebuggerStatement(JSContext* cx, MutableHandleValue vp);
759 : JSTrapStatus fireExceptionUnwind(JSContext* cx, MutableHandleValue vp);
760 : JSTrapStatus fireEnterFrame(JSContext* cx, MutableHandleValue vp);
761 : JSTrapStatus fireNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global, MutableHandleValue vp);
762 : JSTrapStatus firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp);
763 :
764 0 : NativeObject* newVariantWrapper(JSContext* cx, Handle<DebuggerScriptReferent> referent) {
765 0 : return newDebuggerScript(cx, referent);
766 : }
767 0 : NativeObject* newVariantWrapper(JSContext* cx, Handle<DebuggerSourceReferent> referent) {
768 0 : return newDebuggerSource(cx, referent);
769 : }
770 :
771 : /*
772 : * Helper function to help wrap Debugger objects whose referents may be
773 : * variants. Currently Debugger.Script and Debugger.Source referents may
774 : * be variants.
775 : *
776 : * Prefer using wrapScript, wrapWasmScript, wrapSource, and wrapWasmSource
777 : * whenever possible.
778 : */
779 : template <typename ReferentVariant, typename Referent, typename Map>
780 : JSObject* wrapVariantReferent(JSContext* cx, Map& map, Handle<CrossCompartmentKey> key,
781 : Handle<ReferentVariant> referent);
782 : JSObject* wrapVariantReferent(JSContext* cx, Handle<DebuggerScriptReferent> referent);
783 : JSObject* wrapVariantReferent(JSContext* cx, Handle<DebuggerSourceReferent> referent);
784 :
785 : /*
786 : * Allocate and initialize a Debugger.Script instance whose referent is
787 : * |referent|.
788 : */
789 : NativeObject* newDebuggerScript(JSContext* cx, Handle<DebuggerScriptReferent> referent);
790 :
791 : /*
792 : * Allocate and initialize a Debugger.Source instance whose referent is
793 : * |referent|.
794 : */
795 : NativeObject* newDebuggerSource(JSContext* cx, Handle<DebuggerSourceReferent> referent);
796 :
797 : /*
798 : * Receive a "new script" event from the engine. A new script was compiled
799 : * or deserialized.
800 : */
801 : void fireNewScript(JSContext* cx, Handle<DebuggerScriptReferent> scriptReferent);
802 :
803 : /*
804 : * Receive a "garbage collection" event from the engine. A GC cycle with the
805 : * given data was recently completed.
806 : */
807 : void fireOnGarbageCollectionHook(JSContext* cx,
808 : const JS::dbg::GarbageCollectionEvent::Ptr& gcData);
809 :
810 : /*
811 : * Gets a Debugger.Frame object. If maybeIter is non-null, we eagerly copy
812 : * its data if we need to make a new Debugger.Frame.
813 : */
814 : MOZ_MUST_USE bool getScriptFrameWithIter(JSContext* cx, AbstractFramePtr frame,
815 : const FrameIter* maybeIter,
816 : MutableHandleValue vp);
817 : MOZ_MUST_USE bool getScriptFrameWithIter(JSContext* cx, AbstractFramePtr frame,
818 : const FrameIter* maybeIter,
819 : MutableHandleDebuggerFrame result);
820 :
821 : inline Breakpoint* firstBreakpoint() const;
822 :
823 : static MOZ_MUST_USE bool replaceFrameGuts(JSContext* cx, AbstractFramePtr from,
824 : AbstractFramePtr to,
825 : ScriptFrameIter& iter);
826 :
827 : public:
828 : Debugger(JSContext* cx, NativeObject* dbg);
829 : ~Debugger();
830 :
831 : MOZ_MUST_USE bool init(JSContext* cx);
832 : inline const js::GCPtrNativeObject& toJSObject() const;
833 : inline js::GCPtrNativeObject& toJSObjectRef();
834 : static inline Debugger* fromJSObject(const JSObject* obj);
835 : static Debugger* fromChildJSObject(JSObject* obj);
836 :
837 : Zone* zone() const { return toJSObject()->zone(); }
838 :
839 : bool hasMemory() const;
840 : DebuggerMemory& memory() const;
841 :
842 0 : WeakGlobalObjectSet::Range allDebuggees() const { return debuggees.all(); }
843 :
844 : /*********************************** Methods for interaction with the GC. */
845 :
846 : /*
847 : * A Debugger object is live if:
848 : * * the Debugger JSObject is live (Debugger::trace handles this case); OR
849 : * * it is in the middle of dispatching an event (the event dispatching
850 : * code roots it in this case); OR
851 : * * it is enabled, and it is debugging at least one live compartment,
852 : * and at least one of the following is true:
853 : * - it has a debugger hook installed
854 : * - it has a breakpoint set on a live script
855 : * - it has a watchpoint set on a live object.
856 : *
857 : * Debugger::markIteratively handles the last case. If it finds any Debugger
858 : * objects that are definitely live but not yet marked, it marks them and
859 : * returns true. If not, it returns false.
860 : */
861 : static void traceIncomingCrossCompartmentEdges(JSTracer* tracer);
862 : static MOZ_MUST_USE bool markIteratively(GCMarker* marker);
863 : static void traceAllForMovingGC(JSTracer* trc);
864 : static void sweepAll(FreeOp* fop);
865 : static void detachAllDebuggersFromGlobal(FreeOp* fop, GlobalObject* global);
866 : static void findZoneEdges(JS::Zone* v, gc::ZoneComponentFinder& finder);
867 : #ifdef DEBUG
868 : static bool isDebuggerCrossCompartmentEdge(JSObject* obj, const js::gc::Cell* cell);
869 : #endif
870 :
871 : // Checks it the current compartment is allowed to execute code.
872 : static inline MOZ_MUST_USE bool checkNoExecute(JSContext* cx, HandleScript script);
873 :
874 : /*
875 : * JSTrapStatus Overview
876 : * ---------------------
877 : *
878 : * The |onEnterFrame|, |onDebuggerStatement|, and |onExceptionUnwind|
879 : * methods below return a JSTrapStatus code that indicates how execution
880 : * should proceed:
881 : *
882 : * - JSTRAP_CONTINUE: Continue execution normally.
883 : *
884 : * - JSTRAP_THROW: Throw an exception. The method has set |cx|'s
885 : * pending exception to the value to be thrown.
886 : *
887 : * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated
888 : * for running too long). The method has cleared |cx|'s pending
889 : * exception.
890 : *
891 : * - JSTRAP_RETURN: Return from the new frame immediately. The method has
892 : * set the youngest JS frame's return value appropriately.
893 : */
894 :
895 : /*
896 : * Announce to the debugger that the context has entered a new JavaScript
897 : * frame, |frame|. Call whatever hooks have been registered to observe new
898 : * frames.
899 : */
900 : static inline JSTrapStatus onEnterFrame(JSContext* cx, AbstractFramePtr frame);
901 :
902 : /*
903 : * Announce to the debugger a |debugger;| statement on has been
904 : * encountered on the youngest JS frame on |cx|. Call whatever hooks have
905 : * been registered to observe this.
906 : *
907 : * Note that this method is called for all |debugger;| statements,
908 : * regardless of the frame's debuggee-ness.
909 : */
910 : static inline JSTrapStatus onDebuggerStatement(JSContext* cx, AbstractFramePtr frame);
911 :
912 : /*
913 : * Announce to the debugger that an exception has been thrown and propagated
914 : * to |frame|. Call whatever hooks have been registered to observe this.
915 : */
916 : static inline JSTrapStatus onExceptionUnwind(JSContext* cx, AbstractFramePtr frame);
917 :
918 : /*
919 : * Announce to the debugger that the thread has exited a JavaScript frame, |frame|.
920 : * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
921 : * is throwing an exception or terminating.
922 : *
923 : * Change cx's current exception and |frame|'s return value to reflect the changes
924 : * in behavior the hooks request, if any. Return the new error/success value.
925 : *
926 : * This function may be called twice for the same outgoing frame; only the
927 : * first call has any effect. (Permitting double calls simplifies some
928 : * cases where an onPop handler's resumption value changes a return to a
929 : * throw, or vice versa: we can redirect to a complete copy of the
930 : * alternative path, containing its own call to onLeaveFrame.)
931 : */
932 : static inline MOZ_MUST_USE bool onLeaveFrame(JSContext* cx, AbstractFramePtr frame,
933 : jsbytecode* pc, bool ok);
934 :
935 : static inline void onNewScript(JSContext* cx, HandleScript script);
936 : static inline void onNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
937 : static inline void onNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global);
938 : static inline MOZ_MUST_USE bool onLogAllocationSite(JSContext* cx, JSObject* obj,
939 : HandleSavedFrame frame, mozilla::TimeStamp when);
940 : static JSTrapStatus onTrap(JSContext* cx, MutableHandleValue vp);
941 : static JSTrapStatus onSingleStep(JSContext* cx, MutableHandleValue vp);
942 : static MOZ_MUST_USE bool handleBaselineOsr(JSContext* cx, InterpreterFrame* from,
943 : jit::BaselineFrame* to);
944 : static MOZ_MUST_USE bool handleIonBailout(JSContext* cx, jit::RematerializedFrame* from,
945 : jit::BaselineFrame* to);
946 : static void handleUnrecoverableIonBailoutError(JSContext* cx, jit::RematerializedFrame* frame);
947 : static void propagateForcedReturn(JSContext* cx, AbstractFramePtr frame, HandleValue rval);
948 : static bool hasLiveHook(GlobalObject* global, Hook which);
949 : static bool inFrameMaps(AbstractFramePtr frame);
950 :
951 : /************************************* Functions for use by Debugger.cpp. */
952 :
953 : inline bool observesEnterFrame() const;
954 : inline bool observesNewScript() const;
955 : inline bool observesNewGlobalObject() const;
956 : inline bool observesGlobal(GlobalObject* global) const;
957 : bool observesFrame(AbstractFramePtr frame) const;
958 : bool observesFrame(const FrameIter& iter) const;
959 : bool observesScript(JSScript* script) const;
960 : bool observesWasm(wasm::Instance* instance) const;
961 :
962 : /*
963 : * If env is nullptr, call vp->setNull() and return true. Otherwise, find
964 : * or create a Debugger.Environment object for the given Env. On success,
965 : * store the Environment object in *vp and return true.
966 : */
967 : MOZ_MUST_USE bool wrapEnvironment(JSContext* cx, Handle<Env*> env, MutableHandleValue vp);
968 : MOZ_MUST_USE bool wrapEnvironment(JSContext* cx, Handle<Env*> env,
969 : MutableHandleDebuggerEnvironment result);
970 :
971 : /*
972 : * Like cx->compartment()->wrap(cx, vp), but for the debugger compartment.
973 : *
974 : * Preconditions: *vp is a value from a debuggee compartment; cx is in the
975 : * debugger's compartment.
976 : *
977 : * If *vp is an object, this produces a (new or existing) Debugger.Object
978 : * wrapper for it. Otherwise this is the same as JSCompartment::wrap.
979 : *
980 : * If *vp is a magic JS_OPTIMIZED_OUT value, this produces a plain object
981 : * of the form { optimizedOut: true }.
982 : *
983 : * If *vp is a magic JS_OPTIMIZED_ARGUMENTS value signifying missing
984 : * arguments, this produces a plain object of the form { missingArguments:
985 : * true }.
986 : *
987 : * If *vp is a magic JS_UNINITIALIZED_LEXICAL value signifying an
988 : * unaccessible uninitialized binding, this produces a plain object of the
989 : * form { uninitialized: true }.
990 : */
991 : MOZ_MUST_USE bool wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp);
992 : MOZ_MUST_USE bool wrapDebuggeeObject(JSContext* cx, HandleObject obj,
993 : MutableHandleDebuggerObject result);
994 :
995 : /*
996 : * Unwrap a Debug.Object, without rewrapping it for any particular debuggee
997 : * compartment.
998 : *
999 : * Preconditions: cx is in the debugger compartment. *vp is a value in that
1000 : * compartment. (*vp should be a "debuggee value", meaning it is the
1001 : * debugger's reflection of a value in the debuggee.)
1002 : *
1003 : * If *vp is a Debugger.Object, store the referent in *vp. Otherwise, if *vp
1004 : * is an object, throw a TypeError, because it is not a debuggee
1005 : * value. Otherwise *vp is a primitive, so leave it alone.
1006 : *
1007 : * When passing values from the debuggee to the debugger:
1008 : * enter debugger compartment;
1009 : * call wrapDebuggeeValue; // compartment- and debugger-wrapping
1010 : *
1011 : * When passing values from the debugger to the debuggee:
1012 : * call unwrapDebuggeeValue; // debugger-unwrapping
1013 : * enter debuggee compartment;
1014 : * call cx->compartment()->wrap; // compartment-rewrapping
1015 : *
1016 : * (Extreme nerd sidebar: Unwrapping happens in two steps because there are
1017 : * two different kinds of symmetry at work: regardless of which direction
1018 : * we're going, we want any exceptions to be created and thrown in the
1019 : * debugger compartment--mirror symmetry. But compartment wrapping always
1020 : * happens in the target compartment--rotational symmetry.)
1021 : */
1022 : MOZ_MUST_USE bool unwrapDebuggeeValue(JSContext* cx, MutableHandleValue vp);
1023 : MOZ_MUST_USE bool unwrapDebuggeeObject(JSContext* cx, MutableHandleObject obj);
1024 : MOZ_MUST_USE bool unwrapPropertyDescriptor(JSContext* cx, HandleObject obj,
1025 : MutableHandle<PropertyDescriptor> desc);
1026 :
1027 : /*
1028 : * Store the Debugger.Frame object for frame in *vp.
1029 : *
1030 : * Use this if you have already access to a frame pointer without having
1031 : * to incur the cost of walking the stack.
1032 : */
1033 : MOZ_MUST_USE bool getScriptFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleValue vp) {
1034 : return getScriptFrameWithIter(cx, frame, nullptr, vp);
1035 : }
1036 :
1037 : /*
1038 : * Store the Debugger.Frame object for iter in *vp/result. Eagerly copies a
1039 : * ScriptFrameIter::Data.
1040 : *
1041 : * Use this if you had to make a ScriptFrameIter to get the required
1042 : * frame, in which case the cost of walking the stack has already been
1043 : * paid.
1044 : */
1045 0 : MOZ_MUST_USE bool getScriptFrame(JSContext* cx, const FrameIter& iter,
1046 : MutableHandleValue vp) {
1047 0 : return getScriptFrameWithIter(cx, iter.abstractFramePtr(), &iter, vp);
1048 : }
1049 : MOZ_MUST_USE bool getScriptFrame(JSContext* cx, const FrameIter& iter,
1050 : MutableHandleDebuggerFrame result);
1051 :
1052 :
1053 : /*
1054 : * Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
1055 : * standard SpiderMonkey call state: a boolean success value |ok|, a return
1056 : * value |rv|, and a context |cx| that may or may not have an exception set.
1057 : * If an exception was pending on |cx|, it is cleared (and |ok| is asserted
1058 : * to be false).
1059 : */
1060 : static void resultToCompletion(JSContext* cx, bool ok, const Value& rv,
1061 : JSTrapStatus* status, MutableHandleValue value);
1062 :
1063 : /*
1064 : * Set |*result| to a JavaScript completion value corresponding to |status|
1065 : * and |value|. |value| should be the return value or exception value, not
1066 : * wrapped as a debuggee value. |cx| must be in the debugger compartment.
1067 : */
1068 : MOZ_MUST_USE bool newCompletionValue(JSContext* cx, JSTrapStatus status, const Value& value,
1069 : MutableHandleValue result);
1070 :
1071 : /*
1072 : * Precondition: we are in the debuggee compartment (ac is entered) and ok
1073 : * is true if the operation in the debuggee compartment succeeded, false on
1074 : * error or exception.
1075 : *
1076 : * Postcondition: we are in the debugger compartment, having called
1077 : * ac.leave() even if an error occurred.
1078 : *
1079 : * On success, a completion value is in vp and ac.context does not have a
1080 : * pending exception. (This ordinarily returns true even if the ok argument
1081 : * is false.)
1082 : */
1083 : MOZ_MUST_USE bool receiveCompletionValue(mozilla::Maybe<AutoCompartment>& ac, bool ok,
1084 : HandleValue val,
1085 : MutableHandleValue vp);
1086 :
1087 : /*
1088 : * Return the Debugger.Script object for |script|, or create a new one if
1089 : * needed. The context |cx| must be in the debugger compartment; |script|
1090 : * must be a script in a debuggee compartment.
1091 : */
1092 : JSObject* wrapScript(JSContext* cx, HandleScript script);
1093 :
1094 : /*
1095 : * Return the Debugger.Script object for |wasmInstance| (the toplevel
1096 : * script), synthesizing a new one if needed. The context |cx| must be in
1097 : * the debugger compartment; |wasmInstance| must be a WasmInstanceObject in
1098 : * the debuggee compartment.
1099 : */
1100 : JSObject* wrapWasmScript(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
1101 :
1102 : /*
1103 : * Return the Debugger.Source object for |source|, or create a new one if
1104 : * needed. The context |cx| must be in the debugger compartment; |source|
1105 : * must be a script source object in a debuggee compartment.
1106 : */
1107 : JSObject* wrapSource(JSContext* cx, js::HandleScriptSource source);
1108 :
1109 : /*
1110 : * Return the Debugger.Source object for |wasmInstance| (the entire module),
1111 : * synthesizing a new one if needed. The context |cx| must be in the
1112 : * debugger compartment; |wasmInstance| must be a WasmInstanceObject in the
1113 : * debuggee compartment.
1114 : */
1115 : JSObject* wrapWasmSource(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
1116 :
1117 : private:
1118 : Debugger(const Debugger&) = delete;
1119 : Debugger & operator=(const Debugger&) = delete;
1120 : };
1121 :
1122 : enum class DebuggerEnvironmentType {
1123 : Declarative,
1124 : With,
1125 : Object
1126 : };
1127 :
1128 : class DebuggerEnvironment : public NativeObject
1129 : {
1130 : public:
1131 : enum {
1132 : OWNER_SLOT
1133 : };
1134 :
1135 : static const unsigned RESERVED_SLOTS = 1;
1136 :
1137 : static const Class class_;
1138 :
1139 : static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor, HandleObject objProto);
1140 : static DebuggerEnvironment* create(JSContext* cx, HandleObject proto, HandleObject referent,
1141 : HandleNativeObject debugger);
1142 :
1143 : DebuggerEnvironmentType type() const;
1144 : MOZ_MUST_USE bool getParent(JSContext* cx, MutableHandleDebuggerEnvironment result) const;
1145 : MOZ_MUST_USE bool getObject(JSContext* cx, MutableHandleDebuggerObject result) const;
1146 : MOZ_MUST_USE bool getCallee(JSContext* cx, MutableHandleDebuggerObject result) const;
1147 : bool isDebuggee() const;
1148 : bool isOptimized() const;
1149 :
1150 : static MOZ_MUST_USE bool getNames(JSContext* cx, HandleDebuggerEnvironment environment,
1151 : MutableHandle<IdVector> result);
1152 : static MOZ_MUST_USE bool find(JSContext* cx, HandleDebuggerEnvironment environment,
1153 : HandleId id, MutableHandleDebuggerEnvironment result);
1154 : static MOZ_MUST_USE bool getVariable(JSContext* cx, HandleDebuggerEnvironment environment,
1155 : HandleId id, MutableHandleValue result);
1156 : static MOZ_MUST_USE bool setVariable(JSContext* cx, HandleDebuggerEnvironment environment,
1157 : HandleId id, HandleValue value);
1158 :
1159 : private:
1160 : static const ClassOps classOps_;
1161 :
1162 : static const JSPropertySpec properties_[];
1163 : static const JSFunctionSpec methods_[];
1164 :
1165 0 : Env* referent() const {
1166 0 : Env* env = static_cast<Env*>(getPrivate());
1167 0 : MOZ_ASSERT(env);
1168 0 : return env;
1169 : }
1170 :
1171 : Debugger* owner() const;
1172 :
1173 : bool requireDebuggee(JSContext* cx) const;
1174 :
1175 : static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
1176 :
1177 : static MOZ_MUST_USE bool typeGetter(JSContext* cx, unsigned argc, Value* vp);
1178 : static MOZ_MUST_USE bool parentGetter(JSContext* cx, unsigned argc, Value* vp);
1179 : static MOZ_MUST_USE bool objectGetter(JSContext* cx, unsigned argc, Value* vp);
1180 : static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc, Value* vp);
1181 : static MOZ_MUST_USE bool inspectableGetter(JSContext* cx, unsigned argc, Value* vp);
1182 : static MOZ_MUST_USE bool optimizedOutGetter(JSContext* cx, unsigned argc, Value* vp);
1183 :
1184 : static MOZ_MUST_USE bool namesMethod(JSContext* cx, unsigned argc, Value* vp);
1185 : static MOZ_MUST_USE bool findMethod(JSContext* cx, unsigned argc, Value* vp);
1186 : static MOZ_MUST_USE bool getVariableMethod(JSContext* cx, unsigned argc, Value* vp);
1187 : static MOZ_MUST_USE bool setVariableMethod(JSContext* cx, unsigned argc, Value* vp);
1188 : };
1189 :
1190 : enum class DebuggerFrameType {
1191 : Eval,
1192 : Global,
1193 : Call,
1194 : Module,
1195 : WasmCall
1196 : };
1197 :
1198 : enum class DebuggerFrameImplementation {
1199 : Interpreter,
1200 : Baseline,
1201 : Ion,
1202 : Wasm
1203 : };
1204 :
1205 : /*
1206 : * A Handler represents a reference to a handler function. These handler
1207 : * functions are called by the Debugger API to notify the user of certain
1208 : * events. For each event type, we define a separate subclass of Handler. This
1209 : * allows users to define a single reference to an object that implements
1210 : * multiple handlers, by inheriting from the appropriate subclasses.
1211 : *
1212 : * A Handler can be stored on a reflection object, in which case the reflection
1213 : * object becomes responsible for managing the lifetime of the Handler. To aid
1214 : * with this, the Handler base class defines several methods, which are to be
1215 : * called by the reflection object at the appropriate time (see below).
1216 : */
1217 0 : struct Handler {
1218 0 : virtual ~Handler() {}
1219 :
1220 : /*
1221 : * If the Handler is a reference to a callable JSObject, this method returns
1222 : * the latter. This allows the Handler to be used from JS. Otherwise, this
1223 : * method returns nullptr.
1224 : */
1225 : virtual JSObject* object() const = 0;
1226 :
1227 : /*
1228 : * Drops the reference to the handler. This method will be called by the
1229 : * reflection object on which the reference is stored when the former is
1230 : * finalized, or the latter replaced.
1231 : */
1232 : virtual void drop() = 0;
1233 :
1234 : /*
1235 : * Traces the reference to the handler. This method will be called
1236 : * by the reflection object on which the reference is stored whenever the
1237 : * former is traced.
1238 : */
1239 : virtual void trace(JSTracer* tracer) = 0;
1240 : };
1241 :
1242 : class DebuggerArguments : public NativeObject {
1243 : public:
1244 : static const Class class_;
1245 :
1246 : static DebuggerArguments* create(JSContext* cx, HandleObject proto, HandleDebuggerFrame frame);
1247 :
1248 : private:
1249 : enum {
1250 : FRAME_SLOT
1251 : };
1252 :
1253 : static const unsigned RESERVED_SLOTS = 1;
1254 : };
1255 :
1256 : /*
1257 : * An OnStepHandler represents a handler function that is called when a small
1258 : * amount of progress is made in a frame.
1259 : */
1260 0 : struct OnStepHandler : Handler {
1261 : /*
1262 : * If we have made a small amount of progress in a frame, this method is
1263 : * called with the frame as argument. If succesful, this method should
1264 : * return true, with `statusp` and `vp` set to a resumption value
1265 : * specifiying how execution should continue.
1266 : */
1267 : virtual bool onStep(JSContext* cx, HandleDebuggerFrame frame, JSTrapStatus& statusp,
1268 : MutableHandleValue vp) = 0;
1269 : };
1270 :
1271 0 : class ScriptedOnStepHandler final : public OnStepHandler {
1272 : public:
1273 : explicit ScriptedOnStepHandler(JSObject* object);
1274 : virtual JSObject* object() const override;
1275 : virtual void drop() override;
1276 : virtual void trace(JSTracer* tracer) override;
1277 : virtual bool onStep(JSContext* cx, HandleDebuggerFrame frame, JSTrapStatus& statusp,
1278 : MutableHandleValue vp) override;
1279 :
1280 : private:
1281 : HeapPtr<JSObject*> object_;
1282 : };
1283 :
1284 : /*
1285 : * An OnPopHandler represents a handler function that is called just before a
1286 : * frame is popped.
1287 : */
1288 0 : struct OnPopHandler : Handler {
1289 : /*
1290 : * If a frame is about the be popped, this method is called with the frame
1291 : * as argument, and `statusp` and `vp` set to a completion value specifying
1292 : * how this frame's execution completed. If successful, this method should
1293 : * return true, with `statusp` and `vp` set to a resumption value specifying
1294 : * how execution should continue.
1295 : */
1296 : virtual bool onPop(JSContext* cx, HandleDebuggerFrame frame, JSTrapStatus& statusp,
1297 : MutableHandleValue vp) = 0;
1298 : };
1299 :
1300 0 : class ScriptedOnPopHandler final : public OnPopHandler {
1301 : public:
1302 : explicit ScriptedOnPopHandler(JSObject* object);
1303 : virtual JSObject* object() const override;
1304 : virtual void drop() override;
1305 : virtual void trace(JSTracer* tracer) override;
1306 : virtual bool onPop(JSContext* cx, HandleDebuggerFrame frame, JSTrapStatus& statusp,
1307 : MutableHandleValue vp) override;
1308 :
1309 : private:
1310 : HeapPtr<JSObject*> object_;
1311 : };
1312 :
1313 : class DebuggerFrame : public NativeObject
1314 : {
1315 : friend class DebuggerArguments;
1316 : friend class ScriptedOnStepHandler;
1317 : friend class ScriptedOnPopHandler;
1318 :
1319 : public:
1320 : enum {
1321 : OWNER_SLOT
1322 : };
1323 :
1324 : static const unsigned RESERVED_SLOTS = 1;
1325 :
1326 : static const Class class_;
1327 :
1328 : static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor, HandleObject objProto);
1329 : static DebuggerFrame* create(JSContext* cx, HandleObject proto, AbstractFramePtr referent,
1330 : const FrameIter* maybeIter, HandleNativeObject debugger);
1331 :
1332 : static MOZ_MUST_USE bool getArguments(JSContext* cx, HandleDebuggerFrame frame,
1333 : MutableHandleDebuggerArguments result);
1334 : static MOZ_MUST_USE bool getCallee(JSContext* cx, HandleDebuggerFrame frame,
1335 : MutableHandleDebuggerObject result);
1336 : static MOZ_MUST_USE bool getIsConstructing(JSContext* cx, HandleDebuggerFrame frame,
1337 : bool& result);
1338 : static MOZ_MUST_USE bool getEnvironment(JSContext* cx, HandleDebuggerFrame frame,
1339 : MutableHandleDebuggerEnvironment result);
1340 : static bool getIsGenerator(HandleDebuggerFrame frame);
1341 : static MOZ_MUST_USE bool getOffset(JSContext* cx, HandleDebuggerFrame frame, size_t& result);
1342 : static MOZ_MUST_USE bool getOlder(JSContext* cx, HandleDebuggerFrame frame,
1343 : MutableHandleDebuggerFrame result);
1344 : static MOZ_MUST_USE bool getThis(JSContext* cx, HandleDebuggerFrame frame,
1345 : MutableHandleValue result);
1346 : static DebuggerFrameType getType(HandleDebuggerFrame frame);
1347 : static DebuggerFrameImplementation getImplementation(HandleDebuggerFrame frame);
1348 : static MOZ_MUST_USE bool setOnStepHandler(JSContext* cx, HandleDebuggerFrame frame,
1349 : OnStepHandler* handler);
1350 :
1351 : static MOZ_MUST_USE bool eval(JSContext* cx, HandleDebuggerFrame frame,
1352 : mozilla::Range<const char16_t> chars, HandleObject bindings,
1353 : const EvalOptions& options, JSTrapStatus& status,
1354 : MutableHandleValue value);
1355 :
1356 : bool isLive() const;
1357 : OnStepHandler* onStepHandler() const;
1358 : OnPopHandler* onPopHandler() const;
1359 : void setOnPopHandler(OnPopHandler* handler);
1360 :
1361 : private:
1362 : static const ClassOps classOps_;
1363 :
1364 : static const JSPropertySpec properties_[];
1365 : static const JSFunctionSpec methods_[];
1366 :
1367 : static AbstractFramePtr getReferent(HandleDebuggerFrame frame);
1368 : static MOZ_MUST_USE bool getFrameIter(JSContext* cx, HandleDebuggerFrame frame,
1369 : mozilla::Maybe<FrameIter>& result);
1370 : static MOZ_MUST_USE bool requireScriptReferent(JSContext* cx, HandleDebuggerFrame frame);
1371 :
1372 : static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
1373 :
1374 : static MOZ_MUST_USE bool argumentsGetter(JSContext* cx, unsigned argc, Value* vp);
1375 : static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc, Value* vp);
1376 : static MOZ_MUST_USE bool constructingGetter(JSContext* cx, unsigned argc, Value* vp);
1377 : static MOZ_MUST_USE bool environmentGetter(JSContext* cx, unsigned argc, Value* vp);
1378 : static MOZ_MUST_USE bool generatorGetter(JSContext* cx, unsigned argc, Value* vp);
1379 : static MOZ_MUST_USE bool liveGetter(JSContext* cx, unsigned argc, Value* vp);
1380 : static MOZ_MUST_USE bool offsetGetter(JSContext* cx, unsigned argc, Value* vp);
1381 : static MOZ_MUST_USE bool olderGetter(JSContext* cx, unsigned argc, Value* vp);
1382 : static MOZ_MUST_USE bool thisGetter(JSContext* cx, unsigned argc, Value* vp);
1383 : static MOZ_MUST_USE bool typeGetter(JSContext* cx, unsigned argc, Value* vp);
1384 : static MOZ_MUST_USE bool implementationGetter(JSContext* cx, unsigned argc, Value* vp);
1385 : static MOZ_MUST_USE bool onStepGetter(JSContext* cx, unsigned argc, Value* vp);
1386 : static MOZ_MUST_USE bool onStepSetter(JSContext* cx, unsigned argc, Value* vp);
1387 : static MOZ_MUST_USE bool onPopGetter(JSContext* cx, unsigned argc, Value* vp);
1388 : static MOZ_MUST_USE bool onPopSetter(JSContext* cx, unsigned argc, Value* vp);
1389 :
1390 : static MOZ_MUST_USE bool evalMethod(JSContext* cx, unsigned argc, Value* vp);
1391 : static MOZ_MUST_USE bool evalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp);
1392 :
1393 : Debugger* owner() const;
1394 : };
1395 :
1396 : class DebuggerObject : public NativeObject
1397 : {
1398 : public:
1399 : static const Class class_;
1400 :
1401 : static NativeObject* initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor);
1402 : static DebuggerObject* create(JSContext* cx, HandleObject proto, HandleObject obj,
1403 : HandleNativeObject debugger);
1404 :
1405 : // Properties
1406 : static MOZ_MUST_USE bool getClassName(JSContext* cx, HandleDebuggerObject object,
1407 : MutableHandleString result);
1408 : static MOZ_MUST_USE bool getGlobal(JSContext* cx, HandleDebuggerObject object,
1409 : MutableHandleDebuggerObject result);
1410 : static MOZ_MUST_USE bool getParameterNames(JSContext* cx, HandleDebuggerObject object,
1411 : MutableHandle<StringVector> result);
1412 : static MOZ_MUST_USE bool getBoundTargetFunction(JSContext* cx, HandleDebuggerObject object,
1413 : MutableHandleDebuggerObject result);
1414 : static MOZ_MUST_USE bool getBoundThis(JSContext* cx, HandleDebuggerObject object,
1415 : MutableHandleValue result);
1416 : static MOZ_MUST_USE bool getBoundArguments(JSContext* cx, HandleDebuggerObject object,
1417 : MutableHandle<ValueVector> result);
1418 : static MOZ_MUST_USE bool getAllocationSite(JSContext* cx, HandleDebuggerObject object,
1419 : MutableHandleObject result);
1420 : static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object,
1421 : MutableHandleString result);
1422 : static MOZ_MUST_USE bool getErrorNotes(JSContext* cx, HandleDebuggerObject object,
1423 : MutableHandleValue result);
1424 : static MOZ_MUST_USE bool getErrorLineNumber(JSContext* cx, HandleDebuggerObject object,
1425 : MutableHandleValue result);
1426 : static MOZ_MUST_USE bool getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object,
1427 : MutableHandleValue result);
1428 : static MOZ_MUST_USE bool getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
1429 : MutableHandleDebuggerObject result);
1430 : static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
1431 : MutableHandleDebuggerObject result);
1432 : static MOZ_MUST_USE bool getPromiseValue(JSContext* cx, HandleDebuggerObject object,
1433 : MutableHandleValue result);
1434 : static MOZ_MUST_USE bool getPromiseReason(JSContext* cx, HandleDebuggerObject object,
1435 : MutableHandleValue result);
1436 :
1437 : // Methods
1438 : static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object,
1439 : bool& result);
1440 : static MOZ_MUST_USE bool isSealed(JSContext* cx, HandleDebuggerObject object, bool& result);
1441 : static MOZ_MUST_USE bool isFrozen(JSContext* cx, HandleDebuggerObject object, bool& result);
1442 : static MOZ_MUST_USE bool getPrototypeOf(JSContext* cx, HandleDebuggerObject object,
1443 : MutableHandleDebuggerObject result);
1444 : static MOZ_MUST_USE bool getOwnPropertyNames(JSContext* cx, HandleDebuggerObject object,
1445 : MutableHandle<IdVector> result);
1446 : static MOZ_MUST_USE bool getOwnPropertySymbols(JSContext* cx, HandleDebuggerObject object,
1447 : MutableHandle<IdVector> result);
1448 : static MOZ_MUST_USE bool getOwnPropertyDescriptor(JSContext* cx, HandleDebuggerObject object,
1449 : HandleId id,
1450 : MutableHandle<PropertyDescriptor> desc);
1451 : static MOZ_MUST_USE bool preventExtensions(JSContext* cx, HandleDebuggerObject object);
1452 : static MOZ_MUST_USE bool seal(JSContext* cx, HandleDebuggerObject object);
1453 : static MOZ_MUST_USE bool freeze(JSContext* cx, HandleDebuggerObject object);
1454 : static MOZ_MUST_USE bool defineProperty(JSContext* cx, HandleDebuggerObject object,
1455 : HandleId id, Handle<PropertyDescriptor> desc);
1456 : static MOZ_MUST_USE bool defineProperties(JSContext* cx, HandleDebuggerObject object,
1457 : Handle<IdVector> ids,
1458 : Handle<PropertyDescriptorVector> descs);
1459 : static MOZ_MUST_USE bool deleteProperty(JSContext* cx, HandleDebuggerObject object,
1460 : HandleId id, ObjectOpResult& result);
1461 : static MOZ_MUST_USE bool call(JSContext* cx, HandleDebuggerObject object, HandleValue thisv,
1462 : Handle<ValueVector> args, MutableHandleValue result);
1463 : static MOZ_MUST_USE bool forceLexicalInitializationByName(JSContext* cx,
1464 : HandleDebuggerObject object,
1465 : HandleId id, bool& result);
1466 : static MOZ_MUST_USE bool executeInGlobal(JSContext* cx, HandleDebuggerObject object,
1467 : mozilla::Range<const char16_t> chars,
1468 : HandleObject bindings, const EvalOptions& options,
1469 : JSTrapStatus& status, MutableHandleValue value);
1470 : static MOZ_MUST_USE bool makeDebuggeeValue(JSContext* cx, HandleDebuggerObject object,
1471 : HandleValue value, MutableHandleValue result);
1472 : static MOZ_MUST_USE bool unsafeDereference(JSContext* cx, HandleDebuggerObject object,
1473 : MutableHandleObject result);
1474 : static MOZ_MUST_USE bool unwrap(JSContext* cx, HandleDebuggerObject object,
1475 : MutableHandleDebuggerObject result);
1476 :
1477 : // Infallible properties
1478 : bool isCallable() const;
1479 : bool isFunction() const;
1480 : bool isDebuggeeFunction() const;
1481 : bool isBoundFunction() const;
1482 : bool isArrowFunction() const;
1483 : bool isGlobal() const;
1484 : bool isScriptedProxy() const;
1485 : bool isPromise() const;
1486 : JSAtom* name(JSContext* cx) const;
1487 : JSAtom* displayName(JSContext* cx) const;
1488 : JS::PromiseState promiseState() const;
1489 : double promiseLifetime() const;
1490 : double promiseTimeToResolution() const;
1491 :
1492 : private:
1493 : enum {
1494 : OWNER_SLOT
1495 : };
1496 :
1497 : static const unsigned RESERVED_SLOTS = 1;
1498 :
1499 : static const ClassOps classOps_;
1500 :
1501 : static const JSPropertySpec properties_[];
1502 : static const JSPropertySpec promiseProperties_[];
1503 : static const JSFunctionSpec methods_[];
1504 :
1505 0 : JSObject* referent() const {
1506 0 : JSObject* obj = (JSObject*) getPrivate();
1507 0 : MOZ_ASSERT(obj);
1508 0 : return obj;
1509 : }
1510 :
1511 : Debugger* owner() const;
1512 : PromiseObject* promise() const;
1513 :
1514 : static MOZ_MUST_USE bool requireGlobal(JSContext* cx, HandleDebuggerObject object);
1515 : static MOZ_MUST_USE bool requirePromise(JSContext* cx, HandleDebuggerObject object);
1516 : static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
1517 :
1518 : // JSNative properties
1519 : static MOZ_MUST_USE bool callableGetter(JSContext* cx, unsigned argc, Value* vp);
1520 : static MOZ_MUST_USE bool isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
1521 : static MOZ_MUST_USE bool isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
1522 : static MOZ_MUST_USE bool protoGetter(JSContext* cx, unsigned argc, Value* vp);
1523 : static MOZ_MUST_USE bool classGetter(JSContext* cx, unsigned argc, Value* vp);
1524 : static MOZ_MUST_USE bool nameGetter(JSContext* cx, unsigned argc, Value* vp);
1525 : static MOZ_MUST_USE bool displayNameGetter(JSContext* cx, unsigned argc, Value* vp);
1526 : static MOZ_MUST_USE bool parameterNamesGetter(JSContext* cx, unsigned argc, Value* vp);
1527 : static MOZ_MUST_USE bool scriptGetter(JSContext* cx, unsigned argc, Value* vp);
1528 : static MOZ_MUST_USE bool environmentGetter(JSContext* cx, unsigned argc, Value* vp);
1529 : static MOZ_MUST_USE bool boundTargetFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
1530 : static MOZ_MUST_USE bool boundThisGetter(JSContext* cx, unsigned argc, Value* vp);
1531 : static MOZ_MUST_USE bool boundArgumentsGetter(JSContext* cx, unsigned argc, Value* vp);
1532 : static MOZ_MUST_USE bool globalGetter(JSContext* cx, unsigned argc, Value* vp);
1533 : static MOZ_MUST_USE bool allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp);
1534 : static MOZ_MUST_USE bool errorMessageNameGetter(JSContext* cx, unsigned argc, Value* vp);
1535 : static MOZ_MUST_USE bool errorNotesGetter(JSContext* cx, unsigned argc, Value* vp);
1536 : static MOZ_MUST_USE bool errorLineNumberGetter(JSContext* cx, unsigned argc, Value* vp);
1537 : static MOZ_MUST_USE bool errorColumnNumberGetter(JSContext* cx, unsigned argc, Value* vp);
1538 : static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp);
1539 : static MOZ_MUST_USE bool proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp);
1540 : static MOZ_MUST_USE bool proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp);
1541 : static MOZ_MUST_USE bool isPromiseGetter(JSContext* cx, unsigned argc, Value* vp);
1542 : static MOZ_MUST_USE bool promiseStateGetter(JSContext* cx, unsigned argc, Value* vp);
1543 : static MOZ_MUST_USE bool promiseValueGetter(JSContext* cx, unsigned argc, Value* vp);
1544 : static MOZ_MUST_USE bool promiseReasonGetter(JSContext* cx, unsigned argc, Value* vp);
1545 : static MOZ_MUST_USE bool promiseLifetimeGetter(JSContext* cx, unsigned argc, Value* vp);
1546 : static MOZ_MUST_USE bool promiseTimeToResolutionGetter(JSContext* cx, unsigned argc, Value* vp);
1547 : static MOZ_MUST_USE bool promiseAllocationSiteGetter(JSContext* cx, unsigned argc, Value* vp);
1548 : static MOZ_MUST_USE bool promiseResolutionSiteGetter(JSContext* cx, unsigned argc, Value* vp);
1549 : static MOZ_MUST_USE bool promiseIDGetter(JSContext* cx, unsigned argc, Value* vp);
1550 : static MOZ_MUST_USE bool promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Value* vp);
1551 :
1552 : // JSNative methods
1553 : static MOZ_MUST_USE bool isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp);
1554 : static MOZ_MUST_USE bool isSealedMethod(JSContext* cx, unsigned argc, Value* vp);
1555 : static MOZ_MUST_USE bool isFrozenMethod(JSContext* cx, unsigned argc, Value* vp);
1556 : static MOZ_MUST_USE bool getOwnPropertyNamesMethod(JSContext* cx, unsigned argc, Value* vp);
1557 : static MOZ_MUST_USE bool getOwnPropertySymbolsMethod(JSContext* cx, unsigned argc, Value* vp);
1558 : static MOZ_MUST_USE bool getOwnPropertyDescriptorMethod(JSContext* cx, unsigned argc, Value* vp);
1559 : static MOZ_MUST_USE bool preventExtensionsMethod(JSContext* cx, unsigned argc, Value* vp);
1560 : static MOZ_MUST_USE bool sealMethod(JSContext* cx, unsigned argc, Value* vp);
1561 : static MOZ_MUST_USE bool freezeMethod(JSContext* cx, unsigned argc, Value* vp);
1562 : static MOZ_MUST_USE bool definePropertyMethod(JSContext* cx, unsigned argc, Value* vp);
1563 : static MOZ_MUST_USE bool definePropertiesMethod(JSContext* cx, unsigned argc, Value* vp);
1564 : static MOZ_MUST_USE bool deletePropertyMethod(JSContext* cx, unsigned argc, Value* vp);
1565 : static MOZ_MUST_USE bool callMethod(JSContext* cx, unsigned argc, Value* vp);
1566 : static MOZ_MUST_USE bool applyMethod(JSContext* cx, unsigned argc, Value* vp);
1567 : static MOZ_MUST_USE bool asEnvironmentMethod(JSContext* cx, unsigned argc, Value* vp);
1568 : static MOZ_MUST_USE bool forceLexicalInitializationByNameMethod(JSContext* cx, unsigned argc, Value* vp);
1569 : static MOZ_MUST_USE bool executeInGlobalMethod(JSContext* cx, unsigned argc, Value* vp);
1570 : static MOZ_MUST_USE bool executeInGlobalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp);
1571 : static MOZ_MUST_USE bool makeDebuggeeValueMethod(JSContext* cx, unsigned argc, Value* vp);
1572 : static MOZ_MUST_USE bool unsafeDereferenceMethod(JSContext* cx, unsigned argc, Value* vp);
1573 : static MOZ_MUST_USE bool unwrapMethod(JSContext* cx, unsigned argc, Value* vp);
1574 : static MOZ_MUST_USE bool getErrorReport(JSContext* cx, HandleObject maybeError,
1575 : JSErrorReport*& report);
1576 : };
1577 :
1578 : class JSBreakpointSite;
1579 : class WasmBreakpoint;
1580 : class WasmBreakpointSite;
1581 :
1582 : class BreakpointSite {
1583 : friend class Breakpoint;
1584 : friend struct ::JSCompartment;
1585 : friend class ::JSScript;
1586 : friend class Debugger;
1587 :
1588 : public:
1589 : enum class Type { JS, Wasm };
1590 :
1591 : private:
1592 : Type type_;
1593 :
1594 : template<typename T>
1595 : struct SiteSiblingAccess {
1596 0 : static T* GetNext(T* elm) {
1597 0 : return elm->siteLink.mNext;
1598 : }
1599 0 : static void SetNext(T* elm, T* next) {
1600 0 : elm->siteLink.mNext = next;
1601 0 : }
1602 0 : static T* GetPrev(T* elm) {
1603 0 : return elm->siteLink.mPrev;
1604 : }
1605 0 : static void SetPrev(T* elm, T* prev) {
1606 0 : elm->siteLink.mPrev = prev;
1607 0 : }
1608 : };
1609 :
1610 : // List of all js::Breakpoints at this instruction.
1611 : using BreakpointList =
1612 : mozilla::DoublyLinkedList<js::Breakpoint,
1613 : SiteSiblingAccess<js::Breakpoint>>;
1614 : BreakpointList breakpoints;
1615 : size_t enabledCount; /* number of breakpoints in the list that are enabled */
1616 :
1617 : protected:
1618 : virtual void recompile(FreeOp* fop) = 0;
1619 : bool isEmpty() const;
1620 0 : inline bool isEnabled() const { return enabledCount > 0; }
1621 :
1622 : public:
1623 : BreakpointSite(Type type);
1624 : Breakpoint* firstBreakpoint() const;
1625 0 : virtual ~BreakpointSite() {}
1626 : bool hasBreakpoint(Breakpoint* bp);
1627 0 : inline Type type() const { return type_; }
1628 :
1629 : void inc(FreeOp* fop);
1630 : void dec(FreeOp* fop);
1631 : virtual void destroyIfEmpty(FreeOp* fop) = 0;
1632 :
1633 : inline JSBreakpointSite* asJS();
1634 : inline WasmBreakpointSite* asWasm();
1635 : };
1636 :
1637 : /*
1638 : * Each Breakpoint is a member of two linked lists: its debugger's list and its
1639 : * site's list.
1640 : *
1641 : * GC rules:
1642 : * - script is live, breakpoint exists, and debugger is enabled
1643 : * ==> debugger is live
1644 : * - script is live, breakpoint exists, and debugger is live
1645 : * ==> retain the breakpoint and the handler object is live
1646 : *
1647 : * Debugger::markIteratively implements these two rules. It uses
1648 : * Debugger::hasAnyLiveHooks to check for rule 1.
1649 : *
1650 : * Nothing else causes a breakpoint to be retained, so if its script or
1651 : * debugger is collected, the breakpoint is destroyed during GC sweep phase,
1652 : * even if the debugger compartment isn't being GC'd. This is implemented in
1653 : * Zone::sweepBreakpoints.
1654 : */
1655 0 : class Breakpoint {
1656 : friend struct ::JSCompartment;
1657 : friend class Debugger;
1658 : friend class BreakpointSite;
1659 :
1660 : public:
1661 : Debugger * const debugger;
1662 : BreakpointSite * const site;
1663 : private:
1664 : /* |handler| is marked unconditionally during minor GC. */
1665 : js::PreBarrieredObject handler;
1666 :
1667 : /**
1668 : * Link elements for each list this breakpoint can be in.
1669 : */
1670 : mozilla::DoublyLinkedListElement<Breakpoint> debuggerLink;
1671 : mozilla::DoublyLinkedListElement<Breakpoint> siteLink;
1672 :
1673 : public:
1674 : Breakpoint(Debugger* debugger, BreakpointSite* site, JSObject* handler);
1675 : void destroy(FreeOp* fop);
1676 : Breakpoint* nextInDebugger();
1677 : Breakpoint* nextInSite();
1678 0 : const PreBarrieredObject& getHandler() const { return handler; }
1679 0 : PreBarrieredObject& getHandlerRef() { return handler; }
1680 :
1681 : inline WasmBreakpoint* asWasm();
1682 : };
1683 :
1684 0 : class JSBreakpointSite : public BreakpointSite
1685 : {
1686 : public:
1687 : JSScript* script;
1688 : jsbytecode * const pc;
1689 :
1690 : protected:
1691 : void recompile(FreeOp* fop) override;
1692 :
1693 : public:
1694 : JSBreakpointSite(JSScript* script, jsbytecode* pc);
1695 :
1696 : void destroyIfEmpty(FreeOp* fop) override;
1697 : };
1698 :
1699 : inline JSBreakpointSite*
1700 0 : BreakpointSite::asJS()
1701 : {
1702 0 : MOZ_ASSERT(type() == Type::JS);
1703 0 : return static_cast<JSBreakpointSite*>(this);
1704 : }
1705 :
1706 0 : class WasmBreakpointSite : public BreakpointSite
1707 : {
1708 : public:
1709 : wasm::DebugState* debug;
1710 : uint32_t offset;
1711 :
1712 : protected:
1713 : void recompile(FreeOp* fop) override;
1714 :
1715 : public:
1716 : WasmBreakpointSite(wasm::DebugState* debug, uint32_t offset);
1717 :
1718 : void destroyIfEmpty(FreeOp* fop) override;
1719 : };
1720 :
1721 : inline WasmBreakpointSite*
1722 : BreakpointSite::asWasm()
1723 : {
1724 : MOZ_ASSERT(type() == Type::Wasm);
1725 : return static_cast<WasmBreakpointSite*>(this);
1726 : }
1727 :
1728 : class WasmBreakpoint : public Breakpoint
1729 : {
1730 : public:
1731 : WasmInstanceObject* wasmInstance;
1732 :
1733 0 : WasmBreakpoint(Debugger* debugger, WasmBreakpointSite* site, JSObject* handler,
1734 : WasmInstanceObject* wasmInstance_)
1735 0 : : Breakpoint(debugger, site, handler),
1736 0 : wasmInstance(wasmInstance_)
1737 0 : {}
1738 : };
1739 :
1740 : inline WasmBreakpoint*
1741 0 : Breakpoint::asWasm()
1742 : {
1743 0 : MOZ_ASSERT(site && site->type() == BreakpointSite::Type::Wasm);
1744 0 : return static_cast<WasmBreakpoint*>(this);
1745 : }
1746 :
1747 :
1748 : Breakpoint*
1749 0 : Debugger::firstBreakpoint() const
1750 : {
1751 0 : if (breakpoints.isEmpty())
1752 0 : return nullptr;
1753 0 : return &(*breakpoints.begin());
1754 : }
1755 :
1756 : const js::GCPtrNativeObject&
1757 0 : Debugger::toJSObject() const
1758 : {
1759 0 : MOZ_ASSERT(object);
1760 0 : return object;
1761 : }
1762 :
1763 : js::GCPtrNativeObject&
1764 0 : Debugger::toJSObjectRef()
1765 : {
1766 0 : MOZ_ASSERT(object);
1767 0 : return object;
1768 : }
1769 :
1770 : bool
1771 0 : Debugger::observesEnterFrame() const
1772 : {
1773 0 : return enabled && getHook(OnEnterFrame);
1774 : }
1775 :
1776 : bool
1777 0 : Debugger::observesNewScript() const
1778 : {
1779 0 : return enabled && getHook(OnNewScript);
1780 : }
1781 :
1782 : bool
1783 0 : Debugger::observesNewGlobalObject() const
1784 : {
1785 0 : return enabled && getHook(OnNewGlobalObject);
1786 : }
1787 :
1788 : bool
1789 0 : Debugger::observesGlobal(GlobalObject* global) const
1790 : {
1791 0 : ReadBarriered<GlobalObject*> debuggee(global);
1792 0 : return debuggees.has(debuggee);
1793 : }
1794 :
1795 : /* static */ void
1796 2235 : Debugger::onNewScript(JSContext* cx, HandleScript script)
1797 : {
1798 : // We early return in slowPathOnNewScript for self-hosted scripts, so we can
1799 : // ignore those in our assertion here.
1800 2235 : MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() &&
1801 : !script->selfHosted(),
1802 : script->compartment()->firedOnNewGlobalObject);
1803 2235 : if (script->compartment()->isDebuggee())
1804 0 : slowPathOnNewScript(cx, script);
1805 2235 : }
1806 :
1807 : /* static */ void
1808 311 : Debugger::onNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global)
1809 : {
1810 311 : MOZ_ASSERT(!global->compartment()->firedOnNewGlobalObject);
1811 : #ifdef DEBUG
1812 311 : global->compartment()->firedOnNewGlobalObject = true;
1813 : #endif
1814 311 : if (!cx->runtime()->onNewGlobalObjectWatchers().isEmpty())
1815 0 : Debugger::slowPathOnNewGlobalObject(cx, global);
1816 311 : }
1817 :
1818 : /* static */ bool
1819 0 : Debugger::onLogAllocationSite(JSContext* cx, JSObject* obj, HandleSavedFrame frame, mozilla::TimeStamp when)
1820 : {
1821 0 : GlobalObject::DebuggerVector* dbgs = cx->global()->getDebuggers();
1822 0 : if (!dbgs || dbgs->empty())
1823 0 : return true;
1824 0 : RootedObject hobj(cx, obj);
1825 0 : return Debugger::slowPathOnLogAllocationSite(cx, hobj, frame, when, *dbgs);
1826 : }
1827 :
1828 : MOZ_MUST_USE bool ReportObjectRequired(JSContext* cx);
1829 :
1830 : } /* namespace js */
1831 :
1832 : namespace JS {
1833 :
1834 : template <>
1835 : struct DeletePolicy<js::Debugger> : public js::GCManagedDeletePolicy<js::Debugger>
1836 : {};
1837 :
1838 : } /* namespace JS */
1839 :
1840 : #endif /* vm_Debugger_h */
|