/* Chrysalide - Outil d'analyse de fichiers binaires
* switch.c - prise en charge des instructions spéciales (packed|sparse)switch
*
* Copyright (C) 2011-2012 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 "switch.h"
#include
#include
#include "../instruction-int.h"
/* Définition générique d'une instruction d'architecture Dalvik (instance) */
struct _GDalvikSwitchInstr
{
GDalvikInstruction parent; /* A laisser en premier */
uint16_t switch_size; /* Taille du switch considéré */
};
/* Définition générique d'une instruction d'architecture Dalvik (classe) */
struct _GDalvikSwitchInstrClass
{
GDalvikInstructionClass parent; /* A laisser en premier */
};
/* Initialise la classe générique des instructions. */
static void g_dalvik_switch_instr_class_init(GDalvikSwitchInstrClass *);
/* Initialise une instance d'opérande d'architecture. */
static void g_dalvik_switch_instr_init(GDalvikSwitchInstr *);
/* Supprime toutes les références externes. */
static void g_dalvik_switch_instr_dispose(GDalvikSwitchInstr *);
/* Procède à la libération totale de la mémoire. */
static void g_dalvik_switch_instr_finalize(GDalvikSwitchInstr *);
/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
static void g_dalvik_switch_instr_print(GDalvikSwitchInstr *, GCodeBuffer *, MemoryDataSize, const bin_t *, AsmSyntax);
/* Indique le type défini pour une pseudo-instruction Dalvik de remplissage. */
G_DEFINE_TYPE(GDalvikSwitchInstr, g_dalvik_switch_instr, G_TYPE_DALVIK_INSTRUCTION);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe générique des instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dalvik_switch_instr_class_init(GDalvikSwitchInstrClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GArchInstructionClass *instr; /* Encore une autre vision... */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_dalvik_switch_instr_dispose;
object->finalize = (GObjectFinalizeFunc)g_dalvik_switch_instr_finalize;
instr = G_ARCH_INSTRUCTION_CLASS(klass);
//instr->print = (print_instruction_fc)g_dalvik_switch_instr_print;
}
/******************************************************************************
* *
* Paramètres : instr = instance à initialiser. *
* *
* Description : Initialise une instance d'instruction d'architecture. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dalvik_switch_instr_init(GDalvikSwitchInstr *instr)
{
G_DALVIK_INSTRUCTION(instr)->keyword = "##switch##";
}
/******************************************************************************
* *
* Paramètres : instr = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dalvik_switch_instr_dispose(GDalvikSwitchInstr *instr)
{
G_OBJECT_CLASS(g_dalvik_switch_instr_parent_class)->dispose(G_OBJECT(instr));
}
/******************************************************************************
* *
* Paramètres : instr = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dalvik_switch_instr_finalize(GDalvikSwitchInstr *instr)
{
G_OBJECT_CLASS(g_dalvik_switch_instr_parent_class)->finalize(G_OBJECT(instr));
}
/******************************************************************************
* *
* Paramètres : ident = identifiant de l'instruction déjà lu. *
* content = flux de données à analyser. *
* pos = position courante dans ce flux. [OUT] *
* *
* Description : Crée une pesudo-instruction Dalvik de branchement. *
* *
* Retour : Instruction mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *g_dalvik_switch_instr_new(uint16_t ident, const GBinContent *content, vmpa2t *pos)
{
GDalvikSwitchInstr *result; /* Structure à retourner */
phys_t consumed; /* Données consommées */
assert(ident == DPO_PACKED_SWITCH || ident == DPO_SPARSE_SWITCH);
result = g_object_new(G_TYPE_DALVIK_SWITCH_INSTR, NULL);
G_DALVIK_INSTRUCTION(result)->ptype = ident;
if (!g_binary_content_read_u16(content, pos, SRE_LITTLE, &result->switch_size))
goto gdsin_bad;
if (ident != DPO_PACKED_SWITCH)
consumed = (1 + result->switch_size) * sizeof(uint32_t);
else
consumed = (2 * result->switch_size) * sizeof(uint32_t);
if (!g_binary_content_seek(content, pos, consumed))
goto gdsin_bad;
g_arch_instruction_set_displayed_max_length(G_ARCH_INSTRUCTION(result), 4);
return G_ARCH_INSTRUCTION(result);
gdsin_bad:
g_object_unref(result);
return NULL;
}
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à représenter. *
* buffer = espace où placer ledit contenu. *
* syntax = type de représentation demandée. *
* *
* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_dalvik_switch_instr_print(GDalvikSwitchInstr *instr, GCodeBuffer *buffer, MemoryDataSize msize, const bin_t *content, AsmSyntax syntax)
{
GArchInstruction *base; /* Version basique de l'objet */
GBufferLine *line; /* Ligne de destination */
char address[VMPA_MAX_SIZE]; /* Adresse au format texte */
size_t len; /* Taille de l'élément inséré */
char *bin_code; /* Tampon du code binaire */
off_t i; /* Boucle de parcours */
const char *key; /* Mot clef principal */
size_t klen; /* Taille de ce mot clef */
base = G_ARCH_INSTRUCTION(instr);
line = NULL;
//line = g_code_buffer_prepare_new_line(buffer, &range);
#if 0
line = g_code_buffer_append_new_line(buffer, base->address);
/* Adresse virtuelle ou physique */
len = vmpa_to_string(base->address, msize, address);
g_buffer_line_insert_text(line, BLC_PHYSICAL, address, len, RTT_RAW);
/* TODO ... */
/* Code brut */
bin_code = (char *)calloc(3 * 3 + 3, sizeof(char));
for (i = 0; i < 3; i++)
{
if ((i + 1) < 3)
snprintf(&bin_code[i * (2 + 1)], 4, "%02hhx ", content[base->offset + i]);
else
snprintf(&bin_code[i * (2 + 1)], 6, "%02hhx...", content[base->offset + i]);
}
g_buffer_line_insert_text(line, BLC_BINARY,
bin_code, 3 * 3 + 2, RTT_RAW_CODE);
free(bin_code);
#endif
/* Instruction proprement dite */
key = "";
klen = strlen(key);
g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION);
}