michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_OldDebugAPI_h michael@0: #define js_OldDebugAPI_h michael@0: michael@0: /* michael@0: * JS debugger API. michael@0: */ michael@0: michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: #include "jsapi.h" michael@0: #include "jsbytecode.h" michael@0: michael@0: #include "js/CallArgs.h" michael@0: #include "js/TypeDecls.h" michael@0: michael@0: class JSAtom; michael@0: class JSFreeOp; michael@0: michael@0: namespace js { michael@0: class InterpreterFrame; michael@0: class ScriptFrameIter; michael@0: } michael@0: michael@0: // Raw JSScript* because this needs to be callable from a signal handler. michael@0: extern JS_PUBLIC_API(unsigned) michael@0: JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); michael@0: michael@0: extern JS_PUBLIC_API(const char *) michael@0: JS_GetScriptFilename(JSScript *script); michael@0: michael@0: namespace JS { michael@0: michael@0: class FrameDescription michael@0: { michael@0: public: michael@0: explicit FrameDescription(const js::ScriptFrameIter& iter); michael@0: michael@0: unsigned lineno() { michael@0: if (!linenoComputed) { michael@0: lineno_ = JS_PCToLineNumber(nullptr, script_, pc_); michael@0: linenoComputed = true; michael@0: } michael@0: return lineno_; michael@0: } michael@0: michael@0: const char *filename() const { michael@0: return JS_GetScriptFilename(script_); michael@0: } michael@0: michael@0: JSFlatString *funDisplayName() const { michael@0: return funDisplayName_ ? JS_ASSERT_STRING_IS_FLAT(funDisplayName_) : nullptr; michael@0: } michael@0: michael@0: // Both these locations should be traced during GC but otherwise not used; michael@0: // they are implementation details. michael@0: Heap &markedLocation1() { michael@0: return script_; michael@0: } michael@0: Heap &markedLocation2() { michael@0: return funDisplayName_; michael@0: } michael@0: michael@0: private: michael@0: Heap script_; michael@0: Heap funDisplayName_; michael@0: jsbytecode *pc_; michael@0: unsigned lineno_; michael@0: bool linenoComputed; michael@0: }; michael@0: michael@0: struct StackDescription michael@0: { michael@0: unsigned nframes; michael@0: FrameDescription *frames; michael@0: }; michael@0: michael@0: extern JS_PUBLIC_API(StackDescription *) michael@0: DescribeStack(JSContext *cx, unsigned maxFrames); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: FreeStackDescription(JSContext *cx, StackDescription *desc); michael@0: michael@0: extern JS_PUBLIC_API(char *) michael@0: FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool showThisProps); michael@0: michael@0: } // namespace JS michael@0: michael@0: # ifdef JS_DEBUG michael@0: JS_FRIEND_API(void) js_DumpValue(const JS::Value &val); michael@0: JS_FRIEND_API(void) js_DumpId(jsid id); michael@0: JS_FRIEND_API(void) js_DumpInterpreterFrame(JSContext *cx, js::InterpreterFrame *start = nullptr); michael@0: # endif michael@0: michael@0: JS_FRIEND_API(void) michael@0: js_DumpBacktrace(JSContext *cx); michael@0: michael@0: typedef enum JSTrapStatus { michael@0: JSTRAP_ERROR, michael@0: JSTRAP_CONTINUE, michael@0: JSTRAP_RETURN, michael@0: JSTRAP_THROW, michael@0: JSTRAP_LIMIT michael@0: } JSTrapStatus; michael@0: michael@0: typedef JSTrapStatus michael@0: (* JSTrapHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval, michael@0: JS::Value closure); michael@0: michael@0: typedef JSTrapStatus michael@0: (* JSInterruptHook)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval, michael@0: void *closure); michael@0: michael@0: typedef JSTrapStatus michael@0: (* JSDebuggerHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval, michael@0: void *closure); michael@0: michael@0: typedef JSTrapStatus michael@0: (* JSThrowHook)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval, michael@0: void *closure); michael@0: michael@0: typedef bool michael@0: (* JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsid id, JS::Value old, michael@0: JS::Value *newp, void *closure); michael@0: michael@0: /* called just after script creation */ michael@0: typedef void michael@0: (* JSNewScriptHook)(JSContext *cx, michael@0: const char *filename, /* URL of script */ michael@0: unsigned lineno, /* first line */ michael@0: JSScript *script, michael@0: JSFunction *fun, michael@0: void *callerdata); michael@0: michael@0: /* called just before script destruction */ michael@0: typedef void michael@0: (* JSDestroyScriptHook)(JSFreeOp *fop, michael@0: JSScript *script, michael@0: void *callerdata); michael@0: michael@0: typedef void michael@0: (* JSSourceHandler)(const char *filename, unsigned lineno, const jschar *str, michael@0: size_t length, void **listenerTSData, void *closure); michael@0: michael@0: michael@0: michael@0: extern JS_PUBLIC_API(JSCompartment *) michael@0: JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_DecompileScript(JSContext *cx, JS::HandleScript script, const char *name, unsigned indent); michael@0: michael@0: /* michael@0: * Currently, we only support runtime-wide debugging. In the future, we should michael@0: * be able to support compartment-wide debugging. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetRuntimeDebugMode(JSRuntime *rt, bool debug); michael@0: michael@0: /* michael@0: * Debug mode is a compartment-wide mode that enables a debugger to attach michael@0: * to and interact with running methodjit-ed frames. In particular, it causes michael@0: * every function to be compiled as if an eval was present (so eval-in-frame) michael@0: * can work, and it ensures that functions can be re-JITed for other debug michael@0: * features. In general, it is not safe to interact with frames that were live michael@0: * before debug mode was enabled. For this reason, it is also not safe to michael@0: * enable debug mode while frames are live. michael@0: */ michael@0: michael@0: /* Get current state of debugging mode. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetDebugMode(JSContext *cx); michael@0: michael@0: /* michael@0: * Turn on/off debugging mode for all compartments. This returns false if any code michael@0: * from any of the runtime's compartments is running or on the stack. michael@0: */ michael@0: JS_FRIEND_API(bool) michael@0: JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug); michael@0: michael@0: /* michael@0: * Turn on/off debugging mode for a single compartment. This should only be michael@0: * used when no code from this compartment is running or on the stack in any michael@0: * thread. michael@0: */ michael@0: JS_FRIEND_API(bool) michael@0: JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, bool debug); michael@0: michael@0: /* michael@0: * Turn on/off debugging mode for a context's compartment. michael@0: */ michael@0: JS_FRIEND_API(bool) michael@0: JS_SetDebugMode(JSContext *cx, bool debug); michael@0: michael@0: /* Turn on single step mode. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetSingleStepMode(JSContext *cx, JS::HandleScript script, bool singleStep); michael@0: michael@0: /* The closure argument will be marked. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetTrap(JSContext *cx, JS::HandleScript script, jsbytecode *pc, michael@0: JSTrapHandler handler, JS::HandleValue closure); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, michael@0: JSTrapHandler *handlerp, JS::Value *closurep); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ClearScriptTraps(JSRuntime *rt, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ClearAllTrapsForCompartment(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetInterrupt(JSRuntime *rt, JSInterruptHook handler, void *closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *handlerp, void **closurep); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetWatchPoint(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JSWatchPointHandler handler, JS::HandleObject closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id, michael@0: JSWatchPointHandler *handlerp, JSObject **closurep); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(jsbytecode *) michael@0: JS_LineNumberToPC(JSContext *cx, JSScript *script, unsigned lineno); michael@0: michael@0: extern JS_PUBLIC_API(jsbytecode *) michael@0: JS_EndPC(JSContext *cx, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetLinePCs(JSContext *cx, JSScript *script, michael@0: unsigned startLine, unsigned maxLines, michael@0: unsigned* count, unsigned** lines, jsbytecode*** pcs); michael@0: michael@0: extern JS_PUBLIC_API(unsigned) michael@0: JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun); michael@0: michael@0: /* michael@0: * N.B. The mark is in the context temp pool and thus the caller must take care michael@0: * to call JS_ReleaseFunctionLocalNameArray in a LIFO manner (wrt to any other michael@0: * call that may use the temp pool. michael@0: */ michael@0: extern JS_PUBLIC_API(uintptr_t *) michael@0: JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp); michael@0: michael@0: extern JS_PUBLIC_API(JSAtom *) michael@0: JS_LocalNameToAtom(uintptr_t w); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_AtomKey(JSAtom *atom); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: JS_GetFunctionScript(JSContext *cx, JS::HandleFunction fun); michael@0: michael@0: extern JS_PUBLIC_API(JSNative) michael@0: JS_GetFunctionNative(JSContext *cx, JSFunction *fun); michael@0: michael@0: extern JS_PUBLIC_API(JSPrincipals *) michael@0: JS_GetScriptPrincipals(JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(JSPrincipals *) michael@0: JS_GetScriptOriginPrincipals(JSScript *script); michael@0: michael@0: JS_PUBLIC_API(JSFunction *) michael@0: JS_GetScriptFunction(JSContext *cx, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * This is almost JS_GetClass(obj)->name except that certain debug-only michael@0: * proxies are made transparent. In particular, this function turns the class michael@0: * of any scope (returned via JS_GetFrameScopeChain or JS_GetFrameCalleeObject) michael@0: * from "Proxy" to "Call", "Block", "With" etc. michael@0: */ michael@0: extern JS_PUBLIC_API(const char *) michael@0: JS_GetDebugClassName(JSObject *obj); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetScriptSourceMap(JSContext *cx, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(unsigned) michael@0: JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(unsigned) michael@0: JS_GetScriptLineExtent(JSContext *cx, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(JSVersion) michael@0: JS_GetScriptVersion(JSContext *cx, JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetScriptIsSelfHosted(JSScript *script); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Hook setters for script creation and destruction. These macros provide michael@0: * binary compatibility and newer, shorter synonyms. michael@0: */ michael@0: #define JS_SetNewScriptHook JS_SetNewScriptHookProc michael@0: #define JS_SetDestroyScriptHook JS_SetDestroyScriptHookProc michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, michael@0: void *callerdata); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: typedef struct JSPropertyDesc { michael@0: JS::Value id; /* primary id, atomized string, or int */ michael@0: JS::Value value; /* property value */ michael@0: uint8_t flags; /* flags, see below */ michael@0: uint8_t spare; /* unused */ michael@0: JS::Value alias; /* alias id if JSPD_ALIAS flag */ michael@0: } JSPropertyDesc; michael@0: michael@0: #define JSPD_ENUMERATE 0x01 /* visible to for/in loop */ michael@0: #define JSPD_READONLY 0x02 /* assignment is error */ michael@0: #define JSPD_PERMANENT 0x04 /* property cannot be deleted */ michael@0: #define JSPD_ALIAS 0x08 /* property has an alias id */ michael@0: #define JSPD_EXCEPTION 0x40 /* exception occurred fetching the property, */ michael@0: /* value is exception */ michael@0: #define JSPD_ERROR 0x80 /* native getter returned false without */ michael@0: /* throwing an exception */ michael@0: michael@0: typedef struct JSPropertyDescArray { michael@0: uint32_t length; /* number of elements in array */ michael@0: JSPropertyDesc *array; /* alloc'd by Get, freed by Put */ michael@0: } JSPropertyDescArray; michael@0: michael@0: typedef struct JSScopeProperty JSScopeProperty; michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetPropertyDescArray(JSContext *cx, JS::HandleObject obj, JSPropertyDescArray *pda); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * JSAbstractFramePtr is the public version of AbstractFramePtr, a pointer to a michael@0: * StackFrame or baseline JIT frame. michael@0: */ michael@0: class JS_PUBLIC_API(JSAbstractFramePtr) michael@0: { michael@0: uintptr_t ptr_; michael@0: jsbytecode *pc_; michael@0: michael@0: protected: michael@0: JSAbstractFramePtr() michael@0: : ptr_(0), pc_(nullptr) michael@0: { } michael@0: michael@0: public: michael@0: JSAbstractFramePtr(void *raw, jsbytecode *pc); michael@0: michael@0: uintptr_t raw() const { return ptr_; } michael@0: jsbytecode *pc() const { return pc_; } michael@0: michael@0: operator bool() const { return !!ptr_; } michael@0: michael@0: JSObject *scopeChain(JSContext *cx); michael@0: JSObject *callObject(JSContext *cx); michael@0: michael@0: JSFunction *maybeFun(); michael@0: JSScript *script(); michael@0: michael@0: bool getThisValue(JSContext *cx, JS::MutableHandleValue thisv); michael@0: michael@0: bool isDebuggerFrame(); michael@0: michael@0: bool evaluateInStackFrame(JSContext *cx, michael@0: const char *bytes, unsigned length, michael@0: const char *filename, unsigned lineno, michael@0: JS::MutableHandleValue rval); michael@0: michael@0: bool evaluateUCInStackFrame(JSContext *cx, michael@0: const jschar *chars, unsigned length, michael@0: const char *filename, unsigned lineno, michael@0: JS::MutableHandleValue rval); michael@0: }; michael@0: michael@0: class JS_PUBLIC_API(JSNullFramePtr) : public JSAbstractFramePtr michael@0: { michael@0: public: michael@0: JSNullFramePtr() michael@0: : JSAbstractFramePtr() michael@0: {} michael@0: }; michael@0: michael@0: /* michael@0: * This class does not work when IonMonkey is active. It's only used by jsd, michael@0: * which can only be used when IonMonkey is disabled. michael@0: * michael@0: * To find the calling script and line number, use JS_DescribeSciptedCaller. michael@0: * To summarize the call stack, use JS::DescribeStack. michael@0: */ michael@0: class JS_PUBLIC_API(JSBrokenFrameIterator) michael@0: { michael@0: void *data_; michael@0: michael@0: public: michael@0: JSBrokenFrameIterator(JSContext *cx); michael@0: ~JSBrokenFrameIterator(); michael@0: michael@0: bool done() const; michael@0: JSBrokenFrameIterator& operator++(); michael@0: michael@0: JSAbstractFramePtr abstractFramePtr() const; michael@0: jsbytecode *pc() const; michael@0: michael@0: bool isConstructing() const; michael@0: }; michael@0: michael@0: /* michael@0: * This hook captures high level script execution and function calls (JS or michael@0: * native). It is used by JS_SetExecuteHook to hook top level scripts and by michael@0: * JS_SetCallHook to hook function calls. It will get called twice per script michael@0: * or function call: just before execution begins and just after it finishes. michael@0: * In both cases the 'current' frame is that of the executing code. michael@0: * michael@0: * The 'before' param is true for the hook invocation before the execution michael@0: * and false for the invocation after the code has run. michael@0: * michael@0: * The 'ok' param is significant only on the post execution invocation to michael@0: * signify whether or not the code completed 'normally'. michael@0: * michael@0: * The 'closure' param is as passed to JS_SetExecuteHook or JS_SetCallHook michael@0: * for the 'before'invocation, but is whatever value is returned from that michael@0: * invocation for the 'after' invocation. Thus, the hook implementor *could* michael@0: * allocate a structure in the 'before' invocation and return a pointer to that michael@0: * structure. The pointer would then be handed to the hook for the 'after' michael@0: * invocation. Alternately, the 'before' could just return the same value as michael@0: * in 'closure' to cause the 'after' invocation to be called with the same michael@0: * 'closure' value as the 'before'. michael@0: * michael@0: * Returning nullptr in the 'before' hook will cause the 'after' hook *not* to michael@0: * be called. michael@0: */ michael@0: typedef void * michael@0: (* JSInterpreterHook)(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, michael@0: bool before, bool *ok, void *closure); michael@0: michael@0: typedef bool michael@0: (* JSDebugErrorHook)(JSContext *cx, const char *message, JSErrorReport *report, michael@0: void *closure); michael@0: michael@0: typedef struct JSDebugHooks { michael@0: JSInterruptHook interruptHook; michael@0: void *interruptHookData; michael@0: JSNewScriptHook newScriptHook; michael@0: void *newScriptHookData; michael@0: JSDestroyScriptHook destroyScriptHook; michael@0: void *destroyScriptHookData; michael@0: JSDebuggerHandler debuggerHandler; michael@0: void *debuggerHandlerData; michael@0: JSSourceHandler sourceHandler; michael@0: void *sourceHandlerData; michael@0: JSInterpreterHook executeHook; michael@0: void *executeHookData; michael@0: JSInterpreterHook callHook; michael@0: void *callHookData; michael@0: JSThrowHook throwHook; michael@0: void *throwHookData; michael@0: JSDebugErrorHook debugErrorHook; michael@0: void *debugErrorHookData; michael@0: } JSDebugHooks; michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler hook, void *closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(const JSDebugHooks *) michael@0: JS_GetGlobalDebugHooks(JSRuntime *rt); michael@0: michael@0: /** michael@0: * Add various profiling-related functions as properties of the given object. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj); michael@0: michael@0: /* Defined in vm/Debugger.cpp. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineDebuggerObject(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DumpPCCounts(JSContext *cx, JS::HandleScript script); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DumpCompartmentPCCounts(JSContext *cx); michael@0: michael@0: namespace js { michael@0: extern JS_FRIEND_API(bool) michael@0: CanCallContextDebugHandler(JSContext *cx); michael@0: } michael@0: michael@0: /* Call the context debug handler on the topmost scripted frame. */ michael@0: extern JS_FRIEND_API(bool) michael@0: js_CallContextDebugHandler(JSContext *cx); michael@0: michael@0: #endif /* js_OldDebugAPI_h */