Bug 957742 - Logging for CPOWs (r=mrbkap)

This commit is contained in:
Tom Schuster 2014-05-28 18:05:22 -07:00
parent f86aa991e3
commit 28ef5afa8b
7 changed files with 293 additions and 0 deletions

View File

@ -25,6 +25,9 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
void drop(JSObject *obj);
protected:
virtual bool isParent() { return false; }
private:
bool fail(JSContext *cx, ReturnStatus *rs);
bool ok(ReturnStatus *rs);

194
js/ipc/JavaScriptLogging.h Normal file
View File

@ -0,0 +1,194 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=80:
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_jsipc_JavaScriptLogging__
#define mozilla_jsipc_JavaScriptLogging__
#include "nsString.h"
#include "nsPrintfCString.h"
#include "js/OldDebugAPI.h"
namespace mozilla {
namespace jsipc {
#define LOG(...) \
PR_BEGIN_MACRO \
if (LoggingEnabled()) { \
Logging log(this, cx); \
log.print(__VA_ARGS__); \
} \
PR_END_MACRO
#define LOG_STACK() \
PR_BEGIN_MACRO \
if (StackLoggingEnabled()) { \
js_DumpBacktrace(cx); \
} \
PR_END_MACRO
struct ReceiverObj
{
ObjectId id;
ReceiverObj(ObjectId id) : id(id) {}
};
struct InVariant
{
JSVariant variant;
InVariant(const JSVariant &variant) : variant(variant) {}
};
struct OutVariant
{
JSVariant variant;
OutVariant(const JSVariant &variant) : variant(variant) {}
};
class Logging
{
public:
Logging(JavaScriptShared *shared, JSContext *cx) : shared(shared), cx(cx) {}
void print(const nsCString &str) {
const char *side = shared->isParent() ? "from child" : "from parent";
printf("CPOW %s: %s\n", side, str.get());
}
void print(const char *str) {
print(nsCString(str));
}
template<typename T1>
void print(const char *fmt, const T1 &a1) {
nsAutoCString tmp1;
format(a1, tmp1);
print(nsPrintfCString(fmt, tmp1.get()));
}
template<typename T1, typename T2>
void print(const char *fmt, const T1 &a1, const T2 &a2) {
nsAutoCString tmp1;
nsAutoCString tmp2;
format(a1, tmp1);
format(a2, tmp2);
print(nsPrintfCString(fmt, tmp1.get(), tmp2.get()));
}
template<typename T1, typename T2, typename T3>
void print(const char *fmt, const T1 &a1, const T2 &a2, const T3 &a3) {
nsAutoCString tmp1;
nsAutoCString tmp2;
nsAutoCString tmp3;
format(a1, tmp1);
format(a2, tmp2);
format(a3, tmp3);
print(nsPrintfCString(fmt, tmp1.get(), tmp2.get(), tmp3.get()));
}
void format(const nsString &str, nsCString &out) {
out = NS_ConvertUTF16toUTF8(str);
}
void formatObject(bool incoming, bool local, ObjectId id, nsCString &out) {
const char *side, *objDesc;
if (local == incoming) {
RootedObject obj(cx);
obj = shared->findObjectById(id);
if (obj) {
JSAutoCompartment ac(cx, obj);
objDesc = js_ObjectClassName(cx, obj);
} else {
objDesc = "<dead object>";
}
side = shared->isParent() ? "parent" : "child";
} else {
objDesc = "<cpow>";
side = shared->isParent() ? "child" : "parent";
}
out = nsPrintfCString("<%s %s:%d>", side, objDesc, id);
}
void format(const ReceiverObj &obj, nsCString &out) {
formatObject(true, true, obj.id, out);
}
void format(const nsTArray<JSParam> &values, nsCString &out) {
nsAutoCString tmp;
out.Truncate();
for (size_t i = 0; i < values.Length(); i++) {
if (i)
out.AppendLiteral(", ");
if (values[i].type() == JSParam::Tvoid_t) {
out.AppendLiteral("<void>");
} else {
format(InVariant(values[i].get_JSVariant()), tmp);
out += tmp;
}
}
}
void format(const InVariant &value, nsCString &out) {
format(true, value.variant, out);
}
void format(const OutVariant &value, nsCString &out) {
format(false, value.variant, out);
}
void format(bool incoming, const JSVariant &value, nsCString &out) {
switch (value.type()) {
case JSVariant::TUndefinedVariant: {
out = "undefined";
break;
}
case JSVariant::TNullVariant: {
out = "null";
break;
}
case JSVariant::TnsString: {
nsAutoCString tmp;
format(value.get_nsString(), tmp);
out = nsPrintfCString("\"%s\"", tmp.get());
break;
}
case JSVariant::TObjectVariant: {
const ObjectVariant &ovar = value.get_ObjectVariant();
if (ovar.type() == ObjectVariant::TLocalObject)
formatObject(incoming, true, ovar.get_LocalObject().id(), out);
else
formatObject(incoming, false, ovar.get_RemoteObject().id(), out);
break;
}
case JSVariant::Tdouble: {
out = nsPrintfCString("%.0f", value.get_double());
break;
}
case JSVariant::Tbool: {
out = value.get_bool() ? "true" : "false";
break;
}
case JSVariant::TJSIID: {
out = "<JSIID>";
break;
}
default: {
out = "<JSIID>";
break;
}
}
}
private:
JavaScriptShared *shared;
JSContext *cx;
};
}
}
#endif

View File

@ -27,6 +27,9 @@ class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
mozilla::ipc::IProtocol*
CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
protected:
virtual bool isParent() { return true; }
};
} // jsipc

View File

@ -10,6 +10,7 @@
#include "mozilla/dom/TabChild.h"
#include "jsfriendapi.h"
#include "xpcprivate.h"
#include "mozilla/Preferences.h"
using namespace js;
using namespace JS;
@ -144,11 +145,22 @@ ObjectToIdMap::remove(JSObject *obj)
table_->remove(obj);
}
bool JavaScriptShared::sLoggingInitialized;
bool JavaScriptShared::sLoggingEnabled;
bool JavaScriptShared::sStackLoggingEnabled;
JavaScriptShared::JavaScriptShared(JSRuntime *rt)
: rt_(rt),
refcount_(1),
lastId_(0)
{
if (!sLoggingInitialized) {
sLoggingInitialized = true;
Preferences::AddBoolVarCache(&sLoggingEnabled,
"dom.ipc.cpows.log.enabled", false);
Preferences::AddBoolVarCache(&sStackLoggingEnabled,
"dom.ipc.cpows.log.stack", false);
}
}
bool

View File

@ -81,6 +81,8 @@ class ObjectToIdMap
Table *table_;
};
class Logging;
class JavaScriptShared
{
public:
@ -124,6 +126,13 @@ class JavaScriptShared
}
JSObject *findObjectById(JSContext *cx, uint32_t objId);
static bool LoggingEnabled() { return sLoggingEnabled; }
static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
friend class Logging;
virtual bool isParent() = 0;
protected:
JSRuntime *rt_;
uintptr_t refcount_;
@ -133,6 +142,10 @@ class JavaScriptShared
ObjectId lastId_;
ObjectToIdMap objectIds_;
static bool sLoggingInitialized;
static bool sLoggingEnabled;
static bool sStackLoggingEnabled;
};
// Use 47 at most, to be safe, since jsval privates are encoded as doubles.

View File

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WrapperAnswer.h"
#include "JavaScriptLogging.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/BindingUtils.h"
#include "nsContentUtils.h"
@ -71,6 +72,8 @@ WrapperAnswer::AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
if (!JS_PreventExtensions(cx, obj))
return fail(cx, rs);
LOG("%s.preventExtensions()", ReceiverObj(objId));
return ok(rs);
}
@ -99,6 +102,8 @@ WrapperAnswer::AnswerGetPropertyDescriptor(const ObjectId &objId, const nsString
JSAutoCompartment comp(cx, obj);
LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), id);
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -131,6 +136,8 @@ WrapperAnswer::AnswerGetOwnPropertyDescriptor(const ObjectId &objId, const nsStr
JSAutoCompartment comp(cx, obj);
LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), id);
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -161,6 +168,8 @@ WrapperAnswer::AnswerDefineProperty(const ObjectId &objId, const nsString &id,
JSAutoCompartment comp(cx, obj);
LOG("define %s[%s]", ReceiverObj(objId), id);
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -199,6 +208,8 @@ WrapperAnswer::AnswerDelete(const ObjectId &objId, const nsString &id, ReturnSta
JSAutoCompartment comp(cx, obj);
LOG("delete %s[%s]", ReceiverObj(objId), id);
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -223,6 +234,8 @@ WrapperAnswer::AnswerHas(const ObjectId &objId, const nsString &id, ReturnStatus
JSAutoCompartment comp(cx, obj);
LOG("%s.has(%s)", ReceiverObj(objId), id);
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -249,6 +262,8 @@ WrapperAnswer::AnswerHasOwn(const ObjectId &objId, const nsString &id, ReturnSta
JSAutoCompartment comp(cx, obj);
LOG("%s.hasOwn(%s)", ReceiverObj(objId), id);
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -293,6 +308,8 @@ WrapperAnswer::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, cons
if (!toVariant(cx, val, result))
return fail(cx, rs);
LOG("get %s.%s = %s", ReceiverObj(objId), id, OutVariant(*result));
return ok(rs);
}
@ -318,6 +335,8 @@ WrapperAnswer::AnswerSet(const ObjectId &objId, const ObjectId &receiverId, cons
JSAutoCompartment comp(cx, obj);
LOG("set %s[%s] = %s", ReceiverObj(objId), id, InVariant(value));
RootedId internedId(cx);
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
@ -351,6 +370,8 @@ WrapperAnswer::AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool
JSAutoCompartment comp(cx, obj);
LOG("%s.isExtensible()", ReceiverObj(objId));
bool extensible;
if (!JS_IsExtensible(cx, obj, &extensible))
return fail(cx, rs);
@ -453,6 +474,8 @@ WrapperAnswer::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
outparams->ReplaceElementAt(i, JSParam(variant));
}
LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
return ok(rs);
}
@ -472,6 +495,8 @@ WrapperAnswer::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classV
JSAutoCompartment comp(cx, obj);
LOG("%s.objectClassIs()", ReceiverObj(objId));
*result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
return true;
}
@ -490,6 +515,8 @@ WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
JSAutoCompartment comp(cx, obj);
LOG("%s.className()", ReceiverObj(objId));
*name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
return true;
}
@ -507,6 +534,8 @@ WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &fla
JSAutoCompartment comp(cx, obj);
LOG("%s.getPropertyNames()", ReceiverObj(objId));
AutoIdVector props(cx);
if (!js::GetPropertyNames(cx, obj, flags, &props))
return fail(cx, rs);
@ -537,6 +566,8 @@ WrapperAnswer::AnswerInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnS
JSAutoCompartment comp(cx, obj);
LOG("%s.instanceOf()", ReceiverObj(objId));
nsID nsiid;
ConvertID(iid, &nsiid);
@ -563,6 +594,8 @@ WrapperAnswer::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID
JSAutoCompartment comp(cx, obj);
LOG("%s.domInstanceOf()", ReceiverObj(objId));
bool tmp;
if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
return fail(cx, rs);

View File

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WrapperOwner.h"
#include "JavaScriptLogging.h"
#include "mozilla/unused.h"
#include "mozilla/dom/BindingUtils.h"
#include "jsfriendapi.h"
@ -111,6 +112,8 @@ WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy)
if (!CallPreventExtensions(objId, &status))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
}
@ -135,6 +138,9 @@ WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId
PPropertyDescriptor result;
if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
@ -162,6 +168,9 @@ WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, Handle
PPropertyDescriptor result;
if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
@ -193,6 +202,8 @@ WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
if (!CallDefineProperty(objId, idstr, descriptor, &status))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
}
@ -227,6 +238,8 @@ WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
if (!CallDelete(objId, idstr, &status, bp))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
}
@ -261,6 +274,8 @@ WrapperOwner::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
if (!CallHas(objId, idstr, &status, bp))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
}
@ -283,6 +298,8 @@ WrapperOwner::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
if (!CallHasOwn(objId, idstr, &status, bp))
return ipcfail(cx);
LOG_STACK();
return !!ok(cx, status);
}
@ -309,6 +326,8 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
if (!CallGet(objId, receiverId, idstr, &status, &val))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
@ -342,6 +361,8 @@ WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiv
if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
@ -375,6 +396,8 @@ WrapperOwner::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
if (!CallIsExtensible(objId, &status, extensible))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
}
@ -424,6 +447,9 @@ WrapperOwner::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
InfallibleTArray<JSParam> outparams;
if (!CallCall(objId, vals, &status, &result, &outparams))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
@ -470,6 +496,8 @@ WrapperOwner::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue
if (!CallObjectClassIs(objId, classValue, &result))
return false;
LOG_STACK();
return result;
}
@ -491,6 +519,8 @@ WrapperOwner::className(JSContext *cx, HandleObject proxy)
if (!CallClassName(objId, &name))
return "<error>";
LOG_STACK();
return ToNewCString(name);
}
@ -529,6 +559,9 @@ WrapperOwner::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags
InfallibleTArray<nsString> names;
if (!CallGetPropertyNames(objId, flags, &status, &names))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
@ -597,6 +630,8 @@ WrapperOwner::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int d
if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
}