#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)
{
}
-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;
}
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;
}
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;
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;
}
{
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;