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