Chromium Code Reviews| 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..9c076db0bf2ca325f046180d1856cf3d35bf097c |
| --- /dev/null |
| +++ b/syzygy/instrument/transforms/filler_transform.cc |
| @@ -0,0 +1,166 @@ |
| +// 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"; |
| + |
| +// static |
| +void FillerBasicBlockTransform::InjectNop( |
| + const NopSpec& nop_spec, |
| + bool debug_friendly, |
| + BasicBlock::Instructions* instructions) { |
| + BasicBlock::Instructions::iterator inst_it = instructions->begin(); |
| + NopSpec::const_iterator nop_it = nop_spec.begin(); |
| + size_t write_index = 0LL; |
| + while (inst_it != instructions->end() && nop_it != nop_spec.end()) { |
| + if (nop_it->first == write_index) { |
| + block_graph::BasicBlockAssembler assm(inst_it, instructions); |
| + // If specified, set source range for successive NOPs to to be that of the |
| + // current instruction (which follows the NOPs). Caveat: This breaks the |
| + // 1:1 OMAP mapping and may confuse some debuggers. |
| + if (debug_friendly) { |
| + assm.set_source_range(inst_it->source_range()); |
| + auto source_range = inst_it->source_range(); |
|
chrisha
2015/06/10 18:07:27
What is this needed for?
huangs
2015/06/11 14:54:15
Removed.
|
| + } |
| + // Add all NOPs with consecutive instruction indexes. |
| + while (nop_it != nop_spec.end() && nop_it->first == write_index) { |
| + assm.nop(nop_it->second); |
| + ++nop_it; |
| + ++write_index; |
| + } |
| + } |
| + ++inst_it; |
| + ++write_index; |
| + } |
| +} |
| + |
| +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. |
| + NopSpec nop_spec = {{1, NOP1}}; |
|
chrisha
2015/06/10 18:07:27
Is this going to be sufficient? Do we maybe want t
huangs
2015/06/11 14:54:15
We want to start small; will do randomness later.
|
| + |
| + fprintf(stderr, "TransformBasicBlockSubGraph: %s\n", |
| + debug_friendly_ ? "true" : "false"); |
|
chrisha
2015/06/10 18:07:27
Debugging code?
huangs
2015/06/11 14:54:15
Removed.
|
| + |
| + // 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) |
| + InjectNop(nop_spec, debug_friendly_, &bc_block->instructions()); |
| + } |
| + return true; |
| +} |
| + |
| +FillerTransform::FillerTransform(const std::vector<std::string>& target_list) |
| + : debug_friendly_(false), |
| + num_blocks_(0), |
| + num_code_blocks_(0), |
| + num_targets_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(WARNING) << "There are missing target(s):"; |
| + has_missing = true; |
| + } |
| + LOG(WARNING) << " " << 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_blocks_; |
| + if (block->type() != BlockGraph::CODE_BLOCK) |
| + return true; |
| + |
| + ++num_code_blocks_; |
| + 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_targets_updated_; |
| + // Apply the basic block transform. |
| + FillerBasicBlockTransform basic_block_transform; |
| + basic_block_transform.set_debug_friendly(debug_friendly()); |
| + return ApplyBasicBlockSubGraphTransform( |
| + &basic_block_transform, policy, block_graph, block, NULL); |
| +} |
| + |
| +bool FillerTransform::PostBlockGraphIteration( |
| + const TransformPolicyInterface* policy, |
| + BlockGraph* block_graph, |
| + Block* header_block) { |
| + LOG(INFO) << "Found " << num_blocks_ << " block(s)."; |
| + LOG(INFO) << "Found " << num_code_blocks_ << " code block(s)."; |
| + LOG(INFO) << "Updated " << num_targets_updated_ << " blocks(s)."; |
| + CheckAllTargetFound(); |
| + return true; |
| +} |
| + |
| +} // namespace transforms |
| +} // namespace instrument |