Coverage for /Syzygy/pe/pe_relinker.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
97.7%42430.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    :  // Declares PERelinker. Relinking can be seen as decomposing an input image,
  16    :  // applying a sequence of block-graph transforms (some applied implicitly, and
  17    :  // others provided by the user), followed by a sequence of orderers (again, some
  18    :  // implicit, some provided by the user), laying-out, finalizing and finally
  19    :  // writing a new image. After writing the image a similar transformation
  20    :  // workflow is applied to the corresponding PDB file, consisting of applying
  21    :  // any user defined PDB mutations, followed by 2-3 (depending on PeRelinker
  22    :  // configuration) internal mutations (updating the GUID/age, adding the history
  23    :  // stream and adding the serialized block-graph stream). PERelinker encapsulates
  24    :  // this workflow.
  25    :  //
  26    :  // It is intended to be used as follows:
  27    :  //
  28    :  //   PERelinker relinker;
  29    :  //   relinker.set_input_path(...);  // Required.
  30    :  //   relinker.set_output_path(...);  // Required.
  31    :  //   relinker.set_input_pdb_path(...);  // Optional.
  32    :  //   relinker.set_output_pdb_path(...);  // Optional.
  33    :  //   relinker.Init();  // Check the return value!
  34    :  //
  35    :  //   // At this point, the following accessors are valid:
  36    :  //   relinker.input_pe_file();
  37    :  //   relinker.input_image_layout();
  38    :  //   relinker.block_graph();
  39    :  //   relinker.dos_header_block();
  40    :  //   relinker.output_guid();
  41    :  //
  42    :  //   relinker.AppendTransform(...);  // May be called repeatedly.
  43    :  //   relinker.AppendOrderer(...);  // May be called repeatedly.
  44    :  //   relinker.AppendPdbMutator(...);  // May be called repeatedly.
  45    :  //
  46    :  //   relinker.Relink();  // Check the return value!
  47    :  //
  48    :  // NOTE: This split workflow is only necessary as a workaround to deal with
  49    :  //     transforms and orderers built around legacy code. Intermediate
  50    :  //     representations of serialized data-structures should be stored in such
  51    :  //     a way so as not to explicitly require access to the untransformed image.
  52    :  //     Additionally, for checking validity a transform or orderer should require
  53    :  //     no more than the PESignature associated with the original module, and/or
  54    :  //     the toolchain metadata present in the module, if there was any.
  55    :  //
  56    :  // TODO(chrisha): Resimplify this API once Reorderer has been reworked to move
  57    :  //     away from Block pointers.
  58    :  
  59    :  #ifndef SYZYGY_PE_PE_RELINKER_H_
  60    :  #define SYZYGY_PE_PE_RELINKER_H_
  61    :  
  62    :  #include <vector>
  63    :  
  64    :  #include "base/file_path.h"
  65    :  #include "syzygy/block_graph/orderer.h"
  66    :  #include "syzygy/block_graph/transform.h"
  67    :  #include "syzygy/pdb/pdb_mutator.h"
  68    :  #include "syzygy/pe/image_layout_builder.h"
  69    :  #include "syzygy/pe/pe_file.h"
  70    :  
  71    :  namespace pe {
  72    :  
  73    :  // Embodies a transformation on a PE image, from decomposing an original image
  74    :  // to applying some transform(s) to it, to generating the layout and finally
  75    :  // writing the image and accompanying PDB to disk.
  76    :  //
  77    :  // Creating a PERelinker and not changing its default configuration yields an
  78    :  // identity relinker that will produce an identical (nearly, except for cosmetic
  79    :  // differences in some headers) image to the input.
  80    :  //
  81    :  // The workflow is as follows:
  82    :  //
  83    :  // 1. Relinker created with an input image. The PDB file is found automatically
  84    :  //    and the image is decomposed. Optionally the PDB may be directly specified.
  85    :  // 2. The image is transformed:
  86    :  //    a) Transforms provided by the user are applied.
  87    :  //    b) AddMetadataTransform is conditionally applied.
  88    :  //    c) AddPdbInfoTransform is applied.
  89    :  //    d) PrepareHeadersTransform is applied.
  90    :  // 3. The image is ordered:
  91    :  //    a) Orderers provided by the user are applied.
  92    :  //    b) PEOrderer is applied.
  93    :  // 4. ImageLayoutBuilder is used to convert the OrderedBlockGraph to an
  94    :  //    ImageLayout.
  95    :  // 5. Image and accompanying PDB file are written. (Filenames are inferred from
  96    :  //    input filenames or directly specified.)
  97    :  class PERelinker {
  98    :   public:
  99    :    typedef block_graph::BlockGraph BlockGraph;
 100    :    typedef block_graph::BlockGraphOrdererInterface Orderer;
 101    :    typedef block_graph::BlockGraphTransformInterface Transform;
 102    :  
 103    :    PERelinker();
 104    :  
 105    :    // @name Accessors.
 106    :    // @{
 107  E :    const FilePath& input_path() const { return input_path_; }
 108  E :    const FilePath& input_pdb_path() const { return input_pdb_path_; }
 109  E :    const FilePath& output_path() const { return output_path_; }
 110  E :    const FilePath& output_pdb_path() const { return output_pdb_path_; }
 111  E :    bool add_metadata() const { return add_metadata_; }
 112  E :    bool allow_overwrite() const { return allow_overwrite_; }
 113  E :    bool augment_pdb() const { return augment_pdb_; }
 114    :    bool compress_pdb() const { return compress_pdb_; }
 115    :    bool strip_strings() const { return strip_strings_; }
 116  E :    size_t padding() const { return padding_; }
 117    :    // @}
 118    :  
 119    :    // @name Mutators for controlling relinker behaviour.
 120    :    // @{
 121  E :    void set_input_path(const FilePath& input_path) {
 122  E :      input_path_ = input_path;
 123  E :    }
 124  E :    void set_input_pdb_path(const FilePath& input_pdb_path) {
 125  E :      input_pdb_path_ = input_pdb_path;
 126  E :    }
 127  E :    void set_output_path(const FilePath& output_path) {
 128  E :      output_path_ = output_path;
 129  E :    }
 130  E :    void set_output_pdb_path(const FilePath& output_pdb_path) {
 131  E :      output_pdb_path_ = output_pdb_path;
 132  E :    }
 133  E :    void set_add_metadata(bool add_metadata) {
 134  E :      add_metadata_ = add_metadata;
 135  E :    }
 136  E :    void set_allow_overwrite(bool allow_overwrite) {
 137  E :      allow_overwrite_ = allow_overwrite;
 138  E :    }
 139  E :    void set_augment_pdb(bool augment_pdb) {
 140  E :      augment_pdb_ = augment_pdb;
 141  E :    }
 142  E :    void set_compress_pdb(bool compress_pdb) {
 143  E :      compress_pdb_ = compress_pdb;
 144  E :    }
 145  E :    void set_strip_strings(bool strip_strings) {
 146  E :      strip_strings_ = strip_strings;
 147  E :    }
 148  E :    void set_padding(size_t padding) {
 149  E :      padding_ = padding;
 150  E :    }
 151    :    // @}
 152    :  
 153    :    // Appends a transform to be applied by this relinker. If no transforms are
 154    :    // specified, none will be applied and the transform is effectively the
 155    :    // identity transform. Each transform will be applied in the order added
 156    :    // to the relinker, assuming all earlier transforms have succeeded.
 157    :    //
 158    :    // @param transform the transform to append to the list of transforms to
 159    :    //     apply. The pointer must remain valid for the lifespan of the relinker.
 160    :    void AppendTransform(Transform* transform);
 161    :  
 162    :    // Appends a list of transforms to be applied by this relinker. Each transform
 163    :    // will be applied in the order added to the relinker, assuming all earlier
 164    :    // transforms have succeeded.
 165    :    //
 166    :    // @param transforms a vector of transforms to be applied to the input image.
 167    :    //     The pointers must remain valid for the lifespan of the relinker.
 168    :    void AppendTransforms(const std::vector<Transform*>& transforms);
 169    :  
 170    :    // Appends an orderer to be applied by this relinker.
 171    :    //
 172    :    // If no orderers are specified the default orderer will be applied. If no
 173    :    // transforms have been applied this makes the entire relinker an identity
 174    :    // relinker. Each orderer will be applied in the order added to the relinker,
 175    :    // assuming all earlier orderers have succeeded.
 176    :    //
 177    :    // @param orderer a orderer to be applied to the input image. The pointer must
 178    :    //     remain valid for the lifespan of the relinker.
 179    :    void AppendOrderer(Orderer* orderer);
 180    :  
 181    :    // Appends a list of orderers to be applied by this relinker.
 182    :    //
 183    :    // If no orderers are specified the default orderer will be applied. If no
 184    :    // transforms have been applied this makes the entire relinker an identity
 185    :    // relinker. Each orderer will be applied in the order added to the relinker,
 186    :    // assuming all earlier orderers have succeeded.
 187    :    //
 188    :    // @param orderers a vector of orderers to be applied to the input image.
 189    :    //     The pointers must remain valid for the lifespan of the relinker.
 190    :    void AppendOrderers(const std::vector<Orderer*>& orderers);
 191    :  
 192    :    // Appends a PDB mutator to be applied by this relinker.
 193    :    //
 194    :    // Each mutator will be applied in the order added to the relinker,
 195    :    // assuming all earlier mutators have succeeded.
 196    :    //
 197    :    // @param pdb_mutator a PDB mutator to be applied to the input image. The
 198    :    //     pointer must remain valid for the lifespan of the relinker.
 199    :    void AppendPdbMutator(pdb::PdbMutatorInterface* pdb_mutator);
 200    :  
 201    :    // Appends a list of PDB mutators to be applied by this relinker.
 202    :    //
 203    :    // Each mutator will be applied in the order added to the relinker,
 204    :    // assuming all earlier mutators have succeeded.
 205    :    //
 206    :    // @param pdb_mutators a vector of mutators to be applied to the input image.
 207    :    //     The pointers must remain valid for the lifespan of the relinker.
 208    :    void AppendPdbMutators(
 209    :        const std::vector<pdb::PdbMutatorInterface*>& pdb_mutators);
 210    :  
 211    :    // Runs the initialization phase of the relinker. This consists of decomposing
 212    :    // the input image, after which the intermediate data accessors declared below
 213    :    // become valid. This should typically be followed by a call to Relink.
 214    :    //
 215    :    // @returns true on success, false otherwise.
 216    :    // @pre input_path and output_path must be set prior to calling this.
 217    :    //     input_pdb_path and output_pdb_path may optionally have been set prior
 218    :    //     to calling this.
 219    :    // @post input_pe_file and input_image_layout may be called after this.
 220    :    // @note This entrypoint is virtual for unittest/mocking purposes.
 221    :    virtual bool Init();
 222    :  
 223    :    // Runs the relinker, generating an output image and PDB.
 224    :    //
 225    :    // @returns true on success, false otherwise.
 226    :    // @pre Init must have been called successfully.
 227    :    // @note This entrypoint is virtual for unittest/mocking purposes.
 228    :    virtual bool Relink();
 229    :  
 230    :    // @name Intermediate data accessors.
 231    :    // @{
 232    :    // These accessors only return meaningful data after Init has been called. By
 233    :    // the time any transforms or orderers are being called, these will contain
 234    :    // valid data.
 235    :    //
 236    :    // TODO(chrisha): Clean these up as part of the API simplification after
 237    :    //     all legacy code has been refactored.
 238    :    //
 239    :    // @pre Init has been successfully called.
 240  E :    const PEFile& input_pe_file() const { return input_pe_file_; }
 241  i :    const ImageLayout& input_image_layout() const { return input_image_layout_; }
 242  E :    const BlockGraph& block_graph() const { return block_graph_; }
 243  E :    const BlockGraph::Block* dos_header_block() const {
 244  E :      return dos_header_block_; }
 245    :    const GUID& output_guid() const { return output_guid_; }
 246    :    // @}
 247    :  
 248    :   protected:
 249    :    FilePath input_path_;
 250    :    FilePath input_pdb_path_;
 251    :    FilePath output_path_;
 252    :    FilePath output_pdb_path_;
 253    :  
 254    :    // If true, metadata will be added to the output image. Defaults to true.
 255    :    bool add_metadata_;
 256    :    // If true, allow the relinker to rewrite the input files in place. Defaults
 257    :    // to false.
 258    :    bool allow_overwrite_;
 259    :    // If true, the PDB will be augmented with a serialized block-graph and
 260    :    // image layout.
 261    :    bool augment_pdb_;
 262    :    // If true, then the augmented PDB stream will be compressed as it is written.
 263    :    bool compress_pdb_;
 264    :    // If true, strings associated with a block-graph will not be serialized into
 265    :    // the PDB. Defaults to false.
 266    :    bool strip_strings_;
 267    :    // Indicates the amount of padding to be added between blocks. Zero is the
 268    :    // default value and indicates no padding will be added.
 269    :    size_t padding_;
 270    :  
 271    :    // The vectors of user supplied transforms, orderers and mutators to be
 272    :    // applied.
 273    :    std::vector<Transform*> transforms_;
 274    :    std::vector<Orderer*> orderers_;
 275    :    std::vector<pdb::PdbMutatorInterface*> pdb_mutators_;
 276    :  
 277    :    // The internal state of the relinker.
 278    :    bool inited_;
 279    :  
 280    :    // Intermediate variables that are initialized and used by Relink. They are
 281    :    // made externally accessible so that transforms and orderers may make use
 282    :    // of them if necessary.
 283    :  
 284    :    // These refer to the original image, and don't change after init.
 285    :    PEFile input_pe_file_;
 286    :    ImageLayout input_image_layout_;
 287    :  
 288    :    // These refer to the image the whole way through the process. They may
 289    :    // evolve.
 290    :    BlockGraph block_graph_;
 291    :    BlockGraph::Block* dos_header_block_;
 292    :  
 293    :    // These are for the new image that will be produced at the end of Relink.
 294    :    GUID output_guid_;
 295    :  };
 296    :  
 297    :  }  // namespace pe
 298    :  
 299    :  #endif  // SYZYGY_PE_PE_RELINKER_H_

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