EhFrameHdr.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
1//===- EhFrameHdr.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/EhFrameHdr.h>
10
11#include <mcld/Support/MemoryArea.h>
12#include <mcld/Support/MemoryRegion.h>
13#include <mcld/LD/EhFrame.h>
14#include <mcld/LD/LDSection.h>
15
16#include <llvm/Support/Dwarf.h>
17#include <llvm/Support/DataTypes.h>
18
19#include <algorithm>
20#include <cstring>
21
22using namespace mcld;
23using namespace llvm::dwarf;
24
25//===----------------------------------------------------------------------===//
26// Helper Function
27//===----------------------------------------------------------------------===//
28namespace bit32 {
29
30typedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry;
31
32bool EntryCompare(const Entry& pX, const Entry& pY)
33{ return (pX.first < pY.first); }
34
35} // bit32 namespace
36
37//===----------------------------------------------------------------------===//
38// Template Specification Functions
39//===----------------------------------------------------------------------===//
40/// emitOutput<32> - write out eh_frame_hdr
41template<>
42void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput)
43{
44  MemoryRegion* ehframehdr_region =
45    pOutput.request(m_EhFrameHdr.offset(), m_EhFrameHdr.size());
46
47  MemoryRegion* ehframe_region =
48    pOutput.request(m_EhFrame.offset(),
49                    m_EhFrame.size());
50
51  uint8_t* data = (uint8_t*)ehframehdr_region->start();
52  // version
53  data[0] = 1;
54  // eh_frame_ptr_enc
55  data[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
56
57  // eh_frame_ptr
58  uint32_t* eh_frame_ptr = (uint32_t*)(data + 4);
59  *eh_frame_ptr = m_EhFrame.addr() - (m_EhFrameHdr.addr() + 4);
60
61  // fde_count
62  uint32_t* fde_count = (uint32_t*)(data + 8);
63  if (m_EhFrame.hasEhFrame())
64    *fde_count = 0;
65  else
66    *fde_count = m_EhFrame.getEhFrame()->numOfFDEs();
67
68  if (0 != *fde_count) {
69    // fde_count_enc
70    data[2] = DW_EH_PE_udata4;
71    // table_enc
72    data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
73
74  }
75  else {
76    // fde_count_enc
77    data[2] = DW_EH_PE_omit;
78    // table_enc
79    data[3] = DW_EH_PE_omit;
80  }
81
82  if (0 != *fde_count) {
83
84    // prepare the binary search table
85    typedef std::vector<bit32::Entry> SearchTableType;
86    SearchTableType search_table;
87    MemoryRegion* ehframe_region =
88      pOutput.request(m_EhFrame.offset(), m_EhFrame.size());
89    EhFrame::const_fde_iterator fde, fde_end = m_EhFrame.getEhFrame()->fde_end();
90    for(fde = m_EhFrame.getEhFrame()->fde_begin(); fde != fde_end; ++fde) {
91      assert(*fde != NULL);
92      SizeTraits<32>::Offset offset;
93      SizeTraits<32>::Address fde_pc;
94      SizeTraits<32>::Address fde_addr;
95      offset = (*fde)->getOffset();
96      fde_pc = computePCBegin(**fde, *ehframe_region);
97      fde_addr = m_EhFrame.addr() + offset;
98      search_table.push_back(std::make_pair(fde_pc, fde_addr));
99    }
100    pOutput.release(ehframe_region);
101
102    std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
103
104    // write out the binary search table
105    uint32_t* bst = (uint32_t*)(data + 12);
106    SearchTableType::const_iterator entry, entry_end = search_table.end();
107    size_t id = 0;
108    for (entry = search_table.begin(); entry != entry_end; ++entry) {
109      bst[id++] = (*entry).first - m_EhFrameHdr.addr();
110      bst[id++] = (*entry).second - m_EhFrameHdr.addr();
111    }
112  }
113  pOutput.release(ehframehdr_region);
114  pOutput.release(ehframe_region);
115}
116
117/// emitOutput<64> - write out eh_frame_hdr
118template<>
119void EhFrameHdr::emitOutput<64>(MemoryArea& pOutput)
120{
121}
122
123//===----------------------------------------------------------------------===//
124// EhFrameHdr
125//===----------------------------------------------------------------------===//
126
127EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame)
128  : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) {
129}
130
131EhFrameHdr::~EhFrameHdr()
132{
133}
134
135/// @ref lsb core generic 4.1
136/// .eh_frame_hdr section format
137/// uint8_t : version
138/// uint8_t : eh_frame_ptr_enc
139/// uint8_t : fde_count_enc
140/// uint8_t : table_enc
141/// uint32_t : eh_frame_ptr
142/// uint32_t : fde_count
143/// __________________________ when fde_count > 0
144/// <uint32_t, uint32_t>+ : binary search table
145/// sizeOutput - base on the fde count to size output
146void EhFrameHdr::sizeOutput()
147{
148  size_t size = 12;
149  if (m_EhFrame.hasEhFrame())
150    size += 8 * m_EhFrame.getEhFrame()->numOfFDEs();
151  m_EhFrameHdr.setSize(size);
152}
153
154/// computePCBegin - return the address of FDE's pc
155/// @ref binutils gold: ehframe.cc:222
156uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE,
157                                    const MemoryRegion& pEhFrameRegion)
158{
159  uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
160  unsigned int eh_value = fde_encoding & 0x7;
161
162  // check the size to read in
163  if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
164    eh_value = DW_EH_PE_udata4;
165  }
166
167  size_t pc_size = 0x0;
168  switch (eh_value) {
169    case DW_EH_PE_udata2:
170      pc_size = 2;
171      break;
172    case DW_EH_PE_udata4:
173      pc_size = 4;
174      break;
175    case DW_EH_PE_udata8:
176      pc_size = 8;
177      break;
178    default:
179      // TODO
180      break;
181  }
182
183  SizeTraits<32>::Address pc = 0x0;
184  const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() +
185                          pFDE.getOffset() +
186                          pFDE.getDataStart();
187  std::memcpy(&pc, offset, pc_size);
188
189  // adjust the signed value
190  bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
191  if (DW_EH_PE_udata2 == eh_value && is_signed)
192    pc = (pc ^ 0x8000) - 0x8000;
193
194  // handle eh application
195  switch (fde_encoding & 0x70)
196  {
197    case DW_EH_PE_absptr:
198      break;
199    case DW_EH_PE_pcrel:
200      pc += m_EhFrame.addr() + pFDE.getOffset() + pFDE.getDataStart();
201      break;
202    case DW_EH_PE_datarel:
203      // TODO
204      break;
205    default:
206      // TODO
207      break;
208  }
209  return pc;
210}
211