/* OpenIDA - Outil d'analyse de fichiers binaires
* info.c - lecture des informations principales du format DWARF
*
* Copyright (C) 2008 Cyrille Bagard
*
* This file is part of OpenIDA.
*
* 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 "info.h"
#include
#include
#include "abbrev.h"
#include "dwarf-int.h"
#include "utils.h"
/* Informations utiles d'une unité de compilation */
typedef struct _compil_unit
{
off_t startpos; /* Position de début d'unité */
off_t endpos; /* Position d'unité suivante */
off_t offset; /* Position dans les abréviat° */
uint8_t ptrsize; /* Taille des adresses mémoire */
} compil_unit;
/* Procède à la lecture d'une unité de compilation. */
bool read_dwarf_compilation_unit(dwarf_format *, off_t *, compil_unit *);
/* Enregistre toutes les déclarations de fonction trouvées. */
bool look_for_dwarf_subprograms(dwarf_format *, off_t *, const compil_unit *);
/* Obtient la description humaine d'un type. */
char *resolve_dwarf_function_type(dwarf_format *, const dw_abbrev *, const off_t *, const compil_unit *);
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* *
* Description : Charge les informations trouvées dans un DWARF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_dwarf_information(dwarf_format *format)
{
bool result; /* Bilan à renvoyer */
off_t offset;
off_t start;
off_t size;
bool test;
int i;
compil_unit cu;
result = true;
test = find_exe_section(DBG_FORMAT(format)->e_format, ".debug_info", &start, &size, NULL);
offset = start;
printf(" -> offset=%d size=%d\n", offset, size);
for (i = 0; i < size; i++)
{
if (i % 25 == 0) printf("\n");
printf("0x%02hhx ", DBG_FORMAT(format)->content[offset + i]);
}
printf("\n");
while (offset < (start + size) && result)
{
printf("-------------\n");
result = read_dwarf_compilation_unit(format, &offset, &cu);
if (result)
look_for_dwarf_subprograms(format, &offset, &cu);
//break;
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à effacer. *
* *
* Description : Décharge les informations trouvées dans un DWARF. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void unload_dwarf_information(dwarf_format *format)
{
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* cu = unité de compilation lue. [OUT] *
* *
* Description : Procède à la lecture d'une unité de compilation. *
* *
* Retour : true en cas de succès de la lecture, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_dwarf_compilation_unit(dwarf_format *format, off_t *pos, compil_unit *cu)
{
bool result; /* Bilan à retourner */
off_t ulength; /* Taille de l'unité */
uint16_t version; /* Version du format DWARF */
off_t abbrev_pos; /* Position dans les abréviat° */
uint8_t memsize; /* Taille des adresses mémoire */
off_t oldpos;
uint8_t index;
result = true;
cu->startpos = *pos;
if (read_unit_length(format, pos, &ulength))
printf("Unit Length :: %d (0x%x)\n", ulength, ulength);
else printf("error ul\n");
cu->endpos = *pos + ulength;
oldpos = *pos;
if (read_uhalf(format, pos, &version))
printf("version :: %hd\n", version);
else printf("error version\n");
if (version > 3) return false;
if (read_abbrev_offset(format, pos, &abbrev_pos))
printf("abbrev offset :: %d\n", abbrev_pos);
else printf("error abbrev offset\n");
if (read_address_size(format, pos, &memsize))
printf("mem size :: %hhd\n", memsize);
else printf("error memsize\n");
cu->offset = abbrev_pos;
cu->ptrsize = memsize;
printf(" =+> Next :: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",
DBG_FORMAT(format)->content[*pos],
DBG_FORMAT(format)->content[*pos + 1],
DBG_FORMAT(format)->content[*pos + 2],
DBG_FORMAT(format)->content[*pos + 3],
DBG_FORMAT(format)->content[*pos + 4]);
/*
*pos = oldpos + ulength;
*/
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* cu = unité de compilation courante. *
* *
* Description : Enregistre toutes les déclarations de fonction trouvées. *
* *
* Retour : true en cas de succès de la lecture, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool look_for_dwarf_subprograms(dwarf_format *format, off_t *pos, const compil_unit *cu)
{
bool result; /* Bilan à retourner */
uint8_t index; /* Indice de l'abbréviation */
result = true;
off_t oldpos;
off_t oldpos2;
const dw_abbrev *abbrev;
const dw_abbrev *subabbrev;
const dw_abbrev *subabbrev2;
char *name;
uint64_t low_pc;
uint64_t high_pc;
uint32_t type_pos;
char *retstr;
uint64_t tempo;
size_t i; /* Boucle de parcours */
char *prototype = NULL;
size_t proto_len = 0;
bool first_arg; /* Marque le 1er argument */
bool is_pointer; /* Mémorise le type 'pointeur' */
while (*pos < cu->endpos)
{
printf(" =+> Cur :: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",
DBG_FORMAT(format)->content[*pos],
DBG_FORMAT(format)->content[*pos + 1],
DBG_FORMAT(format)->content[*pos + 2],
DBG_FORMAT(format)->content[*pos + 3],
DBG_FORMAT(format)->content[*pos + 4]);
if (read_address_size/*leb128*/(format, pos, &index))
printf("abbrev index :: %hhd\n", index);
else printf("abbrev index error\n");
/* Contraintes d'alignement... */
if (index == 0) continue;
abbrev = find_dwarf_abbreviations_old(format, &cu->offset, index);
//abbrev = find_dwarf_abbreviations(format, &cu->offset, pos);
printf(" --> %p\n", abbrev);
printf(" == 0x%02x (matched ? %d)\n", abbrev->tag, abbrev->tag == DWT_SUBPROGRAM);
oldpos = *pos;
if (abbrev->tag == DWT_SUBPROGRAM)
{
if (read_dwarf_abbrev_attribute(format, &oldpos, false, abbrev, DWA_NAME, &name))
printf(" ## Name :: %s\n", name);
else printf(" error: no name\n");
if (read_dwarf_abbrev_attribute(format, &oldpos, false, abbrev, DWA_LOW_PC, &low_pc))
printf(" ## LOW PC :: 0x%08x\n", low_pc);
else printf(" error: no low pc\n");
if (read_dwarf_abbrev_attribute(format, &oldpos, false, abbrev, DWA_HIGH_PC, &high_pc))
printf(" ## HIGH PC :: 0x%08x\n", high_pc);
else printf(" error: no high pc\n");
/* Type de la fonction */
if (read_dwarf_abbrev_attribute(format, &oldpos, false, abbrev, DWA_TYPE, &type_pos))
printf(" ## type :: 0x%08x\n", type_pos);
else printf(" error: no type\n");
oldpos = cu->startpos + type_pos;
subabbrev2 = find_dwarf_abbreviations(format, &cu->offset, &oldpos);
retstr = resolve_dwarf_function_type(format, subabbrev2, &oldpos, cu);
if (retstr == NULL)
{
proto_len += 3;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, "???");
is_pointer = false;
}
else
{
proto_len += strlen(retstr);
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, retstr);
is_pointer = (retstr[strlen(retstr) - 1] == '*');
free(retstr);
}
/* On saute l'abréviation de la déclaration de fonction... */
oldpos = *pos;
if (!read_uleb128(format, &oldpos, &tempo, true))
printf("error skipping index\n");
if (!skip_dwarf_abbrev(format, &oldpos, abbrev))
printf("error skipping\n");
do
{
if (!read_uleb128(format, &oldpos, &tempo, false))
printf("error skipping padding...\n");
if (tempo == 0)
read_uleb128(format, &oldpos, &tempo, true);
}
while (tempo == 0);
/* Lecture des différents arguments */
proto_len += (!is_pointer ? 1 : 0) + strlen(name) + 1;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
if (!is_pointer) strcat(prototype, " ");
strcat(prototype, name);
strcat(prototype, "(");
first_arg = true;
while (1)
{
subabbrev = find_dwarf_abbreviations(format, &cu->offset, &oldpos);
printf("subabbrev == %p\n", subabbrev);
switch (subabbrev->tag)
{
case DWT_UNSPECIFIED_PARAMETERS:
/* Virgule de séparation */
if (first_arg) first_arg = false;
else
{
proto_len += 2;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, ", ");
}
/* Marque de l'absence de type */
proto_len += 3;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, "...");
break;
case DWT_FORMAL_PARAMETER:
oldpos2 = oldpos;
if (read_dwarf_abbrev_attribute(format, &oldpos2, true, subabbrev, DWA_TYPE, &type_pos))
printf(" ## type :: 0x%08x\n", type_pos);
else printf(" error: no type\n");
oldpos2 = cu->startpos + type_pos;
printf(" =+> Next arg :: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",
DBG_FORMAT(format)->content[oldpos2],
DBG_FORMAT(format)->content[oldpos2 + 1],
DBG_FORMAT(format)->content[oldpos2 + 2],
DBG_FORMAT(format)->content[oldpos2 + 3],
DBG_FORMAT(format)->content[oldpos2 + 4]);
subabbrev2 = find_dwarf_abbreviations(format, &cu->offset, &oldpos2);
printf("subabbrev2 == %p\n", subabbrev2);
retstr = resolve_dwarf_function_type(format, subabbrev2, &oldpos2, cu);
printf(" ----) '%s'\n", retstr);
/* Virgule de séparation */
if (first_arg) first_arg = false;
else
{
proto_len += 2;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, ", ");
}
/* Type de l'argument */
if (retstr == NULL)
{
proto_len += 3;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, "???");
is_pointer = false;
}
else
{
proto_len += strlen(retstr);
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, retstr);
is_pointer = (retstr[strlen(retstr) - 1] == '*');
free(retstr);
}
oldpos2 = oldpos;
if (read_dwarf_abbrev_attribute(format, &oldpos2, true, subabbrev, DWA_NAME, &retstr))
printf(" ## Name :: %s\n", retstr);
else printf(" error: no name\n");
if (retstr != NULL)
{
proto_len += strlen(retstr) + (!is_pointer ? 1 : 0) + 1;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
if (!is_pointer) strcat(prototype, " ");
strcat(prototype, retstr);
free(retstr);
}
break;
default:
goto exit_loop;
break;
}
if (!skip_dwarf_abbrev(format, &oldpos, subabbrev))
printf("error skipping\n");
/*
do
{
if (!read_uleb128(format, &oldpos, &tempo, false))
printf("error skipping padding...\n");
if (tempo == 0)
read_uleb128(format, &oldpos, &tempo, true);
}
while (tempo == 0);
*/
}
exit_loop:
proto_len += 1;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, ")");
printf(" |\n");
printf(" | %s\n", prototype);
printf(" |\n");
prototype = NULL;
proto_len = 0;
}
if (!skip_dwarf_abbrev(format, pos, abbrev))
printf("error skipping :(\n");
printf(" == progress %d\n", *pos - oldpos);
printf(" == %d < %d\n", *pos, cu->endpos);
}
printf(" =+> Next :: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",
DBG_FORMAT(format)->content[*pos],
DBG_FORMAT(format)->content[*pos + 1],
DBG_FORMAT(format)->content[*pos + 2],
DBG_FORMAT(format)->content[*pos + 3],
DBG_FORMAT(format)->content[*pos + 4]);
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* abbrev = abréviation associée au type. *
* pos = tête de lecture à avoir sous le coude. *
* cu = unité de compilation courante. *
* *
* Description : Obtient la description humaine d'un type. *
* *
* Retour : Chaîne de caractères en cas de succès, NULL sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
char *resolve_dwarf_function_type(dwarf_format *format, const dw_abbrev *abbrev, const off_t *pos, const compil_unit *cu)
{
char *result; /* Description à retourner */
off_t oldpos; /* Conservation de l'indice */
uint32_t type_pos; /* Sous-type détecté */
uint64_t index; /* Indice de l'abréviation... */
const dw_abbrev *subabbrev; /* ... et abréviation associée */
size_t len; /* Longeur d'un résultat */
result = NULL;
oldpos = *pos;
switch (abbrev->tag)
{
case DWT_BASE_TYPE:
oldpos = *pos;
read_dwarf_abbrev_attribute(format, &oldpos, true, abbrev, DWA_NAME, &result);
break;
case DWT_POINTER_TYPE:
if (read_dwarf_abbrev_attribute(format, &oldpos, true, abbrev, DWA_TYPE, &type_pos))
printf(" ## sub type :: 0x%08x\n", type_pos);
else printf(" error: no type\n");
oldpos = cu->startpos + type_pos;
subabbrev = find_dwarf_abbreviations(format, &cu->offset, &oldpos);
printf("subabbrev == %p\n", subabbrev);
result = resolve_dwarf_function_type(format, subabbrev, &oldpos, cu);
if (result != NULL)
{
len = strlen(result);
if (result[len - 1] == '*')
{
result = (char *)realloc(result, (len + 2) * sizeof(char));
result[len] = '*';
}
else
{
result = (char *)realloc(result, (len + 3) * sizeof(char));
strcat(result, " *");
}
}
break;
case DWT_CONST_TYPE:
if (read_dwarf_abbrev_attribute(format, &oldpos, true, abbrev, DWA_TYPE, &type_pos))
printf(" ## sub type :: 0x%08x\n", type_pos);
else printf(" error: no type\n");
oldpos = cu->startpos + type_pos;
subabbrev = find_dwarf_abbreviations(format, &cu->offset, &oldpos);
printf("subabbrev == %p\n", subabbrev);
result = resolve_dwarf_function_type(format, subabbrev, &oldpos, cu);
if (result != NULL)
{
len = strlen(result);
result = (char *)realloc(result, (len + strlen("const ") + 1) * sizeof(char));
memmove(&result[strlen("const ")], result, len);
memcpy(result, "const ", strlen("const "));
}
break;
default:
printf("### NOT HANDLED ### Tag :: 0x%02x\n", abbrev->tag);
break;
}
return result;
}