Coverage for /Syzygy/block_graph/block_graph_serializer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
76.4%3634750.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/block_graph/block_graph_serializer.h"
  16    :  
  17    :  #include "base/strings/stringprintf.h"
  18    :  
  19    :  namespace block_graph {
  20    :  
  21    :  namespace {
  22    :  
  23    :  using core::InArchive;
  24    :  using core::OutArchive;
  25    :  
  26    :  // This needs to be incremented any time a non-backwards compatible change
  27    :  // is made to the serialization format.
  28    :  // TODO(chrisha): Enforce this via a unittest. Check in a version of a
  29    :  //     simple block-graph, and ensure it deserializes to the same in-memory
  30    :  //     representation.
  31    :  // Version 3: Added image_format_ block-graph property.
  32    :  // Version 4: Deprecated old decomposer attributes.
  33    :  // Version 5: Added new Block attributes: padding_before and alignment_offset.
  34    :  static const uint32_t kSerializedBlockGraphVersion = 5;
  35    :  
  36    :  // Some constants for use in dealing with backwards compatibility.
  37    :  static const uint32_t kMinSupportedSerializedBlockGraphVersion = 2;
  38    :  static const uint32_t kImageFormatPropertyBlockGraphVersion = 3;
  39    :  static const uint32_t kPaddingBeforePropertyBlockGraphVersion = 5;
  40    :  
  41    :  // Potentially saves a string, depending on whether or not OMIT_STRINGS is
  42    :  // enabled.
  43    :  bool MaybeSaveString(const BlockGraphSerializer& bgs,
  44    :                       const std::string& value,
  45  E :                       OutArchive* out_archive) {
  46  E :    DCHECK(out_archive != NULL);
  47    :  
  48  E :    if (bgs.has_attributes(BlockGraphSerializer::OMIT_STRINGS))
  49  E :      return true;
  50    :  
  51  E :    if (!out_archive->Save(value)) {
  52  i :      LOG(ERROR) << "Unable to save string \"" << value << "\".";
  53  i :      return false;
  54    :    }
  55    :  
  56  E :    return true;
  57  E :  }
  58    :  
  59    :  // Potentially loads a string, depending on whether or not OMIT_STRINGS is
  60    :  // enabled.
  61    :  bool MaybeLoadString(const BlockGraphSerializer& bgs,
  62    :                       std::string* value,
  63  E :                       InArchive* in_archive) {
  64  E :    DCHECK(value != NULL);
  65  E :    DCHECK(in_archive != NULL);
  66    :  
  67  E :    if (bgs.has_attributes(BlockGraphSerializer::OMIT_STRINGS))
  68  E :      return true;
  69    :  
  70  E :    if (!in_archive->Load(value)) {
  71  i :      LOG(ERROR) << "Unable to load string.";
  72  i :      return false;
  73    :    }
  74    :  
  75  E :    return true;
  76  E :  }
  77    :  
  78  E :  bool ValidAttributes(uint32_t attributes, uint32_t attributes_max) {
  79  E :    return (attributes & ~(attributes_max - 1)) == 0;
  80  E :  }
  81    :  
  82    :  }  // namespace
  83    :  
  84    :  bool BlockGraphSerializer::Save(const BlockGraph& block_graph,
  85  E :                                  core::OutArchive* out_archive) const {
  86  E :    CHECK(out_archive != NULL);
  87    :  
  88    :    // Save the serialization attributes so we can read this block-graph without
  89    :    // having to be told how it was saved.
  90    :    if (!out_archive->Save(kSerializedBlockGraphVersion) ||
  91  E :        !out_archive->Save(static_cast<uint32_t>(data_mode_)) ||
  92    :        !out_archive->Save(attributes_)) {
  93  i :      LOG(ERROR) << "Unable to save serialized block-graph properties.";
  94  i :      return false;
  95    :    }
  96    :  
  97    :    // TODO(etienneb): We should serialize the string table in the block graph,
  98    :    //    and encode string ids instead of the raw strings.
  99    :  
 100    :    // This function takes care of outputting a meaningful log message on
 101    :    // failure.
 102  E :    if (!SaveBlockGraphProperties(block_graph, out_archive))
 103  i :      return false;
 104    :  
 105    :    // Save the blocks, except for their references. We do that in a second pass
 106    :    // so that when loading the referenced blocks will exist.
 107  E :    if (!SaveBlocks(block_graph, out_archive)) {
 108  i :      LOG(ERROR) << "Unable to save blocks.";
 109  i :      return false;
 110    :    }
 111    :  
 112    :    // Save all of the references. The referrers are implicitly saved by this.
 113  E :    if (!SaveBlockGraphReferences(block_graph, out_archive)) {
 114  i :      LOG(ERROR) << "Unable to save block graph references.";
 115  i :      return false;
 116    :    }
 117    :  
 118  E :    return true;
 119  E :  }
 120    :  
 121    :  bool BlockGraphSerializer::Load(BlockGraph* block_graph,
 122  E :                                  core::InArchive* in_archive) {
 123  E :    CHECK(block_graph != NULL);
 124  E :    CHECK(in_archive != NULL);
 125    :  
 126  E :    uint32_t version = 0;
 127  E :    if (!in_archive->Load(&version)) {
 128  i :      LOG(ERROR) << "Unable to load serialized block graph version.";
 129  i :      return false;
 130    :    }
 131    :  
 132    :    // We are backwards compatible back to version 2, for now.
 133  E :    if (version < kMinSupportedSerializedBlockGraphVersion ||
 134    :        version > kSerializedBlockGraphVersion) {
 135  E :      LOG(ERROR) << "Unable to load block graph with version " << version << ".";
 136  E :      return false;
 137    :    }
 138    :  
 139    :    // Read the serialization attributes and mode information so that we know how
 140    :    // to load the block-graph.
 141  E :    uint32_t data_mode = 0;
 142  E :    if (!in_archive->Load(&data_mode) || !in_archive->Load(&attributes_)) {
 143  i :      LOG(ERROR) << "Unable to load serialized block-graph properties.";
 144  i :      return false;
 145    :    }
 146  E :    data_mode_ = static_cast<DataMode>(data_mode);
 147    :  
 148    :    // Ensure that the data mode and the attributes are valid.
 149  E :    if (data_mode_ >= DATA_MODE_MAX ||
 150    :        !ValidAttributes(attributes_, ATTRIBUTES_MAX)) {
 151  i :      LOG(ERROR) << "Invalid data mode and/or attributes.";
 152  i :      return false;
 153    :    }
 154    :  
 155    :    // This function takes care of outputting a meaningful log message on
 156    :    // failure.
 157  E :    if (!LoadBlockGraphProperties(version, block_graph, in_archive))
 158  i :      return false;
 159    :  
 160    :    // Load the blocks, except for their references.
 161  E :    if (!LoadBlocks(version, block_graph, in_archive)) {
 162  i :      LOG(ERROR) << "Unable to load blocks.";
 163  i :      return false;
 164    :    }
 165    :  
 166    :    // Now load the references and wire them up.
 167  E :    if (!LoadBlockGraphReferences(block_graph, in_archive)) {
 168  i :      LOG(ERROR) << "Unable to load block graph references.";
 169  i :      return false;
 170    :    }
 171    :  
 172  E :    return true;
 173  E :  }
 174    :  
 175    :  bool BlockGraphSerializer::SaveBlockGraphProperties(
 176    :      const BlockGraph& block_graph,
 177  E :      OutArchive* out_archive) const {
 178  E :    DCHECK(out_archive != NULL);
 179    :  
 180    :    if (!out_archive->Save(block_graph.next_section_id_) ||
 181    :        !out_archive->Save(block_graph.sections_) ||
 182  E :        !out_archive->Save(block_graph.next_block_id_) ||
 183    :        !out_archive->Save(static_cast<uint8_t>(block_graph.image_format_))) {
 184  i :      LOG(ERROR) << "Unable to save block graph properties.";
 185  i :      return false;
 186    :    }
 187    :  
 188  E :    return true;
 189  E :  }
 190    :  
 191    :  bool BlockGraphSerializer::LoadBlockGraphProperties(
 192    :      uint32_t version,
 193    :      BlockGraph* block_graph,
 194  E :      InArchive* in_archive) const {
 195  E :    DCHECK(block_graph != NULL);
 196  E :    DCHECK(in_archive != NULL);
 197    :  
 198    :    // The block graph properties should be empty.
 199  E :    DCHECK_EQ(0u, block_graph->next_section_id_);
 200  E :    DCHECK_EQ(0u, block_graph->sections_.size());
 201  E :    DCHECK_EQ(0u, block_graph->next_block_id_);
 202    :  
 203    :    if (!in_archive->Load(&block_graph->next_section_id_) ||
 204  E :        !in_archive->Load(&block_graph->sections_) ||
 205    :        !in_archive->Load(&block_graph->next_block_id_)) {
 206  i :      LOG(ERROR) << "Unable to load block graph properties.";
 207  i :      return false;
 208    :    }
 209    :  
 210    :    // Read the image format property. This is not present in all versions of the
 211    :    // block-graph.
 212  E :    uint8_t image_format = 0;
 213  E :    if (version >= kImageFormatPropertyBlockGraphVersion) {
 214  E :      if (!in_archive->Load(&image_format)) {
 215  i :        LOG(ERROR) << "Unable to load block graph image format.";
 216  i :        return false;
 217    :      }
 218  E :    } else {
 219    :      // We default to the PE format, as COFF images were not previously
 220    :      // supported.
 221  E :      image_format = BlockGraph::PE_IMAGE;
 222    :    }
 223  E :    block_graph->image_format_ = static_cast<BlockGraph::ImageFormat>(
 224    :        image_format);
 225    :  
 226  E :    return true;
 227  E :  }
 228    :  
 229    :  bool BlockGraphSerializer::SaveBlocks(const BlockGraph& block_graph,
 230  E :                                        OutArchive* out_archive) const {
 231  E :    DCHECK(out_archive != NULL);
 232    :  
 233  E :    if (!out_archive->Save(block_graph.blocks().size())) {
 234  i :      LOG(ERROR) << "Unable to save block count.";
 235  i :      return false;
 236    :    }
 237    :  
 238    :    // Output the basic block properties first.
 239  E :    BlockGraph::BlockMap::const_iterator it = block_graph.blocks_.begin();
 240  E :    for (; it != block_graph.blocks_.end(); ++it) {
 241  E :      BlockGraph::BlockId block_id = it->first;
 242  E :      const BlockGraph::Block& block = it->second;
 243    :      if (!out_archive->Save(block_id) ||
 244    :          !SaveBlockProperties(block, out_archive) ||
 245  E :          !SaveBlockLabels(block, out_archive) ||
 246    :          !SaveBlockData(block, out_archive)) {
 247  i :        LOG(ERROR) << "Unable to save block with id " << block_id << ".";
 248  i :        return false;
 249    :      }
 250  E :    }
 251    :  
 252  E :    return true;
 253  E :  }
 254    :  
 255    :  bool BlockGraphSerializer::LoadBlocks(uint32_t version,
 256    :                                        BlockGraph* block_graph,
 257  E :                                        InArchive* in_archive) const {
 258  E :    DCHECK(block_graph != NULL);
 259  E :    DCHECK(in_archive != NULL);
 260    :  
 261  E :    DCHECK_EQ(0u, block_graph->blocks_.size());
 262    :  
 263  E :    size_t count = 0;
 264  E :    if (!in_archive->Load(&count)) {
 265  i :      LOG(ERROR) << "Unable to load block count.";
 266  i :      return false;
 267    :    }
 268    :  
 269  E :    for (size_t i = 0; i < count; ++i) {
 270  E :      BlockGraph::BlockId id = 0;
 271  E :      if (!in_archive->Load(&id)) {
 272  i :        LOG(ERROR) << "Unable to load id for block " << i << " of " << count
 273    :                   << ".";
 274  i :        return false;
 275    :      }
 276    :  
 277    :      std::pair<BlockGraph::BlockMap::iterator, bool> result =
 278  E :          block_graph->blocks_.insert(
 279    :              std::make_pair(id, BlockGraph::Block(block_graph)));
 280  E :      if (!result.second) {
 281  i :        LOG(ERROR) << "Unable to insert block with id " << id << ".";
 282  i :        return false;
 283    :      }
 284  E :      BlockGraph::Block* block = &result.first->second;
 285  E :      block->id_ = id;
 286    :  
 287    :      if (!LoadBlockProperties(version, block, in_archive) ||
 288  E :          !LoadBlockLabels(block, in_archive) ||
 289    :          !LoadBlockData(block, in_archive)) {
 290  i :        LOG(ERROR) << "Unable to load block " << i << " of " << count
 291    :                   << " with id " << id << ".";
 292  i :        return false;
 293    :      }
 294  E :    }
 295  E :    DCHECK_EQ(count, block_graph->blocks_.size());
 296    :  
 297  E :    return true;
 298  E :  }
 299    :  
 300    :  bool BlockGraphSerializer::SaveBlockGraphReferences(
 301  E :      const BlockGraph& block_graph, OutArchive* out_archive) const {
 302  E :    DCHECK(out_archive != NULL);
 303    :  
 304  E :    BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
 305  E :    for (; it != block_graph.blocks().end(); ++it) {
 306  E :      if (!SaveBlockReferences(it->second, out_archive)) {
 307  i :        LOG(ERROR) << "Unable to save references for block with id "
 308    :                   << it->second.id() << ".";
 309  i :        return false;
 310    :      }
 311  E :    }
 312    :  
 313  E :    return true;
 314  E :  }
 315    :  
 316    :  bool BlockGraphSerializer::LoadBlockGraphReferences(
 317  E :      BlockGraph* block_graph, InArchive* in_archive) const {
 318  E :    DCHECK(block_graph != NULL);
 319  E :    DCHECK(in_archive != NULL);
 320    :  
 321  E :    BlockGraph::BlockMap::iterator it = block_graph->blocks_mutable().begin();
 322  E :    for (; it != block_graph->blocks_mutable().end(); ++it) {
 323  E :      if (!LoadBlockReferences(block_graph, &it->second, in_archive)) {
 324  i :        LOG(ERROR) << "Unable to load references for block with id "
 325    :                   << it->second.id() << ".";
 326  i :        return false;
 327    :      }
 328  E :    }
 329    :  
 330  E :    return true;
 331  E :  }
 332    :  
 333    :  bool BlockGraphSerializer::SaveBlockProperties(const BlockGraph::Block& block,
 334  E :                                                 OutArchive* out_archive) const {
 335  E :    DCHECK(out_archive != NULL);
 336    :  
 337  E :    uint8_t type = static_cast<uint8_t>(block.type());
 338    :  
 339    :    // We use a signed integer for saving the section ID, as -1 is used to
 340    :    // indicate 'no section'.
 341    :    if (!out_archive->Save(type) ||
 342    :        !SaveUint32(static_cast<uint32_t>(block.size()), out_archive) ||
 343    :        !SaveUint32(static_cast<uint32_t>(block.alignment()), out_archive) ||
 344    :        !SaveInt32(block.alignment_offset(), out_archive) ||
 345    :        !SaveUint32(static_cast<uint32_t>(block.padding_before()), out_archive) ||
 346    :        !out_archive->Save(block.source_ranges()) ||
 347    :        !out_archive->Save(block.addr()) ||
 348    :        !SaveInt32(static_cast<uint32_t>(block.section()), out_archive) ||
 349    :        !out_archive->Save(block.attributes()) ||
 350  E :        !MaybeSaveString(*this, block.name(), out_archive) ||
 351    :        !MaybeSaveString(*this, block.compiland_name(), out_archive)) {
 352  i :      LOG(ERROR) << "Unable to save properties for block with id "
 353    :                 << block.id() << ".";
 354  i :      return false;
 355    :    }
 356    :  
 357  E :    return true;
 358  E :  }
 359    :  
 360    :  bool BlockGraphSerializer::LoadBlockPropertiesImpl(
 361    :      uint32_t version,
 362    :      BlockGraph::Block* block,
 363  E :      InArchive* in_archive) const {
 364  E :    DCHECK(block != NULL);
 365  E :    DCHECK(in_archive != NULL);
 366    :  
 367    :    // Make sure the block is freshly initialized.
 368  E :    DCHECK_EQ(BlockGraph::CODE_BLOCK, block->type_);
 369  E :    DCHECK_EQ(0u, block->size_);
 370  E :    DCHECK_EQ(1u, block->alignment_);
 371  E :    DCHECK_EQ(0u, block->source_ranges_.size());
 372  E :    DCHECK_EQ(RelativeAddress::kInvalidAddress, block->addr_);
 373  E :    DCHECK_EQ(BlockGraph::kInvalidSectionId, block->section_);
 374  E :    DCHECK_EQ(0u, block->attributes_);
 375    :  
 376  E :    uint8_t type = 0;
 377  E :    uint32_t size = 0;
 378  E :    uint32_t alignment = 0;
 379  E :    int32_t alignment_offset = 0;
 380  E :    uint32_t padding_before = 0;
 381  E :    uint32_t section = 0;
 382  E :    uint32_t attributes = 0;
 383  E :    std::string name;
 384  E :    std::string compiland_name;
 385    :    if (!in_archive->Load(&type) ||
 386  E :        !LoadUint32(&size, in_archive) ||
 387    :        !LoadUint32(&alignment, in_archive)) {
 388  i :      return false;
 389    :    }
 390  E :    if (version >= kPaddingBeforePropertyBlockGraphVersion) {
 391  E :      if (!LoadInt32(&alignment_offset, in_archive) ||
 392    :          !LoadUint32(&padding_before, in_archive)) {
 393  i :        return false;
 394    :      }
 395    :    }
 396    :    if (!in_archive->Load(&block->source_ranges_) ||
 397    :        !in_archive->Load(&block->addr_) ||
 398    :        !LoadInt32(reinterpret_cast<int32_t*>(&section), in_archive) ||
 399    :        !in_archive->Load(&attributes) ||
 400  E :        !MaybeLoadString(*this, &name, in_archive) ||
 401    :        !MaybeLoadString(*this, &compiland_name, in_archive)) {
 402  i :      return false;
 403    :    }
 404    :  
 405  E :    if (type > BlockGraph::BLOCK_TYPE_MAX ||
 406    :        !ValidAttributes(attributes, BlockGraph::BLOCK_ATTRIBUTES_MAX)) {
 407  i :      LOG(ERROR) << "Invalid block type (" << static_cast<uint32_t>(type)
 408    :                 << ") and/or attributes ("
 409    :                 << base::StringPrintf("%04X", attributes)
 410    :                 << ") for block with id " << block->id() << ".";
 411  i :      return false;
 412    :    }
 413    :  
 414  E :    block->type_ = static_cast<BlockGraph::BlockType>(type);
 415  E :    block->size_ = size;
 416  E :    block->alignment_ = alignment;
 417  E :    block->alignment_offset_ = alignment_offset;
 418  E :    block->padding_before_ = padding_before;
 419  E :    block->section_ = section;
 420  E :    block->attributes_ = attributes;
 421  E :    block->set_name(name);
 422  E :    block->set_compiland_name(compiland_name);
 423  E :    return true;
 424  E :  }
 425    :  
 426    :  bool BlockGraphSerializer::LoadBlockProperties(uint32_t version,
 427    :                                                 BlockGraph::Block* block,
 428  E :                                                 InArchive* in_archive) const {
 429  E :    DCHECK(block != NULL);
 430  E :    DCHECK(in_archive != NULL);
 431    :  
 432  E :    if (!LoadBlockPropertiesImpl(version, block, in_archive)) {
 433  i :      LOG(ERROR) << "Unable to load properties for block with id "
 434    :                 << block->id() << ".";
 435  i :      return false;
 436    :    }
 437    :  
 438  E :    return true;
 439  E :  }
 440    :  
 441    :  bool BlockGraphSerializer::SaveBlockLabels(const BlockGraph::Block& block,
 442  E :                                             OutArchive* out_archive) const {
 443  E :    DCHECK(out_archive != NULL);
 444    :  
 445  E :    if (has_attributes(BlockGraphSerializer::OMIT_LABELS))
 446  i :      return true;
 447    :  
 448  E :    uint32_t count = static_cast<uint32_t>(block.labels().size());
 449  E :    if (!SaveUint32(count, out_archive)) {
 450  i :      LOG(ERROR) << "Unable to save label count.";
 451  i :      return false;
 452    :    }
 453    :  
 454    :    BlockGraph::Block::LabelMap::const_iterator label_iter =
 455  E :        block.labels().begin();
 456  E :    for (; label_iter != block.labels().end(); ++label_iter) {
 457    :      static_assert(BlockGraph::LABEL_ATTRIBUTES_MAX <= (1 << 16),
 458    :                    "Label attributes requires more than 16 bits.");
 459    :  
 460  E :      int32_t offset = label_iter->first;
 461  E :      const BlockGraph::Label& label = label_iter->second;
 462  E :      uint16_t attributes = static_cast<uint16_t>(label.attributes());
 463    :  
 464  E :      if (!SaveInt32(offset, out_archive) || !out_archive->Save(attributes) ||
 465    :          !MaybeSaveString(*this, label.name(), out_archive)) {
 466  i :        LOG(ERROR) << "Unable to save label at offset "
 467    :                   << label_iter->first << " of block with id "
 468    :                   << block.id() << ".";
 469  i :        return false;
 470    :      }
 471  E :    }
 472    :  
 473  E :    return true;
 474  E :  }
 475    :  
 476    :  bool BlockGraphSerializer::LoadBlockLabels(BlockGraph::Block* block,
 477  E :                                             InArchive* in_archive) const {
 478  E :    DCHECK(block != NULL);
 479  E :    DCHECK(in_archive != NULL);
 480    :  
 481    :    // The block shouldn't have any labels yet.
 482  E :    DCHECK_EQ(0u, block->labels().size());
 483    :  
 484  E :    if (has_attributes(BlockGraphSerializer::OMIT_LABELS))
 485  i :      return true;
 486    :  
 487  E :    uint32_t label_count = 0;
 488  E :    if (!LoadUint32(&label_count, in_archive)) {
 489  i :      LOG(ERROR) << "Unable to load label count.";
 490  i :      return false;
 491    :    }
 492    :  
 493  E :    for (size_t i = 0; i < label_count; ++i) {
 494  E :      int32_t offset = 0;
 495  E :      uint16_t attributes = 0;
 496  E :      std::string name;
 497    :  
 498  E :      if (!LoadInt32(&offset, in_archive) || !(in_archive->Load(&attributes)) ||
 499    :          !MaybeLoadString(*this, &name, in_archive)) {
 500  i :        LOG(ERROR) << "Unable to load label " << i << " of " << label_count
 501    :                   << " for block with id " << block->id() << ".";
 502  i :        return false;
 503    :      }
 504    :  
 505    :      // Ensure the attributes are valid.
 506  E :      if (!ValidAttributes(attributes, BlockGraph::LABEL_ATTRIBUTES_MAX)) {
 507  i :        LOG(ERROR) << "Invalid attributes ("
 508    :                   << base::StringPrintf("%04X", attributes) << ") for block "
 509    :                   << "with id " << block->id() << ".";
 510  i :        return false;
 511    :      }
 512    :  
 513  E :      BlockGraph::Label label(name, attributes);
 514  E :      CHECK(block->SetLabel(offset, label));
 515  E :    }
 516  E :    DCHECK_EQ(label_count, block->labels().size());
 517    :  
 518  E :    return true;
 519  E :  }
 520    :  
 521    :  bool BlockGraphSerializer::SaveBlockData(const BlockGraph::Block& block,
 522  E :                                           OutArchive* out_archive) const {
 523  E :    DCHECK(out_archive != NULL);
 524    :  
 525    :    // We always output the data size.
 526  E :    uint32_t data_size = static_cast<uint32_t>(block.data_size());
 527  E :    if (!SaveUint32(data_size, out_archive)) {
 528  i :      LOG(ERROR) << "Unable to save block data size for block with id "
 529    :                 << block.id() << ".";
 530  i :      return false;
 531    :    }
 532    :  
 533  E :    bool output_data = false;
 534    :  
 535  E :    if (block.data_size() > 0) {
 536  E :      switch (data_mode_) {
 537    :        default:
 538  i :          NOTREACHED();
 539    :  
 540    :        case OUTPUT_NO_DATA: {
 541  E :          output_data = false;
 542  E :          break;
 543    :        }
 544    :  
 545    :        case OUTPUT_OWNED_DATA: {
 546  E :          uint8_t owns_data = block.owns_data();
 547  E :          if (!out_archive->Save(owns_data)) {
 548  i :            LOG(ERROR) << "Unable to save 'owns_data' field of block with id "
 549    :                       << block.id() << ".";
 550  i :            return false;
 551    :          }
 552    :  
 553  E :          output_data = block.owns_data();
 554  E :          break;
 555    :        }
 556    :  
 557    :        case OUTPUT_ALL_DATA: {
 558  E :          output_data = true;
 559    :          break;
 560    :        }
 561    :      }
 562    :    }
 563    :  
 564    :    // Save the data if we need to.
 565  E :    if (output_data) {
 566  E :      DCHECK_LT(0u, block.data_size());
 567  E :      if (!out_archive->out_stream()->Write(block.data_size(), block.data())) {
 568  i :        LOG(ERROR) << "Unable to save data for block with id "
 569    :                   << block.id() << ".";
 570  i :        return false;
 571    :      }
 572    :    }
 573    :  
 574    :    // No callback? Then do nothing!
 575  E :    if (save_block_data_callback_.get() == NULL)
 576  E :      return true;
 577    :  
 578    :    // Invoke the callback.
 579  E :    bool data_already_saved = output_data || block.data_size() == 0;
 580  E :    if (!save_block_data_callback_->Run(data_already_saved,
 581    :                                        block, out_archive)) {
 582  i :      return false;
 583    :    }
 584    :  
 585  E :    return true;
 586  E :  }
 587    :  
 588    :  bool BlockGraphSerializer::LoadBlockData(BlockGraph::Block* block,
 589  E :                                           InArchive* in_archive) const {
 590  E :    DCHECK(block != NULL);
 591  E :    DCHECK(in_archive != NULL);
 592  E :    DCHECK_EQ(0u, block->data_size());
 593  E :    DCHECK(block->data() == NULL);
 594  E :    DCHECK(!block->owns_data());
 595    :  
 596  E :    uint32_t data_size = 0;
 597  E :    if (!LoadUint32(&data_size, in_archive)) {
 598  i :      LOG(ERROR) << "Unable to load data size for block with id "
 599    :                 << block->id() << ".";
 600  i :      return false;
 601    :    }
 602    :  
 603    :    // This indicates whether or not we need to explicitly load the data directly
 604    :    // from the serialized stream.
 605  E :    bool data_in_stream = false;
 606    :  
 607  E :    if (data_size > 0) {
 608  E :      switch (data_mode_) {
 609    :        default:
 610  i :          NOTREACHED();
 611    :  
 612    :        case OUTPUT_NO_DATA: {
 613  E :          data_in_stream = false;
 614  E :          break;
 615    :        }
 616    :  
 617    :        case OUTPUT_OWNED_DATA: {
 618  E :          uint8_t owns_data = 0;
 619  E :          if (!in_archive->Load(&owns_data)) {
 620  i :            LOG(ERROR) << "Unable to load 'owns_data' field of block with id "
 621    :                       << block->id() << ".";
 622  i :            return false;
 623    :          }
 624    :  
 625    :          // If we own the data then it must have been serialized to the stream.
 626  E :          data_in_stream = owns_data != 0;
 627  E :          break;
 628    :        }
 629    :  
 630    :        case OUTPUT_ALL_DATA: {
 631  E :          data_in_stream = true;
 632    :          break;
 633    :        }
 634    :      }
 635    :    }
 636    :  
 637  E :    bool callback_needs_to_set_data = !data_in_stream && data_size > 0;
 638    :  
 639  E :    if (data_in_stream) {
 640  E :      DCHECK_LT(0u, data_size);
 641    :  
 642    :      // Read the data from the stream.
 643  E :      block->AllocateData(data_size);
 644  E :      DCHECK_EQ(data_size, block->data_size());
 645  E :      DCHECK(block->data() != NULL);
 646  E :      if (!in_archive->in_stream()->Read(data_size, block->GetMutableData())) {
 647  i :        LOG(ERROR) << "Unable to read data for block with id "
 648    :                   << block->id() << ".";
 649  i :        return false;
 650    :      }
 651    :    }
 652    :  
 653  E :    if (callback_needs_to_set_data) {
 654    :      // If we didn't explicitly load the data, then we expect the callback to
 655    :      // do it. We make sure there is one.
 656  E :      if (load_block_data_callback_.get() == NULL) {
 657  i :        LOG(ERROR) << "No load block data callback specified.";
 658  i :        return false;
 659    :      }
 660    :    }
 661    :  
 662    :    // If there's a callback, invoke it.
 663  E :    if (load_block_data_callback_.get()) {
 664  E :      if (!load_block_data_callback_->Run(callback_needs_to_set_data,
 665    :                                          data_size,
 666    :                                          block,
 667    :                                          in_archive)) {
 668  i :        LOG(ERROR) << "Block data callback failed.";
 669  i :        return false;
 670    :      }
 671    :    }
 672    :  
 673  E :    if (data_size > 0 && block->data() == NULL) {
 674  i :      LOG(ERROR) << "Load block data callback failed to set block data.";
 675  i :      return false;
 676    :    }
 677    :  
 678  E :    if (block->data_size() != data_size) {
 679  i :      LOG(ERROR) << "Load block data callback set incorrect data size.";
 680  i :      return false;
 681    :    }
 682    :  
 683  E :    return true;
 684  E :  }
 685    :  
 686    :  bool BlockGraphSerializer::SaveBlockReferences(const BlockGraph::Block& block,
 687  E :                                                 OutArchive* out_archive) const {
 688    :    // Output the number of references for this block.
 689  E :    if (!out_archive->Save(block.references().size())) {
 690  i :      LOG(ERROR) << "Unable to save reference count for block with id "
 691    :                 << block.id() << ".";
 692  i :      return false;
 693    :    }
 694    :  
 695    :    // Output the references as (offset, reference) pairs.
 696    :    BlockGraph::Block::ReferenceMap::const_iterator it =
 697  E :        block.references().begin();
 698  E :    for (; it != block.references().end(); ++it) {
 699  E :      int32_t offset = it->first;
 700  E :      if (!SaveInt32(offset, out_archive) ||
 701    :          !SaveReference(it->second, out_archive)) {
 702  i :        LOG(ERROR) << "Unable to save (offset, reference) pair at offset "
 703    :                   << offset << " of block with id " << block.id() << ".";
 704  i :        return false;
 705    :      }
 706  E :    }
 707    :  
 708  E :    return true;
 709  E :  }
 710    :  
 711    :  bool BlockGraphSerializer::LoadBlockReferences(BlockGraph* block_graph,
 712    :                                                 BlockGraph::Block* block,
 713  E :                                                 InArchive* in_archive) const {
 714  E :    DCHECK(block_graph != NULL);
 715  E :    DCHECK(block != NULL);
 716  E :    DCHECK(in_archive != NULL);
 717    :  
 718    :    // This block should not have any references yet.
 719  E :    DCHECK_EQ(0u, block->references().size());
 720    :  
 721  E :    size_t count = 0;
 722  E :    if (!in_archive->Load(&count)) {
 723  i :      LOG(ERROR) << "Unable to load reference count for block with id "
 724    :                 << block->id() << ".";
 725  i :      return false;
 726    :    }
 727    :  
 728  E :    for (size_t i = 0; i < count; ++i) {
 729  E :      int32_t offset = 0;
 730  E :      BlockGraph::Reference ref;
 731  E :      if (!LoadInt32(&offset, in_archive) ||
 732    :          !LoadReference(block_graph, &ref, in_archive)) {
 733  i :        LOG(ERROR) << "Unable to load (offset, reference) pair " << i << " of "
 734    :                   << count << " for block with id " << block->id() << ".";
 735  i :        return false;
 736    :      }
 737  E :      DCHECK(ref.referenced() != NULL);
 738    :  
 739  E :      if (!block->SetReference(offset, ref)) {
 740  i :        LOG(ERROR) << "Unable to create block reference at offset " << offset
 741    :                   << " of block with id " << block->id() << ".";
 742  i :        return false;
 743    :      }
 744  E :    }
 745    :  
 746  E :    return true;
 747  E :  }
 748    :  
 749    :  bool BlockGraphSerializer::SaveReference(const BlockGraph::Reference& ref,
 750  E :                                           OutArchive* out_archive) const {
 751  E :    DCHECK(ref.referenced() != NULL);
 752  E :    DCHECK(out_archive != NULL);
 753    :  
 754    :    static_assert(BlockGraph::REFERENCE_TYPE_MAX < 16,
 755    :                  "Reference type requires more than one nibble.");
 756    :    static_assert(BlockGraph::Reference::kMaximumSize < 16,
 757    :                  "Reference size requires more than one nibble.");
 758    :  
 759    :    // The type and size are each stored as a nibble of one byte.
 760  E :    uint8_t type_size = (static_cast<uint8_t>(ref.type()) << 4) |
 761    :                        static_cast<uint8_t>(ref.size());
 762  E :    int32_t offset = ref.offset();
 763    :    // Most often the offset and the base are identical, so we actually save
 764    :    // the base as a difference from the offset to encourage smaller values.
 765  E :    int32_t base_delta = ref.base() - ref.offset();
 766    :  
 767    :    if (!out_archive->Save(type_size) ||
 768    :        !out_archive->Save(ref.referenced()->id()) ||
 769  E :        !SaveInt32(offset, out_archive) || !SaveInt32(base_delta, out_archive)) {
 770  i :      LOG(ERROR) << "Unable to write reference properties.";
 771  i :      return false;
 772    :    }
 773    :  
 774  E :    return true;
 775  E :  }
 776    :  
 777    :  bool BlockGraphSerializer::LoadReference(BlockGraph* block_graph,
 778    :                                           BlockGraph::Reference* ref,
 779  E :                                           InArchive* in_archive) const {
 780  E :    DCHECK(block_graph != NULL);
 781  E :    DCHECK(ref != NULL);
 782  E :    DCHECK(in_archive != NULL);
 783    :  
 784  E :    uint8_t type_size = 0;
 785  E :    BlockGraph::BlockId id = 0;
 786  E :    int32_t offset = 0;
 787  E :    int32_t base_delta = 0;
 788    :  
 789    :    if (!in_archive->Load(&type_size) || !in_archive->Load(&id) ||
 790  E :        !LoadInt32(&offset, in_archive) || !LoadInt32(&base_delta, in_archive)) {
 791  i :      LOG(ERROR) << "Unable to load reference properties.";
 792  i :      return false;
 793    :    }
 794    :  
 795    :    // The type and size are each stored as a nibble of one byte.
 796  E :    uint8_t type = (type_size >> 4) & 0xF;
 797  E :    uint8_t size = type_size & 0xF;
 798    :  
 799  E :    if (type >= BlockGraph::REFERENCE_TYPE_MAX ||
 800    :        size > BlockGraph::Reference::kMaximumSize) {
 801  i :      LOG(ERROR) << "Invalid reference type (" << static_cast<uint32_t>(type)
 802    :                 << ") and/or size (" << static_cast<uint32_t>(size) << ").";
 803  i :      return false;
 804    :    }
 805    :  
 806  E :    BlockGraph::Block* referenced = block_graph->GetBlockById(id);
 807  E :    if (referenced == NULL) {
 808  i :      LOG(ERROR) << "Unable to find referenced block with id " << id << ".";
 809  i :      return false;
 810    :    }
 811    :  
 812  E :    *ref = BlockGraph::Reference(static_cast<BlockGraph::ReferenceType>(type),
 813    :                                 size, referenced, offset, offset + base_delta);
 814    :  
 815  E :    return true;
 816  E :  }
 817    :  
 818    :  // Saves an unsigned 32 bit value. This uses a variable length encoding where
 819    :  // the first three bits are reserved to indicate the number of bytes required to
 820    :  // store the value.
 821    :  bool BlockGraphSerializer::SaveUint32(uint32_t value,
 822  E :                                        OutArchive* out_archive) const {
 823  E :    DCHECK(out_archive != NULL);
 824    :  
 825    :    // Determine the number of bytes needed in the representation.
 826  E :    uint32_t bytes = 1;
 827  E :    if (value >= (1 << 29)) {
 828  E :      bytes = 5;
 829  E :    } else if (value >= (1 << 21)) {
 830  E :      bytes = 4;
 831  E :    } else if (value >= (1 << 13)) {
 832  E :      bytes = 3;
 833  E :    } else if (value >= (1 << 5)) {
 834  E :      bytes = 2;
 835    :    }
 836    :  
 837    :    // Output the value, LSB first. We actually only output 5 bits of the LSB.
 838  E :    uint8_t byte = (value & ((1 << 5) - 1));
 839  E :    byte |= ((bytes - 1) << 5);
 840  E :    value >>= 5;
 841  E :    while (true) {
 842  E :      if (!out_archive->Save(byte)) {
 843  i :        LOG(ERROR) << "Unable to write variable-length 32-bit unsigned integer.";
 844  i :        return false;
 845    :      }
 846    :  
 847  E :      if (--bytes == 0)
 848  E :        break;
 849    :  
 850  E :      byte = value & 0xFF;
 851  E :      value >>= 8;
 852  E :    }
 853    :  
 854  E :    return true;
 855  E :  }
 856    :  
 857    :  // Loads an unsigned 32-bit value using the encoding discussed in SaveUint32.
 858    :  bool BlockGraphSerializer::LoadUint32(uint32_t* value,
 859  E :                                        InArchive* in_archive) const {
 860  E :    DCHECK(value != NULL);
 861  E :    DCHECK(in_archive != NULL);
 862    :  
 863  E :    uint32_t temp_value = 0;
 864  E :    uint32_t bytes = 0;
 865  E :    uint32_t position = 0;
 866  E :    uint8_t byte = 0;
 867    :  
 868  E :    while (true) {
 869  E :      if (!in_archive->Load(&byte)) {
 870  i :        LOG(ERROR) << "Unable to read variable-length 32-bit unsigned integer.";
 871  i :        return false;
 872    :      }
 873    :  
 874    :      // If we're reading the first byte, we need to read the number of bytes
 875    :      // remaining from its 3 leading bits.
 876  E :      if (position == 0) {
 877  E :        bytes = (byte >> 5) & 0x7;
 878  E :        temp_value = byte & ((1 << 5) - 1);
 879  E :        position += 5;
 880  E :      } else {
 881  E :        temp_value |= byte << position;
 882  E :        position += 8;
 883    :      }
 884    :  
 885  E :      if (bytes == 0)
 886  E :        break;
 887    :  
 888  E :      --bytes;
 889  E :    }
 890    :  
 891  E :    *value = temp_value;
 892  E :    return true;
 893  E :  }
 894    :  
 895    :  // Saves a signed 32-bit value using a variable length encoding. This can
 896    :  // represent signed values where the magnitude is at most 31-bits. We use a
 897    :  // simple sign-bit encoding, so there are 2 encodings for 0.
 898    :  bool BlockGraphSerializer::SaveInt32(int32_t value,
 899  E :                                       OutArchive* out_archive) const {
 900  E :    DCHECK(out_archive != NULL);
 901    :  
 902  E :    uint32_t uvalue = static_cast<uint32_t>(value < 0 ? -value : value);
 903  E :    CHECK_GT((1u << 31), uvalue);
 904    :  
 905    :    // Add the sign bit as the least significant bit. This allows values near 0
 906    :    // (positive or negative) to be encoded in as little space as possible.
 907  E :    uvalue <<= 1;
 908  E :    if (value < 0)
 909  E :      uvalue |= 1;
 910    :  
 911  E :    if (!SaveUint32(uvalue, out_archive))
 912  i :      return false;
 913    :  
 914  E :    return true;
 915  E :  }
 916    :  
 917    :  bool BlockGraphSerializer::LoadInt32(int32_t* value,
 918  E :                                       InArchive* in_archive) const {
 919  E :    DCHECK(value != NULL);
 920  E :    DCHECK(in_archive != NULL);
 921    :  
 922  E :    uint32_t uvalue = 0;
 923  E :    if (!LoadUint32(&uvalue, in_archive))
 924  i :      return false;
 925    :  
 926  E :    *value = static_cast<int32_t>(uvalue >> 1);
 927  E :    if ((uvalue & 1) != 0)
 928  E :      *value = -(*value);
 929    :  
 930  E :    return true;
 931  E :  }
 932    :  
 933    :  }  // namespace block_graph

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