blob: d1ead28d028096f630ab0b6631d66518b6ba9b2b [file] [log] [blame]
//===- TestLinker.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "TestLinker.h"
#include <llvm/Support/TargetSelect.h>
#include <mcld/Environment.h>
#include <mcld/InputTree.h>
#include <mcld/LD/TextDiagnosticPrinter.h>
#include <mcld/MC/InputBuilder.h>
#include <mcld/MC/InputFactory.h>
#include <mcld/MC/MCLDDirectory.h>
#include <mcld/Target/TargetLDBackend.h>
#include <mcld/Support/Space.h>
#include <mcld/Support/TargetSelect.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/raw_ostream.h>
#include <mcld/Support/SystemUtils.h>
#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/MC/ContextFactory.h>
using namespace mcld;
using namespace mcld::sys::fs;
using namespace mcld::test;
//===----------------------------------------------------------------------===//
// TestLinker
//===----------------------------------------------------------------------===//
TestLinker::TestLinker()
: m_pTarget(NULL), m_pObjLinker(NULL), m_pConfig(NULL), m_pDiagLineInfo(NULL),
m_pDiagPrinter(NULL), m_pBackend(NULL), m_pBuilder(NULL), m_pOutput(NULL) {
}
TestLinker::~TestLinker()
{
std::list<mcld::FileHandle*>::iterator file, fEnd = m_FileHandleList.end();
for (file = m_FileHandleList.begin(); file != fEnd; ++file)
delete (*file);
std::list<mcld::MemoryArea*>::iterator mem, mEnd = m_MemAreaList.end() ;
for (mem = m_MemAreaList.begin(); mem != mEnd; ++mem)
delete (*mem);
delete m_pObjLinker;
delete m_pConfig;
delete m_pDiagLineInfo;
delete m_pDiagPrinter;
delete m_pBackend;
delete m_pBuilder;
delete m_pOutput;
}
bool TestLinker::initialize(const std::string &pTriple)
{
// initilaize all llvm::Target and mcld::Target
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllTargetMCs();
mcld::Initialize();
// create mcld::LinkerConfig
m_pConfig = new LinkerConfig(pTriple);
m_Root = m_Module.getInputTree().root();
// specify mcld::Target
std::string error;
m_pTarget = mcld::TargetRegistry::lookupTarget(pTriple, error);
if (NULL == m_pTarget) {
fatal(diag::fatal_cannot_init_target) << pTriple << error;
return false;
}
// create mcld::DiagnosticLineInfo
m_pDiagLineInfo = m_pTarget->createDiagnosticLineInfo(*m_pTarget, pTriple);
if (NULL == m_pDiagLineInfo) {
fatal(diag::fatal_cannot_init_lineinfo) << pTriple;
return false;
}
mcld::getDiagnosticEngine().setLineInfo(*m_pDiagLineInfo);
// create mcld::TargetLDBackend
m_pBackend = m_pTarget->createLDBackend(*m_pConfig);
if (NULL == m_pBackend) {
fatal(diag::fatal_cannot_init_backend) << pTriple;
return false;
}
m_pInputFactory = new mcld::InputFactory(10, *m_pConfig);
m_pContextFactory = new mcld::ContextFactory(10);
m_pMemAreaFactory = new mcld::MemoryAreaFactory(10);
m_pBuilder = new mcld::InputBuilder(*m_pConfig,
*m_pInputFactory,
*m_pContextFactory,
*m_pMemAreaFactory,
true);
m_pObjLinker = new mcld::ObjectLinker(*m_pConfig, m_Module, *m_pBuilder, *m_pBackend);
m_pObjLinker->initFragmentLinker();
return true;
}
void TestLinker::addSearchDir(const std::string &pDirPath)
{
assert(NULL != m_pConfig && "initialize() must be called before addSearchDir");
assert(!m_pConfig->options().sysroot().empty() &&
"must setSysRoot before addSearchDir");
if (!m_pConfig->options().directories().insert(pDirPath)) {
mcld::warning(mcld::diag::warn_cannot_open_search_dir) << pDirPath;
}
}
void TestLinker::setSysRoot(const mcld::sys::fs::Path &pPath)
{
assert(NULL != m_pConfig && "initialize() must be called before setSysRoot");
m_pConfig->options().setSysroot(pPath);
}
void TestLinker::addObject(const std::string &pPath)
{
mcld::Input* input = m_pInputFactory->produce(pPath, pPath,
mcld::Input::Unknown);
m_Module.getInputTree().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
if (!handler->open(pPath, mcld::FileHandle::ReadOnly)) {
mcld::error(mcld::diag::err_cannot_open_file)
<< pPath
<< mcld::sys::strerror(handler->error());
}
mcld::MemoryArea* input_memory = new MemoryArea(*handler);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
m_pBuilder->setContext(*input);
}
void TestLinker::addObject(void* pMemBuffer, size_t pSize)
{
mcld::Input* input = m_pInputFactory->produce("memory object", "NAN",
mcld::Input::Unknown);
m_Module.getInputTree().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::Space* space = Space::Create(pMemBuffer, pSize);
mcld::MemoryArea* input_memory = new MemoryArea(*space);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
mcld::LDContext* context = m_pContextFactory->produce();
input->setContext(context);
}
void TestLinker::addObject(int pFileHandler)
{
mcld::Input* input = m_pInputFactory->produce("handler object", "NAN",
mcld::Input::Unknown);
m_Module.getInputTree().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
handler->delegate(pFileHandler);
mcld::MemoryArea* input_memory = new MemoryArea(*handler);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
mcld::LDContext* context = m_pContextFactory->produce();
input->setContext(context);
}
void TestLinker::addNameSpec(const std::string &pNameSpec)
{
mcld::sys::fs::Path* path = NULL;
// find out the real path of the namespec.
if (m_pConfig->attribute().constraint().isSharedSystem()) {
// In the system with shared object support, we can find both archive
// and shared object.
if (m_pInputFactory->attr().isStatic()) {
// with --static, we must search an archive.
path = m_pConfig->options().directories().find(pNameSpec,
mcld::Input::Archive);
}
else {
// otherwise, with --Bdynamic, we can find either an archive or a
// shared object.
path = m_pConfig->options().directories().find(pNameSpec,
mcld::Input::DynObj);
}
}
else {
// In the system without shared object support, we only look for an
// archive.
path = m_pConfig->options().directories().find(pNameSpec,
mcld::Input::Archive);
}
if (NULL == path) {
mcld::fatal(diag::err_cannot_find_namespec) << pNameSpec;
return;
}
mcld::Input* input = m_pInputFactory->produce(pNameSpec, *path,
mcld::Input::Unknown);
m_Module.getInputTree().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
if (!handler->open(*path, mcld::FileHandle::ReadOnly)) {
mcld::error(mcld::diag::err_cannot_open_file)
<< *path
<< mcld::sys::strerror(handler->error());
}
mcld::MemoryArea* input_memory = new MemoryArea(*handler);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
m_pBuilder->setContext(*input);
}
bool TestLinker::setOutput(const std::string &pPath)
{
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
bool open_res = handler->open(pPath, mcld::FileHandle::ReadWrite |
mcld::FileHandle::Truncate |
mcld::FileHandle::Create,
mcld::FileHandle::Permission(0755));
if (!open_res) {
mcld::error(mcld::diag::err_cannot_open_file)
<< pPath
<< mcld::sys::strerror(handler->error());
}
m_pOutput = new MemoryArea(*handler);
// FIXME: remove the initStdSections().
m_pObjLinker->initStdSections();
return true;
}
bool TestLinker::setOutput(const sys::fs::Path &pPath)
{
return setOutput(pPath.native());
}
bool TestLinker::setOutput(int pFileHandler)
{
mcld::FileHandle* handler = new mcld::FileHandle();
handler->delegate(pFileHandler);
m_FileHandleList.push_back(handler);
m_pOutput = new MemoryArea(*handler);
// FIXME: remove the initStdSections().
m_pObjLinker->initStdSections();
return true;
}
void TestLinker::advanceRoot()
{
if (m_Root.isRoot())
--m_Root;
else
++m_Root;
}