Coverage Report

Created: 2018-09-25 14:53

/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 */