Coverage for /Syzygy/pe/pe_coff_file_impl.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
85.7%1381610.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    :  // Template implementation of common definitions and helper routines
  16    :  // for reading both PE and COFF file formats.
  17    :  
  18    :  #ifndef SYZYGY_PE_PE_COFF_FILE_IMPL_H_
  19    :  #define SYZYGY_PE_PE_COFF_FILE_IMPL_H_
  20    :  
  21    :  namespace pe {
  22    :  
  23    :  template <typename AddressSpaceTraits>
  24  E :  void PECoffFile<AddressSpaceTraits>::Init(const base::FilePath& path) {
  25  E :    path_ = path;
  26  E :  }
  27    :  
  28    :  template <typename AddressSpaceTraits>
  29    :  bool PECoffFile<AddressSpaceTraits>::Contains(AddressType addr,
  30  E :                                                SizeType len) const {
  31  E :    const ImageAddressSpace::Range range(addr, len);
  32  E :    return image_data_.FindContaining(range) != image_data_.ranges().end();
  33  E :  }
  34    :  
  35    :  template <typename AddressSpaceTraits>
  36    :  size_t PECoffFile<AddressSpaceTraits>::GetSectionIndex(AddressType addr,
  37  E :                                                         SizeType len) const {
  38  E :    const ImageAddressSpace::Range range(addr, len);
  39    :    ImageAddressSpace::RangeMap::const_iterator it =
  40  E :        image_data_.FindContaining(range);
  41  E :    if (it == image_data_.ranges().end())
  42  E :      return kInvalidSection;
  43  E :    return it->second.id;
  44  E :  }
  45    :  
  46    :  template <typename AddressSpaceTraits>
  47    :  const IMAGE_SECTION_HEADER* PECoffFile<AddressSpaceTraits>::GetSectionHeader(
  48  E :      AddressType addr, SizeType len) const {
  49  E :    size_t id = GetSectionIndex(addr, len);
  50  E :    if (id == kInvalidSection)
  51  E :      return NULL;
  52  E :    DCHECK_LT(id, file_header_->NumberOfSections);
  53  E :    return section_headers_ + id;
  54  E :  }
  55    :  
  56    :  template <typename AddressSpaceTraits>
  57    :  std::string PECoffFile<AddressSpaceTraits>::GetSectionName(
  58  E :      const IMAGE_SECTION_HEADER& section) {
  59  E :    const char* name = reinterpret_cast<const char*>(section.Name);
  60  E :    return std::string(name, strnlen(name, arraysize(section.Name)));
  61  E :  }
  62    :  
  63    :  template <typename AddressSpaceTraits>
  64    :  std::string PECoffFile<AddressSpaceTraits>::GetSectionName(
  65  E :      size_t section_index) const {
  66  E :    DCHECK_LT(section_index, file_header_->NumberOfSections);
  67    :  
  68  E :    const IMAGE_SECTION_HEADER* section = section_headers_ + section_index;
  69  E :    return GetSectionName(*section);
  70  E :  }
  71    :  
  72    :  template <typename AddressSpaceTraits>
  73    :  bool PECoffFile<AddressSpaceTraits>::ReadCommonHeaders(
  74  E :      FILE* file, FileOffsetAddress file_header_start) {
  75    :    // Test for unsupported object files.
  76    :    uint16 obj_sig[2];
  77  E :    if (!ReadAt(file, 0, obj_sig, sizeof(obj_sig))) {
  78  i :      LOG(ERROR) << "Unable to read first 4 bytes from object file.";
  79  i :      return false;
  80    :    }
  81  E :    if (obj_sig[0] == 0 && obj_sig[1] == 0xFFFF) {
  82  E :      LOG(ERROR) << "Unsupported anonymous object file.";
  83  E :      return false;
  84    :    }
  85    :  
  86    :    // Read the COFF file header.
  87  E :    IMAGE_FILE_HEADER file_header = {};
  88    :    if (!ReadAt(file, file_header_start.value(),
  89  E :                &file_header, sizeof(file_header))) {
  90  i :      LOG(ERROR) << "Unable to read COFF file header.";
  91  i :      return false;
  92    :    }
  93    :  
  94    :    // Compute size of all headers, from the beginning of the file to
  95    :    // the end of the section table.
  96    :    FileOffsetAddress opt_header_start(file_header_start.value() +
  97  E :                                       sizeof(file_header));
  98    :    FileOffsetAddress section_table_start(opt_header_start +
  99  E :                                          file_header.SizeOfOptionalHeader);
 100    :    SizeType section_table_size(
 101  E :        file_header.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
 102  E :    FileOffsetAddress header_end(section_table_start + section_table_size);
 103  E :    SizeType header_size = header_end.value();
 104  E :    if (file_header.SizeOfOptionalHeader != 0) {
 105  E :      IMAGE_OPTIONAL_HEADER opt_header = {};
 106    :      if (!ReadAt(file, opt_header_start.value(),
 107  E :                  &opt_header, sizeof(opt_header))) {
 108  i :        LOG(ERROR) << "Unable to read optional header.";
 109  i :        return false;
 110    :      }
 111    :      // In a sane world the stated header size will match that manually
 112    :      // calculated by walking the headers and aligning up by the file alignment.
 113    :      // However, this is not necessary for the PE file to be valid, and there may
 114    :      // be a gap between the two.
 115  E :      header_size = opt_header.SizeOfHeaders;
 116    :    }
 117    :  
 118    :    // We now know how large the headers are, so create a range for them.
 119  E :    ImageAddressSpace::Range header_range(header_address(), header_size);
 120    :    if (!InsertRangeReadAt(file, FileOffsetAddress(0), header_size,
 121  E :                           header_range)) {
 122  i :      return false;
 123    :    }
 124    :  
 125    :    bool success = GetImageData(header_address() + file_header_start.value(),
 126    :                                SizeType(sizeof(*file_header_)),
 127  E :                                &file_header_);
 128  E :    DCHECK(success);
 129    :    success = GetImageData(header_address() + section_table_start.value(),
 130    :                           section_table_size,
 131  E :                           &section_headers_);
 132  E :    DCHECK(success);
 133    :  
 134  E :    return success;
 135  E :  }
 136    :  
 137    :  template <typename AddressSpaceTraits>
 138  E :  bool PECoffFile<AddressSpaceTraits>::ReadSections(FILE* file) {
 139  E :    DCHECK(file_header_ != NULL);
 140  E :    DCHECK(section_headers_ != NULL);
 141    :  
 142  E :    size_t num_sections = file_header_->NumberOfSections;
 143  E :    for (size_t i = 0; i < num_sections; ++i) {
 144  E :      const IMAGE_SECTION_HEADER* hdr = section_headers_ + i;
 145    :  
 146    :      // Construct address in the new address space; FromSectionHeader()
 147    :      // returns header_address() if unmapped.
 148  E :      AddressType addr = AddressSpaceTraits::GetSectionAddress(*hdr);
 149    :  
 150    :      // Ignore unmapped sections, as those, by definition, have no
 151    :      // address to map to within our address space. They need to be
 152    :      // handled separately during decomposition.
 153  E :      if (addr == AddressSpaceTraits::invalid_address())
 154  E :        continue;
 155    :  
 156    :      // Insert the range for the new section.
 157    :      ImageAddressSpace::Range section_range(
 158  E :          addr, AddressSpaceTraits::GetSectionSize(*hdr));
 159  E :      ImageAddressSpace::RangeMap::iterator it;
 160  E :      if (!image_data_.Insert(section_range, SectionInfo(), &it)) {
 161  i :        LOG(ERROR) << "Unable to insert range for section " << hdr->Name << ".";
 162  i :        return false;
 163    :      }
 164    :  
 165  E :      it->second.id = i;
 166  E :      SectionBuffer& buf = it->second.buffer;
 167  E :      if (hdr->SizeOfRawData == 0)
 168  i :        continue;
 169    :  
 170  E :      buf.resize(hdr->SizeOfRawData);
 171  E :      if (!ReadAt(file, hdr->PointerToRawData, &buf.at(0), hdr->SizeOfRawData)) {
 172  i :        LOG(ERROR) << "Unable to read data for section " << hdr->Name << ".";
 173  i :        return false;
 174    :      }
 175  E :    }
 176    :  
 177  E :    return true;
 178  E :  }
 179    :  
 180    :  template <typename AddressSpaceTraits>
 181    :  bool PECoffFile<AddressSpaceTraits>::InsertRangeReadAt(
 182    :      FILE* file, FileOffsetAddress start, size_t size,
 183  E :      const typename ImageAddressSpace::Range& range) {
 184  E :    ImageAddressSpace::RangeMap::iterator it;
 185  E :    bool inserted = image_data_.Insert(range, SectionInfo(), &it);
 186  E :    if (!inserted) {
 187  i :      LOG(ERROR) << "Unable to create new range in address space.";
 188  i :      return false;
 189    :    }
 190    :  
 191  E :    SectionBuffer& buffer = it->second.buffer;
 192  E :    buffer.resize(size);
 193  E :    if (!ReadAt(file, start.value(), &buffer[0], size)) {
 194  i :      LOG(ERROR) << "Unable to file data.";
 195  i :      return false;
 196    :    }
 197    :  
 198  E :    return true;
 199  E :  }
 200    :  
 201    :  template <typename AddressSpaceTraits>
 202    :  bool PECoffFile<AddressSpaceTraits>::ReadAt(FILE* file, size_t pos,
 203  E :                                              void* buf, size_t len) {
 204  E :    if (fseek(file, pos, SEEK_SET) != 0)
 205  i :      return false;
 206    :  
 207  E :    size_t read = fread(buf, 1, len, file);
 208  E :    if (read != len)
 209  i :      return false;
 210    :  
 211  E :    return true;
 212  E :  }
 213    :  
 214    :  template <typename AddressSpaceTraits>
 215    :  const uint8* PECoffFile<AddressSpaceTraits>::GetImageData(AddressType addr,
 216  E :                                                            SizeType len) const {
 217  E :    ImageAddressSpace::Range range(addr, len);
 218    :    ImageAddressSpace::RangeMap::const_iterator it(
 219  E :        image_data_.FindContaining(range));
 220    :  
 221  E :    if (it != image_data_.ranges().end()) {
 222  E :      ptrdiff_t offs = addr - it->first.start();
 223  E :      DCHECK_GE(offs, 0);
 224    :  
 225  E :      const SectionBuffer& buf = it->second.buffer;
 226  E :      if (offs + len <= buf.size())
 227  E :        return &buf.at(offs);
 228    :    }
 229    :  
 230  E :    return NULL;
 231  E :  }
 232    :  
 233    :  template <typename AddressSpaceTraits>
 234    :  uint8* PECoffFile<AddressSpaceTraits>::GetImageData(AddressType addr,
 235  E :                                                      SizeType len) {
 236    :    return const_cast<uint8*>(
 237  E :        static_cast<const PECoffFile*>(this)->GetImageData(addr, len));
 238  E :  }
 239    :  
 240    :  template <typename AddressSpaceTraits>
 241    :  template <typename ItemType>
 242    :  bool PECoffFile<AddressSpaceTraits>::GetImageData(
 243  E :      AddressType addr, SizeType len, const ItemType** item_ptr) const {
 244  E :    const uint8* ptr = GetImageData(addr, len);
 245  E :    if (ptr == NULL)
 246  i :      return false;
 247  E :    *item_ptr = reinterpret_cast<const ItemType*>(ptr);
 248  E :    return true;
 249  E :  }
 250    :  
 251    :  template <typename AddressSpaceTraits>
 252    :  template <typename ItemType>
 253    :  bool PECoffFile<AddressSpaceTraits>::GetImageData(
 254  E :      AddressType addr, SizeType len, ItemType** item_ptr) {
 255  E :    uint8* ptr = GetImageData(addr, len);
 256  E :    if (ptr == NULL)
 257  i :      return false;
 258  E :    *item_ptr = reinterpret_cast<ItemType*>(ptr);
 259  E :    return true;
 260  E :  }
 261    :  
 262    :  template <typename AddressSpaceTraits>
 263    :  bool PECoffFile<AddressSpaceTraits>::ReadImage(AddressType addr,
 264  E :                                                 void* data, SizeType len) const {
 265  E :    DCHECK(data != NULL);
 266  E :    const uint8* buf = GetImageData(addr, len);
 267  E :    if (buf == NULL)
 268  i :      return false;
 269    :  
 270  E :    memcpy(data, buf, len);
 271  E :    return true;
 272  E :  }
 273    :  
 274    :  template <typename AddressSpaceTraits>
 275    :  bool PECoffFile<AddressSpaceTraits>::ReadImageString(AddressType addr,
 276  E :                                                       std::string* str) const {
 277  E :    DCHECK(file_header_ != NULL);
 278  E :    str->clear();
 279    :  
 280    :    // Locate the range that contains the first byte of the string.
 281  E :    ImageAddressSpace::Range range(addr, 1);
 282    :    ImageAddressSpace::RangeMap::const_iterator it(
 283  E :        image_data_.FindContaining(range));
 284    :  
 285  E :    if (it != image_data_.ranges().end()) {
 286  E :      ptrdiff_t offs = addr - it->first.start();
 287  E :      DCHECK_GE(offs, 0);
 288    :      // Stash the start position.
 289  E :      const SectionBuffer& buf = it->second.buffer;
 290  E :      const char* begin = reinterpret_cast<const char*>(&buf.at(offs));
 291    :      // And loop through until we find a zero-terminating byte,
 292    :      // or run off the end.
 293  E :      for (; static_cast<size_t>(offs) < buf.size() && buf.at(offs); ++offs) {
 294    :        // Intentionally empty.
 295  E :      }
 296    :  
 297  E :      if (static_cast<size_t>(offs) == buf.size())
 298  i :        return false;
 299    :  
 300  E :      str->assign(begin);
 301  E :      return true;
 302    :    }
 303    :  
 304  i :    return false;
 305  E :  }
 306    :  
 307    :  }  // namespace  pe
 308    :  
 309    :  #endif  // SYZYGY_PE_PE_COFF_FILE_IMPL_H_

Coverage information generated Wed Dec 11 11:34:16 2013.