File: DebugController.java

package info (click to toggle)
spidermonkey 1.5rc6a-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 6,676 kB
  • ctags: 11,462
  • sloc: ansic: 82,178; cpp: 11,392; java: 859; perl: 722; makefile: 638; asm: 75; awk: 20; sh: 7
file content (378 lines) | stat: -rw-r--r-- 13,102 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation. All
 * Rights Reserved.
 *
 * Contributor(s): 
 */

package netscape.jsdebug;

import netscape.util.Hashtable;
import netscape.security.PrivilegeManager;
import netscape.security.ForbiddenTargetException;

/**
* This is the master control panel for observing events in the VM.
* Each method setXHook() must be passed an object that extends
* the class XHook.  When an event of the specified type
* occurs, a well-known method on XHook will be called (see the
* various XHook classes for details).  The method call takes place
* on the same thread that triggered the event in the first place,
* so that any monitors held by the thread which triggered the hook
* will still be owned in the hook method.
* <p>
* This class is meant to be a singleton and has a private constructor.
* Call the static <code>getDebugController()</code> to get this object.
* <p>
* Note that all functions use netscape.security.PrivilegeManager to verify 
* that the caller has the "Debugger" privilege. The exception 
* netscape.security.ForbiddenTargetException will be throw if this is 
* not enabled.
*
* @author  John Bandhauer
* @author  Nick Thompson
* @version 1.0
* @since   1.0
* @see netscape.security.PrivilegeManager
* @see netscape.security.ForbiddenTargetException
*/
public final class DebugController {

    private static final int majorVersion = 1;
    private static final int minorVersion = 0;

    private static DebugController controller;
    private ScriptHook scriptHook;
    private Hashtable instructionHookTable;
    private InterruptHook interruptHook;
    private DebugBreakHook debugBreakHook;
    private JSErrorReporter errorReporter;

    /**
     * Get the DebugController object for the current VM.
     * <p>
     * @return the singleton DebugController
     */
    public static synchronized DebugController getDebugController() 
        throws ForbiddenTargetException
    {
        try {
            PrivilegeManager.checkPrivilegeEnabled("Debugger");
            if (controller == null)
                controller = new DebugController();
            return controller;
    	} catch (ForbiddenTargetException e) {
            System.out.println("failed in check Priv in DebugController.getDebugController()");
            e.printStackTrace(System.out);
            throw e;
    	}
    }

    private DebugController()
    {
        scriptTable = new Hashtable();
        _setController(true);
    }



    /**
     * Request notification of Script loading events.
     * <p>
     * Whenever a Script is loaded into or unloaded from the VM 
     * the appropriate method of  the ScriptHook argument will be called. 
     * Callers are responsible for chaining hooks if chaining is required.
     *
     * @param h new script hook
     * @return the previous hook object (null if none)
     */
    public synchronized ScriptHook setScriptHook(ScriptHook h)
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        ScriptHook oldHook = scriptHook;
        scriptHook = h;
        return oldHook;
    }

    /**
     * Get the current observer of Script events.
     * <p>
     * @return the current script hook (null if none)
     */
    public ScriptHook getScriptHook()
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        return scriptHook;
    }

    /**
     * Set a hook at the given program counter value.  
     * <p>
     * When a thread reaches that instruction, a ThreadState 
     * object will be created and the appropriate method 
     * of the hook object will be called. Callers are responsible
     * for chaining hooks if chaining is required.
     * 
     * @param pc pc at which hook should be set
     * @param h new hook for this pc
     * @return the previous hook object (null if none)
     */
    public synchronized InstructionHook setInstructionHook(
        PC pc,
        InstructionHook h) 
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        InstructionHook oldHook;
        if (instructionHookTable == null) {
            instructionHookTable = new Hashtable();
        }
        oldHook = (InstructionHook) instructionHookTable.get(pc);
        instructionHookTable.put(pc, h);
        setInstructionHook0(pc);
        return oldHook;
    }

    private native void setInstructionHook0(PC pc);

    /**
     * Get the hook at the given program counter value.
     * <p>
     * @param pc pc for which hook should be found
     * @return the hook (null if none)
     */
    public InstructionHook getInstructionHook(PC pc)
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        return getInstructionHook0(pc);
    }

    // called by native function
    private InstructionHook getInstructionHook0(PC pc)
    {
        if (instructionHookTable == null)
            return null;
        else
            return (InstructionHook) instructionHookTable.get(pc);
    }

    /**************************************************************/

    /**
     * Set the hook at to be called when interrupts occur.
     * <p>
     * The next instruction which starts to execute after 
     * <code>sendInterrupt()</code> has been called will 
     * trigger a call to this hook. A ThreadState 
     * object will be created and the appropriate method 
     * of the hook object will be called. Callers are responsible
     * for chaining hooks if chaining is required.
     * 
     * @param h new hook
     * @return the previous hook object (null if none)
     * @see netscape.jsdebug.DebugController#sendInterrupt
     */
    public synchronized InterruptHook setInterruptHook( InterruptHook h )
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        InterruptHook oldHook = interruptHook;
        interruptHook = h;
        return oldHook;
    }

    /**
     * Get the current hook to be called on interrupt
     * <p>
     * @return the hook (null if none)
     */
    public InterruptHook getInterruptHook()
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        return interruptHook;
    }

    /**
     * Cause the interrupt hook to be called when the next 
     * JavaScript instruction starts to execute.
     * <p>
     * The interrupt is self clearing
     * @see netscape.jsdebug.DebugController#setInterruptHook
     */
    public void sendInterrupt()
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        sendInterrupt0();
    }

    private native void sendInterrupt0();


    /**************************************************************/

    /**
     * Set the hook at to be called when a <i>debug break</i> is requested
     * <p>
     * Set the hook to be called when <i>JSErrorReporter.DEBUG</i> is returned
     * by the <i>error reporter</i> hook. When that happens a ThreadState 
     * object will be created and the appropriate method 
     * of the hook object will be called. Callers are responsible
     * for chaining hooks if chaining is required.
     * 
     * @param h new hook
     * @return the previous hook object (null if none)
     * @see netscape.jsdebug.DebugController#setErrorReporter
     * @see netscape.jsdebug.JSErrorReporter
     */
    public synchronized DebugBreakHook setDebugBreakHook( DebugBreakHook h )
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        DebugBreakHook oldHook = debugBreakHook;
        debugBreakHook = h;
        return oldHook;
    }

    /**
     * Get the current hook to be called on debug break
     * <p>
     * @return the hook (null if none)
     */
    public DebugBreakHook getDebugBreakHook()
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        return debugBreakHook;
    }


    /**************************************************************/
    /**
     * Get the 'handle' which cooresponds to the native code representing the
     * instance of the underlying JavaScript Debugger context.
     * <p>
     * This would not normally be useful in java. Some of the other classes
     * in this package need this. It remains public mostly for historical 
     * reasons. It serves as a check to see that the native classes have been
     * loaded and the built-in native JavaScript Debugger support has been 
     * initialized. This DebugController is not valid (or useful) when it is
     * in a state where this native context equals 0.
     *
     * @return the native context (0 if none)
     */
    public int getNativeContext() 
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
//        System.out.println( "nativecontext = " + _nativeContext + "\n" );
        return _nativeContext;
    }

    private native void _setController( boolean set );
    private Hashtable scriptTable;
    private int _nativeContext;

    /**
     * Execute a string as a JavaScript script within a stack frame
     * <p>
     * This method can be used to execute arbitrary sets of statements on a 
     * stopped thread. It is useful for inspecting and modifying data.
     * <p>
     * This method can only be called while the JavaScript thread is stopped 
     * - i.e. as part of the code responding to a hook. Thgis method 
     * <b>must</b> be called on the same thread as was executing when the 
     * hook was called.
     * <p>
     * If an error occurs while execuing this code, then the error 
     * reporter hook will be called if present.
     * 
     * @param frame the frame context in which to evaluate this script
     * @param text the script text
     * @param filename where to tell the JavaScript engine this code came 
     * from (it is usually best to make this the same as the filename of
     * code represented by the frame)
     * @param lineno the line number to pass to JS ( >=1 )
     * @return The result of the script execution converted to a string.
     * (null if the result was null or void)
     */
    public String executeScriptInStackFrame( JSStackFrameInfo frame,
                                             String text,
                                             String filename,
                                             int lineno )
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        return executeScriptInStackFrame0( frame, text, filename, lineno );
    }

    private native String executeScriptInStackFrame0( JSStackFrameInfo frame,
                                                     String text,
                                                     String filename,
                                                     int lineno );


    /**
     * Set the hook at to be called when a JavaScript error occurs
     * <p>
     * @param er new error reporter hook
     * @return the previous hook object (null if none)
     * @see netscape.jsdebug.JSErrorReporter
     */
    public JSErrorReporter setErrorReporter(JSErrorReporter er)
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        JSErrorReporter old = errorReporter;
        errorReporter = er;
        return old;
    }

    /**
     * Get the hook at to be called when a JavaScript error occurs
     * <p>
     * @return the hook object (null if none)
     * @see netscape.jsdebug.JSErrorReporter
     */
    public JSErrorReporter getErrorReporter()
        throws ForbiddenTargetException
    {
        PrivilegeManager.checkPrivilegeEnabled("Debugger");
        return errorReporter;
    }

    /**
     * Get the major version number of this module
     * <p>
     * @return the version number
     */
    public static int getMajorVersion() {return majorVersion;}
    /**
     * Get the minor version number of this module
     * <p>
     * @return the version number
     */
    public static int getMinorVersion() {return minorVersion;}

    private static native int getNativeMajorVersion();
    private static native int getNativeMinorVersion();
}