[vm] Add NOTIFY_DEBUGGER_ABOUT_RX_PAGES hook
Estimated: adds ~500ms of latency per code space page allocation. TEST=manually Change-Id: I31bc1927fd9a775c312974a1c435d29c875d01eb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/412281 Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Slava Egorov <vegorov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
d8c48032bb
commit
939699a9cf
@@ -94,9 +94,11 @@ MappedMemory* File::Map(MapType type,
|
||||
// Try to allocate near the VM's binary.
|
||||
hint = reinterpret_cast<void*>(&Dart_Initialize);
|
||||
prot = PROT_READ | PROT_EXEC;
|
||||
if (IsAtLeastOS10_14()) {
|
||||
#if !defined(DART_HOST_OS_IOS)
|
||||
if (IsAtLeastMacOSX10_14()) {
|
||||
map_flags |= (MAP_JIT | MAP_ANONYMOUS);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case kReadWrite:
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
@@ -107,10 +109,15 @@ MappedMemory* File::Map(MapType type,
|
||||
map_flags |= MAP_FIXED;
|
||||
}
|
||||
void* addr = start;
|
||||
if ((type == kReadExecute) && IsAtLeastOS10_14()) {
|
||||
// Due to codesigning restrictions, we cannot map the file as executable
|
||||
// directly. We must first copy it into an anonymous mapping and then mark
|
||||
// the mapping as executable.
|
||||
#if !defined(DART_HOST_OS_IOS)
|
||||
// Due to codesigning restrictions, we cannot map the file as executable
|
||||
// directly. We must first copy it into an anonymous mapping and then mark
|
||||
// the mapping as executable.
|
||||
const bool should_copy = (type == kReadExecute) && IsAtLeastMacOSX10_14();
|
||||
#else
|
||||
const bool should_copy = false;
|
||||
#endif
|
||||
if (should_copy) {
|
||||
if (addr == nullptr) {
|
||||
addr = mmap(hint, length, (PROT_READ | PROT_WRITE), map_flags, -1, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
|
||||
@@ -45,7 +45,7 @@ VirtualMemory* VirtualMemory::Allocate(intptr_t size,
|
||||
|
||||
int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
#if (defined(DART_HOST_OS_MACOS) && !defined(DART_HOST_OS_IOS))
|
||||
if (is_executable && IsAtLeastOS10_14()) {
|
||||
if (is_executable && IsAtLeastMacOSX10_14()) {
|
||||
map_flags |= MAP_JIT;
|
||||
}
|
||||
#endif // defined(DART_HOST_OS_MACOS)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "platform/utils.h"
|
||||
#include "platform/utils_macos.h"
|
||||
|
||||
#include <errno.h> // NOLINT
|
||||
#include <sys/utsname.h> // NOLINT
|
||||
|
||||
namespace dart {
|
||||
@@ -81,10 +80,10 @@ int Utils::Unlink(const char* path) {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Returns the running system's Darwin major version. Don't call this, it's
|
||||
// an implementation detail and its result is meant to be cached by
|
||||
// MacOSXMinorVersion.
|
||||
int32_t DarwinMajorVersionInternal() {
|
||||
namespace {
|
||||
// Extracts the version of the running kernel from utsname.release.
|
||||
bool GetDarwinKernelVersionFromUname(int32_t* kernel_major_version,
|
||||
int32_t* kernel_minor_version) {
|
||||
// uname is implemented as a simple series of sysctl system calls to
|
||||
// obtain the relevant data from the kernel. The data is
|
||||
// compiled right into the kernel, so no threads or blocking or other
|
||||
@@ -92,80 +91,103 @@ int32_t DarwinMajorVersionInternal() {
|
||||
|
||||
struct utsname uname_info;
|
||||
if (uname(&uname_info) != 0) {
|
||||
FATAL("Fatal error in DarwinMajorVersionInternal : invalid return uname");
|
||||
return 0;
|
||||
FATAL("GetDarwinKernelVersionFromUname: uname failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(uname_info.sysname, "Darwin") != 0) {
|
||||
FATAL(
|
||||
"Fatal error in DarwinMajorVersionInternal : unexpected uname"
|
||||
"GetDarwinKernelVersionFromUname: unexpected uname"
|
||||
" sysname '%s'",
|
||||
uname_info.sysname);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t darwin_major_version = 0;
|
||||
*kernel_major_version = 0;
|
||||
*kernel_minor_version = 0;
|
||||
char* dot = strchr(uname_info.release, '.');
|
||||
if (dot) {
|
||||
errno = 0;
|
||||
if (dot != nullptr && dot != uname_info.release) {
|
||||
char* end_ptr = nullptr;
|
||||
darwin_major_version = strtol(uname_info.release, &end_ptr, 10);
|
||||
if (errno != 0 || (end_ptr == uname_info.release)) {
|
||||
dot = nullptr;
|
||||
*kernel_major_version = strtol(uname_info.release, &end_ptr, 10);
|
||||
if (end_ptr == dot) { // Expected to parse until `.`
|
||||
char* minor_start = dot + 1;
|
||||
*kernel_minor_version = strtol(minor_start, &end_ptr, 10);
|
||||
if (end_ptr != minor_start) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dot) {
|
||||
FATAL(
|
||||
"Fatal error in DarwinMajorVersionInternal :"
|
||||
" could not parse uname release '%s'",
|
||||
uname_info.release);
|
||||
FATAL(
|
||||
"GetDarwinKernelVersionFromUname: "
|
||||
" could not parse uname release '%s'",
|
||||
uname_info.release);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Returns the running system's Mac OS X or iOS version which matches the
|
||||
// encoding of *_X_VERSION_* defines in AvailabilityVersions.h
|
||||
int32_t DarwinVersionInternal() {
|
||||
int32_t kernel_major_version;
|
||||
int32_t kernel_minor_version;
|
||||
if (!GetDarwinKernelVersionFromUname(&kernel_major_version,
|
||||
&kernel_minor_version)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return darwin_major_version;
|
||||
}
|
||||
int32_t major_version = 0;
|
||||
int32_t minor_version = 0;
|
||||
|
||||
// Returns the running system's Mac OS X version which matches the encoding
|
||||
// of MAC_OS_X_VERSION_* defines in AvailabilityMacros.h
|
||||
int32_t MacOSXVersionInternal() {
|
||||
const int32_t darwin_major_version = DarwinMajorVersionInternal();
|
||||
|
||||
int32_t major_version;
|
||||
int32_t minor_version;
|
||||
|
||||
if (darwin_major_version < 20) {
|
||||
#if defined(DART_HOST_OS_IOS)
|
||||
// We do not expect to run on version of iOS <12.0 so we can assume that
|
||||
// kernel version is off by 6 from iOS version (e.g. kernel 18.0 is iOS 12.0).
|
||||
// This only holds starting from iOS 4.0.
|
||||
major_version = kernel_major_version - 6;
|
||||
if (major_version >= 15) {
|
||||
// After iOS 15 minor version of kernel is the same as minor version of
|
||||
// the iOS release. Before iOS 15 these numbers were not in sync. However
|
||||
// We do not expect to check minor version numbers for older iOS
|
||||
// releases so we just keep it at 0 for them.
|
||||
minor_version = kernel_minor_version;
|
||||
}
|
||||
const int32_t field_multiplier = 100;
|
||||
#else
|
||||
if (kernel_major_version < 20) {
|
||||
// For Mac OS X 10.* minor version is off by 4 from Darwin's major
|
||||
// version, e.g. 5.* is v10.1.*, 6.* is v10.2.* and so on.
|
||||
// Pretend that anything below Darwin v5 is just Mac OS X Cheetah (v10.0).
|
||||
major_version = 10;
|
||||
minor_version = Utils::Maximum(0, darwin_major_version - 4);
|
||||
minor_version = Utils::Maximum(0, kernel_major_version - 4);
|
||||
} else {
|
||||
// Starting from Darwin v20 major version increment in lock-step:
|
||||
// Darwin v20 - Mac OS X v11, Darwin v21 - Mac OS X v12, etc
|
||||
major_version = (darwin_major_version - 9);
|
||||
major_version = (kernel_major_version - 9);
|
||||
minor_version = 0;
|
||||
}
|
||||
|
||||
// Caveat: MAC_OS_X_VERSION_* is encoded using decimal encoding.
|
||||
// Starting at MAC_OS_X_VERSION_10_10 versions use 2 decimal digits for
|
||||
// minor version and patch number.
|
||||
const int32_t field_multiplier = (darwin_major_version < 14) ? 10 : 100;
|
||||
const int32_t field_multiplier = (kernel_major_version < 14) ? 10 : 100;
|
||||
#endif
|
||||
const int32_t major_multiplier = field_multiplier * field_multiplier;
|
||||
const int32_t minor_multiplier = field_multiplier;
|
||||
|
||||
return major_version * major_multiplier + minor_version * minor_multiplier;
|
||||
}
|
||||
|
||||
int32_t MacOSXVersion() {
|
||||
static int mac_os_x_version = MacOSXVersionInternal();
|
||||
return mac_os_x_version;
|
||||
int32_t DarwinVersion() {
|
||||
static int version = DarwinVersionInternal();
|
||||
return version;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#if !defined(DART_HOST_OS_IOS)
|
||||
namespace {
|
||||
int32_t MacOSMinorVersion(int32_t version) {
|
||||
int32_t MacOSXMinorVersion(int32_t version) {
|
||||
// Caveat: MAC_OS_X_VERSION_* is encoded using decimal encoding.
|
||||
// Starting at MAC_OS_X_VERSION_10_10 versions use 2 decimal digits for
|
||||
// minor version and patch number.
|
||||
@@ -174,7 +196,7 @@ int32_t MacOSMinorVersion(int32_t version) {
|
||||
return (version / field_multiplier) % field_multiplier;
|
||||
}
|
||||
|
||||
int32_t MacOSMajorVersion(int32_t version) {
|
||||
int32_t MacOSXMajorVersion(int32_t version) {
|
||||
// Caveat: MAC_OS_X_VERSION_* is encoded using decimal encoding.
|
||||
// Starting at MAC_OS_X_VERSION_10_10 versions use 2 decimal digits for
|
||||
// minor version and patch number.
|
||||
@@ -184,8 +206,8 @@ int32_t MacOSMajorVersion(int32_t version) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
char* CheckIsAtLeastMinRequiredMacOSVersion() {
|
||||
const int32_t current_version = internal::MacOSXVersion();
|
||||
char* CheckIsAtLeastMinRequiredMacOSXVersion() {
|
||||
const int32_t current_version = internal::DarwinVersion();
|
||||
|
||||
if (current_version >= MAC_OS_X_VERSION_MIN_REQUIRED) {
|
||||
return nullptr;
|
||||
@@ -194,10 +216,11 @@ char* CheckIsAtLeastMinRequiredMacOSVersion() {
|
||||
return Utils::SCreate(
|
||||
"Current Mac OS X version %d.%d is lower than minimum supported version "
|
||||
"%d.%d",
|
||||
MacOSMajorVersion(current_version), MacOSMinorVersion(current_version),
|
||||
MacOSMajorVersion(MAC_OS_X_VERSION_MIN_REQUIRED),
|
||||
MacOSMinorVersion(MAC_OS_X_VERSION_MIN_REQUIRED));
|
||||
MacOSXMajorVersion(current_version), MacOSXMinorVersion(current_version),
|
||||
MacOSXMajorVersion(MAC_OS_X_VERSION_MIN_REQUIRED),
|
||||
MacOSXMinorVersion(MAC_OS_X_VERSION_MIN_REQUIRED));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -17,16 +17,28 @@ namespace dart {
|
||||
namespace internal {
|
||||
|
||||
// Returns the running system's Mac OS X version which matches the encoding
|
||||
// of MAC_OS_X_VERSION_* defines in AvailabilityMacros.h
|
||||
int32_t MacOSXVersion();
|
||||
// of MAC_OS_X_VERSION_* defines in AvailabilityVersions.h
|
||||
int32_t DarwinVersion();
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#if defined(DART_HOST_OS_IOS)
|
||||
|
||||
// Run-time OS version checks.
|
||||
#define DEFINE_IS_OS_FUNCS(VERSION_NAME, VALUE) \
|
||||
inline bool IsAtLeastIOS##VERSION_NAME() { \
|
||||
return (internal::DarwinVersion() >= 180400); \
|
||||
}
|
||||
|
||||
DEFINE_IS_OS_FUNCS(18_4, 180400)
|
||||
|
||||
#else
|
||||
|
||||
// Run-time OS version checks.
|
||||
#define DEFINE_IS_OS_FUNCS(VERSION) \
|
||||
inline bool IsAtLeastOS##VERSION() { \
|
||||
inline bool IsAtLeastMacOSX##VERSION() { \
|
||||
return (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_##VERSION) || \
|
||||
(internal::MacOSXVersion() >= MAC_OS_X_VERSION_##VERSION); \
|
||||
(internal::DarwinVersion() >= MAC_OS_X_VERSION_##VERSION); \
|
||||
}
|
||||
|
||||
DEFINE_IS_OS_FUNCS(10_14)
|
||||
@@ -36,7 +48,9 @@ DEFINE_IS_OS_FUNCS(10_14)
|
||||
//
|
||||
// Otherwise returns a malloc allocated error string with human readable
|
||||
// current and expected versions.
|
||||
char* CheckIsAtLeastMinRequiredMacOSVersion();
|
||||
char* CheckIsAtLeastMinRequiredMacOSXVersion();
|
||||
|
||||
#endif // defined(DART_HOST_OS_IOS)
|
||||
|
||||
inline uint16_t Utils::HostToBigEndian16(uint16_t value) {
|
||||
return OSSwapHostToBigInt16(value);
|
||||
|
||||
+1
-1
@@ -267,7 +267,7 @@ char* Dart::DartInit(const Dart_InitializeParams* params) {
|
||||
#endif
|
||||
|
||||
#if defined(DART_HOST_OS_MACOS) && !defined(DART_HOST_OS_IOS)
|
||||
char* error = CheckIsAtLeastMinRequiredMacOSVersion();
|
||||
char* error = CheckIsAtLeastMinRequiredMacOSXVersion();
|
||||
if (error != nullptr) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
// Forward declarations.
|
||||
struct tm;
|
||||
|
||||
namespace dart {
|
||||
|
||||
// Forward declarations.
|
||||
|
||||
@@ -119,6 +119,10 @@ class VirtualMemory {
|
||||
static uword page_size_;
|
||||
static VirtualMemory* compressed_heap_;
|
||||
|
||||
#if defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
static bool notify_debugger_about_rx_pages_;
|
||||
#endif
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(VirtualMemory);
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,9 @@ DECLARE_FLAG(bool, generate_perf_jitdump);
|
||||
|
||||
uword VirtualMemory::page_size_ = 0;
|
||||
VirtualMemory* VirtualMemory::compressed_heap_ = nullptr;
|
||||
#if defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
bool VirtualMemory::notify_debugger_about_rx_pages_ = false;
|
||||
#endif
|
||||
|
||||
static void* Map(void* addr,
|
||||
size_t length,
|
||||
@@ -137,6 +140,125 @@ static MemoryRegion ClipToAlignedRegion(MemoryRegion region, size_t alignment) {
|
||||
}
|
||||
#endif // LARGE_RESERVATIONS_MAY_FAIL
|
||||
|
||||
#if defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// The function NOTIFY_DEBUGGER_ABOUT_RX_PAGES is a hook point for the debugger.
|
||||
//
|
||||
// We expect that LLBD is configured to intercept calls to this function and
|
||||
// takes care of writing into all pages covered by [base, base+size) address
|
||||
// range.
|
||||
//
|
||||
// For example, you can define the following Python helper script:
|
||||
//
|
||||
// ```python
|
||||
// # rx_helper.py
|
||||
// import lldb
|
||||
//
|
||||
// def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
|
||||
// """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
|
||||
// base = frame.register["x0"].GetValueAsAddress()
|
||||
// page_len = frame.register["x1"].GetValueAsUnsigned()
|
||||
|
||||
// # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
|
||||
// # first page to see if handled it correctly. This makes diagnosing
|
||||
// # misconfiguration (e.g. missing breakpoint) easier.
|
||||
// data = bytearray(page_len)
|
||||
// data[0:8] = b'IHELPED!';
|
||||
|
||||
// error = lldb.SBError()
|
||||
// frame.GetThread().GetProcess().WriteMemory(base, data, error)
|
||||
// if not error.Success():
|
||||
// print(f'Failed to write into {base}[+{page_len}]', error)
|
||||
// return
|
||||
//
|
||||
// def __lldb_init_module(debugger: lldb.SBDebugger, _):
|
||||
// target = debugger.GetDummyTarget()
|
||||
// # Caveat: must use BreakpointCreateByRegEx here and not
|
||||
// # BreakpointCreateByName. For some reasons callback function does not
|
||||
// # get carried over from dummy target for the later.
|
||||
// bp = target.bpCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
|
||||
// bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
|
||||
// bp.SetAutoContinue(True)
|
||||
// print("-- LLDB integration loaded --")
|
||||
// ```
|
||||
//
|
||||
// Which is then imported into LLDB via `.lldbinit` script:
|
||||
//
|
||||
// ```
|
||||
// # .lldbinit
|
||||
// command script import --relative-to-command-file rx_helper.py
|
||||
// ```
|
||||
//
|
||||
// XCode allows configuring custom LLDB Init Files: see Product -> Scheme ->
|
||||
// Run -> Info -> LLDB Init File, you can use `$(SRCROOT)/...` to place LLDB
|
||||
// script inside project directory itself.
|
||||
//
|
||||
__attribute__((noinline)) __attribute__((visibility("default"))) extern "C" void
|
||||
NOTIFY_DEBUGGER_ABOUT_RX_PAGES(void* base, size_t size) {
|
||||
// Note: need this to prevent LLVM from optimizing it away even with
|
||||
// noinline.
|
||||
asm volatile("" ::"r"(base), "r"(size) : "memory");
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool CheckIfNeedDebuggerHelpWithRX() {
|
||||
// Do not expect any problems before iOS 18.4.
|
||||
if (!IsAtLeastIOS18_4()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FLAG_write_protect_code) {
|
||||
FATAL("Must run with --write-protect-code on this OS");
|
||||
}
|
||||
|
||||
// Helper to check if RX->RW->RX->RW->RX flip works, with and without
|
||||
// debugger assistance.
|
||||
const auto does_rx_rw_rx_flip_work = [](bool notify_debugger) {
|
||||
const intptr_t size = VirtualMemory::PageSize();
|
||||
void* page = Map(NULL, size, PROT_READ | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (page == MAP_FAILED) {
|
||||
FATAL("Failed to map a test RX page (ENOMEM)");
|
||||
}
|
||||
|
||||
if (notify_debugger) {
|
||||
NOTIFY_DEBUGGER_ABOUT_RX_PAGES(page, size);
|
||||
if (strncmp(reinterpret_cast<const char*>(page), "IHELPED!", 8) != 0) {
|
||||
FATAL("NOTIFY_DEBUGGER_ABOUT_RX_PAGES was not intercepted as expected");
|
||||
}
|
||||
}
|
||||
|
||||
bool failed_to_return_to_rx = false;
|
||||
// Need to try twice: the first RW->RX flip might work, some lazy checking
|
||||
// is involved.
|
||||
for (intptr_t i = 0; i < 2; i++) {
|
||||
// Do not expect this one to fail.
|
||||
VirtualMemory::Protect(page, size, VirtualMemory::kReadWrite);
|
||||
reinterpret_cast<int64_t*>(page)[i] = kBreakInstructionFiller;
|
||||
// This one might fail so we call mprotect directly and check if
|
||||
// it failed.
|
||||
if (mprotect(page, size, PROT_READ | PROT_EXEC) != 0) {
|
||||
failed_to_return_to_rx = true;
|
||||
}
|
||||
}
|
||||
munmap(page, size);
|
||||
return !failed_to_return_to_rx;
|
||||
};
|
||||
|
||||
// First try without debugger assistance.
|
||||
if (does_rx_rw_rx_flip_work(/*notify_debugger=*/false)) {
|
||||
return false; // All works.
|
||||
}
|
||||
|
||||
// RX->RW->RX->RW->RX does not seem to work. Try asking debugger for help.
|
||||
if (!does_rx_rw_rx_flip_work(/*notify_debugger=*/true)) {
|
||||
FATAL("Unable to flip between RX and RW memory protection on pages");
|
||||
}
|
||||
|
||||
return true; // Debugger can help us.
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
void VirtualMemory::Init() {
|
||||
if (FLAG_old_gen_heap_size < 0 || FLAG_old_gen_heap_size > kMaxAddrSpaceMB) {
|
||||
OS::PrintErr(
|
||||
@@ -154,6 +276,10 @@ void VirtualMemory::Init() {
|
||||
FLAG_new_gen_semi_max_size = kDefaultNewGenSemiMaxSize;
|
||||
}
|
||||
page_size_ = CalculatePageSize();
|
||||
#if defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
notify_debugger_about_rx_pages_ = CheckIfNeedDebuggerHelpWithRX();
|
||||
#endif
|
||||
|
||||
#if defined(DART_COMPRESSED_POINTERS)
|
||||
ASSERT(compressed_heap_ == nullptr);
|
||||
#if defined(LARGE_RESERVATIONS_MAY_FAIL)
|
||||
@@ -187,7 +313,6 @@ void VirtualMemory::Init() {
|
||||
VirtualMemoryCompressedHeap::Init(compressed_heap_->address(),
|
||||
compressed_heap_->size());
|
||||
#endif // defined(DART_COMPRESSED_POINTERS)
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
FILE* fp = fopen("/proc/sys/vm/max_map_count", "r");
|
||||
if (fp != nullptr) {
|
||||
@@ -265,13 +390,20 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
|
||||
#endif // defined(DART_COMPRESSED_POINTERS)
|
||||
|
||||
const intptr_t allocated_size = size + alignment - PageSize();
|
||||
|
||||
#if defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
const int prot = (is_executable && notify_debugger_about_rx_pages_)
|
||||
? PROT_READ | PROT_EXEC
|
||||
: PROT_READ | PROT_WRITE;
|
||||
#else
|
||||
const int prot =
|
||||
PROT_READ | PROT_WRITE |
|
||||
((is_executable && !FLAG_write_protect_code) ? PROT_EXEC : 0);
|
||||
#endif
|
||||
|
||||
int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
#if (defined(DART_HOST_OS_MACOS) && !defined(DART_HOST_OS_IOS))
|
||||
if (is_executable && IsAtLeastOS10_14()) {
|
||||
if (is_executable && IsAtLeastMacOSX10_14()) {
|
||||
map_flags |= MAP_JIT;
|
||||
}
|
||||
#endif // defined(DART_HOST_OS_MACOS)
|
||||
@@ -303,6 +435,15 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (is_executable && notify_debugger_about_rx_pages_) {
|
||||
NOTIFY_DEBUGGER_ABOUT_RX_PAGES(reinterpret_cast<void*>(address), size);
|
||||
// Once debugger is notified we can flip RX to RW without loosing
|
||||
// ability to flip back to RX.
|
||||
Protect(address, size, kReadWrite);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
|
||||
// PR_SET_VMA was only added to mainline Linux in 5.17, and some versions of
|
||||
// the Android NDK have incorrect headers, so we manually define it if absent.
|
||||
|
||||
Reference in New Issue
Block a user