EhFrameHdr.cpp revision f7ac0f19a1c8d0ad14bcf6456ce368b830fea886
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 = m_EhFrame.getEhFrame()->numOfFDEs();
65  else
66    *fde_count = 0;
67
68  if (0 == *fde_count) {
69    // fde_count_enc
70    data[2] = DW_EH_PE_omit;
71    // table_enc
72    data[3] = DW_EH_PE_omit;
73  }
74  else {
75    // fde_count_enc
76    data[2] = DW_EH_PE_udata4;
77    // table_enc
78    data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
79
80    // prepare the binary search table
81    typedef std::vector<bit32::Entry> SearchTableType;
82    SearchTableType search_table;
83    EhFrame::const_fde_iterator fde, fde_end = m_EhFrame.getEhFrame()->fde_end();
84    for(fde = m_EhFrame.getEhFrame()->fde_begin(); fde != fde_end; ++fde) {
85      assert(*fde != NULL);
86      SizeTraits<32>::Offset offset;
87      SizeTraits<32>::Address fde_pc;
88      SizeTraits<32>::Address fde_addr;
89      offset = (*fde)->getOffset();
90      fde_pc = computePCBegin(**fde, *ehframe_region);
91      fde_addr = m_EhFrame.addr() + offset;
92      search_table.push_back(std::make_pair(fde_pc, fde_addr));
93    }
94
95    std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
96
97    // write out the binary search table
98    uint32_t* bst = (uint32_t*)(data + 12);
99    SearchTableType::const_iterator entry, entry_end = search_table.end();
100    size_t id = 0;
101    for (entry = search_table.begin(); entry != entry_end; ++entry) {
102      bst[id++] = (*entry).first - m_EhFrameHdr.addr();
103      bst[id++] = (*entry).second - m_EhFrameHdr.addr();
104    }
105  }
106  pOutput.release(ehframehdr_region);
107  pOutput.release(ehframe_region);
108}
109
110//===----------------------------------------------------------------------===//
111// EhFrameHdr
112//===----------------------------------------------------------------------===//
113
114EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame)
115  : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) {
116}
117
118EhFrameHdr::~EhFrameHdr()
119{
120}
121
122/// @ref lsb core generic 4.1
123/// .eh_frame_hdr section format
124/// uint8_t : version
125/// uint8_t : eh_frame_ptr_enc
126/// uint8_t : fde_count_enc
127/// uint8_t : table_enc
128/// uint32_t : eh_frame_ptr
129/// uint32_t : fde_count
130/// __________________________ when fde_count > 0
131/// <uint32_t, uint32_t>+ : binary search table
132/// sizeOutput - base on the fde count to size output
133void EhFrameHdr::sizeOutput()
134{
135  size_t size = 12;
136  if (m_EhFrame.hasEhFrame())
137    size += 8 * m_EhFrame.getEhFrame()->numOfFDEs();
138  m_EhFrameHdr.setSize(size);
139}
140
141/// computePCBegin - return the address of FDE's pc
142/// @ref binutils gold: ehframe.cc:222
143uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE,
144                                    const MemoryRegion& pEhFrameRegion)
145{
146  uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
147  unsigned int eh_value = fde_encoding & 0x7;
148
149  // check the size to read in
150  if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
151    eh_value = DW_EH_PE_udata4;
152  }
153
154  size_t pc_size = 0x0;
155  switch (eh_value) {
156    case DW_EH_PE_udata2:
157      pc_size = 2;
158      break;
159    case DW_EH_PE_udata4:
160      pc_size = 4;
161      break;
162    case DW_EH_PE_udata8:
163      pc_size = 8;
164      break;
165    default:
166      // TODO
167      break;
168  }
169
170  SizeTraits<32>::Address pc = 0x0;
171  const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() +
172                          pFDE.getOffset() +
173                          pFDE.getDataStart();
174  std::memcpy(&pc, offset, pc_size);
175
176  // adjust the signed value
177  bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
178  if (DW_EH_PE_udata2 == eh_value && is_signed)
179    pc = (pc ^ 0x8000) - 0x8000;
180
181  // handle eh application
182  switch (fde_encoding & 0x70)
183  {
184    case DW_EH_PE_absptr:
185      break;
186    case DW_EH_PE_pcrel:
187      pc += m_EhFrame.addr() + pFDE.getOffset() + pFDE.getDataStart();
188      break;
189    case DW_EH_PE_datarel:
190      // TODO
191      break;
192    default:
193      // TODO
194      break;
195  }
196  return pc;
197}
198