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