current commit
260929.11 · deps: update lief to 1.0.0
/* Copyright 2017 - 2026 R. Thomas
 * Copyright 2017 - 2026 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "LIEF/Visitor.hpp"
#include "LIEF/Abstract/Header.hpp"

#if defined(LIEF_ELF_SUPPORT)
  #include "LIEF/ELF/Binary.hpp"
#endif
#if defined(LIEF_MACHO_SUPPORT)
  #include "LIEF/MachO/Binary.hpp"
#endif
#if defined(LIEF_PE_SUPPORT)
  #include "LIEF/PE/Binary.hpp"
#endif

#include <spdlog/fmt/fmt.h>

#include "frozen.hpp"
#include "fmt_formatter.hpp"
#include "logging.hpp"
#include "LIEF/config.h"

FMT_FORMATTER(LIEF::Header::MODES, LIEF::to_string);

namespace LIEF {

static constexpr auto ARRAY_MODES = {
    Header::MODES::NONE,    Header::MODES::ARM64E,  Header::MODES::BITS_16,
    Header::MODES::BITS_32, Header::MODES::BITS_64, Header::MODES::THUMB,
};

#if defined(LIEF_ELF_SUPPORT)
Header Header::from(const ELF::Binary& elf) {
  if constexpr (!lief_elf_support) {
    return {};
  }

  Header hdr;
  hdr.entrypoint_ = elf.entrypoint();

  switch (elf.header().identity_class()) {
    case ELF::Header::CLASS::ELF32: hdr.modes_ |= MODES::BITS_32; break;

    case ELF::Header::CLASS::ELF64: hdr.modes_ |= MODES::BITS_64; break;

    default: break;
  }

  switch (elf.header().machine_type()) {
    case ELF::ARCH::X86_64: hdr.architecture_ = ARCHITECTURES::X86_64; break;

    case ELF::ARCH::I386: hdr.architecture_ = ARCHITECTURES::X86; break;

    case ELF::ARCH::ARM: hdr.architecture_ = ARCHITECTURES::ARM; break;

    case ELF::ARCH::AARCH64: hdr.architecture_ = ARCHITECTURES::ARM64; break;

    case ELF::ARCH::MIPS: hdr.architecture_ = ARCHITECTURES::MIPS; break;

    case ELF::ARCH::PPC: hdr.architecture_ = ARCHITECTURES::PPC; break;

    case ELF::ARCH::PPC64: hdr.architecture_ = ARCHITECTURES::PPC64; break;

    case ELF::ARCH::RISCV: hdr.architecture_ = ARCHITECTURES::RISCV; break;

    case ELF::ARCH::LOONGARCH: hdr.architecture_ = ARCHITECTURES::LOONGARCH; break;

    default: break;
  }

  switch (elf.header().identity_data()) {
    case ELF::Header::ELF_DATA::LSB: hdr.endianness_ = ENDIANNESS::LITTLE; break;
    case ELF::Header::ELF_DATA::MSB: hdr.endianness_ = ENDIANNESS::BIG; break;
    case ELF::Header::ELF_DATA::NONE: hdr.endianness_ = ENDIANNESS::UNKNOWN; break;
  }

  switch (elf.header().file_type()) {
    case ELF::Header::FILE_TYPE::EXEC:
      hdr.object_type_ = OBJECT_TYPES::EXECUTABLE;
      break;

    case ELF::Header::FILE_TYPE::DYN:
      hdr.object_type_ =
          elf.has_interpreter() ? OBJECT_TYPES::EXECUTABLE : OBJECT_TYPES::LIBRARY;
      break;

    case ELF::Header::FILE_TYPE::REL:
      hdr.object_type_ = OBJECT_TYPES::OBJECT;
      break;

    default: break;
  }

  return hdr;
}
#endif

#if defined(LIEF_PE_SUPPORT)
Header Header::from(const PE::Binary& pe) {
  if constexpr (!lief_pe_support) {
    return {};
  }

  Header hdr;
  hdr.entrypoint_ = pe.entrypoint();
  const PE::Header& pe_header = pe.header();

  if (pe.type() == LIEF::PE::PE_TYPE::PE32) {
    hdr.modes_ |= MODES::BITS_32;
  }

  if (pe.type() == LIEF::PE::PE_TYPE::PE32_PLUS) {
    hdr.modes_ |= MODES::BITS_64;
  }

  switch (pe_header.machine()) {
    case PE::Header::MACHINE_TYPES::AMD64:
      hdr.architecture_ = ARCHITECTURES::X86_64;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case PE::Header::MACHINE_TYPES::ARMNT:
    case PE::Header::MACHINE_TYPES::ARM:
      hdr.architecture_ = ARCHITECTURES::ARM;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case PE::Header::MACHINE_TYPES::ARM64:
      hdr.architecture_ = ARCHITECTURES::ARM64;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case PE::Header::MACHINE_TYPES::I386:
      hdr.architecture_ = ARCHITECTURES::X86;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case PE::Header::MACHINE_TYPES::RISCV32:
    case PE::Header::MACHINE_TYPES::RISCV64:
      hdr.architecture_ = ARCHITECTURES::RISCV;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case PE::Header::MACHINE_TYPES::THUMB:
      hdr.architecture_ = ARCHITECTURES::ARM;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      hdr.modes_ |= MODES::THUMB;
      break;

    default: break;
  }

  if (pe_header.has_characteristic(PE::Header::CHARACTERISTICS::DLL)) {
    hdr.object_type_ = OBJECT_TYPES::LIBRARY;
  } else if (pe_header.has_characteristic(
                 PE::Header::CHARACTERISTICS::EXECUTABLE_IMAGE
             ))
  {
    hdr.object_type_ = OBJECT_TYPES::EXECUTABLE;
  }
  return hdr;
}
#endif

#if defined(LIEF_MACHO_SUPPORT)
Header Header::from(const MachO::Binary& macho) {
  if constexpr (!lief_macho_support) {
    return {};
  }

  Header hdr;
  {
    logging::Scoped scope(logging::LEVEL::OFF);
    // Disable warning messages when resolving the entrypoint
    hdr.entrypoint_ = macho.entrypoint();
  }
  const MachO::Header& macho_hdr = macho.header();
  const MachO::MACHO_TYPES magic = macho_hdr.magic();
  if (magic == MachO::MACHO_TYPES::MAGIC_64 ||
      magic == MachO::MACHO_TYPES::CIGAM_64)
  {
    hdr.modes_ |= MODES::BITS_64;
  }

  if (magic == MachO::MACHO_TYPES::MAGIC || magic == MachO::MACHO_TYPES::CIGAM) {
    hdr.modes_ |= MODES::BITS_32;
  }

  switch (macho_hdr.cpu_type()) {
    case MachO::Header::CPU_TYPE::ARM:
      hdr.architecture_ = ARCHITECTURES::ARM;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case MachO::Header::CPU_TYPE::ARM64:
    {
      hdr.architecture_ = ARCHITECTURES::ARM64;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      if (macho.support_arm64_ptr_auth()) {
        hdr.modes_ |= MODES::ARM64E;
      }
      break;
    }

    case MachO::Header::CPU_TYPE::X86:
      hdr.architecture_ = ARCHITECTURES::X86;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case MachO::Header::CPU_TYPE::X86_64:
      hdr.architecture_ = ARCHITECTURES::X86_64;
      hdr.endianness_ = ENDIANNESS::LITTLE;
      break;

    case MachO::Header::CPU_TYPE::MIPS:
      hdr.architecture_ = ARCHITECTURES::MIPS;
      break;

    case MachO::Header::CPU_TYPE::POWERPC64:
      hdr.architecture_ = ARCHITECTURES::PPC64;
      hdr.endianness_ = ENDIANNESS::BIG;
      break;

    case MachO::Header::CPU_TYPE::POWERPC:
      hdr.architecture_ = ARCHITECTURES::PPC;
      hdr.endianness_ = ENDIANNESS::BIG;
      break;

    case MachO::Header::CPU_TYPE::SPARC:
      hdr.architecture_ = ARCHITECTURES::SPARC;
      hdr.endianness_ = ENDIANNESS::BIG;
      break;

    default: break;
  }


  switch (macho_hdr.file_type()) {
    case MachO::Header::FILE_TYPE::EXECUTE:
      hdr.object_type_ = OBJECT_TYPES::EXECUTABLE;
      break;

    case MachO::Header::FILE_TYPE::DYLIB:
      hdr.object_type_ = OBJECT_TYPES::LIBRARY;
      break;

    case MachO::Header::FILE_TYPE::OBJECT:
      hdr.object_type_ = OBJECT_TYPES::OBJECT;
      break;

    default: break;
  }

  return hdr;
}
#endif

std::vector<Header::MODES> Header::modes_list() const {
  std::vector<MODES> flags;
  std::copy_if(ARRAY_MODES.begin(), ARRAY_MODES.end(), std::back_inserter(flags),
               [this](MODES f) { return is(f); });
  return flags;
}

void Header::accept(Visitor& visitor) const {
  visitor.visit(*this);
}

std::ostream& operator<<(std::ostream& os, const Header& hdr) {
  const auto& modes = hdr.modes_list();
  os << fmt::format("[{}] {} (endianness={}) {}", to_string(hdr.object_type()),
                    to_string(hdr.architecture()), to_string(hdr.endianness()),
                    fmt::to_string(modes));
  return os;
}

const char* to_string(Header::ARCHITECTURES e) {
#define ENTRY(X) std::pair(Header::ARCHITECTURES::X, #X)
  STRING_MAP enums2str{
      ENTRY(UNKNOWN), ENTRY(ARM),       ENTRY(ARM64), ENTRY(MIPS), ENTRY(X86),
      ENTRY(X86_64),  ENTRY(PPC),       ENTRY(SPARC), ENTRY(SYSZ), ENTRY(XCORE),
      ENTRY(RISCV),   ENTRY(LOONGARCH), ENTRY(PPC64),
  };
#undef ENTRY
  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "UNKNOWN";
}
const char* to_string(Header::OBJECT_TYPES e) {
#define ENTRY(X) std::pair(Header::OBJECT_TYPES::X, #X)
  STRING_MAP enums2str{
      ENTRY(UNKNOWN),
      ENTRY(EXECUTABLE),
      ENTRY(LIBRARY),
      ENTRY(OBJECT),
  };
#undef ENTRY
  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "UNKNOWN";
}
const char* to_string(Header::MODES e) {
#define ENTRY(X) std::pair(Header::MODES::X, #X)
  STRING_MAP enums2str{
      ENTRY(NONE),    ENTRY(BITS_16), ENTRY(BITS_32),
      ENTRY(BITS_64), ENTRY(THUMB),   ENTRY(ARM64E),
  };
#undef ENTRY
  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "UNKNOWN";
}
const char* to_string(Header::ENDIANNESS e) {
#define ENTRY(X) std::pair(Header::ENDIANNESS::X, #X)
  STRING_MAP enums2str{
      ENTRY(UNKNOWN),
      ENTRY(BIG),
      ENTRY(LITTLE),
  };
#undef ENTRY
  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "UNKNOWN";
}


}