/* Chrysalide - Outil d'analyse de fichiers binaires
 * strtab.h - présentation des chaînes liées au format des binaires ELF
 *
 * Copyright (C) 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 Foobar.  If not, see .
 */
#include "strtab.h"
#include 
#include 
#include 
/* Affiche les chaînes présentes dans une zone de données. */
static void parse_elf_string_table(GElfFormat *, GPreloadInfo *, const GBinContent *, const mrange_t *, GtkStatusStack *);
/******************************************************************************
*                                                                             *
*  Paramètres  : format  = description de l'exécutable à compléter.           *
*                info    = informations à constituer en avance de phase.      *
*                content = contenu binaire à analyser.                        *
*                range   = espace à couvrir pendant l'analyse.                *
*                status  = barre de statut à tenir informée.                  *
*                                                                             *
*  Description : Affiche les chaînes présentes dans une zone de données.      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void parse_elf_string_table(GElfFormat *format, GPreloadInfo *info, const GBinContent *content, const mrange_t *range, GtkStatusStack *status)
{
    phys_t length;                          /* Taille de la couverture     */
    vmpa2t pos;                             /* Tête de lecture             */
    const bin_t *data;                      /* Donnés à parcourir          */
    bool cut;                               /* Séparation nette ?          */
    phys_t i;                               /* Boucle de parcours          */
    phys_t end;                             /* Position de fin de chaîne   */
    GArchInstruction *instr;                /* Instruction décodée         */
    GBinSymbol *symbol;                     /* Symbole à intégrer          */
    char *label;                            /* Désignation de la chaîne    */
    length = get_mrange_length(range);
    copy_vmpa(&pos, get_mrange_addr(range));
    data = g_binary_content_get_raw_access(content, &pos, length);
    cut = true;
    /* Boucle de parcours */
    cut = true;
    for (i = 0; i < length; i++)
        if (isprint(data[i]))
        {
            for (end = i + 1; end < length; end++)
                if (!isprint(data[end])) break;
            if (end < length && isspace(data[end]))
                end++;
            if (end < length && data[end] == '\0')
                end++;
            copy_vmpa(&pos, get_mrange_addr(range));
            advance_vmpa(&pos, i);
            instr = g_raw_instruction_new_array(content, MDS_8_BITS, end - i, &pos, MDS_UNDEFINED);
            g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true);
            g_preload_info_add_instruction(info, instr);
            g_object_ref(G_OBJECT(instr));
            ADD_STR_AS_SYM(format, symbol, instr);
            /* Jointure avec la chaîne précédente ? */
            if (cut)
            {
                copy_vmpa(&pos, get_mrange_addr(range));
                advance_vmpa(&pos, i);
                label = create_string_label(G_BIN_FORMAT(format), &pos, end - i);
                g_binary_symbol_set_alt_label(symbol, label);
                free(label);
            }
            /* Conclusion */
            cut = (data[end - 1] == '\0');
            i = end - 1;
        }
        else cut = true;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                info   = informations à constituer en avance de phase.       *
*                status = barre de statut à tenir informée.                   *
*                                                                             *
*  Description : Affiche les chaînes liées aux sections ELF.                  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void show_elf_section_string_table(GElfFormat *format, GPreloadInfo *info, GtkStatusStack *status)
{
    GBinContent *content;                   /* Contenu binaire à lire      */
    mrange_t range;                         /* Espace à parcourir          */
    bool found;                             /* Détection d'une section     */
    content = g_binary_format_get_content(G_BIN_FORMAT(format));
    found = find_elf_section_range_by_name(format, ".interp", &range);
    if (found)
        parse_elf_string_table(format, info, content, &range, status);
    found = find_elf_section_range_by_name(format, ".shstrtab", &range);
    if (found)
        parse_elf_string_table(format, info, content, &range, status);
    found = find_elf_section_range_by_name(format, ".strtab", &range);
    if (found)
        parse_elf_string_table(format, info, content, &range, status);
    g_object_unref(G_OBJECT(content));
}