#include "llvm/Object/Archive.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace object;
-static const char *Magic = "!<arch>\n";
-
-static bool isInternalMember(const ArchiveMemberHeader &amh) {
- static const char *const internals[] = {
- "/",
- "//"
- };
-
- StringRef name = amh.getName();
- for (std::size_t i = 0; i < sizeof(internals) / sizeof(*internals); ++i) {
- if (name == internals[i])
- return true;
- }
- return false;
-}
+static const char *const Magic = "!<arch>\n";
void Archive::anchor() { }
return Ret;
}
-static const ArchiveMemberHeader *toHeader(const char *base) {
- return reinterpret_cast<const ArchiveMemberHeader *>(base);
+sys::fs::perms ArchiveMemberHeader::getAccessMode() const {
+ unsigned Ret;
+ if (StringRef(AccessMode, sizeof(AccessMode)).rtrim(" ").getAsInteger(8, Ret))
+ llvm_unreachable("Access mode is not an octal number.");
+ return static_cast<sys::fs::perms>(Ret);
+}
+
+sys::TimeValue ArchiveMemberHeader::getLastModified() const {
+ unsigned Seconds;
+ if (StringRef(LastModified, sizeof(LastModified)).rtrim(" ")
+ .getAsInteger(10, Seconds))
+ llvm_unreachable("Last modified time not a decimal number.");
+
+ sys::TimeValue Ret;
+ Ret.fromEpochTime(Seconds);
+ return Ret;
+}
+
+unsigned ArchiveMemberHeader::getUID() const {
+ unsigned Ret;
+ if (StringRef(UID, sizeof(UID)).rtrim(" ").getAsInteger(10, Ret))
+ llvm_unreachable("UID time not a decimal number.");
+ return Ret;
+}
+
+unsigned ArchiveMemberHeader::getGID() const {
+ unsigned Ret;
+ if (StringRef(GID, sizeof(GID)).rtrim(" ").getAsInteger(10, Ret))
+ llvm_unreachable("GID time not a decimal number.");
+ return Ret;
}
Archive::Child::Child(const Archive *Parent, const char *Start)
if (!Start)
return;
- const ArchiveMemberHeader *Header = toHeader(Start);
+ const ArchiveMemberHeader *Header =
+ reinterpret_cast<const ArchiveMemberHeader *>(Start);
Data = StringRef(Start, sizeof(ArchiveMemberHeader) + Header->getSize());
// Setup StartOfFile and PaddingBytes.
+ sizeof(ArchiveMemberHeader)
+ offset;
// Verify it.
- if (Parent->StringTable == Parent->end_children()
+ if (Parent->StringTable == Parent->child_end()
|| addr < (Parent->StringTable->Data.begin()
+ sizeof(ArchiveMemberHeader))
|| addr > (Parent->StringTable->Data.begin()
uint64_t name_size;
if (name.substr(3).rtrim(" ").getAsInteger(10, name_size))
llvm_unreachable("Long name length is not an ingeter");
- Result = Data.substr(sizeof(ArchiveMemberHeader), name_size);
+ Result = Data.substr(sizeof(ArchiveMemberHeader), name_size)
+ .rtrim(StringRef("\0", 1));
return object_error::success;
}
// It's a simple name.
return object_error::success;
}
-error_code Archive::Child::getMemoryBuffer(OwningPtr<MemoryBuffer> &Result,
+error_code Archive::Child::getMemoryBuffer(std::unique_ptr<MemoryBuffer> &Result,
bool FullPath) const {
StringRef Name;
if (error_code ec = getName(Name))
return error_code::success();
}
-error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const {
- OwningPtr<Binary> ret;
- OwningPtr<MemoryBuffer> Buff;
+error_code Archive::Child::getMemoryBuffer(OwningPtr<MemoryBuffer> &Result,
+ bool FullPath) const {
+ std::unique_ptr<MemoryBuffer> MB;
+ error_code ec = getMemoryBuffer(MB, FullPath);
+ Result = std::move(MB);
+ return ec;
+}
+
+error_code Archive::Child::getAsBinary(std::unique_ptr<Binary> &Result,
+ LLVMContext *Context) const {
+ std::unique_ptr<Binary> ret;
+ std::unique_ptr<MemoryBuffer> Buff;
if (error_code ec = getMemoryBuffer(Buff))
return ec;
- if (error_code ec = createBinary(Buff.take(), ret))
- return ec;
- Result.swap(ret);
+ ErrorOr<Binary *> BinaryOrErr = createBinary(Buff.release(), Context);
+ if (error_code EC = BinaryOrErr.getError())
+ return EC;
+ Result.reset(BinaryOrErr.get());
return object_error::success;
}
+error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result,
+ LLVMContext *Context) const {
+ std::unique_ptr<Binary> B;
+ error_code ec = getAsBinary(B, Context);
+ Result = std::move(B);
+ return ec;
+}
+
+ErrorOr<Archive*> Archive::create(MemoryBuffer *Source) {
+ error_code EC;
+ std::unique_ptr<Archive> Ret(new Archive(Source, EC));
+ if (EC)
+ return EC;
+ return Ret.release();
+}
+
Archive::Archive(MemoryBuffer *source, error_code &ec)
- : Binary(Binary::ID_Archive, source) {
+ : Binary(Binary::ID_Archive, source), SymbolTable(child_end()) {
// Check for sufficient magic.
- if (!source || source->getBufferSize()
- < (8 + sizeof(ArchiveMemberHeader)) // Smallest archive.
- || StringRef(source->getBufferStart(), 8) != Magic) {
+ assert(source);
+ if (source->getBufferSize() < 8 ||
+ StringRef(source->getBufferStart(), 8) != Magic) {
ec = object_error::invalid_file_type;
return;
}
// Get the special members.
- child_iterator i = begin_children(false);
- child_iterator e = end_children();
+ child_iterator i = child_begin(false);
+ child_iterator e = child_end();
if (i == e) {
- ec = object_error::parse_failed;
+ ec = object_error::success;
return;
}
// Second member : // (may exist, if it exists, points to the string table)
// Note : The string table is used if the filename exceeds 15 characters
// BSD archive format
- // First member : __.SYMDEF (points to the symbol table)
- // There is no string table, if the filename exceeds 15 characters or has a
- // embedded space, the filename has #1/<size>, The size represents the size
+ // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table)
+ // There is no string table, if the filename exceeds 15 characters or has a
+ // embedded space, the filename has #1/<size>, The size represents the size
// of the filename that needs to be read after the archive header
// COFF archive format
// First member : /
if (Name == "__.SYMDEF") {
Format = K_BSD;
SymbolTable = i;
+ ++i;
+ FirstRegular = i;
ec = object_error::success;
return;
}
+ if (Name.startswith("#1/")) {
+ Format = K_BSD;
+ // We know this is BSD, so getName will work since there is no string table.
+ ec = i->getName(Name);
+ if (ec)
+ return;
+ if (Name == "__.SYMDEF SORTED") {
+ SymbolTable = i;
+ ++i;
+ }
+ FirstRegular = i;
+ return;
+ }
+
if (Name == "/") {
SymbolTable = i;
if (Name == "//") {
Format = K_GNU;
StringTable = i;
+ ++i;
+ FirstRegular = i;
ec = object_error::success;
return;
}
if (Name[0] != '/') {
Format = K_GNU;
+ FirstRegular = i;
ec = object_error::success;
return;
}
++i;
if (i == e) {
+ FirstRegular = i;
ec = object_error::success;
return;
}
Name = i->getRawName();
- if (Name == "//")
+ if (Name == "//") {
StringTable = i;
+ ++i;
+ }
+ FirstRegular = i;
ec = object_error::success;
}
-Archive::child_iterator Archive::begin_children(bool skip_internal) const {
+Archive::child_iterator Archive::child_begin(bool SkipInternal) const {
+ if (Data->getBufferSize() == 8) // empty archive.
+ return child_end();
+
+ if (SkipInternal)
+ return FirstRegular;
+
const char *Loc = Data->getBufferStart() + strlen(Magic);
Child c(this, Loc);
- // Skip internals at the beginning of an archive.
- if (skip_internal && isInternalMember(*toHeader(Loc)))
- return c.getNext();
return c;
}
-Archive::child_iterator Archive::end_children() const {
+Archive::child_iterator Archive::child_end() const {
return Child(this, NULL);
}
return t;
}
-Archive::symbol_iterator Archive::begin_symbols() const {
+Archive::symbol_iterator Archive::symbol_begin() const {
+ if (!hasSymbolTable())
+ return symbol_iterator(Symbol(this, 0, 0));
+
const char *buf = SymbolTable->getBuffer().begin();
if (kind() == K_GNU) {
uint32_t symbol_count = 0;
return symbol_iterator(Symbol(this, 0, string_start_offset));
}
-Archive::symbol_iterator Archive::end_symbols() const {
+Archive::symbol_iterator Archive::symbol_end() const {
+ if (!hasSymbolTable())
+ return symbol_iterator(Symbol(this, 0, 0));
+
const char *buf = SymbolTable->getBuffer().begin();
uint32_t symbol_count = 0;
if (kind() == K_GNU) {
}
Archive::child_iterator Archive::findSym(StringRef name) const {
- Archive::symbol_iterator bs = begin_symbols();
- Archive::symbol_iterator es = end_symbols();
+ Archive::symbol_iterator bs = symbol_begin();
+ Archive::symbol_iterator es = symbol_end();
Archive::child_iterator result;
StringRef symname;
for (; bs != es; ++bs) {
if (bs->getName(symname))
- return end_children();
+ return child_end();
if (symname == name) {
if (bs->getMember(result))
- return end_children();
+ return child_end();
return result;
}
}
- return end_children();
+ return child_end();
+}
+
+bool Archive::hasSymbolTable() const {
+ return SymbolTable != child_end();
}