fixing leak
[oweals/gnunet.git] / src / monkey / action_api.c
index 6c7441ad7ce6e3778f81e8500ac2408dc0bde59f..0412c7630a3c1ca9ee473cef06c3e86fcbe087d5 100644 (file)
 #include "platform.h"
 #include "gnunet_common.h"
 #include "gnunet_monkey_action.h"
+#include "gnunet_monkey_edb.h"
+#include "gnunet_container_lib.h"
 #include <libesmtp.h>
 
-
-#define DEBUG_MODE_GDB 0
-#define DEBUG_MODE_VALGRIND 1
-#define DEBUG_MODE_REPORT_READY 2
-
-extern void sendMail (const char *messageContents);
+extern void sendMail (const char *messageContents, const char *emailAddress);
 
 
 static int async_c=0;
+static struct Expression *expressionListHead = NULL;
+static struct Expression *expressionListTail = NULL;
 
+struct Expression {
+       struct Expression *next;
+       struct Expression *prev;
+       const char* expressionSyntax;
+       int lineNo;
+};
 
 static void cb_console(const char *str, void *data)
 {
@@ -77,32 +82,24 @@ static void cb_async(mi_output *o, void *data)
 }
 
 
-static int wait_for_stop(mi_h *h)
+static int wait_for_stop(mi_h *h, struct GNUNET_MONKEY_ACTION_Context *cntxt)
 {
-       int res=1;
-       mi_stop *sr;
-       mi_frames *f;
-
        while (!mi_get_response(h))
                usleep(1000);
        /* The end of the async. */
-       sr=mi_res_stop(h);
-       if (sr)
+       cntxt->gdb_stop_reason=mi_res_stop(h);
+       if (cntxt->gdb_stop_reason)
        {
-               f = gmi_stack_info_frame(h);
-               if (NULL == f)
-                       printf("f is NULL!\n");
-               if (NULL == f)
+               if (cntxt->gdb_stop_reason->reason == sr_exited_normally)
+                       return GDB_STATE_EXIT_NORMALLY;
+
+               cntxt->gdb_frames = gmi_stack_info_frame(h);
+               if (NULL == cntxt->gdb_frames)
                  GNUNET_break(0);
 
-               mi_free_stop(sr);
-               res = 0;
-       }
-       else
-       {
-       res=0;
+               return GDB_STATE_STOPPED;
        }
-       return res;
+       return GDB_STATE_ERROR;
 }
 
 
@@ -119,7 +116,7 @@ int GNUNET_MONKEY_ACTION_report_file(struct GNUNET_MONKEY_ACTION_Context* cntxt,
 int GNUNET_MONKEY_ACTION_report_email(struct GNUNET_MONKEY_ACTION_Context* cntxt)
 {
        if (cntxt->debug_mode == DEBUG_MODE_REPORT_READY)
-               sendMail(cntxt->debug_report);
+               sendMail(cntxt->debug_report, cntxt->email_address);
 
        return GNUNET_OK;
 }
@@ -131,19 +128,117 @@ int GNUNET_MONKEY_ACTION_rerun_with_valgrind()
        return GNUNET_OK;
 }
 
+static int iterateExpressions(void *cls, int numColumns, char **colValues, char **colNames)
+{
+       struct Expression *expression;
+
+       if (NULL == colValues[0] || NULL == colValues[1])
+               return 1; /* Error */
+
+       expression = GNUNET_malloc(sizeof(struct Expression));
+       expression->expressionSyntax = strdup(colValues[0]);
+       expression->lineNo = atoi(colValues[1]);
+
+
+       GNUNET_CONTAINER_DLL_insert(expressionListHead, expressionListTail, expression);
+
+       return 0; /* OK */
+}
+
+
+static int scopeEndCallback(void *cls, int numColumns, char **colValues, char ** colNames)
+{
+       int *scopeEnd = (int*) cls;
+
+       *scopeEnd = atoi(colValues[0]);
+       if (*scopeEnd < 0)
+               return 1; /* Error */
+       return 0;
+}
+
+
+static int analyzeSegmentationFault(struct GNUNET_MONKEY_ACTION_Context *cntxt)
+{
+       struct Expression *faultyExpression;
+       struct Expression *tmp;
+       int expressionLength = 0;
+       mi_wp *watchPoint;
+
+       tmp = expressionListHead;
+       while (NULL != tmp) {
+               if ((tmp->lineNo == cntxt->gdb_frames->line)
+                               && (strlen(tmp->expressionSyntax) > expressionLength)) {
+                       expressionLength = strlen(tmp->expressionSyntax);
+                       faultyExpression = tmp;
+               }
+               tmp = tmp->next;
+       }
+
+       /* Set watch points on the faulty-expression's subexpressions */
+       tmp = expressionListHead;
+       while (NULL != tmp) {
+               if (tmp != faultyExpression) {
+                       /* Only subexpressions are interesting */
+                        watchPoint = gmi_break_watch(cntxt->gdb_handle, wm_write, tmp->expressionSyntax);
+                        if (!watchPoint)
+                          {
+                           printf("Error in setting watchpoint\n");
+                           return 1;
+                          }
+                        printf("Watchpoint %d for expression: %s\n", watchPoint->number, watchPoint->exp);
+                        mi_free_wp(watchPoint);
+               }
+               tmp = tmp->next;
+       }
+       return GNUNET_OK;
+}
+
+
+int GNUNET_MONKEY_ACTION_inspect_expression_database(struct GNUNET_MONKEY_ACTION_Context *cntxt)
+{
+       struct GNUNET_MONKEY_EDB_Context *edbCntxt;
+       int ret = GNUNET_OK;
+       int endScope;
+
+       edbCntxt = GNUNET_MONKEY_EDB_connect(cntxt->expression_database_path);
+       if (NULL == edbCntxt) {
+               GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Unable to connect to Expression Database file!\n");
+               return GNUNET_NO;
+       }
+
+       ret = GNUNET_MONKEY_EDB_get_expression_scope_end(edbCntxt,
+                                          cntxt->gdb_frames->file, cntxt->gdb_frames->line,
+                                          &scopeEndCallback, &endScope);
+       if (endScope < 0)
+               return GNUNET_NO;
+
+       ret = GNUNET_MONKEY_EDB_get_expressions (edbCntxt,
+                                          cntxt->gdb_frames->file, cntxt->gdb_frames->line,
+                                          endScope,
+                                          &iterateExpressions,
+                                          NULL);
+
+       if (strcasecmp(cntxt->gdb_stop_reason->signal_meaning, "Segmentation fault") == 0)
+               analyzeSegmentationFault(cntxt);
+
+       GNUNET_MONKEY_EDB_disconnect(edbCntxt);
+       return ret;
+}
+
 
 int GNUNET_MONKEY_ACTION_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cntxt)
 {
        cntxt->debug_mode = DEBUG_MODE_GDB;
-       mi_aux_term *xterm_tty=NULL;
 
        /* This is like a file-handle for fopen.
            Here we have all the state of gdb "connection". */
-        mi_h *h;
+       if (NULL != cntxt->gdb_binary_path)
+               mi_set_gdb_exe(cntxt->gdb_binary_path);
+       int ret;
 
         /* Connect to gdb child. */
-        h = mi_connect_local();
-        if (!h)
+       cntxt->gdb_handle = mi_connect_local();
+        if (!cntxt->gdb_handle)
           {
            printf("Connect failed\n");
            return GNUNET_NO;
@@ -151,67 +246,42 @@ int GNUNET_MONKEY_ACTION_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cnt
         printf("Connected to gdb!\n");
 
         /* Set all callbacks. */
-        mi_set_console_cb(h,cb_console,NULL);
-        mi_set_target_cb(h,cb_target,NULL);
-        mi_set_log_cb(h,cb_log,NULL);
-        mi_set_async_cb(h,cb_async,NULL);
-        mi_set_to_gdb_cb(h,cb_to,NULL);
-        mi_set_from_gdb_cb(h,cb_from,NULL);
-
-        /* Set the name of the child and the command line aguments. */
-        if (!gmi_set_exec(h, cntxt->binary_name, NULL))
+        mi_set_console_cb(cntxt->gdb_handle,cb_console,NULL);
+        mi_set_target_cb(cntxt->gdb_handle,cb_target,NULL);
+        mi_set_log_cb(cntxt->gdb_handle,cb_log,NULL);
+        mi_set_async_cb(cntxt->gdb_handle,cb_async,NULL);
+        mi_set_to_gdb_cb(cntxt->gdb_handle,cb_to,NULL);
+        mi_set_from_gdb_cb(cntxt->gdb_handle,cb_from,NULL);
+
+        /* Set the name of the child and the command line arguments. */
+        if (!gmi_set_exec(cntxt->gdb_handle, cntxt->binary_name, NULL))
           {
            printf("Error setting exec y args\n");
-           mi_disconnect(h);
+           mi_disconnect(cntxt->gdb_handle);
            return GNUNET_NO;
           }
 
         /* Tell gdb to attach the child to a terminal. */
-        if (!gmi_target_terminal(h, ttyname(STDIN_FILENO)))
+        if (!gmi_target_terminal(cntxt->gdb_handle, ttyname(STDIN_FILENO)))
           {
            printf("Error selecting target terminal\n");
-           mi_disconnect(h);
+           mi_disconnect(cntxt->gdb_handle);
            return GNUNET_NO;
           }
 
         /* Run the program. */
-        if (!gmi_exec_run(h))
+        if (!gmi_exec_run(cntxt->gdb_handle))
           {
            printf("Error in run!\n");
-           mi_disconnect(h);
+           mi_disconnect(cntxt->gdb_handle);
            return GNUNET_NO;
           }
         /* Here we should be stopped when the program crashes */
-        if (!wait_for_stop(h))
-          {
-           mi_disconnect(h);
-           return GNUNET_NO;
-          }
-
-        /* Continue execution. */
-        if (!gmi_exec_continue(h))
-          {
-           printf("Error in continue!\n");
-           mi_disconnect(h);
-           return GNUNET_NO;
-          }
-        /* Here we should be terminated. */
-        if (!wait_for_stop(h))
-          {
-           mi_disconnect(h);
-           return GNUNET_NO;
-          }
-
-        /* Exit from gdb. */
-        gmi_gdb_exit(h);
-        /* Close the connection. */
-        mi_disconnect(h);
-        /* Wait 5 seconds and close the auxiliar terminal. */
-        printf("Waiting 5 seconds\n");
-        sleep(5);
-        gmi_end_aux_term(xterm_tty);
+        ret = wait_for_stop(cntxt->gdb_handle, cntxt);
+        if (ret != GDB_STATE_ERROR)
+           mi_disconnect(cntxt->gdb_handle);
 
-       return GNUNET_OK;
+       return ret;
 }
 
 
@@ -219,7 +289,7 @@ int GNUNET_MONKEY_ACTION_format_report(struct GNUNET_MONKEY_ACTION_Context* cntx
 {
        switch (cntxt->debug_mode) {
        case DEBUG_MODE_GDB:
-               GNUNET_asprintf(&cntxt->debug_report,
+               GNUNET_asprintf(&(cntxt->debug_report),
                        "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n",
                        cntxt->gdb_frames->file, cntxt->gdb_frames->func, cntxt->gdb_frames->line, mi_reason_enum_to_str(cntxt->gdb_stop_reason->reason), cntxt->gdb_stop_reason->signal_name, cntxt->gdb_stop_reason->signal_meaning);
                break;