1//===- FragmentRef.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/Fragment/FragmentRef.h>
10
11#include <cstring>
12#include <cassert>
13
14#include <llvm/Support/Casting.h>
15#include <llvm/Support/ManagedStatic.h>
16
17#include <mcld/Fragment/Fragment.h>
18#include <mcld/LD/LDSection.h>
19#include <mcld/LD/SectionData.h>
20#include <mcld/LD/EhFrame.h>
21#include <mcld/Support/GCFactory.h>
22#include <mcld/Support/MemoryRegion.h>
23#include <mcld/Fragment/RegionFragment.h>
24#include <mcld/Fragment/Stub.h>
25
26using namespace mcld;
27
28typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory;
29
30static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory;
31
32FragmentRef FragmentRef::g_NullFragmentRef;
33
34//===----------------------------------------------------------------------===//
35// FragmentRef
36//===----------------------------------------------------------------------===//
37FragmentRef::FragmentRef()
38  : m_pFragment(NULL), m_Offset(0) {
39}
40
41FragmentRef::FragmentRef(Fragment& pFrag,
42                         FragmentRef::Offset pOffset)
43  : m_pFragment(&pFrag), m_Offset(pOffset) {
44}
45
46/// Create - create a fragment reference for a given fragment.
47///
48/// @param pFrag - the given fragment
49/// @param pOffset - the offset, can be larger than the fragment, but can not
50///                  be larger than the section size.
51/// @return if the offset is legal, return the fragment reference. Otherwise,
52/// return NULL.
53FragmentRef* FragmentRef::Create(Fragment& pFrag, uint64_t pOffset)
54{
55  int64_t offset = pOffset;
56  Fragment* frag = &pFrag;
57
58  while (NULL != frag) {
59    offset -= frag->size();
60    if (offset <= 0)
61      break;
62    frag = frag->getNextNode();
63  }
64
65
66  if (NULL == frag)
67    return Null();
68
69  FragmentRef* result = g_FragRefFactory->allocate();
70  new (result) FragmentRef(*frag, offset + frag->size());
71
72  return result;
73}
74
75FragmentRef* FragmentRef::Create(LDSection& pSection, uint64_t pOffset)
76{
77  SectionData* data = NULL;
78  switch (pSection.kind()) {
79    case LDFileFormat::Relocation:
80      // No fragment reference refers to a relocation section
81      break;
82    case LDFileFormat::EhFrame:
83      if (pSection.hasEhFrame())
84        data = pSection.getEhFrame()->getSectionData();
85      break;
86    default:
87      data = pSection.getSectionData();
88      break;
89  }
90
91  if (NULL == data || data->empty()) {
92    return Null();
93  }
94
95  return Create(data->front(), pOffset);
96}
97
98void FragmentRef::Clear()
99{
100  g_FragRefFactory->clear();
101}
102
103FragmentRef* FragmentRef::Null()
104{
105  return &g_NullFragmentRef;
106}
107
108FragmentRef& FragmentRef::assign(const FragmentRef& pCopy)
109{
110  m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment);
111  m_Offset = pCopy.m_Offset;
112  return *this;
113}
114
115FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
116{
117  m_pFragment = &pFrag;
118  m_Offset = pOffset;
119  return *this;
120}
121
122void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const
123{
124  // check if the offset is still in a legal range.
125  if (NULL == m_pFragment)
126    return;
127  unsigned int total_offset = m_Offset + pOffset;
128  switch(m_pFragment->getKind()) {
129    case Fragment::Region: {
130      RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment);
131      unsigned int total_length = region_frag->getRegion().size();
132      if (total_length < (total_offset+pNBytes))
133        pNBytes = total_length - total_offset;
134
135      std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes);
136      return;
137    }
138    case Fragment::Stub: {
139      Stub* stub_frag = static_cast<Stub*>(m_pFragment);
140      unsigned int total_length = stub_frag->size();
141      if (total_length < (total_offset+pNBytes))
142        pNBytes = total_length - total_offset;
143      std::memcpy(pDest, stub_frag->getContent() + total_offset, pNBytes);
144      return;
145    }
146    case Fragment::Alignment:
147    case Fragment::Fillment:
148    default:
149      return;
150  }
151}
152
153FragmentRef::Address FragmentRef::deref()
154{
155  if (NULL == m_pFragment)
156    return NULL;
157  Address base = NULL;
158  switch(m_pFragment->getKind()) {
159    case Fragment::Region:
160      base = static_cast<RegionFragment*>(m_pFragment)->getRegion().getBuffer();
161      break;
162    case Fragment::Alignment:
163    case Fragment::Fillment:
164    default:
165      return NULL;
166  }
167  return base + m_Offset;
168}
169
170FragmentRef::ConstAddress FragmentRef::deref() const
171{
172  if (NULL == m_pFragment)
173    return NULL;
174  ConstAddress base = NULL;
175  switch(m_pFragment->getKind()) {
176    case Fragment::Region:
177      base = static_cast<const RegionFragment*>(m_pFragment)->getRegion().getBuffer();
178      break;
179    case Fragment::Alignment:
180    case Fragment::Fillment:
181    default:
182      return NULL;
183  }
184  return base + m_Offset;
185}
186
187FragmentRef::Offset FragmentRef::getOutputOffset() const
188{
189  Offset result = 0;
190  if (NULL != m_pFragment)
191    result = m_pFragment->getOffset();
192  return (result + m_Offset);
193}
194
195