36 #include <system_error> 42 static const char *
const Magic =
"!<arch>\n";
45 void Archive::anchor() {}
49 std::string StringMsg =
"truncated or malformed archive (" + Msg.
str() +
")";
50 return make_error<GenericBinaryError>(std::move(StringMsg),
55 const char *RawHeaderPtr,
58 ArMemHdr(reinterpret_cast<
const ArMemHdrType *>(RawHeaderPtr)) {
59 if (RawHeaderPtr ==
nullptr)
63 if (Size <
sizeof(ArMemHdrType)) {
65 std::string Msg(
"remaining size of archive too small for next archive " 77 if (ArMemHdr->Terminator[0] !=
'`' || ArMemHdr->Terminator[1] !=
'\n') {
82 sizeof(ArMemHdr->Terminator)));
84 std::string Msg(
"terminator characters in archive member \"" + Buf +
85 "\" not the correct \"`\\n\" values for the archive " 105 if (ArMemHdr->Name[0] ==
' ') {
106 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
108 return malformedError(
"name contains a leading space for archive member " 109 "header at offset " +
Twine(Offset));
113 else if (ArMemHdr->Name[0] ==
'/' || ArMemHdr->Name[0] ==
'#')
118 StringRef(ArMemHdr->Name,
sizeof(ArMemHdr->Name)).
find(EndCond);
120 end =
sizeof(ArMemHdr->Name);
121 assert(end <=
sizeof(ArMemHdr->Name) && end > 0);
134 if (Size <
offsetof(ArMemHdrType,
Name) +
sizeof(ArMemHdr->Name)) {
135 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
137 return malformedError(
"archive header truncated before the name field " 138 "for archive member header at offset " +
139 Twine(ArchiveOffset));
149 if (Name[0] ==
'/') {
150 if (Name.
size() == 1)
152 if (Name.
size() == 2 && Name[1] ==
'/')
156 std::size_t StringOffset;
162 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
164 return malformedError(
"long name offset characters after the '/' are " 165 "not all decimal numbers: '" + Buf +
"' for " 166 "archive member header at offset " +
167 Twine(ArchiveOffset));
172 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
175 "the end of the string table for archive member " 176 "header at offset " +
Twine(ArchiveOffset));
186 Twine(StringOffset) +
"not terminated");
200 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
202 return malformedError(
"long name length characters after the #1/ are " 203 "not all decimal numbers: '" + Buf +
"' for " 204 "archive member header at offset " +
205 Twine(ArchiveOffset));
208 uint64_t ArchiveOffset =
reinterpret_cast<const char *
>(ArMemHdr) -
211 " extends past the end of the member or archive " 212 "for archive member header at offset " +
213 Twine(ArchiveOffset));
216 NameLength).
rtrim(
'\0');
220 if (Name[Name.
size() - 1] !=
'/')
221 return Name.
rtrim(
' ');
234 sizeof(ArMemHdr->Size)).
rtrim(
" "));
236 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
238 return malformedError(
"characters in size field in archive header are not " 239 "all decimal numbers: '" + Buf +
"' for archive " 240 "member header at offset " +
Twine(Offset));
252 sizeof(ArMemHdr->AccessMode)).
rtrim(
" "));
254 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
256 return malformedError(
"characters in AccessMode field in archive header " 257 "are not all decimal numbers: '" + Buf +
"' for the " 258 "archive member header at offset " +
Twine(Offset));
267 sizeof(ArMemHdr->LastModified)).
rtrim(
' ')
272 sizeof(ArMemHdr->LastModified)).
rtrim(
" "));
274 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
276 return malformedError(
"characters in LastModified field in archive header " 277 "are not all decimal numbers: '" + Buf +
"' for the " 278 "archive member header at offset " +
Twine(Offset));
294 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
296 return malformedError(
"characters in UID field in archive header " 297 "are not all decimal numbers: '" + Buf +
"' for the " 298 "archive member header at offset " +
Twine(Offset));
313 uint64_t
Offset =
reinterpret_cast<const char *
>(ArMemHdr) -
315 return malformedError(
"characters in GID field in archive header " 316 "are not all decimal numbers: '" + Buf +
"' for the " 317 "archive member header at offset " +
Twine(Offset));
323 uint16_t StartOfFile)
324 : Parent(Parent), Header(Parent, Data.data(), Data.
size(), nullptr),
325 Data(Data), StartOfFile(StartOfFile) {
330 Header(Parent, Start,
341 assert(Err &&
"Err can't be nullptr if Start is not a nullptr");
364 Size += MemberSize.
get();
385 *Err =
malformedError(
"long name length characters after the #1/ are " 386 "not all decimal numbers: '" + Buf +
"' for " 387 "archive member header at offset " +
396 if (Parent->IsThin) {
402 return Data.
size() - StartOfFile;
414 return Parent->IsThin && Name !=
"/" && Name !=
"//";
424 return NameOrErr.takeError();
448 return FullNameOrErr.takeError();
449 const std::string &FullName = *FullNameOrErr;
451 if (std::error_code EC = Buf.
getError())
453 Parent->ThinBuffers.push_back(std::move(*Buf));
454 return Parent->ThinBuffers.back()->getBuffer();
458 size_t SpaceToSkip = Data.
size();
463 const char *NextLoc = Data.
data() + SpaceToSkip;
467 return Child(
nullptr,
nullptr,
nullptr);
471 std::string Msg(
"offset to next archive member past the end of the archive " 485 return std::move(Err);
491 const char *c = Data.
data();
492 uint64_t offset = c - a;
500 uint64_t RawSize = RawSizeOrErr.
get();
527 return std::move(*BinaryOrErr);
528 return BinaryOrErr.takeError();
533 std::unique_ptr<Archive>
Ret(
new Archive(Source, Err));
535 return std::move(Err);
536 return std::move(Ret);
539 void Archive::setFirstRegular(
const Child &
C) {
540 FirstRegularData = C.Data;
541 FirstRegularStartOfFile = C.StartOfFile;
554 Err = make_error<GenericBinaryError>(
"File too small to be an archive",
579 auto Increment = [&]() {
613 if (Name ==
"__.SYMDEF" || Name ==
"__.SYMDEF_64") {
614 if (Name ==
"__.SYMDEF")
625 SymbolTable = BufOrErr.
get();
642 Name = NameOrErr.
get();
643 if (Name ==
"__.SYMDEF SORTED" || Name ==
"__.SYMDEF") {
651 SymbolTable = BufOrErr.
get();
655 else if (Name ==
"__.SYMDEF_64 SORTED" || Name ==
"__.SYMDEF_64") {
664 SymbolTable = BufOrErr.
get();
677 bool has64SymTable =
false;
678 if (Name ==
"/" || Name ==
"/SYM64/") {
686 SymbolTable = BufOrErr.
get();
687 if (Name ==
"/SYM64/")
688 has64SymTable =
true;
701 Name = NameOrErr.
get();
713 StringTable = BufOrErr.
get();
721 if (Name[0] !=
'/') {
741 SymbolTable = BufOrErr.
get();
757 Name = NameOrErr.
get();
767 StringTable = BufOrErr.
get();
777 bool SkipInternal)
const {
783 FirstRegularStartOfFile),
798 return Parent->getSymbolTable().
begin() + StringIndex;
802 const char *Buf = Parent->getSymbolTable().begin();
805 Offsets +=
sizeof(uint64_t);
809 if (Parent->kind() ==
K_GNU) {
810 Offset =
read32be(Offsets + SymbolIndex * 4);
811 }
else if (Parent->kind() ==
K_GNU64) {
812 Offset =
read64be(Offsets + SymbolIndex * 8);
813 }
else if (Parent->kind() ==
K_BSD) {
820 Offset =
read32le(Offsets + SymbolIndex * 8 + 4);
828 Offset =
read64le(Offsets + SymbolIndex * 16 + 8);
832 Buf += MemberCount * 4 + 4;
835 if (SymbolIndex >= SymbolCount)
839 const char *Indices = Buf + 4;
843 uint16_t OffsetIndex =
read16le(Indices + SymbolIndex * 2);
847 if (OffsetIndex >= MemberCount)
850 Offset =
read32le(Offsets + OffsetIndex * 4);
853 const char *Loc = Parent->getData().begin() +
Offset;
855 Child C(Parent, Loc, &Err);
857 return std::move(Err);
863 if (Parent->kind() ==
K_BSD) {
877 const char *Buf = Parent->getSymbolTable().begin();
883 if (t.SymbolIndex + 1 < RanlibCount) {
884 const char *Ranlibs = Buf + 4;
887 CurRanStrx =
read32le(Ranlibs + t.SymbolIndex * 8);
888 NextRanStrx =
read32le(Ranlibs + (t.SymbolIndex + 1) * 8);
889 t.StringIndex -= CurRanStrx;
890 t.StringIndex += NextRanStrx;
894 t.StringIndex = Parent->getSymbolTable().find(
'\0', t.StringIndex) + 1;
910 uint64_t symbol_count =
read64be(buf);
911 buf +=
sizeof(uint64_t) + (symbol_count * (
sizeof(uint64_t)));
921 const char *ranlibs = buf + 4;
935 uint64_t ranlib_count = 0;
937 const char *ranlibs = buf + 8;
938 uint64_t ran_strx = 0;
940 buf +=
sizeof(uint64_t) + (ranlib_count * (2 * (
sizeof(uint64_t))));
942 buf +=
sizeof(uint64_t);
948 buf += 4 + (member_count * 4);
950 buf += 4 + (symbol_count * 2);
974 buf += 4 + (member_count * 4);
982 for (; bs != es; ++bs) {
984 if (SymName == name) {
986 return Child(*MemberOrErr);
988 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.
This class represents lattice values for constants.
static const char *const ThinMagic
const char * getBufferEnd() const
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const
size - Get the string size.
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.
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.
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< 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.
amdgpu Simplify well known AMD library false Value Value const Twine & Name
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?
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.
uint32_t getNumberOfSymbols() const
MemoryBufferRef getMemoryBufferRef() const
StringRef getName() const
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const
empty - Check if the string is empty.
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).
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
#define offsetof(TYPE, MEMBER)
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.
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.
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
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
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.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const char * getBufferStart() const
A raw_ostream that writes to an std::string.
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.
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.
StringRef getData() const
StringRef getSymbolTable() const