js/jsd/jsd_hook.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial