EhFrameReader.cpp revision f7ac0f19a1c8d0ad14bcf6456ce368b830fea886
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
20using namespace mcld;
21using 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.
30static bool
31skip_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//===----------------------------------------------------------------------===//
45template<> EhFrameReader::Token
46EhFrameReader::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
90template<>
91bool 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  LDSection& section = pEhFrame.getSection();
124  if (section.size() == 0x0) {
125    NullFragment* frag = new NullFragment();
126    pEhFrame.addFragment(*frag);
127    return true;
128  }
129
130  // get file offset and address
131  uint64_t file_off = pInput.fileOffset() + section.offset();
132  MemoryRegion* sect_reg =
133                       pInput.memArea()->request(file_off, section.size());
134  ConstAddress handler = (ConstAddress)sect_reg->start();
135
136  State cur_state = Q0;
137  while (Reject != cur_state && Accept != cur_state) {
138
139    Token token = scan<true>(handler, file_off, *sect_reg);
140    MemoryRegion* entry = pInput.memArea()->request(token.file_off, token.size);
141
142    if (!transition[cur_state][token.kind](pEhFrame, *entry, token)) {
143      // fail to scan
144      debug(diag::debug_cannot_scan_eh) << pInput.name();
145      return false;
146    }
147
148    file_off += token.size;
149    handler += token.size;
150
151    if (handler == sect_reg->end())
152      cur_state = Accept;
153    else if (handler > sect_reg->end()) {
154      cur_state = Reject;
155    }
156    else
157      cur_state = autometa[cur_state][token.kind];
158  } // end of while
159
160  if (Reject == cur_state) {
161    // fail to parse
162    debug(diag::debug_cannot_parse_eh) << pInput.name();
163    return false;
164  }
165  return true;
166}
167
168bool EhFrameReader::addCIE(EhFrame& pEhFrame,
169                           MemoryRegion& pRegion,
170                           const EhFrameReader::Token& pToken)
171{
172  // skip Length, Extended Length and CIE ID.
173  ConstAddress handler = pRegion.start() + pToken.data_off;
174  ConstAddress cie_end = pRegion.end();
175
176  // the version should be 1 or 3
177  uint8_t version = *handler++;
178  if (1 != version && 3 != version) {
179    return false;
180  }
181
182  // Set up the Augumentation String
183  ConstAddress aug_str_front = handler;
184  ConstAddress aug_str_back  = static_cast<ConstAddress>(
185                         memchr(aug_str_front, '\0', cie_end - aug_str_front));
186  if (NULL == aug_str_back) {
187    return false;
188  }
189
190  // skip the Augumentation String field
191  handler = aug_str_back + 1;
192
193  // skip the Code Alignment Factor
194  if (!skip_LEB128(&handler, cie_end)) {
195    return false;
196  }
197  // skip the Data Alignment Factor
198  if (!skip_LEB128(&handler, cie_end)) {
199    return false;
200  }
201  // skip the Return Address Register
202  if (cie_end - handler < 1) {
203    return false;
204  }
205  ++handler;
206
207  llvm::StringRef augment((const char*)aug_str_front);
208
209  // we discard this CIE if the augumentation string is '\0'
210  if (0 == augment.size()) {
211    EhFrame::CIE* cie = new EhFrame::CIE(pRegion);
212    cie->setFDEEncode(llvm::dwarf::DW_EH_PE_absptr);
213    pEhFrame.addCIE(*cie);
214    return true;
215  }
216
217  // the Augmentation String start with 'eh' is a CIE from gcc before 3.0,
218  // in LSB Core Spec 3.0RC1. We do not support it.
219  if (augment.size() > 1 && augment[0] == 'e' && augment[1] == 'h') {
220    return false;
221  }
222
223  // parse the Augmentation String to get the FDE encodeing if 'z' existed
224  uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
225  if ('z' == augment[0]) {
226
227    // skip the Augumentation Data Length
228    if (!skip_LEB128(&handler, cie_end)) {
229      return false;
230    }
231
232    // parse the Augmentation String
233    for (size_t i = 1; i < augment.size(); ++i) {
234      switch (augment[i]) {
235        // LDSA encoding (1 byte)
236        case 'L': {
237          if (cie_end - handler < 1) {
238            return false;
239          }
240          ++handler;
241          break;
242        }
243        // Two arguments, the first one represents the encoding of the second
244        // argument (1 byte). The second one is the address of personality
245        // routine.
246        case 'P': {
247          // the first argument
248          if (cie_end - handler < 1) {
249            return false;
250          }
251          uint8_t per_encode = *handler;
252          ++handler;
253          // get the length of the second argument
254          uint32_t per_length = 0;
255          if (0x60 == (per_encode & 0x60)) {
256            return false;
257          }
258          switch (per_encode & 7) {
259            default:
260              return false;
261            case llvm::dwarf::DW_EH_PE_udata2:
262              per_length = 2;
263              break;
264            case llvm::dwarf::DW_EH_PE_udata4:
265              per_length = 4;
266              break;
267            case llvm::dwarf::DW_EH_PE_udata8:
268              per_length = 8;
269              break;
270            case llvm::dwarf::DW_EH_PE_absptr:
271              per_length = 4; // pPkg.bitclass / 8;
272              break;
273          }
274          // skip the alignment
275          if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) {
276            uint32_t per_align = handler - cie_end;
277            per_align += per_length - 1;
278            per_align &= ~(per_length -1);
279            if (static_cast<uint32_t>(cie_end - handler) < per_align) {
280              return false;
281            }
282            handler += per_align;
283          }
284          // skip the second argument
285          if (static_cast<uint32_t>(cie_end - handler) < per_length) {
286            return false;
287          }
288          handler += per_length;
289          break;
290        } // end of case 'P'
291
292        // FDE encoding (1 byte)
293        case 'R': {
294          if (cie_end - handler < 1) {
295            return false;
296          }
297          fde_encoding = *handler;
298          switch (fde_encoding & 7) {
299            case llvm::dwarf::DW_EH_PE_udata2:
300            case llvm::dwarf::DW_EH_PE_udata4:
301            case llvm::dwarf::DW_EH_PE_udata8:
302            case llvm::dwarf::DW_EH_PE_absptr:
303              break;
304            default:
305              return false;
306          }
307          ++handler;
308          break;
309        }
310        default:
311          return false;
312      } // end switch
313    } // the rest chars.
314  } // first char is 'z'
315
316  // create and push back the CIE entry
317  EhFrame::CIE* cie = new EhFrame::CIE(pRegion);
318  cie->setFDEEncode(fde_encoding);
319  pEhFrame.addCIE(*cie);
320  return true;
321}
322
323bool EhFrameReader::addFDE(EhFrame& pEhFrame,
324                           MemoryRegion& pRegion,
325                           const EhFrameReader::Token& pToken)
326{
327  if (pToken.data_off == pRegion.size())
328    return false;
329
330  // create and push back the FDE entry
331  EhFrame::FDE* fde = new EhFrame::FDE(pRegion,
332                                       pEhFrame.cie_back(),
333                                       pToken.data_off);
334  pEhFrame.addFDE(*fde);
335  return true;
336}
337
338bool EhFrameReader::addTerm(EhFrame& pEhFrame,
339                            MemoryRegion& pRegion,
340                            const EhFrameReader::Token& pToken)
341{
342  RegionFragment* frag = new RegionFragment(pRegion);
343  pEhFrame.addFragment(*frag);
344  return true;
345}
346
347bool EhFrameReader::reject(EhFrame& pEhFrame,
348                           MemoryRegion& pRegion,
349                           const EhFrameReader::Token& pToken)
350{
351  return true;
352}
353
354