| 1 | //===- Archive.cpp - ar File Format implementation ------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file defines the ArchiveObjectFile class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "llvm/Object/Archive.h" |
| 14 | #include "llvm/ADT/SmallString.h" |
| 15 | #include "llvm/ADT/StringRef.h" |
| 16 | #include "llvm/ADT/Twine.h" |
| 17 | #include "llvm/Object/Binary.h" |
| 18 | #include "llvm/Object/Error.h" |
| 19 | #include "llvm/Support/Chrono.h" |
| 20 | #include "llvm/Support/ConvertEBCDIC.h" |
| 21 | #include "llvm/Support/Endian.h" |
| 22 | #include "llvm/Support/EndianStream.h" |
| 23 | #include "llvm/Support/Error.h" |
| 24 | #include "llvm/Support/ErrorOr.h" |
| 25 | #include "llvm/Support/FileSystem.h" |
| 26 | #include "llvm/Support/MathExtras.h" |
| 27 | #include "llvm/Support/MemoryBuffer.h" |
| 28 | #include "llvm/Support/Path.h" |
| 29 | #include "llvm/Support/raw_ostream.h" |
| 30 | #include "llvm/TargetParser/Host.h" |
| 31 | #include <cassert> |
| 32 | #include <cstddef> |
| 33 | #include <cstdint> |
| 34 | #include <memory> |
| 35 | #include <string> |
| 36 | #include <system_error> |
| 37 | |
| 38 | using namespace llvm; |
| 39 | using namespace object; |
| 40 | using namespace llvm::support::endian; |
| 41 | |
| 42 | void Archive::anchor() {} |
| 43 | |
| 44 | static Error malformedError(Twine Msg) { |
| 45 | std::string StringMsg = "truncated or malformed archive (" + Msg.str() + ")" ; |
| 46 | return make_error<GenericBinaryError>(Args: std::move(StringMsg), |
| 47 | Args: object_error::parse_failed); |
| 48 | } |
| 49 | |
| 50 | static Error |
| 51 | (const AbstractArchiveMemberHeader *, |
| 52 | const char *, uint64_t Size) { |
| 53 | StringRef Msg("remaining size of archive too small for next archive " |
| 54 | "member header " ); |
| 55 | |
| 56 | Expected<StringRef> NameOrErr = ArMemHeader->getName(Size); |
| 57 | if (NameOrErr) |
| 58 | return malformedError(Msg: Msg + "for " + *NameOrErr); |
| 59 | |
| 60 | consumeError(Err: NameOrErr.takeError()); |
| 61 | uint64_t Offset = RawHeaderPtr - ArMemHeader->Parent->getData().data(); |
| 62 | return malformedError(Msg: Msg + "at offset " + Twine(Offset)); |
| 63 | } |
| 64 | |
| 65 | template <class T, std::size_t N> |
| 66 | StringRef getFieldRawString(const T (&Field)[N]) { |
| 67 | return StringRef(Field, N).rtrim(Chars: " " ); |
| 68 | } |
| 69 | |
| 70 | template <class T> |
| 71 | StringRef CommonArchiveMemberHeader<T>::() const { |
| 72 | return getFieldRawString(ArMemHdr->AccessMode); |
| 73 | } |
| 74 | |
| 75 | template <class T> |
| 76 | StringRef CommonArchiveMemberHeader<T>::() const { |
| 77 | return getFieldRawString(ArMemHdr->LastModified); |
| 78 | } |
| 79 | |
| 80 | template <class T> StringRef CommonArchiveMemberHeader<T>::() const { |
| 81 | return getFieldRawString(ArMemHdr->UID); |
| 82 | } |
| 83 | |
| 84 | template <class T> StringRef CommonArchiveMemberHeader<T>::() const { |
| 85 | return getFieldRawString(ArMemHdr->GID); |
| 86 | } |
| 87 | |
| 88 | template <class T> uint64_t CommonArchiveMemberHeader<T>::() const { |
| 89 | return reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 90 | } |
| 91 | |
| 92 | template class object::<UnixArMemHdrType>; |
| 93 | template class object::<BigArMemHdrType>; |
| 94 | |
| 95 | ArchiveMemberHeader::(const Archive *Parent, |
| 96 | const char *, |
| 97 | uint64_t Size, Error *Err) |
| 98 | : CommonArchiveMemberHeader<UnixArMemHdrType>( |
| 99 | Parent, reinterpret_cast<const UnixArMemHdrType *>(RawHeaderPtr)) { |
| 100 | if (RawHeaderPtr == nullptr) |
| 101 | return; |
| 102 | ErrorAsOutParameter ErrAsOutParam(Err); |
| 103 | |
| 104 | if (Size < getSizeOf()) { |
| 105 | *Err = createMemberHeaderParseError(ArMemHeader: this, RawHeaderPtr, Size); |
| 106 | return; |
| 107 | } |
| 108 | // '\x79\x15' is the EBCDIC equivalent of '`\n' for the z/OS archive |
| 109 | // terminator. |
| 110 | bool ValidTerminator = |
| 111 | Parent->kind() == Archive::K_ZOS |
| 112 | ? (ArMemHdr->Terminator[0] == '\x79' && |
| 113 | ArMemHdr->Terminator[1] == '\x15') |
| 114 | : (ArMemHdr->Terminator[0] == '`' && ArMemHdr->Terminator[1] == '\n'); |
| 115 | if (!ValidTerminator) { |
| 116 | if (Err) { |
| 117 | std::string Buf; |
| 118 | raw_string_ostream OS(Buf); |
| 119 | OS.write_escaped( |
| 120 | Str: StringRef(ArMemHdr->Terminator, sizeof(ArMemHdr->Terminator))); |
| 121 | std::string Msg("terminator characters in archive member \"" + Buf + |
| 122 | "\" not the correct \"`\\n\" values for the archive " |
| 123 | "member header " ); |
| 124 | Expected<StringRef> NameOrErr = getName(Size); |
| 125 | if (!NameOrErr) { |
| 126 | consumeError(Err: NameOrErr.takeError()); |
| 127 | uint64_t Offset = RawHeaderPtr - Parent->getData().data(); |
| 128 | *Err = malformedError(Msg: Msg + "at offset " + Twine(Offset)); |
| 129 | } else { |
| 130 | *Err = malformedError(Msg: Msg + "for " + NameOrErr.get()); |
| 131 | } |
| 132 | } |
| 133 | return; |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | BigArchiveMemberHeader::(const Archive *Parent, |
| 138 | const char *, |
| 139 | uint64_t Size, Error *Err) |
| 140 | : CommonArchiveMemberHeader<BigArMemHdrType>( |
| 141 | Parent, reinterpret_cast<const BigArMemHdrType *>(RawHeaderPtr)) { |
| 142 | if (RawHeaderPtr == nullptr) |
| 143 | return; |
| 144 | ErrorAsOutParameter ErrAsOutParam(Err); |
| 145 | |
| 146 | if (RawHeaderPtr + getSizeOf() >= Parent->getData().end()) { |
| 147 | if (Err) |
| 148 | *Err = malformedError(Msg: "malformed AIX big archive: remaining buffer is " |
| 149 | "unable to contain next archive member" ); |
| 150 | return; |
| 151 | } |
| 152 | |
| 153 | if (Size < getSizeOf()) { |
| 154 | Error SubErr = createMemberHeaderParseError(ArMemHeader: this, RawHeaderPtr, Size); |
| 155 | if (Err) |
| 156 | *Err = std::move(SubErr); |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | // This gets the raw name from the ArMemHdr->Name field and checks that it is |
| 161 | // valid for the kind of archive. If it is not valid it returns an Error. |
| 162 | Expected<StringRef> ArchiveMemberHeader::() const { |
| 163 | char EndCond; |
| 164 | auto Kind = Parent->kind(); |
| 165 | if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN64) { |
| 166 | if (ArMemHdr->Name[0] == ' ') { |
| 167 | uint64_t Offset = |
| 168 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 169 | return malformedError(Msg: "name contains a leading space for archive member " |
| 170 | "header at offset " + |
| 171 | Twine(Offset)); |
| 172 | } |
| 173 | EndCond = ' '; |
| 174 | } else if (ArMemHdr->Name[0] == '/' || ArMemHdr->Name[0] == '#') |
| 175 | EndCond = ' '; |
| 176 | else |
| 177 | EndCond = '/'; |
| 178 | StringRef::size_type end = |
| 179 | StringRef(ArMemHdr->Name, sizeof(ArMemHdr->Name)).find(C: EndCond); |
| 180 | if (end == StringRef::npos) |
| 181 | end = sizeof(ArMemHdr->Name); |
| 182 | assert(end <= sizeof(ArMemHdr->Name) && end > 0); |
| 183 | // Don't include the EndCond if there is one. |
| 184 | return StringRef(ArMemHdr->Name, end); |
| 185 | } |
| 186 | |
| 187 | Expected<uint64_t> |
| 188 | (Twine FieldName, const StringRef RawField, |
| 189 | const Archive *Parent, |
| 190 | const AbstractArchiveMemberHeader *) { |
| 191 | uint64_t Value; |
| 192 | if (RawField.getAsInteger(Radix: 10, Result&: Value)) { |
| 193 | uint64_t Offset = MemHeader->getOffset(); |
| 194 | return malformedError(Msg: "characters in " + FieldName + |
| 195 | " field in archive member header are not " |
| 196 | "all decimal numbers: '" + |
| 197 | RawField + |
| 198 | "' for the archive " |
| 199 | "member header at offset " + |
| 200 | Twine(Offset)); |
| 201 | } |
| 202 | return Value; |
| 203 | } |
| 204 | |
| 205 | Expected<uint64_t> |
| 206 | (Twine FieldName, const StringRef RawField, |
| 207 | const Archive *Parent, |
| 208 | const AbstractArchiveMemberHeader *) { |
| 209 | uint64_t Value; |
| 210 | if (RawField.getAsInteger(Radix: 8, Result&: Value)) { |
| 211 | uint64_t Offset = MemHeader->getOffset(); |
| 212 | return malformedError(Msg: "characters in " + FieldName + |
| 213 | " field in archive member header are not " |
| 214 | "all octal numbers: '" + |
| 215 | RawField + |
| 216 | "' for the archive " |
| 217 | "member header at offset " + |
| 218 | Twine(Offset)); |
| 219 | } |
| 220 | return Value; |
| 221 | } |
| 222 | |
| 223 | Expected<StringRef> BigArchiveMemberHeader::() const { |
| 224 | Expected<uint64_t> NameLenOrErr = getArchiveMemberDecField( |
| 225 | FieldName: "NameLen" , RawField: getFieldRawString(Field: ArMemHdr->NameLen), Parent, MemHeader: this); |
| 226 | if (!NameLenOrErr) |
| 227 | // TODO: Out-of-line. |
| 228 | return NameLenOrErr.takeError(); |
| 229 | uint64_t NameLen = NameLenOrErr.get(); |
| 230 | |
| 231 | // If the name length is odd, pad with '\0' to get an even length. After |
| 232 | // padding, there is the name terminator "`\n". |
| 233 | uint64_t NameLenWithPadding = alignTo(Value: NameLen, Align: 2); |
| 234 | StringRef NameTerminator = "`\n" ; |
| 235 | StringRef NameStringWithNameTerminator = |
| 236 | StringRef(ArMemHdr->Name, NameLenWithPadding + NameTerminator.size()); |
| 237 | if (!NameStringWithNameTerminator.ends_with(Suffix: NameTerminator)) { |
| 238 | uint64_t Offset = |
| 239 | reinterpret_cast<const char *>(ArMemHdr->Name + NameLenWithPadding) - |
| 240 | Parent->getData().data(); |
| 241 | // TODO: Out-of-line. |
| 242 | return malformedError( |
| 243 | Msg: "name does not have name terminator \"`\\n\" for archive member" |
| 244 | "header at offset " + |
| 245 | Twine(Offset)); |
| 246 | } |
| 247 | return StringRef(ArMemHdr->Name, NameLen); |
| 248 | } |
| 249 | |
| 250 | // member including the header, so the size of any name following the header |
| 251 | // is checked to make sure it does not overflow. |
| 252 | Expected<StringRef> ArchiveMemberHeader::(uint64_t Size) const { |
| 253 | |
| 254 | // This can be called from the ArchiveMemberHeader constructor when the |
| 255 | // archive header is truncated to produce an error message with the name. |
| 256 | // Make sure the name field is not truncated. |
| 257 | if (Size < offsetof(UnixArMemHdrType, Name) + sizeof(ArMemHdr->Name)) { |
| 258 | uint64_t ArchiveOffset = |
| 259 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 260 | return malformedError(Msg: "archive header truncated before the name field " |
| 261 | "for archive member header at offset " + |
| 262 | Twine(ArchiveOffset)); |
| 263 | } |
| 264 | |
| 265 | // The raw name itself can be invalid. |
| 266 | Expected<StringRef> NameOrErr = getRawName(); |
| 267 | if (!NameOrErr) |
| 268 | return NameOrErr.takeError(); |
| 269 | StringRef Name = NameOrErr.get(); |
| 270 | |
| 271 | // Check if it's a special name. |
| 272 | if (Name[0] == '/') { |
| 273 | if (Name.size() == 1) // Linker member. |
| 274 | return Name; |
| 275 | if (Name.size() == 2 && Name[1] == '/') // String table. |
| 276 | return Name; |
| 277 | // System libraries from the Windows SDK for Windows 11 contain this symbol. |
| 278 | // It looks like a CFG guard: we just skip it for now. |
| 279 | if (Name == "/<XFGHASHMAP>/" ) |
| 280 | return Name; |
| 281 | // Some libraries (e.g., arm64rt.lib) from the Windows WDK |
| 282 | // (version 10.0.22000.0) contain this undocumented special member. |
| 283 | if (Name == "/<ECSYMBOLS>/" ) |
| 284 | return Name; |
| 285 | // It's a long name. |
| 286 | // Get the string table offset. |
| 287 | std::size_t StringOffset; |
| 288 | if (Name.substr(Start: 1).rtrim(Char: ' ').getAsInteger(Radix: 10, Result&: StringOffset)) { |
| 289 | std::string Buf; |
| 290 | raw_string_ostream OS(Buf); |
| 291 | OS.write_escaped(Str: Name.substr(Start: 1).rtrim(Char: ' ')); |
| 292 | uint64_t ArchiveOffset = |
| 293 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 294 | return malformedError(Msg: "long name offset characters after the '/' are " |
| 295 | "not all decimal numbers: '" + |
| 296 | Buf + "' for archive member header at offset " + |
| 297 | Twine(ArchiveOffset)); |
| 298 | } |
| 299 | |
| 300 | // Verify it. |
| 301 | if (StringOffset >= Parent->getStringTable().size()) { |
| 302 | uint64_t ArchiveOffset = |
| 303 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 304 | return malformedError(Msg: "long name offset " + Twine(StringOffset) + |
| 305 | " past the end of the string table for archive " |
| 306 | "member header at offset " + |
| 307 | Twine(ArchiveOffset)); |
| 308 | } |
| 309 | |
| 310 | // GNU long file names end with a "/\n". |
| 311 | if (Parent->kind() == Archive::K_GNU || |
| 312 | Parent->kind() == Archive::K_GNU64) { |
| 313 | size_t End = Parent->getStringTable().find(C: '\n', /*From=*/StringOffset); |
| 314 | if (End == StringRef::npos || End < 1 || |
| 315 | Parent->getStringTable()[End - 1] != '/') { |
| 316 | return malformedError(Msg: "string table at long name offset " + |
| 317 | Twine(StringOffset) + " not terminated" ); |
| 318 | } |
| 319 | return Parent->getStringTable().slice(Start: StringOffset, End: End - 1); |
| 320 | } |
| 321 | return Parent->getStringTable().begin() + StringOffset; |
| 322 | } |
| 323 | |
| 324 | if (Name.starts_with(Prefix: "#1/" )) { |
| 325 | uint64_t NameLength; |
| 326 | if (Name.substr(Start: 3).rtrim(Char: ' ').getAsInteger(Radix: 10, Result&: NameLength)) { |
| 327 | std::string Buf; |
| 328 | raw_string_ostream OS(Buf); |
| 329 | OS.write_escaped(Str: Name.substr(Start: 3).rtrim(Char: ' ')); |
| 330 | uint64_t ArchiveOffset = |
| 331 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 332 | return malformedError(Msg: "long name length characters after the #1/ are " |
| 333 | "not all decimal numbers: '" + |
| 334 | Buf + "' for archive member header at offset " + |
| 335 | Twine(ArchiveOffset)); |
| 336 | } |
| 337 | if (getSizeOf() + NameLength > Size) { |
| 338 | uint64_t ArchiveOffset = |
| 339 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 340 | return malformedError(Msg: "long name length: " + Twine(NameLength) + |
| 341 | " extends past the end of the member or archive " |
| 342 | "for archive member header at offset " + |
| 343 | Twine(ArchiveOffset)); |
| 344 | } |
| 345 | return StringRef(reinterpret_cast<const char *>(ArMemHdr) + getSizeOf(), |
| 346 | NameLength) |
| 347 | .rtrim(Char: '\0'); |
| 348 | } |
| 349 | |
| 350 | // It is not a long name so trim the blanks at the end of the name. |
| 351 | if (Name[Name.size() - 1] != '/') |
| 352 | return Name.rtrim(Char: ' '); |
| 353 | |
| 354 | // It's a simple name. |
| 355 | return Name.drop_back(N: 1); |
| 356 | } |
| 357 | |
| 358 | Expected<StringRef> BigArchiveMemberHeader::(uint64_t Size) const { |
| 359 | return getRawName(); |
| 360 | } |
| 361 | |
| 362 | Expected<uint64_t> ArchiveMemberHeader::() const { |
| 363 | return getArchiveMemberDecField(FieldName: "size" , RawField: getFieldRawString(Field: ArMemHdr->Size), |
| 364 | Parent, MemHeader: this); |
| 365 | } |
| 366 | |
| 367 | Expected<uint64_t> BigArchiveMemberHeader::() const { |
| 368 | Expected<uint64_t> SizeOrErr = getArchiveMemberDecField( |
| 369 | FieldName: "size" , RawField: getFieldRawString(Field: ArMemHdr->Size), Parent, MemHeader: this); |
| 370 | if (!SizeOrErr) |
| 371 | return SizeOrErr.takeError(); |
| 372 | |
| 373 | Expected<uint64_t> NameLenOrErr = getRawNameSize(); |
| 374 | if (!NameLenOrErr) |
| 375 | return NameLenOrErr.takeError(); |
| 376 | |
| 377 | return *SizeOrErr + alignTo(Value: *NameLenOrErr, Align: 2); |
| 378 | } |
| 379 | |
| 380 | template <std::size_t N> |
| 381 | std::string ebcdicFieldToASCII(const char (&Field)[N]) { |
| 382 | SmallString<64> Dst; |
| 383 | StringRef Src = StringRef(Field, N); |
| 384 | ConverterEBCDIC::convertToUTF8(Source: Src, Result&: Dst); |
| 385 | return Dst.str().rtrim(Chars: " " ).str(); |
| 386 | } |
| 387 | |
| 388 | ZOSArchiveMemberHeader::(const Archive *Parent, |
| 389 | const char *, |
| 390 | uint64_t Size, Error *Err) |
| 391 | : ArchiveMemberHeader(Parent, RawHeaderPtr, Size, Err) { |
| 392 | ErrorAsOutParameter ErrAsOutParam(Err); |
| 393 | // If the base class constructor already detected an error |
| 394 | // do not attempt to read header fields |
| 395 | if (Err && *Err) |
| 396 | return; |
| 397 | setMemberHeaderStrings(Err, Size); |
| 398 | } |
| 399 | |
| 400 | Expected<uint64_t> ZOSArchiveMemberHeader::() const { |
| 401 | return getArchiveMemberDecField(FieldName: "size" , RawField: ebcdicFieldToASCII(Field: ArMemHdr->Size), |
| 402 | Parent, MemHeader: this); |
| 403 | } |
| 404 | |
| 405 | Expected<StringRef> ZOSArchiveMemberHeader::() const { |
| 406 | return StringRef(RawMemberName); |
| 407 | } |
| 408 | |
| 409 | Expected<StringRef> ZOSArchiveMemberHeader::(uint64_t /*Size*/) const { |
| 410 | return StringRef(MemberName); |
| 411 | } |
| 412 | |
| 413 | StringRef ZOSArchiveMemberHeader::() const { |
| 414 | return StringRef(AccessMode); |
| 415 | } |
| 416 | |
| 417 | StringRef ZOSArchiveMemberHeader::() const { |
| 418 | return StringRef(LastModified); |
| 419 | } |
| 420 | |
| 421 | StringRef ZOSArchiveMemberHeader::() const { return StringRef(UID); } |
| 422 | |
| 423 | StringRef ZOSArchiveMemberHeader::() const { return StringRef(GID); } |
| 424 | |
| 425 | void ZOSArchiveMemberHeader::(Error *Err, uint64_t Size) { |
| 426 | uint64_t Offset = |
| 427 | reinterpret_cast<const char *>(ArMemHdr) - Parent->getData().data(); |
| 428 | |
| 429 | // Set RawMemberName |
| 430 | RawMemberName = ebcdicFieldToASCII(Field: ArMemHdr->Name); |
| 431 | if (RawMemberName.empty() || RawMemberName[0] == ' ') { |
| 432 | *Err = malformedError(Msg: "name contains a leading space for archive member " |
| 433 | "header at offset " + |
| 434 | Twine(Offset)); |
| 435 | return; |
| 436 | } |
| 437 | |
| 438 | // Set MemberName. |
| 439 | if (StringRef(RawMemberName).starts_with(Prefix: "#1/" )) { |
| 440 | Expected<StringRef> NameOrErr = ArchiveMemberHeader::getName(Size); |
| 441 | if (!NameOrErr) { |
| 442 | *Err = NameOrErr.takeError(); |
| 443 | return; |
| 444 | } |
| 445 | StringRef Name = NameOrErr.get(); |
| 446 | SmallString<64> ConvertedName; |
| 447 | ConverterEBCDIC::convertToUTF8(Source: Name, Result&: ConvertedName); |
| 448 | MemberName = std::string(ConvertedName); |
| 449 | } else { |
| 450 | MemberName = RawMemberName; |
| 451 | } |
| 452 | |
| 453 | // LastModified |
| 454 | LastModified = ebcdicFieldToASCII(Field: ArMemHdr->LastModified); |
| 455 | if (LastModified.empty()) { |
| 456 | *Err = |
| 457 | malformedError(Msg: "LastModified field is empty or contains only spaces in " |
| 458 | "archive member header at offset " + |
| 459 | Twine(Offset)); |
| 460 | return; |
| 461 | } |
| 462 | |
| 463 | // UID |
| 464 | UID = ebcdicFieldToASCII(Field: ArMemHdr->UID); |
| 465 | if (UID.empty()) { |
| 466 | *Err = malformedError(Msg: "UID field is empty or contains only spaces in " |
| 467 | "archive member header at offset " + |
| 468 | Twine(Offset)); |
| 469 | return; |
| 470 | } |
| 471 | |
| 472 | // GID |
| 473 | GID = ebcdicFieldToASCII(Field: ArMemHdr->GID); |
| 474 | if (GID.empty()) { |
| 475 | *Err = malformedError(Msg: "GID field is empty or contains only spaces in " |
| 476 | "archive member header at offset " + |
| 477 | Twine(Offset)); |
| 478 | return; |
| 479 | } |
| 480 | |
| 481 | // AccessMode |
| 482 | AccessMode = ebcdicFieldToASCII(Field: ArMemHdr->AccessMode); |
| 483 | if (AccessMode.empty()) { |
| 484 | *Err = |
| 485 | malformedError(Msg: "AccessMode field is empty or contains only spaces in " |
| 486 | "archive member header at offset " + |
| 487 | Twine(Offset)); |
| 488 | return; |
| 489 | } |
| 490 | } |
| 491 | |
| 492 | Expected<uint64_t> BigArchiveMemberHeader::() const { |
| 493 | return getArchiveMemberDecField( |
| 494 | FieldName: "NameLen" , RawField: getFieldRawString(Field: ArMemHdr->NameLen), Parent, MemHeader: this); |
| 495 | } |
| 496 | |
| 497 | Expected<uint64_t> BigArchiveMemberHeader::() const { |
| 498 | return getArchiveMemberDecField( |
| 499 | FieldName: "NextOffset" , RawField: getFieldRawString(Field: ArMemHdr->NextOffset), Parent, MemHeader: this); |
| 500 | } |
| 501 | |
| 502 | Expected<sys::fs::perms> AbstractArchiveMemberHeader::() const { |
| 503 | Expected<uint64_t> AccessModeOrErr = |
| 504 | getArchiveMemberOctField(FieldName: "AccessMode" , RawField: getRawAccessMode(), Parent, MemHeader: this); |
| 505 | if (!AccessModeOrErr) |
| 506 | return AccessModeOrErr.takeError(); |
| 507 | return static_cast<sys::fs::perms>(*AccessModeOrErr); |
| 508 | } |
| 509 | |
| 510 | Expected<sys::TimePoint<std::chrono::seconds>> |
| 511 | AbstractArchiveMemberHeader::() const { |
| 512 | Expected<uint64_t> SecondsOrErr = getArchiveMemberDecField( |
| 513 | FieldName: "LastModified" , RawField: getRawLastModified(), Parent, MemHeader: this); |
| 514 | |
| 515 | if (!SecondsOrErr) |
| 516 | return SecondsOrErr.takeError(); |
| 517 | |
| 518 | return sys::toTimePoint(T: *SecondsOrErr); |
| 519 | } |
| 520 | |
| 521 | Expected<unsigned> AbstractArchiveMemberHeader::() const { |
| 522 | StringRef User = getRawUID(); |
| 523 | if (User.empty()) |
| 524 | return 0; |
| 525 | return getArchiveMemberDecField(FieldName: "UID" , RawField: User, Parent, MemHeader: this); |
| 526 | } |
| 527 | |
| 528 | Expected<unsigned> AbstractArchiveMemberHeader::() const { |
| 529 | StringRef Group = getRawGID(); |
| 530 | if (Group.empty()) |
| 531 | return 0; |
| 532 | return getArchiveMemberDecField(FieldName: "GID" , RawField: Group, Parent, MemHeader: this); |
| 533 | } |
| 534 | |
| 535 | Expected<bool> ArchiveMemberHeader::() const { |
| 536 | Expected<StringRef> NameOrErr = getRawName(); |
| 537 | if (!NameOrErr) |
| 538 | return NameOrErr.takeError(); |
| 539 | StringRef Name = NameOrErr.get(); |
| 540 | return Parent->isThin() && Name != "/" && Name != "//" && Name != "/SYM64/" ; |
| 541 | } |
| 542 | |
| 543 | Expected<const char *> ArchiveMemberHeader::() const { |
| 544 | uint64_t Size = getSizeOf(); |
| 545 | Expected<bool> isThinOrErr = isThin(); |
| 546 | if (!isThinOrErr) |
| 547 | return isThinOrErr.takeError(); |
| 548 | |
| 549 | bool isThin = isThinOrErr.get(); |
| 550 | if (!isThin) { |
| 551 | Expected<uint64_t> MemberSize = getSize(); |
| 552 | if (!MemberSize) |
| 553 | return MemberSize.takeError(); |
| 554 | |
| 555 | Size += MemberSize.get(); |
| 556 | } |
| 557 | |
| 558 | // If Size is odd, add 1 to make it even. |
| 559 | const char *NextLoc = |
| 560 | reinterpret_cast<const char *>(ArMemHdr) + alignTo(Value: Size, Align: 2); |
| 561 | |
| 562 | if (NextLoc == Parent->getMemoryBufferRef().getBufferEnd()) |
| 563 | return nullptr; |
| 564 | |
| 565 | return NextLoc; |
| 566 | } |
| 567 | |
| 568 | Expected<const char *> BigArchiveMemberHeader::() const { |
| 569 | if (getOffset() == |
| 570 | static_cast<const BigArchive *>(Parent)->getLastChildOffset()) |
| 571 | return nullptr; |
| 572 | |
| 573 | Expected<uint64_t> NextOffsetOrErr = getNextOffset(); |
| 574 | if (!NextOffsetOrErr) |
| 575 | return NextOffsetOrErr.takeError(); |
| 576 | return Parent->getData().data() + NextOffsetOrErr.get(); |
| 577 | } |
| 578 | |
| 579 | Archive::Child::Child(const Archive *Parent, StringRef Data, |
| 580 | uint16_t StartOfFile) |
| 581 | : Parent(Parent), Data(Data), StartOfFile(StartOfFile) { |
| 582 | Header = Parent->createArchiveMemberHeader(RawHeaderPtr: Data.data(), Size: Data.size(), Err: nullptr); |
| 583 | } |
| 584 | |
| 585 | Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err) |
| 586 | : Parent(Parent) { |
| 587 | if (!Start) { |
| 588 | Header = nullptr; |
| 589 | StartOfFile = -1; |
| 590 | return; |
| 591 | } |
| 592 | |
| 593 | Header = Parent->createArchiveMemberHeader( |
| 594 | RawHeaderPtr: Start, Size: Parent->getData().size() - (Start - Parent->getData().data()), |
| 595 | Err); |
| 596 | |
| 597 | // If we are pointed to real data, Start is not a nullptr, then there must be |
| 598 | // a non-null Err pointer available to report malformed data on. Only in |
| 599 | // the case sentinel value is being constructed is Err is permitted to be a |
| 600 | // nullptr. |
| 601 | assert(Err && "Err can't be nullptr if Start is not a nullptr" ); |
| 602 | |
| 603 | ErrorAsOutParameter ErrAsOutParam(Err); |
| 604 | |
| 605 | // If there was an error in the construction of the Header |
| 606 | // then just return with the error now set. |
| 607 | if (*Err) |
| 608 | return; |
| 609 | |
| 610 | uint64_t Size = Header->getSizeOf(); |
| 611 | Data = StringRef(Start, Size); |
| 612 | Expected<bool> isThinOrErr = isThinMember(); |
| 613 | if (!isThinOrErr) { |
| 614 | *Err = isThinOrErr.takeError(); |
| 615 | return; |
| 616 | } |
| 617 | bool isThin = isThinOrErr.get(); |
| 618 | if (!isThin) { |
| 619 | Expected<uint64_t> MemberSize = getRawSize(); |
| 620 | if (!MemberSize) { |
| 621 | *Err = MemberSize.takeError(); |
| 622 | return; |
| 623 | } |
| 624 | Size += MemberSize.get(); |
| 625 | Data = StringRef(Start, Size); |
| 626 | } |
| 627 | |
| 628 | // Setup StartOfFile and PaddingBytes. |
| 629 | StartOfFile = Header->getSizeOf(); |
| 630 | // Don't include attached name. |
| 631 | Expected<StringRef> NameOrErr = getRawName(); |
| 632 | if (!NameOrErr) { |
| 633 | *Err = NameOrErr.takeError(); |
| 634 | return; |
| 635 | } |
| 636 | StringRef Name = NameOrErr.get(); |
| 637 | |
| 638 | if (Parent->kind() == Archive::K_AIXBIG) { |
| 639 | // The actual start of the file is after the name and any necessary |
| 640 | // even-alignment padding. |
| 641 | StartOfFile += ((Name.size() + 1) >> 1) << 1; |
| 642 | } else if (Name.starts_with(Prefix: "#1/" )) { |
| 643 | uint64_t NameSize; |
| 644 | StringRef RawNameSize = Name.substr(Start: 3).rtrim(Char: ' '); |
| 645 | if (RawNameSize.getAsInteger(Radix: 10, Result&: NameSize)) { |
| 646 | uint64_t Offset = Start - Parent->getData().data(); |
| 647 | *Err = malformedError(Msg: "long name length characters after the #1/ are " |
| 648 | "not all decimal numbers: '" + |
| 649 | RawNameSize + |
| 650 | "' for archive member header at offset " + |
| 651 | Twine(Offset)); |
| 652 | return; |
| 653 | } |
| 654 | StartOfFile += NameSize; |
| 655 | } |
| 656 | } |
| 657 | |
| 658 | Expected<uint64_t> Archive::Child::getSize() const { |
| 659 | if (Parent->IsThin) |
| 660 | return Header->getSize(); |
| 661 | return Data.size() - StartOfFile; |
| 662 | } |
| 663 | |
| 664 | Expected<uint64_t> Archive::Child::getRawSize() const { |
| 665 | return Header->getSize(); |
| 666 | } |
| 667 | |
| 668 | Expected<bool> Archive::Child::isThinMember() const { return Header->isThin(); } |
| 669 | |
| 670 | Expected<std::string> Archive::Child::getFullName() const { |
| 671 | Expected<bool> isThin = isThinMember(); |
| 672 | if (!isThin) |
| 673 | return isThin.takeError(); |
| 674 | assert(isThin.get()); |
| 675 | Expected<StringRef> NameOrErr = getName(); |
| 676 | if (!NameOrErr) |
| 677 | return NameOrErr.takeError(); |
| 678 | StringRef Name = *NameOrErr; |
| 679 | if (sys::path::is_absolute(path: Name)) |
| 680 | return std::string(Name); |
| 681 | |
| 682 | SmallString<128> FullName = sys::path::parent_path( |
| 683 | path: Parent->getMemoryBufferRef().getBufferIdentifier()); |
| 684 | sys::path::append(path&: FullName, a: Name); |
| 685 | return std::string(FullName); |
| 686 | } |
| 687 | |
| 688 | Expected<StringRef> Archive::Child::getBuffer() const { |
| 689 | Expected<bool> isThinOrErr = isThinMember(); |
| 690 | if (!isThinOrErr) |
| 691 | return isThinOrErr.takeError(); |
| 692 | bool isThin = isThinOrErr.get(); |
| 693 | if (!isThin) { |
| 694 | Expected<uint64_t> Size = getSize(); |
| 695 | if (!Size) |
| 696 | return Size.takeError(); |
| 697 | return StringRef(Data.data() + StartOfFile, Size.get()); |
| 698 | } |
| 699 | Expected<std::string> FullNameOrErr = getFullName(); |
| 700 | if (!FullNameOrErr) |
| 701 | return FullNameOrErr.takeError(); |
| 702 | const std::string &FullName = *FullNameOrErr; |
| 703 | ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = |
| 704 | MemoryBuffer::getFile(Filename: FullName, IsText: false, /*RequiresNullTerminator=*/false); |
| 705 | if (std::error_code EC = Buf.getError()) |
| 706 | return errorCodeToError(EC); |
| 707 | Parent->ThinBuffers.push_back(x: std::move(*Buf)); |
| 708 | return Parent->ThinBuffers.back()->getBuffer(); |
| 709 | } |
| 710 | |
| 711 | Expected<Archive::Child> Archive::Child::getNext() const { |
| 712 | Expected<const char *> NextLocOrErr = Header->getNextChildLoc(); |
| 713 | if (!NextLocOrErr) |
| 714 | return NextLocOrErr.takeError(); |
| 715 | |
| 716 | const char *NextLoc = *NextLocOrErr; |
| 717 | |
| 718 | // Check to see if this is at the end of the archive. |
| 719 | if (NextLoc == nullptr) |
| 720 | return Child(nullptr, nullptr, nullptr); |
| 721 | |
| 722 | // Check to see if this is past the end of the archive. |
| 723 | if (NextLoc > Parent->Data.getBufferEnd()) { |
| 724 | std::string Msg("offset to next archive member past the end of the archive " |
| 725 | "after member " ); |
| 726 | Expected<StringRef> NameOrErr = getName(); |
| 727 | if (!NameOrErr) { |
| 728 | consumeError(Err: NameOrErr.takeError()); |
| 729 | uint64_t Offset = Data.data() - Parent->getData().data(); |
| 730 | return malformedError(Msg: Msg + "at offset " + Twine(Offset)); |
| 731 | } else |
| 732 | return malformedError(Msg: Msg + NameOrErr.get()); |
| 733 | } |
| 734 | |
| 735 | Error Err = Error::success(); |
| 736 | Child Ret(Parent, NextLoc, &Err); |
| 737 | if (Err) |
| 738 | return std::move(Err); |
| 739 | return Ret; |
| 740 | } |
| 741 | |
| 742 | uint64_t Archive::Child::getChildOffset() const { |
| 743 | const char *a = Parent->Data.getBuffer().data(); |
| 744 | const char *c = Data.data(); |
| 745 | uint64_t offset = c - a; |
| 746 | return offset; |
| 747 | } |
| 748 | |
| 749 | Expected<StringRef> Archive::Child::getName() const { |
| 750 | Expected<uint64_t> RawSizeOrErr = getRawSize(); |
| 751 | if (!RawSizeOrErr) |
| 752 | return RawSizeOrErr.takeError(); |
| 753 | uint64_t RawSize = RawSizeOrErr.get(); |
| 754 | Expected<StringRef> NameOrErr = |
| 755 | Header->getName(Size: Header->getSizeOf() + RawSize); |
| 756 | if (!NameOrErr) |
| 757 | return NameOrErr.takeError(); |
| 758 | StringRef Name = NameOrErr.get(); |
| 759 | return Name; |
| 760 | } |
| 761 | |
| 762 | Expected<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const { |
| 763 | Expected<StringRef> NameOrErr = getName(); |
| 764 | if (!NameOrErr) |
| 765 | return NameOrErr.takeError(); |
| 766 | StringRef Name = NameOrErr.get(); |
| 767 | Expected<StringRef> Buf = getBuffer(); |
| 768 | if (!Buf) |
| 769 | return createFileError(F: Name, E: Buf.takeError()); |
| 770 | return MemoryBufferRef(*Buf, Name); |
| 771 | } |
| 772 | |
| 773 | Expected<std::unique_ptr<Binary>> |
| 774 | Archive::Child::getAsBinary(LLVMContext *Context) const { |
| 775 | Expected<MemoryBufferRef> BuffOrErr = getMemoryBufferRef(); |
| 776 | if (!BuffOrErr) |
| 777 | return BuffOrErr.takeError(); |
| 778 | |
| 779 | auto BinaryOrErr = createBinary(Source: BuffOrErr.get(), Context); |
| 780 | if (BinaryOrErr) |
| 781 | return std::move(*BinaryOrErr); |
| 782 | return BinaryOrErr.takeError(); |
| 783 | } |
| 784 | |
| 785 | Expected<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) { |
| 786 | Error Err = Error::success(); |
| 787 | std::unique_ptr<Archive> Ret; |
| 788 | StringRef Buffer = Source.getBuffer(); |
| 789 | |
| 790 | if (Buffer.starts_with(Prefix: BigArchiveMagic)) |
| 791 | Ret = std::make_unique<BigArchive>(args&: Source, args&: Err); |
| 792 | else if (Buffer.starts_with(Prefix: ZOSArchiveMagic)) |
| 793 | Ret = std::make_unique<ZOSArchive>(args&: Source, args&: Err); |
| 794 | else |
| 795 | Ret = std::make_unique<Archive>(args&: Source, args&: Err); |
| 796 | |
| 797 | if (Err) |
| 798 | return std::move(Err); |
| 799 | return std::move(Ret); |
| 800 | } |
| 801 | |
| 802 | std::unique_ptr<AbstractArchiveMemberHeader> |
| 803 | Archive::(const char *, uint64_t Size, |
| 804 | Error *Err) const { |
| 805 | ErrorAsOutParameter ErrAsOutParam(Err); |
| 806 | |
| 807 | if (kind() == K_ZOS) |
| 808 | return std::make_unique<ZOSArchiveMemberHeader>(args: this, args&: RawHeaderPtr, args&: Size, |
| 809 | args&: Err); |
| 810 | if (kind() != K_AIXBIG) |
| 811 | return std::make_unique<ArchiveMemberHeader>(args: this, args&: RawHeaderPtr, args&: Size, args&: Err); |
| 812 | return std::make_unique<BigArchiveMemberHeader>(args: this, args&: RawHeaderPtr, args&: Size, |
| 813 | args&: Err); |
| 814 | } |
| 815 | |
| 816 | uint64_t Archive::getArchiveMagicLen() const { |
| 817 | if (isThin()) |
| 818 | return sizeof(ThinArchiveMagic) - 1; |
| 819 | |
| 820 | if (Kind() == K_AIXBIG) |
| 821 | return sizeof(BigArchiveMagic) - 1; |
| 822 | |
| 823 | return sizeof(ArchiveMagic) - 1; |
| 824 | } |
| 825 | |
| 826 | void Archive::setFirstRegular(const Child &C) { |
| 827 | FirstRegularData = C.Data; |
| 828 | FirstRegularStartOfFile = C.StartOfFile; |
| 829 | } |
| 830 | |
| 831 | Archive::Archive(MemoryBufferRef Source, Error &Err) |
| 832 | : Binary(Binary::ID_Archive, Source) { |
| 833 | ErrorAsOutParameter ErrAsOutParam(Err); |
| 834 | StringRef Buffer = Data.getBuffer(); |
| 835 | // Check for sufficient magic. |
| 836 | if (Buffer.starts_with(Prefix: ThinArchiveMagic)) { |
| 837 | IsThin = true; |
| 838 | } else if (Buffer.starts_with(Prefix: ArchiveMagic)) { |
| 839 | IsThin = false; |
| 840 | } else if (Buffer.starts_with(Prefix: BigArchiveMagic)) { |
| 841 | Format = K_AIXBIG; |
| 842 | IsThin = false; |
| 843 | return; |
| 844 | } else if (Buffer.starts_with(Prefix: ZOSArchiveMagic)) { |
| 845 | Format = K_ZOS; |
| 846 | IsThin = false; |
| 847 | return; |
| 848 | } else { |
| 849 | Err = make_error<GenericBinaryError>(Args: "file too small to be an archive" , |
| 850 | Args: object_error::invalid_file_type); |
| 851 | return; |
| 852 | } |
| 853 | |
| 854 | // Make sure Format is initialized before any call to |
| 855 | // ArchiveMemberHeader::getName() is made. This could be a valid empty |
| 856 | // archive which is the same in all formats. So claiming it to be gnu to is |
| 857 | // fine if not totally correct before we look for a string table or table of |
| 858 | // contents. |
| 859 | Format = K_GNU; |
| 860 | |
| 861 | // Get the special members. |
| 862 | child_iterator I = child_begin(Err, SkipInternal: false); |
| 863 | if (Err) |
| 864 | return; |
| 865 | child_iterator E = child_end(); |
| 866 | |
| 867 | // See if this is a valid empty archive and if so return. |
| 868 | if (I == E) { |
| 869 | Err = Error::success(); |
| 870 | return; |
| 871 | } |
| 872 | const Child *C = &*I; |
| 873 | |
| 874 | auto Increment = [&]() { |
| 875 | ++I; |
| 876 | if (Err) |
| 877 | return true; |
| 878 | C = &*I; |
| 879 | return false; |
| 880 | }; |
| 881 | |
| 882 | Expected<StringRef> NameOrErr = C->getRawName(); |
| 883 | if (!NameOrErr) { |
| 884 | Err = NameOrErr.takeError(); |
| 885 | return; |
| 886 | } |
| 887 | StringRef Name = NameOrErr.get(); |
| 888 | |
| 889 | // Below is the pattern that is used to figure out the archive format |
| 890 | // GNU archive format |
| 891 | // First member : / (may exist, if it exists, points to the symbol table ) |
| 892 | // Second member : // (may exist, if it exists, points to the string table) |
| 893 | // Note : The string table is used if the filename exceeds 15 characters |
| 894 | // BSD archive format |
| 895 | // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table) |
| 896 | // There is no string table, if the filename exceeds 15 characters or has a |
| 897 | // embedded space, the filename has #1/<size>, The size represents the size |
| 898 | // of the filename that needs to be read after the archive header |
| 899 | // COFF archive format |
| 900 | // First member : / |
| 901 | // Second member : / (provides a directory of symbols) |
| 902 | // Third member : // (may exist, if it exists, contains the string table) |
| 903 | // Note: Microsoft PE/COFF Spec 8.3 says that the third member is present |
| 904 | // even if the string table is empty. However, lib.exe does not in fact |
| 905 | // seem to create the third member if there's no member whose filename |
| 906 | // exceeds 15 characters. So the third member is optional. |
| 907 | |
| 908 | if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64" ) { |
| 909 | if (Name == "__.SYMDEF" ) |
| 910 | Format = K_BSD; |
| 911 | else // Name == "__.SYMDEF_64" |
| 912 | Format = K_DARWIN64; |
| 913 | // We know that the symbol table is not an external file, but we still must |
| 914 | // check any Expected<> return value. |
| 915 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 916 | if (!BufOrErr) { |
| 917 | Err = BufOrErr.takeError(); |
| 918 | return; |
| 919 | } |
| 920 | SymbolTable = BufOrErr.get(); |
| 921 | if (Increment()) |
| 922 | return; |
| 923 | setFirstRegular(*C); |
| 924 | |
| 925 | Err = Error::success(); |
| 926 | return; |
| 927 | } |
| 928 | |
| 929 | if (Name.starts_with(Prefix: "#1/" )) { |
| 930 | Format = K_BSD; |
| 931 | // We know this is BSD, so getName will work since there is no string table. |
| 932 | Expected<StringRef> NameOrErr = C->getName(); |
| 933 | if (!NameOrErr) { |
| 934 | Err = NameOrErr.takeError(); |
| 935 | return; |
| 936 | } |
| 937 | Name = NameOrErr.get(); |
| 938 | if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF" ) { |
| 939 | // We know that the symbol table is not an external file, but we still |
| 940 | // must check any Expected<> return value. |
| 941 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 942 | if (!BufOrErr) { |
| 943 | Err = BufOrErr.takeError(); |
| 944 | return; |
| 945 | } |
| 946 | SymbolTable = BufOrErr.get(); |
| 947 | if (Increment()) |
| 948 | return; |
| 949 | } else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64" ) { |
| 950 | Format = K_DARWIN64; |
| 951 | // We know that the symbol table is not an external file, but we still |
| 952 | // must check any Expected<> return value. |
| 953 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 954 | if (!BufOrErr) { |
| 955 | Err = BufOrErr.takeError(); |
| 956 | return; |
| 957 | } |
| 958 | SymbolTable = BufOrErr.get(); |
| 959 | if (Increment()) |
| 960 | return; |
| 961 | } |
| 962 | setFirstRegular(*C); |
| 963 | return; |
| 964 | } |
| 965 | |
| 966 | // MIPS 64-bit ELF archives use a special format of a symbol table. |
| 967 | // This format is marked by `ar_name` field equals to "/SYM64/". |
| 968 | // For detailed description see page 96 in the following document: |
| 969 | // http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf |
| 970 | |
| 971 | bool has64SymTable = false; |
| 972 | if (Name == "/" || Name == "/SYM64/" ) { |
| 973 | // We know that the symbol table is not an external file, but we still |
| 974 | // must check any Expected<> return value. |
| 975 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 976 | if (!BufOrErr) { |
| 977 | Err = BufOrErr.takeError(); |
| 978 | return; |
| 979 | } |
| 980 | SymbolTable = BufOrErr.get(); |
| 981 | if (Name == "/SYM64/" ) |
| 982 | has64SymTable = true; |
| 983 | |
| 984 | if (Increment()) |
| 985 | return; |
| 986 | if (I == E) { |
| 987 | Err = Error::success(); |
| 988 | return; |
| 989 | } |
| 990 | Expected<StringRef> NameOrErr = C->getRawName(); |
| 991 | if (!NameOrErr) { |
| 992 | Err = NameOrErr.takeError(); |
| 993 | return; |
| 994 | } |
| 995 | Name = NameOrErr.get(); |
| 996 | } |
| 997 | |
| 998 | if (Name == "//" ) { |
| 999 | Format = has64SymTable ? K_GNU64 : K_GNU; |
| 1000 | // The string table is never an external member, but we still |
| 1001 | // must check any Expected<> return value. |
| 1002 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 1003 | if (!BufOrErr) { |
| 1004 | Err = BufOrErr.takeError(); |
| 1005 | return; |
| 1006 | } |
| 1007 | StringTable = BufOrErr.get(); |
| 1008 | if (Increment()) |
| 1009 | return; |
| 1010 | setFirstRegular(*C); |
| 1011 | Err = Error::success(); |
| 1012 | return; |
| 1013 | } |
| 1014 | |
| 1015 | if (Name[0] != '/') { |
| 1016 | Format = has64SymTable ? K_GNU64 : K_GNU; |
| 1017 | setFirstRegular(*C); |
| 1018 | Err = Error::success(); |
| 1019 | return; |
| 1020 | } |
| 1021 | |
| 1022 | if (Name != "/" ) { |
| 1023 | Err = errorCodeToError(EC: object_error::parse_failed); |
| 1024 | return; |
| 1025 | } |
| 1026 | |
| 1027 | Format = K_COFF; |
| 1028 | // We know that the symbol table is not an external file, but we still |
| 1029 | // must check any Expected<> return value. |
| 1030 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 1031 | if (!BufOrErr) { |
| 1032 | Err = BufOrErr.takeError(); |
| 1033 | return; |
| 1034 | } |
| 1035 | SymbolTable = BufOrErr.get(); |
| 1036 | |
| 1037 | if (Increment()) |
| 1038 | return; |
| 1039 | |
| 1040 | if (I == E) { |
| 1041 | setFirstRegular(*C); |
| 1042 | Err = Error::success(); |
| 1043 | return; |
| 1044 | } |
| 1045 | |
| 1046 | NameOrErr = C->getRawName(); |
| 1047 | if (!NameOrErr) { |
| 1048 | Err = NameOrErr.takeError(); |
| 1049 | return; |
| 1050 | } |
| 1051 | Name = NameOrErr.get(); |
| 1052 | |
| 1053 | if (Name == "//" ) { |
| 1054 | // The string table is never an external member, but we still |
| 1055 | // must check any Expected<> return value. |
| 1056 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 1057 | if (!BufOrErr) { |
| 1058 | Err = BufOrErr.takeError(); |
| 1059 | return; |
| 1060 | } |
| 1061 | StringTable = BufOrErr.get(); |
| 1062 | if (Increment()) |
| 1063 | return; |
| 1064 | |
| 1065 | if (I == E) { |
| 1066 | setFirstRegular(*C); |
| 1067 | Err = Error::success(); |
| 1068 | return; |
| 1069 | } |
| 1070 | |
| 1071 | NameOrErr = C->getRawName(); |
| 1072 | if (!NameOrErr) { |
| 1073 | Err = NameOrErr.takeError(); |
| 1074 | return; |
| 1075 | } |
| 1076 | Name = NameOrErr.get(); |
| 1077 | } |
| 1078 | |
| 1079 | if (Name == "/<ECSYMBOLS>/" ) { |
| 1080 | // ARM64EC-aware libraries contain an additional special member with |
| 1081 | // an EC symbol map after the string table. Its format is similar to a |
| 1082 | // regular symbol map, except it doesn't contain member offsets. Its indexes |
| 1083 | // refer to member offsets from the regular symbol table instead. |
| 1084 | Expected<StringRef> BufOrErr = C->getBuffer(); |
| 1085 | if (!BufOrErr) { |
| 1086 | Err = BufOrErr.takeError(); |
| 1087 | return; |
| 1088 | } |
| 1089 | ECSymbolTable = BufOrErr.get(); |
| 1090 | if (Increment()) |
| 1091 | return; |
| 1092 | } |
| 1093 | |
| 1094 | setFirstRegular(*C); |
| 1095 | Err = Error::success(); |
| 1096 | } |
| 1097 | |
| 1098 | object::Archive::Kind Archive::getDefaultKindForTriple(const Triple &T) { |
| 1099 | if (T.isOSDarwin()) |
| 1100 | return object::Archive::K_DARWIN; |
| 1101 | if (T.isOSAIX()) |
| 1102 | return object::Archive::K_AIXBIG; |
| 1103 | if (T.isOSWindows()) |
| 1104 | return object::Archive::K_COFF; |
| 1105 | if (T.isOSzOS()) |
| 1106 | return object::Archive::K_ZOS; |
| 1107 | return object::Archive::K_GNU; |
| 1108 | } |
| 1109 | |
| 1110 | object::Archive::Kind Archive::getDefaultKind() { |
| 1111 | Triple HostTriple(sys::getDefaultTargetTriple()); |
| 1112 | return getDefaultKindForTriple(T: HostTriple); |
| 1113 | } |
| 1114 | |
| 1115 | Archive::child_iterator Archive::child_begin(Error &Err, |
| 1116 | bool SkipInternal) const { |
| 1117 | if (isEmpty()) |
| 1118 | return child_end(); |
| 1119 | |
| 1120 | if (SkipInternal) |
| 1121 | return child_iterator::itr( |
| 1122 | I: Child(this, FirstRegularData, FirstRegularStartOfFile), Err); |
| 1123 | |
| 1124 | const char *Loc = Data.getBufferStart() + getFirstChildOffset(); |
| 1125 | Child C(this, Loc, &Err); |
| 1126 | if (Err) |
| 1127 | return child_end(); |
| 1128 | return child_iterator::itr(I: C, Err); |
| 1129 | } |
| 1130 | |
| 1131 | Archive::child_iterator Archive::child_end() const { |
| 1132 | return child_iterator::end(I: Child(nullptr, nullptr, nullptr)); |
| 1133 | } |
| 1134 | |
| 1135 | bool Archive::Symbol::isECSymbol() const { |
| 1136 | // Symbols use SymbolCount..SymbolCount+getNumberOfECSymbols() for EC symbol |
| 1137 | // indexes. |
| 1138 | uint32_t SymbolCount = Parent->getNumberOfSymbols(); |
| 1139 | return SymbolCount <= SymbolIndex && |
| 1140 | SymbolIndex < SymbolCount + Parent->getNumberOfECSymbols(); |
| 1141 | } |
| 1142 | |
| 1143 | StringRef Archive::Symbol::getName() const { |
| 1144 | if (isECSymbol()) |
| 1145 | return Parent->ECSymbolTable.begin() + StringIndex; |
| 1146 | return Parent->getSymbolTable().begin() + StringIndex; |
| 1147 | } |
| 1148 | |
| 1149 | Expected<Archive::Child> Archive::Symbol::getMember() const { |
| 1150 | const char *Buf = Parent->getSymbolTable().begin(); |
| 1151 | const char *Offsets = Buf; |
| 1152 | if (Parent->kind() == K_GNU64 || Parent->kind() == K_DARWIN64 || |
| 1153 | Parent->kind() == K_AIXBIG) |
| 1154 | Offsets += sizeof(uint64_t); |
| 1155 | else |
| 1156 | Offsets += sizeof(uint32_t); |
| 1157 | uint64_t Offset = 0; |
| 1158 | if (Parent->kind() == K_GNU) { |
| 1159 | Offset = read32be(P: Offsets + SymbolIndex * 4); |
| 1160 | } else if (Parent->kind() == K_GNU64 || Parent->kind() == K_AIXBIG) { |
| 1161 | Offset = read64be(P: Offsets + SymbolIndex * 8); |
| 1162 | } else if (Parent->kind() == K_BSD) { |
| 1163 | // The SymbolIndex is an index into the ranlib structs that start at |
| 1164 | // Offsets (the first uint32_t is the number of bytes of the ranlib |
| 1165 | // structs). The ranlib structs are a pair of uint32_t's the first |
| 1166 | // being a string table offset and the second being the offset into |
| 1167 | // the archive of the member that defines the symbol. Which is what |
| 1168 | // is needed here. |
| 1169 | Offset = read32le(P: Offsets + SymbolIndex * 8 + 4); |
| 1170 | } else if (Parent->kind() == K_DARWIN64) { |
| 1171 | // The SymbolIndex is an index into the ranlib_64 structs that start at |
| 1172 | // Offsets (the first uint64_t is the number of bytes of the ranlib_64 |
| 1173 | // structs). The ranlib_64 structs are a pair of uint64_t's the first |
| 1174 | // being a string table offset and the second being the offset into |
| 1175 | // the archive of the member that defines the symbol. Which is what |
| 1176 | // is needed here. |
| 1177 | Offset = read64le(P: Offsets + SymbolIndex * 16 + 8); |
| 1178 | } else if (Parent->kind() == K_ZOS) { |
| 1179 | // Each entry in the offset array is 8 bytes long: |
| 1180 | // A 4-byte offset followed by 4 bytes of coded attributes. |
| 1181 | // We multiply the SymbolIndex by 8 to reach the correct entry, |
| 1182 | // and read the first 4 bytes (the offset). |
| 1183 | Offset = read32be(P: Offsets + SymbolIndex * 8); |
| 1184 | } else { |
| 1185 | // Skip offsets. |
| 1186 | uint32_t MemberCount = read32le(P: Buf); |
| 1187 | Buf += MemberCount * 4 + 4; |
| 1188 | |
| 1189 | uint32_t SymbolCount = read32le(P: Buf); |
| 1190 | uint16_t OffsetIndex; |
| 1191 | if (SymbolIndex < SymbolCount) { |
| 1192 | // Skip SymbolCount to get to the indices table. |
| 1193 | const char *Indices = Buf + 4; |
| 1194 | |
| 1195 | // Get the index of the offset in the file member offset table for this |
| 1196 | // symbol. |
| 1197 | OffsetIndex = read16le(P: Indices + SymbolIndex * 2); |
| 1198 | } else if (isECSymbol()) { |
| 1199 | // Skip SymbolCount to get to the indices table. |
| 1200 | const char *Indices = Parent->ECSymbolTable.begin() + 4; |
| 1201 | |
| 1202 | // Get the index of the offset in the file member offset table for this |
| 1203 | // symbol. |
| 1204 | OffsetIndex = read16le(P: Indices + (SymbolIndex - SymbolCount) * 2); |
| 1205 | } else { |
| 1206 | return errorCodeToError(EC: object_error::parse_failed); |
| 1207 | } |
| 1208 | // Subtract 1 since OffsetIndex is 1 based. |
| 1209 | --OffsetIndex; |
| 1210 | |
| 1211 | if (OffsetIndex >= MemberCount) |
| 1212 | return errorCodeToError(EC: object_error::parse_failed); |
| 1213 | |
| 1214 | Offset = read32le(P: Offsets + OffsetIndex * 4); |
| 1215 | } |
| 1216 | |
| 1217 | const char *Loc = Parent->getData().begin() + Offset; |
| 1218 | Error Err = Error::success(); |
| 1219 | Child C(Parent, Loc, &Err); |
| 1220 | if (Err) |
| 1221 | return std::move(Err); |
| 1222 | return C; |
| 1223 | } |
| 1224 | |
| 1225 | Archive::Symbol Archive::Symbol::getNext() const { |
| 1226 | Symbol t(*this); |
| 1227 | if (Parent->kind() == K_BSD) { |
| 1228 | // t.StringIndex is an offset from the start of the __.SYMDEF or |
| 1229 | // "__.SYMDEF SORTED" member into the string table for the ranlib |
| 1230 | // struct indexed by t.SymbolIndex . To change t.StringIndex to the |
| 1231 | // offset in the string table for t.SymbolIndex+1 we subtract the |
| 1232 | // its offset from the start of the string table for t.SymbolIndex |
| 1233 | // and add the offset of the string table for t.SymbolIndex+1. |
| 1234 | |
| 1235 | // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t |
| 1236 | // which is the number of bytes of ranlib structs that follow. The ranlib |
| 1237 | // structs are a pair of uint32_t's the first being a string table offset |
| 1238 | // and the second being the offset into the archive of the member that |
| 1239 | // define the symbol. After that the next uint32_t is the byte count of |
| 1240 | // the string table followed by the string table. |
| 1241 | const char *Buf = Parent->getSymbolTable().begin(); |
| 1242 | uint32_t RanlibCount = 0; |
| 1243 | RanlibCount = read32le(P: Buf) / 8; |
| 1244 | // If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount) |
| 1245 | // don't change the t.StringIndex as we don't want to reference a ranlib |
| 1246 | // past RanlibCount. |
| 1247 | if (t.SymbolIndex + 1 < RanlibCount) { |
| 1248 | const char *Ranlibs = Buf + 4; |
| 1249 | uint32_t CurRanStrx = 0; |
| 1250 | uint32_t = 0; |
| 1251 | CurRanStrx = read32le(P: Ranlibs + t.SymbolIndex * 8); |
| 1252 | NextRanStrx = read32le(P: Ranlibs + (t.SymbolIndex + 1) * 8); |
| 1253 | t.StringIndex -= CurRanStrx; |
| 1254 | t.StringIndex += NextRanStrx; |
| 1255 | } |
| 1256 | } else if (t.isECSymbol()) { |
| 1257 | // Go to one past next null. |
| 1258 | t.StringIndex = Parent->ECSymbolTable.find(C: '\0', From: t.StringIndex) + 1; |
| 1259 | } else { |
| 1260 | // Go to one past next null. |
| 1261 | t.StringIndex = Parent->getSymbolTable().find(C: '\0', From: t.StringIndex) + 1; |
| 1262 | } |
| 1263 | ++t.SymbolIndex; |
| 1264 | return t; |
| 1265 | } |
| 1266 | |
| 1267 | Archive::symbol_iterator Archive::symbol_begin() const { |
| 1268 | if (!hasSymbolTable()) |
| 1269 | return symbol_iterator(Symbol(this, 0, 0)); |
| 1270 | |
| 1271 | const char *buf = getSymbolTable().begin(); |
| 1272 | if (kind() == K_GNU) { |
| 1273 | uint32_t symbol_count = 0; |
| 1274 | symbol_count = read32be(P: buf); |
| 1275 | buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); |
| 1276 | } else if (kind() == K_GNU64) { |
| 1277 | uint64_t symbol_count = read64be(P: buf); |
| 1278 | buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t))); |
| 1279 | } else if (kind() == K_BSD) { |
| 1280 | // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t |
| 1281 | // which is the number of bytes of ranlib structs that follow. The ranlib |
| 1282 | // structs are a pair of uint32_t's the first being a string table offset |
| 1283 | // and the second being the offset into the archive of the member that |
| 1284 | // define the symbol. After that the next uint32_t is the byte count of |
| 1285 | // the string table followed by the string table. |
| 1286 | uint32_t ranlib_count = 0; |
| 1287 | ranlib_count = read32le(P: buf) / 8; |
| 1288 | const char *ranlibs = buf + 4; |
| 1289 | uint32_t ran_strx = 0; |
| 1290 | ran_strx = read32le(P: ranlibs); |
| 1291 | buf += sizeof(uint32_t) + (ranlib_count * (2 * (sizeof(uint32_t)))); |
| 1292 | // Skip the byte count of the string table. |
| 1293 | buf += sizeof(uint32_t); |
| 1294 | buf += ran_strx; |
| 1295 | } else if (kind() == K_DARWIN64) { |
| 1296 | // The __.SYMDEF_64 or "__.SYMDEF_64 SORTED" member starts with a uint64_t |
| 1297 | // which is the number of bytes of ranlib_64 structs that follow. The |
| 1298 | // ranlib_64 structs are a pair of uint64_t's the first being a string |
| 1299 | // table offset and the second being the offset into the archive of the |
| 1300 | // member that define the symbol. After that the next uint64_t is the byte |
| 1301 | // count of the string table followed by the string table. |
| 1302 | uint64_t ranlib_count = 0; |
| 1303 | ranlib_count = read64le(P: buf) / 16; |
| 1304 | const char *ranlibs = buf + 8; |
| 1305 | uint64_t ran_strx = 0; |
| 1306 | ran_strx = read64le(P: ranlibs); |
| 1307 | buf += sizeof(uint64_t) + (ranlib_count * (2 * (sizeof(uint64_t)))); |
| 1308 | // Skip the byte count of the string table. |
| 1309 | buf += sizeof(uint64_t); |
| 1310 | buf += ran_strx; |
| 1311 | } else if (kind() == K_AIXBIG) { |
| 1312 | buf = getStringTable().begin(); |
| 1313 | } else if (kind() == K_ZOS) { |
| 1314 | // The contents of the z/OS symbol table member are: |
| 1315 | // 1. The number of symbols, NS (4-byte integer). |
| 1316 | // 2. NS pairs of 4-byte integers (offset and attributes). Length is NS*8 |
| 1317 | // bytes. |
| 1318 | // 3. NS null terminated strings of corresponding symbol names. |
| 1319 | // Here we skip parts 1 and 2 to reach the start of the string table. |
| 1320 | uint32_t SymbolCount = read32be(P: buf); |
| 1321 | buf += sizeof(uint32_t) + (SymbolCount * (sizeof(uint64_t))); |
| 1322 | } else { |
| 1323 | uint32_t member_count = 0; |
| 1324 | uint32_t symbol_count = 0; |
| 1325 | member_count = read32le(P: buf); |
| 1326 | buf += 4 + (member_count * 4); // Skip offsets. |
| 1327 | symbol_count = read32le(P: buf); |
| 1328 | buf += 4 + (symbol_count * 2); // Skip indices. |
| 1329 | } |
| 1330 | uint32_t string_start_offset = buf - getSymbolTable().begin(); |
| 1331 | return symbol_iterator(Symbol(this, 0, string_start_offset)); |
| 1332 | } |
| 1333 | |
| 1334 | Archive::symbol_iterator Archive::symbol_end() const { |
| 1335 | return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0)); |
| 1336 | } |
| 1337 | |
| 1338 | Expected<iterator_range<Archive::symbol_iterator>> Archive::ec_symbols() const { |
| 1339 | uint32_t Count = 0; |
| 1340 | |
| 1341 | // Validate EC symbol table. |
| 1342 | if (!ECSymbolTable.empty()) { |
| 1343 | if (ECSymbolTable.size() < sizeof(uint32_t)) |
| 1344 | return malformedError(Msg: "invalid EC symbols size (" + |
| 1345 | Twine(ECSymbolTable.size()) + ")" ); |
| 1346 | if (SymbolTable.size() < sizeof(uint32_t)) |
| 1347 | return malformedError(Msg: "invalid symbols size (" + |
| 1348 | Twine(ECSymbolTable.size()) + ")" ); |
| 1349 | |
| 1350 | Count = read32le(P: ECSymbolTable.begin()); |
| 1351 | size_t StringIndex = sizeof(uint32_t) + Count * sizeof(uint16_t); |
| 1352 | if (ECSymbolTable.size() < StringIndex) |
| 1353 | return malformedError(Msg: "invalid EC symbols size. Size was " + |
| 1354 | Twine(ECSymbolTable.size()) + ", but expected " + |
| 1355 | Twine(StringIndex)); |
| 1356 | |
| 1357 | uint32_t MemberCount = read32le(P: SymbolTable.begin()); |
| 1358 | const char *Indexes = ECSymbolTable.begin() + sizeof(uint32_t); |
| 1359 | |
| 1360 | for (uint32_t i = 0; i < Count; ++i) { |
| 1361 | uint16_t Index = read16le(P: Indexes + i * sizeof(uint16_t)); |
| 1362 | if (!Index) |
| 1363 | return malformedError(Msg: "invalid EC symbol index 0" ); |
| 1364 | if (Index > MemberCount) |
| 1365 | return malformedError(Msg: "invalid EC symbol index " + Twine(Index) + |
| 1366 | " is larger than member count " + |
| 1367 | Twine(MemberCount)); |
| 1368 | |
| 1369 | StringIndex = ECSymbolTable.find(C: '\0', From: StringIndex); |
| 1370 | if (StringIndex == StringRef::npos) |
| 1371 | return malformedError(Msg: "malformed EC symbol names: not null-terminated" ); |
| 1372 | ++StringIndex; |
| 1373 | } |
| 1374 | } |
| 1375 | |
| 1376 | uint32_t SymbolCount = getNumberOfSymbols(); |
| 1377 | return make_range( |
| 1378 | x: symbol_iterator(Symbol(this, SymbolCount, |
| 1379 | sizeof(uint32_t) + Count * sizeof(uint16_t))), |
| 1380 | y: symbol_iterator(Symbol(this, SymbolCount + Count, 0))); |
| 1381 | } |
| 1382 | |
| 1383 | uint32_t Archive::getNumberOfSymbols() const { |
| 1384 | if (!hasSymbolTable()) |
| 1385 | return 0; |
| 1386 | const char *buf = getSymbolTable().begin(); |
| 1387 | if (kind() == K_GNU) |
| 1388 | return read32be(P: buf); |
| 1389 | if (kind() == K_GNU64 || kind() == K_AIXBIG) |
| 1390 | return read64be(P: buf); |
| 1391 | if (kind() == K_BSD) |
| 1392 | return read32le(P: buf) / 8; |
| 1393 | if (kind() == K_DARWIN64) |
| 1394 | return read64le(P: buf) / 16; |
| 1395 | if (kind() == K_ZOS) |
| 1396 | return read32be(P: buf); |
| 1397 | uint32_t member_count = 0; |
| 1398 | member_count = read32le(P: buf); |
| 1399 | buf += 4 + (member_count * 4); // Skip offsets. |
| 1400 | return read32le(P: buf); |
| 1401 | } |
| 1402 | |
| 1403 | uint32_t Archive::getNumberOfECSymbols() const { |
| 1404 | if (ECSymbolTable.size() < sizeof(uint32_t)) |
| 1405 | return 0; |
| 1406 | return read32le(P: ECSymbolTable.begin()); |
| 1407 | } |
| 1408 | |
| 1409 | Expected<std::optional<Archive::Child>> Archive::findSym(StringRef name) const { |
| 1410 | Archive::symbol_iterator bs = symbol_begin(); |
| 1411 | Archive::symbol_iterator es = symbol_end(); |
| 1412 | |
| 1413 | for (; bs != es; ++bs) { |
| 1414 | StringRef SymName = bs->getName(); |
| 1415 | if (SymName == name) { |
| 1416 | if (auto MemberOrErr = bs->getMember()) |
| 1417 | return Child(*MemberOrErr); |
| 1418 | else |
| 1419 | return MemberOrErr.takeError(); |
| 1420 | } |
| 1421 | } |
| 1422 | return std::nullopt; |
| 1423 | } |
| 1424 | |
| 1425 | // Returns true if archive file contains no member file. |
| 1426 | bool Archive::isEmpty() const { |
| 1427 | return Data.getBufferSize() == getArchiveMagicLen(); |
| 1428 | } |
| 1429 | |
| 1430 | bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); } |
| 1431 | |
| 1432 | static Error getGlobalSymtabLocAndSize(const MemoryBufferRef &Data, |
| 1433 | uint64_t GlobalSymtabOffset, |
| 1434 | const char *&GlobalSymtabLoc, |
| 1435 | uint64_t &Size, const char *BitMessage) { |
| 1436 | uint64_t BufferSize = Data.getBufferSize(); |
| 1437 | uint64_t GlobalSymtabContentOffset = |
| 1438 | GlobalSymtabOffset + sizeof(BigArMemHdrType); |
| 1439 | if (GlobalSymtabContentOffset > BufferSize) |
| 1440 | return malformedError( |
| 1441 | Msg: Twine(BitMessage) + " global symbol table header at offset 0x" + |
| 1442 | Twine::utohexstr(Val: GlobalSymtabOffset) + " and size 0x" + |
| 1443 | Twine::utohexstr(Val: sizeof(BigArMemHdrType)) + |
| 1444 | " goes past the end of file" ); |
| 1445 | |
| 1446 | GlobalSymtabLoc = Data.getBufferStart() + GlobalSymtabOffset; |
| 1447 | const BigArMemHdrType *GlobalSymHdr = |
| 1448 | reinterpret_cast<const BigArMemHdrType *>(GlobalSymtabLoc); |
| 1449 | StringRef RawOffset = getFieldRawString(Field: GlobalSymHdr->Size); |
| 1450 | if (RawOffset.getAsInteger(Radix: 10, Result&: Size)) |
| 1451 | return malformedError(Msg: Twine(BitMessage) + " global symbol table size \"" + |
| 1452 | RawOffset + "\" is not a number" ); |
| 1453 | |
| 1454 | if (GlobalSymtabContentOffset + Size > BufferSize) |
| 1455 | return malformedError( |
| 1456 | Msg: Twine(BitMessage) + " global symbol table content at offset 0x" + |
| 1457 | Twine::utohexstr(Val: GlobalSymtabContentOffset) + " and size 0x" + |
| 1458 | Twine::utohexstr(Val: Size) + " goes past the end of file" ); |
| 1459 | |
| 1460 | return Error::success(); |
| 1461 | } |
| 1462 | |
| 1463 | struct GlobalSymtabInfo { |
| 1464 | uint64_t SymNum; |
| 1465 | StringRef SymbolTable; |
| 1466 | StringRef SymbolOffsetTable; |
| 1467 | StringRef StringTable; |
| 1468 | }; |
| 1469 | |
| 1470 | static void |
| 1471 | appendGlobalSymbolTableInfo(SmallVector<GlobalSymtabInfo> &SymtabInfos, |
| 1472 | const char *GlobalSymtabLoc, uint64_t Size) { |
| 1473 | // In a big archive, a global symbol table contains the following information: |
| 1474 | // - The number of symbols. |
| 1475 | // - The array of offsets into the archive file. The length is eight |
| 1476 | // times the number of symbols. |
| 1477 | // - The name-string table. The size is: |
| 1478 | // Size-(8*(the number of symbols + 1)). |
| 1479 | |
| 1480 | StringRef SymbolTable = |
| 1481 | StringRef(GlobalSymtabLoc + sizeof(BigArMemHdrType), Size); |
| 1482 | uint64_t SymNum = read64be(P: GlobalSymtabLoc + sizeof(BigArMemHdrType)); |
| 1483 | StringRef SymbolOffsetTable = StringRef(SymbolTable.data() + 8, 8 * SymNum); |
| 1484 | unsigned SymOffsetsSize = 8 * (SymNum + 1); |
| 1485 | uint64_t SymbolTableStringSize = Size - SymOffsetsSize; |
| 1486 | StringRef StringTable = |
| 1487 | StringRef(SymbolTable.data() + SymOffsetsSize, SymbolTableStringSize); |
| 1488 | SymtabInfos.push_back(Elt: {.SymNum: SymNum, .SymbolTable: SymbolTable, .SymbolOffsetTable: SymbolOffsetTable, .StringTable: StringTable}); |
| 1489 | } |
| 1490 | |
| 1491 | BigArchive::BigArchive(MemoryBufferRef Source, Error &Err) |
| 1492 | : Archive(Source, Err) { |
| 1493 | ErrorAsOutParameter ErrAsOutParam(&Err); |
| 1494 | StringRef Buffer = Data.getBuffer(); |
| 1495 | ArFixLenHdr = reinterpret_cast<const FixLenHdr *>(Buffer.data()); |
| 1496 | uint64_t BufferSize = Data.getBufferSize(); |
| 1497 | |
| 1498 | if (BufferSize < sizeof(FixLenHdr)) { |
| 1499 | Err = malformedError(Msg: "malformed AIX big archive: incomplete fixed length " |
| 1500 | "header, the archive is only" + |
| 1501 | Twine(BufferSize) + " byte(s)" ); |
| 1502 | return; |
| 1503 | } |
| 1504 | |
| 1505 | StringRef RawOffset = getFieldRawString(Field: ArFixLenHdr->FirstChildOffset); |
| 1506 | if (RawOffset.getAsInteger(Radix: 10, Result&: FirstChildOffset)) |
| 1507 | // TODO: Out-of-line. |
| 1508 | Err = malformedError(Msg: "malformed AIX big archive: first member offset \"" + |
| 1509 | RawOffset + "\" is not a number" ); |
| 1510 | |
| 1511 | RawOffset = getFieldRawString(Field: ArFixLenHdr->LastChildOffset); |
| 1512 | if (RawOffset.getAsInteger(Radix: 10, Result&: LastChildOffset)) |
| 1513 | // TODO: Out-of-line. |
| 1514 | Err = malformedError(Msg: "malformed AIX big archive: last member offset \"" + |
| 1515 | RawOffset + "\" is not a number" ); |
| 1516 | |
| 1517 | uint64_t GlobSymtab32Offset = 0; |
| 1518 | RawOffset = getFieldRawString(Field: ArFixLenHdr->GlobSymOffset); |
| 1519 | if (RawOffset.getAsInteger(Radix: 10, Result&: GlobSymtab32Offset)) { |
| 1520 | Err = malformedError(Msg: "global symbol table " |
| 1521 | "offset of 32-bit members \"" + |
| 1522 | RawOffset + "\" is not a number" ); |
| 1523 | return; |
| 1524 | } |
| 1525 | |
| 1526 | uint64_t GlobSymtab64Offset = 0; |
| 1527 | RawOffset = getFieldRawString(Field: ArFixLenHdr->GlobSym64Offset); |
| 1528 | if (RawOffset.getAsInteger(Radix: 10, Result&: GlobSymtab64Offset)) { |
| 1529 | Err = malformedError(Msg: "global symbol table " |
| 1530 | "offset of 64-bit members\"" + |
| 1531 | RawOffset + "\" is not a number" ); |
| 1532 | return; |
| 1533 | } |
| 1534 | |
| 1535 | const char *GlobSymtab32Loc = nullptr; |
| 1536 | const char *GlobSymtab64Loc = nullptr; |
| 1537 | uint64_t GlobSymtab32Size = 0; |
| 1538 | uint64_t GlobSymtab64Size = 0; |
| 1539 | const MemoryBufferRef &MemBuffRef = getMemoryBufferRef(); |
| 1540 | |
| 1541 | if (GlobSymtab32Offset) { |
| 1542 | Err = |
| 1543 | getGlobalSymtabLocAndSize(Data: MemBuffRef, GlobalSymtabOffset: GlobSymtab32Offset, |
| 1544 | GlobalSymtabLoc&: GlobSymtab32Loc, Size&: GlobSymtab32Size, BitMessage: "32-bit" ); |
| 1545 | if (Err) |
| 1546 | return; |
| 1547 | |
| 1548 | Has32BitGlobalSymtab = true; |
| 1549 | } |
| 1550 | |
| 1551 | if (GlobSymtab64Offset) { |
| 1552 | Err = |
| 1553 | getGlobalSymtabLocAndSize(Data: MemBuffRef, GlobalSymtabOffset: GlobSymtab64Offset, |
| 1554 | GlobalSymtabLoc&: GlobSymtab64Loc, Size&: GlobSymtab64Size, BitMessage: "64-bit" ); |
| 1555 | if (Err) |
| 1556 | return; |
| 1557 | |
| 1558 | Has64BitGlobalSymtab = true; |
| 1559 | } |
| 1560 | |
| 1561 | SmallVector<GlobalSymtabInfo> SymtabInfos; |
| 1562 | |
| 1563 | if (GlobSymtab32Offset) |
| 1564 | appendGlobalSymbolTableInfo(SymtabInfos, GlobalSymtabLoc: GlobSymtab32Loc, Size: GlobSymtab32Size); |
| 1565 | if (GlobSymtab64Offset) |
| 1566 | appendGlobalSymbolTableInfo(SymtabInfos, GlobalSymtabLoc: GlobSymtab64Loc, Size: GlobSymtab64Size); |
| 1567 | |
| 1568 | if (SymtabInfos.size() == 1) { |
| 1569 | SymbolTable = SymtabInfos[0].SymbolTable; |
| 1570 | StringTable = SymtabInfos[0].StringTable; |
| 1571 | } else if (SymtabInfos.size() == 2) { |
| 1572 | // In order to let the Archive::Symbol::getNext() work for both 32-bit and |
| 1573 | // 64-bit global symbol tables, we need to merge them into a single table. |
| 1574 | raw_string_ostream Out(MergedGlobalSymtabBuf); |
| 1575 | uint64_t SymNum = SymtabInfos[0].SymNum + SymtabInfos[1].SymNum; |
| 1576 | write(os&: Out, value: SymNum, endian: llvm::endianness::big); |
| 1577 | // Merge symbol offset. |
| 1578 | Out << SymtabInfos[0].SymbolOffsetTable; |
| 1579 | Out << SymtabInfos[1].SymbolOffsetTable; |
| 1580 | // Merge string table. |
| 1581 | Out << SymtabInfos[0].StringTable; |
| 1582 | Out << SymtabInfos[1].StringTable; |
| 1583 | SymbolTable = MergedGlobalSymtabBuf; |
| 1584 | // The size of the symbol offset to the member file is 8 bytes. |
| 1585 | StringTable = StringRef(SymbolTable.begin() + (SymNum + 1) * 8, |
| 1586 | SymtabInfos[0].StringTable.size() + |
| 1587 | SymtabInfos[1].StringTable.size()); |
| 1588 | } |
| 1589 | |
| 1590 | child_iterator I = child_begin(Err, SkipInternal: false); |
| 1591 | if (Err) |
| 1592 | return; |
| 1593 | child_iterator E = child_end(); |
| 1594 | if (I == E) { |
| 1595 | Err = Error::success(); |
| 1596 | return; |
| 1597 | } |
| 1598 | setFirstRegular(*I); |
| 1599 | Err = Error::success(); |
| 1600 | } |
| 1601 | |
| 1602 | ZOSArchive::ZOSArchive(MemoryBufferRef Source, Error &Err) |
| 1603 | : Archive(Source, Err) { |
| 1604 | ErrorAsOutParameter ErrAsOutParam(&Err); |
| 1605 | |
| 1606 | // Get the special members. |
| 1607 | child_iterator I = child_begin(Err, SkipInternal: false); |
| 1608 | if (Err) |
| 1609 | return; |
| 1610 | child_iterator E = child_end(); |
| 1611 | |
| 1612 | // See if this is a valid empty archive and if so return. |
| 1613 | if (I == E) { |
| 1614 | Err = Error::success(); |
| 1615 | return; |
| 1616 | } |
| 1617 | const Child *C = &*I; |
| 1618 | |
| 1619 | Expected<StringRef> NameOrErr = C->getRawName(); |
| 1620 | if (!NameOrErr) { |
| 1621 | Err = NameOrErr.takeError(); |
| 1622 | return; |
| 1623 | } |
| 1624 | StringRef Name = NameOrErr.get(); |
| 1625 | |
| 1626 | if (Name == "__.SYMDEF" ) { |
| 1627 | // Copy symbol table converting embedded EBCDIC names to ASCII. |
| 1628 | // getBuffer() cannot fail here because the Child constructor and |
| 1629 | // getNext() already validate that the member's size fits within |
| 1630 | // the archive. |
| 1631 | StringRef EbcdicSymbolTable = cantFail(ValOrErr: C->getBuffer()); |
| 1632 | if (EbcdicSymbolTable.size() < sizeof(uint32_t)) { |
| 1633 | Err = malformedError( |
| 1634 | Msg: "z/OS archive symbol table is too small to read the symbol count, " |
| 1635 | "symbol table size is " + |
| 1636 | Twine(EbcdicSymbolTable.size())); |
| 1637 | return; |
| 1638 | } |
| 1639 | uint64_t EbcdicSymbolCount = read32be(P: EbcdicSymbolTable.data()); |
| 1640 | uint64_t OffsetToEbcdicNames = |
| 1641 | sizeof(uint32_t) + (EbcdicSymbolCount * (sizeof(uint64_t))); |
| 1642 | if (OffsetToEbcdicNames > EbcdicSymbolTable.size()) { |
| 1643 | Err = malformedError(Msg: "z/OS archive symbol table names offset " + |
| 1644 | Twine(OffsetToEbcdicNames) + |
| 1645 | " exceeds symbol table size " + |
| 1646 | Twine(EbcdicSymbolTable.size())); |
| 1647 | return; |
| 1648 | } |
| 1649 | uint64_t EbcdicNamesSize = EbcdicSymbolTable.size() - OffsetToEbcdicNames; |
| 1650 | const char *EbcdicNamesPtr = EbcdicSymbolTable.data() + OffsetToEbcdicNames; |
| 1651 | StringRef EbcdicNames(EbcdicNamesPtr, EbcdicNamesSize); |
| 1652 | |
| 1653 | SmallString<64> Dst; |
| 1654 | ConverterEBCDIC::convertToUTF8(Source: EbcdicNames, Result&: Dst); |
| 1655 | SymbolTableBuf.append(s: EbcdicSymbolTable.data(), n: OffsetToEbcdicNames); |
| 1656 | SymbolTableBuf.append(svt: Dst.str()); |
| 1657 | SymbolTable = StringRef(SymbolTableBuf.data(), SymbolTableBuf.size()); |
| 1658 | |
| 1659 | ++I; |
| 1660 | if (Err) |
| 1661 | return; |
| 1662 | C = &*I; |
| 1663 | |
| 1664 | setFirstRegular(*C); |
| 1665 | Err = Error::success(); |
| 1666 | return; |
| 1667 | } |
| 1668 | |
| 1669 | setFirstRegular(*C); |
| 1670 | Err = Error::success(); |
| 1671 | return; |
| 1672 | } |
| 1673 | |