📄 jsdbgapi.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** 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; jsrefcount nrefs;} JSWatchPoint;#define HoldWatchPoint(wp) ((wp)->nrefs++)static JSBoolDropWatchPoint(JSContext *cx, JSWatchPoint *wp){ JSScopeProperty *sprop; if (--wp->nrefs != 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_GetWatchedSetter(cx->runtime, NULL, sprop)) { sprop = js_ChangeNativePropertyAttrs(cx, wp->object, sprop, 0, sprop->attrs, sprop->getter, wp->setter); if (!sprop) return JS_FALSE; } js_RemoveRoot(cx->runtime, &wp->closure); JS_free(cx, wp); return JS_TRUE;}voidjs_MarkWatchPoints(JSRuntime *rt){ JSWatchPoint *wp; for (wp = (JSWatchPoint *)rt->watchPointList.next; wp != (JSWatchPoint *)&rt->watchPointList; wp = (JSWatchPoint *)wp->links.next) { MARK_SCOPE_PROPERTY(wp->sprop); }}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 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) { JS_LOCK_OBJ(cx, obj); userid = SPROP_USERID(sprop); scope = OBJ_SCOPE(obj); JS_UNLOCK_OBJ(cx, obj); HoldWatchPoint(wp); ok = wp->handler(cx, obj, userid, SPROP_HAS_VALID_SLOT(sprop, scope) ? OBJ_GET_SLOT(cx, obj, wp->sprop->slot) : JSVAL_VOID, vp, wp->closure); if (ok) { /* * Create pseudo-frame for call to setter so that any * stack-walking security code in the setter will correctly * identify the guilty party. */ JSObject *funobj = (JSObject *) wp->closure; JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, funobj); JSStackFrame frame; memset(&frame, 0, sizeof(frame)); frame.script = fun->script; frame.fun = fun; frame.down = cx->fp; 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; } return DropWatchPoint(cx, wp); } } JS_ASSERT(0); /* XXX can't happen */ return JS_FALSE;}JSBool JS_DLL_CALLBACKjs_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ JSObject *funobj; JSFunction *wrapper; jsval userid; funobj = JSVAL_TO_OBJECT(argv[-2]); wrapper = (JSFunction *) JS_GetPrivate(cx, funobj); userid = ATOM_KEY(wrapper->atom); *rval = argv[0]; return js_watch_set(cx, obj, userid, rval);}JSPropertyOpjs_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter){ JSAtom *atom; JSFunction *wrapper; if (!(attrs & JSPROP_SETTER)) return &js_watch_set; /* & to silence schoolmarmish MSVC */ if (!JSVAL_IS_INT(id)) { atom = (JSAtom *)id; } else { atom = js_AtomizeInt(cx, JSVAL_TO_INT(id), 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -