Coverage for /Syzygy/block_graph/block_graph.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
93.0%6256720.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.h"
  16    :  
  17    :  #include <limits>
  18    :  
  19    :  #include "base/logging.h"
  20    :  #include "base/stringprintf.h"
  21    :  
  22    :  namespace block_graph {
  23    :  
  24    :  namespace {
  25    :  
  26    :  COMPILE_ASSERT(BlockGraph::BLOCK_ATTRIBUTES_MAX_BIT < 32,
  27    :                 too_many_block_attributes);
  28    :  
  29    :  // A list of printable names corresponding to block types. This needs to
  30    :  // be kept in sync with the BlockGraph::BlockType enum!
  31    :  const char* kBlockType[] = {
  32    :    "CODE_BLOCK", "DATA_BLOCK",
  33    :  };
  34    :  COMPILE_ASSERT(arraysize(kBlockType) == BlockGraph::BLOCK_TYPE_MAX,
  35    :                 kBlockType_not_in_sync);
  36    :  
  37    :  // Shift all items in an offset -> item map by 'distance', provided the initial
  38    :  // item offset was >= @p offset.
  39    :  template<typename ItemType>
  40    :  void ShiftOffsetItemMap(BlockGraph::Offset offset,
  41    :                          BlockGraph::Offset distance,
  42  E :                          std::map<BlockGraph::Offset, ItemType>* items) {
  43  E :    DCHECK_GE(offset, 0);
  44  E :    DCHECK_NE(distance, 0);
  45  E :    DCHECK(items != NULL);
  46    :  
  47    :    typedef std::map<BlockGraph::Offset, ItemType> ItemMap;
  48    :  
  49    :    // Get iterators to all of the items that need changing.
  50  E :    std::vector<ItemMap::iterator> item_its;
  51  E :    ItemMap::iterator item_it = items->lower_bound(offset);
  52  E :    while (item_it != items->end()) {
  53  E :      item_its.push_back(item_it);
  54  E :      ++item_it;
  55  E :    }
  56    :  
  57    :    // Get the direction and bounds of the iteration. We need to walk through
  58    :    // the iterators in a different order depending on if we're shifting left
  59    :    // or right. This is to ensure that earlier shifts don't land on the values
  60    :    // of later unshifted offsets.
  61  E :    int start = 0;
  62  E :    int stop = item_its.size();
  63  E :    int step = 1;
  64  E :    if (distance > 0) {
  65  E :      start = stop - 1;
  66  E :      stop = -1;
  67  E :      step = -1;
  68    :    }
  69    :  
  70  E :    for (int i = start; i != stop; i += step) {
  71  E :      item_it = item_its[i];
  72    :      items->insert(std::make_pair(item_it->first + distance,
  73  E :                                   item_it->second));
  74  E :      items->erase(item_it);
  75  E :    }
  76  E :  }
  77    :  
  78    :  void ShiftReferences(BlockGraph::Block* block,
  79    :                       BlockGraph::Offset offset,
  80  E :                       BlockGraph::Offset distance) {
  81    :    // Make a copy of the reference map for simplicity.
  82  E :    BlockGraph::Block::ReferenceMap references = block->references();
  83    :  
  84    :    // Start by removing all references that have moved.
  85    :    BlockGraph::Block::ReferenceMap::const_iterator it =
  86  E :        references.lower_bound(offset);
  87  E :    for (; it != references.end(); ++it) {
  88  E :      if (it->first >= offset)
  89  E :        block->RemoveReference(it->first);
  90  E :    }
  91    :  
  92    :    // Then patch up all existing references.
  93  E :    it = references.begin();
  94  E :    for (; it != references.end(); ++it) {
  95  E :      BlockGraph::Reference ref(it->second);
  96  E :      BlockGraph::Offset new_offset(it->first);
  97    :  
  98    :      // If this is self-referential, fix the destination offset.
  99  E :      if (ref.referenced() == block && ref.offset() >= offset) {
 100    :        ref = BlockGraph::Reference(ref.type(),
 101    :                                    ref.size(),
 102    :                                    ref.referenced(),
 103    :                                    ref.offset() + distance,
 104  i :                                    ref.base() + distance);
 105    :      }
 106    :  
 107    :      // If its offset is past the change point, fix that.
 108  E :      if (it->first >= offset)
 109  E :        new_offset += distance;
 110    :  
 111    :      // In many cases this'll be a noop.
 112    :      // TODO(siggi): Optimize this.
 113  E :      block->SetReference(new_offset, ref);
 114  E :    }
 115  E :  }
 116    :  
 117    :  // Shift all referrers beyond @p offset by @p distance.
 118    :  void ShiftReferrers(BlockGraph::Block* self,
 119    :                      BlockGraph::Offset offset,
 120    :                      BlockGraph::Offset distance,
 121  E :                      BlockGraph::Block::ReferrerSet* referrers) {
 122  E :    DCHECK_GE(offset, 0);
 123  E :    DCHECK_NE(distance, 0);
 124  E :    DCHECK(referrers != NULL);
 125    :  
 126    :    typedef BlockGraph::Block::ReferrerSet ReferrerSet;
 127    :    typedef BlockGraph::Reference Reference;
 128    :  
 129  E :    ReferrerSet::iterator ref_it = referrers->begin();
 130  E :    while (ref_it != referrers->end()) {
 131    :      // We need to keep around the next iterator as 'ref_it' will be invalidated
 132    :      // if we need to update the reference. (It will be deleted and then
 133    :      // recreated.)
 134  E :      ReferrerSet::iterator next_ref_it = ref_it;
 135  E :      ++next_ref_it;
 136    :  
 137  E :      BlockGraph::Block* ref_block = ref_it->first;
 138    :      // Our own references will have been moved already.
 139  E :      if (ref_block != self) {
 140  E :        BlockGraph::Offset ref_offset = ref_it->second;
 141    :  
 142  E :        Reference ref;
 143  E :        bool ref_found = ref_block->GetReference(ref_offset, &ref);
 144  E :        DCHECK(ref_found);
 145    :  
 146    :        // Shift the reference if need be.
 147  E :        if (ref.offset() >= offset) {
 148    :          Reference new_ref(ref.type(),
 149    :                            ref.size(),
 150    :                            ref.referenced(),
 151    :                            ref.offset() + distance,
 152  E :                            ref.base() + distance);
 153  E :          bool inserted = ref_block->SetReference(ref_offset, new_ref);
 154  E :          DCHECK(!inserted);
 155    :        }
 156    :      }
 157    :  
 158  E :      ref_it = next_ref_it;
 159  E :    }
 160  E :  }
 161    :  
 162  i :  const char* BlockAttributeToString(BlockGraph::BlockAttributeEnum attr) {
 163  i :    switch (attr) {
 164    :  #define DEFINE_CASE(name) case BlockGraph::name: return #name;
 165  i :      BLOCK_ATTRIBUTE_ENUM(DEFINE_CASE)
 166    :  #undef DEFINE_CASE
 167    :      default:
 168  i :        NOTREACHED();
 169  i :        return NULL;
 170    :    }
 171  i :  }
 172    :  
 173    :  }  // namespace
 174    :  
 175  i :  std::string BlockGraph::BlockAttributesToString(BlockAttributes attrs) {
 176  i :    BlockAttributes attr = 1;
 177  i :    std::string s;
 178  i :    for (; attr < BLOCK_ATTRIBUTES_MAX; attr <<= 1) {
 179  i :      if (attr & attrs) {
 180  i :        if (!s.empty())
 181  i :          s.append("|");
 182  i :        s.append(BlockAttributeToString(static_cast<BlockAttributeEnum>(attr)));
 183    :      }
 184  i :    }
 185  i :    return s;
 186  i :  }
 187    :  
 188  E :  const char* BlockGraph::BlockTypeToString(BlockGraph::BlockType type) {
 189  E :    DCHECK_LE(BlockGraph::CODE_BLOCK, type);
 190  E :    DCHECK_GT(BlockGraph::BLOCK_TYPE_MAX, type);
 191  E :    return kBlockType[type];
 192  E :  }
 193    :  
 194    :  std::string BlockGraph::LabelAttributesToString(
 195  E :      BlockGraph::LabelAttributes label_attributes) {
 196    :    static const char* kLabelAttributes[] = {
 197    :        "Code", "DebugStart", "DebugEnd", "ScopeStart", "ScopeEnd",
 198    :        "CallSite", "JumpTable", "CaseTable", "Data", "PublicSymbol" };
 199    :    COMPILE_ASSERT((1 << arraysize(kLabelAttributes)) == LABEL_ATTRIBUTES_MAX,
 200    :                   label_attribute_names_not_in_sync_with_enum);
 201    :  
 202  E :    std::string s;
 203  E :    for (size_t i = 0; i < arraysize(kLabelAttributes); ++i) {
 204  E :      if (label_attributes & (1 << i)) {
 205  E :        if (!s.empty())
 206  E :          s.append("|");
 207  E :        s.append(kLabelAttributes[i]);
 208    :      }
 209  E :    }
 210  E :    return s;
 211  E :  }
 212    :  
 213  E :  const core::RelativeAddress kInvalidAddress(0xFFFFFFFF);
 214    :  
 215    :  const BlockGraph::SectionId BlockGraph::kInvalidSectionId = -1;
 216    :  
 217    :  BlockGraph::BlockGraph()
 218    :      : next_section_id_(0),
 219  E :        next_block_id_(0) {
 220  E :  }
 221    :  
 222  E :  BlockGraph::~BlockGraph() {
 223  E :  }
 224    :  
 225    :  BlockGraph::Section* BlockGraph::AddSection(const base::StringPiece& name,
 226  E :                                              uint32 characteristics) {
 227  E :    Section new_section(next_section_id_++, name, characteristics);
 228    :    std::pair<SectionMap::iterator, bool> result = sections_.insert(
 229  E :        std::make_pair(new_section.id(), new_section));
 230  E :    DCHECK(result.second);
 231    :  
 232  E :    return &result.first->second;
 233  E :  }
 234    :  
 235  E :  BlockGraph::Section* BlockGraph::FindSection(const base::StringPiece& name) {
 236    :    // This is a linear scan, but thankfully images generally do not have many
 237    :    // sections and we do not create them very often. Fast lookup by index is
 238    :    // more important. If this ever becomes an issue, we could keep around a
 239    :    // second index by name.
 240  E :    SectionMap::iterator it = sections_.begin();
 241  E :    for (; it != sections_.end(); ++it) {
 242  E :      if (it->second.name() == name)
 243  E :        return &it->second;
 244  E :    }
 245    :  
 246  E :    return NULL;
 247  E :  }
 248    :  
 249    :  BlockGraph::Section* BlockGraph::FindOrAddSection(const base::StringPiece& name,
 250  E :                                                    uint32 characteristics) {
 251  E :    Section* section = FindSection(name);
 252  E :    if (section) {
 253  E :      section->set_characteristic(characteristics);
 254  E :      return section;
 255    :    }
 256  E :    return AddSection(name, characteristics);
 257  E :  }
 258    :  
 259  E :  bool BlockGraph::RemoveSection(Section* section) {
 260  E :    DCHECK(section != NULL);
 261    :  
 262  E :    SectionMap::iterator it(sections_.find(section->id()));
 263  E :    if (it == sections_.end() || &it->second != section)
 264  i :      return false;
 265    :  
 266  E :    sections_.erase(it);
 267  E :    return true;
 268  E :  }
 269    :  
 270  E :  bool BlockGraph::RemoveSectionById(SectionId id) {
 271  E :    SectionMap::iterator it(sections_.find(id));
 272  E :    if (it == sections_.end())
 273  E :      return false;
 274    :  
 275  E :    sections_.erase(it);
 276  E :    return true;
 277  E :  }
 278    :  
 279    :  BlockGraph::Block* BlockGraph::AddBlock(BlockType type,
 280    :                                          Size size,
 281  E :                                          const base::StringPiece& name) {
 282  E :    BlockId id = ++next_block_id_;
 283    :    BlockMap::iterator it = blocks_.insert(
 284  E :        std::make_pair(id, Block(id, type, size, name, this))).first;
 285    :  
 286  E :    return &it->second;
 287  E :  }
 288    :  
 289  E :  bool BlockGraph::RemoveBlock(Block* block) {
 290  E :    DCHECK(block != NULL);
 291    :  
 292  E :    BlockMap::iterator it(blocks_.find(block->id()));
 293  E :    if (it == blocks_.end() || &it->second != block)
 294  E :      return false;
 295    :  
 296  E :    return RemoveBlockByIterator(it);
 297  E :  }
 298    :  
 299  E :  bool BlockGraph::RemoveBlockById(BlockId id) {
 300  E :    BlockMap::iterator it(blocks_.find(id));
 301  E :    if (it == blocks_.end())
 302  E :      return false;
 303    :  
 304  E :    return RemoveBlockByIterator(it);
 305  E :  }
 306    :  
 307  E :  BlockGraph::Section* BlockGraph::GetSectionById(SectionId id) {
 308  E :    SectionMap::iterator it(sections_.find(id));
 309    :  
 310  E :    if (it == sections_.end())
 311  E :      return NULL;
 312    :  
 313  E :    return &it->second;
 314  E :  }
 315    :  
 316  E :  const BlockGraph::Section* BlockGraph::GetSectionById(SectionId id) const {
 317  E :    SectionMap::const_iterator it(sections_.find(id));
 318    :  
 319  E :    if (it == sections_.end())
 320  E :      return NULL;
 321    :  
 322  E :    return &it->second;
 323  E :  }
 324    :  
 325  E :  BlockGraph::Block* BlockGraph::GetBlockById(BlockId id) {
 326  E :    BlockMap::iterator it(blocks_.find(id));
 327    :  
 328  E :    if (it == blocks_.end())
 329  E :      return NULL;
 330    :  
 331  E :    return &it->second;
 332  E :  }
 333    :  
 334    :  const BlockGraph::Block* BlockGraph::GetBlockById(BlockId id) const {
 335    :    BlockMap::const_iterator it(blocks_.find(id));
 336    :  
 337    :    if (it == blocks_.end())
 338    :      return NULL;
 339    :  
 340    :    return &it->second;
 341    :  }
 342    :  
 343  E :  const std::string& BlockGraph::InternString(const base::StringPiece& str) {
 344  E :    const std::string& raw_string = str.data();
 345  E :    std::set<std::string>::iterator look = string_table_.find(raw_string);
 346    :  
 347    :    // This string is not interned, add it.
 348  E :    if (look == string_table_.end())
 349  E :      look = string_table_.insert(str.data()).first;
 350    :  
 351  E :    return *look;
 352  E :  }
 353    :  
 354  E :  bool BlockGraph::RemoveBlockByIterator(BlockMap::iterator it) {
 355  E :    DCHECK(it != blocks_.end());
 356    :  
 357    :    // Verify this block is fully disconnected.
 358  E :    if (it->second.referrers().size() > 0 || it->second.references().size() > 0)
 359  E :      return false;
 360    :  
 361  E :    blocks_.erase(it);
 362    :  
 363  E :    return true;
 364  E :  }
 365    :  
 366    :  BlockGraph::AddressSpace::AddressSpace(BlockGraph* graph)
 367  E :      : graph_(graph) {
 368  E :    DCHECK(graph != NULL);
 369  E :  }
 370    :  
 371    :  BlockGraph::Block* BlockGraph::AddressSpace::AddBlock(
 372    :      BlockType type, RelativeAddress addr, Size size,
 373  E :      const base::StringPiece& name) {
 374    :    // First check to see that the range is clear.
 375  E :    AddressSpaceImpl::Range range(addr, size);
 376    :    AddressSpaceImpl::RangeMap::iterator it =
 377  E :        address_space_.FindFirstIntersection(range);
 378  E :    if (it != address_space_.ranges().end())
 379  E :      return NULL;
 380    :  
 381  E :    BlockGraph::Block* block = graph_->AddBlock(type, size, name);
 382  E :    DCHECK(block != NULL);
 383  E :    bool inserted = InsertImpl(addr, block);
 384  E :    DCHECK(inserted);
 385    :  
 386  E :    return block;
 387  E :  }
 388    :  
 389  E :  bool BlockGraph::AddressSpace::InsertBlock(RelativeAddress addr, Block* block) {
 390  E :    return InsertImpl(addr, block);
 391  E :  }
 392    :  
 393    :  BlockGraph::Block* BlockGraph::AddressSpace::GetBlockByAddress(
 394  E :      RelativeAddress addr) const {
 395  E :    return GetContainingBlock(addr, 1);
 396  E :  }
 397    :  
 398    :  BlockGraph::Block* BlockGraph::AddressSpace::GetContainingBlock(
 399  E :      RelativeAddress addr, Size size) const {
 400  E :    AddressSpaceImpl::Range range(addr, size);
 401    :    AddressSpaceImpl::RangeMap::const_iterator it =
 402  E :        address_space_.FindContaining(range);
 403  E :    if (it == address_space_.ranges().end())
 404  E :      return NULL;
 405    :  
 406  E :    return it->second;
 407  E :  }
 408    :  
 409    :  BlockGraph::Block* BlockGraph::AddressSpace::GetFirstIntersectingBlock(
 410  E :      RelativeAddress addr, Size size) {
 411  E :    AddressSpaceImpl::Range range(addr, size);
 412    :    AddressSpaceImpl::RangeMap::iterator it =
 413  E :        address_space_.FindFirstIntersection(range);
 414  E :    if (it == address_space_.ranges().end())
 415  E :      return NULL;
 416    :  
 417  E :    return it->second;
 418  E :  }
 419    :  
 420    :  BlockGraph::AddressSpace::RangeMapConstIterPair
 421    :  BlockGraph::AddressSpace::GetIntersectingBlocks(RelativeAddress address,
 422  E :                                                  Size size) const {
 423  E :    return address_space_.FindIntersecting(Range(address, size));
 424  E :  }
 425    :  
 426    :  BlockGraph::AddressSpace::RangeMapIterPair
 427    :  BlockGraph::AddressSpace::GetIntersectingBlocks(RelativeAddress address,
 428  E :                                                  Size size) {
 429  E :    return address_space_.FindIntersecting(Range(address, size));
 430  E :  }
 431    :  
 432    :  bool BlockGraph::AddressSpace::GetAddressOf(const Block* block,
 433  E :                                              RelativeAddress* addr) const {
 434  E :    DCHECK(block != NULL);
 435  E :    DCHECK(addr != NULL);
 436    :  
 437  E :    BlockAddressMap::const_iterator it(block_addresses_.find(block));
 438  E :    if (it == block_addresses_.end())
 439  E :      return false;
 440    :  
 441  E :    *addr = it->second;
 442  E :    return true;
 443  E :  }
 444    :  
 445  E :  bool BlockGraph::AddressSpace::InsertImpl(RelativeAddress addr, Block* block) {
 446  E :    Range range(addr, block->size());
 447  E :    bool inserted = address_space_.Insert(range, block);
 448  E :    if (!inserted)
 449  E :      return false;
 450    :  
 451  E :    inserted = block_addresses_.insert(std::make_pair(block, addr)).second;
 452  E :    DCHECK(inserted);
 453    :    // Update the address stored in the block.
 454  E :    block->set_addr(addr);
 455    :  
 456  E :    return true;
 457  E :  }
 458    :  
 459  E :  bool BlockGraph::AddressSpace::ContainsBlock(const Block* block) {
 460  E :    DCHECK(block != NULL);
 461  E :    return block_addresses_.count(block) != 0;
 462  E :  }
 463    :  
 464    :  BlockGraph::Block* BlockGraph::AddressSpace::MergeIntersectingBlocks(
 465  E :      const Range& range) {
 466    :    typedef std::vector<std::pair<RelativeAddress, BlockGraph::Block*>>
 467    :        BlockAddressVector;
 468    :  
 469    :    // Find all the blocks that intersect the range, keep them and their
 470    :    // addresses. Start by finding the first intersection, then iterate
 471    :    // from there until we find a block that doesn't intersect with range.
 472    :    AddressSpaceImpl::RangeMap::iterator address_start =
 473  E :        address_space_.FindFirstIntersection(range);
 474  E :    AddressSpaceImpl::RangeMap::iterator address_it(address_start);
 475    :  
 476  E :    BlockAddressVector intersecting;
 477    :    for (; address_it != address_space_.ranges().end() &&
 478  E :           address_it->first.Intersects(range); ++address_it) {
 479    :      intersecting.push_back(std::make_pair(address_it->first.start(),
 480  E :                                            address_it->second));
 481  E :    }
 482    :  
 483    :    // Bail if the intersection doesn't cover at least two blocks.
 484  E :    if (intersecting.empty())
 485  i :      return NULL;
 486    :  
 487    :    // In case of single-block intersection, we're done.
 488  E :    if (intersecting.size() == 1)
 489  i :      return intersecting[0].second;
 490    :  
 491  E :    DCHECK(!intersecting.empty());
 492    :  
 493    :    // Calculate the start and end addresses of the new block.
 494  E :    BlockGraph::Block* first_block = intersecting[0].second;
 495  E :    BlockGraph::Block* last_block = intersecting[intersecting.size() - 1].second;
 496  E :    DCHECK(first_block != NULL && last_block != NULL);
 497    :  
 498  E :    RelativeAddress begin = std::min(range.start(), intersecting[0].first);
 499    :    RelativeAddress end = std::max(range.start() + range.size(),
 500  E :        intersecting[intersecting.size() - 1].first + last_block->size());
 501    :  
 502  E :    DCHECK(begin <= range.start());
 503  E :    DCHECK(end >= range.start() + range.size());
 504    :  
 505  E :    base::StringPiece block_name = first_block->name();
 506  E :    BlockType block_type = first_block->type();
 507  E :    size_t section_id = first_block->section();
 508  E :    size_t alignment = first_block->alignment();
 509  E :    BlockAttributes attributes = 0;
 510    :  
 511  E :    BlockGraph::Block::SourceRanges source_ranges;
 512    :  
 513    :    // Remove the found blocks from the address space, and make sure they're all
 514    :    // of the same type and from the same section as the first block. Merge the
 515    :    // data from all the blocks as we go along, as well as the attributes and
 516    :    // source ranges.
 517  E :    std::vector<uint8> merged_data(end - begin);
 518  E :    bool have_data = false;
 519  E :    for (size_t i = 0; i < intersecting.size(); ++i) {
 520  E :      RelativeAddress addr = intersecting[i].first;
 521  E :      BlockGraph::Block* block = intersecting[i].second;
 522  E :      DCHECK_EQ(block_type, block->type());
 523  E :      DCHECK_EQ(section_id, block->section());
 524    :  
 525  E :      if (block->data() != NULL) {
 526  E :        have_data = true;
 527  E :        memcpy(&merged_data.at(addr - begin), block->data(), block->data_size());
 528    :      }
 529  E :      attributes |= block->attributes();
 530    :  
 531    :      // Merge in the source ranges from each block.
 532  E :      BlockGraph::Offset block_offset = addr - begin;
 533    :      BlockGraph::Block::SourceRanges::RangePairs::const_iterator src_it =
 534  E :          block->source_ranges().range_pairs().begin();
 535  E :      for (; src_it != block->source_ranges().range_pairs().end(); ++src_it) {
 536    :        // The data range is wrt to the containing block, wo we have to translate
 537    :        // each individual block's offset to an offset in the merged block.
 538  E :        BlockGraph::Offset merged_offset = block_offset + src_it->first.start();
 539    :        bool pushed = source_ranges.Push(
 540    :            BlockGraph::Block::DataRange(merged_offset, src_it->first.size()),
 541  E :            src_it->second);
 542  E :        DCHECK(pushed);
 543  E :      }
 544    :  
 545  E :      bool removed = address_space_.Remove(Range(addr, block->size()));
 546  E :      DCHECK(removed);
 547  E :      size_t num_removed = block_addresses_.erase(intersecting[i].second);
 548  E :      DCHECK_EQ(1U, num_removed);
 549  E :    }
 550    :  
 551    :    // Create the new block.
 552    :    BlockGraph::Block* new_block = AddBlock(block_type,
 553    :                                            begin, end - begin,
 554  E :                                            block_name);
 555  E :    DCHECK(new_block != NULL);
 556    :  
 557    :    // Set the rest of the properties for the new block.
 558  E :    new_block->source_ranges() = source_ranges;
 559  E :    new_block->set_section(section_id);
 560  E :    new_block->set_alignment(alignment);
 561  E :    new_block->set_attributes(attributes);
 562  E :    if (have_data) {
 563  E :      uint8* data = new_block->CopyData(merged_data.size(), &merged_data.at(0));
 564  E :      if (data == NULL) {
 565  i :        LOG(ERROR) << "Unable to copy merged data";
 566  i :        return NULL;
 567    :      }
 568    :    }
 569    :  
 570    :    // Now move all labels and references to the new block.
 571  E :    for (size_t i = 0; i < intersecting.size(); ++i) {
 572  E :      RelativeAddress addr = intersecting[i].first;
 573  E :      BlockGraph::Block* block = intersecting[i].second;
 574  E :      BlockGraph::Offset start_offset = addr - begin;
 575    :  
 576    :      // If the destination block is not a code block, preserve the old block
 577    :      // names as labels for debugging. We also need to make sure the label is
 578    :      // not empty, as that is verboten.
 579  E :      if (block_type != BlockGraph::CODE_BLOCK && !block->name().empty()) {
 580    :        new_block->SetLabel(start_offset,
 581    :                            block->name(),
 582  E :                            BlockGraph::DATA_LABEL);
 583    :      }
 584    :  
 585    :      // Move labels.
 586    :      BlockGraph::Block::LabelMap::const_iterator
 587  E :          label_it(block->labels().begin());
 588  E :      for (; label_it != block->labels().end(); ++label_it) {
 589    :        new_block->SetLabel(start_offset + label_it->first,
 590  E :                            label_it->second);
 591  E :      }
 592    :  
 593    :      // Copy the reference map since we mutate the original.
 594  E :      BlockGraph::Block::ReferenceMap refs(block->references());
 595  E :      BlockGraph::Block::ReferenceMap::const_iterator ref_it(refs.begin());
 596  E :      for (; ref_it != refs.end(); ++ref_it) {
 597  E :        block->RemoveReference(ref_it->first);
 598  E :        new_block->SetReference(start_offset + ref_it->first, ref_it->second);
 599  E :      }
 600    :  
 601    :      // Redirect all referrers to the new block.
 602  E :      block->TransferReferrers(start_offset, new_block);
 603    :  
 604    :      // Check that we've removed all references and
 605    :      // referrers from the original block.
 606  E :      DCHECK(block->references().empty());
 607  E :      DCHECK(block->referrers().empty());
 608    :  
 609    :      // Remove the original block.
 610  E :      bool removed = graph_->RemoveBlock(block);
 611  E :      DCHECK(removed);
 612  E :    }
 613    :  
 614  E :    return new_block;
 615  E :  }
 616    :  
 617  E :  bool BlockGraph::Section::set_name(const base::StringPiece& name) {
 618  E :    if (name == NULL)
 619  i :      return false;
 620    :  
 621  E :    if (name.empty())
 622  i :      return false;
 623    :  
 624  E :    name.CopyToString(&name_);
 625  E :    return true;
 626  E :  }
 627    :  
 628  E :  bool BlockGraph::Section::Save(core::OutArchive* out_archive) const {
 629  E :    DCHECK(out_archive != NULL);
 630    :    return out_archive->Save(id_) && out_archive->Save(name_) &&
 631  E :        out_archive->Save(characteristics_);
 632  E :  }
 633    :  
 634  E :  bool BlockGraph::Section::Load(core::InArchive* in_archive) {
 635  E :    DCHECK(in_archive != NULL);
 636    :    return in_archive->Load(&id_) && in_archive->Load(&name_) &&
 637  E :        in_archive->Load(&characteristics_);
 638  E :  }
 639    :  
 640  E :  std::string BlockGraph::Label::ToString() const {
 641    :    return base::StringPrintf("%s (%s)",
 642    :                              name_.c_str(),
 643  E :                              LabelAttributesToString(attributes_).c_str());
 644  E :  }
 645    :  
 646  E :  bool BlockGraph::Label::IsValid() const {
 647  E :    return AreValidAttributes(attributes_);
 648  E :  }
 649    :  
 650  E :  bool BlockGraph::Label::AreValidAttributes(LabelAttributes attributes) {
 651    :    // A label needs to have at least one attribute.
 652  E :    if (attributes == 0)
 653  E :      return false;
 654    :  
 655    :    // TODO(chrisha): Once we make the switch to VS2010 determine where call
 656    :    //     site labels may land. Are they at the beginning of the call
 657    :    //     instruction (in which case they may coincide with *_START_LABEL,
 658    :    //     *_END_LABEL and CODE_LABEL), or do they point at the address of the
 659    :    //     call (in which case they must be completely on their own)? For now, we
 660    :    //     simply ignore them entirely from consideration.
 661  E :    attributes &= ~CALL_SITE_LABEL;
 662    :  
 663    :    // Public symbols can coincide with anything, so we can basically ignore
 664    :    // them.
 665  E :    attributes &= ~PUBLIC_SYMBOL_LABEL;
 666    :  
 667    :    // A code label can coincide with a debug and scope labels. (It can coincide
 668    :    // with *_END_LABEL labels because of 1-byte instructions, like RET or INT.)
 669    :    const LabelAttributes kCodeDebugScopeLabels =
 670    :        CODE_LABEL | DEBUG_START_LABEL | DEBUG_END_LABEL | SCOPE_START_LABEL |
 671  E :        SCOPE_END_LABEL;
 672    :    if ((attributes & CODE_LABEL) != 0 &&
 673  E :        (attributes & ~kCodeDebugScopeLabels) != 0) {
 674  E :      return false;
 675    :    }
 676    :  
 677    :    // A jump table must be paired with a data label. It may also be paired
 678    :    // with a debug-end label if tail-call optimization has been applied by
 679    :    // the compiler/linker.
 680    :    const LabelAttributes kJumpDataLabelAttributes =
 681  E :        JUMP_TABLE_LABEL | DATA_LABEL;
 682  E :    if (attributes & JUMP_TABLE_LABEL) {
 683  E :      if ((attributes & kJumpDataLabelAttributes) != kJumpDataLabelAttributes)
 684  E :        return false;
 685    :      // Filter out the debug-end label if present and check that nothing else
 686    :      // is set.
 687  E :      attributes &= ~DEBUG_END_LABEL;
 688  E :      if ((attributes & ~kJumpDataLabelAttributes) != 0)
 689  i :        return false;
 690  E :      return true;
 691    :    }
 692    :  
 693    :    // A case table must be paired with a data label and nothing else.
 694    :    const LabelAttributes kCaseDataLabelAttributes =
 695  E :        CASE_TABLE_LABEL | DATA_LABEL;
 696  E :    if (attributes & CASE_TABLE_LABEL) {
 697  E :      if ((attributes & kCaseDataLabelAttributes) != kCaseDataLabelAttributes)
 698  E :        return false;
 699  E :      if ((attributes & ~kCaseDataLabelAttributes) != 0)
 700  i :        return false;
 701  E :      return true;
 702    :    }
 703    :  
 704    :    // If there is no case or jump label, then a data label must be on its own.
 705  E :    if ((attributes & DATA_LABEL) != 0 && (attributes & ~DATA_LABEL) != 0)
 706  i :      return false;
 707    :  
 708  E :    return true;
 709  E :  }
 710    :  
 711    :  BlockGraph::Block::Block(BlockGraph* block_graph)
 712    :      : id_(0),
 713    :        type_(BlockGraph::CODE_BLOCK),
 714    :        size_(0),
 715    :        alignment_(1),
 716    :        addr_(kInvalidAddress),
 717    :        block_graph_(block_graph),
 718    :        section_(kInvalidSectionId),
 719    :        attributes_(0),
 720    :        owns_data_(false),
 721    :        data_(NULL),
 722  E :        data_size_(0) {
 723  E :    DCHECK(block_graph != NULL);
 724  E :  }
 725    :  
 726    :  BlockGraph::Block::Block(BlockId id,
 727    :                           BlockType type,
 728    :                           Size size,
 729    :                           const base::StringPiece& name,
 730    :                           BlockGraph* block_graph)
 731    :      : id_(id),
 732    :        type_(type),
 733    :        size_(size),
 734    :        alignment_(1),
 735    :        name_(name.begin(), name.end()),
 736    :        addr_(kInvalidAddress),
 737    :        block_graph_(block_graph),
 738    :        section_(kInvalidSectionId),
 739    :        attributes_(0),
 740    :        owns_data_(false),
 741    :        data_(NULL),
 742  E :        data_size_(0) {
 743  E :    DCHECK(block_graph != NULL);
 744  E :  }
 745    :  
 746  E :  BlockGraph::Block::~Block() {
 747  E :    DCHECK(block_graph_ != NULL);
 748  E :    if (owns_data_)
 749  E :      delete [] data_;
 750  E :  }
 751    :  
 752  E :  uint8* BlockGraph::Block::AllocateRawData(size_t data_size) {
 753  E :    DCHECK_GT(data_size, 0u);
 754  E :    DCHECK_LE(data_size, size_);
 755    :  
 756  E :    uint8* new_data = new uint8[data_size];
 757  E :    if (!new_data)
 758  i :      return NULL;
 759    :  
 760  E :    if (owns_data()) {
 761  i :      DCHECK(data_ != NULL);
 762  i :      delete [] data_;
 763    :    }
 764    :  
 765  E :    data_ = new_data;
 766  E :    data_size_ = data_size;
 767  E :    owns_data_ = true;
 768    :  
 769  E :    return new_data;
 770  E :  }
 771    :  
 772    :  void BlockGraph::Block::InsertData(Offset offset,
 773    :                                     Size size,
 774  E :                                     bool always_allocate_data) {
 775  E :    DCHECK_GE(offset, 0);
 776  E :    DCHECK_LE(offset, static_cast<Offset>(size_));
 777    :  
 778  E :    if (size > 0) {
 779    :      // Patch up the block.
 780  E :      size_ += size;
 781  E :      ShiftOffsetItemMap(offset, size, &labels_);
 782  E :      ShiftReferences(this, offset, size);
 783  E :      ShiftReferrers(this, offset, size, &referrers_);
 784  E :      source_ranges_.InsertUnmappedRange(DataRange(offset, size));
 785    :  
 786    :      // Does this affect already allocated data?
 787  E :      if (static_cast<Size>(offset) < data_size_) {
 788    :        // Reallocate, shift the old data to the end, and zero out the new data.
 789  E :        size_t old_data_size = data_size_;
 790  E :        size_t bytes_to_shift = data_size_ - offset;
 791  E :        ResizeData(data_size_ + size);
 792  E :        uint8* new_data = GetMutableData();
 793  E :        memmove(new_data + offset + size, new_data + offset, bytes_to_shift);
 794  E :        memset(new_data + offset, 0, size);
 795    :      }
 796    :    }
 797    :  
 798    :    // If we've been asked to, at least make sure that the data is allocated.
 799  E :    if (always_allocate_data && data_size_ < offset + size)
 800  E :      ResizeData(offset + size);
 801    :  
 802    :    return;
 803  E :  }
 804    :  
 805  E :  bool BlockGraph::Block::RemoveData(Offset offset, Size size) {
 806  E :    DCHECK_GE(offset, 0);
 807  E :    DCHECK_LE(offset, static_cast<Offset>(size_));
 808    :  
 809  E :    if (size == 0)
 810  i :      return true;
 811    :  
 812    :    // Ensure there are no labels in this range.
 813  E :    if (labels_.lower_bound(offset) != labels_.lower_bound(offset + size))
 814  E :      return false;
 815    :  
 816    :    // Ensure that there are no references intersecting this range.
 817  E :    ReferenceMap::const_iterator refc_it = references_.begin();
 818  E :    for (; refc_it != references_.end(); ++refc_it) {
 819  E :      if (refc_it->first >= static_cast<Offset>(offset + size))
 820  E :        break;
 821  E :      if (static_cast<Offset>(refc_it->first + refc_it->second.size()) > offset)
 822  E :        return false;
 823  E :    }
 824    :  
 825    :    // Ensure there are no referrers pointing to the data we want to remove.
 826  E :    ReferrerSet::const_iterator refr_it = referrers_.begin();
 827  E :    for (; refr_it != referrers_.end(); ++refr_it) {
 828  E :      Reference ref;
 829  E :      if (!refr_it->first->GetReference(refr_it->second, &ref)) {
 830  i :        LOG(ERROR) << "Unable to get reference from referrer.";
 831  i :        return false;
 832    :      }
 833    :      if (ref.offset() < static_cast<Offset>(offset + size) &&
 834  E :          static_cast<Offset>(ref.offset() + ref.size()) > offset) {
 835  E :        return false;
 836    :      }
 837  E :    }
 838    :  
 839    :    // Patch up the block.
 840  E :    size_ -= size;
 841  E :    ShiftOffsetItemMap(offset + size, -static_cast<int>(size), &labels_);
 842  E :    ShiftReferences(this, offset + size, -static_cast<int>(size));
 843  E :    ShiftReferrers(this, offset + size, -static_cast<int>(size), &referrers_);
 844  E :    source_ranges_.RemoveMappedRange(DataRange(offset, size));
 845    :  
 846    :    // Does this affect already allocated data?
 847  E :    if (static_cast<Size>(offset) < data_size_) {
 848  E :      size_t new_data_size = data_size_ - size;
 849    :      // Is there data beyond the section to delete?
 850  E :      if (static_cast<Size>(offset + size) < data_size_) {
 851    :        // Shift tail data to left.
 852  E :        uint8* data = GetMutableData();
 853  E :        size_t bytes_to_shift = data_size_ - offset - size;
 854  E :        size_t old_data_size = data_size_;
 855    :        memmove(data + new_data_size - bytes_to_shift,
 856    :                data + old_data_size - bytes_to_shift,
 857  E :                bytes_to_shift);
 858  E :      } else {
 859  E :        new_data_size = offset;
 860    :      }
 861  E :      ResizeData(new_data_size);
 862    :    }
 863    :  
 864  E :    return true;
 865  E :  }
 866    :  
 867    :  bool BlockGraph::Block::InsertOrRemoveData(Offset offset,
 868    :                                             Size current_size,
 869    :                                             Size new_size,
 870  E :                                             bool always_allocate_data) {
 871  E :    DCHECK_GE(offset, 0);
 872  E :    DCHECK_LE(offset, static_cast<Offset>(size_));
 873    :  
 874    :    // If we're growing use InsertData.
 875  E :    if (new_size > current_size) {
 876  E :      Offset insert_offset = offset + current_size;
 877  E :      Size insert_size = new_size - current_size;
 878  E :      InsertData(insert_offset, insert_size, always_allocate_data);
 879  E :      return true;
 880    :    }
 881    :  
 882    :    // If we're shrinking we'll need to use RemoveData.
 883  E :    if (new_size < current_size) {
 884  E :      Offset remove_offset = offset + new_size;
 885  E :      Size remove_size = current_size - new_size;
 886  E :      if (!RemoveData(remove_offset, remove_size))
 887  i :        return false;
 888    :      // We fall through so that 'always_allocate_data' can be respected.
 889    :    }
 890    :  
 891    :    // If we've been asked to, at least make sure that the data is allocated.
 892  E :    if (always_allocate_data && data_size_ < offset + new_size)
 893  E :      ResizeData(offset + new_size);
 894    :  
 895  E :    return true;
 896  E :  }
 897    :  
 898  E :  void BlockGraph::Block::SetData(const uint8* data, size_t data_size) {
 899    :    DCHECK((data_size == 0 && data == NULL) ||
 900  E :           (data_size != 0 && data != NULL));
 901  E :    DCHECK(data_size <= size_);
 902    :  
 903  E :    if (owns_data_)
 904  E :      delete [] data_;
 905    :  
 906  E :    owns_data_ = false;
 907  E :    data_ = data;
 908  E :    data_size_ = data_size;
 909  E :  }
 910    :  
 911  E :  uint8* BlockGraph::Block::AllocateData(size_t size) {
 912  E :    uint8* new_data = AllocateRawData(size);
 913  E :    if (new_data == NULL)
 914  i :      return NULL;
 915    :  
 916  E :    ::memset(new_data, 0, size);
 917  E :    return new_data;
 918  E :  }
 919    :  
 920  E :  uint8* BlockGraph::Block::CopyData(size_t size, const void* data) {
 921  E :    uint8* new_data = AllocateRawData(size);
 922  E :    if (new_data == NULL)
 923  i :      return NULL;
 924    :  
 925  E :    memcpy(new_data, data, size);
 926  E :    return new_data;
 927  E :  }
 928    :  
 929  E :  const uint8* BlockGraph::Block::ResizeData(size_t new_size) {
 930  E :    if (new_size == data_size_)
 931  E :      return data_;
 932    :  
 933  E :    if (!owns_data() && new_size < data_size_) {
 934    :      // Not in our ownership and shrinking. We only need to adjust our length.
 935  E :      data_size_ = new_size;
 936  E :    } else {
 937    :      // Either our own data, or it's growing (or both). We need to reallocate.
 938  E :      uint8* new_data = new uint8[new_size];
 939  E :      if (new_data == NULL)
 940  i :        return NULL;
 941    :  
 942    :      // Copy the (head of the) old data.
 943  E :      memcpy(new_data, data_, std::min(data_size_, new_size));
 944  E :      if (new_size > data_size_) {
 945    :        // Zero the tail.
 946  E :        memset(new_data + data_size_, 0, new_size - data_size_);
 947    :      }
 948    :  
 949  E :      if (owns_data())
 950  E :        delete [] data_;
 951    :  
 952  E :      owns_data_ = true;
 953  E :      data_ = new_data;
 954  E :      data_size_ = new_size;
 955    :    }
 956    :  
 957  E :    return data_;
 958  E :  }
 959    :  
 960  E :  uint8* BlockGraph::Block::GetMutableData() {
 961  E :    DCHECK(data_size_ != 0);
 962  E :    DCHECK(data_ != NULL);
 963    :  
 964    :    // Make a copy if we don't already own the data.
 965  E :    if (!owns_data()) {
 966  E :      uint8* new_data = new uint8[data_size_];
 967  E :      if (new_data == NULL)
 968  i :        return NULL;
 969  E :      memcpy(new_data, data_, data_size_);
 970  E :      data_ = new_data;
 971  E :      owns_data_ = true;
 972    :    }
 973  E :    DCHECK(owns_data_);
 974    :  
 975  E :    return const_cast<uint8*>(data_);
 976  E :  }
 977    :  
 978  E :  bool BlockGraph::Block::HasExternalReferrers() const {
 979  E :    ReferrerSet::const_iterator it = referrers().begin();
 980  E :    for (; it != referrers().end(); ++it) {
 981  E :      if (it->first != this)
 982  E :        return true;
 983  E :    }
 984  E :    return false;
 985  E :  }
 986    :  
 987  E :  bool BlockGraph::Block::SetReference(Offset offset, const Reference& ref) {
 988  E :    DCHECK(ref.referenced() != NULL);
 989    :  
 990    :    // Non-code blocks can be referred to by pointers that lie outside of their
 991    :    // extent (due to loop induction, arrays indexed with an implicit offset,
 992    :    // etc). Code blocks can not be referred to in this manner, because references
 993    :    // in code blocks must be places where the flow of execution actually lands.
 994  E :    if (ref.referenced()->type() == CODE_BLOCK) {
 995    :      DCHECK(ref.offset() >= 0 &&
 996  E :          static_cast<size_t>(ref.offset()) <= ref.referenced()->size());
 997  E :      DCHECK(offset + ref.size() <= size());
 998    :    }
 999    :  
1000    :  #if defined(DEBUG) || !defined(NDEBUG)
1001    :    {
1002    :      // NOTE: It might be worthwhile making SetReference return true on success,
1003    :      //     and false on failure as it is possible for references to conflict.
1004    :      //     For now we simply check for conflicts in debug builds and die an
1005    :      //     unglorious death if we find any.
1006    :  
1007  E :      if (!ref.IsValid())
1008  i :        NOTREACHED() << "Trying to insert invalid reference.";
1009    :  
1010    :      // Examine references before us that could possibly conflict with us.
1011  E :      Offset offset_begin = offset - Reference::kMaximumSize + 1;
1012    :      ReferenceMap::const_iterator it =
1013  E :          references_.lower_bound(offset_begin);
1014  E :      for (; it != references_.end() && it->first < offset; ++it) {
1015  E :        if (static_cast<Offset>(it->first + it->second.size()) > offset)
1016  i :          NOTREACHED() << "Trying to insert conflicting reference.";
1017  E :      }
1018    :  
1019    :      // Examine the reference at the same offset if there is one. We expect it to
1020    :      // have the same size and type.
1021  E :      if (it != references_.end() && it->first == offset) {
1022  E :        if (it->second.size() != ref.size() || it->second.type() != ref.type()) {
1023    :        }
1024  E :        ++it;
1025    :      }
1026    :  
1027    :      // This is the first reference after our offset. Check to see if it lands
1028    :      // within the range we want to occupy.
1029    :      if (it != references_.end() &&
1030  E :          it->first < static_cast<Offset>(offset + ref.size())) {
1031  i :        NOTREACHED() << "Trying to insert conflicting reference.";
1032    :      }
1033    :    }
1034    :  #endif
1035    :  
1036    :    // Did we have an earlier reference at this location?
1037  E :    ReferenceMap::iterator it(references_.find(offset));
1038  E :    bool inserted = false;
1039  E :    if (it != references_.end()) {
1040    :      // Erase the back reference.
1041  E :      BlockGraph::Block* referenced = it->second.referenced();
1042  E :      Referrer referrer(this, offset);
1043  E :      size_t removed = referenced->referrers_.erase(referrer);
1044  E :      DCHECK_EQ(1U, removed);
1045    :  
1046    :      // Lastly switch the reference.
1047  E :      it->second = ref;
1048  E :    } else {
1049    :      // It's a new reference, insert it.
1050  E :      inserted = references_.insert(std::make_pair(offset, ref)).second;
1051  E :      DCHECK(inserted);
1052    :    }
1053    :  
1054    :    // Record the back-reference.
1055  E :    ref.referenced()->referrers_.insert(std::make_pair(this, offset));
1056    :  
1057  E :    return inserted;
1058  E :  }
1059    :  
1060    :  bool BlockGraph::Block::GetReference(Offset offset,
1061  E :                                       Reference* reference) const {
1062  E :    DCHECK(reference != NULL);
1063  E :    ReferenceMap::const_iterator it(references_.find(offset));
1064  E :    if (it == references_.end())
1065  E :      return false;
1066    :  
1067  E :    *reference = it->second;
1068  E :    return true;
1069  E :  }
1070    :  
1071  E :  bool BlockGraph::Block::RemoveReference(Offset offset) {
1072    :    // Do we have reference at this location?
1073  E :    ReferenceMap::iterator it(references_.find(offset));
1074  E :    if (it == references_.end())
1075  i :      return false;
1076    :  
1077  E :    BlockGraph::Block* referenced = it->second.referenced();
1078  E :    Referrer referrer(this, offset);
1079  E :    size_t removed = referenced->referrers_.erase(referrer);
1080  E :    DCHECK_EQ(1U, removed);
1081  E :    references_.erase(it);
1082    :  
1083  E :    return true;
1084  E :  }
1085    :  
1086  E :  bool BlockGraph::Block::RemoveAllReferences() {
1087  E :    ReferenceMap::iterator it = references_.begin();
1088  E :    while (it != references_.end()) {
1089  E :      ReferenceMap::iterator to_remove = it;
1090  E :      ++it;
1091    :  
1092    :      // TODO(rogerm): As an optimization, we don't need to drop intra-block
1093    :      //     references when disconnecting from the block_graph. Consider having
1094    :      //     BlockGraph::RemoveBlockByIterator() check that the block has no
1095    :      //     external referrers before calling this function and erasing the
1096    :      //     block.
1097    :  
1098    :      // Unregister this reference from the referred block then erase it.
1099  E :      BlockGraph::Block* referenced = to_remove->second.referenced();
1100  E :      Referrer referrer(this, to_remove->first);
1101  E :      size_t removed = referenced->referrers_.erase(referrer);
1102  E :      DCHECK_EQ(1U, removed);
1103  E :      references_.erase(to_remove);
1104  E :    }
1105    :  
1106  E :    return true;
1107  E :  }
1108    :  
1109  E :  bool BlockGraph::Block::SetLabel(Offset offset, const Label& label) {
1110  E :    DCHECK_LE(0, offset);
1111  E :    DCHECK_LE(static_cast<size_t>(offset), size_);
1112    :  
1113  E :    VLOG(2) << name() << ": adding "
1114    :            << LabelAttributesToString(label.attributes()) << " label '"
1115    :            << label.name() << "' at offset " << offset << ".";
1116    :  
1117    :    // Try inserting the label into the label map.
1118    :    std::pair<LabelMap::iterator, bool> result(
1119  E :        labels_.insert(std::make_pair(offset, label)));
1120    :  
1121    :    // If it was freshly inserted then we're done.
1122  E :    if (result.second)
1123  E :      return true;
1124    :  
1125  E :    return false;
1126  E :  }
1127    :  
1128  E :  bool BlockGraph::Block::GetLabel(Offset offset, Label* label) const {
1129  E :    DCHECK(offset >= 0 && static_cast<size_t>(offset) <= size_);
1130  E :    DCHECK(label != NULL);
1131    :  
1132  E :    LabelMap::const_iterator it = labels_.find(offset);
1133  E :    if (it == labels_.end())
1134  E :      return false;
1135    :  
1136  E :    *label = it->second;
1137  E :    return true;
1138  E :  }
1139    :  
1140  E :  bool BlockGraph::Block::RemoveLabel(Offset offset) {
1141  E :    DCHECK(offset >= 0 && static_cast<size_t>(offset) <= size_);
1142    :  
1143  E :    return labels_.erase(offset) == 1;
1144  E :  }
1145    :  
1146  E :  bool BlockGraph::Block::HasLabel(Offset offset) const {
1147  E :    DCHECK(offset >= 0 && static_cast<size_t>(offset) <= size_);
1148    :  
1149  E :    return labels_.find(offset) != labels_.end();
1150  E :  }
1151    :  
1152    :  bool BlockGraph::Block::TransferReferrers(Offset offset,
1153  E :                                            Block* new_block) {
1154    :    // Redirect all referrers to the new block, we copy the referrer set
1155    :    // because it is otherwise mutated during iteration.
1156  E :    BlockGraph::Block::ReferrerSet referrers = referrers_;
1157  E :    BlockGraph::Block::ReferrerSet::const_iterator referrer_it(referrers.begin());
1158    :  
1159  E :    for (; referrer_it != referrers.end(); ++referrer_it) {
1160    :      // Get the original reference.
1161  E :      BlockGraph::Block::Referrer referrer = *referrer_it;
1162    :      BlockGraph::Block::ReferenceMap::const_iterator found_ref(
1163  E :          referrer.first->references().find(referrer.second));
1164  E :      DCHECK(found_ref != referrer.first->references().end());
1165  E :      BlockGraph::Reference ref(found_ref->second);
1166    :  
1167  E :      Offset new_offset = ref.offset() + offset;
1168  E :      Offset new_base = ref.base() + offset;
1169    :  
1170    :      // Same thing as in SetReferrer, references to non-code blocks may lie
1171    :      // outside the extent of the block.
1172  E :      if (type_ == CODE_BLOCK) {
1173    :        if (new_offset < 0 ||
1174  E :            static_cast<size_t>(new_offset) > new_block->size()) {
1175  E :          LOG(ERROR) << "Transferred reference lies outside of code block.";
1176  E :          return false;
1177    :        }
1178    :      }
1179    :  
1180    :      // Redirect the reference to the new block with the adjusted offset.
1181    :      BlockGraph::Reference new_ref(ref.type(),
1182    :                                    ref.size(),
1183    :                                    new_block,
1184    :                                    new_offset,
1185  E :                                    new_base);
1186  E :      referrer.first->SetReference(referrer.second, new_ref);
1187  E :    }
1188    :  
1189  E :    return true;
1190  E :  }
1191    :  
1192    :  // Returns true if this block contains the given range of bytes.
1193  E :  bool BlockGraph::Block::Contains(RelativeAddress address, size_t size) const {
1194  E :    return (address >= addr_ && address + size <= addr_ + size_);
1195  E :  }
1196    :  
1197  E :  bool BlockGraph::Reference::IsValid() const {
1198    :    // We can't reference a NULL block.
1199  E :    if (referenced_ == NULL)
1200  E :      return false;
1201    :  
1202    :    // First see if the base address is valid for the referenced block.
1203  E :    if (base_ < 0 || static_cast<size_t>(base_) >= referenced_->size())
1204  i :      return false;
1205    :  
1206  E :    if (!IsValidTypeSize(type_, size_))
1207  i :      return false;
1208    :  
1209  E :    return true;
1210  E :  }
1211    :  
1212  E :  bool BlockGraph::Reference::IsValidTypeSize(ReferenceType type, Size size) {
1213  E :    switch (type) {
1214    :      // We see 8- and 32-bit relative JMPs.
1215    :      case PC_RELATIVE_REF:
1216  E :        return size == 1 || size == 4;
1217    :  
1218    :      // These guys are all pointer sized.
1219    :      case ABSOLUTE_REF:
1220    :      case RELATIVE_REF:
1221    :      case FILE_OFFSET_REF:
1222  E :        return size == 4;
1223    :  
1224    :      default:
1225  i :        NOTREACHED() << "Unknown ReferenceType.";
1226    :    }
1227    :  
1228  i :    return false;
1229  E :  }
1230    :  
1231    :  }  // namespace block_graph

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