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/utils.hpp"
#include "LIEF/COFF/Symbol.hpp"
#include "LIEF/COFF/String.hpp"
#include "LIEF/COFF/AuxiliarySymbol.hpp"

#include "LIEF/BinaryStream/BinaryStream.hpp"

#include "COFF/structures.hpp"

#include "logging.hpp"
#include "internal_utils.hpp"
#include "frozen.hpp"

namespace LIEF::COFF {

Symbol::Symbol() = default;
Symbol::Symbol(Symbol&&) = default;
Symbol& Symbol::operator=(Symbol&&) = default;

Symbol::~Symbol() = default;
Symbol::Symbol(const Symbol& other) :
  LIEF::Symbol(other),
  type_(other.type_),
  storage_class_(other.storage_class_),
  section_idx_(other.section_idx_) {
  if (!other.auxiliary_symbols_.empty()) {
    auxiliary_symbols_.reserve(other.auxiliary_symbols_.size());
    for (const std::unique_ptr<AuxiliarySymbol>& aux : other.auxiliary_symbols_) {
      auxiliary_symbols_.push_back(aux->clone());
    }
  }
}

Symbol& Symbol::operator=(const Symbol& other) {
  if (this == &other) {
    return *this;
  }
  LIEF::Symbol::operator=(other);
  type_ = other.type_;
  storage_class_ = other.storage_class_;
  section_idx_ = other.section_idx_;

  if (!other.auxiliary_symbols_.empty()) {
    auxiliary_symbols_.reserve(other.auxiliary_symbols_.size());
    for (const std::unique_ptr<AuxiliarySymbol>& aux : other.auxiliary_symbols_) {
      auxiliary_symbols_.push_back(aux->clone());
    }
  }

  return *this;
}

std::unique_ptr<Symbol> Symbol::parse(parsing_context_t& ctx, BinaryStream& stream,
                                      size_t* idx) {
  return ctx.is_bigobj ? parse_impl<details::symbol32>(ctx, stream, idx) :
                         parse_impl<details::symbol16>(ctx, stream, idx);
}

template<class T>
std::unique_ptr<Symbol> Symbol::parse_impl(parsing_context_t& ctx,
                                           BinaryStream& stream, size_t* idx) {
  static_assert(std::is_same_v<T, details::symbol16> ||
                std::is_same_v<T, details::symbol32>);
  auto raw = stream.read<T>();
  if (!raw) {
    return nullptr;
  }
  auto sym = std::make_unique<Symbol>();
  sym->value(raw->value);
  sym->type(raw->type);
  sym->storage_class(raw->storage_class);
  sym->section_idx_ = raw->sec_idx;

  if (raw->name.offset.zeroes == 0) {
    sym->coff_name_ = ctx.find_string(raw->name.offset.offset);
  } else {
    sym->name_ =
        std::string(raw->name.short_name.data(), raw->name.short_name.size());
    sym->name_ = sym->name_.c_str();
  }

  *idx += raw->nb_aux + 1;

  for (size_t i = 0; i < raw->nb_aux; ++i) {
    std::vector<uint8_t> raw_aux;
    if (!stream.read_data(raw_aux, sizeof(T))) {
      return sym;
    }

    auto aux = AuxiliarySymbol::parse(*sym, std::move(raw_aux));
    if (aux == nullptr) {
      LIEF_WARN("Failed to parse auxiliary symbol #{}", i);
      continue;
    }

    sym->add_aux(std::move(aux));
  }

  return sym;
}

const std::string& Symbol::name() const {
  if (coff_name_ != nullptr) {
    return coff_name_->str();
  }
  return name_;
}

std::string& Symbol::name() {
  if (coff_name_ != nullptr) {
    return const_cast<std::string&>(coff_name_->str());
  }
  return name_;
}


std::string Symbol::demangled_name() const {
  logging::needs_lief_extended();

  if constexpr (lief_extended) {
    return LIEF::demangle(name()).value_or("");
  } else {
    return "";
  }
}

std::string Symbol::to_string() const {
  std::ostringstream os;
  os << "Symbol {\n";
  os << "  Name: " << name() << '\n'
     << "  Value: " << value() << '\n'
     << "  Section index: " << section_idx() << '\n'
     << fmt::format("  Base type: {} ({})\n", COFF::to_string(base_type()),
                    (int)base_type())
     << fmt::format("  Complex type: {} ({})\n", COFF::to_string(complex_type()),
                    (int)complex_type())
     << fmt::format("  Storage class: {} ({})\n", COFF::to_string(storage_class()),
                    (int)storage_class())
     << "  Nb auxiliary symbols: " << auxiliary_symbols().size() << '\n';
  for (const AuxiliarySymbol& aux : auxiliary_symbols()) {
    os << indent(aux.to_string(), 2) << '\n';
  }
  os << "}\n";

  return os.str();
}

const char* to_string(Symbol::STORAGE_CLASS e) {
#define ENTRY(X) std::pair(Symbol::STORAGE_CLASS::X, #X)
  STRING_MAP enums2str{
      ENTRY(INVALID),
      ENTRY(END_OF_FUNCTION),
      ENTRY(NONE),
      ENTRY(AUTOMATIC),
      ENTRY(EXTERNAL),
      ENTRY(STATIC),
      ENTRY(REGISTER),
      ENTRY(EXTERNAL_DEF),
      ENTRY(LABEL),
      ENTRY(UNDEFINED_LABEL),
      ENTRY(MEMBER_OF_STRUCT),
      ENTRY(ARGUMENT),
      ENTRY(STRUCT_TAG),
      ENTRY(MEMBER_OF_UNION),
      ENTRY(UNION_TAG),
      ENTRY(TYPE_DEFINITION),
      ENTRY(UNDEFINED_STATIC),
      ENTRY(ENUM_TAG),
      ENTRY(MEMBER_OF_ENUM),
      ENTRY(REGISTER_PARAM),
      ENTRY(BIT_FIELD),
      ENTRY(BLOCK),
      ENTRY(FUNCTION),
      ENTRY(END_OF_STRUCT),
      ENTRY(FILE),
      ENTRY(SECTION),
      ENTRY(WEAK_EXTERNAL),
      ENTRY(CLR_TOKEN),
  };
#undef ENTRY

  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "NONE";
}

const char* to_string(Symbol::BASE_TYPE e) {
#define ENTRY(X) std::pair(Symbol::BASE_TYPE::TY_##X, #X)
  STRING_MAP enums2str{
      ENTRY(NULL),   ENTRY(VOID),  ENTRY(CHAR),  ENTRY(SHORT),
      ENTRY(INT),    ENTRY(LONG),  ENTRY(FLOAT), ENTRY(DOUBLE),
      ENTRY(STRUCT), ENTRY(UNION), ENTRY(ENUM),  ENTRY(MOE),
      ENTRY(BYTE),   ENTRY(WORD),  ENTRY(UINT),  ENTRY(DWORD),
  };
#undef ENTRY

  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "NONE";
}
const char* to_string(Symbol::COMPLEX_TYPE e) {

#define ENTRY(X) std::pair(Symbol::COMPLEX_TYPE::TY_##X, #X)
  STRING_MAP enums2str{
      ENTRY(NULL),
      ENTRY(POINTER),
      ENTRY(FUNCTION),
      ENTRY(ARRAY),
  };
#undef ENTRY

  if (auto it = enums2str.find(e); it != enums2str.end()) {
    return it->second;
  }
  return "NONE";
}


AuxiliarySymbol& Symbol::add_aux(std::unique_ptr<AuxiliarySymbol> sym) {
  auxiliary_symbols_.push_back(std::move(sym));
  return *auxiliary_symbols_.back();
}

}