From b1cb1306723f7e953548fb6c6ebe177bb4910948 Mon Sep 17 00:00:00 2001 From: "Safey A.Halim" Date: Fri, 15 Apr 2011 10:02:28 +0000 Subject: [PATCH] Action API detects segmentation fault --- src/monkey/action_api.c | 147 ++++++++++++++++++++---- src/monkey/bug_null_pointer_exception.c | 12 +- src/monkey/edb_api.c | 42 ++++++- src/monkey/gnunet-monkey.c | 18 ++- src/monkey/gnunet_monkey_action.h | 6 + src/monkey/gnunet_monkey_edb.h | 18 +++ 6 files changed, 215 insertions(+), 28 deletions(-) diff --git a/src/monkey/action_api.c b/src/monkey/action_api.c index ff5c59bf9..0412c7630 100644 --- a/src/monkey/action_api.c +++ b/src/monkey/action_api.c @@ -26,13 +26,23 @@ #include "platform.h" #include "gnunet_common.h" #include "gnunet_monkey_action.h" +#include "gnunet_monkey_edb.h" +#include "gnunet_container_lib.h" #include 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) { @@ -118,6 +128,103 @@ 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) { @@ -125,13 +232,13 @@ int GNUNET_MONKEY_ACTION_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cnt /* This is like a file-handle for fopen. Here we have all the state of gdb "connection". */ - mi_set_gdb_exe("/tmp/gdb/bin/gdb"); - 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; @@ -139,40 +246,40 @@ 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 */ - ret = wait_for_stop(h, cntxt); + ret = wait_for_stop(cntxt->gdb_handle, cntxt); if (ret != GDB_STATE_ERROR) - mi_disconnect(h); + mi_disconnect(cntxt->gdb_handle); return ret; } diff --git a/src/monkey/bug_null_pointer_exception.c b/src/monkey/bug_null_pointer_exception.c index 072904b6d..4accd65af 100644 --- a/src/monkey/bug_null_pointer_exception.c +++ b/src/monkey/bug_null_pointer_exception.c @@ -1,13 +1,17 @@ #include #include + +struct CrashStruct { + const char *crashValue; +}; + void crashFunction() { - char *nullString = NULL; + struct CrashStruct *crashStruct; + crashStruct = NULL; printf("Now the program will crash!\n"); - if (strcmp(nullString, "A string to compare with") == 0) { - printf("How come?! It had to crash!\n"); - } + crashStruct->crashValue = "hello!"; } int main(int argc, char *argv[]) diff --git a/src/monkey/edb_api.c b/src/monkey/edb_api.c index 78a340cd5..df88dc326 100644 --- a/src/monkey/edb_api.c +++ b/src/monkey/edb_api.c @@ -81,11 +81,47 @@ GNUNET_MONKEY_EDB_disconnect (struct GNUNET_MONKEY_EDB_Context *cntxt) } +/** + * Return the line number of the end-of-scope for the expression indicated by start_line_no + * + * @param cntxt context containing the Expression Database handle + * @param file_name path to the file in which the expression in question exists + * @param start_line_no expression's line + * @param iter callback function, iterator for values returned from the Database + * @param iter_cls closure for the expression iterator, will contain the scope-end line number + * @return GNUNET_OK on success, GNUNET_NO on failure + */ +int +GNUNET_MONKEY_EDB_get_expression_scope_end(struct GNUNET_MONKEY_EDB_Context *cntxt, + const char *file_name, int start_line_no, + GNUNET_MONKEY_ExpressionIterator iter, + void *iter_cls) +{ + int err; + char *errMsg; + char *query; + + if (asprintf(&query, "select end_lineno from Expression where file_name LIKE \'\%/%s\' and start_lineno = %d", file_name, start_line_no) == -1) { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Memory allocation problem occurred during creating database query!\n"); + return GNUNET_NO; + } + + err = sqlite3_exec(cntxt->db_handle, query, iter, iter_cls, &errMsg); + if (err) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error occurred while executing Database query. `%s'", + errMsg); + return GNUNET_NO; + } + return GNUNET_OK; +} + + /** * Run an SQLite query to retrieve those expressions that are previous to * given expression and are in the same scope of the given expression * - * @param cntxt context containing the Expression Database handle. + * @param cntxt context containing the Expression Database handle * @param file_name path to the file in which the expression in question exists * @param start_line_no expression beginning line * @param end_line_no line number for the expression's scope end @@ -105,11 +141,11 @@ GNUNET_MONKEY_EDB_get_expressions (struct GNUNET_MONKEY_EDB_Context *cntxt, char *query; if (asprintf (&query, - "select expr_syntax, start_lineno from Expression where file_name = \'%s\' and start_lineno < %d and end_lineno = %d", + "select expr_syntax, start_lineno from Expression where file_name LIKE \'\%/%s\' and start_lineno <= %d and end_lineno = %d", file_name, start_line_no, end_line_no) == -1) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Memory allocation problem occurred."); + "Memory allocation problem occurred!\n"); return GNUNET_NO; } diff --git a/src/monkey/gnunet-monkey.c b/src/monkey/gnunet-monkey.c index c8ac4369c..7821936bf 100644 --- a/src/monkey/gnunet-monkey.c +++ b/src/monkey/gnunet-monkey.c @@ -34,6 +34,8 @@ 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 int ret = 0; /** @@ -51,7 +53,7 @@ run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c) { int result; - struct GNUNET_MONKEY_ACTION_Context* cntxt; + struct GNUNET_MONKEY_ACTION_Context *cntxt; if (strcasecmp(mode, "email") == 0) { if (NULL == emailAddress) { @@ -67,8 +69,12 @@ run (void *cls, } } + /* 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; + result = GNUNET_MONKEY_ACTION_rerun_with_gdb(cntxt); switch (result) { case GDB_STATE_ERROR: @@ -79,6 +85,11 @@ run (void *cls, break; case GDB_STATE_STOPPED: /*FIXME: Expression Database should be inspected here (before writing the report) */ + if (GNUNET_OK != GNUNET_MONKEY_ACTION_inspect_expression_database(cntxt)) { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error using Expression Database!\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; @@ -113,6 +124,10 @@ int main(int argc, char *argv[]) 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 }; @@ -133,3 +148,4 @@ int main(int argc, char *argv[]) return 1; } + diff --git a/src/monkey/gnunet_monkey_action.h b/src/monkey/gnunet_monkey_action.h index 631f04ee9..dd96a03a5 100644 --- a/src/monkey/gnunet_monkey_action.h +++ b/src/monkey/gnunet_monkey_action.h @@ -53,17 +53,23 @@ 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; }; + 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_rerun_with_valgrind(void); +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_format_report(struct GNUNET_MONKEY_ACTION_Context* cntxt); int GNUNET_MONKEY_ACTION_check_bug_redundancy(void); diff --git a/src/monkey/gnunet_monkey_edb.h b/src/monkey/gnunet_monkey_edb.h index b373118f6..27f2f8283 100644 --- a/src/monkey/gnunet_monkey_edb.h +++ b/src/monkey/gnunet_monkey_edb.h @@ -60,6 +60,24 @@ typedef int (*GNUNET_MONKEY_ExpressionIterator) (void *, int, char **, char **); + +/** + * Return the line number of the end-of-scope for the expression indicated by start_line_no + * + * @param cntxt context containing the Expression Database handle + * @param file_name path to the file in which the expression in question exists + * @param start_line_no expression's line + * @param iter callback function, iterator for values returned from the Database + * @param iter_cls closure for the expression iterator, will contain the scope-end line number + * @return GNUNET_OK on success, GNUNET_NO on failure + */ +int +GNUNET_MONKEY_EDB_get_expression_scope_end(struct GNUNET_MONKEY_EDB_Context *cntxt, + const char *file_name, int start_line_no, + GNUNET_MONKEY_ExpressionIterator iter, + void *iter_cls); + + /** * Run an SQLite query to retrieve those expressions that are previous to * given expression and are in the same scope of the given expression -- 2.25.1