Coverage for /Syzygy/optimize/optimize_app.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
72.5%741020.C++source

Line-by-line coverage:

   1    :  // Copyright 2013 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/optimize/optimize_app.h"
  16    :  
  17    :  #include "syzygy/block_graph/block_graph.h"
  18    :  #include "syzygy/block_graph/transforms/fuzzing_transform.h"
  19    :  #include "syzygy/block_graph/transforms/named_transform.h"
  20    :  #include "syzygy/common/indexed_frequency_data.h"
  21    :  #include "syzygy/grinder/basic_block_util.h"
  22    :  #include "syzygy/optimize/application_profile.h"
  23    :  #include "syzygy/optimize/transforms/basic_block_reordering_transform.h"
  24    :  #include "syzygy/optimize/transforms/block_alignment_transform.h"
  25    :  #include "syzygy/optimize/transforms/chained_subgraph_transforms.h"
  26    :  #include "syzygy/optimize/transforms/inlining_transform.h"
  27    :  #include "syzygy/optimize/transforms/peephole_transform.h"
  28    :  #include "syzygy/optimize/transforms/unreachable_block_transform.h"
  29    :  #include "syzygy/pe/pe_relinker.h"
  30    :  #include "syzygy/pe/pe_transform_policy.h"
  31    :  
  32    :  namespace optimize {
  33    :  
  34    :  namespace {
  35    :  
  36    :  using block_graph::transforms::FuzzingTransform;
  37    :  using common::IndexedFrequencyData;
  38    :  using grinder::basic_block_util::IndexedFrequencyMap;
  39    :  using grinder::basic_block_util::LoadBranchStatisticsFromFile;
  40    :  using optimize::transforms::BasicBlockReorderingTransform;
  41    :  using optimize::transforms::BlockAlignmentTransform;
  42    :  using optimize::transforms::ChainedSubgraphTransforms;
  43    :  using optimize::transforms::InliningTransform;
  44    :  using optimize::transforms::PeepholeTransform;
  45    :  using optimize::transforms::UnreachableBlockTransform;
  46    :  
  47    :  const char kUsageFormatStr[] =
  48    :      "Usage: %ls [options]\n"
  49    :      "  Required Options:\n"
  50    :      "    --input-image=<path>  The input image file to optimize.\n"
  51    :      "    --output-image=<path> Output path for the rewritten image file.\n"
  52    :      "\n"
  53    :      "  Options:\n"
  54    :      "    --branch-file=<path>  Branch statistics in JSON format.\n"
  55    :      "    --input-pdb=<path>    The PDB file associated with the input DLL.\n"
  56    :      "                          Default is inferred from input-image.\n"
  57    :      "    --output-pdb=<path>   Output path for the rewritten PDB file.\n"
  58    :      "                          Default is inferred from output-image.\n"
  59    :      "    --overwrite           Allow output files to be overwritten.\n"
  60    :      "\n"
  61    :      "  Optimization Options:\n"
  62    :      "    --all                 Enable all optimizations.\n"
  63    :      "    --allow-inline-assembly\n"
  64    :      "                          Enable the decomposition of inline assembly\n"
  65    :      "                          blocks.\n"
  66    :      "    --basic-block-reorder Enable basic block reodering.\n"
  67    :      "    --block-alignment     Enable block realignment.\n"
  68    :      "    --inlining            Enable function inlining.\n"
  69    :      "    --peephole            Enable peephole optimization.\n"
  70    :      "    --unreachable-block   Enable unreachable block optimization.\n"
  71    :      "\n"
  72    :      "  Unreachable block options:\n"
  73    :      "    --dump-unreachable-graph=<path>\n"
  74    :      "                          Dump the unreachable graph.\n"
  75    :      "\n"
  76    :      "  Testing Options:\n"
  77    :      "    --fuzz                Fuzz the binary.\n"
  78    :      "\n";
  79    :  
  80    :  }  // namespace
  81    :  
  82  E :  bool OptimizeApp::ParseCommandLine(const CommandLine* cmd_line) {
  83    :  
  84  E :    if (cmd_line->HasSwitch("help"))
  85  E :       return Usage(cmd_line, "");
  86    :  
  87  E :    input_image_path_ = AbsolutePath(cmd_line->GetSwitchValuePath("input-image"));
  88  E :    output_image_path_ = cmd_line->GetSwitchValuePath("output-image");
  89  E :    input_pdb_path_ = AbsolutePath(cmd_line->GetSwitchValuePath("input-pdb"));
  90  E :    output_pdb_path_ = cmd_line->GetSwitchValuePath("output-pdb");
  91  E :    branch_file_path_ = AbsolutePath(cmd_line->GetSwitchValuePath("branch-file"));
  92    :  
  93  E :    basic_block_reorder_ = cmd_line->HasSwitch("basic-block-reorder");
  94  E :    block_alignment_ = cmd_line->HasSwitch("block-alignment");
  95  E :    fuzz_ = cmd_line->HasSwitch("fuzz");
  96  E :    inlining_ = cmd_line->HasSwitch("inlining");
  97  E :    allow_inline_assembly_ = cmd_line->HasSwitch("allow-inline-assembly");
  98  E :    peephole_ = cmd_line->HasSwitch("peephole");
  99  E :    unreachable_block_ = cmd_line->HasSwitch("unreachable-block");
 100  E :    overwrite_ = cmd_line->HasSwitch("overwrite");
 101    :  
 102    :    // Enable all optimization transforms.
 103  E :    if (cmd_line->HasSwitch("all")) {
 104  E :      basic_block_reorder_ = true;
 105  E :      block_alignment_ = true;
 106  E :      inlining_ = true;
 107  E :      peephole_ = true;
 108  E :      unreachable_block_ = true;
 109    :    }
 110    :  
 111    :    unreachable_graph_path_ =
 112  E :        AbsolutePath(cmd_line->GetSwitchValuePath("dump-unreachable-graph"));
 113    :  
 114    :    // The --input-image argument is required.
 115  E :    if (input_image_path_.empty())
 116  E :      return Usage(cmd_line, "You must specify --input-image.");
 117    :  
 118    :    // The --output-image argument is required.
 119  E :    if (output_image_path_.empty())
 120  E :      return Usage(cmd_line, "You must specify --output-image.");
 121    :  
 122  E :    return true;
 123  E :  }
 124    :  
 125  E :  bool OptimizeApp::SetUp() {
 126  E :    DCHECK(!input_image_path_.empty());
 127  E :    DCHECK(!output_image_path_.empty());
 128  E :    return true;
 129  E :  }
 130    :  
 131  E :  int OptimizeApp::Run() {
 132  E :    pe::PETransformPolicy policy;
 133  E :    policy.set_allow_inline_assembly(allow_inline_assembly_);
 134  E :    pe::PERelinker relinker(&policy);
 135  E :    relinker.set_input_path(input_image_path_);
 136  E :    relinker.set_input_pdb_path(input_pdb_path_);
 137  E :    relinker.set_output_path(output_image_path_);
 138  E :    relinker.set_output_pdb_path(output_pdb_path_);
 139  E :    relinker.set_allow_overwrite(overwrite_);
 140    :  
 141    :    // Initialize the relinker. This does the decomposition, etc.
 142  E :    if (!relinker.Init()) {
 143  i :      LOG(ERROR) << "Failed to initialize relinker.";
 144  i :      return 1;
 145    :    }
 146    :  
 147    :    // Get module signature and layout.
 148  E :    pe::PEFile::Signature signature;
 149  E :    relinker.input_pe_file().GetSignature(&signature);
 150  E :    const pe::ImageLayout& image_layout = relinker.input_image_layout();
 151    :  
 152    :    // Load profile information from file.
 153  E :    ApplicationProfile profile(&image_layout);
 154  E :    if (!branch_file_path_.empty()) {
 155  i :      IndexedFrequencyMap frequencies;
 156    :      if (!LoadBranchStatisticsFromFile(branch_file_path_,
 157    :                                        signature,
 158  i :                                        &frequencies)) {
 159  i :        LOG(ERROR) << "Unable to load profile information.";
 160  i :        return 1;
 161    :      }
 162  i :      if (!profile.ImportFrequencies(frequencies)) {
 163  i :        LOG(ERROR) << "Could not import metrics for '"
 164    :                   << branch_file_path_.value() << "'.";
 165  i :        return false;
 166    :      }
 167  i :    }
 168    :  
 169    :    // Compute global profile information for the current block graph.
 170  E :    if (!profile.ComputeGlobalProfile()) {
 171  i :      LOG(ERROR) << "Unable to build profile information.";
 172  i :      return 1;
 173    :    }
 174    :  
 175    :    // Construct a chain of basic block transforms.
 176  E :    ChainedSubgraphTransforms chains(&profile);
 177    :  
 178    :    // Declare transforms we may apply.
 179  E :    scoped_ptr<BasicBlockReorderingTransform> basic_block_reordering_transform;
 180  E :    scoped_ptr<BlockAlignmentTransform> block_alignment_transform;
 181  E :    scoped_ptr<FuzzingTransform> fuzzing_transform;
 182  E :    scoped_ptr<InliningTransform> inlining_transform;
 183  E :    scoped_ptr<PeepholeTransform> peephole_transform;
 184  E :    scoped_ptr<UnreachableBlockTransform> unreachable_block_transform;
 185    :  
 186    :    // If block block reordering is enabled, add it to the chain.
 187  E :    if (peephole_) {
 188  i :      peephole_transform.reset(new PeepholeTransform());
 189  i :      chains.AppendTransform(peephole_transform.get());
 190    :    }
 191    :  
 192    :    // If inlining is enabled, add it to the chain.
 193  E :    if (inlining_) {
 194  i :      inlining_transform.reset(new InliningTransform());
 195  i :      chains.AppendTransform(inlining_transform.get());
 196    :    }
 197    :  
 198    :    // If block block reordering is enabled, add it to the chain.
 199  E :    if (basic_block_reorder_) {
 200  i :      basic_block_reordering_transform.reset(new BasicBlockReorderingTransform());
 201  i :      chains.AppendTransform(basic_block_reordering_transform.get());
 202    :    }
 203    :  
 204    :    // If block alignment is enabled, add it to the chain.
 205  E :    if (block_alignment_) {
 206  i :      block_alignment_transform.reset(new BlockAlignmentTransform());
 207  i :      chains.AppendTransform(block_alignment_transform.get());
 208    :    }
 209    :  
 210    :    // Append the chain to the relinker.
 211  E :    if (!relinker.AppendTransform(&chains))
 212  i :      return false;
 213    :  
 214    :    // If unreachable-block is enabled, add it to the relinker.
 215  E :    if (unreachable_block_) {
 216  i :      unreachable_block_transform.reset(new UnreachableBlockTransform());
 217    :      unreachable_block_transform->set_unreachable_graph_path(
 218  i :          unreachable_graph_path_);
 219  i :      relinker.AppendTransform(unreachable_block_transform.get());
 220    :    }
 221    :  
 222    :    // If fuzzing is enabled, add it to the relinker.
 223  E :    if (fuzz_) {
 224  i :      fuzzing_transform.reset(new block_graph::transforms::FuzzingTransform);
 225  i :      relinker.AppendTransform(fuzzing_transform.get());
 226    :    }
 227    :  
 228    :    // Perform the actual relink.
 229  E :    if (!relinker.Relink()) {
 230  i :      LOG(ERROR) << "Unable to relink input image.";
 231  i :      return 1;
 232    :    }
 233    :  
 234  E :    return 0;
 235  E :  }
 236    :  
 237    :  bool OptimizeApp::Usage(const CommandLine* cmd_line,
 238  E :                          const base::StringPiece& message) const {
 239  E :    if (!message.empty()) {
 240  E :      ::fwrite(message.data(), 1, message.length(), err());
 241  E :      ::fprintf(err(), "\n\n");
 242    :    }
 243    :  
 244    :    ::fprintf(err(),
 245    :              kUsageFormatStr,
 246  E :              cmd_line->GetProgram().BaseName().value().c_str());
 247    :  
 248  E :    return false;
 249  E :  }
 250    :  
 251    :  }  // namespace optimize

Coverage information generated Thu Mar 26 16:15:41 2015.