Coverage for /Syzygy/pe/hot_patching_decomposer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
87.5%2102400.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    :    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  E :    size_t num_sections = image_file.GetNTHeaders()->FileHeader.NumberOfSections;
  52  E :    for (size_t i = 0; i < num_sections; ++i) {
  53  E :      const IMAGE_SECTION_HEADER* header = image_file.GetSectionHeader(i);
  54  E :      std::string name = GetSectionName(*header);
  55    :      BlockGraph::Section* section = block_graph->AddSection(
  56  E :          name, header->Characteristics);
  57  E :      DCHECK_NE(static_cast<BlockGraph::Section*>(nullptr), section);
  58    :  
  59    :      // For now, we expect them to have been created with the same IDs as those
  60    :      // in the original image.
  61  E :      if (section->id() != i) {
  62  i :        LOG(ERROR) << "Unexpected section ID.";
  63  i :        return false;
  64    :      }
  65    :  
  66  E :      section_index->insert(std::make_pair(header, section->id()));
  67  E :    }
  68    :  
  69  E :    return true;
  70  E :  }
  71    :  
  72    :  // Interprets the 32-bit unsigned integer parameter as a pointer, and checks
  73    :  // if it points to the block's data, after a specific offset.
  74    :  // @param displacement The 32-bit unsigned integer.
  75    :  // @param block The block to check.
  76    :  // @param offset The pointer must point after this offset.
  77    :  // @returns true if the conditions are met, false otherwise.
  78    :  bool DisplacementPointsIntoBlockAfterOffset(uint32 displacement,
  79    :                                              const BlockGraph::Block* block,
  80  E :                                              size_t offset) {
  81  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
  82    :  
  83    :    return reinterpret_cast<uint8*>(displacement) >=
  84    :               block->data() + offset &&
  85    :           reinterpret_cast<uint8*>(displacement) <
  86  E :               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    :        if (inst.dispSize == 32U &&
 109  E :            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    :    DCHECK(additional_attribute == BlockGraph::JUMP_TABLE_LABEL ||
 132  E :           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    :      : image_layout_(nullptr),
 173    :        image_(nullptr),
 174    :        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    :    bool pushed = block->source_ranges().Push(
 221    :        Block::DataRange(0, size),
 222  E :        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* data = static_cast<const uint8*>(
 238  E :        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* inst_data = block->data() + offset;
 256  E :      if (!core::DecodeOneInstruction(inst_data, code_size - offset, &inst)) {
 257  i :        LOG(ERROR) << "Failed to decode instruction at offset " << offset
 258    :                   << " in block " << BlockInfo(block);
 259  i :        return false;
 260    :      }
 261    :  
 262    :      // Try to recover reference from the instruction.
 263  E :      bool parsed = false;
 264  E :      if (!ParsePCRelativeBranchAndCallInstuction(block, offset, inst, &parsed))
 265  i :        return false;
 266  E :      if (!parsed && !ParseJumpTableCall(block, offset, inst, code_size, &parsed))
 267  i :        return false;
 268  E :      if (!parsed && !ParseCaseTableRead(block, offset, inst, code_size, &parsed))
 269  i :        return false;
 270    :  
 271    :      // Do some sanity checks in DCHECK builds if we see no reference.
 272  E :      if (!parsed)
 273  E :        ExecuteSanityChecks(block, offset, inst);
 274    :  
 275  E :      offset += inst.size;
 276  E :    }
 277    :  
 278  E :    return true;
 279  E :  }
 280    :  
 281    :  bool HotPatchingDecomposer::InferJumpTableReferences(Block* block,
 282  E :                                                       size_t code_size) {
 283  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 284    :  
 285  E :    const uint8* block_start = block->data();
 286  E :    const uint8* block_end = block->data() + block->data_size();
 287    :  
 288  E :    for (auto it = block->labels().begin(); it != block->labels().end();) {
 289  E :      BlockGraph::Offset offset = it->first;
 290  E :      const BlockGraph::Label& label = it->second;
 291    :  
 292    :      // We increment the iterator here because we want to access the next label
 293    :      // below. The current label is already saved in |label|.
 294  E :      ++it;
 295    :  
 296  E :      if (label.has_attributes(BlockGraph::JUMP_TABLE_LABEL)) {
 297    :        // The jump table ends at the next label or at the end of the block.
 298  E :        BlockGraph::Offset end_offset = 0;
 299  E :        if (it != block->labels().end()) {
 300  E :          end_offset = it->first;
 301  E :        } else {
 302  E :          end_offset = block->data_size();
 303    :        }
 304    :  
 305    :        // Calculate start and end relative addresses.
 306  E :        RelativeAddress addr = block->addr() + offset;
 307  E :        const RelativeAddress end_addr = block->addr() + end_offset;
 308    :  
 309    :        // While we have more than 4 bytes remaining.
 310  E :        for (; addr <= end_addr - 4; addr += 4) {
 311    :  
 312    :          // Interpret the 4 bytes starting at |addr| as a pointer.
 313    :          const uint8* const* target_location =
 314    :              reinterpret_cast<const uint8* const*>(
 315  E :                  block->data() + (addr - block->addr()));
 316  E :          const uint8* target_as_pointer = *target_location;
 317    :  
 318    :          // Add an absolute reference if this address points into the block.
 319  E :          if (block_start <= target_as_pointer && target_as_pointer < block_end) {
 320  E :            BlockGraph::Offset target_offset = target_as_pointer - block_start;
 321  E :            DCHECK_GE(target_offset, 0);
 322    :            // The reference should not point into the data part of the block.
 323  E :            DCHECK_LT(target_offset, static_cast<int>(code_size));
 324    :  
 325    :            if (!block->SetReference(addr - block->addr(),
 326    :                                     BlockGraph::Reference(
 327    :                                         BlockGraph::ABSOLUTE_REF,
 328    :                                         4,
 329    :                                         block,
 330    :                                         target_offset,
 331  E :                                         target_offset))) {
 332  i :              return false;
 333    :            }
 334    :          }
 335  E :        }
 336    :      }
 337  E :    }
 338    :  
 339  E :    return true;
 340  E :  }
 341    :  
 342  E :  bool HotPatchingDecomposer::LoadHotPatchableBlocks() {
 343    :    PIMAGE_SECTION_HEADER hp_sect_hdr = pe_image_->GetImageSectionHeaderByName(
 344  E :        common::kHotPatchingMetadataSectionName);
 345  E :    DCHECK_NE(static_cast<PIMAGE_SECTION_HEADER>(nullptr), hp_sect_hdr);
 346    :  
 347    :    // Load metadata section header.
 348    :    block_graph::HotPatchingMetadataHeader* hp_metadata_header =
 349    :        static_cast<block_graph::HotPatchingMetadataHeader*>(
 350  E :            pe_image_->RVAToAddr(hp_sect_hdr->VirtualAddress));
 351    :    DCHECK_NE(static_cast<block_graph::HotPatchingMetadataHeader*>(nullptr),
 352  E :        hp_metadata_header);
 353    :    if (block_graph::kHotPatchingMetadataVersion !=
 354  E :        hp_metadata_header->version) {
 355  i :      return false;
 356    :    }
 357    :  
 358    :    // Locate the block metadata array. The (hp_metadata_header + 1) expression is
 359    :    // a pointer pointing to the location after the header.
 360    :    block_graph::HotPatchingBlockMetadata* hp_block_metadata_arr =
 361    :        reinterpret_cast<block_graph::HotPatchingBlockMetadata*>(
 362  E :            hp_metadata_header + 1);
 363    :  
 364    :    // Create hot patchable code blocks and their labels based on the hot
 365    :    // patching metadata.
 366  E :    for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
 367  E :      Block* block = ProcessHotPatchableCodeBlock(hp_block_metadata_arr[i]);
 368  E :      DCHECK_NE(static_cast<Block*>(nullptr), block);
 369  E :    }
 370    :  
 371    :    // Create references for hot patchable code blocks.
 372    :    //
 373    :    // This must run after all hot patchable blocks have been created because it
 374    :    // searches for the referred block and creates a dummy block if the referred
 375    :    // block is not found.
 376  E :    for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
 377    :      Block* block = image_layout_->blocks.GetBlockByAddress(
 378  E :          RelativeAddress(hp_block_metadata_arr[i].relative_address));
 379    :  
 380  E :      DCHECK_NE(static_cast<Block*>(nullptr), block);
 381    :  
 382  E :      InferCodeReferences(block, hp_block_metadata_arr[i].code_size);
 383    :  
 384    :      if (hp_block_metadata_arr[i].code_size <
 385  E :          hp_block_metadata_arr[i].block_size) {
 386  E :        InferJumpTableReferences(block, hp_block_metadata_arr[i].code_size);
 387    :      }
 388  E :    }
 389    :  
 390  E :    return true;
 391  E :  }
 392    :  
 393  E :  bool HotPatchingDecomposer::LoadSectionInformation() {
 394    :    // Create sections in the image layout.
 395    :    CopySectionHeadersToImageLayout(
 396    :        pe_image_->GetNTHeaders()->FileHeader.NumberOfSections,
 397    :        pe_image_->GetSectionHeader(0),
 398  E :        &(image_layout_->sections));
 399    :  
 400    :    // Create the sections in the underlying block-graph.
 401    :    if (!CopySectionInfoToBlockGraph(*pe_image_,
 402    :                                     image_->graph(),
 403  E :                                     &section_index_)) {
 404  i :      return false;
 405    :    }
 406    :  
 407  E :    return true;
 408  E :  }
 409    :  
 410    :  bool HotPatchingDecomposer::ParseCaseTableRead(BlockGraph::Block* block,
 411    :                                                 BlockGraph::Offset offset,
 412    :                                                 const _DInst &inst,
 413    :                                                 size_t code_size,
 414  E :                                                 bool* parsed) {
 415  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 416  E :    DCHECK_NE(static_cast<bool*>(nullptr), parsed);
 417    :  
 418    :    // Check if the instruction is a case table read.
 419    :    *parsed = inst.opcode == I_MOVZX &&
 420    :              inst.ops[0].type == O_REG &&
 421    :              inst.ops[1].type == O_SMEM &&
 422    :              inst.dispSize == 32U &&
 423    :              inst.ops[2].type == O_NONE &&
 424  E :              DisplacementPointsIntoBlockAfterOffset(inst.disp, block, code_size);
 425    :  
 426    :    // Return early if not.
 427  E :    if (!*parsed)
 428  E :      return true;
 429    :  
 430  E :    int reference_size = inst.dispSize / 8;
 431    :  
 432    :    BlockGraph::Offset ref_source_offset =
 433  E :        offset + inst.size - reference_size;
 434    :    BlockGraph::Offset ref_target_offset =
 435  E :        reinterpret_cast<uint8*>(inst.disp) - block->data();
 436    :  
 437    :    // The displacement is at the end of this instruction.
 438    :    if (!block->SetReference(ref_source_offset,
 439    :                             BlockGraph::Reference(
 440    :                                 BlockGraph::ABSOLUTE_REF,
 441    :                                 reference_size,
 442    :                                 block,
 443    :                                 ref_target_offset,
 444  E :                                 ref_target_offset))) {
 445  i :      LOG(ERROR) << "Failed to create self reference in block "
 446    :                 << BlockInfo(block) << " from offset "
 447    :                 << ref_source_offset << " to offset " << ref_target_offset;
 448  i :      return false;
 449    :    }
 450    :  
 451    :    // Insert a case table label.
 452    :    AddDataLabel(block,
 453    :                 ref_target_offset,
 454    :                 "case-table",
 455  E :                 BlockGraph::CASE_TABLE_LABEL);
 456    :  
 457  E :    return true;
 458  E :  }
 459    :  
 460    :  bool HotPatchingDecomposer::ParseJumpTableCall(BlockGraph::Block* block,
 461    :                                                 BlockGraph::Offset offset,
 462    :                                                 const _DInst &inst,
 463    :                                                 size_t code_size,
 464  E :                                                 bool* parsed) {
 465  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 466  E :    DCHECK_NE(static_cast<bool*>(nullptr), parsed);
 467    :  
 468    :    // Check if the instruction is a jump using a jump table.
 469    :    *parsed = inst.opcode == I_JMP &&
 470    :              inst.ops[0].type == O_MEM &&
 471    :              inst.ops[1].type == O_NONE &&
 472    :              inst.scale == 4U &&
 473    :              inst.dispSize == 32U &&
 474    :              DisplacementPointsIntoBlockAfterOffset(inst.disp, block,
 475  E :                                                     code_size);
 476    :  
 477    :    // Return early if not.
 478  E :    if (!*parsed)
 479  E :      return true;
 480    :  
 481  E :    int reference_size = inst.dispSize / 8;
 482    :  
 483    :    BlockGraph::Offset ref_source_offset =
 484  E :        offset + inst.size - reference_size;
 485    :    BlockGraph::Offset ref_target_offset =
 486  E :        reinterpret_cast<uint8*>(inst.disp) - block->data();
 487    :  
 488    :    // The displacement is always at the end of a one-operand instruction.
 489    :    if (!block->SetReference(ref_source_offset,
 490    :                             BlockGraph::Reference(
 491    :                                 BlockGraph::ABSOLUTE_REF,
 492    :                                 reference_size,
 493    :                                 block,
 494    :                                 ref_target_offset,
 495  E :                                 ref_target_offset))) {
 496  i :      LOG(ERROR) << "Failed to create self reference in block "
 497    :                 << BlockInfo(block) << " from offset "
 498    :                 << ref_source_offset << " to offset " << ref_target_offset;
 499  i :      return false;
 500    :    }
 501    :  
 502    :    // Insert a jump table label.
 503    :    AddDataLabel(block,
 504    :                 ref_target_offset,
 505    :                 "jump-table",
 506  E :                 BlockGraph::JUMP_TABLE_LABEL);
 507    :  
 508  E :    return true;
 509  E :  }
 510    :  
 511    :  bool HotPatchingDecomposer::ParsePCRelativeBranchAndCallInstuction(
 512    :      BlockGraph::Block* block,
 513    :      BlockGraph::Offset offset,
 514    :      const _DInst &inst,
 515  E :      bool* parsed) {
 516  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 517  E :    DCHECK_NE(static_cast<bool*>(nullptr), parsed);
 518    :  
 519    :    *parsed = (core::IsBranch(inst) || core::IsCall(inst)) &&
 520  E :              inst.ops[0].type == O_PC;
 521  E :    if (!*parsed)
 522  E :      return true;
 523    :  
 524  E :    CHECK(inst.ops[1].type == O_NONE);
 525    :  
 526  E :    int reference_size = inst.ops[0].size / 8;
 527    :  
 528  E :    if (reference_size == 4) {
 529    :      // Insert a reference for 32-bit PC-relative jump and call instructions.
 530    :  
 531    :      // Create the reference.
 532  E :      BlockGraph::Offset pc_relative_address = inst.imm.addr;
 533    :      RelativeAddress target_relative_address = RelativeAddress(
 534  E :          block->addr().value() + offset + pc_relative_address + inst.size);
 535    :      Block* referenced_block = image_layout_->blocks.GetBlockByAddress(
 536  E :          target_relative_address);
 537    :  
 538  E :      BlockGraph::Offset ref_target_offset = 0;
 539    :  
 540  E :      if (referenced_block != nullptr) {
 541    :        ref_target_offset =
 542  E :            target_relative_address - referenced_block->addr();
 543    :  
 544  E :        if (referenced_block != block) {
 545    :          // If the following check fails that means that we have an
 546    :          // inter-block reference pointing inside a hot patchable block.
 547  E :          CHECK_EQ(target_relative_address, referenced_block->addr());
 548    :        }
 549  E :      } else {
 550    :        // There is no block at the referred location. This means that the
 551    :        // referred block is not hot patchable. Create a dummy code block that
 552    :        // can be referenced.
 553    :        referenced_block = CreateBlock(BlockGraph::CODE_BLOCK,
 554    :                                       target_relative_address,
 555    :                                       1,
 556  E :                                       "TargetBlock");
 557  E :        DCHECK_NE(static_cast<Block*>(nullptr), referenced_block);
 558    :        // We set the BUILT_BY_UNSUPPORTED_COMPILER attribute on dummy blocks.
 559    :        // This attribute expresses that the block can't be moved and the data
 560    :        // of the block should not be interpreted.
 561    :        referenced_block->set_attribute(
 562  E :            BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
 563    :  
 564  E :        ref_target_offset = 0;
 565    :      }
 566    :  
 567  E :      DCHECK_GE(inst.size, 1 + reference_size);
 568  E :      DCHECK_GE(2 + reference_size, inst.size);
 569    :  
 570    :      // The reference is always at the end of the instruction.
 571    :      if (!block->SetReference(offset + inst.size - reference_size,
 572    :                                BlockGraph::Reference(
 573    :                                    BlockGraph::PC_RELATIVE_REF,
 574    :                                    reference_size,
 575    :                                    referenced_block,
 576    :                                    ref_target_offset,
 577  E :                                    ref_target_offset))) {
 578  i :        return false;
 579    :      }
 580  E :      ++parsed;
 581    :    } else {
 582    :      // We don't deal with smaller references. These are in-block references
 583    :      // that are resolved by the basic block decomposer.
 584    :    }
 585    :  
 586  E :    return true;
 587  E :  }
 588    :  
 589    :  Block *HotPatchingDecomposer::ProcessHotPatchableCodeBlock(
 590  E :      const block_graph::HotPatchingBlockMetadata& block_metadata) {
 591    :  
 592    :    // The relative address will point to the correct field as it should be
 593    :    // relocated.
 594  E :    RelativeAddress data_address(block_metadata.relative_address);
 595  E :    size_t block_size = block_metadata.block_size;
 596    :  
 597    :    // Generate a unique name for the block.
 598  E :    ++last_code_block_id_;
 599  E :    std::string block_name = "CodeBlock" + std::to_string(last_code_block_id_);
 600    :  
 601    :    // Add the block to the block graph.
 602    :    Block* block = CreateBlock(BlockGraph::CODE_BLOCK,
 603    :                               data_address,
 604    :                               block_size,
 605  E :                               block_name);
 606  E :    if (block == nullptr) {
 607  i :      LOG(ERROR) << "Unable to add code block at "
 608    :                 << data_address << " with size " << block_size << ".";
 609  i :      return nullptr;
 610    :    }
 611    :  
 612    :    // Add a code label to the beginning of the block.
 613  E :    block->SetLabel(0, "CODE", BlockGraph::CODE_LABEL);
 614    :  
 615    :    // If the code does not fill the whole data, put a data label at the end of
 616    :    // the code.
 617  E :    if (block_metadata.code_size != block_metadata.block_size) {
 618    :      block->SetLabel(static_cast<int>(block_metadata.code_size),
 619  E :                      "DATA", BlockGraph::DATA_LABEL);
 620    :    }
 621    :  
 622  E :    return block;
 623  E :  }
 624    :  
 625    :  }  // namespace pe

Coverage information generated Thu Jan 14 17:40:38 2016.