/// computePCBegin - return the address of FDE's pc
/// @ref binutils gold: ehframe.cc:222
uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE,
                                    const MemoryRegion& pEhFrameRegion)
{
    uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
    unsigned int eh_value = fde_encoding & 0x7;

    // check the size to read in
    if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
        eh_value = DW_EH_PE_udata4;
    }

    size_t pc_size = 0x0;
    switch (eh_value) {
    case DW_EH_PE_udata2:
        pc_size = 2;
        break;
    case DW_EH_PE_udata4:
        pc_size = 4;
        break;
    case DW_EH_PE_udata8:
        pc_size = 8;
        break;
    default:
        // TODO
        break;
    }

    SizeTraits<32>::Address pc = 0x0;
    const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() +
                            pFDE.getOffset() +
                            pFDE.getDataStart();
    std::memcpy(&pc, offset, pc_size);

    // adjust the signed value
    bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
    if (DW_EH_PE_udata2 == eh_value && is_signed)
        pc = (pc ^ 0x8000) - 0x8000;

    // handle eh application
    switch (fde_encoding & 0x70)
    {
    case DW_EH_PE_absptr:
        break;
    case DW_EH_PE_pcrel:
        pc += m_EhFrame.addr() + pFDE.getOffset() + pFDE.getDataStart();
        break;
    case DW_EH_PE_datarel:
        // TODO
        break;
    default:
        // TODO
        break;
    }
    return pc;
}
void X86GNULDBackend::addEhFrameForPLT(Module& pModule)
{
  LDSection* plt_sect = pModule.getSection(".plt");
  if (!plt_sect || plt_sect->size() == 0u)
    return;

  LDSection* eh_sect = pModule.getSection(".eh_frame");
  if (!eh_sect || !eh_sect->hasEhFrame())
    return;

  EhFrame* eh_frame = eh_sect->getEhFrame();
  SectionData::FragmentListType& frag_list =
      eh_frame->getSectionData()->getFragmentList();
  llvm::StringRef cie_region = createCIERegionForPLT();
  llvm::StringRef fde_region = createFDERegionForPLT();
  EhFrame::CIE* cie = new EhFrame::GeneratedCIE(cie_region);
  EhFrame::FDE* fde = new EhFrame::GeneratedFDE(fde_region, *cie);
  // Augmentation data only contains FDE encoding.
  uint8_t aug_data = (uint8_t)(llvm::dwarf::DW_EH_PE_pcrel |
                               llvm::dwarf::DW_EH_PE_sdata4);
  cie->setFDEEncode(aug_data);
  cie->setAugmentationData(std::string(1, aug_data));

  EhFrame::cie_iterator i = eh_frame->cie_begin();
  for (EhFrame::cie_iterator e = eh_frame->cie_end(); i != e; ++i) {
    EhFrame::CIE& exist_cie = **i;
    if (exist_cie == *cie) {
      // Insert the FDE fragment
      SectionData::iterator cur_iter(exist_cie);
      frag_list.insertAfter(cur_iter, fde);
      fde->setCIE(exist_cie);

      // Cleanup the CIE we created
      cie->clearFDEs();
      delete cie;
      break;
    }
  }
  if (i == eh_frame->cie_end()) {
    // Newly insert
    eh_frame->addCIE(*cie);
    eh_frame->addFDE(*fde);
  }
}
Beispiel #3
0
void EhFrame::addFDE(EhFrame::FDE& pFDE, bool pAlsoAddFragment)
{
  pFDE.getCIE().add(pFDE);
  if (pAlsoAddFragment)
    addFragment(pFDE);
}