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 namespace mcld {
     21 
     22 //===----------------------------------------------------------------------===//
     23 // Helper Function
     24 //===----------------------------------------------------------------------===//
     25 namespace bit32 {
     26 
     27 typedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry;
     28 
     29 bool EntryCompare(const Entry& pX, const Entry& pY) {
     30   return (pX.first < pY.first);
     31 }
     32 
     33 }  // namespace bit32
     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   MemoryRegion ehframehdr_region =
     42       pOutput.request(m_EhFrameHdr.offset(), m_EhFrameHdr.size());
     43 
     44   MemoryRegion ehframe_region =
     45       pOutput.request(m_EhFrame.offset(), m_EhFrame.size());
     46 
     47   uint8_t* data = ehframehdr_region.begin();
     48   // version
     49   data[0] = 1;
     50   // eh_frame_ptr_enc
     51   data[1] = llvm::dwarf::DW_EH_PE_pcrel | llvm::dwarf::DW_EH_PE_sdata4;
     52 
     53   // eh_frame_ptr
     54   uint32_t* eh_frame_ptr = reinterpret_cast<uint32_t*>(data + 4);
     55   *eh_frame_ptr = m_EhFrame.addr() - (m_EhFrameHdr.addr() + 4);
     56 
     57   // fde_count
     58   uint32_t* fde_count = reinterpret_cast<uint32_t*>(data + 8);
     59   if (m_EhFrame.hasEhFrame())
     60     *fde_count = m_EhFrame.getEhFrame()->numOfFDEs();
     61   else
     62     *fde_count = 0;
     63 
     64   if (*fde_count == 0) {
     65     // fde_count_enc
     66     data[2] = llvm::dwarf::DW_EH_PE_omit;
     67     // table_enc
     68     data[3] = llvm::dwarf::DW_EH_PE_omit;
     69   } else {
     70     // fde_count_enc
     71     data[2] = llvm::dwarf::DW_EH_PE_udata4;
     72     // table_enc
     73     data[3] = llvm::dwarf::DW_EH_PE_datarel | llvm::dwarf::DW_EH_PE_sdata4;
     74 
     75     // prepare the binary search table
     76     typedef std::vector<bit32::Entry> SearchTableType;
     77     SearchTableType search_table;
     78 
     79     for (EhFrame::const_cie_iterator i = m_EhFrame.getEhFrame()->cie_begin(),
     80                                      e = m_EhFrame.getEhFrame()->cie_end();
     81          i != e;
     82          ++i) {
     83       EhFrame::CIE& cie = **i;
     84       for (EhFrame::const_fde_iterator fi = cie.begin(), fe = cie.end();
     85            fi != fe;
     86            ++fi) {
     87         EhFrame::FDE& fde = **fi;
     88         SizeTraits<32>::Offset offset;
     89         SizeTraits<32>::Address fde_pc;
     90         SizeTraits<32>::Address fde_addr;
     91         offset = fde.getOffset();
     92         fde_pc = computePCBegin(fde, ehframe_region);
     93         fde_addr = m_EhFrame.addr() + offset;
     94         search_table.push_back(std::make_pair(fde_pc, fde_addr));
     95       }
     96     }
     97 
     98     std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
     99 
    100     // write out the binary search table
    101     uint32_t* bst = reinterpret_cast<uint32_t*>(data + 12);
    102     SearchTableType::const_iterator entry, entry_end = search_table.end();
    103     size_t id = 0;
    104     for (entry = search_table.begin(); entry != entry_end; ++entry) {
    105       bst[id++] = (*entry).first - m_EhFrameHdr.addr();
    106       bst[id++] = (*entry).second - m_EhFrameHdr.addr();
    107     }
    108   }
    109 }
    110 
    111 //===----------------------------------------------------------------------===//
    112 // EhFrameHdr
    113 //===----------------------------------------------------------------------===//
    114 
    115 EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame)
    116     : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) {
    117 }
    118 
    119 EhFrameHdr::~EhFrameHdr() {
    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   size_t size = 12;
    135   if (m_EhFrame.hasEhFrame())
    136     size += 8 * m_EhFrame.getEhFrame()->numOfFDEs();
    137   m_EhFrameHdr.setSize(size);
    138 }
    139 
    140 /// computePCBegin - return the address of FDE's pc
    141 uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE,
    142                                     const MemoryRegion& pEhFrameRegion) {
    143   uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
    144   unsigned int eh_value = fde_encoding & 0x7;
    145 
    146   // check the size to read in
    147   if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
    148     eh_value = llvm::dwarf::DW_EH_PE_udata4;
    149   }
    150 
    151   size_t pc_size = 0x0;
    152   switch (eh_value) {
    153     case llvm::dwarf::DW_EH_PE_udata2:
    154       pc_size = 2;
    155       break;
    156     case llvm::dwarf::DW_EH_PE_udata4:
    157       pc_size = 4;
    158       break;
    159     case llvm::dwarf::DW_EH_PE_udata8:
    160       pc_size = 8;
    161       break;
    162     default:
    163       // TODO
    164       break;
    165   }
    166 
    167   SizeTraits<32>::Address pc = 0x0;
    168   const uint8_t* offset = (const uint8_t*)pEhFrameRegion.begin() +
    169                           pFDE.getOffset() + EhFrame::getDataStartOffset<32>();
    170   std::memcpy(&pc, offset, pc_size);
    171 
    172   // adjust the signed value
    173   bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
    174   if (llvm::dwarf::DW_EH_PE_udata2 == eh_value && is_signed)
    175     pc = (pc ^ 0x8000) - 0x8000;
    176 
    177   // handle eh application
    178   switch (fde_encoding & 0x70) {
    179     case llvm::dwarf::DW_EH_PE_absptr:
    180       break;
    181     case llvm::dwarf::DW_EH_PE_pcrel:
    182       pc += m_EhFrame.addr() + pFDE.getOffset() +
    183             EhFrame::getDataStartOffset<32>();
    184       break;
    185     case llvm::dwarf::DW_EH_PE_datarel:
    186       // TODO
    187       break;
    188     default:
    189       // TODO
    190       break;
    191   }
    192   return pc;
    193 }
    194 
    195 }  // namespace mcld
    196