/* Chrysalide - Outil d'analyse de fichiers binaires
 * gdb.c - débogage à l'aide de gdb.
 *
 * Copyright (C) 2009-2012 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  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 <http://www.gnu.org/licenses/>.
 */


#include "gdb.h"


#include "../debugger-int.h"



#include "helpers.h"
#include "tcp.h"




/* Débogueur utilisant un serveur GDB (instance) */
struct _GGdbDebugger
{
    GBinaryDebugger parent;                 /* A laisser en premier        */

    GGdbStream *stream;                     /* Flux de communication       */


#if 0
    GCond *cond;                            /* Poursuite du déroulement    */
    GMutex *mutex;                          /* Accès à la condition        */

    ptrace_options *options;                /* Configuration du débogage   */

    pid_t child;                            /* Processus suivi lancé       */

    gboolean run_again;                     /* Reprise du débogage         */
#endif
};

/* Débogueur utilisant un serveur GDB (classe) */
struct _GGdbDebuggerClass
{
    GBinaryDebuggerClass parent;            /* A laisser en premier        */

};





/* Initialise la classe du débogueur utilisant gdb. */
static void g_gdb_debugger_class_init(GGdbDebuggerClass *);

/* Procède à l'initialisation du débogueur utilisant gdb. */
static void g_gdb_debugger_init(GGdbDebugger *);


/* Met en marche le débogueur utilisant un serveur GDB. */
static bool g_gdb_debugger_run(GGdbDebugger *);

/* Remet en marche le débogueur utilisant un serveur GDB. */
static bool g_gdb_debugger_resume(GGdbDebugger *);

/* Tue le débogueur utilisant un serveur GDB. */
static bool g_gdb_debugger_kill(GGdbDebugger *);



/* Indique le type défini par la GLib pour le débogueur gdb. */
G_DEFINE_TYPE(GGdbDebugger, g_gdb_debugger, G_TYPE_BINARY_DEBUGGER);



/******************************************************************************
*                                                                             *
*  Paramètres  : klass = classe de débogueur à initialiser.                   *
*                                                                             *
*  Description : Initialise la classe du débogueur utilisant gdb.             *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_gdb_debugger_class_init(GGdbDebuggerClass *klass)
{

}


/******************************************************************************
*                                                                             *
*  Paramètres  : debugger = instance de débogueur à préparer.                 *
*                                                                             *
*  Description : Procède à l'initialisation du débogueur utilisant gdb.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_gdb_debugger_init(GGdbDebugger *debugger)
{
    GBinaryDebugger *parent;                /* Instance parente            */

    parent = G_BINARY_DEBUGGER(debugger);

    parent->run = (basic_debugger_fc)g_gdb_debugger_run;
    parent->resume = (resume_debugger_fc)g_gdb_debugger_resume;
    parent->kill = (basic_debugger_fc)g_gdb_debugger_kill;

    //parent->get_reg_values = (get_register_values_fc)get_register_values_using_gdb_debugger;

    //debugger->cond = g_cond_new();
    //debugger->mutex = g_mutex_new();

}


/******************************************************************************
*                                                                             *
*  Paramètres  : binary  = binaire représenter à déboguer.                    *
*                options = paramètres destinés au débogage.                   *
*                                                                             *
*  Description : Crée un débogueur utilisant un serveur GDB distant.          *
*                                                                             *
*  Retour      : Instance de débogueur mise en place ou NULL.                 *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GBinaryDebugger *g_gdb_debugger_new(GLoadedBinary *binary, void *options)
{
    GBinaryDebugger *result;                /* Débogueur à retourner       */

    result = g_object_new(G_TYPE_GDB_DEBUGGER, NULL);

    return result;

}








/******************************************************************************
*                                                                             *
*  Paramètres  : debugger = débogueur à lancer.                               *
*                                                                             *
*  Description : Met en marche le débogueur utilisant un serveur GDB.         *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool g_gdb_debugger_run(GGdbDebugger *debugger)
{



    GGdbPacket *packet;

    bool test;

    const char *data;
    size_t len;


    int sig;
    vmpa_t addr;
    pid_t thread;


    debugger->stream = g_gdb_tcp_client_new("127.0.0.1", "6666");
    if (debugger->stream == NULL) return false;


    printf("Connection done !\n");



    packet = g_gdb_stream_get_free_packet(debugger->stream);

    g_gdb_packet_start_new_command(packet);
    g_gdb_packet_append(packet, "?");


    test = g_gdb_stream_send_packet(debugger->stream, packet);



    printf(" >> Paquet '%s' bien envoyé ? %s\n", "?", test ? "oui" : "non");



    g_gdb_stream_mark_packet_as_free(debugger->stream, packet);

    packet = g_gdb_stream_recv_packet(debugger->stream);

    g_gdb_packet_get_data(packet, &data, &len, NULL);

    printf(" << Réception de '%s'\n", data);





    get_stop_reply_sig_info(packet, &sig, &addr, &thread, SRE_LITTLE);

    g_signal_emit_by_name(debugger, "halted", sig, addr, thread);

        





    return true;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : debugger = débogueur à relancer.                             *
*                                                                             *
*  Description : Remet en marche le débogueur utilisant un serveur GDB.       *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool g_gdb_debugger_resume(GGdbDebugger *debugger)
{


    /*
    g_mutex_lock(debugger->mutex);
    debugger->run_again = TRUE;
    g_cond_signal(debugger->cond);
    g_mutex_unlock(debugger->mutex);
    */
    return true;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : debugger = débogueur à relancer.                             *
*                                                                             *
*  Description : Tue le débogueur utilisant un serveur GDB.                   *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool g_gdb_debugger_kill(GGdbDebugger *debugger)
{


#if 0
    int ret;                                /* Bilan de l'appel système    */

    ret = kill(debugger->child, SIGKILL);
    if (ret != 0) perror("kill");

    debugger->child = 0;

    g_mutex_lock(debugger->mutex);
    debugger->run_again = TRUE;
    g_cond_signal(debugger->cond);
    g_mutex_unlock(debugger->mutex);
#endif
    return true;

}












void test_gdb(void)
{

    GGdbStream *stream;

    GGdbPacket *packet;

    bool test;

    const char *data;
    size_t len;

    printf("GDB !!!!\n");


    stream = g_gdb_tcp_client_new("192.168.100.141", "6666");



    packet = g_gdb_stream_get_free_packet(stream);

    g_gdb_packet_start_new_command(packet);
    g_gdb_packet_append(packet, "g");


    test = g_gdb_stream_send_packet(stream, packet);



    printf(" >> Paquet '%s' bien envoyé ? %s\n", "g", test ? "oui" : "non");



    g_gdb_stream_mark_packet_as_free(stream, packet);

    packet = g_gdb_stream_recv_packet(stream);

    g_gdb_packet_get_data(packet, &data, &len, NULL);

    printf(" << Réception de '%s'\n", data);




}