/* Chrysalide - Outil d'analyse de fichiers binaires
 * packet.c - définition des paquets destiné au protocole JDWP
 *
 * Copyright (C) 2010-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 "packet.h"


#include "misc/header.h"
#include "../packet-int.h"
#include "../../arch/archbase.h"
#include "../../common/endianness.h"



/* Répresentation d'un paquet de débogage JDWP (instance) */
struct _GJdwpPacket
{
    GDebugPacket parent;                    /* A laisser en premier        */

    jdwp_header header;                     /* En-tête du paquet JDWP      */
    bin_t hblob[sizeof(jdwp_header)];       /* Contenu encodé en B.E.      */

    jdwp_payload payload;                   /* Charge utile du paquet      */
    bin_t pblob[sizeof(jdwp_payload)];      /* Contenu encodé en B.E.      */
    bool got;                               /* Précise le type de charge   */

};


/* Répresentation d'un paquet de débogage JDWP (classe) */
struct _GJdwpPacketClass
{
    GDebugPacketClass parent;               /* A laisser en premier        */

    jdwp_cmd_vm_id_sizes_reply sizes;       /* Réf. des tailles dynamiques */

};


/* Initialise la classe des paquets de débogage JDWP. */
static void g_jdwp_packet_class_init(GJdwpPacketClass *);

/* Initialise une instance de paquet de débogage JDWP. */
static void g_jdwp_packet_init(GJdwpPacket *);

/* Précise les zones mémoires correspondant au contenu. */
static void g_jdwp_packet_vectorize(GJdwpPacket *, struct iovec [UIO_MAXIOV], int *);



/* Indique le type défini pour un paquet de débogage JDWP. */
G_DEFINE_TYPE(GJdwpPacket, g_jdwp_packet, G_TYPE_DEBUG_PACKET);


/******************************************************************************
*                                                                             *
*  Paramètres  : klass = classe à initialiser.                                *
*                                                                             *
*  Description : Initialise la classe des paquets de débogage JDWP.           *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_jdwp_packet_class_init(GJdwpPacketClass *klass)
{

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à initialiser.                             *
*                                                                             *
*  Description : Initialise une instance de paquet de débogage JDWP.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_jdwp_packet_init(GJdwpPacket *packet)
{
    GDebugPacket *dpkt;                     /* Version parente             */

    dpkt = G_DEBUG_PACKET(packet);

    dpkt->vectorize = (debug_vectorize_fc)g_jdwp_packet_vectorize;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à utiliser comme intermédiaire.            *
*                sizes  = références pour la valeur des tailles dynamiques.   *
*                                                                             *
*  Description : Enregistre les différentes tailles dynamiques.               *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void g_jdwp_packet_set_sizes(GJdwpPacket *packet, const jdwp_cmd_vm_id_sizes_reply *sizes)
{
    G_JDWP_PACKET_GET_CLASS(packet)->sizes = *sizes;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à convertir.                               *
*                iov    = table de vecteurs. [OUT]                            *
*                iovcnt = quantité de champs renseignés. [OUT]                *
*                                                                             *
*  Description : Précise les zones mémoires correspondant au contenu.         *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_jdwp_packet_vectorize(GJdwpPacket *packet, struct iovec iov[UIO_MAXIOV], int *iovcnt)
{
    uint32_t length;                        /* Quantité de données         */
    bool empty;                             /* Présence d'une charge utile */

    read_u32(&length, packet->hblob, (off_t []) { 0 }, sizeof(jdwp_header), SRE_BIG);

    iov[0].iov_base = packet->hblob;
    iov[0].iov_len = sizeof(jdwp_header);

    empty = (length == sizeof(jdwp_header));

    if (!empty)
    {
        iov[1].iov_base = packet->pblob;
        iov[1].iov_len = length - sizeof(jdwp_header);
    }

    *iovcnt = (empty ? 1 : 2);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à consulter.                               *
*                                                                             *
*  Description : Fournit l'adresse des données de l'en-tête d'un paquet JDWP. *
*                                                                             *
*  Retour      : Adresse des données de l'en-tête (à priori de requête).      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

jdwp_header *g_jdwp_packet_get_header(GJdwpPacket *packet)
{
    return &packet->header;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à consulter.                               *
*                                                                             *
*  Description : Fournit l'adresse des données de l'en-tête d'un paquet JDWP. *
*                                                                             *
*  Retour      : Adresse des données de l'en-tête (à priori de requête).      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bin_t *g_jdwp_packet_get_hblob(GJdwpPacket *packet)
{
    return packet->hblob;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à mettre à jour.                           *
*                                                                             *
*  Description : Recompose l'en-tête d'un paquet à partir de données brutes.  *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool g_jdwp_packet_parse_header(GJdwpPacket *packet)
{
    return get_jdwp_header(packet->hblob, &packet->header);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet  = paquet à mettre à jour.                            *
*                set     = jeu de commandes de la requête.                    *
*                command = commande proprement dite.                          *
*                                                                             *
*  Description : Définit l'en-tête du paquet pour une requête au format JDWP. *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void g_jdwp_packet_set_request_header(GJdwpPacket *packet, uint8_t set, uint8_t command)
{
    set_jdwp_request_header(&packet->header, packet->hblob,
                            0, set, command);

    packet->got = false;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet  = paquet à mettre à jour.                            *
*                lastid = jeton du paquet à l'origine du besoin de réponse.   *
*                error  = éventuelle indication d'erreur.                     *
*                                                                             *
*  Description : Définit l'en-tête du paquet pour une réponse au format JDWP. *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void g_jdwp_packet_set_reply_header(GJdwpPacket *packet, uint32_t lastid, uint16_t error)
{
    set_jdwp_reply_header(&packet->header, packet->hblob,
                          0, lastid, error);

    packet->got = false;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet  = instance à consulter.                              *
*                payload = modèle de charge à copier.                         *
*                                                                             *
*  Description : Fournit l'adresse des charges utiles d'un paquet JDWP.       *
*                                                                             *
*  Retour      : Adresse des données d'une charge utile.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void g_jdwp_packet_set_payload(GJdwpPacket *packet, const jdwp_payload *payload)
{
    off_t len;                              /* Quantité max puis effective */

    len = sizeof(jdwp_payload);

    set_jdwp_payload(payload, packet->header.set, packet->header.command,
                     &G_JDWP_PACKET_GET_CLASS(packet)->sizes,
                     packet->pblob, &len);

    packet->header.length += len;

    update_jdwp_header_length(&packet->header, packet->hblob);

    packet->got = false;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à consulter.                               *
*                                                                             *
*  Description : Fournit l'adresse des charges utiles d'un paquet JDWP.       *
*                                                                             *
*  Retour      : Adresse des données d'une charge utile.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

jdwp_payload *g_jdwp_packet_get_payload(GJdwpPacket *packet)
{
    return &packet->payload;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à consulter.                               *
*                                                                             *
*  Description : Fournit l'adresse des charges utiles d'un paquet JDWP.       *
*                                                                             *
*  Retour      : Adresse des données d'une charge utile.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bin_t *g_jdwp_packet_get_pblob(GJdwpPacket *packet)
{
    return packet->pblob;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à mettre à jour.                           *
*                set    = jeu de commandes concerné.                          *
*                cmd    = identifiant d'une commande donnée.                  *
*                                                                             *
*  Description : Recompose une charge utile à partir de ses données brutes.   *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool g_jdwp_packet_parse_payload(GJdwpPacket *packet, uint8_t set, uint8_t cmd)
{
    bool result;                            /* Bilan à retourner           */

    result = get_jdwp_payload(packet->pblob, packet->header.length - sizeof(jdwp_header)/* FIXME */,
                              set, cmd, &G_JDWP_PACKET_GET_CLASS(packet)->sizes, &packet->payload);

    if (result)
    {
        packet->header.set = set;
        packet->header.command = cmd;
    }

    packet->got = true;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : packet = instance à mettre à jour.                           *
*                                                                             *
*  Description : Libère la mémoire occupée par une charge utile de paquet.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void g_jdwp_packet_free_payload(GJdwpPacket *packet)
{
    if (packet->header.set == JDWP_CST_NONE || packet->header.command == JDWP_CMD_NONE)
        return;

    free_jdwp_payload(&packet->payload, packet->got,
                      packet->header.set, packet->header.command);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : reply  = instance de paquet à analyser.                      *
*                packet = instance de paquet de référence.                    *
*                                                                             *
*  Description : Détermine si un paquet est une réponse à un premier paquet.  *
*                                                                             *
*  Retour      : true si le paquet correspond à la réponse attendue.          *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool g_jdwp_packet_is_reply(const GJdwpPacket *reply, const GJdwpPacket *packet)
{
    return (reply->header.id == packet->header.id
            && reply->header.flags & JDWP_FLAGS_REPLY);

}