1//===- TestLinker.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 "TestLinker.h"
10
11#include <iostream>
12
13#include <llvm/Support/TargetSelect.h>
14
15#include <mcld/LD/TextDiagnosticPrinter.h>
16#include <mcld/MC/InputTree.h>
17#include <mcld/MC/MCLDDirectory.h>
18#include <mcld/Target/TargetLDBackend.h>
19#include <mcld/Support/RegionFactory.h>
20#include <mcld/Support/TargetSelect.h>
21#include <mcld/Support/MsgHandling.h>
22#include <mcld/Support/raw_ostream.h>
23#include <mcld/Support/SystemUtils.h>
24#include <mcld/Support/MemoryAreaFactory.h>
25
26using namespace std;
27using namespace mcld;
28using namespace mcld::sys::fs;
29using namespace mcld::test;
30
31//===----------------------------------------------------------------------===//
32// TestLinker
33//===----------------------------------------------------------------------===//
34TestLinker::TestLinker()
35  : m_pTarget(NULL), m_pDriver(NULL), m_pInfo(NULL), m_pDiagLineInfo(NULL),
36    m_pDiagPrinter(NULL), m_pBackend(NULL), m_pRegionFactory(NULL),
37    m_pMemAreaFactory(NULL) {
38}
39
40TestLinker::~TestLinker()
41{
42  std::list<mcld::FileHandle*>::iterator file, fEnd = m_FileHandleList.end();
43  for (file = m_FileHandleList.begin(); file != fEnd; ++file)
44    delete (*file);
45
46  std::list<mcld::MemoryArea*>::iterator mem, mEnd = m_MemAreaList.end() ;
47  for (mem = m_MemAreaList.begin(); mem != mEnd; ++mem)
48    delete (*mem);
49
50  delete m_pDriver;
51  delete m_pInfo;
52  delete m_pDiagLineInfo;
53  delete m_pDiagPrinter;
54  delete m_pBackend;
55  delete m_pRegionFactory;
56  delete m_pMemAreaFactory;
57}
58
59bool TestLinker::initialize(const std::string &pTriple)
60{
61  bool is_initialized = false;
62
63  if (is_initialized)
64    return false;
65
66  // initilaize all llvm::Target and mcld::Target
67  llvm::InitializeAllTargets();
68  llvm::InitializeAllAsmPrinters();
69  llvm::InitializeAllAsmParsers();
70  llvm::InitializeAllTargetMCs();
71  mcld::InitializeAllTargets();
72  mcld::InitializeAllDiagnostics();
73
74  // create mcld::MCLDInfo
75  m_pInfo = new MCLDInfo(pTriple, 1, 32);
76  m_Root = m_pInfo->inputs().root();
77
78  // create mcld::RegionFactory
79  m_pRegionFactory = new mcld::RegionFactory(32);
80
81  // specify mcld::Target
82  std::string error;
83  m_pTarget = mcld::TargetRegistry::lookupTarget(pTriple, error);
84  if (NULL == m_pTarget) {
85    fatal(diag::fatal_cannot_init_target) << pTriple << error;
86    return false;
87  }
88
89  // create mcld::DiagnosticEngine
90  m_pDiagLineInfo = m_pTarget->createDiagnosticLineInfo(*m_pTarget, pTriple);
91  if (NULL == m_pDiagLineInfo) {
92    fatal(diag::fatal_cannot_init_lineinfo) << pTriple;
93    return false;
94  }
95
96  m_pDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *m_pInfo);
97
98  mcld::InitializeDiagnosticEngine(*m_pInfo, m_pDiagLineInfo, m_pDiagPrinter);
99
100  // create mcld::TargetLDBackend
101  m_pBackend = m_pTarget->createLDBackend(pTriple);
102  if (NULL == m_pBackend) {
103    fatal(diag::fatal_cannot_init_backend) << pTriple;
104    return false;
105  }
106
107  m_pMemAreaFactory = new MemoryAreaFactory(32);
108
109  m_pDriver = new mcld::MCLDDriver(*m_pInfo, *m_pBackend, *m_pMemAreaFactory);
110  m_pDriver->initMCLinker();
111
112  is_initialized = true;
113  return true;
114}
115
116void TestLinker::addSearchDir(const std::string &pDirPath)
117{
118  assert(NULL != m_pInfo && "initialize() must be called before addSearchDir");
119  assert(!m_pInfo->options().sysroot().empty() &&
120         "must setSysRoot before addSearchDir");
121
122  mcld::MCLDDirectory* sd = new mcld::MCLDDirectory(pDirPath);
123
124  if (sd->isInSysroot()) {
125    sd->setSysroot(m_pInfo->options().sysroot());
126  }
127
128  if (exists(sd->path()) && is_directory(sd->path())) {
129    m_pInfo->options().directories().add(*sd);
130  } else {
131    mcld::warning(mcld::diag::warn_cannot_open_search_dir) << sd->name();
132  }
133}
134
135void TestLinker::setSysRoot(const mcld::sys::fs::Path &pPath)
136{
137  assert(NULL != m_pInfo && "initialize() must be called before setSysRoot");
138  m_pInfo->options().setSysroot(pPath);
139}
140
141void TestLinker::addObject(const std::string &pPath)
142{
143  mcld::Input* input = m_pInfo->inputFactory().produce(pPath, pPath,
144                                                       mcld::Input::Unknown);
145
146  m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
147
148  advanceRoot();
149
150  mcld::FileHandle* handler = new mcld::FileHandle();
151  m_FileHandleList.push_back(handler);
152  if (!handler->open(pPath, mcld::FileHandle::ReadOnly)) {
153    mcld::error(mcld::diag::err_cannot_open_file)
154                                      << pPath
155                                      << mcld::sys::strerror(handler->error());
156  }
157
158  mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *handler);
159  input->setMemArea(input_memory);
160  m_MemAreaList.push_back(input_memory);
161
162  mcld::LDContext* context = m_pInfo->contextFactory().produce(pPath);
163  input->setContext(context);
164}
165
166void TestLinker::addObject(void* pMemBuffer, size_t pSize)
167{
168  mcld::Input* input = m_pInfo->inputFactory().produce("memory object", "NAN",
169                                                       mcld::Input::Unknown);
170
171  m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
172
173  advanceRoot();
174
175  mcld::Space* space = new mcld::Space(mcld::Space::EXTERNAL, pMemBuffer, pSize);
176  mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *space);
177  input->setMemArea(input_memory);
178  m_MemAreaList.push_back(input_memory);
179
180  mcld::LDContext* context = m_pInfo->contextFactory().produce();
181  input->setContext(context);
182}
183
184void TestLinker::addObject(int pFileHandler)
185{
186  mcld::Input* input = m_pInfo->inputFactory().produce("handler object", "NAN",
187                                                       mcld::Input::Unknown);
188
189  m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
190
191  advanceRoot();
192
193  mcld::FileHandle* handler = new mcld::FileHandle();
194  m_FileHandleList.push_back(handler);
195  handler->delegate(pFileHandler);
196
197  mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *handler);
198  input->setMemArea(input_memory);
199  m_MemAreaList.push_back(input_memory);
200
201  mcld::LDContext* context = m_pInfo->contextFactory().produce();
202  input->setContext(context);
203}
204
205void TestLinker::addNameSpec(const std::string &pNameSpec)
206{
207  mcld::sys::fs::Path* path = NULL;
208  // find out the real path of the namespec.
209  if (m_pInfo->attrFactory().constraint().isSharedSystem()) {
210    // In the system with shared object support, we can find both archive
211    // and shared object.
212
213    if (m_pInfo->attrFactory().last().isStatic()) {
214      // with --static, we must search an archive.
215      path = m_pInfo->options().directories().find(pNameSpec,
216                                                   mcld::Input::Archive);
217    }
218    else {
219      // otherwise, with --Bdynamic, we can find either an archive or a
220      // shared object.
221      path = m_pInfo->options().directories().find(pNameSpec,
222                                                   mcld::Input::DynObj);
223    }
224  }
225  else {
226    // In the system without shared object support, we only look for an
227    // archive.
228    path = m_pInfo->options().directories().find(pNameSpec,
229                                                 mcld::Input::Archive);
230  }
231
232  if (NULL == path) {
233    mcld::fatal(diag::err_cannot_find_namespec) << pNameSpec;
234    return;
235  }
236
237  mcld::Input* input = m_pInfo->inputFactory().produce(pNameSpec, *path,
238                                                       mcld::Input::Unknown);
239
240  m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
241
242  advanceRoot();
243
244  mcld::FileHandle* handler = new mcld::FileHandle();
245  m_FileHandleList.push_back(handler);
246  if (!handler->open(*path, mcld::FileHandle::ReadOnly)) {
247    mcld::error(mcld::diag::err_cannot_open_file)
248                                      << *path
249                                      << mcld::sys::strerror(handler->error());
250  }
251
252  mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *handler);
253  input->setMemArea(input_memory);
254  m_MemAreaList.push_back(input_memory);
255
256  mcld::LDContext* context = m_pInfo->contextFactory().produce(*path);
257  input->setContext(context);
258}
259
260bool TestLinker::setOutput(const std::string &pPath)
261{
262  if (m_pInfo->output().hasContext())
263    return false;
264
265  mcld::FileHandle* handler = new mcld::FileHandle();
266  m_FileHandleList.push_back(handler);
267  bool open_res = handler->open(pPath, mcld::FileHandle::ReadWrite |
268                                       mcld::FileHandle::Truncate |
269                                       mcld::FileHandle::Create,
270                                mcld::FileHandle::Permission(0755));
271  if (!open_res) {
272    mcld::error(mcld::diag::err_cannot_open_file)
273                                      << pPath
274                                      << mcld::sys::strerror(handler->error());
275  }
276
277  mcld::MemoryArea* output_memory = new MemoryArea(*m_pRegionFactory, *handler);
278  m_pInfo->output().setMemArea(output_memory);
279  m_MemAreaList.push_back(output_memory);
280
281  mcld::LDContext* context = m_pInfo->contextFactory().produce(pPath);
282  m_pInfo->output().setContext(context);
283
284  // FIXME: remove the initStdSections().
285  m_pDriver->initStdSections();
286  return true;
287}
288
289bool TestLinker::setOutput(const sys::fs::Path &pPath)
290{
291  return setOutput(pPath.native());
292}
293
294bool TestLinker::setOutput(int pFileHandler)
295{
296  if (m_pInfo->output().hasContext())
297    return false;
298
299  mcld::FileHandle* handler = new mcld::FileHandle();
300  handler->delegate(pFileHandler);
301  m_FileHandleList.push_back(handler);
302
303  mcld::MemoryArea* output_memory = new MemoryArea(*m_pRegionFactory, *handler);
304  m_pInfo->output().setMemArea(output_memory);
305  m_MemAreaList.push_back(output_memory);
306
307  mcld::LDContext* context = m_pInfo->contextFactory().produce();
308  m_pInfo->output().setContext(context);
309
310  // FIXME: remove the initStdSections().
311  m_pDriver->initStdSections();
312  return true;
313}
314
315void TestLinker::advanceRoot()
316{
317    if (m_Root.isRoot())
318      --m_Root;
319    else
320      ++m_Root;
321}
322