예제 #1
0
// Try to get the the document corresponding to the given JSStackFrame.
static already_AddRefed<nsIDocument>
GetFrameDocument(JSContext *cx, JSStackFrame *fp)
{
  if (!cx || !fp)
    return nsnull;

  JSObject* scope = JS_GetGlobalForFrame(fp);
  if (!scope)
    return nsnull;

  JSAutoEnterCompartment ac;
  if (!ac.enter(cx, scope))
     return nsnull;

  nsCOMPtr<nsIDOMWindow> window =
    do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, scope));
  if (!window)
    return nsnull;

  // If it's a window, get its document.
  nsCOMPtr<nsIDOMDocument> domDoc;
  window->GetDocument(getter_AddRefs(domDoc));
  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  return doc.forget();
}
예제 #2
0
static char* FormatJSFrame(JSContext* cx, JSStackFrame* fp,
                           char* buf, int num,
                           JSBool showArgs, JSBool showLocals, JSBool showThisProps)
{
    JSPropertyDescArray callProps = {0, nsnull};
    JSPropertyDescArray thisProps = {0, nsnull};
    JSBool gotThisVal = false;
    jsval thisVal;
    JSObject* callObj = nsnull;
    JSString* funname = nsnull;
    JSAutoByteString funbytes;
    const char* filename = nsnull;
    PRInt32 lineno = 0;
    JSFunction* fun = nsnull;
    uint32 namedArgCount = 0;
    jsval val;
    JSBool isString;

    // get the info for this stack frame

    JSScript* script = JS_GetFrameScript(cx, fp);
    jsbytecode* pc = JS_GetFramePC(cx, fp);

    JSAutoRequest ar(cx);
    JSAutoEnterCompartment ac;
    if (!ac.enter(cx, JS_GetGlobalForFrame(fp)))
        return buf;

    if (script && pc) {
        filename = JS_GetScriptFilename(cx, script);
        lineno =  (PRInt32) JS_PCToLineNumber(cx, script, pc);
        fun = JS_GetFrameFunction(cx, fp);
        if (fun)
            funname = JS_GetFunctionId(fun);

        if (showArgs || showLocals) {
            callObj = JS_GetFrameCallObject(cx, fp);
            if (callObj)
                if (!JS_GetPropertyDescArray(cx, callObj, &callProps))
                    callProps.array = nsnull;  // just to be sure
        }

        gotThisVal = JS_GetFrameThis(cx, fp, &thisVal);
        if (!gotThisVal ||
            !showThisProps ||
            JSVAL_IS_PRIMITIVE(thisVal) ||
            !JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(thisVal),
                                     &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, funbytes.encode(cx, 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) {
                JSAutoByteString nameBytes;
                const char* name = JSVAL2String(cx, desc->id, &isString, &nameBytes);
                if (!isString)
                    name = nsnull;
                JSAutoByteString valueBytes;
                const char* value = JSVAL2String(cx, desc->value, &isString, &valueBytes);

                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_t 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)) {
                        JSAutoByteString valueBytes;
                        const char *value = JSVAL2String(cx, val, &isString, &valueBytes);
                        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) {
                JSAutoByteString nameBytes;
                JSAutoByteString valueBytes;
                const char *name = JSVAL2String(cx, desc->id, nsnull, &nameBytes);
                const char *value = JSVAL2String(cx, desc->value, &isString, &valueBytes);

                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) {
        if (gotThisVal) {
            JSString* thisValStr;
            JSAutoByteString thisValBytes;

            if (nsnull != (thisValStr = JS_ValueToString(cx, thisVal)) &&
                thisValBytes.encode(cx, thisValStr)) {
                buf = JS_sprintf_append(buf, TAB "this = %s\n", thisValBytes.ptr());
                if (!buf) goto out;
            }
        } else
            buf = JS_sprintf_append(buf, TAB "<failed to get 'this' value>\n");
    }

    // print the properties of 'this', if it is an object

    if (showThisProps && thisProps.array) {

        for (uint32 i = 0; i < thisProps.length; i++) {
            JSPropertyDesc* desc = &thisProps.array[i];
            if (desc->flags & JSPD_ENUMERATE) {
                JSAutoByteString nameBytes;
                JSAutoByteString valueBytes;
                const char *name = JSVAL2String(cx, desc->id, nsnull, &nameBytes);
                const char *value = JSVAL2String(cx, desc->value, &isString, &valueBytes);
                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;
}