/* Chrysalide - Outil d'analyse de fichiers binaires
* preload.c - préchargement d'instructions à partir d'un format
*
* Copyright (C) 2017-2018 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 "preload.h"
#include
#include "preload-int.h"
/* Initialise la classe des préchargements à partir d'un format. */
static void g_preload_info_class_init(GPreloadInfoClass *);
/* Initialise une instance de préchargement à partir de format. */
static void g_preload_info_init(GPreloadInfo *);
/* Supprime toutes les références externes. */
static void g_preload_info_dispose(GPreloadInfo *);
/* Procède à la libération totale de la mémoire. */
static void g_preload_info_finalize(GPreloadInfo *);
/* Indique le type défini pour un préchargement à partir d'un format. */
G_DEFINE_TYPE(GPreloadInfo, g_preload_info, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des préchargements à partir d'un format.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_preload_info_class_init(GPreloadInfoClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_preload_info_dispose;
object->finalize = (GObjectFinalizeFunc)g_preload_info_finalize;
}
/******************************************************************************
* *
* Paramètres : info = instance à initialiser. *
* *
* Description : Initialise une instance de préchargement à partir de format. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_preload_info_init(GPreloadInfo *info)
{
info->instructions = NULL;
info->comments = NULL;
}
/******************************************************************************
* *
* Paramètres : info = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_preload_info_dispose(GPreloadInfo *info)
{
size_t count; /* Borne de parcours */
size_t i; /* Boucle de parcours */
GArchInstruction *instr; /* Instruction à libérer */
GDbComment *comment; /* Commentaire à libérer */
g_preload_info_lock_instructions(info);
count = _g_preload_info_count_instructions(info);
for (i = 0; i < count; i++)
{
instr = _g_preload_info_grab_instruction(info, i);
g_object_unref(G_OBJECT(instr));
}
_g_preload_info_drain_instructions(info);
g_preload_info_unlock_instructions(info);
g_preload_info_lock_comments(info);
count = _g_preload_info_count_comments(info);
for (i = 0; i < count; i++)
{
comment = _g_preload_info_grab_comment(info, i);
g_object_unref(G_OBJECT(comment));
}
_g_preload_info_drain_comments(info);
g_preload_info_unlock_comments(info);
G_OBJECT_CLASS(g_preload_info_parent_class)->dispose(G_OBJECT(info));
}
/******************************************************************************
* *
* Paramètres : info = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_preload_info_finalize(GPreloadInfo *info)
{
G_OBJECT_CLASS(g_preload_info_parent_class)->finalize(G_OBJECT(info));
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée une nouvelle collecte d'informations préchargées. *
* *
* Retour : Adresse de l'instance mise en place ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GPreloadInfo *g_preload_info_new(void)
{
GPreloadInfo *result; /* Nouveau preloade à renvoyer */
result = g_object_new(G_TYPE_PRELOAD_INFO, NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : src = collecte à consulter. *
* dest = collecte à constituer. [OUT] *
* *
* Description : Copie le contenu d'une collecte d'informations préchargées. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_copy(GPreloadInfo *src, GPreloadInfo *dest)
{
void inc_preloaded_item_ref(GObject **item)
{
g_object_ref(*item);
}
copy_flat_array_items(&src->instructions, &dest->instructions,
sizeof(GArchInstruction *), (item_notify_cb)inc_preloaded_item_ref);
copy_flat_array_items(&src->comments, &dest->comments,
sizeof(GDbComment *), (item_notify_cb)inc_preloaded_item_ref);
}
/******************************************************************************
* *
* Paramètres : info = préchargements à mettre à jour. *
* *
* Description : Verrouille les accès à la liste des instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_lock_instructions(GPreloadInfo *info)
{
lock_flat_array(&info->instructions);
}
/******************************************************************************
* *
* Paramètres : info = préchargements à mettre à jour. *
* *
* Description : Déverrouille les accès à la liste des instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_unlock_instructions(GPreloadInfo *info)
{
unlock_flat_array(&info->instructions);
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* instr = instruction à venir associer. *
* *
* Description : Ajoute une instruction supplémentaire aux préchargements. *
* *
* Retour : true si l'instruction a bien été insérée, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_preload_info_add_instruction(GPreloadInfo *info, GArchInstruction *instr)
{
bool result; /* Bilan à retourner */
g_preload_info_lock_instructions(info);
result = _g_preload_info_add_instruction(info, instr);
g_preload_info_unlock_instructions(info);
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* instr = instruction à venir associer. *
* *
* Description : Ajoute une instruction supplémentaire aux préchargements. *
* *
* Retour : true si l'instruction a bien été insérée, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _g_preload_info_add_instruction(GPreloadInfo *info, GArchInstruction *instr)
{
bool result; /* Bilan à retourner */
int cmp_instr_by_addr(const GArchInstruction **a, const GArchInstruction **b)
{
const mrange_t *range_a; /* Emplacement pour l'instr. A */
const mrange_t *range_b; /* Emplacement pour l'instr. B */
range_a = g_arch_instruction_get_range(*a);
range_b = g_arch_instruction_get_range(*b);
return cmp_vmpa(get_mrange_addr(range_a), get_mrange_addr(range_b));
}
result = !_g_preload_info_has_instruction_for(info, g_arch_instruction_get_range(instr));
if (result)
insert_item_into_flat_array(&info->instructions, &instr, sizeof(GArchInstruction *),
(__compar_fn_t)cmp_instr_by_addr);
else
g_object_unref(G_OBJECT(instr));
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* range = emplacement de l'instruction recherchés. *
* *
* Description : Détermine si une instruction existe sur un espace donné. *
* *
* Retour : true si une instruction existe à l'emplacement indiqué. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _g_preload_info_has_instruction_for(GPreloadInfo *info, const mrange_t *range)
{
bool result; /* Bilan à retourner */
GArchInstruction **ptr; /* Adresse dans le tableau */
int check_for_overlap(const mrange_t *key, const GArchInstruction **i)
{
const mrange_t *irange; /* Emplacement pour l'instr. */
int status; /* Bilan de la recherche */
irange = g_arch_instruction_get_range(*i);
if (mrange_intersects_mrange(irange, key))
status = 0;
else
status = cmp_vmpa(get_mrange_addr(key), get_mrange_addr(irange));
return status;
}
ptr = find_item_in_flat_array(info->instructions, sizeof(GArchInstruction *),
(__compar_fn_t)check_for_overlap, range);
result = (ptr != NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* addr = localisation de l'instruction recherchée. *
* *
* Description : Détermine si une instruction est présente à un point donné. *
* *
* Retour : true si une instruction existe à l'emplacement indiqué. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _g_preload_info_has_instruction_at(GPreloadInfo *info, const vmpa2t *addr)
{
bool result; /* Bilan à retourner */
GArchInstruction **ptr; /* Adresse dans le tableau */
int cmp_instr_by_addr(const vmpa2t *key, const GArchInstruction **i)
{
const mrange_t *range; /* Emplacement pour l'instr. */
range = g_arch_instruction_get_range(*i);
return cmp_vmpa(key, get_mrange_addr(range));
}
ptr = find_item_in_flat_array(info->instructions, sizeof(GArchInstruction *),
(__compar_fn_t)cmp_instr_by_addr, addr);
result = (ptr != NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à consulter. *
* *
* Description : Indique la quantité d'instructions préchargées disponibles. *
* *
* Retour : Nombre d'instructions attachées. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t _g_preload_info_count_instructions(const GPreloadInfo *info)
{
size_t result; /* Décompte à retourner */
result = count_flat_array_items(info->instructions);
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à consulter. *
* index = indice de l'instruction concernée. *
* *
* Description : Fournit une instruction préchargée donnée. *
* *
* Retour : Instruction trouvée. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *_g_preload_info_grab_instruction(const GPreloadInfo *info, size_t index)
{
GArchInstruction *result; /* Opérande à retourner */
GArchInstruction **ptr; /* Adresse dans le tableau */
ptr = get_flat_array_item(info->instructions, index, sizeof(GArchInstruction *));
result = *ptr;
/**
* La propriétée de l'élément est transmise à l'appelant.
*
* Ainsi, pour vider une liste via _g_preload_info_drain_instructions(),
* il suffit juste de libérer la mémoire occupée pour le stockage sans
* se préoccuper des références contenues ; le gain de temps est important
* puisqu'on évite là un parcours et des déplacements.
*/
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à manipuler. *
* *
* Description : Dépile une instruction présente dans les préchargements. *
* *
* Retour : Instruction retirée ou NULL si aucune. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *g_preload_info_pop_instruction(GPreloadInfo *info)
{
GArchInstruction *result; /* Instruction à retourner */
GArchInstruction **ptr; /* Adresse dans le tableau */
g_preload_info_lock_instructions(info);
if (_g_preload_info_count_instructions(info) == 0)
result = NULL;
else
{
ptr = get_flat_array_item(info->instructions, 0, sizeof(GArchInstruction *));
result = *ptr;
rem_item_from_flat_array(&info->instructions, 0, sizeof(GArchInstruction *));
}
g_preload_info_unlock_instructions(info);
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à manipuler. *
* *
* Description : Retire des préchargements toutes les instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void _g_preload_info_drain_instructions(GPreloadInfo *info)
{
/**
* A utiliser en conjonction avec _g_preload_info_grab_instruction()
* uniquement.
*/
reset_flat_array(&info->instructions);
}
/******************************************************************************
* *
* Paramètres : info = préchargements à mettre à jour. *
* *
* Description : Verrouille les accès à la liste des commentaires. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_lock_comments(GPreloadInfo *info)
{
lock_flat_array(&info->comments);
}
/******************************************************************************
* *
* Paramètres : info = préchargements à mettre à jour. *
* *
* Description : Déverrouille les accès à la liste des commentaires. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_unlock_comments(GPreloadInfo *info)
{
unlock_flat_array(&info->comments);
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* comment = commentaire à venir associer. *
* *
* Description : Ajoute un commentaire supplémentaire aux préchargements. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_add_comment(GPreloadInfo *info, GDbComment *comment)
{
g_preload_info_lock_comments(info);
_g_preload_info_add_comment(info, comment);
g_preload_info_unlock_comments(info);
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* comment = commentaire à venir associer. *
* *
* Description : Ajoute un commentaire supplémentaire aux préchargements. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void _g_preload_info_add_comment(GPreloadInfo *info, GDbComment *comment)
{
int cmp_comment_by_addr(const GDbComment * const *a, const GDbComment * const *b)
{
const vmpa2t *addr_a; /* Position du commentaire A */
const vmpa2t *addr_b; /* Position du commentaire B */
addr_a = g_db_comment_get_address(*a);
addr_b = g_db_comment_get_address(*b);
return cmp_vmpa(addr_a, addr_b);
}
insert_item_into_flat_array(&info->comments, &comment, sizeof(GDbComment *),
(__compar_fn_t)cmp_comment_by_addr);
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à consulter. *
* addr = localisation du commentaire recherché. *
* *
* Description : Recherche un commentaire dans des préchargements. *
* *
* Retour : Eventuel commentaire retrouvé ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GDbComment *_g_preload_info_find_comment_at(GPreloadInfo *info, const vmpa2t *addr)
{
GDbComment *result; /* Trouvaille à retourner */
GDbComment **ptr; /* Adresse dans le tableau */
ptr = find_item_in_flat_array(info->comments, sizeof(GDbComment *),
(__compar_fn_t)compare_comment_by_addr, addr);
if (ptr != NULL)
{
result = *ptr;
g_object_ref(G_OBJECT(result));
}
else
result = NULL;
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à consulter. *
* addr = localisation du commentaire recherché. *
* index = indice du commentaire retrouvé ou NULL. [OUT] *
* *
* Description : Recherche un commentaire dans des préchargements. *
* *
* Retour : Eventuel commentaire retrouvé ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GDbComment *g_preload_info_find_comment_at(GPreloadInfo *info, const vmpa2t *addr, size_t *index)
{
GDbComment *result; /* Trouvaille à retourner */
GDbComment **ptr; /* Adresse dans le tableau */
ptr = find_item_in_flat_array(info->comments, sizeof(GDbComment *),
(__compar_fn_t)compare_comment_by_addr, addr);
if (ptr != NULL)
{
result = *ptr;
g_object_ref(G_OBJECT(result));
if (index != NULL)
*index = ((void **)ptr - info->comments);
}
else
result = NULL;
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à mettre à jour. *
* index = indice du commentaire à remplacer. *
* comment = commentaire à venir associer. *
* *
* Description : Remplace un commentaire par un autre à un emplacement donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_preload_info_replace_comment_at(GPreloadInfo *info, size_t index, GDbComment *comment)
{
#ifndef NDEBUG
GDbComment **current; /* Commentaire à remplacer */
#endif
#ifndef NDEBUG
current = get_flat_array_item(info->comments, index, sizeof(GDbComment *));
assert(cmp_vmpa(g_db_comment_get_address(*current), g_db_comment_get_address(comment)));
#endif
rpl_item_in_flat_array(info->comments, index, &comment, sizeof(GDbComment *));
}
/******************************************************************************
* *
* Paramètres : info = instance à consulter. *
* *
* Description : Indique la quantité de commentaires préchargés disponibles. *
* *
* Retour : Nombre de commentaires attachés. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t _g_preload_info_count_comments(const GPreloadInfo *info)
{
size_t result; /* Décompte à retourner */
result = count_flat_array_items(info->comments);
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à consulter. *
* index = indice de l'instruction concernée. *
* *
* Description : Fournit un commentaire préchargé donné. *
* *
* Retour : Commentaire trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
GDbComment *_g_preload_info_grab_comment(const GPreloadInfo *info, size_t index)
{
GDbComment *result; /* Opérande à retourner */
GDbComment **ptr; /* Adresse dans le tableau */
ptr = get_flat_array_item(info->comments, index, sizeof(GDbComment *));
result = *ptr;
/**
* La propriétée de l'élément est transmise à l'appelant.
*
* Ainsi, pour vider une liste via _g_preload_info_drain_comments(),
* il suffit juste de libérer la mémoire occupée pour le stockage sans
* se préoccuper des références contenues ; le gain de temps est important
* puisqu'on évite là un parcours et des déplacements.
*/
return result;
}
/******************************************************************************
* *
* Paramètres : info = instance à manipuler. *
* *
* Description : Retire des préchargements tous les commentaires. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void _g_preload_info_drain_comments(GPreloadInfo *info)
{
/**
* A utiliser en conjonction avec _g_preload_info_grab_comment()
* uniquement.
*/
reset_flat_array(&info->comments);
}