/* 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