• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- EhFrameReader.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/EhFrameReader.h>
10 
11 #include <llvm/ADT/StringRef.h>
12 #include <llvm/Support/Dwarf.h>
13 
14 #include <mcld/MC/MCLDInput.h>
15 #include <mcld/LD/EhFrame.h>
16 #include <mcld/LD/LDSection.h>
17 #include <mcld/Support/MemoryArea.h>
18 #include <mcld/Support/MsgHandling.h>
19 
20 using namespace mcld;
21 using namespace llvm::dwarf;
22 
23 //===----------------------------------------------------------------------===//
24 // Helper Functions
25 //===----------------------------------------------------------------------===//
26 /// skip_LEB128 - skip the first LEB128 encoded value from *pp, update *pp
27 /// to the next character.
28 /// @return - false if we ran off the end of the string.
29 /// @ref - GNU gold 1.11, ehframe.h, Eh_frame::skip_leb128.
30 static bool
skip_LEB128(EhFrameReader::ConstAddress * pp,EhFrameReader::ConstAddress pend)31 skip_LEB128(EhFrameReader::ConstAddress* pp, EhFrameReader::ConstAddress pend)
32 {
33   for (EhFrameReader::ConstAddress p = *pp; p < pend; ++p) {
34     if (0x0 == (*p & 0x80)) {
35       *pp = p + 1;
36       return true;
37     }
38   }
39   return false;
40 }
41 
42 //===----------------------------------------------------------------------===//
43 // EhFrameReader
44 //===----------------------------------------------------------------------===//
45 template<> EhFrameReader::Token
scan(ConstAddress pHandler,uint64_t pOffset,const MemoryRegion & pData) const46 EhFrameReader::scan<true>(ConstAddress pHandler,
47                           uint64_t pOffset,
48                           const MemoryRegion& pData) const
49 {
50   Token result;
51   result.file_off = pOffset;
52 
53   const uint32_t* data = (const uint32_t*)pHandler;
54   size_t cur_idx = 0;
55 
56   // Length Field
57   uint32_t length = data[cur_idx++];
58   if (0x0 == length) {
59     // terminator
60     result.kind = Terminator;
61     result.data_off = 4;
62     result.size = 4;
63     return result;
64   }
65 
66   // Extended Field
67   uint64_t extended = 0x0;
68   if (0xFFFFFFFF == length) {
69     extended = data[cur_idx++];
70     extended <<= 32;
71     extended |= data[cur_idx++];
72     result.size = extended + 12;
73     result.data_off = 16;
74   }
75   else {
76     result.size = length + 4;
77     result.data_off = 8;
78   }
79 
80   // ID Field
81   uint32_t ID = data[cur_idx++];
82   if (0x0 == ID)
83     result.kind = CIE;
84   else
85     result.kind = FDE;
86 
87   return result;
88 }
89 
90 template<>
read(Input & pInput,EhFrame & pEhFrame)91 bool EhFrameReader::read<32, true>(Input& pInput, EhFrame& pEhFrame)
92 {
93   // Alphabet:
94   //   {CIE, FDE, CIEt}
95   //
96   // Regular Expression:
97   //   (CIE FDE*)+ CIEt
98   //
99   // Autometa:
100   //   S = {Q0, Q1, Q2}, Start = Q0, Accept = Q2
101   //
102   //              FDE
103   //             +---+
104   //        CIE   \ /   CIEt
105   //   Q0 -------> Q1 -------> Q2
106   //    |         / \           ^
107   //    |        +---+          |
108   //    |         CIE           |
109   //    +-----------------------+
110   //              CIEt
111   const State autometa[NumOfStates][NumOfTokenKinds] = {
112   //     CIE     FDE    Term  Unknown
113     {     Q1, Reject, Accept, Reject }, // Q0
114     {     Q1,     Q1, Accept, Reject }, // Q1
115   };
116 
117   const Action transition[NumOfStates][NumOfTokenKinds] = {
118    /*    CIE     FDE     Term Unknown */
119     { addCIE, reject, addTerm, reject}, // Q0
120     { addCIE, addFDE, addTerm, reject}, // Q1
121   };
122 
123   // get file offset and address
124   LDSection& section = pEhFrame.getSection();
125   uint64_t file_off = pInput.fileOffset() + section.offset();
126   MemoryRegion* sect_reg =
127                        pInput.memArea()->request(file_off, section.size());
128   ConstAddress handler = (ConstAddress)sect_reg->start();
129 
130   State cur_state = Q0;
131   while (Reject != cur_state && Accept != cur_state) {
132 
133     Token token = scan<true>(handler, file_off, *sect_reg);
134     MemoryRegion* entry = pInput.memArea()->request(token.file_off, token.size);
135 
136     if (!transition[cur_state][token.kind](pEhFrame, *entry, token)) {
137       // fail to scan
138       debug(diag::debug_cannot_scan_eh) << pInput.name();
139       return false;
140     }
141 
142     file_off += token.size;
143     handler += token.size;
144 
145     if (handler == sect_reg->end())
146       cur_state = Accept;
147     else if (handler > sect_reg->end()) {
148       cur_state = Reject;
149     }
150     else
151       cur_state = autometa[cur_state][token.kind];
152   } // end of while
153 
154   if (Reject == cur_state) {
155     // fail to parse
156     debug(diag::debug_cannot_parse_eh) << pInput.name();
157     return false;
158   }
159   return true;
160 }
161 
addCIE(EhFrame & pEhFrame,MemoryRegion & pRegion,const EhFrameReader::Token & pToken)162 bool EhFrameReader::addCIE(EhFrame& pEhFrame,
163                            MemoryRegion& pRegion,
164                            const EhFrameReader::Token& pToken)
165 {
166   // skip Length, Extended Length and CIE ID.
167   ConstAddress handler = pRegion.start() + pToken.data_off;
168   ConstAddress cie_end = pRegion.end();
169 
170   // the version should be 1 or 3
171   uint8_t version = *handler++;
172   if (1 != version && 3 != version) {
173     return false;
174   }
175 
176   // Set up the Augumentation String
177   ConstAddress aug_str_front = handler;
178   ConstAddress aug_str_back  = static_cast<ConstAddress>(
179                          memchr(aug_str_front, '\0', cie_end - aug_str_front));
180   if (NULL == aug_str_back) {
181     return false;
182   }
183 
184   llvm::StringRef augment((const char*)aug_str_front);
185 
186   // skip the Augumentation String field
187   handler = aug_str_back + 1;
188 
189   // skip the Code Alignment Factor
190   if (!skip_LEB128(&handler, cie_end)) {
191     return false;
192   }
193   // skip the Data Alignment Factor
194   if (!skip_LEB128(&handler, cie_end)) {
195     return false;
196   }
197   // skip the Return Address Register
198   if (cie_end - handler < 1) {
199     return false;
200   }
201   ++handler;
202 
203   // the Augmentation String start with 'eh' is a CIE from gcc before 3.0,
204   // in LSB Core Spec 3.0RC1. We do not support it.
205   if (augment[0] == 'e' && augment[1] == 'h') {
206     return false;
207   }
208 
209   // parse the Augmentation String to get the FDE encodeing if 'z' existed
210   uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
211   if ('z' == augment[0]) {
212 
213     // skip the Augumentation Data Length
214     if (!skip_LEB128(&handler, cie_end)) {
215       return false;
216     }
217 
218     // parse the Augmentation String
219     for (size_t i = 1; i < augment.size(); ++i) {
220       switch (augment[i]) {
221         // LDSA encoding (1 byte)
222         case 'L': {
223           if (cie_end - handler < 1) {
224             return false;
225           }
226           ++handler;
227           break;
228         }
229         // Two arguments, the first one represents the encoding of the second
230         // argument (1 byte). The second one is the address of personality
231         // routine.
232         case 'P': {
233           // the first argument
234           if (cie_end - handler < 1) {
235             return false;
236           }
237           uint8_t per_encode = *handler;
238           ++handler;
239           // get the length of the second argument
240           uint32_t per_length = 0;
241           if (0x60 == (per_encode & 0x60)) {
242             return false;
243           }
244           switch (per_encode & 7) {
245             default:
246               return false;
247             case llvm::dwarf::DW_EH_PE_udata2:
248               per_length = 2;
249               break;
250             case llvm::dwarf::DW_EH_PE_udata4:
251               per_length = 4;
252               break;
253             case llvm::dwarf::DW_EH_PE_udata8:
254               per_length = 8;
255               break;
256             case llvm::dwarf::DW_EH_PE_absptr:
257               per_length = 4; // pPkg.bitclass / 8;
258               break;
259           }
260           // skip the alignment
261           if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) {
262             uint32_t per_align = handler - cie_end;
263             per_align += per_length - 1;
264             per_align &= ~(per_length -1);
265             if (static_cast<uint32_t>(cie_end - handler) < per_align) {
266               return false;
267             }
268             handler += per_align;
269           }
270           // skip the second argument
271           if (static_cast<uint32_t>(cie_end - handler) < per_length) {
272             return false;
273           }
274           handler += per_length;
275           break;
276         } // end of case 'P'
277 
278         // FDE encoding (1 byte)
279         case 'R': {
280           if (cie_end - handler < 1) {
281             return false;
282           }
283           fde_encoding = *handler;
284           switch (fde_encoding & 7) {
285             case llvm::dwarf::DW_EH_PE_udata2:
286             case llvm::dwarf::DW_EH_PE_udata4:
287             case llvm::dwarf::DW_EH_PE_udata8:
288             case llvm::dwarf::DW_EH_PE_absptr:
289               break;
290             default:
291               return false;
292           }
293           ++handler;
294           break;
295         }
296         default:
297           return false;
298       } // end switch
299     } // the rest chars.
300   } // first char is 'z'
301 
302   // create and push back the CIE entry
303   EhFrame::CIE* cie = new EhFrame::CIE(pRegion);
304   cie->setFDEEncode(fde_encoding);
305   pEhFrame.addCIE(*cie);
306   return true;
307 }
308 
addFDE(EhFrame & pEhFrame,MemoryRegion & pRegion,const EhFrameReader::Token & pToken)309 bool EhFrameReader::addFDE(EhFrame& pEhFrame,
310                            MemoryRegion& pRegion,
311                            const EhFrameReader::Token& pToken)
312 {
313   if (pToken.data_off == pRegion.size())
314     return false;
315 
316   // create and push back the FDE entry
317   EhFrame::FDE* fde = new EhFrame::FDE(pRegion,
318                                        pEhFrame.cie_back(),
319                                        pToken.data_off);
320   pEhFrame.addFDE(*fde);
321   return true;
322 }
323 
addTerm(EhFrame & pEhFrame,MemoryRegion & pRegion,const EhFrameReader::Token & pToken)324 bool EhFrameReader::addTerm(EhFrame& pEhFrame,
325                             MemoryRegion& pRegion,
326                             const EhFrameReader::Token& pToken)
327 {
328   RegionFragment* frag = new RegionFragment(pRegion);
329   pEhFrame.addFragment(*frag);
330   return true;
331 }
332 
reject(EhFrame & pEhFrame,MemoryRegion & pRegion,const EhFrameReader::Token & pToken)333 bool EhFrameReader::reject(EhFrame& pEhFrame,
334                            MemoryRegion& pRegion,
335                            const EhFrameReader::Token& pToken)
336 {
337   return true;
338 }
339 
340