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 = m_EhFrame.getEhFrame()->numOfFDEs();
     65   else
     66     *fde_count = 0;
     67 
     68   if (0 == *fde_count) {
     69     // fde_count_enc
     70     data[2] = DW_EH_PE_omit;
     71     // table_enc
     72     data[3] = DW_EH_PE_omit;
     73   }
     74   else {
     75     // fde_count_enc
     76     data[2] = DW_EH_PE_udata4;
     77     // table_enc
     78     data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
     79 
     80     // prepare the binary search table
     81     typedef std::vector<bit32::Entry> SearchTableType;
     82     SearchTableType search_table;
     83     EhFrame::const_fde_iterator fde, fde_end = m_EhFrame.getEhFrame()->fde_end();
     84     for(fde = m_EhFrame.getEhFrame()->fde_begin(); fde != fde_end; ++fde) {
     85       assert(*fde != NULL);
     86       SizeTraits<32>::Offset offset;
     87       SizeTraits<32>::Address fde_pc;
     88       SizeTraits<32>::Address fde_addr;
     89       offset = (*fde)->getOffset();
     90       fde_pc = computePCBegin(**fde, *ehframe_region);
     91       fde_addr = m_EhFrame.addr() + offset;
     92       search_table.push_back(std::make_pair(fde_pc, fde_addr));
     93     }
     94 
     95     std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
     96 
     97     // write out the binary search table
     98     uint32_t* bst = (uint32_t*)(data + 12);
     99     SearchTableType::const_iterator entry, entry_end = search_table.end();
    100     size_t id = 0;
    101     for (entry = search_table.begin(); entry != entry_end; ++entry) {
    102       bst[id++] = (*entry).first - m_EhFrameHdr.addr();
    103       bst[id++] = (*entry).second - m_EhFrameHdr.addr();
    104     }
    105   }
    106   pOutput.release(ehframehdr_region);
    107   pOutput.release(ehframe_region);
    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.start() +
    172                           pFDE.getOffset() +
    173                           pFDE.getDataStart();
    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() + pFDE.getDataStart();
    188       break;
    189     case DW_EH_PE_datarel:
    190       // TODO
    191       break;
    192     default:
    193       // TODO
    194       break;
    195   }
    196   return pc;
    197 }
    198