fixing leak
[oweals/gnunet.git] / src / monkey / action_api.c
index c1f39e7887c31be582ee5b36f1c97961ec8d1dfa..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>
 
+extern void sendMail (const char *messageContents, const char *emailAddress);
 
-int GNUNET_MONKEY_ACTION_report_file()
+
+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)
+{
+ printf("CONSOLE> %s\n",str);
+}
+
+
+/* Note that unlike what's documented in gdb docs it isn't usable. */
+static void cb_target(const char *str, void *data)
+{
+ printf("TARGET> %s\n",str);
+}
+
+
+static void cb_log(const char *str, void *data)
+{
+ printf("LOG> %s\n",str);
+}
+
+
+static void cb_to(const char *str, void *data)
+{
+ printf(">> %s",str);
+}
+
+
+static void cb_from(const char *str, void *data)
 {
+ printf("<< %s\n",str);
+}
+
+
+static void cb_async(mi_output *o, void *data)
+{
+ printf("ASYNC\n");
+ async_c++;
+}
+
+
+static int wait_for_stop(mi_h *h, struct GNUNET_MONKEY_ACTION_Context *cntxt)
+{
+       while (!mi_get_response(h))
+               usleep(1000);
+       /* The end of the async. */
+       cntxt->gdb_stop_reason=mi_res_stop(h);
+       if (cntxt->gdb_stop_reason)
+       {
+               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);
+
+               return GDB_STATE_STOPPED;
+       }
+       return GDB_STATE_ERROR;
+}
+
+
+int GNUNET_MONKEY_ACTION_report_file(struct GNUNET_MONKEY_ACTION_Context* cntxt, const char* dumpFileName)
+{
+       FILE* file = fopen(dumpFileName, "w");
+       GNUNET_assert(NULL != file);
+       fprintf(file,"%s", cntxt->debug_report);
+       fclose(file);
        return GNUNET_OK;
 }
 
 
-int GNUNET_MONKEY_ACTION_report_email()
+int GNUNET_MONKEY_ACTION_report_email(struct GNUNET_MONKEY_ACTION_Context* cntxt)
 {
+       if (cntxt->debug_mode == DEBUG_MODE_REPORT_READY)
+               sendMail(cntxt->debug_report, cntxt->email_address);
+
        return GNUNET_OK;
 }
 
@@ -46,9 +128,178 @@ 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]);
+
 
-int GNUNET_MONKEY_ACTION_rerun_with_gdb()
+       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;
+
+       /* This is like a file-handle for fopen.
+           Here we have all the state of gdb "connection". */
+       if (NULL != cntxt->gdb_binary_path)
+               mi_set_gdb_exe(cntxt->gdb_binary_path);
+       int ret;
+
+        /* Connect to gdb child. */
+       cntxt->gdb_handle = mi_connect_local();
+        if (!cntxt->gdb_handle)
+          {
+           printf("Connect failed\n");
+           return GNUNET_NO;
+          }
+        printf("Connected to gdb!\n");
+
+        /* Set all callbacks. */
+        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(cntxt->gdb_handle);
+           return GNUNET_NO;
+          }
+
+        /* Tell gdb to attach the child to a terminal. */
+        if (!gmi_target_terminal(cntxt->gdb_handle, ttyname(STDIN_FILENO)))
+          {
+           printf("Error selecting target terminal\n");
+           mi_disconnect(cntxt->gdb_handle);
+           return GNUNET_NO;
+          }
+
+        /* Run the program. */
+        if (!gmi_exec_run(cntxt->gdb_handle))
+          {
+           printf("Error in run!\n");
+           mi_disconnect(cntxt->gdb_handle);
+           return GNUNET_NO;
+          }
+        /* Here we should be stopped when the program crashes */
+        ret = wait_for_stop(cntxt->gdb_handle, cntxt);
+        if (ret != GDB_STATE_ERROR)
+           mi_disconnect(cntxt->gdb_handle);
+
+       return ret;
+}
+
+
+int GNUNET_MONKEY_ACTION_format_report(struct GNUNET_MONKEY_ACTION_Context* cntxt)
+{
+       switch (cntxt->debug_mode) {
+       case DEBUG_MODE_GDB:
+               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;
+       case DEBUG_MODE_VALGRIND:
+               break;
+       default:
+               break;
+       }
+
+       cntxt->debug_mode = DEBUG_MODE_REPORT_READY;
        return GNUNET_OK;
 }