[wasm][mac][arm64] Enable OOB trap handler
R=ahaas@chromium.org,mark@chromium.org,mseaborn@chromium.org Bug: v8:11098 Change-Id: Ic4eb02a96805e49da71f301269567a6e0ac1b843 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2519555 Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Reviewed-by: Zhi An Ng <zhin@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#72136}
This commit is contained in:
parent
c92aa9e17b
commit
a80d51d488
7
BUILD.gn
7
BUILD.gn
@ -3692,6 +3692,13 @@ v8_source_set("v8_base_without_compiler") {
|
||||
if (v8_control_flow_integrity) {
|
||||
sources += [ "src/execution/arm64/pointer-authentication-arm64.h" ]
|
||||
}
|
||||
if (current_cpu == "arm64" && is_mac) {
|
||||
sources += [
|
||||
"src/trap-handler/handler-inside-posix.cc",
|
||||
"src/trap-handler/handler-inside-posix.h",
|
||||
"src/trap-handler/handler-outside-posix.cc",
|
||||
]
|
||||
}
|
||||
if (is_win) {
|
||||
sources += [
|
||||
"src/diagnostics/unwinding-info-win64.cc",
|
||||
|
@ -5910,7 +5910,14 @@ bool v8::V8::Initialize(const int build_config) {
|
||||
#if V8_OS_LINUX || V8_OS_MACOSX
|
||||
bool TryHandleWebAssemblyTrapPosix(int sig_code, siginfo_t* info,
|
||||
void* context) {
|
||||
#if V8_TARGET_ARCH_X64 && !V8_OS_ANDROID
|
||||
// When the target code runs on the V8 arm simulator, the trap handler does
|
||||
// not behave as expected: the instruction pointer points inside the simulator
|
||||
// code rather than the wasm code, so the trap handler cannot find the landing
|
||||
// pad and lets the process crash. Therefore, only enable trap handlers if
|
||||
// the host and target arch are the same.
|
||||
#if ((V8_TARGET_ARCH_X64 && !V8_OS_ANDROID) || \
|
||||
(V8_TARGET_ARCH_ARM64 && V8_OS_MACOSX)) && \
|
||||
V8_TARGET_ARCH == V8_HOST_ARCH
|
||||
return i::trap_handler::TryHandleSignal(sig_code, info, context);
|
||||
#else
|
||||
return false;
|
||||
|
@ -375,6 +375,74 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
class WasmOutOfLineTrap : public OutOfLineCode {
|
||||
public:
|
||||
WasmOutOfLineTrap(CodeGenerator* gen, Instruction* instr)
|
||||
: OutOfLineCode(gen), gen_(gen), instr_(instr) {}
|
||||
void Generate() override {
|
||||
Arm64OperandConverter i(gen_, instr_);
|
||||
TrapId trap_id =
|
||||
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
|
||||
GenerateCallToTrap(trap_id);
|
||||
}
|
||||
|
||||
protected:
|
||||
CodeGenerator* gen_;
|
||||
|
||||
void GenerateWithTrapId(TrapId trap_id) { GenerateCallToTrap(trap_id); }
|
||||
|
||||
private:
|
||||
void GenerateCallToTrap(TrapId trap_id) {
|
||||
if (trap_id == TrapId::kInvalid) {
|
||||
// We cannot test calls to the runtime in cctest/test-run-wasm.
|
||||
// Therefore we emit a call to C here instead of a call to the runtime.
|
||||
__ CallCFunction(ExternalReference::wasm_call_trap_callback_for_testing(),
|
||||
0);
|
||||
__ LeaveFrame(StackFrame::WASM);
|
||||
auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
|
||||
int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
|
||||
pop_count += (pop_count & 1); // align
|
||||
__ Drop(pop_count);
|
||||
__ Ret();
|
||||
} else {
|
||||
gen_->AssembleSourcePosition(instr_);
|
||||
// A direct call to a wasm runtime stub defined in this module.
|
||||
// Just encode the stub index. This will be patched when the code
|
||||
// is added to the native module and copied into wasm code space.
|
||||
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
|
||||
ReferenceMap* reference_map =
|
||||
gen_->zone()->New<ReferenceMap>(gen_->zone());
|
||||
gen_->RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt);
|
||||
__ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap);
|
||||
}
|
||||
}
|
||||
|
||||
Instruction* instr_;
|
||||
};
|
||||
|
||||
class WasmProtectedInstructionTrap final : public WasmOutOfLineTrap {
|
||||
public:
|
||||
WasmProtectedInstructionTrap(CodeGenerator* gen, int pc, Instruction* instr)
|
||||
: WasmOutOfLineTrap(gen, instr), pc_(pc) {}
|
||||
|
||||
void Generate() override {
|
||||
gen_->AddProtectedInstructionLanding(pc_, __ pc_offset());
|
||||
GenerateWithTrapId(TrapId::kTrapMemOutOfBounds);
|
||||
}
|
||||
|
||||
private:
|
||||
int pc_;
|
||||
};
|
||||
|
||||
void EmitOOLTrapIfNeeded(Zone* zone, CodeGenerator* codegen,
|
||||
InstructionCode opcode, Instruction* instr, int pc) {
|
||||
const MemoryAccessMode access_mode =
|
||||
static_cast<MemoryAccessMode>(MiscField::decode(opcode));
|
||||
if (access_mode == kMemoryAccessProtected) {
|
||||
zone->New<WasmProtectedInstructionTrap>(codegen, pc, instr);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen,
|
||||
InstructionCode opcode, Instruction* instr,
|
||||
Arm64OperandConverter const& i) {
|
||||
@ -1700,39 +1768,49 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Fmov(i.OutputRegister(), i.InputDoubleRegister(0));
|
||||
break;
|
||||
case kArm64Ldrb:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldrb(i.OutputRegister(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64Ldrsb:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldrsb(i.OutputRegister(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64Strb:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Strb(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64Ldrh:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldrh(i.OutputRegister(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64Ldrsh:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldrsh(i.OutputRegister(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64Strh:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Strh(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64Ldrsw:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldrsw(i.OutputRegister(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64LdrW:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldr(i.OutputRegister32(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64StrW:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Str(i.InputOrZeroRegister32(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64Ldr:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldr(i.OutputRegister(), i.MemoryOperand());
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
@ -1749,27 +1827,34 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
|
||||
break;
|
||||
case kArm64Str:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Str(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64StrCompressTagged:
|
||||
__ StoreTaggedField(i.InputOrZeroRegister64(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64LdrS:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
EmitMaybePoisonedFPLoad(this, opcode, &i, i.OutputDoubleRegister().S());
|
||||
break;
|
||||
case kArm64StrS:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Str(i.InputFloat32OrZeroRegister(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64LdrD:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
EmitMaybePoisonedFPLoad(this, opcode, &i, i.OutputDoubleRegister());
|
||||
break;
|
||||
case kArm64StrD:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Str(i.InputFloat64OrZeroRegister(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64LdrQ:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Ldr(i.OutputSimd128Register(), i.MemoryOperand());
|
||||
break;
|
||||
case kArm64StrQ:
|
||||
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, __ pc_offset());
|
||||
__ Str(i.InputSimd128Register(0), i.MemoryOperand(1));
|
||||
break;
|
||||
case kArm64DmbIsh:
|
||||
@ -2801,50 +2886,7 @@ void CodeGenerator::AssembleArchJump(RpoNumber target) {
|
||||
|
||||
void CodeGenerator::AssembleArchTrap(Instruction* instr,
|
||||
FlagsCondition condition) {
|
||||
class OutOfLineTrap final : public OutOfLineCode {
|
||||
public:
|
||||
OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
|
||||
: OutOfLineCode(gen), instr_(instr), gen_(gen) {}
|
||||
void Generate() final {
|
||||
Arm64OperandConverter i(gen_, instr_);
|
||||
TrapId trap_id =
|
||||
static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
|
||||
GenerateCallToTrap(trap_id);
|
||||
}
|
||||
|
||||
private:
|
||||
void GenerateCallToTrap(TrapId trap_id) {
|
||||
if (trap_id == TrapId::kInvalid) {
|
||||
// We cannot test calls to the runtime in cctest/test-run-wasm.
|
||||
// Therefore we emit a call to C here instead of a call to the runtime.
|
||||
__ CallCFunction(
|
||||
ExternalReference::wasm_call_trap_callback_for_testing(), 0);
|
||||
__ LeaveFrame(StackFrame::WASM);
|
||||
auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
|
||||
int pop_count =
|
||||
static_cast<int>(call_descriptor->StackParameterCount());
|
||||
pop_count += (pop_count & 1); // align
|
||||
__ Drop(pop_count);
|
||||
__ Ret();
|
||||
} else {
|
||||
gen_->AssembleSourcePosition(instr_);
|
||||
// A direct call to a wasm runtime stub defined in this module.
|
||||
// Just encode the stub index. This will be patched when the code
|
||||
// is added to the native module and copied into wasm code space.
|
||||
__ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
|
||||
ReferenceMap* reference_map =
|
||||
gen_->zone()->New<ReferenceMap>(gen_->zone());
|
||||
gen_->RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt);
|
||||
if (FLAG_debug_code) {
|
||||
// The trap code should never return.
|
||||
__ Brk(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Instruction* instr_;
|
||||
CodeGenerator* gen_;
|
||||
};
|
||||
auto ool = zone()->New<OutOfLineTrap>(this, instr);
|
||||
auto ool = zone()->New<WasmOutOfLineTrap>(this, instr);
|
||||
Label* tlabel = ool->entry();
|
||||
Condition cc = FlagsConditionToCondition(condition);
|
||||
__ B(cc, tlabel);
|
||||
|
@ -846,16 +846,16 @@ void InstructionSelector::VisitLoad(Node* node) {
|
||||
CHECK_NE(poisoning_level_, PoisoningMitigationLevel::kDontPoison);
|
||||
opcode |= MiscField::encode(kMemoryAccessPoisoned);
|
||||
}
|
||||
if (node->opcode() == IrOpcode::kProtectedLoad) {
|
||||
opcode |= MiscField::encode(kMemoryAccessProtected);
|
||||
}
|
||||
|
||||
EmitLoad(this, node, opcode, immediate_mode, rep);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitPoisonedLoad(Node* node) { VisitLoad(node); }
|
||||
|
||||
void InstructionSelector::VisitProtectedLoad(Node* node) {
|
||||
// TODO(eholk)
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void InstructionSelector::VisitProtectedLoad(Node* node) { VisitLoad(node); }
|
||||
|
||||
void InstructionSelector::VisitStore(Node* node) {
|
||||
Arm64OperandGenerator g(this);
|
||||
@ -987,14 +987,15 @@ void InstructionSelector::VisitStore(Node* node) {
|
||||
opcode |= AddressingModeField::encode(kMode_MRR);
|
||||
}
|
||||
|
||||
if (node->opcode() == IrOpcode::kProtectedStore) {
|
||||
opcode |= MiscField::encode(kMemoryAccessProtected);
|
||||
}
|
||||
|
||||
Emit(opcode, 0, nullptr, input_count, inputs);
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitProtectedStore(Node* node) {
|
||||
// TODO(eholk)
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void InstructionSelector::VisitProtectedStore(Node* node) { VisitStore(node); }
|
||||
|
||||
void InstructionSelector::VisitSimd128ReverseBytes(Node* node) {
|
||||
UNREACHABLE();
|
||||
|
@ -106,20 +106,22 @@ bool TryHandleSignal(int signum, siginfo_t* info, void* context) {
|
||||
SigUnmaskStack unmask(sigs);
|
||||
|
||||
ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
|
||||
#if V8_OS_LINUX
|
||||
auto* context_rip = &uc->uc_mcontext.gregs[REG_RIP];
|
||||
#elif V8_OS_MACOSX
|
||||
auto* context_rip = &uc->uc_mcontext->__ss.__rip;
|
||||
#elif V8_OS_FREEBSD
|
||||
auto* context_rip = &uc->uc_mcontext.mc_rip;
|
||||
#if V8_OS_LINUX && V8_TARGET_ARCH_X64
|
||||
auto* context_ip = &uc->uc_mcontext.gregs[REG_RIP];
|
||||
#elif V8_OS_MACOSX && V8_TARGET_ARCH_ARM64
|
||||
auto* context_ip = &uc->uc_mcontext->__ss.__pc;
|
||||
#elif V8_OS_MACOSX && V8_TARGET_ARCH_X64
|
||||
auto* context_ip = &uc->uc_mcontext->__ss.__rip;
|
||||
#elif V8_OS_FREEBSD && V8_TARGET_ARCH_X64
|
||||
auto* context_ip = &uc->uc_mcontext.mc_rip;
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
uintptr_t fault_addr = *context_rip;
|
||||
uintptr_t fault_addr = *context_ip;
|
||||
uintptr_t landing_pad = 0;
|
||||
if (TryFindLandingPad(fault_addr, &landing_pad)) {
|
||||
// Tell the caller to return to the landing pad.
|
||||
*context_rip = landing_pad;
|
||||
*context_ip = landing_pad;
|
||||
// We will return to wasm code, so restore the g_thread_in_wasm_code flag.
|
||||
g_thread_in_wasm_code = true;
|
||||
return true;
|
||||
|
@ -27,6 +27,8 @@ namespace trap_handler {
|
||||
#define V8_TRAP_HANDLER_SUPPORTED true
|
||||
#elif V8_TARGET_ARCH_X64 && V8_OS_FREEBSD
|
||||
#define V8_TRAP_HANDLER_SUPPORTED true
|
||||
#elif V8_HOST_ARCH_ARM64 && V8_TARGET_ARCH_ARM64 && V8_OS_MACOSX
|
||||
#define V8_TRAP_HANDLER_SUPPORTED true
|
||||
#else
|
||||
#define V8_TRAP_HANDLER_SUPPORTED false
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user