Coverage for /Syzygy/pe/hot_patching_decomposer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
87.8%2152450.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 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/pe/hot_patching_decomposer.h"
  16    :  
  17    :  #include "base/bind.h"
  18    :  #include "syzygy/common/defs.h"
  19    :  #include "syzygy/pe/pe_utils.h"
  20    :  
  21    :  namespace pe {
  22    :  
  23    :  namespace {
  24    :  
  25    :  using block_graph::BlockGraph;
  26    :  using block_graph::BlockInfo;
  27    :  using core::AbsoluteAddress;
  28    :  using core::FileOffsetAddress;
  29    :  using core::RelativeAddress;
  30    :  
  31    :  typedef BlockGraph::Block Block;
  32    :  
  33    :  // NOTE: This is based on GetSectionName in from pe_coff_file_impl.h.
  34  E :  std::string GetSectionName(const IMAGE_SECTION_HEADER& section) {
  35  E :    const char* name = reinterpret_cast<const char*>(section.Name);
  36  E :    return std::string(name, strnlen(name, arraysize(section.Name)));
  37  E :  }
  38    :  
  39    :  // NOTE: This is based on CopySectionInfoToBlockGraph in pe_utils_impl.h.
  40    :  //    Added the section_index parameter to create an index used later in
  41    :  //    CreateBlock.
  42    :  bool CopySectionInfoToBlockGraph(
  43    :      const base::win::PEImage& image_file,
  44    :      BlockGraph* block_graph,
  45  E :      HotPatchingDecomposer::SectionIdMap* section_index) {
  46  E :    DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
  47  E :    DCHECK_NE(static_cast<HotPatchingDecomposer::SectionIdMap*>(nullptr),
  48  E :              section_index);
  49    :  
  50    :    // Iterate through the image sections, and create sections in the BlockGraph.
  51    :    uint32_t num_sections =
  52  E :        image_file.GetNTHeaders()->FileHeader.NumberOfSections;
  53  E :    for (uint32_t i = 0; i < num_sections; ++i) {
  54  E :      const IMAGE_SECTION_HEADER* header = image_file.GetSectionHeader(i);
  55  E :      std::string name = GetSectionName(*header);
  56  E :      BlockGraph::Section* section = block_graph->AddSection(
  57    :          name, header->Characteristics);
  58  E :      DCHECK_NE(static_cast<BlockGraph::Section*>(nullptr), section);
  59    :  
  60    :      // For now, we expect them to have been created with the same IDs as those
  61    :      // in the original image.
  62  E :      if (section->id() != i) {
  63  i :        LOG(ERROR) << "Unexpected section ID.";
  64  i :        return false;
  65    :      }
  66    :  
  67  E :      section_index->insert(std::make_pair(header, section->id()));
  68  E :    }
  69    :  
  70  E :    return true;
  71  E :  }
  72    :  
  73    :  // Interprets the 32-bit unsigned integer parameter as a pointer, and checks
  74    :  // if it points to the block's data, after a specific offset.
  75    :  // @param displacement The 32-bit unsigned integer.
  76    :  // @param block The block to check.
  77    :  // @param offset The pointer must point after this offset.
  78    :  // @returns true if the conditions are met, false otherwise.
  79    :  bool DisplacementPointsIntoBlockAfterOffset(uint32_t displacement,
  80    :                                              const BlockGraph::Block* block,
  81  E :                                              size_t offset) {
  82  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
  83    :  
  84  E :    return reinterpret_cast<uint8_t*>(displacement) >= block->data() + offset &&
  85    :           reinterpret_cast<uint8_t*>(displacement) <
  86    :               block->data() + block->data_size();
  87  E :  }
  88    :  
  89    :  // This function is called when we didn't manage to parse an instruction.
  90    :  // We do some sanity DCHECKs to verify that the instruction does not contain
  91    :  // a reference that we failed to recover.
  92    :  // @param block The block containing the instructions.
  93    :  // @param inst The instruction to examine.
  94    :  void ExecuteSanityChecks(BlockGraph::Block* block,
  95    :                           BlockGraph::Offset offset,
  96  E :                           const _DInst& inst) {
  97  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
  98    :  
  99  E :    for (int i = 0; i < arraysize(inst.ops); ++i) {
 100    :      // Fail if we see PC-relative operand.
 101  E :      if (inst.ops[i].type == O_PC)
 102  i :        NOTREACHED();
 103    :  
 104    :      // Fail if we see an absolute pointer in the displacement that can be
 105    :      // interpreted as a pointer to anywhere inside the block. This is
 106    :      // probably some unknown construct that needs to be handled.
 107  E :      if (inst.ops[i].type == O_SMEM || inst.ops[i].type == O_MEM) {
 108  E :        if (inst.dispSize == 32U &&
 109    :            DisplacementPointsIntoBlockAfterOffset(inst.disp, block, 0U)) {
 110  i :          LOG(ERROR) << "Pointer-like displacement: " << inst.disp;
 111  i :          NOTREACHED();
 112    :        }
 113    :      }
 114  E :    }
 115  E :  }
 116    :  
 117    :  // Adds a data label to a block. If a data label already exists at the offset
 118    :  // that is neither a case table nor a jump table label, it will be replaced.
 119    :  // Otherwise a DCHECK will be used to check if the old and the desired labels
 120    :  // have the same attributes.
 121    :  // @param block The block to add the label to.
 122    :  // @param offset The offset of the desired label.
 123    :  // @param label_name The name of the desired label.
 124    :  // @param additional_attribute Specifies whether the desired label is a
 125    :  //     JUMP_TABLE_LABEL or CASE_TABLE_LABEL.
 126    :  void AddDataLabel(BlockGraph::Block* block,
 127    :                    BlockGraph::Offset offset,
 128    :                    const std::string& label_name,
 129  E :                    BlockGraph::LabelAttributesEnum additional_attribute) {
 130  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 131  E :    DCHECK(additional_attribute == BlockGraph::JUMP_TABLE_LABEL ||
 132    :           additional_attribute == BlockGraph::CASE_TABLE_LABEL);
 133    :  
 134    :    BlockGraph::LabelAttributes label_attributes =
 135  E :        BlockGraph::DATA_LABEL | additional_attribute;
 136    :  
 137  E :    if (block->HasLabel(offset)) {
 138    :      // The label already exists, just update the attribute if needed.
 139  E :      BlockGraph::Label old_label;
 140  E :      block->GetLabel(offset, &old_label);
 141  E :      DCHECK(old_label.has_attributes(BlockGraph::DATA_LABEL));
 142    :  
 143  E :      if (old_label.attributes() == BlockGraph::DATA_LABEL) {
 144    :        // A simple DATA_LABEL is created by the decomposer at the end of the code
 145    :        // block. We replace this label with a more specific one.
 146    :  
 147    :        // The data part may not start with a case table.
 148  E :        DCHECK_EQ(additional_attribute, BlockGraph::JUMP_TABLE_LABEL);
 149    :  
 150    :        // We can't change the label, so remove it and add a new one.
 151  E :        block->RemoveLabel(offset);
 152  E :      } else {
 153    :        // Sanity check: no case table and jump table at the same location.
 154  i :        DCHECK_EQ(old_label.name(), label_name);
 155  i :        DCHECK_EQ(old_label.attributes(), label_attributes);
 156    :  
 157    :        // The label is already there, no need to add it again.
 158  i :        return;
 159    :      }
 160  E :    }
 161    :  
 162  E :    if (!block->SetLabel(offset, label_name, label_attributes)) {
 163    :      // SetLabel returns false if the label already existed, which can't happen
 164    :      // because we've just removed it.
 165  i :      NOTREACHED();
 166    :    }
 167  E :  }
 168    :  
 169    :  }  // namespace
 170    :  
 171    :  HotPatchingDecomposer::HotPatchingDecomposer(HMODULE module)
 172  E :      : image_layout_(nullptr),
 173  E :        image_(nullptr),
 174  E :        last_code_block_id_(0U),
 175  E :        module_(module) {
 176  E :  }
 177    :  
 178  E :  HotPatchingDecomposer::~HotPatchingDecomposer() { }
 179    :  
 180  E :  bool HotPatchingDecomposer::Decompose(ImageLayout* image_layout) {
 181  E :    DCHECK_NE(static_cast<ImageLayout*>(nullptr), image_layout);
 182    :  
 183    :    // The temporaries should be nullptr.
 184  E :    DCHECK_EQ(static_cast<ImageLayout*>(nullptr), image_layout_);
 185  E :    DCHECK_EQ(static_cast<BlockGraph::AddressSpace*>(nullptr), image_);
 186    :  
 187  E :    image_layout_ = image_layout;
 188  E :    image_ = &(image_layout->blocks);
 189    :  
 190    :    // Initialize in-memory PE wrapper.
 191  E :    pe_image_ = std::make_unique<base::win::PEImage>(module_);
 192    :  
 193    :    // Set the image format.
 194  E :    image_->graph()->set_image_format(BlockGraph::PE_IN_MEMORY_IMAGE);
 195    :  
 196    :    // Process sections in image.
 197  E :    if (!LoadSectionInformation())
 198  i :      return false;
 199    :  
 200    :    // Process blocks using the hot patching metadata.
 201  E :    if (!LoadHotPatchableBlocks())
 202  i :      return false;
 203    :  
 204  E :    return true;
 205  E :  }
 206    :  
 207    :  // NOTE: This is based on Decomposer::CreateBlock.
 208    :  Block* HotPatchingDecomposer::CreateBlock(BlockType type,
 209    :                                            RelativeAddress address,
 210    :                                            BlockGraph::Size size,
 211  E :                                            const base::StringPiece& name) {
 212  E :    Block* block = image_->AddBlock(type, address, size, name);
 213  E :    if (block == nullptr) {
 214  i :      LOG(ERROR) << "Unable to add block \"" << name.as_string() << "\" at "
 215    :                 << address << " with size " << size << ".";
 216  i :      return nullptr;
 217    :    }
 218    :  
 219    :    // Mark the source range from whence this block originates.
 220  E :    bool pushed = block->source_ranges().Push(
 221    :        Block::DataRange(0, size),
 222    :        Block::SourceRange(address, size));
 223  E :    DCHECK(pushed);
 224    :  
 225    :    // Search section id in the index.
 226    :    const IMAGE_SECTION_HEADER* block_section_header =
 227  E :        pe_image_->GetImageSectionFromAddr(pe_image_->RVAToAddr(address.value()));
 228  E :    if (block_section_header == nullptr) {
 229  i :      LOG(ERROR) << "Block \"" << name.as_string() << "\" at " << address
 230    :                 << " with size " << size << " lies outside of all sections.";
 231  i :      return nullptr;
 232    :    }
 233  E :    const auto it = section_index_.find(block_section_header);
 234  E :    DCHECK(it != section_index_.end());
 235  E :    block->set_section(it->second);
 236    :  
 237    :    const uint8_t* data =
 238  E :        static_cast<const uint8_t*>(pe_image_->RVAToAddr(address.value()));
 239  E :    if (data != nullptr)
 240  E :      block->SetData(data, size);
 241    :  
 242  E :    return block;
 243  E :  }
 244    :  
 245    :  bool HotPatchingDecomposer::InferCodeReferences(Block* block,
 246  E :                                                  size_t code_size) {
 247  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 248    :  
 249    :    // Disassemble the block
 250  E :    size_t offset = 0;
 251  E :    while (offset < code_size) {
 252    :      _DInst inst;
 253    :  
 254    :      // Try to decode the next instruction.
 255  E :      const uint8_t* inst_data = block->data() + offset;
 256  E :      if (!core::DecodeOneInstruction(inst_data,
 257    :                                      static_cast<int>(code_size - offset),
 258    :                                      &inst)) {
 259  i :        LOG(ERROR) << "Failed to decode instruction at offset " << offset
 260    :                   << " in block " << BlockInfo(block);
 261  i :        return false;
 262    :      }
 263    :  
 264    :      // Try to recover reference from the instruction.
 265  E :      bool parsed = false;
 266  E :      if (!ParsePCRelativeBranchAndCallInstuction(block, offset, inst, &parsed))
 267  i :        return false;
 268  E :      if (!parsed && !ParseJumpTableCall(block, offset, inst, code_size, &parsed))
 269  i :        return false;
 270  E :      if (!parsed && !ParseCaseTableRead(block, offset, inst, code_size, &parsed))
 271  i :        return false;
 272    :  
 273    :      // Do some sanity checks in DCHECK builds if we see no reference.
 274  E :      if (!parsed)
 275  E :        ExecuteSanityChecks(block, offset, inst);
 276    :  
 277  E :      offset += inst.size;
 278  E :    }
 279    :  
 280  E :    return true;
 281  E :  }
 282    :  
 283    :  bool HotPatchingDecomposer::InferJumpTableReferences(Block* block,
 284  E :                                                       size_t code_size) {
 285  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 286    :  
 287  E :    const uint8_t* block_start = block->data();
 288  E :    const uint8_t* block_end = block->data() + block->data_size();
 289    :  
 290  E :    for (auto it = block->labels().begin(); it != block->labels().end();) {
 291  E :      BlockGraph::Offset offset = it->first;
 292  E :      const BlockGraph::Label& label = it->second;
 293    :  
 294    :      // We increment the iterator here because we want to access the next label
 295    :      // below. The current label is already saved in |label|.
 296  E :      ++it;
 297    :  
 298  E :      if (label.has_attributes(BlockGraph::JUMP_TABLE_LABEL)) {
 299    :        // The jump table ends at the next label or at the end of the block.
 300  E :        BlockGraph::Offset end_offset = 0;
 301  E :        if (it != block->labels().end()) {
 302  E :          end_offset = it->first;
 303  E :        } else {
 304  E :          end_offset = block->data_size();
 305    :        }
 306    :  
 307    :        // Calculate start and end relative addresses.
 308  E :        RelativeAddress addr = block->addr() + offset;
 309  E :        const RelativeAddress end_addr = block->addr() + end_offset;
 310    :  
 311    :        // While we have more than 4 bytes remaining.
 312  E :        for (; addr <= end_addr - 4; addr += 4) {
 313    :  
 314    :          // Interpret the 4 bytes starting at |addr| as a pointer.
 315    :          const uint8_t* const* target_location =
 316  E :              reinterpret_cast<const uint8_t* const*>(block->data() +
 317    :                                                      (addr - block->addr()));
 318  E :          const uint8_t* target_as_pointer = *target_location;
 319    :  
 320    :          // Add an absolute reference if this address points into the block.
 321  E :          if (block_start <= target_as_pointer && target_as_pointer < block_end) {
 322  E :            BlockGraph::Offset target_offset = target_as_pointer - block_start;
 323  E :            DCHECK_GE(target_offset, 0);
 324    :            // The reference should not point into the data part of the block.
 325  E :            DCHECK_LT(target_offset, static_cast<int>(code_size));
 326    :  
 327  E :            if (!block->SetReference(addr - block->addr(),
 328    :                                     BlockGraph::Reference(
 329    :                                         BlockGraph::ABSOLUTE_REF,
 330    :                                         4,
 331    :                                         block,
 332    :                                         target_offset,
 333    :                                         target_offset))) {
 334  i :              return false;
 335    :            }
 336    :          }
 337  E :        }
 338    :      }
 339  E :    }
 340    :  
 341  E :    return true;
 342  E :  }
 343    :  
 344  E :  bool HotPatchingDecomposer::LoadHotPatchableBlocks() {
 345  E :    PIMAGE_SECTION_HEADER hp_sect_hdr = pe_image_->GetImageSectionHeaderByName(
 346    :        common::kHotPatchingMetadataSectionName);
 347  E :    DCHECK_NE(static_cast<PIMAGE_SECTION_HEADER>(nullptr), hp_sect_hdr);
 348    :  
 349    :    // Load metadata section header.
 350    :    block_graph::HotPatchingMetadataHeader* hp_metadata_header =
 351    :        static_cast<block_graph::HotPatchingMetadataHeader*>(
 352  E :            pe_image_->RVAToAddr(hp_sect_hdr->VirtualAddress));
 353  E :    DCHECK_NE(static_cast<block_graph::HotPatchingMetadataHeader*>(nullptr),
 354  E :        hp_metadata_header);
 355  E :    if (block_graph::kHotPatchingMetadataVersion !=
 356    :        hp_metadata_header->version) {
 357  i :      return false;
 358    :    }
 359    :  
 360    :    // Locate the block metadata array. The (hp_metadata_header + 1) expression is
 361    :    // a pointer pointing to the location after the header.
 362    :    block_graph::HotPatchingBlockMetadata* hp_block_metadata_arr =
 363    :        reinterpret_cast<block_graph::HotPatchingBlockMetadata*>(
 364  E :            hp_metadata_header + 1);
 365    :  
 366    :    // Create hot patchable code blocks and their labels based on the hot
 367    :    // patching metadata.
 368  E :    for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
 369  E :      Block* block = ProcessHotPatchableCodeBlock(hp_block_metadata_arr[i]);
 370  E :      DCHECK_NE(static_cast<Block*>(nullptr), block);
 371  E :    }
 372    :  
 373    :    // Create references for hot patchable code blocks.
 374    :    //
 375    :    // This must run after all hot patchable blocks have been created because it
 376    :    // searches for the referred block and creates a dummy block if the referred
 377    :    // block is not found.
 378  E :    for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
 379  E :      Block* block = image_layout_->blocks.GetBlockByAddress(
 380    :          RelativeAddress(hp_block_metadata_arr[i].relative_address));
 381    :  
 382  E :      DCHECK_NE(static_cast<Block*>(nullptr), block);
 383    :  
 384  E :      InferCodeReferences(block, hp_block_metadata_arr[i].code_size);
 385    :  
 386  E :      if (hp_block_metadata_arr[i].code_size <
 387    :          hp_block_metadata_arr[i].block_size) {
 388  E :        InferJumpTableReferences(block, hp_block_metadata_arr[i].code_size);
 389    :      }
 390  E :    }
 391    :  
 392  E :    return true;
 393  E :  }
 394    :  
 395  E :  bool HotPatchingDecomposer::LoadSectionInformation() {
 396    :    // Create sections in the image layout.
 397  E :    CopySectionHeadersToImageLayout(
 398    :        pe_image_->GetNTHeaders()->FileHeader.NumberOfSections,
 399    :        pe_image_->GetSectionHeader(0),
 400    :        &(image_layout_->sections));
 401    :  
 402    :    // Create the sections in the underlying block-graph.
 403  E :    if (!CopySectionInfoToBlockGraph(*pe_image_,
 404    :                                     image_->graph(),
 405    :                                     &section_index_)) {
 406  i :      return false;
 407    :    }
 408    :  
 409  E :    return true;
 410  E :  }
 411    :  
 412    :  bool HotPatchingDecomposer::ParseCaseTableRead(BlockGraph::Block* block,
 413    :                                                 BlockGraph::Offset offset,
 414    :                                                 const _DInst &inst,
 415    :                                                 size_t code_size,
 416  E :                                                 bool* parsed) {
 417  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 418  E :    DCHECK_NE(static_cast<bool*>(nullptr), parsed);
 419    :  
 420    :    // Check if the instruction is a case table read.
 421  E :    *parsed = inst.opcode == I_MOVZX &&
 422    :              inst.ops[0].type == O_REG &&
 423    :              inst.ops[1].type == O_SMEM &&
 424    :              inst.dispSize == 32U &&
 425    :              inst.ops[2].type == O_NONE &&
 426    :              DisplacementPointsIntoBlockAfterOffset(inst.disp, block, code_size);
 427    :  
 428    :    // Return early if not.
 429  E :    if (!*parsed)
 430  E :      return true;
 431    :  
 432  E :    int reference_size = inst.dispSize / 8;
 433    :  
 434    :    BlockGraph::Offset ref_source_offset =
 435  E :        offset + inst.size - reference_size;
 436    :    BlockGraph::Offset ref_target_offset =
 437  E :        reinterpret_cast<uint8_t*>(inst.disp) - block->data();
 438    :  
 439    :    // The displacement is at the end of this instruction.
 440  E :    if (!block->SetReference(ref_source_offset,
 441    :                             BlockGraph::Reference(
 442    :                                 BlockGraph::ABSOLUTE_REF,
 443    :                                 reference_size,
 444    :                                 block,
 445    :                                 ref_target_offset,
 446    :                                 ref_target_offset))) {
 447  i :      LOG(ERROR) << "Failed to create self reference in block "
 448    :                 << BlockInfo(block) << " from offset "
 449    :                 << ref_source_offset << " to offset " << ref_target_offset;
 450  i :      return false;
 451    :    }
 452    :  
 453    :    // Insert a case table label.
 454  E :    AddDataLabel(block,
 455    :                 ref_target_offset,
 456    :                 "case-table",
 457    :                 BlockGraph::CASE_TABLE_LABEL);
 458    :  
 459  E :    return true;
 460  E :  }
 461    :  
 462    :  bool HotPatchingDecomposer::ParseJumpTableCall(BlockGraph::Block* block,
 463    :                                                 BlockGraph::Offset offset,
 464    :                                                 const _DInst &inst,
 465    :                                                 size_t code_size,
 466  E :                                                 bool* parsed) {
 467  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 468  E :    DCHECK_NE(static_cast<bool*>(nullptr), parsed);
 469    :  
 470    :    // Check if the instruction is a jump using a jump table.
 471  E :    *parsed = inst.opcode == I_JMP &&
 472    :              inst.ops[0].type == O_MEM &&
 473    :              inst.ops[1].type == O_NONE &&
 474    :              inst.scale == 4U &&
 475    :              inst.dispSize == 32U &&
 476    :              DisplacementPointsIntoBlockAfterOffset(inst.disp, block,
 477    :                                                     code_size);
 478    :  
 479    :    // Return early if not.
 480  E :    if (!*parsed)
 481  E :      return true;
 482    :  
 483  E :    int reference_size = inst.dispSize / 8;
 484    :  
 485    :    BlockGraph::Offset ref_source_offset =
 486  E :        offset + inst.size - reference_size;
 487    :    BlockGraph::Offset ref_target_offset =
 488  E :        reinterpret_cast<uint8_t*>(inst.disp) - block->data();
 489    :  
 490    :    // The displacement is always at the end of a one-operand instruction.
 491  E :    if (!block->SetReference(ref_source_offset,
 492    :                             BlockGraph::Reference(
 493    :                                 BlockGraph::ABSOLUTE_REF,
 494    :                                 reference_size,
 495    :                                 block,
 496    :                                 ref_target_offset,
 497    :                                 ref_target_offset))) {
 498  i :      LOG(ERROR) << "Failed to create self reference in block "
 499    :                 << BlockInfo(block) << " from offset "
 500    :                 << ref_source_offset << " to offset " << ref_target_offset;
 501  i :      return false;
 502    :    }
 503    :  
 504    :    // Insert a jump table label.
 505  E :    AddDataLabel(block,
 506    :                 ref_target_offset,
 507    :                 "jump-table",
 508    :                 BlockGraph::JUMP_TABLE_LABEL);
 509    :  
 510  E :    return true;
 511  E :  }
 512    :  
 513    :  bool HotPatchingDecomposer::ParsePCRelativeBranchAndCallInstuction(
 514    :      BlockGraph::Block* block,
 515    :      BlockGraph::Offset offset,
 516    :      const _DInst &inst,
 517  E :      bool* parsed) {
 518  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 519  E :    DCHECK_NE(static_cast<bool*>(nullptr), parsed);
 520    :  
 521  E :    *parsed = (core::IsBranch(inst) || core::IsCall(inst)) &&
 522    :              inst.ops[0].type == O_PC;
 523  E :    if (!*parsed)
 524  E :      return true;
 525    :  
 526  E :    CHECK(inst.ops[1].type == O_NONE);
 527    :  
 528  E :    int reference_size = inst.ops[0].size / 8;
 529    :  
 530  E :    if (reference_size == 4) {
 531    :      // Insert a reference for 32-bit PC-relative jump and call instructions.
 532    :  
 533    :      // Create the reference.
 534  E :      BlockGraph::Offset pc_relative_address = inst.imm.addr;
 535  E :      RelativeAddress target_relative_address = RelativeAddress(
 536    :          block->addr().value() + offset + pc_relative_address + inst.size);
 537  E :      Block* referenced_block = image_layout_->blocks.GetBlockByAddress(
 538    :          target_relative_address);
 539    :  
 540  E :      BlockGraph::Offset ref_target_offset = 0;
 541    :  
 542  E :      if (referenced_block != nullptr) {
 543  E :        ref_target_offset =
 544    :            target_relative_address - referenced_block->addr();
 545    :  
 546  E :        if (referenced_block != block) {
 547    :          // If the following check fails that means that we have an
 548    :          // inter-block reference pointing inside a hot patchable block.
 549  E :          CHECK_EQ(target_relative_address, referenced_block->addr());
 550    :        }
 551  E :      } else {
 552    :        // There is no block at the referred location. This means that the
 553    :        // referred block is not hot patchable. Create a dummy code block that
 554    :        // can be referenced.
 555  E :        referenced_block = CreateBlock(BlockGraph::CODE_BLOCK,
 556    :                                       target_relative_address,
 557    :                                       1,
 558    :                                       "TargetBlock");
 559  E :        DCHECK_NE(static_cast<Block*>(nullptr), referenced_block);
 560    :        // We set the BUILT_BY_UNSUPPORTED_COMPILER attribute on dummy blocks.
 561    :        // This attribute expresses that the block can't be moved and the data
 562    :        // of the block should not be interpreted.
 563  E :        referenced_block->set_attribute(
 564    :            BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
 565    :  
 566  E :        ref_target_offset = 0;
 567    :      }
 568    :  
 569  E :      DCHECK_GE(inst.size, 1 + reference_size);
 570  E :      DCHECK_GE(2 + reference_size, inst.size);
 571    :  
 572    :      // The reference is always at the end of the instruction.
 573  E :      if (!block->SetReference(offset + inst.size - reference_size,
 574    :                                BlockGraph::Reference(
 575    :                                    BlockGraph::PC_RELATIVE_REF,
 576    :                                    reference_size,
 577    :                                    referenced_block,
 578    :                                    ref_target_offset,
 579    :                                    ref_target_offset))) {
 580  i :        return false;
 581    :      }
 582  E :      ++parsed;
 583    :    } else {
 584    :      // We don't deal with smaller references. These are in-block references
 585    :      // that are resolved by the basic block decomposer.
 586    :    }
 587    :  
 588  E :    return true;
 589  E :  }
 590    :  
 591    :  Block *HotPatchingDecomposer::ProcessHotPatchableCodeBlock(
 592  E :      const block_graph::HotPatchingBlockMetadata& block_metadata) {
 593    :  
 594    :    // The relative address will point to the correct field as it should be
 595    :    // relocated.
 596  E :    RelativeAddress data_address(block_metadata.relative_address);
 597  E :    size_t block_size = block_metadata.block_size;
 598    :  
 599    :    // Generate a unique name for the block.
 600  E :    ++last_code_block_id_;
 601  E :    std::string block_name = "CodeBlock" + std::to_string(last_code_block_id_);
 602    :  
 603    :    // Add the block to the block graph.
 604  E :    Block* block = CreateBlock(BlockGraph::CODE_BLOCK,
 605    :                               data_address,
 606    :                               block_size,
 607    :                               block_name);
 608  E :    if (block == nullptr) {
 609  i :      LOG(ERROR) << "Unable to add code block at "
 610    :                 << data_address << " with size " << block_size << ".";
 611  i :      return nullptr;
 612    :    }
 613    :  
 614    :    // Add a code label to the beginning of the block.
 615  E :    block->SetLabel(0, "CODE", BlockGraph::CODE_LABEL);
 616    :  
 617    :    // If the code does not fill the whole data, put a data label at the end of
 618    :    // the code.
 619  E :    if (block_metadata.code_size != block_metadata.block_size) {
 620  E :      block->SetLabel(static_cast<int>(block_metadata.code_size),
 621    :                      "DATA", BlockGraph::DATA_LABEL);
 622    :    }
 623    :  
 624  E :    return block;
 625  E :  }
 626    :  
 627    :  }  // namespace pe

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