#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);
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)
{
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)
{
/* 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;
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;
}
}
+/**
+ * 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
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;
}
static const char* dumpFileName;
static const char* binaryName;
static const char* emailAddress;
+static const char* edbFilePath;
+static const char* gdbBinaryPath;
static int ret = 0;
/**
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) {
}
}
+ /* 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:
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;
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
};
return 1;
}
+