summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/analysis/binary.c1
-rw-r--r--src/arch/vmpa.c4
-rwxr-xr-xsrc/common/endianness.c220
-rwxr-xr-xsrc/common/endianness.h27
-rw-r--r--src/common/extstr.c4
-rw-r--r--src/common/xml.c99
-rw-r--r--src/common/xml.h9
-rwxr-xr-xsrc/debug/Makefile.am6
-rw-r--r--src/debug/break-int.h64
-rw-r--r--src/debug/break.c489
-rw-r--r--src/debug/break.h90
-rw-r--r--src/debug/debugger-int.h128
-rw-r--r--src/debug/debugger.c1551
-rw-r--r--src/debug/debugger.h193
-rw-r--r--src/debug/gdbrsp/Makefile.am24
-rw-r--r--src/debug/gdbrsp/aops.h57
-rw-r--r--src/debug/gdbrsp/gdb-int.h116
-rw-r--r--src/debug/gdbrsp/gdb.c1524
-rw-r--r--src/debug/gdbrsp/gdb.h (renamed from src/debug/remgdb/gdb.h)8
-rw-r--r--src/debug/gdbrsp/helpers.c (renamed from src/debug/remgdb/helpers.c)85
-rw-r--r--src/debug/gdbrsp/helpers.h (renamed from src/debug/remgdb/helpers.h)11
-rw-r--r--src/debug/gdbrsp/helpers_arm.c252
-rw-r--r--src/debug/gdbrsp/helpers_arm.h37
-rw-r--r--src/debug/gdbrsp/helpers_arm64.c97
-rw-r--r--src/debug/gdbrsp/helpers_arm64.h40
-rw-r--r--src/debug/gdbrsp/packet.c (renamed from src/debug/remgdb/packet.c)14
-rw-r--r--src/debug/gdbrsp/packet.h (renamed from src/debug/remgdb/packet.h)6
-rw-r--r--src/debug/gdbrsp/stream-int.h (renamed from src/debug/remgdb/stream-int.h)21
-rw-r--r--src/debug/gdbrsp/stream.c (renamed from src/debug/remgdb/stream.c)310
-rw-r--r--src/debug/gdbrsp/stream.h (renamed from src/debug/remgdb/stream.h)9
-rw-r--r--src/debug/gdbrsp/support.c598
-rw-r--r--src/debug/gdbrsp/support.h73
-rw-r--r--src/debug/gdbrsp/target.c950
-rw-r--r--src/debug/gdbrsp/target.h72
-rw-r--r--src/debug/gdbrsp/tcp.c (renamed from src/debug/remgdb/tcp.c)25
-rw-r--r--src/debug/gdbrsp/tcp.h (renamed from src/debug/remgdb/tcp.h)9
-rw-r--r--src/debug/gdbrsp/utils.c351
-rw-r--r--src/debug/gdbrsp/utils.h58
-rw-r--r--src/debug/misc.h37
-rw-r--r--src/debug/remgdb/Makefile.am17
-rw-r--r--src/debug/remgdb/gdb.c363
-rw-r--r--src/gtkext/gtkstatusstack.c10
43 files changed, 7235 insertions, 825 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ad9f22d..4b66cfb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,7 +33,6 @@ libchrysadisass_la_LIBADD = \
analysis/libanalysis.la \
arch/libarch.la \
debug/libdebug.la \
- debug/remgdb/libdebugremgdb.la \
format/libformat.la
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index a6f0a31..79c82f5 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -394,7 +394,6 @@ GLoadedBinary *g_loaded_binary_new_from_xml(xmlXPathContextPtr context, const ch
char *access; /* Chemin d'accès à un élément */
char *hash; /* Empreinte à retrouver */
GBinContent *content; /* Contenu à référencer */
-
xmlXPathObjectPtr xobject; /* Cible d'une recherche */
unsigned int i; /* Boucle de parcours */
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index 27262d1..f344101 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -422,7 +422,7 @@ static char *_phys_t_to_string(phys_t phys, MemoryDataSize msize, char buffer[VM
switch (msize)
{
case MDS_8_BITS:
- ret = snprintf(buffer, VMPA_MAX_LEN,"0x%02" PRIx64, phys);
+ ret = snprintf(buffer, VMPA_MAX_LEN, "0x%02" PRIx64, phys);
break;
case MDS_16_BITS:
@@ -499,7 +499,7 @@ char *vmpa2_virt_to_string(const vmpa2t *addr, MemoryDataSize msize, char buffer
switch (msize)
{
case MDS_8_BITS:
- ret = snprintf(buffer, VMPA_MAX_LEN,"0x%02" PRIx64, addr->virtual);
+ ret = snprintf(buffer, VMPA_MAX_LEN, "0x%02" PRIx64, addr->virtual);
break;
case MDS_16_BITS:
diff --git a/src/common/endianness.c b/src/common/endianness.c
index eecb397..ba72f3d 100755
--- a/src/common/endianness.c
+++ b/src/common/endianness.c
@@ -29,6 +29,226 @@
+/* ---------------------------------------------------------------------------------- */
+/* CONVERSION ENTRE BOUTISMES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur d'origine à manipuler. *
+* endian = ordre des bits dans la source. *
+* *
+* Description : Adapte un nombre sur 16 bits à un boutisme donné. *
+* *
+* Retour : Valeur transformée au besoin. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+uint16_t swap_u16(const uint16_t *value, SourceEndian endian)
+{
+ uint16_t result; /* Valeur à retourner */
+
+ switch (endian)
+ {
+ case SRE_LITTLE:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+ result = *value;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+ result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0;
+
+#else
+
+# error "TODO : PDP !"
+
+#endif
+
+ break;
+
+ case SRE_MIDDLE:
+ /* TODO */
+ break;
+
+ case SRE_BIG:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+ result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+ result = *value;
+
+#else
+
+# error "TODO : PDP !"
+
+#endif
+
+ break;
+
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur d'origine à manipuler. *
+* endian = ordre des bits dans la source. *
+* *
+* Description : Adapte un nombre sur 16 bits à un boutisme donné. *
+* *
+* Retour : Valeur transformée au besoin. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+uint32_t swap_u32(const uint32_t *value, SourceEndian endian)
+{
+ uint32_t result; /* Valeur à retourner */
+
+ switch (endian)
+ {
+ case SRE_LITTLE:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+ result = *value;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+ result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16
+ | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0;
+
+#else
+
+# error "TODO : PDP !"
+
+#endif
+
+ break;
+
+ case SRE_MIDDLE:
+ /* TODO */
+ break;
+
+ case SRE_BIG:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+ result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16
+ | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+ result = *value;
+
+#else
+
+# error "TODO : PDP !"
+
+#endif
+
+ break;
+
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur d'origine à manipuler. *
+* endian = ordre des bits dans la source. *
+* *
+* Description : Adapte un nombre sur 16 bits à un boutisme donné. *
+* *
+* Retour : Valeur transformée au besoin. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+uint64_t swap_u64(const uint64_t *value, SourceEndian endian)
+{
+ uint64_t result; /* Valeur à retourner */
+
+ switch (endian)
+ {
+ case SRE_LITTLE:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+ result = *value;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+ result = ((*value >> 0) & 0xff) << 56 | ((*value >> 8) & 0xff) << 48
+ | ((*value >> 16) & 0xff) << 40 | ((*value >> 24) & 0xff) << 32
+ | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16
+ | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0;
+
+#else
+
+# error "TODO : PDP !"
+
+#endif
+
+ break;
+
+ case SRE_MIDDLE:
+ /* TODO */
+ break;
+
+ case SRE_BIG:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+ result = ((*value >> 0) & 0xff) << 56 | ((*value >> 8) & 0xff) << 48
+ | ((*value >> 16) & 0xff) << 40 | ((*value >> 24) & 0xff) << 32
+ | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16
+ | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+ result = *value;
+
+#else
+
+# error "TODO : PDP !"
+
+#endif
+
+ break;
+
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* BOUTISME DES ENTREES / SORTIES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] *
diff --git a/src/common/endianness.h b/src/common/endianness.h
index 2af6493..5ceb2ee 100755
--- a/src/common/endianness.h
+++ b/src/common/endianness.h
@@ -43,6 +43,33 @@ typedef enum _SourceEndian
} SourceEndian;
+/* --------------------------- CONVERSION ENTRE BOUTISMES --------------------------- */
+
+
+/* Adapte un nombre sur 16 bits à un boutisme donné. */
+uint16_t swap_u16(const uint16_t *, SourceEndian);
+
+/* Adapte un nombre sur 16 bits à un boutisme donné. */
+uint32_t swap_u32(const uint32_t *, SourceEndian);
+
+/* Adapte un nombre sur 16 bits à un boutisme donné. */
+uint64_t swap_u64(const uint64_t *, SourceEndian);
+
+
+#define from_u16(v, e) swap_u16(v, e)
+#define from_u32(v, e) swap_u32(v, e)
+#define from_u64(v, e) swap_u64(v, e)
+
+
+#define to_u16(v, e) swap_u16(v, e)
+#define to_u32(v, e) swap_u32(v, e)
+#define to_u64(v, e) swap_u64(v, e)
+
+
+
+/* ------------------------- BOUTISME DES ENTREES / SORTIES ------------------------- */
+
+
/* Lit un nombre non signé sur 4 bits. */
bool read_u4(uint8_t *, const bin_t *, phys_t *, phys_t, bool *);
diff --git a/src/common/extstr.c b/src/common/extstr.c
index 087505a..bd561ba 100644
--- a/src/common/extstr.c
+++ b/src/common/extstr.c
@@ -196,13 +196,13 @@ char *strrpl(char *haystack, const char *needle1, const char *needle2)
haystack = (char *)realloc(haystack, inlen * sizeof(char *));
found = haystack + index;
- memmove(found + len2, found + len1, inlen + len2 - index);
+ memmove(found + len2, found + len1, inlen - len2 - index);
}
else if (len2 < len1)
{
- memmove(found + len2, found + len1, inlen + len2 - index);
+ memmove(found + len2, found + len1, inlen - index - len1);
inlen -= (len1 - len2);
diff --git a/src/common/xml.c b/src/common/xml.c
index cbb7a41..0bd4d86 100644
--- a/src/common/xml.c
+++ b/src/common/xml.c
@@ -45,9 +45,8 @@
/******************************************************************************
* *
-* Paramètres : filename = nom du fichier à ouvrir. *
-* xdoc = structure XML chargée. [OUT] *
-* context = contexte à utiliser pour les recherches. [OUT] *
+* Paramètres : xdoc = structure XML chargée. [OUT] *
+* context = contexte à utiliser pour les recherches. [OUT] *
* *
* Description : Crée un nouveau fichier XML. *
* *
@@ -79,6 +78,41 @@ bool create_new_xml_file(xmlDocPtr *xdoc, xmlXPathContextPtr *context)
/******************************************************************************
* *
+* Paramètres : content = données XML présentes en mémoire et à charge. *
+* length = quantité de ces données. *
+* xdoc = structure XML chargée. [OUT] *
+* context = contexte à utiliser pour les recherches. [OUT] *
+* *
+* Description : Charge un document XML entièrement en mémoire. *
+* *
+* Retour : true si l'opération a pu s'effectuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_xml_from_memory(const char *content, size_t length, xmlDocPtr *xdoc, xmlXPathContextPtr *context)
+{
+ *xdoc = xmlReadMemory(content, length, "noname.xml", NULL, 0);
+
+ if (*xdoc == NULL)
+ return false;
+
+ *context = xmlXPathNewContext(*xdoc);
+
+ if (*context == NULL)
+ {
+ xmlFreeDoc(*xdoc);
+ return false;
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : xdoc = structure XML chargée. *
* filename = nom du fichier à remplir. *
* *
@@ -217,6 +251,65 @@ xmlXPathObjectPtr get_node_xpath_object(xmlXPathContextPtr xpathCtx, const char
* *
* Paramètres : node = noeud dont une propriété est à lire. *
* *
+* Description : Obtient le nom de balise d'un noeud donné. *
+* *
+* Retour : Valeur sous forme de chaîne de caractères ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *qck_get_node_name(xmlNodePtr node)
+{
+ char *result; /* Valeur en question renvoyée */
+
+ result = NULL;
+
+ if (node != NULL)
+ result = strdup((const char *)node->name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : xpathCtx = contexte à utiliser pour les recherches. *
+* path = chemin d'accès au noeud visé. *
+* *
+* Description : Obtient le nom de balise d'un noeud donné. *
+* *
+* Retour : Valeur sous forme de chaîne de caractères ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *get_node_name(xmlXPathContextPtr xpathCtx, const char *path)
+{
+ char *result; /* Valeur en question renvoyée */
+ xmlXPathObjectPtr xpathObj; /* Point de départ XML */
+
+ result = NULL;
+
+ xpathObj = get_node_xpath_object(xpathCtx, path);
+ if (xpathObj == NULL) return NULL;
+
+ if (xpathObj->nodesetval->nodeNr > 0)
+ result = qck_get_node_name(xpathObj->nodesetval->nodeTab[0]);
+
+ xmlXPathFreeObject(xpathObj);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud dont une propriété est à lire. *
+* *
* Description : Obtient une valeur placée entre <...> et </...>. *
* *
* Retour : Valeur sous forme de chaîne de caractères ou NULL. *
diff --git a/src/common/xml.h b/src/common/xml.h
index c3e4b56..ed009c6 100644
--- a/src/common/xml.h
+++ b/src/common/xml.h
@@ -37,6 +37,9 @@
/* Crée un nouveau fichier XML. */
bool create_new_xml_file(xmlDocPtr *, xmlXPathContextPtr *);
+/* Charge un document XML entièrement en mémoire. */
+bool load_xml_from_memory(const char *, size_t, xmlDocPtr *, xmlXPathContextPtr *);
+
/* Sauvegarde une structure XML dans un fichier. */
bool save_xml_file(xmlDocPtr, const char *);
@@ -58,6 +61,12 @@ gboolean open_xml_file(const char *filename, xmlDoc **, xmlXPathContextPtr *);
/* Obtient de façon encadrée l'accès à un noeud défini. */
xmlXPathObjectPtr get_node_xpath_object(xmlXPathContextPtr, const char *);
+/* Obtient le nom de balise d'un noeud donné. */
+char *qck_get_node_name(xmlNodePtr);
+
+/* Obtient le nom de balise d'un noeud donné. */
+char *get_node_name(xmlXPathContextPtr, const char *);
+
/* Obtient une valeur placée entre <...> et </...>. */
char *qck_get_node_text_value(xmlNodePtr);
diff --git a/src/debug/Makefile.am b/src/debug/Makefile.am
index b2f4685..f955a5a 100755
--- a/src/debug/Makefile.am
+++ b/src/debug/Makefile.am
@@ -2,16 +2,18 @@
noinst_LTLIBRARIES = libdebug.la
libdebug_la_SOURCES = \
+ break-int.h \
break.h break.c \
debugger-int.h \
debugger.h debugger.c \
+ misc.h \
packet-int.h \
packet.h packet.c \
stream-int.h \
stream.h stream.c
libdebug_la_LIBADD = \
- jdwp/libdebugjdwp.la
+ gdbrsp/libdebuggdbrsp.la
libdebug_la_CFLAGS = $(AM_CFLAGS)
@@ -20,4 +22,4 @@ AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-SUBDIRS = jdwp remgdb
+SUBDIRS = gdbrsp
diff --git a/src/debug/break-int.h b/src/debug/break-int.h
new file mode 100644
index 0000000..44b3664
--- /dev/null
+++ b/src/debug/break-int.h
@@ -0,0 +1,64 @@
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * break-int.h - prototypes pour la définition générique interne des points d'arrêt
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_BREAK_INT_H
+#define _DEBUG_BREAK_INT_H
+
+
+#include "break.h"
+
+
+
+/* Traçabilité des poses */
+typedef struct _bp_source
+{
+ RawBpOrigin origin; /* Source de la définition */
+
+ /* Si origin != RBO_USER : */
+
+ dbg_thread_id_t tid; /* Identifiant du thread lié */
+ virt_t previous; /* Arrêt officiel d'origine */
+
+} bp_source;
+
+
+/* Définition d'un point d'arrêt appliqué */
+struct _raw_breakpoint
+{
+ virt_t addr; /* Adresse d'application */
+
+ union
+ {
+ bp_source source; /* Origine du point d'arrêt */
+ bp_source *sources; /* Origines du point d'arrêt */
+ };
+ size_t count; /* Nombre de ces origines */
+
+};
+
+
+/* Initialise le coeur d'un point d'arrêt. */
+void init_raw_breakpoint(raw_breakpoint *, virt_t);
+
+
+
+#endif /* _DEBUG_BREAK_INT_H */
diff --git a/src/debug/break.c b/src/debug/break.c
index 19eb787..1d4c2d3 100644
--- a/src/debug/break.c
+++ b/src/debug/break.c
@@ -24,114 +24,20 @@
#include "break.h"
+#include <assert.h>
#include <malloc.h>
-#include <string.h>
-#include "../common/dllist.h"
+#include "break-int.h"
-
-/* --------------------------- GESTION DES POINTS D'ARRET --------------------------- */
-
-
-/* Propriétés d'un point d'arrêt (instance) */
-struct _GBreakPoint
-{
- GObject parent; /* A laisser en premier */
-
- DL_LIST_ITEM(link); /* Maillon de liste chaînée */
-
- vmpa_t address; /* Adresse où s'arrêter */
-
- bool is_enabled; /* Statut d'activité */
-
-};
-
-/* Propriétés d'un point d'arrêt (classe) */
-struct _GBreakPointClass
-{
- GObjectClass parent; /* A laisser en premier */
-
- /* Signaux */
-
- void (* changed) (GBreakPoint *);
-
-};
-
-
-#define bp_list_add_tail(new, head) dl_list_add_tail(new, head, GBreakPoint, link)
-#define bp_list_del(item, head) dl_list_del(item, head, GBreakPoint, link)
-#define bp_list_for_each(pos, head) dl_list_for_each(pos, head, GBreakPoint, link)
-#define bp_list_for_each_safe(pos, head, next) dl_list_for_each_safe(pos, head, next, GBreakPoint, link)
-
-
-/* Initialise la classe des propriétés d'un point d'arrêt. */
-static void g_break_point_class_init(GBreakPointClass *);
-
-/* Initialise des propriétés d'un point d'arrêt. */
-static void g_break_point_init(GBreakPoint *);
-
-
-
-
-
-
-/* ---------------------------- GROUPE DE POINTS D'ARRET ---------------------------- */
-
-
-/* Propriétés d'un groupe de points d'arrêt (instance) */
-struct _GBreakGroup
-{
- GObject parent; /* A laisser en premier */
-
- char *name; /* Désignation humaine */
-
- GBreakPoint *points; /* Liste de points d'arrêt */
-
-};
-
-/* Propriétés d'un groupe de points d'arrêt (classe) */
-struct _GBreakGroupClass
-{
- GObjectClass parent; /* A laisser en premier */
-
- /* Signaux */
-
- void (* added) (GBreakGroup *, GBreakPoint *);
- void (* removed) (GBreakGroup *, GBreakPoint *);
-
-};
-
-
-/* Initialise la classe des groupes de points d'arrêt. */
-static void g_break_group_class_init(GBreakGroupClass *);
-
-/* Initialise un groupe de points d'arrêt. */
-static void g_break_group_init(GBreakGroup *);
-
-
-
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* GESTION DES POINTS D'ARRET */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour des propriétés d'un point d'arrêt. */
-G_DEFINE_TYPE(GBreakPoint, g_break_point, G_TYPE_OBJECT);
-
-
/******************************************************************************
* *
-* Paramètres : klass = classe à initialiser. *
+* Paramètres : bp = point d'arrêt à initialiser. *
+* addr = adresse d'action du point d'arrêt. *
* *
-* Description : Initialise la classe des propriétés d'un point d'arrêt. *
+* Description : Initialise le coeur d'un point d'arrêt. *
* *
* Retour : - *
* *
@@ -139,24 +45,20 @@ G_DEFINE_TYPE(GBreakPoint, g_break_point, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_break_point_class_init(GBreakPointClass *klass)
+void init_raw_breakpoint(raw_breakpoint *bp, virt_t addr)
{
- g_signal_new("changed",
- G_TYPE_BREAK_POINT,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GBreakPointClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ bp->addr = addr;
+
+ bp->count = 0;
}
/******************************************************************************
* *
-* Paramètres : point = instance à initialiser. *
+* Paramètres : bp = point d'arrêt à traiter. *
* *
-* Description : Initialise des propriétés d'un point d'arrêt. *
+* Description : Libère le coeur d'un point d'arrêt. *
* *
* Retour : - *
* *
@@ -164,135 +66,133 @@ static void g_break_point_class_init(GBreakPointClass *klass)
* *
******************************************************************************/
-static void g_break_point_init(GBreakPoint *point)
+void fini_raw_breakpoint(raw_breakpoint *bp)
{
- DL_LIST_ITEM_INIT(&point->link);
+ if (bp->count > 1)
+ free(bp->sources);
+
+ free(bp);
}
/******************************************************************************
* *
-* Paramètres : address = adresse à laquelle s'arrêter. *
+* Paramètres : bp = point d'arrêt à consulter. *
* *
-* Description : Construit un nouveau point d'arrêt. *
+* Description : Indique l'adresse du point d'arrêt dans la mémoire ciblée. *
* *
-* Retour : Point d'arrêt mis en place ou NULL en cas d'échec. *
+* Retour : Adresse associée au point d'arrêt. *
* *
* Remarques : - *
* *
******************************************************************************/
-GBreakPoint *g_break_point_new(vmpa_t address)
+virt_t get_raw_breakpoint_addr(const raw_breakpoint *bp)
{
- GBreakPoint *result; /* Adresse à retourner */
-
- result = g_object_new(G_TYPE_BREAK_POINT, NULL);
-
- result->address = address;
-
- return result;
+ return bp->addr;
}
+
/******************************************************************************
* *
-* Paramètres : point = instance à consulter. *
+* Paramètres : bp = point d'arrêt à consulter. *
* *
-* Description : Fournit l'adresse associée à un point d'arrêt. *
+* Description : Fournit l'adresse d'origine d'un point d'arrêt de pas à pas. *
* *
-* Retour : Adresse associée. *
+* Retour : - *
* *
-* Remarques : - *
+* Remarques : Un appel à cette fonction n'est valide que pour un point *
+* d'arrêt de type RBO_STEP. *
* *
******************************************************************************/
-vmpa_t g_break_point_get_address(const GBreakPoint *point)
+virt_t get_raw_breakpoint_prev_addr(const raw_breakpoint *bp)
{
- return point->address;
+ virt_t result; /* Localisation à retourner */
+ bool found; /* Valide une obtention */
+ size_t i; /* Boucle de parcours */
-}
+ switch (bp->count)
+ {
+ case 1:
+ assert(bp->source.origin == RBO_INTERNAL || bp->source.origin == RBO_STEP);
+ result = bp->source.previous;
+ break;
+ default:
+ found = false;
-/* ---------------------------------------------------------------------------------- */
-/* GROUPE DE POINTS D'ARRET */
-/* ---------------------------------------------------------------------------------- */
+ for (i = 0; i < bp->count && !found; i++)
+ if (bp->sources[i].origin == RBO_INTERNAL || bp->sources[i].origin == RBO_STEP)
+ {
+ result = bp->sources[i].previous;
+ found = true;
+ }
+ assert(found);
-/* Indique le type défini pour les groupes de points d'errêt. */
-G_DEFINE_TYPE(GBreakGroup, g_break_group, G_TYPE_OBJECT);
+ break;
+ }
-/******************************************************************************
-* *
-* Paramètres : klass = classe à initialiser. *
-* *
-* Description : Initialise la classe des groupes de points d'arrêt. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_break_group_class_init(GBreakGroupClass *klass)
-{
- g_signal_new("added",
- G_TYPE_BREAK_GROUP,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GBreakGroupClass, added),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, G_TYPE_BREAK_POINT);
-
- g_signal_new("removed",
- G_TYPE_BREAK_GROUP,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GBreakGroupClass, removed),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, G_TYPE_BREAK_POINT);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : group = instance à initialiser. *
+* Paramètres : addr = adresse à consulter. *
+* bp = point d'arrêt à consulter. *
* *
-* Description : Initialise un groupe de point d'arrêt. *
+* Description : Effectue une comparaison entre adresse et point d'arrêt. *
* *
-* Retour : - *
+* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_break_group_init(GBreakGroup *group)
+int compare_raw_breakpoint_with_addr(const virt_t *addr, const raw_breakpoint **bp)
{
+ int result; /* Bilan à retourner */
+
+ if (*addr < (*bp)->addr)
+ result = -1;
+
+ else if (*addr == (*bp)->addr)
+ result = 0;
+
+ else
+ result = 1;
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : - *
+* Paramètres : a = premier point d'arrêt à consulter. *
+* b = second point d'arrêt à consulter. *
* *
-* Description : Construit un nouveau groupe de points d'arrêt. *
+* Description : Effectue une comparaison entre deux points d'arrêt. *
* *
-* Retour : Groupe de points d'arrêt mis en place ou NULL en cas d'échec.*
+* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
-GBreakGroup *g_break_group_new(void)
+int compare_raw_breakpoints(const raw_breakpoint **a, const raw_breakpoint **b)
{
- GBreakGroup *result; /* Adresse à retourner */
+ int result; /* Bilan à retourner */
- result = g_object_new(G_TYPE_BREAK_GROUP, NULL);
+ result = compare_raw_breakpoint_with_addr(&(*a)->addr, b);
return result;
@@ -301,140 +201,263 @@ GBreakGroup *g_break_group_new(void)
/******************************************************************************
* *
-* Paramètres : group = groupe de points d'arrêt à consulter. *
+* Paramètres : bp = point d'arrêt à manipuler. *
+* origin = origine de la création du point d'arrêt. *
+* tid = identifiant du thread concerné. *
+* previous = éventuelle adresse précédent celle du point. *
* *
-* Description : Fournit la désignation humaine associée à un groupe. *
+* Description : Enregistre la source d'un point d'arrêt posé. *
* *
-* Retour : Désignation humaine associée, jamais NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *g_break_group_get_name(const GBreakGroup *group)
+void set_raw_breakpoint_origin(raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid, virt_t previous)
{
- return group->name;
+#ifndef NDEBUG
+ size_t i; /* Boucle de parcours */
+#endif
+ bp_source *src; /* Source à définir */
+ bp_source tmp; /* Copie temporaire */
+
+#ifndef NDEBUG
+
+ if (bp->count == 1)
+ assert(bp->source.tid != tid || (bp->source.origin & origin) == 0);
+
+ else
+ for (i = 0; i < bp->count; i++)
+ if (bp->source.tid == tid)
+ {
+ assert((bp->sources[i].origin & origin) == 0);
+ break;
+ }
+
+#endif
+
+ bp->count++;
+
+ switch (bp->count)
+ {
+ case 1:
+ src = &bp->source;
+ break;
+
+ case 2:
+ tmp = bp->source;
+ bp->sources = (bp_source *)calloc(2, sizeof(bp_source));
+ bp->sources[0] = tmp;
+ src = &bp->sources[1];
+ break;
+
+ default:
+ bp->sources = (bp_source *)realloc(bp->sources, bp->count * sizeof(bp_source));
+ src = &bp->sources[bp->count - 1];
+ break;
+
+ }
+
+ src->origin = origin;
+ src->tid = tid;
+ src->previous = previous;
}
/******************************************************************************
* *
-* Paramètres : group = groupe de points d'arrêt à modifier. *
-* name = nouveau nom de scène. *
+* Paramètres : bp = point d'arrêt à manipuler. *
+* origin = origine de la création du point d'arrêt. *
+* tid = identifiant du thread concerné. *
+* previous = éventuelle adresse précédent celle du point. *
* *
-* Description : Définit la désignation humaine à associer à un groupe. *
+* Description : Oublie la source d'un point d'arrêt posé. *
* *
-* Retour : Désignation humaine associée, voire NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_break_group_set_name(GBreakGroup *group, const char *name)
+void unset_raw_breakpoint_origin(raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid)
{
- if (group->name != NULL)
- free(group->name);
+ size_t i; /* Boucle de parcours #1 */
+ bp_source tmp; /* Copie temporaire */
+#ifndef NDEBUG
+ size_t j; /* Boucle de parcours #2 */
+#endif
- if (name == NULL)
- group->name = NULL;
+ bool has_same_origin(bp_source *src)
+ {
+ bool result;
- else
- group->name = strdup(name);
+ result = (src->origin == origin && src->tid == tid);
+
+ return result;
+
+ }
+
+ switch (bp->count)
+ {
+ case 1:
+
+ if (has_same_origin(&bp->source))
+ bp->count = 0;
+
+ break;
+
+ case 2:
+
+ if (has_same_origin(&bp->sources[0]))
+ {
+ assert(!has_same_origin(&bp->sources[1]));
+
+ tmp = bp->sources[1];
+
+ bp->count = 1;
+ free(bp->sources);
+
+ bp->source = tmp;
+
+ }
+
+ else if (has_same_origin(&bp->sources[1]))
+ {
+ assert(!has_same_origin(&bp->sources[0]));
+
+ tmp = bp->sources[0];
+
+ bp->count = 1;
+ free(bp->sources);
+
+ bp->source = tmp;
+
+ }
+
+ break;
+
+ default:
+
+ for (i = 0; i < bp->count; i++)
+ {
+ if (has_same_origin(&bp->sources[i]))
+ {
+ if ((i + 1) < bp->count)
+ memmove(&bp->sources[i], &bp->sources[i + 1], (bp->count - i - 1) * sizeof(bp_source));
+
+ bp->sources = (bp_source *)realloc(bp->sources, --bp->count * sizeof(bp_source));
+
+#ifndef NDEBUG
+ for (j = i; j < bp->count; j++)
+ assert(!has_same_origin(&bp->sources[j]));
+#endif
+
+ break;
+
+ }
+
+ }
+
+ break;
+
+ }
}
/******************************************************************************
* *
-* Paramètres : group = groupe de points d'arrêt à consulter. *
-* addr = adresse recherchée dans les points d'arrêt. *
+* Paramètres : bp = point d'arrêt à manipuler. *
+* origin = origine de la création du point d'arrêt. *
+* tid = identifiant du thread concerné. *
* *
-* Description : Indique si une adresse donnée est gérée dans un groupe. *
+* Description : Indique si le point d'arrêt correspond à une source donnée. *
* *
-* Retour : true si l'adresse est gérée ici, false sinon. *
+* Retour : Bilan de l'analyse. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_break_group_has_address(const GBreakGroup *group, vmpa_t addr)
+bool has_raw_breakpoint_origin(const raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid)
{
- GBreakPoint *iter; /* Boucle de parcours */
+ bool result; /* Conclusion à retourner */
+ size_t i; /* Boucle de parcours */
+
+ if (bp->count == 1)
+ result = (bp->source.tid == tid && (bp->source.origin & origin) != 0);
+
+ else
+ {
+ result = false;
+
+ for (i = 0; i < bp->count && !result; i++)
+ result = (bp->sources[i].tid == tid && (bp->sources[i].origin & origin) != 0);
- bp_list_for_each(iter, group->points)
- if (g_break_point_get_address(iter) == addr)
- return true;
+ }
- return false;
+ return result;
}
/******************************************************************************
* *
-* Paramètres : group = groupe de points d'arrêt à modifier. *
-* addr = adresse mémoire à faire basculer. *
+* Paramètres : bp = point d'arrêt à manipuler. *
+* origin = origine de la création du point d'arrêt. *
+* tid = identifiant du thread concerné. *
+* prev = adresse d'instruction qui a conduit à des poses. *
* *
-* Description : Ajoute ou supprime un point d'arrêt dans un groupe. *
+* Description : Indique si le point d'arrêt correspond à une origine donnée. *
* *
-* Retour : - *
+* Retour : Bilan de l'analyse. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_break_group_toggle_breakpoint(GBreakGroup *group, vmpa_t addr)
+bool has_raw_breakpoint_previous_address(const raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid, virt_t prev)
{
- GBreakPoint *iter; /* Boucle de parcours */
- GBreakPoint *next; /* Prochain point de passage */
+ bool result; /* Conclusion à retourner */
+ size_t i; /* Boucle de parcours */
- /* Suppression d'un éventuel existant */
+ if (bp->count == 1)
+ result = (bp->source.tid == tid && (bp->source.origin & origin) != 0 && bp->source.previous == prev);
- bp_list_for_each_safe(iter, &group->points, next)
- if (g_break_point_get_address(iter) == addr)
- {
- g_signal_emit_by_name(group, "removed", iter);
-
- bp_list_del(iter, &group->points);
- g_object_unref(G_OBJECT(iter));
-
- return;
-
- }
-
- /* Si non trouvé, ajout du nouveau point */
+ else
+ {
+ result = false;
- iter = g_break_point_new(addr);
+ for (i = 0; i < bp->count && !result; i++)
+ result = (bp->sources[i].tid == tid && (bp->sources[i].origin & origin) != 0 && bp->sources[i].previous == prev);
- bp_list_add_tail(iter, &group->points);
+ }
- g_signal_emit_by_name(group, "added", iter);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : group = groupe de points d'arrêt à parcourir. *
-* func = fonction à appeler à chaque point trouvé. *
-* data = éventuelle donnée de l'utilisateur à joindre. *
+* Paramètres : bp = point d'arrêt à consulter. *
* *
-* Description : Parcourt l'ensemble des points d'arrêt d'un groupe donné. *
+* Description : Indique si un point d'arrêt a encore une utilité. *
* *
-* Retour : - *
+* Retour : true si le point peut être retiré, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_break_group_for_each(GBreakGroup *group, GExtFunc func, gpointer data)
+bool is_breakpoint_useless(const raw_breakpoint *bp)
{
- GBreakPoint *iter; /* Boucle de parcours */
+ bool result; /* Conclusion à faire remonter */
- /* Suppression d'un éventuel existant */
+ result = (bp->count == 0);
- bp_list_for_each(iter, group->points)
- func(group, iter, data);
+ return result;
}
diff --git a/src/debug/break.h b/src/debug/break.h
index 5946ad2..77d959a 100644
--- a/src/debug/break.h
+++ b/src/debug/break.h
@@ -25,80 +25,58 @@
#define _DEBUG_BREAK_H
-#include <glib-object.h>
-#include <stdbool.h>
+#include "misc.h"
+#include "../arch/vmpa.h"
-#include "../arch/archbase.h"
-#include "../glibext/proto.h"
+/* Origine des points d'arrêt en place */
+typedef enum _RawBpOrigin
+{
+ RBO_INVALID = (0 << 0), /* Existance illégale */
+ RBO_USER = (1 << 0), /* Point d'arrêt utilisateur */
+ //RBO_COMPUTED = (1 << 1), /* Arrêt sur un point spécial */
+ RBO_INTERNAL = (1 << 2), /* Restauration transparente */
+ RBO_STEP = (1 << 3), /* Mise en place éphémère */
+ RBO_COUNT
-/* --------------------------- GESTION DES POINTS D'ARRET --------------------------- */
+} RawBpOrigin;
-#define G_TYPE_BREAK_POINT g_break_point_get_type()
-#define G_BREAK_POINT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_break_point_get_type(), GBreakPoint))
-#define G_IS_BREAK_POINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_break_point_get_type()))
-#define G_BREAK_POINT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_break_point_get_type(), GBreakPointIface))
-#define G_BREAK_POINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BREAK_POINT, GBreakPointClass))
+/* Définition d'un point d'arrêt appliqué */
+typedef struct _raw_breakpoint raw_breakpoint;
-/* Propriétés d'un point d'arrêt (instance) */
-typedef struct _GBreakPoint GBreakPoint;
+/* Libère le coeur d'un point d'arrêt. */
+void fini_raw_breakpoint(raw_breakpoint *);
-/* Propriétés d'un point d'arrêt (classe) */
-typedef struct _GBreakPointClass GBreakPointClass;
+/* Indique l'adresse du point d'arrêt dans la mémoire ciblée. */
+virt_t get_raw_breakpoint_addr(const raw_breakpoint *);
+/* Fournit l'adresse d'origine d'un point d'arrêt de pas à pas. */
+virt_t get_raw_breakpoint_prev_addr(const raw_breakpoint *);
-/* Indique le type défini pour des propriétés d'un point d'arrêt. */
-GType g_break_point_get_type(void);
+/* Effectue une comparaison entre adresse et point d'arrêt. */
+int compare_raw_breakpoint_with_addr(const virt_t *, const raw_breakpoint **);
-/* Construit un nouveau point d'arrêt. */
-GBreakPoint *g_break_point_new(vmpa_t);
+/* Effectue une comparaison entre deux points d'arrêt. */
+int compare_raw_breakpoints(const raw_breakpoint **, const raw_breakpoint **);
-/* Fournit l'adresse associée à un point d'arrêt. */
-vmpa_t g_break_point_get_address(const GBreakPoint *);
+/* Enregistre la source d'un point d'arrêt posé. */
+void set_raw_breakpoint_origin(raw_breakpoint *, RawBpOrigin, dbg_thread_id_t, virt_t);
+/* Oublie la source d'un point d'arrêt posé. */
+void unset_raw_breakpoint_origin(raw_breakpoint *, RawBpOrigin, dbg_thread_id_t);
+/* Indique si le point d'arrêt correspond à une source donnée. */
+bool has_raw_breakpoint_origin(const raw_breakpoint *, RawBpOrigin, dbg_thread_id_t);
-/* ---------------------------- GROUPE DE POINTS D'ARRET ---------------------------- */
+/* Indique si le point d'arrêt correspond à une origine donnée. */
+bool has_raw_breakpoint_previous_address(const raw_breakpoint *, RawBpOrigin, dbg_thread_id_t, virt_t);
-
-#define G_TYPE_BREAK_GROUP g_break_group_get_type()
-#define G_BREAK_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_break_group_get_type(), GBreakGroup))
-#define G_IS_BREAK_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_break_group_get_type()))
-#define G_BREAK_GROUP_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_break_group_get_type(), GBreakGroupIface))
-#define G_BREAK_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BREAK_GROUP, GBreakGroupClass))
-
-
-/* Propriétés d'un groupe de points d'arrêt (instance) */
-typedef struct _GBreakGroup GBreakGroup;
-
-/* Propriétés d'un groupe de points d'arrêt (classe) */
-typedef struct _GBreakGroupClass GBreakGroupClass;
-
-
-/* Indique le type défini pour les groupes de points d'errêt. */
-GType g_break_group_get_type(void);
-
-/* Construit un nouveau groupe de points d'arrêt. */
-GBreakGroup *g_break_group_new(void);
-
-/* Fournit la désignation humaine associée à un groupe. */
-const char *g_break_group_get_name(const GBreakGroup *);
-
-/* Définit la désignation humaine à associer à un groupe. */
-void g_break_group_set_name(GBreakGroup *, const char *);
-
-/* Indique si une adresse donnée est gérée dans un groupe. */
-bool g_break_group_has_address(const GBreakGroup *, vmpa_t);
-
-/* Ajoute ou supprime un point d'arrêt dans un groupe. */
-void g_break_group_toggle_breakpoint(GBreakGroup *, vmpa_t);
-
-/* Parcourt l'ensemble des points d'arrêt d'un groupe donné. */
-void g_break_group_for_each(GBreakGroup *, GExtFunc, gpointer);
+/* Indique si un point d'arrêt a encore une utilité. */
+bool is_breakpoint_useless(const raw_breakpoint *);
diff --git a/src/debug/debugger-int.h b/src/debug/debugger-int.h
index 06aa5d3..58153b8 100644
--- a/src/debug/debugger-int.h
+++ b/src/debug/debugger-int.h
@@ -28,7 +28,15 @@
#include "debugger.h"
-#include <gtk/gtk.h>
+#include "break.h"
+
+
+
+//#include <gtk/gtk.h>////////////////////////////////////////////
+
+
+
+
@@ -39,16 +47,71 @@ typedef bool (* attach_debugger_fc) (GBinaryDebugger *);
typedef bool (* basic_debugger_fc) (GBinaryDebugger *);
/* Reprend une procédure de débogage. */
-typedef bool (* resume_debugger_fc) (GBinaryDebugger *);
+//typedef bool (* resume_debugger_fc) (GBinaryDebugger *);
/* Fournit les identifiants de tous les threads actifs. */
-typedef pid_t * (* dbg_list_all_threads_fc) (GBinaryDebugger *, char ***, size_t *);
+//typedef pid_t * (* dbg_list_all_threads_fc) (GBinaryDebugger *, char ***, size_t *);
/* Fournit la liste des frames courantes d'un thread donné. */
-typedef dbg_frame_t * (* dbg_get_frames_stack_fc) (GBinaryDebugger *, pid_t, size_t *);
+//typedef dbg_frame_t * (* dbg_get_frames_stack_fc) (GBinaryDebugger *, pid_t, size_t *);
/* Fournit la valeur des registres de l'architecture. */
-typedef register_value * (* get_register_values_fc) (GBinaryDebugger *, size_t *);
+//typedef register_value * (* get_register_values_fc) (GBinaryDebugger *, size_t *);
+
+
+
+
+
+
+/* Fournit les identifiants de tous les threads actifs. */
+typedef dbg_thread_desc * (* list_all_threads_fc) (GBinaryDebugger *, size_t *);
+
+
+
+
+/* Lit une valeur quelconque à une adresse arbitraire. */
+typedef bool (* read_mem_any_fc) (GBinaryDebugger *, virt_t, size_t, ...);
+
+/* Ecrit une valeur quelconque à une adresse arbitraire. */
+typedef bool (* write_mem_any_fc) (GBinaryDebugger *, virt_t, size_t, ...);
+
+/* Liste l'ensemble des registres appartenant à un groupe. */
+typedef char ** (* get_reg_names_fc) (const GBinaryDebugger *, const char *, size_t *);
+
+/* Indique la taille associée à un registre donné. */
+typedef unsigned int (* get_reg_size_fc) (const GBinaryDebugger *, const char *);
+
+/* Lit une valeur quelconque à partir d'un registre. */
+typedef bool (* read_write_reg_any_fc) (GBinaryDebugger *, const char *, size_t, ...);
+
+
+
+/* Détermine le point d'exécution courant. */
+typedef bool (* get_current_pc_fc) (GBinaryDebugger *, virt_t *);
+
+/* Remonte la pile d'appels jusqu'au point courant. */
+typedef bool (* get_call_stack_fc) (GBinaryDebugger *, virt_t **, size_t *);
+
+
+
+/* Ajoute un point d'arrêt basique en mémoire. */
+typedef raw_breakpoint * (* enable_mem_bp_fc) (GBinaryDebugger *, virt_t);
+
+/* Retire un point d'arrêt basique en mémoire. */
+typedef bool (* disable_mem_bp_fc) (GBinaryDebugger *, raw_breakpoint *);
+
+/* Redémarre le processus de débogage lié à un serveur GDB. */
+typedef bool (* restart_debugger_fc) (GBinaryDebugger *);
+
+/* Remet en marche le débogueur courant. */
+typedef bool (* resume_debugger_fc) (GBinaryDebugger *);
+
+
+
+
+
+
+
/* Définition des fonctionnalités d'un débogueur (instance) */
@@ -62,13 +125,13 @@ struct _GBinaryDebugger
basic_debugger_fc run; /* Démarre le débogueur */
basic_debugger_fc pause; /* Met en pause le débogueur */
- resume_debugger_fc resume; /* Relance le débogueur */
basic_debugger_fc kill; /* Tue le débogueur */
- dbg_list_all_threads_fc all_threads; /* Liste des threads actifs */
- dbg_get_frames_stack_fc frames_stack; /* Pile des frames courantes */
- get_register_values_fc get_reg_values; /* Obtient les valeurs de reg. */
+
+ raw_breakpoint **bpoints; /* Points d'arrêt posés */
+ size_t bp_count; /* Quantité de ces points posés*/
+ GRWLock bp_lock; /* Verrou d'accès à la liste */
};
@@ -78,13 +141,58 @@ struct _GBinaryDebuggerClass
{
GObjectClass parent; /* A laisser en premier */
+ list_all_threads_fc all_threads; /* Liste des threads actifs */
+
+ read_mem_any_fc read_mem; /* Lecture d'une valeur XX bits*/
+ read_mem_any_fc write_mem; /* Ecriture d'une valeur X bits*/
+ get_reg_names_fc get_reg_names; /* Liste des registres */
+ get_reg_size_fc get_reg_size; /* Taille d'un registre donné */
+ read_write_reg_any_fc read_reg; /* Lecture de registre XX bits */
+ read_write_reg_any_fc write_reg; /* Ecriture de registre XX bits*/
+
+ get_current_pc_fc get_current_pc; /* Obtention du point d'exéc. */
+ get_call_stack_fc get_call_stack; /* Obtention de pile d'appels */
+
+ enable_mem_bp_fc enable_bp; /* Mise en place d'un arrêt */
+ disable_mem_bp_fc disable_bp; /* Retrait d'un point d'arrêt */
+
+ restart_debugger_fc restart; /* Redémarre le débogueur */
+ resume_debugger_fc resume; /* Relance le débogueur */
+
/* Signaux */
- void (* debugger_stopped) (GBinaryDebugger *, uint64_t, uint64_t);
+ void (* signaled) (GBinaryDebugger *, int);
+ void (* exited) (GBinaryDebugger *, int, pid_t);
+ void (* terminated) (GBinaryDebugger *, int, pid_t);
+
+ void (* stopped) (GBinaryDebugger *, virt_t);
+
+
+
+
+ /* Signaux */
void (* debugger_halted) (GBinaryDebugger *, int, vmpa_t, pid_t);
+
+
+
+
+ void (* mem_bp_handled) (GBinaryDebugger *, bool, virt_t);
+
};
+
+/* ------------------------- MANIPULATION DE L'ETAT COURANT ------------------------- */
+
+
+/* Réagit à un arrêt du flot d'exécution. */
+void on_binary_debugger_stopped(GBinaryDebugger *, virt_t);
+
+/* Réagit à la fin de l'opération de débogage. */
+void on_binary_debugger_finished(GBinaryDebugger *, pid_t);
+
+
+
#endif /* _DEBUG_DEBUGGER_INT_H */
diff --git a/src/debug/debugger.c b/src/debug/debugger.c
index 331adc6..0dfe315 100644
--- a/src/debug/debugger.c
+++ b/src/debug/debugger.c
@@ -23,27 +23,70 @@
#include "debugger.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+
+#include <i18n.h>
+
+
#include "debugger-int.h"
-#include "jdwp/debugger.h"
-#include "remgdb/gdb.h"
+#include "../common/sort.h"
#include "../glibext/chrysamarshal.h"
+#include "../gui/panels/log.h"
#include "../plugins/pglist.h"
+/* ---------------------------- TRONC COMMUN DE DEBOGAGE ---------------------------- */
+
+
/* Initialise la classe de base des débogueurs. */
static void g_binary_debugger_class_init(GBinaryDebuggerClass *);
/* Initialise une instance de base d'un débogueur. */
static void g_binary_debugger_init(GBinaryDebugger *);
+/* Supprime toutes les références externes. */
+static void g_binary_debugger_dispose(GBinaryDebugger *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_binary_debugger_finalize(GBinaryDebugger *);
+
+
+
+/* --------------------------- GESTION DES POINTS D'ARRET --------------------------- */
+
+
+/* Active un point d'arrêt à un emplacement de mémoire donné. */
+static bool g_binary_debugger_insert_memory_breakpoint(GBinaryDebugger *, virt_t, RawBpOrigin, dbg_thread_id_t, virt_t);
+
+/* Désactive un point d'arrêt à un emplacement de mémoire donné. */
+static bool g_binary_debugger_remove_memory_breakpoint(GBinaryDebugger *, virt_t);
+
+/* Sème des points d'arrêt sur les instructions suivantes. */
+static bool g_binary_debugger_spread_breakpoints(GBinaryDebugger *, dbg_thread_id_t, virt_t, RawBpOrigin, bool);
+
+/* Retire tous les points d'arrêt issus d'un adresse. */
+static void g_binary_debugger_remove_same_breakpoints(GBinaryDebugger *, dbg_thread_id_t, virt_t, RawBpOrigin);
+
+/* Met à jour les points d'arrêt suite à un arrêt. */
+static bool g_binary_debugger_update_breakpoints_on_stop(GBinaryDebugger *, dbg_thread_id_t, virt_t);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* TRONC COMMUN DE DEBOGAGE */
+/* ---------------------------------------------------------------------------------- */
/* Indique le type définit pour une ligne de représentation. */
G_DEFINE_TYPE(GBinaryDebugger, g_binary_debugger, G_TYPE_OBJECT);
-
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
@@ -58,13 +101,46 @@ G_DEFINE_TYPE(GBinaryDebugger, g_binary_debugger, G_TYPE_OBJECT);
static void g_binary_debugger_class_init(GBinaryDebuggerClass *klass)
{
- g_signal_new("debugger-stopped",
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_debugger_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_binary_debugger_finalize;
+
+ g_signal_new("signaled",
+ G_TYPE_BINARY_DEBUGGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GBinaryDebuggerClass, signaled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+
+ g_signal_new("exited",
G_TYPE_BINARY_DEBUGGER,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GBinaryDebuggerClass, debugger_stopped),
+ G_STRUCT_OFFSET(GBinaryDebuggerClass, exited),
NULL, NULL,
- g_cclosure_user_marshal_VOID__UINT64_UINT64,
- G_TYPE_NONE, 2, G_TYPE_UINT64, G_TYPE_UINT64);
+ g_cclosure_user_marshal_VOID__INT_INT,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+
+ g_signal_new("terminated",
+ G_TYPE_BINARY_DEBUGGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GBinaryDebuggerClass, terminated),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__INT_INT,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+
+ g_signal_new("stopped",
+ G_TYPE_BINARY_DEBUGGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GBinaryDebuggerClass, stopped),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__UINT64,
+ G_TYPE_NONE, 1, G_TYPE_UINT64);
+
+
g_signal_new("halted",
G_TYPE_BINARY_DEBUGGER,
@@ -74,6 +150,18 @@ static void g_binary_debugger_class_init(GBinaryDebuggerClass *klass)
g_cclosure_user_marshal_VOID__INT_UINT64_INT,
G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT64, G_TYPE_INT);
+
+
+
+
+ g_signal_new("mem-bp-handled",
+ G_TYPE_BINARY_DEBUGGER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GBinaryDebuggerClass, mem_bp_handled),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__INT_UINT64_INT,
+ G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT64);
+
}
@@ -91,51 +179,64 @@ static void g_binary_debugger_class_init(GBinaryDebuggerClass *klass)
static void g_binary_debugger_init(GBinaryDebugger *debugger)
{
+ g_rw_lock_init(&debugger->bp_lock);
}
/******************************************************************************
* *
-* Paramètres : type = type de débigueur choisi pour l'opération. *
-* binary = binaire devant être débogué. *
+* Paramètres : debugger = instance d'objet GLib à traiter. *
* *
-* Description : Crée un nouveau débogueur. *
+* Description : Supprime toutes les références externes. *
* *
-* Retour : Composant GObject mis en place ou NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GBinaryDebugger *g_new_binary_debugger(DebuggerType type, GLoadedBinary *binary)
+static void g_binary_debugger_dispose(GBinaryDebugger *debugger)
{
- GBinaryDebugger *result;
+ g_object_unref(G_OBJECT(debugger->binary));
- switch (type)
- {
- case DGT_JDWP:
- result = g_java_debugger_new(binary, NULL);
- break;
+ g_rw_lock_clear(&debugger->bp_lock);
- case DGT_REMOTE_GDB:
- result = g_gdb_debugger_new(binary, NULL);
- break;
+ G_OBJECT_CLASS(g_binary_debugger_parent_class)->dispose(G_OBJECT(debugger));
- default:
- result = NULL;
- break;
+}
- }
- if (result != NULL)
- result->binary = binary;
+/******************************************************************************
+* *
+* Paramètres : debugger = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- return result;
+static void g_binary_debugger_finalize(GBinaryDebugger *debugger)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < debugger->bp_count; i++)
+ fini_raw_breakpoint(debugger->bpoints[i]);
+
+ if (debugger->bpoints != NULL)
+ free(debugger->bpoints);
+
+ G_OBJECT_CLASS(g_binary_debugger_parent_class)->finalize(G_OBJECT(debugger));
}
+
+
+
/******************************************************************************
* *
* Paramètres : debugger = débogueur à manipuler ici. *
@@ -196,11 +297,13 @@ void g_binary_debugger_run(GBinaryDebugger *debugger)
}
+
+
/******************************************************************************
* *
* Paramètres : debugger = débogueur à manipuler ici. *
* *
-* Description : Reprend une procédure de débogage. *
+* Description : Tue une procédure de débogage. *
* *
* Retour : - *
* *
@@ -208,18 +311,37 @@ void g_binary_debugger_run(GBinaryDebugger *debugger)
* *
******************************************************************************/
-void g_binary_debugger_resume(GBinaryDebugger *debugger)
+void g_binary_debugger_kill(GBinaryDebugger *debugger)
{
- debugger->resume(debugger);
+ debugger->kill(debugger);
}
+
+
+
+
+
+
+
+
+
+/* ------------------- MANIPULATION DES DIFFERENTS THREADS ACTIFS ------------------- */
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DES DIFFERENTS THREADS ACTIFS */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : debugger = débogueur à manipuler ici. *
+* Paramètres : list = descriptions à supprimer de la mémoire. *
+* count = taille de cette liste. *
* *
-* Description : Tue une procédure de débogage. *
+* Description : Libère la mémoire d'une liste de threads actifs. *
* *
* Retour : - *
* *
@@ -227,9 +349,15 @@ void g_binary_debugger_resume(GBinaryDebugger *debugger)
* *
******************************************************************************/
-void g_binary_debugger_kill(GBinaryDebugger *debugger)
+void delete_dbg_thread_desc(dbg_thread_desc *list, size_t count)
{
- debugger->kill(debugger);
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < count; i++)
+ free(list[i].name);
+
+ if (list != NULL)
+ free(list);
}
@@ -242,52 +370,932 @@ void g_binary_debugger_kill(GBinaryDebugger *debugger)
* *
* Description : Fournit les identifiants de tous les threads actifs. *
* *
-* Retour : Liste des threads décomptés. *
+* Retour : Liste des threads décomptés, à libérer de la mémoire ensuite.*
* *
* Remarques : - *
* *
******************************************************************************/
-pid_t *g_binary_debugger_list_all_threads(GBinaryDebugger *debugger, char ***names, size_t *count)
+dbg_thread_desc *g_binary_debugger_list_all_threads(GBinaryDebugger *debugger, size_t *count)
{
- pid_t *result; /* Liste à retourner */
+ dbg_thread_desc *result; /* Liste à retourner */
- if (debugger->all_threads != NULL)
- result = debugger->all_threads(debugger, names, count);
- else
- result = NULL;
+ *count = 0;
+
+ result = G_BINARY_DEBUGGER_GET_CLASS(debugger)->all_threads(debugger, count);
+
+ if (result != NULL)
+ {
+ int cmp_dbg_thread_desc(const dbg_thread_desc *a, const dbg_thread_desc *b)
+ {
+ int status; /* Bilan à retourner */
+
+ if (a->id < b->id)
+ status = -1;
+
+ if (a->id > b->id)
+ status = 1;
+
+ else
+ status = -1;
+
+ return status;
+
+ }
+
+ qsort(result, *count, sizeof(dbg_thread_desc), (__compar_fn_t)cmp_dbg_thread_desc);
+
+ }
return result;
}
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ENTREES / SORTIES BASIQUES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : debugger = instance du module de débogage chargé. *
-* thread = thread concerné par l'analyse. *
-* count = nombre de frames en place. [OUT] *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 8 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_memory_u8(GBinaryDebugger *debugger, virt_t addr, uint8_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_mem(debugger, addr, 8, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 16 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_memory_u16(GBinaryDebugger *debugger, virt_t addr, uint16_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_mem(debugger, addr, 16, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 32 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_memory_u32(GBinaryDebugger *debugger, virt_t addr, uint32_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_mem(debugger, addr, 32, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 64 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_memory_u64(GBinaryDebugger *debugger, virt_t addr, uint64_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_mem(debugger, addr, 64, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* len = taille attendue de la valeur en octets. *
+* *
+* Description : Lit une valeur de taille quelconque à une adresse arbitraire.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_memory_data(GBinaryDebugger *debugger, virt_t addr, uint8_t *value, size_t len)
+{
+ bool result; /* Bilan à retourner */
+ size_t iter; /* Tête de lecture / écriture */
+ size_t remaining; /* Quantité restant à replacer */
+
+ result = true;
+
+ iter = 0;
+ remaining = len;
+
+ while (result && remaining > 0)
+ {
+ if (remaining >= 8)
+ {
+ result = g_binary_debugger_read_memory_u64(debugger, addr + iter, (uint64_t *)&value[iter]);
+
+ iter += 8;
+ remaining -= 8;
+
+ }
+
+ else if (remaining >= 4)
+ {
+ result = g_binary_debugger_read_memory_u32(debugger, addr + iter, (uint32_t *)(&value[iter]));
+
+ iter += 4;
+ remaining -= 4;
+
+ }
+
+ else if (remaining >= 2)
+ {
+ result = g_binary_debugger_read_memory_u16(debugger, addr + iter, (uint16_t *)&value[iter]);
+
+ iter += 2;
+ remaining -= 2;
+
+ }
+
+ else if (remaining >= 1)
+ {
+ result = g_binary_debugger_read_memory_u8(debugger, addr + iter, (uint8_t *)&value[iter]);
+
+ iter += 1;
+ remaining -= 1;
+
+ }
+
+ else
+ assert(false);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir modifier. *
+* value = emplacement de la valeur à inscrire. *
+* *
+* Description : Ecrit une valeur de 8 bits à une adresse arbitraire. *
* *
-* Description : Fournit la liste des frames courantes d'un thread donné. *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_memory_u8(GBinaryDebugger *debugger, virt_t addr, const uint8_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_mem(debugger, addr, 8, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir modifier. *
+* value = emplacement de la valeur à inscrire. *
+* *
+* Description : Ecrit une valeur de 16 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_memory_u16(GBinaryDebugger *debugger, virt_t addr, const uint16_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_mem(debugger, addr, 16, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir modifier. *
+* value = emplacement de la valeur à inscrire. *
+* *
+* Description : Ecrit une valeur de 32 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_memory_u32(GBinaryDebugger *debugger, virt_t addr, const uint32_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_mem(debugger, addr, 32, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir modifier. *
+* value = emplacement de la valeur à inscrire. *
+* *
+* Description : Ecrit une valeur de 64 bits à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_memory_u64(GBinaryDebugger *debugger, virt_t addr, const uint64_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_mem(debugger, addr, 64, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* addr = emplacement en mémoire à venir modifier. *
+* value = emplacement de la valeur à incrire. *
+* len = taille de la valeur fournie en octets. *
+* *
+* Description : Ecrit une valeur de taille quelconque à une adresse donnée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_memory_data(GBinaryDebugger *debugger, virt_t addr, const uint8_t *value, size_t len)
+{
+ bool result; /* Bilan à retourner */
+ size_t iter; /* Tête de lecture / écriture */
+ size_t remaining; /* Quantité restant à replacer */
+
+ result = true;
+
+ iter = 0;
+ remaining = len;
+
+ while (result && remaining > 0)
+ {
+ if (remaining >= 8)
+ {
+ result = g_binary_debugger_write_memory_u64(debugger, addr + iter, (uint64_t *)&value[iter]);
+
+ iter += 8;
+ remaining -= 8;
+
+ }
+
+ else if (remaining >= 4)
+ {
+ result = g_binary_debugger_write_memory_u32(debugger, addr + iter, (uint32_t *)&value[iter]);
+
+ iter += 4;
+ remaining -= 4;
+
+ }
+
+ else if (remaining >= 2)
+ {
+ result = g_binary_debugger_write_memory_u16(debugger, addr + iter, (uint16_t *)&value[iter]);
+
+ iter += 2;
+ remaining -= 2;
+
+ }
+
+ else if (remaining >= 1)
+ {
+ result = g_binary_debugger_write_memory_u8(debugger, addr + iter, (uint8_t *)&value[iter]);
+
+ iter += 1;
+ remaining -= 1;
+
+ }
+
+ else
+ assert(false);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* 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_binary_debugger_get_register_names(const GBinaryDebugger *debugger, const char *group, size_t *count)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->get_reg_names(debugger, group, count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* name = désignation du registre visé. *
+* *
+* Description : Indique la taille associée à un registre donné. *
* *
-* Retour : Liste des frames trouvées. *
+* Retour : Taille en bits, ou 0 si le registre n'a pas été trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
-dbg_frame_t *g_binary_debugger_get_frames_stack(GBinaryDebugger *debugger, pid_t thread, size_t *count)
+unsigned int g_binary_debugger_get_register_size(const GBinaryDebugger *debugger, const char *name)
{
- dbg_frame_t *result; /* Liste à retourner */
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->get_reg_size(debugger, name);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 8 bits à partir d'un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_register_u8(GBinaryDebugger *debugger, const char *reg, uint8_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_reg(debugger, reg, 8, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 16 bits à partir d'un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_register_u16(GBinaryDebugger *debugger, const char *reg, uint16_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_reg(debugger, reg, 16, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 32 bits à partir d'un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_register_u32(GBinaryDebugger *debugger, const char *reg, uint32_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_reg(debugger, reg, 32, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur de 64 bits à partir d'un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_read_register_u64(GBinaryDebugger *debugger, const char *reg, uint64_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->read_reg(debugger, reg, 64, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur à écrire. *
+* *
+* Description : Ecrit une valeur de 8 bits dans un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_register_u8(GBinaryDebugger *debugger, const char *reg, const uint8_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_reg(debugger, reg, 8, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur à écrire. *
+* *
+* Description : Ecrit une valeur de 16 bits dans un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_register_u16(GBinaryDebugger *debugger, const char *reg, const uint16_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_reg(debugger, reg, 16, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur à écrire. *
+* *
+* Description : Ecrit une valeur de 32 bits dans un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_register_u32(GBinaryDebugger *debugger, const char *reg, const uint32_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_reg(debugger, reg, 32, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler. *
+* reg = désignation humaine du register à consulter. *
+* value = emplacement de la valeur à écrire. *
+* *
+* Description : Ecrit une valeur de 64 bits dans un registre. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_write_register_u64(GBinaryDebugger *debugger, const char *reg, const uint64_t *value)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->write_reg(debugger, reg, 64, value);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DE L'ETAT COURANT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* pc = adresse de l'instruction courante. [OUT] *
+* *
+* Description : Détermine le point d'exécution courant. *
+* *
+* Retour : Bilan de la récupération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_get_current_pc(GBinaryDebugger *debugger, virt_t *pc)
+{
+ bool result; /* Bilan à retourner */
+
+ result = G_BINARY_DEBUGGER_GET_CLASS(debugger)->get_current_pc(debugger, pc);
+
+ if (!result)
+ log_variadic_message(LMT_WARNING, "Unable to get the current PC!");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* pc = adresse de l'instruction de retour d'appel. [OUT] *
+* *
+* Description : Détermine l'adresse du premier retour d'appel. *
+* *
+* Retour : Bilan de la récupération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_get_return_pc(GBinaryDebugger *debugger, virt_t *pc)
+{
+ bool result; /* Bilan à retourner */
+ virt_t *callstack; /* Pile d'appels courante */
+ size_t size; /* Hauteur de cette pile */
+
+ result = g_binary_debugger_get_call_stack(debugger, &callstack, &size);
+
+ if (result && size > 0)
+ *pc = callstack[size - 1];
+
+ if (callstack != NULL)
+ free(callstack);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* over = indique si les appels doivent être sautés ou non. *
+* count = nombre d'adresses identifiées. *
+* *
+* Description : Détermine les prochaines probables instructions exécutées. *
+* *
+* Retour : Liste d'adresses à libérer de la mémoire après usage. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+virt_t *g_binary_debugger_get_next_pcs(GBinaryDebugger *debugger, virt_t pc, bool over, size_t *count)
+{
+ virt_t *result; /* Liste à retourner */
+ GArchProcessor *proc; /* Processeur lié au binaire */
+ vmpa2t addr; /* Localisation à cibler */
+ instr_iter_t *iter; /* Parcours local d'adresses */
+ GArchInstruction *instr; /* Instruction correspondante */
+ virt_t ret; /* Adresse de retour d'appel */
+ instr_link_t *dests; /* Instr. visées par une autre */
+ size_t dcount; /* Nombre de liens de dest. */
+ size_t i; /* Boucle de parcours */
+ const mrange_t *range; /* Emplacement d'instruction */
+
+ result = NULL;
+ *count = 0;
+
+ proc = g_loaded_binary_get_processor(debugger->binary);
+
+ init_vmpa(&addr, VMPA_NO_PHYSICAL, pc);
+ iter = g_arch_processor_get_iter_from_address(proc, &addr);
+
+ if (iter != NULL)
+ {
+ instr = get_instruction_iterator_current(iter);
+
+ /* Si l'instruction est un retour à l'appelant */
+ if (g_arch_instruction_get_flags(instr) & AIF_RETURN_POINT)
+ {
+ if (g_binary_debugger_get_return_pc(debugger, &ret))
+ {
+ *count = 1;
+ result = (virt_t *)malloc(sizeof(virt_t));
+
+ result[0] = ret;
+
+ }
+
+ }
+
+ /* Sinon on se penche sur ses destinations */
+ else
+ {
+ g_arch_instruction_rlock_dest(instr);
+
+ dcount = g_arch_instruction_get_destinations(instr, &dests);
+
+ for (i = 0; i < dcount; i++)
+ switch (dests[i].type)
+ {
+ case ILT_EXEC_FLOW:
+ case ILT_JUMP:
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
+ case ILT_LOOP:
+
+ (*count)++;
+ result = (virt_t *)realloc(result, *count * sizeof(virt_t));
+
+ range = g_arch_instruction_get_range(dests[i].linked);
+
+ result[*count - 1] = get_virt_addr(get_mrange_addr(range));
+ break;
+
+ case ILT_CALL:
+
+ if (!over)
+ {
+ (*count)++;
+ result = (virt_t *)realloc(result, *count * sizeof(virt_t));
+
+ range = g_arch_instruction_get_range(dests[i].linked);
+
+ result[*count - 1] = get_virt_addr(get_mrange_addr(range));
+
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ g_arch_instruction_runlock_dest(instr);
+
+ /* Si tout ça ne donne rien, on se rabat sur l'instruction suivante par défaut */
+ if (*count == 0)
+ {
+ g_object_unref(G_OBJECT(instr));
+
+ instr = get_instruction_iterator_next(iter);
+
+ if (instr != NULL)
+ {
+ *count = 1;
+ result = (virt_t *)malloc(sizeof(virt_t));
+
+ range = g_arch_instruction_get_range(instr);
+
+ result[0] = get_virt_addr(get_mrange_addr(range));
+
+ }
+
+ }
+
+ }
+
+ if (instr != NULL)
+ g_object_unref(G_OBJECT(instr));
+
+ delete_instruction_iterator(iter);
+
+ }
+
+ g_object_unref(G_OBJECT(proc));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* callstack = pile d'appels reconstituée. [OUT] *
+* size = taille de cette pile. [OUT] *
+* *
+* Description : Remonte la pile d'appels jusqu'au point courant. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_get_call_stack(GBinaryDebugger *debugger, virt_t **callstack, size_t *size)
+{
+ bool result; /* Bilan à retourner */
+
+ *callstack = NULL;
+ *size = 0;
+
+ result = G_BINARY_DEBUGGER_GET_CLASS(debugger)->get_call_stack(debugger, callstack, size);
+
+ if (!result)
+ {
+ if (*callstack != NULL)
+ free(*callstack);
+
+ *callstack = NULL;
+ *size = 0;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* pc = adresse de l'instruction courante. *
+* *
+* Description : Réagit à un arrêt du flot d'exécution. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void on_binary_debugger_stopped(GBinaryDebugger *debugger, virt_t pc)
+{
+ pid_t tid; /* Identifiant du thread */
+ bool auto_resume; /* Poursuite automatique ? */
+
+ tid = 1; // FIXME
+
+ auto_resume = g_binary_debugger_update_breakpoints_on_stop(debugger, tid, pc);
+
+ if (!auto_resume)
+ g_signal_emit_by_name(debugger, "stopped", pc);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* pid = éventuel identifiant de processus concerné ou -1. *
+* *
+* Description : Réagit à la fin de l'opération de débogage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void on_binary_debugger_finished(GBinaryDebugger *debugger, pid_t pid)
+{
+
+ /* TODO : libérer de la mémoire tous les BP */
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION DES POINTS D'ARRET */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* addr = emplacement du point mémoire à traiter. *
+* origin = origine de la création du point d'arrêt. *
+* tid = identifiant du thread concerné. *
+* previous = éventuelle adresse précédent celle du point. *
+* *
+* Description : Active un point d'arrêt à un emplacement de mémoire donné. *
+* *
+* Retour : true si la demande a été prise en compte, false sinon. *
+* *
+* Remarques : L'accès à la liste doit être placée sous la protection de *
+* l'appelant. *
+* *
+******************************************************************************/
+
+static bool g_binary_debugger_insert_memory_breakpoint(GBinaryDebugger *debugger, virt_t addr, RawBpOrigin origin, dbg_thread_id_t tid, virt_t previous)
+{
+ bool result; /* Bilan à retourner */
+ size_t index; /* Indice de ce point d'arrêt */
+ bool found; /* Présence d'un point d'arrêt */
+ raw_breakpoint *bp; /* Point d'arrêt à constituer */
+
+ result = false;
+
+ found = bsearch_index(&addr, debugger->bpoints, debugger->bp_count, sizeof(raw_breakpoint *),
+ (__compar_fn_t)compare_raw_breakpoint_with_addr, &index);
+
+ if (found)
+ {
+ bp = debugger->bpoints[index];
+ result = true;
+ }
- if (debugger->frames_stack != NULL)
- result = debugger->frames_stack(debugger, thread, count);
else
{
- *count = 0;
- result = NULL;
+ bp = G_BINARY_DEBUGGER_GET_CLASS(debugger)->enable_bp(debugger, addr);
+
+ if (bp != NULL)
+ {
+ debugger->bpoints = (raw_breakpoint **)qinsert(debugger->bpoints, &debugger->bp_count,
+ sizeof(raw_breakpoint *),
+ (__compar_fn_t)compare_raw_breakpoints, &bp);
+ result = true;
+ }
+
}
+ if (result)
+ set_raw_breakpoint_origin(bp, origin, tid, previous);
+
return result;
}
@@ -296,18 +1304,445 @@ dbg_frame_t *g_binary_debugger_get_frames_stack(GBinaryDebugger *debugger, pid_t
/******************************************************************************
* *
* Paramètres : debugger = débogueur à manipuler ici. *
-* count = nombre de transmissions effetuées. *
+* index = indice du point à supprimer. *
+* *
+* Description : Désactive un point d'arrêt à un emplacement de mémoire donné.*
+* *
+* Retour : true si la demande a été prise en compte, false sinon. *
* *
-* Description : Fournit la valeur des registres de l'architecture. *
+* Remarques : L'accès à la liste doit être placée sous la protection de *
+* l'appelant. *
* *
-* Retour : Tableau de valeurs transmises à libérer de la mémoire / NULL.*
+******************************************************************************/
+
+static bool g_binary_debugger_remove_memory_breakpoint(GBinaryDebugger *debugger, size_t index)
+{
+ bool result; /* Bilan à retourner */
+ raw_breakpoint *bp; /* Point d'arrêt à manipuler */
+
+ result = false;
+
+ assert(index < debugger->bp_count);
+
+ bp = debugger->bpoints[index];
+
+ result = G_BINARY_DEBUGGER_GET_CLASS(debugger)->disable_bp(debugger, bp);
+
+ if (result)
+ {
+ debugger->bpoints = (raw_breakpoint **)_qdelete(debugger->bpoints, &debugger->bp_count,
+ sizeof(raw_breakpoint *), index);
+
+ fini_raw_breakpoint(bp);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* tid = identifiant du thread concerné. *
+* pc = adresse de l'instruction courante. *
+* type = type de point d'arrêt à insérer. *
+* over = indique si les appels doivent être sautés ou non. *
+* *
+* Description : Sème des points d'arrêt sur les instructions suivantes. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_binary_debugger_spread_breakpoints(GBinaryDebugger *debugger, dbg_thread_id_t tid, virt_t pc, RawBpOrigin type, bool over)
+{
+ bool result; /* Bilan à retourner */
+ virt_t *next_list; /* Liste de points d'arrêts */
+ size_t next_count; /* Taille de cette liste */
+ GArchProcessor *proc; /* Processeur lié au binaire */
+ size_t i; /* Boucle de parcours */
+ vmpa2t addr; /* Format d'adresse complet */
+ GArchInstruction *instr; /* Instruction ciblée */
+ bool valid; /* Point d'arrêt pertinent ? */
+ const char *encoding; /* Encodage de l'instruction */
+
+ result = true;
+
+ next_list = g_binary_debugger_get_next_pcs(debugger, pc, over, &next_count);
+
+ if (next_count == 0)
+ log_variadic_message(LMT_WARNING, "No instruction found to break after 0x%" PRIx64, pc);
+
+ proc = g_loaded_binary_get_processor(debugger->binary);
+
+ /**
+ * Le verrou sur la liste des points est normalement déjà posé.
+ */
+
+ for (i = 0; i < next_count && result; i++)
+ {
+ /**
+ * Des données peuvent suivre du code (typiquement en ARM).
+ * On réalise une validation minimale au préalable donc.
+ */
+
+ init_vmpa(&addr, VMPA_NO_PHYSICAL, next_list[i]);
+ instr = g_arch_processor_find_instr_by_address(proc, &addr);
+
+ if (instr == NULL)
+ valid = false;
+
+ else
+ {
+ encoding = g_arch_instruction_get_encoding(instr);
+
+ valid = strcmp(encoding, _("String")) != 0
+ && strcmp(encoding, _("Raw")) != 0
+ && strcmp(encoding, _("Undefined")) != 0;
+
+ g_object_unref(G_OBJECT(instr));
+
+ }
+
+ if (valid)
+ result = g_binary_debugger_insert_memory_breakpoint(debugger, next_list[i], type, tid, pc);
+
+ }
+
+ if (next_list != NULL)
+ free(next_list);
+
+ g_object_unref(G_OBJECT(proc));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* tid = identifiant du thread concerné. *
+* prev = adresse d'instruction qui a conduit à des poses. *
+* type = type de point d'arrêt à insérer. *
+* *
+* Description : Retire tous les points d'arrêt issus d'un adresse. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_binary_debugger_remove_same_breakpoints(GBinaryDebugger *debugger, dbg_thread_id_t tid, virt_t prev, RawBpOrigin type)
+{
+ size_t i; /* Boucle de parcours */
+ raw_breakpoint *bp; /* Confort de l'accès rapide */
+
+ /**
+ * Le verrou sur la liste des points est normalement déjà posé.
+ */
+
+ for (i = 0; i < debugger->bp_count; i++)
+ {
+ bp = debugger->bpoints[i];
+
+ if (has_raw_breakpoint_previous_address(bp, type, tid, prev))
+ unset_raw_breakpoint_origin(bp, type, tid);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* tid = identifiant du thread concerné. *
+* pc = adresse de l'instruction courante. *
+* *
+* Description : Met à jour les points d'arrêt suite à un arrêt. *
+* *
+* Retour : true si l'exécution a été relancée automatiquement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_binary_debugger_update_breakpoints_on_stop(GBinaryDebugger *debugger, dbg_thread_id_t tid, virt_t pc)
+{
+ bool result; /* Indication à faire remonter */
+ size_t index; /* Indice de ce point d'arrêt */
+ bool found; /* Présence d'un point d'arrêt */
+ raw_breakpoint *bp; /* Confort de l'accès rapide */
+ virt_t previous; /* Adresse d'origine */
+ bool status; /* Bilan d'un retrait */
+ size_t i; /* Boucle de parcours */
+ virt_t addr; /* Localisation d'un point */
+
+ result = false;
+
+ g_rw_lock_writer_lock(&debugger->bp_lock);
+
+ found = bsearch_index(&pc, debugger->bpoints, debugger->bp_count, sizeof(raw_breakpoint *),
+ (__compar_fn_t)compare_raw_breakpoint_with_addr, &index);
+
+ if (found)
+ {
+ bp = debugger->bpoints[index];
+
+ /* S'il s'agissait d'un point d'arrêt à usage interne */
+ if (has_raw_breakpoint_origin(bp, RBO_INTERNAL, tid))
+ {
+ previous = get_raw_breakpoint_prev_addr(bp);
+ assert(previous != VMPA_NO_VIRTUAL);
+
+ g_binary_debugger_remove_same_breakpoints(debugger, tid, previous, RBO_INTERNAL);
+
+ assert(!has_raw_breakpoint_origin(bp, RBO_INTERNAL, tid));
+
+ result = true;
+
+ }
+
+ /* S'il s'agissait d'un arrêt demandé par l'utilisateur */
+ if (has_raw_breakpoint_origin(bp, RBO_USER, tid))
+ {
+ status = G_BINARY_DEBUGGER_GET_CLASS(debugger)->disable_bp(debugger, bp);
+
+ if (!status)
+ log_variadic_message(LMT_ERROR, "Error while removing the breakpoint at 0x%" PRIx64, pc);
+
+ g_binary_debugger_spread_breakpoints(debugger, tid, pc, RBO_INTERNAL, false);
+
+ result = false;
+
+ }
+
+ /* S'il s'agissait d'une progression pas à pas */
+ if (has_raw_breakpoint_origin(bp, RBO_STEP, tid))
+ {
+ previous = get_raw_breakpoint_prev_addr(bp);
+ assert(previous != VMPA_NO_VIRTUAL);
+
+ g_binary_debugger_remove_same_breakpoints(debugger, tid, previous, RBO_STEP);
+
+ assert(!has_raw_breakpoint_origin(bp, RBO_STEP, tid));
+
+ result = false;
+
+ }
+
+ /* En conclusion, on supprime les points inutiles */
+ for (i = 0; i < debugger->bp_count; )
+ {
+ bp = debugger->bpoints[i];
+
+ if (is_breakpoint_useless(bp))
+ {
+ status = g_binary_debugger_remove_memory_breakpoint(debugger, i);
+
+ if (!status)
+ {
+ addr = get_raw_breakpoint_addr(bp);
+ log_variadic_message(LMT_ERROR, "Error while removing the breakpoint at 0x%" PRIx64, addr);
+ i++;
+ }
+
+ }
+
+ else i++;
+
+ }
+
+ }
+
+ g_rw_lock_writer_unlock(&debugger->bp_lock);
+
+ if (result)
+ G_BINARY_DEBUGGER_GET_CLASS(debugger)->resume(debugger);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* addr = emplacement du point mémoire à traiter. *
+* *
+* Description : Ajoute un point d'arrêt basique en mémoire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_add_memory_breakpoint(GBinaryDebugger *debugger, virt_t addr)
+{
+ bool result; /* Bilan à retourner */
+ dbg_thread_id_t tid; /* Identifiant de thread */
+
+ tid = 1;/// FIXME
+
+ g_rw_lock_writer_lock(&debugger->bp_lock);
+
+ result = g_binary_debugger_insert_memory_breakpoint(debugger, addr, RBO_USER, tid, VMPA_NO_VIRTUAL);
+
+ g_rw_lock_writer_unlock(&debugger->bp_lock);
+
+ if (result)
+ g_signal_emit_by_name(debugger, "mem-bp-handled", true, addr);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* addr = emplacement du point mémoire à traiter. *
+* *
+* Description : Retire un point d'arrêt basique en mémoire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_delete_memory_breakpoint(GBinaryDebugger *debugger, virt_t addr)
+{
+ bool result; /* Bilan à retourner */
+ size_t index; /* Indice de ce point d'arrêt */
+ raw_breakpoint *bp; /* Confort de l'accès rapide */
+ dbg_thread_id_t tid; /* Identifiant de thread */
+
+ g_rw_lock_writer_lock(&debugger->bp_lock);
+
+ result = bsearch_index(&addr, debugger->bpoints, debugger->bp_count, sizeof(raw_breakpoint *),
+ (__compar_fn_t)compare_raw_breakpoint_with_addr, &index);
+
+ if (result)
+ {
+ bp = debugger->bpoints[index];
+
+ tid = 1;/// FIXME
+
+ result = has_raw_breakpoint_origin(bp, RBO_USER, tid);
+
+ if (result)
+ {
+ unset_raw_breakpoint_origin(bp, RBO_USER, tid);
+
+ if (is_breakpoint_useless(bp))
+ result = g_binary_debugger_remove_memory_breakpoint(debugger, index);
+
+ }
+
+ }
+
+ g_rw_lock_writer_unlock(&debugger->bp_lock);
+
+ if (result)
+ g_signal_emit_by_name(debugger, "mem-bp-handled", false, addr);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONTROLE DU FLOT D'EXECUTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à redémarrer. *
+* *
+* Description : Redémarre le processus de débogage. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_restart(GBinaryDebugger *debugger)
+{
+ return G_BINARY_DEBUGGER_GET_CLASS(debugger)->restart(debugger);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* *
+* Description : Remet en marche le débogueur courant. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_debugger_resume(GBinaryDebugger *debugger)
+{
+ bool result; /* Bilan à retourner */
+
+ result = G_BINARY_DEBUGGER_GET_CLASS(debugger)->resume(debugger);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à relancer. *
+* over = indique si les appels doivent être sautés ou non. *
+* *
+* Description : Relance l'exécution pour une seule instruction. *
+* *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-register_value *g_binary_debugger_get_registers(GBinaryDebugger *debugger, size_t *count)
+bool g_binary_debugger_stepi(GBinaryDebugger *debugger, bool over)
{
- return debugger->get_reg_values(debugger, count);
+ bool result; /* Bilan à retourner */
+ virt_t pc; /* Position courante */
+ dbg_thread_id_t tid; /* Identifiant de thread */
+
+ result = g_binary_debugger_get_current_pc(debugger, &pc);
+
+ if (result)
+ {
+ tid = 1;/// FIXME
+
+ g_rw_lock_writer_lock(&debugger->bp_lock);
+
+ result = g_binary_debugger_spread_breakpoints(debugger, tid, pc, RBO_STEP, over);
+
+ g_rw_lock_writer_unlock(&debugger->bp_lock);
+
+ }
+
+ if (result)
+ result = G_BINARY_DEBUGGER_GET_CLASS(debugger)->resume(debugger);
+
+ return result;
}
diff --git a/src/debug/debugger.h b/src/debug/debugger.h
index 6553b6d..1050e4e 100644
--- a/src/debug/debugger.h
+++ b/src/debug/debugger.h
@@ -27,51 +27,23 @@
#include <glib-object.h>
#include <stdint.h>
-#include <sys/types.h>
+#include "misc.h"
#include "../analysis/binary.h"
#include "../arch/archbase.h"
-/* Liste de tous les débogueurs */
-typedef enum _DebuggerType
-{
- DGT_JDWP, /* Utilisation du JDWP */
- DGT_REMOTE_GDB, /* Utilisation de GDB */
- DGT_PTRACE, /* Utilisation de ptrace() */
-
- DGT_COUNT2/* FIXME */
-
-} DebuggerType;
-
-
-/* Définition d'une frame */
-typedef struct _dbg_frame_t
-{
-
- vmpa_t addr; /* Position dans le code */
-
-} dbg_frame_t;
-
-
-
-/* Transmission des valeurs des registres */
-typedef struct _register_value
-{
- const char *name; /* Nom à ne pas libérer */
- uint64_t value; /* Valeur (taille maximale) */
-
-} register_value;
+/* ---------------------------- TRONC COMMUN DE DEBOGAGE ---------------------------- */
#define G_TYPE_BINARY_DEBUGGER g_binary_debugger_get_type()
#define G_BINARY_DEBUGGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_binary_debugger_get_type(), GBinaryDebugger))
#define G_IS_BINARY_DEBUGGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_binary_debugger_get_type()))
-#define G_BINARY_DEBUGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BINARY_DEBUGGER, GGBinaryDebuggerClass))
+#define G_BINARY_DEBUGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BINARY_DEBUGGER, GBinaryDebuggerClass))
#define G_IS_BINARY_DEBUGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BINARY_DEBUGGER))
-#define G_BINARY_DEBUGGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BINARY_DEBUGGER, GGBinaryDebuggerClass))
+#define G_BINARY_DEBUGGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BINARY_DEBUGGER, GBinaryDebuggerClass))
/* Définition des fonctionnalités d'un débogueur (instance) */
@@ -84,9 +56,6 @@ typedef struct _GBinaryDebuggerClass GBinaryDebuggerClass;
/* Indique le type définit par la GLib pour le débogueur ptrace(). */
GType g_binary_debugger_get_type(void);
-/* Crée un nouveau débogueur. */
-GBinaryDebugger *g_new_binary_debugger(DebuggerType, GLoadedBinary *);
-
/* Démarre une procédure de débogage. */
bool g_binary_debugger_attach(GBinaryDebugger *);
@@ -94,19 +63,165 @@ bool g_binary_debugger_attach(GBinaryDebugger *);
void g_binary_debugger_run(GBinaryDebugger *);
/* Reprend une procédure de débogage. */
-void g_binary_debugger_resume(GBinaryDebugger *);
+//void g_binary_debugger_resume(GBinaryDebugger *);
/* Tue une procédure de débogage. */
void g_binary_debugger_kill(GBinaryDebugger *);
/* Fournit les identifiants de tous les threads actifs. */
-pid_t *g_binary_debugger_list_all_threads(GBinaryDebugger *, char ***, size_t *);
+//pid_t *g_binary_debugger_list_all_threads(GBinaryDebugger *, char ***, size_t *);
/* Fournit la liste des frames courantes d'un thread donné. */
-dbg_frame_t *g_binary_debugger_get_frames_stack(GBinaryDebugger *, pid_t, size_t *);
+//dbg_frame_t *g_binary_debugger_get_frames_stack(GBinaryDebugger *, pid_t, size_t *);
/* Fournit la valeur des registres de l'architecture. */
-register_value *g_binary_debugger_get_registers(GBinaryDebugger *, size_t *);
+//register_value *g_binary_debugger_get_registers(GBinaryDebugger *, size_t *);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DES DIFFERENTS THREADS ACTIFS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Description humaine à représenter */
+typedef struct _dbg_thread_desc
+{
+ dbg_thread_id_t id; /* Identifiant interne */
+ char *name; /* Dénomination humaine */
+
+} dbg_thread_desc;
+
+
+/* Libère la mémoire d'une liste de threads actifs. */
+void delete_dbg_thread_desc(dbg_thread_desc *, size_t);
+
+/* Fournit les identifiants de tous les threads actifs. */
+dbg_thread_desc *g_binary_debugger_list_all_threads(GBinaryDebugger *, size_t *);
+
+
+
+
+
+
+
+
+
+/* --------------------------- ENTREES / SORTIES BASIQUES --------------------------- */
+
+
+/* Lit une valeur de 8 bits à une adresse arbitraire. */
+bool g_binary_debugger_read_memory_u8(GBinaryDebugger *, virt_t, uint8_t *);
+
+/* Lit une valeur de 16 bits à une adresse arbitraire. */
+bool g_binary_debugger_read_memory_u16(GBinaryDebugger *, virt_t, uint16_t *);
+
+/* Lit une valeur de 32 bits à une adresse arbitraire. */
+bool g_binary_debugger_read_memory_u32(GBinaryDebugger *, virt_t, uint32_t *);
+
+/* Lit une valeur de 64 bits à une adresse arbitraire. */
+bool g_binary_debugger_read_memory_u64(GBinaryDebugger *, virt_t, uint64_t *);
+
+/* Lit une valeur de taille quelconque à une adresse arbitraire. */
+bool g_binary_debugger_read_memory_data(GBinaryDebugger *, virt_t, uint8_t *, size_t);
+
+/* Ecrit une valeur de 8 bits à une adresse arbitraire. */
+bool g_binary_debugger_write_memory_u8(GBinaryDebugger *, virt_t, const uint8_t *);
+
+/* Ecrit une valeur de 16 bits à une adresse arbitraire. */
+bool g_binary_debugger_write_memory_u16(GBinaryDebugger *, virt_t, const uint16_t *);
+
+/* Ecrit une valeur de 32 bits à une adresse arbitraire. */
+bool g_binary_debugger_write_memory_u32(GBinaryDebugger *, virt_t, const uint32_t *);
+
+/* Ecrit une valeur de 64 bits à une adresse arbitraire. */
+bool g_binary_debugger_write_memory_u64(GBinaryDebugger *, virt_t, const uint64_t *);
+
+/* Ecrit une valeur de taille quelconque à une adresse donnée. */
+bool g_binary_debugger_write_memory_data(GBinaryDebugger *, virt_t, const uint8_t *, size_t);
+
+/* Liste l'ensemble des registres appartenant à un groupe. */
+char **g_binary_debugger_get_register_names(const GBinaryDebugger *, const char *, size_t *);
+
+/* Indique la taille associée à un registre donné. */
+unsigned int g_binary_debugger_get_register_size(const GBinaryDebugger *, const char *);
+
+/* Lit une valeur de 8 bits à partir d'un registre. */
+bool g_binary_debugger_read_register_u8(GBinaryDebugger *, const char *, uint8_t *);
+
+/* Lit une valeur de 16 bits à partir d'un registre. */
+bool g_binary_debugger_read_register_u16(GBinaryDebugger *, const char *, uint16_t *);
+
+/* Lit une valeur de 32 bits à partir d'un registre. */
+bool g_binary_debugger_read_register_u32(GBinaryDebugger *, const char *, uint32_t *);
+
+/* Lit une valeur de 64 bits à partir d'un registre. */
+bool g_binary_debugger_read_register_u64(GBinaryDebugger *, const char *, uint64_t *);
+
+/* Ecrit une valeur de 8 bits dans un registre. */
+bool g_binary_debugger_write_register_u8(GBinaryDebugger *, const char *, const uint8_t *);
+
+/* Ecrit une valeur de 16 bits dans un registre. */
+bool g_binary_debugger_write_register_u16(GBinaryDebugger *, const char *, const uint16_t *);
+
+/* Ecrit une valeur de 32 bits dans un registre. */
+bool g_binary_debugger_write_register_u32(GBinaryDebugger *, const char *, const uint32_t *);
+
+/* Ecrit une valeur de 64 bits dans un registre. */
+bool g_binary_debugger_write_register_u64(GBinaryDebugger *, const char *, const uint64_t *);
+
+
+
+/* ------------------------- MANIPULATION DE L'ETAT COURANT ------------------------- */
+
+
+/* Détermine le point d'exécution courant. */
+bool g_binary_debugger_get_current_pc(GBinaryDebugger *, virt_t *);
+
+/* Détermine l'adresse du premier retour d'appel. */
+bool g_binary_debugger_get_return_pc(GBinaryDebugger *, virt_t *);
+
+/* Détermine les prochaines probables instructions exécutées. */
+virt_t *g_binary_debugger_get_next_pcs(GBinaryDebugger *, virt_t, bool, size_t *);
+
+/* Remonte la pile d'appels jusqu'au point courant. */
+bool g_binary_debugger_get_call_stack(GBinaryDebugger *, virt_t **, size_t *);
+
+
+
+/* --------------------------- GESTION DES POINTS D'ARRET --------------------------- */
+
+
+/* Ajoute un point d'arrêt basique en mémoire. */
+bool g_binary_debugger_add_memory_breakpoint(GBinaryDebugger *, virt_t);
+
+/* Retire un point d'arrêt basique en mémoire. */
+bool g_binary_debugger_delete_memory_breakpoint(GBinaryDebugger *, virt_t);
+
+
+
+/* -------------------------- CONTROLE DU FLOT D'EXECUTION -------------------------- */
+
+
+/* Redémarre le processus de débogage. */
+bool g_binary_debugger_restart(GBinaryDebugger *);
+
+/* Remet en marche le débogueur courant. */
+bool g_binary_debugger_resume(GBinaryDebugger *);
+
+/* Relance l'exécution pour une seule instruction. */
+bool g_binary_debugger_stepi(GBinaryDebugger *, bool);
diff --git a/src/debug/gdbrsp/Makefile.am b/src/debug/gdbrsp/Makefile.am
new file mode 100644
index 0000000..fd46f27
--- /dev/null
+++ b/src/debug/gdbrsp/Makefile.am
@@ -0,0 +1,24 @@
+
+noinst_LTLIBRARIES = libdebuggdbrsp.la
+
+libdebuggdbrsp_la_SOURCES = \
+ aops.h \
+ gdb-int.h \
+ gdb.h gdb.c \
+ helpers.h helpers.c \
+ helpers_arm.h helpers_arm.c \
+ helpers_arm64.h helpers_arm64.c \
+ packet.h packet.c \
+ stream-int.h \
+ stream.h stream.c \
+ support.h support.c \
+ target.h target.c \
+ tcp.h tcp.c \
+ utils.h utils.c
+
+libdebuggdbrsp_la_CFLAGS = $(AM_CFLAGS)
+
+
+AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/src/debug/gdbrsp/aops.h b/src/debug/gdbrsp/aops.h
new file mode 100644
index 0000000..02d4982
--- /dev/null
+++ b/src/debug/gdbrsp/aops.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * aops.h - prototypes pour les compléments utiles à GDB pour l'architecture ARM
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_AOPS_H
+#define _DEBUG_GDBRSP_AOPS_H
+
+
+#include "gdb.h"
+
+
+
+/* Détermine le point d'exécution courant. */
+typedef bool (* get_pc_fc) (GGdbDebugger *, virt_t *);
+
+/* Remonte la pile d'appels jusqu'au point courant. */
+typedef bool (* compute_call_stack_fc) (const GGdbDebugger *, virt_t **, size_t *);
+
+/* Complète la commande manipulant des points d'arrêt. */
+typedef const char * (* get_bp_kind_fc) (const GGdbDebugger *, virt_t);
+
+/* Construit une instruction provoquant un arrêt d'exécution. */
+typedef const uint8_t * (* get_bp_data_fc) (const GGdbDebugger *, virt_t, size_t *);
+
+
+/* Procédures spécifiques pour une architecture */
+typedef struct _gdb_arch_ops
+{
+ get_pc_fc get_pc; /* Obtention du point d'exéc. */
+ compute_call_stack_fc compute_cstack; /* Calcule la pile d'appels */
+ get_bp_kind_fc get_bp_kind; /* Fournit le type d'un point */
+ get_bp_data_fc get_bp_data; /* Code d'un point d'arrêt */
+
+} gdb_arch_ops;
+
+
+
+#endif /* _DEBUG_GDBRSP_AOPS_H */
diff --git a/src/debug/gdbrsp/gdb-int.h b/src/debug/gdbrsp/gdb-int.h
new file mode 100644
index 0000000..5055fbf
--- /dev/null
+++ b/src/debug/gdbrsp/gdb-int.h
@@ -0,0 +1,116 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gdb.h - prototypes pour le débogage à l'aide de gdb.
+ *
+ * Copyright (C) 2009-2012 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_GDB_INT_H
+#define _DEBUG_GDBRSP_GDB_INT_H
+
+
+#include "aops.h"
+#include "gdb.h"
+#include "stream.h"
+#include "support.h"
+#include "target.h"
+#include "../break-int.h"
+#include "../debugger-int.h"
+
+
+
+
+
+
+
+
+
+
+/* Définition d'un point d'arrêt appliqué */
+typedef struct _gdb_breakpoint
+{
+ raw_breakpoint raw; /* A laisser en premier */
+
+ bool is_z; /* Usage de commande dédiée ? */
+
+ union
+ {
+ const char *kind; /* Précision de taille */
+
+ struct
+ {
+ uint8_t memory[16]; /* Données d'origine remplacées*/
+ size_t len; /* Quantité de ces données */
+ };
+
+ };
+
+} gdb_breakpoint;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* Débogueur utilisant un serveur GDB (instance) */
+struct _GGdbDebugger
+{
+ GBinaryDebugger parent; /* A laisser en premier */
+
+ SourceEndian endian; /* Boutisme du format */
+ MemoryDataSize msize; /* Taille des adresses */
+
+ const gdb_arch_ops *ops; /* Opérations spécifiques */
+
+ GGdbStream *stream; /* Flux de communication */
+ GGdbSupport *support; /* Configuration à adopter */
+ GGdbTarget *target; /* Architecture ciblée par GDB */
+
+};
+
+
+/* Débogueur utilisant un serveur GDB (classe) */
+struct _GGdbDebuggerClass
+{
+ GBinaryDebuggerClass parent; /* A laisser en premier */
+
+};
+
+
+
+/* ------------------------ ACCUEIL D'EVENEMENTS ASYNCHRONES ------------------------ */
+
+
+/* Réagit à la réception d'un signal par le programme étudié. */
+void g_gdb_debugger_receive_signal_reply(GGdbDebugger *, int);
+
+/* Réagit à la sortie d'exécution d'un programme étudié. */
+void g_gdb_debugger_receive_exit_reply(GGdbDebugger *, int, pid_t);
+
+
+
+#endif /* _DEBUG_GDBRSP_GDB_INT_H */
diff --git a/src/debug/gdbrsp/gdb.c b/src/debug/gdbrsp/gdb.c
new file mode 100644
index 0000000..37a7a73
--- /dev/null
+++ b/src/debug/gdbrsp/gdb.c
@@ -0,0 +1,1524 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gdb.c - débogage à l'aide de gdb.
+ *
+ * Copyright (C) 2009-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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gdb.h"
+
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "gdb-int.h"
+#include "helpers.h"
+#include "helpers_arm.h"
+#include "helpers_arm64.h"
+#include "tcp.h"
+#include "utils.h"
+#include "../../common/cpp.h"
+#include "../../format/format.h"
+
+
+
+
+
+
+
+
+/* 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 *);
+
+/* Supprime toutes les références externes. */
+static void g_gdb_debugger_dispose(GGdbDebugger *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_gdb_debugger_finalize(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 *);
+
+
+
+
+
+
+/* --------------------------- ENTREES / SORTIES BASIQUES --------------------------- */
+
+
+/* Lit une valeur quelconque à une adresse arbitraire. */
+static bool g_gdb_debugger_read_memory(GGdbDebugger *, virt_t, size_t, ...);
+
+/* Ecrit une valeur quelconque à une adresse arbitraire. */
+static bool g_gdb_debugger_write_memory(GGdbDebugger *, virt_t, size_t, ...);
+
+/* Liste l'ensemble des registres appartenant à un groupe. */
+static char **g_gdb_debugger_get_register_names(const GGdbDebugger *, const char *, size_t *);
+
+/* Indique la taille associée à un registre donné. */
+static unsigned int g_gdb_debugger_get_register_size(const GGdbDebugger *, const char *);
+
+/* Effectue la lecture d'un registre donné. */
+static bool g_gdb_debugger_read_register(GGdbDebugger *, const char *, size_t, ...);
+
+/* Effectue l'écriture d'un registre donné. */
+static bool g_gdb_debugger_write_register(GGdbDebugger *, const char *, size_t, ...);
+
+
+
+/* ------------------------- MANIPULATION DE L'ETAT COURANT ------------------------- */
+
+
+/* Détermine le point d'exécution courant. */
+static bool g_gdb_debugger_get_current_pc(GGdbDebugger *, virt_t *);
+
+/* Remonte la pile d'appels jusqu'au point courant. */
+static bool g_gdb_debugger_compute_call_stack(GGdbDebugger *, virt_t **, size_t *);
+
+
+
+/* --------------------------- GESTION DES POINTS D'ARRET --------------------------- */
+
+
+/* Ajoute un point d'arrêt basique en mémoire. */
+static gdb_breakpoint *g_gdb_debugger_enable_memory_breakpoint(GGdbDebugger *, virt_t);
+
+/* Retire un point d'arrêt basique en mémoire. */
+static bool g_gdb_debugger_disable_memory_breakpoint(GGdbDebugger *, gdb_breakpoint *);
+
+
+
+/* -------------------------- CONTROLE DU FLOT D'EXECUTION -------------------------- */
+
+
+/* Redémarre le processus de débogage lié à un serveur GDB. */
+static bool g_gdb_debugger_restart(GGdbDebugger *);
+
+/* Remet en marche le débogueur utilisant un serveur GDB. */
+static bool g_gdb_debugger_resume(GGdbDebugger *);
+
+
+
+
+
+
+
+
+
+
+
+
+/* Détermine l'identifiant du thread principal courant. */
+static char *g_gdb_debugger_get_active_thread(GGdbDebugger *);
+
+
+
+
+
+
+/* ------------------------ ACCUEIL D'EVENEMENTS ASYNCHRONES ------------------------ */
+
+
+
+
+
+
+
+
+/* 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)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GBinaryDebuggerClass *parent; /* Version en classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_gdb_debugger_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_gdb_debugger_finalize;
+
+ parent = G_BINARY_DEBUGGER_CLASS(klass);
+
+ parent->read_mem = (read_mem_any_fc)g_gdb_debugger_read_memory;
+ parent->write_mem = (write_mem_any_fc)g_gdb_debugger_write_memory;
+ parent->get_reg_names = (get_reg_names_fc)g_gdb_debugger_get_register_names;
+ parent->get_reg_size = (get_reg_size_fc)g_gdb_debugger_get_register_size;
+ parent->read_reg = (read_write_reg_any_fc)g_gdb_debugger_read_register;
+ parent->write_reg = (read_write_reg_any_fc)g_gdb_debugger_write_register;
+
+ parent->get_current_pc = (get_current_pc_fc)g_gdb_debugger_get_current_pc;
+ parent->get_call_stack = (get_call_stack_fc)g_gdb_debugger_compute_call_stack;
+
+ parent->enable_bp = (enable_mem_bp_fc)g_gdb_debugger_enable_memory_breakpoint;
+ parent->disable_bp = (disable_mem_bp_fc)g_gdb_debugger_disable_memory_breakpoint;
+
+ parent->restart = (restart_debugger_fc)g_gdb_debugger_restart;
+ parent->resume = (resume_debugger_fc)g_gdb_debugger_resume;
+
+}
+
+
+/******************************************************************************
+* *
+* 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();
+
+
+ // FIXME
+ //debugger->compute_cstack = compute_call_stack_for_arm64;
+ //debugger->fill_mem_bp = fill_memory_breakpoint_cmd_for_arm64;
+
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_debugger_dispose(GGdbDebugger *debugger)
+{
+ if (debugger->stream != NULL)
+ g_object_unref(G_OBJECT(debugger->stream));
+
+ if (debugger->support != NULL)
+ g_object_unref(G_OBJECT(debugger->support));
+
+ if (debugger->target != NULL)
+ g_object_unref(G_OBJECT(debugger->target));
+
+ G_OBJECT_CLASS(g_gdb_debugger_parent_class)->dispose(G_OBJECT(debugger));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_debugger_finalize(GGdbDebugger *debugger)
+{
+ G_OBJECT_CLASS(g_gdb_debugger_parent_class)->finalize(G_OBJECT(debugger));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = binaire représenter à déboguer. *
+* server = nom ou adresse du serveur à contacter. *
+* port = port de connexion. *
+* *
+* 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, const char *server, unsigned short port)
+{
+ GGdbDebugger *result; /* Débogueur à retourner */
+ GExeFormat *format; /* Format du binaire chargé */
+ const char *arch; /* Architecture d'exécution */
+ GArchProcessor *proc; /* Processeur lié au binaire */
+ char service[sizeof(XSTR(UINT16_MAX)) + 1]; /* Conversion requise */
+
+ result = g_object_new(G_TYPE_GDB_DEBUGGER, NULL);
+
+ G_BINARY_DEBUGGER(result)->binary = binary;
+ g_object_ref(G_OBJECT(binary));
+
+ /* Propriétés de la cible */
+
+ format = g_loaded_binary_get_format(binary);
+
+ result->endian = g_binary_format_get_endianness(G_BIN_FORMAT(format));
+
+ arch = g_exe_format_get_target_machine(format);
+
+ if (strcmp(arch, "armv7") == 0)
+ result->ops = get_arm_operations();
+ else
+ result->ops = NULL;
+
+ g_object_unref(G_OBJECT(format));
+
+ if (result->ops == NULL)
+ goto ggdn_error;
+
+ proc = g_loaded_binary_get_processor(binary);
+
+ result->msize = g_arch_processor_get_memory_size(proc);
+
+ g_object_unref(G_OBJECT(proc));
+
+ /* Mise en place des modules auxialiaires */
+
+ snprintf(service, sizeof(service), "%hu", port);
+
+ result->stream = g_gdb_tcp_client_new(server, service, result);
+ if (result->stream == NULL) goto ggdn_error;
+
+ result->support = g_gdb_support_new(result->stream);
+
+ result->target = g_gdb_target_new(result->stream);
+ if (result->target == NULL) goto ggdn_error;
+
+ return G_BINARY_DEBUGGER(result);
+
+ ggdn_error:
+
+ g_object_unref(G_OBJECT(result));
+
+ return NULL;
+
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* 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", NULL);
+ 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 : 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;
+
+}
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* *
+* Description : Détermine l'identifiant du thread principal courant. *
+* *
+* Retour : Identifiant du thread actif principal ou NULL en cas d'échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_gdb_debugger_get_active_thread(GGdbDebugger *debugger)
+{
+ char *result; /* Identifiant à renvoyer */
+ GGdbPacket *packet; /* Paquet de communication */
+ bool status; /* Bilan d'une communication */
+ const char *data; /* Données reçues à analyser */
+ const char *start; /* Début d'identification */
+ const char *end; /* Fin d'identification */
+
+ result = NULL;
+
+ /* Envoi de la requête */
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, "?");
+
+ status = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ if (!status)
+ goto ggdgat_exit;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(debugger->stream);
+
+ g_gdb_packet_get_data(packet, &data, NULL, NULL);
+
+ start = strstr(data, "thread:");
+ if (start == NULL) goto ggdgat_exit;
+
+ start += sizeof("thread:") - 1 /* '\0' */;
+
+ end = strstr(start, ";");
+ if (end == NULL) goto ggdgat_exit;
+
+ result = strndup(start, end - start);
+
+ ggdgat_exit:
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ENTREES / SORTIES BASIQUES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* addr = emplacement en mémoire à venir consulter. *
+* size = taille des données mises en jeu. *
+* ... = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur quelconque à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_read_memory(GGdbDebugger *debugger, virt_t addr, size_t size, ...)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ char cmd[1 + VMPA_MAX_LEN + 3]; /* Commande à émettre */
+ GGdbPacket *packet; /* Paquet de communication */
+ const char *data; /* Données reçues à analyser */
+ size_t len; /* Quantité de données reçues */
+ 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 */
+
+ /* Envoi de la requête */
+
+ cmd[0] = 'm';
+
+ result = translate_virt_to_hex(debugger, addr, &cmd[1]);
+
+ switch (size)
+ {
+ case 8:
+ strcat(cmd, ",1");
+ break;
+
+ case 16:
+ strcat(cmd, ",2");
+ break;
+
+ case 32:
+ strcat(cmd, ",4");
+ break;
+
+ case 64:
+ strcat(cmd, ",8");
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ goto ggdrm_exit;
+ break;
+
+ }
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, cmd);
+
+ result = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ if (!result)
+ goto ggdrm_exit;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(debugger->stream);
+
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+ if (is_error_code(data, len))
+ {
+ result = false;
+ goto ggdrm_error;
+ }
+
+ va_start(ap, size);
+
+ switch (size)
+ {
+ case 8:
+ val8 = va_arg(ap, uint8_t *);
+ result = hex_to_u8(data, val8);
+ break;
+
+ case 16:
+ val16 = va_arg(ap, uint16_t *);
+ result = hex_to_u16(data, &conv16);
+ *val16 = from_u16(&conv16, debugger->endian);
+ break;
+
+ case 32:
+ val32 = va_arg(ap, uint32_t *);
+ result = hex_to_u32(data, &conv32);
+ *val32 = from_u32(&conv32, debugger->endian);
+ break;
+
+ case 64:
+ val64 = va_arg(ap, uint64_t *);
+ result = hex_to_u64(data, &conv64);
+ *val64 = from_u64(&conv64, debugger->endian);
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ va_end(ap);
+
+ ggdrm_error:
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ ggdrm_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler. *
+* addr = emplacement en mémoire à venir consulter. *
+* size = taille des données mises en jeu. *
+* ... = emplacement de la valeur lue à conserver. [OUT] *
+* *
+* Description : Lit une valeur quelconque à une adresse arbitraire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_write_memory(GGdbDebugger *debugger, virt_t addr, size_t size, ...)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ char cmd[1 + 3 * VMPA_MAX_LEN + 3]; /* Commande à émettre */
+ 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 */
+ GGdbPacket *packet; /* Paquet de communication */
+ const char *data; /* Données reçues à analyser */
+ size_t len; /* Quantité de données reçues */
+
+ /* Envoi de la requête */
+
+ cmd[0] = 'M';
+
+ result = translate_virt_to_hex(debugger, addr, &cmd[1]);
+
+ va_start(ap, size);
+
+ switch (size)
+ {
+ case 8:
+ val8 = va_arg(ap, uint8_t *);
+ result = u8_to_hex(val8, hexval);
+
+ strcat(cmd, ",1:");
+ strcat(cmd, hexval);
+ break;
+
+ case 16:
+ val16 = va_arg(ap, uint16_t *);
+ conv16 = to_u16(val16, debugger->endian);
+ result = u16_to_hex(&conv16, hexval);
+
+ strcat(cmd, ",2:");
+ strcat(cmd, hexval);
+ break;
+
+ case 32:
+ val32 = va_arg(ap, uint32_t *);
+ conv32 = to_u32(val32, debugger->endian);
+ result = u32_to_hex(&conv32, hexval);
+
+ strcat(cmd, ",4:");
+ strcat(cmd, hexval);
+ break;
+
+ case 64:
+ val64 = va_arg(ap, uint64_t *);
+ conv64 = to_u64(val64, debugger->endian);
+ result = u16_to_hex(&conv64, hexval);
+
+ strcat(cmd, ",8:");
+ strcat(cmd, hexval);
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ if (!result)
+ goto ggdwm_exit;
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, cmd);
+
+ result = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ if (!result)
+ goto ggdwm_exit;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(debugger->stream);
+
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+ if (len == 3 && data[0] == 'E')
+ {
+ result = false;
+ goto ggdrm_error;
+ }
+
+ ggdrm_error:
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ ggdwm_exit:
+
+ va_end(ap);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* 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 : - *
+* *
+******************************************************************************/
+
+static char **g_gdb_debugger_get_register_names(const GGdbDebugger *debugger, const char *group, size_t *count)
+{
+ return g_gdb_target_get_register_names(debugger->target, group, count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* 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 : - *
+* *
+******************************************************************************/
+
+static unsigned int g_gdb_debugger_get_register_size(const GGdbDebugger *debugger, const char *name)
+{
+ return g_gdb_target_get_register_size(debugger->target, name);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* 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 : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_read_register(GGdbDebugger *debugger, const char *reg, size_t size, ...)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ va_list ap; /* Liste variable d'arguments */
+ uint8_t *val8; /* Valeur sur 8 bits */
+ uint16_t *val16; /* Valeur sur 16 bits */
+ uint32_t *val32; /* Valeur sur 32 bits */
+ uint64_t *val64; /* Valeur sur 64 bits */
+
+ va_start(ap, size);
+
+ switch (size)
+ {
+ case 8:
+ val8 = va_arg(ap, uint8_t *);
+ result = g_gdb_target_read_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 8, val8);
+ break;
+
+ case 16:
+ val16 = va_arg(ap, uint16_t *);
+ result = g_gdb_target_read_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 16, val16);
+ break;
+
+ case 32:
+ val32 = va_arg(ap, uint32_t *);
+ result = g_gdb_target_read_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 32, val32);
+ break;
+
+ case 64:
+ val64 = va_arg(ap, uint64_t *);
+ result = g_gdb_target_read_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 64, val64);
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ va_end(ap);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler. *
+* 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 : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_write_register(GGdbDebugger *debugger, 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 */
+ const uint32_t *val32; /* Valeur sur 32 bits */
+ const uint64_t *val64; /* Valeur sur 64 bits */
+
+ va_start(ap, size);
+
+ switch (size)
+ {
+ case 8:
+ val8 = va_arg(ap, const uint8_t *);
+ result = g_gdb_target_write_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 8, val8);
+ break;
+
+ case 16:
+ val16 = va_arg(ap, const uint16_t *);
+ result = g_gdb_target_write_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 16, val16);
+ break;
+
+ case 32:
+ val32 = va_arg(ap, const uint32_t *);
+ result = g_gdb_target_write_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 32, val32);
+ break;
+
+ case 64:
+ val64 = va_arg(ap, const uint64_t *);
+ result = g_gdb_target_write_register(debugger->target, debugger->stream, debugger->endian,
+ reg, 64, val64);
+ break;
+
+ default:
+ assert(false);
+ result = false;
+ break;
+
+ }
+
+ va_end(ap);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DE L'ETAT COURANT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* pc = adresse de l'instruction courante. [OUT] *
+* *
+* Description : Détermine le point d'exécution courant. *
+* *
+* Retour : Bilan de la récupération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_get_current_pc(GGdbDebugger *debugger, virt_t *pc)
+{
+ bool result; /* Bilan à retourner */
+
+ result = debugger->ops->get_pc(debugger, pc);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* callstack = pile d'appels reconstituée. [OUT] *
+* size = taille de cette pile. [OUT] *
+* *
+* Description : Remonte la pile d'appels jusqu'au point courant. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_compute_call_stack(GGdbDebugger *debugger, virt_t **callstack, size_t *size)
+{
+ bool result; /* Bilan global à retourner */
+
+ if (debugger->ops->compute_cstack != NULL)
+ result = debugger->ops->compute_cstack(debugger, callstack, size);
+
+ else
+ result = false;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION DES POINTS D'ARRET */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* addr = emplacement du point mémoire à traiter. *
+* *
+* Description : Ajoute un point d'arrêt basique en mémoire. *
+* *
+* Retour : Structure de suivi mise en place pour l'occasion, voire NULL.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gdb_breakpoint *g_gdb_debugger_enable_memory_breakpoint(GGdbDebugger *debugger, virt_t addr)
+{
+ gdb_breakpoint *result; /* Nouveau suivi à retourner */
+ char cmd[3 + VMPA_MAX_LEN + 3]; /* Commande à émettre */
+ bool status; /* Bilan d'une opération */
+ const char *kind; /* Taille spécifique du point */
+ GGdbPacket *packet; /* Paquet de communication */
+ const char *data; /* Données reçues à analyser */
+ size_t len; /* Quantité de données reçues */
+ GBinaryDebugger *dbg; /* Autre version du débogueur */
+ const uint8_t *bp; /* Données du point d'arrêt */
+ size_t bp_len; /* Quantité de ces données */
+ uint8_t memory[16]; /* Sauvegarde de la mémoire */
+
+ result = NULL;
+
+ /* Si l'utilisation de la commande dédiée est possible */
+ if (1) //////// TODO
+ {
+ /* Envoi de la requête */
+
+ strcpy(cmd, "Z0,");
+
+ status = translate_virt_to_hex(debugger, addr, &cmd[3]);
+
+ if (!status)
+ goto ggdemb_exit;
+
+ kind = debugger->ops->get_bp_kind(debugger, addr);
+
+ if (kind == NULL)
+ goto ggdemb_exit;
+
+ strcat(cmd, kind);
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, cmd);
+
+ status = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ if (!status)
+ goto ggdemb_exit;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(debugger->stream);
+
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+ if (is_error_code(data, len))
+ {
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+ goto ggdemb_fallback;
+ }
+
+ if (strcmp(data, "OK") != 0)
+ {
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+ goto ggdemb_fallback;
+ }
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ /* Constitution d'un dossier de suivi */
+
+ result = (gdb_breakpoint *)malloc(sizeof(gdb_breakpoint));
+
+ result->is_z = true;
+
+ result->kind = kind;
+
+ }
+
+ else
+ {
+
+ ggdemb_fallback:
+
+ dbg = G_BINARY_DEBUGGER(debugger);
+
+ /* Détermination du point d'arrêt */
+
+ bp = debugger->ops->get_bp_data(debugger, addr, &bp_len);
+
+ assert(bp_len <= 16);
+
+ /* Sauvegarde de la mémoire courante */
+
+ status = g_binary_debugger_read_memory_data(dbg, addr, memory, bp_len);
+
+ if (!status) goto ggdemb_exit;
+
+ /* Application du point d'arrêt */
+
+ status = g_binary_debugger_write_memory_data(dbg, addr, bp, bp_len);
+
+ if (!status) goto ggdemb_exit;
+
+ /* Constitution d'un dossier de suivi */
+
+ result = (gdb_breakpoint *)malloc(sizeof(gdb_breakpoint));
+
+ result->is_z = false;
+
+ memcpy(result->memory, memory, bp_len);
+ result->len = bp_len;
+
+ }
+
+ init_raw_breakpoint((raw_breakpoint *)result, addr);
+
+ ggdemb_exit:
+
+ return result;
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* bp = point d'arrêt à traiter. *
+* *
+* Description : Retire un point d'arrêt basique de la mémoire ciblée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_disable_memory_breakpoint(GGdbDebugger *debugger, gdb_breakpoint *bp)
+{
+ bool result; /* Bilan à retourner */
+ char cmd[3 + VMPA_MAX_LEN + 3]; /* Commande à émettre */
+ bool status; /* Bilan d'une opération */
+ GGdbPacket *packet; /* Paquet de communication */
+ const char *data; /* Données reçues à analyser */
+ size_t len; /* Quantité de données reçues */
+ GBinaryDebugger *dbg; /* Autre version du débogueur */
+
+ result = false;
+
+ /* Si l'utilisation de la commande dédiée est requise */
+ if (bp->is_z)
+ {
+ /* Envoi de la requête */
+
+ strcpy(cmd, "z0,");
+
+ status = translate_virt_to_hex(debugger, bp->raw.addr, &cmd[3]);
+
+ if (!status)
+ goto ggddmb_exit;
+
+ strcat(cmd, bp->kind);
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, cmd);
+
+ status = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ if (!status)
+ goto ggddmb_exit;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(debugger->stream);
+
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+ if (is_error_code(data, len))
+ {
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+ goto ggddmb_exit;
+ }
+
+ if (strcmp(data, "OK") != 0)
+ {
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+ goto ggddmb_exit;
+ }
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ result = true;
+
+ }
+
+ else
+ {
+ dbg = G_BINARY_DEBUGGER(debugger);
+
+ result = g_binary_debugger_write_memory_data(dbg, bp->raw.addr, bp->memory, bp->len);
+
+ }
+
+ ggddmb_exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONTROLE DU FLOT D'EXECUTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à redémarrer. *
+* *
+* Description : Redémarre le processus de débogage lié à un serveur GDB. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_debugger_restart(GGdbDebugger *debugger)
+{
+ bool result; /* Bilan à retourner */
+ GGdbPacket *packet; /* Paquet de communication */
+ return true;
+ /* Envoi de la requête */
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, "R00");
+
+ result = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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)
+{
+ bool result; /* Bilan à retourner */
+ //char *id; /* Identifiant de thread */
+ GGdbPacket *packet; /* Paquet de communication */
+ //const char *data; /* Données reçues à analyser */
+
+ static bool _twice = false;
+
+
+ if (!_twice && 0)
+ {
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, "$QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;2c;4c;");
+
+ result = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ if (!result)
+ goto ggdhmb_exit;
+
+ }
+
+
+
+
+
+
+ /* Envoi de la requête */
+
+ /*
+ id = g_gdb_debugger_get_active_thread(debugger);
+ if (id == NULL) return false;
+
+ printf("ID : %s\n", id);
+ */
+
+ /*
+ id = g_gdb_support_get_id(debugger->support);
+ if (id == NULL) return false;
+
+ printf("ID : %s\n", id);
+ */
+
+ packet = g_gdb_stream_get_free_packet(debugger->stream);
+
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, "vCont;c:-1");
+ //g_gdb_packet_append(packet, "vCont;c:p256f.-1");
+
+
+ /*
+ if (_twice)
+ {
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, "vCont;c:p");
+ g_gdb_packet_append(packet, id);
+ g_gdb_packet_append(packet, ".");
+ g_gdb_packet_append(packet, id);
+ }
+ else
+ {
+ _twice = true;
+ g_gdb_packet_start_new_command(packet);
+ g_gdb_packet_append(packet, "vCont;c:p");
+ g_gdb_packet_append(packet, id);
+ g_gdb_packet_append(packet, ".-1");
+ }
+ */
+
+
+
+
+
+ result = g_gdb_stream_send_packet(debugger->stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+
+ if (!result)
+ goto ggdhmb_exit;
+
+ /* Réception de la réponse */
+ /*
+ packet = g_gdb_stream_recv_packet(debugger->stream);
+
+ g_gdb_packet_get_data(packet, &data, NULL, NULL);
+
+ printf("Ack cont...\n");
+
+ //result = (strcmp(data, "OK") == 0);
+
+ g_gdb_stream_mark_packet_as_free(debugger->stream, packet);
+ */
+ ggdhmb_exit:
+
+ _twice = true;
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ACCUEIL D'EVENEMENTS ASYNCHRONES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = instance liée à un débogueur GDB à manipuler. *
+* signum = indentifiant du signal concerné. *
+* *
+* Description : Réagit à la réception d'un signal par le programme étudié. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_gdb_debugger_receive_signal_reply(GGdbDebugger *debugger, int signum)
+{
+ virt_t pc; /* Position courante du CPU */
+ bool status; /* Bilan d'une opération */
+ GBinaryDebugger *base; /* Version basique du débogueur*/
+
+ base = G_BINARY_DEBUGGER(debugger);
+
+ status = g_binary_debugger_get_current_pc(base, &pc);
+
+ if (!status)
+ pc = VMPA_NO_VIRTUAL;
+
+ on_binary_debugger_stopped(base, pc);
+
+ g_signal_emit_by_name(debugger, "signaled", signum);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = instance liée à un débogueur GDB à manipuler. *
+* status = indication d'état à la sortie. *
+* pid = éventuel identifiant de processus concerné ou -1. *
+* *
+* Description : Réagit à la sortie d'exécution d'un programme étudié. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_gdb_debugger_receive_exit_reply(GGdbDebugger *debugger, int status, pid_t pid)
+{
+ GBinaryDebugger *base; /* Version basique du débogueur*/
+
+ base = G_BINARY_DEBUGGER(debugger);
+
+ on_binary_debugger_finished(base, pid);
+
+ g_signal_emit_by_name(debugger, "exited", status, pid);
+
+}
diff --git a/src/debug/remgdb/gdb.h b/src/debug/gdbrsp/gdb.h
index 38aa8fe..7faa044 100644
--- a/src/debug/remgdb/gdb.h
+++ b/src/debug/gdbrsp/gdb.h
@@ -21,8 +21,8 @@
*/
-#ifndef _DEBUG_REMGDB_GDB_H
-#define _DEBUG_REMGDB_GDB_H
+#ifndef _DEBUG_GDBRSP_GDB_H
+#define _DEBUG_GDBRSP_GDB_H
#include <glib-object.h>
@@ -51,11 +51,11 @@ typedef struct _GGdbDebuggerClass GGdbDebuggerClass;
GType g_gdb_debugger_get_type(void);
/* Crée un débogueur utilisant un serveur GDB distant. */
-GBinaryDebugger *g_gdb_debugger_new(GLoadedBinary *, void *);
+GBinaryDebugger *g_gdb_debugger_new(GLoadedBinary *, const char *, unsigned short);
void test_gdb(void);
-#endif /* _DEBUG_REMGDB_GDB_H */
+#endif /* _DEBUG_GDBRSP_GDB_H */
diff --git a/src/debug/remgdb/helpers.c b/src/debug/gdbrsp/helpers.c
index bae7f0b..296d642 100644
--- a/src/debug/remgdb/helpers.c
+++ b/src/debug/gdbrsp/helpers.c
@@ -28,12 +28,97 @@
#include <string.h>
+#include "gdb-int.h"
+#include "utils.h"
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* addr = emplacement en mémoire à venir consulter. *
+* out = zone d'impression en hexadécimal. [OUT] *
+* *
+* Description : Traduit une adresse en chaîne hexadécimale pour GDB. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool translate_virt_to_hex(const GGdbDebugger *debugger, virt_t addr, char *out)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ uint8_t conv8; /* Valeur adaptée sur 8 bits */
+ uint16_t conv16; /* Valeur adaptée sur 16 bits */
+ uint32_t conv32; /* Valeur adaptée sur 32 bits */
+ uint64_t conv64; /* Valeur adaptée sur 64 bits */
+ char hexval[17]; /* Valeur sous forme hexa */
+ bool got_msn; /* Obtention d'un quartet ? */
+ size_t i; /* Boucle de parcours */
+
+ /* Conversion */
+
+ switch (debugger->msize)
+ {
+ case MDS_8_BITS:
+ conv8 = addr;
+ result = u8_to_hex(&conv8, hexval);
+ break;
+
+ case MDS_16_BITS:
+ conv16 = addr;
+ conv16 = to_u16(&conv16, SRE_BIG);
+ result = u16_to_hex(&conv16, hexval);
+ break;
+
+ case MDS_32_BITS:
+ conv32 = addr;
+ conv32 = to_u32(&conv32, SRE_BIG);
+ result = u32_to_hex(&conv32, hexval);
+ break;
+
+ case MDS_64_BITS:
+ conv64 = addr;
+ conv64 = to_u64(&conv64, SRE_BIG);
+ result = u64_to_hex(&conv64, hexval);
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ /* On saute les zéros préliminaires... */
+
+ if (result)
+ {
+ got_msn = false;
+
+ for (i = 0; i < 17; i++)
+ {
+ if (!got_msn)
+ {
+ if (hexval[i] == '0')
+ continue;
+ else
+ got_msn = true;
+ }
+ *out = hexval[i];
+ out++;
+ }
+
+ *out = '\0';
+
+ }
+
+ return result;
+}
diff --git a/src/debug/remgdb/helpers.h b/src/debug/gdbrsp/helpers.h
index d68fc11..5f5f301 100644
--- a/src/debug/remgdb/helpers.h
+++ b/src/debug/gdbrsp/helpers.h
@@ -21,16 +21,17 @@
*/
-#ifndef _DEBUG_REMGDB_HELPERS_H
-#define _DEBUG_REMGDB_HELPERS_H
+#ifndef _DEBUG_GDBRSP_HELPERS_H
+#define _DEBUG_GDBRSP_HELPERS_H
+#include "gdb.h"
#include "packet.h"
-#include "../../arch/archbase.h"
-#include "../../common/endianness.h"
+/* Traduit une adresse en chaîne hexadécimale pour GDB. */
+bool translate_virt_to_hex(const GGdbDebugger *, virt_t, char *);
@@ -58,4 +59,4 @@ bool get_stop_reply_sig_info(const GGdbPacket *, int *, vmpa_t *, pid_t *, Sourc
-#endif /* _DEBUG_REMGDB_HELPERS_H */
+#endif /* _DEBUG_GDBRSP_HELPERS_H */
diff --git a/src/debug/gdbrsp/helpers_arm.c b/src/debug/gdbrsp/helpers_arm.c
new file mode 100644
index 0000000..e2491ae
--- /dev/null
+++ b/src/debug/gdbrsp/helpers_arm.c
@@ -0,0 +1,252 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers_arm.c - compléments utiles à GDB pour l'architecture ARM
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "helpers_arm.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "gdb-int.h"
+
+
+
+/* Détermine le point d'exécution courant. */
+static bool get_arm_pc(GGdbDebugger *, virt_t *);
+
+/* Remonte la pile d'appels jusqu'au point courant. */
+static bool compute_call_stack_for_arm(const GGdbDebugger *, virt_t **, size_t *);
+
+/* Complète la commande manipulant des points d'arrêt. */
+static const char *get_breakpoint_kind_for_arm(const GGdbDebugger *, virt_t);
+
+/* Construit une instruction provoquant un arrêt d'exécution. */
+static const uint8_t *get_arm_breakpoint_data(const GGdbDebugger *, virt_t, size_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit les fonctions adaptées aux opérations pour ARM. *
+* *
+* Retour : Opérations spécifiques adaptées à ARM. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const gdb_arch_ops *get_arm_operations(void)
+{
+ static const gdb_arch_ops arm_ops = {
+
+ .get_pc = get_arm_pc,
+ .compute_cstack = compute_call_stack_for_arm,
+ .get_bp_kind = get_breakpoint_kind_for_arm,
+ .get_bp_data = get_arm_breakpoint_data
+
+ };
+
+ return &arm_ops;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* pc = adresse de l'instruction courante. [OUT] *
+* *
+* Description : Détermine le point d'exécution courant. *
+* *
+* Retour : Bilan de la récupération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool get_arm_pc(GGdbDebugger *debugger, virt_t *pc)
+{
+ bool result; /* Bilan à retourner */
+ uint32_t value;
+
+ result = g_binary_debugger_read_register_u32(G_BINARY_DEBUGGER(debugger), "pc", &value);
+
+ if (result)
+ *pc = value;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* callstack = pile d'appels reconstituée. [OUT] *
+* size = taille de cette pile. [OUT] *
+* *
+* Description : Remonte la pile d'appels jusqu'au point courant. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool compute_call_stack_for_arm(const GGdbDebugger *debugger, virt_t **callstack, size_t *size)
+{
+ bool result; /* Bilan global à retourner */
+ GBinaryDebugger *base; /* Version basique d'instance */
+ uint32_t lr; /* Retour de fonction */
+ uint32_t fp; /* Pointeur de cadre à suivre */
+
+ base = G_BINARY_DEBUGGER(debugger);
+
+ result = g_binary_debugger_read_register_u32(base, "lr", &lr);
+
+ if (result && lr != 0)
+ {
+ *callstack = (virt_t *)realloc(*callstack, ++(*size) * sizeof(virt_t));
+
+ (*callstack)[*size - 1] = lr;
+
+ }
+
+ result &= g_binary_debugger_read_register_u32(base, "r11", &fp);
+
+ while (result && fp != 0)
+ {
+ /**
+ * fp[-0] : pc sauvegardé
+ * fp[-1] : lr sauvegardé
+ * fp[-2] : sp précédent
+ * fp[-3] : fp précédent
+ */
+
+ result = g_binary_debugger_read_memory_u32(base, fp - 2 * sizeof(uint32_t), &lr);
+ if (!result) break;
+
+ if (lr != 0)
+ {
+ *callstack = (virt_t *)realloc(*callstack, ++(*size) * sizeof(virt_t));
+
+ (*callstack)[*size - 1] = lr;
+
+ }
+
+ result = g_binary_debugger_read_memory_u32(base, fp - 4 * sizeof(uint32_t), &fp);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* virt = emplacement du point mémoire à traiter. *
+* *
+* Description : Complète la commande manipulant des points d'arrêt. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static const char *get_breakpoint_kind_for_arm(const GGdbDebugger *debugger, virt_t virt)
+{
+ const char *result; /* Indication à retourner */
+ GArchProcessor *proc; /* Processeur lié au binaire */
+ vmpa2t addr; /* Format d'adresse complet */
+ GArchInstruction *instr; /* Instruction ciblée */
+ const char *encoding; /* Encodage de l'instruction */
+
+ proc = g_loaded_binary_get_processor(G_BINARY_DEBUGGER(debugger)->binary);
+
+ init_vmpa(&addr, VMPA_NO_PHYSICAL, virt);
+ instr = g_arch_processor_find_instr_by_address(proc, &addr);
+
+ if (instr == NULL)
+ result = NULL;
+
+ else
+ {
+ encoding = g_arch_instruction_get_encoding(instr);
+
+ if (strcmp(encoding, "Thumb/16") == 0)
+ result = ",2";
+
+ if (strcmp(encoding, "Thumb/32") == 0)
+ result = ",3";
+
+ if (strcmp(encoding, "ARM") == 0)
+ result = ",4";
+
+ else
+ result = NULL;
+
+ g_object_unref(G_OBJECT(instr));
+
+ }
+
+ g_object_unref(G_OBJECT(proc));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* addr = emplacement du point mémoire à traiter. *
+* len = quantité de mémoire à remplacer. [OUT] *
+* *
+* Description : Construit une instruction provoquant un arrêt d'exécution. *
+* *
+* Retour : Définition du point d'arrêt à placer à l'adresse donnée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static const uint8_t *get_arm_breakpoint_data(const GGdbDebugger *debugger, virt_t addr, size_t *len)
+{
+ const uint8_t *result; /* Données à placer en mémoire */
+
+ /* Version point d'arrêt */
+ static const uint32_t bkpt_code[] = { 0xe1200070 };
+
+ *len = sizeof(bkpt_code);;
+
+ result = (const uint8_t *)bkpt_code;
+
+ return result;
+
+}
diff --git a/src/debug/gdbrsp/helpers_arm.h b/src/debug/gdbrsp/helpers_arm.h
new file mode 100644
index 0000000..70977bc
--- /dev/null
+++ b/src/debug/gdbrsp/helpers_arm.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers_arm.h - prototypes pour les compléments utiles à GDB pour l'architecture ARM
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_HELPERS_ARM_H
+#define _DEBUG_GDBRSP_HELPERS_ARM_H
+
+
+#include "aops.h"
+
+
+
+/* Fournit les fonctions adaptées aux opérations pour ARM. */
+const gdb_arch_ops *get_arm_operations(void);
+
+
+
+#endif /* _DEBUG_GDBRSP_HELPERS_ARM_H */
diff --git a/src/debug/gdbrsp/helpers_arm64.c b/src/debug/gdbrsp/helpers_arm64.c
new file mode 100644
index 0000000..6807662
--- /dev/null
+++ b/src/debug/gdbrsp/helpers_arm64.c
@@ -0,0 +1,97 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers_arm64.c - compléments utiles à GDB pour l'architecture AArch64
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "helpers_arm64.h"
+
+
+#include <malloc.h>
+
+
+#include "gdb-int.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à consulter. *
+* callstack = pile d'appels reconstituée. [OUT] *
+* size = taille de cette pile. [OUT] *
+* *
+* Description : Remonte la pile d'appels jusqu'au point courant. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool compute_call_stack_for_arm64(GGdbDebugger *debugger, virt_t **callstack, size_t *size)
+{
+ bool result; /* Bilan global à retourner */
+ GBinaryDebugger *base; /* Version basique d'instance */
+ uint64_t fp; /* Pointeur de cadre à suivre */
+ uint64_t previous; /* Appel de fonction précédent */
+
+ base = G_BINARY_DEBUGGER(debugger);
+
+ result = g_binary_debugger_read_register_u64(base, "x29", &fp);
+
+ while (result && fp != 0)
+ {
+ result = g_binary_debugger_read_memory_u64(base, fp + sizeof(uint64_t), &previous);
+ if (!result) break;
+
+ *callstack = (virt_t *)realloc(*callstack, ++(*size) * sizeof(virt_t));
+
+ (*callstack)[*size - 1] = previous;
+
+ result = g_binary_debugger_read_memory_u64(base, fp, &fp);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : debugger = débogueur à manipuler ici. *
+* addr = emplacement du point mémoire à traiter. *
+* cmd = commande en cours de constitution. [OUT] *
+* *
+* Description : Complète la commande manipulant des points d'arrêt. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fill_memory_breakpoint_cmd_for_arm64(GGdbDebugger *debugger, virt_t addr, char *cmd)
+{
+ strcat(cmd, ",4");
+
+ return true;
+
+}
diff --git a/src/debug/gdbrsp/helpers_arm64.h b/src/debug/gdbrsp/helpers_arm64.h
new file mode 100644
index 0000000..80f9312
--- /dev/null
+++ b/src/debug/gdbrsp/helpers_arm64.h
@@ -0,0 +1,40 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers_arm64.h - prototypes pour les compléments utiles à GDB pour l'architecture AArch64
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_HELPERS_ARM64_H
+#define _DEBUG_GDBRSP_HELPERS_ARM64_H
+
+
+#include "gdb.h"
+
+
+
+/* Remonte la pile d'appels jusqu'au point courant. */
+bool compute_call_stack_for_arm64(GGdbDebugger *, virt_t **, size_t *);
+
+/* Complète la commande manipulant des points d'arrêt. */
+bool fill_memory_breakpoint_cmd_for_arm64(GGdbDebugger *, virt_t, char *);
+
+
+
+#endif /* _DEBUG_GDBRSP_HELPERS_ARM64_H */
diff --git a/src/debug/remgdb/packet.c b/src/debug/gdbrsp/packet.c
index 8d798c6..4a70a79 100644
--- a/src/debug/remgdb/packet.c
+++ b/src/debug/gdbrsp/packet.c
@@ -174,13 +174,15 @@ void g_gdb_packet_append(GGdbPacket *packet, const char *string)
len = strlen(string);
/* Si la place n'est pas assez grande */
- if ((packet->len + len + 1) >= packet->allocated)
+ if ((packet->len + len + 1) > packet->allocated)
{
packet->buffer = (char *)realloc(packet->buffer, (packet->len + len + 1) * sizeof(char));
packet->allocated = packet->len + len + 1;
}
- strcat(packet->buffer, string);
+
+ memcpy(packet->buffer + packet->len, string, len + 1);
+ //strcat(packet->buffer, string);
packet->len += len;
@@ -309,6 +311,8 @@ bool g_gdb_packet_decode(GGdbPacket *packet)
if (packet->buffer != NULL)
free(packet->buffer);
+ buffer[k] = '\0';
+
packet->buffer = buffer;
packet->len = k;
packet->allocated = allocated;
@@ -322,7 +326,7 @@ bool g_gdb_packet_decode(GGdbPacket *packet)
* *
* Paramètres : packet = paquet à analyser. *
* data = données contenues dans le paquet. [OUT] *
-* len = quantité de ces données. [OUT] *
+* len = quantité de ces données ou NULL. [OUT] *
* checksum = contrôle d'intégrité des données ou NULL. [OUT] *
* *
* Description : Fournit le contenu du paquet. *
@@ -336,7 +340,9 @@ bool g_gdb_packet_decode(GGdbPacket *packet)
void g_gdb_packet_get_data(const GGdbPacket *packet, const char **data, size_t *len, uint8_t *checksum)
{
*data = packet->buffer;
- *len = packet->len;
+
+ if (len != NULL)
+ *len = packet->len;
if (checksum != NULL)
*checksum = packet->checksum;
diff --git a/src/debug/remgdb/packet.h b/src/debug/gdbrsp/packet.h
index 9c44108..2e8abb7 100644
--- a/src/debug/remgdb/packet.h
+++ b/src/debug/gdbrsp/packet.h
@@ -21,8 +21,8 @@
*/
-#ifndef _DEBUG_REMGDB_PACKET_H
-#define _DEBUG_REMGDB_PACKET_H
+#ifndef _DEBUG_GDBRSP_PACKET_H
+#define _DEBUG_GDBRSP_PACKET_H
#include <glib-object.h>
@@ -79,4 +79,4 @@ GGdbPacket *g_gdb_packet_pop(GGdbPacket **);
-#endif /* _DEBUG_REMGDB_PACKET_H */
+#endif /* _DEBUG_GDBRSP_PACKET_H */
diff --git a/src/debug/remgdb/stream-int.h b/src/debug/gdbrsp/stream-int.h
index 8ac422d..db61d13 100644
--- a/src/debug/remgdb/stream-int.h
+++ b/src/debug/gdbrsp/stream-int.h
@@ -21,10 +21,11 @@
*/
-#ifndef _DEBUG_REMGDB_STREAM_INT_H
-#define _DEBUG_REMGDB_STREAM_INT_H
+#ifndef _DEBUG_GDBRSP_STREAM_INT_H
+#define _DEBUG_GDBRSP_STREAM_INT_H
+#include "gdb.h"
#include "stream.h"
@@ -43,6 +44,8 @@ struct _GGdbStream
int fd; /* Flux ouvert en L./E. */
+ GGdbDebugger *owner; /* Propriétaire du flux */
+
send_gdb_data_fc send_data; /* Envoi d'un paquet GDB */
recv_gdb_byte_fc recv_byte; /* Réception d'un paquet GDB */
@@ -55,6 +58,18 @@ struct _GGdbStream
GCond recv_cond; /* Attente de disponibilité */
GMutex recv_mutex; /* Accès à la liste */
+ GGdbPacket *status_packets; /* Liste des paquets d'état */
+ GCond status_cond; /* Attente de disponibilité */
+ GMutex status_mutex; /* Accès à la liste */
+
+
+
+
+ bool skip_ack;
+
+ bool want_status;
+
+
};
@@ -71,4 +86,4 @@ bool g_gdb_stream_listen(GGdbStream *);
-#endif /* _DEBUG_REMGDB_STREAM_INT_H */
+#endif /* _DEBUG_GDBRSP_STREAM_INT_H */
diff --git a/src/debug/remgdb/stream.c b/src/debug/gdbrsp/stream.c
index cd303c3..979ed9b 100644
--- a/src/debug/remgdb/stream.c
+++ b/src/debug/gdbrsp/stream.c
@@ -24,14 +24,19 @@
#include "stream.h"
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <strings.h>
#include <glib/gthread.h>
#include <sys/select.h>
+#include "gdb-int.h"
#include "stream-int.h"
+#include "utils.h"
#include "../../common/dllist.h"
+#include "../../gui/panels/log.h"
@@ -41,12 +46,21 @@ static void g_gdb_stream_class_init(GGdbStreamClass *);
/* Initialise une instance de flux de communication avec GDB. */
static void g_gdb_stream_init(GGdbStream *);
+/* Supprime toutes les références externes. */
+static void g_gdb_stream_dispose(GGdbStream *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_gdb_stream_finalize(GGdbStream *);
+
/* Envoie un acquittement pour la dernière réception. */
static bool gdb_stream_ack(GGdbStream *);
/* Ecoute une connexion à un serveur GDB. */
static void *gdb_stream_thread(GGdbStream *);
+/* Reste en alerte quant au changement de statut de l'exécution. */
+static void *gdb_stream_status_thread(GGdbStream *);
+
/* Réceptionne un paquet d'un serveur GDB. */
static bool g_gdb_stream_read_packet(GGdbStream *, GGdbPacket *);
@@ -70,6 +84,12 @@ G_DEFINE_TYPE(GGdbStream, g_gdb_stream, G_TYPE_OBJECT);
static void g_gdb_stream_class_init(GGdbStreamClass *klass)
{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_gdb_stream_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_gdb_stream_finalize;
}
@@ -93,11 +113,86 @@ static void g_gdb_stream_init(GGdbStream *stream)
g_cond_init(&stream->recv_cond);
g_mutex_init(&stream->recv_mutex);
+ g_cond_init(&stream->status_cond);
+ g_mutex_init(&stream->status_mutex);
+
+ stream->skip_ack = false;
+
+ stream->want_status = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_stream_dispose(GGdbStream *stream)
+{
+ g_object_unref(G_OBJECT(stream->owner));
+
+
+ /* TODO... */
+
+
+ G_OBJECT_CLASS(g_gdb_stream_parent_class)->dispose(G_OBJECT(stream));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_stream_finalize(GGdbStream *stream)
+{
+
+ /* TODO */
+
+
+ G_OBJECT_CLASS(g_gdb_stream_parent_class)->finalize(G_OBJECT(stream));
+
}
/******************************************************************************
* *
+* Paramètres : stream = instance à modifier. *
+* *
+* Description : Ne participe plus aux acquitements de paquets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_gdb_stream_do_not_ack(GGdbStream *stream)
+{
+ stream->skip_ack = true;
+
+}
+
+
+
+/******************************************************************************
+* *
* Paramètres : stream = instance à réellement lancer. *
* *
* Description : Lance l'écoute d'un flux de communication avec GDB. *
@@ -117,6 +212,9 @@ bool g_gdb_stream_listen(GGdbStream *stream)
if (!g_thread_new("chrysalide_gdb_stream", (GThreadFunc)gdb_stream_thread, stream))
result = false;
+ if (!g_thread_new("chrysalide_gdb_status", (GThreadFunc)gdb_stream_status_thread, stream))
+ result = false;
+
return result;
}
@@ -136,6 +234,9 @@ bool g_gdb_stream_listen(GGdbStream *stream)
static bool gdb_stream_ack(GGdbStream *stream)
{
+ ///
+ //return true;
+
bool result; /* Bilan à retourner */
GGdbPacket *packet; /* Paquet à envoyer */
@@ -171,6 +272,12 @@ static void *gdb_stream_thread(GGdbStream *stream)
int ret; /* Bilan d'un appel */
GGdbPacket *packet; /* Nouveau paquet reçu */
+
+ const char *data; /* Données reçues à analyser */
+ size_t len; /* Quantité de ces données */
+
+
+
while (1)
{
FD_ZERO(&rfds);
@@ -178,8 +285,6 @@ static void *gdb_stream_thread(GGdbStream *stream)
ret = select(stream->fd + 1, &rfds, NULL, NULL, NULL);
- printf("ret :: %d\n", ret);
-
switch (ret)
{
case -1:
@@ -197,10 +302,46 @@ static void *gdb_stream_thread(GGdbStream *stream)
if (g_gdb_stream_read_packet(stream, packet))
{
- /* Acquittement */
- if (!gdb_stream_ack(stream)) goto bad_recv;
+ /* Acquittement ? */
+ if (!stream->skip_ack)
+ {
+ if (!gdb_stream_ack(stream)) goto bad_recv;
+ }
+
+
+ /* On conserve le résultat ? */
+
+
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+
+ //printf("---------------------------\n");
+ //printf(">> want status ? %d\n", stream->want_status);
+ //printf(">> got '%s'\n", data);
+
+
+ if (len >= 1)
+ {
+ if (stream->want_status)
+ stream->want_status = false;
+
+ else if (index("STWX", data[0]) != NULL)
+ {
+ g_mutex_lock(&stream->status_mutex);
+ g_gdb_packet_push(&stream->status_packets, packet);
+ g_mutex_unlock(&stream->status_mutex);
+
+ g_cond_signal(&stream->status_cond);
+
+ break;
+ }
+
+ // else message inconnu -> log_message() !
+
+ }
+
+
- /* On conserve le résultat */
g_mutex_lock(&stream->recv_mutex);
g_gdb_packet_push(&stream->recv_packets, packet);
@@ -210,6 +351,11 @@ static void *gdb_stream_thread(GGdbStream *stream)
}
+ else
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+ break;
+
bad_recv:
printf("bad things happend...\n");
@@ -222,6 +368,115 @@ static void *gdb_stream_thread(GGdbStream *stream)
}
+
+ printf("Oh noes....\n");
+
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stream = encadrement associée à l'opération. *
+* *
+* Description : Reste en alerte quant au changement de statut de l'exécution.*
+* *
+* Retour : ??? *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *gdb_stream_status_thread(GGdbStream *stream)
+{
+ GGdbPacket *packet; /* Nouveau paquet reçu */
+ const char *data; /* Données reçues à analyser */
+ size_t len; /* Quantité de ces données */
+ bool malformed; /* Echec d'interprétation */
+ uint8_t byte; /* Valeur quelconque sur 8 bits*/
+ bool ret; /* Bilan d'un appel */
+
+ while (1)
+ {
+ /* Réception d'un nouveau paquet de statut */
+
+ g_mutex_lock(&stream->status_mutex);
+
+ if (dl_list_empty(stream->status_packets))
+ g_cond_wait(&stream->status_cond, &stream->status_mutex);
+
+ packet = g_gdb_packet_pop(&stream->status_packets);
+
+ g_mutex_unlock(&stream->status_mutex);
+
+ /* Traitement du paquet reçu */
+
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+ malformed = false;
+
+ switch (data[0])
+ {
+ case 'S':
+
+ ret = read_fixed_byte(data + 1, len - 1, &byte);
+
+ if (!ret)
+ {
+ malformed = true;
+ goto gsst_processed;
+ }
+
+ g_gdb_debugger_receive_signal_reply(stream->owner, byte);
+ break;
+
+ case 'T':
+ assert(false); // TODO
+ break;
+
+ case 'W':
+
+ ret = read_fixed_byte(data + 1, len - 1, &byte);
+
+ if (!ret)
+ {
+ malformed = true;
+ goto gsst_processed;
+ }
+
+
+ // TODO : ";process:pid"
+
+
+ printf("Program exited (status=%hhu)\n", byte);
+
+
+ g_gdb_debugger_receive_exit_reply(stream->owner, byte, -1);
+
+
+ // log_message en cas de mauvais format...
+
+
+ break;
+
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ gsst_processed:
+
+ if (malformed && true/* TODO : config->show_... */)
+ log_variadic_message(LMT_WARNING, "Malformed GDB status reply: '%s'", data);
+
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+ }
+
return NULL;
}
@@ -253,6 +508,9 @@ GGdbPacket *g_gdb_stream_get_free_packet(GGdbStream *stream)
g_mutex_unlock(&stream->free_mutex);
+ // ???
+ //g_gdb_packet_start_new_command(result);
+
return result;
}
@@ -273,6 +531,10 @@ GGdbPacket *g_gdb_stream_get_free_packet(GGdbStream *stream)
void g_gdb_stream_mark_packet_as_free(GGdbStream *stream, GGdbPacket *packet)
{
+ //// Utile ?
+ g_gdb_packet_start_new_command(packet);
+
+
g_mutex_lock(&stream->free_mutex);
g_gdb_packet_push(&stream->free_packets, packet);
@@ -301,7 +563,12 @@ static bool g_gdb_stream_read_packet(GGdbStream *stream, GGdbPacket *packet)
char tmp[3]; /* Tampon de réception */
uint8_t checksum; /* Contrôle d'intégrité */
- result = stream->recv_byte(stream, tmp);
+ do
+ {
+ result = stream->recv_byte(stream, tmp);
+ if (tmp[0] != '+') break;
+ }
+ while (0);
if (tmp[0] != '$') return false;
@@ -309,6 +576,8 @@ static bool g_gdb_stream_read_packet(GGdbStream *stream, GGdbPacket *packet)
while ((result = stream->recv_byte(stream, tmp)))
{
+ //printf(" .. '%c'\n", tmp[0]);
+
if (tmp[0] == '#') break;
else g_gdb_packet_append(packet, tmp);
}
@@ -346,7 +615,7 @@ static bool g_gdb_stream_read_packet(GGdbStream *stream, GGdbPacket *packet)
* Remarques : - *
* *
******************************************************************************/
-
+#include <string.h>
bool g_gdb_stream_send_packet(GGdbStream *stream, GGdbPacket *packet)
{
bool result; /* Bilan à renvoyer */
@@ -355,18 +624,43 @@ bool g_gdb_stream_send_packet(GGdbStream *stream, GGdbPacket *packet)
uint8_t checksum; /* Contrôle d'intégrité */
char tmp[3]; /* Impression du checksum */
+ g_gdb_packet_get_data(packet, &data, &len, NULL);
+
+#if 1
+ /* Ack ? */
+ if (len == 1 && data[0] == '+')
+ result = stream->send_data(stream, "+", 1);
+
+ else
+#endif
+ {
+
result = stream->send_data(stream, "$", 1);
+ //result = stream->send_data(stream, "+$", 2);
g_gdb_packet_compute_checksum(packet);
g_gdb_packet_get_data(packet, &data, &len, &checksum);
+
+ if (len == 1 && data[0] == '?')
+ stream->want_status = true;
+
+ /*
+ if (memcmp(data, "vCont;c", strlen("vCont;c")) == 0)
+ stream->want_status = true;
+ */
+
+
+
result &= stream->send_data(stream, data, len);
result = stream->send_data(stream, "#", 1);
- snprintf(tmp, 3, "%hhx", checksum);
+ snprintf(tmp, 3, "%02hhx", checksum);
result &= stream->send_data(stream, tmp, 2);
+ }
+
return result;
}
diff --git a/src/debug/remgdb/stream.h b/src/debug/gdbrsp/stream.h
index f93ff60..b4b483d 100644
--- a/src/debug/remgdb/stream.h
+++ b/src/debug/gdbrsp/stream.h
@@ -21,8 +21,8 @@
*/
-#ifndef _DEBUG_REMGDB_STREAM_H
-#define _DEBUG_REMGDB_STREAM_H
+#ifndef _DEBUG_GDBRSP_STREAM_H
+#define _DEBUG_GDBRSP_STREAM_H
#include "packet.h"
@@ -48,6 +48,9 @@ typedef struct _GGdbStreamClass GGdbStreamClass;
/* Indique le type défini pour un flux de communication avec un serveur GDB. */
GType g_gdb_stream_get_type(void);
+/* Ne participe plus aux acquitements de paquets. */
+void g_gdb_stream_do_not_ack(GGdbStream *);
+
/* Fournit un paquet prêt à emploi. */
GGdbPacket *g_gdb_stream_get_free_packet(GGdbStream *);
@@ -62,4 +65,4 @@ GGdbPacket *g_gdb_stream_recv_packet(GGdbStream *);
-#endif /* _DEBUG_REMGDB_STREAM_H */
+#endif /* _DEBUG_GDBRSP_STREAM_H */
diff --git a/src/debug/gdbrsp/support.c b/src/debug/gdbrsp/support.c
new file mode 100644
index 0000000..5086540
--- /dev/null
+++ b/src/debug/gdbrsp/support.c
@@ -0,0 +1,598 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * support.c - conformité dans l'interfaçage client/serveur
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "support.h"
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/* Indications quant à l'interfaçage client/serveur GDB (instance) */
+struct _GGdbSupport
+{
+ GObject parent; /* A laisser en premier */
+
+ unsigned long packet_size; /* Taille maximale d'un paquet */
+
+ bool os_data;
+
+
+ bool extended_mode; /* Mode étendu présent & actif */
+
+
+ char *id;
+
+};
+
+/* Indications quant à l'interfaçage client/serveur GDB (classe) */
+struct _GGdbSupportClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Initialise la classe des détails d'interfaçage GDB. */
+static void g_gdb_support_class_init(GGdbSupportClass *);
+
+/* Procède à l'initialisation des détails d'interfaçage GDB. */
+static void g_gdb_support_init(GGdbSupport *);
+
+/* Supprime toutes les références externes. */
+static void g_gdb_support_dispose(GGdbSupport *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_gdb_support_finalize(GGdbSupport *);
+
+/* Lit une valeur booléenne à partir des détails du serveur. */
+static bool g_gdb_support_read_bool(GGdbSupport *, const char *, const char *, bool *);
+
+/* Lit une valeur longue à partir des détails du serveur. */
+static bool g_gdb_support_read_ulong(GGdbSupport *, const char *, const char *, unsigned long *);
+
+
+
+/* Indique le type défini par la GLib pour les détails d'interfaçage GDB. */
+G_DEFINE_TYPE(GGdbSupport, g_gdb_support, 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_support_class_init(GGdbSupportClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_gdb_support_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_gdb_support_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : support = instance de débogueur à préparer. *
+* *
+* Description : Procède à l'initialisation des détails d'interfaçage GDB. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_support_init(GGdbSupport *support)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : support = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_support_dispose(GGdbSupport *support)
+{
+ G_OBJECT_CLASS(g_gdb_support_parent_class)->dispose(G_OBJECT(support));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : support = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_gdb_support_finalize(GGdbSupport *support)
+{
+ G_OBJECT_CLASS(g_gdb_support_parent_class)->finalize(G_OBJECT(support));
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#include <string.h>
+
+static char *build_id(GGdbStream *stream)
+{
+ char *result; /* Identifiant à renvoyer */
+ GGdbPacket *packet; /* Paquet de communication */
+ bool status; /* Bilan d'une communication */
+ const char *data; /* Données reçues à analyser */
+ const char *start; /* Début d'identification */
+ const char *end; /* Fin d'identification */
+
+ result = NULL;
+
+ /* 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, "?");
+
+ status = g_gdb_stream_send_packet(stream, packet);
+
+ if (!status)
+ goto ggdgat_exit;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(stream);
+
+ g_gdb_packet_get_data(packet, &data, NULL, NULL);
+
+ start = strstr(data, "thread:");
+ if (start == NULL) goto ggdgat_exit;
+
+ start += sizeof("thread:") - 1 /* '\0' */;
+
+ end = strstr(start, ";");
+ if (end == NULL) goto ggdgat_exit;
+
+ result = strndup(start, end - start);
+
+ ggdgat_exit:
+
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+ return result;
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* 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 : - *
+* *
+******************************************************************************/
+
+GGdbSupport *g_gdb_support_new(GGdbStream *stream)
+{
+ GGdbSupport *result; /* Débogueur à retourner */
+ GGdbPacket *packet; /* Paquet de communication GDB */
+
+
+ //goto end;
+
+ //goto skip;
+
+ packet = g_gdb_stream_get_free_packet(stream);
+
+ g_gdb_packet_start_new_command(packet);
+ //g_gdb_packet_append(packet, "qSupported:multiprocess+;xmlRegisters");
+ g_gdb_packet_append(packet, "qSupported");
+
+ g_gdb_packet_append(packet, "qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+");
+
+
+ bool test;
+
+ const char *data; /* Données reçues à analyser */
+ size_t len;
+
+ test = g_gdb_stream_send_packet(stream, packet);
+
+
+
+ printf(" >> Paquet '%s' bien envoyé ? %s\n", "qSupported", 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);
+
+
+
+
+ result = g_object_new(G_TYPE_GDB_SUPPORT, NULL);
+
+
+
+ /* Découpage des éléments de réponse */
+
+ char *answer; /* Réponse modifiable */
+ char *save; /* Sauvegarde de position */
+ char *token; /* Elément de réponse cerné */
+
+ answer = strdup(data);
+
+ for (token = strtok_r(answer, ";", &save);
+ token != NULL;
+ token = strtok_r(NULL, ";", &save))
+ {
+
+
+ printf("TOKEN :: %s\n", token);
+
+ if (g_gdb_support_read_ulong(result, token, "PacketSize", &result->packet_size))
+ continue;
+
+ if (g_gdb_support_read_bool(result, token, "qXfer:osdata:read", &result->os_data))
+ {
+ printf(" -->> %d\n", result->os_data);
+ continue;
+ }
+
+
+
+
+ }
+
+ free(answer);
+
+
+
+ /**
+ * Première chose : plus d'acquitement !
+ *
+ * Dans les faits, c'est impossible à gérer en asynchrone. Par exemple :
+ *
+ * C> vCont;c
+ * C> g Txx... <S
+ *
+ * Si le client envoie une commande en même temps que le serveur envoie
+ * quelque chose, le serveur attend dans tous les cas un acquitement.
+ * Donc il va consommer les données envoyées par le client jusqu'à y
+ * trouver ce qu'il cherche.
+ */
+
+ /* 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, "QStartNoAckMode");
+
+ test = g_gdb_stream_send_packet(stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+ if (!test)
+ goto ggsn_error;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(stream);
+
+ g_gdb_packet_get_data(packet, &data, NULL, NULL);
+
+ if (strcmp(data, "OK") != 0)
+ goto ggsn_error;
+
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+ /* Désactivation des acquitements */
+
+ g_gdb_stream_do_not_ack(stream);
+
+ /**
+ * Passage en mode étendu. C'est obligatoire pour pouvoir redémarrer un
+ * programme débogué.
+ */
+
+ /* 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, "!");
+
+ test = g_gdb_stream_send_packet(stream, packet);
+
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+ if (!test)
+ goto ggsn_error;
+
+ /* Réception de la réponse */
+
+ packet = g_gdb_stream_recv_packet(stream);
+
+ g_gdb_packet_get_data(packet, &data, NULL, NULL);
+
+ result->extended_mode = (strcmp(data, "OK") == 0);
+
+ g_gdb_stream_mark_packet_as_free(stream, packet);
+
+
+
+
+ result->id = build_id(stream);
+
+
+
+#if 0
+ //end:
+
+#define CMD "?"
+
+
+ packet = g_gdb_stream_get_free_packet(stream);
+
+ g_gdb_packet_start_new_command(packet);
+ //g_gdb_packet_append(packet, "qSupported:multiprocess+;xmlRegisters");
+ g_gdb_packet_append(packet, CMD);
+
+
+ test = g_gdb_stream_send_packet(stream, packet);
+
+
+
+ printf(" >> Paquet '%s' bien envoyé ? %s\n", CMD, 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(" << [pkt = %p ] Réception de '%s' (len=%d)\n", packet, data, (int)len);
+
+
+#endif
+
+
+
+ // qfThreadInfo
+
+
+#undef CMD
+
+ //#define CMD "qXfer:threads:read::0,1fff"
+ //#define CMD "qXfer:btrace:read:all:0,1fff"
+ //#define CMD "g"
+ //#define CMD "m400000,8"
+#define CMD "qsThreadInfo"
+
+ packet = g_gdb_stream_get_free_packet(stream);
+
+ g_gdb_packet_start_new_command(packet);
+ //g_gdb_packet_append(packet, "qSupported:multiprocess+;xmlRegisters");
+ g_gdb_packet_append(packet, CMD);
+
+
+ test = g_gdb_stream_send_packet(stream, packet);
+
+
+
+ printf(" >> Paquet '%s' bien envoyé ? %s\n", CMD, 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(" << [pkt = %p ] Réception de '%s' (len=%d)\n", packet, data, (int)len);
+
+
+
+
+
+
+
+
+
+
+
+ return result;
+
+ ggsn_error:
+
+
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : support = ensemble de détails à préciser. *
+* raw = données brutes à parcourir. *
+* name = désignation de la valeur recherchée. *
+* value = emplacement de la valeur à inscrire. *
+* *
+* Description : Lit une valeur booléenne à partir des détails du serveur. *
+* *
+* Retour : true en cas d'affectation, false dans tous les autres cas. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_support_read_bool(GGdbSupport *support, const char *raw, const char *name, bool *value)
+{
+ bool result; /* Bilan à retourner */
+ size_t rlen; /* Taille de l'ensemble */
+ size_t nlen; /* Taille du nom */
+
+ rlen = strlen(raw);
+ nlen = strlen(name);
+
+ if ((nlen + 1) != rlen)
+ return false;
+
+ if (strncmp(raw, name, nlen) != 0)
+ return false;
+
+ switch (raw[nlen])
+ {
+ case '+':
+ *value = true;
+ result = true;
+ break;
+
+ case '-':
+ case '?':
+ *value = false;
+ result = true;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : support = ensemble de détails à préciser. *
+* raw = données brutes à parcourir. *
+* name = désignation de la valeur recherchée. *
+* value = emplacement de la valeur à inscrire. *
+* *
+* Description : Lit une valeur longue à partir des détails du serveur. *
+* *
+* Retour : true en cas d'affectation, false dans tous les autres cas. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_gdb_support_read_ulong(GGdbSupport *support, const char *raw, const char *name, unsigned long *value)
+{
+ size_t rlen; /* Taille de l'ensemble */
+ size_t nlen; /* Taille du nom */
+ unsigned long v; /* Valeur récupérée à assigner */
+
+ rlen = strlen(raw);
+ nlen = strlen(name);
+
+ if (strncmp(raw, name, nlen) != 0)
+ return false;
+
+ if (raw[nlen] != '=')
+ return false;
+
+ v = strtoul(raw + nlen + 1, NULL, 16);
+
+ if (v == ULONG_MAX/* && errno == ERANGE*/)
+ return false;
+
+ *value = v;
+
+ return true;
+
+}
+
+
+
+
+
+
+char *g_gdb_support_get_id(const GGdbSupport *support)
+{
+ return support->id;
+
+}
+
+
+
+
+
diff --git a/src/debug/gdbrsp/support.h b/src/debug/gdbrsp/support.h
new file mode 100644
index 0000000..6b4ab63
--- /dev/null
+++ b/src/debug/gdbrsp/support.h
@@ -0,0 +1,73 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * support.h - prototypes pour la conformité dans l'interfaçage client/serveur
+ *
+ * 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_SUPPORT_H
+#define _DEBUG_GDBRSP_SUPPORT_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "stream.h"
+
+
+
+#define G_TYPE_GDB_SUPPORT (g_gdb_support_get_type())
+#define G_GDB_SUPPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_GDB_SUPPORT, GGdbSupport))
+#define G_IS_GDB_SUPPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_GDB_SUPPORT))
+#define G_GDB_SUPPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_GDB_SUPPORT, GGdbSupportClass))
+#define G_IS_GDB_SUPPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_GDB_SUPPORT))
+#define G_GDB_SUPPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GDB_SUPPORT, GGdbSupportClass))
+
+
+/* Indications quant à l'interfaçage client/serveur GDB (instance) */
+typedef struct _GGdbSupport GGdbSupport;
+
+/* Indications quant à l'interfaçage client/serveur GDB (classe) */
+typedef struct _GGdbSupportClass GGdbSupportClass;
+
+
+/* Indique le type défini par la GLib pour les détails d'interfaçage GDB. */
+GType g_gdb_support_get_type(void);
+
+/* Crée une définition des détails d'interfaçage GDB. */
+GGdbSupport *g_gdb_support_new(GGdbStream *);
+
+
+
+
+
+
+
+char *g_gdb_support_get_id(const GGdbSupport *support);
+
+
+
+
+
+
+
+
+
+#endif /* _DEBUG_GDBRSP_SUPPORT_H */
diff --git a/src/debug/gdbrsp/target.c b/src/debug/gdbrsp/target.c
new file mode 100644
index 0000000..d6edf6c
--- /dev/null
+++ b/src/debug/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 Foobar. 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;
+
+}
diff --git a/src/debug/gdbrsp/target.h b/src/debug/gdbrsp/target.h
new file mode 100644
index 0000000..805ff49
--- /dev/null
+++ b/src/debug/gdbrsp/target.h
@@ -0,0 +1,72 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * target.h - prototypes pour la 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_TARGET_H
+#define _DEBUG_GDBRSP_TARGET_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "stream.h"
+#include "../../common/endianness.h"
+
+
+
+#define G_TYPE_GDB_TARGET (g_gdb_target_get_type())
+#define G_GDB_TARGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_GDB_TARGET, GGdbTarget))
+#define G_IS_GDB_TARGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_GDB_TARGET))
+#define G_GDB_TARGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_GDB_TARGET, GGdbTargetClass))
+#define G_IS_GDB_TARGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_GDB_TARGET))
+#define G_GDB_TARGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GDB_TARGET, GGdbTargetClass))
+
+
+/* Indications quant à l'interfaçage client/serveur GDB (instance) */
+typedef struct _GGdbTarget GGdbTarget;
+
+/* Indications quant à l'interfaçage client/serveur GDB (classe) */
+typedef struct _GGdbTargetClass GGdbTargetClass;
+
+
+/* Indique le type défini par la GLib pour les détails d'interfaçage GDB. */
+GType g_gdb_target_get_type(void);
+
+/* Crée une définition des détails d'interfaçage GDB. */
+GGdbTarget *g_gdb_target_new(GGdbStream *);
+
+/* Liste l'ensemble des registres appartenant à un groupe. */
+char **g_gdb_target_get_register_names(const GGdbTarget *, const char *, size_t *);
+
+/* Indique la taille associée à un registre donné. */
+unsigned int g_gdb_target_get_register_size(const GGdbTarget *, const char *);
+
+/* Effectue la lecture d'un registre donné. */
+bool g_gdb_target_read_register(GGdbTarget *, GGdbStream *, SourceEndian, const char *, size_t, ...);
+
+/* Effectue l'écriture d'un registre donné. */
+bool g_gdb_target_write_register(GGdbTarget *, GGdbStream *, SourceEndian, const char *, size_t, ...);
+
+
+
+#endif /* _DEBUG_GDBRSP_TARGET_H */
diff --git a/src/debug/remgdb/tcp.c b/src/debug/gdbrsp/tcp.c
index aa10c54..d6a1ef8 100644
--- a/src/debug/remgdb/tcp.c
+++ b/src/debug/gdbrsp/tcp.c
@@ -137,7 +137,7 @@ static int connect_via_tcp(const char *server, const char *port)
struct addrinfo *infos; /* Informations disponibles */
int ret; /* Bilan d'un appel */
struct addrinfo *iter; /* Boucle de parcours */
- struct sockaddr_in addr; /* Infos de connexion distante */
+ struct sockaddr_in addr; /* Infos de connexion distante */
memset(&hints, 0, sizeof(struct addrinfo));
@@ -189,6 +189,7 @@ static int connect_via_tcp(const char *server, const char *port)
* *
* Paramètres : server = nom ou adresse du serveur à contacter. *
* port = port de connexion. *
+* owner = débogueur tributaire du canal de communication. *
* *
* Description : Crée une nouvelle connexion TCP à un serveur GDB. *
* *
@@ -198,7 +199,7 @@ static int connect_via_tcp(const char *server, const char *port)
* *
******************************************************************************/
-GGdbStream *g_gdb_tcp_client_new(const char *server, const char *port)
+GGdbStream *g_gdb_tcp_client_new(const char *server, const char *port, GGdbDebugger *owner)
{
GGdbTcpClient *result; /* Structure à retourner */
int sock; /* Flux ouvert à construire */
@@ -210,6 +211,9 @@ GGdbStream *g_gdb_tcp_client_new(const char *server, const char *port)
G_GDB_STREAM(result)->fd = sock;
+ G_GDB_STREAM(result)->owner = owner;
+ g_object_ref(G_OBJECT(owner));
+
if (!g_gdb_stream_listen(G_GDB_STREAM(result)))
goto ggtcn_error;
@@ -238,7 +242,14 @@ GGdbStream *g_gdb_tcp_client_new(const char *server, const char *port)
static bool g_gdb_tcp_client_send_data(GGdbTcpClient *client, const char *data, size_t len)
{
- return (send(G_GDB_STREAM(client)->fd, data, len, 0) == len);
+ ssize_t sent; /* Quantité de données envoyée */
+
+ sent = send(G_GDB_STREAM(client)->fd, data, len, 0);
+
+ //printf(" sent '%s'\n", data);
+ //printf(" sent ? %d vs %d\n", (int)sent, (int)len);
+
+ return (sent == len);
}
@@ -258,6 +269,12 @@ static bool g_gdb_tcp_client_send_data(GGdbTcpClient *client, const char *data,
static bool g_gdb_tcp_client_recv_byte(GGdbTcpClient *client, char *data)
{
- return (recv(G_GDB_STREAM(client)->fd, data, 1, 0) == 1);
+ ssize_t got; /* Quantité de données reçue */
+
+ got = recv(G_GDB_STREAM(client)->fd, data, 1, 0);
+
+ //printf(" got ? %d vs %d -> %c (0x%02hhx\n", (int)got, (int)1, *data, *data);
+
+ return (got == 1);
}
diff --git a/src/debug/remgdb/tcp.h b/src/debug/gdbrsp/tcp.h
index 7d40f16..18d6c33 100644
--- a/src/debug/remgdb/tcp.h
+++ b/src/debug/gdbrsp/tcp.h
@@ -21,10 +21,11 @@
*/
-#ifndef _DEBUG_REMGDB_TCP_H
-#define _DEBUG_REMGDB_TCP_H
+#ifndef _DEBUG_GDBRSP_TCP_H
+#define _DEBUG_GDBRSP_TCP_H
+#include "gdb.h"
#include "stream.h"
@@ -49,8 +50,8 @@ typedef struct _GGdbTcpClientClass GGdbTcpClientClass;
GType g_gdb_tcp_client_get_type(void);
/* Crée une nouvelle connexion TCP à un serveur GDB. */
-GGdbStream *g_gdb_tcp_client_new(const char *, const char *);
+GGdbStream *g_gdb_tcp_client_new(const char *, const char *, GGdbDebugger *);
-#endif /* _DEBUG_REMGDB_TCP_H */
+#endif /* _DEBUG_GDBRSP_TCP_H */
diff --git a/src/debug/gdbrsp/utils.c b/src/debug/gdbrsp/utils.c
new file mode 100644
index 0000000..8c4cb8a
--- /dev/null
+++ b/src/debug/gdbrsp/utils.c
@@ -0,0 +1,351 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * utils.h - fonctions qui simplifient la vie dans les interactions avec un serveur 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "utils.h"
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+
+
+/******************************************************************************
+* *
+* Paramètres : data = données à inspecter. *
+* len = quantité de ces données. *
+* *
+* Description : Indique si les données correspondent à un code d'erreur. *
+* *
+* Retour : Bilan de l'analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool is_error_code(const char *data, size_t len)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (len == 3);
+
+ if (result)
+ result = (data[0] == 'E' && isdigit(data[1]) && isdigit(data[2]));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = données à analyser. *
+* size = taille de ces données. *
+* byte = statut de sortie d'un programme. [OUT] *
+* *
+* Description : Relit une valeur sur 8 bits et deux lettres. *
+* *
+* Retour : Bilan de la lecture. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool read_fixed_byte(const char *data, size_t len, uint8_t *byte)
+{
+ bool result; /* Bilan à retourner */
+ const char *iter; /* Boucle de parcours #1 */
+ size_t i; /* Boucle de parcours #2 */
+ uint8_t nibble; /* Valeur affichée */
+
+ result = true;
+
+ len = MIN(2, len);
+
+ for (i = 0, iter = data; i < len && result; i++, iter++)
+ {
+ switch (*iter)
+ {
+ case '0' ... '9':
+ nibble = *iter - '0';
+ break;
+
+ case 'a' ... 'f':
+ nibble = *iter - 'a' + 10;
+ break;
+
+ case 'A' ... 'F':
+ nibble = *iter - 'A' + 10;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ if (i == 0)
+ *byte = (nibble << 4);
+ else
+ *byte |= nibble;
+
+ }
+
+ if (result)
+ result = (i == 2);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : hex = tampon d'origine assez grand. *
+* size = taille de la valeur à considérer pour les travaux. *
+* value = valeur sur XX bits à transcrire. [OUT] *
+* *
+* Description : Traduit en valeur sur XX bits une forme textuelle. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool hex_to_any_u(const char *hex, size_t size, ...)
+{
+ bool result; /* Bilan à retourner */
+ va_list ap; /* Gestion de l'inconnue */
+ uint8_t *value8; /* Valeur sur 8 bits */
+ uint16_t *value16; /* Valeur sur 16 bits */
+ uint32_t *value32; /* Valeur sur 32 bits */
+ uint64_t *value64; /* Valeur sur 64 bits */
+ uint8_t *iter; /* Boucle de parcours #1 */
+ size_t i; /* Boucle de parcours #2 */
+ char nibble; /* Valeur à afficher */
+
+ result = false;
+
+ /* Récupération de la destination */
+
+ va_start(ap, size);
+
+ switch (size)
+ {
+ case 1:
+ value8 = va_arg(ap, uint8_t *);
+ iter = value8;
+ break;
+
+ case 2:
+ value16 = va_arg(ap, uint16_t *);
+ iter = (uint8_t *)value16;
+ break;
+
+ case 4:
+ value32 = va_arg(ap, uint32_t *);
+ iter = (uint8_t *)value32;
+ break;
+
+ case 8:
+ value64 = va_arg(ap, uint64_t *);
+ iter = (uint8_t *)value64;
+ break;
+
+ default:
+ goto done;
+ break;
+
+ }
+
+ /* Lecture de la valeur */
+
+ for (i = 0; i < size; i++, iter++)
+ {
+ *iter = 0;
+
+ nibble = hex[i * 2];
+
+ switch (nibble)
+ {
+ case '0' ... '9':
+ *iter = (nibble - '0') << 4;
+ break;
+
+ case 'a' ... 'f':
+ *iter = (nibble - 'a' + 0xa) << 4;
+ break;
+
+ case 'A' ... 'F':
+ *iter = (nibble - 'A' + 0xa) << 4;
+ break;
+
+ default:
+ goto done;
+ break;
+
+ }
+
+ nibble = hex[i * 2 + 1];
+
+ switch (nibble)
+ {
+ case '0' ... '9':
+ *iter |= (nibble - '0');
+ break;
+
+ case 'a' ... 'f':
+ *iter |= (nibble - 'a' + 0xa);
+ break;
+
+ case 'A' ... 'F':
+ *iter |= (nibble - 'A' + 0xa);
+ break;
+
+ default:
+ goto done;
+ break;
+
+ }
+
+ }
+
+ result = (i == size);
+
+ done:
+
+ va_end(ap);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : size = taille de la valeur à considérer pour les travaux. *
+* hex = tampon de destination assez grand. *
+* value = valeur sur XX bits à transcrire. [OUT] *
+* *
+* Description : Traduit une valeur sur XX bits en forme textuelle. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool any_u_to_hex(size_t size, char hex[17], ...)
+{
+ bool result; /* Bilan à retourner */
+ va_list ap; /* Gestion de l'inconnue */
+ uint8_t *value8; /* Valeur sur 8 bits */
+ uint16_t *value16; /* Valeur sur 16 bits */
+ uint32_t *value32; /* Valeur sur 32 bits */
+ uint64_t *value64; /* Valeur sur 64 bits */
+ size_t i; /* Boucle de parcours #1 */
+ const uint8_t *iter; /* Boucle de parcours #2 */
+ uint8_t nibble; /* Valeur à retenir */
+
+ result = true;
+
+ /* Récupération de la destination */
+
+ va_start(ap, hex);
+
+ switch (size)
+ {
+ case 1:
+ value8 = va_arg(ap, uint8_t *);
+ iter = (const uint8_t *)value8;
+ break;
+
+ case 2:
+ value16 = va_arg(ap, uint16_t *);
+ iter = (const uint8_t *)value16;
+ break;
+
+ case 4:
+ value32 = va_arg(ap, uint32_t *);
+ iter = (const uint8_t *)value32;
+ break;
+
+ case 8:
+ value64 = va_arg(ap, uint64_t *);
+ iter = (const uint8_t *)value64;
+ break;
+
+ default:
+ result = false;
+ goto done;
+ break;
+
+ }
+
+ /* Lecture de la valeur */
+
+ for (i = 0; i < size; i++, iter++)
+ {
+ nibble = (*iter & 0xf0) >> 4;
+
+ switch (nibble)
+ {
+ case 0x0 ... 0x9:
+ hex[i * 2] = '0' + nibble;
+ break;
+
+ case 0xa ... 0xf:
+ hex[i * 2] = 'A' + nibble - 0xa;
+ break;
+
+ }
+
+ nibble = (*iter & 0x0f);
+
+ switch (nibble)
+ {
+ case 0x0 ... 0x9:
+ hex[i * 2 + 1] = '0' + nibble;
+ break;
+
+ case 0xa ... 0xf:
+ hex[i * 2 + 1] = 'A' + nibble - 0xa;
+ break;
+
+ }
+
+ }
+
+ hex[size * 2] = '\0';
+
+ done:
+
+ va_end(ap);
+
+ return result;
+
+}
diff --git a/src/debug/gdbrsp/utils.h b/src/debug/gdbrsp/utils.h
new file mode 100644
index 0000000..a67df46
--- /dev/null
+++ b/src/debug/gdbrsp/utils.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * utils.h - prototypes pour les fonctions qui simplifient la vie dans les interactions avec un serveur 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_GDBRSP_UTILS_H
+#define _DEBUG_GDBRSP_UTILS_H
+
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+
+
+/* Indique si les données correspondent à un code d'erreur. */
+bool is_error_code(const char *, size_t);
+
+/* Relit une valeur sur 8 bits et deux lettres. */
+bool read_fixed_byte(const char *, size_t, uint8_t *);
+
+/* Traduit en valeur sur XX bits une forme textuelle. */
+bool hex_to_any_u(const char *, size_t, ...);
+
+#define hex_to_u8(h, v) hex_to_any_u(h, 1, v)
+#define hex_to_u16(h, v) hex_to_any_u(h, 2, v)
+#define hex_to_u32(h, v) hex_to_any_u(h, 4, v)
+#define hex_to_u64(h, v) hex_to_any_u(h, 8, v)
+
+/* Traduit une valeur sur XX bits en forme textuelle. */
+bool any_u_to_hex(size_t, char [17], ...);
+
+#define u8_to_hex(v, h) any_u_to_hex(1, h, v)
+#define u16_to_hex(v, h) any_u_to_hex(2, h, v)
+#define u32_to_hex(v, h) any_u_to_hex(4, h, v)
+#define u64_to_hex(v, h) any_u_to_hex(8, h, v)
+
+
+
+#endif /* _DEBUG_GDBRSP_UTILS_H */
diff --git a/src/debug/misc.h b/src/debug/misc.h
new file mode 100644
index 0000000..dd9492a
--- /dev/null
+++ b/src/debug/misc.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * misc.h - prototypes pour les définitions communes et génériques liées au débogage
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DEBUG_MISC_H
+#define _DEBUG_MISC_H
+
+
+#include <stdint.h>
+
+
+
+/* Couverture maximale des identifiants */
+typedef uint64_t dbg_thread_id_t;
+
+
+
+#endif /* _DEBUG_MISC_H */
diff --git a/src/debug/remgdb/Makefile.am b/src/debug/remgdb/Makefile.am
deleted file mode 100644
index 47e5fdc..0000000
--- a/src/debug/remgdb/Makefile.am
+++ /dev/null
@@ -1,17 +0,0 @@
-
-noinst_LTLIBRARIES = libdebugremgdb.la
-
-libdebugremgdb_la_SOURCES = \
- gdb.h gdb.c \
- helpers.h helpers.c \
- packet.h packet.c \
- stream-int.h \
- stream.h stream.c \
- tcp.h tcp.c
-
-libdebugremgdb_la_CFLAGS = $(AM_CFLAGS)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/src/debug/remgdb/gdb.c b/src/debug/remgdb/gdb.c
deleted file mode 100644
index 728eee6..0000000
--- a/src/debug/remgdb/gdb.c
+++ /dev/null
@@ -1,363 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * gdb.c - débogage à l'aide de gdb.
- *
- * Copyright (C) 2009-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 <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);
-
-
-
-
-}
diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c
index 51107c5..789661e 100644
--- a/src/gtkext/gtkstatusstack.c
+++ b/src/gtkext/gtkstatusstack.c
@@ -845,6 +845,8 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
progress_info *info; /* Informations à consulter */
size_t new; /* Indice de l'activité créée */
+ if (stack == NULL) return 0;
+
info = stack->prog_info;
g_mutex_lock(&info->access);
@@ -904,6 +906,8 @@ void gtk_status_stack_extend_activity(GtkStatusStack *stack, activity_id_t id, u
progress_info *info; /* Informations à consulter */
size_t i; /* Boucle de parcours */
+ if (stack == NULL) return;
+
info = stack->prog_info;
g_mutex_lock(&info->access);
@@ -941,6 +945,8 @@ void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, c
size_t i; /* Boucle de parcours */
bool msg_changed; /* Changement d'intitulé */
+ if (stack == NULL) return;
+
info = stack->prog_info;
g_mutex_lock(&info->access);
@@ -1008,6 +1014,8 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t
progress_status *status; /* Raccourci de confort */
double new; /* Nouvelle progression */
+ if (stack == NULL) return;
+
info = stack->prog_info;
g_mutex_lock(&info->access);
@@ -1061,6 +1069,8 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
progress_info *info; /* Informations à consulter */
size_t i; /* Boucle de parcours */
+ if (stack == NULL) return;
+
info = stack->prog_info;
g_mutex_lock(&info->access);