📄 jsdbgapi.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=78: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla 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/MPL/ * * 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 Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS debugging API. */#include "jsstddef.h"#include <string.h>#include "jstypes.h"#include "jsutil.h" /* Added by JSIFY */#include "jsclist.h"#include "jsapi.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsdbgapi.h"#include "jsfun.h"#include "jsgc.h"#include "jsinterp.h"#include "jslock.h"#include "jsobj.h"#include "jsopcode.h"#include "jsscope.h"#include "jsscript.h"#include "jsstr.h"typedef struct JSTrap { JSCList links; JSScript *script; jsbytecode *pc; JSOp op; JSTrapHandler handler; void *closure;} JSTrap;static JSTrap *FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc){ JSTrap *trap; for (trap = (JSTrap *)rt->trapList.next; trap != (JSTrap *)&rt->trapList; trap = (JSTrap *)trap->links.next) { if (trap->script == script && trap->pc == pc) return trap; } return NULL;}voidjs_PatchOpcode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op){ JSTrap *trap; trap = FindTrap(cx->runtime, script, pc); if (trap) trap->op = op; else *pc = (jsbytecode)op;}JS_PUBLIC_API(JSBool)JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handler, void *closure){ JSRuntime *rt; JSTrap *trap; rt = cx->runtime; trap = FindTrap(rt, script, pc); if (trap) { JS_ASSERT(trap->script == script && trap->pc == pc); JS_ASSERT(*pc == JSOP_TRAP); } else { trap = (JSTrap *) JS_malloc(cx, sizeof *trap); if (!trap || !js_AddRoot(cx, &trap->closure, "trap->closure")) { if (trap) JS_free(cx, trap); return JS_FALSE; } JS_APPEND_LINK(&trap->links, &rt->trapList); trap->script = script; trap->pc = pc; trap->op = (JSOp)*pc; *pc = JSOP_TRAP; } trap->handler = handler; trap->closure = closure; return JS_TRUE;}JS_PUBLIC_API(JSOp)JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc){ JSTrap *trap; trap = FindTrap(cx->runtime, script, pc); if (!trap) { JS_ASSERT(0); /* XXX can't happen */ return JSOP_LIMIT; } return trap->op;}static voidDestroyTrap(JSContext *cx, JSTrap *trap){ JS_REMOVE_LINK(&trap->links); *trap->pc = (jsbytecode)trap->op; js_RemoveRoot(cx->runtime, &trap->closure); JS_free(cx, trap);}JS_PUBLIC_API(void)JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler *handlerp, void **closurep){ JSTrap *trap; trap = FindTrap(cx->runtime, script, pc); if (handlerp) *handlerp = trap ? trap->handler : NULL; if (closurep) *closurep = trap ? trap->closure : NULL; if (trap) DestroyTrap(cx, trap);}JS_PUBLIC_API(void)JS_ClearScriptTraps(JSContext *cx, JSScript *script){ JSRuntime *rt; JSTrap *trap, *next; rt = cx->runtime; for (trap = (JSTrap *)rt->trapList.next; trap != (JSTrap *)&rt->trapList; trap = next) { next = (JSTrap *)trap->links.next; if (trap->script == script) DestroyTrap(cx, trap); }}JS_PUBLIC_API(void)JS_ClearAllTraps(JSContext *cx){ JSRuntime *rt; JSTrap *trap, *next; rt = cx->runtime; for (trap = (JSTrap *)rt->trapList.next; trap != (JSTrap *)&rt->trapList; trap = next) { next = (JSTrap *)trap->links.next; DestroyTrap(cx, trap); }}JS_PUBLIC_API(JSTrapStatus)JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval){ JSTrap *trap; JSTrapStatus status; jsint op; trap = FindTrap(cx->runtime, script, pc); if (!trap) { JS_ASSERT(0); /* XXX can't happen */ return JSTRAP_ERROR; } /* * It's important that we not use 'trap->' after calling the callback -- * the callback might remove the trap! */ op = (jsint)trap->op; status = trap->handler(cx, script, pc, rval, trap->closure); if (status == JSTRAP_CONTINUE) { /* By convention, return the true op to the interpreter in rval. */ *rval = INT_TO_JSVAL(op); } return status;}JS_PUBLIC_API(JSBool)JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure){ rt->interruptHandler = handler; rt->interruptHandlerData = closure; return JS_TRUE;}JS_PUBLIC_API(JSBool)JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep){ if (handlerp) *handlerp = (JSTrapHandler)rt->interruptHandler; if (closurep) *closurep = rt->interruptHandlerData; rt->interruptHandler = 0; rt->interruptHandlerData = 0; return JS_TRUE;}/************************************************************************/typedef struct JSWatchPoint { JSCList links; JSObject *object; /* weak link, see js_FinalizeObject */ JSScopeProperty *sprop; JSPropertyOp setter; JSWatchPointHandler handler; void *closure; uintN flags;} JSWatchPoint;#define JSWP_LIVE 0x1 /* live because set and not cleared */#define JSWP_HELD 0x2 /* held while running handler/setter */static JSBoolDropWatchPoint(JSContext *cx, JSWatchPoint *wp, uintN flag){ JSBool ok; JSScopeProperty *sprop; JSObject *pobj; JSProperty *prop; JSPropertyOp setter; ok = JS_TRUE; wp->flags &= ~flag; if (wp->flags != 0) return JS_TRUE; /* * Remove wp from the list, then if there are no other watchpoints for * wp->sprop in any scope, restore wp->sprop->setter from wp. */ JS_REMOVE_LINK(&wp->links); sprop = wp->sprop; /* * If js_ChangeNativePropertyAttrs fails, propagate failure after removing * wp->closure's root and freeing wp. */ setter = js_GetWatchedSetter(cx->runtime, NULL, sprop); if (!setter) { ok = js_LookupProperty(cx, wp->object, sprop->id, &pobj, &prop); /* * If the property wasn't found on wp->object or didn't exist, then * someone else has dealt with this sprop, and we don't need to change * the property attributes. */ if (ok && prop) { if (pobj == wp->object) { JS_ASSERT(OBJ_SCOPE(pobj)->object == pobj); sprop = js_ChangeScopePropertyAttrs(cx, OBJ_SCOPE(pobj), sprop, 0, sprop->attrs, sprop->getter, wp->setter); if (!sprop) ok = JS_FALSE; } OBJ_DROP_PROPERTY(cx, pobj, prop); } } js_RemoveRoot(cx->runtime, &wp->closure); JS_free(cx, wp); return ok;}voidjs_MarkWatchPoints(JSContext *cx){ JSRuntime *rt; JSWatchPoint *wp; rt = cx->runtime; for (wp = (JSWatchPoint *)rt->watchPointList.next; wp != (JSWatchPoint *)&rt->watchPointList; wp = (JSWatchPoint *)wp->links.next) { MARK_SCOPE_PROPERTY(cx, wp->sprop); if (wp->sprop->attrs & JSPROP_SETTER) JS_MarkGCThing(cx, wp->setter, "wp->setter", NULL); }}static JSWatchPoint *FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id){ JSWatchPoint *wp; for (wp = (JSWatchPoint *)rt->watchPointList.next; wp != (JSWatchPoint *)&rt->watchPointList; wp = (JSWatchPoint *)wp->links.next) { if (wp->object == scope->object && wp->sprop->id == id) return wp; } return NULL;}JSScopeProperty *js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id){ JSWatchPoint *wp; wp = FindWatchPoint(rt, scope, id); if (!wp) return NULL; return wp->sprop;}JSPropertyOpjs_GetWatchedSetter(JSRuntime *rt, JSScope *scope, const JSScopeProperty *sprop){ JSWatchPoint *wp; for (wp = (JSWatchPoint *)rt->watchPointList.next; wp != (JSWatchPoint *)&rt->watchPointList; wp = (JSWatchPoint *)wp->links.next) { if ((!scope || wp->object == scope->object) && wp->sprop == sprop) return wp->setter; } return NULL;}JSBool JS_DLL_CALLBACKjs_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ JSRuntime *rt; JSWatchPoint *wp; JSScopeProperty *sprop; jsval propid, userid; JSScope *scope; JSBool ok; rt = cx->runtime; for (wp = (JSWatchPoint *)rt->watchPointList.next; wp != (JSWatchPoint *)&rt->watchPointList; wp = (JSWatchPoint *)wp->links.next) { sprop = wp->sprop; if (wp->object == obj && SPROP_USERID(sprop) == id && !(wp->flags & JSWP_HELD)) { wp->flags |= JSWP_HELD; JS_LOCK_OBJ(cx, obj); propid = ID_TO_VALUE(sprop->id); userid = (sprop->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL(sprop->shortid) : propid; scope = OBJ_SCOPE(obj); JS_UNLOCK_OBJ(cx, obj); /* NB: wp is held, so we can safely dereference it still. */ ok = wp->handler(cx, obj, propid, SPROP_HAS_VALID_SLOT(sprop, scope) ? OBJ_GET_SLOT(cx, obj, sprop->slot) : JSVAL_VOID, vp, wp->closure); if (ok) { /* * Create a pseudo-frame for the setter invocation so that any * stack-walking security code under the setter will correctly * identify the guilty party. So that the watcher appears to * be active to obj_eval and other such code, point frame.pc * at the JSOP_STOP at the end of the script. */ JSObject *closure; JSClass *clasp; JSFunction *fun; JSScript *script; uintN nslots; jsval smallv[5]; jsval *argv; JSStackFrame frame; closure = (JSObject *) wp->closure; clasp = OBJ_GET_CLASS(cx, closure); if (clasp == &js_FunctionClass) { fun = (JSFunction *) JS_GetPrivate(cx, closure); script = FUN_SCRIPT(fun); } else if (clasp == &js_ScriptClass) { fun = NULL; script = (JSScript *) JS_GetPrivate(cx, closure); } else { fun = NULL; script = NULL; } nslots = 2; if (fun) { nslots += fun->nargs; if (FUN_NATIVE(fun)) nslots += fun->u.n.extra; } if (nslots <= JS_ARRAY_LENGTH(smallv)) { argv = smallv; } else { argv = JS_malloc(cx, nslots * sizeof(jsval)); if (!argv) { DropWatchPoint(cx, wp, JSWP_HELD); return JS_FALSE; } } argv[0] = OBJECT_TO_JSVAL(closure); argv[1] = JSVAL_NULL; memset(argv + 2, 0, (nslots - 2) * sizeof(jsval)); memset(&frame, 0, sizeof(frame)); frame.script = script; if (script) { JS_ASSERT(script->length >= JSOP_STOP_LENGTH); frame.pc = script->code + script->length - JSOP_STOP_LENGTH; } frame.fun = fun; frame.argv = argv + 2; frame.down = cx->fp; frame.scopeChain = OBJ_GET_PARENT(cx, closure); cx->fp = &frame; ok = !wp->setter || ((sprop->attrs & JSPROP_SETTER) ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter), 1, vp, vp) : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp)); cx->fp = frame.down; if (argv != smallv) JS_free(cx, argv); } return DropWatchPoint(cx, wp, JSWP_HELD) && ok; } } return JS_TRUE;}JSBool JS_DLL_CALLBACKjs_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -