Coverage for /Syzygy/pdb/pdb_dbi_stream.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
72.6%1221680.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/pdb/pdb_dbi_stream.h"
  16    :  
  17    :  #include "base/strings/stringprintf.h"
  18    :  #include "syzygy/common/align.h"
  19    :  #include "syzygy/pdb/pdb_constants.h"
  20    :  #include "syzygy/pdb/pdb_stream.h"
  21    :  #include "syzygy/pdb/pdb_stream_reader.h"
  22    :  #include "syzygy/pdb/pdb_util.h"
  23    :  
  24    :  namespace pdb {
  25    :  
  26  E :  bool DbiModuleInfo::Read(common::BinaryStreamParser* parser) {
  27  E :    DCHECK(parser != nullptr);
  28    :  
  29    :    if (!parser->Read(&module_info_base_) || !parser->ReadString(&module_name_) ||
  30  E :        !parser->ReadString(&object_name_) || !parser->AlignTo(4)) {
  31  i :      LOG(ERROR) << "Unable to read module information.";
  32  i :      return false;
  33    :    }
  34    :  
  35  E :    return true;
  36  E :  }
  37    :  
  38    :  // Reads the header from the Dbi stream of the PDB.
  39  E :  bool DbiStream::ReadDbiHeaders(pdb::PdbStream* stream) {
  40  E :    DCHECK(stream != NULL);
  41    :  
  42  E :    if (!stream->ReadBytesAt(0, sizeof(header_), &header_)) {
  43  i :      LOG(ERROR) << "Unable to read the header of the Dbi Stream.";
  44  i :      return false;
  45    :    }
  46    :  
  47  E :    size_t dbg_header_offs = pdb::GetDbiDbgHeaderOffset(header_);
  48  E :    if (!stream->ReadBytesAt(dbg_header_offs, sizeof(dbg_header_),
  49    :                             &dbg_header_)) {
  50  i :      LOG(ERROR) << "Unable to read Dbg header of the Dbi Stream.";
  51  i :      return false;
  52    :    }
  53    :  
  54  E :    return true;
  55  E :  }
  56    :  
  57    :  // Reads the module info substream from the Dbi stream of the PDB.
  58  E :  bool DbiStream::ReadDbiModuleInfo(pdb::PdbStream* stream) {
  59  E :    DCHECK(stream != NULL);
  60    :  
  61    :    // This substream starts just after the Dbi header in the Dbi stream.
  62  E :    size_t module_start = sizeof(pdb::DbiHeader);
  63    :  
  64  E :    pdb::PdbStreamReaderWithPosition reader(module_start, header_.gp_modi_size,
  65    :                                            stream);
  66  E :    common::BinaryStreamParser parser(&reader);
  67    :    // Read each module info block.
  68  E :    while (!reader.AtEnd()) {
  69  E :      DbiModuleInfo module_info;
  70  E :      if (!module_info.Read(&parser))
  71  i :        return false;
  72  E :      modules_.push_back(module_info);
  73  E :    }
  74    :  
  75  E :    if (!reader.AtEnd()) {
  76  i :      LOG(ERROR) << "Module info substream of the Dbi stream is not valid.";
  77  i :      return false;
  78    :    }
  79    :  
  80  E :    return true;
  81  E :  }
  82    :  
  83    :  // Reads the section contribs substream from the Dbi stream of the PDB.
  84  E :  bool DbiStream::ReadDbiSectionContribs(pdb::PdbStream* stream) {
  85  E :    DCHECK(stream != NULL);
  86    :  
  87  E :    size_t section_contribs_start = sizeof(pdb::DbiHeader) + header_.gp_modi_size;
  88  E :    pdb::PdbStreamReaderWithPosition reader(
  89    :        section_contribs_start, header_.section_contribution_size, stream);
  90  E :    common::BinaryStreamParser parser(&reader);
  91  E :    uint32_t signature = 0;
  92  E :    if (!parser.Read(&signature)) {
  93  i :      LOG(ERROR) << "Unable to seek to section contributions substream.";
  94  i :      return false;
  95    :    }
  96    :  
  97  E :    if (signature != kPdbDbiSectionContribsSignature) {
  98  E :      LOG(ERROR) << "Unexpected signature for the section contribs substream. "
  99    :                 << "Expected "
 100    :                 << base::StringPrintf("0x%08X", kPdbDbiSectionContribsSignature)
 101    :                 << ", read "
 102    :                 << base::StringPrintf("0x%08X", signature) << ".";
 103  E :      return false;
 104    :    }
 105    :  
 106    :    size_t section_contrib_count =
 107  E :        (header_.section_contribution_size - reader.Position()) /
 108    :        sizeof(DbiSectionContrib);
 109    :  
 110  E :    if (!parser.ReadMultiple(section_contrib_count, &section_contribs_)) {
 111  i :      LOG(ERROR) << "Unable to read section contributions.";
 112  i :      return false;
 113    :    }
 114    :  
 115  E :    if (!reader.AtEnd()) {
 116  i :      LOG(ERROR) << "Section contribs substream of the Dbi stream is not valid.";
 117  i :      return false;
 118    :    }
 119    :  
 120  E :    return true;
 121  E :  }
 122    :  
 123    :  // Reads the section map substream from the Dbi stream of the PDB.
 124  E :  bool DbiStream::ReadDbiSectionMap(pdb::PdbStream* stream) {
 125  E :    DCHECK(stream != NULL);
 126    :  
 127    :    size_t section_map_start = sizeof(pdb::DbiHeader)
 128    :        + header_.gp_modi_size
 129  E :        + header_.section_contribution_size;
 130  E :    pdb::PdbStreamReaderWithPosition reader(section_map_start,
 131    :                                            header_.section_map_size, stream);
 132  E :    common::BinaryStreamParser parser(&reader);
 133  E :    uint16_t number_of_sections = 0;
 134  E :    if (!parser.Read(&number_of_sections)) {
 135  i :      LOG(ERROR) << "Unable to read the length of the section map in the Dbi "
 136    :                 << "stream.";
 137  i :      return false;
 138    :    }
 139    :  
 140    :    // The number of section appears to be present twice. This check ensure that
 141    :    // the value are always equals. If it's not it'll give us a sample to
 142    :    // understand what's this value.
 143  E :    uint16_t number_of_sections_copy = 0;
 144  E :    if (!parser.Read(&number_of_sections_copy)) {
 145  i :      LOG(ERROR) << "Unable to read the copy of the length of the section map in "
 146    :                 << "the Dbi stream.";
 147  i :      return false;
 148    :    }
 149    :  
 150  E :    if (number_of_sections != number_of_sections_copy) {
 151  i :      LOG(ERROR) << "Mismatched values for the length of the section map ("
 152    :                 <<  number_of_sections << " vs "<< number_of_sections_copy
 153    :                 << ").";
 154  i :      return false;
 155    :    }
 156    :  
 157  E :    while (!reader.AtEnd()) {
 158    :      DbiSectionMapItem section_map_item;
 159  E :      if (!parser.Read(&section_map_item)) {
 160  i :        LOG(ERROR) << "Failed to read a section map item";
 161  i :        return false;
 162    :      }
 163    :  
 164  E :      section_map_[section_map_item.section_number] = section_map_item;
 165  E :    }
 166    :  
 167  E :    if (section_map_.size() != number_of_sections) {
 168  i :      LOG(ERROR) << "Unexpected number of sections in the section map (expected "
 169    :                 << number_of_sections << ", read " << section_map_.size()
 170    :                 << ").";
 171  i :      return false;
 172    :    }
 173    :  
 174  E :    if (!reader.AtEnd()) {
 175  i :      LOG(ERROR) << "Section map substream of the Dbi stream is not valid.";
 176  i :      return false;
 177    :    }
 178    :  
 179  E :    return true;
 180  E :  }
 181    :  
 182    :  // Reads the file info substream from the Dbi stream of the PDB.
 183    :  // The structure of this substream is:
 184    :  // Header | File-blocks table | Offset table | Name table.
 185    :  // - The header contains the number of entries in the File-blocks table (16
 186    :  //    bits) followed by the number of entries in the offset table (16 bits). You
 187    :  //   have to multiply each size by 4 to obtain the size in bytes.
 188    :  // - The file-blocks table is divided in 2 parts. The first part contains the
 189    :  //   starting index of each block (16 bits) and the second one contains
 190    :  //   the length of these blocks. These value refer to the offset table. It
 191    :  //   seems that there's always a last block with a starting value equal to the
 192    :  //   length of the offset table and a length of 0 at the end of this table.
 193    :  // - The offset table contains offsets to the beginning of file names in the
 194    :  //   name table. These offsets are relative to the beginning of the name table.
 195    :  // - The name table contain all the filenames used in this substream.
 196  E :  bool DbiStream::ReadDbiFileInfo(pdb::PdbStream* stream) {
 197  E :    DCHECK(stream != NULL);
 198    :  
 199    :    size_t file_info_start = sizeof(pdb::DbiHeader)
 200    :        + header_.gp_modi_size
 201    :        + header_.section_contribution_size
 202  E :        + header_.section_map_size;
 203  E :    pdb::PdbStreamReaderWithPosition reader(file_info_start,
 204    :                                            header_.file_info_size, stream);
 205  E :    common::BinaryStreamParser parser(&reader);
 206    :  
 207  E :    uint16_t file_blocks_table_size = 0;
 208  E :    uint16_t offset_table_size = 0;
 209  E :    if (!parser.Read(&file_blocks_table_size) ||
 210    :        !parser.Read(&offset_table_size)) {
 211  i :      LOG(ERROR) << "Unable to read the header of the file info substream.";
 212  i :      return false;
 213    :    }
 214    :  
 215    :    // Calculate the starting address of the different sections of this substream.
 216  E :    size_t file_blocks_table_start = file_info_start + reader.Position();
 217    :    size_t offset_table_start =
 218  E :        file_blocks_table_start + file_blocks_table_size * sizeof(uint32_t);
 219    :  
 220  E :    if (!ReadDbiFileInfoBlocks(stream,
 221    :                               file_blocks_table_size,
 222    :                               file_blocks_table_start,
 223    :                               offset_table_start)) {
 224  i :      return false;
 225    :    }
 226    :  
 227    :    size_t name_table_start =
 228  E :        offset_table_start + offset_table_size * sizeof(uint32_t);
 229  E :    size_t file_info_end = file_info_start + header_.file_info_size;
 230    :  
 231    :    // Read the name table in this substream.
 232  E :    if (!ReadDbiFileNameTable(stream,
 233    :                              name_table_start,
 234    :                              file_info_end)) {
 235  i :      return false;
 236    :    }
 237    :  
 238  E :    return true;
 239  E :  }
 240    :  
 241    :  bool DbiStream::ReadDbiFileInfoBlocks(pdb::PdbStream* stream,
 242    :                                        uint16_t file_blocks_table_size,
 243    :                                        size_t file_blocks_table_start,
 244  E :                                        size_t offset_table_start) {
 245  E :    file_info_.first.resize(file_blocks_table_size);
 246    :  
 247    :    // The block info data is composed of two parallel arrays in the stream.
 248    :    // The first array is an array of uint16_t block start positions, and the
 249    :    // second one is an array of uint16_t lengths.
 250    :    // Each {start, length} pair notes the location and length of variable-length
 251    :    // array of uint16_t identifiers. These identifiers in turn then point to
 252    :    // locations in the file name table, and so identify a file name.
 253    :    // This is done because there's a lot of repetition in the file name data, as
 254    :    // every compilation unit ends up including a subset of the same files.
 255    :  
 256    :    // Create a reader over the start position array.
 257  E :    pdb::PdbStreamReaderWithPosition start_reader(
 258    :        file_blocks_table_start, file_blocks_table_size * sizeof(uint16_t),
 259    :        stream);
 260  E :    common::BinaryStreamParser start_parser(&start_reader);
 261    :  
 262    :    // Create a reader over the length array.
 263    :    size_t file_block_length_start =
 264  E :        file_blocks_table_start + file_blocks_table_size * sizeof(uint16_t);
 265  E :    pdb::PdbStreamReaderWithPosition length_reader(
 266    :        file_block_length_start, file_blocks_table_size * sizeof(uint16_t),
 267    :        stream);
 268  E :    common::BinaryStreamParser length_parser(&length_reader);
 269    :  
 270    :    // Read information about each block of the file info substream.
 271  E :    for (int i = 0; i < file_blocks_table_size; ++i) {
 272  E :      uint16_t block_start = 0;
 273  E :      uint16_t block_length = 0;
 274  E :      if (!start_parser.Read(&block_start) ||
 275    :          !length_parser.Read(&block_length)) {
 276  i :        LOG(ERROR) << "Unable to read the file info substream.";
 277  i :        return false;
 278    :      }
 279    :  
 280  E :      pdb::PdbStreamReaderWithPosition block_reader(
 281    :          offset_table_start + block_start * sizeof(uint32_t),
 282    :          block_length * sizeof(uint32_t), stream);
 283  E :      common::BinaryStreamParser block_parser(&block_reader);
 284    :      // Fill the file list.
 285  E :      if (!block_parser.ReadMultiple(block_length, &file_info_.first.at(i))) {
 286  i :        LOG(ERROR) << "Unable to read the file info substream.";
 287  i :        return false;
 288    :      }
 289  E :    }
 290    :  
 291  E :    return true;
 292  E :  }
 293    :  
 294    :  // It would be useful to move this code to a more generic function if we see
 295    :  // this structure somewhere else in the PDB.
 296    :  bool DbiStream::ReadDbiFileNameTable(pdb::PdbStream* stream,
 297    :                                       size_t name_table_start,
 298  E :                                       size_t name_table_end) {
 299  E :    DCHECK_LE(name_table_start, name_table_end);
 300  E :    pdb::PdbStreamReaderWithPosition reader(
 301    :        name_table_start, name_table_end - name_table_start, stream);
 302  E :    common::BinaryStreamParser parser(&reader);
 303    :  
 304  E :    while (!reader.AtEnd()) {
 305  E :      std::string filename;
 306  E :      size_t pos = reader.Position();
 307  E :      if (!parser.ReadString(&filename)) {
 308  i :        LOG(ERROR) << "Unable to read the name table of the file info substream.";
 309  i :        return false;
 310    :      }
 311  E :      file_info_.second.insert(std::make_pair(pos, filename));
 312  E :    }
 313    :  
 314  E :    if (!reader.AtEnd()) {
 315  i :      LOG(ERROR) << "File info substream of the Dbi stream is not valid.";
 316  i :      return false;
 317    :    }
 318    :  
 319  E :    return true;
 320  E :  }
 321    :  
 322  E :  bool DbiStream::ReadDbiECInfo(pdb::PdbStream* stream) {
 323    :    // It's important to note that the ec_info_size field appears after the
 324    :    // dbg_header_size field in the header of this stream but the EC info
 325    :    // substream is located before the DbgHeader substream.
 326    :    size_t ec_info_start = sizeof(pdb::DbiHeader)
 327    :        + header_.gp_modi_size
 328    :        + header_.section_contribution_size
 329    :        + header_.section_map_size
 330    :        + header_.file_info_size
 331  E :        + header_.ts_map_size;
 332  E :    size_t ec_info_end = ec_info_start + header_.ec_info_size;
 333    :  
 334  E :    return ReadStringTable(stream,
 335    :                           "EC info",
 336    :                           ec_info_start,
 337    :                           ec_info_end,
 338    :                           &ec_info_vector_);
 339  E :  }
 340    :  
 341  E :  bool DbiStream::Read(pdb::PdbStream* stream ) {
 342  E :    DCHECK(stream != NULL);
 343    :  
 344  E :    if (!ReadDbiHeaders(stream))
 345  i :      return false;
 346    :  
 347  E :    if (!ReadDbiModuleInfo(stream))
 348  i :      return false;
 349    :  
 350  E :    if (!ReadDbiSectionContribs(stream))
 351  E :      return false;
 352    :  
 353  E :    if (!ReadDbiSectionMap(stream))
 354  i :      return false;
 355    :  
 356  E :    if (!ReadDbiFileInfo(stream))
 357  i :      return false;
 358    :  
 359  E :    if (header_.ts_map_size != 0) {
 360  i :      LOG(ERROR) << "The length of the TS map is expected to be null but we've "
 361    :                 << "read a length of " << header_.ts_map_size << ".";
 362  i :      return false;
 363    :    }
 364    :  
 365  E :    if (!ReadDbiECInfo(stream))
 366  i :      return false;
 367    :  
 368  E :    return true;
 369  E :  }
 370    :  
 371    :  }  // namespace pdb

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