1//===- ScriptFile.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/Script/ScriptFile.h>
10#include <mcld/Script/StringList.h>
11#include <mcld/Script/ScriptCommand.h>
12#include <mcld/Script/EntryCmd.h>
13#include <mcld/Script/OutputFormatCmd.h>
14#include <mcld/Script/GroupCmd.h>
15#include <mcld/Script/OutputCmd.h>
16#include <mcld/Script/SearchDirCmd.h>
17#include <mcld/Script/OutputArchCmd.h>
18#include <mcld/Script/AssertCmd.h>
19#include <mcld/Script/SectionsCmd.h>
20#include <mcld/Script/RpnExpr.h>
21#include <mcld/Script/Operand.h>
22#include <mcld/Script/StrToken.h>
23#include <mcld/MC/Input.h>
24#include <mcld/MC/InputBuilder.h>
25#include <mcld/Support/MemoryArea.h>
26#include <mcld/InputTree.h>
27#include <mcld/ADT/HashEntry.h>
28#include <mcld/ADT/HashTable.h>
29#include <mcld/ADT/StringHash.h>
30#include <llvm/Support/Casting.h>
31#include <llvm/Support/ManagedStatic.h>
32#include <cassert>
33
34using namespace mcld;
35
36typedef HashEntry<std::string,
37                  void*,
38                  hash::StringCompare<std::string> > ParserStrEntry;
39typedef HashTable<ParserStrEntry,
40                  hash::StringHash<hash::DJB>,
41                  EntryFactory<ParserStrEntry> > ParserStrPool;
42static llvm::ManagedStatic<ParserStrPool> g_ParserStrPool;
43
44//===----------------------------------------------------------------------===//
45// ScriptFile
46//===----------------------------------------------------------------------===//
47ScriptFile::ScriptFile(Kind pKind, Input& pInput, InputBuilder& pBuilder)
48  : m_Kind(pKind),
49    m_Input(pInput),
50    m_Name(pInput.path().native()),
51    m_pInputTree(NULL),
52    m_Builder(pBuilder),
53    m_bHasSectionsCmd(false),
54    m_bInSectionsCmd(false),
55    m_bInOutputSectDesc(false),
56    m_pRpnExpr(NULL),
57    m_pStringList(NULL),
58    m_bAsNeeded(false)
59{
60  // FIXME: move creation of input tree out of ScriptFile.
61  m_pInputTree = new InputTree();
62}
63
64ScriptFile::~ScriptFile()
65{
66  for (iterator it = begin(), ie = end(); it != ie; ++it) {
67    if (*it != NULL)
68      delete *it;
69  }
70  if (NULL != m_pInputTree)
71    delete m_pInputTree;
72}
73
74void ScriptFile::dump() const
75{
76  for (const_iterator it = begin(), ie = end(); it != ie; ++it)
77    (*it)->dump();
78}
79
80void ScriptFile::activate(Module& pModule)
81{
82  for (const_iterator it = begin(), ie = end(); it != ie; ++it)
83    (*it)->activate(pModule);
84}
85
86void ScriptFile::addEntryPoint(const std::string& pSymbol)
87{
88  EntryCmd* entry = new EntryCmd(pSymbol);
89
90  if (m_bInSectionsCmd) {
91    assert(!m_CommandQueue.empty());
92    SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
93    sections->push_back(entry);
94  } else {
95    m_CommandQueue.push_back(entry);
96  }
97}
98
99void ScriptFile::addOutputFormatCmd(const std::string& pName)
100{
101  m_CommandQueue.push_back(new OutputFormatCmd(pName));
102}
103
104void ScriptFile::addOutputFormatCmd(const std::string& pDefault,
105                                    const std::string& pBig,
106                                    const std::string& pLittle)
107{
108  m_CommandQueue.push_back(new OutputFormatCmd(pDefault, pBig, pLittle));
109}
110
111void ScriptFile::addGroupCmd(StringList& pStringList,
112                             GroupReader& pGroupReader,
113                             const LinkerConfig& pConfig)
114{
115  m_CommandQueue.push_back(
116    new GroupCmd(pStringList, *m_pInputTree, m_Builder, pGroupReader, pConfig));
117}
118
119void ScriptFile::addOutputCmd(const std::string& pFileName)
120{
121  m_CommandQueue.push_back(new OutputCmd(pFileName));
122}
123
124void ScriptFile::addSearchDirCmd(const std::string& pPath)
125{
126  m_CommandQueue.push_back(new SearchDirCmd(pPath));
127}
128
129void ScriptFile::addOutputArchCmd(const std::string& pArch)
130{
131  m_CommandQueue.push_back(new OutputArchCmd(pArch));
132}
133
134void ScriptFile::addAssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage)
135{
136  m_CommandQueue.push_back(new AssertCmd(pRpnExpr, pMessage));
137}
138
139void ScriptFile::addAssignment(const std::string& pSymbolName,
140                               RpnExpr& pRpnExpr,
141                               Assignment::Type pType)
142{
143  if (m_bInSectionsCmd) {
144    assert(!m_CommandQueue.empty());
145    SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
146    if (m_bInOutputSectDesc) {
147      assert(!sections->empty());
148      OutputSectDesc* output_desc =
149        llvm::cast<OutputSectDesc>(sections->back());
150      output_desc->push_back(new Assignment(Assignment::INPUT_SECTION,
151                                            pType,
152                                            *(SymOperand::create(pSymbolName)),
153                                            pRpnExpr));
154    } else {
155      sections->push_back(new Assignment(Assignment::OUTPUT_SECTION,
156                                         pType,
157                                         *(SymOperand::create(pSymbolName)),
158                                         pRpnExpr));
159    }
160  } else {
161    m_CommandQueue.push_back(new Assignment(Assignment::OUTSIDE_SECTIONS,
162                                            pType,
163                                            *(SymOperand::create(pSymbolName)),
164                                            pRpnExpr));
165  }
166}
167
168bool ScriptFile::hasSectionsCmd() const
169{
170  return m_bHasSectionsCmd;
171}
172
173void ScriptFile::enterSectionsCmd()
174{
175  m_bHasSectionsCmd = true;
176  m_bInSectionsCmd = true;
177  m_CommandQueue.push_back(new SectionsCmd());
178}
179
180void ScriptFile::leaveSectionsCmd()
181{
182  m_bInSectionsCmd = false;
183}
184
185void ScriptFile::enterOutputSectDesc(const std::string& pName,
186                                     const OutputSectDesc::Prolog& pProlog)
187{
188  assert(!m_CommandQueue.empty());
189  assert(m_bInSectionsCmd);
190  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
191  sections->push_back(new OutputSectDesc(pName, pProlog));
192
193  m_bInOutputSectDesc = true;
194}
195
196void ScriptFile::leaveOutputSectDesc(const OutputSectDesc::Epilog& pEpilog)
197{
198  assert(!m_CommandQueue.empty());
199  assert(m_bInSectionsCmd);
200  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
201
202  assert(!sections->empty() && m_bInOutputSectDesc);
203  OutputSectDesc* output_desc = llvm::cast<OutputSectDesc>(sections->back());
204  output_desc->setEpilog(pEpilog);
205
206  m_bInOutputSectDesc = false;
207}
208
209void ScriptFile::addInputSectDesc(InputSectDesc::KeepPolicy pPolicy,
210                                  const InputSectDesc::Spec& pSpec)
211{
212  assert(!m_CommandQueue.empty());
213  assert(m_bInSectionsCmd);
214  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
215
216  assert(!sections->empty() && m_bInOutputSectDesc);
217  OutputSectDesc* output_sect = llvm::cast<OutputSectDesc>(sections->back());
218
219  output_sect->push_back(new InputSectDesc(pPolicy, pSpec, *output_sect));
220}
221
222RpnExpr* ScriptFile::createRpnExpr()
223{
224  m_pRpnExpr = RpnExpr::create();
225  return m_pRpnExpr;
226}
227
228StringList* ScriptFile::createStringList()
229{
230  m_pStringList = StringList::create();
231  return m_pStringList;
232}
233
234void ScriptFile::setAsNeeded(bool pEnable)
235{
236  m_bAsNeeded = pEnable;
237}
238
239const std::string& ScriptFile::createParserStr(const char* pText,
240                                               size_t pLength)
241{
242  bool exist = false;
243  ParserStrEntry* entry =
244    g_ParserStrPool->insert(std::string(pText, pLength), exist);
245  return entry->key();
246}
247
248void ScriptFile::clearParserStrPool()
249{
250  g_ParserStrPool->clear();
251}
252
253