mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 00:38:39 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
2c79eebb23
229 changed files with 212 additions and 23172 deletions
|
|
@ -10,13 +10,10 @@
|
|||
|
||||
#if defined(XP_WIN)
|
||||
# include "jswin.h"
|
||||
#elif defined(XP_UNIX) && !defined(XP_DARWIN)
|
||||
#elif defined(XP_UNIX)
|
||||
# include <signal.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#elif defined(XP_DARWIN)
|
||||
# include <mach/mach.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
|
|
@ -210,7 +207,7 @@ MemoryProtectionExceptionHandler::uninstall()
|
|||
}
|
||||
}
|
||||
|
||||
#elif defined(XP_UNIX) && !defined(XP_DARWIN)
|
||||
#elif defined(XP_UNIX)
|
||||
|
||||
static struct sigaction sPrevSEGVHandler = {};
|
||||
|
||||
|
|
@ -291,465 +288,6 @@ MemoryProtectionExceptionHandler::uninstall()
|
|||
}
|
||||
}
|
||||
|
||||
#elif defined(XP_DARWIN)
|
||||
|
||||
/*
|
||||
* The fact that we need to be able to forward to other exception handlers
|
||||
* makes this code much more complicated. The forwarding logic and the
|
||||
* structures required to make it work are heavily based on the code at
|
||||
* www.ravenbrook.com/project/mps/prototype/2013-06-24/machtest/machtest/main.c
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Begin Mach definitions and helper functions */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* These are the message IDs associated with each exception type.
|
||||
* We'll be using sIDRequest64, but we need the others for forwarding.
|
||||
*/
|
||||
static const mach_msg_id_t sIDRequest32 = 2401;
|
||||
static const mach_msg_id_t sIDRequestState32 = 2402;
|
||||
static const mach_msg_id_t sIDRequestStateIdentity32 = 2403;
|
||||
|
||||
static const mach_msg_id_t sIDRequest64 = 2405;
|
||||
static const mach_msg_id_t sIDRequestState64 = 2406;
|
||||
static const mach_msg_id_t sIDRequestStateIdentity64 = 2407;
|
||||
|
||||
/*
|
||||
* Each message ID has an associated Mach message structure.
|
||||
* We use the preprocessor to make defining them a little less arduous.
|
||||
*/
|
||||
# define REQUEST_HEADER_FIELDS\
|
||||
mach_msg_header_t header;
|
||||
|
||||
# define REQUEST_IDENTITY_FIELDS\
|
||||
mach_msg_body_t msgh_body;\
|
||||
mach_msg_port_descriptor_t thread;\
|
||||
mach_msg_port_descriptor_t task;
|
||||
|
||||
# define REQUEST_GENERAL_FIELDS(bits)\
|
||||
NDR_record_t NDR;\
|
||||
exception_type_t exception;\
|
||||
mach_msg_type_number_t code_count;\
|
||||
int##bits##_t code[2];
|
||||
|
||||
# define REQUEST_STATE_FIELDS\
|
||||
int flavor;\
|
||||
mach_msg_type_number_t old_state_count;\
|
||||
natural_t old_state[THREAD_STATE_MAX];
|
||||
|
||||
# define REQUEST_TRAILER_FIELDS\
|
||||
mach_msg_trailer_t trailer;
|
||||
|
||||
# define EXCEPTION_REQUEST(bits)\
|
||||
struct ExceptionRequest##bits\
|
||||
{\
|
||||
REQUEST_HEADER_FIELDS\
|
||||
REQUEST_IDENTITY_FIELDS\
|
||||
REQUEST_GENERAL_FIELDS(bits)\
|
||||
REQUEST_TRAILER_FIELDS\
|
||||
};\
|
||||
|
||||
# define EXCEPTION_REQUEST_STATE(bits)\
|
||||
struct ExceptionRequestState##bits\
|
||||
{\
|
||||
REQUEST_HEADER_FIELDS\
|
||||
REQUEST_GENERAL_FIELDS(bits)\
|
||||
REQUEST_STATE_FIELDS\
|
||||
REQUEST_TRAILER_FIELDS\
|
||||
};\
|
||||
|
||||
# define EXCEPTION_REQUEST_STATE_IDENTITY(bits)\
|
||||
struct ExceptionRequestStateIdentity##bits\
|
||||
{\
|
||||
REQUEST_HEADER_FIELDS\
|
||||
REQUEST_IDENTITY_FIELDS\
|
||||
REQUEST_GENERAL_FIELDS(bits)\
|
||||
REQUEST_STATE_FIELDS\
|
||||
REQUEST_TRAILER_FIELDS\
|
||||
};\
|
||||
|
||||
/* This is needed because not all fields are naturally aligned on 64-bit. */
|
||||
# ifdef __MigPackStructs
|
||||
# pragma pack(4)
|
||||
# endif
|
||||
|
||||
EXCEPTION_REQUEST(32)
|
||||
EXCEPTION_REQUEST(64)
|
||||
EXCEPTION_REQUEST_STATE(32)
|
||||
EXCEPTION_REQUEST_STATE(64)
|
||||
EXCEPTION_REQUEST_STATE_IDENTITY(32)
|
||||
EXCEPTION_REQUEST_STATE_IDENTITY(64)
|
||||
|
||||
/* We use this as a common base when forwarding to the previous handler. */
|
||||
union ExceptionRequestUnion {
|
||||
mach_msg_header_t header;
|
||||
ExceptionRequest32 r32;
|
||||
ExceptionRequest64 r64;
|
||||
ExceptionRequestState32 rs32;
|
||||
ExceptionRequestState64 rs64;
|
||||
ExceptionRequestStateIdentity32 rsi32;
|
||||
ExceptionRequestStateIdentity64 rsi64;
|
||||
};
|
||||
|
||||
/* This isn't really a full Mach message, but it's all we need to send. */
|
||||
struct ExceptionReply
|
||||
{
|
||||
mach_msg_header_t header;
|
||||
NDR_record_t NDR;
|
||||
kern_return_t RetCode;
|
||||
};
|
||||
|
||||
# ifdef __MigPackStructs
|
||||
# pragma pack()
|
||||
# endif
|
||||
|
||||
# undef EXCEPTION_REQUEST_STATE_IDENTITY
|
||||
# undef EXCEPTION_REQUEST_STATE
|
||||
# undef EXCEPTION_REQUEST
|
||||
# undef REQUEST_STATE_FIELDS
|
||||
# undef REQUEST_GENERAL_FIELDS
|
||||
# undef REQUEST_IDENTITY_FIELDS
|
||||
# undef REQUEST_HEADER_FIELDS
|
||||
|
||||
/*
|
||||
* The exception handler we're forwarding to may not have the same behavior
|
||||
* or thread state flavor as what we're using. These macros help populate
|
||||
* the fields of the message we're about to send to the previous handler.
|
||||
*/
|
||||
# define COPY_REQUEST_COMMON(bits, id)\
|
||||
dst.header = src.header;\
|
||||
dst.header.msgh_id = id;\
|
||||
dst.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(dst) - sizeof(dst.trailer));\
|
||||
dst.NDR = src.NDR;\
|
||||
dst.exception = src.exception;\
|
||||
dst.code_count = src.code_count;\
|
||||
dst.code[0] = int##bits##_t(src.code[0]);\
|
||||
dst.code[1] = int##bits##_t(src.code[1]);
|
||||
|
||||
# define COPY_REQUEST_IDENTITY\
|
||||
dst.msgh_body = src.msgh_body;\
|
||||
dst.thread = src.thread;\
|
||||
dst.task = src.task;
|
||||
|
||||
# define COPY_REQUEST_STATE(flavor, stateCount, state)\
|
||||
mach_msg_size_t stateSize = stateCount * sizeof(natural_t);\
|
||||
dst.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(dst) - sizeof(dst.trailer) -\
|
||||
sizeof(dst.old_state) + stateSize);\
|
||||
dst.flavor = flavor;\
|
||||
dst.old_state_count = stateCount;\
|
||||
memcpy(dst.old_state, state, stateSize);
|
||||
|
||||
# define COPY_EXCEPTION_REQUEST(bits)\
|
||||
static void\
|
||||
CopyExceptionRequest##bits(ExceptionRequest64& src,\
|
||||
ExceptionRequest##bits& dst)\
|
||||
{\
|
||||
COPY_REQUEST_COMMON(bits, sIDRequest##bits)\
|
||||
COPY_REQUEST_IDENTITY\
|
||||
}
|
||||
|
||||
# define COPY_EXCEPTION_REQUEST_STATE(bits)\
|
||||
static void\
|
||||
CopyExceptionRequestState##bits(ExceptionRequest64& src,\
|
||||
ExceptionRequestState##bits& dst,\
|
||||
thread_state_flavor_t flavor,\
|
||||
mach_msg_type_number_t stateCount,\
|
||||
thread_state_t state)\
|
||||
{\
|
||||
COPY_REQUEST_COMMON(bits, sIDRequestState##bits)\
|
||||
COPY_REQUEST_STATE(flavor, stateCount, state)\
|
||||
}
|
||||
|
||||
# define COPY_EXCEPTION_REQUEST_STATE_IDENTITY(bits)\
|
||||
static void\
|
||||
CopyExceptionRequestStateIdentity##bits(ExceptionRequest64& src,\
|
||||
ExceptionRequestStateIdentity##bits& dst,\
|
||||
thread_state_flavor_t flavor,\
|
||||
mach_msg_type_number_t stateCount,\
|
||||
thread_state_t state)\
|
||||
{\
|
||||
COPY_REQUEST_COMMON(bits, sIDRequestStateIdentity##bits)\
|
||||
COPY_REQUEST_IDENTITY\
|
||||
COPY_REQUEST_STATE(flavor, stateCount, state)\
|
||||
}
|
||||
|
||||
COPY_EXCEPTION_REQUEST(32)
|
||||
COPY_EXCEPTION_REQUEST_STATE(32)
|
||||
COPY_EXCEPTION_REQUEST_STATE_IDENTITY(32)
|
||||
COPY_EXCEPTION_REQUEST(64)
|
||||
COPY_EXCEPTION_REQUEST_STATE(64)
|
||||
COPY_EXCEPTION_REQUEST_STATE_IDENTITY(64)
|
||||
|
||||
# undef COPY_EXCEPTION_REQUEST_STATE_IDENTITY
|
||||
# undef COPY_EXCEPTION_REQUEST_STATE
|
||||
# undef COPY_EXCEPTION_REQUEST
|
||||
# undef COPY_REQUEST_STATE
|
||||
# undef COPY_REQUEST_IDENTITY
|
||||
# undef COPY_REQUEST_COMMON
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* End Mach definitions and helper functions */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Every Mach exception handler is parameterized by these four properties. */
|
||||
struct MachExceptionParameters
|
||||
{
|
||||
exception_mask_t mask;
|
||||
mach_port_t port;
|
||||
exception_behavior_t behavior;
|
||||
thread_state_flavor_t flavor;
|
||||
};
|
||||
|
||||
struct ExceptionHandlerState
|
||||
{
|
||||
MachExceptionParameters current;
|
||||
MachExceptionParameters previous;
|
||||
|
||||
/* Each Mach exception handler runs in its own thread. */
|
||||
Thread handlerThread;
|
||||
};
|
||||
|
||||
/* This choice of ID is arbitrary, but must not match our exception ID. */
|
||||
static const mach_msg_id_t sIDQuit = 42;
|
||||
|
||||
static ExceptionHandlerState sMachExceptionState;
|
||||
|
||||
/*
|
||||
* The meat of our exception handler. This thread waits for an exception
|
||||
* message, annotates the exception if needed, then forwards it to the
|
||||
* previously installed handler (which will likely terminate the process).
|
||||
*/
|
||||
static void
|
||||
MachExceptionHandler()
|
||||
{
|
||||
kern_return_t ret;
|
||||
MachExceptionParameters& current = sMachExceptionState.current;
|
||||
MachExceptionParameters& previous = sMachExceptionState.previous;
|
||||
|
||||
// We use the simplest kind of 64-bit exception message here.
|
||||
ExceptionRequest64 request = {};
|
||||
request.header.msgh_local_port = current.port;
|
||||
request.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(request));
|
||||
ret = mach_msg(&request.header, MACH_RCV_MSG, 0, request.header.msgh_size,
|
||||
current.port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
// Restore the previous handler. We're going to forward to it
|
||||
// anyway, and if we crash while doing so we don't want to hang.
|
||||
task_set_exception_ports(mach_task_self(), previous.mask, previous.port,
|
||||
previous.behavior, previous.flavor);
|
||||
|
||||
// If we failed even receiving the message, just give up.
|
||||
if (ret != MACH_MSG_SUCCESS)
|
||||
MOZ_CRASH("MachExceptionHandler: mach_msg failed to receive a message!");
|
||||
|
||||
// Terminate the thread if we're shutting down.
|
||||
if (request.header.msgh_id == sIDQuit)
|
||||
return;
|
||||
|
||||
// The only other valid message ID is the one associated with the
|
||||
// EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES behavior we chose.
|
||||
if (request.header.msgh_id != sIDRequest64)
|
||||
MOZ_CRASH("MachExceptionHandler: Unexpected Message ID!");
|
||||
|
||||
// Make sure we can understand the exception we received.
|
||||
if (request.exception != EXC_BAD_ACCESS || request.code_count != 2)
|
||||
MOZ_CRASH("MachExceptionHandler: Unexpected exception type!");
|
||||
|
||||
// Get the address that the offending code tried to access.
|
||||
uintptr_t address = uintptr_t(request.code[1]);
|
||||
|
||||
// If the faulting address is inside one of our protected regions, we
|
||||
// want to annotate the crash to make it stand out from the crowd.
|
||||
if (sProtectedRegions.isProtected(address)) {
|
||||
ReportCrashIfDebug("Hit MOZ_CRASH(Tried to access a protected region!)\n");
|
||||
MOZ_CRASH_ANNOTATE("MOZ_CRASH(Tried to access a protected region!)");
|
||||
}
|
||||
|
||||
// Forward to the previous handler which may be a debugger, the unix
|
||||
// signal handler, the crash reporter or something else entirely.
|
||||
if (previous.port != MACH_PORT_NULL) {
|
||||
mach_msg_type_number_t stateCount;
|
||||
thread_state_data_t state;
|
||||
if ((uint32_t(previous.behavior) & ~MACH_EXCEPTION_CODES) != EXCEPTION_DEFAULT) {
|
||||
// If the previous handler requested thread state, get it here.
|
||||
stateCount = THREAD_STATE_MAX;
|
||||
ret = thread_get_state(request.thread.name, previous.flavor, state, &stateCount);
|
||||
if (ret != KERN_SUCCESS)
|
||||
MOZ_CRASH("MachExceptionHandler: Could not get the thread state to forward!");
|
||||
}
|
||||
|
||||
// Depending on the behavior of the previous handler, the forwarded
|
||||
// exception message will have a different set of fields.
|
||||
// Of particular note is that exception handlers that lack
|
||||
// MACH_EXCEPTION_CODES will get 32-bit fields even on 64-bit
|
||||
// systems. It appears that OSX simply truncates these fields.
|
||||
ExceptionRequestUnion forward;
|
||||
switch (uint32_t(previous.behavior)) {
|
||||
case EXCEPTION_DEFAULT:
|
||||
CopyExceptionRequest32(request, forward.r32);
|
||||
break;
|
||||
case EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES:
|
||||
CopyExceptionRequest64(request, forward.r64);
|
||||
break;
|
||||
case EXCEPTION_STATE:
|
||||
CopyExceptionRequestState32(request, forward.rs32,
|
||||
previous.flavor, stateCount, state);
|
||||
break;
|
||||
case EXCEPTION_STATE | MACH_EXCEPTION_CODES:
|
||||
CopyExceptionRequestState64(request, forward.rs64,
|
||||
previous.flavor, stateCount, state);
|
||||
break;
|
||||
case EXCEPTION_STATE_IDENTITY:
|
||||
CopyExceptionRequestStateIdentity32(request, forward.rsi32,
|
||||
previous.flavor, stateCount, state);
|
||||
break;
|
||||
case EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES:
|
||||
CopyExceptionRequestStateIdentity64(request, forward.rsi64,
|
||||
previous.flavor, stateCount, state);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("MachExceptionHandler: Unknown previous handler behavior!");
|
||||
}
|
||||
|
||||
// Forward the generated message to the old port. The local and remote
|
||||
// port fields *and their rights* are swapped on arrival, so we need to
|
||||
// swap them back first.
|
||||
forward.header.msgh_bits = (request.header.msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
|
||||
MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(request.header.msgh_bits),
|
||||
MACH_MSGH_BITS_REMOTE(request.header.msgh_bits));
|
||||
forward.header.msgh_local_port = forward.header.msgh_remote_port;
|
||||
forward.header.msgh_remote_port = previous.port;
|
||||
ret = mach_msg(&forward.header, MACH_SEND_MSG, forward.header.msgh_size, 0,
|
||||
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
if (ret != MACH_MSG_SUCCESS)
|
||||
MOZ_CRASH("MachExceptionHandler: Failed to forward to the previous handler!");
|
||||
} else {
|
||||
// There was no previous task-level exception handler, so defer to the
|
||||
// host level one instead. We set the return code to KERN_FAILURE to
|
||||
// indicate that we did not handle the exception.
|
||||
// The reply message ID is always the request ID + 100.
|
||||
ExceptionReply reply = {};
|
||||
reply.header.msgh_bits =
|
||||
MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.header.msgh_bits), 0);
|
||||
reply.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(reply));
|
||||
reply.header.msgh_remote_port = request.header.msgh_remote_port;
|
||||
reply.header.msgh_local_port = MACH_PORT_NULL;
|
||||
reply.header.msgh_id = request.header.msgh_id + 100;
|
||||
reply.NDR = request.NDR;
|
||||
reply.RetCode = KERN_FAILURE;
|
||||
ret = mach_msg(&reply.header, MACH_SEND_MSG, reply.header.msgh_size, 0,
|
||||
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
if (ret != MACH_MSG_SUCCESS)
|
||||
MOZ_CRASH("MachExceptionHandler: Failed to forward to the host level!");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TerminateMachExceptionHandlerThread()
|
||||
{
|
||||
// Send a simple quit message to the exception handler thread.
|
||||
mach_msg_header_t msg;
|
||||
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
|
||||
msg.msgh_size = static_cast<mach_msg_size_t>(sizeof(msg));
|
||||
msg.msgh_remote_port = sMachExceptionState.current.port;
|
||||
msg.msgh_local_port = MACH_PORT_NULL;
|
||||
msg.msgh_reserved = 0;
|
||||
msg.msgh_id = sIDQuit;
|
||||
kern_return_t ret = mach_msg(&msg, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
if (ret == MACH_MSG_SUCCESS)
|
||||
sMachExceptionState.handlerThread.join();
|
||||
else
|
||||
MOZ_CRASH("MachExceptionHandler: Handler thread failed to terminate!");
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryProtectionExceptionHandler::install()
|
||||
{
|
||||
MOZ_ASSERT(!sExceptionHandlerInstalled);
|
||||
|
||||
// If the exception handler is disabled, report success anyway.
|
||||
if (MemoryProtectionExceptionHandler::isDisabled())
|
||||
return true;
|
||||
|
||||
kern_return_t ret;
|
||||
mach_port_t task = mach_task_self();
|
||||
|
||||
// Allocate a new exception port with receive rights.
|
||||
sMachExceptionState.current = {};
|
||||
MachExceptionParameters& current = sMachExceptionState.current;
|
||||
ret = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, ¤t.port);
|
||||
if (ret != KERN_SUCCESS)
|
||||
return false;
|
||||
|
||||
// Give the new port send rights as well.
|
||||
ret = mach_port_insert_right(task, current.port, current.port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
mach_port_deallocate(task, current.port);
|
||||
current = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start the thread that will receive the messages from our exception port.
|
||||
if (!sMachExceptionState.handlerThread.init(MachExceptionHandler)) {
|
||||
mach_port_deallocate(task, current.port);
|
||||
current = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the other properties of our new exception handler.
|
||||
current.mask = EXC_MASK_BAD_ACCESS;
|
||||
current.behavior = exception_behavior_t(EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES);
|
||||
current.flavor = THREAD_STATE_NONE;
|
||||
|
||||
// Tell the task to use our exception handler, and save the previous one.
|
||||
sMachExceptionState.previous = {};
|
||||
MachExceptionParameters& previous = sMachExceptionState.previous;
|
||||
mach_msg_type_number_t previousCount = 1;
|
||||
ret = task_swap_exception_ports(task, current.mask, current.port, current.behavior,
|
||||
current.flavor, &previous.mask, &previousCount,
|
||||
&previous.port, &previous.behavior, &previous.flavor);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
TerminateMachExceptionHandlerThread();
|
||||
mach_port_deallocate(task, current.port);
|
||||
previous = {};
|
||||
current = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
// We should have info on the previous exception handler, even if it's null.
|
||||
MOZ_ASSERT(previousCount == 1);
|
||||
|
||||
sExceptionHandlerInstalled = true;
|
||||
return sExceptionHandlerInstalled;
|
||||
}
|
||||
|
||||
void
|
||||
MemoryProtectionExceptionHandler::uninstall()
|
||||
{
|
||||
if (sExceptionHandlerInstalled) {
|
||||
mach_port_t task = mach_task_self();
|
||||
|
||||
// Restore the previous exception handler.
|
||||
MachExceptionParameters& previous = sMachExceptionState.previous;
|
||||
task_set_exception_ports(task, previous.mask, previous.port,
|
||||
previous.behavior, previous.flavor);
|
||||
|
||||
TerminateMachExceptionHandlerThread();
|
||||
|
||||
// Release the Mach IPC port we used.
|
||||
mach_port_deallocate(task, sMachExceptionState.current.port);
|
||||
|
||||
sMachExceptionState.current = {};
|
||||
sMachExceptionState.previous = {};
|
||||
|
||||
sExceptionHandlerInstalled = false;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "This platform is not supported!"
|
||||
|
|
|
|||
|
|
@ -131,14 +131,6 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
|||
pushedNonVolatileRegisters++;
|
||||
}
|
||||
|
||||
#if defined(XP_IOS) && defined(JS_CODEGEN_ARM)
|
||||
// The stack is 4-byte aligned on iOS, force 8-byte alignment.
|
||||
masm.movePtr(StackPointer, temp0);
|
||||
masm.andPtr(Imm32(~7), StackPointer);
|
||||
masm.push(temp0);
|
||||
masm.push(temp0);
|
||||
#endif
|
||||
|
||||
#ifndef JS_CODEGEN_X86
|
||||
// The InputOutputData* is stored as an argument, save it on the stack
|
||||
// above the frame.
|
||||
|
|
@ -405,11 +397,6 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
|||
masm.freeStack(frameSize);
|
||||
#endif
|
||||
|
||||
#if defined(XP_IOS) && defined(JS_CODEGEN_ARM)
|
||||
masm.pop(temp0);
|
||||
masm.movePtr(temp0, StackPointer);
|
||||
#endif
|
||||
|
||||
// Restore non-volatile registers which were saved on entry.
|
||||
for (GeneralRegisterBackwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter)
|
||||
masm.Pop(*iter);
|
||||
|
|
|
|||
|
|
@ -68,10 +68,6 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len);
|
|||
#include <sys/cachectl.h>
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_ARM) && defined(XP_IOS)
|
||||
#include <libkern/OSCacheControl.h>
|
||||
#endif
|
||||
|
||||
namespace JS {
|
||||
struct CodeSizes;
|
||||
} // namespace JS
|
||||
|
|
@ -255,11 +251,6 @@ class ExecutableAllocator
|
|||
{
|
||||
__clear_cache(code, reinterpret_cast<char*>(code) + size);
|
||||
}
|
||||
#elif (defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)) && defined(XP_IOS)
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
sys_icache_invalidate(code, size);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM) && (defined(__linux__) || defined(ANDROID)) && defined(__GNUC__)
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@
|
|||
#include "js/Utility.h"
|
||||
|
||||
// GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float
|
||||
// ABI target. The iOS toolchain doesn't define anything specific here,
|
||||
// but iOS always supports VFP.
|
||||
#if defined(__ARM_PCS_VFP) || defined(XP_IOS)
|
||||
// ABI target.
|
||||
#if defined(__ARM_PCS_VFP)
|
||||
#define JS_CODEGEN_ARM_HARDFP
|
||||
#endif
|
||||
|
||||
|
|
@ -113,12 +112,7 @@ class Registers
|
|||
(1 << r0) |
|
||||
(1 << r1) |
|
||||
(1 << Registers::r2) |
|
||||
(1 << Registers::r3)
|
||||
#if defined(XP_IOS)
|
||||
// per https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW4
|
||||
| (1 << Registers::r9)
|
||||
#endif
|
||||
;
|
||||
(1 << Registers::r3);
|
||||
|
||||
static const SetType NonVolatileMask =
|
||||
(1 << Registers::r4) |
|
||||
|
|
@ -126,9 +120,7 @@ class Registers
|
|||
(1 << Registers::r6) |
|
||||
(1 << Registers::r7) |
|
||||
(1 << Registers::r8) |
|
||||
#if !defined(XP_IOS)
|
||||
(1 << Registers::r9) |
|
||||
#endif
|
||||
(1 << Registers::r10) |
|
||||
(1 << Registers::r11) |
|
||||
(1 << Registers::r12) |
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
# undef SystemFunction036
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID) || defined(XP_DARWIN) || defined(__DragonFly__) || \
|
||||
#if defined(ANDROID) || defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <stdlib.h>
|
||||
# define HAVE_ARC4RANDOM
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#ifdef XP_WIN
|
||||
# include "jswin.h"
|
||||
|
||||
#elif defined(XP_DARWIN) || defined(DARWIN) || defined(XP_UNIX)
|
||||
#elif defined(XP_UNIX)
|
||||
# include <pthread.h>
|
||||
|
||||
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
|
|
@ -132,10 +132,6 @@ void*
|
|||
js::GetNativeStackBaseImpl()
|
||||
{
|
||||
pthread_t thread = pthread_self();
|
||||
# if defined(XP_DARWIN) || defined(DARWIN)
|
||||
return pthread_get_stackaddr_np(thread);
|
||||
|
||||
# else
|
||||
pthread_attr_t sattr;
|
||||
pthread_attr_init(&sattr);
|
||||
# if defined(__OpenBSD__)
|
||||
|
|
@ -210,7 +206,6 @@ js::GetNativeStackBaseImpl()
|
|||
# else
|
||||
return static_cast<char*>(stackBase) + stackSize;
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
#endif /* !XP_WIN */
|
||||
|
|
|
|||
|
|
@ -1177,7 +1177,7 @@ FirstCharMatcher8bit(const char* text, uint32_t n, const char pat)
|
|||
static const char16_t*
|
||||
FirstCharMatcher16bit(const char16_t* text, uint32_t n, const char16_t pat)
|
||||
{
|
||||
#if defined(XP_DARWIN) || defined(XP_WIN)
|
||||
#if defined(XP_WIN)
|
||||
/*
|
||||
* Performance of memchr is horrible in OSX. Windows is better,
|
||||
* but it is still better to use UnrolledMatcher.
|
||||
|
|
|
|||
|
|
@ -151,9 +151,7 @@ js::ThisThread::SetName(const char* name)
|
|||
#endif
|
||||
|
||||
int rv;
|
||||
#ifdef XP_DARWIN
|
||||
rv = pthread_setname_np(name);
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
rv = 0;
|
||||
#elif defined(__NetBSD__)
|
||||
|
|
|
|||
|
|
@ -10,14 +10,12 @@
|
|||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#if defined(XP_DARWIN)
|
||||
#include <mach/mach.h>
|
||||
#elif defined(XP_UNIX)
|
||||
#if defined(XP_UNIX)
|
||||
#include <sys/resource.h>
|
||||
#elif defined(XP_WIN)
|
||||
#include <processthreadsapi.h>
|
||||
#include <windows.h>
|
||||
#endif // defined(XP_DARWIN) || defined(XP_UNIX) || defined(XP_WIN)
|
||||
#endif // defined(XP_UNIX) || defined(XP_WIN)
|
||||
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@
|
|||
#include "jsclist.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
# include "wasm/WasmSignalHandlers.h"
|
||||
#endif
|
||||
#include "builtin/AtomicsObject.h"
|
||||
#include "builtin/Intl.h"
|
||||
#include "builtin/Promise.h"
|
||||
|
|
@ -932,10 +929,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
*/
|
||||
JSCList onNewGlobalObjectWatchers;
|
||||
|
||||
#if defined(XP_DARWIN)
|
||||
js::wasm::MachExceptionHandler wasmMachExceptionHandler;
|
||||
#endif
|
||||
|
||||
private:
|
||||
js::FreeOp* defaultFreeOp_;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
* Copyright 2021 Moonchild Productions
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -235,10 +236,6 @@ class AutoSetHandlingSegFault
|
|||
# define EPC_sig(p) ((p)->uc_mcontext.mc_pc)
|
||||
# define RFP_sig(p) ((p)->uc_mcontext.mc_regs[30])
|
||||
# endif
|
||||
#elif defined(XP_DARWIN)
|
||||
# define EIP_sig(p) ((p)->uc_mcontext->__ss.__eip)
|
||||
# define RIP_sig(p) ((p)->uc_mcontext->__ss.__rip)
|
||||
# define R15_sig(p) ((p)->uc_mcontext->__ss.__pc)
|
||||
#else
|
||||
# error "Don't know how to read/write to the thread state via the mcontext_t."
|
||||
#endif
|
||||
|
|
@ -348,34 +345,8 @@ enum { REG_EIP = 14 };
|
|||
#endif
|
||||
|
||||
// Define a context type for use in the emulator code. This is usually just
|
||||
// the same as CONTEXT, but on Mac we use a different structure since we call
|
||||
// into the emulator code from a Mach exception handler rather than a
|
||||
// sigaction-style signal handler.
|
||||
#if defined(XP_DARWIN)
|
||||
# if defined(JS_CPU_X64)
|
||||
struct macos_x64_context {
|
||||
x86_thread_state64_t thread;
|
||||
x86_float_state64_t float_;
|
||||
};
|
||||
# define EMULATOR_CONTEXT macos_x64_context
|
||||
# elif defined(JS_CPU_X86)
|
||||
struct macos_x86_context {
|
||||
x86_thread_state_t thread;
|
||||
x86_float_state_t float_;
|
||||
};
|
||||
# define EMULATOR_CONTEXT macos_x86_context
|
||||
# elif defined(JS_CPU_ARM)
|
||||
struct macos_arm_context {
|
||||
arm_thread_state_t thread;
|
||||
arm_neon_state_t float_;
|
||||
};
|
||||
# define EMULATOR_CONTEXT macos_arm_context
|
||||
# else
|
||||
# error Unsupported architecture
|
||||
# endif
|
||||
#else
|
||||
// the same as CONTEXT.
|
||||
# define EMULATOR_CONTEXT CONTEXT
|
||||
#endif
|
||||
|
||||
#if defined(JS_CPU_X64)
|
||||
# define PC_sig(p) RIP_sig(p)
|
||||
|
|
@ -467,7 +438,6 @@ StoreValueFromGPImm(SharedMem<void*> addr, size_t size, int32_t imm)
|
|||
AtomicOperations::memcpySafeWhenRacy(addr, static_cast<void*>(&imm), size);
|
||||
}
|
||||
|
||||
# if !defined(XP_DARWIN)
|
||||
MOZ_COLD static void*
|
||||
AddressOfFPRegisterSlot(CONTEXT* context, FloatRegisters::Encoding encoding)
|
||||
{
|
||||
|
|
@ -517,57 +487,6 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
|
|||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
# else
|
||||
MOZ_COLD static void*
|
||||
AddressOfFPRegisterSlot(EMULATOR_CONTEXT* context, FloatRegisters::Encoding encoding)
|
||||
{
|
||||
switch (encoding) {
|
||||
case X86Encoding::xmm0: return &context->float_.__fpu_xmm0;
|
||||
case X86Encoding::xmm1: return &context->float_.__fpu_xmm1;
|
||||
case X86Encoding::xmm2: return &context->float_.__fpu_xmm2;
|
||||
case X86Encoding::xmm3: return &context->float_.__fpu_xmm3;
|
||||
case X86Encoding::xmm4: return &context->float_.__fpu_xmm4;
|
||||
case X86Encoding::xmm5: return &context->float_.__fpu_xmm5;
|
||||
case X86Encoding::xmm6: return &context->float_.__fpu_xmm6;
|
||||
case X86Encoding::xmm7: return &context->float_.__fpu_xmm7;
|
||||
case X86Encoding::xmm8: return &context->float_.__fpu_xmm8;
|
||||
case X86Encoding::xmm9: return &context->float_.__fpu_xmm9;
|
||||
case X86Encoding::xmm10: return &context->float_.__fpu_xmm10;
|
||||
case X86Encoding::xmm11: return &context->float_.__fpu_xmm11;
|
||||
case X86Encoding::xmm12: return &context->float_.__fpu_xmm12;
|
||||
case X86Encoding::xmm13: return &context->float_.__fpu_xmm13;
|
||||
case X86Encoding::xmm14: return &context->float_.__fpu_xmm14;
|
||||
case X86Encoding::xmm15: return &context->float_.__fpu_xmm15;
|
||||
default: break;
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
MOZ_COLD static void*
|
||||
AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
|
||||
{
|
||||
switch (code) {
|
||||
case X86Encoding::rax: return &context->thread.__rax;
|
||||
case X86Encoding::rcx: return &context->thread.__rcx;
|
||||
case X86Encoding::rdx: return &context->thread.__rdx;
|
||||
case X86Encoding::rbx: return &context->thread.__rbx;
|
||||
case X86Encoding::rsp: return &context->thread.__rsp;
|
||||
case X86Encoding::rbp: return &context->thread.__rbp;
|
||||
case X86Encoding::rsi: return &context->thread.__rsi;
|
||||
case X86Encoding::rdi: return &context->thread.__rdi;
|
||||
case X86Encoding::r8: return &context->thread.__r8;
|
||||
case X86Encoding::r9: return &context->thread.__r9;
|
||||
case X86Encoding::r10: return &context->thread.__r10;
|
||||
case X86Encoding::r11: return &context->thread.__r11;
|
||||
case X86Encoding::r12: return &context->thread.__r12;
|
||||
case X86Encoding::r13: return &context->thread.__r13;
|
||||
case X86Encoding::r14: return &context->thread.__r14;
|
||||
case X86Encoding::r15: return &context->thread.__r15;
|
||||
default: break;
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
# endif // !XP_DARWIN
|
||||
|
||||
MOZ_COLD static void
|
||||
SetRegisterToCoercedUndefined(EMULATOR_CONTEXT* context, size_t size,
|
||||
|
|
@ -873,276 +792,7 @@ WasmFaultHandler(LPEXCEPTION_POINTERS exception)
|
|||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#elif defined(XP_DARWIN)
|
||||
# include <mach/exc.h>
|
||||
|
||||
static uint8_t**
|
||||
ContextToPC(EMULATOR_CONTEXT* context)
|
||||
{
|
||||
# if defined(JS_CPU_X64)
|
||||
static_assert(sizeof(context->thread.__rip) == sizeof(void*),
|
||||
"stored IP should be compile-time pointer-sized");
|
||||
return reinterpret_cast<uint8_t**>(&context->thread.__rip);
|
||||
# elif defined(JS_CPU_X86)
|
||||
static_assert(sizeof(context->thread.uts.ts32.__eip) == sizeof(void*),
|
||||
"stored IP should be compile-time pointer-sized");
|
||||
return reinterpret_cast<uint8_t**>(&context->thread.uts.ts32.__eip);
|
||||
# elif defined(JS_CPU_ARM)
|
||||
static_assert(sizeof(context->thread.__pc) == sizeof(void*),
|
||||
"stored IP should be compile-time pointer-sized");
|
||||
return reinterpret_cast<uint8_t**>(&context->thread.__pc);
|
||||
# else
|
||||
# error Unsupported architecture
|
||||
# endif
|
||||
}
|
||||
|
||||
// This definition was generated by mig (the Mach Interface Generator) for the
|
||||
// routine 'exception_raise' (exc.defs).
|
||||
#pragma pack(4)
|
||||
typedef struct {
|
||||
mach_msg_header_t Head;
|
||||
/* start of the kernel processed data */
|
||||
mach_msg_body_t msgh_body;
|
||||
mach_msg_port_descriptor_t thread;
|
||||
mach_msg_port_descriptor_t task;
|
||||
/* end of the kernel processed data */
|
||||
NDR_record_t NDR;
|
||||
exception_type_t exception;
|
||||
mach_msg_type_number_t codeCnt;
|
||||
int64_t code[2];
|
||||
} Request__mach_exception_raise_t;
|
||||
#pragma pack()
|
||||
|
||||
// The full Mach message also includes a trailer.
|
||||
struct ExceptionRequest
|
||||
{
|
||||
Request__mach_exception_raise_t body;
|
||||
mach_msg_trailer_t trailer;
|
||||
};
|
||||
|
||||
static bool
|
||||
HandleMachException(JSRuntime* rt, const ExceptionRequest& request)
|
||||
{
|
||||
// Don't allow recursive handling of signals, see AutoSetHandlingSegFault.
|
||||
if (rt->handlingSegFault)
|
||||
return false;
|
||||
AutoSetHandlingSegFault handling(rt);
|
||||
|
||||
// Get the port of the JSRuntime's thread from the message.
|
||||
mach_port_t rtThread = request.body.thread.name;
|
||||
|
||||
// Read out the JSRuntime thread's register state.
|
||||
EMULATOR_CONTEXT context;
|
||||
# if defined(JS_CPU_X64)
|
||||
unsigned int thread_state_count = x86_THREAD_STATE64_COUNT;
|
||||
unsigned int float_state_count = x86_FLOAT_STATE64_COUNT;
|
||||
int thread_state = x86_THREAD_STATE64;
|
||||
int float_state = x86_FLOAT_STATE64;
|
||||
# elif defined(JS_CPU_X86)
|
||||
unsigned int thread_state_count = x86_THREAD_STATE_COUNT;
|
||||
unsigned int float_state_count = x86_FLOAT_STATE_COUNT;
|
||||
int thread_state = x86_THREAD_STATE;
|
||||
int float_state = x86_FLOAT_STATE;
|
||||
# elif defined(JS_CPU_ARM)
|
||||
unsigned int thread_state_count = ARM_THREAD_STATE_COUNT;
|
||||
unsigned int float_state_count = ARM_NEON_STATE_COUNT;
|
||||
int thread_state = ARM_THREAD_STATE;
|
||||
int float_state = ARM_NEON_STATE;
|
||||
# else
|
||||
# error Unsupported architecture
|
||||
# endif
|
||||
kern_return_t kret;
|
||||
kret = thread_get_state(rtThread, thread_state,
|
||||
(thread_state_t)&context.thread, &thread_state_count);
|
||||
if (kret != KERN_SUCCESS)
|
||||
return false;
|
||||
kret = thread_get_state(rtThread, float_state,
|
||||
(thread_state_t)&context.float_, &float_state_count);
|
||||
if (kret != KERN_SUCCESS)
|
||||
return false;
|
||||
|
||||
uint8_t** ppc = ContextToPC(&context);
|
||||
uint8_t* pc = *ppc;
|
||||
|
||||
if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
|
||||
return false;
|
||||
|
||||
WasmActivation* activation = rt->wasmActivationStack();
|
||||
if (!activation)
|
||||
return false;
|
||||
|
||||
const Instance* instance = activation->compartment()->wasm.lookupInstanceDeprecated(pc);
|
||||
if (!instance || !instance->codeSegment().containsFunctionPC(pc))
|
||||
return false;
|
||||
|
||||
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]);
|
||||
|
||||
// This check isn't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
if (!IsHeapAccessAddress(*instance, faultingAddress))
|
||||
return false;
|
||||
|
||||
HandleMemoryAccess(&context, pc, faultingAddress, *instance, ppc);
|
||||
|
||||
// Update the thread state with the new pc and register values.
|
||||
kret = thread_set_state(rtThread, float_state, (thread_state_t)&context.float_, float_state_count);
|
||||
if (kret != KERN_SUCCESS)
|
||||
return false;
|
||||
kret = thread_set_state(rtThread, thread_state, (thread_state_t)&context.thread, thread_state_count);
|
||||
if (kret != KERN_SUCCESS)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Taken from mach_exc in /usr/include/mach/mach_exc.defs.
|
||||
static const mach_msg_id_t sExceptionId = 2405;
|
||||
|
||||
// The choice of id here is arbitrary, the only constraint is that sQuitId != sExceptionId.
|
||||
static const mach_msg_id_t sQuitId = 42;
|
||||
|
||||
static void
|
||||
MachExceptionHandlerThread(JSRuntime* rt)
|
||||
{
|
||||
mach_port_t port = rt->wasmMachExceptionHandler.port();
|
||||
kern_return_t kret;
|
||||
|
||||
while(true) {
|
||||
ExceptionRequest request;
|
||||
kret = mach_msg(&request.body.Head, MACH_RCV_MSG, 0, sizeof(request),
|
||||
port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
// If we fail even receiving the message, we can't even send a reply!
|
||||
// Rather than hanging the faulting thread (hanging the browser), crash.
|
||||
if (kret != KERN_SUCCESS) {
|
||||
fprintf(stderr, "MachExceptionHandlerThread: mach_msg failed with %d\n", (int)kret);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// There are only two messages we should be receiving: an exception
|
||||
// message that occurs when the runtime's thread faults and the quit
|
||||
// message sent when the runtime is shutting down.
|
||||
if (request.body.Head.msgh_id == sQuitId)
|
||||
break;
|
||||
if (request.body.Head.msgh_id != sExceptionId) {
|
||||
fprintf(stderr, "Unexpected msg header id %d\n", (int)request.body.Head.msgh_bits);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// Some thread just commited an EXC_BAD_ACCESS and has been suspended by
|
||||
// the kernel. The kernel is waiting for us to reply with instructions.
|
||||
// Our default is the "not handled" reply (by setting the RetCode field
|
||||
// of the reply to KERN_FAILURE) which tells the kernel to continue
|
||||
// searching at the process and system level. If this is an asm.js
|
||||
// expected exception, we handle it and return KERN_SUCCESS.
|
||||
bool handled = HandleMachException(rt, request);
|
||||
kern_return_t replyCode = handled ? KERN_SUCCESS : KERN_FAILURE;
|
||||
|
||||
// This magic incantation to send a reply back to the kernel was derived
|
||||
// from the exc_server generated by 'mig -v /usr/include/mach/mach_exc.defs'.
|
||||
__Reply__exception_raise_t reply;
|
||||
reply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.body.Head.msgh_bits), 0);
|
||||
reply.Head.msgh_size = sizeof(reply);
|
||||
reply.Head.msgh_remote_port = request.body.Head.msgh_remote_port;
|
||||
reply.Head.msgh_local_port = MACH_PORT_NULL;
|
||||
reply.Head.msgh_id = request.body.Head.msgh_id + 100;
|
||||
reply.NDR = NDR_record;
|
||||
reply.RetCode = replyCode;
|
||||
mach_msg(&reply.Head, MACH_SEND_MSG, sizeof(reply), 0, MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
MachExceptionHandler::MachExceptionHandler()
|
||||
: installed_(false),
|
||||
thread_(),
|
||||
port_(MACH_PORT_NULL)
|
||||
{}
|
||||
|
||||
void
|
||||
MachExceptionHandler::uninstall()
|
||||
{
|
||||
if (installed_) {
|
||||
thread_port_t thread = mach_thread_self();
|
||||
kern_return_t kret = thread_set_exception_ports(thread,
|
||||
EXC_MASK_BAD_ACCESS,
|
||||
MACH_PORT_NULL,
|
||||
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
|
||||
THREAD_STATE_NONE);
|
||||
mach_port_deallocate(mach_task_self(), thread);
|
||||
if (kret != KERN_SUCCESS)
|
||||
MOZ_CRASH();
|
||||
installed_ = false;
|
||||
}
|
||||
if (thread_.joinable()) {
|
||||
// Break the handler thread out of the mach_msg loop.
|
||||
mach_msg_header_t msg;
|
||||
msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
|
||||
msg.msgh_size = sizeof(msg);
|
||||
msg.msgh_remote_port = port_;
|
||||
msg.msgh_local_port = MACH_PORT_NULL;
|
||||
msg.msgh_reserved = 0;
|
||||
msg.msgh_id = sQuitId;
|
||||
kern_return_t kret = mach_msg(&msg, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
if (kret != KERN_SUCCESS) {
|
||||
fprintf(stderr, "MachExceptionHandler: failed to send quit message: %d\n", (int)kret);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// Wait for the handler thread to complete before deallocating the port.
|
||||
thread_.join();
|
||||
}
|
||||
if (port_ != MACH_PORT_NULL) {
|
||||
DebugOnly<kern_return_t> kret = mach_port_destroy(mach_task_self(), port_);
|
||||
MOZ_ASSERT(kret == KERN_SUCCESS);
|
||||
port_ = MACH_PORT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MachExceptionHandler::install(JSRuntime* rt)
|
||||
{
|
||||
MOZ_ASSERT(!installed());
|
||||
kern_return_t kret;
|
||||
mach_port_t thread;
|
||||
|
||||
// Get a port which can send and receive data.
|
||||
kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port_);
|
||||
if (kret != KERN_SUCCESS)
|
||||
goto error;
|
||||
kret = mach_port_insert_right(mach_task_self(), port_, port_, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (kret != KERN_SUCCESS)
|
||||
goto error;
|
||||
|
||||
// Create a thread to block on reading port_.
|
||||
if (!thread_.init(MachExceptionHandlerThread, rt))
|
||||
goto error;
|
||||
|
||||
// Direct exceptions on this thread to port_ (and thus our handler thread).
|
||||
// Note: we are totally clobbering any existing *thread* exception ports and
|
||||
// not even attempting to forward. Breakpad and gdb both use the *process*
|
||||
// exception ports which are only called if the thread doesn't handle the
|
||||
// exception, so we should be fine.
|
||||
thread = mach_thread_self();
|
||||
kret = thread_set_exception_ports(thread,
|
||||
EXC_MASK_BAD_ACCESS,
|
||||
port_,
|
||||
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
|
||||
THREAD_STATE_NONE);
|
||||
mach_port_deallocate(mach_task_self(), thread);
|
||||
if (kret != KERN_SUCCESS)
|
||||
goto error;
|
||||
|
||||
installed_ = true;
|
||||
return true;
|
||||
|
||||
error:
|
||||
uninstall();
|
||||
return false;
|
||||
}
|
||||
|
||||
#else // If not Windows or Mac, assume Unix
|
||||
#else // If not Windows, assume Unix-like
|
||||
|
||||
enum class Signal {
|
||||
SegFault,
|
||||
|
|
@ -1246,7 +896,7 @@ WasmFaultHandler(int signum, siginfo_t* info, void* context)
|
|||
else
|
||||
previousSignal->sa_handler(signum);
|
||||
}
|
||||
# endif // XP_WIN || XP_DARWIN || assume unix
|
||||
# endif // XP_WIN || assume Unix-like
|
||||
|
||||
static void
|
||||
RedirectIonBackedgesToInterruptCheck(JSRuntime* rt)
|
||||
|
|
@ -1374,9 +1024,6 @@ ProcessHasSignalHandlers()
|
|||
# if defined(XP_WIN)
|
||||
if (!AddVectoredExceptionHandler(/* FirstHandler = */ true, WasmFaultHandler))
|
||||
return false;
|
||||
# elif defined(XP_DARWIN)
|
||||
// OSX handles seg faults via the Mach exception handler above, so don't
|
||||
// install WasmFaultHandler.
|
||||
# else
|
||||
// SA_NODEFER allows us to reenter the signal handler if we crash while
|
||||
// handling the signal, and fall through to the Breakpad handler by testing
|
||||
|
|
@ -1412,12 +1059,6 @@ wasm::EnsureSignalHandlers(JSRuntime* rt)
|
|||
if (!ProcessHasSignalHandlers())
|
||||
return true;
|
||||
|
||||
#if defined(XP_DARWIN)
|
||||
// On OSX, each JSRuntime gets its own handler thread.
|
||||
if (!rt->wasmMachExceptionHandler.installed() && !rt->wasmMachExceptionHandler.install(rt))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
* Copyright 2021 Moonchild Productions
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -19,10 +20,6 @@
|
|||
#define wasm_signal_handlers_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#if defined(XP_DARWIN)
|
||||
# include <mach/mach.h>
|
||||
#endif
|
||||
#include "threading/Thread.h"
|
||||
|
||||
struct JSRuntime;
|
||||
|
|
@ -46,30 +43,6 @@ EnsureSignalHandlers(JSRuntime* rt);
|
|||
bool
|
||||
HaveSignalHandlers();
|
||||
|
||||
#if defined(XP_DARWIN)
|
||||
// On OSX we are forced to use the lower-level Mach exception mechanism instead
|
||||
// of Unix signals. Mach exceptions are not handled on the victim's stack but
|
||||
// rather require an extra thread. For simplicity, we create one such thread
|
||||
// per JSRuntime (upon the first use of asm.js in the JSRuntime). This thread
|
||||
// and related resources are owned by AsmJSMachExceptionHandler which is owned
|
||||
// by JSRuntime.
|
||||
class MachExceptionHandler
|
||||
{
|
||||
bool installed_;
|
||||
js::Thread thread_;
|
||||
mach_port_t port_;
|
||||
|
||||
void uninstall();
|
||||
|
||||
public:
|
||||
MachExceptionHandler();
|
||||
~MachExceptionHandler() { uninstall(); }
|
||||
mach_port_t port() const { return port_; }
|
||||
bool installed() const { return installed_; }
|
||||
bool install(JSRuntime* rt);
|
||||
};
|
||||
#endif
|
||||
|
||||
// Test whether the given PC is within the innermost wasm activation. Return
|
||||
// false if it is not, or it cannot be determined.
|
||||
bool IsPCInWasmCode(void *pc);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue