Back to index

lightning-sunbird  0.9+nobinonly
jsd_hook.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * JavaScript Debugging support - Hook support
00040  */
00041 
00042 #include "jsd.h"
00043 
00044 JSTrapStatus JS_DLL_CALLBACK
00045 jsd_InterruptHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
00046                      void *closure)
00047 {
00048     JSDScript*      jsdscript;
00049     JSDContext*     jsdc = (JSDContext*) closure;
00050     JSD_ExecutionHookProc hook;
00051     void*                 hookData;
00052 
00053     if( ! jsdc || ! jsdc->inited )
00054         return JSTRAP_CONTINUE;
00055 
00056     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
00057         return JSTRAP_CONTINUE;
00058 
00059     /* local in case jsdc->interruptHook gets cleared on another thread */
00060     JSD_LOCK();
00061     hook     = jsdc->interruptHook;
00062     hookData = jsdc->interruptHookData;
00063     JSD_UNLOCK();
00064 
00065     if (!hook)
00066         return JSTRAP_CONTINUE;
00067     
00068     JSD_LOCK_SCRIPTS(jsdc);
00069     jsdscript = jsd_FindJSDScript(jsdc, script);
00070     JSD_UNLOCK_SCRIPTS(jsdc);
00071     if( ! jsdscript )
00072         return JSTRAP_CONTINUE;
00073 
00074 #ifdef LIVEWIRE
00075     if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (jsuword)pc) )
00076         return JSTRAP_CONTINUE;
00077 #endif
00078 
00079     return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_INTERRUPTED,
00080                                  hook, hookData, rval);
00081 }
00082 
00083 JSTrapStatus JS_DLL_CALLBACK
00084 jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
00085                     jsval *rval, void *closure)
00086 {
00087     JSDScript*      jsdscript;
00088     JSDContext*     jsdc = (JSDContext*) closure;
00089     JSD_ExecutionHookProc hook;
00090     void*                 hookData;
00091 
00092     if( ! jsdc || ! jsdc->inited )
00093         return JSTRAP_CONTINUE;
00094 
00095     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
00096         return JSTRAP_CONTINUE;
00097 
00098     /* local in case jsdc->debuggerHook gets cleared on another thread */
00099     JSD_LOCK();
00100     hook     = jsdc->debuggerHook;
00101     hookData = jsdc->debuggerHookData;
00102     JSD_UNLOCK();
00103     if(!hook)
00104         return JSTRAP_CONTINUE;
00105 
00106     JSD_LOCK_SCRIPTS(jsdc);
00107     jsdscript = jsd_FindJSDScript(jsdc, script);
00108     JSD_UNLOCK_SCRIPTS(jsdc);
00109     if( ! jsdscript )
00110         return JSTRAP_CONTINUE;
00111 
00112     return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUGGER_KEYWORD,
00113                                  hook, hookData, rval);
00114 }
00115 
00116 
00117 JSTrapStatus JS_DLL_CALLBACK
00118 jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
00119                  jsval *rval, void *closure)
00120 {
00121     JSDScript*      jsdscript;
00122     JSDContext*     jsdc = (JSDContext*) closure;
00123     JSD_ExecutionHookProc hook;
00124     void*                 hookData;
00125 
00126     if( ! jsdc || ! jsdc->inited )
00127         return JSD_HOOK_RETURN_CONTINUE_THROW;
00128 
00129     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
00130         return JSD_HOOK_RETURN_CONTINUE_THROW;
00131 
00132     /* local in case jsdc->throwHook gets cleared on another thread */
00133     JSD_LOCK();
00134     hook     = jsdc->throwHook;
00135     hookData = jsdc->throwHookData;
00136     JSD_UNLOCK();
00137     if (!hook)
00138         return JSD_HOOK_RETURN_CONTINUE_THROW;
00139 
00140     JSD_LOCK_SCRIPTS(jsdc);
00141     jsdscript = jsd_FindJSDScript(jsdc, script);
00142     JSD_UNLOCK_SCRIPTS(jsdc);
00143     if( ! jsdscript )
00144         return JSD_HOOK_RETURN_CONTINUE_THROW;
00145 
00146     JS_GetPendingException(cx, rval);
00147 
00148     return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_THROW,
00149                                  hook, hookData, rval);
00150 }
00151 
00152 JSTrapStatus
00153 jsd_CallExecutionHook(JSDContext* jsdc,
00154                       JSContext *cx,
00155                       uintN type,
00156                       JSD_ExecutionHookProc hook,
00157                       void* hookData,
00158                       jsval* rval)
00159 {
00160     uintN hookanswer = JSD_HOOK_THROW == type ? 
00161                             JSD_HOOK_RETURN_CONTINUE_THROW :
00162                             JSD_HOOK_RETURN_CONTINUE;
00163     JSDThreadState* jsdthreadstate;
00164 
00165     if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc,cx)))
00166     {
00167         if ((type != JSD_HOOK_THROW && type != JSD_HOOK_INTERRUPTED) ||
00168             jsdc->flags & JSD_MASK_TOP_FRAME_ONLY ||
00169             !(jsdthreadstate->flags & TS_HAS_DISABLED_FRAME))
00170         {
00171             /*
00172              * if it's not a throw and it's not an interrupt,
00173              * or we're only masking the top frame,
00174              * or there are no disabled frames in this stack,
00175              * then call out.
00176              */
00177              hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval);
00178              jsd_DestroyThreadState(jsdc, jsdthreadstate);
00179         }
00180     }
00181 
00182     switch(hookanswer)
00183     {
00184         case JSD_HOOK_RETURN_ABORT:
00185         case JSD_HOOK_RETURN_HOOK_ERROR:
00186             return JSTRAP_ERROR;
00187         case JSD_HOOK_RETURN_RET_WITH_VAL:
00188             return JSTRAP_RETURN;
00189         case JSD_HOOK_RETURN_THROW_WITH_VAL:
00190             return JSTRAP_THROW;
00191         case JSD_HOOK_RETURN_CONTINUE:
00192             break;
00193         case JSD_HOOK_RETURN_CONTINUE_THROW:
00194             /* only makes sense for jsd_ThrowHandler (which init'd rval) */
00195             JS_ASSERT(JSD_HOOK_THROW == type);
00196             return JSTRAP_THROW;
00197         default:
00198             JS_ASSERT(0);
00199             break;
00200     }
00201     return JSTRAP_CONTINUE;
00202 }
00203 
00204 JSBool
00205 jsd_CallCallHook (JSDContext* jsdc,
00206                   JSContext *cx,
00207                   uintN type,
00208                   JSD_CallHookProc hook,
00209                   void* hookData)
00210 {
00211     JSBool hookanswer;
00212     JSDThreadState*  jsdthreadstate;
00213     
00214     hookanswer = JS_FALSE;
00215     if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc, cx)))
00216     {
00217         hookanswer = hook(jsdc, jsdthreadstate, type, hookData);
00218         jsd_DestroyThreadState(jsdc, jsdthreadstate);
00219     }
00220 
00221     return hookanswer;
00222 }
00223 
00224 JSBool
00225 jsd_SetInterruptHook(JSDContext*           jsdc,
00226                      JSD_ExecutionHookProc hook,
00227                      void*                 callerdata)
00228 {
00229     JSD_LOCK();
00230     jsdc->interruptHookData  = callerdata;
00231     jsdc->interruptHook      = hook;
00232     JS_SetInterrupt(jsdc->jsrt, jsd_InterruptHandler, (void*) jsdc);
00233     JSD_UNLOCK();
00234 
00235     return JS_TRUE;
00236 }
00237 
00238 JSBool
00239 jsd_ClearInterruptHook(JSDContext* jsdc)
00240 {
00241     JSD_LOCK();
00242     JS_ClearInterrupt(jsdc->jsrt, NULL, NULL );
00243     jsdc->interruptHook      = NULL;
00244     JSD_UNLOCK();
00245 
00246     return JS_TRUE;
00247 }
00248 
00249 JSBool
00250 jsd_SetDebugBreakHook(JSDContext*           jsdc,
00251                       JSD_ExecutionHookProc hook,
00252                       void*                 callerdata)
00253 {
00254     JSD_LOCK();
00255     jsdc->debugBreakHookData  = callerdata;
00256     jsdc->debugBreakHook      = hook;
00257     JSD_UNLOCK();
00258 
00259     return JS_TRUE;
00260 }
00261 
00262 JSBool
00263 jsd_ClearDebugBreakHook(JSDContext* jsdc)
00264 {
00265     JSD_LOCK();
00266     jsdc->debugBreakHook      = NULL;
00267     JSD_UNLOCK();
00268 
00269     return JS_TRUE;
00270 }
00271 
00272 JSBool
00273 jsd_SetDebuggerHook(JSDContext*           jsdc,
00274                       JSD_ExecutionHookProc hook,
00275                       void*                 callerdata)
00276 {
00277     JSD_LOCK();
00278     jsdc->debuggerHookData  = callerdata;
00279     jsdc->debuggerHook      = hook;
00280     JSD_UNLOCK();
00281 
00282     return JS_TRUE;
00283 }
00284 
00285 JSBool
00286 jsd_ClearDebuggerHook(JSDContext* jsdc)
00287 {
00288     JSD_LOCK();
00289     jsdc->debuggerHook      = NULL;
00290     JSD_UNLOCK();
00291 
00292     return JS_TRUE;
00293 }
00294 
00295 JSBool
00296 jsd_SetThrowHook(JSDContext*           jsdc,
00297                  JSD_ExecutionHookProc hook,
00298                  void*                 callerdata)
00299 {
00300     JSD_LOCK();
00301     jsdc->throwHookData  = callerdata;
00302     jsdc->throwHook      = hook;
00303     JSD_UNLOCK();
00304 
00305     return JS_TRUE;
00306 }
00307 
00308 JSBool
00309 jsd_ClearThrowHook(JSDContext* jsdc)
00310 {
00311     JSD_LOCK();
00312     jsdc->throwHook      = NULL;
00313     JSD_UNLOCK();
00314 
00315     return JS_TRUE;
00316 }
00317 
00318 JSBool
00319 jsd_SetFunctionHook(JSDContext*      jsdc,
00320                     JSD_CallHookProc hook,
00321                     void*            callerdata)
00322 {
00323     JSD_LOCK();
00324     jsdc->functionHookData  = callerdata;
00325     jsdc->functionHook      = hook;
00326     JSD_UNLOCK();
00327 
00328     return JS_TRUE;
00329 }
00330 
00331 JSBool
00332 jsd_ClearFunctionHook(JSDContext* jsdc)
00333 {
00334     JSD_LOCK();
00335     jsdc->functionHook      = NULL;
00336     JSD_UNLOCK();
00337 
00338     return JS_TRUE;
00339 }
00340 
00341 JSBool
00342 jsd_SetTopLevelHook(JSDContext*      jsdc,
00343                     JSD_CallHookProc hook,
00344                     void*            callerdata)
00345 {
00346     JSD_LOCK();
00347     jsdc->toplevelHookData  = callerdata;
00348     jsdc->toplevelHook      = hook;
00349     JSD_UNLOCK();
00350 
00351     return JS_TRUE;
00352 }
00353 
00354 JSBool
00355 jsd_ClearTopLevelHook(JSDContext* jsdc)
00356 {
00357     JSD_LOCK();
00358     jsdc->toplevelHook      = NULL;
00359     JSD_UNLOCK();
00360 
00361     return JS_TRUE;
00362 }
00363