/* * Copyright 2017 WebAssembly Community Group participants * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Instruments the build with code to intercept all memory reads and writes. // This can be useful in building tools that analyze memory access behaviour. // // The instrumentation is performed by calling an FFI with an ID for each // memory access site. Load / store IDs share the same index space. The // instrumentation wraps the evaluation of the address operand, therefore // it executes before the load / store is executed. Note that Instrumentation // code must return tha address argument. // // Loads: load(id, bytes, offset, address) => address // // Before: // (i32.load8_s align=1 offset=2 (i32.const 3)) // // After: // (i32.load8_s align=1 offset=2 // (call $load // (i32.const n) // ID // (i32.const 1) // bytes // (i32.const 2) // offset // (i32.const 3) // address // ) // ) // // Stores: store(id, bytes, offset, address) => address // // Before: // (i32.store8 align=1 offset=2 (i32.const 3) (i32.const 4)) // // After: // (i32.store16 align=1 offset=2 // (call $store // (i32.const n) // ID // (i32.const 1) // bytes // (i32.const 2) // offset // (i32.const 3) // address // ) // (i32.const 4) // ) #include #include #include #include "shared-constants.h" #include "asmjs/shared-constants.h" #include "asm_v_wasm.h" namespace wasm { Name load("load"); Name store("store"); // TODO: Add support for atomicRMW/cmpxchg struct InstrumentMemory : public WalkerPass> { void visitLoad(Load* curr) { makeLoadCall(curr); } void visitStore(Store* curr) { makeStoreCall(curr); } void addImport(Module *curr, Name name, std::string sig) { auto import = new Import; import->name = name; import->module = INSTRUMENT; import->base = name; import->functionType = ensureFunctionType(sig, curr)->name; import->kind = ExternalKind::Function; curr->addImport(import); } void visitModule(Module *curr) { addImport(curr, load, "iiiii"); addImport(curr, store, "iiiii"); } private: std::atomic id; Expression* makeLoadCall(Load* curr) { Builder builder(*getModule()); curr->ptr = builder.makeCallImport(load, { builder.makeConst(Literal(int32_t(id.fetch_add(1)))), builder.makeConst(Literal(int32_t(curr->bytes))), builder.makeConst(Literal(int32_t(curr->offset.addr))), curr->ptr}, i32 ); return curr; } Expression* makeStoreCall(Store* curr) { Builder builder(*getModule()); curr->ptr = builder.makeCallImport(store, { builder.makeConst(Literal(int32_t(id.fetch_add(1)))), builder.makeConst(Literal(int32_t(curr->bytes))), builder.makeConst(Literal(int32_t(curr->offset.addr))), curr->ptr }, i32 ); return curr; } }; Pass *createInstrumentMemoryPass() { return new InstrumentMemory(); } } // namespace wasm