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