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
26 using namespace std;
27 using namespace mcld;
28 using namespace mcld::sys::fs;
29 using namespace mcld::test;
30
31 //===----------------------------------------------------------------------===//
32 // TestLinker
33 //===----------------------------------------------------------------------===//
TestLinker()34 TestLinker::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
~TestLinker()40 TestLinker::~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
initialize(const std::string & pTriple)59 bool 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
addSearchDir(const std::string & pDirPath)116 void 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
setSysRoot(const mcld::sys::fs::Path & pPath)135 void 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
addObject(const std::string & pPath)141 void 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
addObject(void * pMemBuffer,size_t pSize)166 void 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
addObject(int pFileHandler)184 void 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
addNameSpec(const std::string & pNameSpec)205 void 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
setOutput(const std::string & pPath)260 bool 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
setOutput(const sys::fs::Path & pPath)289 bool TestLinker::setOutput(const sys::fs::Path &pPath)
290 {
291 return setOutput(pPath.native());
292 }
293
setOutput(int pFileHandler)294 bool 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
advanceRoot()315 void TestLinker::advanceRoot()
316 {
317 if (m_Root.isRoot())
318 --m_Root;
319 else
320 ++m_Root;
321 }
322