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 20namespace mcld { 21 22//===----------------------------------------------------------------------===// 23// Helper Function 24//===----------------------------------------------------------------------===// 25namespace bit32 { 26 27typedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry; 28 29bool 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 39template <> 40void 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 115EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame) 116 : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) { 117} 118 119EhFrameHdr::~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 133void 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 141uint32_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