1 //===- EhFrame.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
10 #include <mcld/LD/EhFrame.h>
11
12 #include <llvm/Support/Dwarf.h>
13 #include <llvm/Support/Host.h>
14
15 #include <mcld/MC/MCLinker.h>
16 #include <mcld/Target/TargetLDBackend.h>
17 #include <mcld/Support/MsgHandling.h>
18
19 using namespace mcld;
20
21 //==========================
22 // EhFrame
EhFrame()23 EhFrame::EhFrame()
24 : m_fCanRecognizeAll(true) {
25 }
26
~EhFrame()27 EhFrame::~EhFrame()
28 {
29 }
30
readEhFrame(Layout & pLayout,const TargetLDBackend & pBackend,SectionData & pSD,const Input & pInput,LDSection & pSection,MemoryArea & pArea)31 uint64_t EhFrame::readEhFrame(Layout& pLayout,
32 const TargetLDBackend& pBackend,
33 SectionData& pSD,
34 const Input& pInput,
35 LDSection& pSection,
36 MemoryArea& pArea)
37 {
38 MemoryRegion* region = pArea.request(
39 pInput.fileOffset() + pSection.offset(), pSection.size());
40 // an empty .eh_frame
41 if (NULL == region) {
42 return 0;
43 }
44
45 ConstAddress eh_start = region->start();
46 ConstAddress eh_end = region->end();
47 ConstAddress p = eh_start;
48
49 // read the Length filed
50 uint32_t len = readVal(p, pBackend.isLittleEndian());
51
52 // This CIE is a terminator if the Length field is 0, return 0 to handled it
53 // as an ordinary input.
54 if (0 == len) {
55 pArea.release(region);
56 return 0;
57 }
58
59 if (0xffffffff == len) {
60 debug(diag::debug_eh_unsupport) << pInput.name();
61 pArea.release(region);
62 m_fCanRecognizeAll = false;
63 return 0;
64 }
65
66 // record the order of the CIE and FDE fragments
67 FragListType frag_list;
68
69 while (p < eh_end) {
70
71 if (eh_end - p < 4) {
72 debug(diag::debug_eh_unsupport) << pInput.name();
73 m_fCanRecognizeAll = false;
74 break;
75 }
76 // read the Length field
77 len = readVal(p, pBackend.isLittleEndian());
78 p += 4;
79
80 // the zero length entry should be the end of the section
81 if (0 == len) {
82 if (p < eh_end) {
83 debug(diag::debug_eh_unsupport) << pInput.name();
84 m_fCanRecognizeAll = false;
85 }
86 break;
87 }
88 if (0xffffffff == len) {
89 debug(diag::debug_eh_unsupport) << pInput.name();
90 m_fCanRecognizeAll = false;
91 break;
92 }
93
94 if (eh_end - p < 4) {
95 debug(diag::debug_eh_unsupport) << pInput.name();
96 m_fCanRecognizeAll = false;
97 break;
98 }
99
100 // compute the section offset of this entry
101 uint32_t ent_offset = static_cast<uint32_t>(p - eh_start - 4);
102
103 // get the MemoryRegion for this entry
104 MemoryRegion* ent_region = pArea.request(
105 pInput.fileOffset() + pSection.offset() + ent_offset, len + 4);
106
107 // create and add a CIE or FDE entry
108 uint32_t id = readVal(p, pBackend.isLittleEndian());
109 // CIE
110 if (0 == id) {
111 if (!addCIE(*ent_region, pBackend, frag_list)) {
112 m_fCanRecognizeAll = false;
113 pArea.release(ent_region);
114 break;
115 }
116 }
117
118 // FDE
119 else {
120 if (!addFDE(*ent_region, pBackend, frag_list)) {
121 m_fCanRecognizeAll = false;
122 pArea.release(ent_region);
123 break;
124 }
125 }
126 p += len;
127 }
128
129 if (!m_fCanRecognizeAll) {
130 debug(diag::debug_eh_unsupport) << pInput.name();
131 pArea.release(region);
132 deleteFragments(frag_list, pArea);
133 return 0;
134 }
135
136 // append all CIE and FDE fragments to Layout after we successfully read
137 // this eh_frame
138 size_t section_size = 0;
139 for (FragListType::iterator it = frag_list.begin();
140 it != frag_list.end(); ++it)
141 section_size += pLayout.appendFragment(**it, pSD, pSection.align());
142
143 pArea.release(region);
144 return section_size;
145 }
146
addCIE(MemoryRegion & pRegion,const TargetLDBackend & pBackend,FragListType & pFragList)147 bool EhFrame::addCIE(MemoryRegion& pRegion,
148 const TargetLDBackend& pBackend,
149 FragListType& pFragList)
150 {
151 ConstAddress cie_start = pRegion.start();
152 ConstAddress cie_end = pRegion.end();
153 ConstAddress p = cie_start;
154
155 // skip the Length (4 byte) and CIE ID (4 byte) fields
156 p += 8;
157
158 // the version should be 1
159 if (1 != *p) {
160 return false;
161 }
162 ++p;
163
164 // get the Augumentation String
165 ConstAddress aug_str = p;
166 ConstAddress aug_str_end = static_cast<ConstAddress>(
167 memchr(p, '\0', cie_end - p));
168
169 // skip the Augumentation String field
170 p = aug_str_end + 1;
171
172 // skip the Code Alignment Factor
173 if (!skipLEB128(&p, cie_end)) {
174 return false;
175 }
176 // skip the Data Alignment Factor
177 if (!skipLEB128(&p, cie_end)) {
178 return false;
179 }
180 // skip the Return Address Register
181 if (cie_end - p < 1) {
182 return false;
183 }
184 ++p;
185
186 // the Augmentation String start with 'eh' is a CIE from gcc before 3.0,
187 // in LSB Core Spec 3.0RC1. We do not support it.
188 if (aug_str[0] == 'e' && aug_str[1] == 'h') {
189 return false;
190 }
191
192 // parse the Augmentation String to get the FDE encodeing if 'z' existed
193 std::string aug_str_data;
194 uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
195 if (*aug_str == 'z') {
196
197 aug_str_data += *aug_str;
198 ++aug_str;
199
200 // skip the Augumentation Data Length
201 if (!skipLEB128(&p, cie_end)) {
202 return false;
203 }
204
205 while (aug_str != aug_str_end) {
206 switch (*aug_str) {
207 default:
208 return false;
209
210 // LDSA encoding (1 byte)
211 case 'L':
212 if (cie_end - p < 1) {
213 return false;
214 }
215 ++p;
216 break;
217
218 // Two arguments, the first one represents the encoding of the second
219 // argument (1 byte). The second one is the address of personality
220 // routine.
221 case 'P': {
222 // the first argument
223 if (cie_end - p < 1) {
224 return false;
225 }
226 uint8_t per_encode = *p;
227 ++p;
228 // get the length of the second argument
229 uint32_t per_length = 0;
230 if (0x60 == (per_encode & 0x60)) {
231 return false;
232 }
233 switch (per_encode & 7) {
234 default:
235 return false;
236 case llvm::dwarf::DW_EH_PE_udata2:
237 per_length = 2;
238 break;
239 case llvm::dwarf::DW_EH_PE_udata4:
240 per_length = 4;
241 break;
242 case llvm::dwarf::DW_EH_PE_udata8:
243 per_length = 8;
244 break;
245 case llvm::dwarf::DW_EH_PE_absptr:
246 per_length = pBackend.bitclass() / 8;
247 break;
248 }
249 // skip the alignment
250 if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) {
251 uint32_t per_align = p - cie_end;
252 per_align += per_length - 1;
253 per_align &= ~(per_length -1);
254 if (static_cast<uint32_t>(cie_end - p) < per_align) {
255 return false;
256 }
257 p += per_align;
258 }
259 // skip the second argument
260 if (static_cast<uint32_t>(cie_end - p) < per_length) {
261 return false;
262 }
263 p += per_length;
264 }
265 break;
266
267 // FDE encoding (1 byte)
268 case 'R':
269 if (cie_end - p < 1) {
270 return false;
271 }
272 fde_encoding = *p;
273 switch (fde_encoding & 7) {
274 case llvm::dwarf::DW_EH_PE_udata2:
275 case llvm::dwarf::DW_EH_PE_udata4:
276 case llvm::dwarf::DW_EH_PE_udata8:
277 case llvm::dwarf::DW_EH_PE_absptr:
278 break;
279 default:
280 return false;
281 }
282 ++p;
283 break;
284 } // end switch
285 aug_str_data += *aug_str;
286 ++aug_str;
287 } // end while
288 }
289
290 note(diag::note_eh_cie) << pRegion.size()
291 << aug_str_data
292 << (fde_encoding & 7);
293
294 // create and push back the CIE entry
295 CIE* entry = new CIE(pRegion, fde_encoding);
296 m_CIEs.push_back(entry);
297 pFragList.push_back(static_cast<Fragment*>(entry));
298 return true;
299 }
300
addFDE(MemoryRegion & pRegion,const TargetLDBackend & pBackend,FragListType & pFragList)301 bool EhFrame::addFDE(MemoryRegion& pRegion,
302 const TargetLDBackend& pBackend,
303 FragListType& pFragList)
304 {
305 ConstAddress fde_start = pRegion.start();
306 ConstAddress fde_end = pRegion.end();
307 ConstAddress p = fde_start;
308
309 // skip the Length (4 byte) and CIE Pointer (4 byte) fields
310 p += 8;
311
312 // get the entry offset of the PC Begin
313 if (fde_end - p < 1) {
314 return false;
315 }
316 FDE::Offset pc_offset = static_cast<FDE::Offset>(p - fde_start);
317
318 note(diag::note_eh_fde) << pRegion.size() << pc_offset;
319 // create and push back the FDE entry
320 FDE* entry = new FDE(pRegion, **(m_CIEs.end() -1), pc_offset);
321 m_FDEs.push_back(entry);
322 pFragList.push_back(static_cast<Fragment*>(entry));
323 return true;
324 }
325
readVal(ConstAddress pAddr,bool pIsTargetLittleEndian)326 uint32_t EhFrame::readVal(ConstAddress pAddr, bool pIsTargetLittleEndian)
327 {
328 const uint32_t* p = reinterpret_cast<const uint32_t*>(pAddr);
329 uint32_t val = *p;
330
331 // byte swapping if the host and target have different endian
332 if (llvm::sys::isLittleEndianHost() != pIsTargetLittleEndian)
333 val = bswap32(val);
334 return val;
335 }
336
skipLEB128(ConstAddress * pp,ConstAddress pend)337 bool EhFrame::skipLEB128(ConstAddress* pp, ConstAddress pend)
338 {
339 for (ConstAddress p = *pp; p < pend; ++p) {
340 if (0 == (*p & 0x80)) {
341 *pp = p + 1;
342 return true;
343 }
344 }
345 return false;
346 }
347
deleteFragments(FragListType & pList,MemoryArea & pArea)348 void EhFrame::deleteFragments(FragListType& pList, MemoryArea& pArea)
349 {
350 RegionFragment* frag = NULL;
351 for (FragListType::iterator it = pList.begin(); it != pList.end(); ++it) {
352 frag = static_cast<RegionFragment*>(*it);
353 pArea.release(&(frag->getRegion()));
354 delete *it;
355 }
356 pList.clear();
357 }
358
359