mirror of
https://github.com/ManchildProductions/UXP-Fixed.git
synced 2026-05-26 17:45:49 +00:00
Issue #1751 -- Remove XP_MACOSX conditionals and support files from /xpcom
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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_MacHelpers_h
|
||||
#define mozilla_MacHelpers_h
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult GetSelectedCityInfo(nsAString& aCountryCode);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,40 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "MacHelpers.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
GetSelectedCityInfo(nsAString& aCountryCode)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
// Can be replaced with [[NSLocale currentLocale] countryCode] once we build
|
||||
// with the 10.12 SDK.
|
||||
id countryCode = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||
|
||||
if (![countryCode isKindOfClass:[NSString class]]) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const char* countryCodeUTF8 = [(NSString*)countryCode UTF8String];
|
||||
|
||||
if (!countryCodeUTF8) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
AppendUTF8toUTF16(countryCodeUTF8, aCountryCode);
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
} // namespace Mozilla
|
||||
|
||||
+1
-16
@@ -28,17 +28,6 @@ XPIDL_SOURCES += [
|
||||
'nsrootidl.idl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
XPIDL_SOURCES += [
|
||||
'nsIMacUtils.idl',
|
||||
]
|
||||
EXPORTS.mozilla += [
|
||||
'MacHelpers.h',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'MacHelpers.mm',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'xpcom_base'
|
||||
|
||||
EXPORTS += [
|
||||
@@ -136,11 +125,7 @@ if CONFIG['OS_ARCH'] == 'Linux':
|
||||
'SystemMemoryReporter.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'nsMacUtilsImpl.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
SOURCES += [
|
||||
'nsCrashOnException.cpp',
|
||||
]
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "nsString.h"
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
@@ -58,9 +58,7 @@
|
||||
#define KINFO_PROC struct kinfo_proc
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#define KP_FLAGS kp_proc.p_flag
|
||||
#elif defined(__DragonFly__)
|
||||
#if defined(__DragonFly__)
|
||||
#define KP_FLAGS kp_flags
|
||||
#elif defined(__FreeBSD__)
|
||||
#define KP_FLAGS ki_flag
|
||||
@@ -164,7 +162,7 @@ nsDebugImpl::GetIsDebuggerAttached(bool* aResult)
|
||||
|
||||
#if defined(XP_WIN)
|
||||
*aResult = ::IsDebuggerPresent();
|
||||
#elif defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
// Specify the info we're looking for
|
||||
int mib[] = {
|
||||
@@ -426,8 +424,6 @@ RealBreak()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
::DebugBreak();
|
||||
#elif defined(XP_MACOSX)
|
||||
raise(SIGTRAP);
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
|
||||
asm("int $3");
|
||||
#elif defined(__arm__)
|
||||
@@ -511,12 +507,6 @@ Break(const char* aMsg)
|
||||
}
|
||||
|
||||
RealBreak();
|
||||
#elif defined(XP_MACOSX)
|
||||
/* Note that we put this Mac OS X test above the GNUC/x86 test because the
|
||||
* GNUC/x86 test is also true on Intel Mac OS X and we want the PPC/x86
|
||||
* impls to be the same.
|
||||
*/
|
||||
RealBreak();
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
|
||||
RealBreak();
|
||||
#elif defined(__arm__)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* nsIMacUtils: Generic globally-available Mac-specific utilities.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(5E9072D7-FF95-455E-9466-8AF9841A72EC)]
|
||||
interface nsIMacUtils : nsISupports
|
||||
{
|
||||
/**
|
||||
* True when the main executable is a fat file supporting at least
|
||||
* ppc and x86 (universal binary).
|
||||
*/
|
||||
readonly attribute boolean isUniversalBinary;
|
||||
|
||||
/**
|
||||
* Returns a string containing a list of architectures delimited
|
||||
* by "-". Architecture sets are always in the same order:
|
||||
* ppc > i386 > ppc64 > x86_64 > (future additions)
|
||||
*/
|
||||
readonly attribute AString architecturesInBinary;
|
||||
|
||||
/**
|
||||
* True when running under binary translation (Rosetta).
|
||||
*/
|
||||
readonly attribute boolean isTranslated;
|
||||
};
|
||||
@@ -1,146 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsMacUtilsImpl.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMacUtilsImpl, nsIMacUtils)
|
||||
|
||||
nsresult
|
||||
nsMacUtilsImpl::GetArchString(nsAString& aArchString)
|
||||
{
|
||||
if (!mBinaryArchs.IsEmpty()) {
|
||||
aArchString.Assign(mBinaryArchs);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aArchString.Truncate();
|
||||
|
||||
bool foundPPC = false,
|
||||
foundX86 = false,
|
||||
foundPPC64 = false,
|
||||
foundX86_64 = false;
|
||||
|
||||
CFBundleRef mainBundle = ::CFBundleGetMainBundle();
|
||||
if (!mainBundle) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CFArrayRef archList = ::CFBundleCopyExecutableArchitectures(mainBundle);
|
||||
if (!archList) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CFIndex archCount = ::CFArrayGetCount(archList);
|
||||
for (CFIndex i = 0; i < archCount; i++) {
|
||||
CFNumberRef arch =
|
||||
static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archList, i));
|
||||
|
||||
int archInt = 0;
|
||||
if (!::CFNumberGetValue(arch, kCFNumberIntType, &archInt)) {
|
||||
::CFRelease(archList);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (archInt == kCFBundleExecutableArchitecturePPC) {
|
||||
foundPPC = true;
|
||||
} else if (archInt == kCFBundleExecutableArchitectureI386) {
|
||||
foundX86 = true;
|
||||
} else if (archInt == kCFBundleExecutableArchitecturePPC64) {
|
||||
foundPPC64 = true;
|
||||
} else if (archInt == kCFBundleExecutableArchitectureX86_64) {
|
||||
foundX86_64 = true;
|
||||
}
|
||||
}
|
||||
|
||||
::CFRelease(archList);
|
||||
|
||||
// The order in the string must always be the same so
|
||||
// don't do this in the loop.
|
||||
if (foundPPC) {
|
||||
mBinaryArchs.AppendLiteral("ppc");
|
||||
}
|
||||
|
||||
if (foundX86) {
|
||||
if (!mBinaryArchs.IsEmpty()) {
|
||||
mBinaryArchs.Append('-');
|
||||
}
|
||||
mBinaryArchs.AppendLiteral("i386");
|
||||
}
|
||||
|
||||
if (foundPPC64) {
|
||||
if (!mBinaryArchs.IsEmpty()) {
|
||||
mBinaryArchs.Append('-');
|
||||
}
|
||||
mBinaryArchs.AppendLiteral("ppc64");
|
||||
}
|
||||
|
||||
if (foundX86_64) {
|
||||
if (!mBinaryArchs.IsEmpty()) {
|
||||
mBinaryArchs.Append('-');
|
||||
}
|
||||
mBinaryArchs.AppendLiteral("x86_64");
|
||||
}
|
||||
|
||||
aArchString.Assign(mBinaryArchs);
|
||||
|
||||
return (aArchString.IsEmpty() ? NS_ERROR_FAILURE : NS_OK);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacUtilsImpl::GetIsUniversalBinary(bool* aIsUniversalBinary)
|
||||
{
|
||||
if (NS_WARN_IF(!aIsUniversalBinary)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
*aIsUniversalBinary = false;
|
||||
|
||||
nsAutoString archString;
|
||||
nsresult rv = GetArchString(archString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The delimiter char in the arch string is '-', so if that character
|
||||
// is in the string we know we have multiple architectures.
|
||||
*aIsUniversalBinary = (archString.Find("-") > -1);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacUtilsImpl::GetArchitecturesInBinary(nsAString& aArchString)
|
||||
{
|
||||
return GetArchString(aArchString);
|
||||
}
|
||||
|
||||
// True when running under binary translation (Rosetta).
|
||||
NS_IMETHODIMP
|
||||
nsMacUtilsImpl::GetIsTranslated(bool* aIsTranslated)
|
||||
{
|
||||
#ifdef __ppc__
|
||||
static bool sInitialized = false;
|
||||
|
||||
// Initialize sIsNative to 1. If the sysctl fails because it doesn't
|
||||
// exist, then translation is not possible, so the process must not be
|
||||
// running translated.
|
||||
static int32_t sIsNative = 1;
|
||||
|
||||
if (!sInitialized) {
|
||||
size_t sz = sizeof(sIsNative);
|
||||
sysctlbyname("sysctl.proc_native", &sIsNative, &sz, nullptr, 0);
|
||||
sInitialized = true;
|
||||
}
|
||||
|
||||
*aIsTranslated = !sIsNative;
|
||||
#else
|
||||
// Translation only exists for ppc code. Other architectures aren't
|
||||
// translated.
|
||||
*aIsTranslated = false;
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 nsMacUtilsImpl_h___
|
||||
#define nsMacUtilsImpl_h___
|
||||
|
||||
#include "nsIMacUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsMacUtilsImpl final : public nsIMacUtils
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMACUTILS
|
||||
|
||||
nsMacUtilsImpl()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
~nsMacUtilsImpl()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult GetArchString(nsAString& aArchString);
|
||||
|
||||
// A string containing a "-" delimited list of architectures
|
||||
// in our binary.
|
||||
nsString mBinaryArchs;
|
||||
};
|
||||
|
||||
// Global singleton service
|
||||
// 697BD3FD-43E5-41CE-AD5E-C339175C0818
|
||||
#define NS_MACUTILSIMPL_CID \
|
||||
{0x697BD3FD, 0x43E5, 0x41CE, {0xAD, 0x5E, 0xC3, 0x39, 0x17, 0x5C, 0x08, 0x18}}
|
||||
#define NS_MACUTILSIMPL_CONTRACTID "@mozilla.org/xpcom/mac-utils;1"
|
||||
|
||||
#endif /* nsMacUtilsImpl_h___ */
|
||||
@@ -395,168 +395,6 @@ ResidentFastDistinguishedAmount(int64_t* aN)
|
||||
return ResidentDistinguishedAmount(aN);
|
||||
}
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <mach/shared_region.h>
|
||||
#include <mach/task.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
GetTaskBasicInfo(struct task_basic_info* aTi)
|
||||
{
|
||||
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
|
||||
kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO,
|
||||
(task_info_t)aTi, &count);
|
||||
return kr == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
// The VSIZE figure on Mac includes huge amounts of shared memory and is always
|
||||
// absurdly high, eg. 2GB+ even at start-up. But both 'top' and 'ps' report
|
||||
// it, so we might as well too.
|
||||
#define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
|
||||
static MOZ_MUST_USE nsresult
|
||||
VsizeDistinguishedAmount(int64_t* aN)
|
||||
{
|
||||
task_basic_info ti;
|
||||
if (!GetTaskBasicInfo(&ti)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aN = ti.virtual_size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we're using jemalloc on Mac, we need to instruct jemalloc to purge the
|
||||
// pages it has madvise(MADV_FREE)'d before we read our RSS in order to get
|
||||
// an accurate result. The OS will take away MADV_FREE'd pages when there's
|
||||
// memory pressure, so ideally, they shouldn't count against our RSS.
|
||||
//
|
||||
// Purging these pages can take a long time for some users (see bug 789975),
|
||||
// so we provide the option to get the RSS without purging first.
|
||||
static MOZ_MUST_USE nsresult
|
||||
ResidentDistinguishedAmountHelper(int64_t* aN, bool aDoPurge)
|
||||
{
|
||||
#ifdef HAVE_JEMALLOC_STATS
|
||||
if (aDoPurge) {
|
||||
jemalloc_purge_freed_pages();
|
||||
}
|
||||
#endif
|
||||
|
||||
task_basic_info ti;
|
||||
if (!GetTaskBasicInfo(&ti)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aN = ti.resident_size;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
ResidentFastDistinguishedAmount(int64_t* aN)
|
||||
{
|
||||
return ResidentDistinguishedAmountHelper(aN, /* doPurge = */ false);
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
ResidentDistinguishedAmount(int64_t* aN)
|
||||
{
|
||||
return ResidentDistinguishedAmountHelper(aN, /* doPurge = */ true);
|
||||
}
|
||||
|
||||
#define HAVE_RESIDENT_UNIQUE_REPORTER 1
|
||||
|
||||
static bool
|
||||
InSharedRegion(mach_vm_address_t aAddr, cpu_type_t aType)
|
||||
{
|
||||
mach_vm_address_t base;
|
||||
mach_vm_address_t size;
|
||||
|
||||
switch (aType) {
|
||||
case CPU_TYPE_ARM:
|
||||
base = SHARED_REGION_BASE_ARM;
|
||||
size = SHARED_REGION_SIZE_ARM;
|
||||
break;
|
||||
case CPU_TYPE_I386:
|
||||
base = SHARED_REGION_BASE_I386;
|
||||
size = SHARED_REGION_SIZE_I386;
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
base = SHARED_REGION_BASE_X86_64;
|
||||
size = SHARED_REGION_SIZE_X86_64;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return base <= aAddr && aAddr < (base + size);
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
ResidentUniqueDistinguishedAmount(int64_t* aN)
|
||||
{
|
||||
if (!aN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
cpu_type_t cpu_type;
|
||||
size_t len = sizeof(cpu_type);
|
||||
if (sysctlbyname("sysctl.proc_cputype", &cpu_type, &len, NULL, 0) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Roughly based on libtop_update_vm_regions in
|
||||
// http://www.opensource.apple.com/source/top/top-100.1.2/libtop.c
|
||||
size_t privatePages = 0;
|
||||
mach_vm_size_t size = 0;
|
||||
for (mach_vm_address_t addr = MACH_VM_MIN_ADDRESS; ; addr += size) {
|
||||
vm_region_top_info_data_t info;
|
||||
mach_msg_type_number_t infoCount = VM_REGION_TOP_INFO_COUNT;
|
||||
mach_port_t objectName;
|
||||
|
||||
kern_return_t kr =
|
||||
mach_vm_region(mach_task_self(), &addr, &size, VM_REGION_TOP_INFO,
|
||||
reinterpret_cast<vm_region_info_t>(&info),
|
||||
&infoCount, &objectName);
|
||||
if (kr == KERN_INVALID_ADDRESS) {
|
||||
// Done iterating VM regions.
|
||||
break;
|
||||
} else if (kr != KERN_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (InSharedRegion(addr, cpu_type) && info.share_mode != SM_PRIVATE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (info.share_mode) {
|
||||
case SM_LARGE_PAGE:
|
||||
// NB: Large pages are not shareable and always resident.
|
||||
case SM_PRIVATE:
|
||||
privatePages += info.private_pages_resident;
|
||||
privatePages += info.shared_pages_resident;
|
||||
break;
|
||||
case SM_COW:
|
||||
privatePages += info.private_pages_resident;
|
||||
if (info.ref_count == 1) {
|
||||
// Treat copy-on-write pages as private if they only have one reference.
|
||||
privatePages += info.shared_pages_resident;
|
||||
}
|
||||
break;
|
||||
case SM_SHARED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vm_size_t pageSize;
|
||||
if (host_page_size(mach_host_self(), &pageSize) != KERN_SUCCESS) {
|
||||
pageSize = PAGE_SIZE;
|
||||
}
|
||||
|
||||
*aN = privatePages * pageSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#elif defined(XP_WIN)
|
||||
|
||||
#include <windows.h>
|
||||
@@ -1147,9 +985,7 @@ ResidentPeakDistinguishedAmount(int64_t* aN)
|
||||
// - Solaris: pages? But some sources it actually always returns 0, so
|
||||
// check for that
|
||||
// - Linux, {Net/Open/Free}BSD, DragonFly: KiB
|
||||
#ifdef XP_MACOSX
|
||||
*aN = usage.ru_maxrss;
|
||||
#elif defined(XP_SOLARIS)
|
||||
#if defined(XP_SOLARIS)
|
||||
*aN = usage.ru_maxrss * getpagesize();
|
||||
#else
|
||||
*aN = usage.ru_maxrss * 1024;
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
#include "nsWindowsHelpers.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "MacHelpers.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -44,10 +40,6 @@
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
// Slot for NS_InitXPCOM2 to pass information to nsSystemInfo::Init.
|
||||
// Only set to nonzero (potentially) if XP_UNIX. On such systems, the
|
||||
// system call to discover the appropriate value is not thread-safe,
|
||||
@@ -418,67 +410,6 @@ nsSystemInfo::Init()
|
||||
cpuFamily = si.wProcessorLevel;
|
||||
cpuModel = si.wProcessorRevision >> 8;
|
||||
cpuStepping = si.wProcessorRevision & 0xFF;
|
||||
#elif defined (XP_MACOSX)
|
||||
// CPU speed
|
||||
uint64_t sysctlValue64 = 0;
|
||||
uint32_t sysctlValue32 = 0;
|
||||
size_t len = 0;
|
||||
len = sizeof(sysctlValue64);
|
||||
if (!sysctlbyname("hw.cpufrequency_max", &sysctlValue64, &len, NULL, 0)) {
|
||||
cpuSpeed = static_cast<int>(sysctlValue64/1000000);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue64) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("hw.physicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
|
||||
physicalCPUs = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("hw.logicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
|
||||
logicalCPUs = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue64);
|
||||
if (!sysctlbyname("hw.l2cachesize", &sysctlValue64, &len, NULL, 0)) {
|
||||
cacheSizeL2 = static_cast<int>(sysctlValue64/1024);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue64) == len);
|
||||
|
||||
len = sizeof(sysctlValue64);
|
||||
if (!sysctlbyname("hw.l3cachesize", &sysctlValue64, &len, NULL, 0)) {
|
||||
cacheSizeL3 = static_cast<int>(sysctlValue64/1024);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue64) == len);
|
||||
|
||||
if (!sysctlbyname("machdep.cpu.vendor", NULL, &len, NULL, 0)) {
|
||||
char* cpuVendorStr = new char[len];
|
||||
if (!sysctlbyname("machdep.cpu.vendor", cpuVendorStr, &len, NULL, 0)) {
|
||||
cpuVendor = cpuVendorStr;
|
||||
}
|
||||
delete [] cpuVendorStr;
|
||||
}
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("machdep.cpu.family", &sysctlValue32, &len, NULL, 0)) {
|
||||
cpuFamily = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("machdep.cpu.model", &sysctlValue32, &len, NULL, 0)) {
|
||||
cpuModel = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("machdep.cpu.stepping", &sysctlValue32, &len, NULL, 0)) {
|
||||
cpuStepping = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
#elif defined(XP_LINUX)
|
||||
// Get vendor, family, model, stepping, physical cores, L3 cache size
|
||||
// from /proc/cpuinfo file
|
||||
@@ -655,14 +586,6 @@ nsSystemInfo::Init()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
nsAutoString countryCode;
|
||||
if (NS_SUCCEEDED(GetSelectedCityInfo(countryCode))) {
|
||||
rv = SetPropertyAsAString(NS_LITERAL_STRING("countryCode"), countryCode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
// This must be done here because NSPR can only separate OS's when compiled, not libraries.
|
||||
// 64 bytes is going to be well enough for "GTK " followed by 3 integers
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#if defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
#elif defined(XP_MACOSX)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include "prrng.h"
|
||||
@@ -34,7 +32,7 @@ nsUUIDGenerator::Init()
|
||||
// We're a service, so we're guaranteed that Init() is not going
|
||||
// to be reentered while we're inside Init().
|
||||
|
||||
#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM)
|
||||
#if !defined(XP_WIN) && !defined(HAVE_ARC4RANDOM)
|
||||
/* initialize random number generator using NSPR random noise */
|
||||
unsigned int seed;
|
||||
|
||||
@@ -71,7 +69,7 @@ nsUUIDGenerator::Init()
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* non XP_WIN and non XP_MACOSX and non ARC4RANDOM */
|
||||
#endif /* non XP_WIN and non ARC4RANDOM */
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -106,17 +104,7 @@ nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId)
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#elif defined(XP_MACOSX)
|
||||
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
|
||||
if (!uuid) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
|
||||
memcpy(aId, &bytes, sizeof(nsID));
|
||||
|
||||
CFRelease(uuid);
|
||||
#else /* not windows or OS X; generate randomness using random(). */
|
||||
#else /* not windows; generate randomness using random(). */
|
||||
/* XXX we should be saving the return of setstate here and switching
|
||||
* back to it; instead, we use the value returned when we called
|
||||
* initstate, since older glibc's have broken setstate() return values
|
||||
|
||||
@@ -28,7 +28,7 @@ private:
|
||||
protected:
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM)
|
||||
#if !defined(XP_WIN) && !defined(HAVE_ARC4RANDOM)
|
||||
char mState[128];
|
||||
char* mSavedState;
|
||||
uint8_t mRBytes;
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#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>
|
||||
@@ -43,46 +41,6 @@ private:
|
||||
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(XP_UNIX)
|
||||
static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN])
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ void MozillaUnRegisterDebugFILE(FILE* aFile);
|
||||
|
||||
MOZ_END_EXTERN_C
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||
#if defined(XP_WIN)
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace mozilla {
|
||||
@@ -53,16 +53,6 @@ bool IsDebugFile(intptr_t aFileID);
|
||||
*/
|
||||
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.
|
||||
@@ -72,19 +62,16 @@ void ClearPoisonIOInterposer();
|
||||
} // namespace mozilla
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#else /* XP_WIN || XP_MACOSX */
|
||||
#else /* XP_WIN */
|
||||
|
||||
#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 /* XP_WIN */
|
||||
|
||||
#endif // mozilla_PoisonIOInterposer_h
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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
|
||||
@@ -1015,9 +1015,6 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
|
||||
PROFILER_MARKER("Shutdown xpcom");
|
||||
// If we are doing any shutdown checks, poison writes.
|
||||
if (gShutdownChecks != SCM_NOTHING) {
|
||||
#ifdef XP_MACOSX
|
||||
mozilla::OnlyReportDirtyWrites();
|
||||
#endif /* XP_MACOSX */
|
||||
mozilla::BeginLateWriteChecks();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,789 +0,0 @@
|
||||
// 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
|
||||
@@ -1,121 +0,0 @@
|
||||
/*******************************************************************************
|
||||
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_
|
||||
@@ -32,13 +32,6 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
'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']
|
||||
|
||||
|
||||
@@ -254,15 +254,8 @@ void LogTerm();
|
||||
|
||||
#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"
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
*/
|
||||
#define XRE_SYS_SHARE_EXTENSION_PARENT_DIR "XRESysSExtPD"
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_MACOSX)
|
||||
#if defined(XP_UNIX)
|
||||
/**
|
||||
* Directory service keys for the system-wide and user-specific
|
||||
* directories where host manifests used by the WebExtensions
|
||||
|
||||
@@ -33,10 +33,6 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define IMPLEMENT_BREAK_AFTER_LOAD
|
||||
#endif
|
||||
|
||||
+4
-149
@@ -12,16 +12,7 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <mach/machine.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#elif defined(XP_UNIX)
|
||||
#if defined(XP_UNIX)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#if defined(LINUX)
|
||||
@@ -56,20 +47,6 @@ mozilla::fallocate(PRFileDesc* aFD, int64_t aLength)
|
||||
|
||||
PR_Seek64(aFD, oldpos, PR_SEEK_SET);
|
||||
return retval;
|
||||
#elif defined(XP_MACOSX)
|
||||
int fd = PR_FileDesc2NativeHandle(aFD);
|
||||
fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, aLength};
|
||||
// Try to get a continous chunk of disk space
|
||||
int ret = fcntl(fd, F_PREALLOCATE, &store);
|
||||
if (ret == -1) {
|
||||
// OK, perhaps we are too fragmented, allocate non-continuous
|
||||
store.fst_flags = F_ALLOCATEALL;
|
||||
ret = fcntl(fd, F_PREALLOCATE, &store);
|
||||
if (ret == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ftruncate(fd, aLength) == 0;
|
||||
#elif defined(XP_UNIX)
|
||||
// The following is copied from fcntlSizeHint in sqlite
|
||||
/* If the OS does not have posix_fallocate(), fake it. First use
|
||||
@@ -225,7 +202,7 @@ mozilla::ReadAheadLib(nsIFile* aFile)
|
||||
return;
|
||||
}
|
||||
ReadAheadLib(path.get());
|
||||
#elif defined(LINUX) || defined(XP_MACOSX)
|
||||
#elif defined(LINUX)
|
||||
nsAutoCString nativePath;
|
||||
if (!aFile || NS_FAILED(aFile->GetNativePath(nativePath))) {
|
||||
return;
|
||||
@@ -244,7 +221,7 @@ mozilla::ReadAheadFile(nsIFile* aFile, const size_t aOffset,
|
||||
return;
|
||||
}
|
||||
ReadAheadFile(path.get(), aOffset, aCount, aOutFd);
|
||||
#elif defined(LINUX) || defined(XP_MACOSX)
|
||||
#elif defined(LINUX)
|
||||
nsAutoCString nativePath;
|
||||
if (!aFile || NS_FAILED(aFile->GetNativePath(nativePath))) {
|
||||
return;
|
||||
@@ -271,64 +248,6 @@ static const unsigned char ELFCLASS = ELFCLASS32;
|
||||
typedef Elf32_Off Elf_Off;
|
||||
#endif
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
|
||||
#if defined(__i386__)
|
||||
static const uint32_t CPU_TYPE = CPU_TYPE_X86;
|
||||
#elif defined(__x86_64__)
|
||||
static const uint32_t CPU_TYPE = CPU_TYPE_X86_64;
|
||||
#elif defined(__ppc__)
|
||||
static const uint32_t CPU_TYPE = CPU_TYPE_POWERPC;
|
||||
#elif defined(__ppc64__)
|
||||
static const uint32_t CPU_TYPE = CPU_TYPE_POWERPC64;
|
||||
#else
|
||||
#error Unsupported CPU type
|
||||
#endif
|
||||
|
||||
#ifdef __LP64__
|
||||
#undef LC_SEGMENT
|
||||
#define LC_SEGMENT LC_SEGMENT_64
|
||||
#undef MH_MAGIC
|
||||
#define MH_MAGIC MH_MAGIC_64
|
||||
#define cpu_mach_header mach_header_64
|
||||
#define segment_command segment_command_64
|
||||
#else
|
||||
#define cpu_mach_header mach_header
|
||||
#endif
|
||||
|
||||
class ScopedMMap
|
||||
{
|
||||
public:
|
||||
explicit ScopedMMap(const char* aFilePath)
|
||||
: buf(nullptr)
|
||||
{
|
||||
fd = open(aFilePath, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) < 0) {
|
||||
return;
|
||||
}
|
||||
size = st.st_size;
|
||||
buf = (char*)mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
}
|
||||
~ScopedMMap()
|
||||
{
|
||||
if (buf) {
|
||||
munmap(buf, size);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
operator char*() { return buf; }
|
||||
int getFd() { return fd; }
|
||||
private:
|
||||
int fd;
|
||||
char* buf;
|
||||
size_t size;
|
||||
};
|
||||
#endif
|
||||
|
||||
void
|
||||
@@ -385,14 +304,6 @@ mozilla::ReadAhead(mozilla::filedesc_t aFd, const size_t aOffset,
|
||||
|
||||
readahead(aFd, aOffset, aCount);
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
|
||||
struct radvisory ra;
|
||||
ra.ra_offset = aOffset;
|
||||
ra.ra_count = aCount;
|
||||
// The F_RDADVISE fcntl is equivalent to Linux' readahead() system call.
|
||||
fcntl(aFd, F_RDADVISE, &ra);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -449,62 +360,6 @@ mozilla::ReadAheadLib(mozilla::pathstr_t aFilePath)
|
||||
ReadAhead(fd, 0, end);
|
||||
}
|
||||
close(fd);
|
||||
#elif defined(XP_MACOSX)
|
||||
ScopedMMap buf(aFilePath);
|
||||
char* base = buf;
|
||||
if (!base) {
|
||||
return;
|
||||
}
|
||||
|
||||
// An OSX binary might either be a fat (universal) binary or a
|
||||
// Mach-O binary. A fat binary actually embeds several Mach-O
|
||||
// binaries. If we have a fat binary, find the offset where the
|
||||
// Mach-O binary for our CPU type can be found.
|
||||
struct fat_header* fh = (struct fat_header*)base;
|
||||
|
||||
if (OSSwapBigToHostInt32(fh->magic) == FAT_MAGIC) {
|
||||
uint32_t nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
|
||||
struct fat_arch* arch = (struct fat_arch*)&buf[sizeof(struct fat_header)];
|
||||
for (; nfat_arch; arch++, nfat_arch--) {
|
||||
if (OSSwapBigToHostInt32(arch->cputype) == CPU_TYPE) {
|
||||
base += OSSwapBigToHostInt32(arch->offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (base == buf) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check Mach-O magic in the Mach header
|
||||
struct cpu_mach_header* mh = (struct cpu_mach_header*)base;
|
||||
if (mh->magic != MH_MAGIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The Mach header is followed by a sequence of load commands.
|
||||
// Each command has a header containing the command type and the
|
||||
// command size. LD_SEGMENT commands describes how the dynamic
|
||||
// loader is going to map the file in memory. We use that
|
||||
// information to find the biggest offset from the library that
|
||||
// will be mapped in memory.
|
||||
char* cmd = &base[sizeof(struct cpu_mach_header)];
|
||||
uint32_t end = 0;
|
||||
for (uint32_t ncmds = mh->ncmds; ncmds; ncmds--) {
|
||||
struct segment_command* sh = (struct segment_command*)cmd;
|
||||
if (sh->cmd != LC_SEGMENT) {
|
||||
continue;
|
||||
}
|
||||
if (end < sh->fileoff + sh->filesize) {
|
||||
end = sh->fileoff + sh->filesize;
|
||||
}
|
||||
cmd += sh->cmdsize;
|
||||
}
|
||||
// Let the kernel read ahead what the dynamic loader is going to
|
||||
// map in memory soon after.
|
||||
if (end > 0) {
|
||||
ReadAhead(buf.getFd(), base - buf, end);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -531,7 +386,7 @@ mozilla::ReadAheadFile(mozilla::pathstr_t aFilePath, const size_t aOffset,
|
||||
if (!aOutFd) {
|
||||
CloseHandle(fd);
|
||||
}
|
||||
#elif defined(LINUX) || defined(XP_MACOSX) || defined(XP_SOLARIS)
|
||||
#elif defined(LINUX) || defined(XP_SOLARIS)
|
||||
if (!aFilePath) {
|
||||
if (aOutFd) {
|
||||
*aOutFd = -1;
|
||||
|
||||
@@ -124,9 +124,7 @@ void NS_MakeRandomString(char* aBuf, int32_t aBufLen);
|
||||
// identify or replace all known path separators.
|
||||
#define KNOWN_PATH_SEPARATORS "\\/"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#define FILE_PATH_SEPARATOR "/"
|
||||
#elif defined(XP_WIN)
|
||||
#if defined(XP_WIN)
|
||||
#define FILE_PATH_SEPARATOR "\\"
|
||||
#elif defined(XP_UNIX)
|
||||
#define FILE_PATH_SEPARATOR "/"
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#elif defined(XP_MACOSX)
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
@@ -439,12 +437,6 @@ nsAutoLowPriorityIO::nsAutoLowPriorityIO()
|
||||
#if defined(XP_WIN)
|
||||
lowIOPrioritySet = SetThreadPriority(GetCurrentThread(),
|
||||
THREAD_MODE_BACKGROUND_BEGIN);
|
||||
#elif defined(XP_MACOSX)
|
||||
oldPriority = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD);
|
||||
lowIOPrioritySet = oldPriority != -1 &&
|
||||
setiopolicy_np(IOPOL_TYPE_DISK,
|
||||
IOPOL_SCOPE_THREAD,
|
||||
IOPOL_THROTTLE) != -1;
|
||||
#else
|
||||
lowIOPrioritySet = false;
|
||||
#endif
|
||||
@@ -457,9 +449,5 @@ nsAutoLowPriorityIO::~nsAutoLowPriorityIO()
|
||||
// On Windows the old thread priority is automatically restored
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
|
||||
}
|
||||
#elif defined(XP_MACOSX)
|
||||
if (MOZ_LIKELY(lowIOPrioritySet)) {
|
||||
setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, oldPriority);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1037,9 +1037,6 @@ public:
|
||||
|
||||
private:
|
||||
bool lowIOPrioritySet;
|
||||
#if defined(XP_MACOSX)
|
||||
int oldPriority;
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
|
||||
@@ -97,11 +97,7 @@ static LibHandleType
|
||||
GetLibHandle(pathstr_t aDependentLib)
|
||||
{
|
||||
LibHandleType libHandle = dlopen(aDependentLib,
|
||||
RTLD_GLOBAL | RTLD_LAZY
|
||||
#ifdef XP_MACOSX
|
||||
| RTLD_FIRST
|
||||
#endif
|
||||
);
|
||||
RTLD_GLOBAL | RTLD_LAZY);
|
||||
if (!libHandle) {
|
||||
fprintf(stderr, "XPCOMGlueLoad error for file %s:\n%s\n", aDependentLib,
|
||||
dlerror());
|
||||
@@ -235,22 +231,6 @@ XPCOMGlueLoad(const char* aXPCOMFile)
|
||||
char xpcomDir[MAXPATHLEN];
|
||||
#ifdef XP_WIN
|
||||
const char* lastSlash = ns_strrpbrk(aXPCOMFile, "/\\");
|
||||
#elif XP_MACOSX
|
||||
// On OSX, the dependentlibs.list file lives under Contents/Resources.
|
||||
// However, the actual libraries listed in dependentlibs.list live under
|
||||
// Contents/MacOS. We want to read the list from Contents/Resources, then
|
||||
// load the libraries from Contents/MacOS.
|
||||
const char *tempSlash = strrchr(aXPCOMFile, '/');
|
||||
size_t tempLen = size_t(tempSlash - aXPCOMFile);
|
||||
if (tempLen > MAXPATHLEN) {
|
||||
return nullptr;
|
||||
}
|
||||
char tempBuffer[MAXPATHLEN];
|
||||
memcpy(tempBuffer, aXPCOMFile, tempLen);
|
||||
tempBuffer[tempLen] = '\0';
|
||||
const char *slash = strrchr(tempBuffer, '/');
|
||||
tempLen = size_t(slash - tempBuffer);
|
||||
const char *lastSlash = aXPCOMFile + tempLen;
|
||||
#else
|
||||
const char* lastSlash = strrchr(aXPCOMFile, '/');
|
||||
#endif
|
||||
@@ -259,19 +239,11 @@ XPCOMGlueLoad(const char* aXPCOMFile)
|
||||
size_t len = size_t(lastSlash - aXPCOMFile);
|
||||
|
||||
if (len > MAXPATHLEN - sizeof(XPCOM_FILE_PATH_SEPARATOR
|
||||
#ifdef XP_MACOSX
|
||||
"Resources"
|
||||
XPCOM_FILE_PATH_SEPARATOR
|
||||
#endif
|
||||
XPCOM_DEPENDENT_LIBS_LIST)) {
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(xpcomDir, aXPCOMFile, len);
|
||||
strcpy(xpcomDir + len, XPCOM_FILE_PATH_SEPARATOR
|
||||
#ifdef XP_MACOSX
|
||||
"Resources"
|
||||
XPCOM_FILE_PATH_SEPARATOR
|
||||
#endif
|
||||
XPCOM_DEPENDENT_LIBS_LIST);
|
||||
cursor = xpcomDir + len + 1;
|
||||
} else {
|
||||
@@ -289,14 +261,6 @@ XPCOMGlueLoad(const char* aXPCOMFile)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
tempLen = size_t(cursor - xpcomDir);
|
||||
if (tempLen > MAXPATHLEN - sizeof("MacOS" XPCOM_FILE_PATH_SEPARATOR) - 1) {
|
||||
return nullptr;
|
||||
}
|
||||
strcpy(cursor, "MacOS" XPCOM_FILE_PATH_SEPARATOR);
|
||||
cursor += strlen(cursor);
|
||||
#endif
|
||||
*cursor = '\0';
|
||||
|
||||
char buffer[MAXPATHLEN];
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
// This namespace contains methods with Obj-C/Cocoa implementations. The header
|
||||
// is C/C++ for inclusion in C/C++-only files.
|
||||
|
||||
#ifndef CocoaFileUtils_h_
|
||||
#define CocoaFileUtils_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
namespace CocoaFileUtils {
|
||||
|
||||
nsresult RevealFileInFinder(CFURLRef aUrl);
|
||||
nsresult OpenURL(CFURLRef aUrl);
|
||||
nsresult GetFileCreatorCode(CFURLRef aUrl, OSType* aCreatorCode);
|
||||
nsresult SetFileCreatorCode(CFURLRef aUrl, OSType aCreatorCode);
|
||||
nsresult GetFileTypeCode(CFURLRef aUrl, OSType* aTypeCode);
|
||||
nsresult SetFileTypeCode(CFURLRef aUrl, OSType aTypeCode);
|
||||
void AddOriginMetadataToFile(const CFStringRef filePath,
|
||||
const CFURLRef sourceURL,
|
||||
const CFURLRef referrerURL);
|
||||
void AddQuarantineMetadataToFile(const CFStringRef filePath,
|
||||
const CFURLRef sourceURL,
|
||||
const CFURLRef referrerURL,
|
||||
const bool isFromWeb);
|
||||
CFURLRef GetTemporaryFolderCFURLRef();
|
||||
|
||||
} // namespace CocoaFileUtils
|
||||
|
||||
#endif
|
||||
@@ -1,267 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:set ts=2 sts=2 sw=2 et cin:
|
||||
/* 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 "CocoaFileUtils.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
// Need to cope with us using old versions of the SDK and needing this on 10.10+
|
||||
#if !defined(MAC_OS_X_VERSION_10_10) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10)
|
||||
const CFStringRef kCFURLQuarantinePropertiesKey = CFSTR("NSURLQuarantinePropertiesKey");
|
||||
#endif
|
||||
|
||||
namespace CocoaFileUtils {
|
||||
|
||||
nsresult RevealFileInFinder(CFURLRef url)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (NS_WARN_IF(!url))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
|
||||
BOOL success = [[NSWorkspace sharedWorkspace] selectFile:[(NSURL*)url path] inFileViewerRootedAtPath:@""];
|
||||
[ap release];
|
||||
|
||||
return (success ? NS_OK : NS_ERROR_FAILURE);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult OpenURL(CFURLRef url)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (NS_WARN_IF(!url))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
|
||||
BOOL success = [[NSWorkspace sharedWorkspace] openURL:(NSURL*)url];
|
||||
[ap release];
|
||||
|
||||
return (success ? NS_OK : NS_ERROR_FAILURE);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult GetFileCreatorCode(CFURLRef url, OSType *creatorCode)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (NS_WARN_IF(!url) || NS_WARN_IF(!creatorCode))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
NSString *resolvedPath = [[(NSURL*)url path] stringByResolvingSymlinksInPath];
|
||||
if (!resolvedPath) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSDictionary* dict = [[NSFileManager defaultManager] attributesOfItemAtPath:resolvedPath error:nil];
|
||||
if (!dict) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSNumber* creatorNum = (NSNumber*)[dict objectForKey:NSFileHFSCreatorCode];
|
||||
if (!creatorNum) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*creatorCode = [creatorNum unsignedLongValue];
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult SetFileCreatorCode(CFURLRef url, OSType creatorCode)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (NS_WARN_IF(!url))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:creatorCode] forKey:NSFileHFSCreatorCode];
|
||||
BOOL success = [[NSFileManager defaultManager] setAttributes:dict ofItemAtPath:[(NSURL*)url path] error:nil];
|
||||
[ap release];
|
||||
return (success ? NS_OK : NS_ERROR_FAILURE);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult GetFileTypeCode(CFURLRef url, OSType *typeCode)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (NS_WARN_IF(!url) || NS_WARN_IF(!typeCode))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
NSString *resolvedPath = [[(NSURL*)url path] stringByResolvingSymlinksInPath];
|
||||
if (!resolvedPath) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSDictionary* dict = [[NSFileManager defaultManager] attributesOfItemAtPath:resolvedPath error:nil];
|
||||
if (!dict) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSNumber* typeNum = (NSNumber*)[dict objectForKey:NSFileHFSTypeCode];
|
||||
if (!typeNum) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*typeCode = [typeNum unsignedLongValue];
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult SetFileTypeCode(CFURLRef url, OSType typeCode)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (NS_WARN_IF(!url))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode] forKey:NSFileHFSTypeCode];
|
||||
BOOL success = [[NSFileManager defaultManager] setAttributes:dict ofItemAtPath:[(NSURL*)url path] error:nil];
|
||||
[ap release];
|
||||
return (success ? NS_OK : NS_ERROR_FAILURE);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
void AddOriginMetadataToFile(const CFStringRef filePath,
|
||||
const CFURLRef sourceURL,
|
||||
const CFURLRef referrerURL) {
|
||||
typedef OSStatus (*MDItemSetAttribute_type)(MDItemRef, CFStringRef, CFTypeRef);
|
||||
static MDItemSetAttribute_type mdItemSetAttributeFunc = NULL;
|
||||
|
||||
static bool did_symbol_lookup = false;
|
||||
if (!did_symbol_lookup) {
|
||||
did_symbol_lookup = true;
|
||||
|
||||
CFBundleRef metadata_bundle = ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Metadata"));
|
||||
if (!metadata_bundle) {
|
||||
return;
|
||||
}
|
||||
|
||||
mdItemSetAttributeFunc = (MDItemSetAttribute_type)
|
||||
::CFBundleGetFunctionPointerForName(metadata_bundle, CFSTR("MDItemSetAttribute"));
|
||||
}
|
||||
if (!mdItemSetAttributeFunc) {
|
||||
return;
|
||||
}
|
||||
|
||||
MDItemRef mdItem = ::MDItemCreate(NULL, filePath);
|
||||
if (!mdItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
CFMutableArrayRef list = ::CFArrayCreateMutable(kCFAllocatorDefault, 2, NULL);
|
||||
if (!list) {
|
||||
::CFRelease(mdItem);
|
||||
return;
|
||||
}
|
||||
|
||||
// The first item in the list is the source URL of the downloaded file.
|
||||
if (sourceURL) {
|
||||
::CFArrayAppendValue(list, ::CFURLGetString(sourceURL));
|
||||
}
|
||||
|
||||
// If the referrer is known, store that in the second position.
|
||||
if (referrerURL) {
|
||||
::CFArrayAppendValue(list, ::CFURLGetString(referrerURL));
|
||||
}
|
||||
|
||||
mdItemSetAttributeFunc(mdItem, kMDItemWhereFroms, list);
|
||||
|
||||
::CFRelease(list);
|
||||
::CFRelease(mdItem);
|
||||
}
|
||||
|
||||
void AddQuarantineMetadataToFile(const CFStringRef filePath,
|
||||
const CFURLRef sourceURL,
|
||||
const CFURLRef referrerURL,
|
||||
const bool isFromWeb) {
|
||||
CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
||||
filePath,
|
||||
kCFURLPOSIXPathStyle,
|
||||
false);
|
||||
|
||||
// The properties key changed in 10.10:
|
||||
CFStringRef quarantinePropKey;
|
||||
if (nsCocoaFeatures::OnYosemiteOrLater()) {
|
||||
quarantinePropKey = kCFURLQuarantinePropertiesKey;
|
||||
} else {
|
||||
quarantinePropKey = kLSItemQuarantineProperties;
|
||||
}
|
||||
CFDictionaryRef quarantineProps = NULL;
|
||||
Boolean success = ::CFURLCopyResourcePropertyForKey(fileURL,
|
||||
quarantinePropKey,
|
||||
&quarantineProps,
|
||||
NULL);
|
||||
|
||||
// If there aren't any quarantine properties then the user probably
|
||||
// set up an exclusion and we don't need to add metadata.
|
||||
if (!success || !quarantineProps) {
|
||||
::CFRelease(fileURL);
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't know what to do if the props aren't a dictionary.
|
||||
if (::CFGetTypeID(quarantineProps) != ::CFDictionaryGetTypeID()) {
|
||||
::CFRelease(fileURL);
|
||||
::CFRelease(quarantineProps);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a mutable copy of the properties.
|
||||
CFMutableDictionaryRef mutQuarantineProps =
|
||||
::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)quarantineProps);
|
||||
::CFRelease(quarantineProps);
|
||||
|
||||
// Add metadata that the OS couldn't infer.
|
||||
|
||||
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineTypeKey)) {
|
||||
CFStringRef type = isFromWeb ? kLSQuarantineTypeWebDownload : kLSQuarantineTypeOtherDownload;
|
||||
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineTypeKey, type);
|
||||
}
|
||||
|
||||
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey) && referrerURL) {
|
||||
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineOriginURLKey, referrerURL);
|
||||
}
|
||||
|
||||
if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineDataURLKey) && sourceURL) {
|
||||
::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineDataURLKey, sourceURL);
|
||||
}
|
||||
|
||||
// Set quarantine properties on file.
|
||||
::CFURLSetResourcePropertyForKey(fileURL,
|
||||
quarantinePropKey,
|
||||
mutQuarantineProps,
|
||||
NULL);
|
||||
|
||||
::CFRelease(fileURL);
|
||||
::CFRelease(mutQuarantineProps);
|
||||
}
|
||||
|
||||
CFURLRef GetTemporaryFolderCFURLRef()
|
||||
{
|
||||
NSString* tempDir = ::NSTemporaryDirectory();
|
||||
return tempDir == nil ? NULL : (CFURLRef)[NSURL fileURLWithPath:tempDir
|
||||
isDirectory:YES];
|
||||
}
|
||||
|
||||
} // namespace CocoaFileUtils
|
||||
@@ -37,11 +37,6 @@ XPIDL_SOURCES += [
|
||||
'nsIUnicharOutputStream.idl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
XPIDL_SOURCES += [
|
||||
'nsILocalFileMac.idl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
EXPORTS += ['nsLocalFileWin.h']
|
||||
EXPORTS.mozilla += [
|
||||
@@ -123,11 +118,6 @@ SOURCES += [
|
||||
'FilePreferences.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'CocoaFileUtils.mm',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "nsILocalFile.idl"
|
||||
|
||||
%{C++
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
%}
|
||||
|
||||
native OSType(OSType);
|
||||
native FSSpec(FSSpec);
|
||||
native FSRef(FSRef);
|
||||
[ptr] native FSRefPtr(FSRef);
|
||||
native CFURLRef(CFURLRef);
|
||||
|
||||
[scriptable, builtinclass, uuid(623eca5b-c25d-4e27-be5a-789a66c4b2f7)]
|
||||
interface nsILocalFileMac : nsILocalFile
|
||||
{
|
||||
/**
|
||||
* initWithCFURL
|
||||
*
|
||||
* Init this object with a CFURLRef
|
||||
*
|
||||
* NOTE: Supported only for XP_MACOSX
|
||||
* NOTE: If the path of the CFURL is /a/b/c, at least a/b must exist beforehand.
|
||||
*
|
||||
* @param aCFURL the CoreFoundation URL
|
||||
*
|
||||
*/
|
||||
[noscript] void initWithCFURL(in CFURLRef aCFURL);
|
||||
|
||||
/**
|
||||
* initWithFSRef
|
||||
*
|
||||
* Init this object with an FSRef
|
||||
*
|
||||
* NOTE: Supported only for XP_MACOSX
|
||||
*
|
||||
* @param aFSRef the native FSRef
|
||||
*
|
||||
*/
|
||||
[noscript] void initWithFSRef([const] in FSRefPtr aFSRef);
|
||||
|
||||
/**
|
||||
* getCFURL
|
||||
*
|
||||
* Returns the CFURLRef of the file object. The caller is
|
||||
* responsible for calling CFRelease() on it.
|
||||
*
|
||||
* NOTE: Observes the state of the followLinks attribute.
|
||||
* If the file object is an alias and followLinks is TRUE, returns
|
||||
* the target of the alias. If followLinks is FALSE, returns
|
||||
* the unresolved alias file.
|
||||
*
|
||||
* NOTE: Supported only for XP_MACOSX
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
[noscript] CFURLRef getCFURL();
|
||||
|
||||
/**
|
||||
* getFSRef
|
||||
*
|
||||
* Returns the FSRef of the file object.
|
||||
*
|
||||
* NOTE: Observes the state of the followLinks attribute.
|
||||
* If the file object is an alias and followLinks is TRUE, returns
|
||||
* the target of the alias. If followLinks is FALSE, returns
|
||||
* the unresolved alias file.
|
||||
*
|
||||
* NOTE: Supported only for XP_MACOSX
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
[noscript] FSRef getFSRef();
|
||||
|
||||
/**
|
||||
* getFSSpec
|
||||
*
|
||||
* Returns the FSSpec of the file object.
|
||||
*
|
||||
* NOTE: Observes the state of the followLinks attribute.
|
||||
* If the file object is an alias and followLinks is TRUE, returns
|
||||
* the target of the alias. If followLinks is FALSE, returns
|
||||
* the unresolved alias file.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
[noscript] FSSpec getFSSpec();
|
||||
|
||||
/**
|
||||
* fileSizeWithResFork
|
||||
*
|
||||
* Returns the combined size of both the data fork and the resource
|
||||
* fork (if present) rather than just the size of the data fork
|
||||
* as returned by GetFileSize()
|
||||
*
|
||||
*/
|
||||
readonly attribute int64_t fileSizeWithResFork;
|
||||
|
||||
/**
|
||||
* fileType, creator
|
||||
*
|
||||
* File type and creator attributes
|
||||
*
|
||||
*/
|
||||
[noscript] attribute OSType fileType;
|
||||
[noscript] attribute OSType fileCreator;
|
||||
|
||||
/**
|
||||
* launchWithDoc
|
||||
*
|
||||
* Launch the application that this file points to with a document.
|
||||
*
|
||||
* @param aDocToLoad Must not be NULL. If no document, use nsIFile::launch
|
||||
* @param aLaunchInBackground TRUE if the application should not come to the front.
|
||||
*
|
||||
*/
|
||||
void launchWithDoc(in nsIFile aDocToLoad, in boolean aLaunchInBackground);
|
||||
|
||||
/**
|
||||
* openDocWithApp
|
||||
*
|
||||
* Open the document that this file points to with the given application.
|
||||
*
|
||||
* @param aAppToOpenWith The application with which to open the document.
|
||||
* If NULL, the creator code of the document is used
|
||||
* to determine the application.
|
||||
* @param aLaunchInBackground TRUE if the application should not come to the front.
|
||||
*
|
||||
*/
|
||||
void openDocWithApp(in nsIFile aAppToOpenWith, in boolean aLaunchInBackground);
|
||||
|
||||
/**
|
||||
* isPackage
|
||||
*
|
||||
* returns true if a directory is determined to be a package under Mac OS 9/X
|
||||
*
|
||||
*/
|
||||
boolean isPackage();
|
||||
|
||||
/**
|
||||
* bundleDisplayName
|
||||
*
|
||||
* returns the display name of the application bundle (usually the human
|
||||
* readable name of the application)
|
||||
*/
|
||||
readonly attribute AString bundleDisplayName;
|
||||
|
||||
/**
|
||||
* bundleIdentifier
|
||||
*
|
||||
* returns the identifier of the bundle
|
||||
*/
|
||||
readonly attribute AUTF8String bundleIdentifier;
|
||||
|
||||
/**
|
||||
* Last modified time of a bundle's contents (as opposed to its package
|
||||
* directory). Our convention is to make the bundle's Info.plist file
|
||||
* stand in for the rest of its contents -- since this file contains the
|
||||
* bundle's version information and other identifiers. For non-bundles
|
||||
* this is the same as lastModifiedTime.
|
||||
*/
|
||||
readonly attribute int64_t bundleContentsLastModifiedTime;
|
||||
};
|
||||
|
||||
%{C++
|
||||
extern "C"
|
||||
{
|
||||
NS_EXPORT nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, bool aFollowSymlinks, nsILocalFileMac** result);
|
||||
NS_EXPORT nsresult NS_NewLocalFileWithCFURL(const CFURLRef aURL, bool aFollowSymlinks, nsILocalFileMac** result);
|
||||
}
|
||||
%}
|
||||
@@ -5,44 +5,10 @@
|
||||
|
||||
#include "xpcom-private.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// XP_MACOSX
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(XP_MACOSX)
|
||||
|
||||
#include "nsAString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsString.h"
|
||||
|
||||
nsresult
|
||||
NS_CopyNativeToUnicode(const nsACString& aInput, nsAString& aOutput)
|
||||
{
|
||||
CopyUTF8toUTF16(aInput, aOutput);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_CopyUnicodeToNative(const nsAString& aInput, nsACString& aOutput)
|
||||
{
|
||||
CopyUTF16toUTF8(aInput, aOutput);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NS_StartupNativeCharsetUtils()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NS_ShutdownNativeCharsetUtils()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// XP_UNIX
|
||||
//-----------------------------------------------------------------------------
|
||||
#elif defined(XP_UNIX)
|
||||
#if defined(XP_UNIX)
|
||||
|
||||
#include <stdlib.h> // mbtowc, wctomb
|
||||
#include <locale.h> // setlocale
|
||||
|
||||
@@ -33,22 +33,17 @@ nsresult NS_CopyUnicodeToNative(const nsAString& aInput, nsACString& aOutput);
|
||||
* name in UTF-8 out of nsIFile, we can just use |GetNativeLeafName| rather
|
||||
* than using |GetLeafName| and converting the result to UTF-8 if the file
|
||||
* system encoding is UTF-8.
|
||||
* On Unix (but not on Mac OS X), it depends on the locale and is not known
|
||||
* in advance (at the compilation time) so that this function needs to be
|
||||
* a real function. On Mac OS X it's always UTF-8 while on Windows
|
||||
* and other platforms (e.g. OS2), it's never UTF-8.
|
||||
* On Unix, it depends on the locale and is not known in advance (at the
|
||||
* compilation time) so that this function needs to be a real function.
|
||||
* On Windows and other platforms (e.g. OS2), it's never UTF-8.
|
||||
*/
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
||||
#if defined(XP_UNIX)
|
||||
bool NS_IsNativeUTF8();
|
||||
#else
|
||||
inline bool
|
||||
NS_IsNativeUTF8()
|
||||
{
|
||||
#if defined(XP_MACOSX)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -53,9 +53,7 @@ __asm__ (
|
||||
is what xptcstubs uses. */
|
||||
".align 2\n\t"
|
||||
".globl " SYMBOL_UNDERSCORE "NS_InvokeByIndex\n\t"
|
||||
#ifndef XP_MACOSX
|
||||
".type " SYMBOL_UNDERSCORE "NS_InvokeByIndex,@function\n"
|
||||
#endif
|
||||
SYMBOL_UNDERSCORE "NS_InvokeByIndex:\n\t"
|
||||
"pushl %ebp\n\t"
|
||||
"movl %esp, %ebp\n\t"
|
||||
@@ -91,7 +89,5 @@ __asm__ (
|
||||
"movl %ebp, %esp\n\t"
|
||||
"popl %ebp\n\t"
|
||||
"ret\n"
|
||||
#ifndef XP_MACOSX
|
||||
".size " SYMBOL_UNDERSCORE "NS_InvokeByIndex, . -" SYMBOL_UNDERSCORE "NS_InvokeByIndex\n\t"
|
||||
#endif
|
||||
);
|
||||
|
||||
@@ -66,20 +66,11 @@ PrepareAndDispatch(uint32_t methodIndex, nsXPTCStubBase* self, uint32_t* args)
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
#if !defined(XP_MACOSX)
|
||||
|
||||
#define STUB_HEADER(a, b) ".hidden " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev\n\t" \
|
||||
".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev,@function\n"
|
||||
|
||||
#define STUB_SIZE(a, b) ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev\n\t"
|
||||
|
||||
#else
|
||||
|
||||
#define STUB_HEADER(a, b)
|
||||
#define STUB_SIZE(a, b)
|
||||
|
||||
#endif
|
||||
|
||||
// gcc3 mangling tends to insert the length of the method name
|
||||
#define STUB_ENTRY(n) \
|
||||
asm(".text\n\t" \
|
||||
@@ -112,16 +103,12 @@ asm(".text\n\t" \
|
||||
// static nsresult SharedStub(uint32_t methodIndex) __attribute__((regparm(1)))
|
||||
asm(".text\n\t"
|
||||
".align 2\n\t"
|
||||
#if !defined(XP_MACOSX)
|
||||
".type " SYMBOL_UNDERSCORE "SharedStub,@function\n\t"
|
||||
#endif
|
||||
SYMBOL_UNDERSCORE "SharedStub:\n\t"
|
||||
"leal 0x08(%esp), %ecx\n\t"
|
||||
"movl 0x04(%esp), %edx\n\t"
|
||||
"jmp " SYMBOL_UNDERSCORE "PrepareAndDispatch\n\t"
|
||||
#if !defined(XP_MACOSX)
|
||||
".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub"
|
||||
#endif
|
||||
);
|
||||
|
||||
#define SENTINEL_ENTRY(n) \
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
// Use the system default in ASAN builds, because the default is assumed to be
|
||||
// larger than the size we want to use and is hopefully sufficient for ASAN.
|
||||
static const uint32_t kStackSize = nsIThreadManager::DEFAULT_STACK_SIZE;
|
||||
#elif defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)
|
||||
#elif defined(XP_WIN) || defined(LINUX)
|
||||
static const uint32_t kStackSize = (256 * 1024);
|
||||
#else
|
||||
// All other platforms use their system defaults.
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
# pragma GCC diagnostic pop // -Wshadow
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX)
|
||||
#if defined(XP_LINUX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
@@ -97,8 +97,6 @@ ThreadStackHelper::ThreadStackHelper()
|
||||
THREAD_SUSPEND_RESUME
|
||||
, FALSE, 0);
|
||||
MOZ_ASSERT(mInitialized);
|
||||
#elif defined(XP_MACOSX)
|
||||
mThreadID = mach_thread_self();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -176,26 +174,6 @@ ThreadStackHelper::GetStack(Stack& aStack)
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(::ResumeThread(mThreadID) != DWORD(-1));
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
# if defined(MOZ_VALGRIND) && defined(RUNNING_ON_VALGRIND)
|
||||
if (RUNNING_ON_VALGRIND) {
|
||||
/* thread_suspend and thread_resume sometimes hang runs on Valgrind,
|
||||
for unknown reasons. So, just avoid them. See bug 1100911. */
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
|
||||
MOZ_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
FillStackBuffer();
|
||||
FillThreadContext();
|
||||
|
||||
MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#include <sys/types.h>
|
||||
#elif defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(XP_MACOSX)
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
@@ -94,10 +92,6 @@ private:
|
||||
bool mInitialized;
|
||||
HANDLE mThreadID;
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
private:
|
||||
thread_act_t mThreadID;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsString.h"
|
||||
#ifndef XP_MACOSX
|
||||
#include "prproces.h"
|
||||
#endif
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
@@ -73,7 +71,7 @@ private:
|
||||
int32_t mExitValue;
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
HANDLE mProcess;
|
||||
#elif !defined(XP_MACOSX)
|
||||
#else
|
||||
PRProcess* mProcess;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -33,31 +33,12 @@
|
||||
#include "nsLiteralString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#else
|
||||
#ifdef XP_MACOSX
|
||||
#include <crt_externs.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/errno.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
cpu_type_t pref_cpu_types[2] = {
|
||||
#if defined(__i386__)
|
||||
CPU_TYPE_X86,
|
||||
#elif defined(__x86_64__)
|
||||
CPU_TYPE_X86_64,
|
||||
#elif defined(__ppc__)
|
||||
CPU_TYPE_POWERPC,
|
||||
#endif
|
||||
CPU_TYPE_ANY
|
||||
};
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------//
|
||||
// nsIProcess implementation
|
||||
//-------------------------------------------------------------------//
|
||||
@@ -74,9 +55,7 @@ nsProcess::nsProcess()
|
||||
, mObserver(nullptr)
|
||||
, mWeakObserver(nullptr)
|
||||
, mExitValue(-1)
|
||||
#if !defined(XP_MACOSX)
|
||||
, mProcess(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@@ -261,34 +240,16 @@ nsProcess::Monitor(void* aArg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef XP_MACOSX
|
||||
int exitCode = -1;
|
||||
int status = 0;
|
||||
pid_t result;
|
||||
do {
|
||||
result = waitpid(process->mPid, &status, 0);
|
||||
} while (result == -1 && errno == EINTR);
|
||||
if (result == process->mPid) {
|
||||
if (WIFEXITED(status)) {
|
||||
exitCode = WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
exitCode = 256; // match NSPR's signal exit status
|
||||
}
|
||||
}
|
||||
#else
|
||||
int32_t exitCode = -1;
|
||||
if (PR_WaitProcess(process->mProcess, &exitCode) != PR_SUCCESS) {
|
||||
exitCode = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Lock in case Kill or GetExitCode are called during this
|
||||
{
|
||||
MutexAutoLock lock(process->mLock);
|
||||
#if !defined(XP_MACOSX)
|
||||
process->mProcess = nullptr;
|
||||
#endif
|
||||
process->mExitValue = exitCode;
|
||||
if (process->mShutdown) {
|
||||
return;
|
||||
@@ -499,34 +460,6 @@ nsProcess::RunProcess(bool aBlocking, char** aMyArgv, nsIObserver* aObserver,
|
||||
}
|
||||
|
||||
mPid = GetProcessId(mProcess);
|
||||
#elif defined(XP_MACOSX)
|
||||
// Initialize spawn attributes.
|
||||
posix_spawnattr_t spawnattr;
|
||||
if (posix_spawnattr_init(&spawnattr) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Set spawn attributes.
|
||||
size_t attr_count = ArrayLength(pref_cpu_types);
|
||||
size_t attr_ocount = 0;
|
||||
if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types,
|
||||
&attr_ocount) != 0 ||
|
||||
attr_ocount != attr_count) {
|
||||
posix_spawnattr_destroy(&spawnattr);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Note: |aMyArgv| is already null-terminated as required by posix_spawnp.
|
||||
pid_t newPid = 0;
|
||||
int result = posix_spawnp(&newPid, aMyArgv[0], nullptr, &spawnattr, aMyArgv,
|
||||
*_NSGetEnviron());
|
||||
mPid = static_cast<int32_t>(newPid);
|
||||
|
||||
posix_spawnattr_destroy(&spawnattr);
|
||||
|
||||
if (result != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#else
|
||||
mProcess = PR_CreateProcess(aMyArgv[0], aMyArgv, nullptr, nullptr);
|
||||
if (!mProcess) {
|
||||
@@ -605,10 +538,6 @@ nsProcess::Kill()
|
||||
if (TerminateProcess(mProcess, 0) == 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#elif defined(XP_MACOSX)
|
||||
if (kill(mPid, SIGKILL) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#else
|
||||
if (!mProcess || (PR_KillProcess(mProcess) != PR_SUCCESS)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -52,11 +52,6 @@
|
||||
#define HAVE_SCHED_SETAFFINITY
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <mach/mach.h>
|
||||
#include <mach/thread_policy.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CANARY
|
||||
# include <unistd.h>
|
||||
# include <execinfo.h>
|
||||
@@ -375,16 +370,6 @@ SetThreadAffinity(unsigned int cpu)
|
||||
sched_setaffinity(0, sizeof(cpus), &cpus);
|
||||
// Don't assert sched_setaffinity's return value because it intermittently (?)
|
||||
// fails with EINVAL on Linux x64 try runs.
|
||||
#elif defined(XP_MACOSX)
|
||||
// OS X does not provide APIs to pin threads to specific processors, but you
|
||||
// can tag threads as belonging to the same "affinity set" and the OS will try
|
||||
// to run them on the same processor. To run threads on different processors,
|
||||
// tag them as belonging to different affinity sets. Tag 0, the default, means
|
||||
// "no affinity" so let's pretend each CPU has its own tag `cpu+1`.
|
||||
thread_affinity_policy_data_t policy;
|
||||
policy.affinity_tag = cpu + 1;
|
||||
MOZ_ALWAYS_TRUE(thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY,
|
||||
&policy.affinity_tag, 1) == KERN_SUCCESS);
|
||||
#elif defined(XP_WIN)
|
||||
MOZ_ALWAYS_TRUE(SetThreadIdealProcessor(GetCurrentThread(), cpu) != -1);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user