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