2 This file is part of GNUnet.
3 (C) 2010, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file monkey/action_api.c
23 * @brief Monkey API for actions taken by Monkey while debugging
27 #include "gnunet_common.h"
28 #include "gnunet_monkey_action.h"
29 #include "gnunet_monkey_edb.h"
30 #include "gnunet_container_lib.h"
33 extern void sendMail (const char *messageContents, const char *emailAddress);
37 static struct Expression *expressionListHead = NULL;
38 static struct Expression *expressionListTail = NULL;
41 struct Expression *next;
42 struct Expression *prev;
43 const char* expressionSyntax;
47 static void cb_console(const char *str, void *data)
49 printf("CONSOLE> %s\n",str);
53 /* Note that unlike what's documented in gdb docs it isn't usable. */
54 static void cb_target(const char *str, void *data)
56 printf("TARGET> %s\n",str);
60 static void cb_log(const char *str, void *data)
62 printf("LOG> %s\n",str);
66 static void cb_to(const char *str, void *data)
72 static void cb_from(const char *str, void *data)
74 printf("<< %s\n",str);
78 static void cb_async(mi_output *o, void *data)
85 static int wait_for_stop(mi_h *h, struct GNUNET_MONKEY_ACTION_Context *cntxt)
87 while (!mi_get_response(h))
89 /* The end of the async. */
90 cntxt->gdb_stop_reason=mi_res_stop(h);
91 if (cntxt->gdb_stop_reason)
93 if (cntxt->gdb_stop_reason->reason == sr_exited_normally)
94 return GDB_STATE_EXIT_NORMALLY;
96 cntxt->gdb_frames = gmi_stack_info_frame(h);
97 if (NULL == cntxt->gdb_frames)
100 return GDB_STATE_STOPPED;
102 return GDB_STATE_ERROR;
106 int GNUNET_MONKEY_ACTION_report_file(struct GNUNET_MONKEY_ACTION_Context* cntxt, const char* dumpFileName)
108 FILE* file = fopen(dumpFileName, "w");
109 GNUNET_assert(NULL != file);
110 fprintf(file,"%s", cntxt->debug_report);
116 int GNUNET_MONKEY_ACTION_report_email(struct GNUNET_MONKEY_ACTION_Context* cntxt)
118 if (cntxt->debug_mode == DEBUG_MODE_REPORT_READY)
119 sendMail(cntxt->debug_report, cntxt->email_address);
126 int GNUNET_MONKEY_ACTION_rerun_with_valgrind()
131 static int iterateExpressions(void *cls, int numColumns, char **colValues, char **colNames)
133 struct Expression *expression;
135 if (NULL == colValues[0] || NULL == colValues[1])
136 return 1; /* Error */
138 expression = GNUNET_malloc(sizeof(struct Expression));
139 expression->expressionSyntax = strdup(colValues[0]);
140 expression->lineNo = atoi(colValues[1]);
143 GNUNET_CONTAINER_DLL_insert(expressionListHead, expressionListTail, expression);
149 static int scopeEndCallback(void *cls, int numColumns, char **colValues, char ** colNames)
151 int *scopeEnd = (int*) cls;
153 *scopeEnd = atoi(colValues[0]);
155 return 1; /* Error */
160 static int analyzeSegmentationFault(struct GNUNET_MONKEY_ACTION_Context *cntxt)
162 struct Expression *faultyExpression;
163 struct Expression *tmp;
164 int expressionLength = 0;
167 tmp = expressionListHead;
168 while (NULL != tmp) {
169 if ((tmp->lineNo == cntxt->gdb_frames->line)
170 && (strlen(tmp->expressionSyntax) > expressionLength)) {
171 expressionLength = strlen(tmp->expressionSyntax);
172 faultyExpression = tmp;
177 /* Set watch points on the faulty-expression's subexpressions */
178 tmp = expressionListHead;
179 while (NULL != tmp) {
180 if (tmp != faultyExpression) {
181 /* Only subexpressions are interesting */
182 watchPoint = gmi_break_watch(cntxt->gdb_handle, wm_write, tmp->expressionSyntax);
185 printf("Error in setting watchpoint\n");
188 printf("Watchpoint %d for expression: %s\n", watchPoint->number, watchPoint->exp);
189 mi_free_wp(watchPoint);
197 int GNUNET_MONKEY_ACTION_inspect_expression_database(struct GNUNET_MONKEY_ACTION_Context *cntxt)
199 struct GNUNET_MONKEY_EDB_Context *edbCntxt;
203 edbCntxt = GNUNET_MONKEY_EDB_connect(cntxt->expression_database_path);
204 if (NULL == edbCntxt) {
205 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Unable to connect to Expression Database file!\n");
209 ret = GNUNET_MONKEY_EDB_get_expression_scope_end(edbCntxt,
210 cntxt->gdb_frames->file, cntxt->gdb_frames->line,
211 &scopeEndCallback, &endScope);
215 ret = GNUNET_MONKEY_EDB_get_expressions (edbCntxt,
216 cntxt->gdb_frames->file, cntxt->gdb_frames->line,
221 if (strcasecmp(cntxt->gdb_stop_reason->signal_meaning, "Segmentation fault") == 0)
222 analyzeSegmentationFault(cntxt);
224 GNUNET_MONKEY_EDB_disconnect(edbCntxt);
229 int GNUNET_MONKEY_ACTION_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cntxt)
231 cntxt->debug_mode = DEBUG_MODE_GDB;
233 /* This is like a file-handle for fopen.
234 Here we have all the state of gdb "connection". */
235 if (NULL != cntxt->gdb_binary_path)
236 mi_set_gdb_exe(cntxt->gdb_binary_path);
239 /* Connect to gdb child. */
240 cntxt->gdb_handle = mi_connect_local();
241 if (!cntxt->gdb_handle)
243 printf("Connect failed\n");
246 printf("Connected to gdb!\n");
248 /* Set all callbacks. */
249 mi_set_console_cb(cntxt->gdb_handle,cb_console,NULL);
250 mi_set_target_cb(cntxt->gdb_handle,cb_target,NULL);
251 mi_set_log_cb(cntxt->gdb_handle,cb_log,NULL);
252 mi_set_async_cb(cntxt->gdb_handle,cb_async,NULL);
253 mi_set_to_gdb_cb(cntxt->gdb_handle,cb_to,NULL);
254 mi_set_from_gdb_cb(cntxt->gdb_handle,cb_from,NULL);
256 /* Set the name of the child and the command line arguments. */
257 if (!gmi_set_exec(cntxt->gdb_handle, cntxt->binary_name, NULL))
259 printf("Error setting exec y args\n");
260 mi_disconnect(cntxt->gdb_handle);
264 /* Tell gdb to attach the child to a terminal. */
265 if (!gmi_target_terminal(cntxt->gdb_handle, ttyname(STDIN_FILENO)))
267 printf("Error selecting target terminal\n");
268 mi_disconnect(cntxt->gdb_handle);
272 /* Run the program. */
273 if (!gmi_exec_run(cntxt->gdb_handle))
275 printf("Error in run!\n");
276 mi_disconnect(cntxt->gdb_handle);
279 /* Here we should be stopped when the program crashes */
280 ret = wait_for_stop(cntxt->gdb_handle, cntxt);
281 if (ret != GDB_STATE_ERROR)
282 mi_disconnect(cntxt->gdb_handle);
288 int GNUNET_MONKEY_ACTION_format_report(struct GNUNET_MONKEY_ACTION_Context* cntxt)
290 switch (cntxt->debug_mode) {
292 GNUNET_asprintf(&(cntxt->debug_report),
293 "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n",
294 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);
296 case DEBUG_MODE_VALGRIND:
302 cntxt->debug_mode = DEBUG_MODE_REPORT_READY;
307 int GNUNET_MONKEY_ACTION_check_bug_redundancy()