35 #include <system_error> 41 static const char *
const Magic =
"!<arch>\n";
44 void Archive::anchor() {}
48 std::string StringMsg =
"truncated or malformed archive (" + Msg.
str() +
")";
49 return make_error<GenericBinaryError>(std::move(StringMsg),
54 const char *RawHeaderPtr,
57 ArMemHdr(reinterpret_cast<
const ArMemHdrType *>(RawHeaderPtr)) {
58 if (RawHeaderPtr ==
nullptr)
62 if (Size <
sizeof(ArMemHdrType)) {
64 std::string Msg(
"remaining size of archive too small for next archive " 76 if (ArMemHdr->Terminator[0] !=
'`' || ArMemHdr->Terminator[1] !=
'\n') {
81 sizeof(ArMemHdr->Terminator)));
83 std::string Msg(
"terminator characters in archive member \"" + Buf +
84 "\" not the correct \"`\\n\" values for the archive " 104 if (ArMemHdr->Name[0] ==
' ') {
105 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
107 return malformedError(
"name contains a leading space for archive member " 108 "header at offset " +
Twine(Offset));
112 else if (ArMemHdr->Name[0] ==
'/' || ArMemHdr->Name[0] ==
'#')
117 StringRef(ArMemHdr->Name,
sizeof(ArMemHdr->Name)).
find(EndCond);
119 end =
sizeof(ArMemHdr->Name);
120 assert(end <=
sizeof(ArMemHdr->Name) && end > 0);
133 if (Size <
offsetof(ArMemHdrType,
Name) +
sizeof(ArMemHdr->Name)) {
134 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
136 return malformedError(
"archive header truncated before the name field " 137 "for archive member header at offset " +
138 Twine(ArchiveOffset));
148 if (Name[0] ==
'/') {
149 if (Name.
size() == 1)
151 if (Name.
size() == 2 && Name[1] ==
'/')
155 std::size_t StringOffset;
161 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
163 return malformedError(
"long name offset characters after the '/' are " 164 "not all decimal numbers: '" + Buf +
"' for " 165 "archive member header at offset " +
166 Twine(ArchiveOffset));
171 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
174 "the end of the string table for archive member " 175 "header at offset " +
Twine(ArchiveOffset));
185 Twine(StringOffset) +
"not terminated");
199 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
201 return malformedError(
"long name length characters after the #1/ are " 202 "not all decimal numbers: '" + Buf +
"' for " 203 "archive member header at offset " +
204 Twine(ArchiveOffset));
207 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
210 " extends past the end of the member or archive " 211 "for archive member header at offset " +
212 Twine(ArchiveOffset));
215 NameLength).
rtrim(
'\0');
219 if (Name[Name.
size() - 1] !=
'/')
220 return Name.
rtrim(
' ');
233 sizeof(ArMemHdr->Size)).
rtrim(
" "));
235 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
237 return malformedError(
"characters in size field in archive header are not " 238 "all decimal numbers: '" + Buf +
"' for archive " 239 "member header at offset " +
Twine(Offset));
251 sizeof(ArMemHdr->AccessMode)).
rtrim(
" "));
253 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
255 return malformedError(
"characters in AccessMode field in archive header " 256 "are not all decimal numbers: '" + Buf +
"' for the " 257 "archive member header at offset " +
Twine(Offset));
266 sizeof(ArMemHdr->LastModified)).
rtrim(
' ')
271 sizeof(ArMemHdr->LastModified)).
rtrim(
" "));
273 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
275 return malformedError(
"characters in LastModified field in archive header " 276 "are not all decimal numbers: '" + Buf +
"' for the " 277 "archive member header at offset " +
Twine(Offset));
293 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
295 return malformedError(
"characters in UID field in archive header " 296 "are not all decimal numbers: '" + Buf +
"' for the " 297 "archive member header at offset " +
Twine(Offset));
312 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
314 return malformedError(
"characters in GID field in archive header " 315 "are not all decimal numbers: '" + Buf +
"' for the " 316 "archive member header at offset " +
Twine(Offset));
322 uint16_t StartOfFile)
323 : Parent(Parent), Header(Parent, Data.data(), Data.
size(), nullptr),
324 Data(Data), StartOfFile(StartOfFile) {
329 Header(Parent, Start,
340 assert(Err &&
"Err can't be nullptr if Start is not a nullptr");
363 Size += MemberSize.
get();
384 *Err =
malformedError(
"long name length characters after the #1/ are " 385 "not all decimal numbers: '" + Buf +
"' for " 386 "archive member header at offset " +
395 if (Parent->IsThin) {
401 return Data.
size() - StartOfFile;
413 return Parent->IsThin && Name !=
"/" && Name !=
"//";
423 return NameOrErr.takeError();
447 return FullNameOrErr.takeError();
448 const std::string &FullName = *FullNameOrErr;
450 if (std::error_code EC = Buf.
getError())
452 Parent->ThinBuffers.push_back(std::move(*Buf));
453 return Parent->ThinBuffers.back()->getBuffer();
457 size_t SpaceToSkip = Data.
size();
462 const char *NextLoc = Data.
data() + SpaceToSkip;
466 return Child(
nullptr,
nullptr,
nullptr);
470 std::string Msg(
"offset to next archive member past the end of the archive " 484 return std::move(Err);
490 const char *c = Data.
data();
491 uint64_t offset = c - a;
499 uint64_t RawSize = RawSizeOrErr.
get();
526 return std::move(*BinaryOrErr);
527 return BinaryOrErr.takeError();
532 std::unique_ptr<Archive>
Ret(
new Archive(Source, Err));
534 return std::move(Err);
535 return std::move(Ret);
538 void Archive::setFirstRegular(
const Child &
C) {
539 FirstRegularData = C.Data;
540 FirstRegularStartOfFile = C.StartOfFile;
553 Err = make_error<GenericBinaryError>(
"file too small to be an archive",
578 auto Increment = [&]() {
612 if (Name ==
"__.SYMDEF" || Name ==
"__.SYMDEF_64") {
613 if (Name ==
"__.SYMDEF")
624 SymbolTable = BufOrErr.
get();
641 Name = NameOrErr.
get();
642 if (Name ==
"__.SYMDEF SORTED" || Name ==
"__.SYMDEF") {
650 SymbolTable = BufOrErr.
get();
654 else if (Name ==
"__.SYMDEF_64 SORTED" || Name ==
"__.SYMDEF_64") {
663 SymbolTable = BufOrErr.
get();
676 bool has64SymTable =
false;
677 if (Name ==
"/" || Name ==
"/SYM64/") {
685 SymbolTable = BufOrErr.
get();
686 if (Name ==
"/SYM64/")
687 has64SymTable =
true;
700 Name = NameOrErr.
get();
712 StringTable = BufOrErr.
get();
720 if (Name[0] !=
'/') {
740 SymbolTable = BufOrErr.
get();
756 Name = NameOrErr.
get();
766 StringTable = BufOrErr.
get();
776 bool SkipInternal)
const {
782 Child(
this, FirstRegularData, FirstRegularStartOfFile), Err);
796 return Parent->getSymbolTable().
begin() + StringIndex;
800 const char *Buf = Parent->getSymbolTable().begin();
803 Offsets +=
sizeof(uint64_t);
807 if (Parent->kind() ==
K_GNU) {
808 Offset =
read32be(Offsets + SymbolIndex * 4);
809 }
else if (Parent->kind() ==
K_GNU64) {
810 Offset =
read64be(Offsets + SymbolIndex * 8);
811 }
else if (Parent->kind() ==
K_BSD) {
818 Offset =
read32le(Offsets + SymbolIndex * 8 + 4);
826 Offset =
read64le(Offsets + SymbolIndex * 16 + 8);
830 Buf += MemberCount * 4 + 4;
833 if (SymbolIndex >= SymbolCount)
837 const char *Indices = Buf + 4;
841 uint16_t OffsetIndex =
read16le(Indices + SymbolIndex * 2);
845 if (OffsetIndex >= MemberCount)
848 Offset =
read32le(Offsets + OffsetIndex * 4);
851 const char *Loc = Parent->getData().begin() +
Offset;
853 Child C(Parent, Loc, &Err);
855 return std::move(Err);
861 if (Parent->kind() ==
K_BSD) {
875 const char *Buf = Parent->getSymbolTable().begin();
881 if (t.SymbolIndex + 1 < RanlibCount) {
882 const char *Ranlibs = Buf + 4;
885 CurRanStrx =
read32le(Ranlibs + t.SymbolIndex * 8);
886 NextRanStrx =
read32le(Ranlibs + (t.SymbolIndex + 1) * 8);
887 t.StringIndex -= CurRanStrx;
888 t.StringIndex += NextRanStrx;
892 t.StringIndex = Parent->getSymbolTable().find(
'\0', t.StringIndex) + 1;
908 uint64_t symbol_count =
read64be(buf);
909 buf +=
sizeof(uint64_t) + (symbol_count * (
sizeof(uint64_t)));
919 const char *ranlibs = buf + 4;
933 uint64_t ranlib_count = 0;
935 const char *ranlibs = buf + 8;
936 uint64_t ran_strx = 0;
938 buf +=
sizeof(uint64_t) + (ranlib_count * (2 * (
sizeof(uint64_t))));
940 buf +=
sizeof(uint64_t);
946 buf += 4 + (member_count * 4);
948 buf += 4 + (symbol_count * 2);
972 buf += 4 + (member_count * 4);
980 for (; bs != es; ++bs) {
982 if (SymName == name) {
984 return Child(*MemberOrErr);
986 return MemberOrErr.takeError();
child_iterator child_begin(Error &Err, bool SkipInternal=true) const
const_iterator end(StringRef path)
Get end iterator over path.
Represents either an error or a value T.
static fallible_iterator itr(Underlying I, Error &Err)
Construct a fallible iterator that cannot be used as an end-of-range value.
This class represents lattice values for constants.
static const char *const ThinMagic
const char * getBufferEnd() const
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Archive(MemoryBufferRef Source, Error &Err)
Expected< Optional< Child > > findSym(StringRef name) const
Expected< Child > getNext() const
uint16_t read16le(const void *P)
Error takeError()
Take ownership of the stored error.
static fallible_iterator end(Underlying I)
Construct a fallible iteratro that can be used as an end-of-range value.
uint64_t read64be(const void *P)
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr)
Create a Binary from Source, autodetecting the file type.
Child(const Archive *Parent, const char *Start, Error *Err)
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
uint32_t read32be(const void *P)
symbol_iterator symbol_begin() const
StringRef getBuffer() const
Expected< std::unique_ptr< Binary > > getAsBinary(LLVMContext *Context=nullptr) const
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_NODISCARD StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
Tagged union holding either a T or a Error.
LLVM_NODISCARD StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
uint32_t getNumberOfSymbols() const
MemoryBufferRef getMemoryBufferRef() const
StringRef getName() const
LLVM_NODISCARD size_t size() const
size - Get the string size.
static Expected< std::unique_ptr< Archive > > create(MemoryBufferRef Source)
Expected< uint64_t > getRawSize() const
size_t getBufferSize() const
This is an important class for using LLVM in a threaded context.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
StringRef getStringTable() const
Expected< std::string > getFullName() const
std::error_code getError() const
A wrapper class for fallible iterators.
#define offsetof(TYPE, MEMBER)
LLVM_NODISCARD size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Expected< StringRef > getBuffer() const
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
uint64_t getChildOffset() const
void consumeError(Error Err)
Consume a Error without doing anything.
static const char *const Magic
std::enable_if< std::numeric_limits< T >::is_signed, bool >::type getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
raw_ostream & write_escaped(StringRef Str, bool UseHexEscapes=false)
Output Str, turning '\', '', ' ', '"', and anything that doesn't satisfy llvm::isPrint into an escape...
static ErrorSuccess success()
Create a success value.
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
symbol_iterator symbol_end() const
reference get()
Returns a reference to the stored T value.
Expected< uint64_t > getSize() const
Expected< StringRef > getRawName() const
Expected< MemoryBufferRef > getMemoryBufferRef() const
StringRef getBufferIdentifier() const
Helper for Errors used as out-parameters.
Expected< Child > getMember() const
child_iterator child_end() const
uint64_t read64le(const void *P)
static Error malformedError(Twine Msg)
uint32_t read32le(const void *P)
Expected< StringRef > getName() const
bool hasSymbolTable() const
std::string str() const
Return the twine contents as a std::string.
Provides ErrorOr<T> smart pointer.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
LLVM_NODISCARD const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const char * getBufferStart() const
A raw_ostream that writes to an std::string.
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
LLVM_NODISCARD StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
Lightweight error class with error context and mandatory checking.
LLVM_NODISCARD StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
StringRef - Represent a constant reference to a string, i.e.
StringRef getData() const
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
StringRef getSymbolTable() const