EhFrame.cpp revision affc150dc44fab1911775a49636d0ce85333b634
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#include <mcld/LD/EhFrame.h>
10#include <mcld/MC/MCLinker.h>
11#include <mcld/Support/MsgHandling.h>
12#include <mcld/Target/TargetLDBackend.h>
13#include <llvm/Support/Dwarf.h>
14#include <llvm/Support/Host.h>
15
16using namespace mcld;
17
18//==========================
19// EhFrame
20EhFrame::EhFrame()
21 : m_fCanRecognizeAll(true) {
22}
23
24EhFrame::~EhFrame()
25{
26}
27
28uint64_t EhFrame::readEhFrame(Layout& pLayout,
29                              const TargetLDBackend& pBackend,
30                              llvm::MCSectionData& pSD,
31                              LDSection& pSection,
32                              MemoryArea& pArea)
33{
34  MemoryRegion* region = pArea.request(pSection.offset(),
35                                       pSection.size());
36  // an empty .eh_frame
37  if (NULL == region) {
38    note(diag::note_ehframe) << "an empty eh_frame";
39    return 0;
40  }
41
42  ConstAddress eh_start = region->start();
43  ConstAddress eh_end = region->end();
44  ConstAddress p = eh_start;
45
46  // read the Length filed
47  uint32_t len = readVal(p, pBackend.isLittleEndian());
48
49  // This CIE is a terminator if the Length field is 0, return 0 to handled it
50  // as an ordinary input.
51  if (0 == len) {
52    note(diag::note_ehframe) << "a terminator";
53    pArea.release(region);
54    return 0;
55  }
56
57  if (0xffffffff == len) {
58    debug(diag::debug_eh_unsupport) << "64-bit eh_frame";
59    pArea.release(region);
60    m_fCanRecognizeAll = false;
61    return 0;
62  }
63
64  // record the order of the CIE and FDE fragments
65  FragListType frag_list;
66
67  while (p < eh_end) {
68
69    if (eh_end - p < 4) {
70      debug(diag::debug_eh_unsupport) << "CIE or FDE size smaller than 4";
71      m_fCanRecognizeAll = false;
72      break;
73    }
74    // read the Length field
75    len = readVal(p, pBackend.isLittleEndian());
76    p += 4;
77
78    // the zero length entry should be the end of the section
79    if (0 == len) {
80      if (p < eh_end) {
81        debug(diag::debug_eh_unsupport) << "Non-end entry with zero length";
82        m_fCanRecognizeAll = false;
83      }
84      break;
85    }
86    if (0xffffffff == len) {
87      debug(diag::debug_eh_unsupport) << "64-bit eh_frame";
88      m_fCanRecognizeAll = false;
89      break;
90    }
91
92    if (eh_end - p < 4) {
93      debug(diag::debug_eh_unsupport) <<
94        "CIE:ID field / FDE: CIE Pointer field";
95      m_fCanRecognizeAll = false;
96      break;
97    }
98
99    // compute the section offset of this entry
100    uint32_t ent_offset = static_cast<uint32_t>(p - eh_start - 4);
101
102    // get the MemoryRegion for this entry
103    MemoryRegion* ent_region = pArea.request(pSection.offset() + ent_offset,
104                                             len + 4);
105
106    // create and add a CIE or FDE entry
107    uint32_t id = readVal(p, pBackend.isLittleEndian());
108    // CIE
109    if (0 == id) {
110      if (!addCIE(*ent_region, pBackend, frag_list)) {
111        m_fCanRecognizeAll = false;
112        pArea.release(ent_region);
113        break;
114      }
115    }
116
117    // FDE
118    else {
119      if (!addFDE(*ent_region, pBackend, frag_list)) {
120        m_fCanRecognizeAll = false;
121        pArea.release(ent_region);
122        break;
123      }
124    }
125    p += len;
126  }
127
128  if (!m_fCanRecognizeAll) {
129    pArea.release(region);
130    deleteFragments(frag_list, pArea);
131    return 0;
132  }
133
134  // append all CIE and FDE fragments to Layout after we successfully read
135  // this eh_frame
136  size_t section_size = 0;
137  for (FragListType::iterator it = frag_list.begin();
138         it != frag_list.end(); ++it)
139    section_size += pLayout.appendFragment(**it, pSD, pSection.align());
140
141  pArea.release(region);
142  return section_size;
143}
144
145bool EhFrame::addCIE(MemoryRegion& pRegion,
146                     const TargetLDBackend& pBackend,
147                     FragListType& pFragList)
148{
149  ConstAddress cie_start = pRegion.start();
150  ConstAddress cie_end = pRegion.end();
151  ConstAddress p = cie_start;
152
153  // skip the Length (4 byte) and CIE ID (4 byte) fields
154  p += 8;
155
156  // the version should be 1
157  if (1 != *p) {
158    debug(diag::debug_eh_unsupport) << "CIE version";
159    return false;
160  }
161  ++p;
162
163  // get the Augumentation String
164  ConstAddress aug_str = p;
165  ConstAddress aug_str_end = static_cast<ConstAddress>(
166                               memchr(p, '\0', cie_end - p));
167
168  // skip the Augumentation String field
169  p = aug_str_end + 1;
170
171  // skip the Code Alignment Factor
172  if (!skipLEB128(&p, cie_end)) {
173    debug(diag::debug_eh_unsupport) << "unrecognized Code Alignment Factor";
174    return false;
175  }
176  // skip the Data Alignment Factor
177  if (!skipLEB128(&p, cie_end)) {
178    debug(diag::debug_eh_unsupport) << "unrecognized Data Alignment Factor";
179    return false;
180  }
181  // skip the Return Address Register
182  if (cie_end - p < 1) {
183    debug(diag::debug_eh_unsupport) << "unrecognized Return Address Register";
184    return false;
185  }
186  ++p;
187
188  // the Augmentation String start with 'eh' is a CIE from gcc before 3.0,
189  // in LSB Core Spec 3.0RC1. We do not support it.
190  if (aug_str[0] == 'e' && aug_str[1] == 'h') {
191    debug(diag::debug_eh_unsupport) << "augmentation string `eh`";
192    return false;
193  }
194
195  // parse the Augmentation String to get the FDE encodeing if 'z' existed
196  std::string aug_str_data;
197  uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
198  if (*aug_str == 'z') {
199
200    aug_str_data += *aug_str;
201    ++aug_str;
202
203    // skip the Augumentation Data Length
204    if (!skipLEB128(&p, cie_end)) {
205      debug(diag::debug_eh_unsupport) <<
206        "unrecognized Augmentation Data Length";
207      return false;
208    }
209
210    while (aug_str != aug_str_end) {
211      switch (*aug_str) {
212        default:
213          debug(diag::debug_eh_unsupport) << "augmentation string";
214          return false;
215
216        // LDSA encoding (1 byte)
217        case 'L':
218          if (cie_end - p < 1) {
219            debug(diag::debug_eh_unsupport) << "augmentation string `L`";
220            return false;
221          }
222          ++p;
223          break;
224
225        // Two arguments, the first one represents the encoding of the second
226        // argument (1 byte). The second one is the address of personality
227        // routine.
228        case 'P': {
229          // the first argument
230          if (cie_end - p < 1) {
231            debug(diag::debug_eh_unsupport) << "augmentation string `P`";
232            return false;
233          }
234          uint8_t per_encode = *p;
235          ++p;
236          // get the length of the second argument
237          uint32_t per_length = 0;
238          if (0x60 == (per_encode & 0x60)) {
239            debug(diag::debug_eh_unsupport) << "augmentation string `P`";
240            return false;
241          }
242          switch (per_encode & 7) {
243            default:
244              debug(diag::debug_eh_unsupport) << "augmentation string `P`";
245              return false;
246            case llvm::dwarf::DW_EH_PE_udata2:
247              per_length = 2;
248              break;
249            case llvm::dwarf::DW_EH_PE_udata4:
250              per_length = 4;
251              break;
252            case llvm::dwarf::DW_EH_PE_udata8:
253              per_length = 8;
254              break;
255            case llvm::dwarf::DW_EH_PE_absptr:
256              per_length = pBackend.bitclass() / 8;
257              break;
258          }
259          // skip the alignment
260          if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) {
261            uint32_t per_align = p - cie_end;
262            per_align += per_length - 1;
263            per_align &= ~(per_length -1);
264            if (static_cast<uint32_t>(cie_end - p) < per_align) {
265              debug(diag::debug_eh_unsupport) << "augmentation string `P`";
266              return false;
267            }
268            p += per_align;
269          }
270          // skip the second argument
271          if (static_cast<uint32_t>(cie_end - p) < per_length) {
272            debug(diag::debug_eh_unsupport) << "augmentation string `P`";
273            return false;
274          }
275          p += per_length;
276        }
277        break;
278
279        // FDE encoding (1 byte)
280        case 'R':
281          if (cie_end - p < 1) {
282            debug(diag::debug_eh_unsupport) << "augmentation string `R`";
283            return false;
284          }
285          fde_encoding = *p;
286          switch (fde_encoding & 7) {
287            case llvm::dwarf::DW_EH_PE_udata2:
288            case llvm::dwarf::DW_EH_PE_udata4:
289            case llvm::dwarf::DW_EH_PE_udata8:
290            case llvm::dwarf::DW_EH_PE_absptr:
291              break;
292            default:
293              debug(diag::debug_eh_unsupport) << "FDE encoding";
294              return false;
295          }
296          ++p;
297          break;
298      } // end switch
299      aug_str_data += *aug_str;
300      ++aug_str;
301    } // end while
302  }
303
304  note(diag::note_eh_cie) << pRegion.size()
305                          << aug_str_data
306                          << (fde_encoding & 7);
307
308  // create and push back the CIE entry
309  CIE* entry = new CIE(pRegion, fde_encoding);
310  m_CIEs.push_back(entry);
311  pFragList.push_back(static_cast<llvm::MCFragment*>(entry));
312  return true;
313}
314
315bool EhFrame::addFDE(MemoryRegion& pRegion,
316                     const TargetLDBackend& pBackend,
317                     FragListType& pFragList)
318{
319  ConstAddress fde_start = pRegion.start();
320  ConstAddress fde_end = pRegion.end();
321  ConstAddress p = fde_start;
322
323  // skip the Length (4 byte) and CIE Pointer (4 byte) fields
324  p += 8;
325
326  // get the entry offset of the PC Begin
327  if (fde_end - p < 1) {
328    debug(diag::debug_eh_unsupport) << "FDE PC Begin";
329    return false;
330  }
331  FDE::Offset pc_offset = static_cast<FDE::Offset>(p - fde_start);
332
333  note(diag::note_eh_fde) << pRegion.size() << pc_offset;
334  // create and push back the FDE entry
335  FDE* entry = new FDE(pRegion, **(m_CIEs.end() -1), pc_offset);
336  m_FDEs.push_back(entry);
337  pFragList.push_back(static_cast<llvm::MCFragment*>(entry));
338  return true;
339}
340
341uint32_t EhFrame::readVal(ConstAddress pAddr, bool pIsTargetLittleEndian)
342{
343  const uint32_t* p = reinterpret_cast<const uint32_t*>(pAddr);
344  uint32_t val = *p;
345
346  // byte swapping if the host and target have different endian
347  if (llvm::sys::isLittleEndianHost() != pIsTargetLittleEndian)
348    val = bswap32(val);
349  return val;
350}
351
352bool EhFrame::skipLEB128(ConstAddress* pp, ConstAddress pend)
353{
354  for (ConstAddress p = *pp; p < pend; ++p) {
355    if (0 == (*p & 0x80)) {
356      *pp = p + 1;
357      return true;
358    }
359  }
360  return false;
361}
362
363void EhFrame::deleteFragments(FragListType& pList, MemoryArea& pArea)
364{
365  MCRegionFragment* frag = NULL;
366  for (FragListType::iterator it = pList.begin(); it != pList.end(); ++it) {
367    frag = static_cast<MCRegionFragment*>(*it);
368    pArea.release(&(frag->getRegion()));
369    delete *it;
370  }
371  pList.clear();
372}
373
374