/* Chrysalide - Outil d'analyse de fichiers binaires * processor.c - gestion générique des architectures * * Copyright (C) 2008-2012 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 "processor.h" #include #include #include #include "instruction-int.h" #include "processor-int.h" #include "raw.h" /* Initialise la classe générique des processeurs. */ static void g_arch_processor_class_init(GArchProcessorClass *); /* Initialise une instance de processeur d'architecture. */ static void g_arch_processor_init(GArchProcessor *); /* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */ /* Démarre la définition d'un nouveau groupe d'instructions. */ static void g_arch_processor_add_new_coverage(GArchProcessor *, GArchInstruction *, size_t); /* Termine la définition d'un nouveau groupe d'instructions. */ static void g_arch_processor_finish_last_coverage(GArchProcessor *, GArchInstruction *, size_t); /* Indique le type défini pour un processeur d'architecture. */ G_DEFINE_TYPE(GArchProcessor, g_arch_processor, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe générique des processeurs. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_processor_class_init(GArchProcessorClass *klass) { } /****************************************************************************** * * * Paramètres : proc = instance à initialiser. * * * * Description : Initialise une instance de processeur d'architecture. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_processor_init(GArchProcessor *proc) { proc->coverages = NULL; proc->cov_allocated = 0; proc->cov_count = 0; } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * * * Description : Fournit un contexte propre au processeur d'une architecture. * * * * Retour : Nouveau contexte mis à disposition. * * * * Remarques : - * * * ******************************************************************************/ GProcContext *g_arch_processor_get_context(const GArchProcessor *proc) { GProcContext *result; /* Contexte à retourner */ if (proc->get_ctx != NULL) result = proc->get_ctx(proc); else result = NULL; return result; } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * * * Description : Fournit un contexte lié au processeur pour une décompilation.* * * * Retour : Nouveau contexte mis à disposition. * * * * Remarques : - * * * ******************************************************************************/ #if 0 GDecContext *g_arch_processor_get_decomp_context(const GArchProcessor *proc) { GDecContext *result; /* Contexte à retourner */ if (proc->get_dec_ctx != NULL) result = proc->get_dec_ctx(proc); else result = NULL; return result; } #endif /****************************************************************************** * * * Paramètres : proc = processeur d'architecture à consulter. * * * * Description : Fournit le boustime du processeur d'une architecture. * * * * Retour : Boutisme associé au processeur. * * * * Remarques : - * * * ******************************************************************************/ SourceEndian g_arch_processor_get_endianness(const GArchProcessor *proc) { return proc->endianness; } /****************************************************************************** * * * Paramètres : proc = processeur d'architecture à consulter. * * * * Description : Fournit la taille de l'espace mémoire d'une architecture. * * * * Retour : Taille de l'espace mémoire. * * * * Remarques : - * * * ******************************************************************************/ MemoryDataSize g_arch_processor_get_memory_size(const GArchProcessor *proc) { return proc->memsize; } /****************************************************************************** * * * Paramètres : proc = processeur d'architecture à consulter. * * * * Description : Fournit la taille min. des instructions d'une architecture. * * * * Retour : Taille d'encodage des instructions * * * * Remarques : - * * * ******************************************************************************/ MemoryDataSize g_arch_processor_get_instruction_size(const GArchProcessor *proc) { return proc->inssize; } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * ctx = contexte lié à l'exécution du processeur. * * content = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * format = format du fichier contenant le code. * * * * Description : Désassemble une instruction dans un flux de données. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_processor_disassemble(const GArchProcessor *proc, GProcContext *ctx, const GBinContent *content, vmpa2t *pos, GExeFormat *format) { GArchInstruction *result; /* Instruction à renvoyer */ vmpa2t back; /* Position sauvegardée */ assert(has_phys_addr(pos) && has_virt_addr(pos)); copy_vmpa(&back, pos); result = G_ARCH_PROCESSOR_GET_CLASS(proc)->disassemble(proc, ctx, content, pos, format); if (result == NULL) copy_vmpa(pos, &back); return result; } /* ---------------------------------------------------------------------------------- */ /* MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : proc = architecture à comléter par la procédure. * * first = première instruction d'un nouveau groupe. * * start = indice de cette instruction dans l'ensemble global. * * * * Description : Démarre la définition d'un nouveau groupe d'instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_processor_add_new_coverage(GArchProcessor *proc, GArchInstruction *first, size_t start) { instr_coverage *coverage; /* Couverture à définir */ const mrange_t *irange; /* Couverture de l'instruction */ /* Mise à disposition de d'avantage d'espace */ if (proc->cov_allocated == proc->cov_count) { proc->cov_allocated += INSTR_ALLOC_BLOCK; proc->coverages = (instr_coverage *)realloc(proc->coverages, proc->cov_allocated * sizeof(instr_coverage)); } coverage = &proc->coverages[proc->cov_count++]; irange = g_arch_instruction_get_range(first); init_mrange(&coverage->range, get_mrange_addr(irange), 0); coverage->start = start; } /****************************************************************************** * * * Paramètres : proc = architecture à comléter par la procédure. * * last = dernière instruction d'un nouveau groupe. * * end = indice de cette instruction dans l'ensemble global. * * * * Description : Termine la définition d'un nouveau groupe d'instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_processor_finish_last_coverage(GArchProcessor *proc, GArchInstruction *last, size_t end) { instr_coverage *coverage; /* Couverture à définir */ const mrange_t *irange; /* Couverture de l'instruction */ phys_t diff; /* Ecart entre les extrémités */ coverage = &proc->coverages[proc->cov_count - 1]; irange = g_arch_instruction_get_range(last); diff = compute_vmpa_diff(get_mrange_addr(&coverage->range), get_mrange_addr(irange)); diff += get_mrange_length(irange); set_mrange_length(&coverage->range, diff); coverage->count = end - coverage->start + 1; } /****************************************************************************** * * * Paramètres : proc = processeur recensant diverses instructions. * * addr = position en mémoire ou physique à chercher. * * * * Description : Recherche un groupe d'instruction d'après son adresse. * * * * Retour : Couverture trouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ const instr_coverage *g_arch_processor_find_coverage_by_address(const GArchProcessor *proc, const vmpa2t *addr) { instr_coverage *result; /* Trouvaille à retourner */ void *ptr; /* Résultat des recherches */ int search_for_coverage_by_addr(const vmpa2t *a, const instr_coverage *c) { int status; /* Bilan d'une comparaison */ status = cmp_mrange_with_vmpa(&c->range, a); return status; } ptr = bsearch(addr, proc->coverages, proc->cov_count, sizeof(instr_coverage), (__compar_fn_t)search_for_coverage_by_addr); result = ((instr_coverage *)ptr); return result; } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * list = liste des instructions désassemblées. * * * * Description : Note les instructions désassemblées avec une architecture. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_arch_processor_set_disassembled_instructions(GArchProcessor *proc, GArchInstruction *list) { GArchInstruction *last; /* Dernière instruction traitée*/ GArchInstruction *iter; /* Boucle de parcours */ /* TODO : vider une éventuelle liste existante */ /* TODO : incrémenter les références (cf. code Python) */ last = NULL; ainstr_list_for_each(iter, list) { /* Mise à disposition de d'avantage d'espace */ if (proc->instr_allocated == proc->instr_count) { proc->instr_allocated += INSTR_ALLOC_BLOCK; proc->instructions = (GArchInstruction **)realloc(proc->instructions, proc->instr_allocated * sizeof(GArchInstruction *)); } /* Constitution des groupes */ if (last == NULL || g_arch_instruction_get_flags(iter) & AIF_ROUTINE_START) { if (last != NULL) g_arch_processor_finish_last_coverage(proc, last, proc->instr_count - 1); g_arch_processor_add_new_coverage(proc, iter, proc->instr_count); } /* Enregistrement */ proc->instructions[proc->instr_count++] = iter; last = iter; } if (last != NULL) g_arch_processor_finish_last_coverage(proc, last, proc->instr_count - 1); } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * * * Description : Fournit les instructions désassemblées pour une architecture.* * * * Retour : Liste des instructions désassemblées ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_processor_get_disassembled_instructions(const GArchProcessor *proc) { return (proc->instr_count > 0 ? proc->instructions[0] : NULL); } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * index = indice de l'instruction visée. * * * * Description : Fournit une instruction désassemblée pour une architecture. * * * * Retour : Instructions désassemblée trouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_processor_get_disassembled_instruction(const GArchProcessor *proc, size_t index) { GArchInstruction *result; /* Instruction à retourner */ if (proc->instr_count == 0) result = NULL; else { assert(index < proc->instr_count); result = proc->instructions[index]; } return result; } /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * * * * Description : Compte le nombre d'instructions représentées. * * * * Retour : Nombre d'instructions présentes. * * * * Remarques : - * * * ******************************************************************************/ size_t g_arch_processor_count_disassembled_instructions(const GArchProcessor *proc) { return proc->instr_count; } /****************************************************************************** * * * Paramètres : proc = processeur recensant diverses instructions. * * addr = position en mémoire ou physique à chercher. * * nearby = la recherche s'effectue-t-elle de façon stricte ? * * * * Description : Recherche une instruction d'après son adresse. * * * * Retour : Instruction trouvée à l'adresse donnée, NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *_g_arch_processor_find_instr_by_address(const GArchProcessor *proc, const vmpa2t *addr, bool nearby) { GArchInstruction *result; /* Trouvaille à retourner */ const instr_coverage *coverage; /* Couverture fine à fouiller */ coverage = g_arch_processor_find_coverage_by_address(proc, addr); if (coverage != NULL) result = _g_arch_processor_find_covered_instr_by_address(proc, coverage, addr, nearby); else result = NULL; return result; } /****************************************************************************** * * * Paramètres : proc = processeur recensant diverses instructions. * * coverage = zone de couverture fine à fouiller. * * addr = position en mémoire ou physique à chercher. * * nearby = la recherche s'effectue-t-elle de façon stricte ? * * * * Description : Recherche rapidement une instruction d'après son adresse. * * * * Retour : Instruction trouvée à l'adresse donnée, NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *_g_arch_processor_find_covered_instr_by_address(const GArchProcessor *proc, const instr_coverage *coverage, const vmpa2t *addr, bool nearby) { GArchInstruction *result; /* Trouvaille à retourner */ void *ptr; /* Résultat des recherches */ __compar_fn_t fn; /* Fonction auxiliaire adaptée */ int search_for_instr_by_addr(const vmpa2t *a, const GArchInstruction **b) { const mrange_t *range_b; /* Emplacement pour l'instr. B */ range_b = g_arch_instruction_get_range(*b); return cmp_vmpa(a, get_mrange_addr(range_b)); } int search_for_instr_by_nearby_addr(const vmpa2t *a, const GArchInstruction **b) { const mrange_t *range_b; /* Emplacement pour l'instr. B */ range_b = g_arch_instruction_get_range(*b); return cmp_mrange_with_vmpa(range_b, a); } if (nearby) fn = (__compar_fn_t)search_for_instr_by_nearby_addr; else fn = (__compar_fn_t)search_for_instr_by_addr; ptr = bsearch(addr, &proc->instructions[coverage->start], coverage->count, sizeof(GArchInstruction *), fn); result = (ptr != NULL ? *((GArchInstruction **)ptr) : NULL); return result; } /****************************************************************************** * * * Paramètres : proc = processeur recensant diverses instructions. * * instr = instruction de référence pour un parcours. * * * * Description : Fournit l'instruction qui en précède une autre. * * * * Retour : Instruction précédente trouvée, ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_processor_get_prev_instr(const GArchProcessor *proc, const GArchInstruction *instr) { GArchInstruction *result; /* Instruction à retourner */ GArchInstruction *list; /* Ensemble des instructions */ list = g_arch_processor_get_disassembled_instructions(proc); result = g_arch_instruction_get_prev_iter(list, instr); return result; } /****************************************************************************** * * * Paramètres : proc = processeur recensant diverses instructions. * * instr = instruction de référence pour un parcours. * * * * Description : Fournit l'instruction qui en suit une autre. * * * * Retour : Instruction suivante trouvée, ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_arch_processor_get_next_instr(const GArchProcessor *proc, const GArchInstruction *instr) { GArchInstruction *result; /* Instruction à retourner */ GArchInstruction *list; /* Ensemble des instructions */ list = g_arch_processor_get_disassembled_instructions(proc); result = g_arch_instruction_get_next_iter(list, instr, ~0); return result; }