mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-03 13:57:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
188
xpcom/build/BinaryPath.h
Normal file
188
xpcom/build/BinaryPath.h
Normal 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 */
|
||||
224
xpcom/build/FileLocation.cpp
Normal file
224
xpcom/build/FileLocation.cpp
Normal 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
134
xpcom/build/FileLocation.h
Normal 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 */
|
||||
138
xpcom/build/FrozenFunctions.cpp
Normal file
138
xpcom/build/FrozenFunctions.cpp
Normal 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;
|
||||
}
|
||||
582
xpcom/build/IOInterposer.cpp
Normal file
582
xpcom/build/IOInterposer.cpp
Normal 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
295
xpcom/build/IOInterposer.h
Normal 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
|
||||
167
xpcom/build/IOInterposerPrivate.h
Normal file
167
xpcom/build/IOInterposerPrivate.h
Normal 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
|
||||
|
||||
258
xpcom/build/LateWriteChecks.cpp
Normal file
258
xpcom/build/LateWriteChecks.cpp
Normal 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
|
||||
60
xpcom/build/LateWriteChecks.h
Normal file
60
xpcom/build/LateWriteChecks.h
Normal 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
|
||||
225
xpcom/build/MainThreadIOLogger.cpp
Normal file
225
xpcom/build/MainThreadIOLogger.cpp
Normal 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
|
||||
|
||||
19
xpcom/build/MainThreadIOLogger.h
Normal file
19
xpcom/build/MainThreadIOLogger.h
Normal 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
|
||||
|
||||
185
xpcom/build/NSPRInterposer.cpp
Normal file
185
xpcom/build/NSPRInterposer.cpp
Normal 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
|
||||
|
||||
28
xpcom/build/NSPRInterposer.h
Normal file
28
xpcom/build/NSPRInterposer.h
Normal 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
188
xpcom/build/Omnijar.cpp
Normal 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
160
xpcom/build/Omnijar.h
Normal 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 */
|
||||
91
xpcom/build/PoisonIOInterposer.h
Normal file
91
xpcom/build/PoisonIOInterposer.h
Normal 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
|
||||
291
xpcom/build/PoisonIOInterposerBase.cpp
Normal file
291
xpcom/build/PoisonIOInterposerBase.cpp
Normal 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
|
||||
386
xpcom/build/PoisonIOInterposerMac.cpp
Normal file
386
xpcom/build/PoisonIOInterposerMac.cpp
Normal 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
|
||||
16
xpcom/build/PoisonIOInterposerStub.cpp
Normal file
16
xpcom/build/PoisonIOInterposerStub.cpp
Normal 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"
|
||||
501
xpcom/build/PoisonIOInterposerWin.cpp
Normal file
501
xpcom/build/PoisonIOInterposerWin.cpp
Normal 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
46
xpcom/build/ServiceList.h
Normal 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
71
xpcom/build/Services.cpp
Normal 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
45
xpcom/build/Services.h
Normal 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
178
xpcom/build/XPCOM.h
Normal 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
1126
xpcom/build/XPCOMInit.cpp
Normal file
File diff suppressed because it is too large
Load diff
81
xpcom/build/XPCOMModule.inc
Normal file
81
xpcom/build/XPCOMModule.inc
Normal 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)
|
||||
51
xpcom/build/XREChildData.h
Normal file
51
xpcom/build/XREChildData.h
Normal 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
|
||||
29
xpcom/build/XREShellData.h
Normal file
29
xpcom/build/XREShellData.h
Normal 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
789
xpcom/build/mach_override.c
Normal 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
121
xpcom/build/mach_override.h
Normal 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
102
xpcom/build/moz.build
Normal 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']
|
||||
1127
xpcom/build/nsWindowsDllInterceptor.h
Normal file
1127
xpcom/build/nsWindowsDllInterceptor.h
Normal file
File diff suppressed because it is too large
Load diff
433
xpcom/build/nsXPCOM.h
Normal file
433
xpcom/build/nsXPCOM.h
Normal 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
185
xpcom/build/nsXPCOMCID.h
Normal 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
|
||||
54
xpcom/build/nsXPCOMCIDInternal.h
Normal file
54
xpcom/build/nsXPCOMCIDInternal.h
Normal 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__
|
||||
317
xpcom/build/nsXPCOMPrivate.h
Normal file
317
xpcom/build/nsXPCOMPrivate.h
Normal 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
|
||||
366
xpcom/build/nsXPCOMStrings.cpp
Normal file
366
xpcom/build/nsXPCOMStrings.cpp
Normal 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
164
xpcom/build/nsXREAppData.h
Normal 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
538
xpcom/build/nsXULAppAPI.h
Normal 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
242
xpcom/build/perfprobe.cpp
Normal 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
204
xpcom/build/perfprobe.h
Normal 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
256
xpcom/build/xpcom_alpha.def
Normal 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
25
xpcom/build/xrecore.h
Normal 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__
|
||||
Loading…
Add table
Add a link
Reference in a new issue