/* Chrysalide - Outil d'analyse de fichiers binaires * abbrev.c - manipulation des abréviation DWARF * * Copyright (C) 2008-2018 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 . */ #include "abbrev.h" #include #include "checks.h" #include "format-int.h" #include "utils.h" /* ----------------------- TRAITEMENT D'ABREVIATION A L'UNITE ----------------------- */ /* Description d'un attribut d'une abréviation */ typedef struct _dw_abbrev_attr { DwarfAttrib name; /* Sujet de l'élément */ DwarfForm form; /* Représentation */ } dw_abbrev_attr; /* Description d'une abréviation */ struct _dw_abbrev { uleb128_t code; /* Identifiant attribué */ DwarfTag tag; /* Sujet de l'élément */ bool has_children; /* Présence de sous-éléments ? */ dw_abbrev_attr *attribs; /* Liste des attributs */ size_t count; /* Nombre de ces attributs */ }; /* Charge une abréviation valide pour un DWARF en mémoire. */ static bool load_dwarf_abbreviation(GDwarfFormat *, const dw_compil_unit_header *, GBinContent *, vmpa2t *, dw_abbrev **); /* Supprime de la mémoire toute trace d'une abréviation DWARF. */ static void free_dwarf_abbrev(dw_abbrev *); /* Procède à la conversion de base d'une abréviation DWARF. */ static bool conv_abbrev_decl(GDwarfFormat *, const dw_compil_unit_header *, const dw_abbrev_decl *, dw_abbrev *, const vmpa2t *); /* Procède à la conversion d'un attribut d'abréviation DWARF. */ static bool conv_abbrev_attrib(GDwarfFormat *, const dw_compil_unit_header *, const dw_abbrev_raw_attr *, dw_abbrev_attr *, const vmpa2t *); /* ----------------------- TRAITEMENT D'ABREVIATIONS PAR LOTS ----------------------- */ /* Brochette d'abréviations */ struct _dw_abbrev_brotherhood { dw_abbrev **abbrevs; /* Liste des sous-éléments */ size_t count; /* Nombre de ces éléments */ }; /* ---------------------------------------------------------------------------------- */ /* TRAITEMENT D'ABREVIATION A L'UNITE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : format = informations de débogage à consulter. * * cu = unité de compilation parente. * * content = contenu binaire borné à parcourir. * * pos = tête de lecture à faire évoluer. [OUT] * * abbrev = abréviation lue et complète, NULL si aucune. [OUT] * * * * Description : Charge une abréviation valide pour un DWARF en mémoire. * * * * Retour : Bilan de l'opération, potentiellement un succès sans sortie. * * * * Remarques : - * * * ******************************************************************************/ static bool load_dwarf_abbreviation(GDwarfFormat *format, const dw_compil_unit_header *cu, GBinContent *content, vmpa2t *pos, dw_abbrev **abbrev) { vmpa2t old; /* Mémorisation d'une position */ dw_abbrev *new; /* Nouvelle abréviation */ dw_abbrev_decl decl; /* En-tête d'abréviation */ dw_abbrev_raw_attr attr; /* Attribut de l'abréviation */ bool status; /* Bilan d'une lecture */ new = NULL; /** * Cette routine est la transcription du paragraphe 7.5.3 ("Abbreviations Tables"), * de la quatrième version de la définition du format DWARF. * * La spécification précise : * * As mentioned in Section 2.3, each chain of sibling entries is terminated by a null entry. * * Par ailleurs, readelf comporte le commentaire suivant dans le fichier 'dwarf_reader.cc' : * * Read the abbrev code. A zero here indicates the end of the abbrev table. * */ copy_vmpa(&old, pos); if (!read_dwarf_abbrev_decl(content, pos, &decl)) goto lda_bad_exit; if (decl.code == 0) goto lda_exit; new = (dw_abbrev *)calloc(1, sizeof(dw_abbrev)); if (!conv_abbrev_decl(format, cu, &decl, new, &old)) goto lda_bad_exit; /* Chargement des attributs */ for (;;) { copy_vmpa(&old, pos); status = read_dwarf_abbrev_attr(content, pos, &attr); if (!status) goto lda_bad_exit; if (attr.name == 0 && attr.form == 0) break; new->count++; new->attribs = (dw_abbrev_attr *)realloc(new->attribs, new->count * sizeof(dw_abbrev_attr)); status = conv_abbrev_attrib(format, cu, &attr, &new->attribs[new->count - 1], &old); if (!status) goto lda_bad_exit; } lda_exit: *abbrev = new; return true; lda_bad_exit: if (new != NULL) free_dwarf_abbrev(new); *abbrev = NULL; return false; } /****************************************************************************** * * * Paramètres : abbrev = abréviation chargée en mémoire à traiter. * * * * Description : Supprime de la mémoire toute trace d'une abréviation DWARF. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void free_dwarf_abbrev(dw_abbrev *abbrev) { if (abbrev->attribs != NULL) free(abbrev->attribs); free(abbrev); } /****************************************************************************** * * * Paramètres : format = informations de débogage à consulter. * * cu = unité de compilation parente. * * decl = structure brute dont le contenu est à valider. * * abbrev = abréviation à constituer à partir du brut. [OUT] * * pos = emplacement de l'élément à vérifier dans le binaire.* * * * Description : Procède à la conversion de base d'une abréviation DWARF. * * * * Retour : Validité confirmée ou non. * * * * Remarques : - * * * ******************************************************************************/ static bool conv_abbrev_decl(GDwarfFormat *format, const dw_compil_unit_header *cu, const dw_abbrev_decl *decl, dw_abbrev *abbrev, const vmpa2t *pos) { bool result; /* Validité à retourner */ result = check_dwarf_abbrev_decl(format, decl, cu->version, pos); if (result) { abbrev->code = decl->code; abbrev->tag = decl->tag; abbrev->has_children = (decl->has_children == DW_CHILDREN_yes); } return result; } /****************************************************************************** * * * Paramètres : format = informations de débogage à consulter. * * cu = unité de compilation parente. * * decl = structure brute dont le contenu est à valider. * * abbrev = abréviation à constituer à partir du brut. [OUT] * * pos = emplacement de l'élément à vérifier dans le binaire.* * * * Description : Procède à la conversion d'un attribut d'abréviation DWARF. * * * * Retour : Validité confirmée ou non. * * * * Remarques : - * * * ******************************************************************************/ static bool conv_abbrev_attrib(GDwarfFormat *format, const dw_compil_unit_header *cu, const dw_abbrev_raw_attr *attr, dw_abbrev_attr *attrib, const vmpa2t *pos) { bool result; /* Validité à retourner */ result = check_dwarf_abbrev_attrib(format, attr, cu->version, pos); if (result) { attrib->name = attr->name; attrib->form = attr->form; } return result; } /****************************************************************************** * * * Paramètres : abbrev = abréviation chargée en mémoire à consulter. * * * * Description : Compte le nombre d'attributs présents dans une abréviation. * * * * Retour : Quantité d'attributs pris en compte dans l'abréviation. * * * * Remarques : - * * * ******************************************************************************/ size_t dwarf_abbreviation_count_attribs(const dw_abbrev *abbrev) { return abbrev->count; } /****************************************************************************** * * * Paramètres : abbrev = abréviation à consulter. * * format = contenu binaire de débogage à parcourir. * * content = contenu encadré à parcourir. * * pos = tête de lecture au sein des données. [OUT] * * cu = unité de compilation parente. * * * * Description : Lit la valeur correspondant à un type donné. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ dw_value *translate_abbrev_attribs(const dw_abbrev *abbrev, const GDwarfFormat *format, GBinContent *content, vmpa2t *pos, const dw_compil_unit_header *cu) { dw_value *result; /* Valeurs lues retournées */ size_t i; /* Boucle de parcours */ bool status; /* Bilan d'une lecture */ result = (dw_value *)calloc(abbrev->count, sizeof(dw_value)); for (i = 0; i < abbrev->count; i++) { result[i].attrib = abbrev->attribs[i].name; status = read_dwarf_form_value(format, content, pos, cu, abbrev->attribs[i].form, &result[i].value); if (!status) break; } if (i != abbrev->count) { free_abbrev_attribs(result, abbrev->count); result = NULL; } return result; } /****************************************************************************** * * * Paramètres : values = liste de valeurs typées à traiter. * * count = nombre d'éléments de la liste. * * * * Description : Supprime de la mémoire une liste de valeurs typées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void free_abbrev_attribs(dw_value *values, size_t count) { size_t i; /* Boucle de parcours */ for (i = 0; i < count; i++) if (values[i].value != NULL) free_dwarf_form_value(values[i].value); free(values); } /****************************************************************************** * * * Paramètres : abbrev = abréviation à consulter. * * * * Description : Détermine si l'abréviation possède des enfants. * * * * Retour : true si des sous-éléments sont présents. * * * * Remarques : - * * * ******************************************************************************/ bool has_abbrev_children(const dw_abbrev *abbrev) { bool result; /* Bilan à retourner */ result = abbrev->has_children; return result; } /* ---------------------------------------------------------------------------------- */ /* TRAITEMENT D'ABREVIATIONS PAR LOTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : format = informations de débogage à constituer. * * cu = en-tête de description de l'unité à traiter. * * * * Description : Charge une série d'abréviations présentes dans un DWARF. * * * * Retour : Structure mise en place, ou NULL en cas d'erreur. * * * * Remarques : Le décalage est positionné à VMPA_NO_PHYSICAL en cas de fin. * * * ******************************************************************************/ dw_abbrev_brotherhood *load_all_dwarf_abbreviations(GDwarfFormat *format, const dw_compil_unit_header *cu) { dw_abbrev_brotherhood *result; /* Abréviations à retourner */ GExeFormat *exe; /* Exécutable associé */ mrange_t range; /* Couverture d'une section */ bool status; /* Bilan d'un appel */ GBinContent *content; /* Contenu binaire à lire */ GBinContent *restricted; /* Limitation des traitements */ vmpa2t pos; /* Position de tête de lecture */ dw_abbrev *abbrev; /* Nouvelle abréviation */ result = NULL; exe = G_DBG_FORMAT(format)->executable; status = g_exe_format_get_section_range_by_name(exe, ".debug_abbrev", &range); if (status) { /* Définition d'un zone de travail */ content = G_BIN_FORMAT(format)->content; restricted = g_restricted_content_new(content, &range); copy_vmpa(&pos, get_mrange_addr(&range)); advance_vmpa(&pos, cu->debug_abbrev_offset); /* Lecture de toutes les abréviations */ result = calloc(1, sizeof(dw_abbrev_brotherhood)); while (true) { status = load_dwarf_abbreviation(format, cu, restricted, &pos, &abbrev); if (!status) break; if (abbrev == NULL) break; result->abbrevs = realloc(result->abbrevs, ++result->count * sizeof(dw_abbrev *)); result->abbrevs[result->count - 1] = abbrev; } /* Nettoyage */ if (!status) { free_all_dwarf_abbreviations(result); result = NULL; } g_object_unref(G_OBJECT(restricted)); } return result; } /****************************************************************************** * * * Paramètres : list = série d'abréviations chargées en mémoire à traiter. * * * * Description : Supprime de la mémoire toute trace d'abréviations DWARF. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void free_all_dwarf_abbreviations(dw_abbrev_brotherhood *list) { size_t i; /* Boucle de parcours */ for (i = 0; i < list->count; i++) free_dwarf_abbrev(list->abbrevs[i]); if (list->abbrevs != NULL) free(list->abbrevs); free(list); } /****************************************************************************** * * * Paramètres : list = série d'abréviations à consulter. * * code = identifiant de l'abbréviation recherchée. * * * * Description : Recherche une abréviation DWARF donnée. * * * * Retour : Adresse d'une abréviation ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ const dw_abbrev *find_dwarf_abbreviation(const dw_abbrev_brotherhood *list, uleb128_t code) { const dw_abbrev *result; /* Trouvaille à retourner */ size_t i; /* Boucle de parcours */ result = NULL; for (i = 0; i < list->count; i++) if (list->abbrevs[i]->code == code) { result = list->abbrevs[i]; break; } return result; }