upload android base code part1

This commit is contained in:
August 2018-08-08 15:50:00 +08:00
parent e02f198e2d
commit 0a1de6c4b3
48159 changed files with 9071466 additions and 0 deletions

View file

@ -0,0 +1,22 @@
cc_library_static {
name: "libmcldSupport",
defaults: ["mcld-defaults"],
host_supported: true,
srcs: [
"Demangle.cpp",
"Directory.cpp",
"FileHandle.cpp",
"FileOutputBuffer.cpp",
"FileSystem.cpp",
"LEB128.cpp",
"MemoryArea.cpp",
"MemoryAreaFactory.cpp",
"MsgHandling.cpp",
"Path.cpp",
"raw_ostream.cpp",
"RealPath.cpp",
"SystemUtils.cpp",
"Target.cpp",
"TargetRegistry.cpp",
],
}

View file

@ -0,0 +1,73 @@
//===- Demangle.cpp -------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Config/Config.h"
#include "mcld/Support/CXADemangle.tcc"
#include "mcld/Support/Demangle.h"
#ifdef HAVE_CXXABI_H
#include <cxxabi.h>
#endif
namespace mcld {
std::string demangleName(const std::string& pName) {
#ifdef HAVE_CXXABI_H
// Spoil names of symbols with C linkage, so use an heuristic approach to
// check if the name should be demangled.
if (pName.substr(0, 2) != "_Z")
return pName;
// __cxa_demangle needs manually handle the memory release, so we wrap
// it into this helper function.
size_t output_leng;
int status;
char* buffer =
abi::__cxa_demangle(pName.c_str(), /*buffer=*/0, &output_leng, &status);
if (status != 0) { // Failed
return pName;
}
std::string result(buffer);
free(buffer);
return result;
#else
return pName;
#endif
}
bool isCtorOrDtor(const char* pName, size_t pLength) {
arena<bs> a;
Db db(a);
db.cv = 0;
db.ref = 0;
db.encoding_depth = 0;
db.parsed_ctor_dtor_cv = false;
db.tag_templates = true;
db.template_param.emplace_back(a);
db.fix_forward_references = false;
db.try_to_parse_template_args = true;
int internal_status = success;
demangle(pName, pName + pLength, db, internal_status);
if (internal_status == success && db.fix_forward_references &&
!db.template_param.empty() && !db.template_param.front().empty()) {
db.fix_forward_references = false;
db.tag_templates = false;
db.names.clear();
db.subs.clear();
demangle(pName, pName + pLength, db, internal_status);
if (db.fix_forward_references)
internal_status = invalid_mangled_name;
}
if (internal_status != success) {
db.parsed_ctor_dtor_cv = false;
}
return db.parsed_ctor_dtor_cv;
}
} // namespace mcld

View file

@ -0,0 +1,238 @@
//===- Directory.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/Directory.h"
#include "mcld/Support/FileSystem.h"
namespace mcld {
namespace sys {
namespace fs {
namespace { // anonymous
bool status_known(FileStatus f) {
return f.type() != StatusError;
}
bool is_symlink(FileStatus f) {
return f.type() == SymlinkFile;
}
const Path dot_path(".");
const Path dot_dot_path("..");
} // anonymous namespace
//===----------------------------------------------------------------------===//
// Directory
//===----------------------------------------------------------------------===//
Directory::Directory()
: m_Path(),
m_FileStatus(),
m_SymLinkStatus(),
m_Handler(0),
m_Cache(),
m_CacheFull(false) {
}
Directory::Directory(const Path& pPath, FileStatus st, FileStatus symlink_st)
: m_Path(pPath),
m_FileStatus(st),
m_SymLinkStatus(symlink_st),
m_Handler(0),
m_Cache(),
m_CacheFull(false) {
if (m_Path == dot_path)
detail::get_pwd(m_Path);
m_Path.m_append_separator_if_needed();
detail::open_dir(*this);
}
Directory::Directory(const char* pPath, FileStatus st, FileStatus symlink_st)
: Directory(sys::fs::Path(pPath), st, symlink_st) {
}
Directory::Directory(const Directory& pCopy)
: m_Path(pCopy.m_Path),
m_FileStatus(pCopy.m_FileStatus),
m_SymLinkStatus(pCopy.m_SymLinkStatus),
m_Handler(0),
m_Cache(),
m_CacheFull(false) {
detail::open_dir(*this);
}
Directory::~Directory() {
detail::close_dir(*this);
}
bool Directory::isGood() const {
return (0 != m_Handler);
}
Directory& Directory::operator=(const Directory& pCopy) {
assign(pCopy.m_Path, pCopy.m_FileStatus, pCopy.m_SymLinkStatus);
return *this;
}
void Directory::assign(const Path& pPath,
FileStatus st,
FileStatus symlink_st) {
if (isGood())
clear();
m_Path = pPath;
if (m_Path == dot_path)
detail::get_pwd(m_Path);
m_Path.m_append_separator_if_needed();
m_FileStatus = st;
m_SymLinkStatus = symlink_st;
detail::open_dir(*this);
}
FileStatus Directory::status() const {
if (!status_known(m_FileStatus)) {
// optimization: if the symlink status is known, and it isn't a symlink,
// then status and symlink_status are identical so just copy the
// symlink status to the regular status.
if (status_known(m_SymLinkStatus) && !is_symlink(m_SymLinkStatus)) {
m_FileStatus = m_SymLinkStatus;
} else
detail::status(m_Path, m_FileStatus);
}
return m_FileStatus;
}
FileStatus Directory::symlinkStatus() const {
if (!status_known(m_SymLinkStatus))
detail::symlink_status(m_Path, m_SymLinkStatus);
return m_SymLinkStatus;
}
Directory::iterator Directory::begin() {
if (m_CacheFull && m_Cache.empty())
return end();
PathCache::iterator iter = m_Cache.begin();
if (iter.getEntry() == NULL)
++iter;
return iterator(this, iter);
}
Directory::iterator Directory::end() {
return iterator(0, m_Cache.end());
}
void Directory::clear() {
m_Path.native().clear();
m_FileStatus = FileStatus();
m_SymLinkStatus = FileStatus();
m_Cache.clear();
detail::close_dir(*this);
}
//==========================
// DirIterator
DirIterator::DirIterator(Directory* pParent,
const DirIterator::DirCache::iterator& pIter)
: m_pParent(pParent), m_Iter(pIter) {
m_pEntry = m_Iter.getEntry();
}
DirIterator::DirIterator(const DirIterator& pCopy)
: m_pParent(pCopy.m_pParent),
m_Iter(pCopy.m_Iter),
m_pEntry(pCopy.m_pEntry) {
}
DirIterator::~DirIterator() {
}
Path* DirIterator::path() {
if (m_pParent == NULL)
return NULL;
return &m_pEntry->value();
}
const Path* DirIterator::path() const {
if (m_pParent == NULL)
return NULL;
return &m_pEntry->value();
}
DirIterator& DirIterator::operator=(const DirIterator& pCopy) {
m_pParent = pCopy.m_pParent;
m_Iter = pCopy.m_Iter;
m_pEntry = pCopy.m_pEntry;
return (*this);
}
DirIterator& DirIterator::operator++() {
if (m_pParent == 0)
return *this;
// move forward one step first.
++m_Iter;
if (m_pParent->m_Cache.end() == m_Iter) {
if (!m_pParent->m_CacheFull) {
m_pEntry = detail::bring_one_into_cache(*this);
if (m_pEntry == 0 && m_pParent->m_CacheFull)
m_pParent = 0;
return *this;
}
m_pParent = 0;
return *this;
}
m_pEntry = m_Iter.getEntry();
return *this;
}
DirIterator DirIterator::operator++(int pIn) {
DirIterator tmp(*this);
// move forward one step first.
++m_Iter;
if (m_pParent->m_Cache.end() == m_Iter) {
if (!m_pParent->m_CacheFull) {
m_pEntry = detail::bring_one_into_cache(*this);
if (m_pEntry == 0 && m_pParent->m_CacheFull)
m_pParent = 0;
return tmp;
}
m_pParent = 0;
return tmp;
}
m_pEntry = m_Iter.getEntry();
return tmp;
}
bool DirIterator::operator==(const DirIterator& y) const {
if (m_pParent != y.m_pParent)
return false;
if (m_pParent == 0)
return true;
const Path* x_path = path();
const Path* y_path = y.path();
if (x_path == 0 && y_path == 0)
return true;
if (x_path == 0 || y_path == 0)
return false;
return (*x_path == *y_path);
}
bool DirIterator::operator!=(const DirIterator& y) const {
return !this->operator==(y);
}
} // namespace fs
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,247 @@
//===- FileHandle.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Config/Config.h"
#include "mcld/Support/FileHandle.h"
#include "mcld/Support/FileSystem.h"
#include <errno.h>
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#if defined(HAVE_FCNTL_H)
#include <fcntl.h>
#endif
#include <sys/stat.h>
namespace mcld {
//===----------------------------------------------------------------------===//
// FileHandle
//===----------------------------------------------------------------------===//
FileHandle::FileHandle()
: m_Path(),
m_Handler(-1),
m_Size(0),
m_State(GoodBit),
m_OpenMode(NotOpen) {
}
FileHandle::~FileHandle() {
if (isOpened())
close();
}
inline static int oflag(FileHandle::OpenMode pMode) {
int result = 0x0;
if (FileHandle::Unknown == pMode)
return result;
if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
result |= O_RDWR;
else if (FileHandle::ReadOnly == (pMode & FileHandle::ReadOnly))
result |= O_RDONLY;
else if (FileHandle::WriteOnly == (pMode & FileHandle::WriteOnly))
result |= O_WRONLY;
if (FileHandle::Append == (pMode & FileHandle::Append))
result |= O_APPEND;
if (FileHandle::Create == (pMode & FileHandle::Create))
result |= O_CREAT;
if (FileHandle::Truncate == (pMode & FileHandle::Truncate))
result |= O_TRUNC;
return result;
}
inline static bool get_size(int pHandler, unsigned int& pSize) {
struct ::stat file_stat;
if (-1 == ::fstat(pHandler, &file_stat)) {
pSize = 0;
return false;
}
pSize = file_stat.st_size;
return true;
}
bool FileHandle::open(const sys::fs::Path& pPath,
FileHandle::OpenMode pMode,
FileHandle::Permission pPerm) {
if (isOpened() || Unknown == pMode) {
setState(BadBit);
return false;
}
m_OpenMode = pMode;
if (System == pPerm)
m_Handler = sys::fs::detail::open(pPath, oflag(pMode));
else
m_Handler = sys::fs::detail::open(pPath, oflag(pMode),
static_cast<int>(pPerm));
m_Path = pPath;
if (m_Handler == -1) {
m_OpenMode = OpenMode(NotOpen);
setState(FailBit);
return false;
}
if (!get_size(m_Handler, m_Size)) {
setState(FailBit);
return false;
}
return true;
}
bool FileHandle::delegate(int pFD, FileHandle::OpenModeEnum pMode) {
if (isOpened()) {
setState(BadBit);
return false;
}
m_Handler = pFD;
m_OpenMode = OpenMode(pMode);
m_State = (GoodBit | DeputedBit);
if (!get_size(m_Handler, m_Size)) {
setState(FailBit);
return false;
}
return true;
}
bool FileHandle::close() {
if (!isOpened()) {
setState(BadBit);
return false;
}
if (isOwned()) {
if (::close(m_Handler) == -1) {
setState(FailBit);
return false;
}
}
m_Path.native().clear();
m_Size = 0;
m_OpenMode = OpenMode(NotOpen);
cleanState();
return true;
}
bool FileHandle::truncate(size_t pSize) {
if (!isOpened() || !isWritable()) {
setState(BadBit);
return false;
}
if (sys::fs::detail::ftruncate(m_Handler, pSize) == -1) {
setState(FailBit);
return false;
}
m_Size = pSize;
return true;
}
bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength) {
if (!isOpened() || !isReadable()) {
setState(BadBit);
return false;
}
if (pLength == 0)
return true;
ssize_t read_bytes =
sys::fs::detail::pread(m_Handler, pMemBuffer, pLength, pStartOffset);
if (read_bytes == -1) {
setState(FailBit);
return false;
}
return true;
}
bool FileHandle::write(const void* pMemBuffer,
size_t pStartOffset,
size_t pLength) {
if (!isOpened() || !isWritable()) {
setState(BadBit);
return false;
}
if (pLength == 0)
return true;
ssize_t write_bytes =
sys::fs::detail::pwrite(m_Handler, pMemBuffer, pLength, pStartOffset);
if (write_bytes == -1) {
setState(FailBit);
return false;
}
return true;
}
void FileHandle::setState(FileHandle::IOState pState) {
m_State |= pState;
}
void FileHandle::cleanState(FileHandle::IOState pState) {
m_State = pState;
}
bool FileHandle::isOpened() const {
if (m_Handler != -1 && m_OpenMode != NotOpen && isGood())
return true;
return false;
}
// Assume Unknown OpenMode is readable
bool FileHandle::isReadable() const {
return (m_OpenMode & ReadOnly);
}
// Assume Unknown OpenMode is writable
bool FileHandle::isWritable() const {
return (m_OpenMode & WriteOnly);
}
// Assume Unknown OpenMode is both readable and writable
bool FileHandle::isReadWrite() const {
return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
}
bool FileHandle::isGood() const {
return !(m_State & (BadBit | FailBit));
}
bool FileHandle::isBad() const {
return (m_State & BadBit);
}
bool FileHandle::isFailed() const {
return (m_State & (BadBit | FailBit));
}
bool FileHandle::isOwned() const {
return !(m_State & DeputedBit);
}
} // namespace mcld

View file

@ -0,0 +1,59 @@
//===- FileOutputBuffer.cpp -----------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/FileOutputBuffer.h"
#include "mcld/Support/FileHandle.h"
#include "mcld/Support/Path.h"
namespace mcld {
FileOutputBuffer::FileOutputBuffer(llvm::sys::fs::mapped_file_region* pRegion,
FileHandle& pFileHandle)
: m_pRegion(pRegion), m_FileHandle(pFileHandle) {
}
FileOutputBuffer::~FileOutputBuffer() {
// Unmap buffer, letting OS flush dirty pages to file on disk.
m_pRegion.reset();
}
std::error_code
FileOutputBuffer::create(FileHandle& pFileHandle,
size_t pSize,
std::unique_ptr<FileOutputBuffer>& pResult) {
std::error_code ec;
// Resize the file before mapping the file region.
ec = llvm::sys::fs::resize_file(pFileHandle.handler(), pSize);
if (ec)
return ec;
std::unique_ptr<llvm::sys::fs::mapped_file_region> mapped_file(
new llvm::sys::fs::mapped_file_region(pFileHandle.handler(),
llvm::sys::fs::mapped_file_region::readwrite, pSize, 0, ec));
if (ec)
return ec;
pResult.reset(new FileOutputBuffer(mapped_file.get(), pFileHandle));
if (pResult)
mapped_file.release();
return std::error_code();
}
MemoryRegion FileOutputBuffer::request(size_t pOffset, size_t pLength) {
if (pOffset > getBufferSize() || (pOffset + pLength) > getBufferSize())
return MemoryRegion();
return MemoryRegion(getBufferStart() + pOffset, pLength);
}
llvm::StringRef FileOutputBuffer::getPath() const {
return m_FileHandle.path().native();
}
} // namespace mcld

View file

@ -0,0 +1,37 @@
//===- FileSystem.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Config/Config.h"
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
//===----------------------------------------------------------------------===//
// non-member functions
//===----------------------------------------------------------------------===//
bool mcld::sys::fs::exists(const Path& pPath) {
mcld::sys::fs::FileStatus file_status;
mcld::sys::fs::detail::status(pPath, file_status);
return (file_status.type() != mcld::sys::fs::StatusError) &&
(file_status.type() != mcld::sys::fs::FileNotFound);
}
bool mcld::sys::fs::is_directory(const Path& pPath) {
FileStatus file_status;
detail::status(pPath, file_status);
return (file_status.type() == mcld::sys::fs::DirectoryFile);
}
// Include the truly platform-specific parts.
#if defined(MCLD_ON_UNIX)
#include "Unix/FileSystem.inc"
#include "Unix/PathV3.inc"
#endif
#if defined(MCLD_ON_WIN32)
#include "Windows/FileSystem.inc"
#include "Windows/PathV3.inc"
#endif

View file

@ -0,0 +1,224 @@
//===- LEB128.cpp ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/LEB128.h"
namespace mcld {
namespace leb128 {
//===---------------------- LEB128 Encoding APIs -------------------------===//
template <>
size_t encode<uint64_t>(ByteType*& pBuf, uint64_t pValue) {
size_t size = 0;
do {
ByteType byte = pValue & 0x7f;
pValue >>= 7;
if (pValue)
byte |= 0x80;
*pBuf++ = byte;
size++;
} while (pValue);
return size;
}
/*
* Fast version for encoding 32-bit integer. This unrolls the loop in the
* generic version defined above.
*/
template <>
size_t encode<uint32_t>(ByteType*& pBuf, uint32_t pValue) {
if ((pValue & ~0x7f) == 0) {
*pBuf++ = static_cast<ByteType>(pValue);
return 1;
} else if ((pValue & ~0x3fff) == 0) {
*pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>((pValue >> 7) & 0x7f);
return 2;
} else if ((pValue & ~0x1fffff) == 0) {
*pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>((pValue >> 14) & 0x7f);
return 3;
} else if ((pValue & ~0xfffffff) == 0) {
*pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>(((pValue >> 14) & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>((pValue >> 21) & 0x7f);
return 4;
} else {
*pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>(((pValue >> 14) & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>(((pValue >> 21) & 0x7f) | 0x80);
*pBuf++ = static_cast<ByteType>((pValue >> 28) & 0x7f);
return 5;
}
// unreachable
}
template <>
size_t encode<int64_t>(ByteType*& pBuf, int64_t pValue) {
size_t size = 0;
bool more = true;
do {
ByteType byte = pValue & 0x7f;
pValue >>= 7;
if (((pValue == 0) && ((byte & 0x40) == 0)) ||
((pValue == -1) && ((byte & 0x40) == 0x40)))
more = false;
else
byte |= 0x80;
*pBuf++ = byte;
size++;
} while (more);
return size;
}
template <>
size_t encode<int32_t>(ByteType*& pBuf, int32_t pValue) {
return encode<int64_t>(pBuf, static_cast<int64_t>(pValue));
}
//===---------------------- LEB128 Decoding APIs -------------------------===//
template <>
uint64_t decode<uint64_t>(const ByteType* pBuf, size_t& pSize) {
uint64_t result = 0;
if ((*pBuf & 0x80) == 0) {
pSize = 1;
return *pBuf;
} else if ((*(pBuf + 1) & 0x80) == 0) {
pSize = 2;
return ((*(pBuf + 1) & 0x7f) << 7) | (*pBuf & 0x7f);
} else if ((*(pBuf + 2) & 0x80) == 0) {
pSize = 3;
return ((*(pBuf + 2) & 0x7f) << 14) | ((*(pBuf + 1) & 0x7f) << 7) |
(*pBuf & 0x7f);
} else {
pSize = 4;
result = ((*(pBuf + 3) & 0x7f) << 21) | ((*(pBuf + 2) & 0x7f) << 14) |
((*(pBuf + 1) & 0x7f) << 7) | (*pBuf & 0x7f);
}
if ((*(pBuf + 3) & 0x80) != 0) {
// Large number which is an unusual case.
unsigned shift;
ByteType byte;
// Start the read from the 4th byte.
shift = 28;
pBuf += 4;
do {
byte = *pBuf;
pBuf++;
pSize++;
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);
}
return result;
}
template <>
uint64_t decode<uint64_t>(const ByteType*& pBuf) {
ByteType byte;
uint64_t result;
byte = *pBuf++;
result = byte & 0x7f;
if ((byte & 0x80) == 0) {
return result;
} else {
byte = *pBuf++;
result |= ((byte & 0x7f) << 7);
if ((byte & 0x80) == 0) {
return result;
} else {
byte = *pBuf++;
result |= (byte & 0x7f) << 14;
if ((byte & 0x80) == 0) {
return result;
} else {
byte = *pBuf++;
result |= (byte & 0x7f) << 21;
if ((byte & 0x80) == 0) {
return result;
}
}
}
}
// Large number which is an unusual case.
unsigned shift;
// Start the read from the 4th byte.
shift = 28;
do {
byte = *pBuf++;
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);
return result;
}
/*
* Signed LEB128 decoding is Similar to the unsigned version but setup the sign
* bit if necessary. This is rarely used, therefore we don't provide unrolling
* version like decode() to save the code size.
*/
template <>
int64_t decode<int64_t>(const ByteType* pBuf, size_t& pSize) {
uint64_t result = 0;
ByteType byte;
unsigned shift = 0;
pSize = 0;
do {
byte = *pBuf;
pBuf++;
pSize++;
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);
if ((shift < (8 * sizeof(result))) && (byte & 0x40))
result |= ((static_cast<uint64_t>(-1)) << shift);
return result;
}
template <>
int64_t decode<int64_t>(const ByteType*& pBuf) {
uint64_t result = 0;
ByteType byte;
unsigned shift = 0;
do {
byte = *pBuf;
pBuf++;
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);
if ((shift < (8 * sizeof(result))) && (byte & 0x40))
result |= ((static_cast<uint64_t>(-1)) << shift);
return result;
}
} // namespace leb128
} // namespace mcld

View file

@ -0,0 +1,49 @@
//===- MemoryArea.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/MemoryArea.h"
#include "mcld/Support/MsgHandling.h"
#include <llvm/Support/ErrorOr.h>
#include <cassert>
#include <system_error>
namespace mcld {
//===--------------------------------------------------------------------===//
// MemoryArea
//===--------------------------------------------------------------------===//
MemoryArea::MemoryArea(llvm::StringRef pFilename) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer> > buffer_or_error =
llvm::MemoryBuffer::getFile(pFilename,
/*FileSize*/ -1,
/*RequiresNullTerminator*/ false);
if (!buffer_or_error) {
fatal(diag::fatal_cannot_read_input) << pFilename.str();
}
m_pMemoryBuffer = std::move(buffer_or_error.get());
}
MemoryArea::MemoryArea(const char* pMemBuffer, size_t pSize) {
llvm::StringRef mem(pMemBuffer, pSize);
m_pMemoryBuffer =
llvm::MemoryBuffer::getMemBuffer(mem,
/*BufferName*/ "NaN",
/*RequiresNullTerminator*/ false);
}
llvm::StringRef MemoryArea::request(size_t pOffset, size_t pLength) {
return llvm::StringRef(m_pMemoryBuffer->getBufferStart() + pOffset, pLength);
}
size_t MemoryArea::size() const {
return m_pMemoryBuffer->getBufferSize();
}
} // namespace mcld

View file

@ -0,0 +1,75 @@
//===- MemoryAreaFactory.cpp ----------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/MemoryAreaFactory.h"
#include "mcld/Support/MsgHandling.h"
#include "mcld/Support/SystemUtils.h"
namespace mcld {
//===----------------------------------------------------------------------===//
// MemoryAreaFactory
//===----------------------------------------------------------------------===//
MemoryAreaFactory::MemoryAreaFactory(size_t pNum)
: GCFactory<MemoryArea, 0>(pNum) {
}
MemoryAreaFactory::~MemoryAreaFactory() {
}
MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath,
FileHandle::OpenMode pMode) {
llvm::StringRef name(pPath.native());
if (m_AreaMap.find(name) == m_AreaMap.end()) {
MemoryArea* result = allocate();
new (result) MemoryArea(name);
m_AreaMap[name] = result;
return result;
}
return m_AreaMap[name];
}
MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath,
FileHandle::OpenMode pMode,
FileHandle::Permission pPerm) {
llvm::StringRef name(pPath.native());
if (m_AreaMap.find(name) == m_AreaMap.end()) {
MemoryArea* result = allocate();
new (result) MemoryArea(name);
m_AreaMap[name] = result;
return result;
}
return m_AreaMap[name];
}
MemoryArea* MemoryAreaFactory::produce(void* pMemBuffer, size_t pSize) {
const char* base = reinterpret_cast<const char*>(pMemBuffer);
llvm::StringRef name(base, pSize);
if (m_AreaMap.find(name) == m_AreaMap.end()) {
MemoryArea* result = allocate();
new (result) MemoryArea(base, pSize);
m_AreaMap[name] = result;
return result;
}
return m_AreaMap[name];
}
MemoryArea* MemoryAreaFactory::produce(int pFD, FileHandle::OpenMode pMode) {
// TODO
return NULL;
}
void MemoryAreaFactory::destruct(MemoryArea* pArea) {
destroy(pArea);
deallocate(pArea);
}
} // namespace mcld

View file

@ -0,0 +1,63 @@
//===- MsgHandling.cpp ----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/LD/DiagnosticEngine.h"
#include "mcld/LD/DiagnosticLineInfo.h"
#include "mcld/LD/DiagnosticPrinter.h"
#include "mcld/LD/MsgHandler.h"
#include "mcld/LD/TextDiagnosticPrinter.h"
#include "mcld/Support/MsgHandling.h"
#include "mcld/Support/raw_ostream.h"
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/Signals.h>
#include <cstdlib>
namespace mcld {
//===----------------------------------------------------------------------===//
// static variables
//===----------------------------------------------------------------------===//
static llvm::ManagedStatic<DiagnosticEngine> g_pEngine;
void InitializeDiagnosticEngine(const LinkerConfig& pConfig,
DiagnosticPrinter* pPrinter) {
g_pEngine->reset(pConfig);
if (pPrinter != NULL)
g_pEngine->setPrinter(*pPrinter, false);
else {
DiagnosticPrinter* printer =
new TextDiagnosticPrinter(errs(), pConfig);
g_pEngine->setPrinter(*printer, true);
}
}
DiagnosticEngine& getDiagnosticEngine() {
return *g_pEngine;
}
bool Diagnose() {
if (g_pEngine->getPrinter()->getNumErrors() > 0) {
// If we reached here, we are failing ungracefully. Run the interrupt
// handlers
// to make sure any special cleanups get done, in particular that we remove
// files registered with RemoveFileOnSignal.
llvm::sys::RunInterruptHandlers();
g_pEngine->getPrinter()->finish();
return false;
}
return true;
}
void FinalizeDiagnosticEngine() {
g_pEngine->getPrinter()->finish();
}
} // namespace mcld

View file

@ -0,0 +1,207 @@
//===- Path.cpp -----------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/Path.h"
#include "mcld/Config/Config.h"
#include "mcld/Support/FileSystem.h"
#include <llvm/ADT/StringRef.h>
#include <istream>
#include <locale>
#include <ostream>
#include <string.h>
namespace mcld {
namespace sys {
namespace fs {
//===--------------------------------------------------------------------===//
// Helper
//===--------------------------------------------------------------------===//
namespace {
#if defined(MCLD_ON_WIN32)
bool is_separator(char value) {
return (value == separator || value == preferred_separator);
}
const Path::StringType separator_str("/");
#else
bool is_separator(char value) {
return (value == separator);
}
const Path::StringType separator_str("/");
#endif
} // anonymous namespace
//===--------------------------------------------------------------------===//
// Path
//===--------------------------------------------------------------------===//
Path::Path() : m_PathName() {
}
Path::Path(const Path::ValueType* s) : m_PathName(s) {
}
Path::Path(const Path::StringType& s) : m_PathName(s) {
}
Path::Path(const Path& pCopy) : m_PathName(pCopy.m_PathName) {
}
Path::~Path() {
}
bool Path::isFromRoot() const {
if (m_PathName.empty())
return false;
return (separator == m_PathName[0]);
}
bool Path::isFromPWD() const {
if (m_PathName.size() < 2)
return false;
return ('.' == m_PathName[0] && separator == m_PathName[1]);
}
Path& Path::assign(const Path::StringType& s) {
m_PathName.assign(s);
return *this;
}
Path& Path::assign(const Path::ValueType* s, unsigned int length) {
if (s == 0 || length == 0)
assert(0 && "assign a null or empty string to Path");
m_PathName.assign(s, length);
return *this;
}
// a,/b a/,b a/,b/ a,b is a/b
Path& Path::append(const Path& pPath) {
// first path is a/,second path is /b
if (m_PathName[m_PathName.length() - 1] == separator &&
pPath.native()[0] == separator) {
llvm::StringRef path(pPath.native());
m_PathName.append(path.begin() + 1, path.end());
} else if (this->native()[this->native().size() - 1] != separator &&
pPath.native()[0] != separator) {
// first path is a,second path is b
m_PathName.append(separator_str);
m_PathName.append(pPath.native());
} else {
// a/,b or a,/b just append
m_PathName.append(pPath.native());
}
return *this;
}
// a,/b a/,b a/,b/ a,b is a/b
Path& Path::append(const StringType& pPath) {
Path path(pPath);
this->append(path);
return *this;
}
bool Path::empty() const {
return m_PathName.empty();
}
Path::StringType Path::generic_string() const {
StringType result = m_PathName;
detail::canonicalize(result);
return result;
}
bool Path::canonicalize() {
return detail::canonicalize(m_PathName);
}
Path::StringType::size_type Path::m_append_separator_if_needed() {
#if defined(MCLD_ON_WIN32)
// On Windows platform, path can not append separator.
return 0;
#endif
StringType::value_type last_char = m_PathName[m_PathName.size() - 1];
if (!m_PathName.empty() && !is_separator(last_char)) {
StringType::size_type tmp(m_PathName.size());
m_PathName += separator_str;
return tmp;
}
return 0;
}
void Path::m_erase_redundant_separator(Path::StringType::size_type pSepPos) {
size_t begin = pSepPos;
// skip '/' or '\\'
while (separator == m_PathName[pSepPos]) {
#if defined(MCLD_ON_WIN32)
pSepPos += 2;
#else
++pSepPos;
#endif
}
if (begin != pSepPos)
m_PathName.erase(begin + 1, pSepPos - begin - 1);
}
Path Path::parent_path() const {
size_t end_pos = m_PathName.find_last_of(separator);
if (end_pos != StringType::npos)
return Path(m_PathName.substr(0, end_pos));
return Path();
}
Path Path::filename() const {
size_t pos = m_PathName.find_last_of(separator);
if (pos != StringType::npos) {
++pos;
return Path(m_PathName.substr(pos));
}
return Path(*this);
}
Path Path::stem() const {
size_t begin_pos = m_PathName.find_last_of(separator) + 1;
size_t end_pos = m_PathName.find_last_of(dot);
Path result_path(m_PathName.substr(begin_pos, end_pos - begin_pos));
return result_path;
}
Path Path::extension() const {
size_t pos = m_PathName.find_last_of('.');
if (pos == StringType::npos)
return Path();
return Path(m_PathName.substr(pos));
}
//===--------------------------------------------------------------------===//
// non-member functions
//===--------------------------------------------------------------------===//
bool operator==(const Path& pLHS, const Path& pRHS) {
return (pLHS.generic_string() == pRHS.generic_string());
}
bool operator!=(const Path& pLHS, const Path& pRHS) {
return !(pLHS == pRHS);
}
Path operator+(const Path& pLHS, const Path& pRHS) {
mcld::sys::fs::Path result = pLHS;
result.append(pRHS);
return result;
}
} // namespace fs
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,56 @@
//===- RealPath.cpp -------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/RealPath.h"
#include "mcld/Support/FileSystem.h"
namespace mcld {
namespace sys {
namespace fs {
//==========================
// RealPath
RealPath::RealPath() : Path() {
}
RealPath::RealPath(const RealPath::ValueType* s) : Path(s) {
initialize();
}
RealPath::RealPath(const RealPath::StringType& s) : Path(s) {
initialize();
}
RealPath::RealPath(const Path& pPath) : Path(pPath) {
initialize();
}
RealPath::~RealPath() {
}
RealPath& RealPath::assign(const Path& pPath) {
Path::m_PathName.assign(pPath.native());
return (*this);
}
void RealPath::initialize() {
if (isFromRoot()) {
detail::canonicalize(m_PathName);
} else if (isFromPWD()) {
Path path_name;
detail::get_pwd(path_name);
path_name.native() += preferred_separator;
path_name.native() += m_PathName;
detail::canonicalize(path_name.native());
m_PathName = path_name.native();
}
}
} // namespace fs
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,19 @@
//===- SystemUtils.cpp ----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Config/Config.h"
#include "mcld/Support/SystemUtils.h"
//===----------------------------------------------------------------------===//
// Non-member functions
#if defined(MCLD_ON_UNIX)
#include "Unix/System.inc"
#endif
#if defined(MCLD_ON_WIN32)
#include "Windows/System.inc"
#endif

View file

@ -0,0 +1,75 @@
//===- Target.cpp ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/Target.h"
#include <llvm/ADT/Triple.h>
namespace mcld {
//===----------------------------------------------------------------------===//
// Target
//===----------------------------------------------------------------------===//
Target::Target()
: Name(NULL),
TripleMatchQualityFn(NULL),
TargetMachineCtorFn(NULL),
MCLinkerCtorFn(NULL),
TargetLDBackendCtorFn(NULL),
DiagnosticLineInfoCtorFn(NULL) {
}
unsigned int Target::getTripleQuality(const llvm::Triple& pTriple) const {
if (TripleMatchQualityFn == NULL)
return 0;
return TripleMatchQualityFn(pTriple);
}
MCLDTargetMachine* Target::createTargetMachine(const std::string& pTriple,
const llvm::Target& pTarget,
llvm::TargetMachine& pTM) const {
if (TargetMachineCtorFn == NULL)
return NULL;
return TargetMachineCtorFn(pTarget, *this, pTM, pTriple);
}
/// createMCLinker - create target-specific MCLinker
MCLinker* Target::createMCLinker(const std::string& pTriple,
LinkerConfig& pConfig,
Module& pModule,
FileHandle& pFileHandle) const {
if (MCLinkerCtorFn == NULL)
return NULL;
return MCLinkerCtorFn(pTriple, pConfig, pModule, pFileHandle);
}
/// emulate - given MCLinker default values for the other aspects of the
/// target system.
bool Target::emulate(LinkerScript& pScript, LinkerConfig& pConfig) const {
if (EmulationFn == NULL)
return false;
return EmulationFn(pScript, pConfig);
}
/// createLDBackend - create target-specific LDBackend
TargetLDBackend* Target::createLDBackend(const LinkerConfig& pConfig) const {
if (TargetLDBackendCtorFn == NULL)
return NULL;
return TargetLDBackendCtorFn(pConfig);
}
/// createDiagnosticLineInfo - create target-specific DiagnosticLineInfo
DiagnosticLineInfo* Target::createDiagnosticLineInfo(
const mcld::Target& pTarget,
const std::string& pTriple) const {
if (DiagnosticLineInfoCtorFn == NULL)
return NULL;
return DiagnosticLineInfoCtorFn(pTarget, pTriple);
}
} // namespace mcld

View file

@ -0,0 +1,103 @@
//===- TargetRegistry.cpp -------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/TargetRegistry.h"
namespace mcld {
TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
//===----------------------------------------------------------------------===//
// TargetRegistry
//===----------------------------------------------------------------------===//
void TargetRegistry::RegisterTarget(Target& pTarget,
const char* pName,
Target::TripleMatchQualityFnTy pQualityFn) {
pTarget.Name = pName;
pTarget.TripleMatchQualityFn = pQualityFn;
s_TargetList.push_back(&pTarget);
}
const Target* TargetRegistry::lookupTarget(const std::string& pTriple,
std::string& pError) {
if (empty()) {
pError = "Unable to find target for this triple (no target are registered)";
return NULL;
}
llvm::Triple triple(pTriple);
Target* best = NULL, * ambiguity = NULL;
unsigned int highest = 0;
for (iterator target = begin(), ie = end(); target != ie; ++target) {
unsigned int quality = (*target)->getTripleQuality(triple);
if (quality > 0) {
if (best == NULL || highest < quality) {
highest = quality;
best = *target;
ambiguity = NULL;
} else if (highest == quality) {
ambiguity = *target;
}
}
}
if (best == NULL) {
pError = "No availaible targets are compatible with this triple.";
return NULL;
}
if (NULL != ambiguity) {
pError = std::string("Ambiguous targets: \"") + best->name() + "\" and \"" +
ambiguity->name() + "\"";
return NULL;
}
return best;
}
const Target* TargetRegistry::lookupTarget(const std::string& pArchName,
llvm::Triple& pTriple,
std::string& pError) {
const Target* result = NULL;
if (!pArchName.empty()) {
for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(),
ie = mcld::TargetRegistry::end();
it != ie;
++it) {
if (pArchName == (*it)->name()) {
result = *it;
break;
}
}
if (result == NULL) {
pError = std::string("invalid target '") + pArchName + "'.\n";
return NULL;
}
// Adjust the triple to match (if known), otherwise stick with the
// module/host triple.
llvm::Triple::ArchType type =
llvm::Triple::getArchTypeForLLVMName(pArchName);
if (llvm::Triple::UnknownArch != type)
pTriple.setArch(type);
} else {
std::string error;
result = lookupTarget(pTriple.getTriple(), error);
if (result == NULL) {
pError = std::string("unable to get target for `") + pTriple.getTriple() +
"'\n" + "(Detail: " + error + ")\n";
return NULL;
}
}
return result;
}
} // namespace mcld

View file

@ -0,0 +1,206 @@
//===- FileSystem.inc -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/FileHandle.h"
#include "mcld/Support/Directory.h"
#include <llvm/Support/ErrorHandling.h>
#include <string>
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
namespace mcld {
namespace sys {
namespace fs {
namespace detail {
std::string static_library_extension = ".a";
std::string shared_library_extension = ".so";
std::string executable_extension = "";
std::string relocatable_extension = ".o";
std::string assembly_extension = ".s";
std::string bitcode_extension = ".bc";
//===----------------------------------------------------------------------===//
// Helper Functions
//===----------------------------------------------------------------------===//
/// read_dir - return true if we read one entry
// @return value -1: read error
// 0: read the end
// 1: success
static int read_dir(intptr_t& pDir, std::string& pOutFilename) {
errno = 0;
dirent* cur_dir = ::readdir(reinterpret_cast<DIR*>(pDir));
if (0 == cur_dir && 0 != errno)
return -1;
// idx does not stay at the end, but all elements had beed put into cache.
if (NULL == cur_dir) {
return 0;
}
llvm::StringRef name(cur_dir->d_name, strlen(cur_dir->d_name));
if ((name.size() == 1 && name[0] == '.') ||
(name.size() == 2 && name[0] == '.' && name[1] == '.'))
return read_dir(pDir, pOutFilename);
// find a new directory
pOutFilename.append(name.data(), name.size());
return 1;
}
void open_dir(Directory& pDir) {
pDir.m_Handler = reinterpret_cast<intptr_t>(opendir(pDir.path().c_str()));
if (0 == pDir.m_Handler) {
errno = 0; // opendir() will set errno if it failed to open directory.
// set cache is full, then Directory::begin() can return end().
pDir.m_CacheFull = true;
return;
}
// read one entry for advance the end element of the cache.
std::string path(pDir.path().native());
switch (read_dir(pDir.m_Handler, path)) {
case 1: {
// find a new directory
bool exist = false;
mcld::sys::fs::PathCache::entry_type* entry =
pDir.m_Cache.insert(path, exist);
if (!exist)
entry->setValue(sys::fs::Path(path));
return;
}
case 0:
// FIXME: a warning function
pDir.m_CacheFull = true;
return;
default:
case -1:
llvm::report_fatal_error(std::string("Can't read directory: ") +
pDir.path().native());
}
}
void close_dir(Directory& pDir) {
if (pDir.m_Handler)
closedir(reinterpret_cast<DIR*>(pDir.m_Handler));
pDir.m_Handler = 0;
}
int open(const Path& pPath, int pOFlag) {
return ::open(pPath.native().c_str(), pOFlag);
}
int open(const Path& pPath, int pOFlag, int pPerm) {
mode_t perm = 0;
if (pPerm & FileHandle::ReadOwner)
perm |= S_IRUSR;
if (pPerm & FileHandle::WriteOwner)
perm |= S_IWUSR;
if (pPerm & FileHandle::ExeOwner)
perm |= S_IXUSR;
if (pPerm & FileHandle::ReadGroup)
perm |= S_IRGRP;
if (pPerm & FileHandle::WriteGroup)
perm |= S_IWGRP;
if (pPerm & FileHandle::ExeGroup)
perm |= S_IXGRP;
if (pPerm & FileHandle::ReadOther)
perm |= S_IROTH;
if (pPerm & FileHandle::WriteOther)
perm |= S_IWOTH;
if (pPerm & FileHandle::ExeOther)
perm |= S_IXOTH;
return ::open(pPath.native().c_str(), pOFlag, perm);
}
ssize_t pread(int pFD, void* pBuf, size_t pCount, off_t pOffset) {
return ::pread(pFD, pBuf, pCount, pOffset);
}
ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, off_t pOffset) {
return ::pwrite(pFD, pBuf, pCount, pOffset);
}
int ftruncate(int pFD, size_t pLength) {
return ::ftruncate(pFD, pLength);
}
void get_pwd(Path& pPWD) {
char* pwd = (char*)malloc(PATH_MAX);
pPWD.assign(getcwd(pwd, PATH_MAX));
free(pwd);
}
} // namespace detail
} // namespace fs
} // namespace sys
//===----------------------------------------------------------------------===//
// FileHandler
//===----------------------------------------------------------------------===//
bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength) {
if (!isOpened()) {
setState(BadBit);
return false;
}
if (0 == pLength)
return true;
int prot, flag;
if (isReadable() && !isWritable()) {
// read-only
prot = PROT_READ;
flag = MAP_FILE | MAP_PRIVATE;
} else if (!isReadable() && isWritable()) {
// write-only
prot = PROT_WRITE;
flag = MAP_FILE | MAP_SHARED;
} else if (isReadWrite()) {
// read and write
prot = PROT_READ | PROT_WRITE;
flag = MAP_FILE | MAP_SHARED;
} else {
// can not read/write
setState(BadBit);
return false;
}
pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset);
if (MAP_FAILED == pMemBuffer) {
setState(FailBit);
return false;
}
return true;
}
bool FileHandle::munmap(void* pMemBuffer, size_t pLength) {
if (!isOpened()) {
setState(BadBit);
return false;
}
if (-1 == ::munmap(pMemBuffer, pLength)) {
setState(FailBit);
return false;
}
return true;
}
} // namespace mcld

View file

@ -0,0 +1,216 @@
//===- PathV3.inc ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
#include <llvm/Support/ErrorHandling.h>
#include <cerrno>
#include <stack>
#include <stdio.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace mcld {
namespace sys {
namespace fs {
//===----------------------------------------------------------------------===//
// mcld::sys::fs::detail
//===----------------------------------------------------------------------===//
namespace detail {
// return the last charactor being handled.
size_t canonicalize(std::string& pathname) {
// Variable Index //
// SepTable - stack of result separators
// LR(1) Algorithm //
// traverse pPathName
// if we meet '//', '///', '////', ...
// -> ignore it
// -> push current into stack
// -> jump to the next not '/'
// if we meet '/./'
// -> ignore
// -> jump to the next not '/'
// if we meet '/../'
// -> pop previous position of '/' P
// -> erase P+1 to now
// if we meet other else
// -> go go go
// if we meet '/.../', '/..../', ... -> illegal
if (pathname.empty())
return 0;
size_t handler = 0;
std::stack<size_t> slash_stack;
slash_stack.push(-1);
while (handler < pathname.size()) {
if (separator == pathname[handler]) { // handler = 1st '/'
size_t next = handler + 1;
if (next >= pathname.size())
return handler;
switch (pathname[next]) { // next = handler + 1;
case separator: { // '//'
while (next < pathname.size() && separator == pathname[next])
++next;
// next is the last not '/'
pathname.erase(handler, next - handler - 1);
// handler is the first '/'
slash_stack.push(handler);
break;
}
case '.': { // '/.'
++next; // next = handler + 2
if (next >= pathname.size()) // '/.'
return handler;
switch (pathname[next]) {
case separator: { // '/./'
pathname.erase(handler, 2);
break;
}
case '.': { // '/..'
++next; // next = handler + 3;
if (next >= pathname.size()) // '/..?'
return handler;
switch (pathname[next]) {
case separator: { // '/../'
handler = slash_stack.top();
slash_stack.pop();
pathname.erase(handler + 1, next - handler);
if (static_cast<size_t>(-1) == handler) {
slash_stack.push(-1);
handler = pathname.find_first_of(separator, handler);
}
break;
}
case '.': { // '/...', illegal
return handler;
break;
}
default: { // '/..a'
slash_stack.push(handler);
handler = pathname.find_first_of(separator, handler + 3);
break;
}
}
break;
}
default: { // '/.a'
slash_stack.push(handler);
handler = pathname.find_first_of(separator, handler + 2);
break;
}
}
break;
}
default: { // '/a
slash_stack.push(handler);
handler = pathname.find_first_of(separator, handler + 1);
break;
}
}
} else {
handler = pathname.find_first_of(separator, handler);
}
}
return handler;
}
bool not_found_error(int perrno) {
return perrno == ENOENT || perrno == ENOTDIR;
}
void status(const Path& p, FileStatus& pFileStatus) {
struct stat path_stat;
if (stat(p.c_str(), &path_stat) != 0) {
if (not_found_error(errno)) {
pFileStatus.setType(FileNotFound);
} else
pFileStatus.setType(StatusError);
} else if (S_ISDIR(path_stat.st_mode))
pFileStatus.setType(DirectoryFile);
else if (S_ISREG(path_stat.st_mode))
pFileStatus.setType(RegularFile);
else if (S_ISBLK(path_stat.st_mode))
pFileStatus.setType(BlockFile);
else if (S_ISCHR(path_stat.st_mode))
pFileStatus.setType(CharacterFile);
else if (S_ISFIFO(path_stat.st_mode))
pFileStatus.setType(FifoFile);
else if (S_ISSOCK(path_stat.st_mode))
pFileStatus.setType(SocketFile);
else
pFileStatus.setType(TypeUnknown);
}
void symlink_status(const Path& p, FileStatus& pFileStatus) {
struct stat path_stat;
if (lstat(p.c_str(), &path_stat) != 0) {
if (errno == ENOENT || errno == ENOTDIR) // these are not errors
{
pFileStatus.setType(FileNotFound);
} else
pFileStatus.setType(StatusError);
}
if (S_ISREG(path_stat.st_mode))
pFileStatus.setType(RegularFile);
if (S_ISDIR(path_stat.st_mode))
pFileStatus.setType(DirectoryFile);
if (S_ISLNK(path_stat.st_mode))
pFileStatus.setType(SymlinkFile);
if (S_ISBLK(path_stat.st_mode))
pFileStatus.setType(BlockFile);
if (S_ISCHR(path_stat.st_mode))
pFileStatus.setType(CharacterFile);
if (S_ISFIFO(path_stat.st_mode))
pFileStatus.setType(FifoFile);
if (S_ISSOCK(path_stat.st_mode))
pFileStatus.setType(SocketFile);
else
pFileStatus.setType(TypeUnknown);
}
/// directory_iterator_increment - increment function implementation
//
// iterator will call this function in two situations:
// 1. All elements have been put into cache, and iterator stays at the end
// of cache. (a real end)
// 2. Some but not all elements had been put into cache, and we stoped.
// An iterator now is staying at the end of cache. (a temporal end)
mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter) {
mcld::sys::fs::PathCache::entry_type* entry = 0;
std::string path(pIter.m_pParent->m_Path.native());
switch (read_dir(pIter.m_pParent->m_Handler, path)) {
case 1: {
// read one
bool exist = false;
entry = pIter.m_pParent->m_Cache.insert(path, exist);
if (!exist)
entry->setValue(sys::fs::Path(path));
break;
}
case 0: // meet real end
pIter.m_pParent->m_CacheFull = true;
break;
default:
case -1:
llvm::report_fatal_error(std::string("Can't read directory: ") +
pIter.m_pParent->path().native());
break;
}
return entry;
}
} // namespace detail
} // namespace fs
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,80 @@
//===- System.inc ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <llvm/ADT/StringRef.h>
#include <fcntl.h>
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
namespace mcld {
namespace sys {
char* strerror(int errnum) {
return std::strerror(errnum);
}
static std::string getOSVersion() {
struct utsname info;
if (uname(&info))
return "";
return info.release;
}
std::string getDefaultTargetTriple() {
llvm::StringRef TargetTripleString(MCLD_DEFAULT_TARGET_TRIPLE);
std::pair<llvm::StringRef, llvm::StringRef> ArchSplit =
TargetTripleString.split('-');
// Normalize the arch, since the target triple may not actually match the
// target.
std::string Arch = ArchSplit.first;
std::string Triple(Arch);
Triple += '-';
Triple += ArchSplit.second;
// Force i<N>86 to i386.
if (Triple[0] == 'i' && isdigit(Triple[1]) && Triple[2] == '8' &&
Triple[3] == '6')
Triple[1] = '3';
// On darwin, we want to update the version to match that of the
// target.
std::string::size_type DarwinDashIdx = Triple.find("-darwin");
if (DarwinDashIdx != std::string::npos) {
Triple.resize(DarwinDashIdx + strlen("-darwin"));
Triple += getOSVersion();
}
return Triple;
}
int GetPageSize() {
return getpagesize();
}
/// random - generate a random number.
long GetRandomNum() {
return ::random();
}
/// srandom - set the initial seed value for future calls to random().
void SetRandomSeed(unsigned pSeed) {
::srandom(pSeed);
}
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,162 @@
//===- FileSystem.inc -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/FileHandle.h"
#include "mcld/Support/Directory.h"
#include <string>
#include <cstdlib>
#include <io.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <windows.h>
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
namespace mcld {
namespace sys {
namespace fs {
namespace detail {
// FIXME: the extension depends on target machine, not host machine.
Path::StringType static_library_extension = ".a";
Path::StringType shared_library_extension = ".so";
Path::StringType executable_extension = ".exe";
Path::StringType relocatable_extension = ".o";
Path::StringType assembly_extension = ".s";
Path::StringType bitcode_extension = ".bc";
void open_dir(Directory& pDir) {
fs::Path file_filter(pDir.path());
file_filter.append("*");
WIN32_FIND_DATA FindFileData;
HANDLE hFile = FindFirstFile(file_filter.c_str(), &FindFileData);
pDir.m_Handler = reinterpret_cast<intptr_t>(hFile);
if (INVALID_HANDLE_VALUE == hFile) {
// set cache is full, then Directory::begin() can return end().
pDir.m_CacheFull = true;
return;
}
// find a new directory and file
bool exist = false;
std::string path(FindFileData.cFileName);
fs::PathCache::entry_type* entry = pDir.m_Cache.insert(path, exist);
if (!exist)
entry->setValue(path);
}
void close_dir(Directory& pDir) {
if (pDir.m_Handler)
FindClose(reinterpret_cast<HANDLE>(pDir.m_Handler));
pDir.m_Handler = 0;
}
int open(const Path& pPath, int pOFlag) {
return ::_open(pPath.native().c_str(), pOFlag | _O_BINARY);
}
int open(const Path& pPath, int pOFlag, int pPerm) {
int perm = 0;
if (pPerm & FileHandle::ReadOwner || pPerm & FileHandle::ReadGroup ||
pPerm & FileHandle::ReadOther)
perm |= _S_IREAD;
if (pPerm & FileHandle::WriteOwner || pPerm & FileHandle::WriteGroup ||
pPerm & FileHandle::WriteOther)
perm |= _S_IWRITE;
return ::_open(pPath.native().c_str(), pOFlag | _O_BINARY, perm);
}
ssize_t pread(int pFD, void* pBuf, size_t pCount, off_t pOffset) {
ssize_t ret;
off_t old_pos;
if (-1 == (old_pos = ::lseek(pFD, 0, SEEK_CUR)))
return -1;
if (-1 == ::lseek(pFD, pOffset, SEEK_SET))
return -1;
if (-1 == (ret = ::read(pFD, pBuf, pCount))) {
int err = errno;
::lseek(pFD, old_pos, SEEK_SET);
errno = err;
return -1;
}
if (-1 == ::lseek(pFD, old_pos, SEEK_SET))
return -1;
return ret;
}
ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, off_t pOffset) {
ssize_t ret;
off_t old_pos;
if (-1 == (old_pos = ::lseek(pFD, 0, SEEK_CUR)))
return -1;
if (-1 == ::lseek(pFD, pOffset, SEEK_SET))
return -1;
if (-1 == (ret = ::write(pFD, pBuf, pCount))) {
int err = errno;
::lseek(pFD, old_pos, SEEK_SET);
errno = err;
return -1;
}
if (-1 == ::lseek(pFD, old_pos, SEEK_SET))
return -1;
return ret;
}
int ftruncate(int pFD, size_t pLength) {
return ::_chsize(pFD, pLength);
}
void get_pwd(Path& pPWD) {
char* pwd = (char*)malloc(PATH_MAX);
pPWD.assign(_getcwd(pwd, PATH_MAX));
free(pwd);
}
} // namespace detail
} // namespace fs
} // namespace sys
//===----------------------------------------------------------------------===//
// FileHandle
//===----------------------------------------------------------------------===//
bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength) {
// FIXME: This implementation reduces mmap to read. Use Windows APIs.
pMemBuffer = (void*)::malloc(pLength);
return read(pMemBuffer, pStartOffset, pLength);
}
bool FileHandle::munmap(void* pMemBuffer, size_t pLength) {
// FIXME: This implementation reduces mmap to read. Use Windows APIs.
free(pMemBuffer);
return true;
}
} // namespace mcld

View file

@ -0,0 +1,188 @@
//===- PathV3.inc ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Support/Path.h"
#include <stack>
#include <sys/stat.h>
#include <sys/types.h>
namespace mcld {
namespace sys {
namespace fs {
//===----------------------------------------------------------------------===//
// mcld::sys::fs::detail
//===----------------------------------------------------------------------===//
namespace detail {
// return the last charactor being handled.
size_t canonicalize(std::string& pathname) {
// Variable Index //
// SepTable - stack of result separators
// LR(1) Algorithm //
// traverse pPathName
// if we meet '//', '///', '////', ...
// -> ignore it
// -> push current into stack
// -> jump to the next not '/'
// if we meet '/./'
// -> ignore
// -> jump to the next not '/'
// if we meet '/../'
// -> pop previous position of '/' P
// -> erase P+1 to now
// if we meet other else
// -> go go go
// if we meet '/.../', '/..../', ... -> illegal
if (pathname.empty())
return 0;
size_t handler = 0;
std::stack<size_t> slash_stack;
slash_stack.push(-1);
while (handler < pathname.size()) {
if (separator == pathname[handler]) { // handler = 1st '/'
size_t next = handler + 1;
if (next >= pathname.size())
return handler;
switch (pathname[next]) { // next = handler + 1;
case separator: { // '//'
while (next < pathname.size() && separator == pathname[next])
++next;
// next is the last not '/'
pathname.erase(handler, next - handler - 1);
// handler is the first '/'
slash_stack.push(handler);
break;
}
case '.': { // '/.'
++next; // next = handler + 2
if (next >= pathname.size()) // '/.'
return handler;
switch (pathname[next]) {
case separator: { // '/./'
pathname.erase(handler, 2);
break;
}
case '.': { // '/..'
++next; // next = handler + 3;
if (next >= pathname.size()) // '/..?'
return handler;
switch (pathname[next]) {
case separator: { // '/../'
handler = slash_stack.top();
slash_stack.pop();
pathname.erase(handler + 1, next - handler);
if (static_cast<size_t>(-1) == handler) {
slash_stack.push(-1);
handler = pathname.find_first_of(separator, handler);
}
break;
}
case '.': { // '/...', illegal
return handler;
break;
}
default: { // '/..a'
slash_stack.push(handler);
handler = pathname.find_first_of(separator, handler + 3);
break;
}
}
break;
}
default: { // '/.a'
slash_stack.push(handler);
handler = pathname.find_first_of(separator, handler + 2);
break;
}
}
break;
}
default: { // '/a
slash_stack.push(handler);
handler = pathname.find_first_of(separator, handler + 1);
break;
}
}
} else {
handler = pathname.find_first_of(separator, handler);
}
}
return handler;
}
bool not_found_error(int perrno) {
return perrno == ENOENT || perrno == ENOTDIR;
}
void status(const Path& p, FileStatus& pFileStatus) {
struct ::_stat path_stat;
if (::_stat(p.c_str(), &path_stat) != 0) {
if (not_found_error(errno)) {
pFileStatus.setType(FileNotFound);
} else
pFileStatus.setType(StatusError);
} else if (S_ISDIR(path_stat.st_mode))
pFileStatus.setType(DirectoryFile);
else if (S_ISREG(path_stat.st_mode))
pFileStatus.setType(RegularFile);
else if (S_ISBLK(path_stat.st_mode))
pFileStatus.setType(BlockFile);
else if (S_ISCHR(path_stat.st_mode))
pFileStatus.setType(CharacterFile);
else if (S_ISFIFO(path_stat.st_mode))
pFileStatus.setType(FifoFile);
else
pFileStatus.setType(TypeUnknown);
}
void symlink_status(const Path& p, FileStatus& pFileStatus) {
pFileStatus.setType(FileNotFound);
}
/// directory_iterator_increment - increment function implementation
//
// iterator will call this function in two situations:
// 1. All elements have been put into cache, and iterator stays at the end
// of cache. (a real end)
// 2. Some but not all elements had beed put into cache, and we stoped.
// An iterator now is staying at the end of cache. (a temporal end)
mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter) {
mcld::sys::fs::PathCache::entry_type* entry = 0;
fs::Path file_filter(pIter.m_pParent->m_Path);
file_filter.append("*");
WIN32_FIND_DATA FindFileData;
if (FindNextFile(reinterpret_cast<HANDLE>(pIter.m_pParent->m_Handler),
&FindFileData)) {
// read one
bool exist = false;
std::string path(pIter.m_pParent->m_Path.native());
path += separator;
path += std::string(FindFileData.cFileName);
entry = pIter.m_pParent->m_Cache.insert(path, exist);
if (!exist)
entry->setValue(path);
} else if (ERROR_NO_MORE_FILES == GetLastError()) {
// meet real end
pIter.m_pParent->m_CacheFull = true;
} else {
llvm::report_fatal_error(std::string("Can't read directory: ") +
pIter.m_pParent->path().native());
}
return entry;
}
} // namespace detail
} // namespace fs
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,50 @@
//===- System.inc ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <string>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
namespace mcld {
namespace sys {
char* strerror(int errnum) {
return std::strerror(errnum);
}
std::string getDefaultTargetTriple() {
return MCLD_DEFAULT_TARGET_TRIPLE;
}
int GetPageSize() {
static int _pagesize = 0;
if (!_pagesize) {
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
_pagesize = sysinfo.dwPageSize;
}
return _pagesize;
}
/// random - generate a random number.
long GetRandomNum() {
return ::rand();
}
/// srandom - set the initial seed value for future calls to random().
void SetRandomSeed(unsigned pSeed) {
::srand(pSeed);
}
} // namespace sys
} // namespace mcld

View file

@ -0,0 +1,104 @@
//===- raw_ostream.cpp ----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Config/Config.h"
#include "mcld/Support/raw_ostream.h"
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#if defined(__CYGWIN__) || defined(_MSC_VER) || defined(__MINGW32__)
#include <io.h>
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#endif
namespace mcld {
//===----------------------------------------------------------------------===//
// raw_ostream
//===----------------------------------------------------------------------===//
raw_fd_ostream::raw_fd_ostream(const char* pFilename,
std::error_code& pErrorCode,
llvm::sys::fs::OpenFlags pFlags)
: llvm::raw_fd_ostream(pFilename, pErrorCode, pFlags),
m_bConfigColor(false),
m_bSetColor(false) {
}
raw_fd_ostream::raw_fd_ostream(int pFD,
bool pShouldClose,
bool pUnbuffered)
: llvm::raw_fd_ostream(pFD, pShouldClose, pUnbuffered),
m_bConfigColor(false),
m_bSetColor(false) {
}
raw_fd_ostream::~raw_fd_ostream() {
}
void raw_fd_ostream::setColor(bool pEnable) {
m_bConfigColor = true;
m_bSetColor = pEnable;
}
llvm::raw_ostream& raw_fd_ostream::changeColor(
enum llvm::raw_ostream::Colors pColor,
bool pBold,
bool pBackground) {
if (!is_displayed())
return *this;
return llvm::raw_fd_ostream::changeColor(pColor, pBold, pBackground);
}
llvm::raw_ostream& raw_fd_ostream::resetColor() {
if (!is_displayed())
return *this;
return llvm::raw_fd_ostream::resetColor();
}
llvm::raw_ostream& raw_fd_ostream::reverseColor() {
if (!is_displayed())
return *this;
return llvm::raw_ostream::reverseColor();
}
bool raw_fd_ostream::is_displayed() const {
if (m_bConfigColor)
return m_bSetColor;
return llvm::raw_fd_ostream::is_displayed();
}
//===----------------------------------------------------------------------===//
// outs(), errs(), nulls()
//===----------------------------------------------------------------------===//
raw_fd_ostream& outs() {
// Set buffer settings to model stdout behavior.
static raw_fd_ostream S(STDOUT_FILENO, false);
return S;
}
raw_fd_ostream& errs() {
// Set standard error to be unbuffered by default.
static raw_fd_ostream S(STDERR_FILENO, false, true);
return S;
}
} // namespace mcld