summaryrefslogtreecommitdiff
path: root/src/analysis/decomp/il.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/decomp/il.c')
-rw-r--r--src/analysis/decomp/il.c772
1 files changed, 0 insertions, 772 deletions
diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c
deleted file mode 100644
index cbc0c37..0000000
--- a/src/analysis/decomp/il.c
+++ /dev/null
@@ -1,772 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * il.h - mise en place d'un langage intermédiaire
- *
- * Copyright (C) 2012-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 <http://www.gnu.org/licenses/>.
- */
-
-
-#include "il.h"
-
-
-#include <malloc.h>
-
-
-#include "../blocks/flow.h"
-#include "../blocks/virtual.h"
-#include "../../decomp/expr/block.h"
-#include "../../decomp/expr/immediate.h"
-#include "../../decomp/instr/ite.h"
-#include "../../decomp/instr/keyword.h"
-#include "../../decomp/instr/switch.h"
-
-
-
-/* --------------------- GESTION DES CONTEXTES DE DECOMPILATION --------------------- */
-
-
-/* Détermine les registres utilisés avant leur initialisation. */
-static bool track_used_registers(GFlowBlock *, BlockFollowPosition, GRAccessList **);
-
-/* Etablit le relévé des allocations de registre. */
-static void setup_awaited_regs_allocation(const GInstrBlock *, vmpa_t);
-
-/* Etablit la liste de tous les allocations attendues. */
-static bool merge_all_awaited_regs(GInstrBlock *, BlockVisitOrder, GRAccessList *);
-
-/* Met en place un contexte adapté aux sous-blocs d'un bloc. */
-static GDecContext *create_new_context_for_sub_block(GDecContext *, GInstrBlock *, GHashTable *);
-
-
-
-/* -------------------------- ENCADREMENT DES INSTRUCTIONS -------------------------- */
-
-
-/* Retrouve et rassemble les instructions décompilées. */
-static GDecInstruction *merge_decompiled_instructions(GDecInstruction *, GDecInstruction *);
-
-/* Procède à la décompilation d'un bloc déterminé. */
-static GDecInstruction *decompiled_instructions_block(GFlowBlock *, GDecContext *);
-
-/* Procède à la décompilation d'un ensemble de blocs déterminé. */
-static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *, GDecContext *);
-
-/* Procède à la décompilation d'un bloc basique quelconque. */
-static GDecInstruction *decompiled_basic_block(GInstrBlock *, GDecContext *);
-
-
-
-/* --------------------------- DECOMPILATIONS SPECIFIQUES --------------------------- */
-
-
-/* Procède à la décompilation des éléments d'un 'if then else'. */
-static void build_ite_branches(GITEInstruction *, GFlowBlock *, GDecContext *);
-
-/* Termine le traitement d'un cas de 'switch'. */
-static void close_case_decomp_instructions(GDecInstruction *, GInstrBlock *, GArchInstruction **, size_t, size_t);
-
-/* Procède à la décompilation des éléments d'un 'switch'. */
-static void build_switch_branches(GSwitchInstruction *, GFlowBlock *, GDecContext *);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* GESTION DES CONTEXTES DE DECOMPILATION */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : block = bloc d'instructions visité. *
-* pos = indication sur la position du parcours. *
-* needed = suivi de l'usage des registres entre les blocs. *
-* *
-* Description : Détermine les registres utilisés avant leur initialisation. *
-* *
-* Retour : true pour mener un parcours complet. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool track_used_registers(GFlowBlock *block, BlockFollowPosition pos, GRAccessList **needed)
-{
- GRAccessList *old; /* Ancienne liste remplacée */
- const GRAccessList *accesses; /* Accès divers aux registres */
- size_t count; /* Taille d'un parcours */
- GRAccessList *awaited; /* Satisfactions des besoins */
- reg_access *access; /* Accès à un registre */
- size_t i; /* Boucle de parcours */
- reg_access *found; /* Besoin trouvé ou non */
-
- switch (pos)
- {
- case BFP_ENTER:
- g_object_set_data(G_OBJECT(block), "needed_regs", *needed);
- break;
-
- case BFP_FOLLOW:
- *needed = g_raccess_list_new();
- break;
-
- case BFP_BACK:
-
- old = *needed;
- *needed = G_RACCESS_LIST(g_object_get_data(G_OBJECT(block), "needed_regs"));
-
- g_raccess_list_merge(*needed, old);
- g_object_unref(G_OBJECT(old));
-
- break;
-
- case BFP_EXIT:
-
- g_object_set_data(G_OBJECT(block), "needed_regs", NULL);
-
- accesses = g_flow_block_list_regs_accesses(block);
- count = g_raccess_list_count(accesses);
-
- awaited = g_flow_block_list_awaited_regs(block);
-
- for (i = 0; i < count; i++)
- {
- access = g_raccess_list_get(accesses, i);
-
- /* Enregistrement des contributions possibles */
-
- found = g_raccess_list_find(*needed, access->reg);
-
- if (found != NULL)
- {
- /**
- * Si un autre bloc avait déjà un besoin, on ne prend note
- * qu'une seule fois !
- */
- if (g_raccess_list_find(awaited, access->reg) == NULL)
- g_raccess_list_add(awaited, access);
-
- g_raccess_list_delete(*needed, found);
-
- }
-
- /* Ajoute les besoins du bloc */
- if (access->first_access == RAT_READ)
- g_raccess_list_add(*needed, access);
-
- }
-
- /*
- do
- {
- vmpa_t start, end;
-
- g_flow_block_get_boundary_addresses(block, &start, &end);
-
- printf(" -> flow (%d) : 0x%08x - 0x%08x | needed = %zu - provided = %zu\n",
- pos, start, end,
- g_raccess_list_count(*needed), g_raccess_list_count(awaited));
-
- }
- while (0);
- */
-
- break;
-
- }
-
- return true;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : list = ensemble des instructions d'assemblage à traiter. *
-* start = adresse de départ de la routine visée. *
-* *
-* Description : Etablit le relévé des allocations de registre. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void setup_awaited_regs_allocation(const GInstrBlock *list, vmpa_t start)
-{
- GInstrBlock *first; /* Bloc de départ du flot */
- GRAccessList *needed; /* Registres inter-blocs */
-
- first = g_instr_block_find_by_addr(list, start, true);
-
- needed = g_raccess_list_new();
-
- g_flow_block_follow(G_FLOW_BLOCK(first), list, BFP_ENTER | BFP_EXIT | BFP_EXIT,
- (flow_block_follow_cb)track_used_registers, &needed);
-
- g_object_unref(G_OBJECT(needed));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : block = bloc d'instructions concerné par la visite. *
-* order = position dans la visite. *
-* list = liste à compléter. *
-* *
-* Description : Etablit la liste de tous les allocations attendues. *
-* *
-* Retour : true pour parcourir tous les blocs. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool merge_all_awaited_regs(GInstrBlock *block, BlockVisitOrder order, GRAccessList *list)
-{
- const GRAccessList *awaited; /* Registres conséquents */
-
- if (G_IS_FLOW_BLOCK(block))
- {
- awaited = g_flow_block_list_regs_accesses(G_FLOW_BLOCK(block));
- g_raccess_list_merge(list, awaited);
- }
-
- return true;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : ctx = contexte de décompilation courant. *
-* block = block regroupant les branches de division. *
-* shared = liste des allocations passées de registres attendus.*
-* *
-* Description : Met en place un contexte adapté aux sous-blocs d'un bloc. *
-* *
-* Retour : Nouveau contexte près à emploi. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GDecContext *create_new_context_for_sub_block(GDecContext *ctx, GInstrBlock *block, GHashTable *shared)
-{
- GDecContext *result; /* Contexte à retourner */
- GRAccessList *list; /* Allocations attendues */
-
- result = g_dec_context_dup(ctx);
-
- list = g_raccess_list_new();
- g_instr_block_visit(block, (instr_block_visitor_cb)merge_all_awaited_regs, list);
- g_dec_context_set_awaited(result, list);
- g_object_unref(G_OBJECT(list));
-
- g_dec_context_set_shared_allocs(result, shared);
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* ENCADREMENT DES INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : group = groupe d'instructions à compléter ou constituer. *
-* list = liste d'instructions à intégrer. *
-* *
-* Description : Retrouve et rassemble les instructions décompilées. *
-* *
-* Retour : Groupe fourni ou nouveau groupe créé pour l'occasion. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GDecInstruction *merge_decompiled_instructions(GDecInstruction *group, GDecInstruction *list)
-{
- GExprBlock *block; /* Autre vision du groupe */
- GDecInstruction *iter; /* Boucle de parcours */
-
- if (group == NULL) block = NULL;
- else block = G_EXPR_BLOCK(group);
-
- for (iter = list;
- iter != NULL;
- iter = g_dec_instruction_get_next_iter(list, iter))
- {
- if (block == NULL)
- block = G_EXPR_BLOCK(g_expr_block_new(iter));
- else
- g_expr_block_add_item(block, iter);
-
- }
-
- return G_DEC_INSTRUCTION(block);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : block = ensemble des instructions d'assemblage à traiter. *
-* ctx = contexte de soutien à associer à l'opération. *
-* *
-* Description : Procède à la décompilation d'un bloc déterminé. *
-* *
-* Retour : Instructions créées et enregistrées, ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecContext *ctx)
-{
- GArchInstruction *instrs; /* Liste d'instructions natives*/
- GArchInstruction *first; /* Première instruction du lot */
- vmpa_t max; /* Adresse de fin du bloc */
- GArchInstruction *iter; /* Boucle de parcours #1 */
- GDecInstruction *decomp; /* Dernier résultat de décomp. */
-
- instrs = NULL; // FIXME g_flow_block_get_all_instructions_list(block);
- g_flow_block_get_boundary(block, &first, NULL);
-
- g_flow_block_get_boundary_addresses(block, NULL, &max);
- max++;
-
- /* Décompilation du corps du bloc */
-
- for (iter = first;
- iter != NULL;
- iter = g_arch_instruction_get_next_iter(instrs, iter, max))
- {
- decomp = g_arch_instruction_decompile(iter, ctx);
- }
-
- /* Post-traitement selon les types de lien */
-
- /* if ... then ... else ... */
- if (G_IS_ITE_INSTRUCTION(decomp))
- build_ite_branches(G_ITE_INSTRUCTION(decomp), block, ctx);
-
- /* switch ... case ... */
- else if (G_IS_SWITCH_INSTRUCTION(decomp))
- build_switch_branches(G_SWITCH_INSTRUCTION(decomp), block, ctx);
-
- /* Renvoi des instructions mises en place */
-
- return g_dec_context_get_decomp_instrs(ctx);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : block = ensemble des instructions d'assemblage à traiter. *
-* ctx = contexte de soutien à associer à l'opération. *
-* *
-* Description : Procède à la décompilation d'un ensemble de blocs déterminé. *
-* *
-* Retour : Instructions créées et enregistrées, ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *block, GDecContext *ctx)
-{
- GDecInstruction *result; /* Instructions à renvoyer */
- size_t count; /* Nombre de sous-blocs */
- size_t i; /* Boucle de parcours */
- GInstrBlock *sub_block; /* Sous-bloc à traiter */
- GDecInstruction *dinstrs; /* Instructions décompilées */
-
- result = NULL;
-
- count = g_virtual_block_count_children(block);
-
- for (i = 0; i < count; i++)
- {
- sub_block = g_virtual_block_get_child(block, i);
-
- /**
- * Les groupes de blocs sont forcément rattachés à une instruction,
- * donc ils sont décompilés depuis ces instructions, pas ici.
- */
- if (!G_IS_FLOW_BLOCK(sub_block)) continue;
-
- /* FIXME */
- //g_dec_context_set_decomp_instrs(ctx, NULL);
-
- dinstrs = decompiled_instructions_block(G_FLOW_BLOCK(sub_block), ctx);
- //result = merge_decompiled_instructions(result, dinstrs);
-
- }
-
- result = merge_decompiled_instructions(result, dinstrs);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : block = ensemble des instructions d'assemblage à traiter. *
-* ctx = contexte de soutien à associer à l'opération. *
-* *
-* Description : Procède à la décompilation d'un bloc basique quelconque. *
-* *
-* Retour : Instructions créées et enregistrées, ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GDecInstruction *decompiled_basic_block(GInstrBlock *block, GDecContext *ctx)
-{
- GDecInstruction *result; /* Instructions à retourner */
-
- if (G_IS_VIRTUAL_BLOCK(block))
- result = decompiled_instructions_blocks(G_VIRTUAL_BLOCK(block), ctx);
-
- else
- {
- result = decompiled_instructions_block(G_FLOW_BLOCK(block), ctx);
-
- if (!G_IS_EXPR_BLOCK(result))
- result = merge_decompiled_instructions(NULL, result);
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : routine = routine dont le corps est à traiter. *
-* format = format du binaire contenant les instructions. *
-* proc = architecture du code machine. *
-* *
-* Description : Procède à la décompilation d'une routinée déterminée. *
-* *
-* Retour : Instructions créées ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GDecInstruction *decompiled_routine_instructions(GBinRoutine *routine, GExeFormat *format, GArchProcessor *proc)
-{
- GDecInstruction *result; /* Instructions à retourner */
- GDecContext *context; /* Contexte pour la décompil. */
- GInstrBlock *blocks; /* Blocs basiques de routine */
- const mrange_t *range; /* Emplacement du symbole */
-
- context = g_arch_processor_get_decomp_context(proc);
- g_dec_context_set_info(context, routine, format);
-
- blocks = g_binary_routine_get_basic_blocks(routine);
-
- range = g_binary_symbol_get_range(G_BIN_SYMBOL(routine));
- setup_awaited_regs_allocation(blocks, get_mrange_addr(range)->physical);
-
- result = decompiled_basic_block(blocks, context);
-
- g_object_unref(context);
-
- return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* DECOMPILATIONS SPECIFIQUES */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : decomp = instruction 'if ... then ... else' à compléter. *
-* block = ensemble des instructions d'assemblage traitées. *
-* ctx = contexte de soutien à associer à l'opération. *
-* *
-* Description : Procède à la décompilation des éléments d'un 'if then else'. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void build_ite_branches(GITEInstruction *decomp, GFlowBlock *block, GDecContext *ctx)
-{
- GArchInstruction *last; /* Dernière instruction du lot */
- GInstrBlock *sub_parent; /* Groupe des sous-branches */
- GHashTable *sub_shared; /* Allocations communes */
- GDecContext *sub_ctx; /* Sous-contexte pour branche */
- GDecInstruction *true_dinstr; /* Décompilation 'cond vraie' */
- GDecInstruction *false_dinstr; /* Décompilation 'cond fausse' */
- GArchInstruction *next; /* Instruction de branchement */
- vmpa_t next_addr; /* Adresse de cette instruct° */
- GInstrBlock *next_block; /* Sous-bloc basique direct */
-
- g_flow_block_get_boundary(block, NULL, &last);
-
- sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block));
- sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash,
- (GEqualFunc)NULL,//g_arch_register_equal,
- g_object_unref, g_object_unref);
-
- true_dinstr = NULL;
- false_dinstr = NULL;
-
- /* Branche 'true' */
- next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE);
- if (next != NULL)
- {
- g_arch_instruction_get_location(next, NULL, NULL, &next_addr);
- next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false);
-
- if (next_block != NULL)
- {
- sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared);
- true_dinstr = decompiled_basic_block(next_block, sub_ctx);
- g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx);
- g_object_unref(G_OBJECT(sub_ctx));
- }
-
- g_object_unref(G_OBJECT(next));
-
- }
-
- /* Branche 'false' */
- next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE);
- if (next != NULL)
- {
- g_arch_instruction_get_location(next, NULL, NULL, &next_addr);
- next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false);
-
- if (next_block != NULL)
- {
- sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared);
- false_dinstr = decompiled_basic_block(next_block, sub_ctx);
- g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx);
- g_object_unref(G_OBJECT(sub_ctx));
- }
-
- g_object_unref(G_OBJECT(next));
-
- }
-
- g_ite_instruction_set_branches(decomp, true_dinstr, false_dinstr);
-
- g_hash_table_unref(sub_shared);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : case_dinstr = instructions d'un cas de 'switch' décompilées. *
-* case_block = bloc d'instructions assembleur correspondantes.*
-* cases = listes des instructions des différents cas. *
-* current = indice du cas courant. *
-* ccount = nombre de cas présents dans le 'switch'. *
-* *
-* Description : Termine le traitement d'un cas de 'switch'. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void close_case_decomp_instructions(GDecInstruction *case_dinstr, GInstrBlock *case_block, GArchInstruction **cases, size_t current, size_t ccount)
-{
- vmpa_t *cases_addr; /* Adresses des cas du 'switch'*/
- size_t i; /* Boucle de parcours #1 */
- GInstrBlock **leafs; /* Blocs terminaux du cas */
- size_t lcount; /* Nombre de blocs terminaux */
- vmpa_t common_addr; /* Adresse commune de suite */
- bool is_common; /* Suite commune ? */
- GArchInstruction *last; /* Dernière instruction de bloc*/
- size_t dcount; /* Nombre de liens de dest. */
- size_t j; /* Boucle de parcours #2 */
- const instr_link_t *dest; /* Instr. visée par une autre */
- vmpa_t addr; /* Adresse d'une instruction */
- bool jump_to_case; /* Suite dans le cas suivant ? */
-
- /* Etablit la liste des adresses des cas */
-
- cases_addr = (vmpa_t *)calloc(ccount, sizeof(vmpa_t));
-
- for (i = 0; i < ccount; i++)
- g_arch_instruction_get_location(cases[i], NULL, NULL, &cases_addr[i]);
-
- /* Récupère la (les) fin(s) du cas présent */
-
- leafs = NULL;
- lcount = 0;
-
- g_instr_block_list_leafs_blocks(case_block, &leafs, &lcount);
-
- /* Procède à une première analyse de la suite */
-
- common_addr = VMPA_MAX;
- is_common = true;
-
- for (i = 0; i < lcount && is_common; i++)
- {
- g_flow_block_get_boundary(G_FLOW_BLOCK(leafs[i]), NULL, &last);
-
- g_arch_instruction_lock_dest(last);
- dcount = g_arch_instruction_count_destinations(last);
-
- for (j = 0; j < dcount && is_common; j++)
- {
- dest = g_arch_instruction_get_destination(last, j);
-
- g_arch_instruction_get_location(dest->linked, NULL, NULL, &addr);
-
- if (common_addr == VMPA_MAX)
- common_addr = addr;
- else
- is_common = (common_addr == addr);
-
- unref_instr_link(dest);
-
- }
-
- g_arch_instruction_unlock_dest(last);
-
- }
-
- /* La sortie du cas est unique ! */
- if (is_common)
- {
- if (common_addr == VMPA_MAX)
- goto ecdi_exit;
-
- jump_to_case = false;
-
- for (i = 0; i < ccount && !jump_to_case; i++)
- if (i != current)
- jump_to_case = (cases_addr[i] == common_addr);
-
- if (!jump_to_case)
- g_expr_block_add_item(G_EXPR_BLOCK(case_dinstr), g_keyword_instruction_new(DKW_BREAK));
-
- }
-
- /* ... ou il faut suivre les différentes branches... */
- else
- {
-
- /* TODO */
-
- }
-
- ecdi_exit:
-
- free(cases_addr);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : decomp = instruction 'switch' à compléter. *
-* block = ensemble des instructions d'assemblage traitées. *
-* ctx = contexte de soutien à associer à l'opération. *
-* *
-* Description : Procède à la décompilation des éléments d'un 'switch'. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void build_switch_branches(GSwitchInstruction *decomp, GFlowBlock *block, GDecContext *ctx)
-{
-#if 0
-
- GArchInstruction *last; /* Dernière instruction du lot */
- GInstrBlock *sub_parent; /* Groupe des sous-branches */
- GHashTable *sub_shared; /* Allocations communes */
- GDecContext *sub_ctx; /* Sous-contexte pour branche */
- vmpa_t next_addr; /* Adresse de cette instruct° */
- GInstrBlock *next_block; /* Sous-bloc basique direct */
- GArchInstruction **dests; /* Instr. visée par une autre */
- link_extra_info *info; /* Compléments pour les liens */
- size_t dcount; /* Nombre de liens de dest. */
- size_t i; /* Boucle de parcours #2 */
- GDecInstruction *case_dinstr; /* Décompilation 'case' */
- GDecExpression *case_value; /* Valeur d'aiguillage */
-
- g_flow_block_get_boundary(block, NULL, &last);
-
- sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block));
- sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash,
- (GEqualFunc)g_arch_register_equal,
- g_object_unref, g_object_unref);
-
- dcount = g_arch_instruction_get_destinations(last, &dests, NULL, &info);
-
- for (i = 0; i < dcount; i++)
- {
- g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr);
- next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false);
-
- if (next_block != NULL)
- {
- sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared);
- case_dinstr = decompiled_basic_block(next_block, sub_ctx);
- g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx);
- g_object_unref(G_OBJECT(sub_ctx));
-
- close_case_decomp_instructions(case_dinstr, next_block, dests, i, dcount);
- g_expr_block_set_border_behavior(G_EXPR_BLOCK(case_dinstr), BBB_FORCE_OFF);
-
- if (info[i].imm != NULL)
- {
- case_value = G_DEC_EXPRESSION(g_imm_expression_new(info[i].imm));
- g_switch_instruction_add_case(G_SWITCH_INSTRUCTION(decomp),
- case_value, case_dinstr, next_addr);
- }
- else g_switch_instruction_set_default_case(G_SWITCH_INSTRUCTION(decomp),
- case_dinstr);
-
- }
-
- }
-
- g_hash_table_unref(sub_shared);
-#endif
-}