Loading...
mach_o/RebaseOpcodes.cpp dyld-1340 /dev/null
--- dyld/dyld-1340/mach_o/RebaseOpcodes.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (c) 2021 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 <sys/types.h>
-#include <assert.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mach-o/loader.h>
-#include <mach-o/nlist.h>
-
-#include "RebaseOpcodes.h"
-#include "Misc.h"
-#include "Image.h"
-
-namespace mach_o {
-
-//
-// MARK: --- RebaseOpcodes inspection methods ---
-//
-
-RebaseOpcodes::RebaseOpcodes(const uint8_t* start, size_t size, bool is64)
-  : _opcodesStart(start), _opcodesEnd(start+size), _pointerSize(is64 ? 8 : 4)
-{
-}
-
-
-Error RebaseOpcodes::valid(std::span<const MappedSegment> segments, bool allowTextFixups, bool onlyFixupsInWritableSegments) const
-{
-    __block Error locError;
-    Error opcodeErr = this->forEachRebase(^(const char* opcodeName, int type, bool segIndexSet, uint8_t segmentIndex, uint64_t segmentOffset, bool& stop) {
-        if ( !segIndexSet ) {
-            locError = Error("%s missing preceding REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB", opcodeName);
-            stop = true;
-        }
-        else if ( segmentIndex >= segments.size() )  {
-            locError = Error("%s segment index %d too large", opcodeName, segmentIndex);
-            stop = true;
-        }
-        else if ( segmentOffset > (segments[segmentIndex].runtimeSize-_pointerSize) ) {
-            locError = Error("%s segment offset 0x%08llX beyond segment '%.*s' size (0x%08llX)", opcodeName, segmentOffset,
-                             (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data(),
-                             segments[segmentIndex].runtimeSize);
-            stop = true;
-        }
-        else {
-            switch ( type ) {
-                case REBASE_TYPE_POINTER:
-                    if ( !segments[segmentIndex].writable && onlyFixupsInWritableSegments ) {
-                        locError = Error("%s pointer rebase is in non-writable segment '%.*s'", opcodeName,
-                                         (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
-                        stop = true;
-                    }
-                    else if ( segments[segmentIndex].executable && onlyFixupsInWritableSegments ) {
-                        locError = Error("%s pointer rebase is in executable segment '%.*s'", opcodeName,
-                                         (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
-                        stop = true;
-                    }
-                    break;
-                case REBASE_TYPE_TEXT_ABSOLUTE32:
-                case REBASE_TYPE_TEXT_PCREL32:
-                    if ( !allowTextFixups ) {
-                        locError = Error("%s text rebase not supported for architecture",  opcodeName);
-                        stop     = true;
-                    }
-                    else if ( segments[segmentIndex].writable ) {
-                        locError = Error("%s text rebase is in writable segment '%.*s'", opcodeName,
-                                         (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
-                        stop = true;
-                    }
-                    else if ( !segments[segmentIndex].executable ) {
-                        locError = Error("%s text rebase is in non-executable segment '%.*s'", opcodeName,
-                                         (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
-                        stop = true;
-                    }
-                    break;
-                default:
-                    locError = Error("%s unknown rebase type", opcodeName);
-                    stop = true;
-            }
-        }
-    });
-    if ( opcodeErr )
-        return opcodeErr;
-    return std::move(locError);
-}
-
-Error RebaseOpcodes::forEachRebase(void (^handler)(const char* opcodeName, int type, bool segIndexSet, uint8_t segmentIndex, uint64_t segmentOffset, bool& stop)) const
-{
-    const uint8_t*  p           = _opcodesStart;
-    int             type        = 0;
-    int             segIndex    = 0;
-    uint64_t        segOffset   = 0;
-    bool            segIndexSet = false;
-    bool            stop        = false;
-    bool            malformed   = false;
-    uint64_t        count;
-    uint64_t        skip;
-    while ( !stop && !malformed && (p < _opcodesEnd) ) {
-        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
-        uint8_t opcode    = *p & REBASE_OPCODE_MASK;
-        ++p;
-        switch (opcode) {
-            case REBASE_OPCODE_DONE:
-                // Allow some padding, in case rebases were somehow aligned to 16-bytes in size
-                if ( (_opcodesEnd - p) > 15 )
-                    return Error("rebase opcodes terminated early at offset %d of %d", (int)(p-_opcodesStart), (int)(_opcodesEnd-_opcodesStart));
-                break;
-            case REBASE_OPCODE_SET_TYPE_IMM:
-                switch ( immediate ) {
-                    case REBASE_TYPE_POINTER:
-                    case REBASE_TYPE_TEXT_ABSOLUTE32:
-                    case REBASE_TYPE_TEXT_PCREL32:
-                        type = immediate;
-                        break;
-                    default:
-                        type = 0;
-                        break;
-                }
-                break;
-            case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                segIndex = immediate;
-                segOffset = read_uleb128(p, _opcodesEnd, malformed);
-                segIndexSet = true;
-                break;
-            case REBASE_OPCODE_ADD_ADDR_ULEB:
-                segOffset += read_uleb128(p, _opcodesEnd, malformed);
-                break;
-            case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
-                segOffset += immediate*_pointerSize;
-                break;
-            case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
-                for (int i=0; i < immediate; ++i) {
-                    handler("REBASE_OPCODE_DO_REBASE_IMM_TIMES", type, segIndexSet, segIndex, segOffset, stop);
-                    segOffset += _pointerSize;
-                    if ( stop )
-                        break;
-                }
-                break;
-            case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
-                count = read_uleb128(p, _opcodesEnd, malformed);
-                if ( malformed )
-                    break;
-                for (uint32_t i=0; i < count; ++i) {
-                    handler("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB", type, segIndexSet, segIndex, segOffset, stop);
-                    segOffset += _pointerSize;
-                    if ( stop )
-                        break;
-                }
-                break;
-            case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                handler("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB", type, segIndexSet, segIndex, segOffset, stop);
-                segOffset += read_uleb128(p, _opcodesEnd, malformed) + _pointerSize;
-                break;
-            case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
-                count = read_uleb128(p, _opcodesEnd, malformed);
-                if ( malformed )
-                    break;
-                skip = read_uleb128(p, _opcodesEnd, malformed);
-                if ( malformed )
-                    break;
-                for (uint32_t i=0; i < count; ++i) {
-                    handler("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB", type, segIndexSet, segIndex, segOffset, stop);
-                    segOffset += skip + _pointerSize;
-                    if ( stop )
-                        break;
-                }
-                break;
-            default:
-                return Error("unknown rebase opcode 0x%02X", opcode);
-        }
-    }
-    if ( malformed )
-        return Error("malformed uleb128");
-    else
-        return Error::none();
-}
-
-void RebaseOpcodes::forEachRebaseLocation(void (^callback)(uint32_t segIndex, uint64_t segOffset, bool& stop)) const
-{
-    (void)forEachRebase(^(const char* opcodeName, int type, bool segIndexSet, uint8_t segmentIndex, uint64_t segmentOffset, bool& stop) {
-        callback(segmentIndex, segmentOffset, stop);
-    });
-}
-
-void RebaseOpcodes::forEachRebaseLocation(std::span<const MappedSegment> segments, uint64_t prefLoadAdder, void (^callback)(const Fixup& fixup, bool& stop)) const
-{
-    const bool is64 = (_pointerSize == 8);
-    (void)forEachRebase(^(const char* opcodeName, int type, bool segIndexSet, uint8_t segIndex, uint64_t segOffset, bool& stop) {
-        uint8_t* loc = (uint8_t*)(segments[segIndex].content) + segOffset;
-        uint64_t targetVmOffset;
-        if ( is64 ) {
-            targetVmOffset = *((uint64_t*)loc) - prefLoadAdder;
-        }
-        else {
-            // for i386, there may be "text relocations" which are not 4-byte aligned
-            uint32_t value;
-            memcpy(&value, loc, 4);
-            targetVmOffset = (uint64_t)value - prefLoadAdder;
-        }
-        Fixup fixup(loc, &segments[segIndex], targetVmOffset);
-        callback(fixup, stop);
-    });
-}
-
-const uint8_t* RebaseOpcodes::bytes(size_t& size) const
-{
-    size = (_opcodesEnd - _opcodesStart);
-    return _opcodesStart;
-}
-
-void RebaseOpcodes::printOpcodes(FILE* output, int indentCount) const
-{
-    uint8_t         type = 0;
-    uint64_t        count;
-    uint64_t        skip;
-    uint32_t        segmentIndex;
-    uint64_t        segOffset;
-    bool            done = false;
-    bool            malformed = false;
-    char            indent[indentCount+1];
-    const uint8_t*  p = _opcodesStart;
-    for (int i=0; i < indentCount; ++i)
-        indent[i] = ' ';
-    indent[indentCount] = '\0';
-    while ( !done && !malformed && (p < _opcodesEnd) ) {
-        uint8_t  immediate    = *p & REBASE_IMMEDIATE_MASK;
-        uint8_t  opcode       = *p & REBASE_OPCODE_MASK;
-        long     opcodeOffset = p - _opcodesStart;
-        ++p;
-        switch (opcode) {
-            case REBASE_OPCODE_DONE:
-                done = true;
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_DONE()\n", indent, opcodeOffset);
-                break;
-            case REBASE_OPCODE_SET_TYPE_IMM:
-                type = immediate;
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_SET_TYPE_IMM(%d)\n", indent, opcodeOffset, type);
-                break;
-            case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                segmentIndex = immediate;
-                segOffset = read_uleb128(p, _opcodesEnd, malformed);
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", indent, opcodeOffset, segmentIndex, segOffset);
-                break;
-            case REBASE_OPCODE_ADD_ADDR_ULEB:
-                segOffset = read_uleb128(p, _opcodesEnd, malformed);
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", indent, opcodeOffset, segOffset);
-                break;
-            case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
-                segOffset = immediate * _pointerSize;
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", indent, opcodeOffset, segOffset);
-                break;
-            case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", indent, opcodeOffset, immediate);
-                break;
-            case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
-                count = read_uleb128(p, _opcodesEnd, malformed);
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", indent, opcodeOffset, count);
-                break;
-            case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                skip = read_uleb128(p, _opcodesEnd, malformed) + _pointerSize;
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%lld)\n", indent, opcodeOffset, skip);
-                break;
-            case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
-                count = read_uleb128(p, _opcodesEnd, malformed);
-                skip  = read_uleb128(p, _opcodesEnd, malformed);
-                fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", indent, opcodeOffset, count, skip);
-                break;
-            default:
-                fprintf(output, "%sunknown rebase opcode 0x%02X\n", indent, *p);
-        }
-    }
-}
-
-} // namespace mach_o