/* Chrysalide - Outil d'analyse de fichiers binaires * binportion.c - représentation graphique de portions de binaire * * Copyright (C) 2013-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 Chrysalide. If not, see . */ #include "gbinportion.h" #include #include #include #include #include #include #include "../analysis/human/asm/lang.h" #include "../common/extstr.h" #include "../common/sort.h" #include "../glibext/gbinarycursor.h" #include "../glibext/linegen-int.h" /* ------------------------------- PORTION DE BINAIRE ------------------------------- */ /* Portion de données binaires quelconques (instance) */ struct _GBinPortion { GObject parent; /* A laisser en premier */ char *code; /* Code de la couleur de fond */ cairo_surface_t *icon; /* Image de représentation */ char *desc; /* Désignation humaine */ char **text; /* Lignes brutes à représenter */ size_t lcount; /* Quantité de ces lignes */ mrange_t range; /* Emplacement dans le code */ bool continued; /* Suite d'une découpe ? */ PortionAccessRights rights; /* Droits d'accès */ GBinPortion **subs; /* Portions incluses */ size_t count; /* Quantité d'inclusions */ }; /* Portion de données binaires quelconques (classe) */ struct _GBinPortionClass { GObjectClass parent; /* A laisser en premier */ }; /* Initialise la classe des portions de données binaires. */ static void g_binary_portion_class_init(GBinPortionClass *); /* Initialise une instance de portion de données binaires. */ static void g_binary_portion_init(GBinPortion *); /* Procède à l'initialisation de l'interface de génération. */ static void g_binary_portion_interface_init(GLineGeneratorInterface *); /* Supprime toutes les références externes. */ static void g_binary_portion_dispose(GBinPortion *); /* Procède à la libération totale de la mémoire. */ static void g_binary_portion_finalize(GBinPortion *); /* Détermine l'aire d'une sous-portion. */ static bool g_binary_portion_compute_sub_area(const GBinPortion *, phys_t, const GdkRectangle *, GdkRectangle *); /* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ /* Indique le nombre de ligne prêtes à être générées. */ static size_t g_binary_portion_count_lines(const GBinPortion *); /* Retrouve l'emplacement correspondant à une position donnée. */ static void g_binary_portion_compute_cursor(const GBinPortion *, gint, size_t, size_t, GLineCursor **); /* Détermine si le conteneur s'inscrit dans une plage donnée. */ static int g_binary_portion_contains_cursor(const GBinPortion *, size_t, size_t, const GLineCursor *); /* Renseigne sur les propriétés liées à un générateur. */ static BufferLineFlags g_binary_portion_get_flags(const GBinPortion *, size_t, size_t); /* Imprime dans une ligne de rendu le contenu représenté. */ static void g_binary_portion_print(GBinPortion *, GBufferLine *, size_t, size_t, const GBinContent *); /* ------------------------ PARCOURS D'ENSEMBLES DE PORTIONS ------------------------ */ /* Détermine si une portion contient une adresse donnée. */ static bool g_binary_portion_contains_vmpa(const GBinPortion *, const vmpa2t *); /* Détermine si une portion contient une position donnée. */ static bool g_binary_portion_contains_physical(const GBinPortion *, phys_t); /* Détermine si une portion contient une adresse donnée. */ static bool g_binary_portion_contains_virtual(const GBinPortion *, virt_t); /* ---------------------------------------------------------------------------------- */ /* PORTION DE BINAIRE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour les portions de données binaires. */ G_DEFINE_TYPE_WITH_CODE(GBinPortion, g_binary_portion, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_binary_portion_interface_init)); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des portions de données binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_class_init(GBinPortionClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_portion_dispose; object->finalize = (GObjectFinalizeFunc)g_binary_portion_finalize; } /****************************************************************************** * * * Paramètres : portion = instance à initialiser. * * * * Description : Initialise une instance de portion de données binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_init(GBinPortion *portion) { portion->desc = NULL; portion->text = NULL; portion->lcount = 0; portion->continued = false; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de génération. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_interface_init(GLineGeneratorInterface *iface) { iface->count = (linegen_count_lines_fc)g_binary_portion_count_lines; iface->compute = (linegen_compute_fc)g_binary_portion_compute_cursor; iface->contains = (linegen_contains_fc)g_binary_portion_contains_cursor; iface->get_flags = (linegen_get_flags_fc)g_binary_portion_get_flags; iface->print = (linegen_print_fc)g_binary_portion_print; } /****************************************************************************** * * * Paramètres : portion = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_dispose(GBinPortion *portion) { G_OBJECT_CLASS(g_binary_portion_parent_class)->dispose(G_OBJECT(portion)); } /****************************************************************************** * * * Paramètres : portion = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_finalize(GBinPortion *portion) { size_t i; /* Boucle de parcours */ free(portion->code); if (portion->icon != NULL) cairo_surface_destroy(portion->icon); if (portion->desc != NULL) free(portion->desc); for (i = 0; i < portion->lcount; i++) free(portion->text[i]); if (portion->text != NULL) free(portion->text); G_OBJECT_CLASS(g_binary_portion_parent_class)->finalize(G_OBJECT(portion)); } /****************************************************************************** * * * Paramètres : code = désignation humaine de la couleur de fond. * * addr = emplacement de la section à conserver. * * size = taille de la section à conserver. * * * * Description : Crée une description de partie de code vierge. * * * * Retour : Instance mise en place. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion *g_binary_portion_new(const char *code, const vmpa2t *addr, phys_t size) { GBinPortion *result; /* Structure à retourner */ result = g_object_new(G_TYPE_BIN_PORTION, NULL); result->code = strdup(code); init_mrange(&result->range, addr, size); return result; } /****************************************************************************** * * * Paramètres : a = premières informations à consulter. * * b = secondes informations à consulter. * * * * Description : Etablit la comparaison ascendante entre deux portions. * * * * Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). * * * * Remarques : - * * * ******************************************************************************/ int g_binary_portion_compare(const GBinPortion **a, const GBinPortion **b) { int result; /* Bilan à retourner */ const vmpa2t *addr_a; /* Adresse de la portion 'a' */ const vmpa2t *addr_b; /* Adresse de la portion 'b' */ addr_a = get_mrange_addr(&(*a)->range); addr_b = get_mrange_addr(&(*b)->range); result = cmp_vmpa(addr_a, addr_b); return result; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * icon = image miniature de représentation à associer. * * * * Description : Attribue à la portion une éventuelle image de représentation.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_set_icon(GBinPortion *portion, cairo_surface_t *icon) { if (icon != NULL) portion->icon = cairo_surface_reference(icon); else portion->icon = NULL; } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * * * Description : Fournit une éventuelle image de représentation de portion. * * * * Retour : Image miniature de représentation associée. * * * * Remarques : - * * * ******************************************************************************/ cairo_surface_t *g_binary_portion_get_icon(const GBinPortion *portion) { cairo_surface_t *result; result = portion->icon; if (result != NULL) cairo_surface_reference(result); return result; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * desc = nom à donner à la partie. * * * * Description : Attribue une description humaine à une partie de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_set_desc(GBinPortion *portion, const char *desc) { size_t i; /* Boucle de parcours */ GCodingLanguage *lang; /* Langage de sortie préféré */ if (portion->desc != NULL) { free(portion->desc); for (i = 0; i < portion->lcount; i++) free(portion->text[i]); if (portion->text != NULL) { free(portion->text); portion->text = NULL; } } if (desc == NULL) portion->desc = NULL; else { portion->desc = strdup(desc); if (portion->continued) portion->desc = stradd(portion->desc, _(" (continued)")); /* Constitution du rendu */ portion->text = calloc(5, sizeof(char *)); portion->lcount = 5; portion->text[0] = strdup("======================================================"); portion->text[1] = strdup(""); asprintf(&portion->text[2], "%s (%s%s%s%s)", portion->desc, _("rights: "), portion->rights & PAC_READ ? "r" : "-", portion->rights & PAC_WRITE ? "w" : "-", portion->rights & PAC_EXEC ? "x" : "-"); portion->text[3] = strdup(""); portion->text[4] = strdup("======================================================"); /* Ajout de la touche "commentaires" */ lang = g_asm_language_new(); g_coding_language_encapsulate_comments(lang, &portion->text, &portion->lcount); g_object_unref(G_OBJECT(lang)); /* Ajout de deux bordures vides */ portion->lcount += 2; portion->text = realloc(portion->text, portion->lcount * sizeof(char *)); memmove(&portion->text[1], &portion->text[0], (portion->lcount - 2) * sizeof(char *)); portion->text[0] = NULL; portion->text[portion->lcount - 1] = NULL; } } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * * * Description : Fournit la description attribuée à une partie de code. * * * * Retour : Nom donné à la partie. * * * * Remarques : - * * * ******************************************************************************/ const char *g_binary_portion_get_desc(const GBinPortion *portion) { return portion->desc; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * * * Description : Fournit l'emplacement d'une partie de code binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ const mrange_t *g_binary_portion_get_range(const GBinPortion *portion) { return &portion->range; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * max = taille maximale accordée à la portion. * * * * Description : Assure qu'une portion ne dépasse pas une position donnée. * * * * Retour : true si la portion a été modifiée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_portion_limit_range(GBinPortion *portion, phys_t max) { bool result; /* Bilan à retourner */ phys_t current; /* Taille courante */ current = get_mrange_length(&portion->range); result = (current > max); if (result) set_mrange_length(&portion->range, max); return result; } /****************************************************************************** * * * Paramètres : portion = portion dont la définition est à metre à jour. * * * * Description : Définit la nature de la portion en terme d'originalité. * * * * Retour : - * * * * Remarques : L'action ne modifie aucunement la description courante. * * C'est le changement de description qui s'appuie sur la * * notée ici. * * * ******************************************************************************/ void g_binary_portion_mark_as_continued(GBinPortion *portion, bool continued) { portion->continued = continued; } /****************************************************************************** * * * Paramètres : portion = portion dont la définition est à consulter. * * * * Description : Indique la nature de la portion en terme d'originalité. * * * * Retour : true si la portion est la suite d'une portion découpée. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_portion_is_continuation(const GBinPortion *portion) { return portion->continued; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * rights = droits d'accès de la partie. * * * * Description : Définit les droits associés à une partie de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_set_rights(GBinPortion *portion, PortionAccessRights rights) { portion->rights = rights; } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * * * Description : Fournit les droits associés à une partie de code. * * * * Retour : Droits d'accès de la partie. * * * * Remarques : - * * * ******************************************************************************/ PortionAccessRights g_binary_portion_get_rights(const GBinPortion *portion) { return portion->rights; } /****************************************************************************** * * * Paramètres : portion = description de partie à mettre à jour. * * tooltip = astuce à compléter. [OUT] * * * * Description : Prépare une astuce concernant une portion pour son affichage.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_query_tooltip(GBinPortion *portion, GtkTooltip *tooltip) { char *markup; /* Description à construire */ VMPA_BUFFER(value); /* Traduction en texte */ /* Nom */ if (portion->desc != NULL) { markup = strdup(""); markup = stradd(markup, portion->desc); markup = stradd(markup, "\n"); markup = stradd(markup, "\n"); } else markup = strdup(""); markup = stradd(markup, "taille : "); mrange_length_to_string(&portion->range, MDS_UNDEFINED, value, NULL); markup = stradd(markup, value); markup = stradd(markup, "\n"); /* Localisation */ markup = stradd(markup, ""); markup = stradd(markup, _("Localisation")); markup = stradd(markup, "\n"); markup = stradd(markup, _("physical: from ")); mrange_phys_to_string(&portion->range, MDS_UNDEFINED, true, value, NULL); markup = stradd(markup, value); markup = stradd(markup, _(" to ")); mrange_phys_to_string(&portion->range, MDS_UNDEFINED, false, value, NULL); markup = stradd(markup, value); markup = stradd(markup, "\n"); markup = stradd(markup, _("memory: from ")); mrange_virt_to_string(&portion->range, MDS_UNDEFINED, true, value, NULL); markup = stradd(markup, value); markup = stradd(markup, _(" to ")); mrange_virt_to_string(&portion->range, MDS_UNDEFINED, false, value, NULL); markup = stradd(markup, value); markup = stradd(markup, "\n\n"); /* Droits d'accès */ markup = stradd(markup, ""); markup = stradd(markup, _("Rights")); markup = stradd(markup, "\n"); snprintf(value, 2 * VMPA_MAX_SIZE, "%s%s%s", portion->rights & PAC_READ ? "r" : "-", portion->rights & PAC_WRITE ? "w" : "-", portion->rights & PAC_EXEC ? "x" : "-"); markup = stradd(markup, value); /* Impression finale */ gtk_tooltip_set_markup(tooltip, markup); free(markup); } /****************************************************************************** * * * Paramètres : portion = portion mère à consulter. * * full = taille totale de la couche parente. * * area = étendue de représentation de la portion mère. * * sub_area = étendue de représentation de la portion fille. * * * * Description : Détermine l'aire d'une sous-portion. * * * * Retour : true si la sous-surface a été calculée correctement. * * * * Remarques : - * * * ******************************************************************************/ static bool g_binary_portion_compute_sub_area(const GBinPortion *portion, phys_t full, const GdkRectangle *area, GdkRectangle *sub_area) { phys_t length; /* Taille de la portion */ phys_t start; /* Position de départ */ length = get_mrange_length(&portion->range); /* On saute les portions comme le segment GNU_STACK... */ if (length == 0) return false; start = get_phy_addr(get_mrange_addr(&portion->range)); sub_area->y = area->y; sub_area->height = area->height; sub_area->x = area->x + (start * area->width) / full; sub_area->width = (length * area->width) / full; return true; } /****************************************************************************** * * * Paramètres : portion = description de partie à consulter. * * context = contexte graphique associé à la procédure. * * cr = contexte graphique pour le dessin. * * area = étendue mise à disposition. * * * * Description : Représente la portion sur une bande dédiée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area) { phys_t full; /* Espace total représenté */ size_t i; /* Boucle de parcours */ GBinPortion *sub; /* Portion incluse à montrer */ GdkRectangle sub_area; /* Etendue d'une sous-portion */ /* Dessin de la portion courante */ cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); gtk_style_context_save(context); gtk_style_context_add_class(context, portion->code); gtk_render_background(context, cr, area->x, area->y, area->width, area->height); gtk_render_frame(context, cr, area->x, area->y, area->width, area->height); gtk_style_context_restore(context); /* Dessin des portions contenues */ full = get_mrange_length(&portion->range); for (i = 0; i < portion->count; i++) { sub = portion->subs[i]; if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area)) continue; g_binary_portion_draw(sub, context, cr, &sub_area); } } /****************************************************************************** * * * Paramètres : portion = portion principale à compléter. * * sub = portion à inclure dans la définition courante. * * * * Description : Procède à l'inclusion d'une portion dans une autre. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_binary_portion_include(GBinPortion *portion, GBinPortion *sub) { bool found; /* Zone d'accueil trouvée ? */ size_t best; /* Meilleur point d'insertion */ size_t missed; /* Indice de zone à déplacer */ const mrange_t *brange; /* Raccourci de confort d'usage*/ vmpa2t end; /* Fin de la zone commune */ phys_t overlapping; /* Taille de la zone commune */ bool continued; /* Suite d'une découpe ? */ GBinPortion *left_part; /* Partie intégrable */ vmpa2t start; /* Départ de la seconde partie */ GBinPortion *right_part; /* Partie restante */ int g_binary_portion_is_included(const GBinPortion **a, const GBinPortion **b) { int result; /* Bilan à retourner */ result = mrange_includes_mrange(&(*b)->range, &(*a)->range); return result; } found = bsearch_index(&sub, portion->subs, portion->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_is_included, &best); if (!found) { /** * On se prépare à réaliser une insertion au niveau courant. Mais des * portions précédentes sont peut-être à déplacer dans la nouvelle zone : * * EXIDX 0x001178 0x00009178 0x00009178 0x00008 0x00008 R 0x4 * PHDR 0x000034 0x00008034 0x00008034 0x00120 0x00120 R E 0x4 * INTERP 0x000154 0x00008154 0x00008154 0x00019 0x00019 R 0x1 * LOAD 0x000000 0x00008000 0x00008000 0x01184 0x01184 R E 0x8000 * * On refait donc une passe sur toutes les sous-portions du niveau. * * Cette approche a le mérite de traiter également et naturellement les * sections définies dans le désordre : * * [21] .bss NOBITS 00088240 07823c 0018c8 00 WA 0 0 8 * [22] __libc_freeres_ptrs NOBITS 00089b08 07823c 000018 00 WA 0 0 4 * [23] .comment PROGBITS 00000000 07823c 000022 01 MS 0 0 1 * * Quant aux cas de figure où les portions sont identiques, l'ordre d'appel * induit l'ordre d'inclusion. * * Cela concerne par exemple les zones de données : * * En-têtes de section: * [Nr] Nom Type Adr Décala.Taille ES Fan LN Inf Al * ... * [ 2] .data PROGBITS 00010098 000098 00000c 00 WA 0 0 1 * * En-têtes de programme: * Type Décalage Adr. vir. Adr.phys. T.Fich. T.Mém. Fan Alignement * ... * LOAD 0x000098 0x00010098 0x00010098 0x0000c 0x0000c RW 0x8000 * */ int g_binary_portion_track_missed_inclusion(const GBinPortion **a, const GBinPortion **b) { int result; /* Bilan à retourner */ result = mrange_includes_mrange(&(*a)->range, &(*b)->range); return result; } do { found = bsearch_index(&sub, portion->subs, portion->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_track_missed_inclusion, &missed); if (found) { g_binary_portion_include(sub, portion->subs[missed]); portion->subs = _qdelete(portion->subs, &portion->count, sizeof(GBinPortion *), missed); } } while (found); /** * Il peut arriver que certaines portions débordent de leur zone d'inclusion : * * [24] .bss NOBITS 00012088 002084 000044 00 WA 0 0 8 * [25] .ARM.attributes ARM_ATTRIBUTES 00000000 002084 000037 00 0 0 1 * [26] .shstrtab STRTAB 00000000 0020bb 0000ed 00 0 0 1 * * Afin de respecter une certaine cohérence dans l'arbre des portions, on choisit * de découper la portion qui déborde. */ int g_binary_portion_track_partial_inclusion(const GBinPortion **a, const GBinPortion **b) { int result; /* Bilan à retourner */ result = cmp_mrange_with_vmpa(&(*b)->range, get_mrange_addr(&(*a)->range)); return result; } found = bsearch_index(&sub, portion->subs, portion->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_track_partial_inclusion, &best); if (found) { brange = &portion->subs[best]->range; compute_mrange_end_addr(brange, &end); overlapping = compute_vmpa_diff(get_mrange_addr(&sub->range), &end); continued = g_binary_portion_is_continuation(sub); /* Partie contenue */ left_part = g_binary_portion_new(sub->code, get_mrange_addr(&sub->range), overlapping); g_binary_portion_set_desc(left_part, sub->desc); g_binary_portion_mark_as_continued(left_part, continued); g_binary_portion_set_rights(left_part, sub->rights); /* Partie qui déborde... */ /** * Comme la portion incluante peut avoir une définition d'adresse * virtuelle différente de celle de la portion incluse, on recalcule * la position de départ de la seconde partie de la portion découpée * à partir des données d'origine. */ copy_vmpa(&start, get_mrange_addr(&sub->range)); advance_vmpa(&start, overlapping); right_part = g_binary_portion_new(sub->code, &start, get_mrange_length(&sub->range) - overlapping); if (!continued) g_binary_portion_mark_as_continued(right_part, true); g_binary_portion_set_desc(right_part, sub->desc); if (continued) g_binary_portion_mark_as_continued(right_part, true); g_binary_portion_set_rights(right_part, sub->rights); /* Inclusions des parties */ g_binary_portion_include(portion, left_part); g_binary_portion_include(portion, right_part); g_object_unref(G_OBJECT(sub)); } else portion->subs = qinsert(portion->subs, &portion->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare, &sub); } /* Poursuite de l'inclusion dans la sous-portion adaptée... */ else g_binary_portion_include(portion->subs[best], sub); } /****************************************************************************** * * * Paramètres : portion = première couche amorçant la visite. * * visitor = fonction à appeler à chaque étape de la descente. * * data = adresse pointant vers des données de l'utilisateur.* * * * Description : Parcourt un ensemble de portions binaires. * * * * Retour : true si la visite a été jusqu'à son terme, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_portion_visit(GBinPortion *portion, visit_portion_fc visitor, void *data) { bool result; /* Etat à retourner */ bool visit_portion(GBinPortion *p, GBinPortion *pp) { bool ret; /* Etat à retourner */ size_t i; /* Boucle de parcours */ if (p->count == 0) ret = visitor(p, pp, BPV_SHOW, data); else { ret = visitor(p, pp, BPV_ENTER, data); for (i = 0; i < p->count && ret; i++) ret = visit_portion(p->subs[i], p); if (ret) ret = visitor(p, pp, BPV_EXIT, data); } return ret; } result = visit_portion(portion, NULL); return result; } /* ---------------------------------------------------------------------------------- */ /* OFFRE DE CAPACITES DE GENERATION */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : portion = générateur à consulter. * * * * Description : Indique le nombre de ligne prêtes à être générées. * * * * Retour : Nombre de lignes devant apparaître au final. * * * * Remarques : - * * * ******************************************************************************/ static size_t g_binary_portion_count_lines(const GBinPortion *portion) { return portion->lcount; } /****************************************************************************** * * * Paramètres : portion = générateur à consulter. * * x = position géographique sur la ligne concernée. * * index = indice de cette même ligne dans le tampon global. * * repeat = indice d'utilisations successives du générateur. * * cursor = emplacement à constituer. [OUT] * * * * Description : Retrouve l'emplacement correspondant à une position donnée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_compute_cursor(const GBinPortion *portion, gint x, size_t index, size_t repeat, GLineCursor **cursor) { *cursor = g_binary_cursor_new(); g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&portion->range)); } /****************************************************************************** * * * Paramètres : portion = générateur à consulter. * * index = indice de cette même ligne dans le tampon global. * * repeat = indice d'utilisations successives du générateur. * * cursor = emplacement à analyser. * * * * Description : Détermine si le conteneur s'inscrit dans une plage donnée. * * * * Retour : Bilan de la détermination, utilisable en comparaisons. * * * * Remarques : - * * * ******************************************************************************/ static int g_binary_portion_contains_cursor(const GBinPortion *portion, size_t index, size_t repeat, const GLineCursor *cursor) { int result; /* Conclusion à retourner */ vmpa2t addr; /* Autre emplacement à comparer*/ assert(G_IS_BINARY_CURSOR(cursor)); g_binary_cursor_get_info(G_BINARY_CURSOR(cursor), &addr); result = cmp_vmpa(&addr, get_mrange_addr(&portion->range)); return result; } /****************************************************************************** * * * Paramètres : portion = générateur à consulter. * * index = indice de cette même ligne dans le tampon global. * * repeat = indice d'utilisations successives du générateur. * * * * Description : Renseigne sur les propriétés liées à un générateur. * * * * Retour : Propriétés particulières associées. * * * * Remarques : - * * * ******************************************************************************/ static BufferLineFlags g_binary_portion_get_flags(const GBinPortion *portion, size_t index, size_t repeat) { return (repeat == 0 ? BLF_WIDTH_MANAGER : BLF_NONE); } /****************************************************************************** * * * Paramètres : portion = générateur à utiliser pour l'impression. * * line = ligne de rendu à compléter. * * index = indice de cette même ligne dans le tampon global. * * repeat = indice d'utilisations successives du générateur. * * content = éventuel contenu binaire brut à imprimer. * * * * Description : Imprime dans une ligne de rendu le contenu représenté. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_binary_portion_print(GBinPortion *portion, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) { assert(repeat < portion->lcount); g_buffer_line_fill_vmpa(line, get_mrange_addr(&portion->range), MDS_32_BITS_UNSIGNED, MDS_32_BITS_UNSIGNED); if (portion->text[repeat] != NULL) { g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_LABEL); g_buffer_line_append_text(line, BLC_ASSEMBLY_LABEL, SL(portion->text[repeat]), RTT_COMMENT, NULL); } } /* ---------------------------------------------------------------------------------- */ /* PARCOURS D'ENSEMBLES DE PORTIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : portion = couche de portions à parcourir pour les recherches.* * * * Description : Compte le nombre de portions présentes dans une arborescence.* * * * Retour : Quantité de portions présentes. * * * * Remarques : - * * * ******************************************************************************/ size_t g_binary_portion_count(const GBinPortion *portion) { size_t result; /* Quantité à retourner */ size_t measure_portion_size(const GBinPortion *root) { size_t count; /* Nombre de trouvailles */ size_t i; /* Boucle de parcours */ count = 1; for (i = 0; i < root->count; i++) count += measure_portion_size(root->subs[i]); return count; } result = measure_portion_size(portion); return result; } /****************************************************************************** * * * Paramètres : portion = couche de portions à parcourir pour les recherches.* * x = abscisse du point de recherche. * * area = étendue de portion mère, puis celle trouvée. [OUT] * * * * Description : Recherche la portion présente à un point donné. * * * * Retour : Portion trouvée à l'endroit indiqué. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion *g_binary_portion_find_at_pos(GBinPortion *portion, gint x, GdkRectangle *area) { GBinPortion *result; /* Portion à retourner */ phys_t full; /* Espace total représenté */ size_t i; /* Boucle de parcours */ GBinPortion *sub; /* Portion incluse à traiter */ GdkRectangle sub_area; /* Etendue d'une sous-portion */ result = NULL; full = get_mrange_length(&portion->range); for (i = 0; i < portion->count && result == NULL; i++) { sub = portion->subs[i]; if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area)) continue; if (sub_area.x <= x && x < (sub_area.x + sub_area.width)) { result = g_binary_portion_find_at_pos(sub, x, &sub_area); if (result != NULL) *area = sub_area; } } if (result == NULL) { result = portion; g_object_ref(G_OBJECT(result)); } return result; } /****************************************************************************** * * * Paramètres : portion = portion mère à consulter. * * addr = adresse du point de recherche. * * * * Description : Détermine si une portion contient une adresse donnée. * * * * Retour : true ou false selon le résultat. * * * * Remarques : - * * * ******************************************************************************/ static bool g_binary_portion_contains_vmpa(const GBinPortion *portion, const vmpa2t *addr) { bool result; /* Bilan à retourner */ const mrange_t *range; /* Emplacement de portion */ result = false; range = g_binary_portion_get_range(portion); /* Portion non allouée en mémoire : on écarte */ if (!has_virt_addr(get_mrange_addr(range))) goto not_found; result = mrange_contains_addr(range, addr); not_found: return result; } /****************************************************************************** * * * Paramètres : portion = couche de portions à parcourir pour les recherches.* * addr = adresse du point de recherche. * * area = étendue de portion mère, puis celle trouvée. [OUT] * * * * Description : Recherche la portion présente à une adresse donnée. * * * * Retour : Portion trouvée à l'endroit indiqué. * * * * Remarques : - * * * ******************************************************************************/ GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *addr, GdkRectangle *area) { GBinPortion *result; /* Portion à retourner */ phys_t full; /* Espace total représenté */ size_t i; /* Boucle de parcours #1 */ GBinPortion *sub; /* Portion incluse à traiter */ GdkRectangle sub_area; /* Etendue d'une sous-portion */ result = NULL; full = get_mrange_length(&portion->range); for (i = 0; i < portion->count && result == NULL; i++) { sub = portion->subs[i]; if (!g_binary_portion_contains_vmpa(sub, addr)) continue; if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area)) continue; result = g_binary_portion_find_at_addr(sub, addr, &sub_area); if (result != NULL) *area = sub_area; } if (result == NULL) { result = portion; g_object_ref(G_OBJECT(result)); } return result; } /****************************************************************************** * * * Paramètres : root = couche de portions à parcourir pour les recherches. * * x = abscisse du point de recherche. * * area = étendue de représentation de la portion mère. * * addr = adresse correspondante. [OUT] * * * * Description : Fournit la position correspondant à une adresse donnée. * * * * Retour : Succès de la traduction. * * * * Remarques : - * * * ******************************************************************************/ bool get_binary_portion_addr_from_pos(GBinPortion *root, gint x, const GdkRectangle *area, vmpa2t *addr) { GdkRectangle owner_area; /* Aire de contenance */ GBinPortion *owner; /* Conteneur propriétaire */ owner_area = *area; owner = g_binary_portion_find_at_pos(root, x, &owner_area); if (owner == NULL) return false; copy_vmpa(addr, get_mrange_addr(&owner->range)); advance_vmpa(addr, (get_mrange_length(&owner->range) * (x - owner_area.x)) / owner_area.width); g_object_unref(G_OBJECT(owner)); return true; } /****************************************************************************** * * * Paramètres : root = couche de portions à parcourir pour les recherches. * * addr = adresse du point de recherche. * * area = étendue de représentation de la portion mère. * * x = position correspondante. [OUT] * * * * Description : Fournit l'adresse correspondant à une position donnée. * * * * Retour : Succès de la traduction. * * * * Remarques : - * * * ******************************************************************************/ bool get_binary_portion_pos_from_addr(GBinPortion *root, const vmpa2t *addr, const GdkRectangle *area, gint *x) { GdkRectangle owner_area; /* Aire de contenance */ GBinPortion *owner; /* Conteneur propriétaire */ phys_t diff; /* Décalage à appliquer */ owner_area = *area; owner = g_binary_portion_find_at_addr(root, addr, &owner_area); if (owner == NULL) return false; diff = compute_vmpa_diff(addr, get_mrange_addr(&owner->range)); *x = owner_area.x + (diff * owner_area.width) / get_mrange_length(&owner->range); g_object_unref(G_OBJECT(owner)); return true; } /****************************************************************************** * * * Paramètres : layer = couche de portions à consulter. * * x = abscisse du point de recherche. * * y = ordonnée du point de recherche. * * area = étendue de représentation de la portion mère. * * tooltip = astuce à compléter. [OUT] * * * * Description : Prépare une astuce concernant une portion pour son affichage.* * * * Retour : TRUE pour valider l'affichage. * * * * Remarques : - * * * ******************************************************************************/ gboolean query_tooltip_for_binary_portion(GBinPortion *root, gint x, gint y, const GdkRectangle *area, GtkTooltip *tooltip) { GBinPortion *selected; /* Portion à décrire ici */ selected = g_binary_portion_find_at_pos(root, x, (GdkRectangle []) { *area }); if (selected == NULL) return FALSE; g_binary_portion_query_tooltip(selected, tooltip); g_object_unref(G_OBJECT(selected)); return TRUE; } /****************************************************************************** * * * Paramètres : portion = portion mère à consulter. * * off = position physique du point de recherche. * * * * Description : Détermine si une portion contient une position donnée. * * * * Retour : true ou false selon le résultat. * * * * Remarques : - * * * ******************************************************************************/ static bool g_binary_portion_contains_physical(const GBinPortion *portion, phys_t off) { bool result; /* Bilan à retourner */ const mrange_t *range; /* Emplacement de portion */ const vmpa2t *addr; /* Départ de la portion */ range = g_binary_portion_get_range(portion); addr = get_mrange_addr(range); if (!has_phys_addr(addr)) result = false; else result = (addr->physical <= off && off < (addr->physical + range->length)); return result; } /****************************************************************************** * * * Paramètres : portion = couche de portions à parcourir pour les recherches.* * off = position physique à retrouver. * * pos = position correspondante. [OUT] * * * * Description : Fournit l'emplacement correspondant à une position physique. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_portion_translate_offset_into_vmpa(const GBinPortion *portion, phys_t off, vmpa2t *pos) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours #1 */ GBinPortion *sub; /* Portion incluse à traiter */ const mrange_t *range; /* Emplacement de portion */ const vmpa2t *addr; /* Départ de la portion */ result = false; for (i = 0; i < portion->count; i++) { sub = portion->subs[i]; if (!g_binary_portion_contains_physical(sub, off)) continue; result = g_binary_portion_translate_offset_into_vmpa(sub, off, pos); break; } if (i == portion->count) { result = g_binary_portion_contains_physical(portion, off); if (result) { range = g_binary_portion_get_range(portion); addr = get_mrange_addr(range); if (has_virt_addr(get_mrange_addr(range))) init_vmpa(pos, off, addr->virtual + off - addr->physical); else init_vmpa(pos, off, VMPA_NO_VIRTUAL); } } return result; } /****************************************************************************** * * * Paramètres : portion = portion mère à consulter. * * virt = adresse virtuelle du point de recherche. * * * * Description : Détermine si une portion contient une adresse donnée. * * * * Retour : true ou false selon le résultat. * * * * Remarques : - * * * ******************************************************************************/ static bool g_binary_portion_contains_virtual(const GBinPortion *portion, virt_t virt) { bool result; /* Bilan à retourner */ const mrange_t *range; /* Emplacement de portion */ const vmpa2t *addr; /* Départ de la portion */ range = g_binary_portion_get_range(portion); addr = get_mrange_addr(range); if (!has_virt_addr(addr)) result = false; else result = (addr->virtual <= virt && virt < (addr->virtual + range->length)); return result; } /****************************************************************************** * * * Paramètres : portion = couche de portions à parcourir pour les recherches.* * virt = adresse virtuelle à retrouver. * * pos = position correspondante. [OUT] * * * * Description : Fournit l'emplacement correspondant à une adresse virtuelle. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_binary_portion_translate_address_into_vmpa(const GBinPortion *portion, virt_t virt, vmpa2t *pos) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours #1 */ GBinPortion *sub; /* Portion incluse à traiter */ const mrange_t *range; /* Emplacement de portion */ const vmpa2t *addr; /* Départ de la portion */ result = false; for (i = 0; i < portion->count; i++) { sub = portion->subs[i]; if (!g_binary_portion_contains_virtual(sub, virt)) continue; result = g_binary_portion_translate_address_into_vmpa(sub, virt, pos); break; } if (i == portion->count) { result = g_binary_portion_contains_virtual(portion, virt); if (result) { range = g_binary_portion_get_range(portion); addr = get_mrange_addr(range); if (has_phys_addr(addr) && has_virt_addr(addr)) init_vmpa(pos, addr->physical + virt - addr->virtual, virt); else init_vmpa(pos, VMPA_NO_PHYSICAL, virt); } } return result; }