blob: bc5ed1d7f6103f2fe4f0f0301ade227583358f12 [file] [log] [blame]
Zonr Changaffc1502012-07-16 14:28:23 +08001//===- 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//===----------------------------------------------------------------------===//
Shih-wei Liaocedee4b2012-08-02 23:13:03 -07009
Zonr Changaffc1502012-07-16 14:28:23 +080010#include <mcld/LD/EhFrame.h>
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070011
Zonr Changaffc1502012-07-16 14:28:23 +080012#include <llvm/Support/Dwarf.h>
13#include <llvm/Support/Host.h>
14
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070015#include <mcld/MC/MCLinker.h>
16#include <mcld/Target/TargetLDBackend.h>
17#include <mcld/Support/MsgHandling.h>
18
Zonr Changaffc1502012-07-16 14:28:23 +080019using namespace mcld;
20
21//==========================
22// EhFrame
23EhFrame::EhFrame()
24 : m_fCanRecognizeAll(true) {
25}
26
27EhFrame::~EhFrame()
28{
29}
30
31uint64_t EhFrame::readEhFrame(Layout& pLayout,
32 const TargetLDBackend& pBackend,
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070033 SectionData& pSD,
Shih-wei Liao67e37f12012-07-27 03:50:34 -070034 const Input& pInput,
Zonr Changaffc1502012-07-16 14:28:23 +080035 LDSection& pSection,
36 MemoryArea& pArea)
37{
Shih-wei Liao67e37f12012-07-27 03:50:34 -070038 MemoryRegion* region = pArea.request(
39 pInput.fileOffset() + pSection.offset(), pSection.size());
Zonr Changaffc1502012-07-16 14:28:23 +080040 // an empty .eh_frame
41 if (NULL == region) {
Zonr Changaffc1502012-07-16 14:28:23 +080042 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) {
Zonr Changaffc1502012-07-16 14:28:23 +080055 pArea.release(region);
56 return 0;
57 }
58
59 if (0xffffffff == len) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070060 debug(diag::debug_eh_unsupport) << pInput.name();
Zonr Changaffc1502012-07-16 14:28:23 +080061 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) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070072 debug(diag::debug_eh_unsupport) << pInput.name();
Zonr Changaffc1502012-07-16 14:28:23 +080073 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) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070083 debug(diag::debug_eh_unsupport) << pInput.name();
Zonr Changaffc1502012-07-16 14:28:23 +080084 m_fCanRecognizeAll = false;
85 }
86 break;
87 }
88 if (0xffffffff == len) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070089 debug(diag::debug_eh_unsupport) << pInput.name();
Zonr Changaffc1502012-07-16 14:28:23 +080090 m_fCanRecognizeAll = false;
91 break;
92 }
93
94 if (eh_end - p < 4) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -070095 debug(diag::debug_eh_unsupport) << pInput.name();
Zonr Changaffc1502012-07-16 14:28:23 +080096 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
Shih-wei Liao67e37f12012-07-27 03:50:34 -0700104 MemoryRegion* ent_region = pArea.request(
105 pInput.fileOffset() + pSection.offset() + ent_offset, len + 4);
Zonr Changaffc1502012-07-16 14:28:23 +0800106
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) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -0700130 debug(diag::debug_eh_unsupport) << pInput.name();
Zonr Changaffc1502012-07-16 14:28:23 +0800131 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
147bool 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) {
Zonr Changaffc1502012-07-16 14:28:23 +0800160 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)) {
Zonr Changaffc1502012-07-16 14:28:23 +0800174 return false;
175 }
176 // skip the Data Alignment Factor
177 if (!skipLEB128(&p, cie_end)) {
Zonr Changaffc1502012-07-16 14:28:23 +0800178 return false;
179 }
180 // skip the Return Address Register
181 if (cie_end - p < 1) {
Zonr Changaffc1502012-07-16 14:28:23 +0800182 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') {
Zonr Changaffc1502012-07-16 14:28:23 +0800189 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)) {
Zonr Changaffc1502012-07-16 14:28:23 +0800202 return false;
203 }
204
205 while (aug_str != aug_str_end) {
206 switch (*aug_str) {
207 default:
Zonr Changaffc1502012-07-16 14:28:23 +0800208 return false;
209
210 // LDSA encoding (1 byte)
211 case 'L':
212 if (cie_end - p < 1) {
Zonr Changaffc1502012-07-16 14:28:23 +0800213 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) {
Zonr Changaffc1502012-07-16 14:28:23 +0800224 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)) {
Zonr Changaffc1502012-07-16 14:28:23 +0800231 return false;
232 }
233 switch (per_encode & 7) {
234 default:
Zonr Changaffc1502012-07-16 14:28:23 +0800235 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) {
Zonr Changaffc1502012-07-16 14:28:23 +0800255 return false;
256 }
257 p += per_align;
258 }
259 // skip the second argument
260 if (static_cast<uint32_t>(cie_end - p) < per_length) {
Zonr Changaffc1502012-07-16 14:28:23 +0800261 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) {
Zonr Changaffc1502012-07-16 14:28:23 +0800270 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:
Zonr Changaffc1502012-07-16 14:28:23 +0800280 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);
Shih-wei Liaocedee4b2012-08-02 23:13:03 -0700297 pFragList.push_back(static_cast<Fragment*>(entry));
Zonr Changaffc1502012-07-16 14:28:23 +0800298 return true;
299}
300
301bool 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) {
Zonr Changaffc1502012-07-16 14:28:23 +0800314 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);
Shih-wei Liaocedee4b2012-08-02 23:13:03 -0700322 pFragList.push_back(static_cast<Fragment*>(entry));
Zonr Changaffc1502012-07-16 14:28:23 +0800323 return true;
324}
325
326uint32_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
337bool 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
348void EhFrame::deleteFragments(FragListType& pList, MemoryArea& pArea)
349{
Shih-wei Liaocedee4b2012-08-02 23:13:03 -0700350 RegionFragment* frag = NULL;
Zonr Changaffc1502012-07-16 14:28:23 +0800351 for (FragListType::iterator it = pList.begin(); it != pList.end(); ++it) {
Shih-wei Liaocedee4b2012-08-02 23:13:03 -0700352 frag = static_cast<RegionFragment*>(*it);
Zonr Changaffc1502012-07-16 14:28:23 +0800353 pArea.release(&(frag->getRegion()));
354 delete *it;
355 }
356 pList.clear();
357}
358