Exemple #1
0
static bool
ProcessLine(AutoJSAPI& jsapi, const char* buffer, int startline)
{
    JSContext* cx = jsapi.cx();
    JS::RootedScript script(cx);
    JS::RootedValue result(cx);
    JS::CompileOptions options(cx);
    options.setFileAndLine("typein", startline)
           .setIsRunOnce(true);
    if (!JS_CompileScript(cx, buffer, strlen(buffer), options, &script))
        return false;
    if (compileOnly)
        return true;
    if (!JS_ExecuteScript(cx, script, &result))
        return false;

    if (result.isUndefined())
        return true;
    RootedString str(cx);
    if (!(str = ToString(cx, result)))
        return false;
    JSAutoByteString bytes;
    if (!bytes.encodeLatin1(cx, str))
        return false;

    fprintf(gOutFile, "%s\n", bytes.ptr());
    return true;
}
// static
void
XPCThrower::Verbosify(XPCCallContext& ccx,
                      char** psz, PRBool own)
{
    char* sz = nsnull;

    if(ccx.HasInterfaceAndMember())
    {
        XPCNativeInterface* iface = ccx.GetInterface();
        jsid id = ccx.GetMember()->GetName();
        JSAutoByteString bytes;
        const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encode(ccx, JSID_TO_STRING(id));
        if(!name)
        {
            name = "";
        }
        sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name);
    }

    if(sz)
    {
        if(own)
            JS_smprintf_free(*psz);
        *psz = sz;
    }
}
static void
ThrowBadArg(JSContext *cx, nsresult rv, const char *ifaceName,
            jsid memberId, const char *memberName, unsigned paramnum)
{
    /* Only one memberId or memberName should be given. */
    MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName);

    // From XPCThrower::ThrowBadParam.
    char* sz;
    const char* format;

    if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
        format = "";

    JSAutoByteString memberNameBytes;
    if (!memberName) {
        memberName = JSID_IS_STRING(memberId)
                     ? memberNameBytes.encodeLatin1(cx, JSID_TO_STRING(memberId))
                     : "unknown";
    }
    sz = JS_smprintf("%s arg %u [%s.%s]",
                     format, (unsigned int) paramnum, ifaceName, memberName);

    dom::Throw(cx, rv, sz);

    if (sz)
        JS_smprintf_free(sz);
}
Exemple #4
0
/* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
void
js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg)
{
    const char* usageStr = "usage";
    PropertyName* usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName();
    RootedId id(cx, NameToId(usageAtom));
    DebugOnly<Shape*> shape = static_cast<Shape*>(callee->as<JSFunction>().lookup(cx, id));
    MOZ_ASSERT(!shape->configurable());
    MOZ_ASSERT(!shape->writable());
    MOZ_ASSERT(shape->hasDefaultGetter());

    RootedValue usage(cx);
    if (!JS_GetProperty(cx, callee, "usage", &usage))
        return;

    if (!usage.isString()) {
        JS_ReportErrorASCII(cx, "%s", msg);
    } else {
        RootedString usageStr(cx, usage.toString());
        JSAutoByteString str;
        if (!str.encodeUtf8(cx, usageStr))
            return;
        JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr());
    }
}
static JSBool
DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp)
{
    const char *fileName = NULL;
    JSAutoByteString fileNameBytes;
    if (argc > 0) {
        Value v = JS_ARGV(cx, vp)[0];
        if (v.isString()) {
            JSString *str = v.toString();
            if (!fileNameBytes.encodeLatin1(cx, str))
                return false;
            fileName = fileNameBytes.ptr();
        }
    }

    FILE *dumpFile;
    if (!fileName) {
        dumpFile = stdout;
    } else {
        dumpFile = fopen(fileName, "w");
        if (!dumpFile) {
            JS_ReportError(cx, "can't open %s", fileName);
            return false;
        }
    }

    js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile);

    fclose(dumpFile);

    JS_SET_RVAL(cx, vp, JSVAL_VOID);
    return true;
}
static inline void
ReportInvalidTrapResult(JSContext* cx, JSObject* proxy, JSAtom* atom)
{
    RootedValue v(cx, ObjectOrNullValue(proxy));
    JSAutoByteString bytes;
    if (!AtomToPrintableString(cx, atom, &bytes))
        return;
    ReportValueError2(cx, JSMSG_INVALID_TRAP_RESULT, JSDVG_IGNORE_STACK, v,
                      nullptr, bytes.ptr());
}
static bool
DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);

    DumpHeapNurseryBehaviour nurseryBehaviour = js::IgnoreNurseryObjects;
    FILE *dumpFile = nullptr;

    unsigned i = 0;
    if (argc > i) {
        Value v = args[i];
        if (v.isString()) {
            JSString *str = v.toString();
            bool same = false;
            if (!JS_StringEqualsAscii(cx, str, "collectNurseryBeforeDump", &same))
                return false;
            if (same) {
                nurseryBehaviour = js::CollectNurseryBeforeDump;
                ++i;
            }
        }
    }

    if (argc > i) {
        Value v = args[i];
        if (v.isString()) {
            if (!fuzzingSafe) {
                JSString *str = v.toString();
                JSAutoByteString fileNameBytes;
                if (!fileNameBytes.encodeLatin1(cx, str))
                    return false;
                const char *fileName = fileNameBytes.ptr();
                dumpFile = fopen(fileName, "w");
                if (!dumpFile) {
                    JS_ReportError(cx, "can't open %s", fileName);
                    return false;
                }
            }
            ++i;
        }
    }

    if (i != argc) {
        JS_ReportError(cx, "bad arguments passed to dumpHeapComplete");
        return false;
    }

    js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile ? dumpFile : stdout, nurseryBehaviour);

    if (dumpFile)
        fclose(dumpFile);

    JS_SET_RVAL(cx, vp, JSVAL_VOID);
    return true;
}
bool
ModuleBuilder::appendLocalExportEntry(HandleExportEntryObject exp)
{
    if (!module_->initialEnvironment().lookup(cx_, AtomToId(exp->localName()))) {
        JSAutoByteString str;
        str.encodeLatin1(cx_, exp->localName());
        JS_ReportErrorNumber(cx_, GetErrorMessage, nullptr, JSMSG_MISSING_EXPORT, str.ptr());
        return false;
    }

    return localExportEntries_.append(exp);
}
static bool
ThrowCallFailed(JSContext *cx, nsresult rv,
                const char *ifaceName, HandleId memberId, const char *memberName)
{
    /* Only one of memberId or memberName should be given. */
    MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName);

    // From XPCThrower::ThrowBadResult.
    char* sz;
    const char* format;
    const char* name;

    /*
     *  If there is a pending exception when the native call returns and
     *  it has the same error result as returned by the native call, then
     *  the native call may be passing through an error from a previous JS
     *  call. So we'll just throw that exception into our JS.
     */
    if (XPCThrower::CheckForPendingException(rv, cx))
        return false;

    // else...

    if (!nsXPCException::NameAndFormatForNSResult(NS_ERROR_XPC_NATIVE_RETURNED_FAILURE, nullptr, &format) ||
        !format) {
        format = "";
    }

    JSAutoByteString memberNameBytes;
    if (!memberName) {
        memberName = JSID_IS_STRING(memberId)
                     ? memberNameBytes.encodeLatin1(cx, JSID_TO_STRING(memberId))
                     : "unknown";
    }
    if (nsXPCException::NameAndFormatForNSResult(rv, &name, nullptr)
        && name) {
        sz = JS_smprintf("%s 0x%x (%s) [%s.%s]",
                         format, rv, name, ifaceName, memberName);
    } else {
        sz = JS_smprintf("%s 0x%x [%s.%s]",
                         format, rv, ifaceName, memberName);
    }

    XPCThrower::BuildAndThrowException(cx, rv, sz);

    if (sz)
        JS_smprintf_free(sz);

    return false;
}
static bool
ThrowCallFailed(JSContext *cx, nsresult rv,
                const char *ifaceName, HandleId memberId, const char *memberName)
{
    /* Only one of memberId or memberName should be given. */
    MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName);

    // From XPCThrower::ThrowBadResult.
    char* sz;
    const char* format;
    const char* name;

    // If the cx already has a pending exception, just throw that.
    //
    // We used to check here to make sure the exception matched rv (whatever
    // that means). But this meant that we'd be calling into JSAPI below with
    // a pending exception, which isn't really kosher. The first exception thrown
    // should generally take precedence anyway.
    if (JS_IsExceptionPending(cx))
        return false;

    // else...

    if (!nsXPCException::NameAndFormatForNSResult(NS_ERROR_XPC_NATIVE_RETURNED_FAILURE, nullptr, &format) ||
        !format) {
        format = "";
    }

    JSAutoByteString memberNameBytes;
    if (!memberName) {
        memberName = JSID_IS_STRING(memberId)
                     ? memberNameBytes.encodeLatin1(cx, JSID_TO_STRING(memberId))
                     : "unknown";
    }
    if (nsXPCException::NameAndFormatForNSResult(rv, &name, nullptr)
        && name) {
        sz = JS_smprintf("%s 0x%x (%s) [%s.%s]",
                         format, rv, name, ifaceName, memberName);
    } else {
        sz = JS_smprintf("%s 0x%x [%s.%s]",
                         format, rv, ifaceName, memberName);
    }

    dom::Throw(cx, rv, sz);

    if (sz)
        JS_smprintf_free(sz);

    return false;
}
Exemple #11
0
static JSBool
perlsub_construct(
    JSContext *cx,
    DEFJSFSARGS_
) {
    dTHX;
    DECJSFSARGS;
    JSObject *func = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv));
    SV *callee = (SV *)JS_GetPrivate(cx, func);
    SV *caller = NULL;
#if JS_VERSION < 185
    JSObject *This = JSVAL_TO_OBJECT(argv[-1]);
#else
    JSObject *This = JS_NewObjectForConstructor(cx, vp);
#endif
    JSObject *proto = JS_GetPrototype(cx, This);

    PJS_DEBUG1("Want construct, This is a %s", PJS_GET_CLASS(cx, This)->name);
    if(PJS_GET_CLASS(cx, proto) == &perlpackage_class ||
       ( JS_LookupProperty(cx, func, "prototype", &argv[-1])
         && JSVAL_IS_OBJECT(argv[-1]) && !JSVAL_IS_NULL(argv[-1])
         && (proto = JS_GetPrototype(cx, JSVAL_TO_OBJECT(argv[-1]))) 
         && strEQ(PJS_GET_CLASS(cx, proto)->name, PJS_PACKAGE_CLASS_NAME))
    ) {
	SV *rsv = NULL;
	char *pkgname = PJS_GetPackageName(aTHX_ cx, proto);
#if JS_VERSION >= 185
	JSAutoByteString bytes;
	bytes.initBytes(pkgname);
#endif
	caller = newSVpv(pkgname, 0);

	argv[-1] = OBJECT_TO_JSVAL(This);
	if(!PJS_Call_sv_with_jsvals_rsv(aTHX_ cx, obj, callee, caller,
	                                argc, argv, &rsv, G_SCALAR))
	    return JS_FALSE;

	if(SvROK(rsv) && sv_derived_from(rsv, pkgname)) {
	    JSObject *newobj = PJS_NewPerlObject(aTHX_ cx, JS_GetParent(cx, func), rsv);
	    *rval = OBJECT_TO_JSVAL(newobj);
	    return JS_TRUE;
	}
	JS_ReportError(cx, "%s's constructor don't return an object",
	               SvPV_nolen(caller));
    }
    else JS_ReportError(cx, "Can't use as a constructor"); // Yet! ;-)

    return JS_FALSE;
}
Exemple #12
0
JSBool
xpc_DumpEvalInJSStackFrame(JSContext* cx, JSUint32 frameno, const char* text)
{
    JSStackFrame* fp;
    JSStackFrame* iter = nsnull;
    JSUint32 num = 0;

    if(!cx || !text)
    {
        puts("invalid params passed to xpc_DumpEvalInJSStackFrame!");
        return JS_FALSE;
    }

    printf("js[%d]> %s\n", frameno, text);

    while(nsnull != (fp = JS_FrameIterator(cx, &iter)))
    {
        if(num == frameno)
            break;
        num++;
    }

    if(!fp)
    {
        puts("invalid frame number!");
        return JS_FALSE;
    }

    JSAutoRequest ar(cx);

    JSExceptionState* exceptionState = JS_SaveExceptionState(cx);
    JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter);

    jsval rval;
    JSString* str;
    JSAutoByteString bytes;
    if(JS_EvaluateInStackFrame(cx, fp, text, strlen(text), "eval", 1, &rval) &&
       nsnull != (str = JS_ValueToString(cx, rval)) &&
       bytes.encode(cx, str))
    {
        printf("%s\n", bytes.ptr());
    }
    else
        puts("eval failed!");
    JS_SetErrorReporter(cx, older);
    JS_RestoreExceptionState(cx, exceptionState);
    return JS_TRUE;
}
JSBool
xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text)
{
    if (!cx || !text) {
        DebugDump("%s", "invalid params passed to xpc_DumpEvalInJSStackFrame!\n");
        return false;
    }

    DebugDump("js[%d]> %s\n", frameno, text);

    uint32_t num = 0;

    JSAbstractFramePtr frame = JSNullFramePtr();

    JSBrokenFrameIterator iter(cx);
    while (!iter.done()) {
        if (num == frameno) {
            frame = iter.abstractFramePtr();
            break;
        }
        ++iter;
        num++;
    }

    if (!frame) {
        DebugDump("%s", "invalid frame number!\n");
        return false;
    }

    JSAutoRequest ar(cx);

    JSExceptionState* exceptionState = JS_SaveExceptionState(cx);
    JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter);

    jsval rval;
    JSString* str;
    JSAutoByteString bytes;
    if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) &&
        nullptr != (str = JS_ValueToString(cx, rval)) &&
        bytes.encode(cx, str)) {
        DebugDump("%s\n", bytes.ptr());
    } else
        DebugDump("%s", "eval failed!\n");
    JS_SetErrorReporter(cx, older);
    JS_RestoreExceptionState(cx, exceptionState);
    return true;
}
Exemple #14
0
/* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
void
js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg)
{
    RootedValue usage(cx);
    if (!JS_GetProperty(cx, callee, "usage", &usage))
        return;

    if (!usage.isString()) {
        JS_ReportErrorASCII(cx, "%s", msg);
    } else {
        RootedString usageStr(cx, usage.toString());
        JSAutoByteString str;
        if (!str.encodeUtf8(cx, usageStr))
            return;
        JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr());
    }
}
// static
void
XPCThrower::Verbosify(XPCCallContext& ccx,
                      char** psz, PRBool own)
{
    char* sz = nsnull;

    if(ccx.HasInterfaceAndMember())
    {
        XPCNativeInterface* iface = ccx.GetInterface();
        jsid id = JSID_VOID;
#ifdef XPC_IDISPATCH_SUPPORT
        NS_ASSERTION(ccx.GetIDispatchMember() == nsnull || 
                        ccx.GetMember() == nsnull,
                     "Both IDispatch member and regular XPCOM member "
                     "were set in XPCCallContext");
        if(ccx.GetIDispatchMember())
        {
            XPCDispInterface::Member * member = 
                reinterpret_cast<XPCDispInterface::Member*>(ccx.GetIDispatchMember());
            if(member && JSID_IS_STRING(member->GetName()))
            {
                id = member->GetName();
            }
        }
        else
#endif
        {
            id = ccx.GetMember()->GetName();
        }
        JSAutoByteString bytes;
        const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encode(ccx, JSID_TO_STRING(id));
        if(!name)
        {
            name = "";
        }
        sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name);
    }

    if(sz)
    {
        if(own)
            JS_smprintf_free(*psz);
        *psz = sz;
    }
}
Exemple #16
0
JSErrorReport*
js::ErrorObject::getOrCreateErrorReport(JSContext* cx)
{
    if (JSErrorReport* r = getErrorReport())
        return r;

    // We build an error report on the stack and then use CopyErrorReport to do
    // the nitty-gritty malloc stuff.
    JSErrorReport report;

    // Type.
    JSExnType type_ = type();
    report.exnType = type_;

    // Filename.
    JSAutoByteString filenameStr;
    if (!filenameStr.encodeLatin1(cx, fileName(cx)))
        return nullptr;
    report.filename = filenameStr.ptr();

    // Coordinates.
    report.lineno = lineNumber();
    report.column = columnNumber();

    // Message. Note that |new Error()| will result in an undefined |message|
    // slot, so we need to explicitly substitute the empty string in that case.
    RootedString message(cx, getMessage());
    if (!message)
        message = cx->runtime()->emptyString;
    if (!message->ensureFlat(cx))
        return nullptr;

    UniquePtr<char[], JS::FreePolicy> utf8 = StringToNewUTF8CharsZ(cx, *message);
    if (!utf8)
        return nullptr;
    report.initOwnedMessage(utf8.release());

    // Cache and return.
    JSErrorReport* copy = CopyErrorReport(cx, &report);
    if (!copy)
        return nullptr;
    setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(copy));
    return copy;
}
Exemple #17
0
// {{{ Conversions
bool JSGlobal::JS_btoa(JSContext *cx, JS::CallArgs &args)
{
    if (args[0].isString()) {

        JSAutoByteString cdata;
        JS::RootedString str(cx, args[0].toString());
        cdata.encodeUtf8(cx, str);

        char *ret = Utils::B64Encode(
            reinterpret_cast<unsigned char *>(cdata.ptr()), cdata.length());

        args.rval().setString(JS_NewStringCopyZ(cx, ret));

        free(ret);

    } else {
        args.rval().setNull();
        JS_ReportWarning(cx, "btoa() non-string given");
    }

    return true;
}
Exemple #18
0
static bool
DefaultCalendar(JSContext* cx, const JSAutoByteString& locale, MutableHandleValue rval)
{
    UErrorCode status = U_ZERO_ERROR;
    UCalendar* cal = ucal_open(nullptr, 0, locale.ptr(), UCAL_DEFAULT, &status);

    // This correctly handles nullptr |cal| when opening failed.
    ScopedICUObject<UCalendar, ucal_close> closeCalendar(cal);

    const char* calendar = ucal_getType(cal, &status);
    if (U_FAILURE(status)) {
        intl::ReportInternalError(cx);
        return false;
    }

    // ICU returns old-style keyword values; map them to BCP 47 equivalents
    JSString* str = JS_NewStringCopyZ(cx, uloc_toUnicodeLocaleType("ca", calendar));
    if (!str)
        return false;

    rval.setString(str);
    return true;
}
//
// Native method Install
//
static JSBool
InstallTriggerGlobalInstall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
  nsIDOMInstallTriggerGlobal *nativeThis = getTriggerNative(cx, obj);
  if (!nativeThis)
    return JS_FALSE;

  *rval = JSVAL_FALSE;

  // make sure XPInstall is enabled, return false if not
  nsIScriptGlobalObject *globalObject = nsnull;
  nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx);
  if (scriptContext)
    globalObject = scriptContext->GetGlobalObject();

  if (!globalObject)
      return JS_TRUE;

  nsCOMPtr<nsIScriptSecurityManager> secman(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
  if (!secman)
  {
    JS_ReportError(cx, "Could not the script security manager service.");
    return JS_FALSE;
  }
  // get the principal.  if it doesn't exist, die.
  nsCOMPtr<nsIPrincipal> principal;
  secman->GetSubjectPrincipal(getter_AddRefs(principal));
  if (!principal)
  {
    JS_ReportError(cx, "Could not get the Subject Principal during InstallTrigger.Install()");
    return JS_FALSE;
  }

  // get window.location to construct relative URLs
  nsCOMPtr<nsIURI> baseURL;
  JSObject* global = JS_GetGlobalObject(cx);
  if (global)
  {
    jsval v;
    if (JS_GetProperty(cx,global,"location",&v))
    {
      nsAutoString location;
      ConvertJSValToStr( location, cx, v );
      NS_NewURI(getter_AddRefs(baseURL), location);
    }
  }

  PRBool abortLoad = PR_FALSE;

  // parse associative array of installs
  if ( argc >= 1 && JSVAL_IS_OBJECT(argv[0]) && JSVAL_TO_OBJECT(argv[0]) )
  {
    nsXPITriggerInfo *trigger = new nsXPITriggerInfo();
    if (!trigger)
      return JS_FALSE;

    trigger->SetPrincipal(principal);

    JSIdArray *ida = JS_Enumerate( cx, JSVAL_TO_OBJECT(argv[0]) );
    if ( ida )
    {
      jsval v;
      const PRUnichar *name, *URL;
      const PRUnichar *iconURL = nsnull;

      for (int i = 0; i < ida->length && !abortLoad; i++ )
      {
        JS_IdToValue( cx, ida->vector[i], &v );
        JSString * str = JS_ValueToString( cx, v );
        if (!str)
        {
          abortLoad = PR_TRUE;
          break;
        }

        name = reinterpret_cast<const PRUnichar*>(JS_GetStringChars( str ));

        URL = iconURL = nsnull;
        JSAutoByteString hash;
        JS_GetUCProperty( cx, JSVAL_TO_OBJECT(argv[0]), reinterpret_cast<const jschar*>(name), nsCRT::strlen(name), &v );
        if ( JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) )
        {
          jsval v2;
          if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "URL", &v2 ) && !JSVAL_IS_VOID(v2)) {
            JSString *str = JS_ValueToString(cx, v2);
            if (!str) {
              abortLoad = PR_TRUE;
              break;
            }
            URL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
          }

          if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "IconURL", &v2 ) && !JSVAL_IS_VOID(v2)) {
            JSString *str = JS_ValueToString(cx, v2);
            if (!str) {
              abortLoad = PR_TRUE;
              break;
            }
            iconURL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
          }

          if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "Hash", &v2) && !JSVAL_IS_VOID(v2)) {
            JSString *str = JS_ValueToString(cx, v2);
            if (!str || !hash.encode(cx, str)) {
              abortLoad = PR_TRUE;
              break;
            }
          }
        }
        else
        {
          JSString *str = JS_ValueToString(cx, v);
          if (!str) {
            abortLoad = PR_TRUE;
            break;
          }
          URL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
        }

        if ( URL )
        {
            // Get relative URL to load
            nsAutoString xpiURL(URL);
            if (baseURL)
            {
                nsCAutoString resolvedURL;
                baseURL->Resolve(NS_ConvertUTF16toUTF8(xpiURL), resolvedURL);
                xpiURL = NS_ConvertUTF8toUTF16(resolvedURL);
            }

            nsAutoString icon(iconURL);
            if (iconURL && baseURL)
            {
                nsCAutoString resolvedIcon;
                baseURL->Resolve(NS_ConvertUTF16toUTF8(icon), resolvedIcon);
                icon = NS_ConvertUTF8toUTF16(resolvedIcon);
            }

            // Make sure we're allowed to load this URL and the icon URL
            nsresult rv = InstallTriggerCheckLoadURIFromScript(cx, xpiURL);
            if (NS_FAILED(rv))
                abortLoad = PR_TRUE;

            if (!abortLoad && iconURL)
            {
                rv = InstallTriggerCheckLoadURIFromScript(cx, icon);
                if (NS_FAILED(rv))
                    abortLoad = PR_TRUE;
            }

            if (!abortLoad)
            {
                // Add the install item to the trigger collection
                nsXPITriggerItem *item =
                    new nsXPITriggerItem( name, xpiURL.get(), icon.get(), hash );
                if ( item )
                {
                    trigger->Add( item );
                }
                else
                    abortLoad = PR_TRUE;
            }
        }
        else
            abortLoad = PR_TRUE;
      }
      JS_DestroyIdArray( cx, ida );
    }


    // pass on only if good stuff found
    if (!abortLoad && trigger->Size() > 0)
    {
        nsCOMPtr<nsIURI> checkuri;
        nsresult rv = nativeThis->GetOriginatingURI(globalObject,
                                                    getter_AddRefs(checkuri));
        if (NS_SUCCEEDED(rv))
        {
            nsCOMPtr<nsIDOMWindowInternal> win(do_QueryInterface(globalObject));
            nsCOMPtr<nsIXPIInstallInfo> installInfo =
                new nsXPIInstallInfo(win, checkuri, trigger, 0);
            if (installInfo)
            {
                // installInfo now owns triggers
                PRBool enabled = PR_FALSE;
                nativeThis->UpdateEnabled(checkuri, XPI_WHITELIST, &enabled);
                if (!enabled)
                {
                    nsCOMPtr<nsIObserverService> os =
                      mozilla::services::GetObserverService();
                    if (os)
                        os->NotifyObservers(installInfo,
                                            "xpinstall-install-blocked",
                                            nsnull);
                }
                else
                {
                    // save callback function if any (ignore bad args for now)
                    if ( argc >= 2 && JS_TypeOfValue(cx,argv[1]) == JSTYPE_FUNCTION )
                    {
                        trigger->SaveCallback( cx, argv[1] );
                    }

                    PRBool result;
                    nativeThis->StartInstall(installInfo, &result);
                    *rval = BOOLEAN_TO_JSVAL(result);
                }
                return JS_TRUE;
            }
        }
    }
    // didn't pass it on so we must delete trigger
    delete trigger;
  }

  JS_ReportError(cx, "Incorrect arguments to InstallTrigger.Install()");
  return JS_FALSE;
}
Exemple #20
0
void
XPCShellEnvironment::ProcessFile(JSContext *cx,
                                 JS::Handle<JSObject*> obj,
                                 const char *filename,
                                 FILE *file,
                                 bool forceTTY)
{
    XPCShellEnvironment* env = this;

    JS::Rooted<JS::Value> result(cx);
    int lineno, startline;
    bool ok, hitEOF;
    char *bufp, buffer[4096];
    JSString *str;

    if (forceTTY) {
        file = stdin;
    }
    else if (!isatty(fileno(file)))
    {
        /*
         * It's not interactive - just execute it.
         *
         * Support the UNIX #! shell hack; gobble the first line if it starts
         * with '#'.  TODO - this isn't quite compatible with sharp variables,
         * as a legal js program (using sharp variables) might start with '#'.
         * But that would require multi-character lookahead.
         */
        int ch = fgetc(file);
        if (ch == '#') {
            while((ch = fgetc(file)) != EOF) {
                if(ch == '\n' || ch == '\r')
                    break;
            }
        }
        ungetc(ch, file);

        JSAutoRequest ar(cx);
        JSAutoCompartment ac(cx, obj);

        JS::CompileOptions options(cx);
        options.setUTF8(true)
               .setFileAndLine(filename, 1);
        JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file));
        if (script)
            (void)JS_ExecuteScript(cx, obj, script, result.address());

        return;
    }

    /* It's an interactive filehandle; drop into read-eval-print loop. */
    lineno = 1;
    hitEOF = false;
    do {
        bufp = buffer;
        *bufp = '\0';

        JSAutoRequest ar(cx);
        JSAutoCompartment ac(cx, obj);

        /*
         * Accumulate lines until we get a 'compilable unit' - one that either
         * generates an error (before running out of source) or that compiles
         * cleanly.  This should be whenever we get a complete statement that
         * coincides with the end of a line.
         */
        startline = lineno;
        do {
            if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) {
                hitEOF = true;
                break;
            }
            bufp += strlen(bufp);
            lineno++;
        } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));

        /* Clear any pending exception from previous failed compiles.  */
        JS_ClearPendingException(cx);
        JS::CompileOptions options(cx);
        options.setFileAndLine("typein", startline);
        JS::Rooted<JSScript*> script(cx,
                                     JS_CompileScript(cx, obj, buffer, strlen(buffer), options));
        if (script) {
            JSErrorReporter older;

            ok = JS_ExecuteScript(cx, obj, script, result.address());
            if (ok && result != JSVAL_VOID) {
                /* Suppress error reports from JS::ToString(). */
                older = JS_SetErrorReporter(cx, nullptr);
                str = JS::ToString(cx, result);
                JSAutoByteString bytes;
                if (str)
                    bytes.encodeLatin1(cx, str);
                JS_SetErrorReporter(cx, older);

                if (!!bytes)
                    fprintf(stdout, "%s\n", bytes.ptr());
                else
                    ok = false;
            }
        }
    } while (!hitEOF && !env->IsQuitting());

    fprintf(stdout, "\n");
}
Exemple #21
0
nsresult
RilConsumer::Send(JSContext* aCx, const CallArgs& aArgs)
{
  if (NS_WARN_IF(!mSocket) ||
      NS_WARN_IF(mSocket->GetConnectionStatus() == SOCKET_DISCONNECTED)) {
    // Probably shutting down.
    return NS_OK;
  }

  UniquePtr<UnixSocketRawData> raw;

  Value v = aArgs[1];

  if (v.isString()) {
    JSAutoByteString abs;
    Rooted<JSString*> str(aCx, v.toString());
    if (!abs.encodeUtf8(aCx, str)) {
      return NS_ERROR_FAILURE;
    }

    raw = MakeUnique<UnixSocketRawData>(abs.ptr(), abs.length());
  } else if (!v.isPrimitive()) {
    JSObject* obj = v.toObjectOrNull();
    if (!JS_IsTypedArrayObject(obj)) {
      JS_ReportError(aCx, "Object passed in wasn't a typed array");
      return NS_ERROR_FAILURE;
    }

    uint32_t type = JS_GetArrayBufferViewType(obj);
    if (type != js::Scalar::Int8 &&
        type != js::Scalar::Uint8 &&
        type != js::Scalar::Uint8Clamped) {
      JS_ReportError(aCx, "Typed array data is not octets");
      return NS_ERROR_FAILURE;
    }

    size_t size = JS_GetTypedArrayByteLength(obj);
    bool isShared;
    void* data;
    {
      AutoCheckCannotGC nogc;
      data = JS_GetArrayBufferViewData(obj, &isShared, nogc);
    }
    if (isShared) {
      JS_ReportError(
        aCx, "Incorrect argument.  Shared memory not supported");
      return NS_ERROR_FAILURE;
    }
    raw = MakeUnique<UnixSocketRawData>(data, size);
  } else {
    JS_ReportError(
      aCx, "Incorrect argument. Expecting a string or a typed array");
    return NS_ERROR_FAILURE;
  }

  if (!raw) {
    JS_ReportError(aCx, "Unable to post to RIL");
    return NS_ERROR_FAILURE;
  }

  mSocket->SendSocketData(raw.release());

  return NS_OK;
}
Exemple #22
0
static char *
FormatFrame(JSContext *cx, const NonBuiltinScriptFrameIter &iter, char *buf, int num,
            bool showArgs, bool showLocals, bool showThisProps)
{
    JS_ASSERT(!cx->isExceptionPending());
    RootedScript script(cx, iter.script());
    jsbytecode* pc = iter.pc();

    RootedObject scopeChain(cx, iter.scopeChain());
    JSAutoCompartment ac(cx, scopeChain);

    const char *filename = script->filename();
    unsigned lineno = PCToLineNumber(script, pc);
    RootedFunction fun(cx, iter.maybeCallee());
    RootedString funname(cx);
    if (fun)
        funname = fun->atom();

    RootedValue thisVal(cx);
    AutoPropertyDescArray thisProps(cx);
    if (iter.computeThis(cx)) {
        thisVal = iter.thisv();
        if (showThisProps && !thisVal.isPrimitive()) {
            RootedObject thisObj(cx, &thisVal.toObject());
            thisProps.fetch(thisObj);
        }
    }

    // print the frame number and function name
    if (funname) {
        JSAutoByteString funbytes;
        buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encodeLatin1(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)
        return buf;

    if (showArgs && iter.hasArgs()) {
        BindingVector bindings(cx);
        if (fun && fun->isInterpreted()) {
            if (!FillBindingVector(script, &bindings))
                return buf;
        }


        bool first = true;
        for (unsigned i = 0; i < iter.numActualArgs(); i++) {
            RootedValue arg(cx);
            if (i < iter.numFormalArgs() && script->formalIsAliased(i)) {
                for (AliasedFormalIter fi(script); ; fi++) {
                    if (fi.frameIndex() == i) {
                        arg = iter.callObj().aliasedVar(fi);
                        break;
                    }
                }
            } else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) {
                arg = iter.argsObj().arg(i);
            } else {
                arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
            }

            JSAutoByteString valueBytes;
            const char *value = FormatValue(cx, arg, valueBytes);

            JSAutoByteString nameBytes;
            const char *name = nullptr;

            if (i < bindings.length()) {
                name = nameBytes.encodeLatin1(cx, bindings[i].name());
                if (!buf)
                    return nullptr;
            }

            if (value) {
                buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
                                        !first ? ", " : "",
                                        name ? name :"",
                                        name ? " = " : "",
                                        arg.isString() ? "\"" : "",
                                        value ? value : "?unknown?",
                                        arg.isString() ? "\"" : "");
                if (!buf)
                    return buf;

                first = false;
            } else {
                buf = JS_sprintf_append(buf, "    <Failed to get argument while inspecting stack frame>\n");
                if (!buf)
                    return buf;
                cx->clearPendingException();

            }
        }
    }

    // print filename and line number
    buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
                            fun ? ")" : "",
                            filename ? filename : "<unknown>",
                            lineno);
    if (!buf)
        return buf;


    // Note: Right now we don't dump the local variables anymore, because
    // that is hard to support across all the JITs etc.

    // print the value of 'this'
    if (showLocals) {
        if (!thisVal.isUndefined()) {
            JSAutoByteString thisValBytes;
            RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
            const char *str = nullptr;
            if (thisValStr &&
                (str = thisValBytes.encodeLatin1(cx, thisValStr)))
            {
                buf = JS_sprintf_append(buf, "    this = %s\n", str);
                if (!buf)
                    return buf;
            } else {
                buf = JS_sprintf_append(buf, "    <failed to get 'this' value>\n");
                cx->clearPendingException();
            }
        }
    }

    // print the properties of 'this', if it is an object
    if (showThisProps && thisProps->array) {
        for (uint32_t i = 0; i < thisProps->length; i++) {
            JSPropertyDesc* desc = &thisProps->array[i];
            if (desc->flags & JSPD_ENUMERATE) {
                JSAutoByteString nameBytes;
                JSAutoByteString valueBytes;
                const char *name = FormatValue(cx, desc->id, nameBytes);
                const char *value = FormatValue(cx, desc->value, valueBytes);
                if (name && value) {
                    buf = JS_sprintf_append(buf, "    this.%s = %s%s%s\n",
                                            name,
                                            desc->value.isString() ? "\"" : "",
                                            value,
                                            desc->value.isString() ? "\"" : "");
                    if (!buf)
                        return buf;
                } else {
                    buf = JS_sprintf_append(buf, "    <Failed to format values while inspecting stack frame>\n");
                    cx->clearPendingException();
                }
            }
        }
    }

    JS_ASSERT(!cx->isExceptionPending());
    return buf;
}
static char *
FormatFrame(JSContext *cx, const ScriptFrameIter &iter, char *buf, int num,
            JSBool showArgs, JSBool showLocals, JSBool showThisProps)
{
    AssertCanGC();

    RootedScript script(cx, iter.script());
    jsbytecode* pc = iter.pc();

    RootedObject scopeChain(cx, iter.scopeChain());
    JSAutoCompartment ac(cx, scopeChain);

    const char *filename = script->filename;
    unsigned lineno = PCToLineNumber(script, pc);
    RootedFunction fun(cx, iter.maybeCallee());
    RootedString funname(cx);
    if (fun)
        funname = fun->atom();

    RootedObject callObj(cx);
    AutoPropertyDescArray callProps(cx);

    if (!iter.isIon() && (showArgs || showLocals)) {
        callObj = JS_GetFrameCallObject(cx, Jsvalify(iter.interpFrame()));
        if (callObj)
            callProps.fetch(callObj);
    }

    RootedValue thisVal(cx);
    AutoPropertyDescArray thisProps(cx);
    if (iter.computeThis()) {
        thisVal = iter.thisv();
        if (showThisProps && !thisVal.isPrimitive())
            thisProps.fetch(&thisVal.toObject());
    }

    // print the frame number and function name
    if (funname) {
        JSAutoByteString funbytes;
        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)
        return buf;

    // print the function arguments
    if (showArgs && callObj) {
        uint32_t namedArgCount = 0;
        for (uint32_t i = 0; i < callProps->length; i++) {
            JSPropertyDesc* desc = &callProps->array[i];
            JSAutoByteString nameBytes;
            const char *name = NULL;
            if (JSVAL_IS_STRING(desc->id))
                name = FormatValue(cx, desc->id, nameBytes);

            JSAutoByteString valueBytes;
            const char *value = FormatValue(cx, desc->value, valueBytes);

            buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
                                    namedArgCount ? ", " : "",
                                    name ? name :"",
                                    name ? " = " : "",
                                    desc->value.isString() ? "\"" : "",
                                    value ? value : "?unknown?",
                                    desc->value.isString() ? "\"" : "");
            if (!buf)
                return buf;
            namedArgCount++;
        }

        // print any unnamed trailing args (found in 'arguments' object)
        RootedValue val(cx);
        if (JS_GetProperty(cx, callObj, "arguments", val.address()) && val.isObject()) {
            uint32_t argCount;
            RootedObject argsObj(cx, &val.toObject());
            if (JS_GetProperty(cx, argsObj, "length", val.address()) &&
                ToUint32(cx, val, &argCount) &&
                argCount > namedArgCount)
            {
                for (uint32_t k = namedArgCount; k < argCount; k++) {
                    char number[8];
                    JS_snprintf(number, 8, "%d", (int) k);

                    if (JS_GetProperty(cx, argsObj, number, val.address())) {
                        JSAutoByteString valueBytes;
                        const char *value = FormatValue(cx, val, valueBytes);
                        buf = JS_sprintf_append(buf, "%s%s%s%s",
                                                k ? ", " : "",
                                                val.isString() ? "\"" : "",
                                                value ? value : "?unknown?",
                                                val.isString() ? "\"" : "");
                        if (!buf)
                            return buf;
                    }
                }
            }
        }
    }

    // print filename and line number
    buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
                            fun ? ")" : "",
                            filename ? filename : "<unknown>",
                            lineno);
    if (!buf)
        return buf;

    // print local variables
    if (showLocals && callProps->array) {
        for (uint32_t i = 0; i < callProps->length; i++) {
            JSPropertyDesc* desc = &callProps->array[i];
            JSAutoByteString nameBytes;
            JSAutoByteString valueBytes;
            const char *name = FormatValue(cx, desc->id, nameBytes);
            const char *value = FormatValue(cx, desc->value, valueBytes);

            if (name && value) {
                buf = JS_sprintf_append(buf, "    %s = %s%s%s\n",
                                        name,
                                        desc->value.isString() ? "\"" : "",
                                        value,
                                        desc->value.isString() ? "\"" : "");
                if (!buf)
                    return buf;
            }
        }
    }

    // print the value of 'this'
    if (showLocals) {
        if (!thisVal.isUndefined()) {
            JSAutoByteString thisValBytes;
            RootedString thisValStr(cx, ToString(cx, thisVal));
            if (thisValStr) {
                if (const char *str = thisValBytes.encode(cx, thisValStr)) {
                    buf = JS_sprintf_append(buf, "    this = %s\n", str);
                    if (!buf)
                        return buf;
                }
            }
        } else {
            buf = JS_sprintf_append(buf, "    <failed to get 'this' value>\n");
        }
    }

    // print the properties of 'this', if it is an object
    if (showThisProps && thisProps->array) {
        for (uint32_t i = 0; i < thisProps->length; i++) {
            JSPropertyDesc* desc = &thisProps->array[i];
            if (desc->flags & JSPD_ENUMERATE) {
                JSAutoByteString nameBytes;
                JSAutoByteString valueBytes;
                const char *name = FormatValue(cx, desc->id, nameBytes);
                const char *value = FormatValue(cx, desc->value, valueBytes);
                if (name && value) {
                    buf = JS_sprintf_append(buf, "    this.%s = %s%s%s\n",
                                            name,
                                            desc->value.isString() ? "\"" : "",
                                            value,
                                            desc->value.isString() ? "\"" : "");
                    if (!buf)
                        return buf;
                }
            }
        }
    }

    return buf;
}
Exemple #24
0
void JS_FASTCALL
stubs::DefFun(VMFrame &f, JSFunction *fun_)
{
    /*
     * A top-level function defined in Global or Eval code (see ECMA-262
     * Ed. 3), or else a SpiderMonkey extension: a named function statement in
     * a compound statement (not at the top statement level of global code, or
     * at the top level of a function body).
     */
    JSContext *cx = f.cx;
    StackFrame *fp = f.fp();
    RootedFunction fun(f.cx, fun_);

    /*
     * If static link is not current scope, clone fun's object to link to the
     * current scope via parent. We do this to enable sharing of compiled
     * functions among multiple equivalent scopes, amortizing the cost of
     * compilation over a number of executions.  Examples include XUL scripts
     * and event handlers shared among Firefox or other Mozilla app chrome
     * windows, and user-defined JS functions precompiled and then shared among
     * requests in server-side JS.
     */
    HandleObject scopeChain = f.fp()->scopeChain();
    if (fun->environment() != scopeChain) {
        fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain);
        if (!fun)
            THROW();
    } else {
        JS_ASSERT(f.script()->compileAndGo);
        JS_ASSERT(f.fp()->isGlobalFrame() || f.fp()->isEvalInFunction());
    }

    /*
     * ECMA requires functions defined when entering Eval code to be
     * impermanent.
     */
    unsigned attrs = fp->isEvalFrame()
                  ? JSPROP_ENUMERATE
                  : JSPROP_ENUMERATE | JSPROP_PERMANENT;

    /*
     * We define the function as a property of the variable object and not the
     * current scope chain even for the case of function expression statements
     * and functions defined by eval inside let or with blocks.
     */
    JSObject *parent = &fp->varObj();

    /* ES5 10.5 (NB: with subsequent errata). */
    PropertyName *name = fun->atom->asPropertyName();
    JSProperty *prop = NULL;
    JSObject *pobj;
    if (!parent->lookupProperty(cx, name, &pobj, &prop))
        THROW();

    Value rval = ObjectValue(*fun);

    do {
        /* Steps 5d, 5f. */
        if (!prop || pobj != parent) {
            if (!parent->defineProperty(cx, name, rval,
                                        JS_PropertyStub, JS_StrictPropertyStub, attrs))
            {
                THROW();
            }
            break;
        }

        /* Step 5e. */
        JS_ASSERT(parent->isNative());
        Shape *shape = reinterpret_cast<Shape *>(prop);
        if (parent->isGlobal()) {
            if (shape->configurable()) {
                if (!parent->defineProperty(cx, name, rval,
                                            JS_PropertyStub, JS_StrictPropertyStub, attrs))
                {
                    THROW();
                }
                break;
            }

            if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
                JSAutoByteString bytes;
                if (js_AtomToPrintableString(cx, name, &bytes)) {
                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                         JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
                }
                THROW();
            }
        }

        /*
         * Non-global properties, and global properties which we aren't simply
         * redefining, must be set.  First, this preserves their attributes.
         * Second, this will produce warnings and/or errors as necessary if the
         * specified Call object property is not writable (const).
         */

        /* Step 5f. */
        if (!parent->setProperty(cx, name, &rval, strict))
            THROW();
    } while (false);
}
Exemple #25
0
JSBool
js_ReportUncaughtException(JSContext *cx)
{
    jsval exn;
    JSObject *exnObject;
    jsval roots[5];
    JSErrorReport *reportp, report;
    JSString *str;
    const char *bytes;

    if (!JS_IsExceptionPending(cx))
        return true;

    if (!JS_GetPendingException(cx, &exn))
        return false;

    PodArrayZero(roots);
    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots));

    /*
     * Because js_ValueToString below could error and an exception object
     * could become unrooted, we must root exnObject.  Later, if exnObject is
     * non-null, we need to root other intermediates, so allocate an operand
     * stack segment to protect all of these values.
     */
    if (JSVAL_IS_PRIMITIVE(exn)) {
        exnObject = NULL;
    } else {
        exnObject = JSVAL_TO_OBJECT(exn);
        roots[0] = exn;
    }

    JS_ClearPendingException(cx);
    reportp = js_ErrorFromException(cx, exn);

    /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
    str = js_ValueToString(cx, Valueify(exn));
    JSAutoByteString bytesStorage;
    if (!str) {
        bytes = "unknown (can't convert to string)";
    } else {
        roots[1] = STRING_TO_JSVAL(str);
        if (!bytesStorage.encode(cx, str))
            return false;
        bytes = bytesStorage.ptr();
    }

    JSAutoByteString filename;
    if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) {
        if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
            return false;
        if (JSVAL_IS_STRING(roots[2])) {
            bytesStorage.clear();
            if (!bytesStorage.encode(cx, str))
                return false;
            bytes = bytesStorage.ptr();
        }

        if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]))
            return false;
        str = js_ValueToString(cx, Valueify(roots[3]));
        if (!str || !filename.encode(cx, str))
            return false;

        if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
            return false;
        uint32_t lineno;
        if (!ValueToECMAUint32(cx, Valueify(roots[4]), &lineno))
            return false;

        reportp = &report;
        PodZero(&report);
        report.filename = filename.ptr();
        report.lineno = (uintN) lineno;
        if (JSVAL_IS_STRING(roots[2])) {
            JSFixedString *fixed = JSVAL_TO_STRING(roots[2])->ensureFixed(cx);
            if (!fixed)
                return false;
            report.ucmessage = fixed->chars();
        }
    }

    if (!reportp) {
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                             JSMSG_UNCAUGHT_EXCEPTION, bytes);
    } else {
        /* Flag the error as an exception. */
        reportp->flags |= JSREPORT_EXCEPTION;

        /* Pass the exception object. */
        JS_SetPendingException(cx, exn);
        js_ReportErrorAgain(cx, bytes, reportp);
        JS_ClearPendingException(cx);
    }

    return true;
}
Exemple #26
0
static JS::UniqueChars
FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num,
            bool showArgs, bool showLocals, bool showThisProps)
{
    MOZ_ASSERT(!cx->isExceptionPending());
    RootedScript script(cx, iter.script());
    jsbytecode* pc = iter.pc();

    RootedObject envChain(cx, iter.environmentChain(cx));
    JSAutoCompartment ac(cx, envChain);

    const char* filename = script->filename();
    unsigned lineno = PCToLineNumber(script, pc);
    RootedFunction fun(cx, iter.maybeCallee(cx));
    RootedString funname(cx);
    if (fun)
        funname = fun->displayAtom();

    RootedValue thisVal(cx);
    if (iter.hasUsableAbstractFramePtr() &&
        iter.isFunctionFrame() &&
        fun && !fun->isArrow() && !fun->isDerivedClassConstructor() &&
        !(fun->isBoundFunction() && iter.isConstructing()))
    {
        if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal))
            return nullptr;
    }

    // print the frame number and function name
    JS::UniqueChars buf(Move(inBuf));
    if (funname) {
        JSAutoByteString funbytes;
        char* str = funbytes.encodeLatin1(cx, funname);
        if (!str)
            return nullptr;
        buf = sprintf_append(cx, Move(buf), "%d %s(", num, str);
    } else if (fun) {
        buf = sprintf_append(cx, Move(buf), "%d anonymous(", num);
    } else {
        buf = sprintf_append(cx, Move(buf), "%d <TOP LEVEL>", num);
    }
    if (!buf)
        return nullptr;

    if (showArgs && iter.hasArgs()) {
        PositionalFormalParameterIter fi(script);
        bool first = true;
        for (unsigned i = 0; i < iter.numActualArgs(); i++) {
            RootedValue arg(cx);
            if (i < iter.numFormalArgs() && fi.closedOver()) {
                arg = iter.callObj(cx).aliasedBinding(fi);
            } else if (iter.hasUsableAbstractFramePtr()) {
                if (script->analyzedArgsUsage() &&
                    script->argsObjAliasesFormals() &&
                    iter.hasArgsObj())
                {
                    arg = iter.argsObj().arg(i);
                } else {
                    arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
                }
            } else {
                arg = MagicValue(JS_OPTIMIZED_OUT);
            }

            JSAutoByteString valueBytes;
            const char* value = FormatValue(cx, arg, valueBytes);
            if (!value) {
                if (cx->isThrowingOutOfMemory())
                    return nullptr;
                cx->clearPendingException();
            }

            JSAutoByteString nameBytes;
            const char* name = nullptr;

            if (i < iter.numFormalArgs()) {
                MOZ_ASSERT(fi.argumentSlot() == i);
                if (!fi.isDestructured()) {
                    name = nameBytes.encodeLatin1(cx, fi.name());
                    if (!name)
                        return nullptr;
                } else {
                    name = "(destructured parameter)";
                }
                fi++;
            }

            if (value) {
                buf = sprintf_append(cx, Move(buf), "%s%s%s%s%s%s",
                                     !first ? ", " : "",
                                     name ? name :"",
                                     name ? " = " : "",
                                     arg.isString() ? "\"" : "",
                                     value,
                                     arg.isString() ? "\"" : "");
                if (!buf)
                    return nullptr;

                first = false;
            } else {
                buf = sprintf_append(cx, Move(buf),
                                     "    <Failed to get argument while inspecting stack frame>\n");
                if (!buf)
                    return nullptr;

            }
        }
    }

    // print filename and line number
    buf = sprintf_append(cx, Move(buf), "%s [\"%s\":%d]\n",
                         fun ? ")" : "",
                         filename ? filename : "<unknown>",
                         lineno);
    if (!buf)
        return nullptr;


    // Note: Right now we don't dump the local variables anymore, because
    // that is hard to support across all the JITs etc.

    // print the value of 'this'
    if (showLocals) {
        if (!thisVal.isUndefined()) {
            JSAutoByteString thisValBytes;
            RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
            if (!thisValStr) {
                if (cx->isThrowingOutOfMemory())
                    return nullptr;
                cx->clearPendingException();
            }
            if (thisValStr) {
                const char* str = thisValBytes.encodeLatin1(cx, thisValStr);
                if (!str)
                    return nullptr;
                buf = sprintf_append(cx, Move(buf), "    this = %s\n", str);
            } else {
                buf = sprintf_append(cx, Move(buf), "    <failed to get 'this' value>\n");
            }
            if (!buf)
                return nullptr;
        }
    }

    if (showThisProps && thisVal.isObject()) {
        RootedObject obj(cx, &thisVal.toObject());

        AutoIdVector keys(cx);
        if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
            if (cx->isThrowingOutOfMemory())
                return nullptr;
            cx->clearPendingException();
        }

        RootedId id(cx);
        for (size_t i = 0; i < keys.length(); i++) {
            RootedId id(cx, keys[i]);
            RootedValue key(cx, IdToValue(id));
            RootedValue v(cx);

            if (!GetProperty(cx, obj, obj, id, &v)) {
                if (cx->isThrowingOutOfMemory())
                    return nullptr;
                cx->clearPendingException();
                buf = sprintf_append(cx, Move(buf),
                                     "    <Failed to fetch property while inspecting stack frame>\n");
                if (!buf)
                    return nullptr;
                continue;
            }

            JSAutoByteString nameBytes;
            const char* name = FormatValue(cx, key, nameBytes);
            if (!name) {
                if (cx->isThrowingOutOfMemory())
                    return nullptr;
                cx->clearPendingException();
            }

            JSAutoByteString valueBytes;
            const char* value = FormatValue(cx, v, valueBytes);
            if (!value) {
                if (cx->isThrowingOutOfMemory())
                    return nullptr;
                cx->clearPendingException();
            }

            if (name && value) {
                buf = sprintf_append(cx, Move(buf), "    this.%s = %s%s%s\n",
                                     name,
                                     v.isString() ? "\"" : "",
                                     value,
                                     v.isString() ? "\"" : "");
            } else {
                buf = sprintf_append(cx, Move(buf),
                                     "    <Failed to format values while inspecting stack frame>\n");
            }
            if (!buf)
                return nullptr;
        }
    }

    MOZ_ASSERT(!cx->isExceptionPending());
    return buf;
}
static bool
DefinePropertyIfFound(XPCCallContext& ccx,
                      HandleObject obj,
                      HandleId idArg,
                      XPCNativeSet* set,
                      XPCNativeInterface* ifaceArg,
                      XPCNativeMember* member,
                      XPCWrappedNativeScope* scope,
                      bool reflectToStringAndToSource,
                      XPCWrappedNative* wrapperToReflectInterfaceNames,
                      XPCWrappedNative* wrapperToReflectDoubleWrap,
                      XPCNativeScriptableInfo* scriptableInfo,
                      unsigned propFlags,
                      bool* resolved)
{
    RootedId id(ccx, idArg);
    RefPtr<XPCNativeInterface> iface = ifaceArg;
    XPCJSContext* xpccx = ccx.GetContext();
    bool found;
    const char* name;

    propFlags |= JSPROP_RESOLVING;

    if (set) {
        if (iface)
            found = true;
        else
            found = set->FindMember(id, &member, &iface);
    } else
        found = (nullptr != (member = iface->FindMember(id)));

    if (!found) {
        if (reflectToStringAndToSource) {
            JSNative call;
            uint32_t flags = 0;

            if (scriptableInfo) {
                nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(
                    scriptableInfo->GetCallback());

                if (classInfo) {
                    nsresult rv = classInfo->GetFlags(&flags);
                    if (NS_FAILED(rv))
                        return Throw(rv, ccx);
                }
            }

            bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT)
                || Preferences::GetBool("dom.XPCToStringForDOMClasses", false);

            if(id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING)
                && overwriteToString)
            {
                call = XPC_WN_Shared_ToString;
                name = xpccx->GetStringName(XPCJSContext::IDX_TO_STRING);
            } else if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE)) {
                call = XPC_WN_Shared_ToSource;
                name = xpccx->GetStringName(XPCJSContext::IDX_TO_SOURCE);
            } else if (id == SYMBOL_TO_JSID(
                               JS::GetWellKnownSymbol(ccx, JS::SymbolCode::toPrimitive)))
            {
                call = XPC_WN_Shared_toPrimitive;
                name = "[Symbol.toPrimitive]";
            } else {
                call = nullptr;
            }

            if (call) {
                RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, name));
                if (!fun) {
                    JS_ReportOutOfMemory(ccx);
                    return false;
                }

                AutoResolveName arn(ccx, id);
                if (resolved)
                    *resolved = true;
                RootedObject value(ccx, JS_GetFunctionObject(fun));
                return JS_DefinePropertyById(ccx, obj, id, value,
                                             propFlags & ~JSPROP_ENUMERATE);
            }
        }
        // This *might* be a tearoff name that is not yet part of our
        // set. Let's lookup the name and see if it is the name of an
        // interface. Then we'll see if the object actually *does* this
        // interface and add a tearoff as necessary.

        if (wrapperToReflectInterfaceNames) {
            JSAutoByteString name;
            RefPtr<XPCNativeInterface> iface2;
            XPCWrappedNativeTearOff* to;
            RootedObject jso(ccx);
            nsresult rv = NS_OK;

            if (JSID_IS_STRING(id) &&
                name.encodeLatin1(ccx, JSID_TO_STRING(id)) &&
                (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr()), iface2) &&
                nullptr != (to = wrapperToReflectInterfaceNames->
                           FindTearOff(iface2, true, &rv)) &&
                nullptr != (jso = to->GetJSObject()))

            {
                AutoResolveName arn(ccx, id);
                if (resolved)
                    *resolved = true;
                return JS_DefinePropertyById(ccx, obj, id, jso,
                                             propFlags & ~JSPROP_ENUMERATE);
            } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) {
                return Throw(rv, ccx);
            }
        }

        // This *might* be a double wrapped JSObject
        if (wrapperToReflectDoubleWrap &&
            id == xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
            GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) {
            // We build and add a getter function.
            // A security check is done on a per-get basis.

            JSFunction* fun;

            id = xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT);
            name = xpccx->GetStringName(XPCJSContext::IDX_WRAPPED_JSOBJECT);

            fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter,
                                 0, 0, name);

            if (!fun)
                return false;

            RootedObject funobj(ccx, JS_GetFunctionObject(fun));
            if (!funobj)
                return false;

            propFlags |= JSPROP_GETTER | JSPROP_SHARED;
            propFlags &= ~JSPROP_ENUMERATE;

            AutoResolveName arn(ccx, id);
            if (resolved)
                *resolved = true;
            return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags,
                                         JS_DATA_TO_FUNC_PTR(JSNative, funobj.get()),
                                         nullptr);
        }

        if (resolved)
            *resolved = false;
        return true;
    }

    if (!member) {
        if (wrapperToReflectInterfaceNames) {
            XPCWrappedNativeTearOff* to =
              wrapperToReflectInterfaceNames->FindTearOff(iface, true);

            if (!to)
                return false;
            RootedObject jso(ccx, to->GetJSObject());
            if (!jso)
                return false;

            AutoResolveName arn(ccx, id);
            if (resolved)
                *resolved = true;
            return JS_DefinePropertyById(ccx, obj, id, jso,
                                         propFlags & ~JSPROP_ENUMERATE);
        }
        if (resolved)
            *resolved = false;
        return true;
    }

    if (member->IsConstant()) {
        RootedValue val(ccx);
        AutoResolveName arn(ccx, id);
        if (resolved)
            *resolved = true;
        return member->GetConstantValue(ccx, iface, val.address()) &&
               JS_DefinePropertyById(ccx, obj, id, val, propFlags);
    }

    if (scope->HasInterposition()) {
        Rooted<PropertyDescriptor> desc(ccx);
        if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc))
            return false;

        if (desc.object()) {
            AutoResolveName arn(ccx, id);
            if (resolved)
                *resolved = true;
            desc.attributesRef() |= JSPROP_RESOLVING;
            return JS_DefinePropertyById(ccx, obj, id, desc);
        }
    }

    if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING) ||
        id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE) ||
        (scriptableInfo &&
         scriptableInfo->GetFlags().DontEnumQueryInterface() &&
         id == xpccx->GetStringID(XPCJSContext::IDX_QUERY_INTERFACE)))
        propFlags &= ~JSPROP_ENUMERATE;

    RootedValue funval(ccx);
    if (!member->NewFunctionObject(ccx, iface, obj, funval.address()))
        return false;

    if (member->IsMethod()) {
        AutoResolveName arn(ccx, id);
        if (resolved)
            *resolved = true;
        return JS_DefinePropertyById(ccx, obj, id, funval, propFlags);
    }

    // else...

    MOZ_ASSERT(member->IsAttribute(), "way broken!");

    propFlags |= JSPROP_GETTER | JSPROP_SHARED;
    propFlags &= ~JSPROP_READONLY;
    JSObject* funobj = funval.toObjectOrNull();
    JSNative getter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
    JSNative setter;
    if (member->IsWritableAttribute()) {
        propFlags |= JSPROP_SETTER;
        setter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
    } else {
        setter = nullptr;
    }

    AutoResolveName arn(ccx, id);
    if (resolved)
        *resolved = true;

    return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, getter, setter);
}
Exemple #28
0
static char*
FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
            bool showArgs, bool showLocals, bool showThisProps)
{
    MOZ_ASSERT(!cx->isExceptionPending());
    RootedScript script(cx, iter.script());
    jsbytecode* pc = iter.pc();

    RootedObject scopeChain(cx, iter.scopeChain(cx));
    JSAutoCompartment ac(cx, scopeChain);

    const char* filename = script->filename();
    unsigned lineno = PCToLineNumber(script, pc);
    RootedFunction fun(cx, iter.maybeCallee(cx));
    RootedString funname(cx);
    if (fun)
        funname = fun->displayAtom();

    RootedValue thisVal(cx);
    if (iter.hasUsableAbstractFramePtr() && iter.computeThis(cx)) {
        thisVal = iter.computedThisValue();
    }

    // print the frame number and function name
    if (funname) {
        JSAutoByteString funbytes;
        buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encodeLatin1(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)
        return buf;

    if (showArgs && iter.hasArgs()) {
        BindingIter bi(script);
        bool first = true;
        for (unsigned i = 0; i < iter.numActualArgs(); i++) {
            RootedValue arg(cx);
            if (i < iter.numFormalArgs() && script->formalIsAliased(i)) {
                for (AliasedFormalIter fi(script); ; fi++) {
                    if (fi.frameIndex() == i) {
                        arg = iter.callObj(cx).aliasedVar(fi);
                        break;
                    }
                }
            } else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) {
                arg = iter.argsObj().arg(i);
            } else {
                if (iter.hasUsableAbstractFramePtr())
                    arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
                else
                    arg = MagicValue(JS_OPTIMIZED_OUT);
            }

            JSAutoByteString valueBytes;
            const char* value = FormatValue(cx, arg, valueBytes);

            JSAutoByteString nameBytes;
            const char* name = nullptr;

            if (i < iter.numFormalArgs()) {
                MOZ_ASSERT(i == bi.argIndex());
                name = nameBytes.encodeLatin1(cx, bi->name());
                if (!buf)
                    return nullptr;
                bi++;
            }

            if (value) {
                buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
                                        !first ? ", " : "",
                                        name ? name :"",
                                        name ? " = " : "",
                                        arg.isString() ? "\"" : "",
                                        value,
                                        arg.isString() ? "\"" : "");
                if (!buf)
                    return buf;

                first = false;
            } else {
                buf = JS_sprintf_append(buf, "    <Failed to get argument while inspecting stack frame>\n");
                if (!buf)
                    return buf;
                cx->clearPendingException();

            }
        }
    }

    // print filename and line number
    buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
                            fun ? ")" : "",
                            filename ? filename : "<unknown>",
                            lineno);
    if (!buf)
        return buf;


    // Note: Right now we don't dump the local variables anymore, because
    // that is hard to support across all the JITs etc.

    // print the value of 'this'
    if (showLocals) {
        if (!thisVal.isUndefined()) {
            JSAutoByteString thisValBytes;
            RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
            const char* str = nullptr;
            if (thisValStr &&
                (str = thisValBytes.encodeLatin1(cx, thisValStr)))
            {
                buf = JS_sprintf_append(buf, "    this = %s\n", str);
                if (!buf)
                    return buf;
            } else {
                buf = JS_sprintf_append(buf, "    <failed to get 'this' value>\n");
                cx->clearPendingException();
            }
        }
    }

    if (showThisProps && thisVal.isObject()) {
        RootedObject obj(cx, &thisVal.toObject());

        AutoIdVector keys(cx);
        if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
            cx->clearPendingException();
            return buf;
        }

        RootedId id(cx);
        for (size_t i = 0; i < keys.length(); i++) {
            RootedId id(cx, keys[i]);
            RootedValue key(cx, IdToValue(id));
            RootedValue v(cx);

            if (!GetProperty(cx, obj, obj, id, &v)) {
                buf = JS_sprintf_append(buf, "    <Failed to fetch property while inspecting stack frame>\n");
                cx->clearPendingException();
                continue;
            }

            JSAutoByteString nameBytes;
            JSAutoByteString valueBytes;
            const char* name = FormatValue(cx, key, nameBytes);
            const char* value = FormatValue(cx, v, valueBytes);
            if (name && value) {
                buf = JS_sprintf_append(buf, "    this.%s = %s%s%s\n",
                                        name,
                                        v.isString() ? "\"" : "",
                                        value,
                                        v.isString() ? "\"" : "");
                if (!buf)
                    return buf;
            } else {
                buf = JS_sprintf_append(buf, "    <Failed to format values while inspecting stack frame>\n");
                cx->clearPendingException();
            }
        }
    }

    MOZ_ASSERT(!cx->isExceptionPending());
    return buf;
}
Exemple #29
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 = JS_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_GetFrameScopeChain(cx, 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 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;
}