diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2018-12-07 21:04:46 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2018-12-07 21:04:46 (GMT) |
commit | 648bf475951e6d588d13539441d8a0e54eab2706 (patch) | |
tree | b654558a0c6bb4bc9d15eb9d65c124acb8a3522a /plugins/gdbrsp/target.c | |
parent | c980546e8bca6f1c0c340634a4c3640e14fd1228 (diff) |
Moved some core features into plugins.
Diffstat (limited to 'plugins/gdbrsp/target.c')
-rw-r--r-- | plugins/gdbrsp/target.c | 950 |
1 files changed, 950 insertions, 0 deletions
diff --git a/plugins/gdbrsp/target.c b/plugins/gdbrsp/target.c new file mode 100644 index 0000000..cf28a49 --- /dev/null +++ b/plugins/gdbrsp/target.c @@ -0,0 +1,950 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * target.c - gestion des éléments propres à l'architecture reconnue par GDB + * + * Copyright (C) 2016 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 <http://www.gnu.org/licenses/>. + */ + + +#include "target.h" + + +#include <assert.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "utils.h" +#include "../../common/cpp.h" +#include "../../common/extstr.h" +#include "../../common/xml.h" + + + +/* Définitions de registres */ + +typedef struct _arch_register_t +{ + char *name; /* Nom de registre */ + unsigned int size; /* Taille en bits */ + +} arch_register_t; + +typedef struct _target_cpu_t +{ + char *label; /* Désignation de l'ensemble */ + + arch_register_t *regs; /* Définition des registres */ + unsigned int count; /* Quantité de ces définitions */ + +} target_cpu_t; + + +/* Indications quant à l'interfaçage client/serveur GDB (instance) */ +struct _GGdbTarget +{ + GObject parent; /* A laisser en premier */ + + target_cpu_t **defs; /* Liste de définitions */ + size_t count; /* Taille de cette même liste */ + + bool read_single_register; /* Lecture spécifique permise ?*/ + bool write_single_register; /* Ecriture spécifique valide ?*/ + +}; + +/* Indications quant à l'interfaçage client/serveur GDB (classe) */ +struct _GGdbTargetClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des détails d'interfaçage GDB. */ +static void g_gdb_target_class_init(GGdbTargetClass *); + +/* Procède à l'initialisation des détails d'interfaçage GDB. */ +static void g_gdb_target_init(GGdbTarget *); + +/* Supprime toutes les références externes. */ +static void g_gdb_target_dispose(GGdbTarget *); + +/* Procède à la libération totale de la mémoire. */ +static void g_gdb_target_finalize(GGdbTarget *); + +/* Charge la définition d'un groupe de registres. */ +static bool g_gdb_target_load_register_definition(GGdbTarget *, GGdbStream *, const char *); + +/* Recherche l'indice correspondant à un registre donné. */ +static bool g_gdb_target_find_register_index(const GGdbTarget *, const char *, unsigned int *); + +/* Recherche la position correspondant à un registre donné. */ +static bool g_gdb_target_find_register_offset(const GGdbTarget *, unsigned int, size_t *); + + + +/* Indique le type défini par la GLib pour les détails d'interfaçage GDB. */ +G_DEFINE_TYPE(GGdbTarget, g_gdb_target, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe de débogueur à initialiser. * +* * +* Description : Initialise la classe des détails d'interfaçage GDB. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_gdb_target_class_init(GGdbTargetClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_gdb_target_dispose; + object->finalize = (GObjectFinalizeFunc)g_gdb_target_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : target = instance de débogueur à préparer. * +* * +* Description : Procède à l'initialisation des détails d'interfaçage GDB. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_gdb_target_init(GGdbTarget *target) +{ + target->defs = NULL; + target->count = 0; + + target->read_single_register = true; + target->write_single_register = true; + +} + + +/****************************************************************************** +* * +* Paramètres : target = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_gdb_target_dispose(GGdbTarget *target) +{ + G_OBJECT_CLASS(g_gdb_target_parent_class)->dispose(G_OBJECT(target)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_gdb_target_finalize(GGdbTarget *target) +{ + G_OBJECT_CLASS(g_gdb_target_parent_class)->finalize(G_OBJECT(target)); + +} + + +/****************************************************************************** +* * +* Paramètres : stream = flux de communication ouvert avec le débogueur. * +* * +* Description : Crée une définition des détails d'interfaçage GDB. * +* * +* Retour : Instance de détails mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GGdbTarget *g_gdb_target_new(GGdbStream *stream) +{ + GGdbTarget *result; /* Débogueur à retourner */ + GGdbPacket *packet; /* Paquet de communication GDB */ + bool status; /* Bilan d'une communication */ + + const char *data; /* Données reçues du serveur */ + size_t len; /* Quantité de ces données */ + char *xmldata; /* Données modifiables */ + xmlDocPtr xdoc; /* Document XML récupéré */ + xmlXPathContextPtr context; /* Contexte d'analyse associé */ + xmlXPathObjectPtr xobject; /* Cible d'une recherche */ + unsigned int i; /* Boucle de parcours */ + char *access; /* Chemin d'accès à un élément */ + char *xmlref; /* Référence de définitions */ + + + + + result = NULL; + + + //goto end; + + //goto skip; + + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + //g_gdb_packet_append(packet, "qTargeted:multiprocess+;xmlRegisters"); + g_gdb_packet_append(packet, "qXfer:features:read:target.xml:0,3fff"); + + //g_gdb_packet_append(packet, "qTargeted:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContTargeted+;QThreadEvents+;no-resumed+"); + + + + status = g_gdb_stream_send_packet(stream, packet); + if (!status) goto ggtn_failed; + + + + + 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); + + /* Marqueur de fin placé au début ?! */ + if (data[0] != 'l') + goto ggtn_failed; + + xmldata = strdup(data + 1); + + /** + * On cherche à éviter la déconvenue suivante avec la libxml2 : + * + * noname.xml:12: namespace error : Namespace prefix xi on include is not defined + * <xi:include href="aarch64-core.xml"/> + */ + + xmldata = strrpl(xmldata, "xi:include", "include"); + + if (!load_xml_from_memory(xmldata, len - 1, &xdoc, &context)) + goto ggtn_failed; + + + result = g_object_new(G_TYPE_GDB_TARGET, NULL); + + + xobject = get_node_xpath_object(context, "/target/include"); + + for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++) + { + asprintf(&access, "/target/include[position()=%u]", i + 1); + + xmlref = get_node_prop_value(context, access, "href"); + + free(access); + + if (xmlref != NULL) + { + printf("REF>> %s\n", xmlref); + /*static bool */g_gdb_target_load_register_definition(result, stream, xmlref); + + free(xmlref); + + } + + } + + if(xobject != NULL) + xmlXPathFreeObject(xobject); + + close_xml_file(xdoc, context); + + free(xmldata); + + + + + + + + + + + //result = g_object_new(G_TYPE_GDB_TARGET, NULL); + + + ggtn_failed: + + g_gdb_stream_mark_packet_as_free(stream, packet); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* stream = flux de communication ouvert avec le débogueur. * +* name = désignation des définitions de registres à charger. * +* * +* Description : Charge la définition d'un groupe de registres. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_gdb_target_load_register_definition(GGdbTarget *target, GGdbStream *stream, const char *name) +{ + bool result; /* Bilan à retourner */ + GGdbPacket *packet; /* Paquet de communication GDB */ + bool status; /* Bilan d'une communication */ + const char *data; /* Données reçues du serveur */ + size_t len; /* Quantité de ces données */ + xmlDocPtr xdoc; /* Document XML récupéré */ + xmlXPathContextPtr context; /* Contexte d'analyse associé */ + xmlXPathObjectPtr xobject; /* Cible d'une recherche */ + target_cpu_t *def; /* Nouvelle définition à lire */ + unsigned int i; /* Boucle de parcours */ + char *access; /* Chemin d'accès à un élément */ + char *type; /* Espèce de définition */ + + result = false; + + /* Envoi de la requête */ + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + + g_gdb_packet_append(packet, "qXfer:features:read:"); + g_gdb_packet_append(packet, name); + g_gdb_packet_append(packet, ":0,3fff"); + + status = g_gdb_stream_send_packet(stream, packet); + if (!status) goto ggtlrd_failed; + + g_gdb_stream_mark_packet_as_free(stream, packet); + + /* Réception de la réponse */ + + packet = g_gdb_stream_recv_packet(stream); + + g_gdb_packet_get_data(packet, &data, &len, NULL); + + //printf(">>>> '%s'\n", data); + + /* Marqueur de fin placé au début ?! */ + if (data[0] != 'l') + goto ggtlrd_failed; + + if (!load_xml_from_memory(data + 1, len - 1, &xdoc, &context)) + goto ggtlrd_failed; + + /* Chargement des définitions */ + + xobject = get_node_xpath_object(context, "/feature/*"); + + def = (target_cpu_t *)calloc(1, sizeof(target_cpu_t)); + + def->count = XPATH_OBJ_NODES_COUNT(xobject); + def->regs = (arch_register_t *)calloc(def->count, sizeof(arch_register_t)); + + for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++) + { + asprintf(&access, "/feature/*[position()=%u]", i + 1); + + type = get_node_name(context, access); + + if (strcmp(type, "reg") == 0) + { + def->regs[i].name = get_node_prop_value(context, access, "name"); + def->regs[i].size = atoi(get_node_prop_value(context, access, "bitsize")); + + //printf("load reg '%s' (%u)\n", def->regs[i].name, def->regs[i].size); + + } + + free(type); + + free(access); + + } + + if(xobject != NULL) + xmlXPathFreeObject(xobject); + + close_xml_file(xdoc, context); + + /* Intégration finale */ + + target->defs = (target_cpu_t **)realloc(target->defs, ++target->count * sizeof(target_cpu_t *)); + + target->defs[target->count - 1] = def; + + ggtlrd_failed: + + g_gdb_stream_mark_packet_as_free(stream, packet); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* group = éventuel groupe de registres ciblé ou NULL. * +* count = nombre d'éléments dans la liste de noms. [OUT] * +* * +* Description : Liste l'ensemble des registres appartenant à un groupe. * +* * +* Retour : Liste de noms à libérer de la mémoire après utilisation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char **g_gdb_target_get_register_names(const GGdbTarget *target, const char *group, size_t *count) +{ + char **result; /* Désignations à retourner */ + unsigned int i; /* Boucle de parcours #1 */ + const target_cpu_t *rgrp; /* Groupe de registres */ + unsigned int j; /* Boucle de parcours #2 */ + + result = NULL; + + for (i = 0; i < target->count && result == NULL; i++) + { + rgrp = target->defs[i]; + + if (group != NULL) + { + if (strcmp(rgrp->label, group) != 0) + continue; + } + + *count = rgrp->count; + + result = (char **)calloc(*count, sizeof(char *)); + + for (j = 0; j < *count; j++) + result[j] = strdup(rgrp->regs[j].name); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* name = désignation du registre visé. * +* * +* Description : Indique la taille associée à un registre donné. * +* * +* Retour : Taille en bits, ou 0 si le registre n'a pas été trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned int g_gdb_target_get_register_size(const GGdbTarget *target, const char *name) +{ + unsigned int result; /* Taille en bits à retourner */ + unsigned int i; /* Boucle de parcours #1 */ + const target_cpu_t *rgrp; /* Groupe de registres */ + unsigned int j; /* Boucle de parcours #2 */ + + result = 0; + + for (i = 0; i < target->count && result == 0; i++) + { + rgrp = target->defs[i]; + + for (j = 0; j < rgrp->count; j++) + if (strcmp(rgrp->regs[j].name, name) == 0) + result = rgrp->regs[j].size; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* reg = désignation humaine du register à consulter. * +* index = indice correspondant au registre pour GDB. [OUT] * +* * +* Description : Recherche l'indice correspondant à un registre donné. * +* * +* Retour : Bilan de l'opération : trouvaille ou échec ? * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_gdb_target_find_register_index(const GGdbTarget *target, const char *reg, unsigned int *index) +{ + bool result; /* Bilan à retourner */ + unsigned int i; /* Boucle de parcours #1 */ + unsigned int j; /* Boucle de parcours #2 */ + + result = false; + + *index = 0; + + for (i = 0; i < target->count && !result; i++) + for (j = 0; j < target->defs[i]->count && !result; j++) + { + if (strcmp(target->defs[i]->regs[j].name, reg) == 0) + result = true; + else + (*index)++; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* index = indice correspondant au registre pour GDB. * +* offset = position de valeur du registre dans du texte. [OUT] * +* * +* Description : Recherche la position correspondant à un registre donné. * +* * +* Retour : Bilan de l'opération : trouvaille ou échec ? * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_gdb_target_find_register_offset(const GGdbTarget *target, unsigned int index, size_t *offset) +{ + unsigned int i; /* Boucle de parcours #1 */ + unsigned int j; /* Boucle de parcours #2 */ + + *offset = 0; + + for (i = 0; i < target->count && index > 0; i++) + for (j = 0; j < target->defs[i]->count && index > 0; j++) + { + assert(target->defs[i]->regs[j].size % 4 == 0); + + *offset += target->defs[i]->regs[j].size / 4; + + index--; + + } + + return (index == 0); + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* stream = flux de communication ouvert avec le débogueur. * +* endian = boutisme de la cible. * +* reg = désignation humaine du register à consulter. * +* size = taille des données mises en jeu. * +* ... = emplacement de la valeur lue à conserver. [OUT] * +* * +* Description : Effectue la lecture d'un registre donné. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_gdb_target_read_register(GGdbTarget *target, GGdbStream *stream, SourceEndian endian, const char *reg, size_t size, ...) +{ + bool result; /* Bilan à retourner */ + unsigned int index; /* Indice du registre ciblé */ + GGdbPacket *packet; /* Paquet de communication */ + char cmd[sizeof(XSTR(UINT_MAX)) + 1]; /* Elément de requête */ + const char *data; /* Données reçues à analyser */ + size_t len; /* Quantité de ces données */ + const char *raw; /* Début de zone à relire */ + size_t offset; /* Position dans la masse */ + va_list ap; /* Liste variable d'arguments */ + uint8_t *val8; /* Valeur sur 8 bits */ + uint16_t *val16; /* Valeur sur 16 bits */ + uint16_t conv16; /* Valeur adaptée sur 16 bits */ + uint32_t *val32; /* Valeur sur 32 bits */ + uint32_t conv32; /* Valeur adaptée sur 32 bits */ + uint64_t *val64; /* Valeur sur 64 bits */ + uint64_t conv64; /* Valeur adaptée sur 64 bits */ + + result = g_gdb_target_find_register_index(target, reg, &index); + if (!result) goto ggtrr_error; + + /** + * Essai avec la méthode précise. + */ + + if (!target->read_single_register) + goto read_all_register_fallback; + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + g_gdb_packet_append(packet, "p"); + + snprintf(cmd, sizeof(cmd), "%x", index); + g_gdb_packet_append(packet, cmd); + + result = g_gdb_stream_send_packet(stream, packet); + + g_gdb_stream_mark_packet_as_free(stream, packet); + + if (!result) + goto ggtrr_error; + + /* Réception de la réponse */ + + packet = g_gdb_stream_recv_packet(stream); + + g_gdb_packet_get_data(packet, &data, &len, NULL); + + if (len != 0 && !is_error_code(data, len)) + raw = data; + + else + { + target->read_single_register = false; + + g_gdb_stream_mark_packet_as_free(stream, packet); + + read_all_register_fallback: + + /** + * Utilisation de la méthode de masse au besoin... + */ + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + g_gdb_packet_append(packet, "g"); + + result = g_gdb_stream_send_packet(stream, packet); + + g_gdb_stream_mark_packet_as_free(stream, packet); + + if (!result) + goto ggtrr_error; + + /* Réception de la réponse */ + + packet = g_gdb_stream_recv_packet(stream); + + g_gdb_packet_get_data(packet, &data, &len, NULL); + + result = g_gdb_target_find_register_offset(target, index, &offset); + + if (!result || offset > len) + goto ggtrr_exit; + + raw = data + offset; + len -= offset; + + } + + /* Lecture finale de la valeur recherchée */ + + va_start(ap, size); + + switch (size) + { + case 8: + val8 = va_arg(ap, uint8_t *); + result = hex_to_u8(raw, val8); + break; + + case 16: + val16 = va_arg(ap, uint16_t *); + result = hex_to_u16(raw, &conv16); + *val16 = from_u16(&conv16, endian); + break; + + case 32: + val32 = va_arg(ap, uint32_t *); + result = hex_to_u32(raw, &conv32); + *val32 = from_u32(&conv32, endian); + break; + + case 64: + val64 = va_arg(ap, uint64_t *); + result = hex_to_u64(raw, &conv64); + *val64 = from_u64(&conv64, endian); + break; + + default: + assert(false); + result = false; + break; + + } + + va_end(ap); + + ggtrr_exit: + + g_gdb_stream_mark_packet_as_free(stream, packet); + + ggtrr_error: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = ensemble d'informations liées à l'architecture. * +* stream = flux de communication ouvert avec le débogueur. * +* endian = boutisme de la cible. * +* reg = désignation humaine du register à consulter. * +* size = taille des données mises en jeu. * +* ... = emplacement de la valeur à écrire. * +* * +* Description : Effectue l'écriture d'un registre donné. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_gdb_target_write_register(GGdbTarget *target, GGdbStream *stream, SourceEndian endian, const char *reg, size_t size, ...) +{ + bool result; /* Bilan d'opération à renvoyer*/ + va_list ap; /* Liste variable d'arguments */ + const uint8_t *val8; /* Valeur sur 8 bits */ + const uint16_t *val16; /* Valeur sur 16 bits */ + uint16_t conv16; /* Valeur adaptée sur 16 bits */ + const uint32_t *val32; /* Valeur sur 32 bits */ + uint32_t conv32; /* Valeur adaptée sur 32 bits */ + const uint64_t *val64; /* Valeur sur 64 bits */ + uint64_t conv64; /* Valeur adaptée sur 64 bits */ + char hexval[17]; /* Valeur sous forme hexa */ + unsigned int index; /* Indice du registre ciblé */ + GGdbPacket *packet; /* Paquet de communication */ + char cmd[sizeof(XSTR(UINT_MAX)) + 1]; /* Elément de requête */ + const char *data; /* Données reçues à analyser */ + size_t len; /* Quantité de ces données */ + char *new; /* Nouvelles valeurs générales */ + size_t offset; /* Position dans la masse */ + + /* Tronc commun : récupération de la valeur */ + + va_start(ap, size); + + switch (size) + { + case 8: + val8 = va_arg(ap, uint8_t *); + result = u8_to_hex(val8, hexval); + break; + + case 16: + val16 = va_arg(ap, uint16_t *); + conv16 = to_u16(val16, endian); + result = u16_to_hex(&conv16, hexval); + break; + + case 32: + val32 = va_arg(ap, uint32_t *); + conv32 = to_u32(val32, endian); + result = u32_to_hex(&conv32, hexval); + break; + + case 64: + val64 = va_arg(ap, uint64_t *); + conv64 = to_u64(val64, endian); + result = u16_to_hex(&conv64, hexval); + break; + + default: + assert(false); + result = false; + break; + + } + + va_end(ap); + + if (!result) + goto ggtwr_error; + + /* Préparation de la suite */ + + result = g_gdb_target_find_register_index(target, reg, &index); + if (!result) goto ggtwr_error; + + /** + * Essai avec la méthode précise. + */ + + if (!target->write_single_register) + goto write_all_register_fallback; + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + g_gdb_packet_append(packet, "P"); + + snprintf(cmd, sizeof(cmd), "%x", index); + g_gdb_packet_append(packet, cmd); + + g_gdb_packet_append(packet, "="); + + g_gdb_packet_append(packet, hexval); + + result = g_gdb_stream_send_packet(stream, packet); + + g_gdb_stream_mark_packet_as_free(stream, packet); + + if (!result) + goto ggtwr_error; + + /* Réception de la réponse */ + + packet = g_gdb_stream_recv_packet(stream); + + g_gdb_packet_get_data(packet, &data, &len, NULL); + + if (is_error_code(data, len) || strcmp(data, "OK") != 0) + { + target->write_single_register = false; + + g_gdb_stream_mark_packet_as_free(stream, packet); + + write_all_register_fallback: + + /** + * Utilisation de la méthode de masse au besoin... + */ + + /* Lecture de l'ensemble des registres */ + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + g_gdb_packet_append(packet, "g"); + + result = g_gdb_stream_send_packet(stream, packet); + + g_gdb_stream_mark_packet_as_free(stream, packet); + + if (!result) + goto ggtwr_error; + + /* Réception de la réponse et mise à jour */ + + packet = g_gdb_stream_recv_packet(stream); + + g_gdb_packet_get_data(packet, &data, &len, NULL); + + result = g_gdb_target_find_register_offset(target, index, &offset); + + if (!result || offset > len) + goto ggtwr_exit; + + new = (char *)malloc(len); + + memcpy(new, data, len); + memcpy(new + offset, hexval, strlen(hexval)); + + g_gdb_stream_mark_packet_as_free(stream, packet); + + /* Ecrasement de tous les registres */ + + packet = g_gdb_stream_get_free_packet(stream); + + g_gdb_packet_start_new_command(packet); + g_gdb_packet_append(packet, "G"); + + g_gdb_packet_append(packet, new); + free(new); + + result = g_gdb_stream_send_packet(stream, packet); + + g_gdb_stream_mark_packet_as_free(stream, packet); + + if (!result) + goto ggtwr_error; + + /* Réception de la réponse */ + + packet = g_gdb_stream_recv_packet(stream); + + g_gdb_packet_get_data(packet, &data, &len, NULL); + + result = (!is_error_code(data, len) && strcmp(data, "OK") == 0); + + } + + ggtwr_exit: + + g_gdb_stream_mark_packet_as_free(stream, packet); + + ggtwr_error: + + return result; + +} |