Coverage for /Syzygy/pdb/pdb_util.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
78.4%3484440.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    :  #include "syzygy/pdb/pdb_util.h"
  15    :  
  16    :  #include <algorithm>
  17    :  #include <string>
  18    :  
  19    :  #include "base/strings/stringprintf.h"
  20    :  #include "syzygy/common/binary_stream.h"
  21    :  #include "syzygy/pdb/pdb_byte_stream.h"
  22    :  #include "syzygy/pdb/pdb_file.h"
  23    :  #include "syzygy/pdb/pdb_reader.h"
  24    :  #include "syzygy/pdb/pdb_stream_reader.h"
  25    :  #include "syzygy/pdb/pdb_writer.h"
  26    :  
  27    :  namespace pdb {
  28    :  
  29    :  namespace {
  30    :  
  31    :  // Sets the stream associated with a given entry in the DBI DBG header.
  32    :  // Gets the index at position @p index_offset of the DBI DBG header. If invalid,
  33    :  // adds a new stream to the PDB and updates the index to point to it. If a valid
  34    :  // stream already exists, replaces it with the new @p stream.
  35    :  // @param index_offset the offset of the int16_t stream index within the DBI DBG
  36    :  //     header.
  37    :  // @param stream the stream to be associated with the given DBI DBG entry.
  38    :  // @param pdb_file the PDB file to be updated.
  39    :  bool SetDbiDbgStream(size_t index_offset,
  40    :                       PdbStream* stream,
  41  E :                       PdbFile* pdb_file) {
  42  E :    DCHECK(pdb_file != NULL);
  43    :  
  44  E :    if (!EnsureStreamWritable(kDbiStream, pdb_file)) {
  45  i :      LOG(ERROR) << "Failed to make DBI stream writable.";
  46  i :      return false;
  47    :    }
  48    :  
  49  E :    scoped_refptr<PdbStream> dbi_reader(pdb_file->GetStream(kDbiStream));
  50  E :    scoped_refptr<WritablePdbStream> dbi_writer(dbi_reader->GetWritableStream());
  51  E :    DCHECK(dbi_writer.get() != NULL);
  52    :  
  53    :    // Read the DBI header.
  54  E :    DbiHeader dbi_header = {};
  55  E :    if (!dbi_reader->ReadBytesAt(0, sizeof(dbi_header), &dbi_header)) {
  56  i :      LOG(ERROR) << "Failed to read DBI header.";
  57  i :      return false;
  58    :    }
  59    :  
  60    :    // Get the stream index at the provided offset.
  61  E :    uint32_t dbi_dbg_offset = GetDbiDbgHeaderOffset(dbi_header);
  62  E :    int16_t existing_index = -1;
  63  E :    if (!dbi_reader->ReadBytesAt(dbi_dbg_offset + index_offset,
  64    :                                 sizeof(existing_index), &existing_index)) {
  65  i :      LOG(ERROR) << "Failed to read stream index at offset " << dbi_dbg_offset
  66    :                 << " of DBI DBG header.";
  67  i :      return false;
  68    :    }
  69    :  
  70    :    // If the stream is an invalid index, we create a new one.
  71  E :    int16_t new_index = existing_index;
  72  E :    if (existing_index < 0 ||
  73    :        existing_index >= static_cast<uint16_t>(pdb_file->StreamCount())) {
  74  E :      new_index = static_cast<uint16_t>(pdb_file->AppendStream(stream));
  75  E :    } else {
  76  i :      pdb_file->ReplaceStream(new_index, stream);
  77    :    }
  78    :  
  79    :    // Update the index in the header if we need to.
  80  E :    if (new_index != existing_index) {
  81  E :      dbi_writer->set_pos(dbi_dbg_offset + index_offset);
  82  E :      if (!dbi_writer->Write(new_index)) {
  83  i :        LOG(ERROR) << "Failed to write stream index at offset " << dbi_dbg_offset
  84    :                   << " of DBI DBG header.";
  85  i :        return false;
  86    :      }
  87    :    }
  88    :  
  89  E :    return true;
  90  E :  }
  91    :  
  92    :  bool SetOmapStream(size_t dbi_dbg_index_offset,
  93    :                     const std::vector<OMAP>& omap_list,
  94  E :                     PdbFile* pdb_file) {
  95  E :    DCHECK(pdb_file != NULL);
  96    :  
  97  E :    scoped_refptr<PdbByteStream> stream = new PdbByteStream();
  98  E :    if (!omap_list.empty()) {
  99  E :      if (!stream->Init(reinterpret_cast<const uint8_t*>(&omap_list.at(0)),
 100    :                        omap_list.size() * sizeof(OMAP))) {
 101  i :        LOG(ERROR) << "Failed to initialize OMAP stream.";
 102  i :        return false;
 103    :      }
 104    :    }
 105    :  
 106  E :    return SetDbiDbgStream(dbi_dbg_index_offset, stream.get(), pdb_file);
 107  E :  }
 108    :  
 109    :  // Calculates the size of the hash table required to represent a named stream
 110    :  // hash containing the given number of entries. This has been determined from
 111    :  // inspection of the output produced by pdbstr.exe.
 112  E :  size_t GetNamedStreamsHashTableSize(size_t entries) {
 113    :    // This produces the sequence of sizes: 6, 10, 14, 20, 28, 38, 52, etc.
 114  E :    size_t size = 3;
 115  E :    while (true) {
 116  E :      size_t threshold = 2 * size / 3;
 117  E :      if (entries <= threshold)
 118  E :        return size;
 119  E :      size = 2 * (threshold + 1);
 120  E :    }
 121  E :  }
 122    :  
 123    :  // Sets the bit at the given index, with collision semantics. Returns the index
 124    :  // of the bit that was set. Note that there must be at least one bit that is not
 125    :  // already set, otherwise this will loop forever.
 126    :  size_t SetNamedStreamsHashTableBit(
 127  E :      size_t index, size_t max, PdbBitSet* bitset) {
 128  E :    DCHECK(bitset != NULL);
 129    :  
 130  E :    while (bitset->IsSet(index)) {
 131  E :      ++index;
 132  E :      if (index == max)
 133  i :        index = 0;
 134  E :    }
 135    :  
 136  E :    bitset->Set(index);
 137  E :    return index;
 138  E :  }
 139    :  
 140    :  // A small struct that is used for storing information regarding the name-stream
 141    :  // map, and the associated hash table. The (string table offset, stream id)
 142    :  // pairs need to be output in order of the hash value, which is the default sort
 143    :  // order of this object.
 144    :  struct NamedStreamInfo {
 145  E :    NamedStreamInfo(NameStreamMap::const_iterator it,
 146    :                    uint32_t offset,
 147    :                    uint32_t bucket)
 148  E :        : it(it), offset(offset), bucket(bucket) {}
 149    :  
 150  E :    bool operator<(const NamedStreamInfo& rhs) const {
 151  E :      return bucket < rhs.bucket;
 152  E :    }
 153    :  
 154    :    // An iterator into the (name, stream_id) map.
 155    :    NameStreamMap::const_iterator it;
 156    :    // The offset of the name in the string table.
 157    :    uint32_t offset;
 158    :    // The bucket that this name occupies in the hash map, after collision
 159    :    // resolution. This is the sort key.
 160    :    uint32_t bucket;
 161    :  };
 162    :  
 163  E :  bool ReadStringAt(PdbStream* stream, size_t pos, std::string* out) {
 164  E :    DCHECK(stream != nullptr);
 165  E :    DCHECK(out != nullptr);
 166    :  
 167  E :    pdb::PdbStreamReaderWithPosition reader(pos, stream->length() - pos, stream);
 168  E :    common::BinaryStreamParser parser(&reader);
 169  E :    return parser.ReadString(out);
 170  E :  }
 171    :  
 172    :  }  // namespace
 173    :  
 174  E :  bool PdbBitSet::Read(common::BinaryStreamReader* reader) {
 175  E :    DCHECK(reader != nullptr);
 176  E :    common::BinaryStreamParser parser(reader);
 177  E :    uint32_t size = 0;
 178  E :    if (!parser.Read(&size)) {
 179  E :      LOG(ERROR) << "Failed to read bitset size.";
 180  E :      return false;
 181    :    }
 182  E :    if (!parser.ReadMultiple(size, &bits_)) {
 183  i :      LOG(ERROR) << "Failed to read bitset bits.";
 184  i :      return false;
 185    :    }
 186    :  
 187  E :    return true;
 188  E :  }
 189    :  
 190  E :  bool PdbBitSet::Write(WritablePdbStream* stream, bool with_size) {
 191  E :    DCHECK(stream != NULL);
 192  E :    if (with_size && !stream->Write(static_cast<uint32_t>(bits_.size()))) {
 193  i :      LOG(ERROR) << "Failed to write bitset size.";
 194  i :      return false;
 195    :    }
 196  E :    if (bits_.empty())
 197  E :      return true;
 198  E :    if (!stream->Write(bits_.size(), &bits_[0])) {
 199  i :      LOG(ERROR) << "Failed to write bitset bits.";
 200  i :      return false;
 201    :    }
 202    :  
 203  E :    return true;
 204  E :  }
 205    :  
 206  E :  void PdbBitSet::Resize(size_t bits) {
 207  E :    bits_.resize((bits + 31) / 32);
 208  E :  }
 209    :  
 210  E :  void PdbBitSet::Set(size_t bit) {
 211  E :    size_t index = bit / 32;
 212  E :    if (index >= bits_.size())
 213  i :      return;
 214  E :    bits_[index] |= (1 << (bit % 32));
 215  E :  }
 216    :  
 217  E :  void PdbBitSet::Clear(size_t bit) {
 218  E :    size_t index = bit / 32;
 219  E :    if (index >= bits_.size())
 220  i :      return;
 221  E :    bits_[index] &= ~(1 << (bit % 32));
 222  E :  }
 223    :  
 224  E :  void PdbBitSet::Toggle(size_t bit) {
 225  E :    size_t index = bit / 32;
 226  E :    if (index >= bits_.size())
 227  i :      return;
 228  E :    bits_[index] ^= (1 << (bit % 32));
 229  E :  }
 230    :  
 231  E :  bool PdbBitSet::IsSet(size_t bit) const {
 232  E :    size_t index = bit / 32;
 233  E :    if (index >= bits_.size())
 234  i :      return false;
 235    :  
 236  E :    return (bits_[index] & (1 << (bit % 32))) != 0;
 237  E :  }
 238    :  
 239  E :  bool PdbBitSet::IsEmpty() const {
 240  E :    return bits_.empty();
 241  E :  }
 242    :  
 243  E :  uint16_t HashString(const base::StringPiece& string) {
 244  E :    size_t length = string.size();
 245  E :    const char* data = string.data();
 246    :  
 247  E :    uint32_t hash = 0;
 248  E :    while (length >= 4) {
 249  E :      hash ^= *reinterpret_cast<const uint32_t*>(data);
 250  E :      data += 4;
 251  E :      length -= 4;
 252  E :    }
 253    :  
 254  E :    if (length >= 2) {
 255  E :      hash ^= *reinterpret_cast<const uint16_t*>(data);
 256  E :      data += 2;
 257  E :      length -= 2;
 258    :    }
 259    :  
 260  E :    if (length >= 1)
 261  E :      hash ^= *data;
 262    :  
 263  E :    hash |= 0x20202020;
 264  E :    hash ^= hash >> 11;
 265  E :    hash ^= hash >> 16;
 266    :  
 267  E :    return hash & 0xFFFF;
 268  E :  }
 269    :  
 270  E :  uint32_t GetDbiDbgHeaderOffset(const DbiHeader& dbi_header) {
 271  E :    uint32_t offset = sizeof(DbiHeader);
 272  E :    offset += dbi_header.gp_modi_size;
 273  E :    offset += dbi_header.section_contribution_size;
 274  E :    offset += dbi_header.section_map_size;
 275  E :    offset += dbi_header.file_info_size;
 276  E :    offset += dbi_header.ts_map_size;
 277  E :    offset += dbi_header.ec_info_size;  // Unexpected, but necessary.
 278  E :    return offset;
 279  E :  }
 280    :  
 281  E :  bool EnsureStreamWritable(uint32_t index, PdbFile* pdb_file) {
 282  E :    DCHECK(pdb_file != NULL);
 283    :  
 284    :    // Bail if the index is to a non-existent stream.
 285  E :    if (index >= pdb_file->StreamCount()) {
 286  E :      LOG(ERROR) << "Invalid PDB stream index.";
 287  E :      return false;
 288    :    }
 289    :  
 290    :    // Get the reader. If it doesn't actually exist, create a new one.
 291  E :    scoped_refptr<PdbStream> reader(pdb_file->GetStream(index));
 292  E :    if (reader.get() == NULL)
 293  E :      reader = new PdbByteStream();
 294    :  
 295    :    // Try and get a writer.
 296  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritableStream());
 297  E :    if (writer.get() == NULL) {
 298    :      // If not possible, copy the existing reader to a PdbByteStream which will
 299    :      // be able to give us a writer.
 300  E :      scoped_refptr<PdbByteStream> new_stream = new PdbByteStream();
 301  E :      if (!new_stream->Init(reader.get())) {
 302  i :        LOG(ERROR) << "Failed to initialize writable stream.";
 303  i :        return false;
 304    :      }
 305  E :      reader = new_stream.get();
 306  E :    }
 307    :  
 308  E :    DCHECK_NE(static_cast<WritablePdbStream*>(nullptr),
 309  E :              reader->GetWritableStream());
 310    :  
 311    :    // Be sure to replace the stream at this index with the new one. This is a
 312    :    // no-op if the stream hasn't changed.
 313  E :    pdb_file->ReplaceStream(index, reader.get());
 314    :  
 315  E :    return true;
 316  E :  }
 317    :  
 318    :  bool SetOmapToStream(const std::vector<OMAP>& omap_to_list,
 319  E :                       PdbFile* pdb_file) {
 320  E :    DCHECK(pdb_file != NULL);
 321  E :    return SetOmapStream(offsetof(DbiDbgHeader, omap_to_src),
 322    :                         omap_to_list,
 323    :                         pdb_file);
 324  E :  }
 325    :  
 326    :  bool SetOmapFromStream(const std::vector<OMAP>& omap_from_list,
 327  E :                         PdbFile* pdb_file) {
 328  E :    DCHECK(pdb_file != NULL);
 329  E :    return SetOmapStream(offsetof(DbiDbgHeader, omap_from_src),
 330    :                         omap_from_list,
 331    :                         pdb_file);
 332  E :  }
 333    :  
 334  E :  bool SetGuid(const GUID& guid, PdbFile* pdb_file) {
 335  E :    DCHECK(pdb_file != NULL);
 336    :  
 337    :    // Make sure the Pdb header and the Dbi streams are writable.
 338  E :    if (!EnsureStreamWritable(kPdbHeaderInfoStream, pdb_file)) {
 339  i :      LOG(ERROR) << "Failed to make PDB Header Info stream writable.";
 340  i :      return false;
 341    :    }
 342  E :    if (!EnsureStreamWritable(kDbiStream, pdb_file)) {
 343  i :      LOG(ERROR) << "Failed to make DBI Info stream writable.";
 344  i :      return false;
 345    :    }
 346    :  
 347    :    // Get the reader and writer for the header info stream.
 348  E :    scoped_refptr<PdbStream> reader(pdb_file->GetStream(kPdbHeaderInfoStream));
 349  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritableStream());
 350  E :    DCHECK(writer.get() != NULL);
 351    :  
 352    :    // Read the header.
 353  E :    PdbInfoHeader70 info_header = {};
 354  E :    if (!reader->ReadBytesAt(0, sizeof(info_header), &info_header)) {
 355  E :      LOG(ERROR) << "Failed to read PdbInfoHeader70.";
 356  E :      return false;
 357    :    }
 358    :  
 359    :    // Update it.
 360  E :    info_header.timestamp = static_cast<uint32_t>(time(NULL));
 361  E :    info_header.pdb_age = 1;  // Reset age to 1, as this is a new generation.
 362  E :    info_header.signature = guid;
 363    :  
 364    :    // And write it back.
 365  E :    writer->set_pos(0);
 366  E :    if (!writer->Write(info_header)) {
 367  i :      LOG(ERROR) << "Failed to write PdbInfoHeader70.";
 368  i :      return false;
 369    :    }
 370    :  
 371    :    // Now update the age in the DBI stream to match the age we set above.
 372  E :    reader = pdb_file->GetStream(kDbiStream);
 373  E :    if (reader.get() == NULL) {
 374  i :      LOG(ERROR) << "No DBI stream in PDB.";
 375  i :      return false;
 376    :    }
 377  E :    writer = reader->GetWritableStream();
 378    :  
 379  E :    DCHECK(writer.get() != NULL);
 380    :  
 381    :    // Read the header.
 382  E :    DbiHeader dbi_header = {};
 383  E :    if (!reader->ReadBytesAt(0, sizeof(dbi_header), &dbi_header)) {
 384  E :      LOG(ERROR) << "Failed to read DbiHeader.";
 385  E :      return false;
 386    :    }
 387    :  
 388  E :    dbi_header.age = 1;
 389  E :    writer->set_pos(0);
 390  E :    if (!writer->Write(dbi_header)) {
 391  i :      LOG(ERROR) << "Failed to write DbiHeader";
 392  i :      return false;
 393    :    }
 394    :  
 395  E :    return true;
 396  E :  }
 397    :  
 398    :  bool ReadPdbHeader(const base::FilePath& pdb_path,
 399  E :                     PdbInfoHeader70* pdb_header) {
 400  E :    DCHECK(!pdb_path.empty());
 401  E :    DCHECK(pdb_header != NULL);
 402    :  
 403  E :    PdbReader pdb_reader;
 404  E :    PdbFile pdb_file;
 405  E :    if (!pdb_reader.Read(pdb_path, &pdb_file)) {
 406  E :      LOG(ERROR) << "Unable to process PDB file: " << pdb_path.value();
 407  E :      return false;
 408    :    }
 409    :  
 410  E :    PdbStream* header_stream = pdb_file.GetStream(kPdbHeaderInfoStream).get();
 411  E :    if (header_stream == NULL) {
 412  i :      LOG(ERROR) << "PDB file contains no header stream: " << pdb_path.value();
 413  i :      return false;
 414    :    }
 415    :  
 416  E :    if (!header_stream->ReadBytesAt(0, sizeof(*pdb_header), pdb_header)) {
 417  i :      LOG(ERROR) << "Failure reading PDB header: " << pdb_path.value();
 418  i :      return false;
 419    :    }
 420    :  
 421    :    // We only know how to deal with PDB files of the current version.
 422  E :    if (pdb_header->version != kPdbCurrentVersion) {
 423  i :      LOG(ERROR) << "PDB header has unsupported version (got "
 424    :                 << pdb_header->version << ", expected " << kPdbCurrentVersion
 425    :                 << ").";
 426  i :      return false;
 427    :    }
 428    :  
 429  E :    return true;
 430  E :  }
 431    :  
 432    :  bool ReadHeaderInfoStream(const PdbFile& pdb_file,
 433    :                            PdbInfoHeader70* pdb_header,
 434  E :                            NameStreamMap* name_stream_map) {
 435  E :    DCHECK(pdb_header != NULL);
 436  E :    DCHECK(name_stream_map != NULL);
 437    :  
 438    :    // Get the stream reader.
 439  E :    if (kPdbHeaderInfoStream >= pdb_file.StreamCount()) {
 440  E :      LOG(ERROR) << "No header info stream found.";
 441  E :      return false;
 442    :    }
 443  E :    scoped_refptr<PdbStream> header_reader(
 444    :        pdb_file.GetStream(kPdbHeaderInfoStream));
 445  E :    if (header_reader.get() == NULL) {
 446  i :      LOG(ERROR) << "No header info stream found.";
 447  i :      return false;
 448    :    }
 449    :  
 450    :    // Read the header.
 451  E :    if (!pdb::ReadHeaderInfoStream(header_reader.get(), pdb_header,
 452    :                                   name_stream_map)) {
 453  i :      LOG(ERROR) << "Failed to read header info stream.";
 454  i :      return false;
 455    :    }
 456    :  
 457  E :    return true;
 458  E :  }
 459    :  
 460    :  bool ReadHeaderInfoStream(PdbStream* pdb_stream,
 461    :                            PdbInfoHeader70* pdb_header,
 462  E :                            NameStreamMap* name_stream_map) {
 463  E :    DCHECK(pdb_stream);
 464  E :    DCHECK(pdb_header);
 465  E :    DCHECK(name_stream_map);
 466  E :    VLOG(1) << "Header Info Stream size: " << pdb_stream->length();
 467    :  
 468  E :    pdb::PdbStreamReaderWithPosition reader(pdb_stream);
 469  E :    common::BinaryStreamParser parser(&reader);
 470    :    // The header stream starts with the fixed-size header pdb_header record.
 471  E :    if (!parser.Read(pdb_header)) {
 472  E :      LOG(ERROR) << "Unable to read PDB pdb_header header.";
 473  E :      return false;
 474    :    }
 475    :  
 476  E :    uint32_t string_len = 0;
 477  E :    if (!parser.Read(&string_len)) {
 478  E :      LOG(ERROR) << "Unable to read string table length.";
 479  E :      return false;
 480    :    }
 481    :  
 482    :    // The fixed-size record is followed by information on named streams, which
 483    :    // is essentially a string->id mapping. This starts with the strings
 484    :    // themselves, which have been observed to be a packed run of zero-terminated
 485    :    // strings.
 486    :    // We store the start of the string list, as the string positions we read
 487    :    // later are relative to that position.
 488  E :    size_t string_start = reader.Position();
 489    :  
 490    :    // Seek past the strings.
 491  E :    if (!reader.Consume(string_len)) {
 492  i :      LOG(ERROR) << "Unable to seek past string list";
 493  i :      return false;
 494    :    }
 495    :  
 496    :    // Next there's a pair of integers. The first one of those is the number of
 497    :    // items in the string->id mapping. The purpose of the second one is not
 498    :    // clear, but has been observed as larger or equal to the first one.
 499  E :    uint32_t size = 0;
 500  E :    uint32_t max = 0;
 501  E :    if (!parser.Read(&size) || !parser.Read(&max)) {
 502  i :      LOG(ERROR) << "Unable to read name pdb_stream size/max";
 503  i :      return false;
 504    :    }
 505  E :    DCHECK(max >= size);
 506    :  
 507    :    // After the counts, there's a pair of bitsets. Each bitset has a 32 bit
 508    :    // length, followed by that number of 32 bit words that contain the bits.
 509    :    // The purpose of those is again not clear, though the first set will have
 510    :    // "size" bits of the bits in the range 0-max set.
 511  E :    PdbBitSet used;
 512  E :    PdbBitSet deleted;
 513  E :    if (!used.Read(&reader) || !deleted.Read(&reader)) {
 514  i :      LOG(ERROR) << "Unable to read name pdb_stream bitsets.";
 515  i :      return false;
 516    :    }
 517    :  
 518    :  #ifndef NDEBUG
 519    :    // The first bitset has "size" bits set of the first "max" bits.
 520  E :    size_t set_bits = 0;
 521  E :    for (size_t i = 0; i < max; ++i) {
 522  E :      if (used.IsSet(i))
 523  E :        ++set_bits;
 524  E :    }
 525    :  
 526    :    // The second bitset has always been observed to be empty.
 527  E :    DCHECK(deleted.IsEmpty());
 528    :  
 529  E :    DCHECK_EQ(size, set_bits);
 530    :  #endif
 531    :  
 532    :    // Read the mapping proper, this is simply a run of {string offset, id} pairs.
 533  E :    for (size_t i = 0; i < size; ++i) {
 534  E :      uint32_t str_offs = 0;
 535  E :      uint32_t stream_no = 0;
 536    :      // Read the offset and pdb_stream number.
 537  E :      if (!parser.Read(&str_offs) || !parser.Read(&stream_no)) {
 538  i :        LOG(ERROR) << "Unable to read pdb_stream data.";
 539  i :        return false;
 540    :      }
 541    :  
 542    :      // Read the string itself from the table.
 543  E :      std::string name;
 544  E :      if (!ReadStringAt(pdb_stream, string_start + str_offs, &name)) {
 545  i :        LOG(ERROR) << "Failed to read pdb_stream name.";
 546  i :        return false;
 547    :      }
 548    :  
 549  E :      (*name_stream_map)[name] = stream_no;
 550  E :    }
 551    :  
 552  E :    return true;
 553  E :  }
 554    :  
 555    :  bool WriteHeaderInfoStream(const PdbInfoHeader70& header,
 556    :                             const NameStreamMap& name_stream_map,
 557  E :                             PdbFile* pdb_file) {
 558  E :    DCHECK(pdb_file != NULL);
 559    :  
 560  E :    if (!pdb::EnsureStreamWritable(pdb::kPdbHeaderInfoStream, pdb_file)) {
 561  i :      LOG(ERROR) << "Failed to make PDB Header Info stream writable.";
 562  i :      return false;
 563    :    }
 564    :  
 565    :    // Get the stream reader.
 566  E :    scoped_refptr<PdbStream> header_reader(
 567    :        pdb_file->GetStream(pdb::kPdbHeaderInfoStream));
 568  E :    DCHECK(header_reader.get() != NULL);
 569    :  
 570    :    // Get the stream writer.
 571  E :    scoped_refptr<WritablePdbStream> header_writer(
 572    :        header_reader->GetWritableStream());
 573  E :    DCHECK(header_writer.get() != NULL);
 574    :  
 575    :    // Write the new header.
 576  E :    if (!WriteHeaderInfoStream(header, name_stream_map, header_writer.get())) {
 577  i :      LOG(ERROR) << "Failed to write PDB Header Info stream.";
 578  i :      return false;
 579    :    }
 580    :  
 581  E :    return true;
 582  E :  }
 583    :  
 584    :  bool WriteHeaderInfoStream(const PdbInfoHeader70& pdb_header,
 585    :                             const NameStreamMap& name_stream_map,
 586  E :                             WritablePdbStream* pdb_stream) {
 587  E :    DCHECK(pdb_stream != NULL);
 588    :  
 589  E :    if (!pdb_stream->Write(pdb_header)) {
 590  i :      LOG(ERROR) << "Failed to write PDB header.";
 591  i :      return false;
 592    :    }
 593    :  
 594    :    // Calculate the hash table entry count and size.
 595  E :    uint32_t string_count = name_stream_map.size();
 596  E :    uint32_t table_size = GetNamedStreamsHashTableSize(string_count);
 597    :  
 598    :    // Initialize the 'used' bitset.
 599  E :    PdbBitSet used;
 600  E :    used.Resize(table_size);
 601    :  
 602    :    // Get the string table length. We also calculate hashes for each name,
 603    :    // populating the 'used' bitset and determining the order in which to output
 604    :    // the stream names.
 605  E :    std::vector<NamedStreamInfo> name_infos;
 606  E :    name_infos.reserve(string_count);
 607  E :    uint32_t string_length = 0;
 608  E :    NameStreamMap::const_iterator name_it = name_stream_map.begin();
 609  E :    for (; name_it != name_stream_map.end(); ++name_it) {
 610  E :      uint16_t hash = HashString(name_it->first);
 611  E :      size_t bucket = hash % table_size;
 612  E :      bucket = SetNamedStreamsHashTableBit(bucket, table_size, &used);
 613  E :      name_infos.push_back(NamedStreamInfo(name_it, 0, bucket));
 614  E :      string_length += name_it->first.size() + 1;  // Include the trailing zero.
 615  E :    }
 616    :  
 617    :    // Sort the strings in the order in which they will be output.
 618  E :    std::sort(name_infos.begin(), name_infos.end());
 619    :  
 620    :    // Dump the string table.
 621  E :    if (!pdb_stream->Write(string_length)) {
 622  i :      LOG(ERROR) << "Failed to write stream name table length.";
 623  i :      return false;
 624    :    }
 625  E :    string_length = 0;
 626  E :    for (size_t i = 0; i < name_infos.size(); ++i) {
 627  E :      name_infos[i].offset = string_length;
 628  E :      name_it = name_infos[i].it;
 629  E :      string_length += name_it->first.size() + 1;
 630  E :      if (!pdb_stream->Write(name_it->first.size() + 1, name_it->first.c_str())) {
 631  i :        LOG(ERROR) << "Failed to write stream name.";
 632  i :        return false;
 633    :      }
 634  E :    }
 635    :  
 636    :    // Write the string hash table size.
 637  E :    if (!pdb_stream->Write(string_count) || !pdb_stream->Write(table_size)) {
 638  i :      LOG(ERROR) << "Failed to write string table size.";
 639  i :      return false;
 640    :    }
 641    :  
 642    :    // Write the 'used' bitset.
 643  E :    if (!used.Write(pdb_stream, true)) {
 644  i :      LOG(ERROR) << "Failed to write 'used' bitset.";
 645  i :      return false;
 646    :    }
 647    :  
 648    :    // The 'deleted' bitset is always empty.
 649  E :    PdbBitSet deleted;
 650  E :    DCHECK(deleted.IsEmpty());
 651  E :    if (!deleted.Write(pdb_stream, true)) {
 652  i :      LOG(ERROR) << "Failed to write 'deleted' bitset.";
 653  i :      return false;
 654    :    }
 655    :  
 656    :    // Now output the actual mapping, a run of (string table offset, stream id)
 657    :    // pairs. We output these in order of hash table buckets of each name,
 658    :    // mimicking the output produced by pdbstr.exe.
 659  E :    for (size_t i = 0; i < name_infos.size(); ++i) {
 660  E :      if (!pdb_stream->Write(name_infos[i].offset) ||
 661    :          !pdb_stream->Write(name_infos[i].it->second)) {
 662  i :        LOG(ERROR) << "Failed to write stream name mapping.";
 663  i :        return false;
 664    :      }
 665  E :    }
 666    :  
 667    :    // The run of pairs must be terminated with a single NULL entry.
 668  E :    if (!pdb_stream->Write(static_cast<uint32_t>(0))) {
 669  i :      LOG(ERROR) << "Failed to write terminating NULL.";
 670  i :      return false;
 671    :    }
 672    :  
 673  E :    return true;
 674  E :  }
 675    :  
 676    :  bool ReadStringTable(PdbStream* stream,
 677    :                       const char* table_name,
 678    :                       size_t table_start,
 679    :                       size_t table_end,
 680  E :                       OffsetStringMap* string_map) {
 681  E :    DCHECK(stream != NULL);
 682  E :    DCHECK(table_name != NULL);
 683  E :    DCHECK(string_map != NULL);
 684  E :    DCHECK_LE(table_start, table_end);
 685  E :    uint32_t string_table_signature = 0;
 686  E :    uint32_t string_table_version = 0;
 687    :  
 688  E :    size_t table_len = table_end - table_start;
 689  E :    pdb::PdbStreamReaderWithPosition reader(table_start, table_len, stream);
 690  E :    common::BinaryStreamParser parser(&reader);
 691  E :    if (!parser.Read(&string_table_signature) ||
 692    :        !parser.Read(&string_table_version)) {
 693  i :      LOG(ERROR) << "Unable to seek to " << table_name << " stream.";
 694  i :      return false;
 695    :    }
 696    :  
 697  E :    if (string_table_signature != kPdbStringTableSignature ||
 698    :        string_table_version != kPdbStringTableVersion) {
 699  i :      LOG(ERROR) << "Unexpected " << table_name << " header. Expected "
 700    :                 << "signature/version "
 701    :                 << base::StringPrintf("0x%08X", kPdbStringTableSignature) << "/"
 702    :                 << kPdbStringTableVersion << ", read "
 703    :                 << base::StringPrintf("0x%08X", string_table_signature) << "/"
 704    :                 << string_table_version << ".";
 705  i :      return false;
 706    :    }
 707    :  
 708  E :    size_t string_table_size = 0;
 709  E :    if (!parser.Read(&string_table_size)) {
 710  i :      LOG(ERROR) << "Unable to read the size of the " << table_name << " string "
 711    :                 << "table.";
 712  i :      return false;
 713    :    }
 714    :  
 715  E :    size_t string_table_start = table_start + reader.Position();
 716    :  
 717    :    // Skip the string table and seek to the offset table.
 718  E :    if (!reader.Consume(string_table_size)) {
 719  i :      LOG(ERROR) << "Unable to seek to the " << table_name << " offset table.";
 720  i :      return false;
 721    :    }
 722    :  
 723  E :    size_t entries_count = 0;
 724  E :    if (!parser.Read(&entries_count)) {
 725  i :      LOG(ERROR) << "Unable to read the number of entries in the " << table_name
 726    :                 << " offset table.";
 727  i :      return false;
 728    :    }
 729    :  
 730    :    // Some of the offsets present in the offset table have the value 0, which
 731    :    // refers to an empty string present at the beginning of the string table.
 732  E :    for (size_t i = 0; i < entries_count; ++i) {
 733  E :      size_t string_offset = 0;
 734  E :      if (!parser.Read(&string_offset)) {
 735  i :        LOG(ERROR) << "Unable to read the " << table_name << " name table.";
 736  i :        return false;
 737    :      }
 738    :      // TODO(siggi): It'd be handy to have a PdbStreamReaderWithPos slice
 739    :      //    operand to avoid this kind of arithmetic.
 740  E :      size_t string_stream_offset = string_offset + string_table_start;
 741  E :      pdb::PdbStreamReaderWithPosition string_reader(
 742    :          string_stream_offset, table_end - string_stream_offset, stream);
 743  E :      common::BinaryStreamParser string_parser(&string_reader);
 744  E :      std::string temp_string;
 745  E :      if (!string_parser.ReadString(&temp_string)) {
 746  i :        LOG(ERROR) << "Unable to read the " << table_name << " name table.";
 747  i :        return false;
 748    :      }
 749    :  
 750  E :      string_map->insert(std::make_pair(string_offset, temp_string));
 751  E :    }
 752    :  
 753  E :    uint32_t string_count = 0;
 754    :    // Sometimes the string_count field matches the number of non-empty strings
 755    :    // in the string_map and sometimes it doesn't.
 756    :    // TODO(sebmarchand) : understand what's this value once the compiland streams
 757    :    //     are deciphered.
 758  E :    if (!parser.Read(&string_count)) {
 759  i :      LOG(ERROR) << "Unable to read the number of files present in the "
 760    :                 << table_name << " stream.";
 761  i :      return false;
 762    :    }
 763    :  
 764  E :    if (reader.Position() != table_len) {
 765  i :      LOG(ERROR) << table_name << " stream is not valid.";
 766  i :      return false;
 767    :    }
 768    :  
 769  E :    return true;
 770  E :  }
 771    :  
 772    :  bool LoadNamedStreamFromPdbFile(
 773    :      const base::StringPiece& stream_name,
 774    :      PdbFile* pdb_file,
 775  E :      scoped_refptr<PdbStream>* stream) {
 776  E :    DCHECK(pdb_file != NULL);
 777  E :    DCHECK(stream != NULL);
 778  E :    DCHECK(stream->get() == NULL);
 779    :  
 780    :    // Get the PDB header and try to get the named stream ID from it.
 781  E :    pdb::PdbInfoHeader70 pdb_header = {0};
 782  E :    pdb::NameStreamMap name_stream_map;
 783  E :    if (!ReadHeaderInfoStream(
 784    :            pdb_file->GetStream(pdb::kPdbHeaderInfoStream).get(), &pdb_header,
 785    :            &name_stream_map)) {
 786  i :      LOG(ERROR) << "Failed to read header info stream.";
 787  i :      return false;
 788    :    }
 789    :  
 790    :    // The stream with the given name does not exist.
 791  E :    pdb::NameStreamMap::const_iterator name_it = name_stream_map.find(
 792    :        stream_name.as_string());
 793  E :    if (name_it == name_stream_map.end())
 794  E :      return true;
 795    :  
 796    :    // Get the named stream and ensure that it's not empty.
 797  E :    *stream = pdb_file->GetStream(name_it->second);
 798  E :    if (stream->get() == NULL) {
 799  i :      LOG(ERROR) << "Failed to read the \"" << stream_name.as_string()
 800    :                 << "\" stream from the PDB.";
 801  i :      return false;
 802    :    }
 803    :  
 804  E :    return true;
 805  E :  }
 806    :  
 807    :  }  // namespace pdb

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