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 22 using namespace mcld; 23 using namespace llvm::dwarf; 24 25 //===----------------------------------------------------------------------===// 26 // Helper Function 27 //===----------------------------------------------------------------------===// 28 namespace bit32 { 29 30 typedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry; 31 32 bool 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 41 template<> 42 void 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 118 template<> 119 void EhFrameHdr::emitOutput<64>(MemoryArea& pOutput) 120 { 121 } 122 123 //===----------------------------------------------------------------------===// 124 // EhFrameHdr 125 //===----------------------------------------------------------------------===// 126 127 EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame) 128 : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) { 129 } 130 131 EhFrameHdr::~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 146 void 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 156 uint32_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