/* Chrysalide - Outil d'analyse de fichiers binaires * operand.c - gestion générique des opérandes * * Copyright (C) 2008-2025 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "operand.h" #include #include "operand-int.h" #include "../common/fnv1a.h" #include "../common/sort.h" #include "../glibext/comparable-int.h" #include "../glibext/hashable-int.h" #include "../glibext/serialize-int.h" #include "../glibext/singleton-int.h" #include "../glibext/strbuilder-int.h" /* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ /* Initialise la classe générique des opérandes. */ static void g_arch_operand_class_init(GArchOperandClass *); /* Procède à l'initialisation de l'interface de comparaison. */ static void g_arch_operand_comparable_object_iface_init(GComparableObjectInterface *); /* Procède à l'initialisation de l'interface de détermination. */ static void g_arch_operand_hashable_object_iface_init(GHashableObjectInterface *); /* Procède à l'initialisation de l'interface de sérialisation. */ static void g_arch_operand_serializable_iface_init(GSerializableObjectInterface *); /* Procède à l'initialisation de l'interface de rassemblement. */ static void g_arch_operand_singleton_candidate_iface_init(GSingletonCandidateInterface *); /* Procède à l'initialisation de l'interface d'exportation. */ static void g_arch_operand_string_builder_iface_init(GStringBuilderInterface *); /* Initialise une instance d'opérande d'architecture. */ static void g_arch_operand_init(GArchOperand *); /* Supprime toutes les références externes. */ static void g_arch_operand_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ static void g_arch_operand_finalize(GObject *); /* ---------------------- COMPARAISON DETAILLEE DE DEUX OBJETS ---------------------- */ /* Réalise une comparaison étendue entre objets. */ static int g_arch_operand_compare(const GComparableObject *, const GComparableObject *); /* ---------------------- CALCUL D'UNE EMPREINTE DE L'INSTANCE ---------------------- */ /* Calcule l'empreinte sur 32 bits d'un objet. */ static guint g_arch_operand_hash(const GHashableObject *); /* ------------------- MECANISMES DE CONSERVATION ET RESTAURATION ------------------- */ /* Charge un objet depuis un flux de données. */ static bool g_arch_operand_load(GSerializableObject *, GObjectStorage *, int); /* Sauvegarde un objet dans un flux de données. */ static bool g_arch_operand_store(const GSerializableObject *, GObjectStorage *, int); /* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */ /* Marque un candidat comme figé. */ static void g_arch_operand_mark_as_read_only(GSingletonCandidate *); /* Indique si le candidat est figé. */ static bool g_arch_operand_is_read_only(const GSingletonCandidate *); /* ---------------------------------------------------------------------------------- */ /* DEFINITION D'OPERANDE QUELCONQUE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un opérande d'architecture. */ G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_THICK_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_OBJECT, g_arch_operand_comparable_object_iface_init) G_IMPLEMENT_INTERFACE(G_TYPE_HASHABLE_OBJECT, g_arch_operand_hashable_object_iface_init) G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_operand_serializable_iface_init) G_IMPLEMENT_INTERFACE(G_TYPE_SINGLETON_CANDIDATE, g_arch_operand_singleton_candidate_iface_init) G_IMPLEMENT_INTERFACE(G_TYPE_STRING_BUILDER, g_arch_operand_string_builder_iface_init)); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe générique des opérandes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_class_init(GArchOperandClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = g_arch_operand_dispose; object->finalize = g_arch_operand_finalize; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de comparaison. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_comparable_object_iface_init(GComparableObjectInterface *iface) { iface->compare = g_arch_operand_compare; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de détermination. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_hashable_object_iface_init(GHashableObjectInterface *iface) { iface->hash = g_arch_operand_hash; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de sérialisation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_serializable_iface_init(GSerializableObjectInterface *iface) { iface->load = g_arch_operand_load; iface->store = g_arch_operand_store; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de rassemblement. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_singleton_candidate_iface_init(GSingletonCandidateInterface *iface) { iface->list_inner = NULL; iface->update_inner = NULL; iface->mark_as_ro = g_arch_operand_mark_as_read_only; iface->is_ro = g_arch_operand_is_read_only; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface d'exportation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_string_builder_iface_init(GStringBuilderInterface *iface) { iface->to_string = NULL; } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande d'architecture. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_init(GArchOperand *operand) { } /****************************************************************************** * * * Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_dispose(GObject *object) { G_OBJECT_CLASS(g_arch_operand_parent_class)->dispose(object); } /****************************************************************************** * * * Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_finalize(GObject *object) { G_OBJECT_CLASS(g_arch_operand_parent_class)->finalize(object); } /****************************************************************************** * * * Paramètres : operand = opérande à venir modifier. * * flag = drapeau d'information complémentaire à planter. * * * * Description : Ajoute une information complémentaire à un opérande. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_arch_operand_set_flag(GArchOperand *operand, ArchOperandFlag flag) { bool result; /* Bilan à retourner */ operand_extra_data_t extra; /* Données insérées à modifier */ assert(flag <= AOF_HIGH_USER); extra = GET_ARCH_OP_EXTRA(operand); result = !(extra.flags & flag); extra.flags |= flag; SET_ARCH_OP_EXTRA(operand, &extra); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à venir modifier. * * flag = drapeau d'information complémentaire à planter. * * * * Description : Retire une information complémentaire à un opérande. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_arch_operand_unset_flag(GArchOperand *operand, ArchOperandFlag flag) { bool result; /* Bilan à retourner */ operand_extra_data_t extra; /* Données insérées à modifier */ assert(flag <= AOF_HIGH_USER); extra = GET_ARCH_OP_EXTRA(operand); result = (extra.flags & flag); extra.flags &= ~flag; SET_ARCH_OP_EXTRA(operand, &extra); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à venir consulter. * * flag = drapeau d'information à rechercher. * * * * Description : Détermine si un opérande possède un fanion particulier. * * * * Retour : Bilan de la détection. * * * * Remarques : - * * * ******************************************************************************/ bool g_arch_operand_has_flag(const GArchOperand *operand, ArchOperandFlag flag) { bool result; /* Bilan à retourner */ operand_extra_data_t extra; /* Données insérées à modifier */ assert(flag <= AOF_HIGH_USER); extra = GET_ARCH_OP_EXTRA(operand); result = (extra.flags & flag); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à venir consulter. * * * * Description : Fournit les particularités de l'opérande. * * * * Retour : Somme de tous les fanions associés à l'opérande. * * * * Remarques : - * * * ******************************************************************************/ ArchOperandFlag g_arch_operand_get_flags(const GArchOperand *operand) { ArchOperandFlag result; /* Fanions à retourner */ operand_extra_data_t extra; /* Données insérées à modifier */ extra = GET_ARCH_OP_EXTRA(operand); result = extra.flags; return result; } #if 0 /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * target = instruction à venir retrouver. * * * * Description : Détermine le chemin conduisant à un opérande interne. * * * * Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. * * * * Remarques : - * * * ******************************************************************************/ char *g_arch_operand_find_inner_operand_path(const GArchOperand *operand, const GArchOperand *target) { char *result; /* Chemin à retourner */ GArchOperandClass *class; /* Classe associée à l'objet */ class = G_ARCH_OPERAND_GET_CLASS(operand); if (class->find_inner != NULL) result = class->find_inner(operand, target); else result = NULL; return result; } /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * path = chemin d'accès à un opérande à retrouver. * * * * Description : Obtient l'opérande correspondant à un chemin donné. * * * * Retour : Opérande trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *operand, const char *path) { GArchOperand *result; /* Opérande trouvée à renvoyer */ GArchOperandClass *class; /* Classe associée à l'objet */ class = G_ARCH_OPERAND_GET_CLASS(operand); if (class->get_inner != NULL) result = class->get_inner(operand, path); else result = NULL; return result; } #endif /* ---------------------------------------------------------------------------------- */ /* COMPARAISON DETAILLEE DE DEUX OBJETS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : object = premier objet à consulter pour une comparaison. * * other = second objet à consulter pour une comparaison. * * * * Description : Réalise une comparaison étendue entre objets. * * * * Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ static int g_arch_operand_compare(const GComparableObject *object, const GComparableObject *other) { int result; /* Bilan à retourner */ operand_extra_data_t extra_op; /* Données insérées à consulter*/ operand_extra_data_t extra_other; /* Données insérées à consulter*/ extra_op = GET_ARCH_OP_EXTRA(object); extra_other = GET_ARCH_OP_EXTRA(other); result = sort_unsigned_long(extra_op.flags, extra_other.flags); return result; } /* ---------------------------------------------------------------------------------- */ /* CALCUL D'UNE EMPREINTE DE L'INSTANCE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : object = objet dont l'instance est à consulter. * * * * Description : Calcule l'empreinte sur 32 bits d'un objet. * * * * Retour : Valeur de représentation, unique pour l'objet ou non. * * * * Remarques : - * * * ******************************************************************************/ static guint g_arch_operand_hash(const GHashableObject *object) { guint result; /* Valeur à retourner */ const char *name; /* Désignation du type d'object*/ fnv64_t name_hash; /* Empreinte du nom */ operand_extra_data_t extra; /* Données insérées à consulter*/ name = G_OBJECT_TYPE_NAME(G_OBJECT(object)); name_hash = fnv_64a_hash(name); result = (name_hash & 0xffffffff); result ^= (name_hash >> 32); extra = GET_ARCH_OP_EXTRA(object); result ^= extra.flags; return result; } /* ---------------------------------------------------------------------------------- */ /* MECANISMES DE CONSERVATION ET RESTAURATION */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : object = élément GLib à constuire. * * storage = conservateur de données à manipuler. * * fd = flux ouvert en lecture. * * * * Description : Charge un objet depuis un flux de données. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_arch_operand_load(GSerializableObject *object, GObjectStorage *storage, int fd) { bool result; /* Bilan à retourner */ uleb128_t extra; /* Données embarquées */ result = load_uleb128(&extra, fd); if (result) g_thick_object_set_extra(G_THICK_OBJECT(object), extra); return result; } /****************************************************************************** * * * Paramètres : object = élément GLib à consulter. * * storage = conservateur de données à manipuler. * * fd = flux ouvert en écriture. * * * * Description : Sauvegarde un objet dans un flux de données. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_arch_operand_store(const GSerializableObject *object, GObjectStorage *storage, int fd) { bool result; /* Bilan à retourner */ guint extra; /* Données embarquées */ extra = g_thick_object_get_extra(G_THICK_OBJECT(object)); result = store_uleb128((uleb128_t []) { extra }, fd); return result; } /* ---------------------------------------------------------------------------------- */ /* CONTROLE DU VOLUME DES INSTANCES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : candidate = objet dont l'instance se veut unique. * * * * Description : Marque un candidat comme figé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_mark_as_read_only(GSingletonCandidate *candidate) { GArchOperand *operand; /* Version spécialisée */ operand = G_ARCH_OPERAND(candidate); g_arch_operand_set_flag(operand, AOF_READ_ONLY); } /****************************************************************************** * * * Paramètres : operand = objet dont l'instance se veut unique. * * * * Description : Indique si le candidat est figé. * * * * Retour : true si le contenu du candidat ne peut plus être modifié. * * * * Remarques : - * * * ******************************************************************************/ static bool g_arch_operand_is_read_only(const GSingletonCandidate *candidate) { bool result; /* Etat à retourner */ GArchOperand *operand; /* Version spécialisée */ operand = G_ARCH_OPERAND(candidate); result = g_arch_operand_has_flag(operand, AOF_READ_ONLY); return result; }