/* Chrysalide - Outil d'analyse de fichiers binaires * immediate.c - opérandes représentant des valeurs numériques * * Copyright (C) 2009-2017 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 Foobar. If not, see . */ #include "immediate.h" #include #include #include #include #include #include #include #include #include #include "operand-int.h" #include "sharing/manager.h" #include "../common/asm.h" #include "../common/extstr.h" #include "../format/format.h" /* ------------------ MANIPULATION D'OPERANDES DE VALEUR IMMEDIATE ------------------ */ /* Définition d'un opérande de valeur numérique (instance) */ struct _GImmOperand { GArchOperand parent; /* Instance parente */ uint64_t raw; /* Valeur transtypée */ MemoryDataSize size; /* Taille de l'opérande */ ImmOperandDisplay def_display; /* Type par défaut d'affichage */ ImmOperandDisplay display; /* Format général d'affichage */ unsigned char misc; /* Informations diverses */ }; #define IMM_GET_DEF_ZERO_PADDING(op) ((op)->misc & (1 << 0)) #define IMM_SET_DEF_ZERO_PADDING(op, v) (op)->misc = ((op)->misc & ~(1 << 0)) | ((v) ? (1 << 0) : 0) #define IMM_HAS_ZERO_PADDING(op) ((op)->misc & (1 << 1)) #define IMM_SET_ZERO_PADDING(op) (op)->misc |= (1 << 1) #define IMM_GET_ZERO_PADDING_VALUE(op) ((op)->misc & (1 << 2)) #define IMM_SET_ZERO_PADDING_VALUE(op, v) (op)->misc = ((op)->misc & ~(1 << 2)) | ((v) ? (1 << 2) : 0) #define IMM_HAS_DISPLAY(op) ((op)->misc & (1 << 3)) #define IMM_SET_DISPLAY(op) (op)->misc |= (1 << 3) /* Définition d'un opérande de valeur numérique (classe) */ struct _GImmOperandClass { GArchOperandClass parent; /* Classe parente */ }; /* Initialise la classe des lignes de descriptions initiales. */ static void g_imm_operand_class_init(GImmOperandClass *); /* Initialise la classe des lignes de descriptions initiales. */ static void g_imm_operand_init(GImmOperand *); /* Supprime toutes les références externes. */ static void g_imm_operand_dispose(GImmOperand *); /* Procède à la libération totale de la mémoire. */ static void g_imm_operand_finalize(GImmOperand *); /* Initialise un nouvel objet partagé avec des informations. */ static bool g_imm_operand_do_init(GImmOperand *, const GImmOperand *); /* Réalise une copie minimale d'un contenu partagé. */ static void g_imm_operand_quickly_copy(const GImmOperand *, GImmOperand *); /* Compare un opérande avec un autre. */ static int g_imm_operand_compare(const GImmOperand * const *, const GImmOperand * const *); /* Indique si une valeur est complétée par des zéros. */ static bool g_imm_operand_does_padding_for_display(const GImmOperand *, ImmOperandDisplay); /* Construit la chaîne de caractères correspondant à l'opérande. */ static size_t _g_imm_operand_to_string(const GImmOperand *, AsmSyntax, ImmOperandDisplay, char [IMM_MAX_SIZE]); /* Traduit un opérande en version humainement lisible. */ static void g_imm_operand_print(const GImmOperand *, GBufferLine *, AsmSyntax); /* Construit un petit résumé concis de l'opérande. */ static char *g_imm_operand_build_tooltip(const GImmOperand *, const GLoadedBinary *); /* -------------------------- PARTAGES DE CONTENUS UNIQUES -------------------------- */ /* Gestionnaire des partages d'instances */ static GShareManager *_imm_operand_manager = NULL; /* ---------------------------------------------------------------------------------- */ /* MANIPULATION D'OPERANDES DE VALEUR IMMEDIATE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un opérande de valeur numérique. */ G_DEFINE_TYPE(GImmOperand, g_imm_operand, G_TYPE_ARCH_OPERAND); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des lignes de descriptions initiales. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_imm_operand_class_init(GImmOperandClass *klass) { GObjectClass *object; /* Autre version de la classe */ GArchOperandClass *operand; /* Version de classe parente */ object = G_OBJECT_CLASS(klass); operand = G_ARCH_OPERAND_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_imm_operand_dispose; object->finalize = (GObjectFinalizeFunc)g_imm_operand_finalize; operand->init = (operand_do_init_fc)g_imm_operand_do_init; operand->qck_copy = (operand_qck_copy_fc)g_imm_operand_quickly_copy; operand->compare = (operand_compare_fc)g_imm_operand_compare; operand->print = (operand_print_fc)g_imm_operand_print; operand->build_tooltip = (operand_build_tooltip_fc)g_imm_operand_build_tooltip; } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise la classe des lignes de descriptions initiales. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_imm_operand_init(GImmOperand *operand) { operand->def_display = IOD_HEX; operand->misc = 0; IMM_SET_DEF_ZERO_PADDING(operand, false); } /****************************************************************************** * * * Paramètres : operand = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_imm_operand_dispose(GImmOperand *operand) { G_OBJECT_CLASS(g_imm_operand_parent_class)->dispose(G_OBJECT(operand)); } /****************************************************************************** * * * Paramètres : operand = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_imm_operand_finalize(GImmOperand *operand) { G_OBJECT_CLASS(g_imm_operand_parent_class)->finalize(G_OBJECT(operand)); } /****************************************************************************** * * * Paramètres : size = taille de l'opérande souhaitée. * * content = flux de données à analyser. * * addr = position courante dans ce flux. [OUT] * * low = position éventuelle des 4 bits visés. [OUT] * * endian = ordre des bits dans la source. * * * * Description : Crée un opérande réprésentant une valeur numérique. * * * * Retour : Instruction mise en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *_g_imm_operand_new_from_data(MemoryDataSize size, const GBinContent *content, vmpa2t *addr, bool *low, SourceEndian endian) { GArchOperand *result; /* Opérande à retourner */ GImmOperand fake; /* Transport d'informations */ uint8_t uval8; /* Valeur sur 8 bits */ uint16_t uval16; /* Valeur sur 16 bits */ uint32_t uval32; /* Valeur sur 32 bits */ uint64_t uval64; /* Valeur sur 64 bits */ int8_t sval8; /* Valeur sur 8 bits */ int16_t sval16; /* Valeur sur 16 bits */ int32_t sval32; /* Valeur sur 32 bits */ int64_t sval64; /* Valeur sur 64 bits */ g_imm_operand_init(&fake); fake.size = size; switch (size) { case MDS_4_BITS_UNSIGNED: if (!g_binary_content_read_u4(content, addr, low, &uval8)) goto gionfd_error; fake.raw = uval8; break; case MDS_8_BITS_UNSIGNED: if (!g_binary_content_read_u8(content, addr, &uval8)) goto gionfd_error; fake.raw = uval8; break; case MDS_16_BITS_UNSIGNED: if (!g_binary_content_read_u16(content, addr, endian, &uval16)) goto gionfd_error; fake.raw = uval16; break; case MDS_32_BITS_UNSIGNED: if (!g_binary_content_read_u32(content, addr, endian, &uval32)) goto gionfd_error; fake.raw = uval32; break; case MDS_64_BITS_UNSIGNED: if (!g_binary_content_read_u64(content, addr, endian, &uval64)) goto gionfd_error; fake.raw = uval64; break; case MDS_4_BITS_SIGNED: if (!g_binary_content_read_s4(content, addr, low, &sval8)) goto gionfd_error; fake.raw = sval8; break; case MDS_8_BITS_SIGNED: if (!g_binary_content_read_s8(content, addr, &sval8)) goto gionfd_error; fake.raw = sval8; break; case MDS_16_BITS_SIGNED: if (!g_binary_content_read_s16(content, addr, endian, &sval16)) goto gionfd_error; fake.raw = sval16; break; case MDS_32_BITS_SIGNED: if (!g_binary_content_read_s32(content, addr, endian, &sval32)) goto gionfd_error; fake.raw = sval32; break; case MDS_64_BITS_SIGNED: if (!g_binary_content_read_s64(content, addr, endian, &sval64)) goto gionfd_error; fake.raw = sval64; break; case MDS_UNDEFINED: goto gionfd_error; break; } result = G_ARCH_OPERAND(g_share_manager_get(_imm_operand_manager, (GSharedInstance *)&fake)); return result; gionfd_error: return NULL; } /****************************************************************************** * * * Paramètres : size = taille de l'opérande souhaitée. * * value = valeur sur x bits à venir récupérer. * * * * Description : Crée un opérande réprésentant une valeur numérique. * * * * Retour : Instruction mise en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_imm_operand_new_from_value(MemoryDataSize size, uint64_t value) { GArchOperand *result; /* Opérande à retourner */ GImmOperand fake; /* Transport d'informations */ if (size == MDS_UNDEFINED) result = NULL; else { g_imm_operand_init(&fake); fake.size = size; fake.raw = value; result = G_ARCH_OPERAND(g_share_manager_get(_imm_operand_manager, (GSharedInstance *)&fake)); } return result; } /****************************************************************************** * * * Paramètres : operand = objet partagé à initialiser. * * template = coquille vide contenant les infos à enregistrer. * * * * Description : Initialise un nouvel objet partagé avec des informations. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_imm_operand_do_init(GImmOperand *operand, const GImmOperand *template) { g_imm_operand_quickly_copy(template, operand); return true; } /****************************************************************************** * * * Paramètres : operand = objet partagé à consulter. * * template = informations à retrouver intégralement. * * * * Description : Réalise une copie minimale d'un contenu partagé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_imm_operand_quickly_copy(const GImmOperand *operand, GImmOperand *template) { template->raw = operand->raw; template->size = operand->size; template->def_display = operand->def_display; template->display = operand->display; template->misc = operand->misc; } /****************************************************************************** * * * Paramètres : a = premier opérande à consulter. * * b = second opérande à consulter. * * * * Description : Compare un opérande avec un autre. * * * * Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ static int g_imm_operand_compare(const GImmOperand * const *a, const GImmOperand * const *b) { int result; /* Bilan à retourner */ const GImmOperand *imm_a; /* Accès simplifié à A */ const GImmOperand *imm_b; /* Accès simplifié à B */ imm_a = *a; imm_b = *b; if (imm_a->size < imm_b->size) { result = -1; goto gioc_done; } else if (imm_a->size > imm_b->size) { result = 1; goto gioc_done; } if (imm_a->raw < imm_b->raw) { result = -1; goto gioc_done; } else if (imm_a->raw > imm_b->raw) { result = 1; goto gioc_done; } if (imm_a->def_display < imm_b->def_display) { result = -1; goto gioc_done; } else if (imm_a->def_display > imm_b->def_display) { result = 1; goto gioc_done; } if (IMM_HAS_DISPLAY(imm_a) != IMM_HAS_DISPLAY(imm_b)) { result = (IMM_HAS_DISPLAY(imm_a) ? 1 : -1); goto gioc_done; } if (IMM_HAS_DISPLAY(imm_a)) { if (imm_a->display < imm_b->display) { result = -1; goto gioc_done; } else if (imm_a->display > imm_b->display) { result = 1; goto gioc_done; } } if (IMM_GET_DEF_ZERO_PADDING(imm_a) != IMM_GET_DEF_ZERO_PADDING(imm_b)) { result = (IMM_GET_DEF_ZERO_PADDING(imm_a) ? 1 : -1); goto gioc_done; } if (IMM_HAS_ZERO_PADDING(imm_a) != IMM_HAS_ZERO_PADDING(imm_b)) { result = (IMM_HAS_ZERO_PADDING(imm_a) ? 1 : -1); goto gioc_done; } if (IMM_HAS_ZERO_PADDING(imm_a)) { if (IMM_GET_ZERO_PADDING_VALUE(imm_a) != IMM_GET_ZERO_PADDING_VALUE(imm_b)) { result = (IMM_GET_ZERO_PADDING_VALUE(imm_a) ? 1 : -1); goto gioc_done; } } result = 0; gioc_done: return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Renseigne la taille de la valeur indiquée à la construction. * * * * Retour : Taille de la valeur représentée en mémoire. * * * * Remarques : - * * * ******************************************************************************/ MemoryDataSize g_imm_operand_get_size(const GImmOperand *operand) { return operand->size; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * size = taille de l'opérande souhaitée. * * ... = valeur sur x bits à venir récupérer. * * * * Description : Fournit la valeur portée par une opérande numérique. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_get_value(const GImmOperand *operand, MemoryDataSize size, ...) { bool result; /* Bilan à retourner */ va_list ap; /* Liste des compléments */ uint8_t *uval8; /* Valeur sur 8 bits */ uint16_t *uval16; /* Valeur sur 16 bits */ uint32_t *uval32; /* Valeur sur 32 bits */ uint64_t *uval64; /* Valeur sur 64 bits */ int8_t *sval8; /* Valeur sur 8 bits */ int16_t *sval16; /* Valeur sur 16 bits */ int32_t *sval32; /* Valeur sur 32 bits */ int64_t *sval64; /* Valeur sur 64 bits */ if (operand->size != size) return false; result = true; va_start(ap, size); switch (size) { /* Pour GCC... */ case MDS_UNDEFINED: result = false; break; case MDS_4_BITS_UNSIGNED: case MDS_8_BITS_UNSIGNED: uval8 = va_arg(ap, uint8_t *); *uval8 = operand->raw; break; case MDS_16_BITS_UNSIGNED: uval16 = va_arg(ap, uint16_t *); *uval16 = operand->raw; break; case MDS_32_BITS_UNSIGNED: uval32 = va_arg(ap, uint32_t *); *uval32 = operand->raw; break; case MDS_64_BITS_UNSIGNED: uval64 = va_arg(ap, uint64_t *); *uval64 = operand->raw; break; case MDS_4_BITS_SIGNED: case MDS_8_BITS_SIGNED: sval8 = va_arg(ap, int8_t *); *sval8 = operand->raw; break; case MDS_16_BITS_SIGNED: sval16 = va_arg(ap, int16_t *); *sval16 = operand->raw; break; case MDS_32_BITS_SIGNED: sval32 = va_arg(ap, int32_t *); *sval32 = operand->raw; break; case MDS_64_BITS_SIGNED: sval64 = va_arg(ap, int64_t *); *sval64 = operand->raw; break; } va_end(ap); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * * * Description : Fournit la valeur brute représentée par l'opérande. * * * * Retour : Valeur destinée à un usage interne. * * * * Remarques : - * * * ******************************************************************************/ uint64_t g_imm_operand_get_raw_value(const GImmOperand *operand) { return operand->raw; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à actualiser. [OUT]* * size = taille de l'opérande souhaitée. * * value = valeur sur x bits à venir récupérer. * * container = propriétaire d'origine à tenir au courant. * * * * Description : Définit la nouvelle valeur de l'opérande à une valeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_set_value(GImmOperand **operand, MemoryDataSize size, uint64_t value, GShareContainer *container) { GSharedInstance *shared; /* Instace de travail partagée */ GImmOperand fake; /* Transport d'informations */ assert(size != MDS_UNDEFINED); shared = G_SHARED_INSTANCE(*operand); g_shared_instance_quickly_copy(shared, (GSharedInstance *)&fake); fake.size = size; fake.raw = value; shared = g_share_manager_update(_imm_operand_manager, shared, (GSharedInstance *)&fake, container); *operand = G_IMM_OPERAND(shared); } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à actualiser. [OUT]* * state = true si des zéro sont à ajouter, false sinon. * * container = propriétaire d'origine à tenir au courant. * * * * Description : Précise si des zéro doivent compléter l'affichage ou non. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_pad_by_default(GImmOperand **operand, bool state, GShareContainer *container) { GSharedInstance *shared; /* Instace de travail partagée */ GImmOperand fake; /* Transport d'informations */ shared = G_SHARED_INSTANCE(*operand); g_shared_instance_quickly_copy(shared, (GSharedInstance *)&fake); IMM_SET_DEF_ZERO_PADDING(&fake, state); shared = g_share_manager_update(_imm_operand_manager, shared, (GSharedInstance *)&fake, container); *operand = G_IMM_OPERAND(shared); } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Indique si une valeur est complétée par des zéros par défaut.* * * * Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_does_padding_by_default(const GImmOperand *operand) { bool result; /* Statut à retourner */ result = IMM_GET_DEF_ZERO_PADDING(operand); return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à actualiser. [OUT]* * state = true si des zéro sont à ajouter, false sinon. * * container = propriétaire d'origine à tenir au courant. * * * * Description : Précise si des zéro doivent compléter l'affichage ou non. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_pad(GImmOperand **operand, bool state, GShareContainer *container) { GSharedInstance *shared; /* Instace de travail partagée */ GImmOperand fake; /* Transport d'informations */ shared = G_SHARED_INSTANCE(*operand); g_shared_instance_quickly_copy(shared, (GSharedInstance *)&fake); IMM_SET_ZERO_PADDING(&fake); IMM_SET_ZERO_PADDING_VALUE(&fake, state); shared = g_share_manager_update(_imm_operand_manager, shared, (GSharedInstance *)&fake, container); *operand = G_IMM_OPERAND(shared); } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Indique si une valeur est complétée par des zéros. * * * * Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_does_padding(const GImmOperand *operand) { bool result; /* Statut à retourner */ if (IMM_HAS_ZERO_PADDING(operand)) result = IMM_GET_ZERO_PADDING_VALUE(operand); else result = IMM_GET_DEF_ZERO_PADDING(operand); return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * display = type d'affichage à considérer. * * * * Description : Indique si une valeur est complétée par des zéros. * * * * Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_imm_operand_does_padding_for_display(const GImmOperand *operand, ImmOperandDisplay display) { bool result; /* Statut à retourner */ result = g_imm_operand_does_padding(operand); if (result) { display = g_imm_operand_get_display(operand); if (display != IOD_BIN && display != IOD_HEX) result = false; } return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à actualiser. [OUT]* * display = format global d'un affichage de valeur. * * container = propriétaire d'origine à tenir au courant. * * * * Description : Définit le format textuel par défaut de la valeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_set_default_display(GImmOperand **operand, ImmOperandDisplay display, GShareContainer *container) { GSharedInstance *shared; /* Instace de travail partagée */ GImmOperand fake; /* Transport d'informations */ shared = G_SHARED_INSTANCE(*operand); g_shared_instance_quickly_copy(shared, (GSharedInstance *)&fake); fake.def_display = display; shared = g_share_manager_update(_imm_operand_manager, shared, (GSharedInstance *)&fake, container); *operand = G_IMM_OPERAND(shared); } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Indique le format textuel par défaut de la valeur. * * * * Retour : Format global d'un affichage de valeur. * * * * Remarques : - * * * ******************************************************************************/ ImmOperandDisplay g_imm_operand_get_default_display(const GImmOperand *operand) { return operand->def_display; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à actualiser. [OUT]* * display = format global d'un affichage de valeur. * * container = propriétaire d'origine à tenir au courant. * * * * Description : Définit la grande ligne du format textuel de la valeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_set_display(GImmOperand **operand, ImmOperandDisplay display, GShareContainer *container) { GSharedInstance *shared; /* Instace de travail partagée */ GImmOperand fake; /* Transport d'informations */ shared = G_SHARED_INSTANCE(*operand); g_shared_instance_quickly_copy(shared, (GSharedInstance *)&fake); IMM_SET_DISPLAY(&fake); fake.display = display; shared = g_share_manager_update(_imm_operand_manager, shared, (GSharedInstance *)&fake, container); *operand = G_IMM_OPERAND(shared); } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Indique la grande ligne du format textuel de la valeur. * * * * Retour : Format global d'un affichage de valeur. * * * * Remarques : - * * * ******************************************************************************/ ImmOperandDisplay g_imm_operand_get_display(const GImmOperand *operand) { ImmOperandDisplay result; /* Affichage à retourner */ if (IMM_HAS_DISPLAY(operand)) result = operand->display; else result = operand->def_display; return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Indique le signe d'une valeur immédiate. * * * * Retour : true si la valeur est strictement négative, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_is_negative(const GImmOperand *operand) { bool result; /* Bilan à renvoyer */ switch (operand->size) { case MDS_4_BITS_SIGNED: case MDS_8_BITS_SIGNED: case MDS_16_BITS_SIGNED: case MDS_32_BITS_SIGNED: case MDS_64_BITS_SIGNED: /** * Pour les valeurs plus petites que 64 bits, le compilateur * réalise une extension de signe lors du transtypage. */ result = (operand->raw & 0x8000000000000000ll); break; default: result = false; break; } return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à consulter. * * * * Description : Indique si une valeur immédiate est nulle ou non. * * * * Retour : true si la valeur est nulle, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_is_null(const GImmOperand *operand) { return (operand->raw == 0ll); } /****************************************************************************** * * * Paramètres : operand = opérande à transcrire. * * syntax = type de représentation demandée. * * display = type d'affichage demandé. * * value = valeur portée par l'opérande transcrite. [OUT] * * * * Description : Construit la chaîne de caractères correspondant à l'opérande.* * * * Retour : Nombre de caractères utilisés. * * * * Remarques : - * * * ******************************************************************************/ static size_t _g_imm_operand_to_string(const GImmOperand *operand, AsmSyntax syntax, ImmOperandDisplay display, char value[IMM_MAX_SIZE]) { size_t result; /* Longueur à retourner */ unsigned int range; /* Catégorie de la taille */ const char *prefix; /* Entrée en matière */ const char *suffix; /* Sortie de matière */ const char *alternate; /* Préfixe de forme alternative*/ const char *intro; /* Introduction du formatage */ bool do_padding; /* Indication de bourrage */ const char *zpad; /* Remplissage par des zéros */ const char *lmod; /* Modification de longueur */ const char *conv; /* Opérateur de conversion */ char binval[65]; /* Conversion intégrée */ unsigned int max; /* Indice du plus fort bit */ unsigned int i; /* Boucle de parcours */ char format[16 + 65]; /* Format d'impression final */ static const char *zpad_defs[] = { "", "02", "04", "08", "016" }; static const char *lmod_defs[] = { "hh", "hh", "h", "", __PRI64_PREFIX }; static const char *conv_si_defs[] = { "", "o", "d", "x", "c" }; static const char *conv_us_defs[] = { "", "o", "u", "x", "c" }; assert(display <= IOD_LAST_VALID); range = MDS_RANGE(operand->size); /* Encadrement pour les caractères */ if (display == IOD_CHAR) { prefix = (syntax == ASX_ATT ? "$'" : "'"); suffix = "'"; } else { prefix = (syntax == ASX_ATT ? "$" : ""); suffix = ""; } /* Préfix de forme '0x', 'b' ou '0' */ switch (display) { case IOD_BIN: alternate = "b"; break; case IOD_OCT: alternate = "0"; break; case IOD_HEX: alternate = "0x"; break; default: alternate = ""; break; } /* Va-t-on réellement avoir besoin d'un formatage ? */ if (display != IOD_BIN) intro = "%"; else intro = ""; /* Drapeau de remplissage ? */ do_padding = g_imm_operand_does_padding_for_display(operand, display); switch (display) { case IOD_BIN: case IOD_CHAR: case IOD_OCT: case IOD_DEC: zpad = ""; break; default: zpad = (do_padding ? zpad_defs[range] : ""); break; } /* Modification de la longueur fournie */ if (display != IOD_BIN) lmod = lmod_defs[range]; else lmod = ""; /* Spécification de la conversion */ if (display != IOD_BIN) { if (MDS_IS_SIGNED(operand->size)) conv = conv_si_defs[display]; else conv = conv_us_defs[display]; } else { if (do_padding) max = range * 8; else { if (!msb_64(operand->raw, &max)) { conv = "0"; max = 0; } } if (max > 0) { conv = binval; for (i = max; i > 0; i--) binval[max - i] = (operand->raw & (1llu << (i - 1)) ? '1' : '0'); binval[max] = '\0'; } } /* Impression finale */ snprintf(format, sizeof(format), "%s%s%s%s%s%s%s", prefix, alternate, intro, zpad, lmod, conv, suffix); switch (operand->size) { case MDS_UNDEFINED: result = snprintf(value, IMM_MAX_SIZE, ""); break; case MDS_4_BITS_UNSIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (uint8_t)operand->raw); break; case MDS_8_BITS_UNSIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (uint8_t)operand->raw); break; case MDS_16_BITS_UNSIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (uint16_t)operand->raw); break; case MDS_32_BITS_UNSIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (uint32_t)operand->raw); break; case MDS_64_BITS_UNSIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (uint64_t)operand->raw); break; case MDS_4_BITS_SIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (int8_t)operand->raw); break; case MDS_8_BITS_SIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (int8_t)operand->raw); break; case MDS_16_BITS_SIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (int16_t)operand->raw); break; case MDS_32_BITS_SIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (int32_t)operand->raw); break; case MDS_64_BITS_SIGNED: result = snprintf(value, IMM_MAX_SIZE, format, (int64_t)operand->raw); break; default: assert(false); result = 0; break; } assert(result > 0); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à transcrire. * * syntax = type de représentation demandée. * * value = valeur portée par l'opérande transcrite. [OUT] * * * * Description : Construit la chaîne de caractères correspondant à l'opérande.* * * * Retour : Nombre de caractères utilisés. * * * * Remarques : - * * * ******************************************************************************/ size_t g_imm_operand_to_string(const GImmOperand *operand, AsmSyntax syntax, char value[IMM_MAX_SIZE]) { size_t result; /* Longueur à retourner */ ImmOperandDisplay display; /* Type d'affichage courant */ display = g_imm_operand_get_display(operand); result = _g_imm_operand_to_string(operand, syntax, display, value); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * line = ligne tampon où imprimer l'opérande donné. * * syntax = type de représentation demandée. * * * * Description : Traduit un opérande en version humainement lisible. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_imm_operand_print(const GImmOperand *operand, GBufferLine *line, AsmSyntax syntax) { char value[IMM_MAX_SIZE]; /* Chaîne à imprimer */ size_t len; /* Taille de l'élément inséré */ len = g_imm_operand_to_string(operand, syntax, value); g_buffer_line_append_text(line, BLC_MAIN, value, len, RTT_IMMEDIATE, G_OBJECT(operand)); } /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * binary = informations relatives au binaire chargé. * * * * Description : Construit un petit résumé concis de l'opérande. * * * * Retour : Chaîne de caractères à libérer après usage ou NULL. * * * * Remarques : - * * * ******************************************************************************/ static char *g_imm_operand_build_tooltip(const GImmOperand *operand, const GLoadedBinary *binary) { char *result; /* Description à retourner */ char value[IMM_MAX_SIZE]; /* Conversion artificielle */ char *conv; /* Affichage de la Conversion */ if (operand->raw <= UCHAR_MAX && isprint(operand->raw)) switch (operand->raw) { case '&': asprintf(&result, _("Character: '&'")); break; case '<': asprintf(&result, _("Character: '<'")); break; case '>': asprintf(&result, _("Character: '>'")); break; default: asprintf(&result, _("Character: '%c'"), (char)operand->raw); break; } else asprintf(&result, _("Character: <not printable>")); /* Binaire */ _g_imm_operand_to_string(operand, ASX_INTEL, IOD_BIN, value); asprintf(&conv, _("Binary: %s"), value); result = stradd(result, "\n"); result = stradd(result, conv); free(conv); /* Octal */ _g_imm_operand_to_string(operand, ASX_INTEL, IOD_OCT, value); asprintf(&conv, _("Octal: %s"), value); result = stradd(result, "\n"); result = stradd(result, conv); free(conv); /* Décimal */ _g_imm_operand_to_string(operand, ASX_INTEL, IOD_DEC, value); asprintf(&conv, _("Decimal: %s"), value); result = stradd(result, "\n"); result = stradd(result, conv); free(conv); /* Hexadécimal */ _g_imm_operand_to_string(operand, ASX_INTEL, IOD_HEX, value); asprintf(&conv, _("Hexadecimal: %s"), value); result = stradd(result, "\n"); result = stradd(result, conv); free(conv); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * pos = valeur résultante. [OUT] * * * * Description : Convertit une valeur immédiate en position de type phys_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_to_phys_t(const GImmOperand *operand, phys_t *pos) { bool result; /* Bilan à renvoyer */ result = !MDS_IS_SIGNED(operand->size); if (result) *pos = operand->raw; return result; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * addr = valeur résultante. [OUT] * * * * Description : Convertit une valeur immédiate en adresse de type virt_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_to_virt_t(const GImmOperand *operand, virt_t *addr) { bool result; /* Bilan à renvoyer */ result = !MDS_IS_SIGNED(operand->size); if (result) *addr = operand->raw; return result; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * val = valeur résultante. [OUT] * * * * Description : Convertit une valeur immédiate en valeur de type leb128_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_as_leb128(const GImmOperand *operand, leb128_t *val) { *val = operand->raw; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * val = valeur résultante. [OUT] * * * * Description : Convertit une valeur immédiate en valeur de type uleb128_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ void g_imm_operand_as_uleb128(const GImmOperand *operand, uleb128_t *val) { *val = operand->raw; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * addr = valeur résultante. [OUT] * * * * Description : Convertit une valeur immédiate en adresse de type vmpa_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_to_vmpa_t(const GImmOperand *operand, vmpa_t *addr) { return false; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * value = valeur résultante. [OUT] * * negative = indique si la valeur était négative à l'origine. * * * * Description : Convertit une valeur immédiate en valeur de type size_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_to_size_t(const GImmOperand *operand, size_t *value, bool *negative) { return false; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * value = valeur résultante. [OUT] * * negative = indique si la valeur était négative à l'origine. * * * * Description : Convertit une valeur immédiate en valeur de type off_t. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_imm_operand_to_off_t(const GImmOperand *operand, off_t *value, bool *negative) { return false; } /* ---------------------------------------------------------------------------------- */ /* PARTAGES DE CONTENUS UNIQUES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : - * * * * Description : Initialise les mécanismes de partage d'opérandes immédiates. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool init_imm_operand_sharing(void) { _imm_operand_manager = g_share_manager_new(G_TYPE_IMM_OPERAND); return true; } /****************************************************************************** * * * Paramètres : - * * * * Description : Imprime des statistiques quant aux partages dans l'archi. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ #ifdef DEBUG_DUMP_STATS void dump_imm_operand_share_stats(void) { g_share_manager_dump_stats(_imm_operand_manager); } #endif /****************************************************************************** * * * Paramètres : - * * * * Description : Supprime les mécanismes de partage des opérandes immédiates. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void exit_imm_operand_sharing(void) { g_object_unref(G_OBJECT(_imm_operand_manager)); }