/* OpenIDA - Outil d'analyse de fichiers binaires * instruction.c - gestion générique des instructions * * Copyright (C) 2008-2012 Cyrille Bagard * * This file is part of OpenIDA. * * OpenIDA 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. * * OpenIDA 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 "instruction.h" #include #include "instruction-int.h" #include "../common/extstr.h" /* Initialise la classe générique des instructions. */ static void g_arch_instruction_class_init(GArchInstructionClass *); /* Initialise une instance d'opérande d'architecture. */ static void g_arch_instruction_init(GArchInstruction *); /* --------------------- CONVERSIONS DU FORMAT DES INSTRUCTIONS --------------------- */ /* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */ static void _g_arch_instruction_print(const GArchInstruction *, GCodeBuffer *, MemoryDataSize, const bin_t *, AsmSyntax); /* Indique le type défini pour une instruction d'architecture. */ G_DEFINE_TYPE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe générique des instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_instruction_class_init(GArchInstructionClass *klass) { } /****************************************************************************** * * * Paramètres : instr = instance à initialiser. * * * * Description : Initialise une instance d'instruction d'architecture. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_instruction_init(GArchInstruction *instr) { DL_LIST_ITEM_INIT(&instr->flow); } /****************************************************************************** * * * Paramètres : instr = instruction quelconque à modifier. * * offset = position physique dans le code binaire. * * length = taille de l'instruction. * * address = adresse virtuelle ou position physique. * * * * Description : Définit la localisation d'une instruction. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_set_location(GArchInstruction *instr, off_t offset, off_t length, vmpa_t address) { instr->offset = offset; instr->length = length; instr->address = address; } /****************************************************************************** * * * Paramètres : instr = instruction quelconque à consulter. * * offset = position physique dans le code binaire/NULL. [OUT] * * length = taille de l'instruction ou NULL. [OUT] * * address = adresse virtuelle ou position physique/NULL. [OUT] * * * * Description : Fournit la localisation d'une instruction. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_get_location(const GArchInstruction *instr, off_t *offset, off_t *length, vmpa_t *address) { if (offset != NULL) *offset = instr->offset; if (length != NULL) *length = instr->length; if (address != NULL) *address = instr->address; } /****************************************************************************** * * * Paramètres : instr = instance à mettre à jour. * * opererand = instruction à venir associer. * * * * Description : Attache un opérande supplémentaire à une instruction. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_attach_extra_operand(GArchInstruction *instr, GArchOperand *operand) { instr->operands_count++; instr->operands = (GArchOperand **)realloc(instr->operands, instr->operands_count * sizeof(GArchOperand *)); instr->operands[instr->operands_count - 1] = operand; } /****************************************************************************** * * * Paramètres : instr = instance à consulter. * * * * Description : Indique la quantité d'opérandes présents dans l'instruction. * * * * Retour : Nombre d'opérandes attachés. * * * * Remarques : - * * * ******************************************************************************/ size_t g_arch_instruction_count_operands(const GArchInstruction *instr) { return instr->operands_count; } /****************************************************************************** * * * Paramètres : instr = instance à mettre à jour. * * index = indice de l'opérande concernée. * * * * Description : Fournit un opérande donné d'une instruction. * * * * Retour : Opérande trouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index) { GArchOperand *result; /* Opérande à retourner */ if (index >= instr->operands_count) result = NULL; else result = instr->operands[index]; return result; } /****************************************************************************** * * * Paramètres : instr = instance à mettre à jour. * * new = nouvelle opérande à attacher. * * old = ancienne opérande à détacher. * * * * Description : Remplace un opérande d'une instruction par un autre. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *new, const GArchOperand *old) { size_t i; /* Boucle de parcours */ for (i = 0; i < instr->operands_count; i++) if (instr->operands[i] == old) break; if (i < instr->operands_count) instr->operands[i] = new; } /****************************************************************************** * * * Paramètres : instr = instance à mettre à jour. * * opererand = instruction à venir dissocier. * * * * Description : Détache un opérande liée d'une instruction. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *operand) { size_t i; /* Boucle de parcours */ for (i = 0; i < instr->operands_count; i++) if (instr->operands[i] == operand) break; if ((i + 1) < instr->operands_count) memmove(&instr->operands[i], &instr->operands[i + 1], (instr->operands_count - i - 1) * sizeof(GArchOperand *)); instr->operands_count--; instr->operands = (GArchOperand **)realloc(instr->operands, instr->operands_count * sizeof(GArchOperand *)); } /****************************************************************************** * * * Paramètres : instr = instruction à consulter. * * rregs = liste des rgistres lus. [OUT] * * rcount = nombre de registres lus. [OUT] * * wregs = liste des rgistres écrits. [OUT] * * wcount = nombre de registres écrits. [OUT] * * * * Description : Liste les registres lus et écrits par l'instruction. * * * * Retour : - * * * * Remarques : Les compteurs de références sont à décrémenter après usage ! * * * ******************************************************************************/ void g_arch_instruction_get_rw_registers(const GArchInstruction *instr, GArchRegister ***rregs, size_t *rcount, GArchRegister ***wregs, size_t *wcount) { size_t i; /* Boucle de parcours */ *rregs = NULL; *rcount = 0; *wregs = NULL; *wcount = 0; instr->get_rw_regs(instr, rregs, rcount, wregs, wcount); for (i = 0; i < *rcount; i++) g_object_ref(G_OBJECT((*rregs)[i])); for (i = 0; i < *wcount; i++) g_object_ref(G_OBJECT((*wregs)[i])); } /* ---------------------------------------------------------------------------------- */ /* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : instr = instruction à consulter. * * addr = eventuelle adresse associée à faire connaître. [OUT] * * * * Description : Informe sur une éventuelle référence à une autre instruction.* * * * Retour : Type de lien trouvé ou ILT_NONE si aucun. * * * * Remarques : - * * * ******************************************************************************/ InstructionLinkType g_arch_instruction_get_link(const GArchInstruction *instr, vmpa_t *addr) { return instr->get_link(instr, addr); } /****************************************************************************** * * * Paramètres : instr = instruction à consulter. * * * * Description : Indique si l'instruction correspond à un retour de fonction. * * * * Retour : true si l'instruction est un 'return' quelconque ou false. * * * * Remarques : - * * * ******************************************************************************/ bool g_arch_instruction_is_return(const GArchInstruction *instr) { return instr->is_return(instr); } /****************************************************************************** * * * Paramètres : instr = instruction dont les informations sont à consulter. * * dest = ligne visée par la liaison (côté destination). * * type = type de lien à construire. * * * * Description : Etablit un lien entre deux instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type) { /* Côté destination */ dest->from = (GArchInstruction **)realloc(dest->from, ++dest->from_count * sizeof(GArchInstruction *)); dest->from[dest->from_count - 1] = instr; /* Côté point de départ */ instr->to_count++; instr->to = (GArchInstruction **)realloc(instr->to, instr->to_count * sizeof(GArchInstruction *)); instr->links_type = (InstructionLinkType *)realloc(instr->links_type, instr->to_count * sizeof(InstructionLinkType)); instr->to[instr->to_count - 1] = dest; instr->links_type[instr->to_count - 1] = type; } /****************************************************************************** * * * Paramètres : instr = instruction dont les informations sont à consulter. * * * * Description : Indique si l'instruction a une ou plusieurs origines. * * * * Retour : Bilan de la consultation. * * * * Remarques : - * * * ******************************************************************************/ bool g_arch_instruction_has_sources(const GArchInstruction *instr) { return (instr->from_count > 0); } /****************************************************************************** * * * Paramètres : instr = instruction dont les informations sont à consulter. * * * * Description : Indique si l'instruction a une suite autre que la suivante. * * * * Retour : Bilan de la consultation. * * * * Remarques : - * * * ******************************************************************************/ bool g_arch_instruction_has_destinations(const GArchInstruction *instr) { /* FIXME !? */ //return (instr->to_count > 1 || (instr->to_count == 1 && instr->links_type[0] != ILT_CALL)); return (instr->to_count > 0); } /****************************************************************************** * * * Paramètres : instr = instruction dont les informations sont à consulter. * * dests = liste des instructions de destination. [OUT] * * types = liste des types de liens présents. [OUT] * * * * Description : Fournit les destinations d'une instruction donnée. * * * * Retour : Nombre de ces destinations. * * * * Remarques : - * * * ******************************************************************************/ size_t g_arch_instruction_get_destinations(const GArchInstruction *instr, GArchInstruction ***dests, InstructionLinkType **types) { *dests = instr->to; *types = instr->links_type; return instr->to_count; } /* ---------------------------------------------------------------------------------- */ /* CONVERSIONS DU FORMAT DES INSTRUCTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : instr = instruction d'assemblage à consulter. * * * * Description : Fournit le nom humain de l'instruction manipulée. * * * * Retour : Mot clef de bas niveau. * * * * Remarques : - * * * ******************************************************************************/ const char *g_arch_instruction_get_keyword(const GArchInstruction *instr) { return instr->get_text(instr, NULL/* FIXME */, 0/* FIXME */); } /****************************************************************************** * * * Paramètres : instr = instruction d'assemblage à représenter. * * buffer = espace où placer ledit contenu. * * syntax = type de représentation demandée. * * * * Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void _g_arch_instruction_print(const GArchInstruction *instr, GCodeBuffer *buffer, MemoryDataSize msize, const bin_t *content, AsmSyntax syntax) { GBufferLine *line; /* Ligne de destination */ char address[VMPA_MAX_SIZE]; /* Adresse au format texte */ size_t len; /* Taille de l'élément inséré */ char *bin_code; /* Tampon du code binaire */ off_t i; /* Boucle de parcours #1 */ const char *key; /* Mot clef principal */ size_t klen; /* Taille de ce mot clef */ size_t j; /* Boucle de parcours #2 */ line = g_code_buffer_append_new_line(buffer, instr->address); /* Adresse virtuelle ou physique */ len = vmpa_to_string(instr->address, msize, address); g_buffer_line_insert_text(line, BLC_ADDRESS, address, len, RTT_RAW); /* Code brut */ bin_code = (char *)calloc(instr->length * 3, sizeof(char)); for (i = 0; i < instr->length; i++) { if ((i + 1) < instr->length) snprintf(&bin_code[i * (2 + 1)], 4, "%02hhx ", content[instr->offset + i]); else snprintf(&bin_code[i * (2 + 1)], 3, "%02hhx", content[instr->offset + i]); } g_buffer_line_insert_text(line, BLC_BINARY, bin_code, instr->length * 3 - 1, RTT_RAW_CODE); free(bin_code); /* Instruction proprement dite */ key = instr->get_text(instr, NULL/* FIXME */, 0/* FIXME */); klen = strlen(key); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION); if (instr->operands_count > 0) { g_arch_operand_print(instr->operands[0], line, syntax); for (j = 1; j < instr->operands_count; j++) { g_buffer_line_insert_text(line, BLC_ASSEMBLY, ",", 1, RTT_PUNCT); g_buffer_line_insert_text(line, BLC_ASSEMBLY, " ", 1, RTT_NONE); g_arch_operand_print(instr->operands[j], line, syntax); } } } /****************************************************************************** * * * Paramètres : instr = instruction d'assemblage à représenter. * * buffer = espace où placer ledit contenu. * * syntax = type de représentation demandée. * * * * Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_print(const GArchInstruction *instr, GCodeBuffer *buffer, MemoryDataSize msize, const bin_t *content, AsmSyntax syntax) { if (instr->print != NULL) instr->print(instr, buffer, msize, content, syntax); else _g_arch_instruction_print(instr, buffer, msize, content, syntax); } /****************************************************************************** * * * Paramètres : instr = instruction d'origine à convertir. * * ctx = contexte de la phase de décompilation. * * * * Description : Décompile une instruction de façon générique. * * * * Retour : Instruction mise en place ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GDecInstruction *g_arch_instruction_decompile(const GArchInstruction *instr, GDecContext *ctx) { GDecInstruction *result; /* Instruction à retourner */ GDecInstruction *list; /* Instructions décompilées */ if (instr->decomp != NULL) { result = instr->decomp(instr, ctx); if (result != NULL) { list = g_dec_context_get_decomp_instrs(ctx); if (list == NULL) list = result; else g_dec_instruction_add_to_list(&list, result); g_dec_context_set_decomp_instrs(ctx, list); } } else result = NULL; return result; } /* ---------------------------------------------------------------------------------- */ /* TRAITEMENT DES INSTRUCTIONS PAR ENSEMBLE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : list = liste d'instructions à consulter. * * * * Description : Renvoie vers la dernière instruction d'une série. * * * * Retour : Dernière instruction trouvée (ou NULL ?!). * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_instruction_find_last(const GArchInstruction *list) { return ainstr_list_last(list); } /****************************************************************************** * * * Paramètres : list = liste d'instructions à compléter, ou NULL. * * instr = nouvelle instruction à intégrer à l'ensemble. * * * * Description : Ajoute une instruction à un ensemble existant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_instruction_add_to_list(GArchInstruction **list, GArchInstruction *instr) { ainstr_list_add_tail(instr, list); } /****************************************************************************** * * * Paramètres : list = liste d'instructions à consulter. * * : iter = position actuelle dans la liste. * * * * Description : Fournit l'élement suivant un autre pour un parcours. * * * * Retour : Elément suivant ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_instruction_get_prev_iter(const GArchInstruction *list, const GArchInstruction *iter) { GArchInstruction *result; /* Elément suivant à renvoyer */ result = ainstr_list_prev_iter(iter, list); return result; } /****************************************************************************** * * * Paramètres : list = liste d'instructions à consulter. * * : iter = position actuelle dans la liste. * * max = adresse marquant la limite (exclue) du parcours. * * * * Description : Fournit l'élement suivant un autre pour un parcours. * * * * Retour : Elément suivant ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_instruction_get_next_iter(const GArchInstruction *list, const GArchInstruction *iter, vmpa_t max) { GArchInstruction *result; /* Elément suivant à renvoyer */ result = ainstr_list_next_iter(iter, list); if (result != NULL && result->address >= max) result = NULL; return result; } /****************************************************************************** * * * Paramètres : list = liste de lignes à parcourir. * * addr = position en mémoire ou physique à chercher. * * strict = définit la considération à porter à l'adresse. * * * * Description : Recherche une instruction d'après son adresse. * * * * Retour : Instruction trouvée à l'adresse donnée, NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *list, vmpa_t addr, bool strict) { GArchInstruction *result; /* Trouvaille à retourner */ ainstr_list_for_each(result, list) { if (strict && result->offset == addr) break; else if (!strict && result->offset < addr && addr < (result->offset + result->length)) break; } return result; }