/* Chrysalide - Outil d'analyse de fichiers binaires * output.h - prototypes pour l'impression des instructions désassemblées * * Copyright (C) 2010-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 "output.h" #include #include #include "../../format/format.h" #include "../../glibext/generators/rborder.h" #include "../../gui/panels/log.h" /****************************************************************************** * * * Paramètres : cache = tampon de récueil des résultats d'impression. * * lang = langage de haut niveau préféré pour l'impression. * * binary = tampon de récueil des résultats d'impression. * * info = informations complémentaires à intégrer. * * status = barre de statut avec progression à mettre à jour. * * * * Description : Transcrit du code désassemblé en texte humainement lisible. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang, GLoadedBinary *binary, GPreloadInfo *info, GtkStatusStack *status) { GExeFormat *format; /* Format associé au binaire */ GArchProcessor *proc; /* Processeur de l'architecture*/ GBinPortion *root; /* Couche première de portions */ GBinPortion **portions; /* Morceaux d'encadrement */ size_t portions_count; /* Taille de cette liste */ size_t portion_index; /* Prochaine portion à traiter */ GBinSymbol **symbols; /* Symboles à représenter */ size_t sym_count; /* Qté de symboles présents */ size_t sym_index; /* Prochain symbole non traité */ MemoryDataSize msize; /* Taille du bus d'adresses */ const GBinContent *content; /* Contenu binaire global */ size_t count; /* Nombre total d'instructions */ activity_id_t id; /* Identifiant de progression */ bool expect_outro; /* Fin de zone de code définie */ size_t comment_count; /* Quantité de commentaires */ size_t comment_index; /* Indice du commantaire actif */ GDbComment *comment; /* Commentaire à ajouter */ const vmpa2t *caddr; /* Localisation du commentaire */ size_t i; /* Boucle de parcours */ GArchInstruction *instr; /* Instruction à traiter */ const vmpa2t *iaddr; /* Adresse d'instruction */ GBorderGenerator *border; /* Délimitation de routine */ const vmpa2t *paddr; /* Adresse de portion */ GLineGenerator *generator; /* Générateur de contenu ajouté*/ const vmpa2t *saddr; /* Adresse de symbole */ int compared; /* Bilan d'une comparaison */ SymbolType stype; /* Type de symbole trouvé */ vmpa2t intro_addr; /* Adresse de début de code */ vmpa2t outro_addr; /* Adresse de fin de code */ BufferLineFlags flags; /* Propriétés pour la ligne */ //mrange_t range; /* Couverture sans surface */ unsigned int _missing = 0; format = g_loaded_binary_get_format(binary); proc = g_loaded_binary_get_processor(binary); bool collect_all_portions(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, void *unused) { if (visit == BPV_ENTER || visit == BPV_SHOW) { portions = (GBinPortion **)realloc(portions, ++portions_count * sizeof(GBinPortion *)); portions[portions_count - 1] = portion; } return true; } portions = NULL; portions_count = 0; portion_index = 0; root = g_exe_format_get_portions(format); g_binary_portion_visit(root, (visit_portion_fc)collect_all_portions, NULL); g_object_unref(G_OBJECT(root)); symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count); sym_index = 0; msize = g_arch_processor_get_memory_size(proc); content = g_binary_format_get_content(G_BIN_FORMAT(format)); g_arch_processor_lock(proc); count = g_arch_processor_count_instructions(proc); id = gtk_status_stack_add_activity(status, _("Printing all disassebled parts..."), count); expect_outro = false; g_preload_info_lock_comments(info); comment_count = _g_preload_info_count_comments(info); comment_index = 0; if (comment_index < comment_count) { comment = _g_preload_info_grab_comment(info, comment_index); caddr = g_db_comment_get_address(comment); comment_index++; } else comment = NULL; /* if (comment != NULL) log_variadic_message(LMT_BAD_BINARY, _("Got comment '%s' @ 0x%08x"), g_db_comment_get_text(comment), get_phy_addr(caddr)); */ for (i = 0; i < count; i++) { instr = g_arch_processor_get_instruction(proc, i); iaddr = get_mrange_addr(g_arch_instruction_get_range(instr)); /* Fin d'une portion de code précédente ? */ if (expect_outro && cmp_vmpa(iaddr, &outro_addr) >= 0) { expect_outro = false; border = g_border_generator_new(lang, iaddr, false, msize); g_buffer_cache_append(cache, G_LINE_GENERATOR(border), BLF_NONE); } /* Début d'une nouvelle portion ? */ while (portion_index < portions_count) { paddr = get_mrange_addr(g_binary_portion_get_range(portions[portion_index])); if (cmp_vmpa_by_phy(iaddr, paddr) != 0) break; generator = G_LINE_GENERATOR(portions[portion_index]); /* Si elle comporte une description ! */ if (g_line_generator_count_lines(generator) > 0) g_buffer_cache_append(cache, generator, BLF_NONE); portion_index++; } /* Début d'un nouveau symbole ? */ if (sym_index == sym_count) compared = -1; else { iaddr = get_mrange_addr(g_arch_instruction_get_range(instr)); saddr = get_mrange_addr(g_binary_symbol_get_range(symbols[sym_index])); /* On écarte les symboles qu'on ne sait pas réintroduire */ for (compared = cmp_vmpa(iaddr, saddr); compared > 0; compared = cmp_vmpa(iaddr, saddr)) { log_variadic_message(LMT_BAD_BINARY, _("Unable to find a proper location for symbol '%s' @ 0x%08x"), g_binary_symbol_get_label(symbols[sym_index]), get_phy_addr(saddr)); _missing++; if (++sym_index == sym_count) goto no_more_symbol_finally; saddr = get_mrange_addr(g_binary_symbol_get_range(symbols[sym_index])); } if (compared == 0) { /* Coupure pour une nouvelle routine */ stype = g_binary_symbol_get_target_type(symbols[sym_index]); if (stype == STP_ROUTINE || stype == STP_ENTRY_POINT) { /* Impression de la marque de début */ copy_vmpa(&intro_addr, get_mrange_addr(g_binary_symbol_get_range(symbols[sym_index]))); border = g_border_generator_new(lang, &intro_addr, true, msize); g_buffer_cache_append(cache, G_LINE_GENERATOR(border), BLF_NONE); /* Mémorisation de la fin */ /** * On ne peut pas utiliser l'adresse obtenue dans outro_addr * comme localisation de la marque de clôture. En effet, en * fin du contenu ou de segment, l'adresse générée peut être * inexistante. * * On utilise donc l'adresse de l'instruction suivante. * * On est cependant bien conscient qu'une instruction suivante * est nécessaire pour imprimer cette marque de clôture. */ compute_mrange_end_addr(g_binary_symbol_get_range(symbols[sym_index]), &outro_addr); expect_outro = true; } /* Etiquette ? */ generator = g_binary_symbol_produce_label(symbols[sym_index]); if (generator != NULL) g_buffer_cache_append(cache, generator, BLF_NONE); } } no_more_symbol_finally: flags = BLF_NONE; if (compared == 0) { /* Point d'entrée ? */ if (g_binary_symbol_get_target_type(symbols[sym_index]) == STP_ENTRY_POINT) flags |= BLF_ENTRYPOINT; /** * Début d'un groupe bien cohérent avec les alignements ? * * On décide que, à partir du moment où il y a un symbole, il y a * là le début d'un nouveau bloc avec sa propre nouvelle gestion * des largeurs, quelque soit le type du symbole en question ! */ flags |= BLF_WIDTH_MANAGER; sym_index++; } g_buffer_cache_append(cache, G_LINE_GENERATOR(instr), flags); /* Commentaire en bout de ligne ? */ if (comment != NULL) { compared = cmp_vmpa(iaddr, caddr); if (compared >= 0) { if (compared == 0) g_db_item_apply(G_DB_ITEM(comment), binary); else log_variadic_message(LMT_BAD_BINARY, _("Unable to find a proper location for comment '%s' @ 0x%08x"), g_db_comment_get_text(comment), get_phy_addr(caddr)); g_object_unref(G_OBJECT(comment)); if (comment_index < comment_count) { comment = _g_preload_info_grab_comment(info, comment_index); caddr = g_db_comment_get_address(comment); comment_index++; } else comment = NULL; } } g_object_unref(G_OBJECT(instr)); gtk_status_stack_update_activity_value(status, id, 1); } assert(comment_index == comment_count); _g_preload_info_drain_comments(info); g_preload_info_unlock_comments(info); gtk_status_stack_remove_activity(status, id); g_arch_processor_unlock(proc); g_object_unref(G_OBJECT(content)); if (portions != NULL) free(portions); g_object_unref(G_OBJECT(proc)); g_object_unref(G_OBJECT(format)); fprintf(stderr, "MISSING :: %u symbols\n", _missing); }