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