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