/* OpenIDA - Outil d'analyse de fichiers binaires
* line.c - représentation des lignes de rendu
*
* Copyright (C) 2008 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 "line.h"
#include "line-int.h"
#include
#include
#include
#include
#include "line_code.h"
#include "../common/dllist.h"
/* ------------------------ TRAITEMENT INDIVIDUEL DES LIGNES ------------------------ */
/* Initialise la classe des lignes de représentation. */
static void g_rendering_line_class_init(GRenderingLineClass *);
/* Initialise une instance de ligne de représentation. */
static void g_rendering_line_init(GRenderingLine *);
/* Etablit un lien entre deux lignes de représentation. */
static void g_rendering_line_add_link_reference(GRenderingLine *, GRenderingLine *);
/* Charge une image destinée à être rendue avec la ligne. */
static GdkPixbuf *g_rendering_line_render_icon(const GRenderingLine *, const char *, GtkIconSize);
/* ---------------------------------------------------------------------------------- */
/* TRAITEMENT INDIVIDUEL DES LIGNES */
/* ---------------------------------------------------------------------------------- */
/* Indique le type définit pour une ligne de représentation. */
G_DEFINE_TYPE(GRenderingLine, g_rendering_line, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des lignes de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_rendering_line_class_init(GRenderingLineClass *klass)
{
klass->style = gtk_style_new();
g_signal_new("rendering-line-flags-changed",
G_TYPE_RENDERING_LINE,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GRenderingLineClass, rendering_line_flags_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL);
}
/******************************************************************************
* *
* Paramètres : line = instance à initialiser. *
* *
* Description : Initialise une instance de ligne de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_rendering_line_init(GRenderingLine *line)
{
GdkScreen *screen; /* Ecran d'application */
PangoFontDescription *desc; /* Description de la police */
MainRendering i; /* Boucle de parcours */
static PangoContext *context = NULL; /* Contexte graphique Pango */
DL_LIST_ITEM_INIT(&line->link);
if (context == NULL)
{
screen = gdk_screen_get_default();
desc = pango_font_description_from_string("mono 10");
context = gdk_pango_context_get_for_screen(screen);
pango_context_set_font_description(context, desc);
}
for (i = 0; i < MRD_COUNT; i++)
line->layout[i] = pango_layout_new(context);
line->get_bin_len = NULL;
line->refresh_markup = NULL;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* *
* Description : Fournit l'adresse physique ou en mémoire d'une ligne. *
* *
* Retour : Position physique ou en mémoire associée à la ligne. *
* *
* Remarques : - *
* *
******************************************************************************/
vmpa_t get_rendering_line_address(const GRenderingLine *line)
{
return line->offset;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* *
* Description : Fournit le type d'une ligne. *
* *
* Retour : Type de la ligne fournie. *
* *
* Remarques : - *
* *
******************************************************************************/
RenderingLineType get_rendering_line_type(const GRenderingLine *line)
{
return line->type;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à mettre à jour. *
* flag = extension d'information à ajouter. *
* *
* Description : Ajoute une information supplémentaire à une ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_add_flag(GRenderingLine *line, RenderingLineFlag flag)
{
line->flags |= flag;
g_signal_emit_by_name(line, "rendering-line-flags-changed");
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à mettre à jour. *
* flag = extension d'information à retirer. *
* *
* Description : Retire une information supplémentaire sur d'une ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_remove_flag(GRenderingLine *line, RenderingLineFlag flag)
{
line->flags &= ~flag;
g_signal_emit_by_name(line, "rendering-line-flags-changed");
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à mettre à jour. *
* flag = extension d'information à ajouter ou retirer. *
* *
* Description : Bascule l'état d'une information sur d'une ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_toggle_flag(GRenderingLine *line, RenderingLineFlag flag)
{
line->flags = (line->flags & ~flag) | (line->flags ^ flag);
g_signal_emit_by_name(line, "rendering-line-flags-changed");
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* *
* Description : Fournit les informations supplémentaires d'une ligne. *
* *
* Retour : Extensions d'informations courantes. *
* *
* Remarques : - *
* *
******************************************************************************/
RenderingLineFlag g_rendering_line_get_flags(const GRenderingLine *line)
{
return line->flags;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* src = ligne visée par la liaison (côté origine). *
* *
* Description : Etablit un lien entre deux lignes de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_add_link_reference(GRenderingLine *line, GRenderingLine *src)
{
line->from = (GRenderingLine **)realloc(line->from, ++line->from_count * sizeof(GRenderingLine *));
line->from[line->from_count - 1] = src;
}
/******************************************************************************
* *
* Paramètres : line = ligne 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 lignes de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_link_with(GRenderingLine *line, GRenderingLine *dest, InstructionLinkType type)
{
g_rendering_line_add_link_reference(dest, line);
line->to_count++;
line->to = (GRenderingLine **)realloc(line->to, line->to_count * sizeof(GRenderingLine *));
line->links_type = (InstructionLinkType *)realloc(line->links_type, line->to_count * sizeof(InstructionLinkType));
line->to[line->to_count - 1] = dest;
line->links_type[line->to_count - 1] = type;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* *
* Description : Indique si la ligne a une ou plusieurs origines. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_rendering_line_has_sources(const GRenderingLine *line)
{
return (line->from_count > 0);
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* *
* Description : Indique si la ligne a une suite autre que la ligne suivante. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_rendering_line_has_destinations(const GRenderingLine *line)
{
return (line->to_count > 1 || (line->to_count == 1 && line->links_type[0] != ILT_CALL));
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* lines = liste des lignes de destination. [OUT] *
* types = liste des types de liens présents. [OUT] *
* *
* Description : Fournit la ligne de code de destination du lien de la ligne. *
* *
* Retour : Ligne à l'autre extrémité du lien. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_rendering_line_get_destinations(const GRenderingLine *line, GRenderingLine ***lines, InstructionLinkType **types)
{
*lines = line->to;
*types = line->links_type;
return line->to_count;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à consulter. *
* stock_id = identifiant GTK de l'image à charger. *
* size = taille de l'image souhaitée. *
* *
* Description : Charge une image destinée à être rendue avec la ligne. *
* *
* Retour : Image prête à emploi ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
static GdkPixbuf *g_rendering_line_render_icon(const GRenderingLine *line, const char *stock_id, GtkIconSize size)
{
GdkPixbuf *result; /* Elément mis en place / NULL */
GtkStyle *style; /* Style GTK à utiliser */
GtkIconSet *icon_set; /* Liste d'icones */
style = G_RENDERING_LINE_GET_CLASS(line)->style;
icon_set = gtk_style_lookup_icon_set(style, stock_id);
if (icon_set == NULL)
return NULL;
result = gtk_icon_set_render_icon(icon_set, style,
gtk_widget_get_default_direction(),
GTK_STATE_NORMAL, size,
NULL, NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : line = adresse de la structure à représenter. *
* drawable = support de rendu pour le dessin. *
* gc = contexte graphique à utiliser. *
* x0 = abscisse de la zone de rendu (marge). *
* x1 = abscisse de la zone de rendu (texte). *
* y = ordonnée de la zone de rendu. *
* h = hauteur réservée pour la ligne. *
* rendering = support effectif final des lignes de code. *
* *
* Description : Procède à l'initialisation des bases d'une représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_draw(GRenderingLine *line, GdkDrawable *drawable, GdkGC *gc, gint x0, gint x1, gint y, gint h, MainRendering rendering)
{
GdkPixbuf *pixbuf; /* Données utiles au dessin */
gdk_draw_layout(drawable, gc, x1, y, line->layout[rendering]);
if (line->to != NULL)
pixbuf = g_rendering_line_render_icon(line, "gtk-bold", GTK_ICON_SIZE_MENU);
else
if (line->flags & RLF_BREAK_POINT)
pixbuf = g_rendering_line_render_icon(line, "gtk-yes", GTK_ICON_SIZE_MENU);
else if (line->flags & RLF_RUNNING_BP)
pixbuf = g_rendering_line_render_icon(line, "gtk-no", GTK_ICON_SIZE_MENU);
else pixbuf = NULL;
if (pixbuf != NULL)
{
gdk_draw_pixbuf(drawable, gc, pixbuf, 0, 0, x0, y,
gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
GDK_RGB_DITHER_NORMAL, 0, 0);
g_object_unref(pixbuf);
}
/* Le point d'entrée prime */
if (line->flags & RLF_ENTRY_POINT)
pixbuf = g_rendering_line_render_icon(line, "gtk-go-forward", GTK_ICON_SIZE_MENU);
else pixbuf = NULL;
if (pixbuf != NULL)
{
gdk_draw_pixbuf(drawable, gc, pixbuf, 0, 0, x0, y,
gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
GDK_RGB_DITHER_NORMAL, 0, 0);
g_object_unref(pixbuf);
}
}
/* ---------------------------------------------------------------------------------- */
/* TRAITEMENT DES LIGNES PAR GROUPE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : lines = liste de lignes à compléter, ou NULL. *
* line = nouvelle ligne à intégrer à l'ensemble. *
* *
* Description : Ajoute une ligne à un ensemble existant. *
* *
* Retour : - *
* *
* Remarques : La ligne est considérée comme étant insérée au bon endroit. *
* *
******************************************************************************/
void g_rendering_line_add_to_lines(GRenderingLine **lines, GRenderingLine *line)
{
lines_list_add_tail(line, lines);
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes à compléter, ou NULL. *
* line = nouvelle ligne à intégrer à l'ensemble. *
* first = position de la ligne en cas d'adresse partagée. *
* *
* Description : Insère une ligne dans un ensemble existant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_insert_into_lines(GRenderingLine **lines, GRenderingLine *line, bool first)
{
GRenderingLine *iter; /* Boucle de parcours */
lines_list_for_each(iter, *lines)
{
if (first && iter->offset >= line->offset) break;
else if (!first)
{
/* TODO */;
}
}
if (iter == NULL)
lines_list_add_tail(line, lines);
else
{
if (first)
lines_list_splice_before(iter, lines, line);
else
/* TODO */;
}
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes de représentation à actualiser. *
* : iter = position actuelle dans la liste. *
* last = dernière élément imposé du parcours ou NULL. *
* *
* Description : Fournit l'élement suivant un autre pour un parcours. *
* *
* Retour : Elément suivant ou NULL si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
GRenderingLine *g_rendering_line_get_next_iter(GRenderingLine *lines, const GRenderingLine *iter, const GRenderingLine *last)
{
GRenderingLine *result; /* Elément suivant à renvoyer */
if (iter == NULL) iter = lines;
if (iter == last) result = NULL;
else result = lines_list_next_iter(iter, lines);
return result;
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes de représentation à actualiser. *
* last = dernière élément imposé du parcours ou NULL. *
* rendering = support effectif des lignes pour l'appelant. *
* *
* Description : Met à jour le nombre d'octets maximal par instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_update_bin_len(GRenderingLine *lines, GRenderingLine *last, MainRendering rendering)
{
GRenderingLine *iter; /* Boucle de parcours */
off_t bin_len; /* Taille d'instruction */
bin_len = 0;
lines_list_for_each(iter, lines)
{
if (iter->get_bin_len != NULL)
iter->get_bin_len(iter, &bin_len);
if (iter == last) break;
}
lines_list_for_each(iter, lines)
{
iter->max_bin_len[rendering] = (bin_len > 0 ? bin_len * 2 + (bin_len - 1) : 0);
iter->refresh_markup(iter, rendering);
if (iter == last) break;
}
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes de représentation à actualiser. *
* last = dernière élément imposé du parcours ou NULL. *
* rendering = support effectif final des lignes de code. *
* width = largeur maximale des lignes. [OUT] *
* height = hauteur maximale des lignes. [OUT] *
* alone = hauteur d'une seule ligne. [OUT] *
* *
* Description : Fournit les dimensions de lignes de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_rendering_line_get_size(GRenderingLine *lines, const GRenderingLine *last, MainRendering rendering, int *width, int *height, int *alone)
{
GRenderingLine *iter; /* Boucle de parcours */
int w; /* Largeur de l'objet actuelle */
int h; /* Hauteur de l'objet actuelle */
*width = 0;
*height = 0;
*alone = 0;
lines_list_for_each(iter, lines)
{
pango_layout_get_pixel_size(iter->layout[rendering], &w, &h);
*width = MAX(*width, w);
*height += h;
if (iter == lines)
*alone = h;
if (iter == last) break;
}
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes à parcourir. *
* last = dernière élément imposé du parcours ou NULL. *
* y = ordonnée à vérifier et à mettre à jour. [OUT] *
* *
* Description : Recherche une ligne d'après sa position à l'écran. *
* *
* Retour : Ligne représentant l'adresse donnée, NULL si aucune trouvée. *
* *
* Remarques : - *
* *
******************************************************************************/
GRenderingLine *g_rendering_line_find_by_y(GRenderingLine *lines, const GRenderingLine *last, int *y)
{
GRenderingLine *result; /* Trouvaille à retourner */
int h; /* Hauteur de l'objet actuel */
lines_list_for_each(result, lines)
{
/**
* Comme toutes les dispositions ont la même hauteur,
* on utilise la première...
*/
pango_layout_get_pixel_size(result->layout[0], NULL, &h);
if (*y < h) break;
else *y -= h;
if (result == last)
{
result = NULL;
break;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes à parcourir. *
* last = dernière élément imposé du parcours ou NULL. *
* addr = position en mémoire ou physique à chercher. *
* *
* Description : Recherche une ligne d'après sa position en mémoire/physique. *
* *
* Retour : Ligne représentant l'adresse donnée, NULL si aucune trouvée. *
* *
* Remarques : - *
* *
******************************************************************************/
GRenderingLine *g_rendering_line_find_by_address(GRenderingLine *lines, const GRenderingLine *last, vmpa_t addr)
{
GRenderingLine *result; /* Trouvaille à retourner */
lines_list_for_each(result, lines)
{
if (result->offset <= addr && addr < (result->offset + result->length)) break;
if (result == last)
{
result = NULL;
break;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : start = première ligne de l'ensemble à parcourir. *
* last = dernière élément imposé du parcours ou NULL. *
* *
* Description : Donne la première ligne de code correspondant à une adresse. *
* *
* Retour : Ligne de code pour l'adresse donnée, NULL si aucune trouvée. *
* *
* Remarques : - *
* *
******************************************************************************/
GRenderingLine *g_rendering_line_loop_for_code(GRenderingLine *start, const GRenderingLine *last)
{
GRenderingLine *result; /* Trouvaille à retourner */
vmpa_t reference; /* Adresse à conserver */
result = start;
reference = start->offset;
lines_list_for_each(result, start)
{
if (G_IS_CODE_LINE(result)) break;
if (result->offset != reference)
{
result = NULL;
break;
}
if (result == last)
{
result = NULL;
break;
}
}
return result;
}