Coverage for /Syzygy/relink/relink_app.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
84.5%82970.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc.
   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/relink/relink_app.h"
  16    :  
  17    :  #include "base/logging_win.h"
  18    :  #include "base/string_number_conversions.h"
  19    :  #include "syzygy/block_graph/orderers/random_orderer.h"
  20    :  #include "syzygy/pe/pe_relinker.h"
  21    :  #include "syzygy/pe/transforms/explode_basic_blocks_transform.h"
  22    :  #include "syzygy/reorder/orderers/explicit_orderer.h"
  23    :  
  24    :  namespace relink {
  25    :  
  26    :  namespace {
  27    :  
  28    :  const char kUsageFormatStr[] =
  29    :      "Usage: %ls [options]\n"
  30    :      "  Required Options:\n"
  31    :      "    --input-dll=<path>   The input DLL to relink.\n"
  32    :      "    --output-dll=<path>  Output path for the rewritten DLL.\n"
  33    :      "  Optional Options:\n"
  34    :      "    --basic-blocks       Reorder at the basic-block level. At present,\n"
  35    :      "                         this is only supported for random reorderings.\n"
  36    :      "    --compress-pdb       If --no-augment-pdb is specified, causes the\n"
  37    :      "                         augmented PDB stream to be compressed.\n"
  38    :      "    --exclude-bb-padding When randomly reordering basic blocks, exclude\n"
  39    :      "                         padding and unreachable code from the relinked\n"
  40    :      "                         output binary.\n"
  41    :      "    --input-pdb=<path>   The PDB file associated with the input DLL.\n"
  42    :      "                         Default is inferred from input-dll.\n"
  43    :      "    --no-augment-pdb     Indicates that the relinker should not augment\n"
  44    :      "                         the PDB with roundtrip decomposition info.\n"
  45    :      "    --no-metadata        Prevents the relinker from adding metadata\n"
  46    :      "                         to the output DLL.\n"
  47    :      "    --no-strip-strings   Causes strings to be output in the augmented\n"
  48    :      "                         PDB stream. The default is to omit these to\n"
  49    :      "                         make smaller PDBs.\n"
  50    :      "    --order-file=<path>  Reorder based on a JSON ordering file.\n"
  51    :      "    --output-pdb=<path>  Output path for the rewritten PDB file.\n"
  52    :      "                         Default is inferred from output-dll.\n"
  53    :      "    --overwrite          Allow output files to be overwritten.\n"
  54    :      "    --padding=<integer>  Add bytes of padding between blocks.\n"
  55    :      "    --seed=<integer>     Randomly reorder based on the given seed.\n"
  56    :      "  Notes:\n"
  57    :      "    * The --seed and --order-file options are mutually exclusive\n"
  58    :      "    * If --order-file is specified, --input-dll is optional.\n"
  59    :      "    * The --compress-pdb and --no-strip-strings options are only\n"
  60    :      "      effective if --no-augment-pdb is not specified.\n"
  61    :      "    * The --exclude-bb-padding option is only effective if\n"
  62    :      "      --basic-blocks is specified.\n";
  63    :  
  64  E :  bool ParsePadding(const std::wstring& value_str, size_t* out_value) {
  65  E :    DCHECK(out_value != NULL);
  66    :  
  67    :    int temp;
  68  E :    if (!base::StringToInt(value_str, &temp) || temp < 0) {
  69  i :      return false;
  70    :    }
  71    :  
  72  E :    *out_value = static_cast<size_t>(temp);
  73  E :    return true;
  74  E :  }
  75    :  
  76  E :  bool ParseUInt32(const std::wstring& value_str, uint32* out_value) {
  77  E :    DCHECK(out_value != NULL);
  78  E :    return base::StringToInt(value_str, reinterpret_cast<int*>(out_value));
  79  E :  }
  80    :  
  81    :  void GuessPdbPath(const FilePath& module_path, FilePath* pdb_path) {
  82    :    DCHECK(pdb_path != NULL);
  83    :    *pdb_path = module_path.ReplaceExtension(L"pdb");
  84    :  }
  85    :  
  86    :  }  // namespace
  87    :  
  88  E :  bool RelinkApp::ParseCommandLine(const CommandLine* cmd_line) {
  89  E :    input_dll_path_ = AbsolutePath(cmd_line->GetSwitchValuePath("input-dll"));
  90  E :    input_pdb_path_ = AbsolutePath(cmd_line->GetSwitchValuePath("input-pdb"));
  91  E :    output_dll_path_ = cmd_line->GetSwitchValuePath("output-dll");
  92  E :    output_pdb_path_ = cmd_line->GetSwitchValuePath("output-pdb");
  93  E :    order_file_path_ = AbsolutePath(cmd_line->GetSwitchValuePath("order-file"));
  94  E :    no_augment_pdb_ = cmd_line->HasSwitch("no-augment-pdb");
  95  E :    compress_pdb_ = cmd_line->HasSwitch("compress-pdb");
  96  E :    no_strip_strings_ = cmd_line->HasSwitch("no-strip-strings");
  97  E :    output_metadata_ = !cmd_line->HasSwitch("no-metadata");
  98  E :    overwrite_ = cmd_line->HasSwitch("overwrite");
  99  E :    basic_blocks_ = cmd_line->HasSwitch("basic-blocks");
 100  E :    exclude_bb_padding_ = cmd_line->HasSwitch("exclude-bb-padding");
 101    :  
 102    :    // The --output-dll argument is required.
 103  E :    if (output_dll_path_.empty()) {
 104  E :      return Usage(cmd_line, "You must specify --output-dll.");
 105    :    }
 106    :  
 107    :    // Ensure that we have an input-dll, either explicity specified, or to be
 108    :    // taken from an order file.
 109  E :    if (input_dll_path_.empty() && order_file_path_.empty()) {
 110    :      return Usage(
 111    :          cmd_line,
 112  E :          "You must specify --input-dll if --order-file is not given.");
 113    :    }
 114    :  
 115    :    // Parse the random seed, if given. Note that the --seed and --order-file
 116    :    // arguments are mutually exclusive.
 117  E :    if (cmd_line->HasSwitch("seed")) {
 118  E :      if (cmd_line->HasSwitch("order-file")) {
 119    :        return Usage(cmd_line,
 120  i :                     "The seed and order-file arguments are mutually exclusive");
 121    :      }
 122  E :      std::wstring seed_str(cmd_line->GetSwitchValueNative("seed"));
 123  E :      if (!ParseUInt32(seed_str, &seed_))
 124  i :        return Usage(cmd_line, "Invalid seed value.");
 125  E :    }
 126    :  
 127    :    // Parse the padding argument.
 128  E :    if (cmd_line->HasSwitch("padding")) {
 129  E :      std::wstring padding_str(cmd_line->GetSwitchValueNative("padding"));
 130  E :      if (!ParsePadding(padding_str, &padding_))
 131  i :        return Usage(cmd_line, "Invalid padding value.");
 132  E :    }
 133    :  
 134  E :    return true;
 135  E :  }
 136    :  
 137  E :  bool RelinkApp::SetUp() {
 138  E :    if (input_dll_path_.empty()) {
 139  E :      DCHECK(!order_file_path_.empty());
 140    :      if (!reorder::Reorderer::Order::GetOriginalModulePath(order_file_path_,
 141  E :                                                            &input_dll_path_)) {
 142  E :        LOG(ERROR) << "Unable to infer input-dll.";
 143  E :        return false;
 144    :      }
 145    :  
 146  i :      LOG(INFO) << "Inferring input DLL path from order file: "
 147    :                << input_dll_path_.value();
 148    :    }
 149    :  
 150  E :    DCHECK(!input_dll_path_.empty());
 151  E :    DCHECK(!output_dll_path_.empty());
 152  E :    DCHECK(order_file_path_.empty() || seed_ == 0);
 153    :  
 154  E :    return true;
 155  E :  }
 156    :  
 157  E :  int RelinkApp::Run() {
 158  E :    pe::PERelinker relinker;
 159  E :    relinker.set_input_path(input_dll_path_);
 160  E :    relinker.set_input_pdb_path(input_pdb_path_);
 161  E :    relinker.set_output_path(output_dll_path_);
 162  E :    relinker.set_output_pdb_path(output_pdb_path_);
 163  E :    relinker.set_padding(padding_);
 164  E :    relinker.set_add_metadata(output_metadata_);
 165  E :    relinker.set_allow_overwrite(overwrite_);
 166  E :    relinker.set_augment_pdb(!no_augment_pdb_);
 167  E :    relinker.set_compress_pdb(compress_pdb_);
 168  E :    relinker.set_strip_strings(!no_strip_strings_);
 169    :  
 170    :    // Initialize the relinker. This does the decomposition, etc.
 171  E :    if (!relinker.Init()) {
 172  i :      LOG(ERROR) << "Failed to initialize relinker.";
 173  i :      return 1;
 174    :    }
 175    :  
 176    :    // Set up the orderer.
 177  E :    scoped_ptr<pe::transforms::ExplodeBasicBlocksTransform> bb_explode;
 178  E :    scoped_ptr<block_graph::BlockGraphOrdererInterface> orderer;
 179  E :    scoped_ptr<reorder::Reorderer::Order> order;
 180  E :    if (!order_file_path_.empty()) {
 181  i :      order.reset(new reorder::Reorderer::Order());
 182    :      if (!order->LoadFromJSON(relinker.input_pe_file(),
 183    :                               relinker.input_image_layout(),
 184  i :                               order_file_path_)) {
 185  i :        LOG(ERROR) << "Failed to load order file: " << order_file_path_.value();
 186  i :        return 1;
 187    :      }
 188    :  
 189  i :      orderer.reset(new reorder::orderers::ExplicitOrderer(order.get()));
 190  i :    } else {
 191  E :      orderer.reset(new block_graph::orderers::RandomOrderer(true, seed_));
 192  E :      if (basic_blocks_) {
 193  E :        bb_explode.reset(new pe::transforms::ExplodeBasicBlocksTransform());
 194  E :        bb_explode->set_exclude_padding(exclude_bb_padding_);
 195  E :        relinker.AppendTransform(bb_explode.get());
 196    :      }
 197    :    }
 198    :  
 199    :    // Append the orderer to the relinker.
 200  E :    relinker.AppendOrderer(orderer.get());
 201    :  
 202    :    // Perform the actual relink.
 203  E :    if (!relinker.Relink()) {
 204  i :      LOG(ERROR) << "Unable to relink input image.";
 205  i :      return 1;
 206    :    }
 207    :  
 208  E :    return 0;
 209  E :  }
 210    :  
 211    :  bool RelinkApp::Usage(const CommandLine* cmd_line,
 212  E :                        const base::StringPiece& message) const {
 213  E :    if (!message.empty()) {
 214  E :      ::fwrite(message.data(), 1, message.length(), err());
 215  E :      ::fprintf(err(), "\n\n");
 216    :    }
 217    :  
 218    :    ::fprintf(err(),
 219    :              kUsageFormatStr,
 220  E :              cmd_line->GetProgram().BaseName().value().c_str());
 221    :  
 222  E :    return false;
 223  E :  }
 224    :  
 225    :  }  // namespace relink

Coverage information generated Thu Sep 06 11:30:46 2012.