die strtok_r
[oweals/gnunet.git] / src / monkey / action_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2011 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file monkey/action_api.c
23  * @brief Monkey API for actions taken by Monkey while debugging
24  */
25
26 #include "platform.h"
27 #include "gnunet_common.h"
28 #include "gnunet_monkey_action.h"
29 #include <libesmtp.h>
30
31
32 #define DEBUG_MODE_GDB 0
33 #define DEBUG_MODE_VALGRIND 1
34 #define DEBUG_MODE_REPORT_READY 2
35
36 extern void sendMail (const char *messageContents);
37
38
39 static int async_c=0;
40
41
42 static void cb_console(const char *str, void *data)
43 {
44  printf("CONSOLE> %s\n",str);
45 }
46
47
48 /* Note that unlike what's documented in gdb docs it isn't usable. */
49 static void cb_target(const char *str, void *data)
50 {
51  printf("TARGET> %s\n",str);
52 }
53
54
55 static void cb_log(const char *str, void *data)
56 {
57  printf("LOG> %s\n",str);
58 }
59
60
61 static void cb_to(const char *str, void *data)
62 {
63  printf(">> %s",str);
64 }
65
66
67 static void cb_from(const char *str, void *data)
68 {
69  printf("<< %s\n",str);
70 }
71
72
73 static void cb_async(mi_output *o, void *data)
74 {
75  printf("ASYNC\n");
76  async_c++;
77 }
78
79
80 static int wait_for_stop(mi_h *h)
81 {
82         int res=1;
83         mi_stop *sr;
84         mi_frames *f;
85
86         while (!mi_get_response(h))
87                 usleep(1000);
88         /* The end of the async. */
89         sr=mi_res_stop(h);
90         if (sr)
91         {
92                 f = gmi_stack_info_frame(h);
93                 if (NULL == f)
94                         printf("f is NULL!\n");
95                 if (NULL == f)
96                   GNUNET_break(0);
97
98                 mi_free_stop(sr);
99                 res = 0;
100         }
101         else
102         {
103         res=0;
104         }
105         return res;
106 }
107
108
109 int GNUNET_MONKEY_ACTION_report_file(struct GNUNET_MONKEY_ACTION_Context* cntxt, const char* dumpFileName)
110 {
111         FILE* file = fopen(dumpFileName, "w");
112         GNUNET_assert(NULL != file);
113         fprintf(file,"%s", cntxt->debug_report);
114         fclose(file);
115         return GNUNET_OK;
116 }
117
118
119 int GNUNET_MONKEY_ACTION_report_email(struct GNUNET_MONKEY_ACTION_Context* cntxt)
120 {
121         if (cntxt->debug_mode == DEBUG_MODE_REPORT_READY)
122                 sendMail(cntxt->debug_report);
123
124         return GNUNET_OK;
125 }
126
127
128
129 int GNUNET_MONKEY_ACTION_rerun_with_valgrind()
130 {
131         return GNUNET_OK;
132 }
133
134
135 int GNUNET_MONKEY_ACTION_rerun_with_gdb(struct GNUNET_MONKEY_ACTION_Context* cntxt)
136 {
137         cntxt->debug_mode = DEBUG_MODE_GDB;
138         mi_aux_term *xterm_tty=NULL;
139
140         /* This is like a file-handle for fopen.
141             Here we have all the state of gdb "connection". */
142          mi_h *h;
143
144          /* Connect to gdb child. */
145          h = mi_connect_local();
146          if (!h)
147            {
148             printf("Connect failed\n");
149             return GNUNET_NO;
150            }
151          printf("Connected to gdb!\n");
152
153          /* Set all callbacks. */
154          mi_set_console_cb(h,cb_console,NULL);
155          mi_set_target_cb(h,cb_target,NULL);
156          mi_set_log_cb(h,cb_log,NULL);
157          mi_set_async_cb(h,cb_async,NULL);
158          mi_set_to_gdb_cb(h,cb_to,NULL);
159          mi_set_from_gdb_cb(h,cb_from,NULL);
160
161          /* Set the name of the child and the command line aguments. */
162          if (!gmi_set_exec(h, cntxt->binary_name, NULL))
163            {
164             printf("Error setting exec y args\n");
165             mi_disconnect(h);
166             return GNUNET_NO;
167            }
168
169          /* Tell gdb to attach the child to a terminal. */
170          if (!gmi_target_terminal(h, ttyname(STDIN_FILENO)))
171            {
172             printf("Error selecting target terminal\n");
173             mi_disconnect(h);
174             return GNUNET_NO;
175            }
176
177          /* Run the program. */
178          if (!gmi_exec_run(h))
179            {
180             printf("Error in run!\n");
181             mi_disconnect(h);
182             return GNUNET_NO;
183            }
184          /* Here we should be stopped when the program crashes */
185          if (!wait_for_stop(h))
186            {
187             mi_disconnect(h);
188             return GNUNET_NO;
189            }
190
191          /* Continue execution. */
192          if (!gmi_exec_continue(h))
193            {
194             printf("Error in continue!\n");
195             mi_disconnect(h);
196             return GNUNET_NO;
197            }
198          /* Here we should be terminated. */
199          if (!wait_for_stop(h))
200            {
201             mi_disconnect(h);
202             return GNUNET_NO;
203            }
204
205          /* Exit from gdb. */
206          gmi_gdb_exit(h);
207          /* Close the connection. */
208          mi_disconnect(h);
209          /* Wait 5 seconds and close the auxiliar terminal. */
210          printf("Waiting 5 seconds\n");
211          sleep(5);
212          gmi_end_aux_term(xterm_tty);
213
214         return GNUNET_OK;
215 }
216
217
218 int GNUNET_MONKEY_ACTION_format_report(struct GNUNET_MONKEY_ACTION_Context* cntxt)
219 {
220         switch (cntxt->debug_mode) {
221         case DEBUG_MODE_GDB:
222                 GNUNET_asprintf(&cntxt->debug_report,
223                         "Bug detected in file:%s\nfunction:%s\nline:%d\nreason:%s\nreceived signal:%s\n%s\n",
224                         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);
225                 break;
226         case DEBUG_MODE_VALGRIND:
227                 break;
228         default:
229                 break;
230         }
231
232         cntxt->debug_mode = DEBUG_MODE_REPORT_READY;
233         return GNUNET_OK;
234 }
235
236
237 int GNUNET_MONKEY_ACTION_check_bug_redundancy()
238 {
239         return GNUNET_OK;
240 }