/* Chrysalide - Outil d'analyse de fichiers binaires
* instriter.h - prototypes pour le parcours simplifié d'un ensemble d'instructions
*
* Copyright (C) 2016-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 "instriter.h"
#include
#include "processor.h"
/* Suivi d'un parcours d'instructions */
typedef struct _instr_iter_t
{
GArchProcessor *proc; /* Conteneur associé */
unsigned int stamp; /* Suivi d'évolutions externes */
size_t index; /* Instruction courante */
mrange_t restriction; /* Enventuelle limite de zone */
bool is_restricted; /* Validité de l'étendue */
} instr_iter_t;
/******************************************************************************
* *
* Paramètres : proc = processeur recensant diverses instructions. *
* index = indice de la première instruction à fournir. *
* *
* Description : Construit un itérateur pour parcourir des instructions. *
* *
* Retour : Itérateur prêt à emploi. *
* *
* Remarques : - *
* *
******************************************************************************/
instr_iter_t *create_instruction_iterator(GArchProcessor *proc, size_t index)
{
instr_iter_t *result; /* Structure à retourner */
result = (instr_iter_t *)malloc(sizeof(instr_iter_t));
g_object_ref(G_OBJECT(proc));
result->proc = proc;
result->stamp = g_arch_processor_get_stamp(proc);
result->index = index;
result->is_restricted = false;
return result;
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à copie. *
* *
* Description : Duplique un itérateur de parcours d'instructions existant. *
* *
* Retour : Itérateur prêt à emploi. *
* *
* Remarques : - *
* *
******************************************************************************/
instr_iter_t *copy_instruction_iterator(const instr_iter_t *iter)
{
instr_iter_t *result; /* Structure à retourner */
result = (instr_iter_t *)malloc(sizeof(instr_iter_t));
g_object_ref(G_OBJECT(iter->proc));
result->proc = iter->proc;
result->stamp = iter->stamp;
result->index = iter->index;
result->is_restricted = iter->is_restricted;
if (result->is_restricted)
copy_mrange(&result->restriction, &iter->restriction);
return result;
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à traiter. *
* *
* Description : Détruit un itérateur mis en place. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void delete_instruction_iterator(instr_iter_t *iter)
{
g_object_unref(G_OBJECT(iter->proc));
free(iter);
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à traiter. *
* range = bornes de l'espace de parcours. *
* *
* Description : Limite le parcours des instructions à une zone donnée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void restrict_instruction_iterator(instr_iter_t *iter, const mrange_t *range)
{
instr_iter_t *new; /* Itérateur actualisé */
new = g_arch_processor_get_iter_from_address(iter->proc, get_mrange_addr(range));
if (new)
{
iter->index = new->index;
delete_instruction_iterator(new);
}
copy_mrange(&iter->restriction, range);
iter->is_restricted = true;
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à manipuler. *
* *
* Description : Fournit l'instruction courante de l'itérateur. *
* *
* Retour : Instruction suivante trouvée, ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *get_instruction_iterator_current(instr_iter_t *iter)
{
GArchInstruction *result; /* Résultat à retourner */
const mrange_t *irange; /* Emplacement d'instruction */
g_arch_processor_lock(iter->proc);
if (iter->stamp != g_arch_processor_get_stamp(iter->proc))
result = NULL;
else
{
if (iter->index < g_arch_processor_count_instructions(iter->proc))
{
result = g_arch_processor_get_instruction(iter->proc, iter->index);
/* L'instruction sort-elle des clous ? */
if (iter->is_restricted)
{
irange = g_arch_instruction_get_range(result);
if (!mrange_contains_mrange(&iter->restriction, irange))
{
g_object_unref(G_OBJECT(result));
result = NULL;
}
}
}
else
result = NULL;
}
g_arch_processor_unlock(iter->proc);
return result;
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à manipuler. *
* *
* Description : Fournit l'instruction qui en précède une autre. *
* *
* Retour : Instruction suivante trouvée, ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *get_instruction_iterator_prev(instr_iter_t *iter)
{
GArchInstruction *result; /* Résultat à retourner */
const mrange_t *irange; /* Emplacement d'instruction */
g_arch_processor_lock(iter->proc);
if (iter->stamp != g_arch_processor_get_stamp(iter->proc))
result = NULL;
else
{
if (iter->index > 1)
{
iter->index--;
result = g_arch_processor_get_instruction(iter->proc, iter->index);
/* L'instruction sort-elle des clous ? */
if (iter->is_restricted)
{
irange = g_arch_instruction_get_range(result);
if (!mrange_contains_mrange(&iter->restriction, irange))
{
g_object_unref(G_OBJECT(result));
result = NULL;
}
}
}
else
result = NULL;
}
g_arch_processor_unlock(iter->proc);
return result;
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à manipuler. *
* *
* Description : Fournit l'instruction qui en suit une autre. *
* *
* Retour : Instruction suivante trouvée, ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *get_instruction_iterator_next(instr_iter_t *iter)
{
GArchInstruction *result; /* Résultat à retourner */
const mrange_t *irange; /* Emplacement d'instruction */
g_arch_processor_lock(iter->proc);
if (iter->stamp != g_arch_processor_get_stamp(iter->proc))
result = NULL;
else
{
if ((iter->index + 1) < g_arch_processor_count_instructions(iter->proc))
{
iter->index++;
result = g_arch_processor_get_instruction(iter->proc, iter->index);
/* L'instruction sort-elle des clous ? */
if (iter->is_restricted)
{
irange = g_arch_instruction_get_range(result);
if (!mrange_contains_mrange(&iter->restriction, irange))
{
g_object_unref(G_OBJECT(result));
result = NULL;
}
}
}
else
result = NULL;
}
g_arch_processor_unlock(iter->proc);
return result;
}
/******************************************************************************
* *
* Paramètres : iter = itérateur à consulter. *
* *
* Description : Détermine s'il reste une instruction dans l'itération. *
* *
* Retour : Bilan de la consultation. *
* *
* Remarques : - *
* *
******************************************************************************/
bool has_instruction_iterator_next(const instr_iter_t *iter)
{
bool result; /* Bilan à retourner */
GArchInstruction *instr; /* Prochaine instruction */
const mrange_t *irange; /* Emplacement d'instruction */
g_arch_processor_lock(iter->proc);
if (iter->stamp != g_arch_processor_get_stamp(iter->proc))
result = false;
else
{
if ((iter->index + 1) < g_arch_processor_count_instructions(iter->proc))
{
instr = g_arch_processor_get_instruction(iter->proc, iter->index + 1);
/* L'instruction sort-elle des clous ? */
if (iter->is_restricted)
{
irange = g_arch_instruction_get_range(instr);
result = mrange_contains_mrange(&iter->restriction, irange);
}
else
result = true;
g_object_unref(G_OBJECT(instr));
}
else
result = false;
}
g_arch_processor_unlock(iter->proc);
return result;
}