17330f729Sjoerg //===- Archive.cpp - ar File Format implementation ------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines the ArchiveObjectFile class.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "llvm/Object/Archive.h"
147330f729Sjoerg #include "llvm/ADT/Optional.h"
157330f729Sjoerg #include "llvm/ADT/SmallString.h"
167330f729Sjoerg #include "llvm/ADT/StringRef.h"
177330f729Sjoerg #include "llvm/ADT/Twine.h"
187330f729Sjoerg #include "llvm/Object/Binary.h"
197330f729Sjoerg #include "llvm/Object/Error.h"
207330f729Sjoerg #include "llvm/Support/Chrono.h"
217330f729Sjoerg #include "llvm/Support/Endian.h"
227330f729Sjoerg #include "llvm/Support/Error.h"
237330f729Sjoerg #include "llvm/Support/ErrorOr.h"
247330f729Sjoerg #include "llvm/Support/FileSystem.h"
257330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
267330f729Sjoerg #include "llvm/Support/Path.h"
277330f729Sjoerg #include "llvm/Support/raw_ostream.h"
287330f729Sjoerg #include <algorithm>
297330f729Sjoerg #include <cassert>
307330f729Sjoerg #include <cstddef>
317330f729Sjoerg #include <cstdint>
327330f729Sjoerg #include <cstring>
337330f729Sjoerg #include <memory>
347330f729Sjoerg #include <string>
357330f729Sjoerg #include <system_error>
367330f729Sjoerg
377330f729Sjoerg using namespace llvm;
387330f729Sjoerg using namespace object;
397330f729Sjoerg using namespace llvm::support::endian;
407330f729Sjoerg
41*82d56013Sjoerg const char Magic[] = "!<arch>\n";
42*82d56013Sjoerg const char ThinMagic[] = "!<thin>\n";
437330f729Sjoerg
anchor()447330f729Sjoerg void Archive::anchor() {}
457330f729Sjoerg
467330f729Sjoerg static Error
malformedError(Twine Msg)477330f729Sjoerg malformedError(Twine Msg) {
487330f729Sjoerg std::string StringMsg = "truncated or malformed archive (" + Msg.str() + ")";
497330f729Sjoerg return make_error<GenericBinaryError>(std::move(StringMsg),
507330f729Sjoerg object_error::parse_failed);
517330f729Sjoerg }
527330f729Sjoerg
ArchiveMemberHeader(const Archive * Parent,const char * RawHeaderPtr,uint64_t Size,Error * Err)537330f729Sjoerg ArchiveMemberHeader::ArchiveMemberHeader(const Archive *Parent,
547330f729Sjoerg const char *RawHeaderPtr,
557330f729Sjoerg uint64_t Size, Error *Err)
567330f729Sjoerg : Parent(Parent),
577330f729Sjoerg ArMemHdr(reinterpret_cast<const ArMemHdrType *>(RawHeaderPtr)) {
587330f729Sjoerg if (RawHeaderPtr == nullptr)
597330f729Sjoerg return;
607330f729Sjoerg ErrorAsOutParameter ErrAsOutParam(Err);
617330f729Sjoerg
627330f729Sjoerg if (Size < sizeof(ArMemHdrType)) {
637330f729Sjoerg if (Err) {
647330f729Sjoerg std::string Msg("remaining size of archive too small for next archive "
657330f729Sjoerg "member header ");
667330f729Sjoerg Expected<StringRef> NameOrErr = getName(Size);
677330f729Sjoerg if (!NameOrErr) {
687330f729Sjoerg consumeError(NameOrErr.takeError());
697330f729Sjoerg uint64_t Offset = RawHeaderPtr - Parent->getData().data();
707330f729Sjoerg *Err = malformedError(Msg + "at offset " + Twine(Offset));
717330f729Sjoerg } else
727330f729Sjoerg *Err = malformedError(Msg + "for " + NameOrErr.get());
737330f729Sjoerg }
747330f729Sjoerg return;
757330f729Sjoerg }
767330f729Sjoerg if (ArMemHdr->Terminator[0] != '`' || ArMemHdr->Terminator[1] != '\n') {
777330f729Sjoerg if (Err) {
787330f729Sjoerg std::string Buf;
797330f729Sjoerg raw_string_ostream OS(Buf);
807330f729Sjoerg OS.write_escaped(StringRef(ArMemHdr->Terminator,
817330f729Sjoerg sizeof(ArMemHdr->Terminator)));
827330f729Sjoerg OS.flush();
837330f729Sjoerg std::string Msg("terminator characters in archive member \"" + Buf +
847330f729Sjoerg "\" not the correct \"`\\n\" values for the archive "
857330f729Sjoerg "member header ");
867330f729Sjoerg Expected<StringRef> NameOrErr = getName(Size);
877330f729Sjoerg if (!NameOrErr) {
887330f729Sjoerg consumeError(NameOrErr.takeError());
897330f729Sjoerg uint64_t Offset = RawHeaderPtr - Parent->getData().data();
907330f729Sjoerg *Err = malformedError(Msg + "at offset " + Twine(Offset));
917330f729Sjoerg } else
927330f729Sjoerg *Err = malformedError(Msg + "for " + NameOrErr.get());
937330f729Sjoerg }
947330f729Sjoerg return;
957330f729Sjoerg }
967330f729Sjoerg }
977330f729Sjoerg
987330f729Sjoerg // This gets the raw name from the ArMemHdr->Name field and checks that it is
997330f729Sjoerg // valid for the kind of archive. If it is not valid it returns an Error.
getRawName() const1007330f729Sjoerg Expected<StringRef> ArchiveMemberHeader::getRawName() const {
1017330f729Sjoerg char EndCond;
1027330f729Sjoerg auto Kind = Parent->kind();
1037330f729Sjoerg if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN64) {
1047330f729Sjoerg if (ArMemHdr->Name[0] == ' ') {
1057330f729Sjoerg uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
1067330f729Sjoerg Parent->getData().data();
1077330f729Sjoerg return malformedError("name contains a leading space for archive member "
1087330f729Sjoerg "header at offset " + Twine(Offset));
1097330f729Sjoerg }
1107330f729Sjoerg EndCond = ' ';
1117330f729Sjoerg }
1127330f729Sjoerg else if (ArMemHdr->Name[0] == '/' || ArMemHdr->Name[0] == '#')
1137330f729Sjoerg EndCond = ' ';
1147330f729Sjoerg else
1157330f729Sjoerg EndCond = '/';
1167330f729Sjoerg StringRef::size_type end =
1177330f729Sjoerg StringRef(ArMemHdr->Name, sizeof(ArMemHdr->Name)).find(EndCond);
1187330f729Sjoerg if (end == StringRef::npos)
1197330f729Sjoerg end = sizeof(ArMemHdr->Name);
1207330f729Sjoerg assert(end <= sizeof(ArMemHdr->Name) && end > 0);
1217330f729Sjoerg // Don't include the EndCond if there is one.
1227330f729Sjoerg return StringRef(ArMemHdr->Name, end);
1237330f729Sjoerg }
1247330f729Sjoerg
1257330f729Sjoerg // This gets the name looking up long names. Size is the size of the archive
1267330f729Sjoerg // member including the header, so the size of any name following the header
1277330f729Sjoerg // is checked to make sure it does not overflow.
getName(uint64_t Size) const1287330f729Sjoerg Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const {
1297330f729Sjoerg
1307330f729Sjoerg // This can be called from the ArchiveMemberHeader constructor when the
1317330f729Sjoerg // archive header is truncated to produce an error message with the name.
1327330f729Sjoerg // Make sure the name field is not truncated.
1337330f729Sjoerg if (Size < offsetof(ArMemHdrType, Name) + sizeof(ArMemHdr->Name)) {
1347330f729Sjoerg uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
1357330f729Sjoerg Parent->getData().data();
1367330f729Sjoerg return malformedError("archive header truncated before the name field "
1377330f729Sjoerg "for archive member header at offset " +
1387330f729Sjoerg Twine(ArchiveOffset));
1397330f729Sjoerg }
1407330f729Sjoerg
1417330f729Sjoerg // The raw name itself can be invalid.
1427330f729Sjoerg Expected<StringRef> NameOrErr = getRawName();
1437330f729Sjoerg if (!NameOrErr)
1447330f729Sjoerg return NameOrErr.takeError();
1457330f729Sjoerg StringRef Name = NameOrErr.get();
1467330f729Sjoerg
1477330f729Sjoerg // Check if it's a special name.
1487330f729Sjoerg if (Name[0] == '/') {
1497330f729Sjoerg if (Name.size() == 1) // Linker member.
1507330f729Sjoerg return Name;
1517330f729Sjoerg if (Name.size() == 2 && Name[1] == '/') // String table.
1527330f729Sjoerg return Name;
1537330f729Sjoerg // It's a long name.
1547330f729Sjoerg // Get the string table offset.
1557330f729Sjoerg std::size_t StringOffset;
1567330f729Sjoerg if (Name.substr(1).rtrim(' ').getAsInteger(10, StringOffset)) {
1577330f729Sjoerg std::string Buf;
1587330f729Sjoerg raw_string_ostream OS(Buf);
1597330f729Sjoerg OS.write_escaped(Name.substr(1).rtrim(' '));
1607330f729Sjoerg OS.flush();
1617330f729Sjoerg uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
1627330f729Sjoerg Parent->getData().data();
1637330f729Sjoerg return malformedError("long name offset characters after the '/' are "
1647330f729Sjoerg "not all decimal numbers: '" + Buf + "' for "
1657330f729Sjoerg "archive member header at offset " +
1667330f729Sjoerg Twine(ArchiveOffset));
1677330f729Sjoerg }
1687330f729Sjoerg
1697330f729Sjoerg // Verify it.
1707330f729Sjoerg if (StringOffset >= Parent->getStringTable().size()) {
1717330f729Sjoerg uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
1727330f729Sjoerg Parent->getData().data();
1737330f729Sjoerg return malformedError("long name offset " + Twine(StringOffset) + " past "
1747330f729Sjoerg "the end of the string table for archive member "
1757330f729Sjoerg "header at offset " + Twine(ArchiveOffset));
1767330f729Sjoerg }
1777330f729Sjoerg
1787330f729Sjoerg // GNU long file names end with a "/\n".
1797330f729Sjoerg if (Parent->kind() == Archive::K_GNU ||
1807330f729Sjoerg Parent->kind() == Archive::K_GNU64) {
1817330f729Sjoerg size_t End = Parent->getStringTable().find('\n', /*From=*/StringOffset);
1827330f729Sjoerg if (End == StringRef::npos || End < 1 ||
1837330f729Sjoerg Parent->getStringTable()[End - 1] != '/') {
1847330f729Sjoerg return malformedError("string table at long name offset " +
1857330f729Sjoerg Twine(StringOffset) + "not terminated");
1867330f729Sjoerg }
1877330f729Sjoerg return Parent->getStringTable().slice(StringOffset, End - 1);
1887330f729Sjoerg }
1897330f729Sjoerg return Parent->getStringTable().begin() + StringOffset;
1907330f729Sjoerg }
1917330f729Sjoerg
1927330f729Sjoerg if (Name.startswith("#1/")) {
1937330f729Sjoerg uint64_t NameLength;
1947330f729Sjoerg if (Name.substr(3).rtrim(' ').getAsInteger(10, NameLength)) {
1957330f729Sjoerg std::string Buf;
1967330f729Sjoerg raw_string_ostream OS(Buf);
1977330f729Sjoerg OS.write_escaped(Name.substr(3).rtrim(' '));
1987330f729Sjoerg OS.flush();
1997330f729Sjoerg uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
2007330f729Sjoerg Parent->getData().data();
2017330f729Sjoerg return malformedError("long name length characters after the #1/ are "
2027330f729Sjoerg "not all decimal numbers: '" + Buf + "' for "
2037330f729Sjoerg "archive member header at offset " +
2047330f729Sjoerg Twine(ArchiveOffset));
2057330f729Sjoerg }
2067330f729Sjoerg if (getSizeOf() + NameLength > Size) {
2077330f729Sjoerg uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
2087330f729Sjoerg Parent->getData().data();
2097330f729Sjoerg return malformedError("long name length: " + Twine(NameLength) +
2107330f729Sjoerg " extends past the end of the member or archive "
2117330f729Sjoerg "for archive member header at offset " +
2127330f729Sjoerg Twine(ArchiveOffset));
2137330f729Sjoerg }
2147330f729Sjoerg return StringRef(reinterpret_cast<const char *>(ArMemHdr) + getSizeOf(),
2157330f729Sjoerg NameLength).rtrim('\0');
2167330f729Sjoerg }
2177330f729Sjoerg
2187330f729Sjoerg // It is not a long name so trim the blanks at the end of the name.
2197330f729Sjoerg if (Name[Name.size() - 1] != '/')
2207330f729Sjoerg return Name.rtrim(' ');
2217330f729Sjoerg
2227330f729Sjoerg // It's a simple name.
2237330f729Sjoerg return Name.drop_back(1);
2247330f729Sjoerg }
2257330f729Sjoerg
getSize() const2267330f729Sjoerg Expected<uint64_t> ArchiveMemberHeader::getSize() const {
2277330f729Sjoerg uint64_t Ret;
2287330f729Sjoerg if (StringRef(ArMemHdr->Size,
2297330f729Sjoerg sizeof(ArMemHdr->Size)).rtrim(" ").getAsInteger(10, Ret)) {
2307330f729Sjoerg std::string Buf;
2317330f729Sjoerg raw_string_ostream OS(Buf);
2327330f729Sjoerg OS.write_escaped(StringRef(ArMemHdr->Size,
2337330f729Sjoerg sizeof(ArMemHdr->Size)).rtrim(" "));
2347330f729Sjoerg OS.flush();
2357330f729Sjoerg uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
2367330f729Sjoerg Parent->getData().data();
2377330f729Sjoerg return malformedError("characters in size field in archive header are not "
2387330f729Sjoerg "all decimal numbers: '" + Buf + "' for archive "
2397330f729Sjoerg "member header at offset " + Twine(Offset));
2407330f729Sjoerg }
2417330f729Sjoerg return Ret;
2427330f729Sjoerg }
2437330f729Sjoerg
getAccessMode() const2447330f729Sjoerg Expected<sys::fs::perms> ArchiveMemberHeader::getAccessMode() const {
2457330f729Sjoerg unsigned Ret;
2467330f729Sjoerg if (StringRef(ArMemHdr->AccessMode,
2477330f729Sjoerg sizeof(ArMemHdr->AccessMode)).rtrim(' ').getAsInteger(8, Ret)) {
2487330f729Sjoerg std::string Buf;
2497330f729Sjoerg raw_string_ostream OS(Buf);
2507330f729Sjoerg OS.write_escaped(StringRef(ArMemHdr->AccessMode,
2517330f729Sjoerg sizeof(ArMemHdr->AccessMode)).rtrim(" "));
2527330f729Sjoerg OS.flush();
2537330f729Sjoerg uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
2547330f729Sjoerg Parent->getData().data();
2557330f729Sjoerg return malformedError("characters in AccessMode field in archive header "
2567330f729Sjoerg "are not all decimal numbers: '" + Buf + "' for the "
2577330f729Sjoerg "archive member header at offset " + Twine(Offset));
2587330f729Sjoerg }
2597330f729Sjoerg return static_cast<sys::fs::perms>(Ret);
2607330f729Sjoerg }
2617330f729Sjoerg
2627330f729Sjoerg Expected<sys::TimePoint<std::chrono::seconds>>
getLastModified() const2637330f729Sjoerg ArchiveMemberHeader::getLastModified() const {
2647330f729Sjoerg unsigned Seconds;
2657330f729Sjoerg if (StringRef(ArMemHdr->LastModified,
2667330f729Sjoerg sizeof(ArMemHdr->LastModified)).rtrim(' ')
2677330f729Sjoerg .getAsInteger(10, Seconds)) {
2687330f729Sjoerg std::string Buf;
2697330f729Sjoerg raw_string_ostream OS(Buf);
2707330f729Sjoerg OS.write_escaped(StringRef(ArMemHdr->LastModified,
2717330f729Sjoerg sizeof(ArMemHdr->LastModified)).rtrim(" "));
2727330f729Sjoerg OS.flush();
2737330f729Sjoerg uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
2747330f729Sjoerg Parent->getData().data();
2757330f729Sjoerg return malformedError("characters in LastModified field in archive header "
2767330f729Sjoerg "are not all decimal numbers: '" + Buf + "' for the "
2777330f729Sjoerg "archive member header at offset " + Twine(Offset));
2787330f729Sjoerg }
2797330f729Sjoerg
2807330f729Sjoerg return sys::toTimePoint(Seconds);
2817330f729Sjoerg }
2827330f729Sjoerg
getUID() const2837330f729Sjoerg Expected<unsigned> ArchiveMemberHeader::getUID() const {
2847330f729Sjoerg unsigned Ret;
2857330f729Sjoerg StringRef User = StringRef(ArMemHdr->UID, sizeof(ArMemHdr->UID)).rtrim(' ');
2867330f729Sjoerg if (User.empty())
2877330f729Sjoerg return 0;
2887330f729Sjoerg if (User.getAsInteger(10, Ret)) {
2897330f729Sjoerg std::string Buf;
2907330f729Sjoerg raw_string_ostream OS(Buf);
2917330f729Sjoerg OS.write_escaped(User);
2927330f729Sjoerg OS.flush();
2937330f729Sjoerg uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
2947330f729Sjoerg Parent->getData().data();
2957330f729Sjoerg return malformedError("characters in UID field in archive header "
2967330f729Sjoerg "are not all decimal numbers: '" + Buf + "' for the "
2977330f729Sjoerg "archive member header at offset " + Twine(Offset));
2987330f729Sjoerg }
2997330f729Sjoerg return Ret;
3007330f729Sjoerg }
3017330f729Sjoerg
getGID() const3027330f729Sjoerg Expected<unsigned> ArchiveMemberHeader::getGID() const {
3037330f729Sjoerg unsigned Ret;
3047330f729Sjoerg StringRef Group = StringRef(ArMemHdr->GID, sizeof(ArMemHdr->GID)).rtrim(' ');
3057330f729Sjoerg if (Group.empty())
3067330f729Sjoerg return 0;
3077330f729Sjoerg if (Group.getAsInteger(10, Ret)) {
3087330f729Sjoerg std::string Buf;
3097330f729Sjoerg raw_string_ostream OS(Buf);
3107330f729Sjoerg OS.write_escaped(Group);
3117330f729Sjoerg OS.flush();
3127330f729Sjoerg uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
3137330f729Sjoerg Parent->getData().data();
3147330f729Sjoerg return malformedError("characters in GID field in archive header "
3157330f729Sjoerg "are not all decimal numbers: '" + Buf + "' for the "
3167330f729Sjoerg "archive member header at offset " + Twine(Offset));
3177330f729Sjoerg }
3187330f729Sjoerg return Ret;
3197330f729Sjoerg }
3207330f729Sjoerg
Child(const Archive * Parent,StringRef Data,uint16_t StartOfFile)3217330f729Sjoerg Archive::Child::Child(const Archive *Parent, StringRef Data,
3227330f729Sjoerg uint16_t StartOfFile)
3237330f729Sjoerg : Parent(Parent), Header(Parent, Data.data(), Data.size(), nullptr),
3247330f729Sjoerg Data(Data), StartOfFile(StartOfFile) {
3257330f729Sjoerg }
3267330f729Sjoerg
Child(const Archive * Parent,const char * Start,Error * Err)3277330f729Sjoerg Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err)
3287330f729Sjoerg : Parent(Parent),
3297330f729Sjoerg Header(Parent, Start,
3307330f729Sjoerg Parent
3317330f729Sjoerg ? Parent->getData().size() - (Start - Parent->getData().data())
3327330f729Sjoerg : 0, Err) {
3337330f729Sjoerg if (!Start)
3347330f729Sjoerg return;
3357330f729Sjoerg
3367330f729Sjoerg // If we are pointed to real data, Start is not a nullptr, then there must be
3377330f729Sjoerg // a non-null Err pointer available to report malformed data on. Only in
3387330f729Sjoerg // the case sentinel value is being constructed is Err is permitted to be a
3397330f729Sjoerg // nullptr.
3407330f729Sjoerg assert(Err && "Err can't be nullptr if Start is not a nullptr");
3417330f729Sjoerg
3427330f729Sjoerg ErrorAsOutParameter ErrAsOutParam(Err);
3437330f729Sjoerg
3447330f729Sjoerg // If there was an error in the construction of the Header
3457330f729Sjoerg // then just return with the error now set.
3467330f729Sjoerg if (*Err)
3477330f729Sjoerg return;
3487330f729Sjoerg
3497330f729Sjoerg uint64_t Size = Header.getSizeOf();
3507330f729Sjoerg Data = StringRef(Start, Size);
3517330f729Sjoerg Expected<bool> isThinOrErr = isThinMember();
3527330f729Sjoerg if (!isThinOrErr) {
3537330f729Sjoerg *Err = isThinOrErr.takeError();
3547330f729Sjoerg return;
3557330f729Sjoerg }
3567330f729Sjoerg bool isThin = isThinOrErr.get();
3577330f729Sjoerg if (!isThin) {
3587330f729Sjoerg Expected<uint64_t> MemberSize = getRawSize();
3597330f729Sjoerg if (!MemberSize) {
3607330f729Sjoerg *Err = MemberSize.takeError();
3617330f729Sjoerg return;
3627330f729Sjoerg }
3637330f729Sjoerg Size += MemberSize.get();
3647330f729Sjoerg Data = StringRef(Start, Size);
3657330f729Sjoerg }
3667330f729Sjoerg
3677330f729Sjoerg // Setup StartOfFile and PaddingBytes.
3687330f729Sjoerg StartOfFile = Header.getSizeOf();
3697330f729Sjoerg // Don't include attached name.
3707330f729Sjoerg Expected<StringRef> NameOrErr = getRawName();
3717330f729Sjoerg if (!NameOrErr){
3727330f729Sjoerg *Err = NameOrErr.takeError();
3737330f729Sjoerg return;
3747330f729Sjoerg }
3757330f729Sjoerg StringRef Name = NameOrErr.get();
3767330f729Sjoerg if (Name.startswith("#1/")) {
3777330f729Sjoerg uint64_t NameSize;
3787330f729Sjoerg if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) {
3797330f729Sjoerg std::string Buf;
3807330f729Sjoerg raw_string_ostream OS(Buf);
3817330f729Sjoerg OS.write_escaped(Name.substr(3).rtrim(' '));
3827330f729Sjoerg OS.flush();
3837330f729Sjoerg uint64_t Offset = Start - Parent->getData().data();
3847330f729Sjoerg *Err = malformedError("long name length characters after the #1/ are "
3857330f729Sjoerg "not all decimal numbers: '" + Buf + "' for "
3867330f729Sjoerg "archive member header at offset " +
3877330f729Sjoerg Twine(Offset));
3887330f729Sjoerg return;
3897330f729Sjoerg }
3907330f729Sjoerg StartOfFile += NameSize;
3917330f729Sjoerg }
3927330f729Sjoerg }
3937330f729Sjoerg
getSize() const3947330f729Sjoerg Expected<uint64_t> Archive::Child::getSize() const {
395*82d56013Sjoerg if (Parent->IsThin)
396*82d56013Sjoerg return Header.getSize();
3977330f729Sjoerg return Data.size() - StartOfFile;
3987330f729Sjoerg }
3997330f729Sjoerg
getRawSize() const4007330f729Sjoerg Expected<uint64_t> Archive::Child::getRawSize() const {
4017330f729Sjoerg return Header.getSize();
4027330f729Sjoerg }
4037330f729Sjoerg
isThinMember() const4047330f729Sjoerg Expected<bool> Archive::Child::isThinMember() const {
4057330f729Sjoerg Expected<StringRef> NameOrErr = Header.getRawName();
4067330f729Sjoerg if (!NameOrErr)
4077330f729Sjoerg return NameOrErr.takeError();
4087330f729Sjoerg StringRef Name = NameOrErr.get();
4097330f729Sjoerg return Parent->IsThin && Name != "/" && Name != "//";
4107330f729Sjoerg }
4117330f729Sjoerg
getFullName() const4127330f729Sjoerg Expected<std::string> Archive::Child::getFullName() const {
4137330f729Sjoerg Expected<bool> isThin = isThinMember();
4147330f729Sjoerg if (!isThin)
4157330f729Sjoerg return isThin.takeError();
4167330f729Sjoerg assert(isThin.get());
4177330f729Sjoerg Expected<StringRef> NameOrErr = getName();
4187330f729Sjoerg if (!NameOrErr)
4197330f729Sjoerg return NameOrErr.takeError();
4207330f729Sjoerg StringRef Name = *NameOrErr;
4217330f729Sjoerg if (sys::path::is_absolute(Name))
422*82d56013Sjoerg return std::string(Name);
4237330f729Sjoerg
4247330f729Sjoerg SmallString<128> FullName = sys::path::parent_path(
4257330f729Sjoerg Parent->getMemoryBufferRef().getBufferIdentifier());
4267330f729Sjoerg sys::path::append(FullName, Name);
427*82d56013Sjoerg return std::string(FullName.str());
4287330f729Sjoerg }
4297330f729Sjoerg
getBuffer() const4307330f729Sjoerg Expected<StringRef> Archive::Child::getBuffer() const {
4317330f729Sjoerg Expected<bool> isThinOrErr = isThinMember();
4327330f729Sjoerg if (!isThinOrErr)
4337330f729Sjoerg return isThinOrErr.takeError();
4347330f729Sjoerg bool isThin = isThinOrErr.get();
4357330f729Sjoerg if (!isThin) {
436*82d56013Sjoerg Expected<uint64_t> Size = getSize();
4377330f729Sjoerg if (!Size)
4387330f729Sjoerg return Size.takeError();
4397330f729Sjoerg return StringRef(Data.data() + StartOfFile, Size.get());
4407330f729Sjoerg }
4417330f729Sjoerg Expected<std::string> FullNameOrErr = getFullName();
4427330f729Sjoerg if (!FullNameOrErr)
4437330f729Sjoerg return FullNameOrErr.takeError();
4447330f729Sjoerg const std::string &FullName = *FullNameOrErr;
4457330f729Sjoerg ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(FullName);
4467330f729Sjoerg if (std::error_code EC = Buf.getError())
4477330f729Sjoerg return errorCodeToError(EC);
4487330f729Sjoerg Parent->ThinBuffers.push_back(std::move(*Buf));
4497330f729Sjoerg return Parent->ThinBuffers.back()->getBuffer();
4507330f729Sjoerg }
4517330f729Sjoerg
getNext() const4527330f729Sjoerg Expected<Archive::Child> Archive::Child::getNext() const {
4537330f729Sjoerg size_t SpaceToSkip = Data.size();
4547330f729Sjoerg // If it's odd, add 1 to make it even.
4557330f729Sjoerg if (SpaceToSkip & 1)
4567330f729Sjoerg ++SpaceToSkip;
4577330f729Sjoerg
4587330f729Sjoerg const char *NextLoc = Data.data() + SpaceToSkip;
4597330f729Sjoerg
4607330f729Sjoerg // Check to see if this is at the end of the archive.
4617330f729Sjoerg if (NextLoc == Parent->Data.getBufferEnd())
4627330f729Sjoerg return Child(nullptr, nullptr, nullptr);
4637330f729Sjoerg
4647330f729Sjoerg // Check to see if this is past the end of the archive.
4657330f729Sjoerg if (NextLoc > Parent->Data.getBufferEnd()) {
4667330f729Sjoerg std::string Msg("offset to next archive member past the end of the archive "
4677330f729Sjoerg "after member ");
4687330f729Sjoerg Expected<StringRef> NameOrErr = getName();
4697330f729Sjoerg if (!NameOrErr) {
4707330f729Sjoerg consumeError(NameOrErr.takeError());
4717330f729Sjoerg uint64_t Offset = Data.data() - Parent->getData().data();
4727330f729Sjoerg return malformedError(Msg + "at offset " + Twine(Offset));
4737330f729Sjoerg } else
4747330f729Sjoerg return malformedError(Msg + NameOrErr.get());
4757330f729Sjoerg }
4767330f729Sjoerg
4777330f729Sjoerg Error Err = Error::success();
4787330f729Sjoerg Child Ret(Parent, NextLoc, &Err);
4797330f729Sjoerg if (Err)
4807330f729Sjoerg return std::move(Err);
4817330f729Sjoerg return Ret;
4827330f729Sjoerg }
4837330f729Sjoerg
getChildOffset() const4847330f729Sjoerg uint64_t Archive::Child::getChildOffset() const {
4857330f729Sjoerg const char *a = Parent->Data.getBuffer().data();
4867330f729Sjoerg const char *c = Data.data();
4877330f729Sjoerg uint64_t offset = c - a;
4887330f729Sjoerg return offset;
4897330f729Sjoerg }
4907330f729Sjoerg
getName() const4917330f729Sjoerg Expected<StringRef> Archive::Child::getName() const {
4927330f729Sjoerg Expected<uint64_t> RawSizeOrErr = getRawSize();
4937330f729Sjoerg if (!RawSizeOrErr)
4947330f729Sjoerg return RawSizeOrErr.takeError();
4957330f729Sjoerg uint64_t RawSize = RawSizeOrErr.get();
4967330f729Sjoerg Expected<StringRef> NameOrErr = Header.getName(Header.getSizeOf() + RawSize);
4977330f729Sjoerg if (!NameOrErr)
4987330f729Sjoerg return NameOrErr.takeError();
4997330f729Sjoerg StringRef Name = NameOrErr.get();
5007330f729Sjoerg return Name;
5017330f729Sjoerg }
5027330f729Sjoerg
getMemoryBufferRef() const5037330f729Sjoerg Expected<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const {
5047330f729Sjoerg Expected<StringRef> NameOrErr = getName();
5057330f729Sjoerg if (!NameOrErr)
5067330f729Sjoerg return NameOrErr.takeError();
5077330f729Sjoerg StringRef Name = NameOrErr.get();
5087330f729Sjoerg Expected<StringRef> Buf = getBuffer();
5097330f729Sjoerg if (!Buf)
5107330f729Sjoerg return createFileError(Name, Buf.takeError());
5117330f729Sjoerg return MemoryBufferRef(*Buf, Name);
5127330f729Sjoerg }
5137330f729Sjoerg
5147330f729Sjoerg Expected<std::unique_ptr<Binary>>
getAsBinary(LLVMContext * Context) const5157330f729Sjoerg Archive::Child::getAsBinary(LLVMContext *Context) const {
5167330f729Sjoerg Expected<MemoryBufferRef> BuffOrErr = getMemoryBufferRef();
5177330f729Sjoerg if (!BuffOrErr)
5187330f729Sjoerg return BuffOrErr.takeError();
5197330f729Sjoerg
5207330f729Sjoerg auto BinaryOrErr = createBinary(BuffOrErr.get(), Context);
5217330f729Sjoerg if (BinaryOrErr)
5227330f729Sjoerg return std::move(*BinaryOrErr);
5237330f729Sjoerg return BinaryOrErr.takeError();
5247330f729Sjoerg }
5257330f729Sjoerg
create(MemoryBufferRef Source)5267330f729Sjoerg Expected<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) {
5277330f729Sjoerg Error Err = Error::success();
5287330f729Sjoerg std::unique_ptr<Archive> Ret(new Archive(Source, Err));
5297330f729Sjoerg if (Err)
5307330f729Sjoerg return std::move(Err);
5317330f729Sjoerg return std::move(Ret);
5327330f729Sjoerg }
5337330f729Sjoerg
setFirstRegular(const Child & C)5347330f729Sjoerg void Archive::setFirstRegular(const Child &C) {
5357330f729Sjoerg FirstRegularData = C.Data;
5367330f729Sjoerg FirstRegularStartOfFile = C.StartOfFile;
5377330f729Sjoerg }
5387330f729Sjoerg
Archive(MemoryBufferRef Source,Error & Err)5397330f729Sjoerg Archive::Archive(MemoryBufferRef Source, Error &Err)
5407330f729Sjoerg : Binary(Binary::ID_Archive, Source) {
5417330f729Sjoerg ErrorAsOutParameter ErrAsOutParam(&Err);
5427330f729Sjoerg StringRef Buffer = Data.getBuffer();
5437330f729Sjoerg // Check for sufficient magic.
5447330f729Sjoerg if (Buffer.startswith(ThinMagic)) {
5457330f729Sjoerg IsThin = true;
5467330f729Sjoerg } else if (Buffer.startswith(Magic)) {
5477330f729Sjoerg IsThin = false;
5487330f729Sjoerg } else {
5497330f729Sjoerg Err = make_error<GenericBinaryError>("file too small to be an archive",
5507330f729Sjoerg object_error::invalid_file_type);
5517330f729Sjoerg return;
5527330f729Sjoerg }
5537330f729Sjoerg
5547330f729Sjoerg // Make sure Format is initialized before any call to
5557330f729Sjoerg // ArchiveMemberHeader::getName() is made. This could be a valid empty
5567330f729Sjoerg // archive which is the same in all formats. So claiming it to be gnu to is
5577330f729Sjoerg // fine if not totally correct before we look for a string table or table of
5587330f729Sjoerg // contents.
5597330f729Sjoerg Format = K_GNU;
5607330f729Sjoerg
5617330f729Sjoerg // Get the special members.
5627330f729Sjoerg child_iterator I = child_begin(Err, false);
5637330f729Sjoerg if (Err)
5647330f729Sjoerg return;
5657330f729Sjoerg child_iterator E = child_end();
5667330f729Sjoerg
5677330f729Sjoerg // See if this is a valid empty archive and if so return.
5687330f729Sjoerg if (I == E) {
5697330f729Sjoerg Err = Error::success();
5707330f729Sjoerg return;
5717330f729Sjoerg }
5727330f729Sjoerg const Child *C = &*I;
5737330f729Sjoerg
5747330f729Sjoerg auto Increment = [&]() {
5757330f729Sjoerg ++I;
5767330f729Sjoerg if (Err)
5777330f729Sjoerg return true;
5787330f729Sjoerg C = &*I;
5797330f729Sjoerg return false;
5807330f729Sjoerg };
5817330f729Sjoerg
5827330f729Sjoerg Expected<StringRef> NameOrErr = C->getRawName();
5837330f729Sjoerg if (!NameOrErr) {
5847330f729Sjoerg Err = NameOrErr.takeError();
5857330f729Sjoerg return;
5867330f729Sjoerg }
5877330f729Sjoerg StringRef Name = NameOrErr.get();
5887330f729Sjoerg
5897330f729Sjoerg // Below is the pattern that is used to figure out the archive format
5907330f729Sjoerg // GNU archive format
5917330f729Sjoerg // First member : / (may exist, if it exists, points to the symbol table )
5927330f729Sjoerg // Second member : // (may exist, if it exists, points to the string table)
5937330f729Sjoerg // Note : The string table is used if the filename exceeds 15 characters
5947330f729Sjoerg // BSD archive format
5957330f729Sjoerg // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table)
5967330f729Sjoerg // There is no string table, if the filename exceeds 15 characters or has a
5977330f729Sjoerg // embedded space, the filename has #1/<size>, The size represents the size
5987330f729Sjoerg // of the filename that needs to be read after the archive header
5997330f729Sjoerg // COFF archive format
6007330f729Sjoerg // First member : /
6017330f729Sjoerg // Second member : / (provides a directory of symbols)
6027330f729Sjoerg // Third member : // (may exist, if it exists, contains the string table)
6037330f729Sjoerg // Note: Microsoft PE/COFF Spec 8.3 says that the third member is present
6047330f729Sjoerg // even if the string table is empty. However, lib.exe does not in fact
6057330f729Sjoerg // seem to create the third member if there's no member whose filename
6067330f729Sjoerg // exceeds 15 characters. So the third member is optional.
6077330f729Sjoerg
6087330f729Sjoerg if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64") {
6097330f729Sjoerg if (Name == "__.SYMDEF")
6107330f729Sjoerg Format = K_BSD;
6117330f729Sjoerg else // Name == "__.SYMDEF_64"
6127330f729Sjoerg Format = K_DARWIN64;
6137330f729Sjoerg // We know that the symbol table is not an external file, but we still must
6147330f729Sjoerg // check any Expected<> return value.
6157330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
6167330f729Sjoerg if (!BufOrErr) {
6177330f729Sjoerg Err = BufOrErr.takeError();
6187330f729Sjoerg return;
6197330f729Sjoerg }
6207330f729Sjoerg SymbolTable = BufOrErr.get();
6217330f729Sjoerg if (Increment())
6227330f729Sjoerg return;
6237330f729Sjoerg setFirstRegular(*C);
6247330f729Sjoerg
6257330f729Sjoerg Err = Error::success();
6267330f729Sjoerg return;
6277330f729Sjoerg }
6287330f729Sjoerg
6297330f729Sjoerg if (Name.startswith("#1/")) {
6307330f729Sjoerg Format = K_BSD;
6317330f729Sjoerg // We know this is BSD, so getName will work since there is no string table.
6327330f729Sjoerg Expected<StringRef> NameOrErr = C->getName();
6337330f729Sjoerg if (!NameOrErr) {
6347330f729Sjoerg Err = NameOrErr.takeError();
6357330f729Sjoerg return;
6367330f729Sjoerg }
6377330f729Sjoerg Name = NameOrErr.get();
6387330f729Sjoerg if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF") {
6397330f729Sjoerg // We know that the symbol table is not an external file, but we still
6407330f729Sjoerg // must check any Expected<> return value.
6417330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
6427330f729Sjoerg if (!BufOrErr) {
6437330f729Sjoerg Err = BufOrErr.takeError();
6447330f729Sjoerg return;
6457330f729Sjoerg }
6467330f729Sjoerg SymbolTable = BufOrErr.get();
6477330f729Sjoerg if (Increment())
6487330f729Sjoerg return;
6497330f729Sjoerg }
6507330f729Sjoerg else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") {
6517330f729Sjoerg Format = K_DARWIN64;
6527330f729Sjoerg // We know that the symbol table is not an external file, but we still
6537330f729Sjoerg // must check any Expected<> return value.
6547330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
6557330f729Sjoerg if (!BufOrErr) {
6567330f729Sjoerg Err = BufOrErr.takeError();
6577330f729Sjoerg return;
6587330f729Sjoerg }
6597330f729Sjoerg SymbolTable = BufOrErr.get();
6607330f729Sjoerg if (Increment())
6617330f729Sjoerg return;
6627330f729Sjoerg }
6637330f729Sjoerg setFirstRegular(*C);
6647330f729Sjoerg return;
6657330f729Sjoerg }
6667330f729Sjoerg
6677330f729Sjoerg // MIPS 64-bit ELF archives use a special format of a symbol table.
6687330f729Sjoerg // This format is marked by `ar_name` field equals to "/SYM64/".
6697330f729Sjoerg // For detailed description see page 96 in the following document:
6707330f729Sjoerg // http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
6717330f729Sjoerg
6727330f729Sjoerg bool has64SymTable = false;
6737330f729Sjoerg if (Name == "/" || Name == "/SYM64/") {
6747330f729Sjoerg // We know that the symbol table is not an external file, but we still
6757330f729Sjoerg // must check any Expected<> return value.
6767330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
6777330f729Sjoerg if (!BufOrErr) {
6787330f729Sjoerg Err = BufOrErr.takeError();
6797330f729Sjoerg return;
6807330f729Sjoerg }
6817330f729Sjoerg SymbolTable = BufOrErr.get();
6827330f729Sjoerg if (Name == "/SYM64/")
6837330f729Sjoerg has64SymTable = true;
6847330f729Sjoerg
6857330f729Sjoerg if (Increment())
6867330f729Sjoerg return;
6877330f729Sjoerg if (I == E) {
6887330f729Sjoerg Err = Error::success();
6897330f729Sjoerg return;
6907330f729Sjoerg }
6917330f729Sjoerg Expected<StringRef> NameOrErr = C->getRawName();
6927330f729Sjoerg if (!NameOrErr) {
6937330f729Sjoerg Err = NameOrErr.takeError();
6947330f729Sjoerg return;
6957330f729Sjoerg }
6967330f729Sjoerg Name = NameOrErr.get();
6977330f729Sjoerg }
6987330f729Sjoerg
6997330f729Sjoerg if (Name == "//") {
7007330f729Sjoerg Format = has64SymTable ? K_GNU64 : K_GNU;
7017330f729Sjoerg // The string table is never an external member, but we still
7027330f729Sjoerg // must check any Expected<> return value.
7037330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
7047330f729Sjoerg if (!BufOrErr) {
7057330f729Sjoerg Err = BufOrErr.takeError();
7067330f729Sjoerg return;
7077330f729Sjoerg }
7087330f729Sjoerg StringTable = BufOrErr.get();
7097330f729Sjoerg if (Increment())
7107330f729Sjoerg return;
7117330f729Sjoerg setFirstRegular(*C);
7127330f729Sjoerg Err = Error::success();
7137330f729Sjoerg return;
7147330f729Sjoerg }
7157330f729Sjoerg
7167330f729Sjoerg if (Name[0] != '/') {
7177330f729Sjoerg Format = has64SymTable ? K_GNU64 : K_GNU;
7187330f729Sjoerg setFirstRegular(*C);
7197330f729Sjoerg Err = Error::success();
7207330f729Sjoerg return;
7217330f729Sjoerg }
7227330f729Sjoerg
7237330f729Sjoerg if (Name != "/") {
7247330f729Sjoerg Err = errorCodeToError(object_error::parse_failed);
7257330f729Sjoerg return;
7267330f729Sjoerg }
7277330f729Sjoerg
7287330f729Sjoerg Format = K_COFF;
7297330f729Sjoerg // We know that the symbol table is not an external file, but we still
7307330f729Sjoerg // must check any Expected<> return value.
7317330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
7327330f729Sjoerg if (!BufOrErr) {
7337330f729Sjoerg Err = BufOrErr.takeError();
7347330f729Sjoerg return;
7357330f729Sjoerg }
7367330f729Sjoerg SymbolTable = BufOrErr.get();
7377330f729Sjoerg
7387330f729Sjoerg if (Increment())
7397330f729Sjoerg return;
7407330f729Sjoerg
7417330f729Sjoerg if (I == E) {
7427330f729Sjoerg setFirstRegular(*C);
7437330f729Sjoerg Err = Error::success();
7447330f729Sjoerg return;
7457330f729Sjoerg }
7467330f729Sjoerg
7477330f729Sjoerg NameOrErr = C->getRawName();
7487330f729Sjoerg if (!NameOrErr) {
7497330f729Sjoerg Err = NameOrErr.takeError();
7507330f729Sjoerg return;
7517330f729Sjoerg }
7527330f729Sjoerg Name = NameOrErr.get();
7537330f729Sjoerg
7547330f729Sjoerg if (Name == "//") {
7557330f729Sjoerg // The string table is never an external member, but we still
7567330f729Sjoerg // must check any Expected<> return value.
7577330f729Sjoerg Expected<StringRef> BufOrErr = C->getBuffer();
7587330f729Sjoerg if (!BufOrErr) {
7597330f729Sjoerg Err = BufOrErr.takeError();
7607330f729Sjoerg return;
7617330f729Sjoerg }
7627330f729Sjoerg StringTable = BufOrErr.get();
7637330f729Sjoerg if (Increment())
7647330f729Sjoerg return;
7657330f729Sjoerg }
7667330f729Sjoerg
7677330f729Sjoerg setFirstRegular(*C);
7687330f729Sjoerg Err = Error::success();
7697330f729Sjoerg }
7707330f729Sjoerg
child_begin(Error & Err,bool SkipInternal) const7717330f729Sjoerg Archive::child_iterator Archive::child_begin(Error &Err,
7727330f729Sjoerg bool SkipInternal) const {
7737330f729Sjoerg if (isEmpty())
7747330f729Sjoerg return child_end();
7757330f729Sjoerg
7767330f729Sjoerg if (SkipInternal)
7777330f729Sjoerg return child_iterator::itr(
7787330f729Sjoerg Child(this, FirstRegularData, FirstRegularStartOfFile), Err);
7797330f729Sjoerg
7807330f729Sjoerg const char *Loc = Data.getBufferStart() + strlen(Magic);
7817330f729Sjoerg Child C(this, Loc, &Err);
7827330f729Sjoerg if (Err)
7837330f729Sjoerg return child_end();
7847330f729Sjoerg return child_iterator::itr(C, Err);
7857330f729Sjoerg }
7867330f729Sjoerg
child_end() const7877330f729Sjoerg Archive::child_iterator Archive::child_end() const {
7887330f729Sjoerg return child_iterator::end(Child(nullptr, nullptr, nullptr));
7897330f729Sjoerg }
7907330f729Sjoerg
getName() const7917330f729Sjoerg StringRef Archive::Symbol::getName() const {
7927330f729Sjoerg return Parent->getSymbolTable().begin() + StringIndex;
7937330f729Sjoerg }
7947330f729Sjoerg
getMember() const7957330f729Sjoerg Expected<Archive::Child> Archive::Symbol::getMember() const {
7967330f729Sjoerg const char *Buf = Parent->getSymbolTable().begin();
7977330f729Sjoerg const char *Offsets = Buf;
7987330f729Sjoerg if (Parent->kind() == K_GNU64 || Parent->kind() == K_DARWIN64)
7997330f729Sjoerg Offsets += sizeof(uint64_t);
8007330f729Sjoerg else
8017330f729Sjoerg Offsets += sizeof(uint32_t);
8027330f729Sjoerg uint64_t Offset = 0;
8037330f729Sjoerg if (Parent->kind() == K_GNU) {
8047330f729Sjoerg Offset = read32be(Offsets + SymbolIndex * 4);
8057330f729Sjoerg } else if (Parent->kind() == K_GNU64) {
8067330f729Sjoerg Offset = read64be(Offsets + SymbolIndex * 8);
8077330f729Sjoerg } else if (Parent->kind() == K_BSD) {
8087330f729Sjoerg // The SymbolIndex is an index into the ranlib structs that start at
8097330f729Sjoerg // Offsets (the first uint32_t is the number of bytes of the ranlib
8107330f729Sjoerg // structs). The ranlib structs are a pair of uint32_t's the first
8117330f729Sjoerg // being a string table offset and the second being the offset into
8127330f729Sjoerg // the archive of the member that defines the symbol. Which is what
8137330f729Sjoerg // is needed here.
8147330f729Sjoerg Offset = read32le(Offsets + SymbolIndex * 8 + 4);
8157330f729Sjoerg } else if (Parent->kind() == K_DARWIN64) {
8167330f729Sjoerg // The SymbolIndex is an index into the ranlib_64 structs that start at
8177330f729Sjoerg // Offsets (the first uint64_t is the number of bytes of the ranlib_64
8187330f729Sjoerg // structs). The ranlib_64 structs are a pair of uint64_t's the first
8197330f729Sjoerg // being a string table offset and the second being the offset into
8207330f729Sjoerg // the archive of the member that defines the symbol. Which is what
8217330f729Sjoerg // is needed here.
8227330f729Sjoerg Offset = read64le(Offsets + SymbolIndex * 16 + 8);
8237330f729Sjoerg } else {
8247330f729Sjoerg // Skip offsets.
8257330f729Sjoerg uint32_t MemberCount = read32le(Buf);
8267330f729Sjoerg Buf += MemberCount * 4 + 4;
8277330f729Sjoerg
8287330f729Sjoerg uint32_t SymbolCount = read32le(Buf);
8297330f729Sjoerg if (SymbolIndex >= SymbolCount)
8307330f729Sjoerg return errorCodeToError(object_error::parse_failed);
8317330f729Sjoerg
8327330f729Sjoerg // Skip SymbolCount to get to the indices table.
8337330f729Sjoerg const char *Indices = Buf + 4;
8347330f729Sjoerg
8357330f729Sjoerg // Get the index of the offset in the file member offset table for this
8367330f729Sjoerg // symbol.
8377330f729Sjoerg uint16_t OffsetIndex = read16le(Indices + SymbolIndex * 2);
8387330f729Sjoerg // Subtract 1 since OffsetIndex is 1 based.
8397330f729Sjoerg --OffsetIndex;
8407330f729Sjoerg
8417330f729Sjoerg if (OffsetIndex >= MemberCount)
8427330f729Sjoerg return errorCodeToError(object_error::parse_failed);
8437330f729Sjoerg
8447330f729Sjoerg Offset = read32le(Offsets + OffsetIndex * 4);
8457330f729Sjoerg }
8467330f729Sjoerg
8477330f729Sjoerg const char *Loc = Parent->getData().begin() + Offset;
8487330f729Sjoerg Error Err = Error::success();
8497330f729Sjoerg Child C(Parent, Loc, &Err);
8507330f729Sjoerg if (Err)
8517330f729Sjoerg return std::move(Err);
8527330f729Sjoerg return C;
8537330f729Sjoerg }
8547330f729Sjoerg
getNext() const8557330f729Sjoerg Archive::Symbol Archive::Symbol::getNext() const {
8567330f729Sjoerg Symbol t(*this);
8577330f729Sjoerg if (Parent->kind() == K_BSD) {
8587330f729Sjoerg // t.StringIndex is an offset from the start of the __.SYMDEF or
8597330f729Sjoerg // "__.SYMDEF SORTED" member into the string table for the ranlib
8607330f729Sjoerg // struct indexed by t.SymbolIndex . To change t.StringIndex to the
8617330f729Sjoerg // offset in the string table for t.SymbolIndex+1 we subtract the
8627330f729Sjoerg // its offset from the start of the string table for t.SymbolIndex
8637330f729Sjoerg // and add the offset of the string table for t.SymbolIndex+1.
8647330f729Sjoerg
8657330f729Sjoerg // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
8667330f729Sjoerg // which is the number of bytes of ranlib structs that follow. The ranlib
8677330f729Sjoerg // structs are a pair of uint32_t's the first being a string table offset
8687330f729Sjoerg // and the second being the offset into the archive of the member that
8697330f729Sjoerg // define the symbol. After that the next uint32_t is the byte count of
8707330f729Sjoerg // the string table followed by the string table.
8717330f729Sjoerg const char *Buf = Parent->getSymbolTable().begin();
8727330f729Sjoerg uint32_t RanlibCount = 0;
8737330f729Sjoerg RanlibCount = read32le(Buf) / 8;
8747330f729Sjoerg // If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount)
8757330f729Sjoerg // don't change the t.StringIndex as we don't want to reference a ranlib
8767330f729Sjoerg // past RanlibCount.
8777330f729Sjoerg if (t.SymbolIndex + 1 < RanlibCount) {
8787330f729Sjoerg const char *Ranlibs = Buf + 4;
8797330f729Sjoerg uint32_t CurRanStrx = 0;
8807330f729Sjoerg uint32_t NextRanStrx = 0;
8817330f729Sjoerg CurRanStrx = read32le(Ranlibs + t.SymbolIndex * 8);
8827330f729Sjoerg NextRanStrx = read32le(Ranlibs + (t.SymbolIndex + 1) * 8);
8837330f729Sjoerg t.StringIndex -= CurRanStrx;
8847330f729Sjoerg t.StringIndex += NextRanStrx;
8857330f729Sjoerg }
8867330f729Sjoerg } else {
8877330f729Sjoerg // Go to one past next null.
8887330f729Sjoerg t.StringIndex = Parent->getSymbolTable().find('\0', t.StringIndex) + 1;
8897330f729Sjoerg }
8907330f729Sjoerg ++t.SymbolIndex;
8917330f729Sjoerg return t;
8927330f729Sjoerg }
8937330f729Sjoerg
symbol_begin() const8947330f729Sjoerg Archive::symbol_iterator Archive::symbol_begin() const {
8957330f729Sjoerg if (!hasSymbolTable())
8967330f729Sjoerg return symbol_iterator(Symbol(this, 0, 0));
8977330f729Sjoerg
8987330f729Sjoerg const char *buf = getSymbolTable().begin();
8997330f729Sjoerg if (kind() == K_GNU) {
9007330f729Sjoerg uint32_t symbol_count = 0;
9017330f729Sjoerg symbol_count = read32be(buf);
9027330f729Sjoerg buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t)));
9037330f729Sjoerg } else if (kind() == K_GNU64) {
9047330f729Sjoerg uint64_t symbol_count = read64be(buf);
9057330f729Sjoerg buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t)));
9067330f729Sjoerg } else if (kind() == K_BSD) {
9077330f729Sjoerg // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
9087330f729Sjoerg // which is the number of bytes of ranlib structs that follow. The ranlib
9097330f729Sjoerg // structs are a pair of uint32_t's the first being a string table offset
9107330f729Sjoerg // and the second being the offset into the archive of the member that
9117330f729Sjoerg // define the symbol. After that the next uint32_t is the byte count of
9127330f729Sjoerg // the string table followed by the string table.
9137330f729Sjoerg uint32_t ranlib_count = 0;
9147330f729Sjoerg ranlib_count = read32le(buf) / 8;
9157330f729Sjoerg const char *ranlibs = buf + 4;
9167330f729Sjoerg uint32_t ran_strx = 0;
9177330f729Sjoerg ran_strx = read32le(ranlibs);
9187330f729Sjoerg buf += sizeof(uint32_t) + (ranlib_count * (2 * (sizeof(uint32_t))));
9197330f729Sjoerg // Skip the byte count of the string table.
9207330f729Sjoerg buf += sizeof(uint32_t);
9217330f729Sjoerg buf += ran_strx;
9227330f729Sjoerg } else if (kind() == K_DARWIN64) {
9237330f729Sjoerg // The __.SYMDEF_64 or "__.SYMDEF_64 SORTED" member starts with a uint64_t
9247330f729Sjoerg // which is the number of bytes of ranlib_64 structs that follow. The
9257330f729Sjoerg // ranlib_64 structs are a pair of uint64_t's the first being a string
9267330f729Sjoerg // table offset and the second being the offset into the archive of the
9277330f729Sjoerg // member that define the symbol. After that the next uint64_t is the byte
9287330f729Sjoerg // count of the string table followed by the string table.
9297330f729Sjoerg uint64_t ranlib_count = 0;
9307330f729Sjoerg ranlib_count = read64le(buf) / 16;
9317330f729Sjoerg const char *ranlibs = buf + 8;
9327330f729Sjoerg uint64_t ran_strx = 0;
9337330f729Sjoerg ran_strx = read64le(ranlibs);
9347330f729Sjoerg buf += sizeof(uint64_t) + (ranlib_count * (2 * (sizeof(uint64_t))));
9357330f729Sjoerg // Skip the byte count of the string table.
9367330f729Sjoerg buf += sizeof(uint64_t);
9377330f729Sjoerg buf += ran_strx;
9387330f729Sjoerg } else {
9397330f729Sjoerg uint32_t member_count = 0;
9407330f729Sjoerg uint32_t symbol_count = 0;
9417330f729Sjoerg member_count = read32le(buf);
9427330f729Sjoerg buf += 4 + (member_count * 4); // Skip offsets.
9437330f729Sjoerg symbol_count = read32le(buf);
9447330f729Sjoerg buf += 4 + (symbol_count * 2); // Skip indices.
9457330f729Sjoerg }
9467330f729Sjoerg uint32_t string_start_offset = buf - getSymbolTable().begin();
9477330f729Sjoerg return symbol_iterator(Symbol(this, 0, string_start_offset));
9487330f729Sjoerg }
9497330f729Sjoerg
symbol_end() const9507330f729Sjoerg Archive::symbol_iterator Archive::symbol_end() const {
9517330f729Sjoerg return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0));
9527330f729Sjoerg }
9537330f729Sjoerg
getNumberOfSymbols() const9547330f729Sjoerg uint32_t Archive::getNumberOfSymbols() const {
9557330f729Sjoerg if (!hasSymbolTable())
9567330f729Sjoerg return 0;
9577330f729Sjoerg const char *buf = getSymbolTable().begin();
9587330f729Sjoerg if (kind() == K_GNU)
9597330f729Sjoerg return read32be(buf);
9607330f729Sjoerg if (kind() == K_GNU64)
9617330f729Sjoerg return read64be(buf);
9627330f729Sjoerg if (kind() == K_BSD)
9637330f729Sjoerg return read32le(buf) / 8;
9647330f729Sjoerg if (kind() == K_DARWIN64)
9657330f729Sjoerg return read64le(buf) / 16;
9667330f729Sjoerg uint32_t member_count = 0;
9677330f729Sjoerg member_count = read32le(buf);
9687330f729Sjoerg buf += 4 + (member_count * 4); // Skip offsets.
9697330f729Sjoerg return read32le(buf);
9707330f729Sjoerg }
9717330f729Sjoerg
findSym(StringRef name) const9727330f729Sjoerg Expected<Optional<Archive::Child>> Archive::findSym(StringRef name) const {
9737330f729Sjoerg Archive::symbol_iterator bs = symbol_begin();
9747330f729Sjoerg Archive::symbol_iterator es = symbol_end();
9757330f729Sjoerg
9767330f729Sjoerg for (; bs != es; ++bs) {
9777330f729Sjoerg StringRef SymName = bs->getName();
9787330f729Sjoerg if (SymName == name) {
9797330f729Sjoerg if (auto MemberOrErr = bs->getMember())
9807330f729Sjoerg return Child(*MemberOrErr);
9817330f729Sjoerg else
9827330f729Sjoerg return MemberOrErr.takeError();
9837330f729Sjoerg }
9847330f729Sjoerg }
9857330f729Sjoerg return Optional<Child>();
9867330f729Sjoerg }
9877330f729Sjoerg
9887330f729Sjoerg // Returns true if archive file contains no member file.
isEmpty() const9897330f729Sjoerg bool Archive::isEmpty() const { return Data.getBufferSize() == 8; }
9907330f729Sjoerg
hasSymbolTable() const9917330f729Sjoerg bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); }
992