Coverage for /Syzygy/pe/pe_relinker.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%53530.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    :  // 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/files/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 base::FilePath& input_path() const { return input_path_; }
 108  E :    const base::FilePath& input_pdb_path() const { return input_pdb_path_; }
 109  E :    const base::FilePath& output_path() const { return output_path_; }
 110  E :    const base::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  E :    bool compress_pdb() const { return compress_pdb_; }
 115  E :    bool parse_debug_info() const { return parse_debug_info_; }
 116  E :    bool strip_strings() const { return strip_strings_; }
 117  E :    bool use_new_decomposer() const { return use_new_decomposer_; }
 118  E :    size_t padding() const { return padding_; }
 119    :    // @}
 120    :  
 121    :    // @name Mutators for controlling relinker behaviour.
 122    :    // @{
 123  E :    void set_input_path(const base::FilePath& input_path) {
 124  E :      input_path_ = input_path;
 125  E :    }
 126  E :    void set_input_pdb_path(const base::FilePath& input_pdb_path) {
 127  E :      input_pdb_path_ = input_pdb_path;
 128  E :    }
 129  E :    void set_output_path(const base::FilePath& output_path) {
 130  E :      output_path_ = output_path;
 131  E :    }
 132  E :    void set_output_pdb_path(const base::FilePath& output_pdb_path) {
 133  E :      output_pdb_path_ = output_pdb_path;
 134  E :    }
 135  E :    void set_add_metadata(bool add_metadata) {
 136  E :      add_metadata_ = add_metadata;
 137  E :    }
 138  E :    void set_allow_overwrite(bool allow_overwrite) {
 139  E :      allow_overwrite_ = allow_overwrite;
 140  E :    }
 141  E :    void set_augment_pdb(bool augment_pdb) {
 142  E :      augment_pdb_ = augment_pdb;
 143  E :    }
 144  E :    void set_compress_pdb(bool compress_pdb) {
 145  E :      compress_pdb_ = compress_pdb;
 146  E :    }
 147  E :    void set_parse_debug_info(bool parse_debug_info) {
 148  E :      parse_debug_info_ = parse_debug_info;
 149  E :    }
 150  E :    void set_strip_strings(bool strip_strings) {
 151  E :      strip_strings_ = strip_strings;
 152  E :    }
 153  E :    void set_use_new_decomposer(bool use_new_decomposer) {
 154  E :      use_new_decomposer_ = use_new_decomposer;
 155  E :    }
 156  E :    void set_padding(size_t padding) {
 157  E :      padding_ = padding;
 158  E :    }
 159    :    // @}
 160    :  
 161    :    // Appends a transform to be applied by this relinker. If no transforms are
 162    :    // specified, none will be applied and the transform is effectively the
 163    :    // identity transform. Each transform will be applied in the order added
 164    :    // to the relinker, assuming all earlier transforms have succeeded.
 165    :    //
 166    :    // @param transform the transform to append to the list of transforms to
 167    :    //     apply. The pointer must remain valid for the lifespan of the relinker.
 168    :    void AppendTransform(Transform* transform);
 169    :  
 170    :    // Appends a list of transforms to be applied by this relinker. Each transform
 171    :    // will be applied in the order added to the relinker, assuming all earlier
 172    :    // transforms have succeeded.
 173    :    //
 174    :    // @param transforms a vector of transforms to be applied to the input image.
 175    :    //     The pointers must remain valid for the lifespan of the relinker.
 176    :    void AppendTransforms(const std::vector<Transform*>& transforms);
 177    :  
 178    :    // Appends an orderer to be applied by this relinker.
 179    :    //
 180    :    // If no orderers are specified the default orderer will be applied. If no
 181    :    // transforms have been applied this makes the entire relinker an identity
 182    :    // relinker. Each orderer will be applied in the order added to the relinker,
 183    :    // assuming all earlier orderers have succeeded.
 184    :    //
 185    :    // @param orderer a orderer to be applied to the input image. The pointer must
 186    :    //     remain valid for the lifespan of the relinker.
 187    :    void AppendOrderer(Orderer* orderer);
 188    :  
 189    :    // Appends a list of orderers to be applied by this relinker.
 190    :    //
 191    :    // If no orderers are specified the default orderer will be applied. If no
 192    :    // transforms have been applied this makes the entire relinker an identity
 193    :    // relinker. Each orderer will be applied in the order added to the relinker,
 194    :    // assuming all earlier orderers have succeeded.
 195    :    //
 196    :    // @param orderers a vector of orderers to be applied to the input image.
 197    :    //     The pointers must remain valid for the lifespan of the relinker.
 198    :    void AppendOrderers(const std::vector<Orderer*>& orderers);
 199    :  
 200    :    // Appends a PDB mutator to be applied by this relinker.
 201    :    //
 202    :    // Each mutator will be applied in the order added to the relinker,
 203    :    // assuming all earlier mutators have succeeded.
 204    :    //
 205    :    // @param pdb_mutator a PDB mutator to be applied to the input image. The
 206    :    //     pointer must remain valid for the lifespan of the relinker.
 207    :    void AppendPdbMutator(pdb::PdbMutatorInterface* pdb_mutator);
 208    :  
 209    :    // Appends a list of PDB mutators to be applied by this relinker.
 210    :    //
 211    :    // Each mutator will be applied in the order added to the relinker,
 212    :    // assuming all earlier mutators have succeeded.
 213    :    //
 214    :    // @param pdb_mutators a vector of mutators to be applied to the input image.
 215    :    //     The pointers must remain valid for the lifespan of the relinker.
 216    :    void AppendPdbMutators(
 217    :        const std::vector<pdb::PdbMutatorInterface*>& pdb_mutators);
 218    :  
 219    :    // Runs the initialization phase of the relinker. This consists of decomposing
 220    :    // the input image, after which the intermediate data accessors declared below
 221    :    // become valid. This should typically be followed by a call to Relink.
 222    :    //
 223    :    // @returns true on success, false otherwise.
 224    :    // @pre input_path and output_path must be set prior to calling this.
 225    :    //     input_pdb_path and output_pdb_path may optionally have been set prior
 226    :    //     to calling this.
 227    :    // @post input_pe_file and input_image_layout may be called after this.
 228    :    // @note This entrypoint is virtual for unittest/mocking purposes.
 229    :    virtual bool Init();
 230    :  
 231    :    // Runs the relinker, generating an output image and PDB.
 232    :    //
 233    :    // @returns true on success, false otherwise.
 234    :    // @pre Init must have been called successfully.
 235    :    // @note This entrypoint is virtual for unittest/mocking purposes.
 236    :    virtual bool Relink();
 237    :  
 238    :    // @name Intermediate data accessors.
 239    :    // @{
 240    :    // These accessors only return meaningful data after Init has been called. By
 241    :    // the time any transforms or orderers are being called, these will contain
 242    :    // valid data.
 243    :    //
 244    :    // TODO(chrisha): Clean these up as part of the API simplification after
 245    :    //     all legacy code has been refactored.
 246    :    //
 247    :    // @pre Init has been successfully called.
 248  E :    const PEFile& input_pe_file() const { return input_pe_file_; }
 249  E :    const ImageLayout& input_image_layout() const { return input_image_layout_; }
 250  E :    const BlockGraph& block_graph() const { return block_graph_; }
 251  E :    const BlockGraph::Block* dos_header_block() const {
 252  E :      return dos_header_block_; }
 253    :    const GUID& output_guid() const { return output_guid_; }
 254    :    // @}
 255    :  
 256    :   protected:
 257    :    base::FilePath input_path_;
 258    :    base::FilePath input_pdb_path_;
 259    :    base::FilePath output_path_;
 260    :    base::FilePath output_pdb_path_;
 261    :  
 262    :    // If true, metadata will be added to the output image. Defaults to true.
 263    :    bool add_metadata_;
 264    :    // If true, allow the relinker to rewrite the input files in place. Defaults
 265    :    // to false.
 266    :    bool allow_overwrite_;
 267    :    // If true, the PDB will be augmented with a serialized block-graph and
 268    :    // image layout. Defaults to true.
 269    :    bool augment_pdb_;
 270    :    // If true, then the augmented PDB stream will be compressed as it is written.
 271    :    // Defaults to false.
 272    :    bool compress_pdb_;
 273    :    // If true, then the decomposition will parse full symbol information.
 274    :    // Defaults to true.
 275    :    bool parse_debug_info_;
 276    :    // If true, strings associated with a block-graph will not be serialized into
 277    :    // the PDB. Defaults to false.
 278    :    bool strip_strings_;
 279    :    // If true we will use the new decomposer. Defaults to false.
 280    :    bool use_new_decomposer_;
 281    :    // Indicates the amount of padding to be added between blocks. Zero is the
 282    :    // default value and indicates no padding will be added.
 283    :    size_t padding_;
 284    :  
 285    :    // The vectors of user supplied transforms, orderers and mutators to be
 286    :    // applied.
 287    :    std::vector<Transform*> transforms_;
 288    :    std::vector<Orderer*> orderers_;
 289    :    std::vector<pdb::PdbMutatorInterface*> pdb_mutators_;
 290    :  
 291    :    // The internal state of the relinker.
 292    :    bool inited_;
 293    :  
 294    :    // Intermediate variables that are initialized and used by Relink. They are
 295    :    // made externally accessible so that transforms and orderers may make use
 296    :    // of them if necessary.
 297    :  
 298    :    // These refer to the original image, and don't change after init.
 299    :    PEFile input_pe_file_;
 300    :    ImageLayout input_image_layout_;
 301    :  
 302    :    // These refer to the image the whole way through the process. They may
 303    :    // evolve.
 304    :    BlockGraph block_graph_;
 305    :    BlockGraph::Block* dos_header_block_;
 306    :  
 307    :    // These are for the new image that will be produced at the end of Relink.
 308    :    GUID output_guid_;
 309    :  };
 310    :  
 311    :  }  // namespace pe
 312    :  
 313    :  #endif  // SYZYGY_PE_PE_RELINKER_H_

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