/* Chrysalide - Outil d'analyse de fichiers binaires
* info.c - lecture des informations principales du format DWARF
*
* Copyright (C) 2008-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 Chrysalide. If not, see .
*/
#include "info.h"
#include "die.h"
#include "dwarf-int.h"
#include "../debuggable-int.h"
static bool extract_dies_from_debug_information(GDwarfFormat *format, vmpa2t *pos, SourceEndian endian, const dw_compil_unit_header *header, dw_die *parent, dw_die **die);
/******************************************************************************
* *
* Paramètres : format = informations de débogage DWARF à compléter. *
* *
* Description : Charge les informations depuis une section ".debug_info". *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_dwarf_debug_information(GDwarfFormat *format)
{
bool result; /* Bilan à renvoyer */
mrange_t range; /* Couverture d'une section */
vmpa2t end;
vmpa2t iter; /* Tête de lecture mouvante */
dw_compil_unit_header header;
dw_die *die;
result = g_exe_format_get_section_range_by_name(G_DBG_FORMAT(format)->executable, ".debug_info", &range);
if (!result) goto lddi_exit;
copy_vmpa(&iter, get_mrange_addr(&range));
printf("[%d] Passage :: 0x%08llx 0x%08llx\n",
result,
(unsigned long long)range.addr.physical,
(unsigned long long)range.addr.virtual);
compute_mrange_end_addr(&range, &end);
while (result)
{
/* Si il n'y a plus rien à lire dans la section... */
if (cmp_vmpa(&iter, &end) >= 0) break;
printf("========================================================================\n");
printf("========================================================================\n");
printf("========================================================================\n");
printf("========================================================================\n");
printf("\n");
printf("HEADER START :: 0x%x\n", (unsigned int)iter.physical);
result = read_dwarf_compil_unit_header(G_BIN_FORMAT(format)->content, &iter,
SRE_LITTLE /* FIXME */, &header);
if (!result) break;
printf("[%d] header :: addr size=%hhu\n", result, header.address_size);
result = extract_dies_from_debug_information(format, &iter,
SRE_LITTLE /* FIXME */, &header,
NULL, &die);
}
format->info_die = die;
lddi_exit:
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage DWARF à compléter. *
* pos = position de début de lecture. [OUT] *
* endian = boutisme reconnu dans le format. *
* header = en-tête de description de l'unité à traiter. *
* parent = entrée parent de rattachement ou NULL si racine. *
* die = emplacement de stockage de l'entrée. [OUT] *
* *
* Description : Procède à la lecture de l'en-tête d'un contenu binaire DWARF.*
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool extract_dies_from_debug_information(GDwarfFormat *format, vmpa2t *pos, SourceEndian endian, const dw_compil_unit_header *header, dw_die *parent, dw_die **die)
{
bool result; /* Bilan à faire remonter */
dw_die *child; /* Entrée subordonnée à charger*/
printf("==================================\n");
printf("=== version : 0x%hx\n", header->version);
printf("=== offset abbrev : 0x%llx\n", (unsigned long long)header->debug_abbrev_offset);
printf("==================================\n");
phys_t start = 0x1039;
printf("start :: 0x%x\n", (unsigned int)(pos->physical - start));
printf("start :: 0x%x\n", (unsigned int)(0x0 + pos->physical));
result = build_dwarf_die(format, pos, SRE_LITTLE /* FIXME */, header, die);
if (*die == NULL) return result;
if (parent != NULL)
dw_die_append_child(parent, *die);
if (dw_die_has_children(*die))
{
printf("<<<< children >>>>\n");
printf("next :: 0x%x\n", (unsigned int)(pos->physical - start));
while (result)
{
result = extract_dies_from_debug_information(format, pos, endian, header, *die, &child);
if (!result)
delete_dwarf_die(*die);
/* Entrée avec un code nul -> fin */
if (child == NULL) break;
}
}
return result;
}
#if 0
#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;
#define _(str) str
/* Procède à la lecture d'une unité de compilation. */
bool read_dwarf_compilation_unit(dwarf_format *, off_t *, compil_unit *);
/* Récupère toutes les déclarations DWARF utiles trouvées. */
bool parse_dwarf_compilation_unit(dwarf_format *, off_t *, const compil_unit *);
/* Enregistre toutes les déclarations de fonction trouvées. */
dw_dbg_function *look_for_dwarf_subprograms(dwarf_format *, const dw_abbrev *, 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)
parse_dwarf_compilation_unit(format, &offset, &cu);
}
printf("##############\nRegistered functions:\n");
for (i = 0; i < format->dbg_fc_count; i++)
printf(" > [0x%08llx] %s\n", format->dbg_functions[i]->low_pc, format->dbg_functions[i]->prototype);
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)
{
off_t ulength; /* Taille de l'unité */
uint16_t version; /* Version du format DWARF */
cu->startpos = *pos;
if (!read_unit_length(format, pos, &ulength))
return false;
cu->endpos = *pos + ulength;
if (!read_uhalf(format, pos, &version))
return false;
if (version > 3) return false;
if (!read_abbrev_offset(format, pos, &cu->offset))
return false;
if (!read_address_size(format, pos, &cu->ptrsize))
return false;
return true;
}
/******************************************************************************
* *
* Paramètres : format = informations de débogage à compléter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* cu = unité de compilation courante. *
* *
* Description : Récupère toutes les déclarations DWARF utiles trouvées. *
* *
* Retour : true en cas de succès de la lecture, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool parse_dwarf_compilation_unit(dwarf_format *format, off_t *pos, const compil_unit *cu)
{
bool result; /* Bilan à retourner */
const dw_abbrev *abbrev; /* Abréviation rencontrée */
dw_dbg_function *function; /* Nouvelle fonction lue */
result = true;
while (*pos < cu->endpos && result)
{
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]);
abbrev = find_dwarf_abbreviations(format, &cu->offset, pos);
if (abbrev == NULL)
break;
printf(" --> %p\n", abbrev);
printf(" == 0x%02x (matched ? %d)\n", abbrev->tag, abbrev->tag == DWT_SUBPROGRAM);
switch (abbrev->tag)
{
case DWT_SUBPROGRAM:
function = look_for_dwarf_subprograms(format, abbrev, pos, cu);
if (function != NULL)
{
format->dbg_functions = (dw_dbg_function **)realloc(format->dbg_functions, ++format->dbg_fc_count * sizeof(dw_dbg_function *));
format->dbg_functions[format->dbg_fc_count - 1] = function;
}
else result = false;
break;
default:
break;
}
if (!skip_dwarf_abbrev(format, pos, abbrev))
printf("error skipping :(\n");
}
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 trouvée à traiter. *
* pos = tête de lecture à mettre à jour. [OUT] *
* cu = unité de compilation courante. *
* *
* Description : Enregistre toutes les déclarations de fonction trouvées. *
* *
* Retour : Fonction chargée en mémoire ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
dw_dbg_function *look_for_dwarf_subprograms(dwarf_format *format, const dw_abbrev *abbrev, off_t *pos, const compil_unit *cu)
{
dw_dbg_function *result; /* Structure à retourner */
uint32_t type_pos; /* Décalage p/r au pt courant */
off_t subpos; /* Sous-position de lecture #1 */
const dw_abbrev *subabbrev; /* Abréviation fille à lire */
char *retstr; /* Elément du prototype */
char *prototype; /* Stockage temporaire */
size_t proto_len; /* Taille du prototype */
bool is_pointer; /* Mémorise le type 'pointeur' */
uint64_t index; /* Index de la fonction */
bool first_arg; /* Marque le 1er argument */
off_t subpos2; /* Sous-position de lecture #2 */
const dw_abbrev *subabbrev2; /* Abréviation fille à lire #2 */
result = (dw_dbg_function *)calloc(1, sizeof(dw_dbg_function));
/* Récupération des informations de base */
if (!read_dwarf_abbrev_attribute(format, pos, false, abbrev, DWA_NAME, &result->name))
goto lfds_error;
if (!read_dwarf_abbrev_attribute(format, pos, false, abbrev, DWA_LOW_PC, &result->low_pc))
goto lfds_error;
if (!read_dwarf_abbrev_attribute(format, pos, false, abbrev, DWA_HIGH_PC, &result->high_pc))
goto lfds_error;
/* Type de la fonction */
if (test_dwarf_abbrev_attribute(abbrev, DWA_TYPE))
{
if (!read_dwarf_abbrev_attribute(format, pos, false, abbrev, DWA_TYPE, &type_pos))
goto lfds_error;
subpos = cu->startpos + type_pos;
subabbrev = find_dwarf_abbreviations(format, &cu->offset, &subpos);
retstr = resolve_dwarf_function_type(format, subabbrev, &subpos, cu);
}
else retstr = strdup("void");
if (retstr == NULL)
{
proto_len = 3;
prototype = (char *)calloc(proto_len + 1, sizeof(char));
strcat(prototype, "???");
is_pointer = false;
}
else
{
proto_len = strlen(retstr);
prototype = (char *)calloc(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... */
subpos = *pos;
if (!read_uleb128(format, &subpos, &index, true))
goto lfds_error;
if (!skip_dwarf_abbrev(format, &subpos, abbrev))
goto lfds_error;
/* Lecture des différents arguments */
proto_len += (!is_pointer ? 1 : 0) + strlen(result->name) + 1;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
if (!is_pointer) strcat(prototype, " ");
strcat(prototype, result->name);
strcat(prototype, "(");
first_arg = true;
while (1)
{
subabbrev = find_dwarf_abbreviations(format, &cu->offset, &subpos);
if (subabbrev == NULL) goto exit_loop;
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:
if (!read_dwarf_abbrev_attribute(format, &subpos, false, subabbrev, DWA_TYPE, &type_pos))
goto lfds_error;
subpos2 = cu->startpos + type_pos;
subabbrev2 = find_dwarf_abbreviations(format, &cu->offset, &subpos2);
retstr = resolve_dwarf_function_type(format, subabbrev2, &subpos2, cu);
/* 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);
}
/* Nom de l'argument */
if (test_dwarf_abbrev_attribute(abbrev, DWA_NAME))
{
if (!read_dwarf_abbrev_attribute(format, &subpos, false, subabbrev, DWA_NAME, &retstr))
goto lfds_error;
}
else retstr = strdup(_("[no name]"));
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, &subpos, subabbrev))
goto lfds_error;
}
exit_loop:
proto_len += 1;
prototype = (char *)realloc(prototype, (proto_len + 1) * sizeof(char));
strcat(prototype, ")");
result->prototype = prototype;
return result;
lfds_error:
if (result->name != NULL) free(result->name);
if (result->prototype != NULL) free(result->prototype);
free(result);
return NULL;
}
/******************************************************************************
* *
* 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)
{
/* 0x04 */
case DWT_ENUMERATION_TYPE:
oldpos = *pos;
read_dwarf_abbrev_attribute(format, &oldpos, true /* ??? */, abbrev, DWA_NAME, &result);
if (result != NULL)
{
len = strlen(result);
result = (char *)realloc(result, (strlen("enum ") + len + 1) * sizeof(char));
memmove(&result[strlen("enum ")], result, len);
memcpy(result, "enum ", strlen("enum "));
}
break;
/* 0x0f */
case DWT_POINTER_TYPE:
if (test_dwarf_abbrev_attribute(abbrev, DWA_TYPE))
{
if (!read_dwarf_abbrev_attribute(format, &oldpos, true, abbrev, DWA_TYPE, &type_pos))
return NULL;
oldpos = cu->startpos + type_pos;
subabbrev = find_dwarf_abbreviations(format, &cu->offset, &oldpos);
result = resolve_dwarf_function_type(format, subabbrev, &oldpos, cu);
}
else result = strdup("void");
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;
/* 0x13 */
case DWT_STRUCTURE_TYPE:
oldpos = *pos;
read_dwarf_abbrev_attribute(format, &oldpos, true /* ??? */, abbrev, DWA_NAME, &result);
if (result != NULL)
{
len = strlen(result);
result = (char *)realloc(result, (strlen("struct ") + len + 1) * sizeof(char));
memmove(&result[strlen("struct ")], result, len);
memcpy(result, "struct ", strlen("struct "));
}
break;
/* 0x16 */
case DWT_TYPEDEF:
oldpos = *pos;
read_dwarf_abbrev_attribute(format, &oldpos, true /* ??? */, abbrev, DWA_NAME, &result);
break;
/* 0x24 */
case DWT_BASE_TYPE:
oldpos = *pos;
read_dwarf_abbrev_attribute(format, &oldpos, true /* ??? */, abbrev, DWA_NAME, &result);
break;
/* 0x26 */
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, (strlen("const ") + len + 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;
}
#endif