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