brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · bd37833 Raw
292 lines · cpp
1//===- llvm/BinaryFormat/Magic.cpp - File magic identification --*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/BinaryFormat/Magic.h"10#include "llvm/ADT/StringRef.h"11#include "llvm/ADT/Twine.h"12#include "llvm/BinaryFormat/COFF.h"13#include "llvm/BinaryFormat/MachO.h"14#include "llvm/Support/Endian.h"15#include "llvm/Support/MemoryBuffer.h"16 17#if !defined(_MSC_VER) && !defined(__MINGW32__)18#include <unistd.h>19#else20#include <io.h>21#endif22 23using namespace llvm;24using namespace llvm::support::endian;25using namespace llvm::sys::fs;26 27template <size_t N>28static bool startswith(StringRef Magic, const char (&S)[N]) {29  return Magic.starts_with(StringRef(S, N - 1));30}31 32/// Identify the magic in magic.33file_magic llvm::identify_magic(StringRef Magic) {34  if (Magic.size() < 4)35    return file_magic::unknown;36  switch ((unsigned char)Magic[0]) {37  case 0x00: {38    // COFF bigobj, CL.exe's LTO object file, or short import library file39    if (startswith(Magic, "\0\0\xFF\xFF")) {40      size_t MinSize =41          offsetof(COFF::BigObjHeader, UUID) + sizeof(COFF::BigObjMagic);42      if (Magic.size() < MinSize)43        return file_magic::coff_import_library;44 45      const char *Start = Magic.data() + offsetof(COFF::BigObjHeader, UUID);46      if (memcmp(Start, COFF::BigObjMagic, sizeof(COFF::BigObjMagic)) == 0)47        return file_magic::coff_object;48      if (memcmp(Start, COFF::ClGlObjMagic, sizeof(COFF::BigObjMagic)) == 0)49        return file_magic::coff_cl_gl_object;50      return file_magic::coff_import_library;51    }52    // Windows resource file53    if (Magic.size() >= sizeof(COFF::WinResMagic) &&54        memcmp(Magic.data(), COFF::WinResMagic, sizeof(COFF::WinResMagic)) == 0)55      return file_magic::windows_resource;56    // 0x0000 = COFF unknown machine type57    if (Magic[1] == 0)58      return file_magic::coff_object;59    if (startswith(Magic, "\0asm"))60      return file_magic::wasm_object;61    break;62  }63 64  case 0x01:65    // XCOFF format66    if (startswith(Magic, "\x01\xDF"))67      return file_magic::xcoff_object_32;68    if (startswith(Magic, "\x01\xF7"))69      return file_magic::xcoff_object_64;70    break;71 72  case 0x03:73    if (startswith(Magic, "\x03\xF0\x00"))74      return file_magic::goff_object;75    // SPIR-V format in little-endian mode.76    if (startswith(Magic, "\x03\x02\x23\x07"))77      return file_magic::spirv_object;78    break;79 80  case 0x07: // SPIR-V format in big-endian mode.81    if (startswith(Magic, "\x07\x23\x02\x03"))82      return file_magic::spirv_object;83    break;84 85  case 0x10:86    if (startswith(Magic, "\x10\xFF\x10\xAD"))87      return file_magic::offload_binary;88    break;89 90  case 0xDE: // 0x0B17C0DE = BC wraper91    if (startswith(Magic, "\xDE\xC0\x17\x0B"))92      return file_magic::bitcode;93    break;94  case 'B':95    if (startswith(Magic, "BC\xC0\xDE"))96      return file_magic::bitcode;97    break;98  case 'C':99    if (startswith(Magic, "CCOB"))100      return file_magic::offload_bundle_compressed;101    if (startswith(Magic, "CPCH"))102      return file_magic::clang_ast;103    break;104  case '!':105    if (startswith(Magic, "!<arch>\n") || startswith(Magic, "!<thin>\n"))106      return file_magic::archive;107    break;108  case '<':109    if (startswith(Magic, "<bigaf>\n"))110      return file_magic::archive;111    break;112  case '\177':113    if (startswith(Magic, "\177ELF") && Magic.size() >= 18) {114      bool Data2MSB = Magic[5] == 2;115      unsigned high = Data2MSB ? 16 : 17;116      unsigned low = Data2MSB ? 17 : 16;117      if (Magic[high] == 0) {118        switch (Magic[low]) {119        default:120          return file_magic::elf;121        case 1:122          return file_magic::elf_relocatable;123        case 2:124          return file_magic::elf_executable;125        case 3:126          return file_magic::elf_shared_object;127        case 4:128          return file_magic::elf_core;129        }130      }131      // It's still some type of ELF file.132      return file_magic::elf;133    }134    break;135 136  case 0xCA:137    if (startswith(Magic, "\xCA\xFE\xBA\xBE") ||138        startswith(Magic, "\xCA\xFE\xBA\xBF")) {139      // This is complicated by an overlap with Java class files.140      // See the Mach-O section in /usr/share/file/magic for details.141      if (Magic.size() >= 8 && Magic[7] < 43)142        return file_magic::macho_universal_binary;143    }144    break;145 146  // The two magic numbers for mach-o are:147  // 0xfeedface - 32-bit mach-o148  // 0xfeedfacf - 64-bit mach-o149  case 0xFE:150  case 0xCE:151  case 0xCF: {152    uint16_t type = 0;153    if (startswith(Magic, "\xFE\xED\xFA\xCE") ||154        startswith(Magic, "\xFE\xED\xFA\xCF")) {155      /* Native endian */156      size_t MinSize;157      if (Magic[3] == char(0xCE))158        MinSize = sizeof(MachO::mach_header);159      else160        MinSize = sizeof(MachO::mach_header_64);161      if (Magic.size() >= MinSize)162        type = Magic[12] << 24 | Magic[13] << 12 | Magic[14] << 8 | Magic[15];163    } else if (startswith(Magic, "\xCE\xFA\xED\xFE") ||164               startswith(Magic, "\xCF\xFA\xED\xFE")) {165      /* Reverse endian */166      size_t MinSize;167      if (Magic[0] == char(0xCE))168        MinSize = sizeof(MachO::mach_header);169      else170        MinSize = sizeof(MachO::mach_header_64);171      if (Magic.size() >= MinSize)172        type = Magic[15] << 24 | Magic[14] << 12 | Magic[13] << 8 | Magic[12];173    }174    switch (type) {175    default:176      break;177    case 1:178      return file_magic::macho_object;179    case 2:180      return file_magic::macho_executable;181    case 3:182      return file_magic::macho_fixed_virtual_memory_shared_lib;183    case 4:184      return file_magic::macho_core;185    case 5:186      return file_magic::macho_preload_executable;187    case 6:188      return file_magic::macho_dynamically_linked_shared_lib;189    case 7:190      return file_magic::macho_dynamic_linker;191    case 8:192      return file_magic::macho_bundle;193    case 9:194      return file_magic::macho_dynamically_linked_shared_lib_stub;195    case 10:196      return file_magic::macho_dsym_companion;197    case 11:198      return file_magic::macho_kext_bundle;199    case 12:200      return file_magic::macho_file_set;201    }202    break;203  }204  case 0xF0: // PowerPC Windows205  case 0x83: // Alpha 32-bit206  case 0x84: // Alpha 64-bit207  case 0x66: // MPS R4000 Windows208  case 0x50: // mc68K209    if (startswith(Magic, "\x50\xed\x55\xba"))210      return file_magic::cuda_fatbinary;211    [[fallthrough]];212 213  case 0x4c: // 80386 Windows214  case 0xc4: // ARMNT Windows215    if (Magic[1] == 0x01)216      return file_magic::coff_object;217    [[fallthrough]];218 219  case 0x90: // PA-RISC Windows220  case 0x68: // mc68K Windows221    if (Magic[1] == 0x02)222      return file_magic::coff_object;223    break;224 225  case 'M': // Possible MS-DOS stub on Windows PE file, MSF/PDB file or a226            // Minidump file.227    if (startswith(Magic, "MZ") && Magic.size() >= 0x3c + 4) {228      uint32_t off = read32le(Magic.data() + 0x3c);229      // PE/COFF file, either EXE or DLL.230      if (Magic.substr(off).starts_with(231              StringRef(COFF::PEMagic, sizeof(COFF::PEMagic))))232        return file_magic::pecoff_executable;233    }234    if (Magic.starts_with("Microsoft C/C++ MSF 7.00\r\n"))235      return file_magic::pdb;236    if (startswith(Magic, "MDMP"))237      return file_magic::minidump;238    break;239 240  case 0x64: // x86-64 or ARM64 Windows.241    if (Magic[1] == char(0x86) || Magic[1] == char(0xaa))242      return file_magic::coff_object;243    break;244 245  case 0x2d: // YAML '-' MachO TBD.246    if (startswith(Magic, "--- !tapi") || startswith(Magic, "---\narchs:"))247      return file_magic::tapi_file;248    break;249  case 0x7b: // JSON '{' MachO TBD.250    return file_magic::tapi_file;251    break;252 253  case 'D': // DirectX container file - DXBC254    if (startswith(Magic, "DXBC"))255      return file_magic::dxcontainer_object;256    break;257 258  case 0x41: // ARM64EC windows259    if (Magic[1] == char(0xA6))260      return file_magic::coff_object;261    break;262 263  case 0x4e: // ARM64X windows264    if (Magic[1] == char(0xA6))265      return file_magic::coff_object;266    break;267 268  case '_': {269    const char OBMagic[] = "__CLANG_OFFLOAD_BUNDLE__";270    if (Magic.size() >= sizeof(OBMagic) && startswith(Magic, OBMagic))271      return file_magic::offload_bundle;272    break;273  }274 275  default:276    break;277  }278  return file_magic::unknown;279}280 281std::error_code llvm::identify_magic(const Twine &Path, file_magic &Result) {282  auto FileOrError = MemoryBuffer::getFile(Path, /*IsText=*/false,283                                           /*RequiresNullTerminator=*/false);284  if (!FileOrError)285    return FileOrError.getError();286 287  std::unique_ptr<MemoryBuffer> FileBuffer = std::move(*FileOrError);288  Result = identify_magic(FileBuffer->getBuffer());289 290  return std::error_code();291}292