/* 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/ELF/DynamicEntry.hpp"
#include "LIEF/ELF/EnumToString.hpp"
#include "LIEF/ELF/DynamicEntryLibrary.hpp"
#include "LIEF/ELF/DynamicEntryArray.hpp"
#include "LIEF/ELF/DynamicEntryFlags.hpp"
#include "LIEF/ELF/DynamicEntryRpath.hpp"
#include "LIEF/ELF/DynamicEntryRunPath.hpp"
#include "LIEF/ELF/DynamicSharedObject.hpp"
#include "LIEF/ELF/DynamicEntryAuxiliary.hpp"
#include "LIEF/ELF/DynamicEntryFilter.hpp"
#include <spdlog/fmt/fmt.h>
#include "frozen.hpp"
#include "logging.hpp"
#include "ELF/Structures.hpp"
namespace LIEF::ELF {
DynamicEntry::TAG DynamicEntry::from_value(uint64_t value, ARCH arch) {
static constexpr auto LOPROC = 0x70000000;
static constexpr auto HIPROC = 0x7FFFFFFF;
static constexpr auto LOOS = 0x60000000;
static constexpr auto HIOS = 0x6FFFFFFF;
const bool is_os_spec = (LOOS <= value && value <= HIOS);
const bool is_proc_spec = (LOPROC <= value && value <= HIPROC);
if (is_os_spec && arch == ARCH::IA_64) {
return TAG(IA_64_DISC + value);
}
if (is_proc_spec) {
if (value == static_cast<uint64_t>(TAG::AUXILIARY)) {
return TAG::AUXILIARY;
}
if (value == static_cast<uint64_t>(TAG::FILTER)) {
return TAG::FILTER;
}
switch (arch) {
case ARCH::AARCH64: return TAG(AARCH64_DISC + value);
case ARCH::MIPS_RS3_LE:
case ARCH::MIPS: return TAG(MIPS_DISC + value);
case ARCH::HEXAGON: return TAG(HEXAGON_DISC + value);
case ARCH::PPC: return TAG(PPC_DISC + value);
case ARCH::PPC64: return TAG(PPC64_DISC + value);
case ARCH::RISCV: return TAG(RISCV_DISC + value);
case ARCH::X86_64: return TAG(X86_64_DISC + value);
case ARCH::IA_64: return TAG(IA_64_DISC + value);
default:
LIEF_WARN("Unsupported dynamic tag {:#06x} for "
"architecture ({})",
value, ELF::to_string(arch));
return TAG::UNKNOWN;
}
}
return TAG(value);
}
uint64_t DynamicEntry::to_value(DynamicEntry::TAG tag) {
auto raw_value = static_cast<uint64_t>(tag);
if (tag == TAG::AUXILIARY || tag == TAG::FILTER) {
return raw_value;
}
if (MIPS_DISC <= raw_value && raw_value < AARCH64_DISC) {
return raw_value - MIPS_DISC;
}
if (AARCH64_DISC <= raw_value && raw_value < HEXAGON_DISC) {
return raw_value - AARCH64_DISC;
}
if (HEXAGON_DISC <= raw_value && raw_value < PPC_DISC) {
return raw_value - HEXAGON_DISC;
}
if (PPC_DISC <= raw_value && raw_value < PPC64_DISC) {
return raw_value - PPC_DISC;
}
if (PPC64_DISC <= raw_value && raw_value < RISCV_DISC) {
return raw_value - PPC64_DISC;
}
if (RISCV_DISC <= raw_value && raw_value < X86_64_DISC) {
return raw_value - RISCV_DISC;
}
if (X86_64_DISC <= raw_value) {
return raw_value - X86_64_DISC;
}
if (IA_64_DISC <= raw_value) {
return raw_value - IA_64_DISC;
}
return raw_value;
}
std::unique_ptr<DynamicEntry> DynamicEntry::create(TAG tag, uint64_t value) {
switch (tag) {
default: return std::make_unique<DynamicEntry>(tag, value);
case TAG::NEEDED: return std::make_unique<DynamicEntryLibrary>();
case TAG::SONAME: return std::make_unique<DynamicSharedObject>();
case TAG::AUXILIARY: return std::make_unique<DynamicEntryAuxiliary>();
case TAG::FILTER: return std::make_unique<DynamicEntryFilter>();
case TAG::RUNPATH: return std::make_unique<DynamicEntryRunPath>();
case TAG::RPATH: return std::make_unique<DynamicEntryRpath>();
case TAG::FLAGS_1: return DynamicEntryFlags::create_dt_flag_1(value).clone();
case TAG::FLAGS: return DynamicEntryFlags::create_dt_flag(value).clone();
case TAG::INIT_ARRAY:
case TAG::FINI_ARRAY:
case TAG::PREINIT_ARRAY:
return std::make_unique<DynamicEntryArray>(tag,
DynamicEntryArray::array_t());
}
return std::make_unique<DynamicEntry>(tag, value);
}
DynamicEntry::DynamicEntry(const details::Elf64_Dyn& header, ARCH arch) :
tag_{DynamicEntry::from_value(header.d_tag, arch)},
value_{header.d_un.d_val} {}
DynamicEntry::DynamicEntry(const details::Elf32_Dyn& header, ARCH arch) :
tag_{DynamicEntry::from_value(header.d_tag, arch)},
value_{header.d_un.d_val} {}
void DynamicEntry::accept(Visitor& visitor) const {
visitor.visit(*this);
}
std::ostream& DynamicEntry::print(std::ostream& os) const {
os << fmt::format("{:<20}: {:#08x} ", ELF::to_string(tag()), value());
return os;
}
std::string DynamicEntry::to_string() const {
std::ostringstream oss;
print(oss);
return oss.str();
}
const char* to_string(DynamicEntry::TAG tag) {
#define ENTRY(X) std::pair(DynamicEntry::TAG::X, #X)
STRING_MAP enums2str{
ENTRY(UNKNOWN),
ENTRY(DT_NULL_),
ENTRY(NEEDED),
ENTRY(PLTRELSZ),
ENTRY(PLTGOT),
ENTRY(HASH),
ENTRY(STRTAB),
ENTRY(SYMTAB),
ENTRY(RELA),
ENTRY(RELASZ),
ENTRY(RELAENT),
ENTRY(STRSZ),
ENTRY(SYMENT),
ENTRY(INIT),
ENTRY(FINI),
ENTRY(SONAME),
ENTRY(RPATH),
ENTRY(SYMBOLIC),
ENTRY(REL),
ENTRY(RELSZ),
ENTRY(RELENT),
ENTRY(PLTREL),
ENTRY(DEBUG_TAG),
ENTRY(TEXTREL),
ENTRY(JMPREL),
ENTRY(BIND_NOW),
ENTRY(INIT_ARRAY),
ENTRY(FINI_ARRAY),
ENTRY(INIT_ARRAYSZ),
ENTRY(FINI_ARRAYSZ),
ENTRY(RUNPATH),
ENTRY(FLAGS),
ENTRY(PREINIT_ARRAY),
ENTRY(PREINIT_ARRAYSZ),
ENTRY(SYMTAB_SHNDX),
ENTRY(RELRSZ),
ENTRY(RELR),
ENTRY(RELRENT),
ENTRY(GNU_HASH),
ENTRY(TLSDESC_PLT),
ENTRY(TLSDESC_GOT),
ENTRY(RELACOUNT),
ENTRY(RELCOUNT),
ENTRY(FLAGS_1),
ENTRY(VERSYM),
ENTRY(VERDEF),
ENTRY(VERDEFNUM),
ENTRY(VERNEED),
ENTRY(VERNEEDNUM),
ENTRY(AUXILIARY),
ENTRY(FILTER),
ENTRY(ANDROID_REL_OFFSET),
ENTRY(ANDROID_REL_SIZE),
ENTRY(ANDROID_REL),
ENTRY(ANDROID_RELSZ),
ENTRY(ANDROID_RELA),
ENTRY(ANDROID_RELASZ),
ENTRY(ANDROID_RELR),
ENTRY(ANDROID_RELRSZ),
ENTRY(ANDROID_RELRENT),
ENTRY(ANDROID_RELRCOUNT),
ENTRY(MIPS_RLD_VERSION),
ENTRY(MIPS_TIME_STAMP),
ENTRY(MIPS_ICHECKSUM),
ENTRY(MIPS_IVERSION),
ENTRY(MIPS_FLAGS),
ENTRY(MIPS_BASE_ADDRESS),
ENTRY(MIPS_MSYM),
ENTRY(MIPS_CONFLICT),
ENTRY(MIPS_LIBLIST),
ENTRY(MIPS_LOCAL_GOTNO),
ENTRY(MIPS_CONFLICTNO),
ENTRY(MIPS_LIBLISTNO),
ENTRY(MIPS_SYMTABNO),
ENTRY(MIPS_UNREFEXTNO),
ENTRY(MIPS_GOTSYM),
ENTRY(MIPS_HIPAGENO),
ENTRY(MIPS_RLD_MAP),
ENTRY(MIPS_DELTA_CLASS),
ENTRY(MIPS_DELTA_CLASS_NO),
ENTRY(MIPS_DELTA_INSTANCE),
ENTRY(MIPS_DELTA_INSTANCE_NO),
ENTRY(MIPS_DELTA_RELOC),
ENTRY(MIPS_DELTA_RELOC_NO),
ENTRY(MIPS_DELTA_SYM),
ENTRY(MIPS_DELTA_SYM_NO),
ENTRY(MIPS_DELTA_CLASSSYM),
ENTRY(MIPS_DELTA_CLASSSYM_NO),
ENTRY(MIPS_CXX_FLAGS),
ENTRY(MIPS_PIXIE_INIT),
ENTRY(MIPS_SYMBOL_LIB),
ENTRY(MIPS_LOCALPAGE_GOTIDX),
ENTRY(MIPS_LOCAL_GOTIDX),
ENTRY(MIPS_HIDDEN_GOTIDX),
ENTRY(MIPS_PROTECTED_GOTIDX),
ENTRY(MIPS_OPTIONS),
ENTRY(MIPS_INTERFACE),
ENTRY(MIPS_DYNSTR_ALIGN),
ENTRY(MIPS_INTERFACE_SIZE),
ENTRY(MIPS_RLD_TEXT_RESOLVE_ADDR),
ENTRY(MIPS_PERF_SUFFIX),
ENTRY(MIPS_COMPACT_SIZE),
ENTRY(MIPS_GP_VALUE),
ENTRY(MIPS_AUX_DYNAMIC),
ENTRY(MIPS_PLTGOT),
ENTRY(MIPS_RWPLT),
ENTRY(MIPS_RLD_MAP_REL),
ENTRY(MIPS_XHASH),
ENTRY(AARCH64_BTI_PLT),
ENTRY(AARCH64_PAC_PLT),
ENTRY(AARCH64_VARIANT_PCS),
ENTRY(AARCH64_MEMTAG_MODE),
ENTRY(AARCH64_MEMTAG_HEAP),
ENTRY(AARCH64_MEMTAG_STACK),
ENTRY(AARCH64_MEMTAG_GLOBALS),
ENTRY(AARCH64_MEMTAG_GLOBALSSZ),
ENTRY(HEXAGON_SYMSZ),
ENTRY(HEXAGON_VER),
ENTRY(HEXAGON_PLT),
ENTRY(PPC_GOT),
ENTRY(PPC_OPT),
ENTRY(PPC64_GLINK),
ENTRY(PPC64_OPT),
ENTRY(RISCV_VARIANT_CC),
ENTRY(X86_64_PLT),
ENTRY(X86_64_PLTSZ),
ENTRY(X86_64_PLTENT),
ENTRY(IA_64_PLT_RESERVE),
ENTRY(IA_64_VMS_SUBTYPE),
ENTRY(IA_64_VMS_IMGIOCNT),
ENTRY(IA_64_VMS_LNKFLAGS),
ENTRY(IA_64_VMS_VIR_MEM_BLK_SIZ),
ENTRY(IA_64_VMS_IDENT),
ENTRY(IA_64_VMS_NEEDED_IDENT),
ENTRY(IA_64_VMS_IMG_RELA_CNT),
ENTRY(IA_64_VMS_SEG_RELA_CNT),
ENTRY(IA_64_VMS_FIXUP_RELA_CNT),
ENTRY(IA_64_VMS_FIXUP_NEEDED),
ENTRY(IA_64_VMS_SYMVEC_CNT),
ENTRY(IA_64_VMS_XLATED),
ENTRY(IA_64_VMS_STACKSIZE),
ENTRY(IA_64_VMS_UNWINDSZ),
ENTRY(IA_64_VMS_UNWIND_CODSEG),
ENTRY(IA_64_VMS_UNWIND_INFOSEG),
ENTRY(IA_64_VMS_LINKTIME),
ENTRY(IA_64_VMS_SEG_NO),
ENTRY(IA_64_VMS_SYMVEC_OFFSET),
ENTRY(IA_64_VMS_SYMVEC_SEG),
ENTRY(IA_64_VMS_UNWIND_OFFSET),
ENTRY(IA_64_VMS_UNWIND_SEG),
ENTRY(IA_64_VMS_STRTAB_OFFSET),
ENTRY(IA_64_VMS_SYSVER_OFFSET),
ENTRY(IA_64_VMS_IMG_RELA_OFF),
ENTRY(IA_64_VMS_SEG_RELA_OFF),
ENTRY(IA_64_VMS_FIXUP_RELA_OFF),
ENTRY(IA_64_VMS_PLTGOT_OFFSET),
ENTRY(IA_64_VMS_PLTGOT_SEG),
ENTRY(IA_64_VMS_FPMODE),
};
#undef ENTRY
if (auto it = enums2str.find(tag); it != enums2str.end()) {
return it->second;
}
return "UNKNOWN";
}
}