Coverage for /Syzygy/pe/pe_relinker_util.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
71.4%1872620.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/pe/pe_relinker_util.h"
  16    :  
  17    :  #include "base/files/file_util.h"
  18    :  #include "syzygy/block_graph/transform.h"
  19    :  #include "syzygy/core/file_util.h"
  20    :  #include "syzygy/core/zstream.h"
  21    :  #include "syzygy/pdb/pdb_byte_stream.h"
  22    :  #include "syzygy/pdb/pdb_util.h"
  23    :  #include "syzygy/pe/find.h"
  24    :  #include "syzygy/pe/metadata.h"
  25    :  #include "syzygy/pe/pe_image_layout_builder.h"
  26    :  #include "syzygy/pe/pe_utils.h"
  27    :  #include "syzygy/pe/serialization.h"
  28    :  #include "syzygy/pe/orderers/pe_orderer.h"
  29    :  #include "syzygy/pe/transforms/add_metadata_transform.h"
  30    :  #include "syzygy/pe/transforms/add_pdb_info_transform.h"
  31    :  #include "syzygy/pe/transforms/pe_prepare_headers_transform.h"
  32    :  #include "syzygy/pe/transforms/pe_remove_empty_sections_transform.h"
  33    :  
  34    :  namespace pe {
  35    :  
  36    :  namespace {
  37    :  
  38    :  using block_graph::BlockGraph;
  39    :  using block_graph::BlockGraphTransformInterface;
  40    :  using block_graph::OrderedBlockGraph;
  41    :  using core::RelativeAddress;
  42    :  using pdb::NameStreamMap;
  43    :  using pdb::PdbByteStream;
  44    :  using pdb::PdbFile;
  45    :  using pdb::PdbInfoHeader70;
  46    :  using pdb::PdbStream;
  47    :  using pdb::WritablePdbStream;
  48    :  using pe::PETransformPolicy;
  49    :  
  50    :  // A utility class for wrapping a serialization OutStream around a
  51    :  // WritablePdbStream.
  52    :  // TODO(chrisha): We really need to centralize stream/buffer semantics in
  53    :  //     a small set of clean interfaces, and make all input/output/parsing work
  54    :  //     on these interfaces.
  55    :  class PdbOutStream : public core::OutStream {
  56    :   public:
  57  E :    explicit PdbOutStream(WritablePdbStream* pdb_stream)
  58  E :        : pdb_stream_(pdb_stream) {
  59  E :      DCHECK(pdb_stream != NULL);
  60  E :    }
  61    :  
  62  E :    virtual ~PdbOutStream() { }
  63    :  
  64  E :    bool Write(size_t length, const core::Byte* bytes) override {
  65  E :      return pdb_stream_->Write(length, bytes);
  66  E :    }
  67    :  
  68    :   private:
  69    :    scoped_refptr<WritablePdbStream> pdb_stream_;
  70    :  };
  71    :  
  72    :  void BuildOmapVectors(const RelativeAddressRange& input_range,
  73    :                        const ImageLayout& output_image_layout,
  74    :                        std::vector<OMAP>* omap_to,
  75  E :                        std::vector<OMAP>* omap_from) {
  76  E :    DCHECK(omap_to != NULL);
  77  E :    DCHECK(omap_from != NULL);
  78    :  
  79  E :    LOG(INFO) << "Building OMAP vectors.";
  80    :  
  81    :    // Get the range of the output image, sans headers. This is required for
  82    :    // generating OMAP information.
  83  E :    RelativeAddressRange output_range;
  84  E :    GetOmapRange(output_image_layout.sections, &output_range);
  85    :  
  86  E :    ImageSourceMap reverse_map;
  87  E :    BuildImageSourceMap(output_image_layout, &reverse_map);
  88    :  
  89  E :    ImageSourceMap forward_map;
  90  E :    if (reverse_map.ComputeInverse(&forward_map) != 0) {
  91  E :      LOG(WARNING) << "OMAPFROM not unique (there exist repeated source ranges).";
  92    :    }
  93    :  
  94    :    // Build the two OMAP vectors.
  95  E :    BuildOmapVectorFromImageSourceMap(output_range, reverse_map, omap_to);
  96  E :    BuildOmapVectorFromImageSourceMap(input_range, forward_map, omap_from);
  97  E :  }
  98    :  
  99    :  // Get a specific named stream if it already exists, otherwise create one.
 100    :  // @param stream_name The name of the stream.
 101    :  // @param name_stream_map The map containing the names of the streams in the
 102    :  //     PDB. If the stream doesn't already exist the map will be augmented with
 103    :  //     another entry.
 104    :  // @param pdb_file The PDB file to which the stream will be added.
 105    :  // @param replace_stream If true, will cause a new stream to be created even if
 106    :  //     another one already existed.
 107    :  // @return a pointer to the PDB stream on success, NULL on failure.
 108    :  PdbStream* GetOrCreatePdbStreamByName(const char* stream_name,
 109    :                                        bool replace_stream,
 110    :                                        NameStreamMap* name_stream_map,
 111  E :                                        PdbFile* pdb_file) {
 112  E :    DCHECK(name_stream_map != NULL);
 113  E :    DCHECK(pdb_file != NULL);
 114  E :    scoped_refptr<PdbStream> stream;
 115    :  
 116  E :    NameStreamMap::const_iterator name_it = name_stream_map->find(stream_name);
 117  E :    if (name_it != name_stream_map->end()) {
 118    :      // Replace the existing stream by a brand-new one if it's required.
 119  i :      if (replace_stream) {
 120  i :        stream = new PdbByteStream();
 121  i :        pdb_file->ReplaceStream(name_it->second, stream.get());
 122  i :      } else {
 123  i :        if (!pdb::EnsureStreamWritable(name_it->second, pdb_file)) {
 124  i :          LOG(ERROR) << "Failed to make " << stream_name << " stream writable.";
 125  i :          return NULL;
 126    :        }
 127  i :        stream = pdb_file->GetStream(name_it->second);
 128    :      }
 129  i :    } else {
 130  E :      stream = new PdbByteStream();
 131    :      uint32_t index = static_cast<uint32_t>(
 132  E :          pdb_file->AppendStream(stream.get()));
 133  E :      (*name_stream_map)[stream_name] = index;
 134    :    }
 135    :  
 136  E :    return stream.get();
 137  E :  }
 138    :  
 139    :  // This updates or creates the Syzygy history stream, appending the metadata
 140    :  // describing this module and transform. The history stream consists of
 141    :  // a named PDB stream with the name /Syzygy/History. It consists of:
 142    :  //
 143    :  //   uint32_t version
 144    :  //   uint32_t history_length
 145    :  //   serialized pe::Metadata 0
 146    :  //   ...
 147    :  //   serialized pe::Metadata history_length - 1
 148    :  //
 149    :  // If the format is changed, be sure to update this documentation and
 150    :  // pdb::kSyzygyHistoryStreamVersion (in pdb_constants.h).
 151    :  bool WriteSyzygyHistoryStream(const base::FilePath& input_path,
 152    :                                NameStreamMap* name_stream_map,
 153  E :                                PdbFile* pdb_file) {
 154    :    // Get the history stream.
 155    :    scoped_refptr<PdbStream> history_reader =
 156  E :        GetOrCreatePdbStreamByName(pdb::kSyzygyHistoryStreamName,
 157    :                                   false,
 158    :                                   name_stream_map,
 159    :                                   pdb_file);
 160    :  
 161  E :    if (history_reader.get() == nullptr) {
 162  i :      LOG(ERROR) << "Failed to get the history stream.";
 163  i :      return false;
 164    :    }
 165    :  
 166    :    scoped_refptr<WritablePdbStream> history_writer =
 167  E :        history_reader->GetWritableStream();
 168  E :    DCHECK(history_writer.get() != nullptr);
 169    :  
 170    :    // Get the metadata.
 171  E :    Metadata metadata;
 172  E :    PEFile pe_file;
 173  E :    if (!pe_file.Init(input_path)) {
 174  i :      LOG(ERROR) << "Failed to initialize PE file for \"" << input_path.value()
 175    :                 << "\".";
 176  i :      return false;
 177    :    }
 178    :  
 179  E :    PEFile::Signature pe_sig;
 180  E :    pe_file.GetSignature(&pe_sig);
 181  E :    if (!metadata.Init(pe_sig)) {
 182  i :      LOG(ERROR) << "Failed to initialize metadata for \"" << input_path.value()
 183    :                 << "\".";
 184  i :      return false;
 185    :    }
 186    :  
 187    :    // Validate the history stream if it is non-empty.
 188  E :    if (history_reader->length() > 0) {
 189    :      // Read the header.
 190  i :      uint32_t version = 0;
 191  i :      uint32_t history_length = 0;
 192  i :      if (!history_reader->ReadBytesAt(0, sizeof(version), &version) ||
 193    :          !history_reader->ReadBytesAt(sizeof(version), sizeof(history_length),
 194    :                                       &history_length)) {
 195  i :        LOG(ERROR) << "Failed to read existing Syzygy history stream header.";
 196  i :        return false;
 197    :      }
 198    :  
 199    :      // Check the version.
 200  i :      if (version != pdb::kSyzygyHistoryStreamVersion) {
 201  i :        LOG(ERROR) << "PDB contains unsupported Syzygy history stream version "
 202    :                   << "(got " << version << ", expected "
 203    :                   << pdb::kSyzygyHistoryStreamVersion << ").";
 204  i :        return false;
 205    :      }
 206    :  
 207    :      // Increment the history length and rewrite it.
 208  i :      history_length++;
 209  i :      history_writer->set_pos(sizeof(pdb::kSyzygyHistoryStreamVersion));
 210  i :      if (!history_writer->Write(history_length)) {
 211  i :        LOG(ERROR) << "Failed to write new Syzygy history stream length.";
 212  i :        return false;
 213    :      }
 214  i :    } else {
 215    :      // If there wasn't already a history stream, create one and write the
 216    :      // header.
 217  E :      DCHECK_EQ(0u, history_writer->pos());
 218  E :      const uint32_t kHistoryLength = 1;
 219  E :      if (!history_writer->Write(pdb::kSyzygyHistoryStreamVersion) ||
 220    :          !history_writer->Write(kHistoryLength)) {
 221  i :        LOG(ERROR) << "Failed to write Syzygy history stream header.";
 222  i :        return false;
 223    :      }
 224    :    }
 225    :  
 226    :    // Append the metadata to the history.
 227  E :    history_writer->set_pos(history_writer->length());
 228  E :    PdbOutStream out_stream(history_writer.get());
 229  E :    core::OutArchive out_archive(&out_stream);
 230  E :    if (!out_archive.Save(metadata)) {
 231  i :      LOG(ERROR) << "Failed to write metadata to Syzygy history stream.";
 232  i :      return false;
 233    :    }
 234    :  
 235  E :    return true;
 236  E :  }
 237    :  
 238    :  // This writes the serialized block-graph and the image layout in a PDB stream
 239    :  // named /Syzygy/BlockGraph. If the format is changed, be sure to update this
 240    :  // documentation and pdb::kSyzygyBlockGraphStreamVersion (in pdb_constants.h).
 241    :  // The block graph stream will not include the data from the blocks of the
 242    :  // block-graph. If the strip-strings flag is set to true the strings contained
 243    :  // in the block-graph won't be saved.
 244    :  bool WriteSyzygyBlockGraphStream(const PEFile& pe_file,
 245    :                                   const ImageLayout& image_layout,
 246    :                                   bool strip_strings,
 247    :                                   bool compress,
 248    :                                   NameStreamMap* name_stream_map,
 249  E :                                   PdbFile* pdb_file) {
 250    :    // Get the redecomposition data stream.
 251    :    scoped_refptr<PdbStream> block_graph_reader =
 252  E :        GetOrCreatePdbStreamByName(pdb::kSyzygyBlockGraphStreamName,
 253    :                                   true,
 254    :                                   name_stream_map,
 255    :                                   pdb_file);
 256    :  
 257  E :    if (block_graph_reader.get() == nullptr) {
 258  i :      LOG(ERROR) << "Failed to get the block-graph stream.";
 259  i :      return false;
 260    :    }
 261  E :    DCHECK_EQ(0u, block_graph_reader->length());
 262    :  
 263    :    scoped_refptr<WritablePdbStream> block_graph_writer =
 264  E :        block_graph_reader->GetWritableStream();
 265  E :    DCHECK(block_graph_writer.get() != NULL);
 266    :  
 267    :    // Write the version of the BlockGraph stream, and whether or not its
 268    :    // contents are compressed.
 269  E :    if (!block_graph_writer->Write(pdb::kSyzygyBlockGraphStreamVersion) ||
 270    :        !block_graph_writer->Write(static_cast<unsigned char>(compress))) {
 271  i :      LOG(ERROR) << "Failed to write Syzygy BlockGraph stream header.";
 272  i :      return false;
 273    :    }
 274    :  
 275    :    // Set up the output stream.
 276  E :    PdbOutStream pdb_out_stream(block_graph_writer.get());
 277  E :    core::OutStream* out_stream = &pdb_out_stream;
 278    :  
 279    :    // If requested, compress the output.
 280  E :    std::unique_ptr<core::ZOutStream> zip_stream;
 281  E :    if (compress) {
 282  E :      zip_stream.reset(new core::ZOutStream(&pdb_out_stream));
 283  E :      out_stream = zip_stream.get();
 284  E :      if (!zip_stream->Init(core::ZOutStream::kZBestCompression)) {
 285  i :        LOG(ERROR) << "Failed to initialize zlib compressor.";
 286  i :        return false;
 287    :      }
 288    :    }
 289    :  
 290  E :    core::OutArchive out_archive(out_stream);
 291    :  
 292    :    // Set up the serialization properties.
 293  E :    block_graph::BlockGraphSerializer::Attributes attributes = 0;
 294  E :    if (strip_strings)
 295  E :      attributes |= block_graph::BlockGraphSerializer::OMIT_STRINGS;
 296    :  
 297    :    // And finally, perform the serialization.
 298  E :    if (!SaveBlockGraphAndImageLayout(pe_file, attributes, image_layout,
 299    :                                      &out_archive)) {
 300  i :      LOG(ERROR) << "SaveBlockGraphAndImageLayout failed.";
 301  i :      return false;
 302    :    }
 303    :  
 304    :    // We have to flush the stream in case it's a zstream.
 305  E :    out_stream->Flush();
 306    :  
 307  E :    return true;
 308  E :  }
 309    :  
 310    :  }  // namespace
 311    :  
 312    :  bool ValidateAndInferPaths(
 313    :      const base::FilePath& input_module,
 314    :      const base::FilePath& output_module,
 315    :      bool allow_overwrite,
 316    :      base::FilePath* input_pdb,
 317  E :      base::FilePath* output_pdb) {
 318  E :    DCHECK(!input_module.empty());
 319  E :    DCHECK(!output_module.empty());
 320  E :    DCHECK_NE(reinterpret_cast<base::FilePath*>(NULL), input_pdb);
 321  E :    DCHECK_NE(reinterpret_cast<base::FilePath*>(NULL), output_pdb);
 322    :  
 323  E :    if (!base::PathExists(input_module)) {
 324  E :      LOG(ERROR) << "Input module not found: " << input_module.value();
 325  E :      return false;
 326    :    }
 327    :  
 328  E :    if (!allow_overwrite && base::PathExists(output_module)) {
 329  E :      LOG(ERROR) << "Output module exists: " << output_module.value();
 330  E :      LOG(ERROR) << "Specify --overwrite to ignore this error.";
 331  E :      return false;
 332    :    }
 333    :  
 334    :    // If no input PDB was specified then search for it.
 335  E :    if (input_pdb->empty()) {
 336  E :      LOG(INFO) << "Input PDB not specified, searching for it.";
 337  E :      if (!pe::FindPdbForModule(input_module, input_pdb) ||
 338    :          input_pdb->empty()) {
 339  i :        LOG(ERROR) << "Unable to find PDB file for module: "
 340    :                   << input_module.value();
 341  i :        return NULL;
 342    :      }
 343    :    }
 344    :  
 345  E :    if (!base::PathExists(*input_pdb)) {
 346  E :      LOG(ERROR) << "Input PDB not found: " << input_pdb->value();
 347  E :      return false;
 348    :    }
 349    :  
 350    :    // If no output PDB path is specified, infer one.
 351  E :    if (output_pdb->empty()) {
 352    :      // If the input and output DLLs have the same basename, default to writing
 353    :      // using the same PDB basename, but alongside the new module.
 354  E :      if (input_module.BaseName() == output_module.BaseName()) {
 355  E :        *output_pdb = output_module.DirName().Append(input_pdb->BaseName());
 356  E :      } else {
 357    :        // Otherwise, default to using the output basename with a PDB extension
 358    :        // added to it.
 359  E :        *output_pdb = output_module.AddExtension(L"pdb");
 360    :      }
 361    :  
 362  E :      LOG(INFO) << "Using default output PDB path: " << output_pdb->value();
 363    :    }
 364    :  
 365  E :    if (!allow_overwrite && base::PathExists(*output_pdb)) {
 366  E :      LOG(ERROR) << "Output PDB exists: " << output_pdb->value();
 367  E :      LOG(ERROR) << "Specify --overwrite to ignore this error.";
 368  E :      return false;
 369    :    }
 370    :  
 371    :    // Perform some extra checking to make sure that writes aren't going to
 372    :    // collide. This prevents us from overwriting the input, effectively
 373    :    // preventing in-place transforms. This is not fool-proof in the face of
 374    :    // weird junctions but it will catch common errors.
 375    :  
 376    :    core::FilePathCompareResult result =
 377  E :        core::CompareFilePaths(input_module, output_module);
 378  E :    if (result == core::kEquivalentFilePaths) {
 379  i :      LOG(ERROR) << "Input and output module paths are equivalent.";
 380  i :      LOG(ERROR) << "Input module path: " << input_module.value();
 381  i :      LOG(ERROR) << "Output module path: " << output_module.value();
 382  i :      return false;
 383    :    }
 384    :  
 385  E :    result = core::CompareFilePaths(*input_pdb, *output_pdb);
 386  E :    if (result == core::kEquivalentFilePaths) {
 387  i :      LOG(ERROR) << "Input and output PDB paths are equivalent.";
 388  i :      LOG(ERROR) << "Input PDB path: " << input_pdb->value();
 389  i :      LOG(ERROR) << "Output PDB path: " << output_pdb->value();
 390  i :      return false;
 391    :    }
 392    :  
 393  E :    result = core::CompareFilePaths(output_module, *output_pdb);
 394  E :    if (result == core::kEquivalentFilePaths) {
 395  i :      LOG(ERROR) << "Output module and PDB paths are equivalent.";
 396  i :      LOG(ERROR) << "Output module path: " << output_module.value();
 397  i :      LOG(ERROR) << "Output PDB path: " << output_pdb->value();
 398  i :      return false;
 399    :    }
 400    :  
 401  E :    return true;
 402  E :  }
 403    :  
 404    :  bool FinalizeBlockGraph(const base::FilePath& input_module,
 405    :                          const base::FilePath& output_pdb,
 406    :                          const GUID& pdb_guid,
 407    :                          bool add_metadata,
 408    :                          const PETransformPolicy* policy,
 409    :                          BlockGraph* block_graph,
 410  E :                          BlockGraph::Block* dos_header_block) {
 411  E :    DCHECK_NE(reinterpret_cast<PETransformPolicy*>(NULL), policy);
 412  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 413  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dos_header_block);
 414  E :    LOG(INFO) << "Finalizing block-graph for \"" << input_module.value() << "\".";
 415    :  
 416  E :    std::vector<BlockGraphTransformInterface*> post_transforms;
 417  E :    pe::transforms::AddMetadataTransform add_metadata_tx(input_module);
 418  E :    pe::transforms::AddPdbInfoTransform add_pdb_info_tx(output_pdb, 1,
 419    :                                                        pdb_guid);
 420  E :    pe::transforms::PERemoveEmptySectionsTransform remove_empty_sections;
 421  E :    pe::transforms::PEPrepareHeadersTransform prep_headers_tx;
 422    :  
 423  E :    if (add_metadata)
 424  E :      post_transforms.push_back(&add_metadata_tx);
 425  E :    post_transforms.push_back(&add_pdb_info_tx);
 426  E :    post_transforms.push_back(&remove_empty_sections);
 427  E :    post_transforms.push_back(&prep_headers_tx);
 428    :  
 429  E :    if (!block_graph::ApplyBlockGraphTransforms(post_transforms,
 430    :                                                policy,
 431    :                                                block_graph,
 432    :                                                dos_header_block)) {
 433  i :      return false;
 434    :    }
 435    :  
 436  E :    return true;
 437  E :  }
 438    :  
 439    :  bool FinalizeOrderedBlockGraph(
 440    :      OrderedBlockGraph* ordered_block_graph,
 441  E :      BlockGraph::Block* dos_header_block) {
 442  E :    DCHECK_NE(reinterpret_cast<OrderedBlockGraph*>(NULL), ordered_block_graph);
 443  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dos_header_block);
 444  E :    pe::orderers::PEOrderer pe_orderer;
 445  E :    if (!pe_orderer.OrderBlockGraph(ordered_block_graph, dos_header_block))
 446  i :      return false;
 447  E :    return true;
 448  E :  }
 449    :  
 450    :  bool BuildImageLayout(size_t padding,
 451    :                        size_t code_alignment,
 452    :                        const OrderedBlockGraph& ordered_block_graph,
 453    :                        BlockGraph::Block* dos_header_block,
 454  E :                        ImageLayout* image_layout) {
 455  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dos_header_block);
 456  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 457    :  
 458  E :    LOG(INFO) << "Building image layout.";
 459    :  
 460  E :    PEImageLayoutBuilder builder(image_layout);
 461  E :    builder.set_padding(padding);
 462  E :    builder.set_code_alignment(code_alignment);
 463  E :    if (!builder.LayoutImageHeaders(dos_header_block)) {
 464  i :      LOG(ERROR) << "PEImageLayoutBuilder::LayoutImageHeaders failed.";
 465  i :      return false;
 466    :    }
 467    :  
 468  E :    if (!builder.LayoutOrderedBlockGraph(ordered_block_graph)) {
 469  i :      LOG(ERROR) << "PEImageLayoutBuilder::LayoutOrderedBlockGraph failed.";
 470  i :      return false;
 471    :    }
 472    :  
 473  E :    LOG(INFO) << "Finalizing image layout.";
 474  E :    if (!builder.Finalize()) {
 475  i :      LOG(ERROR) << "PEImageLayoutBuilder::Finalize failed.";
 476  i :      return false;
 477    :    }
 478    :  
 479  E :    return true;
 480  E :  }
 481    :  
 482    :  void GetOmapRange(const std::vector<ImageLayout::SectionInfo>& sections,
 483  E :                    RelativeAddressRange* range) {
 484  E :    DCHECK_NE(reinterpret_cast<RelativeAddressRange*>(NULL), range);
 485    :  
 486    :    // There need to be at least two sections, one containing something and the
 487    :    // other containing the relocs.
 488  E :    DCHECK_GT(sections.size(), 1u);
 489  E :    DCHECK_EQ(sections.back().name, std::string(kRelocSectionName));
 490    :  
 491    :    // For some reason, if we output OMAP entries for the headers (before the
 492    :    // first section), everything falls apart. Not outputting these allows the
 493    :    // unittests to pass. Also, we don't want to output OMAP information for
 494    :    // the relocs, as these are entirely different from image to image.
 495  E :    RelativeAddress start_of_image = sections.front().addr;
 496  E :    RelativeAddress end_of_image = sections.back().addr;
 497  E :    *range = RelativeAddressRange(start_of_image, end_of_image - start_of_image);
 498  E :  }
 499    :  
 500    :  bool FinalizePdbFile(const base::FilePath input_module,
 501    :                       const base::FilePath output_module,
 502    :                       const RelativeAddressRange input_range,
 503    :                       const ImageLayout& image_layout,
 504    :                       const GUID& guid,
 505    :                       bool augment_pdb,
 506    :                       bool strip_strings,
 507    :                       bool compress_pdb,
 508  E :                       pdb::PdbFile* pdb_file) {
 509  E :    DCHECK(pdb_file != NULL);
 510    :  
 511  E :    LOG(INFO) << "Finalizing PDB file.";
 512    :  
 513  E :    VLOG(1) << "Updating GUID.";
 514  E :    if (!pdb::SetGuid(guid, pdb_file)) {
 515  i :      LOG(ERROR) << "Unable to set PDB GUID.";
 516  i :      return false;
 517    :    }
 518    :  
 519  E :    VLOG(1) << "Building OMAP vectors.";
 520  E :    std::vector<OMAP> omap_to, omap_from;
 521  E :    BuildOmapVectors(input_range, image_layout, &omap_to, &omap_from);
 522    :  
 523  E :    VLOG(1) << "Writing OMAP vectors.";
 524  E :    if (!pdb::SetOmapToStream(omap_to, pdb_file)) {
 525  i :      LOG(ERROR) << "Unable to set OMAP_TO.";
 526  i :      return false;
 527    :    }
 528  E :    if (!pdb::SetOmapFromStream(omap_from, pdb_file)) {
 529  i :      LOG(ERROR) << "Unable to set OMAP_FROM.";
 530  i :      return false;
 531    :    }
 532    :  
 533    :    // Parse the header and named streams.
 534  E :    pdb::PdbInfoHeader70 header = {};
 535  E :    pdb::NameStreamMap name_stream_map;
 536  E :    if (!pdb::ReadHeaderInfoStream(*pdb_file, &header, &name_stream_map))
 537  i :      return false;
 538    :  
 539    :    // Update/create the Syzygy history stream.
 540  E :    VLOG(1) << "Adding history stream to PDB.";
 541  E :    if (!WriteSyzygyHistoryStream(input_module, &name_stream_map, pdb_file))
 542  i :      return false;
 543    :  
 544    :    // Add redecomposition data in another stream, only if augment_pdb_ is set.
 545  E :    if (augment_pdb) {
 546  E :      PEFile new_pe_file;
 547  E :      if (!new_pe_file.Init(output_module)) {
 548  i :        LOG(ERROR) << "Failed to read newly written PE file.";
 549  i :        return false;
 550    :      }
 551    :  
 552  E :      VLOG(1) << "Adding serialized block-graph stream to PDB.";
 553  E :      if (!WriteSyzygyBlockGraphStream(new_pe_file,
 554    :                                       image_layout,
 555    :                                       strip_strings,
 556    :                                       compress_pdb,
 557    :                                       &name_stream_map,
 558    :                                       pdb_file)) {
 559  i :        return false;
 560    :      }
 561  E :    }
 562    :  
 563    :    // Write the updated name-stream map back to the header info stream.
 564  E :    VLOG(1) << "Updating PDB headers.";
 565  E :    if (!pdb::WriteHeaderInfoStream(header, name_stream_map, pdb_file))
 566  i :      return false;
 567    :  
 568    :    // Stream 0 contains a copy of the previous PDB's directory. This, combined
 569    :    // with copy-on-write semantics of individual blocks makes the file contain
 570    :    // its whole edit history. Since we're writing a 'new' PDB file (we reset the
 571    :    // GUID and age), we have no history so can safely throw away this stream.
 572  E :    VLOG(1) << "Removing previous PDB directory stream.";
 573  E :    pdb_file->ReplaceStream(0, NULL);
 574    :  
 575  E :    return true;
 576  E :  }
 577    :  
 578    :  }  // namespace pe

Coverage information generated Fri Jul 29 11:00:21 2016.