/* Chrysalide - Outil d'analyse de fichiers binaires * parser.c - interprétation des champs d'un format binaire * * Copyright (C) 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 Foobar. If not, see . */ #include "parser.h" #include #include #include /* Effectue l'interprétation d'une définition de champ. */ static bool parse_field_definition(const fmt_field_def *, GBinFormat *, GPreloadInfo *, vmpa2t *, void *); /****************************************************************************** * * * Paramètres : def = définition de champ à considérer. * * format = description de l'exécutable à compléter. * * info = informations à constituer en avance de phase. * * pos = tête de lecture pour les données. * * data = infos complémentaires éventuellement fournies. * * * * Description : Effectue l'interprétation d'une définition de champ. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool parse_field_definition(const fmt_field_def *def, GBinFormat *format, GPreloadInfo *info, vmpa2t *pos, void *data) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu binaire à lire */ SourceEndian endian; /* Boutisme utilisé */ vmpa2t mod; /* Position modifiable */ GArchInstruction *instr; /* Instruction décodée */ GImmOperand *imm; /* Opérande à transformer */ size_t i; /* Boucle de parcours */ const vmpa2t *addr; /* Emplacement d'instruction */ GDbComment *comment; /* Définition de commentaire */ uint64_t raw; /* Valeur brute à étudier */ const comment_part *part; /* Accès plus direct */ bool inserted; /* Bilan d'une insertion */ /* Lecture */ content = g_binary_format_get_content(format); endian = g_binary_format_get_endianness(format); if (def->get_value != NULL) { copy_vmpa(&mod, pos); result = def->get_value(def, content, &mod, endian, data); if (!result) goto pfd_exit; } if (def->is_uleb128) instr = g_raw_instruction_new_uleb128(content, pos); else if (def->is_leb128) instr = g_raw_instruction_new_sleb128(content, pos); else { assert(def->repeat > 0); instr = g_raw_instruction_new_array(content, def->size, def->repeat, pos, endian); } result = (instr != NULL); if (!result) goto pfd_exit; if (def->is_padding) g_raw_instruction_mark_as_padding(G_RAW_INSTRUCTION(instr), true); if (def->has_display_rules) { assert((def->is_uleb128 && def->disp_count == 1) || (def->is_leb128 && def->disp_count == 1) || (!def->is_uleb128 && !def->is_leb128 && def->disp_count <= def->repeat)); for (i = 0; i < def->disp_count; i++) { imm = G_IMM_OPERAND(g_arch_instruction_get_operand(instr, i)); g_imm_operand_set_default_display(imm, def->disp_rules[i]); g_object_unref(G_OBJECT(imm)); } } /* Commentaire */ addr = get_mrange_addr(g_arch_instruction_get_range(instr)); comment = g_db_comment_new_inlined(addr, BLF_HAS_CODE, false); g_db_item_set_volatile(G_DB_ITEM(comment), true); switch (def->ctype) { case FCT_PLAIN: g_db_comment_add_static_text(comment, _(def->comment.plain)); break; case FCT_SWITCH: imm = G_IMM_OPERAND(g_arch_instruction_get_operand(instr, 0)); raw = g_imm_operand_get_raw_value(imm); g_object_unref(G_OBJECT(imm)); for (i = 0; i < def->comment.ccount; i++) { if (def->comment.choices[i].is_range) { if (raw < def->comment.choices[i].lower) continue; if (raw > def->comment.choices[i].upper) continue; } else if (raw != def->comment.choices[i].fixed) continue; g_db_comment_add_static_text(comment, _(def->comment.choices[i].desc)); break; } if (i == def->comment.ccount) g_db_comment_add_static_text(comment, _(def->comment.def_choice)); break; case FCT_MULTI: for (i = 0; i < def->comment.pcount; i++) { part = &def->comment.parts[i]; if (part->is_static) { if (part->avoid_i18n) g_db_comment_add_static_text(comment, part->static_text); else g_db_comment_add_static_text(comment, _(part->static_text)); } else { if (part->avoid_i18n) g_db_comment_add_dynamic_text(comment, part->dynamic_text); else g_db_comment_add_dynamic_text(comment, _(part->dynamic_text)); } } break; } /* Insertions */ inserted = g_preload_info_add_instruction(info, instr); if (inserted) g_preload_info_add_comment(info, comment); else g_object_unref(G_OBJECT(comment)); pfd_exit: g_object_unref(G_OBJECT(content)); return result; } /****************************************************************************** * * * Paramètres : defs = liste de définitions à traiter. * * count = taille de cette liste. * * format = description de l'exécutable à compléter. * * info = informations à constituer en avance de phase. * * pos = tête de lecture pour les données. * * data = infos complémentaires éventuellement fournies. * * * * Description : Lance l'interprétation d'une série de définitions de champs. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool parse_field_definitions(const fmt_field_def *defs, size_t count, GBinFormat *format, GPreloadInfo *info, vmpa2t *pos, void *data) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ result = true; for (i = 0; i < count && result; i++) result = parse_field_definition(defs + i, format, info, pos, data); return result; }