mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-01 15:40:46 +00:00
First kinda/sorta working version of the Archive library. Reading is not
yet supported but writing works. Way too early to review this. More to come git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17499 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
07adb2836b
commit
362cbf0d74
24
lib/Archive/Archive.cpp
Normal file
24
lib/Archive/Archive.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Reid Spencer and is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Builds up standard unix archive files (.a) containing LLVM bytecode.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ArchiveInternals.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
Archive::Archive() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive::~Archive() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: sw=2 ai
|
158
lib/Archive/ArchiveInternals.h
Normal file
158
lib/Archive/ArchiveInternals.h
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
//===-- lib/Bytecode/ArchiveInternals.h -------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Reid Spencer and is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Internal implementation header for LLVM Archive files.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LIB_BYTECODE_ARCHIVEINTERNALS_H
|
||||||
|
#define LIB_BYTECODE_ARCHIVEINTERNALS_H
|
||||||
|
|
||||||
|
#include "llvm/Bytecode/Archive.h"
|
||||||
|
#include "llvm/System/TimeValue.h"
|
||||||
|
|
||||||
|
#define ARFILE_MAGIC "!<arch>\n" ///< magic string
|
||||||
|
#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1) ///< length of magic string
|
||||||
|
#define ARFILE_SYMTAB_NAME "/" ///< name of symtab entry
|
||||||
|
#define ARFILE_STRTAB_NAME "//" ///< name of strtab entry
|
||||||
|
#define ARFILE_PAD '\n' ///< inter-file align padding
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
/// The ArchiveMemberHeader structure is used internally for bytecode archives.
|
||||||
|
/// The header precedes each file member in the archive. This structure is
|
||||||
|
/// defined using character arrays for direct and correct interpretation
|
||||||
|
/// regardless of the endianess of the machine that produced it.
|
||||||
|
/// @brief Archive File Member Header
|
||||||
|
class ArchiveMemberHeader {
|
||||||
|
public:
|
||||||
|
void init() {
|
||||||
|
memset(name,' ',16);
|
||||||
|
memset(date,' ',12);
|
||||||
|
memset(uid,' ',6);
|
||||||
|
memset(gid,' ',6);
|
||||||
|
memset(mode,' ',8);
|
||||||
|
memset(size,' ',10);
|
||||||
|
fmag[0] = '`';
|
||||||
|
fmag[1] = '\n';
|
||||||
|
}
|
||||||
|
void setDate( int secondsSinceEpoch = 0 ) {
|
||||||
|
if (secondsSinceEpoch == 0) {
|
||||||
|
sys::TimeValue tv = sys::TimeValue::now();
|
||||||
|
uint64_t secs; uint32_t nanos;
|
||||||
|
tv.GetTimespecTime(secs,nanos);
|
||||||
|
secondsSinceEpoch = (int) secs;
|
||||||
|
}
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer,"%d", secondsSinceEpoch);
|
||||||
|
memcpy(date,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize(size_t sz) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%u", (unsigned)sz);
|
||||||
|
memcpy(size,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMode(int m) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%o", m);
|
||||||
|
memcpy(mode,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUid(unsigned u) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%u", u);
|
||||||
|
memcpy(uid,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGid(unsigned g) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%u", g);
|
||||||
|
memcpy(gid,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setName(const std::string& nm) {
|
||||||
|
if (nm.length() > 0 && nm.length() <= 16) {
|
||||||
|
memcpy(name,nm.c_str(),nm.length());
|
||||||
|
for (int i = nm.length()+1; i < 16; i++ ) name[i] = ' ';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char name[16]; ///< Name of the file member. The filename is terminated with '/'
|
||||||
|
///< and blanks. The empty name (/ and 15 blanks) is for the
|
||||||
|
///< symbol table. The special name "//" and 15 blanks is for
|
||||||
|
///< the string table, used for long file names. It must be
|
||||||
|
///< first in the archive.
|
||||||
|
char date[12]; ///< File date, decimal seconds since Epoch
|
||||||
|
char uid[6]; ///< user id in ASCII decimal
|
||||||
|
char gid[6]; ///< group id in ASCII decimal
|
||||||
|
char mode[8]; ///< file mode in ASCII octal
|
||||||
|
char size[10]; ///< file size in ASCII decimal
|
||||||
|
char fmag[2]; ///< Always contains ARFILE_MAGIC_TERMINATOR
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The ArchiveInternals class is used to hold the content of the archive
|
||||||
|
/// while it is in memory. It also provides the bulk of the implementation for
|
||||||
|
/// the llvm:Archive class's interface.
|
||||||
|
class Archive::ArchiveInternals {
|
||||||
|
/// @name Types
|
||||||
|
/// @{
|
||||||
|
public:
|
||||||
|
typedef std::vector<std::string> StrTab;
|
||||||
|
|
||||||
|
/// This structure holds information for one member in the archive. It is
|
||||||
|
/// used temporarily while the contents of the archive are being
|
||||||
|
/// determined.
|
||||||
|
struct MemberInfo {
|
||||||
|
MemberInfo() {}
|
||||||
|
sys::Path path;
|
||||||
|
std::string name;
|
||||||
|
sys::Path::StatusInfo status;
|
||||||
|
StrTab symbols;
|
||||||
|
unsigned offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Methods
|
||||||
|
/// @{
|
||||||
|
public:
|
||||||
|
/// @brief Add a file member to the archive.
|
||||||
|
void addFileMember(
|
||||||
|
const sys::Path& path, ///< The path to the file to be added
|
||||||
|
const std::string& name, ///< The name for the member
|
||||||
|
const StrTab* syms = 0 ///< The symbol table of the member
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @brief Write the accumulated archive information to an archive file
|
||||||
|
void writeArchive();
|
||||||
|
void writeMember(const MemberInfo& member,std::ofstream& ARFile);
|
||||||
|
void writeSymbolTable(std::ofstream& ARFile);
|
||||||
|
void writeInteger(int num, std::ofstream& ARFile);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Data
|
||||||
|
/// @{
|
||||||
|
private:
|
||||||
|
friend class Archive; ///< Parent class is a friend
|
||||||
|
sys::Path fname; ///< Path to the archive file
|
||||||
|
std::vector<MemberInfo> members; ///< Info about member files
|
||||||
|
Archive::SymTab* symtab; ///< User's symbol table
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: sw=2 ai
|
284
lib/Archive/ArchiveWriter.cpp
Normal file
284
lib/Archive/ArchiveWriter.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
//===-- ArchiveWriter.cpp - LLVM archive writing --------------------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Reid Spencerand is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Builds up standard unix archive files (.a) containing LLVM bytecode.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ArchiveInternals.h"
|
||||||
|
#include "llvm/Module.h"
|
||||||
|
#include "llvm/Bytecode/Reader.h"
|
||||||
|
#include "llvm/Support/FileUtilities.h"
|
||||||
|
#include "llvm/ADT/StringExtras.h"
|
||||||
|
#include "llvm/System/MappedFile.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
Archive*
|
||||||
|
Archive::CreateEmpty(const sys::Path& Filename) {
|
||||||
|
Archive* result = new Archive;
|
||||||
|
Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
|
||||||
|
impl->fname = Filename;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive*
|
||||||
|
Archive::CreateFromFiles(
|
||||||
|
const sys::Path& Filename,
|
||||||
|
const PathList& Files,
|
||||||
|
const std::string& StripName
|
||||||
|
) {
|
||||||
|
Archive* result = new Archive;
|
||||||
|
Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
|
||||||
|
impl->fname = Filename;
|
||||||
|
|
||||||
|
try {
|
||||||
|
size_t strip_len = StripName.length();
|
||||||
|
for (PathList::const_iterator P = Files.begin(), E = Files.end(); P != E ;++P)
|
||||||
|
{
|
||||||
|
if (P->readable()) {
|
||||||
|
std::string name(P->get());
|
||||||
|
if (strip_len > 0 && StripName == name.substr(0,strip_len)) {
|
||||||
|
name.erase(0,strip_len);
|
||||||
|
}
|
||||||
|
if (P->isBytecodeFile()) {
|
||||||
|
std::vector<std::string> syms;
|
||||||
|
if (!GetBytecodeSymbols(*P, syms))
|
||||||
|
throw std::string("Can not get symbols from: ") + P->get();
|
||||||
|
impl->addFileMember(*P, name, &syms);
|
||||||
|
} else {
|
||||||
|
impl->addFileMember(*P, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::string("Can not read: ") + P->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we've collected everything, write the archive
|
||||||
|
impl->writeArchive();
|
||||||
|
|
||||||
|
} catch(...) {
|
||||||
|
delete impl;
|
||||||
|
result->impl = 0;
|
||||||
|
delete result;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::addFileMember(
|
||||||
|
const sys::Path& filePath,
|
||||||
|
const std::string& memberName,
|
||||||
|
const StrTab* symbols
|
||||||
|
) {
|
||||||
|
MemberInfo info;
|
||||||
|
info.path = filePath;
|
||||||
|
info.name = memberName;
|
||||||
|
filePath.getStatusInfo(info.status);
|
||||||
|
if (symbols)
|
||||||
|
info.symbols = *symbols;
|
||||||
|
info.offset = 0;
|
||||||
|
members.push_back(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeInteger(int num, std::ofstream& ARFile) {
|
||||||
|
char buff[4];
|
||||||
|
buff[0] = (num >> 24) & 255;
|
||||||
|
buff[1] = (num >> 16) & 255;
|
||||||
|
buff[2] = (num >> 8) & 255;
|
||||||
|
buff[3] = num & 255;
|
||||||
|
ARFile.write(buff, sizeof(buff));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeSymbolTable( std::ofstream& ARFile ) {
|
||||||
|
|
||||||
|
// Compute the number of symbols in the symbol table and the
|
||||||
|
// total byte size of the string pool. While we're traversing,
|
||||||
|
// build the string pool for supporting long file names. Also,
|
||||||
|
// build the table of file offsets for the symbol table and
|
||||||
|
// the
|
||||||
|
typedef std::map<std::string,unsigned> SymbolMap;
|
||||||
|
StrTab stringPool;
|
||||||
|
SymbolMap symbolTable;
|
||||||
|
std::vector<unsigned> fileOffsets;
|
||||||
|
std::string symTabStrings;
|
||||||
|
unsigned fileOffset = 0;
|
||||||
|
unsigned spOffset = 0;
|
||||||
|
unsigned numSymbols = 0;
|
||||||
|
unsigned numSymBytes = 0;
|
||||||
|
for (unsigned i = 0; i < members.size(); i++ ) {
|
||||||
|
MemberInfo& mi = members[i];
|
||||||
|
StrTab& syms = mi.symbols;
|
||||||
|
size_t numSym = syms.size();
|
||||||
|
numSymbols += numSym;
|
||||||
|
for (unsigned j = 0; j < numSym; j++ ) {
|
||||||
|
numSymBytes += syms[j].size() + 1;
|
||||||
|
symbolTable[syms[i]] = i;
|
||||||
|
}
|
||||||
|
if (mi.name.length() > 15 || std::string::npos != mi.name.find('/')) {
|
||||||
|
stringPool.push_back(mi.name + "/\n");
|
||||||
|
mi.name = std::string("/") + utostr(spOffset);
|
||||||
|
spOffset += mi.name.length() + 2;
|
||||||
|
} else if (mi.name[mi.name.length()-1] != '/') {
|
||||||
|
mi.name += "/";
|
||||||
|
}
|
||||||
|
fileOffsets.push_back(fileOffset);
|
||||||
|
fileOffset += sizeof(ArchiveMemberHeader) + mi.status.fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compute the size of the symbol table file member
|
||||||
|
unsigned symTabSize = 0;
|
||||||
|
if (numSymbols != 0)
|
||||||
|
symTabSize =
|
||||||
|
sizeof(ArchiveMemberHeader) + // Size of the file header
|
||||||
|
4 + // Size of "number of entries"
|
||||||
|
(4 * numSymbols) + // Size of member file indices
|
||||||
|
numSymBytes; // Size of the string table
|
||||||
|
|
||||||
|
// Compute the size of the string pool
|
||||||
|
unsigned strPoolSize = 0;
|
||||||
|
if (spOffset != 0 )
|
||||||
|
strPoolSize =
|
||||||
|
sizeof(ArchiveMemberHeader) + // Size of the file header
|
||||||
|
spOffset; // Number of bytes in the string pool
|
||||||
|
|
||||||
|
// Compute the byte index offset created by symbol table and string pool
|
||||||
|
unsigned firstFileOffset = symTabSize + strPoolSize;
|
||||||
|
|
||||||
|
// Create header for symbol table. This must be first if there is
|
||||||
|
// a symbol table and must have a special name.
|
||||||
|
if ( symTabSize > 0 ) {
|
||||||
|
ArchiveMemberHeader Hdr;
|
||||||
|
Hdr.init();
|
||||||
|
|
||||||
|
// Name of symbol table is '/ ' but "" is passed in
|
||||||
|
// because the setName method always terminates with a /
|
||||||
|
Hdr.setName(ARFILE_SYMTAB_NAME);
|
||||||
|
Hdr.setDate();
|
||||||
|
Hdr.setSize(symTabSize - sizeof(ArchiveMemberHeader));
|
||||||
|
Hdr.setMode(0);
|
||||||
|
Hdr.setUid(0);
|
||||||
|
Hdr.setGid(0);
|
||||||
|
|
||||||
|
// Write header to archive file
|
||||||
|
ARFile.write((char*)&Hdr, sizeof(Hdr));
|
||||||
|
|
||||||
|
// Write the number of entries in the symbol table
|
||||||
|
this->writeInteger(numSymbols, ARFile);
|
||||||
|
|
||||||
|
// Write the file offset indices for each symbol and build the
|
||||||
|
// symbol table string pool
|
||||||
|
std::string symTabStrPool;
|
||||||
|
symTabStrPool.reserve(256 * 1024); // Reserve 256KBytes for symbols
|
||||||
|
for (SymbolMap::iterator I = symbolTable.begin(), E = symbolTable.end();
|
||||||
|
I != E; ++I ) {
|
||||||
|
this->writeInteger(firstFileOffset + fileOffsets[I->second], ARFile);
|
||||||
|
symTabStrPool += I->first;
|
||||||
|
symTabStrPool += "\0";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the symbol table's string pool
|
||||||
|
ARFile.write(symTabStrPool.data(), symTabStrPool.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//============== DONE WITH SYMBOL TABLE
|
||||||
|
|
||||||
|
if (strPoolSize > 0) {
|
||||||
|
// Initialize the header for the string pool
|
||||||
|
ArchiveMemberHeader Hdr;
|
||||||
|
Hdr.init();
|
||||||
|
Hdr.setName(ARFILE_STRTAB_NAME);
|
||||||
|
Hdr.setDate();
|
||||||
|
Hdr.setSize(spOffset);
|
||||||
|
Hdr.setMode(0);
|
||||||
|
Hdr.setUid(0);
|
||||||
|
Hdr.setGid(0);
|
||||||
|
|
||||||
|
// Write the string pool header
|
||||||
|
ARFile.write((char*)&Hdr, sizeof(Hdr));
|
||||||
|
|
||||||
|
// Write the string pool
|
||||||
|
for (unsigned i = 0; i < stringPool.size(); i++) {
|
||||||
|
ARFile.write(stringPool[i].data(), stringPool[i].size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeMember(
|
||||||
|
const MemberInfo& member,
|
||||||
|
std::ofstream& ARFile
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Map the file into memory. We do this early for two reasons. First,
|
||||||
|
// if there's any kind of error, we want to know about it. Second, we
|
||||||
|
// want to ensure we're using the most recent size for this file.
|
||||||
|
sys::MappedFile mFile(member.path);
|
||||||
|
mFile.map();
|
||||||
|
|
||||||
|
// Header for the archive member
|
||||||
|
ArchiveMemberHeader Hdr;
|
||||||
|
Hdr.init();
|
||||||
|
|
||||||
|
// Set the name. If its longer than 15 chars, it will have already
|
||||||
|
// been reduced by the writeSymbolTable.
|
||||||
|
Hdr.setName(member.name);
|
||||||
|
|
||||||
|
// Set the other header members
|
||||||
|
Hdr.setSize( mFile.size() );
|
||||||
|
Hdr.setMode( member.status.mode);
|
||||||
|
Hdr.setUid ( member.status.user);
|
||||||
|
Hdr.setGid ( member.status.group);
|
||||||
|
Hdr.setDate( member.status.modTime.ToPosixTime() );
|
||||||
|
|
||||||
|
// Write header to archive file
|
||||||
|
ARFile.write((char*)&Hdr, sizeof(Hdr));
|
||||||
|
|
||||||
|
//write to archive file
|
||||||
|
ARFile.write(mFile.charBase(),mFile.size());
|
||||||
|
|
||||||
|
mFile.unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeArchive() {
|
||||||
|
|
||||||
|
// Create archive file for output.
|
||||||
|
std::ofstream ArchiveFile(fname.get().c_str());
|
||||||
|
|
||||||
|
// Check for errors opening or creating archive file.
|
||||||
|
if ( !ArchiveFile.is_open() || ArchiveFile.bad() ) {
|
||||||
|
throw std::string("Error opening archive file: ") + fname.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write magic string to archive.
|
||||||
|
ArchiveFile << ARFILE_MAGIC;
|
||||||
|
|
||||||
|
// Write the symbol table and string pool
|
||||||
|
writeSymbolTable(ArchiveFile);
|
||||||
|
|
||||||
|
//Loop over all member files, and add to the archive.
|
||||||
|
for ( unsigned i = 0; i < members.size(); ++i) {
|
||||||
|
if(ArchiveFile.tellp() % 2 != 0)
|
||||||
|
ArchiveFile << ARFILE_PAD;
|
||||||
|
writeMember(members[i],ArchiveFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Close archive file.
|
||||||
|
ArchiveFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: sw=2 ai
|
24
lib/Bytecode/Archive/Archive.cpp
Normal file
24
lib/Bytecode/Archive/Archive.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Reid Spencer and is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Builds up standard unix archive files (.a) containing LLVM bytecode.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ArchiveInternals.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
Archive::Archive() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive::~Archive() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: sw=2 ai
|
158
lib/Bytecode/Archive/ArchiveInternals.h
Normal file
158
lib/Bytecode/Archive/ArchiveInternals.h
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
//===-- lib/Bytecode/ArchiveInternals.h -------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Reid Spencer and is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Internal implementation header for LLVM Archive files.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LIB_BYTECODE_ARCHIVEINTERNALS_H
|
||||||
|
#define LIB_BYTECODE_ARCHIVEINTERNALS_H
|
||||||
|
|
||||||
|
#include "llvm/Bytecode/Archive.h"
|
||||||
|
#include "llvm/System/TimeValue.h"
|
||||||
|
|
||||||
|
#define ARFILE_MAGIC "!<arch>\n" ///< magic string
|
||||||
|
#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1) ///< length of magic string
|
||||||
|
#define ARFILE_SYMTAB_NAME "/" ///< name of symtab entry
|
||||||
|
#define ARFILE_STRTAB_NAME "//" ///< name of strtab entry
|
||||||
|
#define ARFILE_PAD '\n' ///< inter-file align padding
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
/// The ArchiveMemberHeader structure is used internally for bytecode archives.
|
||||||
|
/// The header precedes each file member in the archive. This structure is
|
||||||
|
/// defined using character arrays for direct and correct interpretation
|
||||||
|
/// regardless of the endianess of the machine that produced it.
|
||||||
|
/// @brief Archive File Member Header
|
||||||
|
class ArchiveMemberHeader {
|
||||||
|
public:
|
||||||
|
void init() {
|
||||||
|
memset(name,' ',16);
|
||||||
|
memset(date,' ',12);
|
||||||
|
memset(uid,' ',6);
|
||||||
|
memset(gid,' ',6);
|
||||||
|
memset(mode,' ',8);
|
||||||
|
memset(size,' ',10);
|
||||||
|
fmag[0] = '`';
|
||||||
|
fmag[1] = '\n';
|
||||||
|
}
|
||||||
|
void setDate( int secondsSinceEpoch = 0 ) {
|
||||||
|
if (secondsSinceEpoch == 0) {
|
||||||
|
sys::TimeValue tv = sys::TimeValue::now();
|
||||||
|
uint64_t secs; uint32_t nanos;
|
||||||
|
tv.GetTimespecTime(secs,nanos);
|
||||||
|
secondsSinceEpoch = (int) secs;
|
||||||
|
}
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer,"%d", secondsSinceEpoch);
|
||||||
|
memcpy(date,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize(size_t sz) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%u", (unsigned)sz);
|
||||||
|
memcpy(size,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMode(int m) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%o", m);
|
||||||
|
memcpy(mode,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUid(unsigned u) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%u", u);
|
||||||
|
memcpy(uid,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGid(unsigned g) {
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%u", g);
|
||||||
|
memcpy(gid,buffer,strlen(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setName(const std::string& nm) {
|
||||||
|
if (nm.length() > 0 && nm.length() <= 16) {
|
||||||
|
memcpy(name,nm.c_str(),nm.length());
|
||||||
|
for (int i = nm.length()+1; i < 16; i++ ) name[i] = ' ';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char name[16]; ///< Name of the file member. The filename is terminated with '/'
|
||||||
|
///< and blanks. The empty name (/ and 15 blanks) is for the
|
||||||
|
///< symbol table. The special name "//" and 15 blanks is for
|
||||||
|
///< the string table, used for long file names. It must be
|
||||||
|
///< first in the archive.
|
||||||
|
char date[12]; ///< File date, decimal seconds since Epoch
|
||||||
|
char uid[6]; ///< user id in ASCII decimal
|
||||||
|
char gid[6]; ///< group id in ASCII decimal
|
||||||
|
char mode[8]; ///< file mode in ASCII octal
|
||||||
|
char size[10]; ///< file size in ASCII decimal
|
||||||
|
char fmag[2]; ///< Always contains ARFILE_MAGIC_TERMINATOR
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The ArchiveInternals class is used to hold the content of the archive
|
||||||
|
/// while it is in memory. It also provides the bulk of the implementation for
|
||||||
|
/// the llvm:Archive class's interface.
|
||||||
|
class Archive::ArchiveInternals {
|
||||||
|
/// @name Types
|
||||||
|
/// @{
|
||||||
|
public:
|
||||||
|
typedef std::vector<std::string> StrTab;
|
||||||
|
|
||||||
|
/// This structure holds information for one member in the archive. It is
|
||||||
|
/// used temporarily while the contents of the archive are being
|
||||||
|
/// determined.
|
||||||
|
struct MemberInfo {
|
||||||
|
MemberInfo() {}
|
||||||
|
sys::Path path;
|
||||||
|
std::string name;
|
||||||
|
sys::Path::StatusInfo status;
|
||||||
|
StrTab symbols;
|
||||||
|
unsigned offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Methods
|
||||||
|
/// @{
|
||||||
|
public:
|
||||||
|
/// @brief Add a file member to the archive.
|
||||||
|
void addFileMember(
|
||||||
|
const sys::Path& path, ///< The path to the file to be added
|
||||||
|
const std::string& name, ///< The name for the member
|
||||||
|
const StrTab* syms = 0 ///< The symbol table of the member
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @brief Write the accumulated archive information to an archive file
|
||||||
|
void writeArchive();
|
||||||
|
void writeMember(const MemberInfo& member,std::ofstream& ARFile);
|
||||||
|
void writeSymbolTable(std::ofstream& ARFile);
|
||||||
|
void writeInteger(int num, std::ofstream& ARFile);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Data
|
||||||
|
/// @{
|
||||||
|
private:
|
||||||
|
friend class Archive; ///< Parent class is a friend
|
||||||
|
sys::Path fname; ///< Path to the archive file
|
||||||
|
std::vector<MemberInfo> members; ///< Info about member files
|
||||||
|
Archive::SymTab* symtab; ///< User's symbol table
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: sw=2 ai
|
284
lib/Bytecode/Archive/ArchiveWriter.cpp
Normal file
284
lib/Bytecode/Archive/ArchiveWriter.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
//===-- ArchiveWriter.cpp - LLVM archive writing --------------------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Reid Spencerand is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Builds up standard unix archive files (.a) containing LLVM bytecode.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ArchiveInternals.h"
|
||||||
|
#include "llvm/Module.h"
|
||||||
|
#include "llvm/Bytecode/Reader.h"
|
||||||
|
#include "llvm/Support/FileUtilities.h"
|
||||||
|
#include "llvm/ADT/StringExtras.h"
|
||||||
|
#include "llvm/System/MappedFile.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
Archive*
|
||||||
|
Archive::CreateEmpty(const sys::Path& Filename) {
|
||||||
|
Archive* result = new Archive;
|
||||||
|
Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
|
||||||
|
impl->fname = Filename;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive*
|
||||||
|
Archive::CreateFromFiles(
|
||||||
|
const sys::Path& Filename,
|
||||||
|
const PathList& Files,
|
||||||
|
const std::string& StripName
|
||||||
|
) {
|
||||||
|
Archive* result = new Archive;
|
||||||
|
Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
|
||||||
|
impl->fname = Filename;
|
||||||
|
|
||||||
|
try {
|
||||||
|
size_t strip_len = StripName.length();
|
||||||
|
for (PathList::const_iterator P = Files.begin(), E = Files.end(); P != E ;++P)
|
||||||
|
{
|
||||||
|
if (P->readable()) {
|
||||||
|
std::string name(P->get());
|
||||||
|
if (strip_len > 0 && StripName == name.substr(0,strip_len)) {
|
||||||
|
name.erase(0,strip_len);
|
||||||
|
}
|
||||||
|
if (P->isBytecodeFile()) {
|
||||||
|
std::vector<std::string> syms;
|
||||||
|
if (!GetBytecodeSymbols(*P, syms))
|
||||||
|
throw std::string("Can not get symbols from: ") + P->get();
|
||||||
|
impl->addFileMember(*P, name, &syms);
|
||||||
|
} else {
|
||||||
|
impl->addFileMember(*P, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::string("Can not read: ") + P->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we've collected everything, write the archive
|
||||||
|
impl->writeArchive();
|
||||||
|
|
||||||
|
} catch(...) {
|
||||||
|
delete impl;
|
||||||
|
result->impl = 0;
|
||||||
|
delete result;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::addFileMember(
|
||||||
|
const sys::Path& filePath,
|
||||||
|
const std::string& memberName,
|
||||||
|
const StrTab* symbols
|
||||||
|
) {
|
||||||
|
MemberInfo info;
|
||||||
|
info.path = filePath;
|
||||||
|
info.name = memberName;
|
||||||
|
filePath.getStatusInfo(info.status);
|
||||||
|
if (symbols)
|
||||||
|
info.symbols = *symbols;
|
||||||
|
info.offset = 0;
|
||||||
|
members.push_back(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeInteger(int num, std::ofstream& ARFile) {
|
||||||
|
char buff[4];
|
||||||
|
buff[0] = (num >> 24) & 255;
|
||||||
|
buff[1] = (num >> 16) & 255;
|
||||||
|
buff[2] = (num >> 8) & 255;
|
||||||
|
buff[3] = num & 255;
|
||||||
|
ARFile.write(buff, sizeof(buff));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeSymbolTable( std::ofstream& ARFile ) {
|
||||||
|
|
||||||
|
// Compute the number of symbols in the symbol table and the
|
||||||
|
// total byte size of the string pool. While we're traversing,
|
||||||
|
// build the string pool for supporting long file names. Also,
|
||||||
|
// build the table of file offsets for the symbol table and
|
||||||
|
// the
|
||||||
|
typedef std::map<std::string,unsigned> SymbolMap;
|
||||||
|
StrTab stringPool;
|
||||||
|
SymbolMap symbolTable;
|
||||||
|
std::vector<unsigned> fileOffsets;
|
||||||
|
std::string symTabStrings;
|
||||||
|
unsigned fileOffset = 0;
|
||||||
|
unsigned spOffset = 0;
|
||||||
|
unsigned numSymbols = 0;
|
||||||
|
unsigned numSymBytes = 0;
|
||||||
|
for (unsigned i = 0; i < members.size(); i++ ) {
|
||||||
|
MemberInfo& mi = members[i];
|
||||||
|
StrTab& syms = mi.symbols;
|
||||||
|
size_t numSym = syms.size();
|
||||||
|
numSymbols += numSym;
|
||||||
|
for (unsigned j = 0; j < numSym; j++ ) {
|
||||||
|
numSymBytes += syms[j].size() + 1;
|
||||||
|
symbolTable[syms[i]] = i;
|
||||||
|
}
|
||||||
|
if (mi.name.length() > 15 || std::string::npos != mi.name.find('/')) {
|
||||||
|
stringPool.push_back(mi.name + "/\n");
|
||||||
|
mi.name = std::string("/") + utostr(spOffset);
|
||||||
|
spOffset += mi.name.length() + 2;
|
||||||
|
} else if (mi.name[mi.name.length()-1] != '/') {
|
||||||
|
mi.name += "/";
|
||||||
|
}
|
||||||
|
fileOffsets.push_back(fileOffset);
|
||||||
|
fileOffset += sizeof(ArchiveMemberHeader) + mi.status.fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compute the size of the symbol table file member
|
||||||
|
unsigned symTabSize = 0;
|
||||||
|
if (numSymbols != 0)
|
||||||
|
symTabSize =
|
||||||
|
sizeof(ArchiveMemberHeader) + // Size of the file header
|
||||||
|
4 + // Size of "number of entries"
|
||||||
|
(4 * numSymbols) + // Size of member file indices
|
||||||
|
numSymBytes; // Size of the string table
|
||||||
|
|
||||||
|
// Compute the size of the string pool
|
||||||
|
unsigned strPoolSize = 0;
|
||||||
|
if (spOffset != 0 )
|
||||||
|
strPoolSize =
|
||||||
|
sizeof(ArchiveMemberHeader) + // Size of the file header
|
||||||
|
spOffset; // Number of bytes in the string pool
|
||||||
|
|
||||||
|
// Compute the byte index offset created by symbol table and string pool
|
||||||
|
unsigned firstFileOffset = symTabSize + strPoolSize;
|
||||||
|
|
||||||
|
// Create header for symbol table. This must be first if there is
|
||||||
|
// a symbol table and must have a special name.
|
||||||
|
if ( symTabSize > 0 ) {
|
||||||
|
ArchiveMemberHeader Hdr;
|
||||||
|
Hdr.init();
|
||||||
|
|
||||||
|
// Name of symbol table is '/ ' but "" is passed in
|
||||||
|
// because the setName method always terminates with a /
|
||||||
|
Hdr.setName(ARFILE_SYMTAB_NAME);
|
||||||
|
Hdr.setDate();
|
||||||
|
Hdr.setSize(symTabSize - sizeof(ArchiveMemberHeader));
|
||||||
|
Hdr.setMode(0);
|
||||||
|
Hdr.setUid(0);
|
||||||
|
Hdr.setGid(0);
|
||||||
|
|
||||||
|
// Write header to archive file
|
||||||
|
ARFile.write((char*)&Hdr, sizeof(Hdr));
|
||||||
|
|
||||||
|
// Write the number of entries in the symbol table
|
||||||
|
this->writeInteger(numSymbols, ARFile);
|
||||||
|
|
||||||
|
// Write the file offset indices for each symbol and build the
|
||||||
|
// symbol table string pool
|
||||||
|
std::string symTabStrPool;
|
||||||
|
symTabStrPool.reserve(256 * 1024); // Reserve 256KBytes for symbols
|
||||||
|
for (SymbolMap::iterator I = symbolTable.begin(), E = symbolTable.end();
|
||||||
|
I != E; ++I ) {
|
||||||
|
this->writeInteger(firstFileOffset + fileOffsets[I->second], ARFile);
|
||||||
|
symTabStrPool += I->first;
|
||||||
|
symTabStrPool += "\0";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the symbol table's string pool
|
||||||
|
ARFile.write(symTabStrPool.data(), symTabStrPool.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//============== DONE WITH SYMBOL TABLE
|
||||||
|
|
||||||
|
if (strPoolSize > 0) {
|
||||||
|
// Initialize the header for the string pool
|
||||||
|
ArchiveMemberHeader Hdr;
|
||||||
|
Hdr.init();
|
||||||
|
Hdr.setName(ARFILE_STRTAB_NAME);
|
||||||
|
Hdr.setDate();
|
||||||
|
Hdr.setSize(spOffset);
|
||||||
|
Hdr.setMode(0);
|
||||||
|
Hdr.setUid(0);
|
||||||
|
Hdr.setGid(0);
|
||||||
|
|
||||||
|
// Write the string pool header
|
||||||
|
ARFile.write((char*)&Hdr, sizeof(Hdr));
|
||||||
|
|
||||||
|
// Write the string pool
|
||||||
|
for (unsigned i = 0; i < stringPool.size(); i++) {
|
||||||
|
ARFile.write(stringPool[i].data(), stringPool[i].size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeMember(
|
||||||
|
const MemberInfo& member,
|
||||||
|
std::ofstream& ARFile
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Map the file into memory. We do this early for two reasons. First,
|
||||||
|
// if there's any kind of error, we want to know about it. Second, we
|
||||||
|
// want to ensure we're using the most recent size for this file.
|
||||||
|
sys::MappedFile mFile(member.path);
|
||||||
|
mFile.map();
|
||||||
|
|
||||||
|
// Header for the archive member
|
||||||
|
ArchiveMemberHeader Hdr;
|
||||||
|
Hdr.init();
|
||||||
|
|
||||||
|
// Set the name. If its longer than 15 chars, it will have already
|
||||||
|
// been reduced by the writeSymbolTable.
|
||||||
|
Hdr.setName(member.name);
|
||||||
|
|
||||||
|
// Set the other header members
|
||||||
|
Hdr.setSize( mFile.size() );
|
||||||
|
Hdr.setMode( member.status.mode);
|
||||||
|
Hdr.setUid ( member.status.user);
|
||||||
|
Hdr.setGid ( member.status.group);
|
||||||
|
Hdr.setDate( member.status.modTime.ToPosixTime() );
|
||||||
|
|
||||||
|
// Write header to archive file
|
||||||
|
ARFile.write((char*)&Hdr, sizeof(Hdr));
|
||||||
|
|
||||||
|
//write to archive file
|
||||||
|
ARFile.write(mFile.charBase(),mFile.size());
|
||||||
|
|
||||||
|
mFile.unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Archive::ArchiveInternals::writeArchive() {
|
||||||
|
|
||||||
|
// Create archive file for output.
|
||||||
|
std::ofstream ArchiveFile(fname.get().c_str());
|
||||||
|
|
||||||
|
// Check for errors opening or creating archive file.
|
||||||
|
if ( !ArchiveFile.is_open() || ArchiveFile.bad() ) {
|
||||||
|
throw std::string("Error opening archive file: ") + fname.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write magic string to archive.
|
||||||
|
ArchiveFile << ARFILE_MAGIC;
|
||||||
|
|
||||||
|
// Write the symbol table and string pool
|
||||||
|
writeSymbolTable(ArchiveFile);
|
||||||
|
|
||||||
|
//Loop over all member files, and add to the archive.
|
||||||
|
for ( unsigned i = 0; i < members.size(); ++i) {
|
||||||
|
if(ArchiveFile.tellp() % 2 != 0)
|
||||||
|
ArchiveFile << ARFILE_PAD;
|
||||||
|
writeMember(members[i],ArchiveFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Close archive file.
|
||||||
|
ArchiveFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: sw=2 ai
|
Loading…
Reference in New Issue
Block a user