diff options
author | Shankar Easwaran <shankare@codeaurora.org> | 2012-11-13 18:38:42 +0000 |
---|---|---|
committer | Shankar Easwaran <shankare@codeaurora.org> | 2012-11-13 18:38:42 +0000 |
commit | 206252cc9f5509b27aa0761c677fdee8daff001c (patch) | |
tree | 10ffe1df6508703df2117670df2f4f0e38076d98 /lib/Object | |
parent | f7414823871c7707a6af61c19e5f9ce3a4fa861c (diff) |
Adding changes to support GNU style archive library reading
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@167853 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Object')
-rw-r--r-- | lib/Object/Archive.cpp | 144 |
1 files changed, 118 insertions, 26 deletions
diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 2a5951ada5..b55dab8f85 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -122,7 +122,14 @@ error_code Archive::Child::getName(StringRef &Result) const { + sizeof(ArchiveMemberHeader) + Parent->StringTable->getSize())) return object_error::parse_failed; - Result = addr; + + // GNU long file names end with a /. + if (Parent->kind() == K_GNU) { + StringRef::size_type End = StringRef(addr).find('/'); + Result = StringRef(addr, End); + } else { + Result = addr; + } return object_error::success; } else if (name.startswith("#1/")) { APInt name_size; @@ -187,15 +194,52 @@ Archive::Archive(MemoryBuffer *source, error_code &ec) child_iterator i = begin_children(false); child_iterator e = end_children(); - if (i != e) ++i; // Nobody cares about the first member. - if (i != e) { - SymbolTable = i; - ++i; - } - if (i != e) { - StringTable = i; - } + StringRef name; + if ((ec = i->getName(name))) + return; + // Below is the pattern that is used to figure out the archive format + // GNU archive format + // First member : / (points to the symbol table ) + // 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 + // of the filename that needs to be read after the archive header + // COFF archive format + // First member : / + // Second member : / (provides a directory of symbols) + // Third member : // contains the string table, this is present even if the + // string table is empty + if (name == "/") { + SymbolTable = i; + StringTable = e; + if (i != e) ++i; + if ((ec = i->getName(name))) + return; + if (name[0] != '/') { + Format = K_GNU; + } else if ((name.size() > 1) && (name == "//")) { + Format = K_GNU; + StringTable = i; + ++i; + } else { + Format = K_COFF; + if (i != e) { + SymbolTable = i; + ++i; + } + if (i != e) { + StringTable = i; + } + } + } else if (name == "__.SYMDEF") { + Format = K_BSD; + SymbolTable = i; + StringTable = e; + } ec = object_error::success; } @@ -222,17 +266,28 @@ error_code Archive::Symbol::getName(StringRef &Result) const { error_code Archive::Symbol::getMember(child_iterator &Result) const { const char *buf = Parent->SymbolTable->getBuffer()->getBufferStart(); - uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); const char *offsets = buf + 4; - buf += 4 + (member_count * 4); // Skip offsets. - const char *indicies = buf + 4; - - uint16_t offsetindex = - *(reinterpret_cast<const support::ulittle16_t*>(indicies) - + SymbolIndex); - - uint32_t offset = *(reinterpret_cast<const support::ulittle32_t*>(offsets) - + (offsetindex - 1)); + uint32_t offset = 0; + if (Parent->kind() == K_GNU) { + offset = *(reinterpret_cast<const support::ubig32_t*>(offsets) + + SymbolIndex); + } else if (Parent->kind() == K_BSD) { + assert("BSD format is not supported"); + } else { + uint32_t member_count = 0; + member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (member_count * 4); // Skip offsets. + const char *indicies = buf + 4; + uint16_t offsetindex = + *(reinterpret_cast<const support::ulittle16_t*>(indicies) + + SymbolIndex); + uint32_t *offsetaddr = + (uint32_t *)(reinterpret_cast<const support::ulittle32_t*>(offsets) + + (offsetindex - 1)); + assert((const char *)offsetaddr < + Parent->SymbolTable->getBuffer()->getBufferEnd()); + offset = *(offsetaddr); + } const char *Loc = Parent->getData().begin() + offset; size_t Size = sizeof(ArchiveMemberHeader) + @@ -253,10 +308,20 @@ Archive::Symbol Archive::Symbol::getNext() const { Archive::symbol_iterator Archive::begin_symbols() const { const char *buf = SymbolTable->getBuffer()->getBufferStart(); - uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); - buf += 4 + (member_count * 4); // Skip offsets. - uint32_t symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf); - buf += 4 + (symbol_count * 2); // Skip indices. + if (kind() == K_GNU) { + uint32_t symbol_count = 0; + symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf); + buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); + } else if (kind() == K_BSD) { + assert("BSD archive format is not supported"); + } else { + uint32_t member_count = 0; + uint32_t symbol_count = 0; + member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (member_count * 4); // Skip offsets. + symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (symbol_count * 2); // Skip indices. + } uint32_t string_start_offset = buf - SymbolTable->getBuffer()->getBufferStart(); return symbol_iterator(Symbol(this, 0, string_start_offset)); @@ -264,9 +329,36 @@ Archive::symbol_iterator Archive::begin_symbols() const { Archive::symbol_iterator Archive::end_symbols() const { const char *buf = SymbolTable->getBuffer()->getBufferStart(); - uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); - buf += 4 + (member_count * 4); // Skip offsets. - uint32_t symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + uint32_t symbol_count = 0; + if (kind() == K_GNU) { + symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf); + buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); + } else if (kind() == K_BSD) { + assert("BSD archive format is not supported"); + } else { + uint32_t member_count = 0; + member_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + buf += 4 + (member_count * 4); // Skip offsets. + symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf); + } return symbol_iterator( Symbol(this, symbol_count, 0)); } + +Archive::child_iterator Archive::findSym(StringRef name) const { + Archive::symbol_iterator bs = begin_symbols(); + Archive::symbol_iterator es = end_symbols(); + Archive::child_iterator result; + + StringRef symname; + for (; bs != es; ++bs) { + if (bs->getName(symname)) + return end_children(); + if (symname == name) { + if (bs->getMember(result)) + return end_children(); + return result; + } + } + return end_children(); +} |