/* Chrysalide - Outil d'analyse de fichiers binaires
* abbrev.c - manipulation des abréviation DWARF
*
* Copyright (C) 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_KNOWN_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;
}