• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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