1affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//===- EhFrameHdr.cpp -----------------------------------------------------===//
2affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//
3affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//                     The MCLinker Project
4affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//
5affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// This file is distributed under the University of Illinois Open Source
6affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// License. See LICENSE.TXT for details.
7affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//
8affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//===----------------------------------------------------------------------===//
9affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <mcld/LD/EhFrameHdr.h>
10affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
1122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <mcld/Support/MemoryArea.h>
1222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <mcld/Support/MemoryRegion.h>
1322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <mcld/LD/EhFrame.h>
1422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <mcld/LD/LDSection.h>
1522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <llvm/Support/Dwarf.h>
1722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <llvm/Support/DataTypes.h>
1822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <algorithm>
2022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <cstring>
2122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
22affc150dc44fab1911775a49636d0ce85333b634Zonr Changusing namespace mcld;
2322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaousing namespace llvm::dwarf;
24affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
2522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
2622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// Helper Function
2722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
2822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaonamespace bit32 {
2922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
3022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaotypedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry;
3122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
3222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaobool EntryCompare(const Entry& pX, const Entry& pY)
3322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao{ return (pX.first < pY.first); }
3422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
3522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao} // bit32 namespace
3622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
3722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
3822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// Template Specification Functions
3922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
4022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao/// emitOutput<32> - write out eh_frame_hdr
4122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaotemplate<>
4222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaovoid EhFrameHdr::emitOutput<32>(MemoryArea& pOutput)
43affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
4422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  MemoryRegion* ehframehdr_region =
4522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    pOutput.request(m_EhFrameHdr.offset(), m_EhFrameHdr.size());
4622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
4722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  MemoryRegion* ehframe_region =
4822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    pOutput.request(m_EhFrame.offset(),
4922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                    m_EhFrame.size());
5022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
5122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint8_t* data = (uint8_t*)ehframehdr_region->start();
5222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // version
5322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  data[0] = 1;
5422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // eh_frame_ptr_enc
5522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  data[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
5622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
5722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // eh_frame_ptr
5822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint32_t* eh_frame_ptr = (uint32_t*)(data + 4);
5922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  *eh_frame_ptr = m_EhFrame.addr() - (m_EhFrameHdr.addr() + 4);
6022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
6122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // fde_count
6222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint32_t* fde_count = (uint32_t*)(data + 8);
6322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (m_EhFrame.hasEhFrame())
6422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    *fde_count = m_EhFrame.getEhFrame()->numOfFDEs();
65f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  else
66f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    *fde_count = 0;
6722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
68f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (0 == *fde_count) {
6922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // fde_count_enc
70f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    data[2] = DW_EH_PE_omit;
7122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // table_enc
72f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    data[3] = DW_EH_PE_omit;
7322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
7422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  else {
7522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // fde_count_enc
76f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    data[2] = DW_EH_PE_udata4;
7722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // table_enc
78f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
7922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
8022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // prepare the binary search table
8122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    typedef std::vector<bit32::Entry> SearchTableType;
8222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    SearchTableType search_table;
8322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    EhFrame::const_fde_iterator fde, fde_end = m_EhFrame.getEhFrame()->fde_end();
8422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    for(fde = m_EhFrame.getEhFrame()->fde_begin(); fde != fde_end; ++fde) {
8522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      assert(*fde != NULL);
8622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      SizeTraits<32>::Offset offset;
8722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      SizeTraits<32>::Address fde_pc;
8822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      SizeTraits<32>::Address fde_addr;
8922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      offset = (*fde)->getOffset();
9022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      fde_pc = computePCBegin(**fde, *ehframe_region);
9122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      fde_addr = m_EhFrame.addr() + offset;
9222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      search_table.push_back(std::make_pair(fde_pc, fde_addr));
9322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    }
9422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
9522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare);
9622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
9722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // write out the binary search table
9822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    uint32_t* bst = (uint32_t*)(data + 12);
9922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    SearchTableType::const_iterator entry, entry_end = search_table.end();
10022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    size_t id = 0;
10122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    for (entry = search_table.begin(); entry != entry_end; ++entry) {
10222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      bst[id++] = (*entry).first - m_EhFrameHdr.addr();
10322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      bst[id++] = (*entry).second - m_EhFrameHdr.addr();
10422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    }
10522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
10622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  pOutput.release(ehframehdr_region);
10722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  pOutput.release(ehframe_region);
10822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
10922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
11022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
11122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// EhFrameHdr
11222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
11322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
11422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei LiaoEhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame)
11522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) {
116affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
117affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
118affc150dc44fab1911775a49636d0ce85333b634Zonr ChangEhFrameHdr::~EhFrameHdr()
119affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
120affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
121affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
122affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// @ref lsb core generic 4.1
123affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// .eh_frame_hdr section format
124affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// uint8_t : version
125affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// uint8_t : eh_frame_ptr_enc
126affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// uint8_t : fde_count_enc
127affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// uint8_t : table_enc
128affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// uint32_t : eh_frame_ptr
129affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// uint32_t : fde_count
130affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// __________________________ when fde_count > 0
131affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// <uint32_t, uint32_t>+ : binary search table
132affc150dc44fab1911775a49636d0ce85333b634Zonr Chang/// sizeOutput - base on the fde count to size output
133affc150dc44fab1911775a49636d0ce85333b634Zonr Changvoid EhFrameHdr::sizeOutput()
134affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
135affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  size_t size = 12;
13622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (m_EhFrame.hasEhFrame())
13722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    size += 8 * m_EhFrame.getEhFrame()->numOfFDEs();
13822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  m_EhFrameHdr.setSize(size);
139affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
140affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
14122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao/// computePCBegin - return the address of FDE's pc
14222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao/// @ref binutils gold: ehframe.cc:222
14322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaouint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE,
14422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                                    const MemoryRegion& pEhFrameRegion)
14522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao{
14622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint8_t fde_encoding = pFDE.getCIE().getFDEEncode();
14722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  unsigned int eh_value = fde_encoding & 0x7;
14822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
14922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // check the size to read in
15022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (eh_value == llvm::dwarf::DW_EH_PE_absptr) {
15122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    eh_value = DW_EH_PE_udata4;
15222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
15322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
15422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  size_t pc_size = 0x0;
15522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  switch (eh_value) {
15622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    case DW_EH_PE_udata2:
15722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      pc_size = 2;
15822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
15922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    case DW_EH_PE_udata4:
16022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      pc_size = 4;
16122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
16222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    case DW_EH_PE_udata8:
16322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      pc_size = 8;
16422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
16522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    default:
16622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      // TODO
16722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
16822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
16922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
17022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  SizeTraits<32>::Address pc = 0x0;
17122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() +
17222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                          pFDE.getOffset() +
17322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                          pFDE.getDataStart();
17422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  std::memcpy(&pc, offset, pc_size);
17522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
17622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // adjust the signed value
17722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0;
17822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (DW_EH_PE_udata2 == eh_value && is_signed)
17922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    pc = (pc ^ 0x8000) - 0x8000;
18022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
18122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // handle eh application
18222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  switch (fde_encoding & 0x70)
18322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  {
18422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    case DW_EH_PE_absptr:
18522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
18622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    case DW_EH_PE_pcrel:
18722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      pc += m_EhFrame.addr() + pFDE.getOffset() + pFDE.getDataStart();
18822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
18922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    case DW_EH_PE_datarel:
19022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      // TODO
19122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
19222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    default:
19322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      // TODO
19422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      break;
19522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
19622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return pc;
19722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
198