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 
EntryCompare(const Entry & pX,const Entry & pY)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<>
emitOutput(FileOutputBuffer & pOutput)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 
EhFrameHdr(LDSection & pEhFrameHdr,const LDSection & pEhFrame)114 EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame)
115   : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) {
116 }
117 
~EhFrameHdr()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
sizeOutput()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
computePCBegin(const EhFrame::FDE & pFDE,const MemoryRegion & pEhFrameRegion)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