Loading...
--- dyld/dyld-1340/mach_o/Archive.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) 2022 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <TargetConditionals.h>
-
-#if !TARGET_OS_EXCLAVEKIT
-
-#include "Archive.h"
-
-// stl
-#include <string_view>
-
-// Darwin
-#include <ar.h>
-#include <mach-o/ranlib.h>
-#include <mach/mach.h>
-#include <mach/vm_map.h>
-
-namespace mach_o {
-
-constexpr std::string_view AR_EFMT1_SV(AR_EFMT1);
-
-static inline uint64_t align(uint64_t addr, uint8_t p2)
-{
- uint64_t mask = (1 << p2);
- return (addr + mask - 1) & (-mask);
-}
-
-uint64_t Entry::extendedFormatNameSize(std::string_view name)
-{
- // In extended format the name is stored after the member header.
- // It's always \0 terminated, it's padded to 8 bytes and also contains
- // an extra padding for the member header. This makes sure that member
- // contents are always 8 bytes aligned.
- return align(name.size() + 1, 3) + align(sizeof(Entry), 3) - sizeof(Entry);
-}
-
-uint64_t Entry::entrySize(bool extendedFormatNames, std::string_view name, uint64_t contentSize)
-{
- if ( extendedFormatNames ) {
- return sizeof(Entry) + extendedFormatNameSize(name) + align(contentSize, 3);
- }
- return sizeof(Entry) + align(contentSize, 3);
-}
-
-size_t Entry::write(std::span<uint8_t> buffer, bool extendedFormatNames, std::string_view name, uint64_t mktime, std::span<const uint8_t> content)
-{
- Entry* entry = (Entry*)buffer.data();
-
- const uint64_t alignedNameSize = extendedFormatNames ? extendedFormatNameSize(name) : 0;
- // Content is 8-bytes aligned and padded with \n characters.
- const uint64_t alignedContentSize = align(content.size(), 3);
- const uint64_t headerSize = sizeof(Entry) + alignedNameSize;
- const uint64_t totalSize = headerSize + alignedContentSize;
- assert(totalSize == entrySize(extendedFormatNames, name, content.size()));
- assert(buffer.size() >= (totalSize));
- bzero(buffer.data(), (size_t)headerSize);
-
- snprintf(entry->ar_date, sizeof(Entry::ar_date), "%llu", mktime);
- memcpy(entry->ar_fmag, ARFMAG, sizeof(Entry::ar_fmag));
-
- if ( extendedFormatNames ) {
- snprintf(entry->ar_size, sizeof(Entry::ar_size), "%llu", alignedContentSize + alignedNameSize);
- snprintf(entry->ar_name, sizeof(Entry::ar_name), AR_EFMT1 "%llu", alignedNameSize);
-
- char* nameBuffer = (char*)(entry + 1);
- memcpy(nameBuffer, name.data(), name.size());
- nameBuffer[name.size()] = 0;
- } else {
- snprintf(entry->ar_size, sizeof(Entry::ar_size), "%llu", alignedContentSize);
-
- // Note that the truncated name doesn't need to be \0 terminated
- std::string_view shortName = name.substr(0, sizeof(Entry::ar_name));
- memcpy(entry->ar_name, shortName.data(), shortName.size());
- }
-
- uint8_t* contentStart = buffer.data() + sizeof(Entry) + alignedNameSize;
- memcpy(contentStart, content.data(), content.size());
- // Pad content alignment with \n characters
- if ( content.size() != alignedContentSize )
- memset(contentStart + content.size(), '\n', (size_t)alignedContentSize - content.size());
-
- return (size_t)totalSize;
-}
-
-bool Entry::hasLongName() const
-{
- return std::string_view(ar_name, AR_EFMT1_SV.size()) == AR_EFMT1_SV;
-}
-
-uint64_t Entry::getLongNameSpace() const
-{
- char* endptr;
- return strtoull(&ar_name[AR_EFMT1_SV.size()], &endptr, 10);
-}
-
-void Entry::getName(char *buf, int bufsz) const
-{
- if ( hasLongName() ) {
- uint64_t len = getLongNameSpace();
- assert(bufsz >= len+1);
- strncpy(buf, ((char*)this)+sizeof(ar_hdr), (size_t)len);
- buf[len] = '\0';
- } else {
- assert(bufsz >= 16+1);
- strncpy(buf, ar_name, 16);
- buf[16] = '\0';
- char* space = strchr(buf, ' ');
- if ( space != NULL )
- *space = '\0';
- }
-}
-
-uint64_t Entry::modificationTime() const
-{
- char temp[14];
- strncpy(temp, ar_date, 12);
- temp[12] = '\0';
- char* endptr;
- return strtoull(temp, &endptr, 10);
-}
-
-Error Entry::content(std::span<const uint8_t>& content) const
-{
- char temp[12];
- strncpy(temp, ar_size, 10);
- temp[10] = 0;
- char* endptr = nullptr;
- uint64_t size = strtoull(temp, &endptr, 10);
- if ( *endptr != 0 && *endptr != ' ' )
- return Error("archive member size contains non-numeric characters: '%s'", (const char*)temp);
-
- const uint8_t* data;
- // long name is included in ar_size
- if ( hasLongName() ) {
- uint64_t space = getLongNameSpace();
- assert(size >= space);
- size -= space;
- data = ((const uint8_t*)this) + sizeof(ar_hdr) + space;
- } else {
- data = ((const uint8_t*)this) + sizeof(ar_hdr);
- }
-
- content = std::span(data, (size_t)size);
- return Error::none();
-}
-
-Error Entry::next(Entry*& next) const
-{
- next = nullptr;
- std::span<const uint8_t> content;
- if (Error err = this->content(content) )
- return err;
-
- const uint8_t* p = content.data() + content.size();
- p = (uint8_t*)align((uint64_t)p, 2); // 4-byte align
- next = (Entry*)p;
- return Error::none();
-}
-
-Error Entry::valid() const
-{
- if ( memcmp(ar_fmag, ARFMAG, sizeof(ar_fmag)) == 0 ) {
- return Error::none();
- }
-
- return Error("archive member invalid control bits");
-}
-
-std::optional<Archive> Archive::isArchive(std::span<const uint8_t> buffer)
-{
- if ( buffer.size() >= archive_magic.size()
- && std::string_view((const char*)buffer.data(), archive_magic.size()) == archive_magic ) {
- return Archive(buffer);
- }
- return std::nullopt;
-}
-
-Error Archive::forEachMember(void (^handler)(const Member&, bool& stop)) const
-{
- const Entry* current = (Entry*)(buffer.data() + archive_magic.size());
- const Entry* const end = (Entry*)(buffer.data() + buffer.size());
-
- std::array<char, 256> nameBuffer;
- bool stop = false;
- unsigned memberIndex = 1;
- while ( !stop && current < end ) {
- if ( (current + 1) > end )
- return Error("malformed archive, member exceeds file size");
-
- if ( Error err = current->valid() )
- return err;
-
- std::span<const uint8_t> content;
- if ( Error err = current->content(content) )
- return err;
-
- Entry* next;
- if ( Error err = current->next(next) )
- return err;
- if ( next > end )
- return Error("malformed archive, member exceeds file size");
-
- current->getName(nameBuffer.data(), nameBuffer.size());
- handler(Member{ nameBuffer.data(), content, current->modificationTime(), memberIndex }, stop);
- current = next;
- memberIndex++;
- }
-
- return Error::none();
-}
-
-static bool isBitCodeHeader(std::span<const uint8_t> contents)
-{
- return (contents[0] == 0xDE) && (contents[1] == 0xC0) && (contents[2] == 0x17) && (contents[3] == 0x0B);
-}
-
-Error Archive::forEachMachO(void (^handler)(const Member&, const mach_o::Header*, bool& stop)) const
-{
- __block Error err = Error::none();
- __block bool hadSymdefFile = false;
-
- Error iterErr = forEachMember(^(const Member& member, bool &stop) {
- if ( const Header* header = Header::isMachO(member.contents) ) {
- handler(std::move(member), header, stop);
- }
- else if ( isBitCodeHeader(member.contents) ) {
- handler(std::move(member), nullptr, stop);
- }
- else {
- if ( member.name == SYMDEF || member.name == SYMDEF_SORTED ||
- member.name == SYMDEF_64 || member.name == SYMDEF_64_SORTED ) {
- if ( hadSymdefFile ) {
- err = Error("multiple SYMDEF member files found in an archive");
- } else {
- hadSymdefFile = true;
- return;
- }
- } else {
- err = Error("archive member '%s' not a mach-o file", member.name.data()) ;
- }
- stop = true;
- }
- });
-
- if ( iterErr )
- return iterErr;
-
- return std::move(err);
-}
-
-}
-
-#endif // !TARGET_OS_EXCLAVEKIT