1//===- ARMException.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
10#include "ARMException.h"
11
12#include "ARMLDBackend.h"
13
14#include "mcld/Fragment/RegionFragment.h"
15#include "mcld/LD/ELFFileFormat.h"
16#include "mcld/LD/LDContext.h"
17#include "mcld/Support/MsgHandling.h"
18
19#include <memory>
20
21namespace mcld {
22
23static RegionFragment* findRegionFragment(LDSection& pSection) {
24  SectionData* sectData = pSection.getSectionData();
25  for (SectionData::iterator it = sectData->begin(),
26                             end = sectData->end(); it != end; ++it) {
27    if (it->getKind() == Fragment::Region) {
28      return static_cast<RegionFragment*>(&*it);
29    }
30  }
31  return NULL;
32}
33
34void ARMExData::addInputMap(Input* pInput,
35                            std::unique_ptr<ARMInputExMap> pExMap) {
36  assert(m_Inputs.find(pInput) == m_Inputs.end() &&
37         "multiple maps for an input");
38
39  ARMInputExMap* exMap = pExMap.get();
40
41  // Add mapping to the input-to-exdata map.
42  m_Inputs.insert(std::make_pair(pInput, std::move(pExMap)));
43
44  // Add mapping to the fragment-to-exdata map.
45  for (ARMInputExMap::iterator it = exMap->begin(), end = exMap->end();
46       it != end; ++it) {
47    ARMExSectionTuple* exTuple = it->second.get();
48    m_ExIdxToTuple[exTuple->getExIdxFragment()] = exTuple;
49  }
50}
51
52std::unique_ptr<ARMExData> ARMExData::create(Module& pModule) {
53  std::unique_ptr<ARMExData> exData(new ARMExData());
54  for (Module::obj_iterator it = pModule.obj_begin(),
55                            end = pModule.obj_end(); it != end; ++it) {
56    Input* input = *it;
57    exData->addInputMap(input, ARMInputExMap::create(*input));
58  }
59  return exData;
60}
61
62std::unique_ptr<ARMInputExMap> ARMInputExMap::create(Input& pInput) {
63  std::unique_ptr<ARMInputExMap> exMap(new ARMInputExMap());
64
65  // Scan the input and collect all related sections.
66  LDContext* ctx = pInput.context();
67  for (LDContext::sect_iterator it = ctx->sectBegin(),
68                                end = ctx->sectEnd(); it != end; ++it) {
69    LDSection* sect = *it;
70    if (sect->type() == llvm::ELF::SHT_ARM_EXIDX) {
71      ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(*sect);
72      exTuple->setExIdxSection(sect);
73      exTuple->setTextSection(sect->getLink());
74      if (sect->getLink() == NULL) {
75        fatal(diag::eh_missing_text_section) << sect->name() << pInput.name();
76      }
77    }
78  }
79
80  // Remove the invalid exception tuples and convert LDSection to RegionFragment
81  // or RelocData.
82  ARMInputExMap::iterator it = exMap->begin();
83  ARMInputExMap::iterator end = exMap->end();
84  while (it != end) {
85    ARMExSectionTuple* exTuple = it->second.get();
86    LDSection* const text = exTuple->getTextSection();
87    LDSection* const exIdx = exTuple->getExIdxSection();
88
89    // Ignore the exception section if the text section is ignored.
90    if ((text->kind() == LDFileFormat::Ignore) ||
91        (text->kind() == LDFileFormat::Folded)) {
92      // Set the related exception sections as LDFileFormat::Ignore.
93      exIdx->setKind(LDFileFormat::Ignore);
94      // Remove this tuple from the input exception map.
95      ARMInputExMap::iterator deadIt = it++;
96      exMap->erase(deadIt);
97      continue;
98    }
99
100    // Get RegionFragment from ".text", ".ARM.exidx", and ".ARM.extab" sections.
101    RegionFragment* textFrag = findRegionFragment(*text);
102    RegionFragment* exIdxFrag = findRegionFragment(*exIdx);
103
104    exTuple->setTextFragment(textFrag);
105    exTuple->setExIdxFragment(exIdxFrag);
106
107    // If there is no region fragment in the .ARM.extab section, then we can
108    // skip this tuple.
109    if (exIdxFrag == NULL) {
110      ARMInputExMap::iterator deadIt = it++;
111      exMap->erase(deadIt);
112      continue;
113    }
114
115    // Check next tuple
116    ++it;
117  }
118
119  return exMap;
120}
121
122}  // namespace mcld
123