summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-11-26 23:30:01 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-11-26 23:30:01 (GMT)
commit6b1a70c16f83a926f7b1f1fb2af5d6a2e017737b (patch)
tree8ffb0b3d8f3063c612f8cebe4f00a65f8b029a52
parenta93a5dca1a7292b7e61ae09b74f3252e04b73488 (diff)
Used several threads without lock to disassemble binary code.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@610 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
-rw-r--r--ChangeLog30
-rw-r--r--src/analysis/disass/area.c1085
-rw-r--r--src/analysis/disass/area.h43
-rw-r--r--src/analysis/disass/disassembler.c11
-rw-r--r--src/analysis/disass/fetch.c429
-rw-r--r--src/analysis/disass/fetch.h3
-rw-r--r--src/arch/archbase.h25
-rw-r--r--src/arch/arm/context-int.h1
-rw-r--r--src/arch/arm/context.c18
-rw-r--r--src/arch/arm/v7/context.c10
-rw-r--r--src/arch/context-int.h12
-rw-r--r--src/arch/context.c69
-rw-r--r--src/arch/context.h2
-rw-r--r--src/common/bits.c68
-rw-r--r--src/common/bits.h9
-rw-r--r--src/format/elf/elf.c6
-rw-r--r--src/format/symbol.h4
17 files changed, 1741 insertions, 84 deletions
diff --git a/ChangeLog b/ChangeLog
index 2e13b93..308e126 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+15-11-27 Cyrille Bagard <nocbos@gmail.com>
+
+ * src/analysis/disass/area.c:
+ * src/analysis/disass/area.h:
+ * src/analysis/disass/disassembler.c:
+ * src/analysis/disass/fetch.c:
+ * src/analysis/disass/fetch.h:
+ Use several threads without lock to disassemble binary code.
+
+ * src/arch/archbase.h:
+ Provide memory data sizes from byte sizes with MDS_FROM_BYTES.
+
+ * src/arch/arm/context.c:
+ * src/arch/arm/context-int.h:
+ * src/arch/arm/v7/context.c:
+ * src/arch/context.c:
+ * src/arch/context.h:
+ * src/arch/context-int.h:
+ Protect data access using locks.
+
+ * src/common/bits.c:
+ * src/common/bits.h:
+ Add bits to bit fields in an atomic way.
+
+ * src/format/elf/elf.c:
+ Do not load inner sections as portions.
+
+ * src/format/symbol.h:
+ Define the HAS_DATA_INSTR macro to filter symbols.
+
15-11-26 Cyrille Bagard <nocbos@gmail.com>
* plugins/pychrysa/analysis/content.c:
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index 1d841be..355b716 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -27,6 +27,1087 @@
#include <assert.h>
+#include <i18n.h>
+
+
+#include "../../analysis/contents/restricted.h"
+#include "../../common/bits.h"
+#include "../../gui/panels/log.h"
+
+
+
+
+/* Zone mémoire bien bornée */
+typedef struct _mem_area_v2
+{
+ GBinFormat *format; /* Format du fichier binaire */
+ GBinContent *content; /* Données binaires à lire */
+ GArchProcessor *proc; /* Architecture du binaire */
+ SourceEndian endianness; /* Boutisme de cette machine */
+
+ mrange_t range; /* Couverture de la zone */
+
+ phys_t packing_size; /* Granularité des découpages */
+
+ bitfield_t *processed; /* Octets traités dans la zone */
+ GArchInstruction **instructions; /* Instructions en place */
+
+
+
+
+ bool is_exec; /* Zone exécutable ? */
+
+} mem_area_v2;
+
+
+
+/* Initialise une aire de données à partir d'une adresse donnée. */
+static void init_mem_area_from_addr_v2(mem_area_v2 *, const vmpa2t *, phys_t, const GLoadedBinary *);
+
+/* Libère d'une aire de données les ressources allouées. */
+static void fini_mem_area_v2(mem_area_v2 *);
+
+/* Indique si une zone donnée est intégralement vierge ou non. */
+static bool is_range_blank_in_mem_area_v2(mem_area_v2 *, phys_t, phys_t);
+
+/* Marque une série d'octets comme ayant été traités. */
+static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *, GArchInstruction *, bool);
+
+
+
+
+/* Procède au désassemblage d'un contenu binaire non exécutable. */
+static void load_data_from_mem_area_v2(mem_area_v2 *, GProcContext *, const vmpa2t *, status_blob_info *);
+
+/* S'assure qu'une aire contient toutes ses instructions. */
+static void fill_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, status_blob_info *);
+
+/* Rassemble les instructions conservées dans une zone donnée. */
+static GArchInstruction *get_instructions_from_mem_area_v2(const mem_area_v2 *);
+
+
+
+
+
+
+/* S'assure de la présence d'un début de routine à un point. */
+static void update_address_as_routine(GBinFormat *, const vmpa2t *);
+
+
+/**
+ * Content :: à passer en restricted.
+
+ * Les sections croisées : pas de sens de les traiter ici, car au final une instruction sera à cheval
+ * sur deux sections différentes -> incohérence au niveau de l'éditeur.
+ * => régler le périmètres de segments règle donc tous les soucis.
+
+ */
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à initialiser. *
+* addr = adresse de départ de l'espace à mettre en place. *
+* len = longueur de l'espace à créer. *
+* binary = binaire analysé content quantités d'informations. *
+* *
+* Description : Initialise une aire de données à partir d'une adresse donnée.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_mem_area_from_addr_v2(mem_area_v2 *area, const vmpa2t *addr, phys_t len, const GLoadedBinary *binary)
+{
+ GBinContent *content; /* Données binaires à lire */
+
+ assert(len > 0);
+
+ area->format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+ content = g_binary_format_get_content(area->format);
+
+ area->proc = g_loaded_binary_get_processor(binary);
+ area->endianness = g_arch_processor_get_endianness(area->proc);
+
+ init_mrange(&area->range, addr, len);
+
+ area->content = g_restricted_content_new(content, &area->range);
+
+ area->packing_size = 2; /* FIXME */
+
+ area->processed = create_bit_field(len, false);
+ area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à nettoyer en mémoire. *
+* *
+* Description : Libère d'une aire de données les ressources allouées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void fini_mem_area_v2(mem_area_v2 *area)
+{
+ phys_t len; /* Etendue du parcours total */
+ phys_t i; /* Boucle de parcours */
+
+ //g_object_unref(area->format); /* FIXME */
+ g_object_unref(area->content);
+ //g_object_unref(area->proc); /* FIXME */
+
+ delete_bit_field(area->processed);
+
+ len = get_mrange_length(&area->range);
+
+ for (i = 0; i < len; i++)
+ if (area->instructions[i] != NULL)
+ g_object_unref(G_OBJECT(area->instructions[i]));
+
+ free(area->instructions);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à parcourir. *
+* start = début de la zone à manipuler. *
+* len = taille de cette même aire de données. *
+* *
+* Description : Indique si une zone donnée est intégralement vierge ou non. *
+* *
+* Retour : true si l'aire visée n'a jamais été traitée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool is_range_blank_in_mem_area_v2(mem_area_v2 *area, phys_t start, phys_t len)
+{
+ bool result; /* Résultat à renvoyer */
+
+ if ((start + len) >= get_mrange_length(&area->range))
+ result = false;
+
+ else
+ result = !test_in_bit_field(area->processed, start, len);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à parcourir. *
+* instr = instruction à mémoriser pour la suite. *
+* force = impose l'enregistrement de l'instruction. *
+* *
+* Description : Marque une série d'octets comme ayant été traités. *
+* *
+* Retour : true si l'enregistrement a bien été réalisé, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *area, GArchInstruction *instr, bool force)
+{
+ bool result; /* Bilan d'action à renvoyer */
+ const vmpa2t *start; /* Adresse de départ de la zone*/
+ const mrange_t *range; /* Emplacement d'instruction */
+ const vmpa2t *addr; /* Début de la zone à traiter */
+ phys_t len; /* Taille de l'aire visée */
+ phys_t offset; /* Décallage de départ */
+
+ start = get_mrange_addr(&area->range);
+
+ range = g_arch_instruction_get_range(instr);
+ addr = get_mrange_addr(range);
+ len = get_mrange_length(range);
+
+ offset = compute_vmpa_diff(start, addr);
+
+ result = set_atomic_in_bit_field(area->processed, offset, len);
+
+ /* Si l'instruction était bien la première à s'inscrire... */
+
+ result |= force;
+
+ if (result)
+ area->instructions[offset] = instr;
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à parcourir. *
+* list = liste de zones délimitant des contenus à traiter. *
+* count = nombre de zones à disposition. *
+* index = indice de l'aire à considérer pendant l'opération. *
+* binary = représentation de binaire chargé. *
+* ctx = contexte offert en soutien à un désassemblage. *
+* start = démarrage de l'exécution au sein de la zone. *
+* info = indications quant à la progression à afficher. *
+* *
+* Description : Procède au désassemblage d'un contenu binaire exécutable. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, const vmpa2t *start, status_blob_info *info)
+{
+
+
+
+ GBinFormat *format; /* Format du fichier binaire */
+ GArchProcessor *proc; /* Architecture du binaire */
+ GBinContent *content; /* Données binaires à lire */
+
+ phys_t diff; /* Volume de données traité */
+ phys_t alen; /* Taille de l'aire utilisée */
+
+ phys_t i; /* Boucle de parcours */
+
+
+ vmpa2t pos; /* Boucle de parcours */
+ vmpa2t prev; /* Boucle de parcours */
+
+ GArchInstruction *instr; /* Instruction décodée */
+
+
+
+ mrange_t range; /* Couverture de l'instruction */
+
+
+ bool done; /* Enregistrement effectué ? */
+
+
+ vmpa2t sym_addr; /* Adresse de nouveau symbole */
+ bool has_new_sym; /* Statut d'un dépilement */
+
+ GBinSymbol *symbol; /* Symbole créé en parallèle */
+
+
+
+
+
+ /* Récupération des informations de base */
+
+ format = area->format;
+ proc = area->proc;
+ content = area->content;
+
+ diff = compute_vmpa_diff(get_mrange_addr(&area->range), start);
+ alen = get_mrange_length(&area->range);
+
+ copy_vmpa(&pos, start);
+
+ /* Traitement de la zone */
+
+ printf("=== processing @ 0x%08x\n", (unsigned int)start->virtual);
+
+ for (i = diff; i < alen; i += diff)
+ {
+ /**
+ * On réalise un premier test informel (car non atomique) peu coûteux
+ * avant de se lancer dans un désassemblage d'instruction potentiellement
+ * inutile.
+ */
+
+ printf(" (%u) blank ? %d\n", (unsigned int)i, is_range_blank_in_mem_area_v2(area, i, 1));
+ printf(" +1 blank ? %d\n", is_range_blank_in_mem_area_v2(area, i + 1, 1));
+
+ if (!is_range_blank_in_mem_area_v2(area, i, 1))
+ break;
+
+ /* Décodage d'une nouvelle instruction */
+
+ copy_vmpa(&prev, &pos);
+
+ instr = g_arch_processor_disassemble(proc, ctx, content, &pos);
+ if (instr == NULL) break;
+
+ /* Enregistrement des positions et adresses */
+
+ diff = compute_vmpa_diff(&prev, &pos);
+
+ init_mrange(&range, &prev, diff);
+
+ g_arch_instruction_set_range(instr, &range);
+
+ /* Progression dans les traitements */
+
+ done = mark_range_in_mem_area_as_processed_v2(area, instr, false);
+
+ if (!done)
+ {
+ g_object_unref(G_OBJECT(instr));
+ break;
+ }
+
+ inc_progessive_status(info, diff);
+
+ assert(!is_range_blank_in_mem_area_v2(area, i, diff));
+
+ /* Enregistrement d'un éventuel début de routine */
+
+ if (g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START)
+ update_address_as_routine(format, &prev);
+
+ /* Eventuel renvoi vers d'autres adresses */
+
+ g_arch_instruction_call_hook(instr, IPH_FETCH, proc, ctx, format);
+
+ /* Insertion des symboles découverts en parallèle */
+
+ for (has_new_sym = g_proc_context_pop_new_symbol_at(ctx, &sym_addr);
+ has_new_sym;
+ has_new_sym = g_proc_context_pop_new_symbol_at(ctx, &sym_addr))
+ {
+ has_new_sym = g_binary_format_find_symbol_at(format, &sym_addr, &symbol);
+ assert(has_new_sym);
+
+ insert_extra_symbol_into_mem_areas_v2(list, count, symbol);
+
+ }
+
+ /* Rupture du flot d'exécution ? */
+ if (g_arch_instruction_get_flags(instr) & AIF_RETURN_POINT)
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à parcourir. *
+* ctx = contexte offert en soutien à un désassemblage. *
+* start = démarrage de l'exécution au sein de la zone. *
+* info = indications quant à la progression à afficher. *
+* *
+* Description : Procède au désassemblage d'un contenu binaire non exécutable.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, const vmpa2t *start, status_blob_info *info)
+{
+ GBinContent *content; /* Données binaires à lire */
+ SourceEndian endianness; /* Boutisme de cette machine */
+ phys_t diff; /* Volume de données traité */
+ phys_t alen; /* Taille de l'aire utilisée */
+ vmpa2t pos; /* Boucle de parcours */
+ phys_t i; /* Boucle de parcours */
+ vmpa2t prev; /* Boucle de parcours */
+ GArchInstruction *instr; /* Instruction décodée */
+ mrange_t range; /* Couverture de l'instruction */
+ bool done; /* Enregistrement effectué ? */
+
+ /* Récupération des informations de base */
+
+ content = area->content;
+ endianness = area->endianness;
+
+ diff = compute_vmpa_diff(get_mrange_addr(&area->range), start);
+ alen = get_mrange_length(&area->range);
+
+ copy_vmpa(&pos, start);
+
+ /* Traitement de la zone */
+
+ for (i = diff; i < alen; i += diff)
+ {
+ /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */
+
+ if (!is_range_blank_in_mem_area_v2(area, i, 1))
+ break;
+
+ instr = NULL;
+
+ copy_vmpa(&prev, &pos);
+
+ /* Décodage d'une nouvelle instruction, sur mesure puis minimale */
+
+ if (get_virt_addr(&pos) % area->packing_size == 0
+ && is_range_blank_in_mem_area_v2(area, i, area->packing_size))
+ {
+ diff = area->packing_size;
+
+ instr = g_raw_instruction_new_array(content, MDS_FROM_BYTES(diff), 1, &pos, endianness);
+
+ if (instr == NULL)
+ copy_vmpa(&pos, &prev);
+
+ }
+
+ if (instr == NULL)
+ {
+ diff = 1;
+
+ instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, &pos, endianness);
+
+ }
+
+ /* On rencontre ici un morceau déjà traité. */
+
+ if (instr == NULL) break;
+
+ /* Enregistrement des positions et adresses */
+
+ assert(diff == compute_vmpa_diff(&prev, &pos));
+
+ init_mrange(&range, &prev, diff);
+
+ g_arch_instruction_set_range(instr, &range);
+
+ /* Progression dans les traitements */
+
+ done = mark_range_in_mem_area_as_processed_v2(area, instr, false);
+
+ if (!done)
+ {
+ g_object_unref(G_OBJECT(instr));
+ break;
+ }
+
+ inc_progessive_status(info, diff);
+
+ assert(!is_range_blank_in_mem_area_v2(area, i, diff));
+
+ /* On laisse une chance au code pour se reprendre... */
+
+ if (area->is_exec) break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à parcourir. *
+* list = liste de zones délimitant des contenus à traiter. *
+* count = nombre de zones à disposition. *
+* binary = représentation de binaire chargé. *
+* ctx = contexte offert en soutien à un désassemblage. *
+* info = indications quant à la progression à afficher. *
+* *
+* Description : S'assure qu'une aire contient toutes ses instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void fill_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, status_blob_info *info)
+{
+ const vmpa2t *addr; /* Début de la zone à traiter */
+ phys_t len; /* Taille de la zone à remplir */
+ phys_t i; /* Boucle de parcours */
+ vmpa2t start; /* Adresse de départ de combles*/
+
+ addr = get_mrange_addr(&area->range);
+ len = get_mrange_length(&area->range);
+
+ for (i = 0; i < len; i++)
+ {
+ if (is_range_blank_in_mem_area_v2(area, i, 1))
+ {
+ copy_vmpa(&start, addr);
+ advance_vmpa(&start, i);
+
+ if (area->is_exec && get_virt_addr(&start) % area->packing_size == 0)
+ load_code_from_mem_area_v2(area, list, count, ctx, &start, info);
+
+ if (is_range_blank_in_mem_area_v2(area, i, 1))
+ load_data_from_mem_area_v2(area, ctx, &start, info);
+
+ }
+
+ assert(!is_range_blank_in_mem_area_v2(area, i, 1));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : area = aire représentant à contenu à parcourir. *
+* *
+* Description : Rassemble les instructions conservées dans une zone donnée. *
+* *
+* Retour : Liste d'instructions prêtes à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GArchInstruction *get_instructions_from_mem_area_v2(const mem_area_v2 *area)
+{
+ GArchInstruction *result; /* Liste d'instr. à renvoyer */
+ phys_t len; /* Nombre d'instructions au max*/
+ phys_t i; /* Boucle de parcours */
+ GArchInstruction *instr; /* Instruction décodée */
+
+ result = NULL;
+
+ len = get_mrange_length(&area->range);
+
+ for (i = 0; i < len; i++)
+ {
+ instr = area->instructions[i];
+
+ if (instr != NULL)
+ {
+ g_object_ref(G_OBJECT(instr));
+ g_arch_instruction_add_to_list(&result, instr);
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : list = listes de zones utable à consulter. *
+* count = nombre de zones mises en place. *
+* addr = adresse à retrouver dans les aires présentes. *
+* *
+* Description : Détermine une liste de zones contigües à traiter. *
+* *
+* Retour : Indice de la zone trouvée, ou nombre d'aires en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+mem_area_v2 *find_memory_area_by_addr_v2(mem_area_v2 *list, size_t count, const vmpa2t *addr)
+{
+ mem_area_v2 *result; /* Elément trouvé à renvoyer */
+
+ int find_mem_area(const vmpa2t *addr, const mem_area_v2 *area)
+ {
+ int status; /* Bilan à retourner */
+
+ if (mrange_contains_addr(&area->range, addr))
+ status = 0;
+
+ else
+ status = cmp_vmpa(addr, get_mrange_addr(&area->range));
+
+ return status;
+
+ }
+
+ result = bsearch(addr, list, count, sizeof(mem_area_v2), (__compar_fn_t)find_mem_area);
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = binaire analysé contenant quantités d'infos. *
+* bin_length = quantité d'octets à traiter au total. *
+* count = nombre de zones mises en place. [OUT] *
+* *
+* Description : Détermine une liste de zones contigües à traiter. *
+* *
+* Retour : Liste de zones mémoire à libérer après usage. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_length, size_t *count)
+{
+ mem_area_v2 *result; /* Liste à renvoyer */
+ GExeFormat *format; /* Format de fichier associé */
+ mrange_t *exe_ranges; /* Liste de zones exécutables */
+ size_t exe_count; /* Nombre de ces zones */
+ GBinSymbol **symbols; /* Symboles à représenter */
+ size_t sym_count; /* Qté de symboles présents */
+ vmpa2t last; /* Dernière bordure rencontrée */
+ bool status; /* Bilan d'une conversion */
+ size_t i; /* Boucle de parcours #1 */
+ const vmpa2t *border; /* Nouvelle bordure rencontrée */
+ mem_area_v2 *area; /* Zone avec valeurs à éditer */
+ vmpa2t tmp; /* Stockage temporaire */
+ GBinPortion **portions; /* Morceaux d'encadrement */
+ size_t portions_count; /* Taille de cette liste */
+ const vmpa2t *portion_start; /* Point de départ de portion */
+ size_t j; /* Boucle de parcours #2 */
+ SymbolType type; /* Nature d'un symbole */
+ const mrange_t *range; /* Couverture d'un symbole */
+ phys_t length; /* Taille de ce même symbole */
+ phys_t new_length; /* Nouvelle taille déterminée */
+
+ result = NULL;
+ *count = 0;
+
+ /**
+ * Le parcours n'est valide que si les zones exécutables sont triées !
+ */
+
+ format = g_loaded_binary_get_format(binary);
+
+ exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
+
+ symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
+
+ /* Première étape : on comble les trous ! */
+
+ status = g_exe_format_translate_offset_into_vmpa(format, 0, &last);
+ assert(status);
+
+ for (i = 0; i < exe_count; i++)
+ {
+ border = get_mrange_addr(&exe_ranges[i]);
+
+ /* Zone tampon à constituer */
+
+ if (cmp_vmpa(&last, border) < 0)
+ {
+ result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));
+
+ area = &result[*count - 1];
+
+ init_mem_area_from_addr_v2(area, &last, compute_vmpa_diff(&last, border), binary);
+ area->is_exec = false;
+
+ }
+
+ /* Insertion d'une zone exécutable déjà définie */
+
+ result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));
+
+ area = &result[*count - 1];
+
+ init_mem_area_from_addr_v2(area, get_mrange_addr(&exe_ranges[i]),
+ get_mrange_length(&exe_ranges[i]), binary);
+ area->is_exec = true;
+
+ /* Avancée du curseur */
+
+ compute_mrange_end_addr(&exe_ranges[i], &last);
+
+ }
+
+ /* Extension finale complémentaire ? */
+
+ area = &result[*count - 1];
+
+ copy_vmpa(&tmp, get_mrange_addr(&area->range));
+ advance_vmpa(&tmp, get_mrange_length(&area->range));
+
+ if (get_phy_addr(&tmp) < bin_length)
+ {
+ result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));
+
+ area = &result[*count - 1];
+
+ init_mem_area_from_addr_v2(area, &tmp, bin_length - get_phy_addr(&tmp), binary);
+ area->is_exec = false;
+
+ }
+
+
+
+
+
+
+
+
+ for (i = 0; i < *count; i++)
+ {
+ printf(" (init) AREA %zu :: 0x%x / 0x%x + 0x%x\n",
+ i,
+ (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)),
+ (unsigned int)get_virt_addr(get_mrange_addr(&result[i].range)),
+ (unsigned int)get_mrange_length(&result[i].range));
+
+ }
+
+ printf("--------------------\n");
+
+
+
+
+
+
+
+
+ /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */
+
+ portions = g_exe_format_get_portions_at_level(format, -1, &portions_count);
+
+ for (i = 1; i < portions_count; i++)
+ {
+ portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i]));
+
+ printf(" [portion % 3zu] addr = 0x%x / 0x%x\n",
+ i,
+ (unsigned int)get_phy_addr(portion_start),
+ (unsigned int)get_virt_addr(portion_start));
+
+ for (j = 0; j < *count; j++)
+ {
+ area = &result[j];
+
+ if (!mrange_contains_addr(&area->range, portion_start))
+ continue;
+
+ /* Si le déccoupage actuel ne correspond pas au besoin des portions... */
+ if (cmp_vmpa(get_mrange_addr(&area->range), portion_start) != 0)
+ {
+ fini_mem_area_v2(&result[j]);
+
+ result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));
+
+ memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area_v2));
+
+ status = result[j].is_exec;
+
+ /* Première moitié */
+
+ area = &result[j];
+
+ copy_vmpa(&tmp, get_mrange_addr(&area->range));
+ length = get_mrange_length(&area->range);
+
+ new_length = compute_vmpa_diff(&tmp, portion_start);
+
+ init_mem_area_from_addr_v2(area, &tmp, new_length, binary);
+ area->is_exec = status;
+
+ /* Seconde moitié */
+
+ length -= get_mrange_length(&area->range);
+
+ area = &result[j + 1];
+
+ init_mem_area_from_addr_v2(area, portion_start, length, binary);
+ area->is_exec = status;
+
+ }
+
+ j = *count;
+
+ }
+
+ }
+
+
+
+
+
+
+
+
+ for (i = 0; i < *count; i++)
+ {
+ printf(" (fini) AREA %zu :: 0x%x / 0x%x + 0x%x\n",
+ i,
+ (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)),
+ (unsigned int)get_virt_addr(get_mrange_addr(&result[i].range)),
+ (unsigned int)get_mrange_length(&result[i].range));
+
+ }
+
+ printf("--------------------\n");
+
+
+
+
+
+
+
+
+ /* Troisième étape : on insère les symboles existants */
+
+ for (i = 0; i < sym_count; i++)
+ {
+ type = g_binary_symbol_get_target_type(symbols[i]);
+
+ /**
+ * On ne garde que les symboles renvoyant directement une ou
+ * plusieurs instructions, c'est à dire les symboles valides
+ * pour un appel à g_binary_symbol_get_instruction().
+ *
+ * Les instructions des autres symboles sont obtenues et mises
+ * en place durant la procédure de désassemblage.
+ */
+
+ if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
+ continue;
+
+ range = g_binary_symbol_get_range(symbols[i]);
+
+ length = get_mrange_length(range);
+
+ if (length == 0)
+ continue;
+
+ insert_extra_symbol_into_mem_areas_v2(result, *count, symbols[i]);
+
+ }
+
+ /* Nettoyage final */
+
+ if (portions != NULL)
+ free(portions);
+
+ if (exe_ranges != NULL)
+ free(exe_ranges);
+
+ /// FIXME g_object_unref(G_OBJECT(format));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : areas = liste de zones délimitant des contenus à traiter. *
+* count = nombre de zones à disposition. *
+* symbol = élément nouveau à venir insérer dans les zones. *
+* *
+* Description : Insère un symbole dans un découpage en aires. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *areas, size_t count, const GBinSymbol *symbol)
+{
+ SymbolType type; /* Type de symbole */
+ GArchInstruction *list; /* Ensemble à insérer */
+ GArchInstruction *iter; /* Boucle de parcours */
+ const mrange_t *range; /* Emplacement d'instruction */
+ const vmpa2t *addr; /* Départ de cet emplacement */
+ mem_area_v2 *area; /* Zone d'accueil désignée */
+ VMPA_BUFFER(loc); /* Description d'un emplacement*/
+ phys_t start; /* Point de départ */
+
+ type = g_binary_symbol_get_target_type(symbol);
+
+ if (!HAS_DATA_INSTR(type))
+ return;
+
+ list = g_binary_symbol_get_instruction(symbol);
+
+ for (iter = list; iter != NULL; iter = g_arch_instruction_get_next_iter(list, iter, ~0))
+ {
+ range = g_arch_instruction_get_range(iter);
+ addr = get_mrange_addr(range);
+
+ /* Une aire d'accueil existe-t-elle ? */
+
+ area = find_memory_area_by_addr_v2(areas, count, addr);
+
+ if (area == NULL)
+ {
+ vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);
+
+ log_variadic_message(LMT_WARNING, _("No place found for symbol located at %s."), loc);
+ continue;
+
+ }
+
+ /* L'instruction est-elle accueillie dans son intégralité ? */
+
+ start = compute_vmpa_diff(get_mrange_addr(&area->range), addr);
+
+ if (start + get_mrange_length(range) > get_mrange_length(&area->range))
+ {
+ vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);
+
+ log_variadic_message(LMT_WARNING, _("The symbol located at %s is too big for one place only."), loc);
+ continue;
+
+ }
+
+ /* Inscription d'une instruction de symbole (sans retour arrière possible :/ ) */
+
+ mark_range_in_mem_area_as_processed_v2(area, iter, true);
+
+ g_object_ref(G_OBJECT(iter));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = liste de zones délimitant des contenus à traiter. *
+* count = nombre de zones à disposition. *
+* binary = représentation de binaire chargé. *
+* ctx = contexte offert en soutien à un désassemblage. *
+* info = indications quant à la progression à afficher. *
+* *
+* Description : S'assure que l'ensemble des aires est entièrement décodé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void ensure_all_mem_areas_are_filled(mem_area_v2 *list, size_t count, GProcContext *ctx, status_blob_info *info)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < count; i++)
+ fill_mem_area_v2(&list[i], list, count, ctx, info);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : areas = série d'aires représentant à contenu à parcourir. *
+* count = nombre de ces zones présentes. *
+* *
+* Description : Rassemble les instructions conservées dans des zones données.*
+* *
+* Retour : Liste d'instructions prêtes à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GArchInstruction *collect_instructions_from_mem_areas_v2(const mem_area_v2 *list, size_t count)
+{
+ GArchInstruction *result; /* Liste d'instr. à renvoyer */
+ size_t i; /* Boucle de parcours */
+ GArchInstruction *instr; /* Instruction(s) à insérer */
+
+ result = NULL;
+
+ for (i = 0; i < count; i++)
+ {
+ instr = get_instructions_from_mem_area_v2(&list[i]);
+ g_arch_instruction_merge_lists(&result, &instr);
+ }
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+//////////////////////////////////::://////////////////////////////////////////////////////////////////////
+
+
+
/* Zone mémoire bien bornée */
typedef struct _mem_area
@@ -72,7 +1153,7 @@ static bool mark_range_in_mem_area_as_processed(mem_area *, phys_t, phys_t, GArc
/* S'assure de la présence d'un début de routine à un point. */
-static void update_address_as_routine(GBinFormat *, const vmpa2t *);
+//static void update_address_as_routine(GBinFormat *, const vmpa2t *);
@@ -1468,8 +2549,6 @@ static bool insert_extra_symbol_into_mem_areas(mem_area **list, size_t *count, G
memmove(&(*list)[index + 1], &(*list)[index], (*count - index - 1) * sizeof(mem_area));
- /* Aire raccourcie */
-
copy_vmpa(&area_pos, get_mrange_addr(&area_range));
new_length = get_mrange_length(&area_range) - get_mrange_length(sym_range);
diff --git a/src/analysis/disass/area.h b/src/analysis/disass/area.h
index 35a3533..aa26da0 100644
--- a/src/analysis/disass/area.h
+++ b/src/analysis/disass/area.h
@@ -25,10 +25,52 @@
#define _ANALYSIS_DISASS_AREA_H
+#include "../binary.h"
+#include "../../arch/instruction.h"
+#include "../../gtkext/gtkextstatusbar.h"
+
+
+
+
+/* Zone mémoire bien bornée */
+typedef struct _mem_area_v2 mem_area_v2;
+
+
+
+
+
+/* Procède au désassemblage d'un contenu binaire exécutable. */
+void load_code_from_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, const vmpa2t *, status_blob_info *);
+
+
+
+
+/* Détermine une liste de zones contigües à traiter. */
+mem_area_v2 *find_memory_area_by_addr_v2(mem_area_v2 *, size_t, const vmpa2t *);
+
+
+
+/* Détermine une liste de zones contigües à traiter. */
+mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *, phys_t, size_t *);
+
+/* Insère un symbole dans un découpage en aires. */
+void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *, size_t, const GBinSymbol *);
+
+/* S'assure que l'ensemble des aires est entièrement décodé. */
+void ensure_all_mem_areas_are_filled(mem_area_v2 *, size_t, GProcContext *, status_blob_info *);
+
+/* Rassemble les instructions conservées dans des zones données. */
+GArchInstruction *collect_instructions_from_mem_areas_v2(const mem_area_v2 *, size_t);
+
+
+
+
+
#include <stdbool.h>
+
#include "../binary.h"
#include "../../format/executable.h"
#include "../../gtkext/gtkextstatusbar.h"
@@ -48,6 +90,7 @@ typedef struct _mem_area mem_area;
+
/* Procède au désassemblage d'un contenu binaire exécutable. */
bool load_code_from_mem_area(mem_area **, size_t *, size_t *, const GLoadedBinary *, GProcContext *, const vmpa2t *, status_blob_info *);
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index ce49aca..ce2e6ff 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -190,6 +190,8 @@ static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *binary, GAr
static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar)
{
+ wgroup_id_t gid; /* Identifiant pour les tâches */
+
//GBinFormat *format; /* Format du fichier binaire */
GArchProcessor *proc; /* Architecture du binaire */
@@ -208,6 +210,13 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
//GArchProcessor *proc; /* Architecture du binaire */
+
+ gid = g_work_queue_define_work_group(get_work_queue());
+
+
+
+
+
//format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
proc = g_loaded_binary_get_processor(disass->binary);
@@ -225,7 +234,7 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
- *disass->instrs = disassemble_binary_content(disass->binary, statusbar);
+ *disass->instrs = disassemble_binary_content(disass->binary, gid, statusbar);
g_arch_processor_set_disassembled_instructions(proc, *disass->instrs);
diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c
index 67a6f3b..bfc0598 100644
--- a/src/analysis/disass/fetch.c
+++ b/src/analysis/disass/fetch.c
@@ -31,18 +31,331 @@
#include "area.h"
+#include "../../glibext/delayed-int.h"
+
+
+
+
+
+
+
+
+/* ------------------------- RECUPERATIONS EN TOILE DE FOND ------------------------- */
+/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */
+
+
+#define G_TYPE_DELAYED_FETCHING g_delayed_fetching_get_type()
+#define G_DELAYED_FETCHING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_fetching_get_type(), GDelayedFetching))
+#define G_IS_DELAYED_FETCHING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_fetching_get_type()))
+#define G_DELAYED_FETCHING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_FETCHING, GDelayedFetchingClass))
+#define G_IS_DELAYED_FETCHING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_FETCHING))
+#define G_DELAYED_FETCHING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_FETCHING, GDelayedFetchingClass))
+
+
+/* Ensembles binaires à désassembler (instance) */
+typedef struct _GDelayedFetching
+{
+ GDelayedWork parent; /* A laisser en premier */
+
+ wgroup_id_t gid; /* Groupe de travail parallèle */
+
+ GExeFormat *format; /* Format du fichier binaire */
+
+ GProcContext *ctx; /* Contexte de désassemblage */
+ mem_area_v2 *areas; /* Zone de productions */
+ size_t count; /* Nombre de ces zones */
+ status_blob_info *info; /* Informations de progression */
+
+ virt_t virt; /* Adresse de départ dépilée */
+
+} GDelayedFetching;
+
+/* Ensembles binaires à désassembler (classe) */
+typedef struct _GDelayedFetchingClass
+{
+ GDelayedWorkClass parent; /* A laisser en premier */
+
+} GDelayedFetchingClass;
+
+
+/* Indique le type défini pour les tâches de récupération différée. */
+GType g_delayed_fetching_get_type(void);
+
+/* Initialise la classe des tâches de désassemblage différé. */
+static void g_delayed_fetching_class_init(GDelayedFetchingClass *);
+
+/* Initialise une tâche de désassemblage différé. */
+static void g_delayed_fetching_init(GDelayedFetching *);
+
+/* Supprime toutes les références externes. */
+static void g_delayed_fetching_dispose(GDelayedFetching *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_delayed_fetching_finalize(GDelayedFetching *);
+
+/* Crée une tâche de récupération d'instructions différée. */
+static GDelayedFetching *g_delayed_fetching_new(const GDelayedFetching *, virt_t);
+
+/* Assure la récupération d'instructions en différé. */
+static void g_delayed_fetching_process(GDelayedFetching *, GtkExtStatusBar *);
+
+
+
+
+
+
+
+
+
+
+/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */
+/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */
+
/* Suit un flot d'exécution pour désassembler du code. */
static void follow_execution_flow(const GLoadedBinary *, GProcContext *, mem_area **, size_t *, status_blob_info *);
-/* S'assure que l'ensemble des aires est entièrement décodé. */
-static void ensure_all_mem_areas_are_filled(mem_area **, size_t *, const GLoadedBinary *, GProcContext *, status_blob_info *);
+
+
+/* ---------------------------------------------------------------------------------- */
+/* RECUPERATIONS EN TOILE DE FOND */
+/* ---------------------------------------------------------------------------------- */
+
+
+
+
+
+
+
+
+/* Indique le type défini pour les tâches de récupération différée. */
+G_DEFINE_TYPE(GDelayedFetching, g_delayed_fetching, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des tâches de récupération différée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_delayed_fetching_class_init(GDelayedFetchingClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GDelayedWorkClass *work; /* Version en classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_fetching_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_delayed_fetching_finalize;
+
+ work = G_DELAYED_WORK_CLASS(klass);
+
+ work->run = (run_task_fc)g_delayed_fetching_process;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fetching = instance à initialiser. *
+* *
+* Description : Initialise une tâche de récupération différée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_delayed_fetching_init(GDelayedFetching *fetching)
+{
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fetching = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_delayed_fetching_dispose(GDelayedFetching *fetching)
+{
+ g_object_unref(G_OBJECT(fetching->format));
+
+ g_object_unref(G_OBJECT(fetching->ctx));
+
+ G_OBJECT_CLASS(g_delayed_fetching_parent_class)->dispose(G_OBJECT(fetching));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fetching = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_delayed_fetching_finalize(GDelayedFetching *fetching)
+{
+ G_OBJECT_CLASS(g_delayed_fetching_parent_class)->finalize(G_OBJECT(fetching));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : template = modèle dont les informations sont à copier. *
+* virt = point départ dépilé et personnalisant l'instance. *
+* *
+* Description : Crée une tâche de récupération d'instructions différée. *
+* *
+* Retour : Tâche créée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GDelayedFetching *g_delayed_fetching_new(const GDelayedFetching *template, virt_t virt)
+{
+ GDelayedFetching *result; /* Tâche à retourner */
+
+ result = g_object_new(G_TYPE_DELAYED_FETCHING, NULL);
+
+ result->gid = template->gid;
+
+ result->format = template->format;
+ g_object_ref(G_OBJECT(result->format));
+
+ result->ctx = template->ctx;
+ g_object_ref(G_OBJECT(result->ctx));
+
+ result->areas = template->areas;
+ result->count = template->count;
+ result->info = template->info;
+
+ result->virt = virt;
+
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fetching = récupération à mener. *
+* statusbar = barre de statut à tenir informée. *
+* *
+* Description : Assure la récupération d'instructions en différé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_delayed_fetching_process(GDelayedFetching *fetching, GtkExtStatusBar *statusbar)
+{
+ vmpa2t addr; /* Conversion en pleine adresse*/
+ mem_area_v2 *area; /* Zone trouvée à traiter */
+
+ if (!g_exe_format_translate_address_into_vmpa(fetching->format, fetching->virt, &addr))
+ init_vmpa(&addr, VMPA_NO_PHYSICAL, fetching->virt);
+
+ area = find_memory_area_by_addr_v2(fetching->areas, fetching->count, &addr);
+
+ if (area != NULL)
+ load_code_from_mem_area_v2(area, fetching->areas, fetching->count,
+ fetching->ctx, &addr, fetching->info);
+
+}
+
+
+
+
+
+
+
+
+
+
+/* Poursuit l'analyse à partir des points d'entrée découverts. */
+static void follow_execution_flow_v2(GProcContext *, const GDelayedFetching *);
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : ctx = contexte de désass. avec une nouvelle entrée. *
+* template = modèle dont les informations sont à copier. *
+* *
+* Description : Poursuit l'analyse à partir des points d'entrée découverts. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void follow_execution_flow_v2(GProcContext *ctx, const GDelayedFetching *template)
+{
+ GWorkQueue *queue; /* Gestionnaire de différés */
+ virt_t virt; /* Adresse de départ dépilée */
+ GDelayedFetching *fetching; /* Récupération à mener */
+
+ queue = get_work_queue();
+
+ while (g_proc_context_pop_drop_point(ctx, &virt))
+ {
+ fetching = g_delayed_fetching_new(template, virt);
+
+ /**
+ * Pas très élégant : l'identifiant du groupe de travail ne sert qu'ici ;
+ * il n'est donc aucune utilité dans la tâche elle-même.
+ *
+ * Cependant, les paramètres d'appel étant limités, il faudrait créer
+ * une structure intermediare pour communiquer l'identifiant, ce qui
+ * est tout aussi moche.
+ */
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(fetching), template->gid);
+
+ }
+
+}
+
+
/******************************************************************************
* *
* Paramètres : binary = représentation de binaire chargé. *
@@ -68,7 +381,7 @@ static void follow_execution_flow(const GLoadedBinary *binary, GProcContext *ctx
while (g_proc_context_has_drop_points(ctx))
{
- virt = g_proc_context_pop_drop_point(ctx);
+ g_proc_context_pop_drop_point(ctx, &virt);
format = g_loaded_binary_get_format(binary);
@@ -96,38 +409,13 @@ static void follow_execution_flow(const GLoadedBinary *binary, GProcContext *ctx
}
-
-/******************************************************************************
-* *
-* Paramètres : list = liste de zones délimitant des contenus à traiter. *
-* count = nombre de zones à disposition. *
-* binary = représentation de binaire chargé. *
-* ctx = contexte offert en soutien à un désassemblage. *
-* info = indications quant à la progression à afficher. *
-* *
-* Description : S'assure que l'ensemble des aires est entièrement décodé. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void ensure_all_mem_areas_are_filled(mem_area **list, size_t *count, const GLoadedBinary *binary, GProcContext *ctx, status_blob_info *info)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < *count; i++)
- fill_mem_area(list, count, &i, binary, ctx, info);
-
-}
-
+static GDelayedFetching template; /* Patron des tâches à venir */
/******************************************************************************
* *
* Paramètres : binary = représentation de binaire chargé. *
+* gid = identifiant du groupe de travail à utiliser. *
* statusbar = barre de statut avec progression à mettre à jour.*
-* id = identifiant du message affiché à l'utilisateur. *
* *
* Description : Procède au désassemblage basique d'un contenu binaire. *
* *
@@ -137,75 +425,96 @@ static void ensure_all_mem_areas_are_filled(mem_area **list, size_t *count, cons
* *
******************************************************************************/
-GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, GtkExtStatusBar *statusbar)
+GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup_id_t gid, GtkExtStatusBar *statusbar)
{
GArchInstruction *result; /* Instruction désassemblées */
+ //GDelayedFetching template; /* Patron des tâches à venir */
GBinFormat *format; /* Format du fichier binaire */
GArchProcessor *proc; /* Architecture du binaire */
- GProcContext *ctx; /* Contexte de désassemblage */
GBinContent *content; /* Contenu binaire à manipuler */
phys_t length; /* Taille des données à lire */
- mem_area *areas; /* Zone de productions */
- size_t count; /* Nombre de ces zones */
- status_blob_info *info; /* Informations de progression */
+ GWorkQueue *queue; /* Gestionnaire de différés */
double done; /* Portion de travail accompli */
- format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
- proc = g_loaded_binary_get_processor(binary);
- ctx = g_arch_processor_get_context(proc);
- g_binary_format_setup_disassembling_context(format, ctx);
- /* Définition à la découpe des parties à traiter */
+
+
+
+
+
+ /* Constitution du modèle de référence */
+
+ template.gid = gid;
+
+ template.format = g_loaded_binary_get_format(binary);
+ format = G_BIN_FORMAT(template.format);
+
+ proc = g_loaded_binary_get_processor(binary);
+ template.ctx = g_arch_processor_get_context(proc);
+ g_object_unref(G_OBJECT(proc));
content = g_binary_format_get_content(format);
length = g_binary_content_compute_size(content);
+ g_object_unref(G_OBJECT(content));
- areas = compute_memory_areas(G_EXE_FORMAT(format), length, &count);
+ template.areas = compute_memory_areas_v2(binary, length, &template.count);
+
+ /* Amorce des traitements */
+
+ g_signal_connect(template.ctx, "drop-point-pushed", G_CALLBACK(follow_execution_flow_v2), &template);
+
+ queue = get_work_queue();
/**
* Première phase de désassemblage : suivi des chemins tracés.
*/
- info = init_progessive_status(statusbar,
- _("Disassembling following the execution flow..."),
- 0, length);
+ template.info = init_progessive_status(statusbar,
+ _("Disassembling following the execution flow..."),
+ 0, length);
+
+ g_binary_format_setup_disassembling_context(format, template.ctx);
+
+ g_work_queue_wait_for_completion(queue, gid);
- follow_execution_flow(binary, ctx, &areas, &count, info);
+ printf("===================== DONE !\n");
- done = get_current_progessive_status(info);
+ done = get_current_progessive_status(template.info);
- fini_progessive_status(info);
+ fini_progessive_status(template.info);
/**
* Seconde phase : on comble les trous laissés.
*/
- info = init_progessive_status(statusbar,
- _("Disassembling the remaining instructions..."),
- done, length);
+ template.info = init_progessive_status(statusbar,
+ _("Disassembling the remaining instructions..."),
+ done, length);
- ensure_all_mem_areas_are_filled(&areas, &count, binary, ctx, info);
+ ensure_all_mem_areas_are_filled(template.areas, template.count, template.ctx, template.info);
- fini_progessive_status(info);
+ fini_progessive_status(template.info);
/**
* Troisième et dernière phase : récolte des fruits.
*/
- info = init_progessive_status(statusbar,
- _("Collecting disassembled instructions..."),
- 0, length);
+ template.info = init_progessive_status(statusbar,
+ _("Collecting disassembled instructions..."),
+ 0, length);
- result = collect_instructions_from_mem_areas(areas, count);
+ result = collect_instructions_from_mem_areas_v2(template.areas, template.count);
- fini_progessive_status(info);
+ fini_progessive_status(template.info);
- /* free */
+ /* Libérations finales */
- g_object_unref(G_OBJECT(content));
+ //g_object_unref(G_OBJECT(template.format));
- g_object_unref(G_OBJECT(proc));
+ g_object_unref(G_OBJECT(template.ctx));
+
+ /* TODO / del(areas); */
return result;
diff --git a/src/analysis/disass/fetch.h b/src/analysis/disass/fetch.h
index 0270f78..37dac80 100644
--- a/src/analysis/disass/fetch.h
+++ b/src/analysis/disass/fetch.h
@@ -26,12 +26,13 @@
#include "../binary.h"
+#include "../../glibext/delayed.h"
#include "../../gtkext/gtkextstatusbar.h"
/* Procède au désassemblage basique d'un contenu binaire. */
-GArchInstruction *disassemble_binary_content(const GLoadedBinary *, GtkExtStatusBar *);
+GArchInstruction *disassemble_binary_content(const GLoadedBinary *, wgroup_id_t, GtkExtStatusBar *);
diff --git a/src/arch/archbase.h b/src/arch/archbase.h
index 24cfd77..fc6fe4d 100644
--- a/src/arch/archbase.h
+++ b/src/arch/archbase.h
@@ -74,6 +74,31 @@ typedef enum _MemoryDataSize
#define MDS_IS_SIGNED(mds) (mds & 0x80)
+#define MDS_FROM_BYTES(sz) \
+ ({ \
+ MemoryDataSize __result; \
+ switch (sz) \
+ { \
+ case 1: \
+ __result = MDS_8_BITS_UNSIGNED; \
+ break; \
+ case 2: \
+ __result = MDS_16_BITS_UNSIGNED; \
+ break; \
+ case 4: \
+ __result = MDS_32_BITS_UNSIGNED; \
+ break; \
+ case 8: \
+ __result = MDS_64_BITS_UNSIGNED; \
+ break; \
+ default: \
+ __result = MDS_UNDEFINED; \
+ break; \
+ } \
+ __result; \
+ })
+
+
#define MDS_4_BITS MDS_4_BITS_UNSIGNED
#define MDS_8_BITS MDS_8_BITS_UNSIGNED
#define MDS_16_BITS MDS_16_BITS_UNSIGNED
diff --git a/src/arch/arm/context-int.h b/src/arch/arm/context-int.h
index 51ed6d0..fbd3a6f 100644
--- a/src/arch/arm/context-int.h
+++ b/src/arch/arm/context-int.h
@@ -50,6 +50,7 @@ struct _GArmContext
disass_arm_area *areas; /* Désassemblage découpé */
size_t acount; /* Nombre de zones définies */
+ GMutex areas_access; /* Accès aux découpes de zones */
};
diff --git a/src/arch/arm/context.c b/src/arch/arm/context.c
index b54de42..d805e8c 100644
--- a/src/arch/arm/context.c
+++ b/src/arch/arm/context.c
@@ -139,6 +139,7 @@ static void g_arm_context_class_init(GArmContextClass *klass)
static void g_arm_context_init(GArmContext *ctx)
{
+ g_mutex_init(&ctx->areas_access);
}
@@ -157,6 +158,8 @@ static void g_arm_context_init(GArmContext *ctx)
static void g_arm_context_dispose(GArmContext *ctx)
{
+ g_mutex_clear(&ctx->areas_access);
+
G_OBJECT_CLASS(g_arm_context_parent_class)->dispose(G_OBJECT(ctx));
}
@@ -263,11 +266,11 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int
{
size_t selected; /* Zone associée à une adresse */
- /* TODO : pose de verroux ? */
+ g_mutex_lock(&ctx->areas_access);
selected = find_disass_arm_area(ctx->areas, addr, 0, ctx->acount - 1);
- assert(ctx->areas[selected].start != addr || ctx->areas[selected].marker == marker);
+ //assert(ctx->areas[selected].start != addr || ctx->areas[selected].marker == marker);
/* S'agit-il d'une redéfinition ? */
if (ctx->areas[selected].start == addr)
@@ -290,6 +293,8 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int
}
+ g_mutex_unlock(&ctx->areas_access);
+
}
@@ -308,13 +313,18 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int
unsigned int _g_arm_context_find_encoding(GArmContext *ctx, virt_t addr)
{
+ unsigned int result; /* Identifiant à retourner */
size_t selected; /* Zone associée à une adresse */
- /* TODO : pose de verroux ? */
+ g_mutex_lock(&ctx->areas_access);
selected = find_disass_arm_area(ctx->areas, addr, 0, ctx->acount - 1);
- return ctx->areas[selected].marker;
+ result = ctx->areas[selected].marker;
+
+ g_mutex_unlock(&ctx->areas_access);
+
+ return result;
}
diff --git a/src/arch/arm/v7/context.c b/src/arch/arm/v7/context.c
index 885ce70..030457e 100644
--- a/src/arch/arm/v7/context.c
+++ b/src/arch/arm/v7/context.c
@@ -245,7 +245,15 @@ void g_armv7_context_push_drop_point_ext(GArmV7Context *ctx, virt_t addr, ArmV7I
g_armv7_context_define_encoding(ctx, addr, marker);
- G_PROC_CONTEXT_CLASS(g_armv7_context_parent_class)->push_point(G_PROC_CONTEXT(ctx), addr);
+ /**
+ * Il faut impérativement passer pour l'interface publique afin :
+ * - de poser le verrou associé.
+ * - de déclencher l'émission du signal lié.
+ *
+ * Pas d'appel via G_PROC_CONTEXT_CLASS(g_armv7_context_parent_class)->push_point() donc.
+ */
+
+ g_proc_context_push_drop_point(G_PROC_CONTEXT(ctx), addr);
}
diff --git a/src/arch/context-int.h b/src/arch/context-int.h
index 64465a2..086a8ec 100644
--- a/src/arch/context-int.h
+++ b/src/arch/context-int.h
@@ -29,6 +29,10 @@
+/* Granularité des allocations */
+#define DP_ALLOC_BLOCK 10
+
+
/* Ajoute une adresse virtuelle comme point de départ de code. */
typedef void (* push_drop_point_fc) (GProcContext *, virt_t);
@@ -39,7 +43,9 @@ struct _GProcContext
GObject parent; /* A laisser en premier */
virt_t *drop_points; /* Liste de points de départ */
- size_t dp_count; /* Taille de cette liste */
+ size_t dp_allocated; /* Taille de liste allouée */
+ size_t dp_count; /* Quantité utile de la liste */
+ GMutex dp_access; /* Accès à la liste FIFO */
vmpa2t *extra_symbols; /* Adresses de symboles */
size_t esyms_count; /* Nombres de nouveautés */
@@ -54,6 +60,10 @@ struct _GProcContextClass
push_drop_point_fc push_point; /* Inclusion de points de chute*/
+ /* Signaux */
+
+ void (* drop_point_pushed) (GProcContext *);
+
};
diff --git a/src/arch/context.c b/src/arch/context.c
index 5427e4a..968a6ea 100644
--- a/src/arch/context.c
+++ b/src/arch/context.c
@@ -65,6 +65,14 @@ static void g_proc_context_class_init(GProcContextClass *klass)
{
klass->push_point = (push_drop_point_fc)_g_proc_context_push_drop_point;
+ g_signal_new("drop-point-pushed",
+ G_TYPE_PROC_CONTEXT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GProcContextClass, drop_point_pushed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
}
@@ -83,7 +91,9 @@ static void g_proc_context_class_init(GProcContextClass *klass)
static void g_proc_context_init(GProcContext *ctx)
{
ctx->drop_points = NULL;
+ ctx->dp_allocated = 0;
ctx->dp_count = 0;
+ g_mutex_init(&ctx->dp_access);
ctx->extra_symbols = NULL;
ctx->esyms_count = 0;
@@ -106,9 +116,15 @@ static void g_proc_context_init(GProcContext *ctx)
static void _g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr)
{
- ctx->drop_points = (virt_t *)realloc(ctx->drop_points, ++ctx->dp_count * sizeof(virt_t));
+ if (ctx->dp_count >= ctx->dp_allocated)
+ {
+ ctx->dp_allocated += DP_ALLOC_BLOCK;
+
+ ctx->drop_points = (virt_t *)realloc(ctx->drop_points, ctx->dp_allocated * sizeof(virt_t));
+
+ }
- ctx->drop_points[ctx->dp_count - 1] = addr;
+ ctx->drop_points[ctx->dp_count++] = addr;
}
@@ -128,7 +144,13 @@ static void _g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr)
void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr)
{
- return G_PROC_CONTEXT_GET_CLASS(ctx)->push_point(ctx, addr);
+ g_mutex_lock(&ctx->dp_access);
+
+ G_PROC_CONTEXT_GET_CLASS(ctx)->push_point(ctx, addr);
+
+ g_mutex_unlock(&ctx->dp_access);
+
+ g_signal_emit_by_name(ctx, "drop-point-pushed");
}
@@ -147,7 +169,15 @@ void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr)
bool g_proc_context_has_drop_points(const GProcContext *ctx)
{
- return ctx->dp_count > 0;
+ bool result; /* Etat à retourner */
+
+ g_mutex_lock(&ctx->dp_access);
+
+ result = (ctx->dp_count > 0);
+
+ g_mutex_unlock(&ctx->dp_access);
+
+ return result;
}
@@ -172,9 +202,13 @@ bool g_proc_context_has_addr_as_drop_points(const GProcContext *ctx, virt_t addr
result = false;
+ g_mutex_lock(&ctx->dp_access);
+
for (i = 0; i < ctx->dp_count && !result; i++)
result = (ctx->drop_points[i] == addr);
+ g_mutex_unlock(&ctx->dp_access);
+
return result;
}
@@ -183,27 +217,38 @@ bool g_proc_context_has_addr_as_drop_points(const GProcContext *ctx, virt_t addr
/******************************************************************************
* *
* Paramètres : ctx = contexte de désassemblage à compléter. *
+* virt = adresse d'un point de départ de code à traiter. *
* *
* Description : Fournit une adresse virtuelle comme point de départ de code. *
* *
-* Retour : Adresse d'un point de départ de code à traiter. *
+* Retour : true si une adresse a pu être dépilée, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
-virt_t g_proc_context_pop_drop_point(GProcContext *ctx)
+bool g_proc_context_pop_drop_point(GProcContext *ctx, virt_t *virt)
{
- virt_t result; /* Adresse à retourner */
+ bool result; /* Bilan d'accès à retourner */
- assert(ctx->dp_count > 0);
+ g_mutex_lock(&ctx->dp_access);
- result = ctx->drop_points[0];
+ if (ctx->dp_count > 0)
+ {
+ result = true;
+
+ *virt = ctx->drop_points[0];
+
+ if (ctx->dp_count > 1)
+ memmove(&ctx->drop_points[0], &ctx->drop_points[1], (ctx->dp_count - 1) * sizeof(virt_t));
- if (ctx->dp_count > 1)
- memmove(&ctx->drop_points[0], &ctx->drop_points[1], (ctx->dp_count - 1) * sizeof(virt_t));
+ ctx->dp_count--;
+
+ }
+ else
+ result = false;
- ctx->drop_points = (virt_t *)realloc(ctx->drop_points, --ctx->dp_count * sizeof(virt_t));
+ g_mutex_unlock(&ctx->dp_access);
return result;
diff --git a/src/arch/context.h b/src/arch/context.h
index 390d9f9..973b7ae 100644
--- a/src/arch/context.h
+++ b/src/arch/context.h
@@ -61,7 +61,7 @@ bool g_proc_context_has_drop_points(const GProcContext *);
bool g_proc_context_has_addr_as_drop_points(const GProcContext *, virt_t);
/* Fournit une adresse virtuelle comme point de départ de code. */
-virt_t g_proc_context_pop_drop_point(GProcContext *);
+bool g_proc_context_pop_drop_point(GProcContext *, virt_t *);
/* Empile une adresse de nouveau symbole à prendre en compte. */
void g_proc_context_push_new_symbol_at(GProcContext *, const vmpa2t *);
diff --git a/src/common/bits.c b/src/common/bits.c
index d451100..b08dcb4 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -25,6 +25,7 @@
#include <assert.h>
+#include <glib.h>
#include <malloc.h>
#include <string.h>
@@ -41,6 +42,7 @@ struct _bitfield_t
void *tail; /* Limite du tableau de bits */
+ GMutex mutex; /* Garantie d'atomicité */
unsigned long bits[0]; /* Mémoire d'accès associée */
};
@@ -94,6 +96,8 @@ static bitfield_t *_create_bit_field(size_t length, bool state, size_t extra)
result->tail = ((char *)result) + base;
+ g_mutex_init(&result->mutex);
+
if (state)
set_all_in_bit_field(result);
else
@@ -177,6 +181,8 @@ bitfield_t *create_bit_field_from(const bitfield_t *field)
void delete_bit_field(bitfield_t *field)
{
+ g_mutex_clear(&field->mutex);
+
free(field);
}
@@ -330,6 +336,68 @@ void set_in_bit_field(bitfield_t *field, size_t first, size_t count)
/******************************************************************************
* *
+* Paramètres : field = champ de bits à modifier. *
+* first = indice du premier bit à traiter. *
+* count = nombre de bits à marquer. *
+* *
+* Description : Bascule à 1 de façon atomique une partie d'un champ de bits. *
+* *
+* Retour : true si la zone traitée était entièrement vierge. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool set_atomic_in_bit_field(bitfield_t *field, size_t first, size_t count)
+{
+ bool result; /* Bilan à retourner */
+ size_t start; /* Mot de départ */
+ size_t end; /* Mot d'arrivée */
+ size_t remaining; /* Nombre de bits restants */
+ unsigned long oldval; /* Ancienne valeur présente */
+ unsigned long mask; /* Nouvelle valeur à insérer */
+
+ start = first / (sizeof(unsigned long) * 8);
+ end = (first + count - 1) / (sizeof(unsigned long) * 8);
+
+#if 0 //sizeof(gsize) != sizeof(unsigned long)
+# warning "Can not perform atomic operations on bit fields!"
+#else
+ if (start == end)
+ {
+ remaining = first % (sizeof(unsigned long) * 8);
+
+ assert(count > 0);
+
+ mask = (1 << count) - 1;
+ mask <<= remaining;
+
+ oldval = g_atomic_pointer_or(&field->bits[start], mask);
+
+ result = ((oldval & mask) == 0);
+
+ }
+ else
+#endif
+ {
+ g_mutex_lock(&field->mutex);
+
+ result = !test_in_bit_field(field, first, count);
+
+ if (result)
+ set_in_bit_field(field, first, count);
+
+ g_mutex_unlock(&field->mutex);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : dest = champ de bits à modifier. *
* src = champ de bits à utiliser pour l'opération. *
* *
diff --git a/src/common/bits.h b/src/common/bits.h
index 0e8ef65..074aac4 100644
--- a/src/common/bits.h
+++ b/src/common/bits.h
@@ -60,6 +60,9 @@ void set_all_in_bit_field(bitfield_t *);
/* Bascule à 1 une partie d'un champ de bits. */
void set_in_bit_field(bitfield_t *, size_t, size_t);
+/* Bascule à 1 de façon atomique une partie d'un champ de bits. */
+bool set_atomic_in_bit_field(bitfield_t *, size_t, size_t);
+
/* Réalise une opération ET logique entre deux champs de bits. */
void and_bit_field(bitfield_t *, const bitfield_t *);
@@ -74,6 +77,7 @@ bool is_bit_field_equal_to(const bitfield_t *, const bitfield_t *);
+
unsigned long gfw(const bitfield_t *);
@@ -104,4 +108,9 @@ bool test_in_mem_field(memfield_t *, const vmpa2t *);
+#define set_atomic_in_mem_field(f, range) false
+
+
+
+
#endif /* _COMMON_BITS_H */
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index ea520b9..3dc5d64 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -432,6 +432,12 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *
sh_flags = ELF_SHDR(format, section, sh_flags);
+ printf("[section % 2hu] 0x%08x -> %x -> %d\n", i, sh_flags,
+ sh_flags & SHF_ALLOC, (sh_flags & SHF_ALLOC) == 0);
+
+ if ((sh_flags & SHF_ALLOC) == 0)
+ continue;
+
if (sh_flags & SHF_EXECINSTR) background = BPC_CODE;
else if (sh_flags & SHF_WRITE) background = BPC_DATA;
else background = BPC_DATA_RO;
diff --git a/src/format/symbol.h b/src/format/symbol.h
index 1368691..6f38020 100644
--- a/src/format/symbol.h
+++ b/src/format/symbol.h
@@ -51,6 +51,10 @@ typedef enum _SymbolType
} SymbolType;
+#define HAS_DATA_INSTR(type) (type == STP_DATA || type == STP_RO_STRING)
+
+
+
#define G_TYPE_BIN_SYMBOL g_binary_symbol_get_type()
#define G_BIN_SYMBOL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_binary_symbol_get_type(), GBinSymbol))
#define G_IS_BIN_SYMBOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_binary_symbol_get_type()))