js/jsd/jsd_hook.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:6b0d8cff8480
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 /*
8 * JavaScript Debugging support - Hook support
9 */
10
11 #include "jsd.h"
12
13 JSTrapStatus
14 jsd_InterruptHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
15 void *closure)
16 {
17 JSDScript* jsdscript;
18 JSDContext* jsdc = (JSDContext*) closure;
19 JSD_ExecutionHookProc hook;
20 void* hookData;
21
22 if( ! jsdc || ! jsdc->inited )
23 return JSTRAP_CONTINUE;
24
25 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
26 return JSTRAP_CONTINUE;
27
28 /* local in case jsdc->interruptHook gets cleared on another thread */
29 JSD_LOCK();
30 hook = jsdc->interruptHook;
31 hookData = jsdc->interruptHookData;
32 JSD_UNLOCK();
33
34 if (!hook)
35 return JSTRAP_CONTINUE;
36
37 JSD_LOCK_SCRIPTS(jsdc);
38 jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr());
39 JSD_UNLOCK_SCRIPTS(jsdc);
40 if( ! jsdscript )
41 return JSTRAP_CONTINUE;
42
43 return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_INTERRUPTED,
44 hook, hookData, rval);
45 }
46
47 JSTrapStatus
48 jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
49 jsval *rval, void *closure)
50 {
51 JSDScript* jsdscript;
52 JSDContext* jsdc = (JSDContext*) closure;
53 JSD_ExecutionHookProc hook;
54 void* hookData;
55
56 if( ! jsdc || ! jsdc->inited )
57 return JSTRAP_CONTINUE;
58
59 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
60 return JSTRAP_CONTINUE;
61
62 /* local in case jsdc->debuggerHook gets cleared on another thread */
63 JSD_LOCK();
64 hook = jsdc->debuggerHook;
65 hookData = jsdc->debuggerHookData;
66 JSD_UNLOCK();
67 if(!hook)
68 return JSTRAP_CONTINUE;
69
70 JSD_LOCK_SCRIPTS(jsdc);
71 jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr());
72 JSD_UNLOCK_SCRIPTS(jsdc);
73 if( ! jsdscript )
74 return JSTRAP_CONTINUE;
75
76 return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUGGER_KEYWORD,
77 hook, hookData, rval);
78 }
79
80
81 JSTrapStatus
82 jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
83 jsval *rvalArg, void *closure)
84 {
85 JSDScript* jsdscript;
86 JSDContext* jsdc = (JSDContext*) closure;
87 JSD_ExecutionHookProc hook;
88 void* hookData;
89
90 if( ! jsdc || ! jsdc->inited )
91 return JSTRAP_CONTINUE;
92
93 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
94 return JSTRAP_CONTINUE;
95
96 /* local in case jsdc->throwHook gets cleared on another thread */
97 JSD_LOCK();
98 hook = jsdc->throwHook;
99 hookData = jsdc->throwHookData;
100 JSD_UNLOCK();
101 if (!hook)
102 return JSTRAP_CONTINUE;
103
104 JSD_LOCK_SCRIPTS(jsdc);
105 jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr());
106 JSD_UNLOCK_SCRIPTS(jsdc);
107 if( ! jsdscript )
108 return JSTRAP_CONTINUE;
109
110 JS::RootedValue rval(cx);
111 JS_GetPendingException(cx, &rval);
112
113 JSTrapStatus result = jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_THROW,
114 hook, hookData, rval.address());
115 *rvalArg = rval;
116 return result;
117 }
118
119 JSTrapStatus
120 jsd_CallExecutionHook(JSDContext* jsdc,
121 JSContext *cx,
122 unsigned type,
123 JSD_ExecutionHookProc hook,
124 void* hookData,
125 jsval* rval)
126 {
127 unsigned hookanswer = JSD_HOOK_THROW == type ?
128 JSD_HOOK_RETURN_CONTINUE_THROW :
129 JSD_HOOK_RETURN_CONTINUE;
130 JSDThreadState* jsdthreadstate;
131
132 if(hook && nullptr != (jsdthreadstate = jsd_NewThreadState(jsdc, cx)))
133 {
134 if ((type != JSD_HOOK_THROW && type != JSD_HOOK_INTERRUPTED) ||
135 jsdc->flags & JSD_MASK_TOP_FRAME_ONLY ||
136 !(jsdthreadstate->flags & TS_HAS_DISABLED_FRAME))
137 {
138 /*
139 * if it's not a throw and it's not an interrupt,
140 * or we're only masking the top frame,
141 * or there are no disabled frames in this stack,
142 * then call out.
143 */
144 hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval);
145 jsd_DestroyThreadState(jsdc, jsdthreadstate);
146 }
147 }
148
149 switch(hookanswer)
150 {
151 case JSD_HOOK_RETURN_ABORT:
152 case JSD_HOOK_RETURN_HOOK_ERROR:
153 return JSTRAP_ERROR;
154 case JSD_HOOK_RETURN_RET_WITH_VAL:
155 return JSTRAP_RETURN;
156 case JSD_HOOK_RETURN_THROW_WITH_VAL:
157 return JSTRAP_THROW;
158 case JSD_HOOK_RETURN_CONTINUE:
159 break;
160 case JSD_HOOK_RETURN_CONTINUE_THROW:
161 /* only makes sense for jsd_ThrowHandler (which init'd rval) */
162 MOZ_ASSERT(JSD_HOOK_THROW == type);
163 return JSTRAP_THROW;
164 default:
165 MOZ_ASSERT(0);
166 break;
167 }
168 return JSTRAP_CONTINUE;
169 }
170
171 bool
172 jsd_CallCallHook (JSDContext* jsdc,
173 JSContext *cx,
174 unsigned type,
175 JSD_CallHookProc hook,
176 void* hookData)
177 {
178 bool hookanswer;
179 JSDThreadState* jsdthreadstate;
180
181 hookanswer = false;
182 if(hook && nullptr != (jsdthreadstate = jsd_NewThreadState(jsdc, cx)))
183 {
184 hookanswer = hook(jsdc, jsdthreadstate, type, hookData);
185 jsd_DestroyThreadState(jsdc, jsdthreadstate);
186 }
187
188 return hookanswer;
189 }
190
191 bool
192 jsd_SetInterruptHook(JSDContext* jsdc,
193 JSD_ExecutionHookProc hook,
194 void* callerdata)
195 {
196 JSD_LOCK();
197 jsdc->interruptHookData = callerdata;
198 jsdc->interruptHook = hook;
199 JS_SetInterrupt(jsdc->jsrt, jsd_InterruptHandler, (void*) jsdc);
200 JSD_UNLOCK();
201
202 return true;
203 }
204
205 bool
206 jsd_ClearInterruptHook(JSDContext* jsdc)
207 {
208 JSD_LOCK();
209 JS_ClearInterrupt(jsdc->jsrt, nullptr, nullptr);
210 jsdc->interruptHook = nullptr;
211 JSD_UNLOCK();
212
213 return true;
214 }
215
216 bool
217 jsd_SetDebugBreakHook(JSDContext* jsdc,
218 JSD_ExecutionHookProc hook,
219 void* callerdata)
220 {
221 JSD_LOCK();
222 jsdc->debugBreakHookData = callerdata;
223 jsdc->debugBreakHook = hook;
224 JSD_UNLOCK();
225
226 return true;
227 }
228
229 bool
230 jsd_ClearDebugBreakHook(JSDContext* jsdc)
231 {
232 JSD_LOCK();
233 jsdc->debugBreakHook = nullptr;
234 JSD_UNLOCK();
235
236 return true;
237 }
238
239 bool
240 jsd_SetDebuggerHook(JSDContext* jsdc,
241 JSD_ExecutionHookProc hook,
242 void* callerdata)
243 {
244 JSD_LOCK();
245 jsdc->debuggerHookData = callerdata;
246 jsdc->debuggerHook = hook;
247 JSD_UNLOCK();
248
249 return true;
250 }
251
252 bool
253 jsd_ClearDebuggerHook(JSDContext* jsdc)
254 {
255 JSD_LOCK();
256 jsdc->debuggerHook = nullptr;
257 JSD_UNLOCK();
258
259 return true;
260 }
261
262 bool
263 jsd_SetThrowHook(JSDContext* jsdc,
264 JSD_ExecutionHookProc hook,
265 void* callerdata)
266 {
267 JSD_LOCK();
268 jsdc->throwHookData = callerdata;
269 jsdc->throwHook = hook;
270 JSD_UNLOCK();
271
272 return true;
273 }
274
275 bool
276 jsd_ClearThrowHook(JSDContext* jsdc)
277 {
278 JSD_LOCK();
279 jsdc->throwHook = nullptr;
280 JSD_UNLOCK();
281
282 return true;
283 }
284
285 bool
286 jsd_SetFunctionHook(JSDContext* jsdc,
287 JSD_CallHookProc hook,
288 void* callerdata)
289 {
290 JSD_LOCK();
291 jsdc->functionHookData = callerdata;
292 jsdc->functionHook = hook;
293 JSD_UNLOCK();
294
295 return true;
296 }
297
298 bool
299 jsd_ClearFunctionHook(JSDContext* jsdc)
300 {
301 JSD_LOCK();
302 jsdc->functionHook = nullptr;
303 JSD_UNLOCK();
304
305 return true;
306 }
307
308 bool
309 jsd_SetTopLevelHook(JSDContext* jsdc,
310 JSD_CallHookProc hook,
311 void* callerdata)
312 {
313 JSD_LOCK();
314 jsdc->toplevelHookData = callerdata;
315 jsdc->toplevelHook = hook;
316 JSD_UNLOCK();
317
318 return true;
319 }
320
321 bool
322 jsd_ClearTopLevelHook(JSDContext* jsdc)
323 {
324 JSD_LOCK();
325 jsdc->toplevelHook = nullptr;
326 JSD_UNLOCK();
327
328 return true;
329 }
330

mercurial