Coverage for /Syzygy/pe/pe_relinker.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
76.5%3104050.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 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/pe/pe_relinker.h"
  16    :  
  17    :  #include "base/file_util.h"
  18    :  #include "syzygy/block_graph/orderers/original_orderer.h"
  19    :  #include "syzygy/core/zstream.h"
  20    :  #include "syzygy/pdb/pdb_byte_stream.h"
  21    :  #include "syzygy/pdb/pdb_file.h"
  22    :  #include "syzygy/pdb/pdb_reader.h"
  23    :  #include "syzygy/pdb/pdb_util.h"
  24    :  #include "syzygy/pdb/pdb_writer.h"
  25    :  #include "syzygy/pe/decomposer.h"
  26    :  #include "syzygy/pe/find.h"
  27    :  #include "syzygy/pe/image_layout_builder.h"
  28    :  #include "syzygy/pe/image_source_map.h"
  29    :  #include "syzygy/pe/metadata.h"
  30    :  #include "syzygy/pe/new_decomposer.h"
  31    :  #include "syzygy/pe/pdb_info.h"
  32    :  #include "syzygy/pe/pe_file_writer.h"
  33    :  #include "syzygy/pe/pe_utils.h"
  34    :  #include "syzygy/pe/serialization.h"
  35    :  #include "syzygy/pe/orderers/pe_orderer.h"
  36    :  #include "syzygy/pe/transforms/add_metadata_transform.h"
  37    :  #include "syzygy/pe/transforms/add_pdb_info_transform.h"
  38    :  #include "syzygy/pe/transforms/prepare_headers_transform.h"
  39    :  
  40    :  namespace pe {
  41    :  
  42    :  namespace {
  43    :  
  44    :  typedef block_graph::BlockGraphTransformInterface Transform;
  45    :  typedef block_graph::BlockGraphOrdererInterface Orderer;
  46    :  
  47    :  using block_graph::ApplyBlockGraphTransform;
  48    :  using block_graph::BlockGraph;
  49    :  using block_graph::OrderedBlockGraph;
  50    :  using core::RelativeAddress;
  51    :  using pdb::NameStreamMap;
  52    :  using pdb::PdbByteStream;
  53    :  using pdb::PdbFile;
  54    :  using pdb::PdbInfoHeader70;
  55    :  using pdb::PdbMutatorInterface;
  56    :  using pdb::PdbStream;
  57    :  using pdb::WritablePdbStream;
  58    :  
  59    :  // A utility class for wrapping a serialization OutStream around a
  60    :  // WritablePdbStream.
  61    :  // TODO(chrisha): We really need to centralize stream/buffer semantics in
  62    :  //     a small set of clean interfaces, and make all input/output/parsing work
  63    :  //     on these interfaces.
  64    :  class PdbOutStream : public core::OutStream {
  65    :   public:
  66  E :    explicit PdbOutStream(WritablePdbStream* pdb_stream)
  67    :        : pdb_stream_(pdb_stream) {
  68  E :      DCHECK(pdb_stream != NULL);
  69  E :    }
  70    :  
  71  E :    virtual ~PdbOutStream() { }
  72    :  
  73  E :    virtual bool Write(size_t length, const core::Byte* bytes) OVERRIDE {
  74  E :      return pdb_stream_->Write(length, bytes);
  75  E :    }
  76    :  
  77    :   private:
  78    :    scoped_refptr<WritablePdbStream> pdb_stream_;
  79    :  };
  80    :  
  81    :  void GetOmapRange(const std::vector<ImageLayout::SectionInfo>& sections,
  82  E :                    RelativeAddressRange* range) {
  83  E :    DCHECK(range != NULL);
  84    :  
  85    :    // There need to be at least two sections, one containing something and the
  86    :    // other containing the relocs.
  87  E :    DCHECK_GT(sections.size(), 1u);
  88  E :    DCHECK_EQ(sections.back().name, std::string(kRelocSectionName));
  89    :  
  90    :    // For some reason, if we output OMAP entries for the headers (before the
  91    :    // first section), everything falls apart. Not outputting these allows the
  92    :    // unittests to pass. Also, we don't want to output OMAP information for
  93    :    // the relocs, as these are entirely different from image to image.
  94  E :    RelativeAddress start_of_image = sections.front().addr;
  95  E :    RelativeAddress end_of_image = sections.back().addr;
  96  E :    *range = RelativeAddressRange(start_of_image, end_of_image - start_of_image);
  97  E :  }
  98    :  
  99    :  // TODO(chrisha): Make this utility function part of orderer.h.
 100    :  bool ApplyOrderer(Orderer* orderer,
 101    :                    OrderedBlockGraph* obg,
 102  E :                    BlockGraph::Block* header_block) {
 103  E :    DCHECK(orderer != NULL);
 104  E :    DCHECK(obg != NULL);
 105  E :    DCHECK(header_block != NULL);
 106    :  
 107  E :    if (!orderer->OrderBlockGraph(obg, header_block)) {
 108  E :      LOG(ERROR) << "Orderer failed: " << orderer->name();
 109  E :      return false;
 110    :    }
 111    :  
 112  E :    return true;
 113  E :  }
 114    :  
 115    :  bool ApplyPdbMutator(PdbMutatorInterface* pdb_mutator,
 116  E :                       PdbFile* pdb_file) {
 117  E :    DCHECK(pdb_mutator != NULL);
 118  E :    DCHECK(pdb_file != NULL);
 119    :  
 120  E :    if (!pdb_mutator->MutatePdb(pdb_file)) {
 121  E :      LOG(ERROR) << "PDB mutator failed: " << pdb_mutator->name();
 122  E :      return false;
 123    :    }
 124    :  
 125  E :    return true;
 126  E :  }
 127    :  
 128    :  // Initializes input_pdb_path, output_pdb_path, pe_file and guid. If the input
 129    :  // paths are unable to be found this will return false. If @p allow_overwrite is
 130    :  // false and output path or output_pdb_path will overwrite an existing file this
 131    :  // will return false. @p input_pdb_path may be left empty in which case it will
 132    :  // be automatically determined from the debug information in @p input_path; this
 133    :  // step may fail causing this to return false. @p output_pdb_path may also be
 134    :  // left empty in which case it will be inferred from input_pdb_path, being
 135    :  // placed alongside output_path.
 136    :  bool InitializePaths(const base::FilePath& input_path,
 137    :                       const base::FilePath& output_path,
 138    :                       bool allow_overwrite,
 139    :                       base::FilePath* input_pdb_path,
 140  E :                       base::FilePath* output_pdb_path) {
 141  E :    DCHECK(input_pdb_path != NULL);
 142  E :    DCHECK(output_pdb_path != NULL);
 143    :  
 144    :    // At a very minimum we have to specify input and outputs.
 145  E :    if (input_path.empty() || output_path.empty()) {
 146  E :      LOG(ERROR) << "input_path and output_path must be set!";
 147  E :      return false;
 148    :    }
 149    :  
 150  E :    if (!file_util::PathExists(input_path)) {
 151  E :      LOG(ERROR) << "Input module not found: " << input_path.value();
 152  E :      return false;
 153    :    }
 154    :  
 155    :    // No input PDB specified? Find it automagically.
 156  E :    if (input_pdb_path->empty()) {
 157  E :      LOG(INFO) << "Input PDB not specified, searching for it.";
 158    :      if (!FindPdbForModule(input_path, input_pdb_path) ||
 159  E :          input_pdb_path->empty()) {
 160  i :        LOG(ERROR) << "Unable to find PDB file for module: "
 161    :                   << input_path.value();
 162  i :        return false;
 163    :      }
 164    :    }
 165    :  
 166  E :    if (!file_util::PathExists(*input_pdb_path)) {
 167  i :      LOG(ERROR) << "Input PDB not found: " << input_pdb_path->value();
 168  i :      return false;
 169    :    }
 170    :  
 171    :    // If no output PDB path is specified, infer one.
 172  E :    if (output_pdb_path->empty()) {
 173    :      // If the input and output DLLs have the same basename, default to writing
 174    :      // using the same PDB basename, but alongside the new module.
 175  E :      if (input_path.BaseName() == output_path.BaseName()) {
 176    :        *output_pdb_path = output_path.DirName().Append(
 177  E :            input_pdb_path->BaseName());
 178  E :      } else {
 179    :        // Otherwise, default to using the output basename with a PDB extension.
 180  i :        *output_pdb_path = output_path.ReplaceExtension(L"pdb");
 181    :      }
 182    :  
 183  E :      LOG(INFO) << "Using default output PDB path: " << output_pdb_path->value();
 184    :    }
 185    :  
 186    :    // Ensure we aren't about to overwrite anything we don't want to. We do this
 187    :    // early on so that we abort before decomposition, transformation, etc.
 188  E :    if (!allow_overwrite) {
 189  E :      bool terminate = false;
 190  E :      if (file_util::PathExists(output_path)) {
 191  E :        terminate = true;
 192  E :        LOG(ERROR) << "Output module path already exists.";
 193    :      }
 194  E :      if (file_util::PathExists(*output_pdb_path)) {
 195  i :        terminate = true;
 196  i :        LOG(ERROR) << "Output PDB path already exists.";
 197    :      }
 198  E :      if (terminate)
 199  E :        return false;
 200    :    }
 201    :  
 202  E :    return true;
 203  E :  }
 204    :  
 205    :  // Decomposes the module enclosed by the given PE file.
 206    :  bool Decompose(bool use_new_decomposer,
 207    :                 bool parse_debug_info,
 208    :                 const PEFile& pe_file,
 209    :                 const base::FilePath& pdb_path,
 210    :                 ImageLayout* image_layout,
 211  E :                 BlockGraph::Block** dos_header_block) {
 212  E :    DCHECK(image_layout != NULL);
 213  E :    DCHECK(dos_header_block != NULL);
 214    :  
 215  E :    LOG(INFO) << "Decomposing module: " << pe_file.path().value();
 216    :  
 217  E :    BlockGraph* block_graph = image_layout->blocks.graph();
 218  E :    ImageLayout orig_image_layout(block_graph);
 219    :  
 220    :    // Decompose the input image.
 221  E :    if (use_new_decomposer) {
 222  E :      LOG(INFO) << "Using new decomposer for decomposition.";
 223  E :      if (!parse_debug_info)
 224  E :        LOG(INFO) << "Not parsing debug information.";
 225  E :      NewDecomposer decomposer(pe_file);
 226  E :      decomposer.set_pdb_path(pdb_path);
 227  E :      decomposer.set_parse_debug_info(parse_debug_info);
 228  E :      if (!decomposer.Decompose(&orig_image_layout)) {
 229  i :        LOG(ERROR) << "Unable to decompose module: " << pe_file.path().value();
 230  i :        return false;
 231    :      }
 232  E :    } else {
 233  E :      Decomposer decomposer(pe_file);
 234  E :      decomposer.set_pdb_path(pdb_path);
 235  E :      if (!decomposer.Decompose(&orig_image_layout)) {
 236  i :        LOG(ERROR) << "Unable to decompose module: " << pe_file.path().value();
 237  i :        return false;
 238    :      }
 239  E :    }
 240    :  
 241    :    // Make a copy of the image layout without padding. We don't want to carry
 242    :    // the padding through the toolchain.
 243  E :    LOG(INFO) << "Removing padding blocks.";
 244  E :    if (!pe::CopyImageLayoutWithoutPadding(orig_image_layout, image_layout)) {
 245  i :      LOG(ERROR) << "Failed to remove padding blocks.";
 246  i :      return false;
 247    :    }
 248    :  
 249    :    // Get the DOS header block.
 250    :    *dos_header_block =
 251    :        image_layout->blocks.GetBlockByAddress(
 252  E :            BlockGraph::RelativeAddress(0));
 253  E :    if (*dos_header_block == NULL) {
 254  i :      LOG(ERROR) << "Unable to find the DOS header block.";
 255  i :      return false;
 256    :    }
 257    :  
 258  E :    return true;
 259  E :  }
 260    :  
 261    :  bool ApplyTransforms(const base::FilePath& input_path,
 262    :                       const base::FilePath& output_pdb_path,
 263    :                       const GUID& guid,
 264    :                       bool add_metadata,
 265    :                       std::vector<Transform*>* transforms,
 266    :                       BlockGraph* block_graph,
 267  E :                       BlockGraph::Block* dos_header_block) {
 268  E :    DCHECK(transforms != NULL);
 269  E :    DCHECK(block_graph != NULL);
 270  E :    DCHECK(dos_header_block != NULL);
 271    :  
 272  E :    LOG(INFO) << "Transforming block graph.";
 273    :  
 274  E :    std::vector<Transform*> local_transforms(*transforms);
 275    :  
 276  E :    pe::transforms::AddMetadataTransform add_metadata_tx(input_path);
 277  E :    pe::transforms::AddPdbInfoTransform add_pdb_info_tx(output_pdb_path, 1, guid);
 278  E :    pe::transforms::PrepareHeadersTransform prep_headers_tx;
 279    :  
 280    :    // We first run the sequence of user requested transforms.
 281    :  
 282    :    // If we've been requested to we add metadata to the image.
 283  E :    if (add_metadata)
 284  E :      local_transforms.push_back(&add_metadata_tx);
 285    :  
 286    :    // Update the PDB information to point to the correct PDB file.
 287  E :    local_transforms.push_back(&add_pdb_info_tx);
 288    :  
 289    :    // Finally, run the prepare headers transform. This ensures that the header
 290    :    // block is properly sized to receive layout information post-ordering.
 291  E :    local_transforms.push_back(&prep_headers_tx);
 292    :  
 293    :    // Apply the transforms.
 294  E :    for (size_t i = 0; i < local_transforms.size(); ++i) {
 295  E :      LOG(INFO) << "Applying transform: " << local_transforms[i]->name() << ".";
 296    :      // ApplyBlockGraphTransform takes care of verbosely logging any failures.
 297    :      if (!ApplyBlockGraphTransform(local_transforms[i],
 298    :                                    block_graph,
 299  E :                                    dos_header_block)) {
 300  E :        return false;
 301    :      }
 302  E :    }
 303    :  
 304  E :    return true;
 305  E :  }
 306    :  
 307    :  bool ApplyOrderers(std::vector<Orderer*>* orderers,
 308    :                     OrderedBlockGraph* obg,
 309  E :                     BlockGraph::Block* dos_header_block) {
 310  E :    DCHECK(orderers != NULL);
 311  E :    DCHECK(obg != NULL);
 312  E :    DCHECK(dos_header_block != NULL);
 313    :  
 314  E :    LOG(INFO) << "Ordering block graph.";
 315    :  
 316  E :    std::vector<Orderer*> local_orderers(*orderers);
 317    :  
 318  E :    block_graph::orderers::OriginalOrderer orig_orderer;
 319  E :    pe::orderers::PEOrderer pe_orderer;
 320    :  
 321  E :    if (local_orderers.size() == 0) {
 322  E :      LOG(INFO) << "No orderers specified, using original orderer.";
 323  E :      local_orderers.push_back(&orig_orderer);
 324    :    }
 325    :  
 326  E :    local_orderers.push_back(&pe_orderer);
 327    :  
 328    :    // Apply the orderers.
 329  E :    for (size_t i = 0; i < local_orderers.size(); ++i) {
 330  E :      LOG(INFO) << "Applying orderer: " << local_orderers[i]->name();
 331  E :      if (!ApplyOrderer(local_orderers[i], obg, dos_header_block))
 332  E :        return false;
 333  E :    }
 334    :  
 335  E :    return true;
 336  E :  }
 337    :  
 338    :  bool ApplyPdbMutators(const std::vector<PdbMutatorInterface*>& pdb_mutators,
 339  E :                        PdbFile* pdb_file) {
 340  E :    DCHECK(pdb_file != NULL);
 341    :  
 342  E :    LOG(INFO) << "Mutating PDB.";
 343    :  
 344    :    // Apply the orderers.
 345  E :    for (size_t i = 0; i < pdb_mutators.size(); ++i) {
 346  E :      LOG(INFO) << "Applying PDB mutator: " << pdb_mutators[i]->name();
 347  E :      if (!ApplyPdbMutator(pdb_mutators[i], pdb_file))
 348  E :        return false;
 349  E :    }
 350    :  
 351  E :    return true;
 352  E :  }
 353    :  
 354    :  // Lays out the image.
 355    :  bool BuildImageLayout(size_t padding,
 356    :                        const OrderedBlockGraph& ordered_block_graph,
 357    :                        BlockGraph::Block* dos_header_block,
 358  E :                        ImageLayout* image_layout) {
 359  E :    DCHECK(dos_header_block != NULL);
 360  E :    DCHECK(image_layout != NULL);
 361    :  
 362  E :    LOG(INFO) << "Building image layout.";
 363    :  
 364  E :    ImageLayoutBuilder builder(image_layout);
 365  E :    builder.set_padding(padding);
 366  E :    if (!builder.LayoutImageHeaders(dos_header_block)) {
 367  i :      LOG(ERROR) << "ImageLayoutBuilder::LayoutImageHeaders failed.";
 368  i :      return false;
 369    :    }
 370    :  
 371  E :    if (!builder.LayoutOrderedBlockGraph(ordered_block_graph)) {
 372  i :      LOG(ERROR) << "ImageLayoutBuilder::LayoutOrderedBlockGraph failed.";
 373  i :      return false;
 374    :    }
 375    :  
 376  E :    LOG(INFO) << "Finalizing image layout.";
 377  E :    if (!builder.Finalize()) {
 378  i :      LOG(ERROR) << "ImageLayoutBuilder::Finalize failed.";
 379  i :      return false;
 380    :    }
 381    :  
 382  E :    return true;
 383  E :  }
 384    :  
 385    :  // Writes the image.
 386    :  bool WriteImage(const ImageLayout& image_layout,
 387  E :                  const base::FilePath& output_path) {
 388  E :    PEFileWriter writer(image_layout);
 389    :  
 390  E :    LOG(INFO) << "Writing image: " << output_path.value();
 391  E :    if (!writer.WriteImage(output_path)) {
 392  i :      LOG(ERROR) << "Failed to write image \"" << output_path.value() << "\".";
 393  i :      return false;
 394    :    }
 395    :  
 396  E :    return true;
 397  E :  }
 398    :  
 399    :  void BuildOmapVectors(const RelativeAddressRange& input_range,
 400    :                        const ImageLayout& output_image_layout,
 401    :                        std::vector<OMAP>* omap_to,
 402  E :                        std::vector<OMAP>* omap_from) {
 403  E :    DCHECK(omap_to != NULL);
 404  E :    DCHECK(omap_from != NULL);
 405    :  
 406  E :    LOG(INFO) << "Building OMAP vectors.";
 407    :  
 408    :    // Get the range of the output image, sans headers. This is required for
 409    :    // generating OMAP information.
 410  E :    RelativeAddressRange output_range;
 411  E :    GetOmapRange(output_image_layout.sections, &output_range);
 412    :  
 413  E :    ImageSourceMap reverse_map;
 414  E :    BuildImageSourceMap(output_image_layout, &reverse_map);
 415    :  
 416  E :    ImageSourceMap forward_map;
 417  E :    if (reverse_map.ComputeInverse(&forward_map) != 0) {
 418  E :      LOG(WARNING) << "OMAPFROM not unique (there exist repeated source ranges).";
 419    :    }
 420    :  
 421    :    // Build the two OMAP vectors.
 422  E :    BuildOmapVectorFromImageSourceMap(output_range, reverse_map, omap_to);
 423  E :    BuildOmapVectorFromImageSourceMap(input_range, forward_map, omap_from);
 424  E :  }
 425    :  
 426    :  // Updates the OMAP and GUID info in the given PDB file.
 427    :  bool SetOmapAndGuid(const RelativeAddressRange input_range,
 428    :                      const ImageLayout& image_layout,
 429    :                      const GUID& guid,
 430  E :                      PdbFile* pdb_file) {
 431  E :    DCHECK(pdb_file != NULL);
 432    :  
 433  E :    LOG(INFO) << "Updating OMAP and GUID information.";
 434    :  
 435  E :    std::vector<OMAP> omap_to, omap_from;
 436  E :    BuildOmapVectors(input_range, image_layout, &omap_to, &omap_from);
 437    :  
 438  E :    if (!pdb::SetGuid(guid, pdb_file)) {
 439  i :      LOG(ERROR) << "Unable to set PDB GUID.";
 440  i :      return false;
 441    :    }
 442    :  
 443  E :    if (!pdb::SetOmapToStream(omap_to, pdb_file)) {
 444  i :      LOG(ERROR) << "Unable to set OMAP_TO.";
 445  i :      return false;
 446    :    }
 447    :  
 448  E :    if (!pdb::SetOmapFromStream(omap_from, pdb_file)) {
 449  i :      LOG(ERROR) << "Unable to set OMAP_FROM.";
 450  i :      return false;
 451    :    }
 452    :  
 453  E :    return true;
 454  E :  }
 455    :  
 456    :  bool WritePdbFile(const base::FilePath& output_pdb_path,
 457  E :                    const PdbFile& pdb_file) {
 458  E :    LOG(INFO) << "Writing PDB file: " << output_pdb_path.value();
 459    :  
 460  E :    base::FilePath temp_pdb;
 461    :    if (!file_util::CreateTemporaryFileInDir(output_pdb_path.DirName(),
 462  E :                                             &temp_pdb)) {
 463  i :      LOG(ERROR) << "Unable to create temporary PDB file.";
 464  i :      return false;
 465    :    }
 466    :  
 467  E :    pdb::PdbWriter pdb_writer;
 468  E :    if (!pdb_writer.Write(temp_pdb, pdb_file)) {
 469  i :      LOG(ERROR) << "Failed to write temporary PDB file to \""
 470    :                 << temp_pdb.value() << "\".";
 471    :    }
 472    :  
 473  E :    if (!file_util::ReplaceFile(temp_pdb, output_pdb_path)) {
 474  i :      LOG(ERROR) << "Unable to move temporary PDB file to \""
 475    :          << output_pdb_path.value() << "\".";
 476  i :      file_util::Delete(temp_pdb, false);
 477  i :      return false;
 478    :    }
 479    :  
 480  E :    return true;
 481  E :  }
 482    :  
 483    :  // Get a specific named stream if it already exists, otherwise create one.
 484    :  // @param stream_name The name of the stream.
 485    :  // @param name_stream_map The map containing the names of the streams in the
 486    :  //     PDB. If the stream doesn't already exist the map will be augmented with
 487    :  //     another entry.
 488    :  // @param pdb_file The PDB file to which the stream will be added.
 489    :  // @param replace_stream If true, will cause a new stream to be created even if
 490    :  //     another one already existed.
 491    :  // @return a pointer to the PDB stream on success, NULL on failure.
 492    :  PdbStream* GetOrCreatePdbStreamByName(const char* stream_name,
 493    :                                        bool replace_stream,
 494    :                                        NameStreamMap* name_stream_map,
 495  E :                                        PdbFile* pdb_file) {
 496  E :    DCHECK(name_stream_map != NULL);
 497  E :    DCHECK(pdb_file != NULL);
 498  E :    scoped_refptr<PdbStream> stream;
 499    :  
 500  E :    NameStreamMap::const_iterator name_it = name_stream_map->find(stream_name);
 501  E :    if (name_it != name_stream_map->end()) {
 502    :      // Replace the existing stream by a brand-new one if it's required.
 503  i :      if (replace_stream) {
 504  i :        stream = new PdbByteStream();
 505  i :        pdb_file->ReplaceStream(name_it->second, stream.get());
 506  i :      } else {
 507  i :        if (!pdb::EnsureStreamWritable(name_it->second, pdb_file)) {
 508  i :          LOG(ERROR) << "Failed to make " << stream_name << " stream writable.";
 509  i :          return NULL;
 510    :        }
 511  i :        stream = pdb_file->GetStream(name_it->second);
 512    :      }
 513  i :    } else {
 514  E :      stream = new PdbByteStream();
 515  E :      uint32 index = pdb_file->AppendStream(stream.get());
 516  E :      (*name_stream_map)[stream_name] = index;
 517    :    }
 518    :  
 519  E :    return stream.get();
 520  E :  }
 521    :  
 522    :  // This updates or creates the Syzygy history stream, appending the metadata
 523    :  // describing this module and transform. The history stream consists of
 524    :  // a named PDB stream with the name /Syzygy/History. It consists of:
 525    :  //
 526    :  //   uint32 version
 527    :  //   uint32 history_length
 528    :  //   serialized pe::Metadata 0
 529    :  //   ...
 530    :  //   serialized pe::Metadata history_length - 1
 531    :  //
 532    :  // If the format is changed, be sure to update this documentation and
 533    :  // pdb::kSyzygyHistoryStreamVersion (in pdb_constants.h).
 534    :  bool WriteSyzygyHistoryStream(const base::FilePath& input_path,
 535    :                                NameStreamMap* name_stream_map,
 536  E :                                PdbFile* pdb_file) {
 537    :    // Get the history stream.
 538    :    scoped_refptr<PdbStream> history_reader =
 539    :        GetOrCreatePdbStreamByName(pdb::kSyzygyHistoryStreamName,
 540    :                                   false,
 541    :                                   name_stream_map,
 542  E :                                   pdb_file);
 543    :  
 544  E :    if (history_reader == NULL) {
 545  i :      LOG(ERROR) << "Failed to get the history stream.";
 546  i :      return false;
 547    :    }
 548    :  
 549    :    scoped_refptr<WritablePdbStream> history_writer =
 550  E :        history_reader->GetWritablePdbStream();
 551  E :    DCHECK(history_writer.get() != NULL);
 552    :  
 553    :    // Get the metadata.
 554  E :    Metadata metadata;
 555  E :    PEFile pe_file;
 556  E :    if (!pe_file.Init(input_path)) {
 557  i :      LOG(ERROR) << "Failed to initialize PE file for \"" << input_path.value()
 558    :                 << "\".";
 559  i :      return false;
 560    :    }
 561    :  
 562  E :    PEFile::Signature pe_sig;
 563  E :    pe_file.GetSignature(&pe_sig);
 564  E :    if (!metadata.Init(pe_sig)) {
 565  i :      LOG(ERROR) << "Failed to initialize metadata for \"" << input_path.value()
 566    :                 << "\".";
 567  i :      return false;
 568    :    }
 569    :  
 570    :    // Validate the history stream if it is non-empty.
 571  E :    if (history_reader->length() > 0) {
 572    :      // Read the header.
 573  i :      uint32 version = 0;
 574  i :      uint32 history_length = 0;
 575    :      if (!history_reader->Seek(0) ||
 576    :          !history_reader->Read(&version, 1) ||
 577  i :          !history_reader->Read(&history_length, 1)) {
 578  i :        LOG(ERROR) << "Failed to read existing Syzygy history stream header.";
 579  i :        return false;
 580    :      }
 581    :  
 582    :      // Check the version.
 583  i :      if (version != pdb::kSyzygyHistoryStreamVersion) {
 584  i :        LOG(ERROR) << "PDB contains unsupported Syzygy history stream version "
 585    :                   << "(got " << version << ", expected "
 586    :                   << pdb::kSyzygyHistoryStreamVersion << ").";
 587  i :        return false;
 588    :      }
 589    :  
 590    :      // Increment the history length and rewrite it.
 591  i :      history_length++;
 592  i :      history_writer->set_pos(sizeof(pdb::kSyzygyHistoryStreamVersion));
 593  i :      if (!history_writer->Write(history_length)) {
 594  i :        LOG(ERROR) << "Failed to write new Syzygy history stream length.";
 595  i :        return false;
 596    :      }
 597  i :    } else {
 598    :      // If there wasn't already a history stream, create one and write the
 599    :      // header.
 600  E :      DCHECK_EQ(0u, history_writer->pos());
 601  E :      const uint32 kHistoryLength = 1;
 602    :      if (!history_writer->Write(pdb::kSyzygyHistoryStreamVersion) ||
 603  E :          !history_writer->Write(kHistoryLength)) {
 604  i :        LOG(ERROR) << "Failed to write Syzygy history stream header.";
 605  i :        return false;
 606    :      }
 607    :    }
 608    :  
 609    :    // Append the metadata to the history.
 610  E :    history_writer->set_pos(history_writer->length());
 611  E :    PdbOutStream out_stream(history_writer.get());
 612  E :    core::OutArchive out_archive(&out_stream);
 613  E :    if (!out_archive.Save(metadata)) {
 614  i :      LOG(ERROR) << "Failed to write metadata to Syzygy history stream.";
 615  i :      return false;
 616    :    }
 617    :  
 618  E :    return true;
 619  E :  }
 620    :  
 621    :  // This writes the serialized block-graph and the image layout in a PDB stream
 622    :  // named /Syzygy/BlockGraph. If the format is changed, be sure to update this
 623    :  // documentation and pdb::kSyzygyBlockGraphStreamVersion (in pdb_constants.h).
 624    :  // The block graph stream will not include the data from the blocks of the
 625    :  // block-graph. If the strip-strings flag is set to true the strings contained
 626    :  // in the block-graph won't be saved.
 627    :  bool WriteSyzygyBlockGraphStream(const PEFile& pe_file,
 628    :                                   const ImageLayout& image_layout,
 629    :                                   bool strip_strings,
 630    :                                   bool compress,
 631    :                                   NameStreamMap* name_stream_map,
 632  E :                                   PdbFile* pdb_file) {
 633    :    // Get the redecomposition data stream.
 634    :    scoped_refptr<PdbStream> block_graph_reader =
 635    :        GetOrCreatePdbStreamByName(pdb::kSyzygyBlockGraphStreamName,
 636    :                                   true,
 637    :                                   name_stream_map,
 638  E :                                   pdb_file);
 639    :  
 640  E :    if (block_graph_reader == NULL) {
 641  i :      LOG(ERROR) << "Failed to get the block-graph stream.";
 642  i :      return false;
 643    :    }
 644  E :    DCHECK_EQ(0u, block_graph_reader->length());
 645    :  
 646    :    scoped_refptr<WritablePdbStream> block_graph_writer =
 647  E :        block_graph_reader->GetWritablePdbStream();
 648  E :    DCHECK(block_graph_writer.get() != NULL);
 649    :  
 650    :    // Write the version of the BlockGraph stream, and whether or not its
 651    :    // contents are compressed.
 652    :    if (!block_graph_writer->Write(pdb::kSyzygyBlockGraphStreamVersion) ||
 653  E :        !block_graph_writer->Write(static_cast<unsigned char>(compress))) {
 654  i :      LOG(ERROR) << "Failed to write Syzygy BlockGraph stream header.";
 655  i :      return false;
 656    :    }
 657    :  
 658    :    // Set up the output stream.
 659  E :    PdbOutStream pdb_out_stream(block_graph_writer.get());
 660  E :    core::OutStream* out_stream = &pdb_out_stream;
 661    :  
 662    :    // If requested, compress the output.
 663  E :    scoped_ptr<core::ZOutStream> zip_stream;
 664  E :    if (compress) {
 665  E :      zip_stream.reset(new core::ZOutStream(&pdb_out_stream));
 666  E :      out_stream = zip_stream.get();
 667  E :      if (!zip_stream->Init(core::ZOutStream::kZBestCompression)) {
 668  i :        LOG(ERROR) << "Failed to initialize zlib compressor.";
 669  i :        return false;
 670    :      }
 671    :    }
 672    :  
 673  E :    core::OutArchive out_archive(out_stream);
 674    :  
 675    :    // Set up the serialization properties.
 676  E :    block_graph::BlockGraphSerializer::Attributes attributes = 0;
 677  E :    if (strip_strings)
 678  E :      attributes |= block_graph::BlockGraphSerializer::OMIT_STRINGS;
 679    :  
 680    :    // And finally, perform the serialization.
 681    :    if (!SaveBlockGraphAndImageLayout(pe_file, attributes, image_layout,
 682  E :                                      &out_archive)) {
 683  i :      LOG(ERROR) << "SaveBlockGraphAndImageLayout failed.";
 684  i :      return false;
 685    :    }
 686    :  
 687    :    // We have to flush the stream in case it's a zstream.
 688  E :    out_stream->Flush();
 689    :  
 690  E :    return true;
 691  E :  }
 692    :  
 693    :  }  // namespace
 694    :  
 695    :  PERelinker::PERelinker()
 696    :      : add_metadata_(true), allow_overwrite_(false), augment_pdb_(true),
 697    :        compress_pdb_(false), parse_debug_info_(true), strip_strings_(false),
 698    :        use_new_decomposer_(false), padding_(0), inited_(false),
 699    :        input_image_layout_(&block_graph_), dos_header_block_(NULL),
 700  E :        output_guid_(GUID_NULL) {
 701  E :  }
 702    :  
 703  E :  void PERelinker::AppendTransform(Transform* transform) {
 704  E :    DCHECK(transform != NULL);
 705  E :    transforms_.push_back(transform);
 706  E :  }
 707    :  
 708  E :  void PERelinker::AppendTransforms(const std::vector<Transform*>& transforms) {
 709  E :    transforms_.insert(transforms_.end(), transforms.begin(), transforms.end());
 710  E :  }
 711    :  
 712  E :  void PERelinker::AppendOrderer(Orderer* orderer) {
 713  E :    DCHECK(orderer != NULL);
 714  E :    orderers_.push_back(orderer);
 715  E :  }
 716    :  
 717  E :  void PERelinker::AppendOrderers(const std::vector<Orderer*>& orderers) {
 718  E :    orderers_.insert(orderers_.end(), orderers.begin(), orderers.end());
 719  E :  }
 720    :  
 721  E :  void PERelinker::AppendPdbMutator(PdbMutatorInterface* pdb_mutator) {
 722  E :    DCHECK(pdb_mutator != NULL);
 723  E :    pdb_mutators_.push_back(pdb_mutator);
 724  E :  }
 725    :  
 726    :  void PERelinker::AppendPdbMutators(
 727  E :      const std::vector<PdbMutatorInterface*>& pdb_mutators) {
 728    :    pdb_mutators_.insert(pdb_mutators_.end(),
 729    :                         pdb_mutators.begin(),
 730  E :                         pdb_mutators.end());
 731  E :  }
 732    :  
 733  E :  bool PERelinker::Init() {
 734  E :    DCHECK(inited_ == false);
 735    :  
 736    :    // Initialize the paths.
 737    :    if (!InitializePaths(input_path_, output_path_, allow_overwrite_,
 738  E :                         &input_pdb_path_, &output_pdb_path_)) {
 739  E :      return false;
 740    :    }
 741    :  
 742  E :    LOG(INFO) << "Input module : " << input_path_.value();
 743  E :    LOG(INFO) << "Input PDB    : " << input_pdb_path_.value();
 744  E :    LOG(INFO) << "Output module: " << output_path_.value();
 745  E :    LOG(INFO) << "Output PDB   : " << output_pdb_path_.value();
 746    :  
 747    :    // Open the input PE file.
 748  E :    if (!input_pe_file_.Init(input_path_)) {
 749  i :      LOG(ERROR) << "Unable to load \"" << input_path_.value() << "\".";
 750  i :      return false;
 751    :    }
 752    :  
 753    :    // Generate a GUID for the relinked image's PDB file.
 754  E :    if (FAILED(::CoCreateGuid(&output_guid_))) {
 755  i :      LOG(ERROR) << "Failed to create new PDB GUID.";
 756  i :      return false;
 757    :    }
 758    :  
 759    :    // Decompose the image.
 760    :    if (!Decompose(use_new_decomposer_, parse_debug_info_,
 761    :                   input_pe_file_, input_pdb_path_,
 762  E :                   &input_image_layout_, &dos_header_block_)) {
 763  i :      return false;
 764    :    }
 765    :  
 766  E :    inited_ = true;
 767    :  
 768  E :    return true;
 769  E :  }
 770    :  
 771  E :  bool PERelinker::Relink() {
 772  E :    if (!inited_) {
 773  i :      LOG(ERROR) << "Init has not been successfully called.";
 774  i :      return false;
 775    :    }
 776    :  
 777    :    // Transform it.
 778    :    if (!ApplyTransforms(input_path_, output_pdb_path_, output_guid_,
 779    :                         add_metadata_, &transforms_, &block_graph_,
 780  E :                         dos_header_block_)) {
 781  E :      return false;
 782    :    }
 783    :  
 784    :    // Order it.
 785  E :    OrderedBlockGraph ordered_block_graph(&block_graph_);
 786  E :    if (!ApplyOrderers(&orderers_, &ordered_block_graph, dos_header_block_))
 787  E :      return false;
 788    :  
 789    :    // Lay it out.
 790  E :    ImageLayout output_image_layout(&block_graph_);
 791    :    if (!BuildImageLayout(padding_, ordered_block_graph, dos_header_block_,
 792  E :                          &output_image_layout)) {
 793  i :      return false;
 794    :    }
 795    :  
 796    :    // Write the image.
 797  E :    if (!WriteImage(output_image_layout, output_path_))
 798  i :      return false;
 799    :  
 800    :    // From here on down we are processing the PDB file.
 801    :  
 802    :    // Read the PDB file.
 803  E :    LOG(INFO) << "Reading PDB file: " << input_pdb_path_.value();
 804  E :    pdb::PdbReader pdb_reader;
 805  E :    PdbFile pdb_file;
 806  E :    if (!pdb_reader.Read(input_pdb_path_, &pdb_file)) {
 807  i :      LOG(ERROR) << "Unable to read PDB file: " << input_pdb_path_.value();
 808  i :      return false;
 809    :    }
 810    :  
 811    :    // Apply the mutators to the PDB file.
 812  E :    if (!ApplyPdbMutators(pdb_mutators_, &pdb_file))
 813  E :      return false;
 814    :  
 815    :    // TODO(chrisha): Make the following 3 PDB updates PdbMutatorInterface
 816    :    //     implementations.
 817    :  
 818    :    // Update the OMAP and GUID information.
 819  E :    RelativeAddressRange input_range;
 820  E :    GetOmapRange(input_image_layout_.sections, &input_range);
 821    :    if (!SetOmapAndGuid(input_range, output_image_layout, output_guid_,
 822  E :                        &pdb_file)) {
 823  i :      return false;
 824    :    }
 825    :  
 826    :    // Parse the header and named streams.
 827  E :    pdb::PdbInfoHeader70 header = {};
 828  E :    pdb::NameStreamMap name_stream_map;
 829  E :    if (!pdb::ReadHeaderInfoStream(pdb_file, &header, &name_stream_map))
 830  i :      return false;
 831    :  
 832    :    // Update/create the Syzygy history stream.
 833  E :    if (!WriteSyzygyHistoryStream(input_path_, &name_stream_map, &pdb_file))
 834  i :      return false;
 835    :  
 836    :    // Add redecomposition data in another stream, only if augment_pdb_ is set.
 837  E :    if (augment_pdb_) {
 838  E :      LOG(INFO) << "The block-graph stream is being written to the PDB.";
 839    :  
 840  E :      PEFile new_pe_file;
 841  E :      if (!new_pe_file.Init(output_path_)) {
 842  i :        LOG(ERROR) << "Failed to read newly written PE file.";
 843  i :        return false;
 844    :      }
 845    :  
 846    :      if (!WriteSyzygyBlockGraphStream(new_pe_file,
 847    :                                       output_image_layout,
 848    :                                       strip_strings_,
 849    :                                       compress_pdb_,
 850    :                                       &name_stream_map,
 851  E :                                       &pdb_file)) {
 852  i :        return false;
 853    :      }
 854  E :    }
 855    :  
 856    :    // Write the updated name-stream map back to the header info stream.
 857  E :    if (!pdb::WriteHeaderInfoStream(header, name_stream_map, &pdb_file))
 858  i :      return false;
 859    :  
 860    :    // Stream 0 contains a copy of the previous PDB's directory. This, combined
 861    :    // with copy-on-write semantics of individual blocks makes the file contain
 862    :    // its whole edit history. Since we're writing a 'new' PDB file (we reset the
 863    :    // GUID and age), we have no history so can safely throw away this stream.
 864  E :    pdb_file.ReplaceStream(0, NULL);
 865    :  
 866    :    // Write the PDB file. We use a helper function that first writes it to a
 867    :    // temporary file and then moves it, enabling overwrites.
 868  E :    if (!WritePdbFile(output_pdb_path_, pdb_file))
 869  i :      return false;
 870    :  
 871  E :    return true;
 872  E :  }
 873    :  
 874    :  }  // namespace pe

Coverage information generated Thu Jul 04 09:34:53 2013.