static JSDObject* _createJSDObject(JSDContext* jsdc, JSContext *cx, JSObject *obj) { JSDObject* jsdobj; JSStackFrame* fp; JSStackFrame* iter = NULL; const char* newURL; jsbytecode* pc; JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc)); jsdobj = (JSDObject*) calloc(1, sizeof(JSDObject)); if (jsdobj) { JS_INIT_CLIST(&jsdobj->links); JS_APPEND_LINK(&jsdobj->links, &jsdc->objectsList); jsdobj->obj = obj; JS_HashTableAdd(jsdc->objectsTable, obj, jsdobj); if (jsdc->flags & JSD_DISABLE_OBJECT_TRACE) return jsdobj; /* walk the stack to find js frame (if any) causing creation */ while (NULL != (fp = JS_FrameIterator(cx, &iter))) { if( !JS_IsNativeFrame(cx, fp) ) { JSScript* script = JS_GetFrameScript(cx, fp); if( !script ) continue; newURL = JS_GetScriptFilename(cx, script); if( newURL ) jsdobj->newURL = jsd_AddAtom(jsdc, newURL); pc = JS_GetFramePC(cx, fp); if( pc ) jsdobj->newLineno = JS_PCToLineNumber(cx, script, pc); break; } } } return jsdobj; }
JSBool jsd_IsStackFrameNative(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe) { JSBool rv; JSD_LOCK_THREADSTATES(jsdc); if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) { rv = JS_IsNativeFrame(jsdthreadstate->context, jsdframe->fp); } else { rv = JS_FALSE; } JSD_UNLOCK_THREADSTATES(jsdc); return rv; }
static JSDStackFrameInfo* _addNewFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSScript* script, jsuword pc, JSStackFrame* fp) { JSDStackFrameInfo* jsdframe; JSDScript* jsdscript = NULL; if (!JS_IsNativeFrame(jsdthreadstate->context, fp)) { JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES && !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))) { return NULL; } if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)) jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME; } jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo)); if( ! jsdframe ) return NULL; jsdframe->jsdthreadstate = jsdthreadstate; jsdframe->jsdscript = jsdscript; jsdframe->pc = pc; jsdframe->fp = fp; JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack); jsdthreadstate->stackDepth++; return jsdframe; }
void jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj, JSStackFrame *fp) { JSDObject* jsdobj; JSScript* script; JSDScript* jsdscript; const char* ctorURL; const char* ctorName; JSD_LOCK_OBJECTS(jsdc); jsdobj = jsd_GetJSDObjectForJSObject(jsdc, obj); if( jsdobj && !jsdobj->ctorURL && !JS_IsNativeFrame(cx, fp) ) { script = JS_GetFrameScript(cx, fp); if( script ) { ctorURL = JS_GetScriptFilename(cx, script); if( ctorURL ) jsdobj->ctorURL = jsd_AddAtom(jsdc, ctorURL); JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, fp); JSD_UNLOCK_SCRIPTS(jsdc); if( jsdscript ) { ctorName = jsd_GetScriptFunctionName(jsdc, jsdscript); if( ctorName ) jsdobj->ctorName = jsd_AddAtom(jsdc, ctorName); } jsdobj->ctorLineno = JS_GetScriptBaseLineNumber(cx, script); } } TRACEOBJ(jsdc, jsdobj, 3); JSD_UNLOCK_OBJECTS(jsdc); }
JSDThreadState* jsd_NewThreadState(JSDContext* jsdc, JSContext *cx ) { JSDThreadState* jsdthreadstate; JSStackFrame * iter = NULL; JSStackFrame * fp; jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState)); if( ! jsdthreadstate ) return NULL; jsdthreadstate->context = cx; jsdthreadstate->thread = JSD_CURRENT_THREAD(); JS_INIT_CLIST(&jsdthreadstate->stack); jsdthreadstate->stackDepth = 0; JS_BeginRequest(jsdthreadstate->context); while( NULL != (fp = JS_FrameIterator(cx, &iter)) ) { JSScript* script = JS_GetFrameScript(cx, fp); jsuword pc = (jsuword) JS_GetFramePC(cx, fp); /* * don't construct a JSDStackFrame for dummy frames (those without a * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES * isn't set. */ if (JS_GetFrameThis(cx, fp) && ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) || !JS_IsNativeFrame(cx, fp))) { JSDStackFrameInfo *frame; frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp ); if ((jsdthreadstate->stackDepth == 0 && !frame) || (jsdthreadstate->stackDepth == 1 && frame && frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript))) { /* * if we failed to create the first frame, or the top frame * is not enabled for debugging, fail the entire thread state. */ JS_INIT_CLIST(&jsdthreadstate->links); JS_EndRequest(jsdthreadstate->context); jsd_DestroyThreadState(jsdc, jsdthreadstate); return NULL; } } } JS_EndRequest(jsdthreadstate->context); if (jsdthreadstate->stackDepth == 0) { free(jsdthreadstate); return NULL; } JSD_LOCK_THREADSTATES(jsdc); JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates); JSD_UNLOCK_THREADSTATES(jsdc); return jsdthreadstate; }
static char* FormatJSFrame(JSContext* cx, JSStackFrame* fp, char* buf, int num, JSBool showArgs, JSBool showLocals, JSBool showThisProps) { if(JS_IsNativeFrame(cx, fp)) return JS_sprintf_append(buf, "%d [native frame]\n", num); JSPropertyDescArray callProps = {0, nsnull}; JSPropertyDescArray thisProps = {0, nsnull}; JSObject* thisObj = nsnull; JSObject* callObj = nsnull; const char* funname = nsnull; const char* filename = nsnull; PRInt32 lineno = 0; JSFunction* fun = nsnull; uint32 namedArgCount = 0; jsval val; const char* name; const char* value; JSBool isString; // get the info for this stack frame JSScript* script = JS_GetFrameScript(cx, fp); jsbytecode* pc = JS_GetFramePC(cx, fp); if(script && pc) { filename = JS_GetScriptFilename(cx, script); lineno = (PRInt32) JS_PCToLineNumber(cx, script, pc); fun = JS_GetFrameFunction(cx, fp); if(fun) funname = JS_GetFunctionName(fun); if(showArgs || showLocals) { callObj = JS_GetFrameCallObject(cx, fp); if(callObj) if(!JS_GetPropertyDescArray(cx, callObj, &callProps)) callProps.array = nsnull; // just to be sure } thisObj = JS_GetFrameThis(cx, fp); if(showThisProps) { if(thisObj) if(!JS_GetPropertyDescArray(cx, thisObj, &thisProps)) thisProps.array = nsnull; // just to be sure } } // print the frame number and function name if(funname) buf = JS_sprintf_append(buf, "%d %s(", num, funname); else if(fun) buf = JS_sprintf_append(buf, "%d anonymous(", num); else buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num); if(!buf) goto out; // print the function arguments if(showArgs && callObj) { for(uint32 i = 0; i < callProps.length; i++) { JSPropertyDesc* desc = &callProps.array[i]; if(desc->flags & JSPD_ARGUMENT) { name = JSVAL2String(cx, desc->id, &isString); if(!isString) name = nsnull; value = JSVAL2String(cx, desc->value, &isString); buf = JS_sprintf_append(buf, "%s%s%s%s%s%s", namedArgCount ? ", " : "", name ? name :"", name ? " = " : "", isString ? "\"" : "", value ? value : "?unknown?", isString ? "\"" : ""); if(!buf) goto out; namedArgCount++; } } // print any unnamed trailing args (found in 'arguments' object) if(JS_GetProperty(cx, callObj, "arguments", &val) && JSVAL_IS_OBJECT(val)) { uint32 argCount; JSObject* argsObj = JSVAL_TO_OBJECT(val); if(JS_GetProperty(cx, argsObj, "length", &val) && JS_ValueToECMAUint32(cx, val, &argCount) && argCount > namedArgCount) { for(uint32 k = namedArgCount; k < argCount; k++) { char number[8]; JS_snprintf(number, 8, "%d", (int) k); if(JS_GetProperty(cx, argsObj, number, &val)) { value = JSVAL2String(cx, val, &isString); buf = JS_sprintf_append(buf, "%s%s%s%s", k ? ", " : "", isString ? "\"" : "", value ? value : "?unknown?", isString ? "\"" : ""); if(!buf) goto out; } } } } } // print filename and line number buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n", fun ? ")" : "", filename ? filename : "<unknown>", lineno); if(!buf) goto out; // print local variables if(showLocals && callProps.array) { for(uint32 i = 0; i < callProps.length; i++) { JSPropertyDesc* desc = &callProps.array[i]; if(desc->flags & JSPD_VARIABLE) { name = JSVAL2String(cx, desc->id, nsnull); value = JSVAL2String(cx, desc->value, &isString); if(name && value) { buf = JS_sprintf_append(buf, TAB "%s = %s%s%s\n", name, isString ? "\"" : "", value, isString ? "\"" : ""); if(!buf) goto out; } } } } // print the value of 'this' if(showLocals && thisObj) { jsval thisJSVal = OBJECT_TO_JSVAL(thisObj); JSString* thisValStr; char* thisVal; if(nsnull != (thisValStr = JS_ValueToString(cx, thisJSVal)) && nsnull != (thisVal = JS_GetStringBytes(thisValStr))) { buf = JS_sprintf_append(buf, TAB "this = %s\n", thisVal); if(!buf) goto out; } } // print the properties of 'this' if(showThisProps && thisProps.array) { for(uint32 i = 0; i < thisProps.length; i++) { JSPropertyDesc* desc = &thisProps.array[i]; if(desc->flags & JSPD_ENUMERATE) { name = JSVAL2String(cx, desc->id, nsnull); value = JSVAL2String(cx, desc->value, &isString); if(name && value) { buf = JS_sprintf_append(buf, TAB "this.%s = %s%s%s\n", name, isString ? "\"" : "", value, isString ? "\"" : ""); if(!buf) goto out; } } } } out: if(callProps.array) JS_PutPropertyDescArray(cx, &callProps); if(thisProps.array) JS_PutPropertyDescArray(cx, &thisProps); return buf; }