diff options
author | Michael Bebenita <mbebenita@gmail.com> | 2017-04-29 13:17:31 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2017-04-29 13:17:31 -0700 |
commit | 5bd7b2869f9ec664fd3e8746c1d469a04566a548 (patch) | |
tree | 23b99e4e6b0677f1dec004a24b07996d09ad9e06 /src/passes/InstrumentMemory.cpp | |
parent | a88d9b83a4629f4bf4c3b210b07d11d2396c594d (diff) | |
download | binaryen-5bd7b2869f9ec664fd3e8746c1d469a04566a548.tar.gz binaryen-5bd7b2869f9ec664fd3e8746c1d469a04566a548.tar.bz2 binaryen-5bd7b2869f9ec664fd3e8746c1d469a04566a548.zip |
Add pass to instrument loads / stores. (#959)
* Add pass to instrument loads / stores
* Simplify instrumentation.
* Document.
Diffstat (limited to 'src/passes/InstrumentMemory.cpp')
-rw-r--r-- | src/passes/InstrumentMemory.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp new file mode 100644 index 000000000..536031064 --- /dev/null +++ b/src/passes/InstrumentMemory.cpp @@ -0,0 +1,123 @@ +/* + * 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 <wasm.h> +#include <wasm-builder.h> +#include <pass.h> +#include "shared-constants.h" +#include "asmjs/shared-constants.h" +#include "asm_v_wasm.h" + +namespace wasm { + +Name load("load"); +Name store("store"); + +struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> { + 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<Index> 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 |