/* Chrysalide - Outil d'analyse de fichiers binaires
* manager.c - prise en compte d'une syntaxe du langage d'assemblage
*
* Copyright (C) 2014 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* 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 "manager.h"
#include
#include
#include "../helpers.h"
/* Propriétés particulières pour les opérandes */
typedef enum _SyntaxItemFlags
{
SIF_NONE = (0 << 0), /* Aucune propriété */
SIF_DECIMAL = (1 << 0), /* Affichage en décimal */
SIF_OPTIONAL = (1 << 1) /* Absence tolérée */
} SyntaxItemFlags;
/* Elément défini dans une syntaxe */
typedef struct _syntax_item
{
char *name; /* Désignation humaine */
SyntaxItemType impact; /* Portée de l'élément */
SyntaxItemFlags flags; /* Propriétés supplémentaires */
} syntax_item;
/* Syntaxe d'une ligne d'assembleur */
struct _asm_syntax
{
syntax_item *items; /* Eléments de la syntaxe */
size_t items_count; /* Nombre de ces éléments */
};
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un nouvel indicateur pour l'écriture d'une instruction. *
* *
* Retour : Nouvelle structure prête à emploi. *
* *
* Remarques : - *
* *
******************************************************************************/
asm_syntax *create_asm_syntax(void)
{
asm_syntax *result; /* Définition vierge à renvoyer*/
result = (asm_syntax *)calloc(1, sizeof(asm_syntax));
return result;
}
/******************************************************************************
* *
* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
* *
* Description : Supprime de la mémoire un indicateur d'écriture ASM. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void delete_asm_syntax(asm_syntax *syntax)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < syntax->items_count; i++)
free(syntax->items[i].name);
if (syntax->items != NULL)
free(syntax->items);
free(syntax);
}
/******************************************************************************
* *
* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
* name = désignation de l'opérande dans la spécification. *
* impact = précise la portée effective de l'opérande *
* *
* Description : Enregistre la présence d'un nouvel opérande dans la syntaxe. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact)
{
syntax_item *item; /* Nouvelle prise en compte */
size_t len; /* Taille du nom fourni */
syntax->items = (syntax_item *)realloc(syntax->items, ++syntax->items_count * sizeof(syntax_item));
item = &syntax->items[syntax->items_count - 1];
/* Récupération des drapeaux */
item->flags = SIF_NONE;
for (len = strlen(name); len > 0; len--)
switch (name[0])
{
case '#':
item->flags |= SIF_DECIMAL;
memmove(name, name + 1, len);
break;
case '?':
item->flags |= SIF_OPTIONAL;
memmove(name, name + 1, len);
break;
default:
len = 1;
break;
}
if (impact == SIT_KEYWORD)
item->name = name;
else
item->name = make_string_lower(name);
item->impact = impact;
}
/******************************************************************************
* *
* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
* *
* Description : Marque les champs de bits effectivement utilisés. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const conv_list *list)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
syntax_item *item; /* Lien vers un opérande */
conv_func *func; /* Fonction de conversion */
result = true;
for (i = 0; i < syntax->items_count && result; i++)
{
item = &syntax->items[i];
if (item->impact == SIT_KEYWORD) continue;
func = find_named_conv_in_list(list, item->name);
if (func == NULL)
{
fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name);
result = false;
}
result = mark_conv_func(func, false, bits, list);
}
return result;
}
/******************************************************************************
* *
* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
* fd = descripteur d'un flux ouvert en écriture. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
* wide = taille des mots décodés. *
* *
* Description : Déclare les variables C associées aux opérandes de syntaxe. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide)
{
bool result; /* Bilan à retourner */
bool has_operand; /* Présence d'un opérande */
size_t i; /* Boucle de parcours */
syntax_item *item; /* Lien vers un opérande */
result = true;
has_operand = false;
for (i = 0; i < syntax->items_count && result; i++)
{
item = &syntax->items[i];
if (item->impact == SIT_KEYWORD) continue;
has_operand |= (item->impact == SIT_EXT_OPERAND);
}
if (has_operand)
dprintf(fd, "\t\tGArchOperand *op;\n");
return result;
}
/******************************************************************************
* *
* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
* *
* Description : Fournit si elle existe un nom nouveau pour une instruction. *
* *
* Retour : Eventuelle chaîne de caractères trouvée ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax)
{
const char *result; /* Nom éventuel à renvoyer */
result = NULL;
if (syntax->items_count > 0
&& syntax->items[0].impact == SIT_KEYWORD)
{
result = syntax->items[0].name;
}
return result;
}
/******************************************************************************
* *
* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
* fd = descripteur d'un flux ouvert en écriture. *
* arch = architecture visée par l'opération globale. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
* pp = pré-processeur pour les échanges de chaînes. *
* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : Définit les variables C associées aux opérandes de syntaxe. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool define_syntax_items(const asm_syntax *syntax, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
syntax_item *item; /* Lien vers un opérande */
conv_func *func; /* Fonction de conversion */
bool internal; /* Usage interne ou non ? */
result = true;
for (i = 0; i < syntax->items_count && result; i++)
{
item = &syntax->items[i];
switch (item->impact)
{
case SIT_KEYWORD:
/**
* TODO : à faire évoluer vers extend...
*/
//_exit(123);
// rev_A88146
/*
if (i > 0)
dprintf(fd, "\t\tg_arch_instruction_append_suffix(instr, \"%s\");\n", item->name);
else
continue;
*/
break;
case SIT_INT_OPERAND: // A supprimer
case SIT_EXT_OPERAND:
internal = (item->impact == SIT_INT_OPERAND);
func = find_named_conv_in_list(list, item->name);
if (func == NULL)
{
fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name);
result = false;
}
/* Appel proprement dit */
if (is_conv_func_already_defined(func))
{
dprintf(fd, "\t\top = val_%s;\n", item->name);
dprintf(fd, "\n");
if (item->flags & SIF_DECIMAL)
dprintf(fd, "\t\tg_imm_operand_set_default_display(G_IMM_OPERAND(op), IOD_DEC);\n");
dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n");
}
else
{
result &= define_conv_func(func, true, internal, fd, arch, bits, list, pp, exit);
if (!result) break;
/* Raccordement : propriété ou opérande ? */
if (internal)
{
dprintf(fd, "\t\t\tgoto bad_exit;\n");
*exit = true;
}
else
{
dprintf(fd, "\t\tif (op == NULL) goto bad_exit;\n");
*exit = true;
dprintf(fd, "\n");
if (item->flags & SIF_DECIMAL)
dprintf(fd, "\t\tg_imm_operand_set_default_display(G_IMM_OPERAND(op), IOD_DEC);\n");
dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n");
}
}
*exit = true;
break;
}
dprintf(fd, "\n");
}
return result;
}