1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/jsd/jsd_hook.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,330 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JavaScript Debugging support - Hook support 1.12 + */ 1.13 + 1.14 +#include "jsd.h" 1.15 + 1.16 +JSTrapStatus 1.17 +jsd_InterruptHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, 1.18 + void *closure) 1.19 +{ 1.20 + JSDScript* jsdscript; 1.21 + JSDContext* jsdc = (JSDContext*) closure; 1.22 + JSD_ExecutionHookProc hook; 1.23 + void* hookData; 1.24 + 1.25 + if( ! jsdc || ! jsdc->inited ) 1.26 + return JSTRAP_CONTINUE; 1.27 + 1.28 + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) 1.29 + return JSTRAP_CONTINUE; 1.30 + 1.31 + /* local in case jsdc->interruptHook gets cleared on another thread */ 1.32 + JSD_LOCK(); 1.33 + hook = jsdc->interruptHook; 1.34 + hookData = jsdc->interruptHookData; 1.35 + JSD_UNLOCK(); 1.36 + 1.37 + if (!hook) 1.38 + return JSTRAP_CONTINUE; 1.39 + 1.40 + JSD_LOCK_SCRIPTS(jsdc); 1.41 + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr()); 1.42 + JSD_UNLOCK_SCRIPTS(jsdc); 1.43 + if( ! jsdscript ) 1.44 + return JSTRAP_CONTINUE; 1.45 + 1.46 + return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_INTERRUPTED, 1.47 + hook, hookData, rval); 1.48 +} 1.49 + 1.50 +JSTrapStatus 1.51 +jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc, 1.52 + jsval *rval, void *closure) 1.53 +{ 1.54 + JSDScript* jsdscript; 1.55 + JSDContext* jsdc = (JSDContext*) closure; 1.56 + JSD_ExecutionHookProc hook; 1.57 + void* hookData; 1.58 + 1.59 + if( ! jsdc || ! jsdc->inited ) 1.60 + return JSTRAP_CONTINUE; 1.61 + 1.62 + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) 1.63 + return JSTRAP_CONTINUE; 1.64 + 1.65 + /* local in case jsdc->debuggerHook gets cleared on another thread */ 1.66 + JSD_LOCK(); 1.67 + hook = jsdc->debuggerHook; 1.68 + hookData = jsdc->debuggerHookData; 1.69 + JSD_UNLOCK(); 1.70 + if(!hook) 1.71 + return JSTRAP_CONTINUE; 1.72 + 1.73 + JSD_LOCK_SCRIPTS(jsdc); 1.74 + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr()); 1.75 + JSD_UNLOCK_SCRIPTS(jsdc); 1.76 + if( ! jsdscript ) 1.77 + return JSTRAP_CONTINUE; 1.78 + 1.79 + return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUGGER_KEYWORD, 1.80 + hook, hookData, rval); 1.81 +} 1.82 + 1.83 + 1.84 +JSTrapStatus 1.85 +jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, 1.86 + jsval *rvalArg, void *closure) 1.87 +{ 1.88 + JSDScript* jsdscript; 1.89 + JSDContext* jsdc = (JSDContext*) closure; 1.90 + JSD_ExecutionHookProc hook; 1.91 + void* hookData; 1.92 + 1.93 + if( ! jsdc || ! jsdc->inited ) 1.94 + return JSTRAP_CONTINUE; 1.95 + 1.96 + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) 1.97 + return JSTRAP_CONTINUE; 1.98 + 1.99 + /* local in case jsdc->throwHook gets cleared on another thread */ 1.100 + JSD_LOCK(); 1.101 + hook = jsdc->throwHook; 1.102 + hookData = jsdc->throwHookData; 1.103 + JSD_UNLOCK(); 1.104 + if (!hook) 1.105 + return JSTRAP_CONTINUE; 1.106 + 1.107 + JSD_LOCK_SCRIPTS(jsdc); 1.108 + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, JSNullFramePtr()); 1.109 + JSD_UNLOCK_SCRIPTS(jsdc); 1.110 + if( ! jsdscript ) 1.111 + return JSTRAP_CONTINUE; 1.112 + 1.113 + JS::RootedValue rval(cx); 1.114 + JS_GetPendingException(cx, &rval); 1.115 + 1.116 + JSTrapStatus result = jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_THROW, 1.117 + hook, hookData, rval.address()); 1.118 + *rvalArg = rval; 1.119 + return result; 1.120 +} 1.121 + 1.122 +JSTrapStatus 1.123 +jsd_CallExecutionHook(JSDContext* jsdc, 1.124 + JSContext *cx, 1.125 + unsigned type, 1.126 + JSD_ExecutionHookProc hook, 1.127 + void* hookData, 1.128 + jsval* rval) 1.129 +{ 1.130 + unsigned hookanswer = JSD_HOOK_THROW == type ? 1.131 + JSD_HOOK_RETURN_CONTINUE_THROW : 1.132 + JSD_HOOK_RETURN_CONTINUE; 1.133 + JSDThreadState* jsdthreadstate; 1.134 + 1.135 + if(hook && nullptr != (jsdthreadstate = jsd_NewThreadState(jsdc, cx))) 1.136 + { 1.137 + if ((type != JSD_HOOK_THROW && type != JSD_HOOK_INTERRUPTED) || 1.138 + jsdc->flags & JSD_MASK_TOP_FRAME_ONLY || 1.139 + !(jsdthreadstate->flags & TS_HAS_DISABLED_FRAME)) 1.140 + { 1.141 + /* 1.142 + * if it's not a throw and it's not an interrupt, 1.143 + * or we're only masking the top frame, 1.144 + * or there are no disabled frames in this stack, 1.145 + * then call out. 1.146 + */ 1.147 + hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval); 1.148 + jsd_DestroyThreadState(jsdc, jsdthreadstate); 1.149 + } 1.150 + } 1.151 + 1.152 + switch(hookanswer) 1.153 + { 1.154 + case JSD_HOOK_RETURN_ABORT: 1.155 + case JSD_HOOK_RETURN_HOOK_ERROR: 1.156 + return JSTRAP_ERROR; 1.157 + case JSD_HOOK_RETURN_RET_WITH_VAL: 1.158 + return JSTRAP_RETURN; 1.159 + case JSD_HOOK_RETURN_THROW_WITH_VAL: 1.160 + return JSTRAP_THROW; 1.161 + case JSD_HOOK_RETURN_CONTINUE: 1.162 + break; 1.163 + case JSD_HOOK_RETURN_CONTINUE_THROW: 1.164 + /* only makes sense for jsd_ThrowHandler (which init'd rval) */ 1.165 + MOZ_ASSERT(JSD_HOOK_THROW == type); 1.166 + return JSTRAP_THROW; 1.167 + default: 1.168 + MOZ_ASSERT(0); 1.169 + break; 1.170 + } 1.171 + return JSTRAP_CONTINUE; 1.172 +} 1.173 + 1.174 +bool 1.175 +jsd_CallCallHook (JSDContext* jsdc, 1.176 + JSContext *cx, 1.177 + unsigned type, 1.178 + JSD_CallHookProc hook, 1.179 + void* hookData) 1.180 +{ 1.181 + bool hookanswer; 1.182 + JSDThreadState* jsdthreadstate; 1.183 + 1.184 + hookanswer = false; 1.185 + if(hook && nullptr != (jsdthreadstate = jsd_NewThreadState(jsdc, cx))) 1.186 + { 1.187 + hookanswer = hook(jsdc, jsdthreadstate, type, hookData); 1.188 + jsd_DestroyThreadState(jsdc, jsdthreadstate); 1.189 + } 1.190 + 1.191 + return hookanswer; 1.192 +} 1.193 + 1.194 +bool 1.195 +jsd_SetInterruptHook(JSDContext* jsdc, 1.196 + JSD_ExecutionHookProc hook, 1.197 + void* callerdata) 1.198 +{ 1.199 + JSD_LOCK(); 1.200 + jsdc->interruptHookData = callerdata; 1.201 + jsdc->interruptHook = hook; 1.202 + JS_SetInterrupt(jsdc->jsrt, jsd_InterruptHandler, (void*) jsdc); 1.203 + JSD_UNLOCK(); 1.204 + 1.205 + return true; 1.206 +} 1.207 + 1.208 +bool 1.209 +jsd_ClearInterruptHook(JSDContext* jsdc) 1.210 +{ 1.211 + JSD_LOCK(); 1.212 + JS_ClearInterrupt(jsdc->jsrt, nullptr, nullptr); 1.213 + jsdc->interruptHook = nullptr; 1.214 + JSD_UNLOCK(); 1.215 + 1.216 + return true; 1.217 +} 1.218 + 1.219 +bool 1.220 +jsd_SetDebugBreakHook(JSDContext* jsdc, 1.221 + JSD_ExecutionHookProc hook, 1.222 + void* callerdata) 1.223 +{ 1.224 + JSD_LOCK(); 1.225 + jsdc->debugBreakHookData = callerdata; 1.226 + jsdc->debugBreakHook = hook; 1.227 + JSD_UNLOCK(); 1.228 + 1.229 + return true; 1.230 +} 1.231 + 1.232 +bool 1.233 +jsd_ClearDebugBreakHook(JSDContext* jsdc) 1.234 +{ 1.235 + JSD_LOCK(); 1.236 + jsdc->debugBreakHook = nullptr; 1.237 + JSD_UNLOCK(); 1.238 + 1.239 + return true; 1.240 +} 1.241 + 1.242 +bool 1.243 +jsd_SetDebuggerHook(JSDContext* jsdc, 1.244 + JSD_ExecutionHookProc hook, 1.245 + void* callerdata) 1.246 +{ 1.247 + JSD_LOCK(); 1.248 + jsdc->debuggerHookData = callerdata; 1.249 + jsdc->debuggerHook = hook; 1.250 + JSD_UNLOCK(); 1.251 + 1.252 + return true; 1.253 +} 1.254 + 1.255 +bool 1.256 +jsd_ClearDebuggerHook(JSDContext* jsdc) 1.257 +{ 1.258 + JSD_LOCK(); 1.259 + jsdc->debuggerHook = nullptr; 1.260 + JSD_UNLOCK(); 1.261 + 1.262 + return true; 1.263 +} 1.264 + 1.265 +bool 1.266 +jsd_SetThrowHook(JSDContext* jsdc, 1.267 + JSD_ExecutionHookProc hook, 1.268 + void* callerdata) 1.269 +{ 1.270 + JSD_LOCK(); 1.271 + jsdc->throwHookData = callerdata; 1.272 + jsdc->throwHook = hook; 1.273 + JSD_UNLOCK(); 1.274 + 1.275 + return true; 1.276 +} 1.277 + 1.278 +bool 1.279 +jsd_ClearThrowHook(JSDContext* jsdc) 1.280 +{ 1.281 + JSD_LOCK(); 1.282 + jsdc->throwHook = nullptr; 1.283 + JSD_UNLOCK(); 1.284 + 1.285 + return true; 1.286 +} 1.287 + 1.288 +bool 1.289 +jsd_SetFunctionHook(JSDContext* jsdc, 1.290 + JSD_CallHookProc hook, 1.291 + void* callerdata) 1.292 +{ 1.293 + JSD_LOCK(); 1.294 + jsdc->functionHookData = callerdata; 1.295 + jsdc->functionHook = hook; 1.296 + JSD_UNLOCK(); 1.297 + 1.298 + return true; 1.299 +} 1.300 + 1.301 +bool 1.302 +jsd_ClearFunctionHook(JSDContext* jsdc) 1.303 +{ 1.304 + JSD_LOCK(); 1.305 + jsdc->functionHook = nullptr; 1.306 + JSD_UNLOCK(); 1.307 + 1.308 + return true; 1.309 +} 1.310 + 1.311 +bool 1.312 +jsd_SetTopLevelHook(JSDContext* jsdc, 1.313 + JSD_CallHookProc hook, 1.314 + void* callerdata) 1.315 +{ 1.316 + JSD_LOCK(); 1.317 + jsdc->toplevelHookData = callerdata; 1.318 + jsdc->toplevelHook = hook; 1.319 + JSD_UNLOCK(); 1.320 + 1.321 + return true; 1.322 +} 1.323 + 1.324 +bool 1.325 +jsd_ClearTopLevelHook(JSDContext* jsdc) 1.326 +{ 1.327 + JSD_LOCK(); 1.328 + jsdc->toplevelHook = nullptr; 1.329 + JSD_UNLOCK(); 1.330 + 1.331 + return true; 1.332 +} 1.333 +