/* 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
#include
#include
#include
#include "../common/dllist.h"
/* FIXME */
extern GtkWidget *mywid;
/* Méthode de mise à jour du nombre d'octets maximal par instruction. */
typedef void (* get_bin_len_fc) (rendering_line *, off_t *);
/* Méthode de mise à jour d'une ligne de représentation. */
typedef void (* refresh_markup_fc) (rendering_line *);
/* Ligne de représentation générique */
struct _rendering_line
{
DL_LIST_ITEM;
uint64_t offset; /* Position en mémoire/physique*/
RenderingLineType type; /* Type de représentation */
RenderingLineFlag flags; /* Extension d'informations */
PangoLayout *layout; /* Moteur de rendu du code/txt */
get_bin_len_fc get_bin_len; /* Nbre d'octets représentés */
off_t max_bin_len; /* Nombre global maximal */
refresh_markup_fc refresh_markup; /* Reconstruit la représentat° */
};
#define RENDERING_LINE(l) ((rendering_line *)l)
/* Procède à l'initialisation des bases d'une représentation. */
void init_rendering_line(rendering_line *);
/* ------------------------- LIGNE EN TETE DE DESASSEMBLAGE ------------------------- */
/* Ligne de représentation de prologue */
typedef struct _prologue_line
{
rendering_line basic; /* A laisser en premier */
char *comment; /* Texte à afficher */
} prologue_line;
/* Met à jour la ligne de représentation de prologue. */
void refresh_prologue_markup(prologue_line *);
/* ----------------------- COMMENTAIRES SUR UNE LIGNE ENTIERE ----------------------- */
/* Ligne de commantaires entière */
typedef struct _comment_line
{
rendering_line basic; /* A laisser en premier */
char *comment; /* Texte à afficher */
const disass_options *options; /* Options de représentation */
} comment_line;
/* Met à jour la ligne de représentation de commentaires. */
void refresh_comment_markup(comment_line *);
/* ------------------------ LIGNE DE CODE EN LANGAGE MACHINE ------------------------ */
/* Ligne de représentation de prologue */
typedef struct _code_line
{
rendering_line basic; /* A laisser en premier */
asm_instr *instr; /* Instruction représentée */
const disass_options *options; /* Options de représentation */
} code_line;
/* Taille max d'une traduction */
#define CODE_BUFFER_LEN 128
/* Met à jour la nombre d'octets maximale par instruction. */
void get_code_binary_len(code_line *, off_t *);
/* Met à jour la ligne de représentation de code. */
void refresh_code_markup(code_line *);
/******************************************************************************
* *
* Paramètres : line = adresse de la structure commune. *
* *
* Description : Procède à l'initialisation des bases d'une représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void init_rendering_line(rendering_line *line)
{
DL_LIST_ITEM_INIT(DLL_CAST(line));
line->layout = gtk_widget_create_pango_layout(mywid, NULL);
line->get_bin_len = NULL;
line->refresh_markup = NULL;
}
/******************************************************************************
* *
* 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 add_rendering_line_flag(rendering_line *line, RenderingLineFlag flag)
{
line->flags |= flag;
}
/******************************************************************************
* *
* 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 remove_rendering_line_flag(rendering_line *line, RenderingLineFlag flag)
{
line->flags &= ~flag;
}
/******************************************************************************
* *
* Paramètres : line = ligne dont les informations sont à mettre à jour. *
* *
* Description : Fournit les informations supplémentaires d'une ligne. *
* *
* Retour : Extensions d'informations courantes. *
* *
* Remarques : - *
* *
******************************************************************************/
RenderingLineFlag get_rendering_line_flags(const rendering_line *line)
{
return line->flags;
}
/******************************************************************************
* *
* 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 add_line_to_rendering_lines(rendering_line **lines, rendering_line *line)
{
dl_list_add_tail(DLL_CAST(line), (dl_list_item **)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 insert_line_into_rendering_lines(rendering_line **lines, rendering_line *line, bool first)
{
rendering_line *iter; /* Boucle de parcours */
rendering_line *next; /* Prochaine ligne parcourue */
dl_list_for_each_safe(iter, DLL_HCAST(lines), next, rendering_line *)
{
if (first && iter->offset >= line->offset) break;
else if (!first)
{
/* TODO */;
}
}
if (iter == NULL)
dl_list_add_tail(line, DLL_HCAST(lines));
else
{
if (first)
dl_list_insert_before(line, iter, DLL_HCAST(lines));
else
/* TODO */;
}
}
/******************************************************************************
* *
* Paramètres : lines = liste de lignes à parcourir. *
* offset = 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 : - *
* *
******************************************************************************/
rendering_line *find_offset_in_rendering_lines(const rendering_line **lines, uint64_t offset)
{
rendering_line *result;
dl_list_for_each(result, DLL_HCAST(lines), rendering_line *)
if (result->offset == offset) break;
return result;
}
/******************************************************************************
* *
* Paramètres : line = ligne de représentation à actualiser. *
* blen = longueur maximale à mettre à jour. [OUT] *
* *
* Description : Met à jour le nombre d'octets maximal par instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void get_rendering_line_binary_len(rendering_line *line, off_t *blen)
{
if (line->get_bin_len != NULL)
line->get_bin_len(line, blen);
}
/******************************************************************************
* *
* Paramètres : line = ligne de représentation à actualiser. *
* blen = longueur maximale à prendre en compte. *
* *
* Description : Prend en compte le nombre d'octets maximal par instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void set_rendering_line_max_binary_len(rendering_line *line, off_t blen)
{
line->max_bin_len = blen * 2 + (blen - 1);
line->refresh_markup(line);
}
/******************************************************************************
* *
* Paramètres : line = adresse de la structure à représenter. *
* width = largeur maximale des lignes à compléter. *
* height = hauteur maximale des lignes à compléter. *
* *
* Description : Fournit les dimensions d'une ligne par rapport à d'autres. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void get_rendering_line_size(rendering_line *line, int *width, int *height)
{
int w; /* Largeur de l'objet actuelle */
int h; /* Hauteur de l'objet actuelle */
pango_layout_get_pixel_size(line->layout, &w, &h);
*width = MAX(*width, w);
*height += h;
}
/******************************************************************************
* *
* 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. *
* *
* Description : Procède à l'initialisation des bases d'une représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void draw_rendering_line(rendering_line *line, GdkDrawable *drawable, GdkGC *gc, gint x0, gint x1, gint y, gint h)
{
GdkPixbuf *pixbuf; /* Données utiles au dessin */
gdk_draw_layout(drawable, gc, x1, y, line->layout);
if (line->flags & RLF_ENTRY_POINT)
pixbuf = gtk_widget_render_icon(mywid, "gtk-go-forward", GTK_ICON_SIZE_MENU, NULL);
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);
}
}
/* ---------------------------------------------------------------------------------- */
/* LIGNE EN TETE DE DESASSEMBLAGE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : comment = texte à afficher au final. *
* *
* Description : Crée une des lignes de description initiales. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
rendering_line *create_prologue_line(const char *comment)
{
prologue_line *result; /* Structure à retourner */
result = (prologue_line *)calloc(1, sizeof(prologue_line));
init_rendering_line(RENDERING_LINE(result));
RENDERING_LINE(result)->offset = 0;
RENDERING_LINE(result)->type = RLT_PROLOGUE;
RENDERING_LINE(result)->refresh_markup = (refresh_markup_fc)refresh_prologue_markup;
result->comment = strdup(comment);
return RENDERING_LINE(result);
}
/******************************************************************************
* *
* Paramètres : line = ligne de représentation à actualiser. *
* *
* Description : Met à jour la ligne de représentation de prologue. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void refresh_prologue_markup(prologue_line *line)
{
size_t len; /* Taille du contenu */
char *content; /* Contenu réellement imprimé */
len = strlen("");
len += strlen("; ") + strlen(line->comment);
len += strlen("");
content = (char *)calloc(len + 1, sizeof(char));
snprintf(content, len + 1, "; %s", line->comment);
pango_layout_set_markup(RENDERING_LINE(line)->layout, content, len);
free(content);
}
/* ---------------------------------------------------------------------------------- */
/* COMMENTAIRES SUR UNE LIGNE ENTIERE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : offset = position dans la mémoire ou le fichier. *
* type = type du commentaire. *
* comment = texte à afficher au final. *
* options = paramétrage du rendu. *
* *
* Description : Crée une ligne de commentaires entière. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
rendering_line *create_comment_line(uint64_t offset, RenderingLineType type, const char *comment, const disass_options *options)
{
comment_line *result; /* Structure à retourner */
result = (prologue_line *)calloc(1, sizeof(prologue_line));
init_rendering_line(RENDERING_LINE(result));
RENDERING_LINE(result)->offset = offset;
RENDERING_LINE(result)->type = type;
RENDERING_LINE(result)->refresh_markup = (refresh_markup_fc)refresh_comment_markup;
result->comment = strdup(comment);
result->options = options;
return RENDERING_LINE(result);
}
/******************************************************************************
* *
* Paramètres : line = ligne de représentation à actualiser. *
* *
* Description : Met à jour la ligne de représentation de commentaires. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void refresh_comment_markup(comment_line *line)
{
size_t len; /* Taille du contenu */
char *content; /* Contenu réellement imprimé */
char buffer[CODE_BUFFER_LEN]; /* Zone tampon à utiliser */
size_t clen; /* Taille du commentaire */
len = strlen("") + 1;
content = (char *)calloc(len, sizeof(char));
strcpy(content, "");
/* Eventuelle adresse virtuelle */
if (line->options->show_address)
{
switch (ADM_32BITS /* FIXME */)
{
case ADM_32BITS:
snprintf(buffer, CODE_BUFFER_LEN,
"0x%08llx",
RENDERING_LINE(line)->offset);
break;
case ADM_64BITS:
snprintf(buffer, CODE_BUFFER_LEN,
"0x%16llx",
RENDERING_LINE(line)->offset);
break;
}
len += strlen(buffer);
content = (char *)realloc(content, len * sizeof(char));
strcat(content, buffer);
}
/* Eventuel code brut (sauté) */
if (line->options->show_code)
{
clen = (line->options->show_address ? strlen("\t") : 0);
clen += RENDERING_LINE(line)->max_bin_len;
content = (char *)realloc(content, (len + clen) * sizeof(char));
if (line->options->show_address)
{
strcat(content, "\t");
len += strlen("\t");
}
memset(&content[len - 1], RENDERING_LINE(line)->type == RLT_PROTOTYPE ? '-' : ' ',
RENDERING_LINE(line)->max_bin_len);
len += RENDERING_LINE(line)->max_bin_len;
content[len] = '\0';
}
/* Commentaire proprement dit */
clen = (line->options->show_address || line->options->show_code ? strlen("\t") : 0);
clen += strlen("");
clen += strlen("; ") + strlen(line->comment);
clen += strlen("");
content = (char *)realloc(content, (len + clen) * sizeof(char));
if (line->options->show_address || line->options->show_code)
{
strcat(content, "\t");
len += strlen("\t");
clen -= strlen("\t");
}
snprintf(&content[len - 1], clen + 1, "; %s", line->comment);
len += clen;
/* Finalisation */
len += strlen("");
content = (char *)realloc(content, len * sizeof(char));
strcat(content, "");
pango_layout_set_markup(RENDERING_LINE(line)->layout, content, len - 1);
free(content);
}
/* ---------------------------------------------------------------------------------- */
/* LIGNE DE CODE EN LANGAGE MACHINE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : instr = instruction à représenter. *
* options = paramétrage du rendu. *
* *
* Description : Crée une ligne de représentation de code binaire. *
* *
* Retour : Adresse de la structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
rendering_line *create_code_line(asm_instr *instr, uint64_t offset, const disass_options *options)
{
code_line *result; /* Structure à retourner */
result = (code_line *)calloc(1, sizeof(code_line));
init_rendering_line(RENDERING_LINE(result));
RENDERING_LINE(result)->offset = offset;
RENDERING_LINE(result)->type = RLT_CODE;
RENDERING_LINE(result)->get_bin_len = (get_bin_len_fc)get_code_binary_len;
RENDERING_LINE(result)->refresh_markup = (refresh_markup_fc)refresh_code_markup;
result->instr = instr;
result->options = options;
return RENDERING_LINE(result);
}
/******************************************************************************
* *
* Paramètres : line = ligne de représentation à actualiser. *
* blen = longueur maximale à mettre à jour. [OUT] *
* *
* Description : Met à jour le nombre d'octets maximal par instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void get_code_binary_len(code_line *line, off_t *blen)
{
off_t len; /* Taille propre à la ligne */
get_asm_instr_offset_and_length(line->instr, NULL, &len);
*blen = MAX(*blen, len);
}
/******************************************************************************
* *
* Paramètres : line = ligne de représentation à actualiser. *
* *
* Description : Met à jour la ligne de représentation de code. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void refresh_code_markup(code_line *line)
{
size_t len; /* Taille du contenu */
char *content; /* Contenu réellement imprimé */
off_t bin_offset; /* Début de l'instruction */
off_t bin_len; /* Taille d'instruction */
char buffer[CODE_BUFFER_LEN]; /* Zone tampon à utiliser */
const uint8_t *exe_content; /* Contenu binaire global */
char *bin_code; /* Tampon du code binaire */
off_t k; /* Boucle de parcours #2 */
off_t j; /* Boucle de parcours #1 */
len = strlen("") + 1;
content = (char *)calloc(len, sizeof(char));
strcpy(content, "");
if (line->options->show_code)
get_asm_instr_offset_and_length(line->instr, &bin_offset, &bin_len);
/* Eventuelle adresse virtuelle */
if (line->options->show_address)
{
switch (ADM_32BITS /* FIXME */)
{
case ADM_32BITS:
snprintf(buffer, CODE_BUFFER_LEN,
"0x%08llx",
RENDERING_LINE(line)->offset);
break;
case ADM_64BITS:
snprintf(buffer, CODE_BUFFER_LEN,
"0x%16llx",
RENDERING_LINE(line)->offset);
break;
}
len += strlen(buffer);
content = (char *)realloc(content, len * sizeof(char));
strcat(content, buffer);
}
/* Eventuel code brut */
if (line->options->show_code)
{
exe_content = get_exe_content(line->options->format, NULL);
bin_code = (char *)calloc(RENDERING_LINE(line)->max_bin_len + 1, sizeof(char));
k = 0;
for (j = 0; j < bin_len; j++)
{
if ((j + 1) < bin_len)
k += snprintf(&bin_code[j * (2 + 1)], 4, "%02hhx ", exe_content[bin_offset + j]);
else
k += snprintf(&bin_code[j * (2 + 1)], 3, "%02hhx", exe_content[bin_offset + j]);
}
for (; k < RENDERING_LINE(line)->max_bin_len; k++)
snprintf(&bin_code[k], 2, " ");
if (line->options->show_address) len += strlen("\t");
len += strlen(bin_code);
content = (char *)realloc(content, len * sizeof(char));
if (line->options->show_address) strcat(content, "\t");
strcat(content, bin_code);
free(bin_code);
}
/* Instruction proprement dite */
print_hinstruction(line->options->proc, line->options->format,
line->instr, buffer, CODE_BUFFER_LEN, ASX_INTEL/*FIXME*/);
if (line->options->show_address || line->options->show_code) len += strlen("\t");
len += strlen(buffer);
content = (char *)realloc(content, len * sizeof(char));
if (line->options->show_address || line->options->show_code) strcat(content, "\t");
strcat(content, buffer);
/* Finalisation */
len += strlen("");
content = (char *)realloc(content, len * sizeof(char));
strcat(content, "");
pango_layout_set_markup(RENDERING_LINE(line)->layout, content, len - 1);
free(content);
}