summaryrefslogtreecommitdiff
path: root/src/analysis/db/items/comment.c
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 /src/analysis/db/items/comment.c
parent18be9204f2f6b054f254d1fa045039952ddfad41 (diff)
Created storable items for user comments.
Diffstat (limited to 'src/analysis/db/items/comment.c')
-rw-r--r--src/analysis/db/items/comment.c460
1 files changed, 449 insertions, 11 deletions
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;
}