1//===- MCFragmentRef.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 <llvm/Support/MathExtras.h>
10#include <mcld/MC/MCFragmentRef.h>
11#include <mcld/MC/MCRegionFragment.h>
12#include <mcld/MC/MCTargetFragment.h>
13#include <mcld/LD/Layout.h>
14#include <cstring>
15#include <cassert>
16
17using namespace mcld;
18
19/// compunteFragmentSize - compute the specific MCFragment size
20uint64_t mcld::computeFragmentSize(const Layout& pLayout,
21                                   const llvm::MCFragment& pFrag)
22{
23  switch (pFrag.getKind()) {
24    case llvm::MCFragment::FT_Data:
25      return static_cast<const llvm::MCDataFragment&>(pFrag).getContents().size();
26    case llvm::MCFragment::FT_Fill:
27      return static_cast<const llvm::MCFillFragment&>(pFrag).getSize();
28    case llvm::MCFragment::FT_Inst:
29      return static_cast<const llvm::MCInstFragment&>(pFrag).getInstSize();
30
31    case llvm::MCFragment::FT_LEB:
32      return static_cast<const llvm::MCLEBFragment&>(pFrag).getContents().size();
33
34    case llvm::MCFragment::FT_Align: {
35      uint64_t offset = pLayout.getOutputOffset(pFrag);
36      const llvm::MCAlignFragment& align_frag = static_cast<const llvm::MCAlignFragment&>(pFrag);
37      uint64_t size = llvm::OffsetToAlignment(offset, align_frag.getAlignment());
38      if (size > align_frag.getMaxBytesToEmit())
39        return 0;
40      return size;
41    }
42
43    case llvm::MCFragment::FT_Org: {
44      // TODO
45      assert(0 && "FT_Org: Not implemented yet");
46      return 0;
47    }
48
49    case llvm::MCFragment::FT_Dwarf:
50      return static_cast<const llvm::MCDwarfLineAddrFragment&>(pFrag).getContents().size();
51    case llvm::MCFragment::FT_DwarfFrame:
52      return static_cast<const llvm::MCDwarfCallFrameFragment&>(pFrag).getContents().size();
53
54    case llvm::MCFragment::FT_Region:
55      return static_cast<const MCRegionFragment&>(pFrag).getRegion().size();
56
57    case llvm::MCFragment::FT_Target:
58      return static_cast<const MCTargetFragment&>(pFrag).getSize();
59
60    case llvm::MCFragment::FT_Reloc:
61      assert(0 && "the size of FT_Reloc fragment is handled by backend");
62      return 0;
63
64    default:
65      assert(0 && "invalid fragment kind");
66      return 0;
67  }
68}
69
70//==========================
71// MCFragmentRef
72MCFragmentRef::MCFragmentRef()
73  : m_pFragment(NULL), m_Offset(0) {
74}
75
76MCFragmentRef::MCFragmentRef(llvm::MCFragment& pFrag,
77                             MCFragmentRef::Offset pOffset)
78  : m_pFragment(&pFrag), m_Offset(pOffset) {
79}
80
81MCFragmentRef::~MCFragmentRef()
82{
83  m_pFragment = NULL;
84  m_Offset = 0;
85}
86
87MCFragmentRef& MCFragmentRef::assign(const MCFragmentRef& pCopy)
88{
89  m_pFragment = const_cast<llvm::MCFragment*>(pCopy.m_pFragment);
90  m_Offset = pCopy.m_Offset;
91  return *this;
92}
93
94MCFragmentRef& MCFragmentRef::assign(llvm::MCFragment& pFrag, MCFragmentRef::Offset pOffset)
95{
96  m_pFragment = &pFrag;
97  m_Offset = pOffset;
98  return *this;
99}
100
101void MCFragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const
102{
103  // check if the offset is still in a legal range.
104  if (NULL == m_pFragment)
105    return;
106  unsigned int total_offset = m_Offset + pOffset;
107  switch(m_pFragment->getKind()) {
108    case llvm::MCFragment::FT_Inst: {
109      llvm::MCInstFragment* inst_frag = static_cast<llvm::MCInstFragment*>(m_pFragment);
110      unsigned int total_length = inst_frag->getCode().size();
111      if (total_length < (total_offset+pNBytes))
112        pNBytes = total_length - total_offset;
113
114      std::memcpy(pDest, (inst_frag->getCode().data()+total_offset), pNBytes);
115      return;
116    }
117    case llvm::MCFragment::FT_Data: {
118      llvm::MCDataFragment* data_frag = static_cast<llvm::MCDataFragment*>(m_pFragment);
119      unsigned int total_length = data_frag->getContents().size();
120      if (total_length < (total_offset+pNBytes))
121        pNBytes = total_length - total_offset;
122
123      std::memcpy(pDest, (data_frag->getContents().data()+total_offset), pNBytes);
124      return;
125    }
126    case llvm::MCFragment::FT_Region: {
127      MCRegionFragment* region_frag = static_cast<mcld::MCRegionFragment*>(m_pFragment);
128      unsigned int total_length = region_frag->getRegion().size();
129      if (total_length < (total_offset+pNBytes))
130        pNBytes = total_length - total_offset;
131
132      std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes);
133      return;
134    }
135    case llvm::MCFragment::FT_Align:
136    case llvm::MCFragment::FT_Fill:
137    case llvm::MCFragment::FT_Org:
138    case llvm::MCFragment::FT_Dwarf:
139    case llvm::MCFragment::FT_DwarfFrame:
140    case llvm::MCFragment::FT_LEB:
141    default:
142      return;
143  }
144}
145
146MCFragmentRef::Address MCFragmentRef::deref()
147{
148  if (NULL == m_pFragment)
149    return NULL;
150  Address base = NULL;
151  switch(m_pFragment->getKind()) {
152    case llvm::MCFragment::FT_Inst:
153      base = (Address)static_cast<llvm::MCInstFragment*>(m_pFragment)->getCode().data();
154      break;
155    case llvm::MCFragment::FT_Data:
156      base = (Address)static_cast<llvm::MCDataFragment*>(m_pFragment)->getContents().data();
157      break;
158    case llvm::MCFragment::FT_Region:
159      base = static_cast<mcld::MCRegionFragment*>(m_pFragment)->getRegion().getBuffer();
160      break;
161    case llvm::MCFragment::FT_Align:
162    case llvm::MCFragment::FT_Fill:
163    case llvm::MCFragment::FT_Org:
164    case llvm::MCFragment::FT_Dwarf:
165    case llvm::MCFragment::FT_DwarfFrame:
166    case llvm::MCFragment::FT_LEB:
167    default:
168      return NULL;
169  }
170  return base + m_Offset;
171}
172
173MCFragmentRef::ConstAddress MCFragmentRef::deref() const
174{
175  if (NULL == m_pFragment)
176    return NULL;
177  ConstAddress base = NULL;
178  switch(m_pFragment->getKind()) {
179    case llvm::MCFragment::FT_Inst:
180      base = (ConstAddress)static_cast<const llvm::MCInstFragment*>(m_pFragment)->getCode().data();
181      break;
182    case llvm::MCFragment::FT_Data:
183      base = (ConstAddress)static_cast<const llvm::MCDataFragment*>(m_pFragment)->getContents().data();
184      break;
185    case llvm::MCFragment::FT_Region:
186      base = static_cast<const mcld::MCRegionFragment*>(m_pFragment)->getRegion().getBuffer();
187      break;
188    case llvm::MCFragment::FT_Align:
189    case llvm::MCFragment::FT_Fill:
190    case llvm::MCFragment::FT_Org:
191    case llvm::MCFragment::FT_Dwarf:
192    case llvm::MCFragment::FT_DwarfFrame:
193    case llvm::MCFragment::FT_LEB:
194    default:
195      return NULL;
196  }
197  return base + m_Offset;
198}
199
200