From 06c08bc0f341f99e6939bc5e7b448645de5a9961 Mon Sep 17 00:00:00 2001 From: "Safey A.Halim" Date: Thu, 2 Jun 2011 09:27:35 +0000 Subject: [PATCH] Monkey supports Assertions, and inspects user-defined expressions --- src/monkey/Makefile.am | 6 +- src/monkey/action_api.c | 651 +++++++++++++++++++---------- src/monkey/bug_assertion_failure.c | 15 + src/monkey/gnunet-monkey.c | 243 ++++++----- src/monkey/gnunet_monkey_action.h | 69 ++- 5 files changed, 626 insertions(+), 358 deletions(-) create mode 100644 src/monkey/bug_assertion_failure.c diff --git a/src/monkey/Makefile.am b/src/monkey/Makefile.am index effa37bd4..b1d6cb89b 100644 --- a/src/monkey/Makefile.am +++ b/src/monkey/Makefile.am @@ -41,7 +41,8 @@ bin_PROGRAMS = \ noinst_PROGRAMS = \ bug_null_pointer_exception \ - bug_bad_memory_access + bug_bad_memory_access \ + bug_assertion_failure gnunet_monkey_SOURCES = \ gdbmi.h \ @@ -84,6 +85,9 @@ bug_null_pointer_exception: bug_bad_memory_access: gcc -g -O0 -o bug_bad_memory_access bug_bad_memory_access.c +bug_assertion_failure: + gcc -g -O0 -o bug_assertion_failure bug_assertion_failure.c + check_PROGRAMS = \ test_monkey_edb #test_gnunet_monkey diff --git a/src/monkey/action_api.c b/src/monkey/action_api.c index db73f070a..7614ad844 100644 --- a/src/monkey/action_api.c +++ b/src/monkey/action_api.c @@ -33,322 +33,513 @@ extern void sendMail (const char *messageContents, const char *emailAddress); -static int async_c=0; +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; +struct Expression +{ + struct Expression *next; + struct Expression *prev; + const char *expressionSyntax; + int lineNo; }; -static void cb_console(const char *str, void *data) +static void +cb_console (const char *str, void *data) { - printf("CONSOLE> %s\n",str); + 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) +static void +cb_target (const char *str, void *data) { - printf("TARGET> %s\n",str); + printf ("TARGET> %s\n", str); } -static void cb_log(const char *str, void *data) +static void +cb_log (const char *str, void *data) { - printf("LOG> %s\n",str); + printf ("LOG> %s\n", str); } -static void cb_to(const char *str, void *data) +static void +cb_to (const char *str, void *data) { - printf(">> %s",str); + printf (">> %s", str); } -static void cb_from(const char *str, void *data) +static void +cb_from (const char *str, void *data) { - printf("<< %s\n",str); + printf ("<< %s\n", str); } -static void cb_async(mi_output *o, void *data) +static void +cb_async (mi_output * o, void *data) { - printf("ASYNC\n"); - async_c++; + printf ("ASYNC\n"); + async_c++; } -static int wait_for_stop(mi_h *h, struct GNUNET_MONKEY_ACTION_Context *cntxt) +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) + 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); + + if (0 == cntxt->gdb_frames->line) { - 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; + /* + * This happens if the program stops in a shared library (inner frames) + * We will move to outer frames until reaching the faulty line in the source code + */ + cntxt->gdb_frames = gmi_stack_list_frames (cntxt->gdb_handle); + do + { + cntxt->gdb_frames = cntxt->gdb_frames->next; + } + while (0 == cntxt->gdb_frames->line); } - return GDB_STATE_ERROR; + + return GDB_STATE_STOPPED; + } + return GDB_STATE_ERROR; } -int GNUNET_MONKEY_ACTION_report_file(struct GNUNET_MONKEY_ACTION_Context* cntxt, const char* dumpFileName) +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; + 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(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, cntxt->email_address); + if (cntxt->debug_mode == DEBUG_MODE_REPORT_READY) + sendMail (cntxt->debug_report, cntxt->email_address); - return GNUNET_OK; + return GNUNET_OK; } -static int iterateExpressions(void *cls, int numColumns, char **colValues, char **colNames) +static int +iterateExpressions (void *cls, int numColumns, char **colValues, + char **colNames) { - struct Expression *expression; + struct Expression *expression; - if (NULL == colValues[0] || NULL == colValues[1]) - return 1; /* Error */ + 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]); + expression = GNUNET_malloc (sizeof (struct Expression)); + expression->expressionSyntax = strdup (colValues[0]); + expression->lineNo = atoi (colValues[1]); + printf ("Inserting expression:%s", expression->expressionSyntax); + GNUNET_CONTAINER_DLL_insert (expressionListHead, expressionListTail, + expression); - GNUNET_CONTAINER_DLL_insert(expressionListHead, expressionListTail, expression); - - return 0; /* OK */ + return 0; /* OK */ } -static int scopeEndCallback(void *cls, int numColumns, char **colValues, char ** colNames) +static int +scopeEndCallback (void *cls, int numColumns, char **colValues, + char **colNames) { - int *scopeEnd = (int*) cls; + int *scopeEnd = (int *) cls; - *scopeEnd = atoi(colValues[0]); - if (*scopeEnd < 0) - return 1; /* Error */ - return 0; + *scopeEnd = atoi (colValues[0]); + if (*scopeEnd < 0) + return 1; /* Error */ + return 0; } -static int analyzeSegmentationFault(struct GNUNET_MONKEY_ACTION_Context *cntxt) +static struct Expression * +getFaultyExpression (struct GNUNET_MONKEY_ACTION_Context *cntxt) { - struct Expression *faultyExpression = NULL; - 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; + struct Expression *faultyExpression = NULL; + struct Expression *tmp = NULL; + int expressionLength = 0; + + 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; + } - if (NULL != faultyExpression) { - tmp = expressionListHead; - while (NULL != tmp) { - const char* eval; - if (tmp != faultyExpression) { - eval = gmi_data_evaluate_expression(cntxt->gdb_handle, tmp->expressionSyntax); - if (NULL != eval && strcmp(eval, "0x0") == 0) { - cntxt->gdb_null_variable = tmp->expressionSyntax; - return GNUNET_OK; - } - } - tmp = tmp->next; + return faultyExpression; +} + +static int +analyzeSegmentationFault (struct GNUNET_MONKEY_ACTION_Context *cntxt) +{ + struct Expression *faultyExpression = NULL; + struct Expression *tmp; + int expressionLength = 0; + + + faultyExpression = getFaultyExpression (cntxt); + + if (NULL != faultyExpression) + { + tmp = expressionListHead; + while (NULL != tmp) + { + const char *eval; + if (tmp != faultyExpression) + { + eval = + gmi_data_evaluate_expression (cntxt->gdb_handle, + tmp->expressionSyntax); + if (NULL != eval + && (strcmp (eval, "0x0") == 0 + || strcmp (eval, "NULL") == 0)) + { + cntxt->gdb_null_variable = tmp->expressionSyntax; + return GNUNET_OK; } + } + tmp = tmp->next; } - /* Set watch points on the faulty-expression's subexpressions */ -// if (NULL != faultyExpression) { -// 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; -// } - return GDB_STATE_ERROR; + } + /* Set watch points on the faulty-expression's subexpressions */ +// if (NULL != faultyExpression) { +// 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; +// } + return GDB_STATE_ERROR; } -int GNUNET_MONKEY_ACTION_inspect_expression_database(struct GNUNET_MONKEY_ACTION_Context *cntxt) + +static int +analyzeCustomFault (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; + struct Expression *tmp; + struct Expression *faultyExpression = getFaultyExpression (cntxt); + struct Variable *variable; + if (NULL != faultyExpression) + { + tmp = expressionListHead; + while (NULL != tmp) + { + const char *eval; + if (tmp != faultyExpression) + { + eval = + gmi_data_evaluate_expression (cntxt->gdb_handle, + tmp->expressionSyntax); + variable = GNUNET_malloc (sizeof (struct Variable)); + variable->name = tmp->expressionSyntax; + variable->value = eval; + GNUNET_CONTAINER_DLL_insert (cntxt->variable_list_head, + cntxt->variable_list_tail, + variable); + } + tmp = tmp->next; } + } + return GNUNET_OK; +} - 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) - ret = analyzeSegmentationFault(cntxt); - GNUNET_MONKEY_EDB_disconnect(edbCntxt); - mi_disconnect(cntxt->gdb_handle); - return ret; +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; + const char *signalMeaning = cntxt->gdb_stop_reason->signal_meaning; + + 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 (signalMeaning, "Segmentation fault") == 0) + { + cntxt->bug_detected = BUG_NULL_POINTER; + ret = analyzeSegmentationFault (cntxt); + } + else if (strcasecmp (signalMeaning, "Aborted") == 0) + { + cntxt->bug_detected = BUG_CUSTOM; + ret = analyzeCustomFault (cntxt); + } + + GNUNET_MONKEY_EDB_disconnect (edbCntxt); + mi_disconnect (cntxt->gdb_handle); + return ret; } -int GNUNET_MONKEY_ACTION_rerun_with_valgrind(struct GNUNET_MONKEY_ACTION_Context* cntxt) { - FILE* valgrindPipe; - int size; - char* valgrindCommand; - cntxt->debug_mode = DEBUG_MODE_VALGRIND; - GNUNET_asprintf(&valgrindCommand, "valgrind --leak-check=yes %s", cntxt->binary_name); - valgrindPipe = popen(valgrindCommand, "r"); - if (NULL == valgrindPipe) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error in running Valgrind!\n"); - GNUNET_free (valgrindCommand); - return GNUNET_NO; - } +int +GNUNET_MONKEY_ACTION_rerun_with_valgrind (struct GNUNET_MONKEY_ACTION_Context + *cntxt) +{ + FILE *valgrindPipe; + int size; + char *valgrindCommand; + cntxt->debug_mode = DEBUG_MODE_VALGRIND; + GNUNET_asprintf (&valgrindCommand, "valgrind --leak-check=yes %s", + cntxt->binary_name); + valgrindPipe = popen (valgrindCommand, "r"); + if (NULL == valgrindPipe) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error in running Valgrind!\n"); + GNUNET_free (valgrindCommand); + return GNUNET_NO; + } + + fscanf (valgrindPipe, "%d", &size); + + /* Read Valgrind stream */ + cntxt->valgrind_output = GNUNET_malloc (size); + fscanf (valgrindPipe, "%s", cntxt->valgrind_output); + GNUNET_free (valgrindCommand); + if (0 != pclose (valgrindPipe)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error while closing Valgrind pipe!\n"); + return GNUNET_NO; + } + return GNUNET_OK; +} - fscanf(valgrindPipe, "%d", &size); - /* Read Valgrind stream */ - cntxt->valgrind_output = GNUNET_malloc(size); - fscanf(valgrindPipe, "%s", cntxt->valgrind_output); - GNUNET_free (valgrindCommand); - if (0 != pclose(valgrindPipe)) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error while closing Valgrind pipe!\n"); - return GNUNET_NO; +int +GNUNET_MONKEY_ACTION_rerun_with_gdb (struct GNUNET_MONKEY_ACTION_Context + *cntxt) +{ + mi_wp *watchPoint; + 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; + } + + if (NULL != cntxt->inspect_expression) + { + watchPoint = + gmi_break_watch (cntxt->gdb_handle, wm_write, + cntxt->inspect_expression); + if (NULL == watchPoint) + { + printf ("Error in setting watch point\n"); + mi_disconnect (cntxt->gdb_handle); + return GNUNET_NO; } - return GNUNET_OK; + } + + /* 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_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cntxt) +static const char * +variableListToString (struct Variable *head) { - 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; + const char *string = GNUNET_malloc (200 * sizeof (char)); + const char *strTmp; + struct Variable *tmp = head; + asprintf (&strTmp, "%s = %s\n", tmp->name, tmp->value); + strcpy (string, strTmp); + free (strTmp); + while (NULL != tmp) + { + asprintf (&strTmp, "%s = %s\n", tmp->name, tmp->value); + strcat (string, strTmp); + free (strTmp); + tmp = tmp->next; + } + return string; } -int GNUNET_MONKEY_ACTION_format_report(struct GNUNET_MONKEY_ACTION_Context* cntxt) +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 Details:\n Expression:%s is NULL\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, cntxt->gdb_null_variable); - break; - case DEBUG_MODE_VALGRIND: - GNUNET_asprintf(&(cntxt->debug_report), - "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n Details:\n Memory Check from Valgrind:%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, cntxt->valgrind_output); - break; - default: - break; + switch (cntxt->debug_mode) + { + case DEBUG_MODE_GDB: + if (cntxt->bug_detected == BUG_NULL_POINTER) + { + GNUNET_asprintf (&(cntxt->debug_report), + "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n Details:\n Expression:%s is NULL\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, + cntxt->gdb_null_variable); } - - cntxt->debug_mode = DEBUG_MODE_REPORT_READY; - return GNUNET_OK; + else if (cntxt->bug_detected == BUG_CUSTOM) + { + if (NULL == cntxt->inspect_expression) + { + /* Assertion Failure */ + GNUNET_asprintf (&(cntxt->debug_report), + "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n Details:\n Assertion Failure\n Expression evaluation:\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, + variableListToString (cntxt-> + variable_list_head)); + } + else + { + /* Failure in a user-defined expression */ + GNUNET_asprintf (&(cntxt->debug_report), + "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n Details:\n Failure in user-defined expression:%s\n Expression evaluation:\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, + cntxt->inspect_expression, + variableListToString (cntxt-> + variable_list_head)); + } + } + break; + case DEBUG_MODE_VALGRIND: + GNUNET_asprintf (&(cntxt->debug_report), + "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n Details:\n Memory Check from Valgrind:%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, + cntxt->valgrind_output); + break; + default: + break; + } + + cntxt->debug_mode = DEBUG_MODE_REPORT_READY; + return GNUNET_OK; } -int GNUNET_MONKEY_ACTION_check_bug_redundancy() +int +GNUNET_MONKEY_ACTION_check_bug_redundancy () { - return GNUNET_OK; + return GNUNET_OK; } diff --git a/src/monkey/bug_assertion_failure.c b/src/monkey/bug_assertion_failure.c new file mode 100644 index 000000000..416fd6fe3 --- /dev/null +++ b/src/monkey/bug_assertion_failure.c @@ -0,0 +1,15 @@ +#include +#include + +void assertionFailure() +{ + int x = 5; + printf("Assertion Failure Now!\n"); + assert(x < 4); +} + +int main(int argc, char *argv[]) +{ + assertionFailure(); + return 0; +} diff --git a/src/monkey/gnunet-monkey.c b/src/monkey/gnunet-monkey.c index 030eb0774..1019a87a0 100644 --- a/src/monkey/gnunet-monkey.c +++ b/src/monkey/gnunet-monkey.c @@ -30,12 +30,13 @@ #include "gnunet_program_lib.h" #include "gnunet_monkey_action.h" -static const char* mode; -static const char* dumpFileName; -static const char* binaryName; -static const char* emailAddress; -static const char* edbFilePath; -static const char* gdbBinaryPath; +static const char *mode; +static const char *dumpFileName; +static const char *binaryName; +static const char *emailAddress; +static const char *edbFilePath; +static const char *gdbBinaryPath; +static const char *inspectExpression; static int ret = 0; /** @@ -49,113 +50,147 @@ static int ret = 0; static void run (void *cls, char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { - int result; - struct GNUNET_MONKEY_ACTION_Context *cntxt; + int result; + struct GNUNET_MONKEY_ACTION_Context *cntxt; - if (strcasecmp(mode, "email") == 0) { - if (NULL == emailAddress) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Working in email mode requires an email address!\n"); - ret = 1; - return; - } - } else if (strcasecmp(mode, "text") == 0) { - if (NULL == dumpFileName) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Working in text mode requires a path for the dump file!\n"); - ret = 1; - return; - } + if (strcasecmp (mode, "email") == 0) + { + if (NULL == emailAddress) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Working in email mode requires an email address!\n"); + ret = 1; + return; } + } + else if (strcasecmp (mode, "text") == 0) + { + if (NULL == dumpFileName) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Working in text mode requires a path for the dump file!\n"); + ret = 1; + return; + } + } - /* Initialize context for the Action API */ - cntxt = GNUNET_malloc(sizeof(struct GNUNET_MONKEY_ACTION_Context)); - cntxt->binary_name = binaryName; - cntxt->expression_database_path = edbFilePath; - cntxt->gdb_binary_path = gdbBinaryPath; + /* Initialize context for the Action API */ + cntxt = GNUNET_malloc (sizeof (struct GNUNET_MONKEY_ACTION_Context)); + cntxt->binary_name = binaryName; + cntxt->expression_database_path = edbFilePath; + cntxt->gdb_binary_path = gdbBinaryPath; + cntxt->inspect_expression = inspectExpression; - result = GNUNET_MONKEY_ACTION_rerun_with_gdb(cntxt); - switch (result) { - int retVal; - case GDB_STATE_ERROR: - break; - case GDB_STATE_EXIT_NORMALLY: - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Debug with gdb, program exited normally!\n"); - /*FIXME: Valgrind should be launched here */ - break; - case GDB_STATE_STOPPED: - /*FIXME: Expression Database should be inspected here (before writing the report) */ - retVal = GNUNET_MONKEY_ACTION_inspect_expression_database(cntxt); - if (GNUNET_NO == retVal) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error using Expression Database!\n"); - ret = 1; - break; - } else if (GDB_STATE_ERROR == retVal) { - /* GDB could not locate a NULL value expression, launch Valgrind */ - retVal = GNUNET_MONKEY_ACTION_rerun_with_valgrind(cntxt); - if (GNUNET_NO == retVal) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error using Valgrind!\n"); - ret = 1; - break; - } - } - if(GNUNET_OK != GNUNET_MONKEY_ACTION_format_report(cntxt)){ - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error in generating debug report!\n"); - ret = 1; - } - if (strcasecmp(mode, "email") == 0) { - if (GNUNET_OK != GNUNET_MONKEY_ACTION_report_email(cntxt)) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error sending email!\n"); - ret = 1; - } - } else { - /* text mode */ - if (GNUNET_OK != GNUNET_MONKEY_ACTION_report_file(cntxt, dumpFileName)) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error in saving debug file!\n"); - ret = 1; - } - } - break; - default: - break; + result = GNUNET_MONKEY_ACTION_rerun_with_gdb (cntxt); + switch (result) + { + int retVal; + case GDB_STATE_ERROR: + break; + case GDB_STATE_EXIT_NORMALLY: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Debug with gdb, program exited normally!\n"); + /*FIXME: Valgrind should be launched here */ + break; + case GDB_STATE_STOPPED: + /*FIXME: Expression Database should be inspected here (before writing the report) */ + retVal = GNUNET_MONKEY_ACTION_inspect_expression_database (cntxt); + if (GNUNET_NO == retVal) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error using Expression Database!\n"); + ret = 1; + break; + } + else if (GDB_STATE_ERROR == retVal) + { + /* GDB could not locate a NULL value expression, launch Valgrind */ + retVal = GNUNET_MONKEY_ACTION_rerun_with_valgrind (cntxt); + if (GNUNET_NO == retVal) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error using Valgrind!\n"); + ret = 1; + break; + } + } + if (GNUNET_OK != GNUNET_MONKEY_ACTION_format_report (cntxt)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error in generating debug report!\n"); + ret = 1; + } + if (strcasecmp (mode, "email") == 0) + { + if (GNUNET_OK != GNUNET_MONKEY_ACTION_report_email (cntxt)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error sending email!\n"); + ret = 1; + } } + else + { + /* text mode */ + if (GNUNET_OK != + GNUNET_MONKEY_ACTION_report_file (cntxt, dumpFileName)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error in saving debug file!\n"); + ret = 1; + } + } + break; + default: + break; + } } -int main(int argc, char *argv[]) +int +main (int argc, char *argv[]) { - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'m', "mode", NULL, gettext_noop ("monkey's mode of operation: options are \"text\" or \"email\""), - GNUNET_YES, &GNUNET_GETOPT_set_string, &mode}, - {'b', "binary", NULL, gettext_noop ("binary for program to debug with monkey"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &binaryName}, - {'o', "output", NULL, gettext_noop ("path to file to dump monkey's output in case of text mode"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &dumpFileName}, - {'a', "address", NULL, gettext_noop ("address to send email to in case of email mode"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &emailAddress}, - {'d', "database", NULL, gettext_noop ("path to Expression Database file"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &edbFilePath}, - {'g', "gdb", NULL, gettext_noop ("path to gdb binary in use; default is /usr/bin/gdb"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &gdbBinaryPath}, - GNUNET_GETOPT_OPTION_END - }; - - if (argc < 2) { - printf("%s", "Monkey should take arguments: Use --help to get a list of options.\n"); - return 1; - } - - if (GNUNET_OK == GNUNET_PROGRAM_run (argc, - argv, - "gnunet-monkey", - gettext_noop - ("Automatically debug a service"), - options, &run, NULL)) - { - return ret; - } + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'m', "mode", NULL, + gettext_noop + ("monkey's mode of operation: options are \"text\" or \"email\""), + GNUNET_YES, &GNUNET_GETOPT_set_string, &mode}, + {'b', "binary", NULL, + gettext_noop ("binary for program to debug with monkey"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &binaryName}, + {'o', "output", NULL, + gettext_noop + ("path to file to dump monkey's output in case of text mode"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &dumpFileName}, + {'a', "address", NULL, + gettext_noop ("address to send email to in case of email mode"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &emailAddress}, + {'d', "database", NULL, gettext_noop ("path to Expression Database file"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &edbFilePath}, + {'g', "gdb", NULL, + gettext_noop ("path to gdb binary in use; default is /usr/bin/gdb"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &gdbBinaryPath}, + {'i', "inspect", NULL, gettext_noop ("A custom expression to inspect"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &inspectExpression}, + GNUNET_GETOPT_OPTION_END + }; - return 1; -} + if (argc < 2) + { + printf ("%s", + "Monkey should take arguments: Use --help to get a list of options.\n"); + return 1; + } + if (GNUNET_OK == GNUNET_PROGRAM_run (argc, + argv, + "gnunet-monkey", + gettext_noop + ("Automatically debug a service"), + options, &run, NULL)) + { + return ret; + } + + return 1; +} diff --git a/src/monkey/gnunet_monkey_action.h b/src/monkey/gnunet_monkey_action.h index d8af8d712..9e4aebf50 100644 --- a/src/monkey/gnunet_monkey_action.h +++ b/src/monkey/gnunet_monkey_action.h @@ -44,6 +44,17 @@ extern "C" #define GDB_STATE_ERROR 3 #define DEBUG_MODE_VALGRIND 4 #define DEBUG_MODE_REPORT_READY 5 +#define BUG_NULL_POINTER 6 +#define BUG_CUSTOM 7 + + +struct Variable +{ + struct Variable *next; + struct Varialble *prev; + const char *name; + const char *value; +}; /** @@ -51,32 +62,44 @@ extern "C" */ struct GNUNET_MONKEY_ACTION_Context { - const char* binary_name; - const char* email_address; - const char* expression_database_path; - const char* gdb_binary_path; - int debug_mode; - char* debug_report; - - /* gdb debugging attributes */ - mi_h *gdb_handle; - const char* gdb_in_use; - mi_stop* gdb_stop_reason; - mi_frames* gdb_frames; - const char* gdb_null_variable; - - /* Valgrind memcheck attributes */ - char* valgrind_output; + const char *binary_name; + const char *email_address; + const char *expression_database_path; + const char *gdb_binary_path; + const char *inspect_expression; + int debug_mode; + int bug_detected; + char *debug_report; + + /* gdb debugging attributes */ + mi_h *gdb_handle; + const char *gdb_in_use; + mi_stop *gdb_stop_reason; + mi_frames *gdb_frames; + const char *gdb_null_variable; + struct Variable *variable_list_head; + struct Variable *variable_list_tail; + + /* Valgrind memcheck attributes */ + char *valgrind_output; }; -int GNUNET_MONKEY_ACTION_report_file(struct GNUNET_MONKEY_ACTION_Context* cntxt, const char* dumpFileName); -int GNUNET_MONKEY_ACTION_report_email(struct GNUNET_MONKEY_ACTION_Context* cntxt); -int GNUNET_MONKEY_ACTION_inspect_expression_database(struct GNUNET_MONKEY_ACTION_Context* cntxt); -int GNUNET_MONKEY_ACTION_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cntxt); -int GNUNET_MONKEY_ACTION_rerun_with_valgrind(struct GNUNET_MONKEY_ACTION_Context* cntxt); -int GNUNET_MONKEY_ACTION_format_report(struct GNUNET_MONKEY_ACTION_Context* cntxt); -int GNUNET_MONKEY_ACTION_check_bug_redundancy(void); +int GNUNET_MONKEY_ACTION_report_file (struct GNUNET_MONKEY_ACTION_Context + *cntxt, const char *dumpFileName); +int GNUNET_MONKEY_ACTION_report_email (struct GNUNET_MONKEY_ACTION_Context + *cntxt); +int GNUNET_MONKEY_ACTION_inspect_expression_database (struct + GNUNET_MONKEY_ACTION_Context + *cntxt); +int GNUNET_MONKEY_ACTION_rerun_with_gdb (struct GNUNET_MONKEY_ACTION_Context + *cntxt); +int GNUNET_MONKEY_ACTION_rerun_with_valgrind (struct + GNUNET_MONKEY_ACTION_Context + *cntxt); +int GNUNET_MONKEY_ACTION_format_report (struct GNUNET_MONKEY_ACTION_Context + *cntxt); +int GNUNET_MONKEY_ACTION_check_bug_redundancy (void); #if 0 /* keep Emacsens' auto-indent happy */ -- 2.25.1