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