diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2018-08-07 18:08:47 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2018-08-07 18:08:47 (GMT) |
commit | 0442cf03782e65bd680449cc213ace9a21bb081b (patch) | |
tree | 1ad713e14aeba3189c77454c219b7ab398331615 /src/analysis/decomp/il.c | |
parent | ae2be2044d39abebfa7b8d5ce64571e72f7ff6fd (diff) |
Removed old code used for decompilation.
Diffstat (limited to 'src/analysis/decomp/il.c')
-rw-r--r-- | src/analysis/decomp/il.c | 772 |
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 -} |