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
19using namespace mcld;
20
21//==========================
22// EhFrame
23EhFrame::EhFrame()
24 : m_fCanRecognizeAll(true) {
25}
26
27EhFrame::~EhFrame()
28{
29}
30
31uint64_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
147bool 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
301bool 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
326uint32_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
337bool 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
348void 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