summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2016-01-23 17:48:50 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2016-01-23 17:48:50 (GMT)
commitadb98feb93f09d8de343c504a0c8c72815d62dab (patch)
treec345bf863252c2384b946b8ebfa315cda88b8ba9
parent18be9204f2f6b054f254d1fa045039952ddfad41 (diff)
Created storable items for user comments.
-rw-r--r--plugins/pychrysa/analysis/db/items/comment.c3
-rw-r--r--src/analysis/db/collection.c39
-rw-r--r--src/analysis/db/items/bookmark.c2
-rw-r--r--src/analysis/db/items/comment.c460
-rw-r--r--src/analysis/db/items/comment.h6
-rw-r--r--src/analysis/db/items/switcher.c2
-rw-r--r--src/analysis/disass/output.c2
-rw-r--r--src/common/sqlite.h5
-rw-r--r--src/format/symbol.h20
-rw-r--r--src/glibext/gbufferline.c59
-rw-r--r--src/glibext/gbufferline.h3
-rw-r--r--src/glibext/gcodebuffer.c74
-rw-r--r--src/glibext/gcodebuffer.h7
13 files changed, 634 insertions, 48 deletions
diff --git a/plugins/pychrysa/analysis/db/items/comment.c b/plugins/pychrysa/analysis/db/items/comment.c
index 951f6ce..ead5179 100644
--- a/plugins/pychrysa/analysis/db/items/comment.c
+++ b/plugins/pychrysa/analysis/db/items/comment.c
@@ -81,7 +81,8 @@ static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject
addr = get_internal_vmpa(py_vmpa);
if (py_vmpa == NULL) Py_RETURN_NONE;
- comment = g_db_comment_new(addr, text, is_volatile);
+ return NULL;/* FIXME */
+ //comment = g_db_comment_new(addr, text, is_volatile);
result = pygobject_new(G_OBJECT(comment));
g_object_unref(comment);
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index d5518dd..aa7591e 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -992,15 +992,21 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
/**
* On réalise une petite conversion selon le champ.
*
- * Le filtre SQLITE_NATIVE est destiné à conserver un champ sur 32 bits
- * quand il s'agit du format utilisé, même si toutes les valeurs sont
- * enregistrées en 64 bits.
+ * Le filtre SQLITE_NATIVE est destiné à conserver le type choisi par
+ * SQLite. Typiquement, une chaîne peut être à SQLITE_NULL ou SQLITE_TEXT
+ * selon la valeur conservée dans la base.
*
- * C'est par exemple le cas dans les bascules d'affichage.
- *
- * D'autres éléments, comme les localisations en mémoire, peuvent
+ * D'autres éléments, comme les localisations en mémoire, peuvent aussi
* avoir un champ éventuellement nul, donc la définition à partir des
* indications de la base de données reste importante.
+ *
+ * En ce qui concerne les valeurs numériques, SQLite ne fait pas de
+ * distinction : tout passe par la fonction sqlite3VdbeIntValue(),
+ * qui effectue des transtypages au besoin pour tout ce qui n'est
+ * pas numérique.
+ *
+ * Pour les types internes SQLITE_INTEGER et SQLITE_BOOLEAN,
+ * il est donc nécessaire d'ajuster en interne.
*/
if (native_type == SQLITE_INTEGER)
@@ -1010,13 +1016,18 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
values[i].type = native_type;
else
- assert(values[i].type == native_type || values[i].type == SQLITE_INTEGER);
-
+ assert(values[i].type == native_type
+ || values[i].type == SQLITE_INTEGER
+ || values[i].type == SQLITE_BOOLEAN);
switch (values[i].type)
{
+ case SQLITE_BOOLEAN:
+ values[i].boolean = (bool)sqlite3_column_int(stmt, i);
+ break;
+
case SQLITE_INTEGER:
- values[i].integer = (int)sqlite3_column_int64(stmt, i);
+ values[i].integer = sqlite3_column_int(stmt, i);
break;
case SQLITE_INT64:
@@ -1142,6 +1153,11 @@ static bool g_db_collection_store_item(const GDbCollection *collec, const GDbIte
{
switch (values[i].type)
{
+ case SQLITE_BOOLEAN:
+ ret = sqlite3_bind_int(stmt, index, values[i].boolean);
+ index++;
+ break;
+
case SQLITE_INTEGER:
ret = sqlite3_bind_int(stmt, index, values[i].integer);
index++;
@@ -1301,6 +1317,11 @@ static bool g_db_collection_store_updated_item(const GDbCollection *collec, cons
switch (values[i].type)
{
+ case SQLITE_BOOLEAN:
+ ret = sqlite3_bind_int(stmt, index, values[i].boolean);
+ index++;
+ break;
+
case SQLITE_INTEGER:
ret = sqlite3_bind_int(stmt, index, values[i].integer);
index++;
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 6914bc3..4c93faf 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -393,7 +393,7 @@ static void g_db_bookmark_build_label(GDbBookmark *bookmark)
* *
* Paramètres : bookmark = signet à manipuler. *
* binary = binaire chargé en mémoire à modifier. *
-* prev = état précédent de la présence du drapeau. *
+* prev = état précédent de la présence du drapeau. [OUT] *
* set = précision quant au nouvel état du drapeau. *
* *
* Description : Exécute un signet sur un tampon de binaire chargé. *
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index 9212cae..b4a1dc0 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -24,12 +24,18 @@
#include "comment.h"
+#include <assert.h>
+#include <malloc.h>
#include <stdio.h>
#include <sys/socket.h>
+#include <i18n.h>
+
+
#include "../collection-int.h"
#include "../item-int.h"
+#include "../../../common/io.h"
@@ -42,8 +48,21 @@ struct _GDbComment
GDbItem parent; /* A laisser en premier */
vmpa2t addr; /* Adresse du commentaire */
+ BufferLineFlags flags; /* Identification de l'accroche*/
+
rle_string text; /* Contenu du commentaire */
+ bool inlined; /* Intégration dans une ligne ?*/
+
+ union
+ {
+ bool repeatable; /* Répétition aux lignes liées */
+ bool before; /* Zone dédiée au dessus ? */
+ };
+
+ GDbComment **oldies; /* Commentaires d'origine ? */
+ size_t old_count; /* Nombre de places à restaurer*/
+
};
/* Commentaire à placer dans du texte quelconque (classe) */
@@ -75,6 +94,18 @@ static bool g_db_comment_recv_from_fd(GDbComment *, int, int);
/* Exporte la définition d'un commentaire dans un flux réseau. */
static bool g_db_comment_send_to_fd(const GDbComment *, int, int);
+/* Construit la description humaine d'un commentaire. */
+static void g_db_comment_build_label(GDbComment *);
+
+/* Exécute l'impression de commentaire dans du code de binaire. */
+static bool g_db_comment_run(GDbComment *, GLoadedBinary *, bool);
+
+/* Réalise l'impression de commentaire dans du code de binaire. */
+static bool g_db_comment_apply(GDbComment *, GLoadedBinary *);
+
+/* Annule l'impression d'un commentaire dans du code de binaire. */
+static bool g_db_comment_cancel(GDbComment *, GLoadedBinary *);
+
/* Constitue les champs destinés à une insertion / modification. */
static bool g_db_comment_prepare_db_statement(const GDbComment *, bound_value **, size_t *);
@@ -162,6 +193,10 @@ static void g_db_comment_class_init(GDbCommentClass *klass)
item->recv = (recv_db_item_fc)g_db_comment_recv_from_fd;
item->send = (send_db_item_fc)g_db_comment_send_to_fd;
+ item->build_label = (build_item_label_fc)g_db_comment_build_label;
+ item->apply = (run_item_fc)g_db_comment_apply;
+ item->cancel = (run_item_fc)g_db_comment_cancel;
+
item->prepare_stmt = (prepare_db_statement)g_db_comment_prepare_db_statement;
item->load = (load_db_item_fc)g_db_comment_load;
@@ -200,6 +235,14 @@ static void g_db_comment_init(GDbComment *comment)
static void g_db_comment_dispose(GDbComment *comment)
{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < comment->old_count; i++)
+ g_object_unref(G_OBJECT(comment->oldies[i]));
+
+ if (comment->oldies != NULL)
+ free(comment->oldies);
+
G_OBJECT_CLASS(g_db_comment_parent_class)->dispose(G_OBJECT(comment));
}
@@ -228,9 +271,10 @@ static void g_db_comment_finalize(GDbComment *comment)
/******************************************************************************
* *
-* Paramètres : addr = adresse inamovible localisant une position. *
-* text = commentaire construit ou NULL. *
-* is_volatile = état du besoin en sauvegarde. *
+* Paramètres : addr = adresse inamovible localisant une position. *
+* flags = indentifiants supplémentaires de ligne visée. *
+* text = commentaire construit ou NULL. *
+* repeatable = repétition aux instructions liées ? *
* *
* Description : Crée une définition de commentaire dans une zone de texte. *
* *
@@ -240,7 +284,7 @@ static void g_db_comment_finalize(GDbComment *comment)
* *
******************************************************************************/
-GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volatile)
+GDbComment *g_db_comment_new_inlined(const vmpa2t *addr, BufferLineFlags flags, const char *text, bool repeatable)
{
GDbComment *result; /* Instance à retourner */
@@ -248,9 +292,49 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat
copy_vmpa(&result->addr, addr);
+ result->flags = flags;
+
g_db_comment_set_text(result, text);
- g_db_item_set_volatile(G_DB_ITEM(result), is_volatile);
+ result->inlined = true;
+
+ result->repeatable = repeatable;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : addr = adresse inamovible localisant une position. *
+* flags = indentifiants supplémentaires de ligne visée. *
+* text = commentaire construit ou NULL. *
+* before = précision quant à la position de la zone à définir. *
+* *
+* Description : Crée une définition de commentaire dans une zone de texte. *
+* *
+* Retour : Commentaire mis en place ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GDbComment *g_db_comment_new_area(const vmpa2t *addr, BufferLineFlags flags, const char *text, bool before)
+{
+ GDbComment *result; /* Instance à retourner */
+
+ result = g_object_new(G_TYPE_DB_COMMENT, NULL);
+
+ copy_vmpa(&result->addr, addr);
+
+ result->flags = flags;
+
+ g_db_comment_set_text(result, text);
+
+ result->inlined = false;
+
+ result->before = before;
return result;
@@ -305,6 +389,8 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b, bool with)
static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
{
bool status; /* Bilan d'opération initiale */
+ uint32_t val32; /* Valeur sur 32 bits */
+ uint8_t val8; /* Valeur sur 8 bits */
status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->recv(G_DB_ITEM(comment), fd, flags);
if (!status) return false;
@@ -312,9 +398,24 @@ static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
if (!recv_vmpa(&comment->addr, fd, flags))
return false;
+ status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags);
+ if (!status) return false;
+
+ comment->flags = be32toh(val32);
+
if (!recv_rle_string(&comment->text, fd, flags))
return false;
+ status = safe_recv(fd, &val8, sizeof(uint8_t), MSG_WAITALL | flags);
+ if (!status) return false;
+
+ comment->inlined = val8;
+
+ status = safe_recv(fd, &val8, sizeof(uint8_t), MSG_WAITALL | flags);
+ if (!status) return false;
+
+ comment->repeatable = val8;
+
return true;
}
@@ -344,9 +445,18 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags
if (!send_vmpa(&comment->addr, fd, MSG_MORE | flags))
return false;
- if (!send_rle_string(&comment->text, fd, flags))
+ status = safe_send(fd, (uint32_t []) { htobe32(comment->flags) }, sizeof(uint32_t), MSG_MORE | flags);
+ if (!status) return false;
+
+ if (!send_rle_string(&comment->text, fd, MSG_MORE | flags))
return false;
+ status = safe_send(fd, (uint8_t []) { (uint8_t)comment->inlined }, sizeof(uint8_t), MSG_MORE | flags);
+ if (!status) return false;
+
+ status = safe_send(fd, (uint8_t []) { (uint8_t)comment->repeatable }, sizeof(uint8_t), flags);
+ if (!status) return false;
+
return true;
}
@@ -354,6 +464,250 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags
/******************************************************************************
* *
+* Paramètres : comment = définition de commentaire à manipuler. *
+* *
+* Description : Construit la description humaine d'un commentaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_db_comment_build_label(GDbComment *comment)
+{
+ VMPA_BUFFER(loc); /* Indication de position */
+
+ if (has_virt_addr(&comment->addr))
+ vmpa2_virt_to_string(&comment->addr, MDS_UNDEFINED, loc, NULL);
+ else
+ vmpa2_phys_to_string(&comment->addr, MDS_UNDEFINED, loc, NULL);
+
+ if (is_rle_string_empty(&comment->text))
+ asprintf(&G_DB_ITEM(comment)->label, _("Delete comment at %s"), loc);
+
+ else
+ {
+ if (comment->inlined)
+ asprintf(&G_DB_ITEM(comment)->label, _("Enter inlined comment at %s"), loc);
+ else
+ asprintf(&G_DB_ITEM(comment)->label, _("Enter comment area at %s"), loc);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : comment = définition de commentaire à manipuler. *
+* binary = binaire chargé en mémoire à modifier. *
+* apply = indique s'il faut appliquer la définition ou non. *
+* *
+* Description : Exécute l'impression de commentaire dans du code de binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool apply)
+{
+ bool result; /* Bilan à faire remonter */
+ GCodeBuffer *buffer; /* Tampon de lignes à traiter */
+ GBufferLine *line; /* Ligne de tampon à marquer */
+ GArchProcessor *proc; /* Propriétaire d'instructions */
+ GArchInstruction *instr; /* Instruction à traiter */
+ GArchInstruction **sources; /* Instructions diverses liées */
+ size_t scount; /* Nbre de sources affichées */
+ size_t i; /* Boucle de parcours */
+ const mrange_t *range; /* Emplacement d'instruction */
+ GBufferLine *linked; /* Ligne liée à traiter */
+ GDbComment *old; /* Ancien élément à restaurer */
+
+ result = true;
+
+ /* Recherche de la ligne visée */
+
+ buffer = g_loaded_binary_get_disassembled_buffer(binary);
+
+ line = g_code_buffer_find_line_by_addr(buffer, &comment->addr, comment->flags, NULL);
+ if (line == NULL)
+ {
+ result = false;
+ goto exit_gui;
+ }
+
+ /* Détermination de l'imprimeur précédent */
+
+ if (apply)
+ {
+ assert(comment->old_count == 0);
+
+ comment->old_count = 1;
+ comment->oldies = (GDbComment **)calloc(comment->old_count, sizeof(GDbComment *));
+
+ }
+
+ /* Applications globales finales */
+
+#define g_code_buffer_update_inlined_comment_dummy(b, l, c, d, o) \
+ g_code_buffer_update_inlined_comment(b, l, c, o)
+
+ /**
+ * Note : on part du principe qu'un commentaire intégré ne peut remplacer qu'un
+ * commentaire intégré. Et pareil pour les commentaires en blocs.
+ */
+
+#define RUN_COMMENT_ON(ln, idx, func) \
+ if (apply) \
+ { \
+ comment->oldies[idx] = (GDbComment *)g_code_buffer_get_comment_creator(buffer, ln); \
+ assert(comment->oldies[idx] == NULL || G_IS_DB_COMMENT(comment->oldies[idx])); \
+ assert(comment->oldies[idx] == NULL || comment->oldies[idx]->inlined == comment->inlined); \
+ \
+ if (is_rle_string_empty(&comment->text)) \
+ result = g_code_buffer_delete_lines_comment(buffer, ln); \
+ else \
+ result = func(buffer, ln, get_rle_string(&comment->text), \
+ comment->before, G_OBJECT(comment)); \
+ } \
+ else \
+ { \
+ old = comment->oldies[idx]; \
+ \
+ if (old == NULL) \
+ { \
+ if (!is_rle_string_empty(&comment->text)) \
+ result = g_code_buffer_delete_lines_comment(buffer, ln); \
+ else \
+ result = true; \
+ } \
+ else \
+ { \
+ if (is_rle_string_empty(&old->text)) \
+ result = g_code_buffer_delete_lines_comment(buffer, ln); \
+ else \
+ result = func(buffer, ln, get_rle_string(&old->text), \
+ old->before, G_OBJECT(old)); \
+ } \
+ \
+ }
+
+ if (comment->inlined)
+ {
+ /* Traitement d'un commentaire inscrusté */
+
+ RUN_COMMENT_ON(line, 0, g_code_buffer_update_inlined_comment_dummy);
+
+ /* Traitement des répétitions ? */
+
+ if (comment->repeatable/* && result*/)
+ {
+ proc = g_loaded_binary_get_processor(binary);
+
+ range = g_buffer_line_get_range(line);
+
+ instr = g_arch_processor_find_instr_by_address(proc, get_mrange_addr(range));
+ assert(instr != NULL);
+
+ scount = g_arch_instruction_get_sources(instr, &sources, NULL);
+
+ if (apply)
+ {
+ comment->old_count += scount;
+ comment->oldies = (GDbComment **)realloc(comment->oldies,
+ comment->old_count * sizeof(GDbComment *));
+ }
+
+ for (i = 0; i < scount && result; i++)
+ {
+ range = g_arch_instruction_get_range(sources[i]);
+
+ /**
+ * On recherche ici une ligne potentiellement BLF_HAS_CODE ou BLF_IS_LABEL.
+ * Comme on ne peut pas traiter les deux cas, on prend la première qui vient
+ * avec BLF_NONE.
+ */
+ linked = g_code_buffer_find_line_by_addr(buffer, get_mrange_addr(range), BLF_NONE, NULL);
+ assert(linked != NULL);
+
+ RUN_COMMENT_ON(linked, 1 + i, g_code_buffer_update_inlined_comment_dummy);
+
+ }
+
+ g_object_unref(G_OBJECT(proc));
+
+ }
+
+ }
+
+ else
+ {
+ RUN_COMMENT_ON(line, 0, g_code_buffer_update_comment_area);
+ }
+
+ g_object_unref(G_OBJECT(line));
+
+ exit_gui:
+
+ /* TODO g_object_unref(G_OBJECT(buffer));*/
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : comment = définition de commentaire à manipuler. *
+* binary = binaire chargé en mémoire à modifier. *
+* *
+* Description : Réalise l'impression de commentaire dans du code de binaire. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_db_comment_apply(GDbComment *comment, GLoadedBinary *binary)
+{
+ bool result; /* Bilan à faire remonter */
+
+ result = g_db_comment_run(comment, binary, true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : comment = définition de commentaire à manipuler. *
+* binary = binaire chargé en mémoire à modifier. *
+* *
+* Description : Annule l'impression d'un commentaire dans du code de binaire.*
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_db_comment_cancel(GDbComment *comment, GLoadedBinary *binary)
+{
+ bool result; /* Bilan à faire remonter */
+
+ result = g_db_comment_run(comment, binary, false);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : comment = base d'éléments sur laquelle s'appuyer. *
* values = couples de champs et de valeurs à lier. [OUT] *
* count = nombre de ces couples. [OUT] *
@@ -369,6 +723,7 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags
static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_value **values, size_t *count)
{
bool status; /* Bilan d'opération initiale */
+ bound_value *value; /* Valeur à éditer / définir */
status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->prepare_stmt(G_DB_ITEM(comment), values, count);
if (!status) return false;
@@ -376,9 +731,36 @@ static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_v
status = prepare_vmpa_db_statement(&comment->addr, values, count);
if (!status) return false;
+ *count += 1;
+ *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+ value = &(*values)[*count - 1];
+
+ value->name = "flags";
+ value->type = SQLITE_INTEGER;
+ value->integer = comment->flags;
+ value->delete = NULL;
+
status &= prepare_db_statement_for_rle_string(&comment->text, "text", values, count);
if (!status) return false;
+ *count += 2;
+ *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+ value = &(*values)[*count - 2];
+
+ value->name = "inlined";
+ value->type = SQLITE_BOOLEAN;
+ value->boolean = comment->inlined;
+ value->delete = NULL;
+
+ value = &(*values)[*count - 1];
+
+ value->name = "repeatable";
+ value->type = SQLITE_BOOLEAN;
+ value->boolean = comment->repeatable;
+ value->delete = NULL;
+
return true;
}
@@ -401,13 +783,44 @@ static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_v
static bool g_db_comment_load(GDbComment *comment, const bound_value *values, size_t count)
{
bool result; /* Bilan à faire remonter */
+ const bound_value *value; /* Valeur à éditer / définir */
result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->load(G_DB_ITEM(comment), values, count);
result &= load_vmpa(&comment->addr, values, count);
+ if (result)
+ {
+ value = find_bound_value(values, count, "flags");
+ result = (value != NULL && value->type == SQLITE_INTEGER);
+
+ if (result)
+ comment->flags = value->integer;
+
+ }
+
result &= load_rle_string(&comment->text, "text", values, count);
+ if (result)
+ {
+ value = find_bound_value(values, count, "inlined");
+ result = (value != NULL && value->type == SQLITE_BOOLEAN);
+
+ if (result)
+ comment->inlined = value->boolean;
+
+ }
+
+ if (result)
+ {
+ value = find_bound_value(values, count, "repeatable");
+ result = (value != NULL && value->type == SQLITE_BOOLEAN);
+
+ if (result)
+ comment->repeatable = value->boolean;
+
+ }
+
return result;
}
@@ -526,7 +939,7 @@ static void g_comment_collection_class_init(GCommentCollectionClass *klass)
static void g_comment_collection_init(GCommentCollection *collec)
{
- G_DB_COLLECTION(collec)->featuring = 0;
+ G_DB_COLLECTION(collec)->featuring = DBF_COMMENTS;
G_DB_COLLECTION(collec)->type = G_TYPE_DB_COMMENT;
G_DB_COLLECTION(collec)->name = "Comments";
@@ -613,10 +1026,13 @@ static bool g_comment_collection_create_db_table(const GCommentCollection *colle
int ret; /* Bilan de la création */
char *msg; /* Message d'erreur */
- sql = "CREATE TABLE Comments (" \
- SQLITE_DB_ITEM_CREATE ", " \
- SQLITE_VMPA_CREATE ", " \
- SQLITE_RLESTR_CREATE("text") \
+ sql = "CREATE TABLE Comments (" \
+ SQLITE_DB_ITEM_CREATE ", " \
+ SQLITE_VMPA_CREATE ", " \
+ "flags INTEGER, " \
+ SQLITE_RLESTR_CREATE("text") ", " \
+ "inlined INTEGER, " \
+ "repeatable INTEGER" \
");";
ret = sqlite3_exec(db, sql, NULL, NULL, &msg);
@@ -648,6 +1064,7 @@ static bool g_comment_collection_create_db_table(const GCommentCollection *colle
static bool g_comment_collection_setup_load(GCommentCollection *collec, bound_value **values, size_t *count)
{
bool status; /* Bilan d'une préparation */
+ bound_value *value; /* Valeur à éditer / définir */
status = G_DB_COLLECTION_CLASS(g_comment_collection_parent_class)->setup_load(G_DB_COLLECTION(collec), \
values, count);
@@ -656,9 +1073,30 @@ static bool g_comment_collection_setup_load(GCommentCollection *collec, bound_va
if (!setup_load_for_vmpa(NULL, values, count))
return false;
+ *count += 1;
+ *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+ value = &(*values)[*count - 1];
+
+ value->name = "flags";
+ value->type = SQLITE_INTEGER;
+
if (!setup_load_of_rle_string(NULL, "text", values, count))
return false;
+ *count += 2;
+ *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+ value = &(*values)[*count - 2];
+
+ value->name = "inlined";
+ value->type = SQLITE_BOOLEAN;
+
+ value = &(*values)[*count - 1];
+
+ value->name = "repeatable";
+ value->type = SQLITE_BOOLEAN;
+
return true;
}
diff --git a/src/analysis/db/items/comment.h b/src/analysis/db/items/comment.h
index 316f4c5..dc9addc 100644
--- a/src/analysis/db/items/comment.h
+++ b/src/analysis/db/items/comment.h
@@ -32,6 +32,7 @@
#include "../../../arch/vmpa.h"
+#include "../../../glibext/gbufferline.h"
@@ -57,7 +58,10 @@ typedef struct _GDbCommentClass GDbCommentClass;
GType g_db_comment_get_type(void);
/* Crée une définition de commentaire dans une zone de texte. */
-GDbComment *g_db_comment_new(const vmpa2t *, const char *, bool);
+GDbComment *g_db_comment_new_inlined(const vmpa2t *, BufferLineFlags, const char *, bool);
+
+/* Crée une définition de commentaire dans une zone de texte. */
+GDbComment *g_db_comment_new_area(const vmpa2t *, BufferLineFlags, const char *, bool);
/* Fournit l'adresse associée à un commentaire. */
const vmpa2t *g_db_comment_get_address(GDbComment *);
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 7b72cf2..6497e41 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -481,7 +481,7 @@ static void g_db_switcher_build_label(GDbSwitcher *switcher)
* *
* Paramètres : switcher = bascule d'affichage à manipuler. *
* binary = binaire chargé en mémoire à modifier. *
-* old = état précédent à conserver. *
+* old = état précédent à conserver. [OUT] *
* new = nouvel état à appliquer. *
* *
* Description : Exécute une bascule d'affichage d'opérande sur un binaire. *
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 75444a5..07165c0 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -269,6 +269,8 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form
if (comment != NULL)
{
+ /* FIXME : appliquer ! */
+
text = g_db_comment_get_text(comment);
diff --git a/src/common/sqlite.h b/src/common/sqlite.h
index 2036589..064972b 100644
--- a/src/common/sqlite.h
+++ b/src/common/sqlite.h
@@ -25,6 +25,7 @@
#define _COMMON_SQLITE_H
+#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
@@ -33,7 +34,8 @@
/* Type pour les insertions brutes */
#define SQLITE_RAW 0 /* En dur dans une requête */
#define SQLITE_INT64 10 /* Entier sur 64 bits */
-#define SQLITE_NATIVE 11 /* Déterminé par la base */
+#define SQLITE_BOOLEAN 11 /* Booléen sur 1 bit */
+#define SQLITE_NATIVE 12 /* Déterminé par la base */
/* Description des champs et de leur valeur associée */
@@ -44,6 +46,7 @@ typedef struct _bound_value
union
{
+ bool boolean; /* Etat sur 1 bit */
int32_t integer; /* Nombre sur 32 bits */
int64_t integer64; /* Nombre sur 64 bits */
char *string; /* Chaîne de caractères #1 */
diff --git a/src/format/symbol.h b/src/format/symbol.h
index 94003bb..6f2078c 100644
--- a/src/format/symbol.h
+++ b/src/format/symbol.h
@@ -29,6 +29,7 @@
#include "../analysis/routine.h"
+#include "../analysis/db/item.h"
#include "../analysis/db/items/comment.h"
#include "../arch/instruction.h"
@@ -129,15 +130,16 @@ GDbComment *g_binary_symbol_get_comment(const GBinSymbol *);
} \
while (0)
-#define ADD_RAW_AS_SYM(_fmt, _sym, _pos, _ins, _cmt, _txt) \
- do \
- { \
- _cmt = g_db_comment_new(_pos, _txt, true); \
- _sym = g_binary_symbol_new(STP_DATA); \
- g_binary_symbol_attach_instruction(_sym, _ins); \
- g_binary_symbol_set_comment(_sym, _cmt); \
- g_binary_format_add_symbol(G_BIN_FORMAT(_fmt), _sym); \
- } \
+#define ADD_RAW_AS_SYM(_fmt, _sym, _pos, _ins, _cmt, _txt) \
+ do \
+ { \
+ _cmt = g_db_comment_new_inlined(_pos, BLF_HAS_CODE, _txt, false); \
+ g_db_item_set_volatile(G_DB_ITEM(_cmt), true); \
+ _sym = g_binary_symbol_new(STP_DATA); \
+ g_binary_symbol_attach_instruction(_sym, _ins); \
+ g_binary_symbol_set_comment(_sym, _cmt); \
+ g_binary_format_add_symbol(G_BIN_FORMAT(_fmt), _sym); \
+ } \
while (0)
#define ADD_STR_AS_SYM(_fmt, _sym, _ins) \
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index 2f29ee4..b8838ae 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -78,6 +78,9 @@ static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScr
static GBufferSegment *find_near_segment(const buffer_line_column *, GBufferSegment *, GdkScrollDirection);
/* Fournit le segment créé par un objet particulier. */
+static GObject *find_first_segment_creator(const buffer_line_column *);
+
+/* Fournit le segment créé par un objet particulier. */
static GBufferSegment *find_segment_from_creator(const buffer_line_column *, GObject *);
/* Imprime le contenu d'une colonne de ligne de texte. */
@@ -410,6 +413,33 @@ static GBufferSegment *find_near_segment(const buffer_line_column *column, GBuff
/******************************************************************************
* *
+* Paramètres : column = colonne de ligne de texte à consulter. *
+* *
+* Description : Fournit le segment créé par un objet particulier. *
+* *
+* Retour : Créateur trouvé à déréférencer par la suite ou NULL si échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GObject *find_first_segment_creator(const buffer_line_column *column)
+{
+ GObject *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ for (i = 0; i < column->count && result == NULL; i++)
+ result = g_buffer_segment_get_creator(column->segments[i]);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : column = colonne de ligne de texte à consulter. *
* creator = créateur à l'origine du segment recherché. *
* *
@@ -1165,6 +1195,35 @@ GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBuffer
/******************************************************************************
* *
+* Paramètres : line = ligne à venir consulter. *
+* column = indice de la colonne visée par les recherches. *
+* *
+* Description : Recherche le premier créateur enregistré dans des segments. *
+* *
+* Retour : Créateur trouvé à déréférencer par la suite ou NULL si échec.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, BufferLineColumn column)
+{
+ GObject *result; /* Trouvaille à retourner */
+
+ assert(column < BLC_COUNT);
+
+ result = find_first_segment_creator(&line->columns[column]);
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : line = ligne à venir consulter. *
* creator = créateur à l'origine du segment recherché. *
* *
diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h
index 19652ab..89313be 100644
--- a/src/glibext/gbufferline.h
+++ b/src/glibext/gbufferline.h
@@ -120,6 +120,9 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const gint [BL
/* Fournit le segment voisin d'un autre segment identifié. */
GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegment *, const gint [BLC_COUNT], const bool *, GdkScrollDirection, gint *);
+/* Recherche le premier créateur enregistré dans des segments. */
+GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn);
+
/* Fournit le segment créé par un objet particulier. */
GBufferSegment *g_buffer_line_find_segment_from_creator(const GBufferLine *, GObject *);
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index f96212c..be7fa37 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -158,10 +158,10 @@ static void g_code_buffer_insert_lines_at(GCodeBuffer *, GBufferLine **, size_t,
/* Affiche un commentaire sur une ligne de tampon donnée. */
-static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *, GBufferLine *, const char *);
+static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *, GBufferLine *, const char *, GObject *);
/* Affiche un commentaire sur une ligne de tampon dédiée. */
-static bool _g_code_buffer_write_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool);
+static bool _g_code_buffer_write_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool, GObject *);
/* Retrouve la première ligne d'une zone de commentaire. */
static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *, size_t);
@@ -453,6 +453,7 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar)
* Paramètres : buffer = tampon de lignes à consulter. *
* line = ligne à l'intérieur d'un commentaire. *
* comment = nouveau commentaire à inscrire à la ligne donnée. *
+* creator = créateur à l'origine de la construction. *
* *
* Description : Affiche un commentaire sur une ligne de tampon donnée. *
* *
@@ -462,7 +463,7 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar)
* *
******************************************************************************/
-static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment)
+static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
{
bool result; /* Bilan à retourner */
const mrange_t *range; /* Emplace de ligne à utiliser */
@@ -472,6 +473,7 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
char *saveptr; /* Sauvegarde pour la sécurité */
char *token; /* Fragment à insérer */
size_t len; /* Taille dudit fragment */
+ GBufferSegment *segment; /* Segment à marquer au fer */
GBufferLine *new; /* Nouvelle ligne créée */
size_t i; /* Boucle de parcours */
@@ -493,12 +495,17 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
len = strlen(token);
if (!result)
- g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT);
+ {
+ segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT);
+ g_buffer_segment_set_creator(segment, creator);
+ }
else
{
new = g_code_buffer_prepare_new_line(buffer, range);
- g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT);
+
+ segment = g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT);
+ g_buffer_segment_set_creator(segment, creator);
extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
@@ -534,6 +541,7 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
* Paramètres : buffer = tampon de lignes à consulter. *
* line = ligne à l'intérieur d'un commentaire. *
* comment = nouveau commentaire à inscrire à la ligne donnée. *
+* creator = créateur à l'origine de la construction. *
* *
* Description : Affiche un commentaire sur une ligne de tampon donnée. *
* *
@@ -543,7 +551,7 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
* *
******************************************************************************/
-bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment)
+bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
{
bool result; /* Bilan à retourner */
@@ -553,7 +561,7 @@ bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line
result = true;
if (result)
- result = _g_code_buffer_write_inlined_comment(buffer, line, comment);
+ result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator);
/* TODO : emit() */
@@ -568,6 +576,7 @@ bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line
* line = ligne à l'intérieur d'un commentaire. *
* comment = nouveau commentaire à inscrire à la ligne donnée. *
* before = précise la position du commentaire. *
+* creator = créateur à l'origine de la construction. *
* *
* Description : Affiche un commentaire sur une ligne de tampon dédiée. *
* *
@@ -577,7 +586,7 @@ bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line
* *
******************************************************************************/
-static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before)
+static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
{
bool result; /* Bilan à retourner */
const mrange_t *range; /* Emplace de ligne à utiliser */
@@ -588,6 +597,7 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
char *token; /* Fragment à insérer */
size_t len; /* Taille dudit fragment */
GBufferLine *new; /* Nouvelle ligne créée */
+ GBufferSegment *segment; /* Segment à marquer au fer */
size_t i; /* Boucle de parcours */
assert(!g_buffer_line_has_comment(line));
@@ -609,7 +619,9 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
new = g_code_buffer_prepare_new_line(buffer, range);
g_buffer_line_start_merge_at(new, BLC_DISPLAY);
- g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT);
+
+ segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT);
+ g_buffer_segment_set_creator(segment, creator);
extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
@@ -644,6 +656,7 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
* line = ligne à l'intérieur d'un commentaire. *
* comment = nouveau commentaire à inscrire à la ligne donnée. *
* before = précise la position du commentaire. *
+* creator = créateur à l'origine de la construction. *
* *
* Description : Affiche un commentaire sur une ligne de tampon dédiée. *
* *
@@ -653,7 +666,7 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
* *
******************************************************************************/
-bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before)
+bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
{
bool result; /* Bilan à retourner */
@@ -663,7 +676,7 @@ bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, c
result = true;
if (result)
- result = _g_code_buffer_write_comment_area(buffer, line, comment, before);
+ result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator);
/* TODO : emit() */
@@ -873,6 +886,43 @@ static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, si
* Paramètres : buffer = tampon de lignes à consulter. *
* line = ligne à l'intérieur d'un commentaire. *
* *
+* Description : Retrouve le créateur d'un commentaire existant. *
+* *
+* Retour : Instance trouvée à déréférencer ensuite ou NULL si aucune. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line)
+{
+ GObject *result; /* Instance à retourner */
+ BufferLineColumn merge_col; /* Colonne de fusion */
+
+ if (g_buffer_line_has_comment(line))
+ {
+ merge_col = g_buffer_line_get_merge_start(line);
+
+ if (merge_col == BLC_DISPLAY)
+ result = g_buffer_line_find_first_segment_creator(line, BLC_DISPLAY);
+ else
+ result = g_buffer_line_find_first_segment_creator(line, BLC_COMMENTS);
+
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : buffer = tampon de lignes à consulter. *
+* line = ligne à l'intérieur d'un commentaire. *
+* *
* Description : Récupère le contenu d'un commentaire existant. *
* *
* Retour : Commentaire retrouver à libérer ou NULL en cas d'échec. *
@@ -1536,7 +1586,7 @@ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vm
result = buffer->lines[index];
if (flags != BLF_NONE)
- while ((g_buffer_line_get_flags(result) & flags) == 0)
+ while ((g_buffer_line_get_flags(result) & flags) != flags)
{
if ((index + 1) == buffer->used) break;
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index d04ed76..8bcbc4a 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -111,10 +111,13 @@ GDelayedWork *g_buffer_code_scan(GCodeBuffer *, const vmpa2t *, const vmpa2t *,
/* Affiche un commentaire sur une ligne de tampon donnée. */
-bool g_code_buffer_update_inlined_comment(GCodeBuffer *, GBufferLine *, const char *);
+bool g_code_buffer_update_inlined_comment(GCodeBuffer *, GBufferLine *, const char *, GObject *);
/* Affiche un commentaire sur une ligne de tampon dédiée. */
-bool g_code_buffer_update_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool);
+bool g_code_buffer_update_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool, GObject *);
+
+/* Retrouve le créateur d'un commentaire existant. */
+GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *, const GBufferLine *);
/* Récupère le contenu d'un commentaire existant. */
char *g_code_buffer_get_lines_comment(const GCodeBuffer *, const GBufferLine *);