/* Chrysalide - Outil d'analyse de fichiers binaires
* abbrev.c - manipulation des abréviation DWARF
*
* Copyright (C) 2008 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* OpenIDA 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.
*
* OpenIDA 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 "abbrev.h"
#include
#include
#include
#include "utils.h"
#include
/* Libère de la mémoire une abréviation DWARF. */
void free_dwarf_abbrev(dw_abbrev *);
/* Charge une abréviations DWARF. */
dw_abbrev *read_dwarf_abbreviations(dwarf_format *, off_t *, uint64_t *);
/* Recherche une abréviation DWARF donnée. */
const dw_abbrev *_find_dwarf_abbreviations(const dw_abbrev *, uint8_t *);
/* Lit la valeur d'un attribut DWARF. */
bool _read_dwarf_abbrev_attribute(dwarf_format *, off_t *, DwarfForm, ...);
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* *
* Description : Charge les abréviations trouvées pour un DWARF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_dwarf_abbreviations(dwarf_format *format)
{
bool result; /* Bilan à renvoyer */
off_t offset;
off_t start;
off_t size;
bool test;
int i;
dw_abbrev *abbrev;
uint64_t index;
printf("Searching...\n");
result = true;
test = find_exe_section(DBG_FORMAT(format)->e_format, ".debug_abbrev", &start, &size, NULL);
offset = start;
printf(" -> offset=%d size=%d\n", offset, size);
for (i = 0; i < size; i++)
{
if (i % 10 == 0) printf("\n");
printf("0x%02hhx ", DBG_FORMAT(format)->content[offset + i]);
}
printf("\n");
while (offset < (start + size))
{
abbrev = read_dwarf_abbreviations(format, &offset, &index);
offset++; /* 0x00 */
printf("abbrev :: %p\n", abbrev);
if (abbrev != NULL)
{
abbrev->offset -= start;
format->abbrevs = (dw_abbrev **)realloc(format->abbrevs, ++format->abbrevs_count * sizeof(dw_abbrev *));
format->abbrevs[format->abbrevs_count - 1] = abbrev;
printf(" %d attribs, %d children\n", abbrev->attribs_count, abbrev->children_count);
}
else
{
unload_dwarf_abbreviations(format);
result = false;
break;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à effacer. *
* *
* Description : Décharge les abréviations trouvées pour un DWARF. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void unload_dwarf_abbreviations(dwarf_format *format)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < format->abbrevs_count; i++)
free_dwarf_abbrev(format->abbrevs[i]);
}
/******************************************************************************
* *
* Paramètres : abbrev = élément à supprimer de la mémoire. *
* *
* Description : Libère de la mémoire une abréviation DWARF. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void free_dwarf_abbrev(dw_abbrev *abbrev)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < abbrev->children_count; i++)
free_dwarf_abbrev(abbrev->children[i]);
free(abbrev->attribs);
free(abbrev->children);
free(abbrev);
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* index = code de l'abréviation. [OUT] *
* *
* Description : Charge une abréviation DWARF. *
* *
* Retour : Adresse d'une abréviation ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
dw_abbrev *read_dwarf_abbreviations(dwarf_format *format, off_t *pos, uint64_t *index)
{
dw_abbrev *result; /* Abréviation à retourner */
bool has_children; /* Indique la présence de fils */
uint64_t value1; /* Valeur quelconque lue #1 */
uint64_t value2; /* Valeur quelconque lue #2 */
uint64_t sub_index; /* Indice d'un sous-élément */
dw_abbrev *child; /* Sous-élément à intégrer */
result = (dw_abbrev *)calloc(1, sizeof(dw_abbrev));
result->offset = *pos;
/* Code de l'élément */
if (!read_uleb128(format, pos, index, true)) goto rda_error;
if (!read_uleb128(format, pos, &value1, true)) goto rda_error;
result->tag = value1;
printf(" --ta :: 0x%02llx\n", value1);
if (*pos >= DBG_FORMAT(format)->length) goto rda_error;
has_children = (DBG_FORMAT(format)->content[(*pos)++] == DW_CHILDREN_YES);
printf(" --ch ? %d\n", has_children);
/* Liste des attributs */
while (DBG_FORMAT(format)->content[*pos] != 0x00)
{
if (!read_uleb128(format, pos, &value1, true)) goto rda_error;
if (!read_uleb128(format, pos, &value2, true)) goto rda_error;
result->attribs = (dw_abbrev_attr *)realloc(result->attribs, ++result->attribs_count * sizeof(dw_abbrev_attr));
result->attribs[result->attribs_count - 1].attrib = value1;
result->attribs[result->attribs_count - 1].form = value2;
}
(*pos) += 2; /* 0x00 0x00 */
/* Chargement des sous-éléments */
if (has_children)
while (DBG_FORMAT(format)->content[*pos] != 0x00)
{
child = read_dwarf_abbreviations(format, pos, &sub_index);
if (child == NULL) goto rda_error;
if ((sub_index - *index - 1) != result->children_count) goto rda_error;
result->children = (dw_abbrev **)realloc(result->children, ++result->children_count * sizeof(dw_abbrev *));
result->children[result->children_count - 1] = child;
}
return result;
rda_error:
free_dwarf_abbrev(result);
return NULL;
}
/******************************************************************************
* *
* Paramètres : abbrev = abréviation racine à parcourir. *
* index = code de l'abréviation. [OUT] *
* *
* 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_abbreviations(const dw_abbrev *abbrev, uint8_t *index)
{
const dw_abbrev *result; /* Structure à retourner */
size_t i; /* Boucle de parcours */
result = NULL;
if (*index == 0) result = abbrev;
else
for (i = 0; i < abbrev->children_count && result == NULL; i++)
{
(*index)--;
result = _find_dwarf_abbreviations(abbrev->children[i], index);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à consulter. *
* offset = position dans les abréviations. *
* pos = position dans le flux binaire courant. [OUT] *
* *
* 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_abbreviations(dwarf_format *format, const off_t *offset, off_t *pos)
{
const dw_abbrev *result; /* Structure à retourner */
uint64_t index; /* Code de l'abréviation */
size_t i; /* Boucle de parcours */
result = NULL;
do
{
if (!read_uleb128(format, pos, &index, true))
{
printf("error skipping padding...\n");
return NULL;
}
}
while (index == 0);
for (i = 0; i < format->abbrevs_count; i++)
if (format->abbrevs[i]->offset == *offset) break;
if (i < format->abbrevs_count)
{
index--;
result = _find_dwarf_abbreviations(format->abbrevs[i], &index);
}
return result;
}
/******************************************************************************
* *
* Paramètres : abbrev = informations à parcourir. *
* attrib = attribut visé par la lecture. *
* *
* Description : Indique la présence ou l'absence d'un attribut donné. *
* *
* Retour : true si l'attribut est présent, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool test_dwarf_abbrev_attribute(const dw_abbrev *abbrev, DwarfAttrib attrib)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
result = false;
for (i = 0; i < abbrev->attribs_count && !result; i++)
result = (abbrev->attribs[i].attrib == attrib);
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* form = format des données à lire. *
* ... = lieu d'enregistrement ou NULL. [OUT] *
* *
* Description : Lit la valeur d'un attribut DWARF. *
* *
* Retour : true si la lecture est un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _read_dwarf_abbrev_attribute(dwarf_format *format, off_t *pos, DwarfForm form, ...)
{
bool result; /* Bilan à revoyer */
va_list ap; /* Adresse fournie en dernier */
uint8_t *val8; /* Données sur 8 bits */
uint16_t *val16; /* Données sur 16 bits */
uint32_t *val32; /* Données sur 32 bits */
uint64_t *val64; /* Données sur 64 bits */
uint64_t *sval64; /* Données sur 64 bits (signée)*/
bool *boolval; /* Valeur booléenne */
uint8_t tmp8; /* Données sur 8 bits */
uint16_t tmp16; /* Données sur 16 bits */
uint32_t tmp32; /* Données sur 32 bits */
uint64_t tmp64; /* Données sur 64 bits */
uint64_t stmp64; /* Données sur 64 bits (signée)*/
uint64_t size_to_read; /* Nombre d'octets à lire */
off_t offset; /* Décallage dans une zone */
char **strval; /* Chaîne de caractères */
size_t length; /* Taille d'une chaîne */
va_start(ap, form);
switch (form)
{
case DWF_ADDR:
result = ((*pos + (format->format == DWF_32_BITS ? 4 : 8)) <= DBG_FORMAT(format)->length);
if (result)
{
val64 = va_arg(ap, uint64_t *);
if (val64 != NULL)
{
if (format->format == DWF_32_BITS)
{
memcpy(&tmp32, &DBG_FORMAT(format)->content[*pos], 4);
*val64 = tmp32;
}
else memcpy(val64, &DBG_FORMAT(format)->content[*pos], 8);
}
*pos += (format->format == DWF_32_BITS ? 4 : 8);
}
break;
case DWF_BLOCK2:
result = ((*pos + 2) <= DBG_FORMAT(format)->length);
if (result)
{
memcpy(&tmp16, &DBG_FORMAT(format)->content[*pos], 2);
size_to_read = tmp16;
/* ... */
*pos += 2 + size_to_read;
}
break;
case DWF_BLOCK4:
result = ((*pos + 4) <= DBG_FORMAT(format)->length);
if (result)
{
memcpy(&tmp32, &DBG_FORMAT(format)->content[*pos], 4);
size_to_read = tmp32;
/* ... */
*pos += 4 + size_to_read;
}
break;
case DWF_DATA2:
result = ((*pos + 2) <= DBG_FORMAT(format)->length);
if (result)
{
val16 = va_arg(ap, uint16_t *);
if (val16 != NULL) memcpy(val16, &DBG_FORMAT(format)->content[*pos], 2);
*pos += 2;
}
break;
case DWF_DATA4:
result = ((*pos + 4) <= DBG_FORMAT(format)->length);
if (result)
{
val32 = va_arg(ap, uint32_t *);
if (val32 != NULL) memcpy(val32, &DBG_FORMAT(format)->content[*pos], 4);
*pos += 4;
}
break;
case DWF_DATA8:
result = ((*pos + 8) <= DBG_FORMAT(format)->length);
if (result)
{
val64 = va_arg(ap, uint64_t *);
if (val64 != NULL) memcpy(val64, &DBG_FORMAT(format)->content[*pos], 8);
*pos += 8;
}
break;
case DWF_STRING:
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (result)
{
strval = va_arg(ap, char **);
if (strval != NULL) *strval = (char *)calloc(1, sizeof(char));
length = 0;
while (result)
{
if (DBG_FORMAT(format)->content[*pos] == '\0') break;
length++;
if (strval != NULL)
{
*strval = (char *)realloc(*strval, (length + 1) * sizeof(char));
(*strval)[length - 1] = DBG_FORMAT(format)->content[*pos];
}
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (!result) break;
(*pos)++;
}
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (result)
{
(*pos)++;
if (strval != NULL)
(*strval)[length] = 0;
}
else if (strval != NULL)
{
free(*strval);
*strval = NULL;
}
}
break;
case DWF_BLOCK:
result = read_uleb128(format, pos, &size_to_read, true);
result &= ((*pos + size_to_read) <= DBG_FORMAT(format)->length);
if (result)
{
/* ... */
*pos += size_to_read;
}
break;
case DWF_BLOCK1:
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (result)
{
memcpy(&tmp8, &DBG_FORMAT(format)->content[*pos], 1);
size_to_read = tmp8;
/* ... */
*pos += 1 + size_to_read;
}
break;
case DWF_DATA1:
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (result)
{
val8 = va_arg(ap, uint8_t *);
if (val8 != NULL) memcpy(val8, &DBG_FORMAT(format)->content[*pos], 1);
*pos += 1;
}
break;
case DWF_FLAG:
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (result)
{
boolval = va_arg(ap, bool *);
if (boolval != NULL) *boolval = (DBG_FORMAT(format)->content[*pos] != 0x00);
*pos += 1;
}
break;
case DWF_SDATA:
sval64 = va_arg(ap, int64_t *);
if (sval64 == NULL) sval64 = &stmp64;
result = read_uleb128(format, pos, sval64, true);
break;
case DWF_STRP:
result = read_abbrev_offset(format, pos, &offset);
if (result)
{
if (va_arg(ap, bool *) != NULL)
{
printf("TODO\n");
exit(0);
}
/*
boolval = va_arg(ap, bool *);
if (boolval != NULL) *boolval = (DBG_FORMAT(format)->content[*pos] != 0x00);
*/
}
break;
case DWF_UDATA:
val64 = va_arg(ap, uint64_t *);
if (val64 == NULL) val64 = &tmp64;
result = read_uleb128(format, pos, val64, true);
break;
case DWF_REF_ADDR:
result = ((*pos + 4) <= DBG_FORMAT(format)->length);
printf("bad at %d\n", __LINE__); exit(0);
break;
case DWF_REF1:
result = ((*pos + 1) <= DBG_FORMAT(format)->length);
if (result)
{
val8 = va_arg(ap, uint8_t *);
if (val8 != NULL) memcpy(val8, &DBG_FORMAT(format)->content[*pos], 1);
*pos += 1;
}
break;
case DWF_REF2:
result = ((*pos + 2) <= DBG_FORMAT(format)->length);
if (result)
{
val16 = va_arg(ap, uint16_t *);
if (val16 != NULL) memcpy(val16, &DBG_FORMAT(format)->content[*pos], 2);
*pos += 2;
}
break;
case DWF_REF4:
result = ((*pos + 4) <= DBG_FORMAT(format)->length);
if (result)
{
val32 = va_arg(ap, uint32_t *);
if (val32 != NULL) memcpy(val32, &DBG_FORMAT(format)->content[*pos], 4);
*pos += 4;
}
break;
case DWF_REF8:
result = ((*pos + 8) <= DBG_FORMAT(format)->length);
if (result)
{
val64 = va_arg(ap, uint64_t *);
if (val64 != NULL) memcpy(val64, &DBG_FORMAT(format)->content[*pos], 8);
*pos += 8;
}
break;
case DWF_REF_UDATA:
result = ((*pos + 4) <= DBG_FORMAT(format)->length);
printf("bad at %d\n", __LINE__); exit(0);
break;
case DWF_INDIRECT:
result = ((*pos + 4) <= DBG_FORMAT(format)->length);
printf("bad at %d\n", __LINE__); exit(0);
break;
default:
result = false;
break;
}
va_end(ap);
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* update = indique si la position est à mettre à jour. *
* abbrev = informations à parcourir. *
* attrib = attribut visé par la lecture. *
* ... = lieu d'enregistrement ou NULL. [OUT] *
* *
* Description : Lit la valeur d'un attribut DWARF. *
* *
* Retour : true si la lecture est un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_dwarf_abbrev_attribute(dwarf_format *format, off_t *pos, bool update, const dw_abbrev *abbrev, DwarfAttrib attrib, ...)
{
bool result; /* Bilan à retourner */
off_t curpos; /* Tête de lecture effective */
size_t i; /* Boucle de parcours */
va_list ap; /* Adresse fournie en dernier */
result = true;
curpos = *pos;
for (i = 0; i < abbrev->attribs_count && result; i++)
if (abbrev->attribs[i].attrib == attrib) break;
else result = _read_dwarf_abbrev_attribute(format, &curpos, abbrev->attribs[i].form, NULL);
if (result)
{
va_start(ap, attrib);
if (i < abbrev->attribs_count)
result = _read_dwarf_abbrev_attribute(format, &curpos, abbrev->attribs[i].form, va_arg(ap, void *));
else
result = false;
va_end(ap);
}
if (result && update) *pos = curpos;
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* abbrev = informations à survoler. *
* *
* Description : Fait avancer la tête de lecture d'une seule abréviation. *
* *
* Retour : true si l'opération est un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool skip_dwarf_abbrev(dwarf_format *format, off_t *pos, const dw_abbrev *abbrev)
{
bool result; /* Bilan à revoyer */
size_t i; /* Boucle de parcours */
uint64_t index; /* Code de padding */
result = true;
/* Ecartement du corps */
for (i = 0; i < abbrev->attribs_count && result; i++)
result = _read_dwarf_abbrev_attribute(format, pos, abbrev->attribs[i].form, NULL);
/* Ecartement du padding */
do
{
if (!read_uleb128(format, pos, &index, false))
{
printf("error skipping padding...\n");
return false;
}
if (index == 0)
read_uleb128(format, pos, &index, true);
}
while (index == 0);
return result;
}