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