Home | History | Annotate | Download | only in LD
      1 //===- EhFrameHdr.cpp -----------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include <mcld/LD/EhFrameHdr.h>
     10 
     11 #include <mcld/LD/EhFrame.h>
     12 #include <mcld/LD/LDSection.h>
     13 
     14 #include <llvm/Support/Dwarf.h>
     15 #include <llvm/Support/DataTypes.h>
     16 
     17 #include <algorithm>
     18 #include <cstring>
     19 
     20 using namespace mcld;
     21 using namespace llvm::dwarf;
     22 
     23 //===----------------------------------------------------------------------===//
     24 // Helper Function
     25 //===----------------------------------------------------------------------===//
     26 namespace bit32 {
     27 
     28 typedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry;
     29 
     30 bool EntryCompare(const Entry& pX, const Entry& pY)
     31 { return (pX.first < pY.first); }
     32 
     33 } // bit32 namespace
     34 
     35 //===----------------------------------------------------------------------===//
     36 // Template Specification Functions
     37 //===----------------------------------------------------------------------===//
     38 /// emitOutput<32> - write out eh_frame_hdr
     39 template<>
     40 void EhFrameHdr::emitOutput<32>(FileOutputBuffer& pOutput)
     41 {
     42   MemoryRegion ehframehdr_region = pOutput.request(m_EhFrameHdr.offset(),
     43                                                    m_EhFrameHdr.size());
     44 
     45   MemoryRegion ehframe_region = pOutput.request(m_EhFrame.offset(),
     46                                                 m_EhFrame.size());
     47 
     48   uint8_t* data = ehframehdr_region.begin();
     49   // version
     50   data[0] = 1;
     51   // eh_frame_ptr_enc
     52   data[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
     53 
     54   // eh_frame_ptr
     55   uint32_t* eh_frame_ptr = (uint32_t*)(data + 4);
     56   *eh_frame_ptr = m_EhFrame.addr() - (m_EhFrameHdr.addr() + 4);
     57 
     58   // fde_count
     59   uint32_t* fde_count = (uint32_t*)(data + 8);
     60   if (m_EhFrame.hasEhFrame())
     61     *fde_count = m_EhFrame.getEhFrame()->numOfFDEs();
     62   else
     63     *fde_count = 0;
     64 
     65   if (0 == *fde_count) {
     66     // fde_count_enc
     67     data[2] = DW_EH_PE_omit;
     68     // table_enc
     69     data[3] = DW_EH_PE_omit;
     70   }
     71   else {
     72     // fde_count_enc
     73     data[2] = DW_EH_PE_udata4;
     74     // table_enc
     75     data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
     76 
     77     // prepare the binary search table
     78     typedef std::vector<bit32::Entry> SearchTableType;
     79     SearchTableType search_table;
     80 
     81     for (EhFrame::const_cie_iterator i = m_EhFrame.getEhFrame()->cie_begin(),
     82          e = m_EhFrame.getEhFrame()->cie_end(); i != e; ++i) {
     83       EhFrame::CIE& cie = **i;
     84       for (EhFrame::const_fde_iterator fi = cie.begin(), fe = cie.end();
     85            fi != fe; ++fi) {
     86         EhFrame::FDE& fde = **fi;
     87         SizeTraits<32>::Offset offset;
     88         SizeTraits<32>::Address fde_pc;
     89         SizeTraits<32>::Address fde_addr;
     90         offset = fde.getOffset();
     91         fde_pc = computePCBegin(fde, ehframe_region);
     92         fde_addr = m_EhFrame.addr() + offset;
     93         search_table.push_back(std::make_pair(fde_pc, fde_addr));
     94       }
     95     }
     96 
     97     std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
     98 
     99     // write out the binary search table
    100     uint32_t* bst = (uint32_t*)(data + 12);
    101     SearchTableType::const_iterator entry, entry_end = search_table.end();
    102     size_t id = 0;
    103     for (entry = search_table.begin(); entry != entry_end; ++entry) {
    104       bst[id++] = (*entry).first - m_EhFrameHdr.addr();
    105       bst[id++] = (*entry).second - m_EhFrameHdr.addr();
    106     }
    107   }
    108 }
    109 
    110 //===----------------------------------------------------------------------===//
    111 // EhFrameHdr
    112 //===----------------------------------------------------------------------===//
    113 
    114 EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame)
    115   : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) {
    116 }
    117 
    118 EhFrameHdr::~EhFrameHdr()
    119 {
    120 }
    121 
    122 /// @ref lsb core generic 4.1
    123 /// .eh_frame_hdr section format
    124 /// uint8_t : version
    125 /// uint8_t : eh_frame_ptr_enc
    126 /// uint8_t : fde_count_enc
    127 /// uint8_t : table_enc
    128 /// uint32_t : eh_frame_ptr
    129 /// uint32_t : fde_count
    130 /// __________________________ when fde_count > 0
    131 /// <uint32_t, uint32_t>+ : binary search table
    132 /// sizeOutput - base on the fde count to size output
    133 void EhFrameHdr::sizeOutput()
    134 {
    135   size_t size = 12;
    136   if (m_EhFrame.hasEhFrame())
    137     size += 8 * m_EhFrame.getEhFrame()->numOfFDEs();
    138   m_EhFrameHdr.setSize(size);
    139 }
    140 
    141 /// computePCBegin - return the address of FDE's pc
    142 /// @ref binutils gold: ehframe.cc:222
    143 uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE,
    144                                     const MemoryRegion& pEhFrameRegion)
    145 {
    146   uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
    147   unsigned int eh_value = fde_encoding & 0x7;
    148 
    149   // check the size to read in
    150   if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
    151     eh_value = DW_EH_PE_udata4;
    152   }
    153 
    154   size_t pc_size = 0x0;
    155   switch (eh_value) {
    156     case DW_EH_PE_udata2:
    157       pc_size = 2;
    158       break;
    159     case DW_EH_PE_udata4:
    160       pc_size = 4;
    161       break;
    162     case DW_EH_PE_udata8:
    163       pc_size = 8;
    164       break;
    165     default:
    166       // TODO
    167       break;
    168   }
    169 
    170   SizeTraits<32>::Address pc = 0x0;
    171   const uint8_t* offset = (const uint8_t*) pEhFrameRegion.begin() +
    172                           pFDE.getOffset() +
    173                           EhFrame::getDataStartOffset<32>();
    174   std::memcpy(&pc, offset, pc_size);
    175 
    176   // adjust the signed value
    177   bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
    178   if (DW_EH_PE_udata2 == eh_value && is_signed)
    179     pc = (pc ^ 0x8000) - 0x8000;
    180 
    181   // handle eh application
    182   switch (fde_encoding & 0x70)
    183   {
    184     case DW_EH_PE_absptr:
    185       break;
    186     case DW_EH_PE_pcrel:
    187       pc += m_EhFrame.addr() + pFDE.getOffset() +
    188                                EhFrame::getDataStartOffset<32>();
    189       break;
    190     case DW_EH_PE_datarel:
    191       // TODO
    192       break;
    193     default:
    194       // TODO
    195       break;
    196   }
    197   return pc;
    198 }
    199