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 // Interfaces by which the embedding can interact with the Debugger API.
8 
9 #ifndef js_Debug_h
10 #define js_Debug_h
11 
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/MemoryReporting.h"
15 
16 #include "jsapi.h"
17 #include "jspubtd.h"
18 
19 #include "js/GCAPI.h"
20 #include "js/RootingAPI.h"
21 #include "js/TypeDecls.h"
22 
23 namespace js {
24 class Debugger;
25 } // namespace js
26 
27 namespace JS {
28 namespace dbg {
29 
30 // Helping embedding code build objects for Debugger
31 // -------------------------------------------------
32 //
33 // Some Debugger API features lean on the embedding application to construct
34 // their result values. For example, Debugger.Frame.prototype.scriptEntryReason
35 // calls hooks provided by the embedding to construct values explaining why it
36 // invoked JavaScript; if F is a frame called from a mouse click event handler,
37 // F.scriptEntryReason would return an object of the form:
38 //
39 //   { eventType: "mousedown", event: <object> }
40 //
41 // where <object> is a Debugger.Object whose referent is the event being
42 // dispatched.
43 //
44 // However, Debugger implements a trust boundary. Debuggee code may be
45 // considered untrusted; debugger code needs to be protected from debuggee
46 // getters, setters, proxies, Object.watch watchpoints, and any other feature
dce_rpc_add_program(gpointer key_ptr,gpointer value_ptr,gpointer rsrtd_ptr)47 // that might accidentally cause debugger code to set the debuggee running. The
48 // Debugger API tries to make it easy to write safe debugger code by only
49 // offering access to debuggee objects via Debugger.Object instances, which
50 // ensure that only those operations whose explicit purpose is to invoke
51 // debuggee code do so. But this protective membrane is only helpful if we
52 // interpose Debugger.Object instances in all the necessary spots.
53 //
54 // SpiderMonkey's compartment system also implements a trust boundary. The
55 // debuggee and debugger are always in different compartments. Inter-compartment
56 // work requires carefully tracking which compartment each JSObject or JS::Value
57 // belongs to, and ensuring that is is correctly wrapped for each operation.
58 //
59 // It seems precarious to expect the embedding's hooks to implement these trust
60 // boundaries. Instead, the JS::dbg::Builder API segregates the code which
61 // constructs trusted objects from that which deals with untrusted objects.
62 // Trusted objects have an entirely different C++ type, so code that improperly
63 // mixes trusted and untrusted objects is caught at compile time.
64 //
65 // In the structure shown above, there are two trusted objects, and one
66 // untrusted object:
67 //
68 // - The overall object, with the 'eventType' and 'event' properties, is a
69 //   trusted object. We're going to return it to D.F.p.scriptEntryReason's
70 //   caller, which will handle it directly.
71 //
72 // - The Debugger.Object instance appearing as the value of the 'event' property
73 //   is a trusted object. It belongs to the same Debugger instance as the
74 //   Debugger.Frame instance whose scriptEntryReason accessor was called, and
75 //   presents a safe reflection-oriented API for inspecting its referent, which
76 //   is:
77 //
78 // - The actual event object, an untrusted object, and the referent of the
79 //   Debugger.Object above. (Content can do things like replacing accessors on
80 //   Event.prototype.)
81 //
82 // Using JS::dbg::Builder, all objects and values the embedding deals with
83 // directly are considered untrusted, and are assumed to be debuggee values. The
84 // only way to construct trusted objects is to use Builder's own methods, which
85 // return a separate Object type. The only way to set a property on a trusted
86 // object is through that Object type. The actual trusted object is never
87 // exposed to the embedding.
88 //
89 // So, for example, the embedding might use code like the following to construct
90 // the object shown above, given a Builder passed to it by Debugger:
91 //
92 //    bool
93 //    MyScriptEntryReason::explain(JSContext* cx,
94 //                                 Builder& builder,
95 //                                 Builder::Object& result)
96 //    {
97 //        JSObject* eventObject = ... obtain debuggee event object somehow ...;
98 //        if (!eventObject)
99 //            return false;
100 //        result = builder.newObject(cx);
101 //        return result &&
102 //               result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) &&
103 //               result.defineProperty(cx, "event", eventObject);
104 //    }
105 //
106 //
107 // Object::defineProperty also accepts an Object as the value to store on the
108 // property. By its type, we know that the value is trusted, so we set it
109 // directly as the property's value, without interposing a Debugger.Object
110 // wrapper. This allows the embedding to builted nested structures of trusted
111 // objects.
112 //
113 // The Builder and Builder::Object methods take care of doing whatever
114 // compartment switching and wrapping are necessary to construct the trusted
115 // values in the Debugger's compartment.
116 //
117 // The Object type is self-rooting. Construction, assignment, and destruction
118 // all properly root the referent object.
119 
120 class BuilderOrigin;
121 
122 class Builder {
123     // The Debugger instance whose client we are building a value for. We build
124     // objects in this object's compartment.
125     PersistentRootedObject debuggerObject;
126 
127     // debuggerObject's Debugger structure, for convenience.
128     js::Debugger* debugger;
129 
130     // Check that |thing| is in the same compartment as our debuggerObject. Used
131     // for assertions when constructing BuiltThings. We can overload this as we
132     // add more instantiations of BuiltThing.
133 #if DEBUG
134     void assertBuilt(JSObject* obj);
135 #else
136     void assertBuilt(JSObject* obj) { }
137 #endif
138 
139   protected:
140     // A reference to a trusted object or value. At the moment, we only use it
141     // with JSObject*.
142     template<typename T>
createDceRpcSrtDialog(QWidget & parent,const QString,const QString opt_arg,CaptureFile & cf)143     class BuiltThing {
144         friend class BuilderOrigin;
145 
146       protected:
147         // The Builder to which this trusted thing belongs.
148         Builder& owner;
149 
150         // A rooted reference to our value.
151         PersistentRooted<T> value;
152 
153         BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy<T>::initial())
154           : owner(owner_), value(cx, value_)
155         {
156             owner.assertBuilt(value_);
157         }
158 
159         // Forward some things from our owner, for convenience.
160         js::Debugger* debugger() const { return owner.debugger; }
161         JSObject* debuggerObject() const { return owner.debuggerObject; }
162 
163       public:
164         BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) { }
165         BuiltThing& operator=(const BuiltThing& rhs) {
166             MOZ_ASSERT(&owner == &rhs.owner);
167             owner.assertBuilt(rhs.value);
168             value = rhs.value;
169             return *this;
170         }
171 
172         explicit operator bool() const {
173             // If we ever instantiate BuiltThing<Value>, this might not suffice.
174             return value;
175         }
176 
177       private:
178         BuiltThing() = delete;
179     };
180 
181   public:
182     // A reference to a trusted object, possibly null. Instances of Object are
183     // always properly rooted. They can be copied and assigned, as if they were
184     // pointers.
185     class Object: private BuiltThing<JSObject*> {
186         friend class Builder;           // for construction
187         friend class BuilderOrigin;     // for unwrapping
188 
189         typedef BuiltThing<JSObject*> Base;
190 
191         // This is private, because only Builders can create Objects that
192         // actually point to something (hence the 'friend' declaration).
193         Object(JSContext* cx, Builder& owner_, HandleObject obj) : Base(cx, owner_, obj.get()) { }
createOncRpcSrtDialog(QWidget & parent,const QString,const QString opt_arg,CaptureFile & cf)194 
195         bool definePropertyToTrusted(JSContext* cx, const char* name,
196                                      JS::MutableHandleValue value);
197 
198       public:
199         Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) { }
200         Object(const Object& rhs) : Base(rhs) { }
201 
202         // Our automatically-generated assignment operator can see our base
203         // class's assignment operator, so we don't need to write one out here.
204 
205         // Set the property named |name| on this object to |value|.
206         //
207         // If |value| is a string or primitive, re-wrap it for the debugger's
208         // compartment.
209         //
210         // If |value| is an object, assume it is a debuggee object and make a
211         // Debugger.Object instance referring to it. Set that as the propery's
212         // value.
213         //
214         // If |value| is another trusted object, store it directly as the
215         // property's value.
216         //
217         // On error, report the problem on cx and return false.
218         bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value);
219         bool defineProperty(JSContext* cx, const char* name, JS::HandleObject value);
220         bool defineProperty(JSContext* cx, const char* name, Object& value);
221 
222         using Base::operator bool;
223     };
224 
225     // Build an empty object for direct use by debugger code, owned by this
226     // Builder. If an error occurs, report it on cx and return a false Object.
227     Object newObject(JSContext* cx);
228 
229   protected:
230     Builder(JSContext* cx, js::Debugger* debugger);
addDceRpcProgram(_guid_key * key,_dcerpc_uuid_value * value)231 };
232 
233 // Debugger itself instantiates this subclass of Builder, which can unwrap
234 // BuiltThings that belong to it.
235 class BuilderOrigin : public Builder {
addDceRpcProgramVersion(_guid_key * key)236     template<typename T>
237     T unwrapAny(const BuiltThing<T>& thing) {
238         MOZ_ASSERT(&thing.owner == this);
239         return thing.value.get();
240     }
241 
242   public:
243     BuilderOrigin(JSContext* cx, js::Debugger* debugger_)
addOncRpcProgram(guint32 program,_rpc_prog_info_value * value)244       : Builder(cx, debugger_)
245     { }
246 
247     JSObject* unwrap(Object& object) { return unwrapAny(object); }
248 };
addOncRpcProgramVersion(guint32 program,guint32 version)249 
250 
251 
252 // Finding the size of blocks allocated with malloc
253 // ------------------------------------------------
254 //
255 // Debugger.Memory wants to be able to report how many bytes items in memory are
256 // consuming. To do this, it needs a function that accepts a pointer to a block,
257 // and returns the number of bytes allocated to that block. SpiderMonkey itself
258 // doesn't know which function is appropriate to use, but the embedding does.
259 
260 // Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of
261 // malloc'd blocks.
262 JS_PUBLIC_API(void)
263 SetDebuggerMallocSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf);
264 
updateOncRpcProcedureCount(guint32 program,guint32 version,int procedure)265 // Get the MallocSizeOf function that the given context is using to find the
266 // size of malloc'd blocks.
267 JS_PUBLIC_API(mozilla::MallocSizeOf)
268 GetDebuggerMallocSizeOf(JSContext* cx);
269 
270 
271 
272 // Debugger and Garbage Collection Events
setDceRpcUuidAndVersion(_e_guid_t * uuid,int version)273 // --------------------------------------
274 //
275 // The Debugger wants to report about its debuggees' GC cycles, however entering
276 // JS after a GC is troublesome since SpiderMonkey will often do something like
277 // force a GC and then rely on the nursery being empty. If we call into some
278 // Debugger's hook after the GC, then JS runs and the nursery won't be
279 // empty. Instead, we rely on embedders to call back into SpiderMonkey after a
280 // GC and notify Debuggers to call their onGarbageCollection hook.
281 
282 
283 // For each Debugger that observed a debuggee involved in the given GC event,
284 // call its `onGarbageCollection` hook.
285 JS_PUBLIC_API(bool)
286 FireOnGarbageCollectionHook(JSContext* cx, GarbageCollectionEvent::Ptr&& data);
287 
288 
289 
290 // Handlers for observing Promises
291 // -------------------------------
292 //
setOncRpcProgramAndVersion(int program,int version)293 // The Debugger wants to observe behavior of promises, which are implemented by
294 // Gecko with webidl and which SpiderMonkey knows nothing about. On the other
295 // hand, Gecko knows nothing about which (if any) debuggers are observing a
296 // promise's global. The compromise is that Gecko is responsible for calling
297 // these handlers at the appropriate times, and SpiderMonkey will handle
298 // notifying any Debugger instances that are observing the given promise's
299 // global.
300 
301 // Notify any Debugger instances observing this promise's global that a new
302 // promise was allocated.
303 JS_PUBLIC_API(void)
304 onNewPromise(JSContext* cx, HandleObject promise);
305 
306 // Notify any Debugger instances observing this promise's global that the
307 // promise has settled (ie, it has either been fulfilled or rejected). Note that
308 // this is *not* equivalent to the promise resolution (ie, the promise's fate
309 // getting locked in) because you can resolve a promise with another pending
310 // promise, in which case neither promise has settled yet.
311 //
312 // It is Gecko's responsibility to ensure that this is never called on the same
setRpcNameAndVersion(const QString & program_name,int version)313 // promise more than once (because a promise can only make the transition from
314 // unsettled to settled once).
315 JS_PUBLIC_API(void)
316 onPromiseSettled(JSContext* cx, HandleObject promise);
317 
318 
319 
320 // Return true if the given value is a Debugger object, false otherwise.
321 JS_PUBLIC_API(bool)
322 IsDebugger(JSObject& obj);
323 
324 // Append each of the debuggee global objects observed by the Debugger object
325 // |dbgObj| to |vector|. Returns true on success, false on failure.
326 JS_PUBLIC_API(bool)
327 GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, AutoObjectVector& vector);
328 
329 
330 // Hooks for reporting where JavaScript execution began.
331 //
332 // Our performance tools would like to be able to label blocks of JavaScript
dceRpcProgramChanged(const QString & program_name)333 // execution with the function name and source location where execution began:
334 // the event handler, the callback, etc.
335 //
336 // Construct an instance of this class on the stack, providing a JSContext
337 // belonging to the runtime in which execution will occur. Each time we enter
338 // JavaScript --- specifically, each time we push a JavaScript stack frame that
339 // has no older JS frames younger than this AutoEntryMonitor --- we will
340 // call the appropriate |Entry| member function to indicate where we've begun
341 // execution.
342 
343 class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEntryMonitor) {
344     JSRuntime* runtime_;
345     AutoEntryMonitor* savedMonitor_;
346 
347   public:
348     explicit AutoEntryMonitor(JSContext* cx);
349     ~AutoEntryMonitor();
350 
351     // SpiderMonkey reports the JavaScript entry points occuring within this
352     // AutoEntryMonitor's scope to the following member functions, which the
353     // embedding is expected to override.
354     //
355     // It is important to note that |asyncCause| is owned by the caller and its
356     // lifetime must outlive the lifetime of the AutoEntryMonitor object. It is
357     // strongly encouraged that |asyncCause| be a string constant or similar
358     // statically allocated string.
359 
360     // We have begun executing |function|. Note that |function| may not be the
361     // actual closure we are running, but only the canonical function object to
362     // which the script refers.
363     virtual void Entry(JSContext* cx, JSFunction* function,
364                        HandleValue asyncStack,
365                        const char* asyncCause) = 0;
366 
367     // Execution has begun at the entry point of |script|, which is not a
368     // function body. (This is probably being executed by 'eval' or some
369     // JSAPI equivalent.)
370     virtual void Entry(JSContext* cx, JSScript* script,
371                        HandleValue asyncStack,
372                        const char* asyncCause) = 0;
373 
374     // Execution of the function or script has ended.
375     virtual void Exit(JSContext* cx) { }
376 };
377 
378 
379 
380 } // namespace dbg
381 } // namespace JS
382 
383 
384 #endif /* js_Debug_h */
385