import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

188
xpcom/build/BinaryPath.h Normal file
View file

@ -0,0 +1,188 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_BinaryPath_h
#define mozilla_BinaryPath_h
#include "nsXPCOMPrivate.h" // for MAXPATHLEN
#ifdef XP_WIN
#include <windows.h>
#elif defined(XP_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#elif defined(XP_UNIX)
#include <sys/stat.h>
#include <string.h>
#endif
namespace mozilla {
class BinaryPath
{
public:
#ifdef XP_WIN
static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
{
wchar_t wide_path[MAXPATHLEN];
nsresult rv = GetW(argv0, wide_path);
if (NS_FAILED(rv)) {
return rv;
}
WideCharToMultiByte(CP_UTF8, 0, wide_path, -1,
aResult, MAXPATHLEN, nullptr, nullptr);
return NS_OK;
}
private:
static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN])
{
if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) {
return NS_OK;
}
return NS_ERROR_FAILURE;
}
#elif defined(XP_MACOSX)
static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
{
// Works even if we're not bundled.
CFBundleRef appBundle = CFBundleGetMainBundle();
if (!appBundle) {
return NS_ERROR_FAILURE;
}
CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
if (!executableURL) {
return NS_ERROR_FAILURE;
}
nsresult rv;
if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8*)aResult,
MAXPATHLEN)) {
// Sanitize path in case the app was launched from Terminal via
// './firefox' for example.
size_t readPos = 0;
size_t writePos = 0;
while (aResult[readPos] != '\0') {
if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') {
readPos += 2;
} else {
aResult[writePos] = aResult[readPos];
readPos++;
writePos++;
}
}
aResult[writePos] = '\0';
rv = NS_OK;
} else {
rv = NS_ERROR_FAILURE;
}
CFRelease(executableURL);
return rv;
}
#elif defined(ANDROID)
static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
{
// On Android, we use the GRE_HOME variable that is set by the Java
// bootstrap code.
const char* greHome = getenv("GRE_HOME");
#if defined(MOZ_WIDGET_GONK)
if (!greHome) {
greHome = "/system/b2g";
}
#endif
if (!greHome) {
return NS_ERROR_FAILURE;
}
snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy");
aResult[MAXPATHLEN - 1] = '\0';
return NS_OK;
}
#elif defined(XP_UNIX)
static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN])
{
struct stat fileStat;
// on unix, there is no official way to get the path of the current binary.
// instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
// multiple applications, we will try a series of techniques:
//
// 1) use realpath() on argv[0], which works unless we're loaded from the
// PATH. Only do so if argv[0] looks like a path (contains a /).
// 2) manually walk through the PATH and look for ourself
// 3) give up
if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) &&
stat(aResult, &fileStat) == 0) {
return NS_OK;
}
const char* path = getenv("PATH");
if (!path) {
return NS_ERROR_FAILURE;
}
char* pathdup = strdup(path);
if (!pathdup) {
return NS_ERROR_OUT_OF_MEMORY;
}
bool found = false;
char* token = strtok(pathdup, ":");
while (token) {
char tmpPath[MAXPATHLEN];
sprintf(tmpPath, "%s/%s", token, aArgv0);
if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) {
found = true;
break;
}
token = strtok(nullptr, ":");
}
free(pathdup);
if (found) {
return NS_OK;
}
return NS_ERROR_FAILURE;
}
#else
#error Oops, you need platform-specific code here
#endif
public:
static nsresult GetFile(const char* aArgv0, nsIFile** aResult)
{
nsCOMPtr<nsIFile> lf;
#ifdef XP_WIN
wchar_t exePath[MAXPATHLEN];
nsresult rv = GetW(aArgv0, exePath);
#else
char exePath[MAXPATHLEN];
nsresult rv = Get(aArgv0, exePath);
#endif
if (NS_FAILED(rv)) {
return rv;
}
#ifdef XP_WIN
rv = NS_NewLocalFile(nsDependentString(exePath), true,
getter_AddRefs(lf));
#else
rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true,
getter_AddRefs(lf));
#endif
if (NS_FAILED(rv)) {
return rv;
}
NS_ADDREF(*aResult = lf);
return NS_OK;
}
};
} // namespace mozilla
#endif /* mozilla_BinaryPath_h */

View file

@ -0,0 +1,224 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "FileLocation.h"
#include "nsZipArchive.h"
#include "nsURLHelper.h"
namespace mozilla {
FileLocation::FileLocation()
{
}
FileLocation::~FileLocation()
{
}
FileLocation::FileLocation(nsIFile* aFile)
{
Init(aFile);
}
FileLocation::FileLocation(nsIFile* aFile, const char* aPath)
{
Init(aFile, aPath);
}
FileLocation::FileLocation(const FileLocation& aFile, const char* aPath)
{
if (aFile.IsZip()) {
if (aFile.mBaseFile) {
Init(aFile.mBaseFile, aFile.mPath.get());
}
else {
Init(aFile.mBaseZip, aFile.mPath.get());
}
if (aPath) {
int32_t i = mPath.RFindChar('/');
if (kNotFound == i) {
mPath.Truncate(0);
} else {
mPath.Truncate(i + 1);
}
mPath += aPath;
}
} else {
if (aPath) {
nsCOMPtr<nsIFile> cfile;
aFile.mBaseFile->GetParent(getter_AddRefs(cfile));
#if defined(XP_WIN)
nsAutoCString pathStr(aPath);
char* p;
uint32_t len = pathStr.GetMutableData(&p);
for (; len; ++p, --len) {
if ('/' == *p) {
*p = '\\';
}
}
cfile->AppendRelativeNativePath(pathStr);
#else
cfile->AppendRelativeNativePath(nsDependentCString(aPath));
#endif
Init(cfile);
} else {
Init(aFile.mBaseFile);
}
}
}
void
FileLocation::Init(nsIFile* aFile)
{
mBaseZip = nullptr;
mBaseFile = aFile;
mPath.Truncate();
}
void
FileLocation::Init(nsIFile* aFile, const char* aPath)
{
mBaseZip = nullptr;
mBaseFile = aFile;
mPath = aPath;
}
void
FileLocation::Init(nsZipArchive* aZip, const char* aPath)
{
mBaseZip = aZip;
mBaseFile = nullptr;
mPath = aPath;
}
void
FileLocation::GetURIString(nsACString& aResult) const
{
if (mBaseFile) {
net_GetURLSpecFromActualFile(mBaseFile, aResult);
} else if (mBaseZip) {
RefPtr<nsZipHandle> handler = mBaseZip->GetFD();
handler->mFile.GetURIString(aResult);
}
if (IsZip()) {
aResult.Insert("jar:", 0);
aResult += "!/";
aResult += mPath;
}
}
already_AddRefed<nsIFile>
FileLocation::GetBaseFile()
{
if (IsZip() && mBaseZip) {
RefPtr<nsZipHandle> handler = mBaseZip->GetFD();
if (handler) {
return handler->mFile.GetBaseFile();
}
return nullptr;
}
nsCOMPtr<nsIFile> file = mBaseFile;
return file.forget();
}
bool
FileLocation::Equals(const FileLocation& aFile) const
{
if (mPath != aFile.mPath) {
return false;
}
if (mBaseFile && aFile.mBaseFile) {
bool eq;
return NS_SUCCEEDED(mBaseFile->Equals(aFile.mBaseFile, &eq)) && eq;
}
const FileLocation* a = this;
const FileLocation* b = &aFile;
if (a->mBaseZip) {
RefPtr<nsZipHandle> handler = a->mBaseZip->GetFD();
a = &handler->mFile;
}
if (b->mBaseZip) {
RefPtr<nsZipHandle> handler = b->mBaseZip->GetFD();
b = &handler->mFile;
}
return a->Equals(*b);
}
nsresult
FileLocation::GetData(Data& aData)
{
if (!IsZip()) {
return mBaseFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &aData.mFd.rwget());
}
aData.mZip = mBaseZip;
if (!aData.mZip) {
aData.mZip = new nsZipArchive();
aData.mZip->OpenArchive(mBaseFile);
}
aData.mItem = aData.mZip->GetItem(mPath.get());
if (aData.mItem) {
return NS_OK;
}
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
}
nsresult
FileLocation::Data::GetSize(uint32_t* aResult)
{
if (mFd) {
PRFileInfo64 fileInfo;
if (PR_SUCCESS != PR_GetOpenFileInfo64(mFd, &fileInfo)) {
return NS_ErrorAccordingToNSPR();
}
if (fileInfo.size > int64_t(UINT32_MAX)) {
return NS_ERROR_FILE_TOO_BIG;
}
*aResult = fileInfo.size;
return NS_OK;
}
else if (mItem) {
*aResult = mItem->RealSize();
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
nsresult
FileLocation::Data::Copy(char* aBuf, uint32_t aLen)
{
if (mFd) {
for (uint32_t totalRead = 0; totalRead < aLen;) {
int32_t read = PR_Read(mFd, aBuf + totalRead,
XPCOM_MIN(aLen - totalRead, uint32_t(INT32_MAX)));
if (read < 0) {
return NS_ErrorAccordingToNSPR();
}
totalRead += read;
}
return NS_OK;
}
else if (mItem) {
nsZipCursor cursor(mItem, mZip, reinterpret_cast<uint8_t*>(aBuf),
aLen, true);
uint32_t readLen;
cursor.Copy(&readLen);
if (readLen != aLen) {
nsZipArchive::sFileCorruptedReason = "FileLocation::Data: insufficient data";
return NS_ERROR_FILE_CORRUPTED;
}
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
} /* namespace mozilla */

134
xpcom/build/FileLocation.h Normal file
View file

@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_FileLocation_h
#define mozilla_FileLocation_h
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIFile.h"
#include "FileUtils.h"
class nsZipArchive;
class nsZipItem;
namespace mozilla {
class FileLocation
{
public:
/**
* FileLocation is an helper to handle different kind of file locations
* within Gecko:
* - on filesystems
* - in archives
* - in archives within archives
* As such, it stores a path within an archive, as well as the archive
* path itself, or the complete file path alone when on a filesystem.
* When the archive is in an archive, an nsZipArchive is stored instead
* of a file path.
*/
FileLocation();
~FileLocation();
/**
* Constructor for plain files
*/
explicit FileLocation(nsIFile* aFile);
/**
* Constructors for path within an archive. The archive can be given either
* as nsIFile or nsZipArchive.
*/
FileLocation(nsIFile* aZip, const char* aPath);
FileLocation(nsZipArchive* aZip, const char* aPath);
/**
* Creates a new file location relative to another one.
*/
FileLocation(const FileLocation& aFile, const char* aPath = nullptr);
/**
* Initialization functions corresponding to constructors
*/
void Init(nsIFile* aFile);
void Init(nsIFile* aZip, const char* aPath);
void Init(nsZipArchive* aZip, const char* aPath);
/**
* Returns an URI string corresponding to the file location
*/
void GetURIString(nsACString& aResult) const;
/**
* Returns the base file of the location, where base file is defined as:
* - The file itself when the location is on a filesystem
* - The archive file when the location is in an archive
* - The outer archive file when the location is in an archive in an archive
*/
already_AddRefed<nsIFile> GetBaseFile();
/**
* Returns whether the "base file" (see GetBaseFile) is an archive
*/
bool IsZip() const { return !mPath.IsEmpty(); }
/**
* Returns the path within the archive, when within an archive
*/
void GetPath(nsACString& aResult) const { aResult = mPath; }
/**
* Boolean value corresponding to whether the file location is initialized
* or not.
*/
explicit operator bool() const { return mBaseFile || mBaseZip; }
/**
* Returns whether another FileLocation points to the same resource
*/
bool Equals(const FileLocation& aFile) const;
/**
* Data associated with a FileLocation.
*/
class Data
{
public:
/**
* Returns the data size
*/
nsresult GetSize(uint32_t* aResult);
/**
* Copies the data in the given buffer
*/
nsresult Copy(char* aBuf, uint32_t aLen);
protected:
friend class FileLocation;
nsZipItem* mItem;
RefPtr<nsZipArchive> mZip;
mozilla::AutoFDClose mFd;
};
/**
* Returns the data associated with the resource pointed at by the file
* location.
*/
nsresult GetData(Data& aData);
private:
nsCOMPtr<nsIFile> mBaseFile;
RefPtr<nsZipArchive> mBaseZip;
nsCString mPath;
}; /* class FileLocation */
} /* namespace mozilla */
#endif /* mozilla_FileLocation_h */

View file

@ -0,0 +1,138 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "nsXPCOM.h"
#include "nsXPCOMPrivate.h"
#include "nsXPCOMStrings.h"
#include "xptcall.h"
#include <string.h>
/**
* Private Method to register an exit routine. This method
* used to allow you to setup a callback that will be called from
* the NS_ShutdownXPCOM function after all services and
* components have gone away. It was fatally flawed in that the component
* DLL could be released before the exit function was called; it is now a
* stub implementation that does nothing.
*/
XPCOM_API(nsresult)
NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine aExitRoutine, uint32_t aPriority);
XPCOM_API(nsresult)
NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine aExitRoutine);
static const XPCOMFunctions kFrozenFunctions = {
XPCOM_GLUE_VERSION,
sizeof(XPCOMFunctions),
&NS_InitXPCOM2,
&NS_ShutdownXPCOM,
&NS_GetServiceManager,
&NS_GetComponentManager,
&NS_GetComponentRegistrar,
&NS_GetMemoryManager,
&NS_NewLocalFile,
&NS_NewNativeLocalFile,
&NS_RegisterXPCOMExitRoutine,
&NS_UnregisterXPCOMExitRoutine,
// these functions were added post 1.4
&NS_GetDebug,
nullptr,
// these functions were added post 1.6
&NS_StringContainerInit,
&NS_StringContainerFinish,
&NS_StringGetData,
&NS_StringSetData,
&NS_StringSetDataRange,
&NS_StringCopy,
&NS_CStringContainerInit,
&NS_CStringContainerFinish,
&NS_CStringGetData,
&NS_CStringSetData,
&NS_CStringSetDataRange,
&NS_CStringCopy,
&NS_CStringToUTF16,
&NS_UTF16ToCString,
&NS_StringCloneData,
&NS_CStringCloneData,
// these functions were added post 1.7 (post Firefox 1.0)
&moz_xmalloc,
&moz_xrealloc,
&free,
&NS_StringContainerInit2,
&NS_CStringContainerInit2,
&NS_StringGetMutableData,
&NS_CStringGetMutableData,
nullptr,
// these functions were added post 1.8
&NS_DebugBreak,
&NS_LogInit,
&NS_LogTerm,
&NS_LogAddRef,
&NS_LogRelease,
&NS_LogCtor,
&NS_LogDtor,
&NS_LogCOMPtrAddRef,
&NS_LogCOMPtrRelease,
&NS_GetXPTCallStub,
&NS_DestroyXPTCallStub,
&NS_InvokeByIndex,
nullptr,
nullptr,
&NS_StringSetIsVoid,
&NS_StringGetIsVoid,
&NS_CStringSetIsVoid,
&NS_CStringGetIsVoid,
// these functions were added post 1.9, but then made obsolete
nullptr,
nullptr,
&NS_CycleCollectorSuspect3,
};
EXPORT_XPCOM_API(nsresult)
NS_GetFrozenFunctions(XPCOMFunctions* aFunctions, const char* /* aLibraryPath */)
{
if (!aFunctions) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (aFunctions->version != XPCOM_GLUE_VERSION) {
return NS_ERROR_FAILURE;
}
uint32_t size = aFunctions->size;
if (size > sizeof(XPCOMFunctions)) {
size = sizeof(XPCOMFunctions);
}
size -= offsetof(XPCOMFunctions, init);
memcpy(&aFunctions->init, &kFrozenFunctions.init, size);
return NS_OK;
}
/*
* Stubs for nsXPCOMPrivate.h
*/
EXPORT_XPCOM_API(nsresult)
NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine aExitRoutine, uint32_t aPriority)
{
return NS_OK;
}
EXPORT_XPCOM_API(nsresult)
NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine aExitRoutine)
{
return NS_OK;
}

View file

@ -0,0 +1,582 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include <algorithm>
#include <vector>
#include "IOInterposer.h"
#include "IOInterposerPrivate.h"
#include "MainThreadIOLogger.h"
#include "mozilla/Atomics.h"
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/ThreadLocal.h"
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
#if !defined(XP_WIN)
#include "NSPRInterposer.h"
#endif // !defined(XP_WIN)
#include "nsXULAppAPI.h"
#include "PoisonIOInterposer.h"
using namespace mozilla;
namespace {
/** Find if a vector contains a specific element */
template<class T>
bool
VectorContains(const std::vector<T>& aVector, const T& aElement)
{
return std::find(aVector.begin(), aVector.end(), aElement) != aVector.end();
}
/** Remove element from a vector */
template<class T>
void
VectorRemove(std::vector<T>& aVector, const T& aElement)
{
typename std::vector<T>::iterator newEnd =
std::remove(aVector.begin(), aVector.end(), aElement);
aVector.erase(newEnd, aVector.end());
}
/** Lists of Observers */
struct ObserverLists
{
private:
~ObserverLists() {}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ObserverLists)
ObserverLists() {}
ObserverLists(ObserverLists const& aOther)
: mCreateObservers(aOther.mCreateObservers)
, mReadObservers(aOther.mReadObservers)
, mWriteObservers(aOther.mWriteObservers)
, mFSyncObservers(aOther.mFSyncObservers)
, mStatObservers(aOther.mStatObservers)
, mCloseObservers(aOther.mCloseObservers)
, mStageObservers(aOther.mStageObservers)
{
}
// Lists of observers for I/O events.
// These are implemented as vectors since they are allowed to survive gecko,
// without reporting leaks. This is necessary for the IOInterposer to be used
// for late-write checks.
std::vector<IOInterposeObserver*> mCreateObservers;
std::vector<IOInterposeObserver*> mReadObservers;
std::vector<IOInterposeObserver*> mWriteObservers;
std::vector<IOInterposeObserver*> mFSyncObservers;
std::vector<IOInterposeObserver*> mStatObservers;
std::vector<IOInterposeObserver*> mCloseObservers;
std::vector<IOInterposeObserver*> mStageObservers;
};
class PerThreadData
{
public:
explicit PerThreadData(bool aIsMainThread = false)
: mIsMainThread(aIsMainThread)
, mIsHandlingObservation(false)
, mCurrentGeneration(0)
{
MOZ_COUNT_CTOR(PerThreadData);
}
~PerThreadData()
{
MOZ_COUNT_DTOR(PerThreadData);
}
void CallObservers(IOInterposeObserver::Observation& aObservation)
{
// Prevent recursive reporting.
if (mIsHandlingObservation) {
return;
}
mIsHandlingObservation = true;
// Decide which list of observers to inform
std::vector<IOInterposeObserver*>* observers = nullptr;
switch (aObservation.ObservedOperation()) {
case IOInterposeObserver::OpCreateOrOpen:
observers = &mObserverLists->mCreateObservers;
break;
case IOInterposeObserver::OpRead:
observers = &mObserverLists->mReadObservers;
break;
case IOInterposeObserver::OpWrite:
observers = &mObserverLists->mWriteObservers;
break;
case IOInterposeObserver::OpFSync:
observers = &mObserverLists->mFSyncObservers;
break;
case IOInterposeObserver::OpStat:
observers = &mObserverLists->mStatObservers;
break;
case IOInterposeObserver::OpClose:
observers = &mObserverLists->mCloseObservers;
break;
case IOInterposeObserver::OpNextStage:
observers = &mObserverLists->mStageObservers;
break;
default: {
// Invalid IO operation, see documentation comment for
// IOInterposer::Report()
MOZ_ASSERT(false);
// Just ignore it in non-debug builds.
return;
}
}
MOZ_ASSERT(observers);
// Inform observers
for (auto i = observers->begin(), e = observers->end(); i != e; ++i) {
(*i)->Observe(aObservation);
}
mIsHandlingObservation = false;
}
inline uint32_t GetCurrentGeneration() const { return mCurrentGeneration; }
inline bool IsMainThread() const { return mIsMainThread; }
inline void SetObserverLists(uint32_t aNewGeneration,
RefPtr<ObserverLists>& aNewLists)
{
mCurrentGeneration = aNewGeneration;
mObserverLists = aNewLists;
}
inline void ClearObserverLists()
{
if (mObserverLists) {
mCurrentGeneration = 0;
mObserverLists = nullptr;
}
}
private:
bool mIsMainThread;
bool mIsHandlingObservation;
uint32_t mCurrentGeneration;
RefPtr<ObserverLists> mObserverLists;
};
class MasterList
{
public:
MasterList()
: mObservedOperations(IOInterposeObserver::OpNone)
, mIsEnabled(true)
{
MOZ_COUNT_CTOR(MasterList);
}
~MasterList()
{
MOZ_COUNT_DTOR(MasterList);
}
inline void Disable() { mIsEnabled = false; }
inline void Enable() { mIsEnabled = true; }
void Register(IOInterposeObserver::Operation aOp,
IOInterposeObserver* aObserver)
{
IOInterposer::AutoLock lock(mLock);
ObserverLists* newLists = nullptr;
if (mObserverLists) {
newLists = new ObserverLists(*mObserverLists);
} else {
newLists = new ObserverLists();
}
// You can register to observe multiple types of observations
// but you'll never be registered twice for the same observations.
if (aOp & IOInterposeObserver::OpCreateOrOpen &&
!VectorContains(newLists->mCreateObservers, aObserver)) {
newLists->mCreateObservers.push_back(aObserver);
}
if (aOp & IOInterposeObserver::OpRead &&
!VectorContains(newLists->mReadObservers, aObserver)) {
newLists->mReadObservers.push_back(aObserver);
}
if (aOp & IOInterposeObserver::OpWrite &&
!VectorContains(newLists->mWriteObservers, aObserver)) {
newLists->mWriteObservers.push_back(aObserver);
}
if (aOp & IOInterposeObserver::OpFSync &&
!VectorContains(newLists->mFSyncObservers, aObserver)) {
newLists->mFSyncObservers.push_back(aObserver);
}
if (aOp & IOInterposeObserver::OpStat &&
!VectorContains(newLists->mStatObservers, aObserver)) {
newLists->mStatObservers.push_back(aObserver);
}
if (aOp & IOInterposeObserver::OpClose &&
!VectorContains(newLists->mCloseObservers, aObserver)) {
newLists->mCloseObservers.push_back(aObserver);
}
if (aOp & IOInterposeObserver::OpNextStage &&
!VectorContains(newLists->mStageObservers, aObserver)) {
newLists->mStageObservers.push_back(aObserver);
}
mObserverLists = newLists;
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations | aOp);
mCurrentGeneration++;
}
void Unregister(IOInterposeObserver::Operation aOp,
IOInterposeObserver* aObserver)
{
IOInterposer::AutoLock lock(mLock);
ObserverLists* newLists = nullptr;
if (mObserverLists) {
newLists = new ObserverLists(*mObserverLists);
} else {
newLists = new ObserverLists();
}
if (aOp & IOInterposeObserver::OpCreateOrOpen) {
VectorRemove(newLists->mCreateObservers, aObserver);
if (newLists->mCreateObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpCreateOrOpen);
}
}
if (aOp & IOInterposeObserver::OpRead) {
VectorRemove(newLists->mReadObservers, aObserver);
if (newLists->mReadObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpRead);
}
}
if (aOp & IOInterposeObserver::OpWrite) {
VectorRemove(newLists->mWriteObservers, aObserver);
if (newLists->mWriteObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpWrite);
}
}
if (aOp & IOInterposeObserver::OpFSync) {
VectorRemove(newLists->mFSyncObservers, aObserver);
if (newLists->mFSyncObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpFSync);
}
}
if (aOp & IOInterposeObserver::OpStat) {
VectorRemove(newLists->mStatObservers, aObserver);
if (newLists->mStatObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpStat);
}
}
if (aOp & IOInterposeObserver::OpClose) {
VectorRemove(newLists->mCloseObservers, aObserver);
if (newLists->mCloseObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpClose);
}
}
if (aOp & IOInterposeObserver::OpNextStage) {
VectorRemove(newLists->mStageObservers, aObserver);
if (newLists->mStageObservers.empty()) {
mObservedOperations =
(IOInterposeObserver::Operation)(mObservedOperations &
~IOInterposeObserver::OpNextStage);
}
}
mObserverLists = newLists;
mCurrentGeneration++;
}
void Update(PerThreadData& aPtd)
{
if (mCurrentGeneration == aPtd.GetCurrentGeneration()) {
return;
}
// If the generation counts don't match then we need to update the current
// thread's observer list with the new master list.
IOInterposer::AutoLock lock(mLock);
aPtd.SetObserverLists(mCurrentGeneration, mObserverLists);
}
inline bool IsObservedOperation(IOInterposeObserver::Operation aOp)
{
// The quick reader may observe that no locks are being employed here,
// hence the result of the operations is truly undefined. However, most
// computers will usually return either true or false, which is good enough.
// It is not a problem if we occasionally report more or less IO than is
// actually occurring.
return mIsEnabled && !!(mObservedOperations & aOp);
}
private:
RefPtr<ObserverLists> mObserverLists;
// Note, we cannot use mozilla::Mutex here as the ObserverLists may be leaked
// (We want to monitor IO during shutdown). Furthermore, as we may have to
// unregister observers during shutdown an OffTheBooksMutex is not an option
// either, as its base calls into sDeadlockDetector which may be nullptr
// during shutdown.
IOInterposer::Mutex mLock;
// Flags tracking which operations are being observed
IOInterposeObserver::Operation mObservedOperations;
// Used for quickly disabling everything by IOInterposer::Disable()
Atomic<bool> mIsEnabled;
// Used to inform threads that the master observer list has changed
Atomic<uint32_t> mCurrentGeneration;
};
// Special observation used by IOInterposer::EnteringNextStage()
class NextStageObservation : public IOInterposeObserver::Observation
{
public:
NextStageObservation()
: IOInterposeObserver::Observation(IOInterposeObserver::OpNextStage,
"IOInterposer", false)
{
mStart = TimeStamp::Now();
mEnd = mStart;
}
};
// List of observers registered
static StaticAutoPtr<MasterList> sMasterList;
static MOZ_THREAD_LOCAL(PerThreadData*) sThreadLocalData;
static bool sThreadLocalDataInitialized;
} // namespace
IOInterposeObserver::Observation::Observation(Operation aOperation,
const char* aReference,
bool aShouldReport)
: mOperation(aOperation)
, mReference(aReference)
, mShouldReport(IOInterposer::IsObservedOperation(aOperation) &&
aShouldReport)
{
if (mShouldReport) {
mStart = TimeStamp::Now();
}
}
IOInterposeObserver::Observation::Observation(Operation aOperation,
const TimeStamp& aStart,
const TimeStamp& aEnd,
const char* aReference)
: mOperation(aOperation)
, mStart(aStart)
, mEnd(aEnd)
, mReference(aReference)
, mShouldReport(false)
{
}
const char*
IOInterposeObserver::Observation::ObservedOperationString() const
{
switch (mOperation) {
case OpCreateOrOpen:
return "create/open";
case OpRead:
return "read";
case OpWrite:
return "write";
case OpFSync:
return "fsync";
case OpStat:
return "stat";
case OpClose:
return "close";
case OpNextStage:
return "NextStage";
default:
return "unknown";
}
}
void
IOInterposeObserver::Observation::Report()
{
if (mShouldReport) {
mEnd = TimeStamp::Now();
IOInterposer::Report(*this);
}
}
bool
IOInterposer::Init()
{
// Don't initialize twice...
if (sMasterList) {
return true;
}
if (!sThreadLocalData.init()) {
return false;
}
sThreadLocalDataInitialized = true;
bool isMainThread = true;
RegisterCurrentThread(isMainThread);
sMasterList = new MasterList();
MainThreadIOLogger::Init();
// Now we initialize the various interposers depending on platform
InitPoisonIOInterposer();
// We don't hook NSPR on Windows because PoisonIOInterposer captures a
// superset of the former's events.
#if !defined(XP_WIN)
InitNSPRIOInterposing();
#endif
return true;
}
bool
IOInterposeObserver::IsMainThread()
{
if (!sThreadLocalDataInitialized) {
return false;
}
PerThreadData* ptd = sThreadLocalData.get();
if (!ptd) {
return false;
}
return ptd->IsMainThread();
}
void
IOInterposer::Clear()
{
/* Clear() is a no-op on release builds so that we may continue to trap I/O
until process termination. In leak-checking builds, we need to shut down
IOInterposer so that all references are properly released. */
#ifdef NS_FREE_PERMANENT_DATA
UnregisterCurrentThread();
sMasterList = nullptr;
#endif
}
void
IOInterposer::Disable()
{
if (!sMasterList) {
return;
}
sMasterList->Disable();
}
void
IOInterposer::Enable()
{
if (!sMasterList) {
return;
}
sMasterList->Enable();
}
void
IOInterposer::Report(IOInterposeObserver::Observation& aObservation)
{
PerThreadData* ptd = sThreadLocalData.get();
if (!ptd) {
// In this case the current thread is not registered with IOInterposer.
// Alternatively we could take the slow path and just lock everything if
// we're not registered. That could potentially perform poorly, though.
return;
}
if (!sMasterList) {
// If there is no longer a master list then we should clear the local one.
ptd->ClearObserverLists();
return;
}
sMasterList->Update(*ptd);
// Don't try to report if there's nobody listening.
if (!IOInterposer::IsObservedOperation(aObservation.ObservedOperation())) {
return;
}
ptd->CallObservers(aObservation);
}
bool
IOInterposer::IsObservedOperation(IOInterposeObserver::Operation aOp)
{
return sMasterList && sMasterList->IsObservedOperation(aOp);
}
void
IOInterposer::Register(IOInterposeObserver::Operation aOp,
IOInterposeObserver* aObserver)
{
MOZ_ASSERT(aObserver);
if (!sMasterList || !aObserver) {
return;
}
sMasterList->Register(aOp, aObserver);
}
void
IOInterposer::Unregister(IOInterposeObserver::Operation aOp,
IOInterposeObserver* aObserver)
{
if (!sMasterList) {
return;
}
sMasterList->Unregister(aOp, aObserver);
}
void
IOInterposer::RegisterCurrentThread(bool aIsMainThread)
{
if (!sThreadLocalDataInitialized) {
return;
}
MOZ_ASSERT(!sThreadLocalData.get());
PerThreadData* curThreadData = new PerThreadData(aIsMainThread);
sThreadLocalData.set(curThreadData);
}
void
IOInterposer::UnregisterCurrentThread()
{
if (!sThreadLocalDataInitialized) {
return;
}
PerThreadData* curThreadData = sThreadLocalData.get();
MOZ_ASSERT(curThreadData);
sThreadLocalData.set(nullptr);
delete curThreadData;
}
void
IOInterposer::EnteringNextStage()
{
if (!sMasterList) {
return;
}
NextStageObservation observation;
Report(observation);
}

295
xpcom/build/IOInterposer.h Normal file
View file

@ -0,0 +1,295 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_IOInterposer_h
#define mozilla_IOInterposer_h
#include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/TimeStamp.h"
namespace mozilla {
/**
* Interface for I/O interposer observers. This is separate from the
* IOInterposer because we have multiple uses for these observations.
*/
class IOInterposeObserver
{
public:
enum Operation
{
OpNone = 0,
OpCreateOrOpen = (1 << 0),
OpRead = (1 << 1),
OpWrite = (1 << 2),
OpFSync = (1 << 3),
OpStat = (1 << 4),
OpClose = (1 << 5),
OpNextStage = (1 << 6), // Meta - used when leaving startup, entering shutdown
OpWriteFSync = (OpWrite | OpFSync),
OpAll = (OpCreateOrOpen | OpRead | OpWrite | OpFSync | OpStat | OpClose),
OpAllWithStaging = (OpAll | OpNextStage)
};
/** A representation of an I/O observation */
class Observation
{
protected:
/**
* This constructor is for use by subclasses that are intended to take
* timing measurements via RAII. The |aShouldReport| parameter may be
* used to make the measurement and reporting conditional on the
* satisfaction of an arbitrary predicate that was evaluated
* in the subclass. Note that IOInterposer::IsObservedOperation() is
* always ANDed with aShouldReport, so the subclass does not need to
* include a call to that function explicitly.
*/
Observation(Operation aOperation, const char* aReference,
bool aShouldReport = true);
public:
/**
* Since this constructor accepts start and end times, it does *not* take
* its own timings, nor does it report itself.
*/
Observation(Operation aOperation, const TimeStamp& aStart,
const TimeStamp& aEnd, const char* aReference);
/**
* Operation observed, this is one of the individual Operation values.
* Combinations of these flags are only used when registering observers.
*/
Operation ObservedOperation() const { return mOperation; }
/**
* Return the observed operation as a human-readable string.
*/
const char* ObservedOperationString() const;
/** Time at which the I/O operation was started */
TimeStamp Start() const { return mStart; }
/**
* Time at which the I/O operation ended, for asynchronous methods this is
* the time at which the call initiating the asynchronous request returned.
*/
TimeStamp End() const { return mEnd; }
/**
* Duration of the operation, for asynchronous I/O methods this is the
* duration of the call initiating the asynchronous request.
*/
TimeDuration Duration() const { return mEnd - mStart; }
/**
* IO reference, function name or name of component (sqlite) that did IO
* this is in addition the generic operation. This attribute may be platform
* specific, but should only take a finite number of distinct values.
* E.g. sqlite-commit, CreateFile, NtReadFile, fread, fsync, mmap, etc.
* I.e. typically the platform specific function that did the IO.
*/
const char* Reference() const { return mReference; }
/** Request filename associated with the I/O operation, null if unknown */
virtual const char16_t* Filename() { return nullptr; }
virtual ~Observation() {}
protected:
void
Report();
Operation mOperation;
TimeStamp mStart;
TimeStamp mEnd;
const char* mReference; // Identifies the source of the Observation
bool mShouldReport; // Measure and report if true
};
/**
* Invoked whenever an implementation of the IOInterposeObserver should
* observe aObservation. Implement this and do your thing...
* But do consider if it is wise to use IO functions in this method, they are
* likely to cause recursion :)
* At least, see PoisonIOInterposer.h and register your handle as a debug file
* even, if you don't initialize the poison IO interposer, someone else might.
*
* Remark: Observations may occur on any thread.
*/
virtual void Observe(Observation& aObservation) = 0;
virtual ~IOInterposeObserver() {}
protected:
/**
* We don't use NS_IsMainThread() because we need to be able to determine the
* main thread outside of XPCOM Initialization. IOInterposer observers should
* call this function instead.
*/
static bool IsMainThread();
};
/**
* These functions are responsible for ensuring that events are routed to the
* appropriate observers.
*/
namespace IOInterposer {
/**
* This function must be called from the main-thread when no other threads are
* running before any of the other methods on this class may be used.
*
* IO reports can however, safely assume that IsObservedOperation() will
* return false until the IOInterposer is initialized.
*
* Remark, it's safe to call this method multiple times, so just call it when
* you to utilize IO interposing.
*
* Using the IOInterposerInit class is preferred to calling this directly.
*/
bool Init();
/**
* This function must be called from the main thread, and furthermore
* it must be called when no other threads are executing. Effectively
* restricting us to calling it only during shutdown.
*
* Callers should take care that no other consumers are subscribed to events,
* as these events will stop when this function is called.
*
* In practice, we don't use this method as the IOInterposer is used for
* late-write checks.
*/
void Clear();
/**
* This function immediately disables IOInterposer functionality in a fast,
* thread-safe manner. Primarily for use by the crash reporter.
*/
void Disable();
/**
* This function re-enables IOInterposer functionality in a fast, thread-safe
* manner. Primarily for use by the crash reporter.
*/
void Enable();
/**
* Report IO to registered observers.
* Notice that the reported operation must be either OpRead, OpWrite or
* OpFSync. You are not allowed to report an observation with OpWriteFSync or
* OpAll, these are just auxiliary values for use with Register().
*
* If the IO call you're reporting does multiple things, write and fsync, you
* can choose to call Report() twice once with write and once with FSync. You
* may not call Report() with OpWriteFSync! The Observation::mOperation
* attribute is meant to be generic, not perfect.
*
* Notice that there is no reason to report an observation with an operation
* which is not being observed. Use IsObservedOperation() to check if the
* operation you are about to report is being observed. This is especially
* important if you are constructing expensive observations containing
* filename and full-path.
*
* Remark: Init() must be called before any IO is reported. But
* IsObservedOperation() will return false until Init() is called.
*/
void Report(IOInterposeObserver::Observation& aObservation);
/**
* Return whether or not an operation is observed. Reporters should not
* report operations that are not being observed by anybody. This mechanism
* allows us to avoid reporting I/O when no observers are registered.
*/
bool IsObservedOperation(IOInterposeObserver::Operation aOp);
/**
* Register IOInterposeObserver, the observer object will receive all
* observations for the given operation aOp.
*
* Remark: Init() must be called before observers are registered.
*/
void Register(IOInterposeObserver::Operation aOp,
IOInterposeObserver* aObserver);
/**
* Unregister an IOInterposeObserver for a given operation
* Remark: It is always safe to unregister for all operations, even if yoú
* didn't register for them all.
* I.e. IOInterposer::Unregister(IOInterposeObserver::OpAll, aObserver)
*
* Remark: Init() must be called before observers are unregistered.
*/
void Unregister(IOInterposeObserver::Operation aOp,
IOInterposeObserver* aObserver);
/**
* Registers the current thread with the IOInterposer. This must be done to
* ensure that per-thread data is created in an orderly fashion.
* We could have written this to initialize that data lazily, however this
* could have unintended consequences if a thread that is not aware of
* IOInterposer was implicitly registered: its per-thread data would never
* be deleted because it would not know to unregister itself.
*
* @param aIsMainThread true if IOInterposer should treat the current thread
* as the main thread.
*/
void RegisterCurrentThread(bool aIsMainThread = false);
/**
* Unregisters the current thread with the IOInterposer. This is important
* to call when a thread is shutting down because it cleans up data that
* is stored in a TLS slot.
*/
void UnregisterCurrentThread();
/**
* Called to inform observers that the process has transitioned out of the
* startup stage or into the shutdown stage. Main thread only.
*/
void EnteringNextStage();
} // namespace IOInterposer
class IOInterposerInit
{
public:
IOInterposerInit()
{
#if !defined(RELEASE_OR_BETA)
IOInterposer::Init();
#endif
}
~IOInterposerInit()
{
#if !defined(RELEASE_OR_BETA)
IOInterposer::Clear();
#endif
}
};
class MOZ_RAII AutoIOInterposerDisable final
{
public:
explicit AutoIOInterposerDisable(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
IOInterposer::Disable();
}
~AutoIOInterposerDisable()
{
IOInterposer::Enable();
}
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
} // namespace mozilla
#endif // mozilla_IOInterposer_h

View file

@ -0,0 +1,167 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 xpcom_build_IOInterposerPrivate_h
#define xpcom_build_IOInterposerPrivate_h
/* This header file contains declarations for helper classes that are
to be used exclusively by IOInterposer and its observers. This header
file is not to be used by anything else and MUST NOT be exported! */
#include <prcvar.h>
#include <prlock.h>
namespace mozilla {
namespace IOInterposer {
/**
* The following classes are simple wrappers for PRLock and PRCondVar.
* IOInterposer and friends use these instead of Mozilla::Mutex et al because
* of the fact that IOInterposer is permitted to run until the process
* terminates; we can't use anything that plugs into leak checkers or deadlock
* detectors because IOInterposer will outlive those and generate false
* positives.
*/
class Monitor
{
public:
Monitor()
: mLock(PR_NewLock())
, mCondVar(PR_NewCondVar(mLock))
{
}
~Monitor()
{
PR_DestroyCondVar(mCondVar);
mCondVar = nullptr;
PR_DestroyLock(mLock);
mLock = nullptr;
}
void Lock()
{
PR_Lock(mLock);
}
void Unlock()
{
PR_Unlock(mLock);
}
bool Wait(PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT)
{
return PR_WaitCondVar(mCondVar, aTimeout) == PR_SUCCESS;
}
bool Notify()
{
return PR_NotifyCondVar(mCondVar) == PR_SUCCESS;
}
private:
PRLock* mLock;
PRCondVar* mCondVar;
};
class MonitorAutoLock
{
public:
explicit MonitorAutoLock(Monitor& aMonitor)
: mMonitor(aMonitor)
{
mMonitor.Lock();
}
~MonitorAutoLock()
{
mMonitor.Unlock();
}
bool Wait(PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT)
{
return mMonitor.Wait(aTimeout);
}
bool Notify()
{
return mMonitor.Notify();
}
private:
Monitor& mMonitor;
};
class MonitorAutoUnlock
{
public:
explicit MonitorAutoUnlock(Monitor& aMonitor)
: mMonitor(aMonitor)
{
mMonitor.Unlock();
}
~MonitorAutoUnlock()
{
mMonitor.Lock();
}
private:
Monitor& mMonitor;
};
class Mutex
{
public:
Mutex()
: mPRLock(PR_NewLock())
{
}
~Mutex()
{
PR_DestroyLock(mPRLock);
mPRLock = nullptr;
}
void Lock()
{
PR_Lock(mPRLock);
}
void Unlock()
{
PR_Unlock(mPRLock);
}
private:
PRLock* mPRLock;
};
class AutoLock
{
public:
explicit AutoLock(Mutex& aLock)
: mLock(aLock)
{
mLock.Lock();
}
~AutoLock()
{
mLock.Unlock();
}
private:
Mutex& mLock;
};
} // namespace IOInterposer
} // namespace mozilla
#endif // xpcom_build_IOInterposerPrivate_h

View file

@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include <algorithm>
#include "mozilla/IOInterposer.h"
#include "mozilla/PoisonIOInterposer.h"
#include "mozilla/ProcessedStack.h"
#include "mozilla/SHA1.h"
#include "mozilla/Scoped.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsPrintfCString.h"
#include "mozilla/StackWalk.h"
#include "plstr.h"
#include "prio.h"
#ifdef XP_WIN
#define NS_T(str) L ## str
#define NS_SLASH "\\"
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <windows.h>
#else
#define NS_SLASH "/"
#endif
#include "LateWriteChecks.h"
#define OBSERVE_LATE_WRITES
using namespace mozilla;
/*************************** Auxiliary Declarations ***************************/
// This a wrapper over a file descriptor that provides a Printf method and
// computes the sha1 of the data that passes through it.
class SHA1Stream
{
public:
explicit SHA1Stream(FILE* aStream)
: mFile(aStream)
{
MozillaRegisterDebugFILE(mFile);
}
void Printf(const char* aFormat, ...)
{
MOZ_ASSERT(mFile);
va_list list;
va_start(list, aFormat);
nsAutoCString str;
str.AppendPrintf(aFormat, list);
va_end(list);
mSHA1.update(str.get(), str.Length());
fwrite(str.get(), 1, str.Length(), mFile);
}
void Finish(SHA1Sum::Hash& aHash)
{
int fd = fileno(mFile);
fflush(mFile);
MozillaUnRegisterDebugFD(fd);
fclose(mFile);
mSHA1.finish(aHash);
mFile = nullptr;
}
private:
FILE* mFile;
SHA1Sum mSHA1;
};
static void
RecordStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
{
std::vector<uintptr_t>* stack =
static_cast<std::vector<uintptr_t>*>(aClosure);
stack->push_back(reinterpret_cast<uintptr_t>(aPC));
}
/**************************** Late-Write Observer ****************************/
/**
* An implementation of IOInterposeObserver to be registered with IOInterposer.
* This observer logs all writes as late writes.
*/
class LateWriteObserver final : public IOInterposeObserver
{
public:
explicit LateWriteObserver(const char* aProfileDirectory)
: mProfileDirectory(PL_strdup(aProfileDirectory))
{
}
~LateWriteObserver()
{
PL_strfree(mProfileDirectory);
mProfileDirectory = nullptr;
}
void Observe(IOInterposeObserver::Observation& aObservation);
private:
char* mProfileDirectory;
};
void
LateWriteObserver::Observe(IOInterposeObserver::Observation& aOb)
{
#ifdef OBSERVE_LATE_WRITES
// Crash if that is the shutdown check mode
if (gShutdownChecks == SCM_CRASH) {
MOZ_CRASH();
}
// If we have shutdown mode SCM_NOTHING or we can't record then abort
if (gShutdownChecks == SCM_NOTHING || !Telemetry::CanRecordExtended()) {
return;
}
// Write the stack and loaded libraries to a file. We can get here
// concurrently from many writes, so we use multiple temporary files.
std::vector<uintptr_t> rawStack;
MozStackWalk(RecordStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
reinterpret_cast<void*>(&rawStack), 0, nullptr);
Telemetry::ProcessedStack stack = Telemetry::GetStackAndModules(rawStack);
nsPrintfCString nameAux("%s%s%s", mProfileDirectory,
NS_SLASH, "Telemetry.LateWriteTmpXXXXXX");
char* name;
nameAux.GetMutableData(&name);
// We want the sha1 of the entire file, so please don't write to fd
// directly; use sha1Stream.
FILE* stream;
#ifdef XP_WIN
HANDLE hFile;
do {
// mkstemp isn't supported so keep trying until we get a file
int result = _mktemp_s(name, strlen(name) + 1);
hFile = CreateFileA(name, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, nullptr);
} while (GetLastError() == ERROR_FILE_EXISTS);
if (hFile == INVALID_HANDLE_VALUE) {
NS_RUNTIMEABORT("Um, how did we get here?");
}
// http://support.microsoft.com/kb/139640
int fd = _open_osfhandle((intptr_t)hFile, _O_APPEND);
if (fd == -1) {
NS_RUNTIMEABORT("Um, how did we get here?");
}
stream = _fdopen(fd, "w");
#else
int fd = mkstemp(name);
stream = fdopen(fd, "w");
#endif
SHA1Stream sha1Stream(stream);
size_t numModules = stack.GetNumModules();
sha1Stream.Printf("%u\n", (unsigned)numModules);
for (size_t i = 0; i < numModules; ++i) {
Telemetry::ProcessedStack::Module module = stack.GetModule(i);
sha1Stream.Printf("%s %s\n", module.mBreakpadId.c_str(),
module.mName.c_str());
}
size_t numFrames = stack.GetStackSize();
sha1Stream.Printf("%u\n", (unsigned)numFrames);
for (size_t i = 0; i < numFrames; ++i) {
const Telemetry::ProcessedStack::Frame& frame = stack.GetFrame(i);
// NOTE: We write the offsets, while the atos tool expects a value with
// the virtual address added. For example, running otool -l on the the firefox
// binary shows
// cmd LC_SEGMENT_64
// cmdsize 632
// segname __TEXT
// vmaddr 0x0000000100000000
// so to print the line matching the offset 123 one has to run
// atos -o firefox 0x100000123.
sha1Stream.Printf("%d %x\n", frame.mModIndex, (unsigned)frame.mOffset);
}
SHA1Sum::Hash sha1;
sha1Stream.Finish(sha1);
// Note: These files should be deleted by telemetry once it reads them. If
// there were no telemetry runs by the time we shut down, we just add files
// to the existing ones instead of replacing them. Given that each of these
// files is a bug to be fixed, that is probably the right thing to do.
// We append the sha1 of the contents to the file name. This provides a simple
// client side deduplication.
nsPrintfCString finalName("%s%s", mProfileDirectory,
"/Telemetry.LateWriteFinal-");
for (int i = 0; i < 20; ++i) {
finalName.AppendPrintf("%02x", sha1[i]);
}
PR_Delete(finalName.get());
PR_Rename(name, finalName.get());
#endif
}
/******************************* Setup/Teardown *******************************/
static StaticAutoPtr<LateWriteObserver> sLateWriteObserver;
namespace mozilla {
void
InitLateWriteChecks()
{
nsCOMPtr<nsIFile> mozFile;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
if (mozFile) {
nsAutoCString nativePath;
nsresult rv = mozFile->GetNativePath(nativePath);
if (NS_SUCCEEDED(rv) && nativePath.get()) {
sLateWriteObserver = new LateWriteObserver(nativePath.get());
}
}
}
void
BeginLateWriteChecks()
{
if (sLateWriteObserver) {
IOInterposer::Register(
IOInterposeObserver::OpWriteFSync,
sLateWriteObserver
);
}
}
void
StopLateWriteChecks()
{
if (sLateWriteObserver) {
IOInterposer::Unregister(
IOInterposeObserver::OpAll,
sLateWriteObserver
);
// Deallocation would not be thread-safe, and StopLateWriteChecks() is
// called at shutdown and only in special cases.
// sLateWriteObserver = nullptr;
}
}
} // namespace mozilla

View file

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_LateWriteChecks_h
#define mozilla_LateWriteChecks_h
// This file, along with LateWriteChecks.cpp, serves to check for and report
// late writes. The idea is discover writes to the file system that happens
// during shutdown such that these maybe be moved forward and the process may be
// killed without waiting for static destructors.
namespace mozilla {
/** Different shutdown check modes */
enum ShutdownChecksMode
{
SCM_CRASH, /** Crash on shutdown check failure */
SCM_RECORD, /** Record shutdown check violations */
SCM_NOTHING /** Don't attempt any shutdown checks */
};
/**
* Current shutdown check mode.
* This variable is defined and initialized in nsAppRunner.cpp
*/
extern ShutdownChecksMode gShutdownChecks;
/**
* Allocate structures and acquire information from XPCOM necessary to do late
* write checks. This function must be invoked before BeginLateWriteChecks()
* and before XPCOM has stopped working.
*/
void InitLateWriteChecks();
/**
* Begin recording all writes as late-writes. This function should be called
* when all legitimate writes have occurred. This function does not rely on
* XPCOM as it is designed to be invoked during XPCOM shutdown.
*
* For late-write checks to work you must initialize one or more backends that
* reports IO through the IOInterposer API. PoisonIOInterposer would probably
* be the backend of choice in this case.
*
* Note: BeginLateWriteChecks() must have been invoked before this function.
*/
void BeginLateWriteChecks();
/**
* Stop recording all writes as late-writes, call this function when you want
* late-write checks to stop. I.e. exception handling, or the special case on
* Mac described in bug 826029.
*/
void StopLateWriteChecks();
} // namespace mozilla
#endif // mozilla_LateWriteChecks_h

View file

@ -0,0 +1,225 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "MainThreadIOLogger.h"
#include "GeckoProfiler.h"
#include "IOInterposerPrivate.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsAutoPtr.h"
#include "nsNativeCharsetUtils.h"
/**
* This code uses NSPR stuff and STL containers because it must be detached
* from leak checking code; this observer runs until the process terminates.
*/
#include <prenv.h>
#include <prprf.h>
#include <prthread.h>
#include <vector>
namespace {
struct ObservationWithStack
{
ObservationWithStack(mozilla::IOInterposeObserver::Observation& aObs,
ProfilerBacktrace* aStack)
: mObservation(aObs)
, mStack(aStack)
{
const char16_t* filename = aObs.Filename();
if (filename) {
mFilename = filename;
}
}
mozilla::IOInterposeObserver::Observation mObservation;
ProfilerBacktrace* mStack;
nsString mFilename;
};
class MainThreadIOLoggerImpl final : public mozilla::IOInterposeObserver
{
public:
MainThreadIOLoggerImpl();
~MainThreadIOLoggerImpl();
bool Init();
void Observe(Observation& aObservation);
private:
static void sIOThreadFunc(void* aArg);
void IOThreadFunc();
TimeStamp mLogStartTime;
const char* mFileName;
PRThread* mIOThread;
IOInterposer::Monitor mMonitor;
bool mShutdownRequired;
std::vector<ObservationWithStack> mObservations;
};
static StaticAutoPtr<MainThreadIOLoggerImpl> sImpl;
MainThreadIOLoggerImpl::MainThreadIOLoggerImpl()
: mFileName(nullptr)
, mIOThread(nullptr)
, mShutdownRequired(false)
{
}
MainThreadIOLoggerImpl::~MainThreadIOLoggerImpl()
{
if (!mIOThread) {
return;
}
{
// Scope for lock
IOInterposer::MonitorAutoLock lock(mMonitor);
mShutdownRequired = true;
lock.Notify();
}
PR_JoinThread(mIOThread);
mIOThread = nullptr;
}
bool
MainThreadIOLoggerImpl::Init()
{
if (mFileName) {
// Already initialized
return true;
}
mFileName = PR_GetEnv("MOZ_MAIN_THREAD_IO_LOG");
if (!mFileName) {
// Can't start
return false;
}
mIOThread = PR_CreateThread(PR_USER_THREAD, &sIOThreadFunc, this,
PR_PRIORITY_LOW, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0);
if (!mIOThread) {
return false;
}
return true;
}
/* static */ void
MainThreadIOLoggerImpl::sIOThreadFunc(void* aArg)
{
PR_SetCurrentThreadName("MainThreadIOLogger");
MainThreadIOLoggerImpl* obj = static_cast<MainThreadIOLoggerImpl*>(aArg);
obj->IOThreadFunc();
}
void
MainThreadIOLoggerImpl::IOThreadFunc()
{
PRFileDesc* fd = PR_Open(mFileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
PR_IRUSR | PR_IWUSR | PR_IRGRP);
if (!fd) {
IOInterposer::MonitorAutoLock lock(mMonitor);
mShutdownRequired = true;
std::vector<ObservationWithStack>().swap(mObservations);
return;
}
mLogStartTime = TimeStamp::Now();
{
// Scope for lock
IOInterposer::MonitorAutoLock lock(mMonitor);
while (true) {
while (!mShutdownRequired && mObservations.empty()) {
lock.Wait();
}
if (mShutdownRequired) {
break;
}
// Pull events off the shared array onto a local one
std::vector<ObservationWithStack> observationsToWrite;
observationsToWrite.swap(mObservations);
// Release the lock so that we're not holding anybody up during I/O
IOInterposer::MonitorAutoUnlock unlock(mMonitor);
// Now write the events.
for (auto i = observationsToWrite.begin(), e = observationsToWrite.end();
i != e; ++i) {
if (i->mObservation.ObservedOperation() == OpNextStage) {
PR_fprintf(fd, "%f,NEXT-STAGE\n",
(TimeStamp::Now() - mLogStartTime).ToMilliseconds());
continue;
}
double durationMs = i->mObservation.Duration().ToMilliseconds();
nsAutoCString nativeFilename;
nativeFilename.AssignLiteral("(not available)");
if (!i->mFilename.IsEmpty()) {
if (NS_FAILED(NS_CopyUnicodeToNative(i->mFilename, nativeFilename))) {
nativeFilename.AssignLiteral("(conversion failed)");
}
}
/**
* Format:
* Start Timestamp (Milliseconds), Operation, Duration (Milliseconds), Event Source, Filename
*/
if (PR_fprintf(fd, "%f,%s,%f,%s,%s\n",
(i->mObservation.Start() - mLogStartTime).ToMilliseconds(),
i->mObservation.ObservedOperationString(), durationMs,
i->mObservation.Reference(), nativeFilename.get()) > 0) {
ProfilerBacktrace* stack = i->mStack;
if (stack) {
// TODO: Write out the callstack
// (This will be added in a later bug)
profiler_free_backtrace(stack);
}
}
}
}
}
PR_Close(fd);
}
void
MainThreadIOLoggerImpl::Observe(Observation& aObservation)
{
if (!mFileName || !IsMainThread()) {
return;
}
IOInterposer::MonitorAutoLock lock(mMonitor);
if (mShutdownRequired) {
// The writer thread isn't running. Don't enqueue any more data.
return;
}
// Passing nullptr as aStack parameter for now
mObservations.push_back(ObservationWithStack(aObservation, nullptr));
lock.Notify();
}
} // namespace
namespace mozilla {
namespace MainThreadIOLogger {
bool
Init()
{
nsAutoPtr<MainThreadIOLoggerImpl> impl(new MainThreadIOLoggerImpl());
if (!impl->Init()) {
return false;
}
sImpl = impl.forget();
IOInterposer::Register(IOInterposeObserver::OpAllWithStaging, sImpl);
return true;
}
} // namespace MainThreadIOLogger
} // namespace mozilla

View file

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_MainThreadIOLogger_h
#define mozilla_MainThreadIOLogger_h
namespace mozilla {
namespace MainThreadIOLogger {
bool Init();
} // namespace MainThreadIOLogger
} // namespace mozilla
#endif // mozilla_MainThreadIOLogger_h

View file

@ -0,0 +1,185 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "IOInterposer.h"
#include "NSPRInterposer.h"
#include "prio.h"
#include "private/pprio.h"
#include "nsDebug.h"
#include "nscore.h"
namespace {
using namespace mozilla;
/* Original IO methods */
PRCloseFN sCloseFn = nullptr;
PRReadFN sReadFn = nullptr;
PRWriteFN sWriteFn = nullptr;
PRFsyncFN sFSyncFn = nullptr;
PRFileInfoFN sFileInfoFn = nullptr;
PRFileInfo64FN sFileInfo64Fn = nullptr;
/**
* RAII class for timing the duration of an NSPR I/O call and reporting the
* result to the IOInterposeObserver API.
*/
class NSPRIOAutoObservation : public IOInterposeObserver::Observation
{
public:
explicit NSPRIOAutoObservation(IOInterposeObserver::Operation aOp)
: IOInterposeObserver::Observation(aOp, "NSPRIOInterposer")
{
}
~NSPRIOAutoObservation()
{
Report();
}
};
PRStatus PR_CALLBACK
interposedClose(PRFileDesc* aFd)
{
// If we don't have a valid original function pointer something is very wrong.
NS_ASSERTION(sCloseFn, "NSPR IO Interposing: sCloseFn is NULL");
NSPRIOAutoObservation timer(IOInterposeObserver::OpClose);
return sCloseFn(aFd);
}
int32_t PR_CALLBACK
interposedRead(PRFileDesc* aFd, void* aBuf, int32_t aAmt)
{
// If we don't have a valid original function pointer something is very wrong.
NS_ASSERTION(sReadFn, "NSPR IO Interposing: sReadFn is NULL");
NSPRIOAutoObservation timer(IOInterposeObserver::OpRead);
return sReadFn(aFd, aBuf, aAmt);
}
int32_t PR_CALLBACK
interposedWrite(PRFileDesc* aFd, const void* aBuf, int32_t aAmt)
{
// If we don't have a valid original function pointer something is very wrong.
NS_ASSERTION(sWriteFn, "NSPR IO Interposing: sWriteFn is NULL");
NSPRIOAutoObservation timer(IOInterposeObserver::OpWrite);
return sWriteFn(aFd, aBuf, aAmt);
}
PRStatus PR_CALLBACK
interposedFSync(PRFileDesc* aFd)
{
// If we don't have a valid original function pointer something is very wrong.
NS_ASSERTION(sFSyncFn, "NSPR IO Interposing: sFSyncFn is NULL");
NSPRIOAutoObservation timer(IOInterposeObserver::OpFSync);
return sFSyncFn(aFd);
}
PRStatus PR_CALLBACK
interposedFileInfo(PRFileDesc* aFd, PRFileInfo* aInfo)
{
// If we don't have a valid original function pointer something is very wrong.
NS_ASSERTION(sFileInfoFn, "NSPR IO Interposing: sFileInfoFn is NULL");
NSPRIOAutoObservation timer(IOInterposeObserver::OpStat);
return sFileInfoFn(aFd, aInfo);
}
PRStatus PR_CALLBACK
interposedFileInfo64(PRFileDesc* aFd, PRFileInfo64* aInfo)
{
// If we don't have a valid original function pointer something is very wrong.
NS_ASSERTION(sFileInfo64Fn, "NSPR IO Interposing: sFileInfo64Fn is NULL");
NSPRIOAutoObservation timer(IOInterposeObserver::OpStat);
return sFileInfo64Fn(aFd, aInfo);
}
} // namespace
namespace mozilla {
void
InitNSPRIOInterposing()
{
// Check that we have not interposed any of the IO methods before
MOZ_ASSERT(!sCloseFn && !sReadFn && !sWriteFn && !sFSyncFn && !sFileInfoFn &&
!sFileInfo64Fn);
// We can't actually use this assertion because we initialize this code
// before XPCOM is initialized, so NS_IsMainThread() always returns false.
// MOZ_ASSERT(NS_IsMainThread());
// Get IO methods from NSPR and const cast the structure so we can modify it.
PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods());
// Something is badly wrong if we don't get IO methods... However, we don't
// want to crash over that in non-debug builds. This is unlikely to happen
// so an assert is enough, no need to report it to the caller.
MOZ_ASSERT(methods);
if (!methods) {
return;
}
// Store original functions
sCloseFn = methods->close;
sReadFn = methods->read;
sWriteFn = methods->write;
sFSyncFn = methods->fsync;
sFileInfoFn = methods->fileInfo;
sFileInfo64Fn = methods->fileInfo64;
// Overwrite with our interposed functions
methods->close = &interposedClose;
methods->read = &interposedRead;
methods->write = &interposedWrite;
methods->fsync = &interposedFSync;
methods->fileInfo = &interposedFileInfo;
methods->fileInfo64 = &interposedFileInfo64;
}
void
ClearNSPRIOInterposing()
{
// If we have already cleared IO interposing, or not initialized it this is
// actually bad.
MOZ_ASSERT(sCloseFn && sReadFn && sWriteFn && sFSyncFn && sFileInfoFn &&
sFileInfo64Fn);
// Get IO methods from NSPR and const cast the structure so we can modify it.
PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods());
// Something is badly wrong if we don't get IO methods... However, we don't
// want to crash over that in non-debug builds. This is unlikely to happen
// so an assert is enough, no need to report it to the caller.
MOZ_ASSERT(methods);
if (!methods) {
return;
}
// Restore original functions
methods->close = sCloseFn;
methods->read = sReadFn;
methods->write = sWriteFn;
methods->fsync = sFSyncFn;
methods->fileInfo = sFileInfoFn;
methods->fileInfo64 = sFileInfo64Fn;
// Forget about original functions
sCloseFn = nullptr;
sReadFn = nullptr;
sWriteFn = nullptr;
sFSyncFn = nullptr;
sFileInfoFn = nullptr;
sFileInfo64Fn = nullptr;
}
} // namespace mozilla

View file

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 NSPRINTERPOSER_H_
#define NSPRINTERPOSER_H_
namespace mozilla {
/**
* Initialize IO interposing for NSPR. This will report NSPR read, writes and
* fsyncs to the IOInterposerObserver. It is only safe to call this from the
* main-thread when no other threads are running.
*/
void InitNSPRIOInterposing();
/**
* Removes interception of NSPR IO methods as setup by InitNSPRIOInterposing.
* Note, that it is only safe to call this on the main-thread when all other
* threads have stopped. Which is typically the case at shutdown.
*/
void ClearNSPRIOInterposing();
} // namespace mozilla
#endif // NSPRINTERPOSER_H_

188
xpcom/build/Omnijar.cpp Normal file
View file

@ -0,0 +1,188 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "Omnijar.h"
#include "nsDirectoryService.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIFile.h"
#include "nsZipArchive.h"
#include "nsNetUtil.h"
namespace mozilla {
StaticRefPtr<nsIFile> Omnijar::sPath[2];
StaticRefPtr<nsZipArchive> Omnijar::sReader[2];
StaticRefPtr<nsZipArchive> Omnijar::sOuterReader[2];
bool Omnijar::sInitialized = false;
bool Omnijar::sIsUnified = false;
static const char* sProp[2] = {
NS_GRE_DIR, NS_XPCOM_CURRENT_PROCESS_DIR
};
#define SPROP(Type) ((Type == mozilla::Omnijar::GRE) ? sProp[GRE] : sProp[APP])
void
Omnijar::CleanUpOne(Type aType)
{
if (sReader[aType]) {
sReader[aType]->CloseArchive();
sReader[aType] = nullptr;
}
if (sOuterReader[aType]) {
sOuterReader[aType]->CloseArchive();
sOuterReader[aType] = nullptr;
}
sPath[aType] = nullptr;
}
void
Omnijar::InitOne(nsIFile* aPath, Type aType)
{
nsCOMPtr<nsIFile> file;
if (aPath) {
file = aPath;
} else {
nsCOMPtr<nsIFile> dir;
nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile),
getter_AddRefs(dir));
NS_NAMED_LITERAL_CSTRING(kOmnijarName, NS_STRINGIFY(OMNIJAR_NAME));
if (NS_FAILED(dir->Clone(getter_AddRefs(file))) ||
NS_FAILED(file->AppendNative(kOmnijarName))) {
return;
}
}
bool isFile;
if (NS_FAILED(file->IsFile(&isFile)) || !isFile) {
// If we're not using an omni.jar for GRE, and we don't have an
// omni.jar for APP, check if both directories are the same.
if ((aType == APP) && (!sPath[GRE])) {
nsCOMPtr<nsIFile> greDir, appDir;
bool equals;
nsDirectoryService::gService->Get(sProp[GRE], NS_GET_IID(nsIFile),
getter_AddRefs(greDir));
nsDirectoryService::gService->Get(sProp[APP], NS_GET_IID(nsIFile),
getter_AddRefs(appDir));
if (NS_SUCCEEDED(greDir->Equals(appDir, &equals)) && equals) {
sIsUnified = true;
}
}
return;
}
bool equals;
if ((aType == APP) && (sPath[GRE]) &&
NS_SUCCEEDED(sPath[GRE]->Equals(file, &equals)) && equals) {
// If we're using omni.jar on both GRE and APP and their path
// is the same, we're in the unified case.
sIsUnified = true;
return;
}
RefPtr<nsZipArchive> zipReader = new nsZipArchive();
if (NS_FAILED(zipReader->OpenArchive(file))) {
return;
}
RefPtr<nsZipArchive> outerReader;
RefPtr<nsZipHandle> handle;
if (NS_SUCCEEDED(nsZipHandle::Init(zipReader, NS_STRINGIFY(OMNIJAR_NAME),
getter_AddRefs(handle)))) {
outerReader = zipReader;
zipReader = new nsZipArchive();
if (NS_FAILED(zipReader->OpenArchive(handle))) {
return;
}
}
CleanUpOne(aType);
sReader[aType] = zipReader;
sOuterReader[aType] = outerReader;
sPath[aType] = file;
}
void
Omnijar::Init(nsIFile* aGrePath, nsIFile* aAppPath)
{
InitOne(aGrePath, GRE);
InitOne(aAppPath, APP);
sInitialized = true;
}
void
Omnijar::CleanUp()
{
CleanUpOne(GRE);
CleanUpOne(APP);
sInitialized = false;
}
already_AddRefed<nsZipArchive>
Omnijar::GetReader(nsIFile* aPath)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
bool equals;
nsresult rv;
if (sPath[GRE]) {
rv = sPath[GRE]->Equals(aPath, &equals);
if (NS_SUCCEEDED(rv) && equals) {
return IsNested(GRE) ? GetOuterReader(GRE) : GetReader(GRE);
}
}
if (sPath[APP]) {
rv = sPath[APP]->Equals(aPath, &equals);
if (NS_SUCCEEDED(rv) && equals) {
return IsNested(APP) ? GetOuterReader(APP) : GetReader(APP);
}
}
return nullptr;
}
nsresult
Omnijar::GetURIString(Type aType, nsACString& aResult)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
aResult.Truncate();
// Return an empty string for APP in the unified case.
if ((aType == APP) && sIsUnified) {
return NS_OK;
}
nsAutoCString omniJarSpec;
if (sPath[aType]) {
nsresult rv = NS_GetURLSpecFromActualFile(sPath[aType], omniJarSpec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aResult = "jar:";
if (IsNested(aType)) {
aResult += "jar:";
}
aResult += omniJarSpec;
aResult += "!";
if (IsNested(aType)) {
aResult += "/" NS_STRINGIFY(OMNIJAR_NAME) "!";
}
} else {
nsCOMPtr<nsIFile> dir;
nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile),
getter_AddRefs(dir));
nsresult rv = NS_GetURLSpecFromActualFile(dir, aResult);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
aResult += "/";
return NS_OK;
}
} /* namespace mozilla */

160
xpcom/build/Omnijar.h Normal file
View file

@ -0,0 +1,160 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_Omnijar_h
#define mozilla_Omnijar_h
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIFile.h"
#include "nsZipArchive.h"
#include "mozilla/StaticPtr.h"
namespace mozilla {
class Omnijar
{
private:
/**
* Store an nsIFile for an omni.jar. We can store two paths here, one
* for GRE (corresponding to resource://gre/) and one for APP
* (corresponding to resource:/// and resource://app/), but only
* store one when both point to the same location (unified).
*/
static StaticRefPtr<nsIFile> sPath[2];
/**
* Cached nsZipArchives for the corresponding sPath
*/
static StaticRefPtr<nsZipArchive> sReader[2];
/**
* Cached nsZipArchives for the outer jar, when using nested jars.
* Otherwise nullptr.
*/
static StaticRefPtr<nsZipArchive> sOuterReader[2];
/**
* Has Omnijar::Init() been called?
*/
static bool sInitialized;
/**
* Is using unified GRE/APP jar?
*/
static bool sIsUnified;
public:
enum Type
{
GRE = 0,
APP = 1
};
private:
/**
* Returns whether we are using nested jars.
*/
static inline bool IsNested(Type aType)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
return !!sOuterReader[aType];
}
/**
* Returns a nsZipArchive pointer for the outer jar file when using nested
* jars. Returns nullptr in the same cases GetPath() would, or if not using
* nested jars.
*/
static inline already_AddRefed<nsZipArchive> GetOuterReader(Type aType)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
RefPtr<nsZipArchive> reader = sOuterReader[aType].get();
return reader.forget();
}
public:
/**
* Returns whether SetBase has been called at least once with
* a valid nsIFile
*/
static inline bool IsInitialized() { return sInitialized; }
/**
* Initializes the Omnijar API with the given directory or file for GRE and
* APP. Each of the paths given can be:
* - a file path, pointing to the omnijar file,
* - a directory path, pointing to a directory containing an "omni.jar" file,
* - nullptr for autodetection of an "omni.jar" file.
*/
static void Init(nsIFile* aGrePath = nullptr, nsIFile* aAppPath = nullptr);
/**
* Cleans up the Omnijar API
*/
static void CleanUp();
/**
* Returns an nsIFile pointing to the omni.jar file for GRE or APP.
* Returns nullptr when there is no corresponding omni.jar.
* Also returns nullptr for APP in the unified case.
*/
static inline already_AddRefed<nsIFile> GetPath(Type aType)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
nsCOMPtr<nsIFile> path = sPath[aType].get();
return path.forget();
}
/**
* Returns whether GRE or APP use an omni.jar. Returns PR_False for
* APP when using an omni.jar in the unified case.
*/
static inline bool HasOmnijar(Type aType)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
return !!sPath[aType];
}
/**
* Returns a nsZipArchive pointer for the omni.jar file for GRE or
* APP. Returns nullptr in the same cases GetPath() would.
*/
static inline already_AddRefed<nsZipArchive> GetReader(Type aType)
{
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
RefPtr<nsZipArchive> reader = sReader[aType].get();
return reader.forget();
}
/**
* Returns a nsZipArchive pointer for the given path IAOI the given
* path is the omni.jar for either GRE or APP.
*/
static already_AddRefed<nsZipArchive> GetReader(nsIFile* aPath);
/**
* Returns the URI string corresponding to the omni.jar or directory
* for GRE or APP. i.e. jar:/path/to/omni.jar!/ for omni.jar and
* /path/to/base/dir/ otherwise. Returns an empty string for APP in
* the unified case.
* The returned URI is guaranteed to end with a slash.
*/
static nsresult GetURIString(Type aType, nsACString& aResult);
private:
/**
* Used internally, respectively by Init() and CleanUp()
*/
static void InitOne(nsIFile* aPath, Type aType);
static void CleanUpOne(Type aType);
}; /* class Omnijar */
} /* namespace mozilla */
#endif /* mozilla_Omnijar_h */

View file

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_PoisonIOInterposer_h
#define mozilla_PoisonIOInterposer_h
#include "mozilla/Types.h"
#include <stdio.h>
MOZ_BEGIN_EXTERN_C
/** Register file handle to be ignored by poisoning IO interposer. This function
* and the corresponding UnRegister function are necessary for exchange of handles
* between binaries not using the same CRT on Windows (which happens when one of
* them links the static CRT). In such cases, giving file descriptors or FILEs
* doesn't work because _get_osfhandle fails with "invalid parameter". */
void MozillaRegisterDebugHandle(intptr_t aHandle);
/** Register file descriptor to be ignored by poisoning IO interposer */
void MozillaRegisterDebugFD(int aFd);
/** Register file to be ignored by poisoning IO interposer */
void MozillaRegisterDebugFILE(FILE* aFile);
/** Unregister file handle from being ignored by poisoning IO interposer */
void MozillaUnRegisterDebugHandle(intptr_t aHandle);
/** Unregister file descriptor from being ignored by poisoning IO interposer */
void MozillaUnRegisterDebugFD(int aFd);
/** Unregister file from being ignored by poisoning IO interposer */
void MozillaUnRegisterDebugFILE(FILE* aFile);
MOZ_END_EXTERN_C
#if defined(XP_WIN) || defined(XP_MACOSX)
#ifdef __cplusplus
namespace mozilla {
/**
* Check if a file is registered as a debug file.
*/
bool IsDebugFile(intptr_t aFileID);
/**
* Initialize IO poisoning, this is only safe to do on the main-thread when no
* other threads are running.
*
* Please, note that this probably has performance implications as all
*/
void InitPoisonIOInterposer();
#ifdef XP_MACOSX
/**
* Check that writes are dirty before reporting I/O (Mac OS X only)
* This is necessary for late-write checks on Mac OS X, but reading the buffer
* from file to see if we're writing dirty bits is expensive, so we don't want
* to do this for everything else that uses
*/
void OnlyReportDirtyWrites();
#endif /* XP_MACOSX */
/**
* Clear IO poisoning, this is only safe to do on the main-thread when no other
* threads are running.
*/
void ClearPoisonIOInterposer();
} // namespace mozilla
#endif /* __cplusplus */
#else /* XP_WIN || XP_MACOSX */
#ifdef __cplusplus
namespace mozilla {
inline bool IsDebugFile(intptr_t aFileID) { return true; }
inline void InitPoisonIOInterposer() {}
inline void ClearPoisonIOInterposer() {}
#ifdef XP_MACOSX
inline void OnlyReportDirtyWrites() {}
#endif /* XP_MACOSX */
} // namespace mozilla
#endif /* __cplusplus */
#endif /* XP_WIN || XP_MACOSX */
#endif // mozilla_PoisonIOInterposer_h

View file

@ -0,0 +1,291 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "mozilla/Mutex.h"
#include "mozilla/Scoped.h"
#include "mozilla/UniquePtr.h"
#include <algorithm>
#include "PoisonIOInterposer.h"
#ifdef MOZ_REPLACE_MALLOC
#include "replace_malloc_bridge.h"
#endif
// Auxiliary method to convert file descriptors to ids
#if defined(XP_WIN32)
#include <io.h>
inline intptr_t
FileDescriptorToHandle(int aFd)
{
return _get_osfhandle(aFd);
}
#else
inline intptr_t
FileDescriptorToHandle(int aFd)
{
return aFd;
}
#endif /* if not XP_WIN32 */
using namespace mozilla;
namespace {
struct DebugFilesAutoLockTraits
{
typedef PRLock* type;
typedef const PRLock* const_type;
static const_type empty() { return nullptr; }
static void release(type aL) { PR_Unlock(aL); }
};
class DebugFilesAutoLock : public Scoped<DebugFilesAutoLockTraits>
{
static PRLock* Lock;
public:
static void Clear();
static PRLock* getDebugFileIDsLock()
{
// On windows this static is not thread safe, but we know that the first
// call is from
// * An early registration of a debug FD or
// * The call to InitWritePoisoning.
// Since the early debug FDs are logs created early in the main thread
// and no writes are trapped before InitWritePoisoning, we are safe.
if (!Lock) {
Lock = PR_NewLock();
}
// We have to use something lower level than a mutex. If we don't, we
// can get recursive in here when called from logging a call to free.
return Lock;
}
DebugFilesAutoLock()
: Scoped<DebugFilesAutoLockTraits>(getDebugFileIDsLock())
{
PR_Lock(get());
}
};
PRLock* DebugFilesAutoLock::Lock;
void
DebugFilesAutoLock::Clear()
{
MOZ_ASSERT(Lock != nullptr);
Lock = nullptr;
}
// The ChunkedList<T> class implements, at the high level, a non-iterable
// list of instances of T. Its goal is to be somehow minimalist for the
// use case of storing the debug files handles here, with the property of
// not requiring a lock to look up whether it contains a specific value.
// It is also chunked in blocks of chunk_size bytes so that its
// initialization doesn't require a memory allocation, while keeping the
// possibility to increase its size as necessary. Note that chunks are
// never deallocated (except in the destructor).
// All operations are essentially O(N) but N is not expected to be large
// enough to matter.
template <typename T, size_t chunk_size=64>
class ChunkedList {
struct ListChunk {
static const size_t kLength = \
(chunk_size - sizeof(ListChunk*)) / sizeof(mozilla::Atomic<T>);
mozilla::Atomic<T> mElements[kLength];
mozilla::UniquePtr<ListChunk> mNext;
ListChunk() : mNext(nullptr) {}
};
ListChunk mList;
mozilla::Atomic<size_t> mLength;
public:
ChunkedList() : mLength(0) {}
~ChunkedList() {
// There can be writes happening after this destructor runs, so keep
// the list contents and don't reset mLength. But if there are more
// elements left than the first chunk can hold, then all hell breaks
// loose for any write that would happen after that because any extra
// chunk would be deallocated, so just crash in that case.
MOZ_RELEASE_ASSERT(mLength <= ListChunk::kLength);
}
// Add an element at the end of the last chunk of the list. Create a new
// chunk if there is not enough room.
// This is not thread-safe with another thread calling Add or Remove.
void Add(T aValue)
{
ListChunk *list = &mList;
size_t position = mLength;
for (; position >= ListChunk::kLength; position -= ListChunk::kLength) {
if (!list->mNext) {
list->mNext.reset(new ListChunk());
}
list = list->mNext.get();
}
// Use an order of operations that ensures any racing Contains call
// can't be hurt.
list->mElements[position] = aValue;
mLength++;
}
// Remove an element from the list by replacing it with the last element
// of the list, and then shrinking the list.
// This is not thread-safe with another thread calling Add or Remove.
void Remove(T aValue)
{
if (!mLength) {
return;
}
ListChunk *list = &mList;
size_t last = mLength - 1;
do {
size_t position = 0;
// Look for an element matching the given value.
for (; position < ListChunk::kLength; position++) {
if (aValue == list->mElements[position]) {
ListChunk *last_list = list;
// Look for the last element in the list, starting from where we are
// instead of starting over.
for (; last >= ListChunk::kLength; last -= ListChunk::kLength) {
last_list = last_list->mNext.get();
}
// Use an order of operations that ensures any racing Contains call
// can't be hurt.
T value = last_list->mElements[last];
list->mElements[position] = value;
mLength--;
return;
}
}
last -= ListChunk::kLength;
list = list->mNext.get();
} while (list);
}
// Returns whether the list contains the given value. It is meant to be safe
// to use without locking, with the tradeoff of being not entirely accurate
// if another thread adds or removes an element while this function runs.
bool Contains(T aValue)
{
ListChunk *list = &mList;
// Fix the range of the lookup to whatever the list length is when the
// function is called.
size_t length = mLength;
do {
size_t list_length = ListChunk::kLength;
list_length = std::min(list_length, length);
for (size_t position = 0; position < list_length; position++) {
if (aValue == list->mElements[position]) {
return true;
}
}
length -= ListChunk::kLength;
list = list->mNext.get();
} while (list);
return false;
}
};
typedef ChunkedList<intptr_t> FdList;
// Return a list used to hold the IDs of the current debug files. On unix
// an ID is a file descriptor. On Windows it is a file HANDLE.
FdList&
getDebugFileIDs()
{
static FdList DebugFileIDs;
return DebugFileIDs;
}
} // namespace
namespace mozilla {
// Auxiliary Method to test if a file descriptor is registered to be ignored
// by the poisoning IO interposer
bool
IsDebugFile(intptr_t aFileID)
{
return getDebugFileIDs().Contains(aFileID);
}
} // namespace mozilla
extern "C" {
void
MozillaRegisterDebugHandle(intptr_t aHandle)
{
DebugFilesAutoLock lockedScope;
FdList& DebugFileIDs = getDebugFileIDs();
MOZ_ASSERT(!DebugFileIDs.Contains(aHandle));
DebugFileIDs.Add(aHandle);
}
void
MozillaRegisterDebugFD(int aFd)
{
MozillaRegisterDebugHandle(FileDescriptorToHandle(aFd));
}
void
MozillaRegisterDebugFILE(FILE* aFile)
{
int fd = fileno(aFile);
if (fd == 1 || fd == 2) {
return;
}
MozillaRegisterDebugFD(fd);
}
void
MozillaUnRegisterDebugHandle(intptr_t aHandle)
{
DebugFilesAutoLock lockedScope;
FdList& DebugFileIDs = getDebugFileIDs();
MOZ_ASSERT(DebugFileIDs.Contains(aHandle));
DebugFileIDs.Remove(aHandle);
}
void
MozillaUnRegisterDebugFD(int aFd)
{
MozillaUnRegisterDebugHandle(FileDescriptorToHandle(aFd));
}
void
MozillaUnRegisterDebugFILE(FILE* aFile)
{
int fd = fileno(aFile);
if (fd == 1 || fd == 2) {
return;
}
fflush(aFile);
MozillaUnRegisterDebugFD(fd);
}
} // extern "C"
#ifdef MOZ_REPLACE_MALLOC
void
DebugFdRegistry::RegisterHandle(intptr_t aHandle)
{
MozillaRegisterDebugHandle(aHandle);
}
void
DebugFdRegistry::UnRegisterHandle(intptr_t aHandle)
{
MozillaUnRegisterDebugHandle(aHandle);
}
#endif

View file

@ -0,0 +1,386 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "PoisonIOInterposer.h"
#include "mach_override.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/Mutex.h"
#include "mozilla/ProcessedStack.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsPrintfCString.h"
#include "mozilla/StackWalk.h"
#include "nsTraceRefcnt.h"
#include "plstr.h"
#include "prio.h"
#include <algorithm>
#include <vector>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <aio.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef MOZ_REPLACE_MALLOC
#include "replace_malloc_bridge.h"
#endif
namespace {
using namespace mozilla;
// Bit tracking if poisoned writes are enabled
static bool sIsEnabled = false;
// Check if writes are dirty before reporting IO
static bool sOnlyReportDirtyWrites = false;
// Routines for write validation
bool IsValidWrite(int aFd, const void* aWbuf, size_t aCount);
bool IsIPCWrite(int aFd, const struct stat& aBuf);
/******************************** IO AutoTimer ********************************/
/**
* RAII class for timing the duration of an I/O call and reporting the result
* to the IOInterposeObserver API.
*/
class MacIOAutoObservation : public IOInterposeObserver::Observation
{
public:
MacIOAutoObservation(IOInterposeObserver::Operation aOp, int aFd)
: IOInterposeObserver::Observation(aOp, sReference, sIsEnabled &&
!IsDebugFile(aFd))
, mFd(aFd)
, mHasQueriedFilename(false)
, mFilename(nullptr)
{
}
MacIOAutoObservation(IOInterposeObserver::Operation aOp, int aFd,
const void* aBuf, size_t aCount)
: IOInterposeObserver::Observation(aOp, sReference, sIsEnabled &&
!IsDebugFile(aFd) &&
IsValidWrite(aFd, aBuf, aCount))
, mFd(aFd)
, mHasQueriedFilename(false)
, mFilename(nullptr)
{
}
// Custom implementation of IOInterposeObserver::Observation::Filename
const char16_t* Filename() override;
~MacIOAutoObservation()
{
Report();
if (mFilename) {
free(mFilename);
mFilename = nullptr;
}
}
private:
int mFd;
bool mHasQueriedFilename;
char16_t* mFilename;
static const char* sReference;
};
const char* MacIOAutoObservation::sReference = "PoisonIOInterposer";
// Get filename for this observation
const char16_t*
MacIOAutoObservation::Filename()
{
// If mHasQueriedFilename is true, then we already have it
if (mHasQueriedFilename) {
return mFilename;
}
char filename[MAXPATHLEN];
if (fcntl(mFd, F_GETPATH, filename) != -1) {
mFilename = UTF8ToNewUnicode(nsDependentCString(filename));
} else {
mFilename = nullptr;
}
mHasQueriedFilename = true;
// Return filename
return mFilename;
}
/****************************** Write Validation ******************************/
// We want to detect "actual" writes, not IPC. Some IPC mechanisms are
// implemented with file descriptors, so filter them out.
bool
IsIPCWrite(int aFd, const struct stat& aBuf)
{
if ((aBuf.st_mode & S_IFMT) == S_IFIFO) {
return true;
}
if ((aBuf.st_mode & S_IFMT) != S_IFSOCK) {
return false;
}
sockaddr_storage address;
socklen_t len = sizeof(address);
if (getsockname(aFd, (sockaddr*)&address, &len) != 0) {
return true; // Ignore the aFd if we can't find what it is.
}
return address.ss_family == AF_UNIX;
}
// We want to report actual disk IO not things that don't move bits on the disk
bool
IsValidWrite(int aFd, const void* aWbuf, size_t aCount)
{
// Ignore writes of zero bytes, Firefox does some during shutdown.
if (aCount == 0) {
return false;
}
{
struct stat buf;
int rv = fstat(aFd, &buf);
if (rv != 0) {
return true;
}
if (IsIPCWrite(aFd, buf)) {
return false;
}
}
// For writev we pass a nullptr aWbuf. We should only get here from
// dbm, and it uses write, so assert that we have aWbuf.
if (!aWbuf) {
return true;
}
// Break, here if we're allowed to report non-dirty writes
if (!sOnlyReportDirtyWrites) {
return true;
}
// As a really bad hack, accept writes that don't change the on disk
// content. This is needed because dbm doesn't keep track of dirty bits
// and can end up writing the same data to disk twice. Once when the
// user (nss) asks it to sync and once when closing the database.
auto wbuf2 = MakeUniqueFallible<char[]>(aCount);
if (!wbuf2) {
return true;
}
off_t pos = lseek(aFd, 0, SEEK_CUR);
if (pos == -1) {
return true;
}
ssize_t r = read(aFd, wbuf2.get(), aCount);
if (r < 0 || (size_t)r != aCount) {
return true;
}
int cmp = memcmp(aWbuf, wbuf2.get(), aCount);
if (cmp != 0) {
return true;
}
off_t pos2 = lseek(aFd, pos, SEEK_SET);
if (pos2 != pos) {
return true;
}
// Otherwise this is not a valid write
return false;
}
/*************************** Function Interception ***************************/
/** Structure for declaration of function override */
struct FuncData
{
const char* Name; // Name of the function for the ones we use dlsym
const void* Wrapper; // The function that we will replace 'Function' with
void* Function; // The function that will be replaced with 'Wrapper'
void* Buffer; // Will point to the jump buffer that lets us call
// 'Function' after it has been replaced.
};
// Wrap aio_write. We have not seen it before, so just assert/report it.
typedef ssize_t (*aio_write_t)(struct aiocb* aAioCbp);
ssize_t wrap_aio_write(struct aiocb* aAioCbp);
FuncData aio_write_data = { 0, (void*)wrap_aio_write, (void*)aio_write };
ssize_t
wrap_aio_write(struct aiocb* aAioCbp)
{
MacIOAutoObservation timer(IOInterposeObserver::OpWrite,
aAioCbp->aio_fildes);
aio_write_t old_write = (aio_write_t)aio_write_data.Buffer;
return old_write(aAioCbp);
}
// Wrap pwrite-like functions.
// We have not seen them before, so just assert/report it.
typedef ssize_t (*pwrite_t)(int aFd, const void* buf, size_t aNumBytes,
off_t aOffset);
template<FuncData& foo>
ssize_t
wrap_pwrite_temp(int aFd, const void* aBuf, size_t aNumBytes, off_t aOffset)
{
MacIOAutoObservation timer(IOInterposeObserver::OpWrite, aFd);
pwrite_t old_write = (pwrite_t)foo.Buffer;
return old_write(aFd, aBuf, aNumBytes, aOffset);
}
// Define a FuncData for a pwrite-like functions.
#define DEFINE_PWRITE_DATA(X, NAME) \
FuncData X ## _data = { NAME, (void*) wrap_pwrite_temp<X ## _data> }; \
// This exists everywhere.
DEFINE_PWRITE_DATA(pwrite, "pwrite")
// These exist on 32 bit OS X
DEFINE_PWRITE_DATA(pwrite_NOCANCEL_UNIX2003, "pwrite$NOCANCEL$UNIX2003");
DEFINE_PWRITE_DATA(pwrite_UNIX2003, "pwrite$UNIX2003");
// This exists on 64 bit OS X
DEFINE_PWRITE_DATA(pwrite_NOCANCEL, "pwrite$NOCANCEL");
typedef ssize_t (*writev_t)(int aFd, const struct iovec* aIov, int aIovCount);
template<FuncData& foo>
ssize_t
wrap_writev_temp(int aFd, const struct iovec* aIov, int aIovCount)
{
MacIOAutoObservation timer(IOInterposeObserver::OpWrite, aFd, nullptr,
aIovCount);
writev_t old_write = (writev_t)foo.Buffer;
return old_write(aFd, aIov, aIovCount);
}
// Define a FuncData for a writev-like functions.
#define DEFINE_WRITEV_DATA(X, NAME) \
FuncData X ## _data = { NAME, (void*) wrap_writev_temp<X ## _data> }; \
// This exists everywhere.
DEFINE_WRITEV_DATA(writev, "writev");
// These exist on 32 bit OS X
DEFINE_WRITEV_DATA(writev_NOCANCEL_UNIX2003, "writev$NOCANCEL$UNIX2003");
DEFINE_WRITEV_DATA(writev_UNIX2003, "writev$UNIX2003");
// This exists on 64 bit OS X
DEFINE_WRITEV_DATA(writev_NOCANCEL, "writev$NOCANCEL");
typedef ssize_t (*write_t)(int aFd, const void* aBuf, size_t aCount);
template<FuncData& foo>
ssize_t
wrap_write_temp(int aFd, const void* aBuf, size_t aCount)
{
MacIOAutoObservation timer(IOInterposeObserver::OpWrite, aFd, aBuf, aCount);
write_t old_write = (write_t)foo.Buffer;
return old_write(aFd, aBuf, aCount);
}
// Define a FuncData for a write-like functions.
#define DEFINE_WRITE_DATA(X, NAME) \
FuncData X ## _data = { NAME, (void*) wrap_write_temp<X ## _data> }; \
// This exists everywhere.
DEFINE_WRITE_DATA(write, "write");
// These exist on 32 bit OS X
DEFINE_WRITE_DATA(write_NOCANCEL_UNIX2003, "write$NOCANCEL$UNIX2003");
DEFINE_WRITE_DATA(write_UNIX2003, "write$UNIX2003");
// This exists on 64 bit OS X
DEFINE_WRITE_DATA(write_NOCANCEL, "write$NOCANCEL");
FuncData* Functions[] = {
&aio_write_data,
&pwrite_data,
&pwrite_NOCANCEL_UNIX2003_data,
&pwrite_UNIX2003_data,
&pwrite_NOCANCEL_data,
&write_data,
&write_NOCANCEL_UNIX2003_data,
&write_UNIX2003_data,
&write_NOCANCEL_data,
&writev_data,
&writev_NOCANCEL_UNIX2003_data,
&writev_UNIX2003_data,
&writev_NOCANCEL_data
};
const int NumFunctions = ArrayLength(Functions);
} // namespace
/******************************** IO Poisoning ********************************/
namespace mozilla {
void
InitPoisonIOInterposer()
{
// Enable reporting from poisoned write methods
sIsEnabled = true;
// Make sure we only poison writes once!
static bool WritesArePoisoned = false;
if (WritesArePoisoned) {
return;
}
WritesArePoisoned = true;
// stdout and stderr are OK.
MozillaRegisterDebugFD(1);
MozillaRegisterDebugFD(2);
#ifdef MOZ_REPLACE_MALLOC
// The contract with InitDebugFd is that the given registry can be used
// at any moment, so the instance needs to persist longer than the scope
// of this functions.
static DebugFdRegistry registry;
ReplaceMalloc::InitDebugFd(registry);
#endif
for (int i = 0; i < NumFunctions; ++i) {
FuncData* d = Functions[i];
if (!d->Function) {
d->Function = dlsym(RTLD_DEFAULT, d->Name);
}
if (!d->Function) {
continue;
}
DebugOnly<mach_error_t> t = mach_override_ptr(d->Function, d->Wrapper,
&d->Buffer);
MOZ_ASSERT(t == err_none);
}
}
void
OnlyReportDirtyWrites()
{
sOnlyReportDirtyWrites = true;
}
void
ClearPoisonIOInterposer()
{
// Not sure how or if we can unpoison the functions. Would be nice, but no
// worries we won't need to do this anyway.
sIsEnabled = false;
}
} // namespace mozilla

View file

@ -0,0 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include <stdio.h>
extern "C" {
void MozillaRegisterDebugFD(int aFd) {}
void MozillaRegisterDebugFILE(FILE* aFile) {}
void MozillaUnRegisterDebugFD(int aFd) {}
void MozillaUnRegisterDebugFILE(FILE* aFile) {}
} // extern "C"

View file

@ -0,0 +1,501 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "PoisonIOInterposer.h"
#include <algorithm>
#include <stdio.h>
#include <vector>
#include <io.h>
#include <windows.h>
#include <winternl.h>
#include "mozilla/Assertions.h"
#include "mozilla/FileUtilsWin.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "nsTArray.h"
#include "nsWindowsDllInterceptor.h"
#include "plstr.h"
#ifdef MOZ_REPLACE_MALLOC
#include "replace_malloc_bridge.h"
#endif
using namespace mozilla;
namespace {
// Keep track of poisoned state. Notice that there is no reason to lock access
// to this variable as it's only changed in InitPoisonIOInterposer and
// ClearPoisonIOInterposer which may only be called on the main-thread when no
// other threads are running.
static bool sIOPoisoned = false;
/************************ Internal NT API Declarations ************************/
/*
* Function pointer declaration for internal NT routine to create/open files.
* For documentation on the NtCreateFile routine, see MSDN.
*/
typedef NTSTATUS (NTAPI* NtCreateFileFn)(
PHANDLE aFileHandle,
ACCESS_MASK aDesiredAccess,
POBJECT_ATTRIBUTES aObjectAttributes,
PIO_STATUS_BLOCK aIoStatusBlock,
PLARGE_INTEGER aAllocationSize,
ULONG aFileAttributes,
ULONG aShareAccess,
ULONG aCreateDisposition,
ULONG aCreateOptions,
PVOID aEaBuffer,
ULONG aEaLength);
/**
* Function pointer declaration for internal NT routine to read data from file.
* For documentation on the NtReadFile routine, see ZwReadFile on MSDN.
*/
typedef NTSTATUS (NTAPI* NtReadFileFn)(
HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
PVOID aBuffer,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey);
/**
* Function pointer declaration for internal NT routine to read data from file.
* No documentation exists, see wine sources for details.
*/
typedef NTSTATUS (NTAPI* NtReadFileScatterFn)(
HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
FILE_SEGMENT_ELEMENT* aSegments,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey);
/**
* Function pointer declaration for internal NT routine to write data to file.
* For documentation on the NtWriteFile routine, see ZwWriteFile on MSDN.
*/
typedef NTSTATUS (NTAPI* NtWriteFileFn)(
HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
PVOID aBuffer,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey);
/**
* Function pointer declaration for internal NT routine to write data to file.
* No documentation exists, see wine sources for details.
*/
typedef NTSTATUS (NTAPI* NtWriteFileGatherFn)(
HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
FILE_SEGMENT_ELEMENT* aSegments,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey);
/**
* Function pointer declaration for internal NT routine to flush to disk.
* For documentation on the NtFlushBuffersFile routine, see ZwFlushBuffersFile
* on MSDN.
*/
typedef NTSTATUS (NTAPI* NtFlushBuffersFileFn)(
HANDLE aFileHandle,
PIO_STATUS_BLOCK aIoStatusBlock);
typedef struct _FILE_NETWORK_OPEN_INFORMATION* PFILE_NETWORK_OPEN_INFORMATION;
/**
* Function pointer delaration for internal NT routine to query file attributes.
* (equivalent to stat)
*/
typedef NTSTATUS (NTAPI* NtQueryFullAttributesFileFn)(
POBJECT_ATTRIBUTES aObjectAttributes,
PFILE_NETWORK_OPEN_INFORMATION aFileInformation);
/*************************** Auxiliary Declarations ***************************/
/**
* RAII class for timing the duration of an I/O call and reporting the result
* to the IOInterposeObserver API.
*/
class WinIOAutoObservation : public IOInterposeObserver::Observation
{
public:
WinIOAutoObservation(IOInterposeObserver::Operation aOp,
HANDLE aFileHandle, const LARGE_INTEGER* aOffset)
: IOInterposeObserver::Observation(
aOp, sReference, !IsDebugFile(reinterpret_cast<intptr_t>(aFileHandle)))
, mFileHandle(aFileHandle)
, mHasQueriedFilename(false)
, mFilename(nullptr)
{
if (mShouldReport) {
mOffset.QuadPart = aOffset ? aOffset->QuadPart : 0;
}
}
WinIOAutoObservation(IOInterposeObserver::Operation aOp, nsAString& aFilename)
: IOInterposeObserver::Observation(aOp, sReference)
, mFileHandle(nullptr)
, mHasQueriedFilename(false)
, mFilename(nullptr)
{
if (mShouldReport) {
nsAutoString dosPath;
if (NtPathToDosPath(aFilename, dosPath)) {
mFilename = ToNewUnicode(dosPath);
mHasQueriedFilename = true;
}
mOffset.QuadPart = 0;
}
}
// Custom implementation of IOInterposeObserver::Observation::Filename
const char16_t* Filename() override;
~WinIOAutoObservation()
{
Report();
if (mFilename) {
MOZ_ASSERT(mHasQueriedFilename);
free(mFilename);
mFilename = nullptr;
}
}
private:
HANDLE mFileHandle;
LARGE_INTEGER mOffset;
bool mHasQueriedFilename;
char16_t* mFilename;
static const char* sReference;
};
const char* WinIOAutoObservation::sReference = "PoisonIOInterposer";
// Get filename for this observation
const char16_t*
WinIOAutoObservation::Filename()
{
// If mHasQueriedFilename is true, then filename is already stored in mFilename
if (mHasQueriedFilename) {
return mFilename;
}
nsAutoString utf16Filename;
if (HandleToFilename(mFileHandle, mOffset, utf16Filename)) {
// Heap allocate with leakable memory
mFilename = ToNewUnicode(utf16Filename);
}
mHasQueriedFilename = true;
// Return filename
return mFilename;
}
/*************************** IO Interposing Methods ***************************/
// Function pointers to original functions
static NtCreateFileFn gOriginalNtCreateFile;
static NtReadFileFn gOriginalNtReadFile;
static NtReadFileScatterFn gOriginalNtReadFileScatter;
static NtWriteFileFn gOriginalNtWriteFile;
static NtWriteFileGatherFn gOriginalNtWriteFileGather;
static NtFlushBuffersFileFn gOriginalNtFlushBuffersFile;
static NtQueryFullAttributesFileFn gOriginalNtQueryFullAttributesFile;
static NTSTATUS NTAPI
InterposedNtCreateFile(PHANDLE aFileHandle,
ACCESS_MASK aDesiredAccess,
POBJECT_ATTRIBUTES aObjectAttributes,
PIO_STATUS_BLOCK aIoStatusBlock,
PLARGE_INTEGER aAllocationSize,
ULONG aFileAttributes,
ULONG aShareAccess,
ULONG aCreateDisposition,
ULONG aCreateOptions,
PVOID aEaBuffer,
ULONG aEaLength)
{
// Report IO
const wchar_t* buf =
aObjectAttributes ? aObjectAttributes->ObjectName->Buffer : L"";
uint32_t len =
aObjectAttributes ? aObjectAttributes->ObjectName->Length / sizeof(WCHAR) :
0;
nsDependentSubstring filename(buf, len);
WinIOAutoObservation timer(IOInterposeObserver::OpCreateOrOpen, filename);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtCreateFile);
// Execute original function
return gOriginalNtCreateFile(aFileHandle,
aDesiredAccess,
aObjectAttributes,
aIoStatusBlock,
aAllocationSize,
aFileAttributes,
aShareAccess,
aCreateDisposition,
aCreateOptions,
aEaBuffer,
aEaLength);
}
static NTSTATUS NTAPI
InterposedNtReadFile(HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
PVOID aBuffer,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey)
{
// Report IO
WinIOAutoObservation timer(IOInterposeObserver::OpRead, aFileHandle, aOffset);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtReadFile);
// Execute original function
return gOriginalNtReadFile(aFileHandle,
aEvent,
aApc,
aApcCtx,
aIoStatus,
aBuffer,
aLength,
aOffset,
aKey);
}
static NTSTATUS NTAPI
InterposedNtReadFileScatter(HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
FILE_SEGMENT_ELEMENT* aSegments,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey)
{
// Report IO
WinIOAutoObservation timer(IOInterposeObserver::OpRead, aFileHandle, aOffset);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtReadFileScatter);
// Execute original function
return gOriginalNtReadFileScatter(aFileHandle,
aEvent,
aApc,
aApcCtx,
aIoStatus,
aSegments,
aLength,
aOffset,
aKey);
}
// Interposed NtWriteFile function
static NTSTATUS NTAPI
InterposedNtWriteFile(HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
PVOID aBuffer,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey)
{
// Report IO
WinIOAutoObservation timer(IOInterposeObserver::OpWrite, aFileHandle,
aOffset);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtWriteFile);
// Execute original function
return gOriginalNtWriteFile(aFileHandle,
aEvent,
aApc,
aApcCtx,
aIoStatus,
aBuffer,
aLength,
aOffset,
aKey);
}
// Interposed NtWriteFileGather function
static NTSTATUS NTAPI
InterposedNtWriteFileGather(HANDLE aFileHandle,
HANDLE aEvent,
PIO_APC_ROUTINE aApc,
PVOID aApcCtx,
PIO_STATUS_BLOCK aIoStatus,
FILE_SEGMENT_ELEMENT* aSegments,
ULONG aLength,
PLARGE_INTEGER aOffset,
PULONG aKey)
{
// Report IO
WinIOAutoObservation timer(IOInterposeObserver::OpWrite, aFileHandle,
aOffset);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtWriteFileGather);
// Execute original function
return gOriginalNtWriteFileGather(aFileHandle,
aEvent,
aApc,
aApcCtx,
aIoStatus,
aSegments,
aLength,
aOffset,
aKey);
}
static NTSTATUS NTAPI
InterposedNtFlushBuffersFile(HANDLE aFileHandle,
PIO_STATUS_BLOCK aIoStatusBlock)
{
// Report IO
WinIOAutoObservation timer(IOInterposeObserver::OpFSync, aFileHandle,
nullptr);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtFlushBuffersFile);
// Execute original function
return gOriginalNtFlushBuffersFile(aFileHandle,
aIoStatusBlock);
}
static NTSTATUS NTAPI
InterposedNtQueryFullAttributesFile(
POBJECT_ATTRIBUTES aObjectAttributes,
PFILE_NETWORK_OPEN_INFORMATION aFileInformation)
{
// Report IO
const wchar_t* buf =
aObjectAttributes ? aObjectAttributes->ObjectName->Buffer : L"";
uint32_t len =
aObjectAttributes ? aObjectAttributes->ObjectName->Length / sizeof(WCHAR) :
0;
nsDependentSubstring filename(buf, len);
WinIOAutoObservation timer(IOInterposeObserver::OpStat, filename);
// Something is badly wrong if this function is undefined
MOZ_ASSERT(gOriginalNtQueryFullAttributesFile);
// Execute original function
return gOriginalNtQueryFullAttributesFile(aObjectAttributes,
aFileInformation);
}
} // namespace
/******************************** IO Poisoning ********************************/
// Windows DLL interceptor
static WindowsDllInterceptor sNtDllInterceptor;
namespace mozilla {
void
InitPoisonIOInterposer()
{
// Don't poison twice... as this function may only be invoked on the main
// thread when no other threads are running, it safe to allow multiple calls
// to InitPoisonIOInterposer() without complaining (ie. failing assertions).
if (sIOPoisoned) {
return;
}
sIOPoisoned = true;
// Stdout and Stderr are OK.
MozillaRegisterDebugFD(1);
MozillaRegisterDebugFD(2);
#ifdef MOZ_REPLACE_MALLOC
// The contract with InitDebugFd is that the given registry can be used
// at any moment, so the instance needs to persist longer than the scope
// of this functions.
static DebugFdRegistry registry;
ReplaceMalloc::InitDebugFd(registry);
#endif
// Initialize dll interceptor and add hooks
sNtDllInterceptor.Init("ntdll.dll");
sNtDllInterceptor.AddHook(
"NtCreateFile",
reinterpret_cast<intptr_t>(InterposedNtCreateFile),
reinterpret_cast<void**>(&gOriginalNtCreateFile));
sNtDllInterceptor.AddHook(
"NtReadFile",
reinterpret_cast<intptr_t>(InterposedNtReadFile),
reinterpret_cast<void**>(&gOriginalNtReadFile));
sNtDllInterceptor.AddHook(
"NtReadFileScatter",
reinterpret_cast<intptr_t>(InterposedNtReadFileScatter),
reinterpret_cast<void**>(&gOriginalNtReadFileScatter));
sNtDllInterceptor.AddHook(
"NtWriteFile",
reinterpret_cast<intptr_t>(InterposedNtWriteFile),
reinterpret_cast<void**>(&gOriginalNtWriteFile));
sNtDllInterceptor.AddHook(
"NtWriteFileGather",
reinterpret_cast<intptr_t>(InterposedNtWriteFileGather),
reinterpret_cast<void**>(&gOriginalNtWriteFileGather));
sNtDllInterceptor.AddHook(
"NtFlushBuffersFile",
reinterpret_cast<intptr_t>(InterposedNtFlushBuffersFile),
reinterpret_cast<void**>(&gOriginalNtFlushBuffersFile));
sNtDllInterceptor.AddHook(
"NtQueryFullAttributesFile",
reinterpret_cast<intptr_t>(InterposedNtQueryFullAttributesFile),
reinterpret_cast<void**>(&gOriginalNtQueryFullAttributesFile));
}
void
ClearPoisonIOInterposer()
{
MOZ_ASSERT(false);
if (sIOPoisoned) {
// Destroy the DLL interceptor
sIOPoisoned = false;
sNtDllInterceptor = WindowsDllInterceptor();
}
}
} // namespace mozilla

46
xpcom/build/ServiceList.h Normal file
View file

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
// IWYU pragma: private, include "mozilla/Services.h"
MOZ_SERVICE(ChromeRegistryService, nsIChromeRegistry,
"@mozilla.org/chrome/chrome-registry;1")
MOZ_SERVICE(ToolkitChromeRegistryService, nsIToolkitChromeRegistry,
"@mozilla.org/chrome/chrome-registry;1")
MOZ_SERVICE(XULChromeRegistryService, nsIXULChromeRegistry,
"@mozilla.org/chrome/chrome-registry;1")
MOZ_SERVICE(XULOverlayProviderService, nsIXULOverlayProvider,
"@mozilla.org/chrome/chrome-registry;1")
MOZ_SERVICE(IOService, nsIIOService,
"@mozilla.org/network/io-service;1")
MOZ_SERVICE(ObserverService, nsIObserverService,
"@mozilla.org/observer-service;1")
MOZ_SERVICE(StringBundleService, nsIStringBundleService,
"@mozilla.org/intl/stringbundle;1")
MOZ_SERVICE(XPConnect, nsIXPConnect,
"@mozilla.org/js/xpc/XPConnect;1")
MOZ_SERVICE(InDOMUtils, inIDOMUtils,
"@mozilla.org/inspector/dom-utils;1")
MOZ_SERVICE(PermissionManager, nsIPermissionManager,
"@mozilla.org/permissionmanager;1");
MOZ_SERVICE(ServiceWorkerManager, nsIServiceWorkerManager,
"@mozilla.org/serviceworkers/manager;1");
MOZ_SERVICE(AsyncShutdown, nsIAsyncShutdownService,
"@mozilla.org/async-shutdown-service;1")
MOZ_SERVICE(UUIDGenerator, nsIUUIDGenerator,
"@mozilla.org/uuid-generator;1");
MOZ_SERVICE(GfxInfo, nsIGfxInfo,
"@mozilla.org/gfx/info;1");
#ifdef MOZ_USE_NAMESPACE
namespace mozilla {
#endif
MOZ_SERVICE(HistoryService, IHistory,
"@mozilla.org/browser/history;1")
#ifdef MOZ_USE_NAMESPACE
} // namespace mozilla
#endif

71
xpcom/build/Services.cpp Normal file
View file

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "mozilla/Likely.h"
#include "mozilla/Services.h"
#include "nsComponentManager.h"
#include "nsIObserverService.h"
#include "nsNetCID.h"
#include "nsObserverService.h"
#include "nsXPCOMPrivate.h"
#include "nsIIOService.h"
#include "nsIDirectoryService.h"
#include "nsIChromeRegistry.h"
#include "nsIStringBundle.h"
#include "nsIToolkitChromeRegistry.h"
#include "nsIXULOverlayProvider.h"
#include "IHistory.h"
#include "nsIXPConnect.h"
#include "inIDOMUtils.h"
#include "nsIPermissionManager.h"
#include "nsIServiceWorkerManager.h"
#include "nsIAsyncShutdown.h"
#include "nsIUUIDGenerator.h"
#include "nsIGfxInfo.h"
using namespace mozilla;
using namespace mozilla::services;
/*
* Define a global variable and a getter for every service in ServiceList.
* eg. gIOService and GetIOService()
*/
#define MOZ_SERVICE(NAME, TYPE, CONTRACT_ID) \
static TYPE* g##NAME = nullptr; \
\
already_AddRefed<TYPE> \
mozilla::services::Get##NAME() \
{ \
if (MOZ_UNLIKELY(gXPCOMShuttingDown)) { \
return nullptr; \
} \
if (!g##NAME) { \
nsCOMPtr<TYPE> os = do_GetService(CONTRACT_ID); \
os.swap(g##NAME); \
} \
nsCOMPtr<TYPE> ret = g##NAME; \
return ret.forget(); \
} \
NS_EXPORT_(already_AddRefed<TYPE>) \
mozilla::services::_external_Get##NAME() \
{ \
return Get##NAME(); \
}
#include "ServiceList.h"
#undef MOZ_SERVICE
/**
* Clears service cache, sets gXPCOMShuttingDown
*/
void
mozilla::services::Shutdown()
{
gXPCOMShuttingDown = true;
#define MOZ_SERVICE(NAME, TYPE, CONTRACT_ID) NS_IF_RELEASE(g##NAME);
#include "ServiceList.h"
#undef MOZ_SERVICE
}

45
xpcom/build/Services.h Normal file
View file

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_Services_h
#define mozilla_Services_h
#include "nscore.h"
#include "nsCOMPtr.h"
#define MOZ_USE_NAMESPACE
#define MOZ_SERVICE(NAME, TYPE, SERVICE_CID) class TYPE;
#include "ServiceList.h"
#undef MOZ_SERVICE
#undef MOZ_USE_NAMESPACE
namespace mozilla {
namespace services {
#ifdef MOZILLA_INTERNAL_API
#define MOZ_SERVICE(NAME, TYPE, SERVICE_CID) \
already_AddRefed<TYPE> Get##NAME(); \
NS_EXPORT_(already_AddRefed<TYPE>) _external_Get##NAME();
#include "ServiceList.h"
#undef MOZ_SERVICE
#else
#define MOZ_SERVICE(NAME, TYPE, SERVICE_CID) \
NS_IMPORT_(already_AddRefed<TYPE>) _external_Get##NAME(); \
inline already_AddRefed<TYPE> Get##NAME() \
{ \
return _external_Get##NAME(); \
}
#include "ServiceList.h"
#undef MOZ_SERVICE
#endif
} // namespace services
} // namespace mozilla
#endif

178
xpcom/build/XPCOM.h Normal file
View file

@ -0,0 +1,178 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_XPCOM_h
#define mozilla_XPCOM_h
// NOTE: the following headers are sorted topologically, not alphabetically.
// Do not reorder them without review from bsmedberg.
// system headers required by XPCOM headers
#include <string.h>
// core headers required by pretty much everything else
#include "nscore.h"
#include "nsXPCOMCID.h"
#include "nsXPCOM.h"
#include "nsError.h"
#include "nsDebug.h"
#include "nsMemory.h"
#include "nsID.h"
#include "nsISupports.h"
#include "nsTArray.h"
#include "nsTWeakRef.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#ifndef MOZILLA_INTERNAL_API
#include "nsStringAPI.h"
#else
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsNativeCharsetUtils.h"
#endif
#include "nsISupportsUtils.h"
#include "nsISupportsImpl.h"
// core data structures
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsBaseHashtable.h"
#include "nsDataHashtable.h"
#include "nsInterfaceHashtable.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
// interfaces that inherit directly from nsISupports
#include "nsIArray.h"
#include "nsIAtom.h"
#include "nsIAtomService.h"
#include "nsICategoryManager.h"
#include "nsIClassInfo.h"
#include "nsIComponentManager.h"
#include "nsIConsoleListener.h"
#include "nsIConsoleMessage.h"
#include "nsIConsoleService.h"
#include "nsIDebug2.h"
#include "nsIDirectoryEnumerator.h"
#include "nsIEnvironment.h"
#include "nsIErrorService.h"
#include "nsIEventTarget.h"
#include "nsIException.h"
#include "nsIFactory.h"
#include "nsIFile.h"
#include "nsIHashable.h"
#include "nsIINIParser.h"
#include "nsIInputStream.h"
#include "nsIInterfaceRequestor.h"
#include "nsILineInputStream.h"
#include "nsIMemory.h"
#include "nsIMutable.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIOutputStream.h"
#include "nsIProcess.h"
#include "nsIProperties.h"
#include "nsIPropertyBag2.h"
#include "nsIRunnable.h"
#include "nsISeekableStream.h"
#include "nsISerializable.h"
#include "nsIServiceManager.h"
#include "nsIScriptableInputStream.h"
#include "nsISimpleEnumerator.h"
#include "nsIStreamBufferAccess.h"
#include "nsIStringEnumerator.h"
#include "nsIStorageStream.h"
#include "nsISupportsIterators.h"
#include "nsISupportsPrimitives.h"
#include "nsISupportsPriority.h"
#include "nsIThreadManager.h"
#include "nsITimer.h"
#include "nsIUUIDGenerator.h"
#include "nsIUnicharInputStream.h"
#include "nsIUnicharOutputStream.h"
#include "nsIUnicharLineInputStream.h"
#include "nsIVariant.h"
#include "nsIVersionComparator.h"
#include "nsIWritablePropertyBag2.h"
// interfaces that include something above
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIBinaryInputStream.h"
#include "nsIBinaryOutputStream.h"
#include "nsIConverterInputStream.h"
#include "nsIConverterOutputStream.h"
#include "nsIInputStreamTee.h"
#include "nsIMultiplexInputStream.h"
#include "nsIMutableArray.h"
#include "nsIPersistentProperties2.h"
#include "nsIStringStream.h"
#include "nsIThread.h"
#include "nsIThreadPool.h"
// interfaces that include something above
#include "nsILocalFileWin.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIPipe.h"
#ifdef MOZ_WIDGET_COCOA
#include "nsILocalFileMac.h"
#include "nsIMacUtils.h"
#endif
// xpcom/glue utility headers
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsIWeakReferenceUtils.h"
#include "nsWeakReference.h"
#include "nsArrayEnumerator.h"
#include "nsArrayUtils.h"
#include "nsCRTGlue.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDeque.h"
#include "nsEnumeratorUtils.h"
#include "nsIClassInfoImpl.h"
#include "mozilla/ModuleUtils.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsINIParser.h"
#include "nsProxyRelease.h"
#include "nsTObserverArray.h"
#include "nsTextFormatter.h"
#include "nsThreadUtils.h"
#include "nsVersionComparator.h"
#include "nsXPTCUtils.h"
// xpcom/base utility headers
#include "nsAgg.h"
#include "nsAutoRef.h"
#include "nsInterfaceRequestorAgg.h"
// xpcom/io utility headers
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#endif // mozilla_XPCOM_h

1126
xpcom/build/XPCOMInit.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,81 @@
COMPONENT_M(MEMORY, nsMemoryImpl::Create, Module::ALLOW_IN_GPU_PROCESS)
COMPONENT_M(DEBUG, nsDebugImpl::Create, Module::ALLOW_IN_GPU_PROCESS)
COMPONENT(ERRORSERVICE, nsErrorService::Create)
COMPONENT_M(CATEGORYMANAGER, nsCategoryManager::Create, Module::ALLOW_IN_GPU_PROCESS)
COMPONENT(SCRIPTABLEINPUTSTREAM, nsScriptableInputStream::Create)
COMPONENT(BINARYINPUTSTREAM, nsBinaryInputStreamConstructor)
COMPONENT(BINARYOUTPUTSTREAM, nsBinaryOutputStreamConstructor)
COMPONENT(STORAGESTREAM, nsStorageStreamConstructor)
COMPONENT(VERSIONCOMPARATOR, nsVersionComparatorImplConstructor)
COMPONENT(SCRIPTABLEBASE64ENCODER, nsScriptableBase64EncoderConstructor)
COMPONENT(PIPE, nsPipeConstructor)
COMPONENT(PROPERTIES, nsPropertiesConstructor)
COMPONENT(PERSISTENTPROPERTIES, nsPersistentProperties::Create)
COMPONENT(SUPPORTSARRAY, nsSupportsArray::Create)
COMPONENT(ARRAY, nsArrayBase::XPCOMConstructor)
COMPONENT(CONSOLESERVICE, nsConsoleServiceConstructor)
COMPONENT(ATOMSERVICE, nsAtomServiceConstructor)
COMPONENT_M(OBSERVERSERVICE, nsObserverService::Create, Module::ALLOW_IN_GPU_PROCESS)
COMPONENT_M(TIMER, nsTimerConstructor, Module::ALLOW_IN_GPU_PROCESS)
#define COMPONENT_SUPPORTS(TYPE, Type) \
COMPONENT(SUPPORTS_##TYPE, nsSupports##Type##Constructor)
COMPONENT_SUPPORTS(ID, ID)
COMPONENT_SUPPORTS(STRING, String)
COMPONENT_SUPPORTS(CSTRING, CString)
COMPONENT_SUPPORTS(PRBOOL, PRBool)
COMPONENT_SUPPORTS(PRUINT8, PRUint8)
COMPONENT_SUPPORTS(PRUINT16, PRUint16)
COMPONENT_SUPPORTS(PRUINT32, PRUint32)
COMPONENT_SUPPORTS(PRUINT64, PRUint64)
COMPONENT_SUPPORTS(PRTIME, PRTime)
COMPONENT_SUPPORTS(CHAR, Char)
COMPONENT_SUPPORTS(PRINT16, PRInt16)
COMPONENT_SUPPORTS(PRINT32, PRInt32)
COMPONENT_SUPPORTS(PRINT64, PRInt64)
COMPONENT_SUPPORTS(FLOAT, Float)
COMPONENT_SUPPORTS(DOUBLE, Double)
COMPONENT_SUPPORTS(VOID, Void)
COMPONENT_SUPPORTS(INTERFACE_POINTER, InterfacePointer)
#undef COMPONENT_SUPPORTS
COMPONENT(LOCAL_FILE, nsLocalFile::nsLocalFileConstructor)
COMPONENT(DIRECTORY_SERVICE, nsDirectoryService::Create)
COMPONENT(PROCESS, nsProcessConstructor)
COMPONENT(ENVIRONMENT, nsEnvironment::Create)
COMPONENT(THREADMANAGER, nsThreadManagerGetSingleton)
COMPONENT_M(THREADPOOL, nsThreadPoolConstructor, Module::ALLOW_IN_GPU_PROCESS)
COMPONENT(STRINGINPUTSTREAM, nsStringInputStreamConstructor)
COMPONENT(MULTIPLEXINPUTSTREAM, nsMultiplexInputStreamConstructor)
COMPONENT(VARIANT, nsVariantCCConstructor)
COMPONENT(INTERFACEINFOMANAGER_SERVICE, nsXPTIInterfaceInfoManagerGetSingleton)
COMPONENT(HASH_PROPERTY_BAG, nsHashPropertyBagCCConstructor)
COMPONENT(UUID_GENERATOR, nsUUIDGeneratorConstructor)
#if defined(XP_WIN)
COMPONENT(WINDOWSREGKEY, nsWindowsRegKeyConstructor)
#endif
#if defined(MOZ_WIDGET_COCOA)
COMPONENT(MACUTILSIMPL, nsMacUtilsImplConstructor)
#endif
COMPONENT(SYSTEMINFO, nsSystemInfoConstructor)
COMPONENT(MEMORY_REPORTER_MANAGER, nsMemoryReporterManagerConstructor)
COMPONENT(MEMORY_INFO_DUMPER, nsMemoryInfoDumperConstructor)
COMPONENT(IOUTIL, nsIOUtilConstructor)
COMPONENT(CYCLE_COLLECTOR_LOGGER, nsCycleCollectorLoggerConstructor)
COMPONENT(MESSAGE_LOOP, nsMessageLoopConstructor)
COMPONENT(STATUS_REPORTER_MANAGER, nsStatusReporterManagerConstructor)

View file

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 XREChildData_h
#define XREChildData_h
#include "mozilla/UniquePtr.h"
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "mozilla/sandboxing/loggingTypes.h"
namespace sandbox {
class TargetServices;
}
#endif
namespace mozilla {
namespace gmp {
class GMPLoader;
}
}
/**
* Data needed to start a child process.
*/
struct XREChildData
{
#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK)
/**
* Used to load the GMP binary.
*/
mozilla::UniquePtr<mozilla::gmp::GMPLoader> gmpLoader;
#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
/**
* Chromium sandbox TargetServices.
*/
sandbox::TargetServices* sandboxTargetServices = nullptr;
/**
* Function to provide a logging function to the chromium sandbox code.
*/
mozilla::sandboxing::ProvideLogFunctionCb ProvideLogFunction = nullptr;
#endif
};
#endif // XREChildData_h

View file

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 XREShellData_h
#define XREShellData_h
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
namespace sandbox {
class BrokerServices;
}
#endif
/**
* Data needed by XRE_XPCShellMain.
*/
struct XREShellData
{
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
/**
* Chromium sandbox BrokerServices.
*/
sandbox::BrokerServices* sandboxBrokerServices;
#endif
};
#endif // XREShellData_h

789
xpcom/build/mach_override.c Normal file
View file

@ -0,0 +1,789 @@
// Copied from upstream at revision 195c13743fe0ebc658714e2a9567d86529f20443.
// mach_override.c semver:1.2.0
// Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
// Some rights reserved: http://opensource.org/licenses/mit
// https://github.com/rentzsch/mach_override
#include "mach_override.h"
#include <mach-o/dyld.h>
#include <mach/mach_host.h>
#include <mach/mach_init.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
#include <CoreServices/CoreServices.h>
/**************************
*
* Constants
*
**************************/
#pragma mark -
#pragma mark (Constants)
#define kPageSize 4096
#if defined(__ppc__) || defined(__POWERPC__)
long kIslandTemplate[] = {
0x9001FFFC, // stw r0,-4(SP)
0x3C00DEAD, // lis r0,0xDEAD
0x6000BEEF, // ori r0,r0,0xBEEF
0x7C0903A6, // mtctr r0
0x8001FFFC, // lwz r0,-4(SP)
0x60000000, // nop ; optionally replaced
0x4E800420 // bctr
};
#define kAddressHi 3
#define kAddressLo 5
#define kInstructionHi 10
#define kInstructionLo 11
#elif defined(__i386__)
#define kOriginalInstructionsSize 16
// On X86 we migh need to instert an add with a 32 bit immediate after the
// original instructions.
#define kMaxFixupSizeIncrease 5
unsigned char kIslandTemplate[] = {
// kOriginalInstructionsSize nop instructions so that we
// should have enough space to host original instructions
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
// Now the real jump instruction
0xE9, 0xEF, 0xBE, 0xAD, 0xDE
};
#define kInstructions 0
#define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
#elif defined(__x86_64__)
#define kOriginalInstructionsSize 32
// On X86-64 we never need to instert a new instruction.
#define kMaxFixupSizeIncrease 0
#define kJumpAddress kOriginalInstructionsSize + 6
unsigned char kIslandTemplate[] = {
// kOriginalInstructionsSize nop instructions so that we
// should have enough space to host original instructions
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
// Now the real jump instruction
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
#endif
/**************************
*
* Data Types
*
**************************/
#pragma mark -
#pragma mark (Data Types)
typedef struct {
char instructions[sizeof(kIslandTemplate)];
} BranchIsland;
/**************************
*
* Funky Protos
*
**************************/
#pragma mark -
#pragma mark (Funky Protos)
static mach_error_t
allocateBranchIsland(
BranchIsland **island,
void *originalFunctionAddress);
mach_error_t
freeBranchIsland(
BranchIsland *island );
#if defined(__ppc__) || defined(__POWERPC__)
mach_error_t
setBranchIslandTarget(
BranchIsland *island,
const void *branchTo,
long instruction );
#endif
#if defined(__i386__) || defined(__x86_64__)
mach_error_t
setBranchIslandTarget_i386(
BranchIsland *island,
const void *branchTo,
char* instructions );
void
atomic_mov64(
uint64_t *targetAddress,
uint64_t value );
static Boolean
eatKnownInstructions(
unsigned char *code,
uint64_t *newInstruction,
int *howManyEaten,
char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes );
static void
fixupInstructions(
uint32_t offset,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes );
#endif
/*******************************************************************************
*
* Interface
*
*******************************************************************************/
#pragma mark -
#pragma mark (Interface)
#if defined(__i386__) || defined(__x86_64__)
mach_error_t makeIslandExecutable(void *address) {
mach_error_t err = err_none;
uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
int e = err_none;
e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
e |= msync((void *)page, kPageSize, MS_INVALIDATE );
if (e) {
err = err_cannot_override;
}
return err;
}
#endif
mach_error_t
mach_override_ptr(
void *originalFunctionAddress,
const void *overrideFunctionAddress,
void **originalFunctionReentryIsland )
{
assert( originalFunctionAddress );
assert( overrideFunctionAddress );
// this addresses overriding such functions as AudioOutputUnitStart()
// test with modified DefaultOutputUnit project
#if defined(__x86_64__)
for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
else break;
}
#elif defined(__i386__)
for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
else break;
}
#endif
long *originalFunctionPtr = (long*) originalFunctionAddress;
mach_error_t err = err_none;
#if defined(__ppc__) || defined(__POWERPC__)
// Ensure first instruction isn't 'mfctr'.
#define kMFCTRMask 0xfc1fffff
#define kMFCTRInstruction 0x7c0903a6
long originalInstruction = *originalFunctionPtr;
if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
err = err_cannot_override;
#elif defined(__i386__) || defined(__x86_64__)
int eatenCount = 0;
int originalInstructionCount = 0;
char originalInstructions[kOriginalInstructionsSize];
uint8_t originalInstructionSizes[kOriginalInstructionsSize];
uint64_t jumpRelativeInstruction = 0; // JMP
Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
&jumpRelativeInstruction, &eatenCount,
originalInstructions, &originalInstructionCount,
originalInstructionSizes );
if (eatenCount + kMaxFixupSizeIncrease > kOriginalInstructionsSize) {
//printf ("Too many instructions eaten\n");
overridePossible = false;
}
if (!overridePossible) err = err_cannot_override;
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
#endif
// Make the original function implementation writable.
if( !err ) {
err = vm_protect( mach_task_self(),
(vm_address_t) originalFunctionPtr, 8, false,
(VM_PROT_ALL | VM_PROT_COPY) );
if( err )
err = vm_protect( mach_task_self(),
(vm_address_t) originalFunctionPtr, 8, false,
(VM_PROT_DEFAULT | VM_PROT_COPY) );
}
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
// Allocate and target the escape island to the overriding function.
BranchIsland *escapeIsland = NULL;
if( !err )
err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
#if defined(__ppc__) || defined(__POWERPC__)
if( !err )
err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
// Build the branch absolute instruction to the escape island.
long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
if( !err ) {
long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
}
#elif defined(__i386__) || defined(__x86_64__)
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
if( !err )
err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
// Build the jump relative instruction to the escape island
#endif
#if defined(__i386__) || defined(__x86_64__)
if (!err) {
uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
addressOffset = OSSwapInt32(addressOffset);
jumpRelativeInstruction |= 0xE900000000000000LL;
jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
}
#endif
// Optionally allocate & return the reentry island. This may contain relocated
// jmp instructions and so has all the same addressing reachability requirements
// the escape island has to the original function, except the escape island is
// technically our original function.
BranchIsland *reentryIsland = NULL;
if( !err && originalFunctionReentryIsland ) {
err = allocateBranchIsland( &reentryIsland, escapeIsland);
if( !err )
*originalFunctionReentryIsland = reentryIsland;
}
#if defined(__ppc__) || defined(__POWERPC__)
// Atomically:
// o If the reentry island was allocated:
// o Insert the original instruction into the reentry island.
// o Target the reentry island at the 2nd instruction of the
// original function.
// o Replace the original instruction with the branch absolute.
if( !err ) {
int escapeIslandEngaged = false;
do {
if( reentryIsland )
err = setBranchIslandTarget( reentryIsland,
(void*) (originalFunctionPtr+1), originalInstruction );
if( !err ) {
escapeIslandEngaged = CompareAndSwap( originalInstruction,
branchAbsoluteInstruction,
(UInt32*)originalFunctionPtr );
if( !escapeIslandEngaged ) {
// Someone replaced the instruction out from under us,
// re-read the instruction, make sure it's still not
// 'mfctr' and try again.
originalInstruction = *originalFunctionPtr;
if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
err = err_cannot_override;
}
}
} while( !err && !escapeIslandEngaged );
}
#elif defined(__i386__) || defined(__x86_64__)
// Atomically:
// o If the reentry island was allocated:
// o Insert the original instructions into the reentry island.
// o Target the reentry island at the first non-replaced
// instruction of the original function.
// o Replace the original first instructions with the jump relative.
//
// Note that on i386, we do not support someone else changing the code under our feet
if ( !err ) {
uint32_t offset = (uintptr_t)originalFunctionPtr - (uintptr_t)reentryIsland;
fixupInstructions(offset, originalInstructions,
originalInstructionCount, originalInstructionSizes );
if( reentryIsland )
err = setBranchIslandTarget_i386( reentryIsland,
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
// try making islands executable before planting the jmp
#if defined(__x86_64__) || defined(__i386__)
if( !err )
err = makeIslandExecutable(escapeIsland);
if( !err && reentryIsland )
err = makeIslandExecutable(reentryIsland);
#endif
if ( !err )
atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
}
#endif
// Clean up on error.
if( err ) {
if( reentryIsland )
freeBranchIsland( reentryIsland );
if( escapeIsland )
freeBranchIsland( escapeIsland );
}
return err;
}
/*******************************************************************************
*
* Implementation
*
*******************************************************************************/
#pragma mark -
#pragma mark (Implementation)
static bool jump_in_range(intptr_t from, intptr_t to) {
intptr_t field_value = to - from - 5;
int32_t field_value_32 = field_value;
return field_value == field_value_32;
}
/*******************************************************************************
Implementation: Allocates memory for a branch island.
@param island <- The allocated island.
@result <- mach_error_t
***************************************************************************/
static mach_error_t
allocateBranchIslandAux(
BranchIsland **island,
void *originalFunctionAddress,
bool forward)
{
assert( island );
assert( sizeof( BranchIsland ) <= kPageSize );
vm_map_t task_self = mach_task_self();
vm_address_t original_address = (vm_address_t) originalFunctionAddress;
vm_address_t address = original_address;
for (;;) {
vm_size_t vmsize = 0;
memory_object_name_t object = 0;
kern_return_t kr = 0;
vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
// Find the region the address is in.
#if __WORDSIZE == 32
vm_region_basic_info_data_t info;
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
kr = vm_region(task_self, &address, &vmsize, flavor,
(vm_region_info_t)&info, &info_count, &object);
#else
vm_region_basic_info_data_64_t info;
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
kr = vm_region_64(task_self, &address, &vmsize, flavor,
(vm_region_info_t)&info, &info_count, &object);
#endif
if (kr != KERN_SUCCESS)
return kr;
assert((address & (kPageSize - 1)) == 0);
// Go to the first page before or after this region
vm_address_t new_address = forward ? address + vmsize : address - kPageSize;
#if __WORDSIZE == 64
if(!jump_in_range(original_address, new_address))
break;
#endif
address = new_address;
// Try to allocate this page.
kr = vm_allocate(task_self, &address, kPageSize, 0);
if (kr == KERN_SUCCESS) {
*island = (BranchIsland*) address;
return err_none;
}
if (kr != KERN_NO_SPACE)
return kr;
}
return KERN_NO_SPACE;
}
static mach_error_t
allocateBranchIsland(
BranchIsland **island,
void *originalFunctionAddress)
{
mach_error_t err =
allocateBranchIslandAux(island, originalFunctionAddress, true);
if (!err)
return err;
return allocateBranchIslandAux(island, originalFunctionAddress, false);
}
/*******************************************************************************
Implementation: Deallocates memory for a branch island.
@param island -> The island to deallocate.
@result <- mach_error_t
***************************************************************************/
mach_error_t
freeBranchIsland(
BranchIsland *island )
{
assert( island );
assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
assert( sizeof( BranchIsland ) <= kPageSize );
return vm_deallocate( mach_task_self(), (vm_address_t) island,
kPageSize );
}
/*******************************************************************************
Implementation: Sets the branch island's target, with an optional
instruction.
@param island -> The branch island to insert target into.
@param branchTo -> The address of the target.
@param instruction -> Optional instruction to execute prior to branch. Set
to zero for nop.
@result <- mach_error_t
***************************************************************************/
#if defined(__ppc__) || defined(__POWERPC__)
mach_error_t
setBranchIslandTarget(
BranchIsland *island,
const void *branchTo,
long instruction )
{
// Copy over the template code.
bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
// Fill in the address.
((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
((short*)island->instructions)[kAddressHi]
= (((long) branchTo) >> 16) & 0x0000FFFF;
// Fill in the (optional) instuction.
if( instruction != 0 ) {
((short*)island->instructions)[kInstructionLo]
= instruction & 0x0000FFFF;
((short*)island->instructions)[kInstructionHi]
= (instruction >> 16) & 0x0000FFFF;
}
//MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
return err_none;
}
#endif
#if defined(__i386__)
mach_error_t
setBranchIslandTarget_i386(
BranchIsland *island,
const void *branchTo,
char* instructions )
{
// Copy over the template code.
bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
// copy original instructions
if (instructions) {
bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
}
// Fill in the address.
int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
*((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
return err_none;
}
#elif defined(__x86_64__)
mach_error_t
setBranchIslandTarget_i386(
BranchIsland *island,
const void *branchTo,
char* instructions )
{
// Copy over the template code.
bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
// Copy original instructions.
if (instructions) {
bcopy (instructions, island->instructions, kOriginalInstructionsSize);
}
// Fill in the address.
*((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
return err_none;
}
#endif
#if defined(__i386__) || defined(__x86_64__)
// simplistic instruction matching
typedef struct {
unsigned int length; // max 15
unsigned char mask[15]; // sequence of bytes in memory order
unsigned char constraint[15]; // sequence of bytes in memory order
} AsmInstructionMatch;
#if defined(__i386__)
static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
{ 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xFF}, {0x55} }, // push %esp
{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
{ 0x1, {0xFF}, {0x53} }, // push %ebx
{ 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
{ 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
{ 0x1, {0xFF}, {0x57} }, // push %edi
{ 0x1, {0xFF}, {0x56} }, // push %esi
{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
{ 0x6, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xE8, 0x00, 0x00, 0x00, 0x00, 0x58} }, // call $imm; pop %eax
{ 0x0 }
};
#elif defined(__x86_64__)
static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xF8}, {0x50} }, // push %rX
{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
{ 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
{ 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} }, // movsbl %sil, %ecx
{ 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
{ 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
{ 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
{ 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %eax
//leaq offset(%rip),%rax
{ 0x7, {0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x48, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00} },
{ 0x0 }
};
#endif
static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
{
Boolean match = true;
size_t i;
for (i=0; i<instruction->length; i++) {
unsigned char mask = instruction->mask[i];
unsigned char constraint = instruction->constraint[i];
unsigned char codeValue = code[i];
match = ((codeValue & mask) == constraint);
if (!match) break;
}
return match;
}
#if defined(__i386__) || defined(__x86_64__)
static Boolean
eatKnownInstructions(
unsigned char *code,
uint64_t *newInstruction,
int *howManyEaten,
char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes )
{
Boolean allInstructionsKnown = true;
int totalEaten = 0;
unsigned char* ptr = code;
int remainsToEat = 5; // a JMP instruction takes 5 bytes
int instructionIndex = 0;
if (howManyEaten) *howManyEaten = 0;
if (originalInstructionCount) *originalInstructionCount = 0;
while (remainsToEat > 0) {
Boolean curInstructionKnown = false;
// See if instruction matches one we know
AsmInstructionMatch* curInstr = possibleInstructions;
do {
if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
curInstr++;
} while (curInstr->length > 0);
// if all instruction matches failed, we don't know current instruction then, stop here
if (!curInstructionKnown) {
allInstructionsKnown = false;
fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
break;
}
// At this point, we've matched curInstr
int eaten = curInstr->length;
ptr += eaten;
remainsToEat -= eaten;
totalEaten += eaten;
if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
instructionIndex += 1;
if (originalInstructionCount) *originalInstructionCount = instructionIndex;
}
if (howManyEaten) *howManyEaten = totalEaten;
if (originalInstructions) {
Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
if (enoughSpaceForOriginalInstructions) {
memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
bcopy(code, originalInstructions, totalEaten);
} else {
// printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
return false;
}
}
if (allInstructionsKnown) {
// save last 3 bytes of first 64bits of codre we'll replace
uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
}
return allInstructionsKnown;
}
static void
fixupInstructions(
uint32_t offset,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes )
{
// The start of "leaq offset(%rip),%rax"
static const uint8_t LeaqHeader[] = {0x48, 0x8d, 0x05};
int index;
for (index = 0;index < instructionCount;index += 1)
{
if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
{
uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
*jumpOffsetPtr += offset;
}
// leaq offset(%rip),%rax
if (memcmp(instructionsToFix, LeaqHeader, 3) == 0) {
uint32_t *LeaqOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 3);
*LeaqOffsetPtr += offset;
}
// 32-bit call relative to the next addr; pop %eax
if (*(uint8_t*)instructionsToFix == 0xE8)
{
// Just this call is larger than the jump we use, so we
// know this is the last instruction.
assert(index == (instructionCount - 1));
assert(instructionSizes[index] == 6);
// Insert "addl $offset, %eax" in the end so that when
// we jump to the rest of the function %eax has the
// value it would have if eip had been pushed by the
// call in its original position.
uint8_t *op = instructionsToFix;
op += 6;
*op = 0x05; // addl
uint32_t *addImmPtr = (uint32_t*)(op + 1);
*addImmPtr = offset;
}
instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
}
}
#endif
#if defined(__i386__)
__asm(
".text;"
".align 2, 0x90;"
"_atomic_mov64:;"
" pushl %ebp;"
" movl %esp, %ebp;"
" pushl %esi;"
" pushl %ebx;"
" pushl %ecx;"
" pushl %eax;"
" pushl %edx;"
// atomic push of value to an address
// we use cmpxchg8b, which compares content of an address with
// edx:eax. If they are equal, it atomically puts 64bit value
// ecx:ebx in address.
// We thus put contents of address in edx:eax to force ecx:ebx
// in address
" mov 8(%ebp), %esi;" // esi contains target address
" mov 12(%ebp), %ebx;"
" mov 16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
" mov (%esi), %eax;"
" mov 4(%esi), %edx;" // edx:eax now contains value currently contained in target address
" lock; cmpxchg8b (%esi);" // atomic move.
// restore registers
" popl %edx;"
" popl %eax;"
" popl %ecx;"
" popl %ebx;"
" popl %esi;"
" popl %ebp;"
" ret"
);
#elif defined(__x86_64__)
void atomic_mov64(
uint64_t *targetAddress,
uint64_t value )
{
*targetAddress = value;
}
#endif
#endif

121
xpcom/build/mach_override.h Normal file
View file

@ -0,0 +1,121 @@
/*******************************************************************************
mach_override.h
Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
Some rights reserved: <http://opensource.org/licenses/mit-license.php>
***************************************************************************/
/***************************************************************************//**
@mainpage mach_override
@author Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
This package, coded in C to the Mach API, allows you to override ("patch")
program- and system-supplied functions at runtime. You can fully replace
functions with your implementations, or merely head- or tail-patch the
original implementations.
Use it by #include'ing mach_override.h from your .c, .m or .mm file(s).
@todo Discontinue use of Carbon's MakeDataExecutable() and
CompareAndSwap() calls and start using the Mach equivalents, if they
exist. If they don't, write them and roll them in. That way, this
code will be pure Mach, which will make it easier to use everywhere.
Update: MakeDataExecutable() has been replaced by
msync(MS_INVALIDATE). There is an OSCompareAndSwap in libkern, but
I'm currently unsure if I can link against it. May have to roll in
my own version...
@todo Stop using an entire 4K high-allocated VM page per 28-byte escape
branch island. Done right, this will dramatically speed up escape
island allocations when they number over 250. Then again, if you're
overriding more than 250 functions, maybe speed isn't your main
concern...
@todo Add detection of: b, bl, bla, bc, bcl, bcla, bcctrl, bclrl
first-instructions. Initially, we should refuse to override
functions beginning with these instructions. Eventually, we should
dynamically rewrite them to make them position-independent.
@todo Write mach_unoverride(), which would remove an override placed on a
function. Must be multiple-override aware, which means an almost
complete rewrite under the covers, because the target address can't
be spread across two load instructions like it is now since it will
need to be atomically updatable.
@todo Add non-rentry variants of overrides to test_mach_override.
***************************************************************************/
#ifndef _mach_override_
#define _mach_override_
#include <sys/types.h>
#include <mach/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
Returned if the function to be overrided begins with a 'mfctr' instruction.
*/
#define err_cannot_override (err_local|1)
/************************************************************************************//**
Dynamically overrides the function implementation referenced by
originalFunctionAddress with the implentation pointed to by overrideFunctionAddress.
Optionally returns a pointer to a "reentry island" which, if jumped to, will resume
the original implementation.
@param originalFunctionAddress -> Required address of the function to
override (with overrideFunctionAddress).
@param overrideFunctionAddress -> Required address to the overriding
function.
@param originalFunctionReentryIsland <- Optional pointer to pointer to the
reentry island. Can be nullptr.
@result <- err_cannot_override if the original
function's implementation begins with
the 'mfctr' instruction.
************************************************************************************/
mach_error_t
mach_override_ptr(
void *originalFunctionAddress,
const void *overrideFunctionAddress,
void **originalFunctionReentryIsland );
/************************************************************************************//**
************************************************************************************/
#ifdef __cplusplus
#define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR ) \
{ \
static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS; \
static bool ORIGINAL_FUNCTION_NAME##_overriden = false; \
class mach_override_class__##ORIGINAL_FUNCTION_NAME { \
public: \
static kern_return_t override(void *originalFunctionPtr) { \
kern_return_t result = err_none; \
if (!ORIGINAL_FUNCTION_NAME##_overriden) { \
ORIGINAL_FUNCTION_NAME##_overriden = true; \
result = mach_override_ptr( (void*)originalFunctionPtr, \
(void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement, \
(void**)&ORIGINAL_FUNCTION_NAME##_reenter ); \
} \
return result; \
} \
static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS {
#define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME ) \
} \
}; \
\
err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME); \
}
#endif
#ifdef __cplusplus
}
#endif
#endif // _mach_override_

102
xpcom/build/moz.build Normal file
View file

@ -0,0 +1,102 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsXPCOM.h',
'nsXPCOMCID.h',
'nsXPCOMCIDInternal.h',
'nsXREAppData.h',
'nsXULAppAPI.h',
'XREChildData.h',
'xrecore.h',
'XREShellData.h',
]
EXPORTS.mozilla += [
'FileLocation.h',
'IOInterposer.h',
'LateWriteChecks.h',
'Omnijar.h',
'PoisonIOInterposer.h',
'ServiceList.h',
'Services.h',
'XPCOM.h',
]
if CONFIG['OS_ARCH'] == 'WINNT':
EXPORTS += ['nsWindowsDllInterceptor.h']
EXPORTS.mozilla += ['perfprobe.h']
SOURCES += [
'perfprobe.cpp',
'PoisonIOInterposerBase.cpp',
'PoisonIOInterposerWin.cpp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
UNIFIED_SOURCES += [
'PoisonIOInterposerBase.cpp',
'PoisonIOInterposerMac.cpp',
]
SOURCES += ['mach_override.c']
SOURCES['mach_override.c'].flags += ['-Wno-unused-function']
else:
SOURCES += ['PoisonIOInterposerStub.cpp']
include('../glue/objs.mozbuild')
UNIFIED_SOURCES += xpcom_gluens_src_cppsrcs
UNIFIED_SOURCES += xpcom_glue_src_cppsrcs
UNIFIED_SOURCES += [
'FrozenFunctions.cpp',
'IOInterposer.cpp',
'LateWriteChecks.cpp',
'MainThreadIOLogger.cpp',
'nsXPCOMStrings.cpp',
'Services.cpp',
'XPCOMInit.cpp',
]
if CONFIG['OS_ARCH'] != 'WINNT':
SOURCES += [
'NSPRInterposer.cpp',
]
# FileLocation.cpp and Omnijar.cpp cannot be built in unified mode because they
# use plarena.h.
SOURCES += [
'FileLocation.cpp',
'Omnijar.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
DEFINES['_IMPL_NS_STRINGAPI'] = True
DEFINES['OMNIJAR_NAME'] = CONFIG['OMNIJAR_NAME']
if CONFIG['MOZ_ICU_DATA_ARCHIVE']:
DEFINES['MOZ_ICU_DATA_ARCHIVE'] = True
LOCAL_INCLUDES += [
'!..',
'../base',
'../components',
'../ds',
'../glue',
'../io',
'../reflect/xptinfo',
'../threads',
'/chrome',
'/docshell/base',
]
if CONFIG['MOZ_VPX']:
LOCAL_INCLUDES += [
'/media/libvpx',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
CXXFLAGS += CONFIG['TK_CFLAGS']

File diff suppressed because it is too large Load diff

433
xpcom/build/nsXPCOM.h Normal file
View file

@ -0,0 +1,433 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 nsXPCOM_h__
#define nsXPCOM_h__
#include "nscore.h"
#include "nsXPCOMCID.h"
#ifdef __cplusplus
#define DECL_CLASS(c) class c
#define DECL_STRUCT(c) struct c
#else
#define DECL_CLASS(c) typedef struct c c
#define DECL_STRUCT(c) typedef struct c c
#endif
DECL_CLASS(nsAString);
DECL_CLASS(nsACString);
DECL_CLASS(nsISupports);
DECL_CLASS(nsIModule);
DECL_CLASS(nsIComponentManager);
DECL_CLASS(nsIComponentRegistrar);
DECL_CLASS(nsIServiceManager);
DECL_CLASS(nsIFile);
DECL_CLASS(nsILocalFile);
DECL_CLASS(nsIDirectoryServiceProvider);
DECL_CLASS(nsIMemory);
DECL_CLASS(nsIDebug2);
#ifdef __cplusplus
namespace mozilla {
struct Module;
} // namespace mozilla
#endif
/**
* Initialises XPCOM. You must call one of the NS_InitXPCOM methods
* before proceeding to use xpcom. The one exception is that you may
* call NS_NewLocalFile to create a nsIFile.
*
* @note Use <CODE>NS_NewLocalFile</CODE> or <CODE>NS_NewNativeLocalFile</CODE>
* to create the file object you supply as the bin directory path in this
* call. The function may be safely called before the rest of XPCOM or
* embedding has been initialised.
*
* @param aResult The service manager. You may pass null.
*
* @param aBinDirectory The directory containing the component
* registry and runtime libraries;
* or use <CODE>nullptr</CODE> to use the working
* directory.
*
* @param aAppFileLocationProvider The object to be used by Gecko that
* specifies to Gecko where to find profiles, the
* component registry preferences and so on; or use
* <CODE>nullptr</CODE> for the default behaviour.
*
* @see NS_NewLocalFile
* @see nsIFile
* @see nsIDirectoryServiceProvider
*
* @return NS_OK for success;
* NS_ERROR_NOT_INITIALIZED if static globals were not initialized,
* which can happen if XPCOM is reloaded, but did not completly
* shutdown. Other error codes indicate a failure during
* initialisation.
*/
XPCOM_API(nsresult)
NS_InitXPCOM2(nsIServiceManager** aResult,
nsIFile* aBinDirectory,
nsIDirectoryServiceProvider* aAppFileLocationProvider);
/**
* Initialize only minimal components of XPCOM. This ensures nsThreadManager,
* logging, and timers will work.
*/
XPCOM_API(nsresult)
NS_InitMinimalXPCOM();
/**
* Shutdown XPCOM. You must call this method after you are finished
* using xpcom.
*
* @param aServMgr The service manager which was returned by NS_InitXPCOM.
* This will release servMgr. You may pass null.
*
* @return NS_OK for success;
* other error codes indicate a failure during initialisation.
*/
XPCOM_API(nsresult) NS_ShutdownXPCOM(nsIServiceManager* aServMgr);
/**
* Public Method to access to the service manager.
*
* @param aResult Interface pointer to the service manager
*
* @return NS_OK for success;
* other error codes indicate a failure during initialisation.
*/
XPCOM_API(nsresult) NS_GetServiceManager(nsIServiceManager** aResult);
/**
* Public Method to access to the component manager.
*
* @param aResult Interface pointer to the service
*
* @return NS_OK for success;
* other error codes indicate a failure during initialisation.
*/
XPCOM_API(nsresult) NS_GetComponentManager(nsIComponentManager** aResult);
/**
* Public Method to access to the component registration manager.
*
* @param aResult Interface pointer to the service
*
* @return NS_OK for success;
* other error codes indicate a failure during initialisation.
*/
XPCOM_API(nsresult) NS_GetComponentRegistrar(nsIComponentRegistrar** aResult);
/**
* Public Method to access to the memory manager. See nsIMemory
*
* @param aResult Interface pointer to the memory manager
*
* @return NS_OK for success;
* other error codes indicate a failure during initialisation.
*/
XPCOM_API(nsresult) NS_GetMemoryManager(nsIMemory** aResult);
/**
* Public Method to create an instance of a nsIFile. This function
* may be called prior to NS_InitXPCOM.
*
* @param aPath
* A string which specifies a full file path to a
* location. Relative paths will be treated as an
* error (NS_ERROR_FILE_UNRECOGNIZED_PATH).
* |NS_NewNativeLocalFile|'s path must be in the
* filesystem charset.
* @param aFollowLinks
* This attribute will determine if the nsLocalFile will auto
* resolve symbolic links. By default, this value will be false
* on all non unix systems. On unix, this attribute is effectively
* a noop.
* @param aResult Interface pointer to a new instance of an nsIFile
*
* @return NS_OK for success;
* other error codes indicate a failure.
*/
#ifdef __cplusplus
XPCOM_API(nsresult) NS_NewLocalFile(const nsAString& aPath,
bool aFollowLinks,
nsIFile** aResult);
XPCOM_API(nsresult) NS_NewNativeLocalFile(const nsACString& aPath,
bool aFollowLinks,
nsIFile** aResult);
#endif
/**
* Allocator functions for the standalone glue.
* Do not use outside the xpcom glue code.
* Use moz_xmalloc/moz_xrealloc/free, or new/delete instead.
*/
#ifdef XPCOM_GLUE
/**
* Allocates a block of memory of a particular size. If the memory cannot
* be allocated (because of an out-of-memory condition), the process aborts.
*
* @param aSize The size of the block to allocate
* @result The block of memory
* @note This function is thread-safe.
*/
XPCOM_API(void*) NS_Alloc(size_t aSize);
/**
* Reallocates a block of memory to a new size.
*
* @param aPtr The block of memory to reallocate. This block must originally
have been allocated by NS_Alloc or NS_Realloc
* @param aSize The new size. If 0, frees the block like NS_Free
* @result The reallocated block of memory
* @note This function is thread-safe.
*
* If aPtr is null, this function behaves like NS_Alloc.
* If s is the size of the block to which aPtr points, the first min(s, size)
* bytes of aPtr's block are copied to the new block. If the allocation
* succeeds, aPtr is freed and a pointer to the new block is returned. If the
* allocation fails, the process aborts.
*/
XPCOM_API(void*) NS_Realloc(void* aPtr, size_t aSize);
/**
* Frees a block of memory. Null is a permissible value, in which case no
* action is taken.
*
* @param aPtr The block of memory to free. This block must originally have
* been allocated by NS_Alloc or NS_Realloc
* @note This function is thread-safe.
*/
XPCOM_API(void) NS_Free(void* aPtr);
#else
#define NS_Alloc moz_xmalloc
#define NS_Realloc moz_xrealloc
#define NS_Free free
#endif
/**
* Support for warnings, assertions, and debugging breaks.
*/
enum
{
NS_DEBUG_WARNING = 0,
NS_DEBUG_ASSERTION = 1,
NS_DEBUG_BREAK = 2,
NS_DEBUG_ABORT = 3
};
/**
* Print a runtime assertion. This function is available in both debug and
* release builds.
*
* @note Based on the value of aSeverity and the XPCOM_DEBUG_BREAK
* environment variable, this function may cause the application to
* print the warning, print a stacktrace, break into a debugger, or abort
* immediately.
*
* @param aSeverity A NS_DEBUG_* value
* @param aStr A readable error message (ASCII, may be null)
* @param aExpr The expression evaluated (may be null)
* @param aFile The source file containing the assertion (may be null)
* @param aLine The source file line number (-1 indicates no line number)
*/
XPCOM_API(void) NS_DebugBreak(uint32_t aSeverity,
const char* aStr, const char* aExpr,
const char* aFile, int32_t aLine);
/**
* Perform a stack-walk to a debugging log under various
* circumstances. Used to aid debugging of leaked object graphs.
*
* The NS_Log* functions are available in both debug and release
* builds of XPCOM, but the output will be useless unless binary
* debugging symbols for all modules in the stacktrace are available.
*/
/**
* By default, refcount logging is enabled at NS_InitXPCOM and
* refcount statistics are printed at NS_ShutdownXPCOM. NS_LogInit and
* NS_LogTerm allow applications to enable logging earlier and delay
* printing of logging statistics. They should always be used as a
* matched pair.
*/
XPCOM_API(void) NS_LogInit();
XPCOM_API(void) NS_LogTerm();
#ifdef __cplusplus
/**
* A helper class that calls NS_LogInit in its constructor and
* NS_LogTerm in its destructor.
*/
class ScopedLogging
{
public:
ScopedLogging()
{
NS_LogInit();
}
~ScopedLogging()
{
NS_LogTerm();
}
};
#endif
/**
* Log construction and destruction of objects. Processing tools can use the
* stacktraces printed by these functions to identify objects that are being
* leaked.
*
* @param aPtr A pointer to the concrete object.
* @param aTypeName The class name of the type
* @param aInstanceSize The size of the type
*/
XPCOM_API(void) NS_LogCtor(void* aPtr, const char* aTypeName,
uint32_t aInstanceSize);
XPCOM_API(void) NS_LogDtor(void* aPtr, const char* aTypeName,
uint32_t aInstanceSize);
/**
* Log a stacktrace when an XPCOM object's refcount is incremented or
* decremented. Processing tools can use the stacktraces printed by these
* functions to identify objects that were leaked due to XPCOM references.
*
* @param aPtr A pointer to the concrete object
* @param aNewRefCnt The new reference count.
* @param aTypeName The class name of the type
* @param aInstanceSize The size of the type
*/
XPCOM_API(void) NS_LogAddRef(void* aPtr, nsrefcnt aNewRefCnt,
const char* aTypeName, uint32_t aInstanceSize);
XPCOM_API(void) NS_LogRelease(void* aPtr, nsrefcnt aNewRefCnt,
const char* aTypeName);
/**
* Log reference counting performed by COMPtrs. Processing tools can
* use the stacktraces printed by these functions to simplify reports
* about leaked objects generated from the data printed by
* NS_LogAddRef/NS_LogRelease.
*
* @param aCOMPtr the address of the COMPtr holding a strong reference
* @param aObject the object being referenced by the COMPtr
*/
XPCOM_API(void) NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject);
XPCOM_API(void) NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject);
/**
* The XPCOM cycle collector analyzes and breaks reference cycles between
* participating XPCOM objects. All objects in the cycle must implement
* nsCycleCollectionParticipant to break cycles correctly.
*/
#ifdef __cplusplus
class nsCycleCollectionParticipant;
class nsCycleCollectingAutoRefCnt;
XPCOM_API(void) NS_CycleCollectorSuspect3(void* aPtr,
nsCycleCollectionParticipant* aCp,
nsCycleCollectingAutoRefCnt* aRefCnt,
bool* aShouldDelete);
#endif
/**
* Categories (in the category manager service) used by XPCOM:
*/
/**
* A category which is read after component registration but before
* the "xpcom-startup" notifications. Each category entry is treated
* as the contract ID of a service which implements
* nsIDirectoryServiceProvider. Each directory service provider is
* installed in the global directory service.
*/
#define XPCOM_DIRECTORY_PROVIDER_CATEGORY "xpcom-directory-providers"
/**
* A category which is read after component registration but before
* NS_InitXPCOM returns. Each category entry is treated as the contractID of
* a service: each service is instantiated, and if it implements nsIObserver
* the nsIObserver.observe method is called with the "xpcom-startup" topic.
*/
#define NS_XPCOM_STARTUP_CATEGORY "xpcom-startup"
/**
* Observer topics (in the observer service) used by XPCOM:
*/
/**
* At XPCOM startup after component registration is complete, the
* following topic is notified. In order to receive this notification,
* component must register their contract ID in the category manager,
*
* @see NS_XPCOM_STARTUP_CATEGORY
*/
#define NS_XPCOM_STARTUP_OBSERVER_ID "xpcom-startup"
/**
* At XPCOM shutdown, this topic is notified just before "xpcom-shutdown".
* Components should only use this to mark themselves as 'being destroyed'.
* Nothing should be dispatched to any event loop.
*/
#define NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID "xpcom-will-shutdown"
/**
* At XPCOM shutdown, this topic is notified. All components must
* release any interface references to objects in other modules when
* this topic is notified.
*/
#define NS_XPCOM_SHUTDOWN_OBSERVER_ID "xpcom-shutdown"
/**
* This topic is notified when an entry was added to a category in the
* category manager. The subject of the notification will be the name of
* the added entry as an nsISupportsCString, and the data will be the
* name of the category. The notification will occur on the main thread.
*/
#define NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID \
"xpcom-category-entry-added"
/**
* This topic is notified when an entry was removed from a category in the
* category manager. The subject of the notification will be the name of
* the removed entry as an nsISupportsCString, and the data will be the
* name of the category. The notification will occur on the main thread.
*/
#define NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID \
"xpcom-category-entry-removed"
/**
* This topic is notified when an a category was cleared in the category
* manager. The subject of the notification will be the category manager,
* and the data will be the name of the cleared category.
* The notification will occur on the main thread.
*/
#define NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID "xpcom-category-cleared"
XPCOM_API(nsresult) NS_GetDebug(nsIDebug2** aResult);
#endif

185
xpcom/build/nsXPCOMCID.h Normal file
View file

@ -0,0 +1,185 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 nsXPCOMCID_h__
#define nsXPCOMCID_h__
/**
* XPCOM Directory Service Contract ID
* The directory service provides ways to obtain file system locations. The
* directory service is a singleton.
*
* This contract supports the nsIDirectoryService and the nsIProperties
* interfaces.
*
*/
#define NS_DIRECTORY_SERVICE_CONTRACTID "@mozilla.org/file/directory_service;1"
/**
* XPCOM File
* The file abstraction provides ways to obtain and access files and
* directories located on the local system.
*
* This contract supports the nsIFile interface.
* This contract may also support platform specific interfaces such as
* nsILocalFileMac on platforms where additional interfaces are required.
*
*/
#define NS_LOCAL_FILE_CONTRACTID "@mozilla.org/file/local;1"
/**
* XPCOM Category Manager Contract ID
* The contract supports the nsICategoryManager interface. The
* category manager is a singleton.
* The "enumerateCategory" method of nsICategoryManager will return an object
* that implements nsIUTF8StringEnumerator. In addition, the enumerator will
* return the entries in sorted order (sorted by byte comparison).
*/
#define NS_CATEGORYMANAGER_CONTRACTID "@mozilla.org/categorymanager;1"
/**
* XPCOM Properties Object Contract ID
* Simple mapping object which supports the nsIProperties interface.
*/
#define NS_PROPERTIES_CONTRACTID "@mozilla.org/properties;1"
/**
* XPCOM Array Object ContractID
* Simple array implementation which supports the nsIArray and
* nsIMutableArray interfaces.
*/
#define NS_ARRAY_CONTRACTID "@mozilla.org/array;1"
/**
* Observer Service ContractID
* The observer service implements the global nsIObserverService object.
* It should be used from the main thread only.
*/
#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1"
/**
* IO utilities service contract id.
* This guarantees implementation of nsIIOUtil. Usable from any thread.
*/
#define NS_IOUTIL_CONTRACTID "@mozilla.org/io-util;1"
/**
* Memory reporter service CID
*/
#define NS_MEMORY_REPORTER_MANAGER_CONTRACTID "@mozilla.org/memory-reporter-manager;1"
/**
* Memory info dumper service CID
*/
#define NS_MEMORY_INFO_DUMPER_CONTRACTID "@mozilla.org/memory-info-dumper;1"
/**
* Status reporter service CID
*/
#define NS_STATUS_REPORTER_MANAGER_CONTRACTID "@mozilla.org/status-reporter-manager;1"
/**
* Cycle collector logger contract id
*/
#define NS_CYCLE_COLLECTOR_LOGGER_CONTRACTID "@mozilla.org/cycle-collector-logger;1"
/**
* nsMessageLoop contract id
*/
#define NS_MESSAGE_LOOP_CONTRACTID "@mozilla.org/message-loop;1"
#define NS_COMPARTMENT_INFO_CONTRACTID "@mozilla.org/compartment-info;1"
/**
* The following are the CIDs and Contract IDs of the nsISupports wrappers for
* primative types.
*/
#define NS_SUPPORTS_ID_CID \
{ 0xacf8dc40, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_ID_CONTRACTID "@mozilla.org/supports-id;1"
#define NS_SUPPORTS_CSTRING_CID \
{ 0xacf8dc41, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_CSTRING_CONTRACTID "@mozilla.org/supports-cstring;1"
#define NS_SUPPORTS_STRING_CID \
{ 0xacf8dc42, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_STRING_CONTRACTID "@mozilla.org/supports-string;1"
#define NS_SUPPORTS_PRBOOL_CID \
{ 0xacf8dc43, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRBOOL_CONTRACTID "@mozilla.org/supports-PRBool;1"
#define NS_SUPPORTS_PRUINT8_CID \
{ 0xacf8dc44, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT8_CONTRACTID "@mozilla.org/supports-PRUint8;1"
#define NS_SUPPORTS_PRUINT16_CID \
{ 0xacf8dc46, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT16_CONTRACTID "@mozilla.org/supports-PRUint16;1"
#define NS_SUPPORTS_PRUINT32_CID \
{ 0xacf8dc47, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT32_CONTRACTID "@mozilla.org/supports-PRUint32;1"
#define NS_SUPPORTS_PRUINT64_CID \
{ 0xacf8dc48, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT64_CONTRACTID "@mozilla.org/supports-PRUint64;1"
#define NS_SUPPORTS_PRTIME_CID \
{ 0xacf8dc49, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRTIME_CONTRACTID "@mozilla.org/supports-PRTime;1"
#define NS_SUPPORTS_CHAR_CID \
{ 0xacf8dc4a, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_CHAR_CONTRACTID "@mozilla.org/supports-char;1"
#define NS_SUPPORTS_PRINT16_CID \
{ 0xacf8dc4b, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRINT16_CONTRACTID "@mozilla.org/supports-PRInt16;1"
#define NS_SUPPORTS_PRINT32_CID \
{ 0xacf8dc4c, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRINT32_CONTRACTID "@mozilla.org/supports-PRInt32;1"
#define NS_SUPPORTS_PRINT64_CID \
{ 0xacf8dc4d, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRINT64_CONTRACTID "@mozilla.org/supports-PRInt64;1"
#define NS_SUPPORTS_FLOAT_CID \
{ 0xcbf86870, 0x4ac0, 0x11d3, \
{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
#define NS_SUPPORTS_FLOAT_CONTRACTID "@mozilla.org/supports-float;1"
#define NS_SUPPORTS_DOUBLE_CID \
{ 0xcbf86871, 0x4ac0, 0x11d3, \
{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
#define NS_SUPPORTS_DOUBLE_CONTRACTID "@mozilla.org/supports-double;1"
#define NS_SUPPORTS_VOID_CID \
{ 0xaf10f3e0, 0x568d, 0x11d3, \
{ 0xba, 0xf8, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
#define NS_SUPPORTS_VOID_CONTRACTID "@mozilla.org/supports-void;1"
#define NS_SUPPORTS_INTERFACE_POINTER_CID \
{ 0xA99FEBBA, 0x1DD1, 0x11B2, \
{ 0xA9, 0x43, 0xB0, 0x23, 0x34, 0xA6, 0xD0, 0x83 } }
#define NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID "@mozilla.org/supports-interface-pointer;1"
#endif

View file

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 nsXPCOMCIDInternal_h__
#define nsXPCOMCIDInternal_h__
#include "nsXPCOMCID.h"
/**
* A hashtable-based property bag component.
* @implements nsIWritablePropertyBag, nsIWritablePropertyBag2
*/
#define NS_HASH_PROPERTY_BAG_CID \
{ 0x678c50b8, 0x6bcb, 0x4ad0, \
{ 0xb9, 0xb8, 0xc8, 0x11, 0x75, 0x95, 0x51, 0x99 } }
#define NS_HASH_PROPERTY_BAG_CONTRACTID "@mozilla.org/hash-property-bag;1"
/**
* Factory for creating nsIUnicharInputStream
* @implements nsIUnicharInputStreamFactory
* @note nsIUnicharInputStream instances cannot be created via
* createInstance. Code must use one of the custom factory methods.
*/
#define NS_SIMPLE_UNICHAR_STREAM_FACTORY_CONTRACTID \
"@mozilla.org/xpcom/simple-unichar-stream-factory;1"
/**
* The global thread manager service. This component is a singleton.
* @implements nsIThreadManager
*/
#define NS_THREADMANAGER_CONTRACTID "@mozilla.org/thread-manager;1"
/**
* A thread pool component.
* @implements nsIThreadPool
*/
#define NS_THREADPOOL_CONTRACTID "@mozilla.org/thread-pool;1"
/**
* The contract id for the nsIXULAppInfo service.
*/
#define XULAPPINFO_SERVICE_CONTRACTID \
"@mozilla.org/xre/app-info;1"
/**
* The contract id for the nsIXULRuntime service.
*/
#define XULRUNTIME_SERVICE_CONTRACTID \
"@mozilla.org/xre/runtime;1"
#endif // nsXPCOMCIDInternal_h__

View file

@ -0,0 +1,317 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 nsXPCOMPrivate_h__
#define nsXPCOMPrivate_h__
#include "nscore.h"
#include "nsXPCOM.h"
#include "nsXPCOMStrings.h"
#include "xptcall.h"
class nsStringContainer;
class nsCStringContainer;
class nsPurpleBufferEntry;
/**
* During this shutdown notification all threads which run XPCOM code must
* be joined.
*/
#define NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID "xpcom-shutdown-threads"
/**
* During this shutdown notification all module loaders must unload XPCOM
* modules.
*/
#define NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID "xpcom-shutdown-loaders"
// PUBLIC
typedef nsresult (*InitFunc)(nsIServiceManager** aResult,
nsIFile* aBinDirectory,
nsIDirectoryServiceProvider* aAppFileLocationProvider);
typedef nsresult (*ShutdownFunc)(nsIServiceManager* aServMgr);
typedef nsresult (*GetServiceManagerFunc)(nsIServiceManager** aResult);
typedef nsresult (*GetComponentManagerFunc)(nsIComponentManager** aResult);
typedef nsresult (*GetComponentRegistrarFunc)(nsIComponentRegistrar** aResult);
typedef nsresult (*GetMemoryManagerFunc)(nsIMemory** aResult);
typedef nsresult (*NewLocalFileFunc)(const nsAString& aPath,
bool aFollowLinks, nsIFile** aResult);
typedef nsresult (*NewNativeLocalFileFunc)(const nsACString& aPath,
bool aFollowLinks,
nsIFile** aResult);
typedef nsresult (*GetDebugFunc)(nsIDebug2** aResult);
typedef nsresult (*StringContainerInitFunc)(nsStringContainer&);
typedef nsresult (*StringContainerInit2Func)(nsStringContainer&,
const char16_t*,
uint32_t, uint32_t);
typedef void (*StringContainerFinishFunc)(nsStringContainer&);
typedef uint32_t (*StringGetDataFunc)(const nsAString&, const char16_t**,
bool*);
typedef uint32_t (*StringGetMutableDataFunc)(nsAString&, uint32_t,
char16_t**);
typedef char16_t* (*StringCloneDataFunc)(const nsAString&);
typedef nsresult (*StringSetDataFunc)(nsAString&, const char16_t*, uint32_t);
typedef nsresult (*StringSetDataRangeFunc)(nsAString&, uint32_t, uint32_t,
const char16_t*, uint32_t);
typedef nsresult (*StringCopyFunc)(nsAString&, const nsAString&);
typedef void (*StringSetIsVoidFunc)(nsAString&, const bool);
typedef bool (*StringGetIsVoidFunc)(const nsAString&);
typedef nsresult (*CStringContainerInitFunc)(nsCStringContainer&);
typedef nsresult (*CStringContainerInit2Func)(nsCStringContainer&,
const char*,
uint32_t, uint32_t);
typedef void (*CStringContainerFinishFunc)(nsCStringContainer&);
typedef uint32_t (*CStringGetDataFunc)(const nsACString&, const char**,
bool*);
typedef uint32_t (*CStringGetMutableDataFunc)(nsACString&, uint32_t, char**);
typedef char* (*CStringCloneDataFunc)(const nsACString&);
typedef nsresult (*CStringSetDataFunc)(nsACString&, const char*, uint32_t);
typedef nsresult (*CStringSetDataRangeFunc)(nsACString&, uint32_t, uint32_t,
const char*, uint32_t);
typedef nsresult (*CStringCopyFunc)(nsACString&, const nsACString&);
typedef void (*CStringSetIsVoidFunc)(nsACString&, const bool);
typedef bool (*CStringGetIsVoidFunc)(const nsACString&);
typedef nsresult (*CStringToUTF16)(const nsACString&, nsCStringEncoding,
nsAString&);
typedef nsresult (*UTF16ToCString)(const nsAString&, nsCStringEncoding,
nsACString&);
typedef void* (*AllocFunc)(size_t aSize);
typedef void* (*ReallocFunc)(void* aPtr, size_t aSize);
typedef void (*FreeFunc)(void* aPtr);
typedef void (*DebugBreakFunc)(uint32_t aSeverity,
const char* aStr, const char* aExpr,
const char* aFile, int32_t aLine);
typedef void (*xpcomVoidFunc)();
typedef void (*LogAddRefFunc)(void*, nsrefcnt, const char*, uint32_t);
typedef void (*LogReleaseFunc)(void*, nsrefcnt, const char*);
typedef void (*LogCtorFunc)(void*, const char*, uint32_t);
typedef void (*LogCOMPtrFunc)(void*, nsISupports*);
typedef nsresult (*GetXPTCallStubFunc)(REFNSIID, nsIXPTCProxy*,
nsISomeInterface**);
typedef void (*DestroyXPTCallStubFunc)(nsISomeInterface*);
typedef nsresult (*InvokeByIndexFunc)(nsISupports*, uint32_t, uint32_t,
nsXPTCVariant*);
typedef bool (*CycleCollectorFunc)(nsISupports*);
typedef nsPurpleBufferEntry*
(*CycleCollectorSuspect2Func)(void*,
nsCycleCollectionParticipant*);
typedef bool (*CycleCollectorForget2Func)(nsPurpleBufferEntry*);
typedef void (*CycleCollectorSuspect3Func)(void*,
nsCycleCollectionParticipant*,
nsCycleCollectingAutoRefCnt*,
bool*);
// PRIVATE AND DEPRECATED
typedef NS_CALLBACK(XPCOMExitRoutine)(void);
typedef nsresult (*RegisterXPCOMExitRoutineFunc)(XPCOMExitRoutine aExitRoutine,
uint32_t aPriority);
typedef nsresult (*UnregisterXPCOMExitRoutineFunc)(XPCOMExitRoutine aExitRoutine);
typedef struct XPCOMFunctions
{
uint32_t version;
uint32_t size;
InitFunc init;
ShutdownFunc shutdown;
GetServiceManagerFunc getServiceManager;
GetComponentManagerFunc getComponentManager;
GetComponentRegistrarFunc getComponentRegistrar;
GetMemoryManagerFunc getMemoryManager;
NewLocalFileFunc newLocalFile;
NewNativeLocalFileFunc newNativeLocalFile;
RegisterXPCOMExitRoutineFunc registerExitRoutine;
UnregisterXPCOMExitRoutineFunc unregisterExitRoutine;
// Added for Mozilla 1.5
GetDebugFunc getDebug;
void* getTraceRefcnt;
// Added for Mozilla 1.7
StringContainerInitFunc stringContainerInit;
StringContainerFinishFunc stringContainerFinish;
StringGetDataFunc stringGetData;
StringSetDataFunc stringSetData;
StringSetDataRangeFunc stringSetDataRange;
StringCopyFunc stringCopy;
CStringContainerInitFunc cstringContainerInit;
CStringContainerFinishFunc cstringContainerFinish;
CStringGetDataFunc cstringGetData;
CStringSetDataFunc cstringSetData;
CStringSetDataRangeFunc cstringSetDataRange;
CStringCopyFunc cstringCopy;
CStringToUTF16 cstringToUTF16;
UTF16ToCString utf16ToCString;
StringCloneDataFunc stringCloneData;
CStringCloneDataFunc cstringCloneData;
// Added for Mozilla 1.8
AllocFunc allocFunc;
ReallocFunc reallocFunc;
FreeFunc freeFunc;
StringContainerInit2Func stringContainerInit2;
CStringContainerInit2Func cstringContainerInit2;
StringGetMutableDataFunc stringGetMutableData;
CStringGetMutableDataFunc cstringGetMutableData;
void* init3; // obsolete
// Added for Mozilla 1.9
DebugBreakFunc debugBreakFunc;
xpcomVoidFunc logInitFunc;
xpcomVoidFunc logTermFunc;
LogAddRefFunc logAddRefFunc;
LogReleaseFunc logReleaseFunc;
LogCtorFunc logCtorFunc;
LogCtorFunc logDtorFunc;
LogCOMPtrFunc logCOMPtrAddRefFunc;
LogCOMPtrFunc logCOMPtrReleaseFunc;
GetXPTCallStubFunc getXPTCallStubFunc;
DestroyXPTCallStubFunc destroyXPTCallStubFunc;
InvokeByIndexFunc invokeByIndexFunc;
CycleCollectorFunc cycleSuspectFunc; // obsolete: use cycleSuspect3Func
CycleCollectorFunc cycleForgetFunc; // obsolete
StringSetIsVoidFunc stringSetIsVoid;
StringGetIsVoidFunc stringGetIsVoid;
CStringSetIsVoidFunc cstringSetIsVoid;
CStringGetIsVoidFunc cstringGetIsVoid;
// Added for Mozilla 1.9.1
CycleCollectorSuspect2Func cycleSuspect2Func; // obsolete: use cycleSuspect3Func
CycleCollectorForget2Func cycleForget2Func; // obsolete
CycleCollectorSuspect3Func cycleSuspect3Func;
} XPCOMFunctions;
typedef nsresult (*GetFrozenFunctionsFunc)(XPCOMFunctions* aEntryPoints,
const char* aLibraryPath);
XPCOM_API(nsresult) NS_GetFrozenFunctions(XPCOMFunctions* aEntryPoints,
const char* aLibraryPath);
namespace mozilla {
/**
* Shutdown XPCOM. You must call this method after you are finished
* using xpcom.
*
* @param aServMgr The service manager which was returned by NS_InitXPCOM.
* This will release servMgr. You may pass null.
*
* @return NS_OK for success;
* other error codes indicate a failure during shutdown
*
*/
nsresult
ShutdownXPCOM(nsIServiceManager* aServMgr);
void SetICUMemoryFunctions();
/**
* C++ namespaced version of NS_LogTerm.
*/
void LogTerm();
} // namespace mozilla
// think hard before changing this
#define XPCOM_GLUE_VERSION 1
/* XPCOM Specific Defines
*
* XPCOM_DLL - name of the loadable xpcom library on disk.
* XUL_DLL - name of the loadable XUL library on disk
* XPCOM_SEARCH_KEY - name of the environment variable that can be
* modified to include additional search paths.
* GRE_CONF_NAME - Name of the GRE Configuration file
*/
#if defined(XP_WIN32)
#define XPCOM_SEARCH_KEY "PATH"
#define GRE_CONF_NAME "gre.config"
#define GRE_WIN_REG_LOC L"Software\\mozilla.org\\GRE"
#define XPCOM_DLL XUL_DLL
#define LXPCOM_DLL LXUL_DLL
#define XUL_DLL "xul.dll"
#define LXUL_DLL L"xul.dll"
#else // Unix
#include <limits.h> // for PATH_MAX
#define XPCOM_DLL XUL_DLL
// you have to love apple..
#ifdef XP_MACOSX
#define XPCOM_SEARCH_KEY "DYLD_LIBRARY_PATH"
#define GRE_FRAMEWORK_NAME "XUL.framework"
#define XUL_DLL "XUL"
#else
#define XPCOM_SEARCH_KEY "LD_LIBRARY_PATH"
#define XUL_DLL "libxul" MOZ_DLL_SUFFIX
#endif
#define GRE_CONF_NAME ".gre.config"
#define GRE_CONF_PATH "/etc/gre.conf"
#define GRE_CONF_DIR "/etc/gre.d"
#define GRE_USER_CONF_DIR ".gre.d"
#endif
#if defined(XP_WIN)
#define XPCOM_FILE_PATH_SEPARATOR "\\"
#define XPCOM_ENV_PATH_SEPARATOR ";"
#elif defined(XP_UNIX)
#define XPCOM_FILE_PATH_SEPARATOR "/"
#define XPCOM_ENV_PATH_SEPARATOR ":"
#else
#error need_to_define_your_file_path_separator_and_illegal_characters
#endif
#ifdef AIX
#include <sys/param.h>
#endif
#ifndef MAXPATHLEN
#ifdef PATH_MAX
#define MAXPATHLEN PATH_MAX
#elif defined(_MAX_PATH)
#define MAXPATHLEN _MAX_PATH
#elif defined(CCHMAXPATH)
#define MAXPATHLEN CCHMAXPATH
#else
#define MAXPATHLEN 1024
#endif
#endif
extern bool gXPCOMShuttingDown;
extern bool gXPCOMThreadsShutDown;
// Needed by the IPC layer from off the main thread
extern char16_t* gGREBinPath;
namespace mozilla {
namespace services {
/**
* Clears service cache, sets gXPCOMShuttingDown
*/
void Shutdown();
} // namespace services
} // namespace mozilla
#endif

View file

@ -0,0 +1,366 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "nsString.h"
#include "nsCharTraits.h"
#include "nsXPCOMStrings.h"
#include "nsNativeCharsetUtils.h"
/* ------------------------------------------------------------------------- */
XPCOM_API(nsresult)
NS_StringContainerInit(nsStringContainer& aContainer)
{
NS_ASSERTION(sizeof(nsStringContainer_base) >= sizeof(nsString),
"nsStringContainer is not large enough");
// use placement new to avoid heap allocating nsString object
new (&aContainer) nsString();
return NS_OK;
}
XPCOM_API(nsresult)
NS_StringContainerInit2(nsStringContainer& aContainer,
const char16_t* aData,
uint32_t aDataLength,
uint32_t aFlags)
{
NS_ASSERTION(sizeof(nsStringContainer_base) >= sizeof(nsString),
"nsStringContainer is not large enough");
if (!aData) {
new (&aContainer) nsString();
} else {
if (aDataLength == UINT32_MAX) {
if (NS_WARN_IF(aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING)) {
return NS_ERROR_INVALID_ARG;
}
aDataLength = nsCharTraits<char16_t>::length(aData);
}
if (aFlags & (NS_STRING_CONTAINER_INIT_DEPEND |
NS_STRING_CONTAINER_INIT_ADOPT)) {
uint32_t flags;
if (aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING) {
flags = nsSubstring::F_NONE;
} else {
flags = nsSubstring::F_TERMINATED;
}
if (aFlags & NS_STRING_CONTAINER_INIT_ADOPT) {
flags |= nsSubstring::F_OWNED;
}
new (&aContainer) nsSubstring(const_cast<char16_t*>(aData),
aDataLength, flags);
} else {
new (&aContainer) nsString(aData, aDataLength);
}
}
return NS_OK;
}
XPCOM_API(void)
NS_StringContainerFinish(nsStringContainer& aContainer)
{
// call the nsString dtor
reinterpret_cast<nsString*>(&aContainer)->~nsString();
}
/* ------------------------------------------------------------------------- */
XPCOM_API(uint32_t)
NS_StringGetData(const nsAString& aStr, const char16_t** aData,
bool* aTerminated)
{
if (aTerminated) {
*aTerminated = aStr.IsTerminated();
}
*aData = aStr.BeginReading();
return aStr.Length();
}
XPCOM_API(uint32_t)
NS_StringGetMutableData(nsAString& aStr, uint32_t aDataLength,
char16_t** aData)
{
if (aDataLength != UINT32_MAX) {
aStr.SetLength(aDataLength);
if (aStr.Length() != aDataLength) {
*aData = nullptr;
return 0;
}
}
*aData = aStr.BeginWriting();
return aStr.Length();
}
XPCOM_API(char16_t*)
NS_StringCloneData(const nsAString& aStr)
{
return ToNewUnicode(aStr);
}
XPCOM_API(nsresult)
NS_StringSetData(nsAString& aStr, const char16_t* aData, uint32_t aDataLength)
{
aStr.Assign(aData, aDataLength);
return NS_OK; // XXX report errors
}
XPCOM_API(nsresult)
NS_StringSetDataRange(nsAString& aStr,
uint32_t aCutOffset, uint32_t aCutLength,
const char16_t* aData, uint32_t aDataLength)
{
if (aCutOffset == UINT32_MAX) {
// append case
if (aData) {
aStr.Append(aData, aDataLength);
}
return NS_OK; // XXX report errors
}
if (aCutLength == UINT32_MAX) {
aCutLength = aStr.Length() - aCutOffset;
}
if (aData) {
if (aDataLength == UINT32_MAX) {
aStr.Replace(aCutOffset, aCutLength, nsDependentString(aData));
} else {
aStr.Replace(aCutOffset, aCutLength, Substring(aData, aDataLength));
}
} else {
aStr.Cut(aCutOffset, aCutLength);
}
return NS_OK; // XXX report errors
}
XPCOM_API(nsresult)
NS_StringCopy(nsAString& aDest, const nsAString& aSrc)
{
aDest.Assign(aSrc);
return NS_OK; // XXX report errors
}
XPCOM_API(void)
NS_StringSetIsVoid(nsAString& aStr, const bool aIsVoid)
{
aStr.SetIsVoid(aIsVoid);
}
XPCOM_API(bool)
NS_StringGetIsVoid(const nsAString& aStr)
{
return aStr.IsVoid();
}
/* ------------------------------------------------------------------------- */
XPCOM_API(nsresult)
NS_CStringContainerInit(nsCStringContainer& aContainer)
{
NS_ASSERTION(sizeof(nsStringContainer_base) >= sizeof(nsCString),
"nsCStringContainer is not large enough");
// use placement new to avoid heap allocating nsCString object
new (&aContainer) nsCString();
return NS_OK;
}
XPCOM_API(nsresult)
NS_CStringContainerInit2(nsCStringContainer& aContainer,
const char* aData,
uint32_t aDataLength,
uint32_t aFlags)
{
NS_ASSERTION(sizeof(nsStringContainer_base) >= sizeof(nsCString),
"nsStringContainer is not large enough");
if (!aData) {
new (&aContainer) nsCString();
} else {
if (aDataLength == UINT32_MAX) {
if (NS_WARN_IF(aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING)) {
return NS_ERROR_INVALID_ARG;
}
aDataLength = nsCharTraits<char>::length(aData);
}
if (aFlags & (NS_CSTRING_CONTAINER_INIT_DEPEND |
NS_CSTRING_CONTAINER_INIT_ADOPT)) {
uint32_t flags;
if (aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING) {
flags = nsCSubstring::F_NONE;
} else {
flags = nsCSubstring::F_TERMINATED;
}
if (aFlags & NS_CSTRING_CONTAINER_INIT_ADOPT) {
flags |= nsCSubstring::F_OWNED;
}
new (&aContainer) nsCSubstring(const_cast<char*>(aData),
aDataLength, flags);
} else {
new (&aContainer) nsCString(aData, aDataLength);
}
}
return NS_OK;
}
XPCOM_API(void)
NS_CStringContainerFinish(nsCStringContainer& aContainer)
{
// call the nsCString dtor
reinterpret_cast<nsCString*>(&aContainer)->~nsCString();
}
/* ------------------------------------------------------------------------- */
XPCOM_API(uint32_t)
NS_CStringGetData(const nsACString& aStr, const char** aData,
bool* aTerminated)
{
if (aTerminated) {
*aTerminated = aStr.IsTerminated();
}
*aData = aStr.BeginReading();
return aStr.Length();
}
XPCOM_API(uint32_t)
NS_CStringGetMutableData(nsACString& aStr, uint32_t aDataLength, char** aData)
{
if (aDataLength != UINT32_MAX) {
aStr.SetLength(aDataLength);
if (aStr.Length() != aDataLength) {
*aData = nullptr;
return 0;
}
}
*aData = aStr.BeginWriting();
return aStr.Length();
}
XPCOM_API(char*)
NS_CStringCloneData(const nsACString& aStr)
{
return ToNewCString(aStr);
}
XPCOM_API(nsresult)
NS_CStringSetData(nsACString& aStr, const char* aData, uint32_t aDataLength)
{
aStr.Assign(aData, aDataLength);
return NS_OK; // XXX report errors
}
XPCOM_API(nsresult)
NS_CStringSetDataRange(nsACString& aStr,
uint32_t aCutOffset, uint32_t aCutLength,
const char* aData, uint32_t aDataLength)
{
if (aCutOffset == UINT32_MAX) {
// append case
if (aData) {
aStr.Append(aData, aDataLength);
}
return NS_OK; // XXX report errors
}
if (aCutLength == UINT32_MAX) {
aCutLength = aStr.Length() - aCutOffset;
}
if (aData) {
if (aDataLength == UINT32_MAX) {
aStr.Replace(aCutOffset, aCutLength, nsDependentCString(aData));
} else {
aStr.Replace(aCutOffset, aCutLength, Substring(aData, aDataLength));
}
} else {
aStr.Cut(aCutOffset, aCutLength);
}
return NS_OK; // XXX report errors
}
XPCOM_API(nsresult)
NS_CStringCopy(nsACString& aDest, const nsACString& aSrc)
{
aDest.Assign(aSrc);
return NS_OK; // XXX report errors
}
XPCOM_API(void)
NS_CStringSetIsVoid(nsACString& aStr, const bool aIsVoid)
{
aStr.SetIsVoid(aIsVoid);
}
XPCOM_API(bool)
NS_CStringGetIsVoid(const nsACString& aStr)
{
return aStr.IsVoid();
}
/* ------------------------------------------------------------------------- */
XPCOM_API(nsresult)
NS_CStringToUTF16(const nsACString& aSrc,
nsCStringEncoding aSrcEncoding,
nsAString& aDest)
{
switch (aSrcEncoding) {
case NS_CSTRING_ENCODING_ASCII:
CopyASCIItoUTF16(aSrc, aDest);
break;
case NS_CSTRING_ENCODING_UTF8:
CopyUTF8toUTF16(aSrc, aDest);
break;
case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM:
NS_CopyNativeToUnicode(aSrc, aDest);
break;
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
return NS_OK; // XXX report errors
}
XPCOM_API(nsresult)
NS_UTF16ToCString(const nsAString& aSrc,
nsCStringEncoding aDestEncoding,
nsACString& aDest)
{
switch (aDestEncoding) {
case NS_CSTRING_ENCODING_ASCII:
LossyCopyUTF16toASCII(aSrc, aDest);
break;
case NS_CSTRING_ENCODING_UTF8:
CopyUTF16toUTF8(aSrc, aDest);
break;
case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM:
NS_CopyUnicodeToNative(aSrc, aDest);
break;
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
return NS_OK; // XXX report errors
}

164
xpcom/build/nsXREAppData.h Normal file
View file

@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 nsXREAppData_h
#define nsXREAppData_h
#include <stdint.h>
#include "mozilla/Attributes.h"
class nsIFile;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
namespace sandbox {
class BrokerServices;
}
#endif
/**
* Application-specific data needed to start the apprunner.
*
* @note When this structure is allocated and manipulated by XRE_CreateAppData,
* string fields will be allocated with moz_xmalloc, and interface pointers
* are strong references.
*/
struct nsXREAppData
{
/**
* This should be set to sizeof(nsXREAppData). This structure may be
* extended in future releases, and this ensures that binary compatibility
* is maintained.
*/
uint32_t size;
/**
* The directory of the application to be run. May be null if the
* xulrunner and the app are installed into the same directory.
*/
nsIFile* MOZ_NON_OWNING_REF directory;
/**
* The name of the application vendor. This must be ASCII, and is normally
* mixed-case, e.g. "Mozilla". Optional (may be null), but highly
* recommended. Must not be the empty string.
*/
const char* vendor;
/**
* The name of the application. This must be ASCII, and is normally
* mixed-case, e.g. "Firefox". Required (must not be null or an empty
* string).
*/
const char* name;
/**
* The internal name of the application for remoting purposes. When left
* unspecified, "name" is used instead. This must be ASCII, and is normally
* lowercase, e.g. "firefox". Optional (may be null but not an empty string).
*/
const char* remotingName;
/**
* The major version, e.g. "0.8.0+". Optional (may be null), but
* required for advanced application features such as the extension
* manager and update service. Must not be the empty string.
*/
const char* version;
/**
* The application's build identifier, e.g. "2004051604"
*/
const char* buildID;
/**
* The application's UUID. Used by the extension manager to determine
* compatible extensions. Optional, but required for advanced application
* features such as the extension manager and update service.
*
* This has traditionally been in the form
* "{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}" but for new applications
* a more readable form is encouraged: "appname@vendor.tld". Only
* the following characters are allowed: a-z A-Z 0-9 - . @ _ { } *
*/
const char* ID;
/**
* The copyright information to print for the -h commandline flag,
* e.g. "Copyright (c) 2003 mozilla.org".
*/
const char* copyright;
/**
* Combination of NS_XRE_ prefixed flags (defined below).
*/
uint32_t flags;
/**
* The location of the XRE. XRE_main may not be able to figure this out
* programatically.
*/
nsIFile* MOZ_NON_OWNING_REF xreDirectory;
/**
* The minimum/maximum compatible XRE version.
*/
const char* minVersion;
const char* maxVersion;
/**
* The server URL to send crash reports to.
*/
const char* crashReporterURL;
/**
* The profile directory that will be used. Optional (may be null). Must not
* be the empty string, must be ASCII. The path is split into components
* along the path separator characters '/' and '\'.
*
* The application data directory ("UAppData", see below) is normally
* composed as follows, where $HOME is platform-specific:
*
* UAppData = $HOME[/$vendor]/$name
*
* If present, the 'profile' string will be used instead of the combination of
* vendor and name as follows:
*
* UAppData = $HOME/$profile
*/
const char* profile;
/**
* The application name to use in the User Agent string.
*/
const char* UAName;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
/**
* Chromium sandbox BrokerServices.
*/
sandbox::BrokerServices* sandboxBrokerServices;
#endif
};
/**
* Indicates whether or not the profile migrator service may be
* invoked at startup when creating a profile.
*/
#define NS_XRE_ENABLE_PROFILE_MIGRATOR (1 << 1)
/**
* Indicates the Windows DLL Blocklist initialized properly. For testing
* purposes only. Set in nsBrowserApp on startup, automated tests then
* check the result.
*/
#define NS_XRE_DLL_BLOCKLIST_ENABLED (1 << 2)
/**
* Indicates whether or not to use Breakpad crash reporting.
*/
#define NS_XRE_ENABLE_CRASH_REPORTER (1 << 3)
#endif // nsXREAppData_h

538
xpcom/build/nsXULAppAPI.h Normal file
View file

@ -0,0 +1,538 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 _nsXULAppAPI_h__
#define _nsXULAppAPI_h__
#include "nsID.h"
#include "xrecore.h"
#include "nsXPCOM.h"
#include "nsISupports.h"
#include "mozilla/Logging.h"
#include "nsXREAppData.h"
#include "js/TypeDecls.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Vector.h"
#include "mozilla/TimeStamp.h"
#include "XREChildData.h"
#include "XREShellData.h"
/**
* A directory service key which provides the platform-correct "application
* data" directory as follows, where $name and $vendor are as defined above and
* $vendor is optional:
*
* Windows:
* HOME = Documents and Settings\$USER\Application Data
* UAppData = $HOME[\$vendor]\$name
*
* Unix:
* HOME = ~
* UAppData = $HOME/.[$vendor/]$name
*
* Mac:
* HOME = ~
* UAppData = $HOME/Library/Application Support/$name
*
* Note that the "profile" member above will change the value of UAppData as
* follows:
*
* Windows:
* UAppData = $HOME\$profile
*
* Unix:
* UAppData = $HOME/.$profile
*
* Mac:
* UAppData = $HOME/Library/Application Support/$profile
*/
#define XRE_USER_APP_DATA_DIR "UAppData"
/**
* A directory service key which provides a list of all enabled extension
* directories and files (packed XPIs). The list includes compatible
* platform-specific extension subdirectories.
*
* @note The directory list will have no members when the application is
* launched in safe mode.
*/
#define XRE_EXTENSIONS_DIR_LIST "XREExtDL"
/**
* A directory service key which provides the executable file used to
* launch the current process. This is the same value returned by the
* XRE_GetBinaryPath function defined below.
*/
#define XRE_EXECUTABLE_FILE "XREExeF"
/**
* A directory service key which specifies the profile
* directory. Unlike the NS_APP_USER_PROFILE_50_DIR key, this key may
* be available when the profile hasn't been "started", or after is
* has been shut down. If the application is running without a
* profile, such as when showing the profile manager UI, this key will
* not be available. This key is provided by the XUL apprunner or by
* the aAppDirProvider object passed to XRE_InitEmbedding.
*/
#define NS_APP_PROFILE_DIR_STARTUP "ProfDS"
/**
* A directory service key which specifies the profile
* directory. Unlike the NS_APP_USER_PROFILE_LOCAL_50_DIR key, this key may
* be available when the profile hasn't been "started", or after is
* has been shut down. If the application is running without a
* profile, such as when showing the profile manager UI, this key will
* not be available. This key is provided by the XUL apprunner or by
* the aAppDirProvider object passed to XRE_InitEmbedding.
*/
#define NS_APP_PROFILE_LOCAL_DIR_STARTUP "ProfLDS"
/**
* A directory service key which specifies the system extension
* parent directory containing platform-specific extensions.
* This key may not be available on all platforms.
*/
#define XRE_SYS_LOCAL_EXTENSION_PARENT_DIR "XRESysLExtPD"
/**
* A directory service key which specifies the system extension
* parent directory containing platform-independent extensions.
* This key may not be available on all platforms.
* Additionally, the directory may be equal to that returned by
* XRE_SYS_LOCAL_EXTENSION_PARENT_DIR on some platforms.
*/
#define XRE_SYS_SHARE_EXTENSION_PARENT_DIR "XRESysSExtPD"
#if defined(XP_UNIX) || defined(XP_MACOSX)
/**
* Directory service keys for the system-wide and user-specific
* directories where host manifests used by the WebExtensions
* native messaging feature are found.
*/
#define XRE_SYS_NATIVE_MESSAGING_MANIFESTS "XRESysNativeMessaging"
#define XRE_USER_NATIVE_MESSAGING_MANIFESTS "XREUserNativeMessaging"
#endif
/**
* A directory service key which specifies the user system extension
* parent directory.
*/
#define XRE_USER_SYS_EXTENSION_DIR "XREUSysExt"
/**
* A directory service key which specifies the distribution specific files for
* the application.
*/
#define XRE_APP_DISTRIBUTION_DIR "XREAppDist"
/**
* A directory service key which specifies the location for system add-ons.
*/
#define XRE_APP_FEATURES_DIR "XREAppFeat"
/**
* A directory service key which specifies the location for app dir add-ons.
* Should be a synonym for XCurProcD everywhere except in tests.
*/
#define XRE_ADDON_APP_DIR "XREAddonAppDir"
/**
* A directory service key which provides the update directory. Callers should
* fall back to appDir.
* Windows: If vendor name exists:
* Documents and Settings\<User>\Local Settings\Application Data\
* <vendor name>\updates\
* <hash of the path to XRE_EXECUTABLE_FILE’s parent directory>
*
* If vendor name doesn't exist, but product name exists:
* Documents and Settings\<User>\Local Settings\Application Data\
* <product name>\updates\
* <hash of the path to XRE_EXECUTABLE_FILE’s parent directory>
*
* If neither vendor nor product name exists:
* If app dir is under Program Files:
* Documents and Settings\<User>\Local Settings\Application Data\
* <relative path to app dir from Program Files>
*
* If app dir isn’t under Program Files:
* Documents and Settings\<User>\Local Settings\Application Data\
* <MOZ_APP_NAME>
*
* Mac: ~/Library/Caches/Mozilla/updates/<absolute path to app dir>
*
* Gonk: /data/local
*
* All others: Parent directory of XRE_EXECUTABLE_FILE.
*/
#define XRE_UPDATE_ROOT_DIR "UpdRootD"
/**
* A directory service key which provides an alternate location
* to UpdRootD to to store large files. This key is currently
* only implemented in the Gonk directory service provider.
*/
#define XRE_UPDATE_ARCHIVE_DIR "UpdArchD"
/**
* A directory service key which provides the directory where an OS update is
* applied.
* At present this is supported only in Gonk.
*/
#define XRE_OS_UPDATE_APPLY_TO_DIR "OSUpdApplyToD"
/**
* Begin an XUL application. Does not return until the user exits the
* application.
*
* @param argc/argv Command-line parameters to pass to the application. On
* Windows, these should be in UTF8. On unix-like platforms
* these are in the "native" character set.
*
* @param aAppData Information about the application to be run.
*
* @param aFlags Platform specific flags.
*
* @return A native result code suitable for returning from main().
*
* @note If the binary is linked against the standalone XPCOM glue,
* XPCOMGlueStartup() should be called before this method.
*/
XRE_API(int,
XRE_main, (int argc, char* argv[], const nsXREAppData* aAppData,
uint32_t aFlags))
/**
* Given a path relative to the current working directory (or an absolute
* path), return an appropriate nsIFile object.
*
* @note Pass UTF8 strings on Windows... native charset on other platforms.
*/
XRE_API(nsresult,
XRE_GetFileFromPath, (const char* aPath, nsIFile** aResult))
/**
* Get the path of the running application binary and store it in aResult.
* @param aArgv0 The value passed as argv[0] of main(). This value is only
* used on *nix, and only when other methods of determining
* the binary path have failed.
*/
XRE_API(nsresult,
XRE_GetBinaryPath, (const char* aArgv0, nsIFile** aResult))
/**
* Get the static module built in to libxul.
*/
XRE_API(const mozilla::Module*,
XRE_GetStaticModule, ())
/**
* Lock a profile directory using platform-specific semantics.
*
* @param aDirectory The profile directory to lock.
* @param aLockObject An opaque lock object. The directory will remain locked
* as long as the XPCOM reference is held.
*/
XRE_API(nsresult,
XRE_LockProfileDirectory, (nsIFile* aDirectory,
nsISupports** aLockObject))
/**
* Initialize libXUL for embedding purposes.
*
* @param aLibXULDirectory The directory in which the libXUL shared library
* was found.
* @param aAppDirectory The directory in which the application components
* and resources can be found. This will map to
* the NS_OS_CURRENT_PROCESS_DIR directory service
* key.
* @param aAppDirProvider A directory provider for the application. This
* provider will be aggregated by a libxul provider
* which will provide the base required GRE keys.
*
* @note This function must be called from the "main" thread.
*
* @note At the present time, this function may only be called once in
* a given process. Use XRE_TermEmbedding to clean up and free
* resources allocated by XRE_InitEmbedding.
*/
XRE_API(nsresult,
XRE_InitEmbedding2, (nsIFile* aLibXULDirectory,
nsIFile* aAppDirectory,
nsIDirectoryServiceProvider* aAppDirProvider))
/**
* Register static XPCOM component information.
* This method may be called at any time before or after XRE_main or
* XRE_InitEmbedding.
*/
XRE_API(nsresult,
XRE_AddStaticComponent, (const mozilla::Module* aComponent))
/**
* Register XPCOM components found in an array of files/directories.
* This method may be called at any time before or after XRE_main or
* XRE_InitEmbedding.
*
* @param aFiles An array of files or directories.
* @param aFileCount the number of items in the aFiles array.
* @note appdir/components is registered automatically.
*
* NS_APP_LOCATION specifies a location to search for binary XPCOM
* components as well as component/chrome manifest files.
*
* NS_EXTENSION_LOCATION excludes binary XPCOM components but allows other
* manifest instructions.
*
* NS_SKIN_LOCATION specifies a location to search for chrome manifest files
* which are only allowed to register only skin packages and style overlays.
*/
enum NSLocationType
{
NS_APP_LOCATION,
NS_EXTENSION_LOCATION,
NS_SKIN_LOCATION,
NS_BOOTSTRAPPED_LOCATION
};
XRE_API(nsresult,
XRE_AddManifestLocation, (NSLocationType aType,
nsIFile* aLocation))
/**
* Register XPCOM components found in a JAR.
* This is similar to XRE_AddManifestLocation except the file specified
* must be a zip archive with a manifest named chrome.manifest
* This method may be called at any time before or after XRE_main or
* XRE_InitEmbedding.
*
* @param aFiles An array of files or directories.
* @param aFileCount the number of items in the aFiles array.
* @note appdir/components is registered automatically.
*
* NS_COMPONENT_LOCATION specifies a location to search for binary XPCOM
* components as well as component/chrome manifest files.
*
* NS_SKIN_LOCATION specifies a location to search for chrome manifest files
* which are only allowed to register only skin packages and style overlays.
*/
XRE_API(nsresult,
XRE_AddJarManifestLocation, (NSLocationType aType,
nsIFile* aLocation))
/**
* Fire notifications to inform the toolkit about a new profile. This
* method should be called after XRE_InitEmbedding if the embedder
* wishes to run with a profile. Normally the embedder should call
* XRE_LockProfileDirectory to lock the directory before calling this
* method.
*
* @note There are two possibilities for selecting a profile:
*
* 1) Select the profile before calling XRE_InitEmbedding. The aAppDirProvider
* object passed to XRE_InitEmbedding should provide the
* NS_APP_USER_PROFILE_50_DIR key, and may also provide the following keys:
* - NS_APP_USER_PROFILE_LOCAL_50_DIR
* - NS_APP_PROFILE_DIR_STARTUP
* - NS_APP_PROFILE_LOCAL_DIR_STARTUP
* In this scenario XRE_NotifyProfile should be called immediately after
* XRE_InitEmbedding. Component registration information will be stored in
* the profile and JS components may be stored in the fastload cache.
*
* 2) Select a profile some time after calling XRE_InitEmbedding. In this case
* the embedder must install a directory service provider which provides
* NS_APP_USER_PROFILE_50_DIR and optionally
* NS_APP_USER_PROFILE_LOCAL_50_DIR. Component registration information
* will be stored in the application directory and JS components will not
* fastload.
*/
XRE_API(void,
XRE_NotifyProfile, ())
/**
* Terminate embedding started with XRE_InitEmbedding or XRE_InitEmbedding2
*/
XRE_API(void,
XRE_TermEmbedding, ())
/**
* Create a new nsXREAppData structure from an application.ini file.
*
* @param aINIFile The application.ini file to parse.
* @param aAppData A newly-allocated nsXREAppData structure. The caller is
* responsible for freeing this structure using
* XRE_FreeAppData.
*/
XRE_API(nsresult,
XRE_CreateAppData, (nsIFile* aINIFile,
nsXREAppData** aAppData))
/**
* Parse an INI file (application.ini or override.ini) into an existing
* nsXREAppData structure.
*
* @param aINIFile The INI file to parse
* @param aAppData The nsXREAppData structure to fill.
*/
XRE_API(nsresult,
XRE_ParseAppData, (nsIFile* aINIFile,
nsXREAppData* aAppData))
/**
* Free a nsXREAppData structure that was allocated with XRE_CreateAppData.
*/
XRE_API(void,
XRE_FreeAppData, (nsXREAppData* aAppData))
enum GeckoProcessType
{
GeckoProcessType_Default = 0,
GeckoProcessType_Plugin,
GeckoProcessType_Content,
GeckoProcessType_IPDLUnitTest,
GeckoProcessType_GMPlugin, // Gecko Media Plugin
GeckoProcessType_GPU, // GPU and compositor process
GeckoProcessType_End,
GeckoProcessType_Invalid = GeckoProcessType_End
};
static const char* const kGeckoProcessTypeString[] = {
"default",
"plugin",
"tab",
"ipdlunittest",
"geckomediaplugin",
"gpu"
};
static_assert(MOZ_ARRAY_LENGTH(kGeckoProcessTypeString) ==
GeckoProcessType_End,
"Array length mismatch");
XRE_API(const char*,
XRE_ChildProcessTypeToString, (GeckoProcessType aProcessType))
XRE_API(void,
XRE_SetProcessType, (const char* aProcessTypeString))
#if defined(MOZ_CRASHREPORTER)
// Used in the "master" parent process hosting the crash server
XRE_API(bool,
XRE_TakeMinidumpForChild, (uint32_t aChildPid, nsIFile** aDump,
uint32_t* aSequence))
// Used in child processes.
XRE_API(bool,
XRE_SetRemoteExceptionHandler, (const char* aPipe))
#endif
namespace mozilla {
namespace gmp {
class GMPLoader;
} // namespace gmp
} // namespace mozilla
XRE_API(nsresult,
XRE_InitChildProcess, (int aArgc,
char* aArgv[],
const XREChildData* aChildData))
XRE_API(GeckoProcessType,
XRE_GetProcessType, ())
XRE_API(bool,
XRE_IsParentProcess, ())
XRE_API(bool,
XRE_IsContentProcess, ())
XRE_API(bool,
XRE_IsGPUProcess, ())
typedef void (*MainFunction)(void* aData);
XRE_API(nsresult,
XRE_InitParentProcess, (int aArgc,
char* aArgv[],
MainFunction aMainFunction,
void* aMainFunctionExtraData))
XRE_API(int,
XRE_RunIPDLTest, (int aArgc,
char* aArgv[]))
XRE_API(nsresult,
XRE_RunAppShell, ())
XRE_API(nsresult,
XRE_InitCommandLine, (int aArgc, char* aArgv[]))
XRE_API(nsresult,
XRE_DeinitCommandLine, ())
class MessageLoop;
XRE_API(void,
XRE_ShutdownChildProcess, ())
XRE_API(MessageLoop*,
XRE_GetIOMessageLoop, ())
XRE_API(bool,
XRE_SendTestShellCommand, (JSContext* aCx,
JSString* aCommand,
void* aCallback))
XRE_API(bool,
XRE_ShutdownTestShell, ())
XRE_API(void,
XRE_InstallX11ErrorHandler, ())
XRE_API(void,
XRE_TelemetryAccumulate, (int aID, uint32_t aSample))
XRE_API(void,
XRE_StartupTimelineRecord, (int aEvent, mozilla::TimeStamp aWhen))
XRE_API(void,
XRE_InitOmnijar, (nsIFile* aGreOmni,
nsIFile* aAppOmni))
XRE_API(void,
XRE_StopLateWriteChecks, (void))
XRE_API(void,
XRE_EnableSameExecutableForContentProc, ())
XRE_API(int,
XRE_XPCShellMain, (int argc, char** argv, char** envp,
const XREShellData* aShellData))
#if MOZ_WIDGET_GTK == 2
XRE_API(void,
XRE_GlibInit, ())
#endif
#ifdef LIBFUZZER
#include "LibFuzzerRegistry.h"
XRE_API(void,
XRE_LibFuzzerSetMain, (int, char**, LibFuzzerMain))
XRE_API(void,
XRE_LibFuzzerGetFuncs, (const char*, LibFuzzerInitFunc*,
LibFuzzerTestingFunc*))
#endif // LIBFUZZER
#endif // _nsXULAppAPI_h__

242
xpcom/build/perfprobe.cpp Normal file
View file

@ -0,0 +1,242 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
/*****************************
Windows implementation of probes, using xperf
*****************************/
#include <windows.h>
#include <wmistr.h>
#include <evntrace.h>
#include "perfprobe.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace probes {
#if defined(MOZ_LOGGING)
static LazyLogModule sProbeLog("SysProbe");
#define LOG(x) MOZ_LOG(sProbeLog, mozilla::LogLevel::Debug, x)
#else
#define LOG(x)
#endif
// Utility function
GUID
CID_to_GUID(const nsCID& aCID)
{
GUID result;
result.Data1 = aCID.m0;
result.Data2 = aCID.m1;
result.Data3 = aCID.m2;
for (int i = 0; i < 8; ++i) {
result.Data4[i] = aCID.m3[i];
}
return result;
}
// Implementation of Probe
Probe::Probe(const nsCID& aGUID,
const nsACString& aName,
ProbeManager* aManager)
: mGUID(CID_to_GUID(aGUID))
, mName(aName)
, mManager(aManager)
{
}
nsresult
Probe::Trigger()
{
if (!(mManager->mIsActive)) {
//Do not trigger if there is no session
return NS_OK;
}
_EVENT_TRACE_HEADER event;
ZeroMemory(&event, sizeof(event));
event.Size = sizeof(event);
event.Flags = WNODE_FLAG_TRACED_GUID ;
event.Guid = (const GUID)mGUID;
event.Class.Type = 1;
event.Class.Version = 0;
event.Class.Level = TRACE_LEVEL_INFORMATION;
ULONG result = TraceEvent(mManager->mSessionHandle, &event);
LOG(("Probes: Triggered %s, %s, %ld",
mName.Data(),
result == ERROR_SUCCESS ? "success" : "failure",
result));
nsresult rv;
switch (result) {
case ERROR_SUCCESS:
rv = NS_OK;
break;
case ERROR_INVALID_FLAG_NUMBER:
case ERROR_MORE_DATA:
case ERROR_INVALID_PARAMETER:
rv = NS_ERROR_INVALID_ARG;
break;
case ERROR_INVALID_HANDLE:
rv = NS_ERROR_FAILURE;
break;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
rv = NS_ERROR_OUT_OF_MEMORY;
break;
default:
rv = NS_ERROR_UNEXPECTED;
}
return rv;
}
// Implementation of ProbeManager
ProbeManager::~ProbeManager()
{
//If the manager goes out of scope, stop the session.
if (mIsActive && mRegistrationHandle) {
StopSession();
}
}
ProbeManager::ProbeManager(const nsCID& aApplicationUID,
const nsACString& aApplicationName)
: mIsActive(false)
, mApplicationUID(aApplicationUID)
, mApplicationName(aApplicationName)
, mSessionHandle(0)
, mRegistrationHandle(0)
, mInitialized(false)
{
#if defined(MOZ_LOGGING)
char cidStr[NSID_LENGTH];
aApplicationUID.ToProvidedString(cidStr);
LOG(("ProbeManager::Init for application %s, %s",
aApplicationName.Data(), cidStr));
#endif
}
//Note: The Windows API is just a little bit scary there.
//The only way to obtain the session handle is to
//- ignore the session handle obtained from RegisterTraceGuids
//- pass a callback
//- in that callback, request the session handle through
// GetTraceLoggerHandle and some opaque value received by the callback
ULONG WINAPI
ControlCallback(WMIDPREQUESTCODE aRequestCode,
PVOID aContext,
ULONG* aReserved,
PVOID aBuffer)
{
ProbeManager* context = (ProbeManager*)aContext;
switch (aRequestCode) {
case WMI_ENABLE_EVENTS: {
context->mIsActive = true;
TRACEHANDLE sessionHandle = GetTraceLoggerHandle(aBuffer);
//Note: We only accept one handle
if ((HANDLE)sessionHandle == INVALID_HANDLE_VALUE) {
ULONG result = GetLastError();
LOG(("Probes: ControlCallback failed, %ul", result));
return result;
} else if (context->mIsActive && context->mSessionHandle &&
context->mSessionHandle != sessionHandle) {
LOG(("Probes: Can only handle one context at a time, "
"ignoring activation"));
return ERROR_SUCCESS;
} else {
context->mSessionHandle = sessionHandle;
LOG(("Probes: ControlCallback activated"));
return ERROR_SUCCESS;
}
}
case WMI_DISABLE_EVENTS:
context->mIsActive = false;
context->mSessionHandle = 0;
LOG(("Probes: ControlCallback deactivated"));
return ERROR_SUCCESS;
default:
LOG(("Probes: ControlCallback does not know what to do with %d",
aRequestCode));
return ERROR_INVALID_PARAMETER;
}
}
already_AddRefed<Probe>
ProbeManager::GetProbe(const nsCID& aEventUID, const nsACString& aEventName)
{
RefPtr<Probe> result(new Probe(aEventUID, aEventName, this));
mAllProbes.AppendElement(result);
return result.forget();
}
nsresult
ProbeManager::StartSession()
{
return StartSession(mAllProbes);
}
nsresult
ProbeManager::StartSession(nsTArray<RefPtr<Probe>>& aProbes)
{
const size_t probesCount = aProbes.Length();
_TRACE_GUID_REGISTRATION* probes = new _TRACE_GUID_REGISTRATION[probesCount];
for (unsigned int i = 0; i < probesCount; ++i) {
const Probe* probe = aProbes[i];
const Probe* probeX = static_cast<const Probe*>(probe);
probes[i].Guid = (LPCGUID)&probeX->mGUID;
}
ULONG result =
RegisterTraceGuids(&ControlCallback
/*RequestAddress: Sets mSessions appropriately.*/,
this
/*RequestContext: Passed to ControlCallback*/,
(LPGUID)&mApplicationUID
/*ControlGuid: Tracing GUID
the cast comes from MSDN examples*/,
probesCount
/*GuidCount: Number of probes*/,
probes
/*TraceGuidReg: Probes registration*/,
nullptr
/*MofImagePath: Must be nullptr, says MSDN*/,
nullptr
/*MofResourceName:Must be nullptr, says MSDN*/,
&mRegistrationHandle
/*RegistrationHandle: Handler.
used only for unregistration*/
);
delete[] probes;
if (NS_WARN_IF(result != ERROR_SUCCESS)) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
nsresult
ProbeManager::StopSession()
{
LOG(("Probes: Stopping measures"));
if (mSessionHandle != 0) {
ULONG result = UnregisterTraceGuids(mSessionHandle);
mSessionHandle = 0;
if (result != ERROR_SUCCESS) {
return NS_ERROR_INVALID_ARG;
}
}
return NS_OK;
}
} // namespace probes
} // namespace mozilla

204
xpcom/build/perfprobe.h Normal file
View file

@ -0,0 +1,204 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
/**
* A mechanism for interacting with operating system-provided
* debugging/profiling tools such as Microsoft EWT/Windows Performance Toolkit.
*/
#ifndef mozilla_perfprobe_h
#define mozilla_perfprobe_h
#if !defined(XP_WIN)
#error "For the moment, perfprobe.h is defined only for Windows platforms"
#endif
#include "nsError.h"
#include "nsString.h"
#include "mozilla/Logging.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include <windows.h>
#undef GetStartupInfo //Prevent Windows from polluting global namespace
#include <wmistr.h>
#include <evntrace.h>
namespace mozilla {
namespace probes {
class ProbeManager;
/**
* A data structure supporting a trigger operation that can be used to
* send information to the operating system.
*/
class Probe
{
public:
NS_INLINE_DECL_REFCOUNTING(Probe)
/**
* Trigger the event.
*
* Note: Can be called from any thread.
*/
nsresult Trigger();
protected:
~Probe() {};
Probe(const nsCID& aGUID, const nsACString& aName, ProbeManager* aManager);
friend class ProbeManager;
protected:
/**
* The system GUID associated to this probe. See the documentation
* of |ProbeManager::Make| for more details.
*/
const GUID mGUID;
/**
* The name of this probe. See the documentation
* of |ProbeManager::Make| for more details.
*/
const nsCString mName;
/**
* The ProbeManager managing this probe.
*
* Note: This is a weak reference to avoid a useless cycle.
*/
class ProbeManager* mManager;
};
/**
* A manager for a group of probes.
*
* You can have several managers in one application, provided that they all
* have distinct IDs and names. However, having more than 2 is considered a bad
* practice.
*/
class ProbeManager
{
public:
NS_INLINE_DECL_REFCOUNTING(ProbeManager)
/**
* Create a new probe manager.
*
* This constructor should be called from the main thread.
*
* @param aApplicationUID The unique ID of the probe. Under Windows, this
* unique ID must have been previously registered using an external tool.
* See MyCategory on http://msdn.microsoft.com/en-us/library/aa364100.aspx
* @param aApplicationName A name for the probe. Currently used only for
* logging purposes. In the future, may be attached to the data sent to the
* operating system.
*
* Note: If two ProbeManagers are constructed with the same uid and/or name,
* behavior is unspecified.
*/
ProbeManager(const nsCID& aApplicationUID,
const nsACString& aApplicationName);
/**
* Acquire a probe.
*
* Note: Only probes acquired before the call to SetReady are taken into
* account
* Note: Can be called only from the main thread.
*
* @param aEventUID The unique ID of the probe. Under Windows, this unique
* ID must have been previously registered using an external tool.
* See MyCategory on http://msdn.microsoft.com/en-us/library/aa364100.aspx
* @param aEventName A name for the probe. Currently used only for logging
* purposes. In the
* future, may be attached to the data sent to the operating system.
* @return Either |null| in case of error or a valid |Probe*|.
*
* Note: If this method is called twice with the same uid and/or name,
* behavior is undefined.
*/
already_AddRefed<Probe> GetProbe(const nsCID& aEventUID,
const nsACString& aEventName);
/**
* Start/stop the measuring session.
*
* This method should be called from the main thread.
*
* Note that starting an already started probe manager has no effect,
* nor does stopping an already stopped probe manager.
*/
nsresult StartSession();
nsresult StopSession();
/**
* @return true If measures are currently on, i.e. if triggering probes is any
* is useful. You do not have to check this before triggering a probe, unless
* this can avoid complex computations.
*/
bool IsActive();
protected:
~ProbeManager();
nsresult StartSession(nsTArray<RefPtr<Probe>>& aProbes);
nsresult Init(const nsCID& aApplicationUID,
const nsACString& aApplicationName);
protected:
/**
* `true` if a session is in activity, `false` otherwise.
*/
bool mIsActive;
/**
* The UID of this manager.
* See documentation above for registration steps that you
* may have to take.
*/
nsCID mApplicationUID;
/**
* The name of the application.
*/
nsCString mApplicationName;
/**
* All the probes that have been created for this manager.
*/
nsTArray<RefPtr<Probe>> mAllProbes;
/**
* Handle used for triggering events
*/
TRACEHANDLE mSessionHandle;
/**
* Handle used for registration/unregistration
*/
TRACEHANDLE mRegistrationHandle;
/**
* `true` if initialization has been performed, `false` until then.
*/
bool mInitialized;
friend class Probe; // Needs to access |mSessionHandle|
friend ULONG WINAPI ControlCallback(WMIDPREQUESTCODE aRequestCode,
PVOID aContext,
ULONG* aReserved,
PVOID aBuffer); // Sets |mSessionHandle|
};
} // namespace probes
} // namespace mozilla
#endif //mozilla_perfprobe_h

256
xpcom/build/xpcom_alpha.def Normal file
View file

@ -0,0 +1,256 @@
;+# 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/.
LIBRARY xpcom
DESCRIPTION "xpcom library"
EXPORTS
?Stub3@nsXPTCStubBase@@UAAIXZ
?Stub4@nsXPTCStubBase@@UAAIXZ
?Stub5@nsXPTCStubBase@@UAAIXZ
?Stub6@nsXPTCStubBase@@UAAIXZ
?Stub7@nsXPTCStubBase@@UAAIXZ
?Stub8@nsXPTCStubBase@@UAAIXZ
?Stub9@nsXPTCStubBase@@UAAIXZ
?Stub10@nsXPTCStubBase@@UAAIXZ
?Stub11@nsXPTCStubBase@@UAAIXZ
?Stub12@nsXPTCStubBase@@UAAIXZ
?Stub13@nsXPTCStubBase@@UAAIXZ
?Stub14@nsXPTCStubBase@@UAAIXZ
?Stub15@nsXPTCStubBase@@UAAIXZ
?Stub16@nsXPTCStubBase@@UAAIXZ
?Stub17@nsXPTCStubBase@@UAAIXZ
?Stub18@nsXPTCStubBase@@UAAIXZ
?Stub19@nsXPTCStubBase@@UAAIXZ
?Stub20@nsXPTCStubBase@@UAAIXZ
?Stub21@nsXPTCStubBase@@UAAIXZ
?Stub22@nsXPTCStubBase@@UAAIXZ
?Stub23@nsXPTCStubBase@@UAAIXZ
?Stub24@nsXPTCStubBase@@UAAIXZ
?Stub25@nsXPTCStubBase@@UAAIXZ
?Stub26@nsXPTCStubBase@@UAAIXZ
?Stub27@nsXPTCStubBase@@UAAIXZ
?Stub28@nsXPTCStubBase@@UAAIXZ
?Stub29@nsXPTCStubBase@@UAAIXZ
?Stub30@nsXPTCStubBase@@UAAIXZ
?Stub31@nsXPTCStubBase@@UAAIXZ
?Stub32@nsXPTCStubBase@@UAAIXZ
?Stub33@nsXPTCStubBase@@UAAIXZ
?Stub34@nsXPTCStubBase@@UAAIXZ
?Stub35@nsXPTCStubBase@@UAAIXZ
?Stub36@nsXPTCStubBase@@UAAIXZ
?Stub37@nsXPTCStubBase@@UAAIXZ
?Stub38@nsXPTCStubBase@@UAAIXZ
?Stub39@nsXPTCStubBase@@UAAIXZ
?Stub40@nsXPTCStubBase@@UAAIXZ
?Stub41@nsXPTCStubBase@@UAAIXZ
?Stub42@nsXPTCStubBase@@UAAIXZ
?Stub43@nsXPTCStubBase@@UAAIXZ
?Stub44@nsXPTCStubBase@@UAAIXZ
?Stub45@nsXPTCStubBase@@UAAIXZ
?Stub46@nsXPTCStubBase@@UAAIXZ
?Stub47@nsXPTCStubBase@@UAAIXZ
?Stub48@nsXPTCStubBase@@UAAIXZ
?Stub49@nsXPTCStubBase@@UAAIXZ
?Stub50@nsXPTCStubBase@@UAAIXZ
?Stub51@nsXPTCStubBase@@UAAIXZ
?Stub52@nsXPTCStubBase@@UAAIXZ
?Stub53@nsXPTCStubBase@@UAAIXZ
?Stub54@nsXPTCStubBase@@UAAIXZ
?Stub55@nsXPTCStubBase@@UAAIXZ
?Stub56@nsXPTCStubBase@@UAAIXZ
?Stub57@nsXPTCStubBase@@UAAIXZ
?Stub58@nsXPTCStubBase@@UAAIXZ
?Stub59@nsXPTCStubBase@@UAAIXZ
?Stub60@nsXPTCStubBase@@UAAIXZ
?Stub61@nsXPTCStubBase@@UAAIXZ
?Stub62@nsXPTCStubBase@@UAAIXZ
?Stub63@nsXPTCStubBase@@UAAIXZ
?Stub64@nsXPTCStubBase@@UAAIXZ
?Stub65@nsXPTCStubBase@@UAAIXZ
?Stub66@nsXPTCStubBase@@UAAIXZ
?Stub67@nsXPTCStubBase@@UAAIXZ
?Stub68@nsXPTCStubBase@@UAAIXZ
?Stub69@nsXPTCStubBase@@UAAIXZ
?Stub70@nsXPTCStubBase@@UAAIXZ
?Stub71@nsXPTCStubBase@@UAAIXZ
?Stub72@nsXPTCStubBase@@UAAIXZ
?Stub73@nsXPTCStubBase@@UAAIXZ
?Stub74@nsXPTCStubBase@@UAAIXZ
?Stub75@nsXPTCStubBase@@UAAIXZ
?Stub76@nsXPTCStubBase@@UAAIXZ
?Stub77@nsXPTCStubBase@@UAAIXZ
?Stub78@nsXPTCStubBase@@UAAIXZ
?Stub79@nsXPTCStubBase@@UAAIXZ
?Stub80@nsXPTCStubBase@@UAAIXZ
?Stub81@nsXPTCStubBase@@UAAIXZ
?Stub82@nsXPTCStubBase@@UAAIXZ
?Stub83@nsXPTCStubBase@@UAAIXZ
?Stub84@nsXPTCStubBase@@UAAIXZ
?Stub85@nsXPTCStubBase@@UAAIXZ
?Stub86@nsXPTCStubBase@@UAAIXZ
?Stub87@nsXPTCStubBase@@UAAIXZ
?Stub88@nsXPTCStubBase@@UAAIXZ
?Stub89@nsXPTCStubBase@@UAAIXZ
?Stub90@nsXPTCStubBase@@UAAIXZ
?Stub91@nsXPTCStubBase@@UAAIXZ
?Stub92@nsXPTCStubBase@@UAAIXZ
?Stub93@nsXPTCStubBase@@UAAIXZ
?Stub94@nsXPTCStubBase@@UAAIXZ
?Stub95@nsXPTCStubBase@@UAAIXZ
?Stub96@nsXPTCStubBase@@UAAIXZ
?Stub97@nsXPTCStubBase@@UAAIXZ
?Stub98@nsXPTCStubBase@@UAAIXZ
?Stub99@nsXPTCStubBase@@UAAIXZ
?Stub100@nsXPTCStubBase@@UAAIXZ
?Stub101@nsXPTCStubBase@@UAAIXZ
?Stub102@nsXPTCStubBase@@UAAIXZ
?Stub103@nsXPTCStubBase@@UAAIXZ
?Stub104@nsXPTCStubBase@@UAAIXZ
?Stub105@nsXPTCStubBase@@UAAIXZ
?Stub106@nsXPTCStubBase@@UAAIXZ
?Stub107@nsXPTCStubBase@@UAAIXZ
?Stub108@nsXPTCStubBase@@UAAIXZ
?Stub109@nsXPTCStubBase@@UAAIXZ
?Stub110@nsXPTCStubBase@@UAAIXZ
?Stub111@nsXPTCStubBase@@UAAIXZ
?Stub112@nsXPTCStubBase@@UAAIXZ
?Stub113@nsXPTCStubBase@@UAAIXZ
?Stub114@nsXPTCStubBase@@UAAIXZ
?Stub115@nsXPTCStubBase@@UAAIXZ
?Stub116@nsXPTCStubBase@@UAAIXZ
?Stub117@nsXPTCStubBase@@UAAIXZ
?Stub118@nsXPTCStubBase@@UAAIXZ
?Stub119@nsXPTCStubBase@@UAAIXZ
?Stub120@nsXPTCStubBase@@UAAIXZ
?Stub121@nsXPTCStubBase@@UAAIXZ
?Stub122@nsXPTCStubBase@@UAAIXZ
?Stub123@nsXPTCStubBase@@UAAIXZ
?Stub124@nsXPTCStubBase@@UAAIXZ
?Stub125@nsXPTCStubBase@@UAAIXZ
?Stub126@nsXPTCStubBase@@UAAIXZ
?Stub127@nsXPTCStubBase@@UAAIXZ
?Stub128@nsXPTCStubBase@@UAAIXZ
?Stub129@nsXPTCStubBase@@UAAIXZ
?Stub130@nsXPTCStubBase@@UAAIXZ
?Stub131@nsXPTCStubBase@@UAAIXZ
?Stub132@nsXPTCStubBase@@UAAIXZ
?Stub133@nsXPTCStubBase@@UAAIXZ
?Stub134@nsXPTCStubBase@@UAAIXZ
?Stub135@nsXPTCStubBase@@UAAIXZ
?Stub136@nsXPTCStubBase@@UAAIXZ
?Stub137@nsXPTCStubBase@@UAAIXZ
?Stub138@nsXPTCStubBase@@UAAIXZ
?Stub139@nsXPTCStubBase@@UAAIXZ
?Stub140@nsXPTCStubBase@@UAAIXZ
?Stub141@nsXPTCStubBase@@UAAIXZ
?Stub142@nsXPTCStubBase@@UAAIXZ
?Stub143@nsXPTCStubBase@@UAAIXZ
?Stub144@nsXPTCStubBase@@UAAIXZ
?Stub145@nsXPTCStubBase@@UAAIXZ
?Stub146@nsXPTCStubBase@@UAAIXZ
?Stub147@nsXPTCStubBase@@UAAIXZ
?Stub148@nsXPTCStubBase@@UAAIXZ
?Stub149@nsXPTCStubBase@@UAAIXZ
?Stub150@nsXPTCStubBase@@UAAIXZ
?Stub151@nsXPTCStubBase@@UAAIXZ
?Stub152@nsXPTCStubBase@@UAAIXZ
?Stub153@nsXPTCStubBase@@UAAIXZ
?Stub154@nsXPTCStubBase@@UAAIXZ
?Stub155@nsXPTCStubBase@@UAAIXZ
?Stub156@nsXPTCStubBase@@UAAIXZ
?Stub157@nsXPTCStubBase@@UAAIXZ
?Stub158@nsXPTCStubBase@@UAAIXZ
?Stub159@nsXPTCStubBase@@UAAIXZ
?Stub160@nsXPTCStubBase@@UAAIXZ
?Stub161@nsXPTCStubBase@@UAAIXZ
?Stub162@nsXPTCStubBase@@UAAIXZ
?Stub163@nsXPTCStubBase@@UAAIXZ
?Stub164@nsXPTCStubBase@@UAAIXZ
?Stub165@nsXPTCStubBase@@UAAIXZ
?Stub166@nsXPTCStubBase@@UAAIXZ
?Stub167@nsXPTCStubBase@@UAAIXZ
?Stub168@nsXPTCStubBase@@UAAIXZ
?Stub169@nsXPTCStubBase@@UAAIXZ
?Stub170@nsXPTCStubBase@@UAAIXZ
?Stub171@nsXPTCStubBase@@UAAIXZ
?Stub172@nsXPTCStubBase@@UAAIXZ
?Stub173@nsXPTCStubBase@@UAAIXZ
?Stub174@nsXPTCStubBase@@UAAIXZ
?Stub175@nsXPTCStubBase@@UAAIXZ
?Stub176@nsXPTCStubBase@@UAAIXZ
?Stub177@nsXPTCStubBase@@UAAIXZ
?Stub178@nsXPTCStubBase@@UAAIXZ
?Stub179@nsXPTCStubBase@@UAAIXZ
?Stub180@nsXPTCStubBase@@UAAIXZ
?Stub181@nsXPTCStubBase@@UAAIXZ
?Stub182@nsXPTCStubBase@@UAAIXZ
?Stub183@nsXPTCStubBase@@UAAIXZ
?Stub184@nsXPTCStubBase@@UAAIXZ
?Stub185@nsXPTCStubBase@@UAAIXZ
?Stub186@nsXPTCStubBase@@UAAIXZ
?Stub187@nsXPTCStubBase@@UAAIXZ
?Stub188@nsXPTCStubBase@@UAAIXZ
?Stub189@nsXPTCStubBase@@UAAIXZ
?Stub190@nsXPTCStubBase@@UAAIXZ
?Stub191@nsXPTCStubBase@@UAAIXZ
?Stub192@nsXPTCStubBase@@UAAIXZ
?Stub193@nsXPTCStubBase@@UAAIXZ
?Stub194@nsXPTCStubBase@@UAAIXZ
?Stub195@nsXPTCStubBase@@UAAIXZ
?Stub196@nsXPTCStubBase@@UAAIXZ
?Stub197@nsXPTCStubBase@@UAAIXZ
?Stub198@nsXPTCStubBase@@UAAIXZ
?Stub199@nsXPTCStubBase@@UAAIXZ
?Stub200@nsXPTCStubBase@@UAAIXZ
?Stub201@nsXPTCStubBase@@UAAIXZ
?Stub202@nsXPTCStubBase@@UAAIXZ
?Stub203@nsXPTCStubBase@@UAAIXZ
?Stub204@nsXPTCStubBase@@UAAIXZ
?Stub205@nsXPTCStubBase@@UAAIXZ
?Stub206@nsXPTCStubBase@@UAAIXZ
?Stub207@nsXPTCStubBase@@UAAIXZ
?Stub208@nsXPTCStubBase@@UAAIXZ
?Stub209@nsXPTCStubBase@@UAAIXZ
?Stub210@nsXPTCStubBase@@UAAIXZ
?Stub211@nsXPTCStubBase@@UAAIXZ
?Stub212@nsXPTCStubBase@@UAAIXZ
?Stub213@nsXPTCStubBase@@UAAIXZ
?Stub214@nsXPTCStubBase@@UAAIXZ
?Stub215@nsXPTCStubBase@@UAAIXZ
?Stub216@nsXPTCStubBase@@UAAIXZ
?Stub217@nsXPTCStubBase@@UAAIXZ
?Stub218@nsXPTCStubBase@@UAAIXZ
?Stub219@nsXPTCStubBase@@UAAIXZ
?Stub220@nsXPTCStubBase@@UAAIXZ
?Stub221@nsXPTCStubBase@@UAAIXZ
?Stub222@nsXPTCStubBase@@UAAIXZ
?Stub223@nsXPTCStubBase@@UAAIXZ
?Stub224@nsXPTCStubBase@@UAAIXZ
?Stub225@nsXPTCStubBase@@UAAIXZ
?Stub226@nsXPTCStubBase@@UAAIXZ
?Stub227@nsXPTCStubBase@@UAAIXZ
?Stub228@nsXPTCStubBase@@UAAIXZ
?Stub229@nsXPTCStubBase@@UAAIXZ
?Stub230@nsXPTCStubBase@@UAAIXZ
?Stub231@nsXPTCStubBase@@UAAIXZ
?Stub232@nsXPTCStubBase@@UAAIXZ
?Stub233@nsXPTCStubBase@@UAAIXZ
?Stub234@nsXPTCStubBase@@UAAIXZ
?Stub235@nsXPTCStubBase@@UAAIXZ
?Stub236@nsXPTCStubBase@@UAAIXZ
?Stub237@nsXPTCStubBase@@UAAIXZ
?Stub238@nsXPTCStubBase@@UAAIXZ
?Stub239@nsXPTCStubBase@@UAAIXZ
?Stub240@nsXPTCStubBase@@UAAIXZ
?Stub241@nsXPTCStubBase@@UAAIXZ
?Stub242@nsXPTCStubBase@@UAAIXZ
?Stub243@nsXPTCStubBase@@UAAIXZ
?Stub244@nsXPTCStubBase@@UAAIXZ
?Stub245@nsXPTCStubBase@@UAAIXZ
?Stub246@nsXPTCStubBase@@UAAIXZ
?Stub247@nsXPTCStubBase@@UAAIXZ
?Stub248@nsXPTCStubBase@@UAAIXZ
?Stub249@nsXPTCStubBase@@UAAIXZ

25
xpcom/build/xrecore.h Normal file
View file

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 xrecore_h__
#define xrecore_h__
#include "nscore.h"
/**
* Import/export macros for libXUL APIs.
*/
#ifdef XPCOM_GLUE
#define XRE_API(type, name, params) \
typedef type (NS_FROZENCALL * name##Type) params; \
extern name##Type name NS_HIDDEN;
#elif defined(IMPL_LIBXUL)
#define XRE_API(type, name, params) EXPORT_XPCOM_API(type) name params;
#else
#define XRE_API(type, name, params) IMPORT_XPCOM_API(type) name params;
#endif
#endif // xrecore_h__