| Index: syzygy/instrument/transforms/filler_transform.cc
|
| diff --git a/syzygy/instrument/transforms/filler_transform.cc b/syzygy/instrument/transforms/filler_transform.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..54dd059fa57f1359b02d143fca83899bfb1b366e
|
| --- /dev/null
|
| +++ b/syzygy/instrument/transforms/filler_transform.cc
|
| @@ -0,0 +1,154 @@
|
| +// Copyright 2015 Google Inc. All Rights Reserved.
|
| +//
|
| +// 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.
|
| +
|
| +#include "syzygy/instrument/transforms/filler_transform.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "syzygy/assm/assembler_base.h"
|
| +#include "syzygy/block_graph/basic_block_assembler.h"
|
| +#include "syzygy/block_graph/basic_block_subgraph.h"
|
| +#include "syzygy/block_graph/block_util.h"
|
| +#include "syzygy/block_graph/transform_policy.h"
|
| +
|
| +namespace instrument {
|
| +namespace transforms {
|
| +
|
| +const char FillerBasicBlockTransform::kTransformName[] =
|
| + "FillerBasicBlockTransform";
|
| +
|
| +const char FillerTransform::kTransformName[] = "FillerTransform";
|
| +
|
| +size_t NopInjector::Inject(BasicBlock::Instructions* instructions) const {
|
| + size_t num_injected = 0LL;
|
| + // Since the locations in |nop_spec_| are sorted, we can perform a parallel
|
| + // visit of |nop_spec_| and |instructions| to inject NOPs.
|
| + NopSpec::const_iterator nop_it = nop_spec_.begin();
|
| + BasicBlock::Instructions::iterator inst_it = instructions->begin();
|
| + size_t offset = 0LL;
|
| + while (nop_it != nop_spec_.end() && inst_it != instructions->end()) {
|
| + // Always increase offset. For each offset, either add NOP or proceed to
|
| + // the next instruction.
|
| + if (nop_it->first == offset) {
|
| + block_graph::BasicBlockAssembler assm(inst_it, instructions);
|
| + assm.nop(nop_it->second);
|
| + ++nop_it;
|
| + ++num_injected;
|
| + } else {
|
| + ++inst_it;
|
| + }
|
| + ++offset;
|
| + }
|
| + return num_injected;
|
| +}
|
| +
|
| +bool FillerBasicBlockTransform::TransformBasicBlockSubGraph(
|
| + const TransformPolicyInterface* policy,
|
| + BlockGraph* block_graph,
|
| + BasicBlockSubGraph* basic_block_subgraph) {
|
| + DCHECK(nullptr != policy);
|
| + DCHECK(nullptr != block_graph);
|
| + DCHECK(nullptr != basic_block_subgraph);
|
| +
|
| + // Locations for code injection.
|
| + NopInjector nop_injector({{1, NopInjector::NOP1}});
|
| +
|
| + // Visit each basic code block and inject NOPs.
|
| + BasicBlockSubGraph::BBCollection& basic_blocks =
|
| + basic_block_subgraph->basic_blocks();
|
| + for (auto bb = basic_blocks.begin(); bb != basic_blocks.end(); ++bb) {
|
| + BasicCodeBlock* bc_block = BasicCodeBlock::Cast(*bb);
|
| + if (bc_block != nullptr)
|
| + nop_injector.Inject(&bc_block->instructions());
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +FillerTransform::FillerTransform(const std::vector<std::string>& target_list)
|
| + : basic_block_transform_(new FillerBasicBlockTransform()),
|
| + num_block_(0),
|
| + num_code_block_(0),
|
| + num_target_updated_(0) {
|
| + // Targets are not found yet, so initialize value to false.
|
| + for (const std::string& target : target_list)
|
| + target_names_[target] = false;
|
| +}
|
| +
|
| +bool FillerTransform::ShouldProcessBlock(Block* block) const {
|
| + return target_names_.find(block->name()) != target_names_.end();
|
| +}
|
| +
|
| +void FillerTransform::CheckAllTargetFound() const {
|
| + bool has_missing = false;
|
| + for (auto it = target_names_.begin(); it != target_names_.end(); ++it) {
|
| + if (it->second)
|
| + continue;
|
| + if (!has_missing) {
|
| + LOG(ERROR) << "There are missing target(s):";
|
| + has_missing = true;
|
| + }
|
| + LOG(ERROR) << " " << it->first;
|
| + }
|
| +}
|
| +
|
| +bool FillerTransform::PreBlockGraphIteration(
|
| + const TransformPolicyInterface* policy,
|
| + BlockGraph* block_graph,
|
| + Block* header_block) {
|
| + return true;
|
| +}
|
| +
|
| +bool FillerTransform::OnBlock(const TransformPolicyInterface* policy,
|
| + BlockGraph* block_graph,
|
| + Block* block) {
|
| + DCHECK(nullptr != policy);
|
| + DCHECK(nullptr != block_graph);
|
| + DCHECK(nullptr != block);
|
| +
|
| + ++num_block_;
|
| + if (block->type() != BlockGraph::CODE_BLOCK)
|
| + return true;
|
| +
|
| + ++num_code_block_;
|
| + if (!ShouldProcessBlock(block))
|
| + return true;
|
| +
|
| + // Mark target as found.
|
| + std::string name(block->name());
|
| + auto target_it = target_names_.find(block->name());
|
| + if (target_it != target_names_.end())
|
| + target_it->second = true;
|
| +
|
| + // Skip blocks that aren't eligible for basic-block decomposition.
|
| + if (!policy->BlockIsSafeToBasicBlockDecompose(block))
|
| + return true;
|
| +
|
| + ++num_target_updated_;
|
| + // Apply the basic block transform.
|
| + return ApplyBasicBlockSubGraphTransform(
|
| + basic_block_transform_.get(), policy, block_graph, block, NULL);
|
| +}
|
| +
|
| +bool FillerTransform::PostBlockGraphIteration(
|
| + const TransformPolicyInterface* policy,
|
| + BlockGraph* block_graph,
|
| + Block* header_block) {
|
| + LOG(INFO) << "Found " << num_block_ << " block(s).";
|
| + LOG(INFO) << "Found " << num_code_block_ << " code block(s).";
|
| + LOG(INFO) << "Updated " << num_target_updated_ << " blocks(s).";
|
| + CheckAllTargetFound();
|
| + return true;
|
| +}
|
| +
|
| +} // namespace transforms
|
| +} // namespace instrument
|
|
|