22 using namespace object;
23 using namespace llvm::support::endian;
25 static const char *
const Magic =
"!<arch>\n";
28 void Archive::anchor() { }
32 std::string StringMsg =
"truncated or malformed archive (" + Msg.
str() +
")";
33 return make_error<GenericBinaryError>(std::move(StringMsg),
38 const char *RawHeaderPtr,
39 uint64_t Size,
Error *Err)
41 ArMemHdr(reinterpret_cast<
const ArMemHdrType *>(RawHeaderPtr)) {
42 if (RawHeaderPtr ==
nullptr)
46 if (Size <
sizeof(ArMemHdrType)) {
48 std::string Msg(
"remaining size of archive too small for next archive "
60 if (ArMemHdr->Terminator[0] !=
'`' || ArMemHdr->Terminator[1] !=
'\n') {
65 sizeof(ArMemHdr->Terminator)));
67 std::string Msg(
"terminator characters in archive member \"" + Buf +
68 "\" not the correct \"`\\n\" values for the archive "
88 if (ArMemHdr->Name[0] ==
' ') {
89 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
91 return malformedError(
"name contains a leading space for archive member "
92 "header at offset " +
Twine(Offset));
96 else if (ArMemHdr->Name[0] ==
'/' || ArMemHdr->Name[0] ==
'#')
103 end =
sizeof(ArMemHdr->Name);
104 assert(end <=
sizeof(ArMemHdr->Name) && end > 0);
117 if (Size < offsetof(ArMemHdrType,
Name) +
sizeof(ArMemHdr->Name)) {
118 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
120 return malformedError(
"archive header truncated before the name field "
121 "for archive member header at offset " +
122 Twine(ArchiveOffset));
132 if (Name[0] ==
'/') {
133 if (Name.
size() == 1)
135 if (Name.
size() == 2 && Name[1] ==
'/')
139 std::size_t StringOffset;
145 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
147 return malformedError(
"long name offset characters after the '/' are "
148 "not all decimal numbers: '" + Buf +
"' for "
149 "archive member header at offset " +
150 Twine(ArchiveOffset));
155 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
158 "the end of the string table for archive member "
159 "header at offset " +
Twine(ArchiveOffset));
179 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
181 return malformedError(
"long name length characters after the #1/ are "
182 "not all decimal numbers: '" + Buf +
"' for "
183 "archive member header at offset " +
184 Twine(ArchiveOffset));
187 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
190 " extends past the end of the member or archive "
191 "for archive member header at offset " +
192 Twine(ArchiveOffset));
195 NameLength).
rtrim(
'\0');
199 if (Name[Name.
size() - 1] !=
'/')
200 return Name.
rtrim(
' ');
213 sizeof(ArMemHdr->Size)).
rtrim(
" "));
215 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
217 return malformedError(
"characters in size field in archive header are not "
218 "all decimal numbers: '" + Buf +
"' for archive "
219 "member header at offset " +
Twine(Offset));
231 sizeof(ArMemHdr->AccessMode)).
rtrim(
" "));
233 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
235 return malformedError(
"characters in AccessMode field in archive header "
236 "are not all decimal numbers: '" + Buf +
"' for the "
237 "archive member header at offset " +
Twine(Offset));
246 sizeof(ArMemHdr->LastModified)).
rtrim(
' ')
251 sizeof(ArMemHdr->LastModified)).
rtrim(
" "));
253 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
255 return malformedError(
"characters in LastModified field in archive header "
256 "are not all decimal numbers: '" + Buf +
"' for the "
257 "archive member header at offset " +
Twine(Offset));
273 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
275 return malformedError(
"characters in UID field in archive header "
276 "are not all decimal numbers: '" + Buf +
"' for the "
277 "archive member header at offset " +
Twine(Offset));
292 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
294 return malformedError(
"characters in GID field in archive header "
295 "are not all decimal numbers: '" + Buf +
"' for the "
296 "archive member header at offset " +
Twine(Offset));
302 uint16_t StartOfFile)
303 : Parent(Parent), Header(Parent, Data.data(), Data.size(), nullptr),
304 Data(Data), StartOfFile(StartOfFile) {
309 Header(Parent, Start,
320 assert(Err &&
"Err can't be nullptr if Start is not a nullptr");
343 Size += MemberSize.
get();
364 *Err =
malformedError(
"long name length characters after the #1/ are "
365 "not all decimal numbers: '" + Buf +
"' for "
366 "archive member header at offset " +
375 if (Parent->IsThin) {
381 return Data.size() - StartOfFile;
385 return Header.getSize();
393 return Parent->IsThin && Name !=
"/" && Name !=
"//";
403 return NameOrErr.takeError();
409 Parent->getMemoryBufferRef().getBufferIdentifier());
428 const std::string &FullName = *FullNameOrErr;
430 if (std::error_code EC = Buf.
getError())
432 Parent->ThinBuffers.push_back(std::move(*Buf));
433 return Parent->ThinBuffers.back()->getBuffer();
437 size_t SpaceToSkip =
Data.size();
442 const char *NextLoc =
Data.data() + SpaceToSkip;
445 if (NextLoc == Parent->Data.getBufferEnd())
446 return Child(
nullptr,
nullptr,
nullptr);
449 if (NextLoc > Parent->Data.getBufferEnd()) {
450 std::string Msg(
"offset to next archive member past the end of the archive "
455 uint64_t
Offset =
Data.data() - Parent->getData().data();
464 return std::move(Err);
469 const char *a = Parent->Data.getBuffer().data();
470 const char *c =
Data.data();
471 uint64_t offset = c - a;
479 uint64_t RawSize = RawSizeOrErr.
get();
506 return std::move(*BinaryOrErr);
507 return BinaryOrErr.takeError();
512 std::unique_ptr<Archive>
Ret(
new Archive(Source, Err));
514 return std::move(Err);
515 return std::move(Ret);
518 void Archive::setFirstRegular(
const Child &
C) {
519 FirstRegularData = C.Data;
520 FirstRegularStartOfFile = C.StartOfFile;
533 Err = make_error<GenericBinaryError>(
"File too small to be an archive",
558 auto Increment = [&]() {
592 if (Name ==
"__.SYMDEF" || Name ==
"__.SYMDEF_64") {
593 if (Name ==
"__.SYMDEF")
604 SymbolTable = BufOrErr.
get();
621 Name = NameOrErr.
get();
622 if (Name ==
"__.SYMDEF SORTED" || Name ==
"__.SYMDEF") {
630 SymbolTable = BufOrErr.
get();
634 else if (Name ==
"__.SYMDEF_64 SORTED" || Name ==
"__.SYMDEF_64") {
643 SymbolTable = BufOrErr.
get();
656 bool has64SymTable =
false;
657 if (Name ==
"/" || Name ==
"/SYM64/") {
665 SymbolTable = BufOrErr.
get();
666 if (Name ==
"/SYM64/")
667 has64SymTable =
true;
680 Name = NameOrErr.
get();
692 StringTable = BufOrErr.
get();
700 if (Name[0] !=
'/') {
720 SymbolTable = BufOrErr.
get();
736 Name = NameOrErr.
get();
746 StringTable = BufOrErr.
get();
756 bool SkipInternal)
const {
762 FirstRegularStartOfFile),
781 const char *Buf = Parent->getSymbolTable().begin();
784 Offsets +=
sizeof(uint64_t);
788 if (Parent->kind() ==
K_GNU) {
789 Offset =
read32be(Offsets + SymbolIndex * 4);
790 }
else if (Parent->kind() ==
K_MIPS64) {
791 Offset =
read64be(Offsets + SymbolIndex * 8);
792 }
else if (Parent->kind() ==
K_BSD) {
799 Offset =
read32le(Offsets + SymbolIndex * 8 + 4);
807 Offset =
read64le(Offsets + SymbolIndex * 16 + 8);
811 Buf += MemberCount * 4 + 4;
814 if (SymbolIndex >= SymbolCount)
818 const char *Indices = Buf + 4;
822 uint16_t OffsetIndex =
read16le(Indices + SymbolIndex * 2);
826 if (OffsetIndex >= MemberCount)
829 Offset =
read32le(Offsets + OffsetIndex * 4);
832 const char *Loc = Parent->getData().begin() +
Offset;
834 Child C(Parent, Loc, &Err);
836 return std::move(Err);
842 if (Parent->kind() ==
K_BSD) {
856 const char *Buf = Parent->getSymbolTable().begin();
862 if (t.SymbolIndex + 1 < RanlibCount) {
863 const char *Ranlibs = Buf + 4;
866 CurRanStrx =
read32le(Ranlibs + t.SymbolIndex * 8);
867 NextRanStrx =
read32le(Ranlibs + (t.SymbolIndex + 1) * 8);
868 t.StringIndex -= CurRanStrx;
869 t.StringIndex += NextRanStrx;
873 t.StringIndex = Parent->getSymbolTable().find(
'\0', t.StringIndex) + 1;
889 uint64_t symbol_count =
read64be(buf);
890 buf +=
sizeof(uint64_t) + (symbol_count * (
sizeof(uint64_t)));
900 const char *ranlibs = buf + 4;
914 uint64_t ranlib_count = 0;
916 const char *ranlibs = buf + 8;
917 uint64_t ran_strx = 0;
919 buf +=
sizeof(uint64_t) + (ranlib_count * (2 * (
sizeof(uint64_t))));
921 buf +=
sizeof(uint64_t);
927 buf += 4 + (member_count * 4);
929 buf += 4 + (symbol_count * 2);
953 buf += 4 + (member_count * 4);
961 for (; bs != es; ++bs) {
963 if (SymName == name) {
965 return Child(*MemberOrErr);
967 return MemberOrErr.takeError();
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.
const_iterator end(StringRef path)
Get end iterator over path.
std::error_code getError() const
Represents either an error or a value T.
symbol_iterator symbol_end() const
static const char *const ThinMagic
Expected< Optional< Child > > findSym(StringRef name) const
Expected< uint64_t > getRawSize() const
Archive(MemoryBufferRef Source, Error &Err)
uint64_t getChildOffset() const
StringRef getStringTable() const
child_iterator child_begin(Error &Err, bool SkipInternal=true) const
const char * getBufferStart() const
StringRef getSymbolTable() const
uint16_t read16le(const void *P)
Error takeError()
Take ownership of the stored error.
uint64_t read64be(const void *P)
LLVM_ATTRIBUTE_ALWAYS_INLINE TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
Expected< uint64_t > getSize() const
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)
Expected< StringRef > getName() const
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
std::string str() const
Return the twine contents as a std::string.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
uint32_t read32be(const void *P)
StringRef getData() const
static StringRef getName(Value *V)
bool is_absolute(const Twine &path)
Is path absolute?
LLVM_NODISCARD StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
Tagged union holding either a T or a Error.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
MemoryBufferRef getMemoryBufferRef() const
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const
size - Get the string size.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
static Expected< std::unique_ptr< Archive > > create(MemoryBufferRef Source)
bool hasSymbolTable() const
Expected< Child > getNext() const
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t find(char C, size_t From=0) const
Search for the first character C in the string.
child_iterator child_end() const
This is an important class for using LLVM in a threaded context.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
StringRef getName() const
static const unsigned End
Expected< std::string > getFullName() const
void consumeError(Error Err)
Consume a Error without doing anything.
size_t getBufferSize() const
static const char *const Magic
Expected< std::unique_ptr< Binary > > getAsBinary(LLVMContext *Context=nullptr) const
raw_ostream & write_escaped(StringRef Str, bool UseHexEscapes=false)
Output Str, turning '\', '', ' ', '"', and anything that doesn't satisfy std::isprint into an escape...
static ErrorSuccess success()
Create a success value.
symbol_iterator symbol_begin() const
StringRef getBuffer() const
reference get()
Returns a reference to the stored T value.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
StringRef parent_path(StringRef path)
Get parent path.
Helper for Errors used as out-parameters.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const
empty - Check if the string is empty.
Expected< StringRef > getRawName() const
uint64_t read64le(const void *P)
static Error malformedError(Twine Msg)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatileSize=false)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
Expected< Child > getMember() const
uint32_t read32le(const void *P)
uint32_t getNumberOfSymbols() const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Lightweight error class with error context and mandatory checking.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Expected< StringRef > getBuffer() const
StringRef - Represent a constant reference to a string, i.e.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
Expected< MemoryBufferRef > getMemoryBufferRef() const