Commit e312038d authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[wasm] Add trap-handler support for arm64 simulator

This adds a little {Simulator::ProbeMemory} method that is used from
several places in the arm64 simulator to test if a memory address can be
accessed, and trigger a signal from a specific location such that the
trap-handler can handle it. In case of a trap, the simulator is
redirected to the landing pad and stops executing the memory
instruction that triggered the trap.

Standard memory accesses and SIMD memory loads and stores are
instrumented to probe the memory. This passes all existing tests. In
case this CL misses certain spots, we can still add them later. This
will not be a security problem, since we do not use the simulator in
production.

R=ahaas@chromium.org
CC=mseaborn@chromium.org, v8-arm-ports@googlegroups.com

Bug: v8:11955
Change-Id: I52a81341e99fabc5fcf9e41ef4d8dd2226092803
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3015557
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75843}
parent 4e0035cd
......@@ -58,6 +58,7 @@ include_rules = [
"+src/trap-handler/handler-inside-posix.h",
"+src/trap-handler/handler-inside-win.h",
"+src/trap-handler/trap-handler.h",
"+src/trap-handler/trap-handler-simulator.h",
"+testing/gtest/include/gtest/gtest_prod.h",
"-src/libplatform",
"-include/libplatform",
......
......@@ -27,6 +27,10 @@
#include "src/runtime/runtime-utils.h"
#include "src/utils/ostreams.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/trap-handler/trap-handler-simulator.h"
#endif // V8_ENABLE_WEBASSEMBLY
namespace v8 {
namespace internal {
......@@ -65,6 +69,20 @@ TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : "";
DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
Simulator::GlobalMonitor::Get)
bool Simulator::ProbeMemory(uintptr_t address, uintptr_t access_size) {
#if V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED
uintptr_t last_accessed_byte = address + access_size - 1;
uintptr_t current_pc = reinterpret_cast<uintptr_t>(pc_);
uintptr_t landing_pad =
trap_handler::ProbeMemory(last_accessed_byte, current_pc);
if (!landing_pad) return true;
set_pc(landing_pad);
return false;
#else
return true;
#endif
}
// This is basically the same as PrintF, with a guard for FLAG_trace_sim.
void Simulator::TraceSim(const char* format, ...) {
if (FLAG_trace_sim) {
......@@ -1801,6 +1819,10 @@ void Simulator::LoadStoreHelper(Instruction* instr, int64_t offset,
uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
uintptr_t stack = 0;
unsigned access_size = 1 << instr->SizeLS();
// First, check whether the memory is accessible (for wasm trap handling).
if (!ProbeMemory(address, access_size)) return;
{
base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
if (instr->IsLoad()) {
......@@ -1907,7 +1929,6 @@ void Simulator::LoadStoreHelper(Instruction* instr, int64_t offset,
// Print a detailed trace (including the memory address) instead of the basic
// register:value trace generated by set_*reg().
unsigned access_size = 1 << instr->SizeLS();
if (instr->IsLoad()) {
if ((op == LDR_s) || (op == LDR_d)) {
LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
......@@ -4886,6 +4907,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
case NEON_LD1R:
case NEON_LD1R_post: {
vf = vf_t;
if (!ProbeMemory(addr, LaneSizeInBytesFromFormat(vf))) return;
ld1r(vf, vreg(rt), addr);
do_load = true;
break;
......@@ -4894,6 +4916,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
case NEON_LD2R:
case NEON_LD2R_post: {
vf = vf_t;
if (!ProbeMemory(addr, 2 * LaneSizeInBytesFromFormat(vf))) return;
int rt2 = (rt + 1) % kNumberOfVRegisters;
ld2r(vf, vreg(rt), vreg(rt2), addr);
do_load = true;
......@@ -4903,6 +4926,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
case NEON_LD3R:
case NEON_LD3R_post: {
vf = vf_t;
if (!ProbeMemory(addr, 3 * LaneSizeInBytesFromFormat(vf))) return;
int rt2 = (rt + 1) % kNumberOfVRegisters;
int rt3 = (rt2 + 1) % kNumberOfVRegisters;
ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr);
......@@ -4913,6 +4937,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
case NEON_LD4R:
case NEON_LD4R_post: {
vf = vf_t;
if (!ProbeMemory(addr, 4 * LaneSizeInBytesFromFormat(vf))) return;
int rt2 = (rt + 1) % kNumberOfVRegisters;
int rt3 = (rt2 + 1) % kNumberOfVRegisters;
int rt4 = (rt3 + 1) % kNumberOfVRegisters;
......@@ -4940,6 +4965,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
case NEONLoadStoreSingle1:
scale = 1;
if (!ProbeMemory(addr, scale * esize)) return;
if (do_load) {
ld1(vf, vreg(rt), lane, addr);
LogVRead(addr, rt, print_format, lane);
......@@ -4950,6 +4976,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
break;
case NEONLoadStoreSingle2:
scale = 2;
if (!ProbeMemory(addr, scale * esize)) return;
if (do_load) {
ld2(vf, vreg(rt), vreg(rt2), lane, addr);
LogVRead(addr, rt, print_format, lane);
......@@ -4962,6 +4989,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
break;
case NEONLoadStoreSingle3:
scale = 3;
if (!ProbeMemory(addr, scale * esize)) return;
if (do_load) {
ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
LogVRead(addr, rt, print_format, lane);
......@@ -4976,6 +5004,7 @@ void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
break;
case NEONLoadStoreSingle4:
scale = 4;
if (!ProbeMemory(addr, scale * esize)) return;
if (do_load) {
ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
LogVRead(addr, rt, print_format, lane);
......
......@@ -761,7 +761,7 @@ class Simulator : public DecoderVisitor, public SimulatorBase {
// Simulation helpers.
template <typename T>
void set_pc(T new_pc) {
DCHECK(sizeof(T) == sizeof(pc_));
STATIC_ASSERT(sizeof(T) == sizeof(pc_));
memcpy(&pc_, &new_pc, sizeof(T));
pc_modified_ = true;
}
......@@ -1502,6 +1502,18 @@ class Simulator : public DecoderVisitor, public SimulatorBase {
AddrMode addr_mode);
void CheckMemoryAccess(uintptr_t address, uintptr_t stack);
// "Probe" if an address range can be read. This is currently implemented
// by doing a 1-byte read of the last accessed byte, since the assumption is
// that if the last byte is accessible, also all lower bytes are accessible
// (which holds true for Wasm).
// Returns true if the access was successful, false if the access raised a
// signal which was then handled by the trap handler (also see
// {trap_handler::ProbeMemory}). If the access raises a signal which is not
// handled by the trap handler (e.g. because the current PC is not registered
// as a protected instruction), the signal will propagate and make the process
// crash. If no trap handler is available, this always returns true.
bool ProbeMemory(uintptr_t address, uintptr_t access_size);
// Memory read helpers.
template <typename T, typename A>
T MemoryRead(A address) {
......
......@@ -277,13 +277,7 @@ RUNTIME_FUNCTION(Runtime_IsWasmCode) {
RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
DisallowGarbageCollection no_gc;
DCHECK_EQ(0, args.length());
// We currently lie to tests about enabled trap handling in simulator builds.
// TODO(clemensb): Remove this once the arm64 simulator support trap handling.
#ifdef USE_SIMULATOR
return isolate->heap()->ToBoolean(false);
#else
return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled());
#endif
}
RUNTIME_FUNCTION(Runtime_IsThreadInWasm) {
......
......@@ -823,10 +823,7 @@ BoundsCheckStrategy GetBoundsChecks(const WasmModule* module) {
if (FLAG_wasm_enforce_bounds_checks) return kExplicitBoundsChecks;
// We do not have trap handler support for memory64 yet.
if (module->is_memory64) return kExplicitBoundsChecks;
// TODO(clemensb): Enable trap handling in the arm64 simulator.
#ifndef USE_SIMULATOR
if (trap_handler::IsTrapHandlerEnabled()) return kTrapHandler;
#endif // USE_SIMULATOR
return kExplicitBoundsChecks;
}
} // namespace
......
......@@ -109,16 +109,13 @@ TEST_F(SimulatorTrapHandlerTest, ProbeMemoryWithLandingPad) {
i_isolate(), reinterpret_cast<Address>(desc.buffer));
SetThreadInWasm();
// TODO(clemensb): This should pass after adding memory probing in the
// simulator.
// code.Call();
EXPECT_DEATH_IF_SUPPORTED(code.Call(), "");
code.Call();
ResetThreadInWasm();
ReleaseHandlerData(handler_data_index);
RemoveTrapHandler();
// EXPECT_EQ(1u, GetRecoveredTrapCount());
EXPECT_EQ(1u, GetRecoveredTrapCount());
}
} // namespace trap_handler
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment