aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am5
-rw-r--r--src/monkey/Makefile.am100
-rw-r--r--src/monkey/alloc.c308
-rw-r--r--src/monkey/breakpoint.c265
-rw-r--r--src/monkey/bug_null_pointer_exception.c27
-rw-r--r--src/monkey/connect.c884
-rw-r--r--src/monkey/cpp_int.cc1123
-rw-r--r--src/monkey/data_man.c241
-rw-r--r--src/monkey/error.c38
-rw-r--r--src/monkey/get_free_pty.c132
-rw-r--r--src/monkey/get_free_vt.c153
-rw-r--r--src/monkey/gnunet-monkey.c159
-rw-r--r--src/monkey/gnunet-service-monkey.c6
-rw-r--r--src/monkey/libmigdb.h4
-rw-r--r--src/monkey/mail_sender.c235
-rw-r--r--src/monkey/mi_gdb.h972
-rw-r--r--src/monkey/misc.c118
-rw-r--r--src/monkey/monkey.h0
-rw-r--r--src/monkey/monkey_api.c0
-rw-r--r--src/monkey/parse.c1923
-rw-r--r--src/monkey/prg_control.c454
-rw-r--r--src/monkey/stack_man.c222
-rw-r--r--src/monkey/symbol_query.c32
-rw-r--r--src/monkey/target_man.c119
-rwxr-xr-xsrc/monkey/test_gnunet_monkey.sh199
-rw-r--r--src/monkey/test_monkey_api.c6
-rw-r--r--src/monkey/thread.c89
-rw-r--r--src/monkey/var_obj.c369
29 files changed, 8184 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index f484f9295..0abacd253 100644
--- a/configure.ac
+++ b/configure.ac
@@ -673,6 +673,7 @@ src/testing/Makefile
673src/topology/Makefile 673src/topology/Makefile
674src/transport/Makefile 674src/transport/Makefile
675src/util/Makefile 675src/util/Makefile
676src/monkey/Makefile
676]) 677])
677AC_OUTPUT 678AC_OUTPUT
678 679
diff --git a/src/Makefile.am b/src/Makefile.am
index cca2c0294..cdab96621 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,12 +6,17 @@ if !MINGW
6 NAT_DIR = nat 6 NAT_DIR = nat
7endif 7endif
8 8
9if HAVE_ESMTP
10 MONKEY_DIR = monkey
11endif
12
9SUBDIRS = \ 13SUBDIRS = \
10 include $(INTLEMU_SUBDIRS) \ 14 include $(INTLEMU_SUBDIRS) \
11 util \ 15 util \
12 block \ 16 block \
13 statistics \ 17 statistics \
14 arm \ 18 arm \
19 $(MONKEY_DIR) \
15 hello \ 20 hello \
16 peerinfo \ 21 peerinfo \
17 datacache \ 22 datacache \
diff --git a/src/monkey/Makefile.am b/src/monkey/Makefile.am
new file mode 100644
index 000000000..516f8c08e
--- /dev/null
+++ b/src/monkey/Makefile.am
@@ -0,0 +1,100 @@
1INCLUDES = -I$(top_srcdir)/src/include
2
3if MINGW
4 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
5endif
6
7if USE_COVERAGE
8 AM_CFLAGS = --coverage -O0
9 XLIB = -lgcov
10endif
11
12
13lib_LTLIBRARIES = libgnunetmonkey.la
14
15libgnunetmonkey_la_SOURCES = \
16 monkey_api.c monkey.h
17libgnunetmonkey_la_LIBADD = \
18 $(top_builddir)/src/util/libgnunetutil.la \
19 -lesmtp
20libgnunetmonkey_la_LDFLAGS = \
21 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
22 -version-info 0:0:0
23
24
25bin_PROGRAMS = \
26 gnunet-monkey \
27 gnunet-service-monkey \
28 bug_null_pointer_exception \
29 mail_sender
30
31gnunet_monkey_SOURCES = \
32 mi_gdb.h \
33 alloc.c \
34 breakpoint.c \
35 connect.c \
36 cpp_int.cc \
37 data_man.c \
38 error.c \
39 get_free_pty.c \
40 get_free_vt.c \
41 gnunet-monkey.c \
42 misc.c \
43 parse.c \
44 prg_control.c \
45 stack_man.c \
46 symbol_query.c \
47 target_man.c \
48 thread.c \
49 var_obj.c
50
51gnunet_monkey_LDADD = \
52 $(top_builddir)/src/monkey/libgnunetmonkey.la \
53 $(top_builddir)/src/util/libgnunetutil.la \
54 $(GN_LIBINTL)
55
56
57
58gnunet_service_monkey_SOURCES = \
59 gnunet-service-monkey.c
60gnunet_service_monkey_LDADD = \
61 $(top_builddir)/src/monkey/libgnunetmonkey.la \
62 $(top_builddir)/src/util/libgnunetutil.la \
63 $(GN_LIBINTL)
64
65
66mail_sender_SOURCES = \
67 mail_sender.c
68mail_sender_LDADD = \
69 $(top_builddir)/src/monkey/libgnunetmonkey.la \
70 $(top_builddir)/src/util/libgnunetutil.la \
71 $(GN_LIBINTL)
72
73bug_null_pointer_exception_SOURCES = \
74 bug_null_pointer_exception.c
75bug_null_pointer_exception_LDADD = \
76 $(top_builddir)/src/monkey/libgnunetmonkey.la \
77 $(top_builddir)/src/util/libgnunetutil.la \
78 $(GN_LIBINTL)
79
80
81
82check_PROGRAMS = \
83 test_monkey_api
84
85TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
86
87test_monkey_api_SOURCES = \
88 test_monkey_api.c
89test_monkey_api_LDADD = \
90 $(top_builddir)/src/monkey/libgnunetmonkey.la \
91 $(top_builddir)/src/util/libgnunetutil.la
92
93check_SCRIPTS = \
94 test_gnunet_monkey.sh
95
96EXTRA_DIST = \
97 test_monkey_api_data.conf \
98 $(check_SCRIPTS)
99
100
diff --git a/src/monkey/alloc.c b/src/monkey/alloc.c
new file mode 100644
index 000000000..9e1ffa740
--- /dev/null
+++ b/src/monkey/alloc.c
@@ -0,0 +1,308 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Allocator.
7 Comments:
8 Most alloc/free routines are here. Free routines must accept NULL
9pointers. Alloc functions must set mi_error.@p
10
11***************************************************************************/
12
13#include "mi_gdb.h"
14
15void *mi_calloc(size_t count, size_t sz)
16{
17 void *res=calloc(count,sz);
18 if (!res)
19 mi_error=MI_OUT_OF_MEMORY;
20 return res;
21}
22
23void *mi_calloc1(size_t sz)
24{
25 return mi_calloc(1,sz);
26}
27
28char *mi_malloc(size_t sz)
29{
30 char *res=malloc(sz);
31 if (!res)
32 mi_error=MI_OUT_OF_MEMORY;
33 return res;
34}
35
36mi_results *mi_alloc_results(void)
37{
38 return (mi_results *)mi_calloc1(sizeof(mi_results));
39}
40
41mi_output *mi_alloc_output(void)
42{
43 return (mi_output *)mi_calloc1(sizeof(mi_output));
44}
45
46mi_frames *mi_alloc_frames(void)
47{
48 return (mi_frames *)mi_calloc1(sizeof(mi_frames));
49}
50
51mi_gvar *mi_alloc_gvar(void)
52{
53 return (mi_gvar *)mi_calloc1(sizeof(mi_gvar));
54}
55
56mi_gvar_chg *mi_alloc_gvar_chg(void)
57{
58 return (mi_gvar_chg *)mi_calloc1(sizeof(mi_gvar_chg));
59}
60
61mi_bkpt *mi_alloc_bkpt(void)
62{
63 mi_bkpt *b=(mi_bkpt *)mi_calloc1(sizeof(mi_bkpt));
64 if (b)
65 {
66 b->thread=-1;
67 b->ignore=-1;
68 }
69 return b;
70}
71
72mi_wp *mi_alloc_wp(void)
73{
74 return (mi_wp *)mi_calloc1(sizeof(mi_wp));
75}
76
77mi_stop *mi_alloc_stop(void)
78{
79 return (mi_stop *)mi_calloc1(sizeof(mi_stop));
80}
81
82mi_asm_insns *mi_alloc_asm_insns(void)
83{
84 return (mi_asm_insns *)mi_calloc1(sizeof(mi_asm_insns));
85}
86
87mi_asm_insn *mi_alloc_asm_insn(void)
88{
89 return (mi_asm_insn *)mi_calloc1(sizeof(mi_asm_insn));
90}
91
92mi_chg_reg *mi_alloc_chg_reg(void)
93{
94 return (mi_chg_reg *)mi_calloc1(sizeof(mi_chg_reg));
95}
96
97/*****************************************************************************
98 Free functions
99*****************************************************************************/
100
101void mi_free_frames(mi_frames *f)
102{
103 mi_frames *aux;
104
105 while (f)
106 {
107 free(f->func);
108 free(f->file);
109 free(f->from);
110 mi_free_results(f->args);
111 aux=f->next;
112 free(f);
113 f=aux;
114 }
115}
116
117void mi_free_bkpt(mi_bkpt *b)
118{
119 mi_bkpt *aux;
120
121 while (b)
122 {
123 free(b->func);
124 free(b->file);
125 free(b->file_abs);
126 free(b->cond);
127 aux=b->next;
128 free(b);
129 b=aux;
130 }
131}
132
133void mi_free_gvar(mi_gvar *v)
134{
135 mi_gvar *aux;
136
137 while (v)
138 {
139 free(v->name);
140 free(v->type);
141 free(v->exp);
142 free(v->value);
143 if (v->numchild && v->child)
144 mi_free_gvar(v->child);
145 aux=v->next;
146 free(v);
147 v=aux;
148 }
149}
150
151void mi_free_gvar_chg(mi_gvar_chg *p)
152{
153 mi_gvar_chg *aux;
154
155 while (p)
156 {
157 free(p->name);
158 free(p->new_type);
159 aux=p->next;
160 free(p);
161 p=aux;
162 }
163}
164
165void mi_free_results_but(mi_results *r, mi_results *no)
166{
167 mi_results *aux;
168
169 while (r)
170 {
171 if (r==no)
172 {
173 aux=r->next;
174 r->next=NULL;
175 r=aux;
176 }
177 else
178 {
179 free(r->var);
180 switch (r->type)
181 {
182 case t_const:
183 free(r->v.cstr);
184 break;
185 case t_tuple:
186 case t_list:
187 mi_free_results_but(r->v.rs,no);
188 break;
189 }
190 aux=r->next;
191 free(r);
192 r=aux;
193 }
194 }
195}
196
197void mi_free_results(mi_results *r)
198{
199 mi_free_results_but(r,NULL);
200}
201
202void mi_free_output_but(mi_output *r, mi_output *no, mi_results *no_r)
203{
204 mi_output *aux;
205
206 while (r)
207 {
208 if (r==no)
209 {
210 aux=r->next;
211 r->next=NULL;
212 r=aux;
213 }
214 else
215 {
216 if (r->c)
217 mi_free_results_but(r->c,no_r);
218 aux=r->next;
219 free(r);
220 r=aux;
221 }
222 }
223}
224
225void mi_free_output(mi_output *r)
226{
227 mi_free_output_but(r,NULL,NULL);
228}
229
230void mi_free_stop(mi_stop *s)
231{
232 if (!s)
233 return;
234 mi_free_frames(s->frame);
235 mi_free_wp(s->wp);
236 free(s->wp_old);
237 free(s->wp_val);
238 free(s->gdb_result_var);
239 free(s->return_value);
240 free(s->signal_name);
241 free(s->signal_meaning);
242 free(s);
243}
244
245void mi_free_wp(mi_wp *wp)
246{
247 mi_wp *aux;
248 while (wp)
249 {
250 free(wp->exp);
251 aux=wp->next;
252 free(wp);
253 wp=aux;
254 }
255}
256
257void mi_free_asm_insns(mi_asm_insns *i)
258{
259 mi_asm_insns *aux;
260
261 while (i)
262 {
263 free(i->file);
264 mi_free_asm_insn(i->ins);
265 aux=i->next;
266 free(i);
267 i=aux;
268 }
269}
270
271void mi_free_asm_insn(mi_asm_insn *i)
272{
273 mi_asm_insn *aux;
274
275 while (i)
276 {
277 free(i->func);
278 free(i->inst);
279 aux=i->next;
280 free(i);
281 i=aux;
282 }
283}
284
285/*void mi_free_charp_list(char **l)
286{
287 char **c=l;
288 while (c)
289 {
290 free(*c);
291 c++;
292 }
293 free(l);
294}*/
295
296void mi_free_chg_reg(mi_chg_reg *r)
297{
298 mi_chg_reg *aux;
299 while (r)
300 {
301 free(r->val);
302 free(r->name);
303 aux=r->next;
304 free(r);
305 r=aux;
306 }
307}
308
diff --git a/src/monkey/breakpoint.c b/src/monkey/breakpoint.c
new file mode 100644
index 000000000..645c27444
--- /dev/null
+++ b/src/monkey/breakpoint.c
@@ -0,0 +1,265 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Breakpoint table commands.
7 Comments:
8 GDB/MI commands for the "Breakpoint Table Commands" section.@p
9
10@<pre>
11gdb command: Implemented?
12
13-break-after Yes
14-break-condition Yes
15-break-delete Yes
16-break-disable Yes
17-break-enable Yes
18-break-info N.A. (info break NUMBER) (*)
19-break-insert Yes
20-break-list No (*)
21-break-watch Yes
22@</pre>
23
24(*) I think the program should keep track of the breakpoints, so it will
25be implemented when I have more time.@p
26
27***************************************************************************/
28
29#include "mi_gdb.h"
30
31/* Low level versions. */
32
33void mi_break_insert_fl(mi_h *h, const char *file, int line)
34{
35 mi_send(h,"-break-insert %s:%d\n",file,line);
36}
37
38void mi_break_insert(mi_h *h, int temporary, int hard_assist,
39 const char *cond, int count, int thread,
40 const char *where)
41{
42 char s_count[32];
43 char s_thread[32];
44
45 if (count>=0)
46 snprintf(s_count,32,"%d",count);
47 if (thread>=0)
48 snprintf(s_thread,32,"%d",thread);
49 if (cond)
50 // Conditions may contain spaces, in fact, if they don't gdb will add
51 // them after parsing. Enclosing the expression with "" solves the
52 // problem.
53 mi_send(h,"-break-insert %s %s -c \"%s\" %s %s %s %s %s\n",
54 temporary ? "-t" : "",
55 hard_assist ? "-h" : "",
56 cond,
57 count>=0 ? "-i" : "", count>=0 ? s_count : "",
58 thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
59 where);
60 else
61 mi_send(h,"-break-insert %s %s %s %s %s %s %s\n",
62 temporary ? "-t" : "",
63 hard_assist ? "-h" : "",
64 count>=0 ? "-i" : "", count>=0 ? s_count : "",
65 thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
66 where);
67}
68
69void mi_break_insert_flf(mi_h *h, const char *file, int line, int temporary,
70 int hard_assist, const char *cond, int count,
71 int thread)
72{
73 char s_count[32];
74 char s_thread[32];
75
76 if (count>=0)
77 snprintf(s_count,32,"%d",count);
78 if (thread>=0)
79 snprintf(s_thread,32,"%d",thread);
80 mi_send(h,"-break-insert %s %s %s %s %s %s %s %s %s:%d\n",
81 temporary ? "-t" : "",
82 hard_assist ? "-h" : "",
83 cond ? "-c" : "", cond ? cond : "",
84 count>=0 ? "-i" : "", count>=0 ? s_count : "",
85 thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
86 file,line);
87}
88
89void mi_break_delete(mi_h *h, int number)
90{
91 mi_send(h,"-break-delete %d\n",number);
92}
93
94void mi_break_after(mi_h *h, int number, int count)
95{
96 mi_send(h,"-break-after %d %d\n",number,count);
97}
98
99void mi_break_condition(mi_h *h, int number, const char *condition)
100{
101 mi_send(h,"-break-condition %d %s\n",number,condition);
102}
103
104void mi_break_enable(mi_h *h, int number)
105{
106 mi_send(h,"-break-enable %d\n",number);
107}
108
109void mi_break_disable(mi_h *h, int number)
110{
111 mi_send(h,"-break-disable %d\n",number);
112}
113
114void mi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp)
115{
116 if (mode==wm_write)
117 mi_send(h,"-break-watch \"%s\"\n",exp);
118 else
119 mi_send(h,"-break-watch -%c \"%s\"\n",mode==wm_rw ? 'a' : 'r',exp);
120}
121
122/* High level versions. */
123
124/**[txh]********************************************************************
125
126 Description:
127 Insert a breakpoint at file:line.
128
129 Command: -break-insert file:line
130 Return: A new mi_bkpt structure with info about the breakpoint. NULL on
131error.
132
133***************************************************************************/
134
135mi_bkpt *gmi_break_insert(mi_h *h, const char *file, int line)
136{
137 mi_break_insert_fl(h,file,line);
138 return mi_res_bkpt(h);
139}
140
141/**[txh]********************************************************************
142
143 Description:
144 Insert a breakpoint, all available options.
145
146 Command: -break-insert
147 Return: A new mi_bkpt structure with info about the breakpoint. NULL on
148error.
149
150***************************************************************************/
151
152mi_bkpt *gmi_break_insert_full(mi_h *h, int temporary, int hard_assist,
153 const char *cond, int count, int thread,
154 const char *where)
155{
156 mi_break_insert(h,temporary,hard_assist,cond,count,thread,where);
157 return mi_res_bkpt(h);
158}
159
160/**[txh]********************************************************************
161
162 Description:
163 Insert a breakpoint, all available options.
164
165 Command: -break-insert [ops] file:line
166 Return: A new mi_bkpt structure with info about the breakpoint. NULL on
167error.
168
169***************************************************************************/
170
171mi_bkpt *gmi_break_insert_full_fl(mi_h *h, const char *file, int line,
172 int temporary, int hard_assist,
173 const char *cond, int count, int thread)
174{
175 mi_break_insert_flf(h,file,line,temporary,hard_assist,cond,count,thread);
176 return mi_res_bkpt(h);
177}
178
179/**[txh]********************************************************************
180
181 Description:
182 Remove a breakpoint.
183
184 Command: -break-delete
185 Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
186console.
187
188***************************************************************************/
189
190int gmi_break_delete(mi_h *h, int number)
191{
192 mi_break_delete(h,number);
193 return mi_res_simple_done(h);
194}
195
196/**[txh]********************************************************************
197
198 Description:
199 Modify the "ignore" count for a breakpoint.
200
201 Command: -break-after
202 Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
203console.
204
205***************************************************************************/
206
207int gmi_break_set_times(mi_h *h, int number, int count)
208{
209 mi_break_after(h,number,count);
210 return mi_res_simple_done(h);
211}
212
213/**[txh]********************************************************************
214
215 Description:
216 Associate a condition with the breakpoint.
217
218 Command: -break-condition
219 Return: !=0 OK
220
221***************************************************************************/
222
223int gmi_break_set_condition(mi_h *h, int number, const char *condition)
224{
225 mi_break_condition(h,number,condition);
226 return mi_res_simple_done(h);
227}
228
229/**[txh]********************************************************************
230
231 Description:
232 Enable or disable a breakpoint.
233
234 Command: -break-enable + -break-disable
235 Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
236console.
237
238***************************************************************************/
239
240int gmi_break_state(mi_h *h, int number, int enable)
241{
242 if (enable)
243 mi_break_enable(h,number);
244 else
245 mi_break_disable(h,number);
246 return mi_res_simple_done(h);
247}
248
249/**[txh]********************************************************************
250
251 Description:
252 Set a watchpoint. It doesn't work for remote targets!
253
254 Command: -break-watch
255 Return: A new mi_wp structure with info about the watchpoint. NULL on
256error.
257
258***************************************************************************/
259
260mi_wp *gmi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp)
261{
262 mi_break_watch(h,mode,exp);
263 return mi_res_wp(h);
264}
265
diff --git a/src/monkey/bug_null_pointer_exception.c b/src/monkey/bug_null_pointer_exception.c
new file mode 100644
index 000000000..27428816d
--- /dev/null
+++ b/src/monkey/bug_null_pointer_exception.c
@@ -0,0 +1,27 @@
1#include <stdio.h>
2#include <string.h>
3
4void crashFunction()
5{
6 //char *stringCannotBeChanged = "String cannot be changed!";
7 char *nullString = NULL;
8
9 printf("Now the program will crash! Take a cover! \n");
10 //*stringCannotBeChanged = 'h';
11 printf("Nonsense!\n");
12 if (strcmp(nullString, "A string to compare with") == 0) {
13 printf("How come?! It had to be crashed!\n");
14 }
15}
16
17int main(int argc, char *argv[])
18{
19 int i = 0;
20 printf("arguments: %d\n", argc);
21 for (i=0; i<argc; i++)
22 printf("%d: %s\n", i, argv[i]);
23 printf("Press ENTER\n");
24 getchar();
25 crashFunction();
26 return 0;
27}
diff --git a/src/monkey/connect.c b/src/monkey/connect.c
new file mode 100644
index 000000000..eaca967da
--- /dev/null
+++ b/src/monkey/connect.c
@@ -0,0 +1,884 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2009 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Connect.
7 Comments:
8 This module handles the dialog with gdb, including starting and stopping
9gdb.@p
10
11GDB Bug workaround for "file -readnow": I tried to workaround a bug using
12it but looks like this option also have bugs!!!! so I have to use the
13command line option --readnow.
14It also have a bug!!!! when the binary is changed and gdb must reload it
15this option is ignored. So it looks like we have no solution but 3 gdb bugs
16in a row.
17
18***************************************************************************/
19
20#define _GNU_SOURCE
21#include <sys/types.h>
22#include <unistd.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/wait.h>
26#include <fcntl.h>
27#include <string.h>
28#include <stdarg.h>
29#include <limits.h>
30#include <errno.h>
31#include <signal.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include "mi_gdb.h"
35
36#ifndef TEMP_FAILURE_RETRY
37 #define TEMP_FAILURE_RETRY(a) (a)
38#endif
39
40int mi_error=MI_OK;
41char *mi_error_from_gdb=NULL;
42static char *gdb_exe=NULL;
43static char *xterm_exe=NULL;
44static char *gdb_start=NULL;
45static char *gdb_conn=NULL;
46static char *main_func=NULL;
47static char disable_psym_search_workaround=0;
48
49mi_h *mi_alloc_h()
50{
51 mi_h *h=(mi_h *)calloc(1,sizeof(mi_h));
52 if (!h)
53 {
54 mi_error=MI_OUT_OF_MEMORY;
55 return NULL;
56 }
57 h->to_gdb[0]=h->to_gdb[1]=h->from_gdb[0]=h->from_gdb[1]=-1;
58 h->pid=-1;
59 return h;
60}
61
62int mi_check_running_pid(pid_t pid)
63{
64 int status;
65
66 if (pid<=0)
67 return 0;
68 /* If waitpid returns the number of our child means it communicated
69 to as a termination status. */
70 if (waitpid(pid,&status,WNOHANG)==pid)
71 {
72 pid=0;
73 return 0;
74 }
75 return 1;
76}
77
78int mi_check_running(mi_h *h)
79{
80 return !h->died && mi_check_running_pid(h->pid);
81}
82
83void mi_kill_child(pid_t pid)
84{
85 kill(pid,SIGTERM);
86 usleep(100000);
87 if (mi_check_running_pid(pid))
88 {
89 int status;
90 kill(pid,SIGKILL);
91 waitpid(pid,&status,0);
92 }
93}
94
95void mi_free_h(mi_h **handle)
96{
97 mi_h *h=*handle;
98 if (h->to_gdb[0]>=0)
99 close(h->to_gdb[0]);
100 if (h->to)
101 fclose(h->to);
102 else if (h->to_gdb[1]>=0)
103 close(h->to_gdb[1]);
104 if (h->from)
105 fclose(h->from);
106 else if (h->from_gdb[0]>=0)
107 close(h->from_gdb[0]);
108 if (h->from_gdb[1]>=0)
109 close(h->from_gdb[1]);
110 if (mi_check_running(h))
111 {/* GDB is running! */
112 mi_kill_child(h->pid);
113 }
114 if (h->line)
115 free(h->line);
116 mi_free_output(h->po);
117 free(h->catched_console);
118 free(h);
119 *handle=NULL;
120}
121
122void mi_set_nonblk(int h)
123{
124 int flf;
125 flf=fcntl(h,F_GETFL,0);
126 flf=flf | O_NONBLOCK;
127 fcntl(h,F_SETFL,flf);
128}
129
130int mi_getline(mi_h *h)
131{
132 char c;
133
134 while (read(h->from_gdb[0],&c,1)==1)
135 {
136 if (h->lread>=h->llen)
137 {
138 h->llen=h->lread+128;
139 h->line=(char *)realloc(h->line,h->llen);
140 if (!h->line)
141 {
142 h->llen=0;
143 h->lread=0;
144 return -1;
145 }
146 }
147 if (c=='\n')
148 {
149 int ret=h->lread;
150 h->line[ret]=0;
151 h->lread=0;
152 return ret;
153 }
154 h->line[h->lread]=c;
155 h->lread++;
156 }
157 return 0;
158}
159
160char *get_cstr(mi_output *o)
161{
162 if (!o->c || o->c->type!=t_const)
163 return NULL;
164 return o->c->v.cstr;
165}
166
167int mi_get_response(mi_h *h)
168{
169 int l=mi_getline(h);
170 if (!l)
171 return 0;
172
173 if (h->from_gdb_echo)
174 h->from_gdb_echo(h->line,h->from_gdb_echo_data);
175 if (strncmp(h->line,"(gdb)",5)==0)
176 {/* End of response. */
177 return 1;
178 }
179 else
180 {/* Add to the response. */
181 mi_output *o;
182 int add=1, is_exit=0;
183 o=mi_parse_gdb_output(h->line);
184
185 if (!o)
186 return 0;
187 /* Tunneled streams callbacks. */
188 if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_STREAM)
189 {
190 char *aux;
191 add=0;
192 switch (o->sstype)
193 {
194 case MI_SST_CONSOLE:
195 aux=get_cstr(o);
196 if (h->console)
197 h->console(aux,h->console_data);
198 if (h->catch_console && aux)
199 {
200 h->catch_console--;
201 if (!h->catch_console)
202 {
203 free(h->catched_console);
204 h->catched_console=strdup(aux);
205 }
206 }
207 break;
208 case MI_SST_TARGET:
209 /* This one seems to be useless. */
210 if (h->target)
211 h->target(get_cstr(o),h->target_data);
212 break;
213 case MI_SST_LOG:
214 if (h->log)
215 h->log(get_cstr(o),h->log_data);
216 break;
217 }
218 }
219 else if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_ASYNC)
220 {
221 if (h->async)
222 h->async(o,h->async_data);
223 }
224 else if (o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_ERROR)
225 {/* Error from gdb, record it. */
226 mi_error=MI_FROM_GDB;
227 free(mi_error_from_gdb);
228 mi_error_from_gdb=NULL;
229 if (o->c && strcmp(o->c->var,"msg")==0 && o->c->type==t_const)
230 mi_error_from_gdb=strdup(o->c->v.cstr);
231 }
232 is_exit=(o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_EXIT);
233 /* Add to the list of responses. */
234 if (add)
235 {
236 if (h->last)
237 h->last->next=o;
238 else
239 h->po=o;
240 h->last=o;
241 }
242 else
243 mi_free_output(o);
244 /* Exit RR means gdb exited, we won't get a new prompt ;-) */
245 if (is_exit)
246 return 1;
247 }
248
249 return 0;
250}
251
252mi_output *mi_retire_response(mi_h *h)
253{
254 mi_output *ret=h->po;
255 h->po=h->last=NULL;
256 return ret;
257}
258
259mi_output *mi_get_response_blk(mi_h *h)
260{
261 int r;
262 /* Sometimes gdb dies. */
263 if (!mi_check_running(h))
264 {
265 h->died=1;
266 mi_error=MI_GDB_DIED;
267 return NULL;
268 }
269 do
270 {
271 if (1)
272 {
273 /*
274 That's a must. If we just keep trying to read and failing things
275 become really sloooowwww. Instead we try and if it fails we wait
276 until something is available.
277 TODO: Implement something with the time out, a callback to ask the
278 application is we have to wait or not could be a good thing.
279 */
280 fd_set set;
281 struct timeval timeout;
282 int ret;
283
284 r=mi_get_response(h);
285 if (r)
286 return mi_retire_response(h);
287
288 FD_ZERO(&set);
289 FD_SET(h->from_gdb[0],&set);
290 timeout.tv_sec=h->time_out;
291 timeout.tv_usec=0;
292 ret=TEMP_FAILURE_RETRY(select(FD_SETSIZE,&set,NULL,NULL,&timeout));
293 if (!ret)
294 {
295 if (!mi_check_running(h))
296 {
297 h->died=1;
298 mi_error=MI_GDB_DIED;
299 return NULL;
300 }
301 if (h->time_out_cb)
302 ret=h->time_out_cb(h->time_out_cb_data);
303 if (!ret)
304 {
305 mi_error=MI_GDB_TIME_OUT;
306 return NULL;
307 }
308 }
309 }
310 else
311 {
312 r=mi_get_response(h);
313 if (r)
314 return mi_retire_response(h);
315 else
316 usleep(100);
317 }
318 }
319 while (!r);
320
321 return NULL;
322}
323
324void mi_send_commands(mi_h *h, const char *file)
325{
326 FILE *f;
327 char b[PATH_MAX];
328
329 //printf("File: %s\n",file);
330 if (!file)
331 return;
332 f=fopen(file,"rt");
333 if (!f)
334 return;
335 while (!feof(f))
336 {
337 if (fgets(b,PATH_MAX,f))
338 {
339 //printf("Send: %s\n",b);
340 mi_send(h,b);
341 mi_res_simple_done(h);
342 }
343 }
344 fclose(f);
345}
346
347void mi_send_target_commands(mi_h *h)
348{
349 mi_send_commands(h,gdb_conn);
350}
351
352/**[txh]********************************************************************
353
354 Description:
355 Connect to a local copy of gdb. Note that the mi_h structure is something
356similar to a "FILE *" for stdio.
357
358 Return: A new mi_h structure or NULL on error.
359
360***************************************************************************/
361
362mi_h *mi_connect_local()
363{
364 mi_h *h;
365 const char *gdb=mi_get_gdb_exe();
366
367 /* Start without error. */
368 mi_error=MI_OK;
369 /* Verify we have a GDB binary. */
370 if (access(gdb,X_OK))
371 {
372 mi_error=MI_MISSING_GDB;
373 return NULL;
374 }
375 /* Alloc the handle structure. */
376 h=mi_alloc_h();
377 if (!h)
378 return h;
379 h->time_out=MI_DEFAULT_TIME_OUT;
380 /* Create the pipes to connect with the child. */
381 if (pipe(h->to_gdb) || pipe(h->from_gdb))
382 {
383 mi_error=MI_PIPE_CREATE;
384 mi_free_h(&h);
385 return NULL;
386 }
387 mi_set_nonblk(h->to_gdb[1]);
388 mi_set_nonblk(h->from_gdb[0]);
389 /* Associate streams to the file handles. */
390 h->to=fdopen(h->to_gdb[1],"w");
391 h->from=fdopen(h->from_gdb[0],"r");
392 if (!h->to || !h->from)
393 {
394 mi_error=MI_PIPE_CREATE;
395 mi_free_h(&h);
396 return NULL;
397 }
398 /* Create the child. */
399 h->pid=fork();
400 if (h->pid==0)
401 {/* We are the child. */
402 char *argv[5];
403 /* Connect stdin/out to the pipes. */
404 dup2(h->to_gdb[0],STDIN_FILENO);
405 dup2(h->from_gdb[1],STDOUT_FILENO);
406 /* Pass the control to gdb. */
407 argv[0]=(char *)gdb; /* Is that OK? */
408 argv[1]="--interpreter=mi";
409 argv[2]="--quiet";
410 argv[3]=disable_psym_search_workaround ? 0 : "--readnow";
411 argv[4]=0;
412 execvp(argv[0],argv);
413 /* We get here only if exec failed. */
414 _exit(127);
415 }
416 /* We are the parent. */
417 if (h->pid==-1)
418 {/* Fork failed. */
419 mi_error=MI_FORK;
420 mi_free_h(&h);
421 return NULL;
422 }
423 if (!mi_check_running(h))
424 {
425 mi_error=MI_DEBUGGER_RUN;
426 mi_free_h(&h);
427 return NULL;
428 }
429 /* Wait for the prompt. */
430 mi_get_response_blk(h);
431 /* Send the start-up commands */
432 mi_send_commands(h,gdb_start);
433
434 return h;
435}
436
437/**[txh]********************************************************************
438
439 Description:
440 Close connection. You should ask gdb to quit first @x{gmi_gdb_exit}.
441
442***************************************************************************/
443
444void mi_disconnect(mi_h *h)
445{
446 mi_free_h(&h);
447 free(mi_error_from_gdb);
448 mi_error_from_gdb=NULL;
449}
450
451void mi_set_console_cb(mi_h *h, stream_cb cb, void *data)
452{
453 h->console=cb;
454 h->console_data=data;
455}
456
457void mi_set_target_cb(mi_h *h, stream_cb cb, void *data)
458{
459 h->target=cb;
460 h->target_data=data;
461}
462
463void mi_set_log_cb(mi_h *h, stream_cb cb, void *data)
464{
465 h->log=cb;
466 h->log_data=data;
467}
468
469stream_cb mi_get_console_cb(mi_h *h, void **data)
470{
471 if (data)
472 *data=h->console_data;
473 return h->console;
474}
475
476stream_cb mi_get_target_cb(mi_h *h, void **data)
477{
478 if (data)
479 *data=h->target_data;
480 return h->target;
481}
482
483stream_cb mi_get_log_cb(mi_h *h, void **data)
484{
485 if (data)
486 *data=h->log_data;
487 return h->log;
488}
489
490void mi_set_async_cb(mi_h *h, async_cb cb, void *data)
491{
492 h->async=cb;
493 h->async_data=data;
494}
495
496async_cb mi_get_async_cb(mi_h *h, void **data)
497{
498 if (data)
499 *data=h->async_data;
500 return h->async;
501}
502
503void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data)
504{
505 h->to_gdb_echo=cb;
506 h->to_gdb_echo_data=data;
507}
508
509void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data)
510{
511 h->from_gdb_echo=cb;
512 h->from_gdb_echo_data=data;
513}
514
515stream_cb mi_get_to_gdb_cb(mi_h *h, void **data)
516{
517 if (data)
518 *data=h->to_gdb_echo_data;
519 return h->to_gdb_echo;
520}
521
522stream_cb mi_get_from_gdb_cb(mi_h *h, void **data)
523{
524 if (data)
525 *data=h->from_gdb_echo_data;
526 return h->from_gdb_echo;
527}
528
529void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data)
530{
531 h->time_out_cb=cb;
532 h->time_out_cb_data=data;
533}
534
535tm_cb mi_get_time_out_cb(mi_h *h, void **data)
536{
537 if (data)
538 *data=h->time_out_cb_data;
539 return h->time_out_cb;
540}
541
542void mi_set_time_out(mi_h *h, int to)
543{
544 h->time_out=to;
545}
546
547int mi_get_time_out(mi_h *h)
548{
549 return h->time_out;
550}
551
552int mi_send(mi_h *h, const char *format, ...)
553{
554 int ret;
555 char *str;
556 va_list argptr;
557
558 if (h->died)
559 return 0;
560
561 va_start(argptr,format);
562 ret=vasprintf(&str,format,argptr);
563 va_end(argptr);
564 fputs(str,h->to);
565 fflush(h->to);
566 if (h->to_gdb_echo)
567 h->to_gdb_echo(str,h->to_gdb_echo_data);
568 free(str);
569
570 return ret;
571}
572
573void mi_clean_up_globals()
574{
575 free(gdb_exe);
576 gdb_exe=NULL;
577 free(xterm_exe);
578 xterm_exe=NULL;
579 free(gdb_start);
580 gdb_start=NULL;
581 free(gdb_conn);
582 gdb_conn=NULL;
583 free(main_func);
584 main_func=NULL;
585}
586
587void mi_register_exit()
588{
589 static int registered=0;
590 if (!registered)
591 {
592 registered=1;
593 atexit(mi_clean_up_globals);
594 }
595}
596
597void mi_set_gdb_exe(const char *name)
598{
599 free(gdb_exe);
600 gdb_exe=name ? strdup(name) : NULL;
601 mi_register_exit();
602}
603
604void mi_set_gdb_start(const char *name)
605{
606 free(gdb_start);
607 gdb_start=name ? strdup(name) : NULL;
608 mi_register_exit();
609}
610
611void mi_set_gdb_conn(const char *name)
612{
613 free(gdb_conn);
614 gdb_conn=name ? strdup(name) : NULL;
615 mi_register_exit();
616}
617
618static
619char *mi_search_in_path(const char *file)
620{
621 char *path, *pt, *r;
622 char test[PATH_MAX];
623 struct stat st;
624
625 path=getenv("PATH");
626 if (!path)
627 return NULL;
628 pt=strdup(path);
629 r=strtok(pt,":");
630 while (r)
631 {
632 strcpy(test,r);
633 strcat(test,"/");
634 strcat(test,file);
635 if (stat(test,&st)==0 && S_ISREG(st.st_mode))
636 {
637 free(pt);
638 return strdup(test);
639 }
640 r=strtok(NULL,":");
641 }
642 free(pt);
643 return NULL;
644}
645
646const char *mi_get_gdb_exe()
647{
648 if (!gdb_exe)
649 {/* Look for gdb in path */
650 gdb_exe=mi_search_in_path("gdb");
651 if (!gdb_exe)
652 return "/usr/bin/gdb";
653 }
654 return gdb_exe;
655}
656
657const char *mi_get_gdb_start()
658{
659 return gdb_start;
660}
661
662const char *mi_get_gdb_conn()
663{
664 return gdb_conn;
665}
666
667void mi_set_xterm_exe(const char *name)
668{
669 free(xterm_exe);
670 xterm_exe=name ? strdup(name) : NULL;
671 mi_register_exit();
672}
673
674const char *mi_get_xterm_exe()
675{
676 if (!xterm_exe)
677 {/* Look for xterm in path */
678 xterm_exe=mi_search_in_path("xterm");
679 if (!xterm_exe)
680 return "/usr/bin/X11/xterm";
681 }
682 return xterm_exe;
683}
684
685void mi_set_main_func(const char *name)
686{
687 free(main_func);
688 main_func=name ? strdup(name) : NULL;
689 mi_register_exit();
690}
691
692const char *mi_get_main_func()
693{
694 if (main_func)
695 return main_func;
696 return "main";
697}
698
699/**[txh]********************************************************************
700
701 Description:
702 Opens a new xterm to be used by the child process to debug.
703
704 Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
705release it.
706
707***************************************************************************/
708
709mi_aux_term *gmi_start_xterm()
710{
711 char nsh[14]="/tmp/shXXXXXX";
712 char ntt[14]="/tmp/ttXXXXXX";
713 const char *xterm;
714 struct stat st;
715 int hsh, htt=-1;
716 mi_aux_term *res=NULL;
717 FILE *f;
718 pid_t pid;
719 char buf[PATH_MAX];
720
721 /* Verify we have an X terminal. */
722 xterm=mi_get_xterm_exe();
723 if (access(xterm,X_OK))
724 {
725 mi_error=MI_MISSING_XTERM;
726 return NULL;
727 }
728
729 /* Create 2 temporals. */
730 hsh=mkstemp(nsh);
731 if (hsh==-1)
732 {
733 mi_error=MI_CREATE_TEMPORAL;
734 return NULL;
735 }
736 htt=mkstemp(ntt);
737 if (htt==-1)
738 {
739 close(hsh);
740 unlink(nsh);
741 mi_error=MI_CREATE_TEMPORAL;
742 return NULL;
743 }
744 close(htt);
745 /* Create the script. */
746 f=fdopen(hsh,"w");
747 if (!f)
748 {
749 close(hsh);
750 unlink(nsh);
751 unlink(ntt);
752 mi_error=MI_CREATE_TEMPORAL;
753 return NULL;
754 }
755 fprintf(f,"#!/bin/sh\n");
756 fprintf(f,"tty > %s\n",ntt);
757 fprintf(f,"rm %s\n",nsh);
758 fprintf(f,"sleep 365d\n");
759 fclose(f);
760 /* Spawn xterm. */
761 /* Create the child. */
762 pid=fork();
763 if (pid==0)
764 {/* We are the child. */
765 char *argv[5];
766 /* Pass the control to gdb. */
767 argv[0]=(char *)mi_get_xterm_exe(); /* Is that ok? */
768 argv[1]="-e";
769 argv[2]="/bin/sh";
770 argv[3]=nsh;
771 argv[4]=0;
772 execvp(argv[0],argv);
773 /* We get here only if exec failed. */
774 unlink(nsh);
775 unlink(ntt);
776 _exit(127);
777 }
778 /* We are the parent. */
779 if (pid==-1)
780 {/* Fork failed. */
781 unlink(nsh);
782 unlink(ntt);
783 mi_error=MI_FORK;
784 return NULL;
785 }
786 /* Wait until the shell is deleted. */
787 while (stat(nsh,&st)==0)
788 usleep(1000);
789 /* Try to read the tty name. */
790 f=fopen(ntt,"rt");
791 if (f)
792 {
793 if (fgets(buf,PATH_MAX,f))
794 {
795 char *s; /* Strip the \n. */
796 for (s=buf; *s && *s!='\n'; s++);
797 *s=0;
798 res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
799 if (res)
800 {
801 res->pid=pid;
802 res->tty=strdup(buf);
803 }
804 }
805 fclose(f);
806 }
807 unlink(ntt);
808 return res;
809}
810
811void mi_free_aux_term(mi_aux_term *t)
812{
813 if (!t)
814 return;
815 free(t->tty);
816 free(t);
817}
818
819/**[txh]********************************************************************
820
821 Description:
822 Closes the auxiliar terminal and releases the allocated memory.
823
824***************************************************************************/
825
826void gmi_end_aux_term(mi_aux_term *t)
827{
828 if (!t)
829 return;
830 if (t->pid!=-1 && mi_check_running_pid(t->pid))
831 mi_kill_child(t->pid);
832 mi_free_aux_term(t);
833}
834
835/**[txh]********************************************************************
836
837 Description:
838 Forces the MI version. Currently the library can't detect it so you must
839force it manually. GDB 5.x implemented MI v1 and 6.x v2.
840
841***************************************************************************/
842
843void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
844 unsigned vMinor)
845{
846 h->version=MI_VERSION2U(vMajor,vMiddle,vMinor);
847}
848
849/**[txh]********************************************************************
850
851 Description:
852 Dis/Enables the @var{wa} workaround for a bug in gdb.
853
854***************************************************************************/
855
856void mi_set_workaround(unsigned wa, int enable)
857{
858 switch (wa)
859 {
860 case MI_PSYM_SEARCH:
861 disable_psym_search_workaround=enable ? 0 : 1;
862 break;
863 }
864}
865
866/**[txh]********************************************************************
867
868 Description:
869 Finds if the @var{wa} workaround for a bug in gdb is enabled.
870
871 Return: !=0 if enabled.
872
873***************************************************************************/
874
875int mi_get_workaround(unsigned wa)
876{
877 switch (wa)
878 {
879 case MI_PSYM_SEARCH:
880 return disable_psym_search_workaround==0;
881 }
882 return 0;
883}
884
diff --git a/src/monkey/cpp_int.cc b/src/monkey/cpp_int.cc
new file mode 100644
index 000000000..815d6f7b7
--- /dev/null
+++ b/src/monkey/cpp_int.cc
@@ -0,0 +1,1123 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2007 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: C++ Interface.
7 Comments:
8 Implements a very simple (naive ;-) C++ wrapper.@p
9
10***************************************************************************/
11
12#include <string.h>
13#include <limits.h>
14#include "mi_gdb.h"
15
16/**[txh]********************************************************************
17
18 Description:
19 Initializes a debugger object. It starts in the "disconnected" state.
20Use @x{::Connect} after it.
21
22***************************************************************************/
23
24MIDebugger::MIDebugger()
25{
26 state=disconnected;
27 h=NULL;
28 aux_tty=NULL;
29 waitingTempBkpt=0;
30 targetEndian=enUnknown;
31 targetArch=arUnknown;
32}
33
34/**[txh]********************************************************************
35
36 Description:
37 This is the destructor for the class. It tries to change the state to
38"disconnected" doing the needed actions.
39
40***************************************************************************/
41
42MIDebugger::~MIDebugger()
43{
44 if (state==running)
45 {
46 Stop();
47 mi_stop *rs;
48 // TODO: Some kind of time-out
49 while (!Poll(rs));
50 mi_free_stop(rs);
51 state=stopped;
52 }
53 if (state==stopped)
54 {
55 Kill();
56 state=target_specified;
57 }
58 if (state==target_specified)
59 {
60 TargetUnselect();
61 state=connected;
62 }
63 if (state==connected)
64 Disconnect();
65 // Here state==disconnected
66}
67
68/**[txh]********************************************************************
69
70 Description:
71 Connects to gdb. Currently only local connections are supported, that's
72a gdb limitation. Call it when in "unconnected" state, on success it will
73change to the "connected" state. After it you should call one of the
74SelectTarget members. @x{::SelectTargetX11}, @x{::SelectTargetLinux} or
75@x{::SelectTargetRemote}. To finish the connection use @x{::Disconnect}.
76
77 Return: !=0 OK.
78
79***************************************************************************/
80
81int MIDebugger::Connect(bool )
82{
83 if (state==disconnected)
84 {
85 h=mi_connect_local();
86 if (h!=NULL)
87 {
88 state=connected;
89 return 1;
90 }
91 }
92 return 0;
93}
94
95/**[txh]********************************************************************
96
97 Description:
98 Finishes the connection to gdb. Call when in "connected" state, on success
99it will change to "disconnected" state. This function first tries to exit
100from gdb and then close the connection. But if gdb fails to exit it will be
101killed.
102
103 Return: !=0 OK
104
105***************************************************************************/
106
107int MIDebugger::Disconnect()
108{
109 if (state==connected)
110 {
111 gmi_gdb_exit(h);
112 mi_disconnect(h);
113 state=disconnected;
114 return 1;
115 }
116 return 0;
117}
118
119/**[txh]********************************************************************
120
121 Description:
122 Protected member that implements @x{::SelectTargetX11} and
123@x{::SelectTargetLinux}.
124
125 Return: !=0 OK.
126
127***************************************************************************/
128
129int MIDebugger::SelectTargetTTY(const char *exec, const char *args,
130 const char *auxtty, dMode m)
131{
132 if (state!=connected)
133 return 0;
134
135 targetEndian=enUnknown;
136 targetArch=arUnknown;
137 mode=m;
138 if (!gmi_set_exec(h,exec,args))
139 return 0;
140
141 const char *tty_name;
142 #ifndef __CYGWIN__
143 if (!auxtty)
144 {
145 aux_tty=m==dmLinux ? gmi_look_for_free_vt() : gmi_start_xterm();
146 if (!aux_tty)
147 return 0;
148 tty_name=aux_tty->tty;
149 }
150 else
151 {
152 tty_name=auxtty;
153 }
154 if (!gmi_target_terminal(h,tty_name))
155 return 0;
156 #else
157 tty_name=NULL;
158 if (!gmi_gdb_set(h,"new-console","on"))
159 return 0;
160 #endif
161
162 state=target_specified;
163 preRun=false;
164 return 1;
165}
166
167/**[txh]********************************************************************
168
169 Description:
170 Starts a debug session for X11. It opens an xterm console for the program
171to debug and tells gdb which executable to debug and the command line
172options to pass. You can specify an already existing tty console to be used.
173Can be called when the state is "connected". On success will change to the
174"target_specified" state. After it you can use @x{::Run} or use the members
175to define breakpoints and similar stuff. To finish it use
176@x{::TargetUnselect}.
177
178 Return: !=0 OK.
179
180***************************************************************************/
181
182int MIDebugger::SelectTargetX11(const char *exec, const char *args,
183 const char *auxtty)
184{
185 return SelectTargetTTY(exec,args,auxtty,dmX11);
186}
187
188
189/**[txh]********************************************************************
190
191 Description:
192 Starts a debug session for Linux console. It selects an empty VT for the
193program to debug and tells gdb which executable to debug and the command line
194options to pass. You can specify an already existing tty console to be used.
195Can be called when the state is "connected". On success will change to the
196"target_specified" state. After it you can use @x{::Run} or use the members
197to define breakpoints and similar stuff. To finish it use
198@x{::TargetUnselect}.
199
200 Return: !=0 OK.
201
202***************************************************************************/
203
204int MIDebugger::SelectTargetLinux(const char *exec, const char *args,
205 const char *auxtty)
206{
207 return SelectTargetTTY(exec,args,auxtty,dmLinux);
208}
209
210/**[txh]********************************************************************
211
212 Description:
213 Starts a remote session. The other end should be running gdbserver. You
214must specify a local copy of the program to debug with debug info. The remote
215copy can be stripped. The @var{rtype} and @var{rparams} selects the protocol
216and the remote machine. Read gdb docs to know more about the available
217options. If @var{rtype} is omitted "extended-remote" protocol is used.
218Can be called when the state is "connected". On success will change to the
219"target_specified" state. After it you can use @x{::Run} or use the members
220to define breakpoints and similar stuff. To finish it use
221@x{::TargetUnselect}. Note that when gdb uses remote debugging the remote
222program starts running. The @x{::Run} member knows about it.
223
224 Return: !=0 OK.
225 Example:
226 o->SelectTargetRemote("./exec_file","192.168.1.65:5000");
227
228***************************************************************************/
229
230int MIDebugger::SelectTargetRemote(const char *exec, const char *rparams,
231 const char *rtype, bool download)
232{
233 if (state!=connected)
234 return 0;
235
236 mode=dmRemote;
237 preRun=true;
238 targetEndian=enUnknown;
239 targetArch=arUnknown;
240 if (rtype==NULL)
241 rtype="extended-remote";
242
243 /* Tell gdb to load symbols from the local copy. */
244 int res=download ? gmi_set_exec(h,exec,NULL) : gmi_file_symbol_file(h,exec);
245 if (!res)
246 return 0;
247 /* Select the target */
248 if (!gmi_target_select(h,rtype,rparams))
249 return 0;
250 /* Download the binary */
251 if (download)
252 {
253 if (!gmi_target_download(h))
254 return 0;
255 }
256
257 state=target_specified;
258 return 1;
259}
260
261/**[txh]********************************************************************
262
263 Description:
264 Starts a local session using an already running process.
265
266 Return: !=0 OK.
267
268***************************************************************************/
269
270mi_frames *MIDebugger::SelectTargetPID(const char *exec, int pid)
271{
272 if (state!=connected)
273 return NULL;
274
275 mode=dmPID;
276 preRun=false;
277 targetEndian=enUnknown;
278 targetArch=arUnknown;
279
280 mi_frames *res=gmi_target_attach(h,pid);
281 if (res)
282 {
283 state=stopped;
284
285 /* Tell gdb to load symbols from the local copy. */
286 if (!gmi_file_symbol_file(h,exec))
287 {
288 mi_free_frames(res);
289 return NULL;
290 }
291 }
292
293 return res;
294}
295
296/**[txh]********************************************************************
297
298 Description:
299 Used to unselect the current target. When X11 mode it closes the auxiliar
300terminal. For remote debugging it uses "detach". Can be called when in
301"target_specified" state. On success it changes to "connected" state.
302
303 Return: !=0 OK
304
305***************************************************************************/
306
307int MIDebugger::TargetUnselect()
308{
309 switch (mode)
310 {
311 case dmX11:
312 case dmLinux:
313 if (state!=target_specified)
314 return 0;
315 if (aux_tty)
316 {
317 gmi_end_aux_term(aux_tty);
318 aux_tty=NULL;
319 }
320 break;
321 case dmPID:
322 case dmRemote:
323 if (state!=target_specified)
324 {
325 if (state!=stopped || !gmi_target_detach(h))
326 return 0;
327 }
328 break;
329 }
330 state=connected;
331 return 1;
332}
333
334/**[txh]********************************************************************
335
336 Description:
337 Starts running the program. You should set breakpoint before it. Can be
338called when state is "target_specified". On success will change to "running"
339state. After it you should poll for async responses using @x{::Poll}. The
340program can stop for many reasons asynchronously and also exit. This
341information is known using Poll. You can stop the program using @x{::Stop}.
342
343 Return: !=0 OK.
344
345***************************************************************************/
346
347int MIDebugger::Run()
348{
349 if (state!=target_specified)
350 return 0;
351
352 int res;
353 if (preRun)
354 res=gmi_exec_continue(h);
355 else
356 res=gmi_exec_run(h);
357 if (res)
358 state=running;
359
360 return res;
361}
362
363/**[txh]********************************************************************
364
365 Description:
366 Stops the program execution. GDB sends an interrupt signal to the program.
367Can be called when the state is "running". It won't switch to "stopped"
368state automatically. Instead you must poll for async events and wait for a
369stopped notification. After it you can call @x{::Continue} to resume
370execution.
371
372 Return:
373 Example: !=0 OK
374
375***************************************************************************/
376
377int MIDebugger::Stop()
378{
379 if (state!=running)
380 return 0;
381 return gmi_exec_interrupt(h);
382}
383
384/**[txh]********************************************************************
385
386 Description:
387 Polls gdb looking for async responses. Currently it just looks for
388"stopped" messages. You must call it when the state is "running". But the
389function will poll gdb even if the state isn't "running". When a stopped
390message is received the state changes to stopped or target_specified (the
391last is when we get some exit).
392
393 Return: !=0 if we got a response. The @var{rs} pointer will point to an
394mi_stop structure if we got it or will be NULL if we didn't.
395
396***************************************************************************/
397
398int MIDebugger::Poll(mi_stop *&rs)
399{
400 if (state==disconnected || !mi_get_response(h))
401 return 0;
402
403 mi_stop *res=mi_res_stop(h);
404 if (res)
405 {
406 if (res->reason==sr_exited_signalled ||
407 res->reason==sr_exited ||
408 res->reason==sr_exited_normally)
409 // When we use a PID the exit makes it invalid, so we don't have a
410 // valid target to re-run.
411 state=mode==dmPID ? connected : target_specified;
412 else
413 state=stopped;
414 if (res->reason==sr_unknown && waitingTempBkpt)
415 {
416 waitingTempBkpt=0;
417 res->reason=sr_bkpt_hit;
418 }
419 }
420 else
421 {// We got an error. It looks like most async commands returns running even
422 // before they are sure the process is running. Latter we get the real
423 // error. So I'm assuming the program is stopped.
424 // Lamentably -target-exec-status isn't implemented and even in this case
425 // if the program is really running as real async isn't implemented it
426 // will fail anyways.
427 if (state==running)
428 state=stopped;
429 }
430 rs=res;
431 return 1;
432}
433
434/**[txh]********************************************************************
435
436 Description:
437 Resumes execution after the program "stopped". Can be called when the state
438is stopped. On success will change to "running" state.
439
440 Return: !=0 OK
441
442***************************************************************************/
443
444int MIDebugger::Continue()
445{
446 if (state!=stopped)
447 return 0;
448 int res=gmi_exec_continue(h);
449 if (res)
450 state=running;
451 return res;
452}
453
454/**[txh]********************************************************************
455
456 Description:
457 Starts program execution or resumes it. When the state is target_specified
458it calls @x{::Run} otherwise it uses @x{::Continue}. Can be called when the
459state is "target_specified" or "stopped". On success will change to
460"running" state.
461
462 Return: !=0 OK
463
464***************************************************************************/
465
466int MIDebugger::RunOrContinue()
467{
468 if (state==target_specified)
469 return Run();
470 return Continue();
471}
472
473/**[txh]********************************************************************
474
475 Description:
476 Kills the program you are debugging. Can be called when the state is
477"stopped" or "running". On success changes the state to "target_specified".
478Note that if you want to restart the program you can just call @x{::Run} and
479if you want to just stop the program call @x{::Stop}.
480
481 Return: !=0 OK
482
483***************************************************************************/
484
485int MIDebugger::Kill()
486{
487 if (state!=stopped && state!=running)
488 return 0;
489 /* GDB/MI doesn't implement it (yet), so we use the regular kill. */
490 /* Ensure confirm is off. */
491 char *prev=gmi_gdb_show(h,"confirm");
492 if (!prev)
493 return 0;
494 if (strcmp(prev,"off"))
495 {
496 if (!gmi_gdb_set(h,"confirm","off"))
497 {
498 free(prev);
499 return 0;
500 }
501 }
502 else
503 {
504 free(prev);
505 prev=NULL;
506 }
507 /* Do the kill. */
508 int res=gmi_exec_kill(h);
509 /* Revert confirm option if needed. */
510 if (prev)
511 {
512 gmi_gdb_set(h,"confirm",prev);
513 free(prev);
514 }
515
516 if (res)
517 state=target_specified;
518
519 return res;
520}
521
522/**[txh]********************************************************************
523
524 Description:
525 Inserts a breakpoint at @var{file} and @var{line}. Can be called when the
526state is "stopped" or "target_specified".
527
528 Return: An mi_bkpt structure or NULL if error.
529
530***************************************************************************/
531
532mi_bkpt *MIDebugger::Breakpoint(const char *file, int line)
533{
534 if (state!=stopped && state!=target_specified)
535 return NULL;
536 return gmi_break_insert(h,file,line);
537}
538
539/**[txh]********************************************************************
540
541 Description:
542 Inserts a breakpoint at @var{where}, all options available. Can be called
543when the state is "stopped" or "target_specified".
544
545 Return: An mi_bkpt structure or NULL if error.
546
547***************************************************************************/
548
549mi_bkpt *MIDebugger::Breakpoint(const char *where, bool temporary,
550 const char *cond, int count, int thread,
551 bool hard_assist)
552{
553 if (state!=stopped && state!=target_specified)
554 return NULL;
555 return gmi_break_insert_full(h,temporary,hard_assist,cond,count,thread,where);
556}
557
558
559const int maxWhere=PATH_MAX+256;
560
561mi_bkpt *MIDebugger::Breakpoint(mi_bkpt *b)
562{
563 if (state!=stopped && state!=target_specified)
564 return NULL;
565
566 char buf[maxWhere];
567 buf[0]=0;
568 switch (b->mode)
569 {
570 case m_file_line:
571 snprintf(buf,maxWhere,"%s:%d",b->file,b->line);
572 break;
573 case m_function:
574 snprintf(buf,maxWhere,"%s",b->func);
575 break;
576 case m_file_function:
577 snprintf(buf,maxWhere,"%s:%s",b->file,b->func);
578 break;
579 case m_address:
580 snprintf(buf,maxWhere,"*%p",b->addr);
581 break;
582 }
583 return Breakpoint(buf,b->disp==d_del,b->cond,b->ignore,b->thread,
584 b->type==t_hw);
585}
586
587/**[txh]********************************************************************
588
589 Description:
590 Inserts a breakpoint at @var{file} and @var{line} all options available.
591Can be called when the state is "stopped" or "target_specified".
592
593 Return: An mi_bkpt structure or NULL if error.
594
595***************************************************************************/
596
597mi_bkpt *MIDebugger::BreakpointFull(const char *file, int line,
598 bool temporary, const char *cond,
599 int count, int thread, bool hard_assist)
600{
601 if (state!=stopped && state!=target_specified)
602 return NULL;
603 return gmi_break_insert_full_fl(h,file,line,temporary,hard_assist,cond,
604 count,thread);
605}
606
607/**[txh]********************************************************************
608
609 Description:
610 Removes the specified breakpoint. It doesn't free the structure. Can be
611called when the state is "stopped" or "target_specified".
612
613 Return: !=0 OK
614
615***************************************************************************/
616
617int MIDebugger::BreakDelete(mi_bkpt *b)
618{
619 if ((state!=stopped && state!=target_specified) || !b)
620 return 0;
621 return gmi_break_delete(h,b->number);
622}
623
624/**[txh]********************************************************************
625
626 Description:
627 Inserts a watchpoint for the specified expression. Can be called when the
628state is "stopped" or "target_specified".
629
630 Return: An mi_wp structure or NULL if error.
631
632***************************************************************************/
633
634mi_wp *MIDebugger::Watchpoint(enum mi_wp_mode mode, const char *exp)
635{
636 if (state!=stopped && state!=target_specified)
637 return NULL;
638 return gmi_break_watch(h,mode,exp);
639}
640
641/**[txh]********************************************************************
642
643 Description:
644 Removes the specified watchpoint. It doesn't free the structure. Can be
645called when the state is "stopped" or "target_specified".
646
647 Return: !=0 OK
648
649***************************************************************************/
650
651int MIDebugger::WatchDelete(mi_wp *w)
652{
653 if ((state!=stopped && state!=target_specified) || !w)
654 return 0;
655 return gmi_break_delete(h,w->number);
656}
657
658/**[txh]********************************************************************
659
660 Description:
661 Puts a temporal breakpoint in main function and starts running. Can be
662called when the state is "target_specified". If successful the state will
663change to "running".
664
665 Return: !=0 OK
666
667***************************************************************************/
668
669int MIDebugger::RunToMain()
670{
671 if (state!=target_specified)
672 return 0;
673 mi_bkpt *b=Breakpoint(mi_get_main_func(),true);
674 if (!b)
675 return 0;
676 mi_free_bkpt(b);
677 waitingTempBkpt=1;
678 return Run();
679}
680
681/**[txh]********************************************************************
682
683 Description:
684 Executes upto the next line, doesn't follow function calls. The @var{inst}
685argument is for assembler. If the state is "target_specified" it will go to
686the first line in the main function. If the state is "stopped" will use the
687next command. If successfully the state will change to "running".
688
689 Return: !=0 OK
690
691***************************************************************************/
692
693int MIDebugger::StepOver(bool inst)
694{
695 int res=0;
696
697 if (state==target_specified)
698 {// We aren't running
699 // Walk to main
700 return RunToMain();
701 }
702 if (state==stopped)
703 {
704 if (inst)
705 res=gmi_exec_next_instruction(h);
706 else
707 res=gmi_exec_next(h);
708 if (res)
709 state=running;
710 }
711 return res;
712}
713
714/**[txh]********************************************************************
715
716 Description:
717 Executes until the specified point. If the state is "target_specified" it
718uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
719Fails for any other state.
720
721 Return: !=0 OK
722
723***************************************************************************/
724
725int MIDebugger::GoTo(const char *file, int line)
726{
727 int res=0;
728
729 if (state==target_specified)
730 {// We aren't running
731 // Use a temporal breakpoint
732 int l=strlen(file)+32;
733 char buf[l];
734 snprintf(buf,l,"%s:%d",file,line);
735 mi_bkpt *b=Breakpoint(buf,true);
736 if (b)
737 {
738 mi_free_bkpt(b);
739 waitingTempBkpt=1;
740 res=Run();
741 }
742 }
743 else if (state==stopped)
744 {
745 res=gmi_exec_until(h,file,line);
746 if (res)
747 state=running;
748 }
749 return res;
750}
751
752/**[txh]********************************************************************
753
754 Description:
755 Executes until the specified point. If the state is "target_specified" it
756uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
757Fails for any other state.
758
759 Return: !=0 OK
760
761***************************************************************************/
762
763int MIDebugger::GoTo(void *addr)
764{
765 int res=0;
766
767 if (state==target_specified)
768 {// We aren't running
769 // Use a temporal breakpoint
770 char buf[32];
771 snprintf(buf,32,"*%p",addr);
772 mi_bkpt *b=Breakpoint(buf,true);
773 if (b)
774 {
775 mi_free_bkpt(b);
776 waitingTempBkpt=1;
777 res=Run();
778 }
779 }
780 else if (state==stopped)
781 {
782 res=gmi_exec_until_addr(h,addr);
783 if (res)
784 state=running;
785 }
786 return res;
787}
788
789
790/**[txh]********************************************************************
791
792 Description:
793 Resumes execution until the end of the current funtion is reached. Only
794usable when we are in the "stopped" state.
795
796 Return: !=0 OK
797
798***************************************************************************/
799
800int MIDebugger::FinishFun()
801{
802 if (state!=stopped)
803 return 0;
804 int res=gmi_exec_finish(h);
805 if (res)
806 state=running;
807 return res;
808}
809
810/**[txh]********************************************************************
811
812 Description:
813 Returns immediately. Only usable when we are in the "stopped" state.
814
815 Return: !=NULL OK, the returned frame is the current location. That's a
816synchronous function.
817
818***************************************************************************/
819
820mi_frames *MIDebugger::ReturnNow()
821{
822 if (state!=stopped)
823 return 0;
824 return gmi_exec_return(h);
825}
826
827/**[txh]********************************************************************
828
829 Description:
830 Returns the current list of frames.
831
832 Return: !=NULL OK, the list of frames is returned.
833
834***************************************************************************/
835
836mi_frames *MIDebugger::CallStack(bool args)
837{
838 if (state!=stopped)
839 return 0;
840 mi_frames *fr1=gmi_stack_list_frames(h);
841 if (fr1 && args)
842 {// Get the function arguments
843 mi_frames *fr2=gmi_stack_list_arguments(h,1);
844 if (fr2)
845 {// Transfer them to the other list
846 mi_frames *p=fr1, *p2=fr2;
847 while (p2 && p)
848 {
849 p->args=p2->args;
850 p2->args=NULL;
851 p2=p2->next;
852 p=p->next;
853 }
854 mi_free_frames(fr2);
855 }
856 }
857 return fr1;
858}
859
860/**[txh]********************************************************************
861
862 Description:
863 Executes upto the next line, it follows function calls. The @var{inst}
864argument is for assembler. If the state is "target_specified" it will go to
865the first line in the main function. If the state is "stopped" will use the
866next command. If successfully the state will change to "running".
867
868 Return: !=0 OK
869
870***************************************************************************/
871
872int MIDebugger::TraceInto(bool inst)
873{
874 int res=0;
875
876 if (state==target_specified)
877 {// We aren't running
878 // Walk to main
879 return RunToMain();
880 }
881 if (state==stopped)
882 {
883 if (inst)
884 res=gmi_exec_step_instruction(h);
885 else
886 res=gmi_exec_step(h);
887 if (res)
888 state=running;
889 }
890 return res;
891}
892
893/**[txh]********************************************************************
894
895 Description:
896 Evaluates the provided expression. If we get an error the error
897description is returned instead. Can't be called if "disconnected" or
898"running".
899
900 Return: The result of the expression (use free) or NULL.
901
902***************************************************************************/
903
904char *MIDebugger::EvalExpression(const char *exp)
905{
906 if (state==disconnected ||
907 state==running) // No async :-(
908 return NULL;
909 // Evaluate it
910 mi_error=MI_OK;
911 char *res=gmi_data_evaluate_expression(h,exp);
912 if (!res && mi_error_from_gdb)
913 {// Not valid, return the error
914 res=strdup(mi_error_from_gdb);
915 }
916 return res;
917}
918
919/**[txh]********************************************************************
920
921 Description:
922 Modifies the provided expression. If we get an error the error
923description is returned instead. Can't be called if "disconnected" or
924"running".
925
926 Return: The result of the expression (use free) or NULL.
927
928***************************************************************************/
929
930char *MIDebugger::ModifyExpression(char *exp, char *newVal)
931{
932 if (state==disconnected ||
933 state==running) // No async :-(
934 return NULL;
935 // Create an assignment
936 int l1=strlen(exp);
937 int l2=strlen(newVal);
938 char b[l1+l2+2], *s=b;
939 memcpy(s,exp,l1);
940 s+=l1;
941 *s='=';
942 memcpy(++s,newVal,l2);
943 s[l2]=0;
944 // Evaluate it
945 char *res=gmi_data_evaluate_expression(h,b);
946 if (!res && mi_error_from_gdb)
947 {// Not valid, return the error
948 res=strdup(mi_error_from_gdb);
949 }
950 return res;
951}
952
953/**[txh]********************************************************************
954
955 Description:
956 Sends a command to gdb.
957
958 Return: !=0 OK
959
960***************************************************************************/
961
962int MIDebugger::Send(const char *command)
963{
964 if (state==disconnected ||
965 state==running) // No async :-(
966 return 0;
967 // TODO: detect and use -interpreter-exec?
968 mi_send(h,"%s\n",command);
969 return mi_res_simple_done(h);
970}
971
972
973/**[txh]********************************************************************
974
975 Description:
976 Fills the type and value fields of the mi_gvar provided list.
977
978 Return: !=0 OK
979
980***************************************************************************/
981
982int MIDebugger::FillTypeVal(mi_gvar *var)
983{
984 while (var)
985 {
986 if (!var->type && !gmi_var_info_type(h,var))
987 return 0;
988 if (!var->value && !gmi_var_evaluate_expression(h,var))
989 return 0;
990 var=var->next;
991 }
992 return 1;
993}
994
995int MIDebugger::FillOneTypeVal(mi_gvar *var)
996{
997 if (!var)
998 return 0;
999
1000 int ok=1;
1001 if (!var->type && !gmi_var_info_type(h,var))
1002 {
1003 var->type=strdup("");
1004 ok=0;
1005 }
1006 if (!var->value && !gmi_var_evaluate_expression(h,var))
1007 {
1008 var->value=strdup("");
1009 ok=0;
1010 }
1011 return ok;
1012}
1013
1014int MIDebugger::AssigngVar(mi_gvar *var, const char *exp)
1015{
1016 if (state!=stopped)
1017 return 0;
1018 return gmi_var_assign(h,var,exp);
1019}
1020
1021char *MIDebugger::Show(const char *var)
1022{
1023 if (state==running || state==disconnected)
1024 return 0;
1025 // GDB 5.x doesn't reply all in the response record, just to the console :-(
1026 h->catch_console=1;
1027 if (h->catched_console)
1028 {
1029 free(h->catched_console);
1030 h->catched_console=NULL;
1031 }
1032 char *res=gmi_gdb_show(h,var);
1033 h->catch_console=0;
1034 if (!res && h->catched_console)
1035 {
1036 res=h->catched_console;
1037 h->catched_console=NULL;
1038 }
1039 return res;
1040}
1041
1042MIDebugger::endianType MIDebugger::GetTargetEndian()
1043{
1044 if (targetEndian!=enUnknown)
1045 return targetEndian;
1046 if (state!=stopped && state!=target_specified)
1047 return enUnknown;
1048
1049 char *end=Show("endian");
1050 if (end)
1051 {
1052 if (strstr(end,"big"))
1053 targetEndian=enBig;
1054 else if (strstr(end,"little"))
1055 targetEndian=enLittle;
1056 free(end);
1057 }
1058 return targetEndian;
1059}
1060
1061MIDebugger::archType MIDebugger::GetTargetArchitecture()
1062{
1063 if (targetArch!=arUnknown)
1064 return targetArch;
1065 if (state!=stopped && state!=target_specified)
1066 return arUnknown;
1067
1068 char *end=Show("architecture");
1069 if (end)
1070 {
1071 if (strstr(end,"i386"))
1072 targetArch=arIA32;
1073 else if (strstr(end,"sparc"))
1074 targetArch=arSPARC;
1075 else if (strstr(end,"pic14"))
1076 targetArch=arPIC14;
1077 else if (strstr(end,"avr"))
1078 targetArch=arAVR;
1079 free(end);
1080 }
1081 return targetArch;
1082}
1083
1084int MIDebugger::GetErrorNumberSt()
1085{
1086 if (mi_error==MI_GDB_DIED)
1087 {
1088 state=target_specified;
1089 TargetUnselect();
1090 state=connected;
1091 Disconnect();
1092 }
1093 return mi_error;
1094}
1095
1096int MIDebugger::UpdateRegisters(mi_chg_reg *regs)
1097{
1098 int updated=0;
1099 mi_chg_reg *chg=GetChangedRegisters();
1100 if (chg)
1101 {
1102 mi_chg_reg *r=regs, *c;
1103 while (r)
1104 {
1105 c=chg;
1106 while (c && c->reg!=r->reg)
1107 c=c->next;
1108 if (c)
1109 {
1110 r->updated=1;
1111 free(r->val);
1112 r->val=c->val;
1113 c->val=NULL;
1114 updated++;
1115 }
1116 else
1117 r->updated=0;
1118 r=r->next;
1119 }
1120 }
1121 return updated;
1122}
1123
diff --git a/src/monkey/data_man.c b/src/monkey/data_man.c
new file mode 100644
index 000000000..a7e9f11bf
--- /dev/null
+++ b/src/monkey/data_man.c
@@ -0,0 +1,241 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Data manipulation.
7 Comments:
8 GDB/MI commands for the "Data manipulation" section.@p
9
10@<pre>
11gdb command: Implemented?
12
13-data-disassemble Yes
14-data-evaluate-expression Yes
15-data-list-changed-registers No
16-data-list-register-names Yes
17-data-list-register-values No
18-data-read-memory No
19-display-delete N.A. (delete display)
20-display-disable N.A. (disable display)
21-display-enable N.A. (enable display)
22-display-insert N.A. (display)
23-display-list N.A. (info display)
24-environment-cd No
25-environment-directory Yes, MI v1 implementation
26-environment-path No
27@</pre>
28
29Notes:@p
30
311) -display* aren't implemented. You can use CLI command display, but the
32results are sent to the console. So it looks like the best is to manually
33use -data-evaluate-expression to emulate it.@p
34
352) GDB bug mi/1770: Affects gdb<=6.2, when you ask for the names of the
36registers you get it plus the name of the "pseudo-registers", but if you
37try to get the value of a pseudo-register you get an error saying the
38register number is invalid. I reported to gdb-patches@sources.redhat.com
39on 2004/08/25 and as I didn't get any answer I filled a bug report on
402004/09/02. The patch to fix this annoying bug is:
41
42Index: gdb/mi/mi-main.c
43===================================================================
44RCS file: /cvs/src/src/gdb/mi/mi-main.c,v
45retrieving revision 1.64
46diff -u -r1.64 mi-main.c
47--- gdb/mi/mi-main.c 3 Aug 2004 00:57:27 -0000 1.64
48+++ gdb/mi/mi-main.c 25 Aug 2004 14:12:50 -0000
49@@ -423,7 +423,7 @@
50 case, some entries of REGISTER_NAME will change depending upon
51 the particular processor being debugged.
52
53- numregs = NUM_REGS;
54+ numregs = NUM_REGS + NUM_PSEUDO_REGS;
55
56 if (argc == 0)
57 {
58----
59
60Note I had to remove an end of comment in the patch to include it here.
61This bug forced me to create another set of functions. The only way is to
62first get the values and then the names.
63Fixed by Changelog entry:
64
652004-09-12 Salvador E. Tropea <set@users.sf.net>
66 Andrew Cagney <cagney@gnu.org>
67
68 * mi/mi-main.c (mi_cmd_data_list_changed_registers)
69 (mi_cmd_data_list_register_values)
70 (mi_cmd_data_write_register_values): Include the PSEUDO_REGS in
71 the register number computation.
72
73***************************************************************************/
74
75#include "mi_gdb.h"
76
77/* Low level versions. */
78
79void mi_data_evaluate_expression(mi_h *h, const char *expression)
80{
81 mi_send(h,"-data-evaluate-expression \"%s\"\n",expression);
82}
83
84void mi_dir(mi_h *h, const char *path)
85{
86 if (h->version>=MI_VERSION2U(2,0,0))
87 {// MI v2
88 if (path)
89 mi_send(h,"-environment-directory \"%s\"\n",path);
90 else
91 mi_send(h,"-environment-directory -r\n");
92 }
93 else
94 {
95 mi_send(h,"-environment-directory %s\n",path ? path : "");
96 }
97}
98
99void mi_data_read_memory_hx(mi_h *h, const char *exp, unsigned ws,
100 unsigned c, int convAddr)
101{
102 if (convAddr)
103 mi_send(h,"-data-read-memory \"&%s\" x %d 1 %d\n",exp,ws,c);
104 else
105 mi_send(h,"-data-read-memory \"%s\" x %d 1 %d\n",exp,ws,c);
106}
107
108void mi_data_disassemble_se(mi_h *h, const char *start, const char *end,
109 int mode)
110{
111 mi_send(h,"-data-disassemble -s \"%s\" -e \"%s\" -- %d\n",start,end,mode);
112}
113
114void mi_data_disassemble_fl(mi_h *h, const char *file, int line, int lines,
115 int mode)
116{
117 mi_send(h,"-data-disassemble -f \"%s\" -l %d -n %d -- %d\n",file,line,lines,
118 mode);
119}
120
121void mi_data_list_register_names(mi_h *h)
122{
123 mi_send(h,"-data-list-register-names\n");
124}
125
126void mi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
127{
128 mi_send(h,"-data-list-register-names ");
129 while (l)
130 {
131 mi_send(h,"%d ",l->reg);
132 l=l->next;
133 }
134 mi_send(h,"\n");
135}
136
137void mi_data_list_changed_registers(mi_h *h)
138{
139 mi_send(h,"-data-list-changed-registers\n");
140}
141
142void mi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
143{
144 mi_send(h,"-data-list-register-values %c ",mi_format_enum_to_char(fmt));
145 while (l)
146 {
147 mi_send(h,"%d ",l->reg);
148 l=l->next;
149 }
150 mi_send(h,"\n");
151}
152
153/* High level versions. */
154
155/**[txh]********************************************************************
156
157 Description:
158 Evaluate an expression. Returns a parsed tree.
159
160 Command: -data-evaluate-expression
161 Return: The resulting value (as plain text) or NULL on error.
162
163***************************************************************************/
164
165char *gmi_data_evaluate_expression(mi_h *h, const char *expression)
166{
167 mi_data_evaluate_expression(h,expression);
168 return mi_res_value(h);
169}
170
171/**[txh]********************************************************************
172
173 Description:
174 Path for sources. You must use it to indicate where are the sources for
175the program to debug. Only the MI v1 implementation is available.
176
177 Command: -environment-directory
178 Return: !=0 OK
179
180***************************************************************************/
181
182int gmi_dir(mi_h *h, const char *path)
183{
184 mi_dir(h,path);
185 return mi_res_simple_done(h);
186}
187
188int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
189 unsigned char *dest, int *na, int convAddr,
190 unsigned long *addr)
191{
192 mi_data_read_memory_hx(h,exp,1,size,convAddr);
193 return mi_get_read_memory(h,dest,1,na,addr);
194}
195
196mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
197 const char *end, int mode)
198{
199 mi_data_disassemble_se(h,start,end,mode);
200 return mi_get_asm_insns(h);
201}
202
203mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
204 int lines, int mode)
205{
206 mi_data_disassemble_fl(h,file,line,lines,mode);
207 return mi_get_asm_insns(h);
208}
209
210// Affected by gdb bug mi/1770
211mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many)
212{
213 mi_data_list_register_names(h);
214 return mi_get_list_registers(h,how_many);
215}
216
217int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
218{
219 mi_data_list_register_names_l(h,l);
220 return mi_get_list_registers_l(h,l);
221}
222
223mi_chg_reg *gmi_data_list_changed_registers(mi_h *h)
224{
225 mi_error=MI_OK;
226 mi_data_list_changed_registers(h);
227 return mi_get_list_changed_regs(h);
228}
229
230int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
231{
232 mi_data_list_register_values(h,fmt,l);
233 return mi_get_reg_values(h,l);
234}
235
236mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many)
237{
238 mi_data_list_register_values(h,fmt,NULL);
239 return mi_get_reg_values_l(h,how_many);
240}
241
diff --git a/src/monkey/error.c b/src/monkey/error.c
new file mode 100644
index 000000000..adeb16c16
--- /dev/null
+++ b/src/monkey/error.c
@@ -0,0 +1,38 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Error.
7 Comment:
8 Translates error numbers into messages.
9
10***************************************************************************/
11
12#include "mi_gdb.h"
13
14static
15const char *error_strs[]=
16{
17 "Ok",
18 "Out of memory",
19 "Pipe creation",
20 "Fork failed",
21 "GDB not running",
22 "Parser failed",
23 "Unknown asyn response",
24 "Unknown result response",
25 "Error from gdb",
26 "Time out in gdb response",
27 "GDB suddenly died",
28 "Can't execute X terminal",
29 "Failed to create temporal",
30 "Can't execute the debugger"
31};
32
33const char *mi_get_error_str()
34{
35 if (mi_error<0 || mi_error>MI_LAST_ERROR)
36 return "Unknown";
37 return error_strs[mi_error];
38}
diff --git a/src/monkey/get_free_pty.c b/src/monkey/get_free_pty.c
new file mode 100644
index 000000000..8c145d0db
--- /dev/null
+++ b/src/monkey/get_free_pty.c
@@ -0,0 +1,132 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: pseudo terminal
7 Comments:
8 Helper to find a free pseudo terminal. Use this if you need to manage
9 input *and* output to the target process. If you just need output then
10 define a handler for target output stream records (assuming that this
11 is working for your particular version of gdb).
12 Usage:
13
14 mi_pty *pty = gmi_look_for_free_pty();
15 if (pty) gmi_target_terminal(mih, pty->slave);
16 ...
17 * reading from pty->master will get stdout from target *
18 * writing to pty->master will send to target stdin *
19
20 Note: Contributed by Greg Watson (gwatson lanl gov)
21
22***************************************************************************/
23
24#define _GNU_SOURCE
25#include <string.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <fcntl.h>
29#include <sys/ioctl.h>
30
31#include "mi_gdb.h"
32
33/**[txh]********************************************************************
34
35 Description:
36 Look for a free and usable pseudo terminal. Low level, use
37@x{gmi_look_for_free_pty}.
38
39 Return: A file descriptor connected to the master pty and the name of the slave device, or <0 on error.
40
41***************************************************************************/
42
43#ifdef __APPLE__
44
45#include <util.h>
46
47int mi_look_for_free_pty(int *master, char **slave)
48{
49 int fdmaster;
50 int fdslave;
51 static char name[BUFSIZ];
52
53 if (openpty(&fdmaster,&fdslave,name,NULL,NULL)<0)
54 return -1;
55
56 (void)close(fdslave); /* this will be reopened by gdb */
57 *master=fdmaster;
58 *slave =name;
59
60 return 0;
61}
62
63#elif defined(__linux__)
64
65int mi_look_for_free_pty(int *master, char **slave)
66{
67 if ((*master=open("/dev/ptmx",O_RDWR))<0)
68 return -1;
69 if (grantpt(*master)<0 || unlockpt(*master)<0)
70 return -1;
71 *slave = ptsname(*master);
72
73 return 0;
74}
75
76#else /* undefined o/s */
77
78int mi_look_for_free_pty(int *master, char **slave)
79{
80 return -1;
81}
82#endif
83
84/**[txh]********************************************************************
85
86 Description:
87 Look for a free and usable pseudo terminal to be used by the child.
88
89 Return: A new mi_pty structure, you can use @x{gmi_end_pty} to
90release it.
91
92***************************************************************************/
93
94mi_pty *gmi_look_for_free_pty()
95{
96 int master;
97 char *slave;
98 int pty=mi_look_for_free_pty(&master,&slave);
99 mi_pty *res;
100
101 if (pty<0)
102 return NULL;
103 res=(mi_pty *)malloc(sizeof(mi_pty));
104 if (!res)
105 return NULL;
106 res->slave=strdup(slave);
107 res->master=master;
108 return res;
109}
110
111void mi_free_pty(mi_pty *p)
112{
113 if (!p)
114 return;
115 free(p->slave);
116 free(p);
117}
118
119/**[txh]********************************************************************
120
121 Description:
122 Closes the pseudo termial master and releases the allocated memory.
123
124***************************************************************************/
125
126void gmi_end_pty(mi_pty *p)
127{
128 if (!p)
129 return;
130 close(p->master);
131 mi_free_pty(p);
132}
diff --git a/src/monkey/get_free_vt.c b/src/monkey/get_free_vt.c
new file mode 100644
index 000000000..f5c980005
--- /dev/null
+++ b/src/monkey/get_free_vt.c
@@ -0,0 +1,153 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Linux VT.
7 Comments:
8 Helper to find a free VT. That's 100% Linux specific.@p
9 The code comes from "lconsole.c" from Allegro project and was originally
10created by Marek Habersack and then modified by George Foot. I addapted it
11to my needs and changed license from giftware to GPL.@p
12
13***************************************************************************/
14
15#define _GNU_SOURCE
16#include <string.h>
17#include <stdio.h>
18#include <unistd.h>
19#include <fcntl.h>
20#include <sys/ioctl.h>
21#ifdef __APPLE__
22#include <util.h>
23#endif /* __APPLE__ */
24
25#include "mi_gdb.h"
26
27#if !defined(__linux__)
28
29int mi_look_for_free_vt()
30{
31 return -1;
32}
33
34mi_aux_term *gmi_look_for_free_vt()
35{
36 return NULL;
37}
38
39#else
40
41#include <linux/vt.h>
42
43/**[txh]********************************************************************
44
45 Description:
46 Look for a free and usable Linux VT. Low level, use
47@x{gmi_look_for_free_vt}.
48
49 Return: The VT number or <0 on error.
50
51***************************************************************************/
52
53int mi_look_for_free_vt()
54{/* Code from Allegro. */
55 int tty, console_fd, fd;
56 unsigned short mask;
57 char tty_name[16];
58 struct vt_stat vts;
59
60 /* Now we need to find a VT we can use. It must be readable and
61 * writable by us, if we're not setuid root. VT_OPENQRY itself
62 * isn't too useful because it'll only ever come up with one
63 * suggestion, with no guarrantee that we actually have access
64 * to it.
65 *
66 * At some stage I think this is a candidate for config
67 * file overriding, but for now we'll stat the first N consoles
68 * to see which ones we can write to (hopefully at least one!),
69 * so that we can use that one to do ioctls. We used to use
70 * /dev/console for that purpose but it looks like it's not
71 * always writable by enough people.
72 *
73 * Having found and opened a writable device, we query the state
74 * of the first sixteen (fifteen really) consoles, and try
75 * opening each unused one in turn.
76 */
77
78 console_fd=open("/dev/console",O_WRONLY);
79 if (console_fd<0)
80 {
81 int n;
82 /* Try some ttys instead... */
83 for (n=1; n<=24; n++)
84 {
85 snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",n);
86 console_fd=open(tty_name,O_WRONLY);
87 if (console_fd>=0)
88 break;
89 }
90 if (n>24)
91 return -1;
92 }
93
94 /* Get the state of the console -- in particular, the free VT field */
95 if (ioctl(console_fd,VT_GETSTATE,&vts))
96 return -2;
97 close(console_fd);
98
99 /* We attempt to set our euid to 0; if we were run with euid 0 to
100 * start with, we'll be able to do this now. Otherwise, we'll just
101 * ignore the error returned since it might not be a problem if the
102 * ttys we look at are owned by the user running the program. */
103 seteuid(0);
104
105 /* tty0 is not really a console, so start counting at 2. */
106 fd=-1;
107 for (tty=1, mask=2; mask; tty++, mask<<=1)
108 if (!(vts.v_state & mask))
109 {
110 snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",tty);
111 fd=open(tty_name,O_RDWR);
112 if (fd!=-1)
113 {
114 close(fd);
115 break;
116 }
117 }
118
119 seteuid(getuid());
120
121 if (!mask)
122 return -3;
123
124 return tty;
125}
126
127/**[txh]********************************************************************
128
129 Description:
130 Look for a free and usable Linux VT to be used by the child.
131
132 Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
133release it.
134
135***************************************************************************/
136
137mi_aux_term *gmi_look_for_free_vt()
138{
139 int vt=mi_look_for_free_vt();
140 mi_aux_term *res;
141
142 if (vt<0)
143 return NULL;
144 res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
145 if (!res)
146 return NULL;
147 res->pid=-1;
148 asprintf(&res->tty,"/dev/tty%d",vt);
149 return res;
150}
151
152#endif
153
diff --git a/src/monkey/gnunet-monkey.c b/src/monkey/gnunet-monkey.c
new file mode 100644
index 000000000..f8b0e9e93
--- /dev/null
+++ b/src/monkey/gnunet-monkey.c
@@ -0,0 +1,159 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Comment:
7 X11 example/test of the libmigdb.
8 Run it from an X11 terminal (xterm, Eterm, etc.).
9
10***************************************************************************/
11
12#include <stdio.h>
13#include <unistd.h> //usleep
14#include <libesmtp.h>
15#include "mi_gdb.h"
16
17void cb_console(const char *str, void *data)
18{
19 printf("CONSOLE> %s\n",str);
20}
21
22/* Note that unlike what's documented in gdb docs it isn't usable. */
23void cb_target(const char *str, void *data)
24{
25 printf("TARGET> %s\n",str);
26}
27
28void cb_log(const char *str, void *data)
29{
30 printf("LOG> %s\n",str);
31}
32
33void cb_to(const char *str, void *data)
34{
35 printf(">> %s",str);
36}
37
38void cb_from(const char *str, void *data)
39{
40 printf("<< %s\n",str);
41}
42
43volatile int async_c=0;
44
45void cb_async(mi_output *o, void *data)
46{
47 printf("ASYNC\n");
48 async_c++;
49}
50
51int wait_for_stop(mi_h *h)
52{
53 int res=1;
54 mi_stop *sr;
55 mi_frames *f;
56
57 while (!mi_get_response(h))
58 usleep(1000);
59 /* The end of the async. */
60 sr=mi_res_stop(h);
61 if (sr)
62 {
63 printf("Stopped, reason: %s\n",mi_reason_enum_to_str(sr->reason));
64 printf("Received signal name: %s\n", sr->signal_name);
65 printf("Received signal meaning: %s\n", sr->signal_meaning);
66 //printf("In file: %s\n", sr->frame->file);
67 //printf("Line Number: %d\n", sr->frame->line);
68 f = gmi_stack_info_frame(h);
69 mi_free_stop(sr);
70 }
71 else
72 {
73 printf("Error while waiting\n");
74 printf("mi_error: %d\nmi_error_from_gdb: %s\n",mi_error,mi_error_from_gdb);
75 res=0;
76 }
77 return res;
78}
79
80int main(int argc, char *argv[])
81{
82 mi_aux_term *xterm_tty=NULL;
83
84 /* This is like a file-handle for fopen.
85 Here we have all the state of gdb "connection". */
86 mi_h *h;
87
88 /* Connect to gdb child. */
89 h=mi_connect_local();
90 if (!h)
91 {
92 printf("Connect failed\n");
93 return 1;
94 }
95 printf("Connected to gdb!\n");
96
97 /* Set all callbacks. */
98 mi_set_console_cb(h,cb_console,NULL);
99 mi_set_target_cb(h,cb_target,NULL);
100 mi_set_log_cb(h,cb_log,NULL);
101 mi_set_async_cb(h,cb_async,NULL);
102 mi_set_to_gdb_cb(h,cb_to,NULL);
103 mi_set_from_gdb_cb(h,cb_from,NULL);
104
105 /* Set the name of the child and the command line aguments. */
106 if (!gmi_set_exec(h,"bug_null_pointer_exception", NULL))
107 {
108 printf("Error setting exec y args\n");
109 mi_disconnect(h);
110 return 1;
111 }
112
113 /* Tell gdb to attach the child to a terminal. */
114 if (!gmi_target_terminal(h, ttyname(STDIN_FILENO)))
115 {
116 printf("Error selecting target terminal\n");
117 mi_disconnect(h);
118 return 1;
119 }
120
121 /* Run the program. */
122 if (!gmi_exec_run(h))
123 {
124 printf("Error in run!\n");
125 mi_disconnect(h);
126 return 1;
127 }
128 /* Here we should be stopped when the program crashes */
129 if (!wait_for_stop(h))
130 {
131 mi_disconnect(h);
132 return 1;
133 }
134
135 /* Continue execution. */
136 if (!gmi_exec_continue(h))
137 {
138 printf("Error in continue!\n");
139 mi_disconnect(h);
140 return 1;
141 }
142 /* Here we should be terminated. */
143 if (!wait_for_stop(h))
144 {
145 mi_disconnect(h);
146 return 1;
147 }
148
149 /* Exit from gdb. */
150 gmi_gdb_exit(h);
151 /* Close the connection. */
152 mi_disconnect(h);
153 /* Wait 5 seconds and close the auxiliar terminal. */
154 printf("Waiting 5 seconds\n");
155 sleep(5);
156 gmi_end_aux_term(xterm_tty);
157
158 return 0;
159}
diff --git a/src/monkey/gnunet-service-monkey.c b/src/monkey/gnunet-service-monkey.c
new file mode 100644
index 000000000..b0a0583ee
--- /dev/null
+++ b/src/monkey/gnunet-service-monkey.c
@@ -0,0 +1,6 @@
1
2
3int main(int argc, char *argv[])
4{
5 return 0;
6} \ No newline at end of file
diff --git a/src/monkey/libmigdb.h b/src/monkey/libmigdb.h
new file mode 100644
index 000000000..c4c404def
--- /dev/null
+++ b/src/monkey/libmigdb.h
@@ -0,0 +1,4 @@
1#ifndef LIBMIGDB_H_
2#define LIBMIGDB_H_
3
4#endif /*LIBMIGDB_H_*/
diff --git a/src/monkey/mail_sender.c b/src/monkey/mail_sender.c
new file mode 100644
index 000000000..ff5d13e47
--- /dev/null
+++ b/src/monkey/mail_sender.c
@@ -0,0 +1,235 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <ctype.h>
4#include <unistd.h>
5#include <getopt.h>
6#include <string.h>
7#include <fcntl.h>
8#include <signal.h>
9#include <errno.h>
10#include <stdarg.h>
11
12#include <openssl/ssl.h>
13#include <auth-client.h>
14#include <libesmtp.h>
15
16#if !defined (__GNUC__) || __GNUC__ < 2
17# define __attribute__(x)
18#endif
19#define unused __attribute__((unused))
20
21
22int
23handle_invalid_peer_certificate(long vfy_result)
24{
25 const char *k ="rare error";
26 switch(vfy_result) {
27 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
28 k="X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"; break;
29 case X509_V_ERR_UNABLE_TO_GET_CRL:
30 k="X509_V_ERR_UNABLE_TO_GET_CRL"; break;
31 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
32 k="X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"; break;
33 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
34 k="X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"; break;
35 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
36 k="X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"; break;
37 case X509_V_ERR_CERT_SIGNATURE_FAILURE:
38 k="X509_V_ERR_CERT_SIGNATURE_FAILURE"; break;
39 case X509_V_ERR_CRL_SIGNATURE_FAILURE:
40 k="X509_V_ERR_CRL_SIGNATURE_FAILURE"; break;
41 case X509_V_ERR_CERT_NOT_YET_VALID:
42 k="X509_V_ERR_CERT_NOT_YET_VALID"; break;
43 case X509_V_ERR_CERT_HAS_EXPIRED:
44 k="X509_V_ERR_CERT_HAS_EXPIRED"; break;
45 case X509_V_ERR_CRL_NOT_YET_VALID:
46 k="X509_V_ERR_CRL_NOT_YET_VALID"; break;
47 case X509_V_ERR_CRL_HAS_EXPIRED:
48 k="X509_V_ERR_CRL_HAS_EXPIRED"; break;
49 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
50 k="X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"; break;
51 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
52 k="X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"; break;
53 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
54 k="X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"; break;
55 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
56 k="X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"; break;
57 case X509_V_ERR_OUT_OF_MEM:
58 k="X509_V_ERR_OUT_OF_MEM"; break;
59 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
60 k="X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"; break;
61 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
62 k="X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"; break;
63 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
64 k="X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"; break;
65 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
66 k="X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"; break;
67 case X509_V_ERR_CERT_CHAIN_TOO_LONG:
68 k="X509_V_ERR_CERT_CHAIN_TOO_LONG"; break;
69 case X509_V_ERR_CERT_REVOKED:
70 k="X509_V_ERR_CERT_REVOKED"; break;
71 case X509_V_ERR_INVALID_CA:
72 k="X509_V_ERR_INVALID_CA"; break;
73 case X509_V_ERR_PATH_LENGTH_EXCEEDED:
74 k="X509_V_ERR_PATH_LENGTH_EXCEEDED"; break;
75 case X509_V_ERR_INVALID_PURPOSE:
76 k="X509_V_ERR_INVALID_PURPOSE"; break;
77 case X509_V_ERR_CERT_UNTRUSTED:
78 k="X509_V_ERR_CERT_UNTRUSTED"; break;
79 case X509_V_ERR_CERT_REJECTED:
80 k="X509_V_ERR_CERT_REJECTED"; break;
81 }
82 printf("SMTP_EV_INVALID_PEER_CERTIFICATE: %ld: %s\n", vfy_result, k);
83 return 1; /* Accept the problem */
84}
85
86
87void event_cb (smtp_session_t session, int event_no, void *arg,...)
88{
89 va_list alist;
90 int *ok;
91
92 va_start(alist, arg);
93 switch(event_no) {
94 case SMTP_EV_CONNECT:
95 case SMTP_EV_MAILSTATUS:
96 case SMTP_EV_RCPTSTATUS:
97 case SMTP_EV_MESSAGEDATA:
98 case SMTP_EV_MESSAGESENT:
99 case SMTP_EV_DISCONNECT: break;
100 case SMTP_EV_WEAK_CIPHER: {
101 int bits;
102 bits = va_arg(alist, long); ok = va_arg(alist, int*);
103 printf("SMTP_EV_WEAK_CIPHER, bits=%d - accepted.\n", bits);
104 *ok = 1; break;
105 }
106 case SMTP_EV_STARTTLS_OK:
107 puts("SMTP_EV_STARTTLS_OK - TLS started here."); break;
108 case SMTP_EV_INVALID_PEER_CERTIFICATE: {
109 long vfy_result;
110 vfy_result = va_arg(alist, long); ok = va_arg(alist, int*);
111 *ok = handle_invalid_peer_certificate(vfy_result);
112 break;
113 }
114 case SMTP_EV_NO_PEER_CERTIFICATE: {
115 ok = va_arg(alist, int*);
116 puts("SMTP_EV_NO_PEER_CERTIFICATE - accepted.");
117 *ok = 1; break;
118 }
119 case SMTP_EV_WRONG_PEER_CERTIFICATE: {
120 ok = va_arg(alist, int*);
121 puts("SMTP_EV_WRONG_PEER_CERTIFICATE - accepted.");
122 *ok = 1; break;
123 }
124 case SMTP_EV_NO_CLIENT_CERTIFICATE: {
125 ok = va_arg(alist, int*);
126 puts("SMTP_EV_NO_CLIENT_CERTIFICATE - accepted.");
127 *ok = 1; break;
128 }
129 default:
130 printf("Got event: %d - ignored.\n", event_no);
131 }
132 va_end(alist);
133}
134
135
136/* Callback to prnt the recipient status */
137void
138print_recipient_status (smtp_recipient_t recipient,
139 const char *mailbox, void *arg unused)
140{
141 const smtp_status_t *status;
142
143 status = smtp_recipient_status (recipient);
144 printf ("%s: %d %s", mailbox, status->code, status->text);
145}
146
147
148void sendMail()
149{
150 smtp_session_t session;
151 smtp_message_t message;
152 smtp_recipient_t recipient;
153 auth_context_t authctx;
154 const smtp_status_t *status;
155 struct sigaction sa;
156 char *host = "localhost:25";
157 char *from = "gnunet-monkey";
158 char *subject = "e-mail from Libesmtp!";
159 const char *recipient_address = "halims@in.tum.de";
160 char tempFileName[1000];
161 int tempFd;
162 FILE *fp;
163 enum notify_flags notify = Notify_SUCCESS | Notify_FAILURE;
164
165 auth_client_init();
166 session = smtp_create_session();
167 message = smtp_add_message(session);
168
169 /* Ignore sigpipe */
170 sa.sa_handler = SIG_IGN;
171 sigemptyset(&sa.sa_mask);
172 sa.sa_flags = 0;
173 sigaction(SIGPIPE, &sa, NULL);
174
175
176 smtp_set_server(session, host);
177 smtp_set_eventcb(session, event_cb, NULL);
178
179 /* Set the reverse path for the mail envelope. (NULL is ok)
180 */
181 smtp_set_reverse_path(message, from);
182
183 /* Set the Subject: header. For no reason, we want the supplied subject
184 to override any subject line in the message headers. */
185 if (subject != NULL) {
186 smtp_set_header(message, "Subject", subject);
187 smtp_set_header_option(message, "Subject", Hdr_OVERRIDE, 1);
188 }
189
190
191 /* Prepare message */
192 memset(tempFileName, 0, sizeof(tempFileName));
193 sprintf(tempFileName, "/tmp/messageXXXXXX");
194 tempFd = mkstemp(tempFileName);
195 fp = fdopen(tempFd, "w");
196 fprintf(fp, "Hello! This is a test message!\r\n");
197 fclose(fp);
198 fp = fopen(tempFileName, "r");
199 smtp_set_message_fp(message, fp);
200
201
202 recipient = smtp_add_recipient(message, recipient_address);
203
204 smtp_dsn_set_notify (recipient, notify);
205
206 /* Initiate a connection to the SMTP server and transfer the
207 message. */
208 if (!smtp_start_session(session)) {
209 char buf[128];
210
211 fprintf(stderr, "SMTP server problem %s\n", smtp_strerror(smtp_errno(),
212 buf, sizeof buf));
213 } else {
214 /* Report on the success or otherwise of the mail transfer.
215 */
216 status = smtp_message_transfer_status(message);
217 printf("%d %s", status->code, (status->text != NULL) ? status->text
218 : "\n");
219 smtp_enumerate_recipients(message, print_recipient_status, NULL);
220 }
221
222 /* Free resources consumed by the program.
223 */
224 smtp_destroy_session(session);
225 auth_destroy_context(authctx);
226 fclose(fp);
227 auth_client_exit();
228 exit(0);
229}
230
231int main()
232{
233 sendMail();
234 return 0;
235}
diff --git a/src/monkey/mi_gdb.h b/src/monkey/mi_gdb.h
new file mode 100644
index 000000000..df932b4ec
--- /dev/null
+++ b/src/monkey/mi_gdb.h
@@ -0,0 +1,972 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2009 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Comments:
7 Main header for libmigdb.
8
9***************************************************************************/
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <unistd.h> /* pid_t */
18
19#define MI_OK 0
20#define MI_OUT_OF_MEMORY 1
21#define MI_PIPE_CREATE 2
22#define MI_FORK 3
23#define MI_DEBUGGER_RUN 4
24#define MI_PARSER 5
25#define MI_UNKNOWN_ASYNC 6
26#define MI_UNKNOWN_RESULT 7
27#define MI_FROM_GDB 8
28#define MI_GDB_TIME_OUT 9
29#define MI_GDB_DIED 10
30#define MI_MISSING_XTERM 11
31#define MI_CREATE_TEMPORAL 12
32#define MI_MISSING_GDB 13
33#define MI_LAST_ERROR 13
34
35#define MI_R_NONE 0 /* We are no waiting any response. */
36#define MI_R_SKIP 1 /* We want to discard it. */
37#define MI_R_FE_AND_S 2 /* Wait for done. */
38#define MI_R_E_ARGS 3
39
40enum mi_val_type { t_const, t_tuple, t_list };
41
42/* Types and subtypes. */
43/* Type. */
44#define MI_T_OUT_OF_BAND 0
45#define MI_T_RESULT_RECORD 1
46/* Out of band subtypes. */
47#define MI_ST_ASYNC 0
48#define MI_ST_STREAM 1
49/* Async sub-subtypes. */
50#define MI_SST_EXEC 0
51#define MI_SST_STATUS 1
52#define MI_SST_NOTIFY 2
53/* Stream sub-subtypes. */
54#define MI_SST_CONSOLE 3
55#define MI_SST_TARGET 4
56#define MI_SST_LOG 5
57/* Classes. */
58/* Async classes. */
59#define MI_CL_UNKNOWN 0
60#define MI_CL_STOPPED 1
61#define MI_CL_DOWNLOAD 2
62/* Result classes. */
63#define MI_CL_DONE 2
64#define MI_CL_RUNNING 3
65#define MI_CL_CONNECTED 4
66#define MI_CL_ERROR 5
67#define MI_CL_EXIT 6
68
69#define MI_DEFAULT_TIME_OUT 10
70
71#define MI_DIS_ASM 0
72#define MI_DIS_SRC_ASM 1
73
74/* Implemented workaround for gdb bugs that we can dis/enable. */
75/* At least gdb<=6.1.1 fails to find a source file with absolute path if the
76 name is for a psym instead of a sym. psym==partially loaded symbol table. */
77#define MI_PSYM_SEARCH 0
78
79#define MI_VERSION_STR "0.8.12"
80#define MI_VERSION_MAJOR 0
81#define MI_VERSION_MIDDLE 8
82#define MI_VERSION_MINOR 12
83
84struct mi_results_struct
85{
86 char *var; /* Result name or NULL if just a value. */
87 enum mi_val_type type;
88 union
89 {
90 char *cstr;
91 struct mi_results_struct *rs;
92 } v;
93 struct mi_results_struct *next;
94};
95typedef struct mi_results_struct mi_results;
96
97struct mi_output_struct
98{
99 /* Type of output. */
100 char type;
101 char stype;
102 char sstype;
103 char tclass;
104 /* Content. */
105 mi_results *c;
106 /* Always modeled as a list. */
107 struct mi_output_struct *next;
108};
109typedef struct mi_output_struct mi_output;
110
111typedef void (*stream_cb)(const char *, void *);
112typedef void (*async_cb)(mi_output *o, void *);
113typedef int (*tm_cb)(void *);
114
115/* Values of this structure shouldn't be manipulated by the user. */
116struct mi_h_struct
117{
118 /* Pipes connected to gdb. */
119 int to_gdb[2];
120 int from_gdb[2];
121 /* Streams for the pipes. */
122 FILE *to, *from;
123 /* PID of child gdb. */
124 pid_t pid;
125 char died;
126 /* Which rensponse we are waiting for. */
127 /*int response;*/
128 /* The line we are reading. */
129 char *line;
130 int llen, lread;
131 /* Parsed output. */
132 mi_output *po, *last;
133 /* Tunneled streams callbacks. */
134 stream_cb console;
135 void *console_data;
136 stream_cb target;
137 void *target_data;
138 stream_cb log;
139 void *log_data;
140 /* Async responses callback. */
141 async_cb async;
142 void *async_data;
143 /* Callbacks to get echo of gdb dialog. */
144 stream_cb to_gdb_echo;
145 void *to_gdb_echo_data;
146 stream_cb from_gdb_echo;
147 void *from_gdb_echo_data;
148 /* Time out */
149 tm_cb time_out_cb;
150 void *time_out_cb_data;
151 int time_out;
152 /* Ugly workaround for some of the show responses :-( */
153 int catch_console;
154 char *catched_console;
155 /* MI version, currently unknown but the user can force v2 */
156 unsigned version;
157};
158typedef struct mi_h_struct mi_h;
159
160#define MI_TO(a) ((a)->to_gdb[1])
161
162enum mi_bkp_type { t_unknown=0, t_breakpoint=1, t_hw=2 };
163enum mi_bkp_disp { d_unknown=0, d_keep=1, d_del=2 };
164enum mi_bkp_mode { m_file_line=0, m_function=1, m_file_function=2, m_address=3 };
165
166struct mi_bkpt_struct
167{
168 int number;
169 enum mi_bkp_type type;
170 enum mi_bkp_disp disp; /* keep or del if temporal */
171 char enabled;
172 void *addr;
173 char *func;
174 char *file;
175 int line;
176 int ignore;
177 int times;
178
179 /* For the user: */
180 char *cond;
181 char *file_abs;
182 int thread;
183 enum mi_bkp_mode mode;
184 struct mi_bkpt_struct *next;
185};
186typedef struct mi_bkpt_struct mi_bkpt;
187
188enum mi_wp_mode { wm_unknown=0, wm_write=1, wm_read=2, wm_rw=3 };
189
190struct mi_wp_struct
191{
192 int number;
193 char *exp;
194 enum mi_wp_mode mode;
195
196 /* For the user: */
197 struct mi_wp_struct *next;
198 char enabled;
199};
200typedef struct mi_wp_struct mi_wp;
201
202struct mi_frames_struct
203{
204 int level; /* The frame number, 0 being the topmost frame, i.e. the innermost
205 function. */
206 void *addr; /* The `$pc' value for that frame. */
207 char *func; /* Function name. */
208 char *file; /* File name of the source file where the function lives. */
209 char *from;
210 int line; /* Line number corresponding to the `$pc'. */
211 /* When arguments are available: */
212 mi_results *args;
213 int thread_id;
214 /* When more than one is provided: */
215 struct mi_frames_struct *next;
216};
217typedef struct mi_frames_struct mi_frames;
218
219struct mi_aux_term_struct
220{
221 pid_t pid;
222 char *tty;
223};
224typedef struct mi_aux_term_struct mi_aux_term;
225
226struct mi_pty_struct
227{
228 char *slave;
229 int master;
230};
231typedef struct mi_pty_struct mi_pty;
232
233enum mi_gvar_fmt { fm_natural=0, fm_binary=1, fm_decimal=2, fm_hexadecimal=3,
234 fm_octal=4,
235 /* Only for registers format: */
236 fm_raw=5 };
237enum mi_gvar_lang { lg_unknown=0, lg_c, lg_cpp, lg_java };
238
239#define MI_ATTR_DONT_KNOW 0
240#define MI_ATTR_NONEDITABLE 1
241#define MI_ATTR_EDITABLE 2
242
243struct mi_gvar_struct
244{
245 char *name;
246 int numchild;
247 char *type;
248 enum mi_gvar_fmt format;
249 enum mi_gvar_lang lang;
250 char *exp;
251 int attr;
252
253 /* MI v2 fills it, not yet implemented here. */
254 /* Use gmi_var_evaluate_expression. */
255 char *value;
256
257 /* Pointer to the parent. NULL if none. */
258 struct mi_gvar_struct *parent;
259 /* List containing the children.
260 Filled by gmi_var_list_children.
261 NULL if numchild==0 or not yet filled. */
262 struct mi_gvar_struct *child;
263 /* Next var in the list. */
264 struct mi_gvar_struct *next;
265
266 /* For the user: */
267 char opened; /* We will show its children. 1 when we fill "child" */
268 char changed; /* Needs to be updated. 0 when created. */
269 int vischild; /* How many items visible. numchild when we fill "child" */
270 int depth; /* How deep is this var. */
271 char ispointer;
272};
273typedef struct mi_gvar_struct mi_gvar;
274
275struct mi_gvar_chg_struct
276{
277 char *name;
278 int in_scope; /* if true the other fields apply. */
279 char *new_type; /* NULL if type_changed==false */
280 int new_num_children; /* only when new_type!=NULL */
281
282 struct mi_gvar_chg_struct *next;
283};
284typedef struct mi_gvar_chg_struct mi_gvar_chg;
285
286
287/* A list of assembler instructions. */
288struct mi_asm_insn_struct
289{
290 void *addr;
291 char *func;
292 unsigned offset;
293 char *inst;
294
295 struct mi_asm_insn_struct *next;
296};
297typedef struct mi_asm_insn_struct mi_asm_insn;
298
299/* A list of source lines containing assembler instructions. */
300struct mi_asm_insns_struct
301{
302 char *file;
303 int line;
304 mi_asm_insn *ins;
305
306 struct mi_asm_insns_struct *next;
307};
308typedef struct mi_asm_insns_struct mi_asm_insns;
309
310/* Changed register. */
311struct mi_chg_reg_struct
312{
313 int reg;
314 char *val;
315 char *name;
316 char updated;
317
318 struct mi_chg_reg_struct *next;
319};
320typedef struct mi_chg_reg_struct mi_chg_reg;
321
322/*
323 Examining gdb sources and looking at docs I can see the following "stop"
324reasons:
325
326Breakpoints:
327a) breakpoint-hit (bkptno) + frame
328Also: without reason for temporal breakpoints.
329
330Watchpoints:
331b) watchpoint-trigger (wpt={number,exp};value={old,new}) + frame
332c) read-watchpoint-trigger (hw-rwpt{number,exp};value={value}) + frame
333d) access-watchpoint-trigger (hw-awpt{number,exp};value={[old,]new}) + frame
334e) watchpoint-scope (wpnum) + frame
335
336Movement:
337f) function-finished ([gdb-result-var,return-value]) + frame
338g) location-reached + frame
339h) end-stepping-range + frame
340
341Exit:
342i) exited-signalled (signal-name,signal-meaning)
343j) exited (exit-code)
344k) exited-normally
345
346Signal:
347l) signal-received (signal-name,signal-meaning) + frame
348
349Plus: thread-id
350*/
351enum mi_stop_reason
352{
353 sr_unknown=0,
354 sr_bkpt_hit,
355 sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
356 sr_function_finished, sr_location_reached, sr_end_stepping_range,
357 sr_exited_signalled, sr_exited, sr_exited_normally,
358 sr_signal_received
359};
360
361struct mi_stop_struct
362{
363 enum mi_stop_reason reason; /* If more than one reason just the last. */
364 /* Flags indicating if non-pointer fields are filled. */
365 char have_thread_id;
366 char have_bkptno;
367 char have_exit_code;
368 char have_wpno;
369 /* Where stopped. Doesn't exist for sr_exited*. */
370 int thread_id;
371 mi_frames *frame;
372 /* sr_bkpt_hit */
373 int bkptno;
374 /* sr_*wp_* no scope */
375 mi_wp *wp;
376 char *wp_old;
377 char *wp_val;
378 /* sr_wp_scope */
379 int wpno;
380 /* sr_function_finished. Not for void func. */
381 char *gdb_result_var;
382 char *return_value;
383 /* sr_exited_signalled, sr_signal_received */
384 char *signal_name;
385 char *signal_meaning;
386 /* sr_exited */
387 int exit_code;
388};
389typedef struct mi_stop_struct mi_stop;
390
391/* Variable containing the last error. */
392extern int mi_error;
393extern char *mi_error_from_gdb;
394const char *mi_get_error_str();
395
396/* Indicate the name of gdb exe. Default is /usr/bin/gdb */
397void mi_set_gdb_exe(const char *name);
398const char *mi_get_gdb_exe();
399/* Indicate the name of a file containing commands to send at start-up */
400void mi_set_gdb_start(const char *name);
401const char *mi_get_gdb_start();
402/* Indicate the name of a file containing commands to send after connection */
403void mi_set_gdb_conn(const char *name);
404const char *mi_get_gdb_conn();
405void mi_send_target_commands(mi_h *h);
406/* Connect to a local copy of gdb. */
407mi_h *mi_connect_local();
408/* Close connection. You should ask gdb to quit first. */
409void mi_disconnect(mi_h *h);
410/* Force MI version. */
411#define MI_VERSION2U(maj,mid,min) (maj*0x1000000+mid*0x10000+min)
412void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
413 unsigned vMinor);
414void mi_set_workaround(unsigned wa, int enable);
415int mi_get_workaround(unsigned wa);
416/* Parse gdb output. */
417mi_output *mi_parse_gdb_output(const char *str);
418/* Functions to set/get the tunneled streams callbacks. */
419void mi_set_console_cb(mi_h *h, stream_cb cb, void *data);
420void mi_set_target_cb(mi_h *h, stream_cb cb, void *data);
421void mi_set_log_cb(mi_h *h, stream_cb cb, void *data);
422stream_cb mi_get_console_cb(mi_h *h, void **data);
423stream_cb mi_get_target_cb(mi_h *h, void **data);
424stream_cb mi_get_log_cb(mi_h *h, void **data);
425/* The callback to deal with async events. */
426void mi_set_async_cb(mi_h *h, async_cb cb, void *data);
427async_cb mi_get_async_cb(mi_h *h, void **data);
428/* Time out in gdb responses. */
429void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data);
430tm_cb mi_get_time_out_cb(mi_h *h, void **data);
431void mi_set_time_out(mi_h *h, int to);
432int mi_get_time_out(mi_h *h);
433/* Callbacks to "see" the dialog with gdb. */
434void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data);
435void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data);
436stream_cb mi_get_to_gdb_cb(mi_h *h, void **data);
437stream_cb mi_get_from_gdb_cb(mi_h *h, void **data);
438/* Sends a message to gdb. */
439int mi_send(mi_h *h, const char *format, ...);
440/* Wait until gdb sends a response. */
441mi_output *mi_get_response_blk(mi_h *h);
442/* Check if gdb sent a complete response. Use with mi_retire_response. */
443int mi_get_response(mi_h *h);
444/* Get the last response. Use with mi_get_response. */
445mi_output *mi_retire_response(mi_h *h);
446/* Look for a result record in gdb output. */
447mi_output *mi_get_rrecord(mi_output *r);
448/* Look if the output contains an async stop.
449 If that's the case return the reason for the stop.
450 If the output contains an error the description is returned in reason. */
451int mi_get_async_stop_reason(mi_output *r, char **reason);
452mi_stop *mi_get_stopped(mi_results *r);
453mi_frames *mi_get_async_frame(mi_output *r);
454/* Wait until gdb sends a response.
455 Then check if the response is of the desired type. */
456int mi_res_simple_exit(mi_h *h);
457int mi_res_simple_done(mi_h *h);
458int mi_res_simple_running(mi_h *h);
459int mi_res_simple_connected(mi_h *h);
460/* It additionally extracts an specified variable. */
461mi_results *mi_res_done_var(mi_h *h, const char *var);
462/* Extract a frames list from the response. */
463mi_frames *mi_res_frames_array(mi_h *h, const char *var);
464mi_frames *mi_res_frames_list(mi_h *h);
465mi_frames *mi_parse_frame(mi_results *c);
466mi_frames *mi_res_frame(mi_h *h);
467/* Create an auxiliar terminal using xterm. */
468mi_aux_term *gmi_start_xterm();
469/* Indicate the name of xterm exe. Default is /usr/bin/X11/xterm */
470void mi_set_xterm_exe(const char *name);
471const char *mi_get_xterm_exe();
472/* Kill the auxiliar terminal and release the structure. */
473void gmi_end_aux_term(mi_aux_term *t);
474/* Look for a free Linux VT for the child. */
475mi_aux_term *gmi_look_for_free_vt();
476/* Look for a free and usable Linux VT. */
477int mi_look_for_free_vt();
478/* Close master and release the structure. */
479void gmi_end_pty(mi_pty *p);
480/* Look for a free pseudo terminal. */
481mi_pty *gmi_look_for_free_pty();
482/* Extract a list of thread IDs from response. */
483int mi_res_thread_ids(mi_h *h, int **list);
484int mi_get_thread_ids(mi_output *res, int **list);
485/* A variable response. */
486mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression);
487enum mi_gvar_fmt mi_format_str_to_enum(const char *format);
488const char *mi_format_enum_to_str(enum mi_gvar_fmt format);
489char mi_format_enum_to_char(enum mi_gvar_fmt format);
490enum mi_gvar_lang mi_lang_str_to_enum(const char *lang);
491const char *mi_lang_enum_to_str(enum mi_gvar_lang lang);
492int mi_res_changelist(mi_h *h, mi_gvar_chg **changed);
493int mi_res_children(mi_h *h, mi_gvar *v);
494mi_bkpt *mi_res_bkpt(mi_h *h);
495mi_wp *mi_res_wp(mi_h *h);
496char *mi_res_value(mi_h *h);
497mi_stop *mi_res_stop(mi_h *h);
498enum mi_stop_reason mi_reason_str_to_enum(const char *s);
499const char *mi_reason_enum_to_str(enum mi_stop_reason r);
500int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
501 unsigned long *addr);
502mi_asm_insns *mi_get_asm_insns(mi_h *h);
503/* Starting point of the program. */
504void mi_set_main_func(const char *name);
505const char *mi_get_main_func();
506mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many);
507int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l);
508mi_chg_reg *mi_get_list_changed_regs(mi_h *h);
509int mi_get_reg_values(mi_h *h, mi_chg_reg *l);
510mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many);
511int gmi_target_download(mi_h *h);
512
513/* Allocation functions: */
514void *mi_calloc(size_t count, size_t sz);
515void *mi_calloc1(size_t sz);
516char *mi_malloc(size_t sz);
517mi_results *mi_alloc_results(void);
518mi_output *mi_alloc_output(void);
519mi_frames *mi_alloc_frames(void);
520mi_gvar *mi_alloc_gvar(void);
521mi_gvar_chg *mi_alloc_gvar_chg(void);
522mi_bkpt *mi_alloc_bkpt(void);
523mi_wp *mi_alloc_wp(void);
524mi_stop *mi_alloc_stop(void);
525mi_asm_insns *mi_alloc_asm_insns(void);
526mi_asm_insn *mi_alloc_asm_insn(void);
527mi_chg_reg *mi_alloc_chg_reg(void);
528void mi_free_output(mi_output *r);
529void mi_free_output_but(mi_output *r, mi_output *no, mi_results *no_r);
530void mi_free_frames(mi_frames *f);
531void mi_free_aux_term(mi_aux_term *t);
532void mi_free_results(mi_results *r);
533void mi_free_results_but(mi_results *r, mi_results *no);
534void mi_free_gvar(mi_gvar *v);
535void mi_free_gvar_chg(mi_gvar_chg *p);
536void mi_free_wp(mi_wp *wp);
537void mi_free_stop(mi_stop *s);
538void mi_free_asm_insns(mi_asm_insns *i);
539void mi_free_asm_insn(mi_asm_insn *i);
540void mi_free_charp_list(char **l);
541void mi_free_chg_reg(mi_chg_reg *r);
542
543/* Porgram control: */
544/* Specify the executable and arguments for local debug. */
545int gmi_set_exec(mi_h *h, const char *file, const char *args);
546/* Start running the executable. Remote sessions starts running. */
547int gmi_exec_run(mi_h *h);
548/* Continue the execution after a "stop". */
549int gmi_exec_continue(mi_h *h);
550/* Indicate which terminal will use the target program. For local sessions. */
551int gmi_target_terminal(mi_h *h, const char *tty_name);
552/* Specify what's the local copy that have debug info. For remote sessions. */
553int gmi_file_symbol_file(mi_h *h, const char *file);
554/* Continue until function return, the return value is included in the async
555 response. */
556int gmi_exec_finish(mi_h *h);
557/* Stop the program using SIGINT. */
558int gmi_exec_interrupt(mi_h *h);
559/* Next line of code. */
560int gmi_exec_next(mi_h *h);
561/* Next count lines of code. */
562int gmi_exec_next_cnt(mi_h *h, int count);
563/* Next line of assembler code. */
564int gmi_exec_next_instruction(mi_h *h);
565/* Next line of code. Get inside functions. */
566int gmi_exec_step(mi_h *h);
567/* Next count lines of code. Get inside functions. */
568int gmi_exec_step_cnt(mi_h *h, int count);
569/* Next line of assembler code. Get inside calls. */
570int gmi_exec_step_instruction(mi_h *h);
571/* Execute until location is reached. If file is NULL then is until next line. */
572int gmi_exec_until(mi_h *h, const char *file, int line);
573int gmi_exec_until_addr(mi_h *h, void *addr);
574/* Return to previous frame inmediatly. */
575mi_frames *gmi_exec_return(mi_h *h);
576/* Just kill the program. Please read the notes in prg_control.c. */
577int gmi_exec_kill(mi_h *h);
578
579/* Target manipulation: */
580/* Connect to a remote gdbserver using the specified methode. */
581int gmi_target_select(mi_h *h, const char *type, const char *params);
582/* Attach to an already running process. */
583mi_frames *gmi_target_attach(mi_h *h, pid_t pid);
584/* Detach from an attached process. */
585int gmi_target_detach(mi_h *h);
586
587/* Miscellaneous commands: */
588/* Exit gdb killing the child is it is running. */
589void gmi_gdb_exit(mi_h *h);
590/* Send the version to the console. */
591int gmi_gdb_version(mi_h *h);
592/* Set a gdb variable. */
593int gmi_gdb_set(mi_h *h, const char *var, const char *val);
594/* Get a gdb variable. */
595char *gmi_gdb_show(mi_h *h, const char *var);
596
597/* Breakpoints manipulation: */
598/* Insert a breakpoint at file:line. */
599mi_bkpt *gmi_break_insert(mi_h *h, const char *file, int line);
600/* Insert a breakpoint, all available options. */
601mi_bkpt *gmi_break_insert_full(mi_h *h, int temporary, int hard_assist,
602 const char *cond, int count, int thread,
603 const char *where);
604mi_bkpt *gmi_break_insert_full_fl(mi_h *h, const char *file, int line,
605 int temporary, int hard_assist,
606 const char *cond, int count, int thread);
607/* Remove a breakpoint. */
608int gmi_break_delete(mi_h *h, int number);
609/* Free the memory used for a breakpoint description. */
610void mi_free_bkpt(mi_bkpt *b);
611/* Modify the "ignore" count for a breakpoint. */
612int gmi_break_set_times(mi_h *h, int number, int count);
613/* Associate a condition with the breakpoint. */
614int gmi_break_set_condition(mi_h *h, int number, const char *condition);
615/* Enable or disable a breakpoint. */
616int gmi_break_state(mi_h *h, int number, int enable);
617/* Set a watchpoint. It doesn't work for remote targets! */
618mi_wp *gmi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp);
619
620/* Data Manipulation. */
621/* Evaluate an expression. Returns a parsed tree. */
622char *gmi_data_evaluate_expression(mi_h *h, const char *expression);
623/* Path for sources. */
624int gmi_dir(mi_h *h, const char *path);
625/* A very limited "data read memory" implementation. */
626int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
627 unsigned char *dest, int *na, int convAddr,
628 unsigned long *addr);
629mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
630 const char *end, int mode);
631mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
632 int lines, int mode);
633mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many);
634int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l);
635mi_chg_reg *gmi_data_list_changed_registers(mi_h *h);
636int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l);
637mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many);
638
639/* Stack manipulation. */
640/* List of frames. Arguments aren't filled. */
641mi_frames *gmi_stack_list_frames(mi_h *h);
642/* List of frames. Indicating a range. */
643mi_frames *gmi_stack_list_frames_r(mi_h *h, int from, int to);
644/* List arguments. Only level and args filled. */
645mi_frames *gmi_stack_list_arguments(mi_h *h, int show);
646/* List arguments. Indicating a range. Only level and args filled. */
647mi_frames *gmi_stack_list_arguments_r(mi_h *h, int show, int from, int to);
648/* Information about the current frame, including args. */
649mi_frames *gmi_stack_info_frame(mi_h *h);
650/* Stack info depth. error => -1 */
651int gmi_stack_info_depth_get(mi_h *h);
652/* Set stack info depth. error => -1 */
653int gmi_stack_info_depth(mi_h *h, int max_depth);
654/* Change current frame. */
655int gmi_stack_select_frame(mi_h *h, int framenum);
656/* List of local vars. */
657mi_results *gmi_stack_list_locals(mi_h *h, int show);
658
659/* Thread. */
660/* List available thread ids. */
661int gmi_thread_list_ids(mi_h *h, int **list);
662/* Select a thread. */
663mi_frames *gmi_thread_select(mi_h *h, int id);
664/* List available threads. */
665mi_frames *gmi_thread_list_all_threads(mi_h *h);
666
667/* Variable objects. */
668/* Create a variable object. */
669mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp);
670mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp);
671/* Create the variable and also fill the lang and attr fields. */
672mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp);
673/* Delete a variable object. Doesn't free the mi_gvar data. */
674int gmi_var_delete(mi_h *h, mi_gvar *var);
675/* Set the format used to represent the result. */
676int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format);
677/* Fill the format field with info from gdb. */
678int gmi_var_show_format(mi_h *h, mi_gvar *var);
679/* Fill the numchild field with info from gdb. */
680int gmi_var_info_num_children(mi_h *h, mi_gvar *var);
681/* Fill the type field with info from gdb. */
682int gmi_var_info_type(mi_h *h, mi_gvar *var);
683/* Fill the expression and lang fields with info from gdb.
684 Note that lang isn't filled during creation. */
685int gmi_var_info_expression(mi_h *h, mi_gvar *var);
686/* Fill the attr field with info from gdb.
687 Note that attr isn't filled during creation. */
688int gmi_var_show_attributes(mi_h *h, mi_gvar *var);
689/* Update variable. Use NULL for all.
690 Note that *changed can be NULL if none updated. */
691int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed);
692/* Change variable. Fills the value field. */
693int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression);
694/* Get current value for a variable. */
695int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var);
696/* List children. It ONLY returns the first level information. :-( */
697int gmi_var_list_children(mi_h *h, mi_gvar *var);
698
699#ifdef __cplusplus
700};
701
702/* C++ interface */
703
704/*
705 State Can:
706 disconnected Connect
707 connected SelectTarget, Disconnect
708 target_specified TargetUnselect, Run, Set breakpoints/watchpoints, etc.
709 running Stop
710 stopped Kill, Restart?, Step, Trace, Continue, etc.
711 [auto exit]
712
713 Modes:
714 dmX11 Local debug for X11.
715 dmLinux Local debug for Linux console.
716 dmRemote Remote debug.
717*/
718class MIDebugger
719{
720public:
721 MIDebugger();
722 ~MIDebugger();
723
724 enum eState { disconnected, connected, target_specified, running, stopped };
725 enum dMode { dmX11, dmLinux, dmRemote, dmPID };
726 enum endianType { enUnknown, enLittle, enBig };
727 // Currently tested architectures
728 enum archType { arUnknown, arIA32, arSPARC, arPIC14, arAVR, arUnsupported };
729
730 int Connect(bool remote=false); /* remote is currently ignored. */
731 int Disconnect();
732 /* SelectTarget* */
733 int SelectTargetX11(const char *exec, const char *args=NULL,
734 const char *auxtty=NULL);
735 int SelectTargetLinux(const char *exec, const char *args,
736 const char *auxtty=NULL);
737 int SelectTargetRemote(const char *exec, const char *rparams,
738 const char *rtype=NULL, bool download=false);
739 // TODO: Linux PIDs can be represented as intergers. What should I use?
740 // ato_pid_t doesn't exist ;-)
741 mi_frames *SelectTargetPID(const char *exec, int pid);
742 int TargetUnselect();
743 int Run();
744 int Stop();
745 int Poll(mi_stop *&rs);
746 int Continue();
747 int RunOrContinue();
748 int Kill();
749 mi_bkpt *Breakpoint(const char *file, int line);
750 mi_bkpt *Breakpoint(const char *where, bool temporary=false, const char *cond=NULL,
751 int count=-1, int thread=-1, bool hard_assist=false);
752 mi_bkpt *BreakpointFull(const char *file, int line, bool temporary=false,
753 const char *cond=NULL, int count=-1, int thread=-1,
754 bool hard_assist=false);
755 mi_bkpt *Breakpoint(mi_bkpt *b);
756 int BreakDelete(mi_bkpt *b);
757 int BreakAfter(mi_bkpt *b)
758 {
759 if (state!=target_specified && state!=stopped)
760 return 0;
761 return gmi_break_set_times(h,b->number,b->ignore);
762 }
763 mi_wp *Watchpoint(enum mi_wp_mode mode, const char *exp);
764 int WatchDelete(mi_wp *w);
765 int RunToMain();
766 int StepOver(bool inst=false);
767 int TraceInto(bool inst=false);
768 int GoTo(const char *file, int line);
769 int GoTo(void *addr);
770 int FinishFun();
771 mi_frames *ReturnNow();
772 mi_frames *CallStack(bool args);
773 char *EvalExpression(const char *exp);
774 char *ModifyExpression(char *exp, char *newVal);
775 mi_gvar *AddgVar(const char *exp, int frame=-1)
776 {
777 if (state!=stopped)
778 return NULL;
779 return gmi_full_var_create(h,frame,exp);
780 }
781 int DelgVar(mi_gvar *var)
782 {
783 if (state!=stopped)
784 return 0;
785 return gmi_var_delete(h,var);
786 }
787 int EvalgVar(mi_gvar *var)
788 {
789 if (state!=stopped)
790 return 0;
791 return gmi_var_evaluate_expression(h,var);
792 }
793 int GetChildgVar(mi_gvar *var)
794 {
795 if (state!=stopped)
796 return 0;
797 return gmi_var_list_children(h,var);
798 }
799 int FillTypeVal(mi_gvar *var);
800 int FillOneTypeVal(mi_gvar *var);
801 int FillAttr(mi_gvar *var)
802 {
803 if (state!=stopped)
804 return 0;
805 return gmi_var_show_attributes(h,var);
806 }
807 int FillFormat(mi_gvar *var)
808 {
809 if (state!=stopped)
810 return 0;
811 return gmi_var_show_format(h,var);
812 }
813 int SetFormatgVar(mi_gvar *var, enum mi_gvar_fmt format)
814 {
815 if (state!=stopped)
816 return 0;
817 return gmi_var_set_format(h,var,format);
818 }
819 int ListChangedgVar(mi_gvar_chg *&changed)
820 {
821 if (state!=stopped)
822 return 0;
823 return gmi_var_update(h,NULL,&changed);
824 }
825 int AssigngVar(mi_gvar *var, const char *exp);
826 int Send(const char *command);
827 int Version()
828 {
829 if (state==running || state==disconnected)
830 return 0;
831 return gmi_gdb_version(h);
832 }
833 int PathSources(const char *path)
834 {
835 if (state==running || state==disconnected)
836 return 0;
837 return gmi_dir(h,path);
838 }
839 int ReadMemory(const char *exp, unsigned size, unsigned char *dest,
840 int &na, int convAddr, unsigned long *addr)
841 {
842 if (state!=stopped)
843 return 0;
844 return gmi_read_memory(h,exp,size,dest,&na,convAddr,addr);
845 }
846 char *Show(const char *var);
847 int ThreadListIDs(int *&list)
848 {
849 if (state!=stopped)
850 return 0;
851 return gmi_thread_list_ids(h,&list);
852 }
853 mi_frames *ThreadList()
854 {
855 if (state!=stopped)
856 return 0;
857 return gmi_thread_list_all_threads(h);
858 }
859 mi_frames *ThreadSelect(int id)
860 {
861 if (state!=stopped)
862 return NULL;
863 return gmi_thread_select(h,id);
864 }
865 mi_asm_insns *Disassemble(const char *start, const char *end, int mode)
866 {
867 if (state!=stopped)
868 return NULL;
869 return gmi_data_disassemble_se(h,start,end,mode);
870 }
871 mi_asm_insns *Disassemble(const char *file, int line, int lines, int mode)
872 {
873 if (state!=stopped)
874 return NULL;
875 return gmi_data_disassemble_fl(h,file,line,lines,mode);
876 }
877 mi_chg_reg *GetRegisterNames(int *how_many)
878 {
879 if (state!=target_specified && state!=stopped)
880 return NULL;
881 return gmi_data_list_register_names(h,how_many);
882 }
883 int GetRegisterNames(mi_chg_reg *chg)
884 {
885 if (state!=target_specified && state!=stopped)
886 return 0;
887 return gmi_data_list_register_names_l(h,chg);
888 }
889 int GetRegisterValues(mi_chg_reg *chg)
890 {
891 if (state!=stopped)
892 return 0;
893 return gmi_data_list_register_values(h,fm_natural,chg);
894 }
895 mi_chg_reg *GetRegisterValues(int *how_many)
896 {
897 if (state!=stopped)
898 return 0;
899 return gmi_data_list_all_register_values(h,fm_natural,how_many);
900 }
901 mi_chg_reg *GetChangedRegisters()
902 {
903 if (state!=stopped)
904 return NULL;
905 mi_chg_reg *chg=gmi_data_list_changed_registers(h);
906 if (chg && !gmi_data_list_register_values(h,fm_natural,chg))
907 {
908 mi_free_chg_reg(chg);
909 chg=NULL;
910 }
911 return chg;
912 }
913 int UpdateRegisters(mi_chg_reg *regs);
914
915 endianType GetTargetEndian();
916 archType GetTargetArchitecture();
917 eState GetState() { return state; }
918
919 /* Some wrappers */
920 static void SetGDBExe(const char *name) { mi_set_gdb_exe(name); }
921 static const char *GetGDBExe() { return mi_get_gdb_exe(); }
922 static void SetXTermExe(const char *name) { mi_set_xterm_exe(name); }
923 static const char *GetXTermExe() { return mi_get_xterm_exe(); }
924 static void SetGDBStartFile(const char *name) { mi_set_gdb_start(name); }
925 static const char *GetGDBStartFile() { return mi_get_gdb_start(); }
926 static void SetGDBConnFile(const char *name) { mi_set_gdb_conn(name); }
927 static const char *GetGDBConnFile() { return mi_get_gdb_conn(); }
928 static void SetMainFunc(const char *name) { mi_set_main_func(name); }
929 static const char *GetMainFunc() { return mi_get_main_func(); }
930
931 static const char *GetErrorStr() { return mi_get_error_str(); }
932 static const char *GetGDBError() { return mi_error_from_gdb; }
933 static int GetErrorNumber() { return mi_error; }
934 int GetErrorNumberSt();
935 void SetConsoleCB(stream_cb cb, void *data=NULL)
936 { mi_set_console_cb(h,cb,data); }
937 void SetTargetCB(stream_cb cb, void *data=NULL)
938 { mi_set_target_cb(h,cb,data); }
939 void SetLogCB(stream_cb cb, void *data=NULL)
940 { mi_set_log_cb(h,cb,data); }
941 void SetAsyncCB(async_cb cb, void *data=NULL)
942 { mi_set_async_cb(h,cb,data); }
943 void SetToGDBCB(stream_cb cb, void *data=NULL)
944 { mi_set_to_gdb_cb(h,cb,data); }
945 void SetFromGDBCB(stream_cb cb, void *data=NULL)
946 { mi_set_from_gdb_cb(h,cb,data); }
947 void SetTimeOutCB(tm_cb cb, void *data)
948 { mi_set_time_out_cb(h,cb,data); }
949 void SetTimeOut(int to)
950 { mi_set_time_out(h,to); }
951 void ForceMIVersion(unsigned vMajor, unsigned vMiddle, unsigned vMinor)
952 { mi_force_version(h,vMajor,vMiddle,vMinor); }
953
954 const char *GetAuxTTY()
955 { return aux_tty ? aux_tty->tty : NULL; }
956
957protected:
958 eState state;
959 dMode mode;
960 endianType targetEndian;
961 archType targetArch;
962 bool preRun; // Remote targets starts running but outside main.
963 mi_h *h;
964 mi_aux_term *aux_tty;
965 int waitingTempBkpt;
966
967 int SelectTargetTTY(const char *exec, const char *args, const char *auxtty,
968 dMode m);
969};
970
971#endif
972
diff --git a/src/monkey/misc.c b/src/monkey/misc.c
new file mode 100644
index 000000000..5440ab0f0
--- /dev/null
+++ b/src/monkey/misc.c
@@ -0,0 +1,118 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Miscellaneous commands.
7 Comments:
8 GDB/MI commands for the "Miscellaneous Commands" section.@p
9
10@<pre>
11gdb command: Implemented?
12
13-gdb-exit Yes
14-gdb-set Yes
15-gdb-show Yes
16-gdb-version Yes
17@</pre>
18
19GDB Bug workaround for "-gdb-show architecture": gdb 6.1 and olders doesn't
20report it in "value", but they give the output of "show architecture". In
216.4 we observed that not even a clue is reported. So now we always use
22"show architecture".
23
24***************************************************************************/
25
26#include <string.h>
27#include "mi_gdb.h"
28
29/* Low level versions. */
30
31void mi_gdb_exit(mi_h *h)
32{
33 mi_send(h,"-gdb-exit\n");
34}
35
36void mi_gdb_version(mi_h *h)
37{
38 mi_send(h,"-gdb-version\n");
39}
40
41void mi_gdb_set(mi_h *h, const char *var, const char *val)
42{
43 mi_send(h,"-gdb-set %s %s\n",var,val);
44}
45
46void mi_gdb_show(mi_h *h, const char *var)
47{
48 if (strcmp(var,"architecture")==0)
49 mi_send(h,"show %s\n",var);
50 else
51 mi_send(h,"-gdb-show %s\n",var);
52}
53
54/* High level versions. */
55
56/**[txh]********************************************************************
57
58 Description:
59 Exit gdb killing the child is it is running.
60
61 Command: -gdb-exit
62
63***************************************************************************/
64
65void gmi_gdb_exit(mi_h *h)
66{
67 mi_gdb_exit(h);
68 mi_res_simple_exit(h);
69}
70
71/**[txh]********************************************************************
72
73 Description:
74 Send the version to the console.
75
76 Command: -gdb-version
77 Return: !=0 OK
78
79***************************************************************************/
80
81int gmi_gdb_version(mi_h *h)
82{
83 mi_gdb_version(h);
84 return mi_res_simple_done(h);
85}
86
87/**[txh]********************************************************************
88
89 Description:
90 Set a gdb variable.
91
92 Command: -gdb-set
93 Return: !=0 OK
94
95***************************************************************************/
96
97int gmi_gdb_set(mi_h *h, const char *var, const char *val)
98{
99 mi_gdb_set(h,var,val);
100 return mi_res_simple_done(h);
101}
102
103/**[txh]********************************************************************
104
105 Description:
106 Get a gdb variable.
107
108 Command: -gdb-show
109 Return: The current value of the variable or NULL on error.
110
111***************************************************************************/
112
113char *gmi_gdb_show(mi_h *h, const char *var)
114{
115 mi_gdb_show(h,var);
116 return mi_res_value(h);
117}
118
diff --git a/src/monkey/monkey.h b/src/monkey/monkey.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/monkey/monkey.h
diff --git a/src/monkey/monkey_api.c b/src/monkey/monkey_api.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/monkey/monkey_api.c
diff --git a/src/monkey/parse.c b/src/monkey/parse.c
new file mode 100644
index 000000000..0dea6cb5d
--- /dev/null
+++ b/src/monkey/parse.c
@@ -0,0 +1,1923 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2007 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Parser.
7 Comments:
8 Parses the output of gdb. It basically converts the text from gdb into a
9tree (could be a complex one) that we can easily interpret using C code.
10
11***************************************************************************/
12
13#include <ctype.h>
14#include <string.h>
15#include <assert.h>
16#include "mi_gdb.h"
17
18mi_results *mi_get_result(const char *str, const char **end);
19int mi_get_value(mi_results *r, const char *str, const char **end);
20
21
22/* GDB BUG!!!! I got:
23^error,msg="Problem parsing arguments: data-evaluate-expression ""1+2"""
24Afects gdb 2002-04-01-cvs and 6.1.1 for sure.
25That's an heuristical workaround.
26*/
27static inline
28int EndOfStr(const char *s)
29{
30 if (*s=='"')
31 {
32 s++;
33 return !*s || *s==',' || *s==']' || *s=='}';
34 }
35 return 0;
36}
37
38int mi_get_cstring_r(mi_results *r, const char *str, const char **end)
39{
40 const char *s;
41 char *d;
42 int len;
43
44 if (*str!='"')
45 {
46 mi_error=MI_PARSER;
47 return 0;
48 }
49 str++;
50 /* Meassure. */
51 for (s=str, len=0; *s && !EndOfStr(s); s++)
52 {
53 if (*s=='\\')
54 {
55 if (!*s)
56 {
57 mi_error=MI_PARSER;
58 return 0;
59 }
60 s++;
61 }
62 len++;
63 }
64 /* Copy. */
65 r->type=t_const;
66 d=r->v.cstr=mi_malloc(len+1);
67 if (!r->v.cstr)
68 return 0;
69 for (s=str; *s && !EndOfStr(s); s++, d++)
70 {
71 if (*s=='\\')
72 {
73 s++;
74 switch (*s)
75 {
76 case 'n':
77 *d='\n';
78 break;
79 case 't':
80 *d='\t';
81 break;
82 default:
83 *d=*s;
84 }
85 }
86 else
87 *d=*s;
88 }
89 *d=0;
90 if (end)
91 *end=s+1;
92
93 return 1;
94}
95
96/* TODO: What's a valid variable name?
97 I'll assume a-zA-Z0-9_- */
98inline
99int mi_is_var_name_char(char c)
100{
101 return isalnum(c) || c=='-' || c=='_';
102}
103
104char *mi_get_var_name(const char *str, const char **end)
105{
106 const char *s;
107 char *r;
108 int l;
109 /* Meassure. */
110 for (s=str; *s && mi_is_var_name_char(*s); s++);
111 if (*s!='=')
112 {
113 mi_error=MI_PARSER;
114 return NULL;
115 }
116 /* Allocate. */
117 l=s-str;
118 r=mi_malloc(l+1);
119 /* Copy. */
120 memcpy(r,str,l);
121 r[l]=0;
122 if (end)
123 *end=s+1;
124 return r;
125}
126
127
128int mi_get_list_res(mi_results *r, const char *str, const char **end, char closeC)
129{
130 mi_results *last_r, *rs;
131
132 last_r=NULL;
133 do
134 {
135 rs=mi_get_result(str,&str);
136 if (last_r)
137 last_r->next=rs;
138 else
139 r->v.rs=rs;
140 last_r=rs;
141 if (*str==closeC)
142 {
143 *end=str+1;
144 return 1;
145 }
146 if (*str!=',')
147 break;
148 str++;
149 }
150 while (1);
151
152 mi_error=MI_PARSER;
153 return 0;
154}
155
156#ifdef __APPLE__
157int mi_get_tuple_val(mi_results *r, const char *str, const char **end)
158{
159 mi_results *last_r, *rs;
160
161 last_r=NULL;
162 do
163 {
164 rs=mi_alloc_results();
165 if (!rs || !mi_get_value(rs,str,&str))
166 {
167 mi_free_results(rs);
168 return 0;
169 }
170 /* Note that rs->var is NULL, that indicates that's just a value and not
171 a result. */
172 if (last_r)
173 last_r->next=rs;
174 else
175 r->v.rs=rs;
176 last_r=rs;
177 if (*str=='}')
178 {
179 *end=str+1;
180 return 1;
181 }
182 if (*str!=',')
183 break;
184 str++;
185 }
186 while (1);
187
188 mi_error=MI_PARSER;
189 return 0;
190}
191#endif /* __APPLE__ */
192
193int mi_get_tuple(mi_results *r, const char *str, const char **end)
194{
195 if (*str!='{')
196 {
197 mi_error=MI_PARSER;
198 return 0;
199 }
200 r->type=t_tuple;
201 str++;
202 if (*str=='}')
203 {/* Special case: empty tuple */
204 *end=str+1;
205 return 1;
206 }
207 #ifdef __APPLE__
208 if (mi_is_var_name_char(*str))
209 return mi_get_list_res(r,str,end,'}');
210 return mi_get_tuple_val(r,str,end);
211 #else /* __APPLE__ */
212 return mi_get_list_res(r,str,end,'}');
213 #endif /* __APPLE__ */
214}
215
216int mi_get_list_val(mi_results *r, const char *str, const char **end)
217{
218 mi_results *last_r, *rs;
219
220 last_r=NULL;
221 do
222 {
223 rs=mi_alloc_results();
224 if (!rs || !mi_get_value(rs,str,&str))
225 {
226 mi_free_results(rs);
227 return 0;
228 }
229 /* Note that rs->var is NULL, that indicates that's just a value and not
230 a result. */
231 if (last_r)
232 last_r->next=rs;
233 else
234 r->v.rs=rs;
235 last_r=rs;
236 if (*str==']')
237 {
238 *end=str+1;
239 return 1;
240 }
241 if (*str!=',')
242 break;
243 str++;
244 }
245 while (1);
246
247 mi_error=MI_PARSER;
248 return 0;
249}
250
251int mi_get_list(mi_results *r, const char *str, const char **end)
252{
253 if (*str!='[')
254 {
255 mi_error=MI_PARSER;
256 return 0;
257 }
258 r->type=t_list;
259 str++;
260 if (*str==']')
261 {/* Special case: empty list */
262 *end=str+1;
263 return 1;
264 }
265 /* Comment: I think they could choose () for values. Is confusing in this way. */
266 if (mi_is_var_name_char(*str))
267 return mi_get_list_res(r,str,end,']');
268 return mi_get_list_val(r,str,end);
269}
270
271int mi_get_value(mi_results *r, const char *str, const char **end)
272{
273 switch (str[0])
274 {
275 case '"':
276 return mi_get_cstring_r(r,str,end);
277 case '{':
278 return mi_get_tuple(r,str,end);
279 case '[':
280 return mi_get_list(r,str,end);
281 }
282 mi_error=MI_PARSER;
283 return 0;
284}
285
286mi_results *mi_get_result(const char *str, const char **end)
287{
288 char *var;
289 mi_results *r;
290
291 var=mi_get_var_name(str,&str);
292 if (!var)
293 return NULL;
294
295 r=mi_alloc_results();
296 if (!r)
297 {
298 free(var);
299 return NULL;
300 }
301 r->var=var;
302
303 if (!mi_get_value(r,str,end))
304 {
305 mi_free_results(r);
306 return NULL;
307 }
308
309 return r;
310}
311
312mi_output *mi_get_results_alone(mi_output *r,const char *str)
313{
314 mi_results *last_r, *rs;
315
316 /* * results */
317 last_r=NULL;
318 do
319 {
320 if (!*str)
321 return r;
322 if (*str!=',')
323 {
324 mi_error=MI_PARSER;
325 break;
326 }
327 str++;
328 rs=mi_get_result(str,&str);
329 if (!rs)
330 break;
331 if (!last_r)
332 r->c=rs;
333 else
334 last_r->next=rs;
335 last_r=rs;
336 }
337 while (1);
338 mi_free_output(r);
339 return NULL;
340}
341
342mi_output *mi_parse_result_record(mi_output *r,const char *str)
343{
344 r->type=MI_T_RESULT_RECORD;
345
346 /* Solve the result-class. */
347 if (strncmp(str,"done",4)==0)
348 {
349 str+=4;
350 r->tclass=MI_CL_DONE;
351 }
352 else if (strncmp(str,"running",7)==0)
353 {
354 str+=7;
355 r->tclass=MI_CL_RUNNING;
356 }
357 else if (strncmp(str,"connected",9)==0)
358 {
359 str+=9;
360 r->tclass=MI_CL_CONNECTED;
361 }
362 else if (strncmp(str,"error",5)==0)
363 {
364 str+=5;
365 r->tclass=MI_CL_ERROR;
366 }
367 else if (strncmp(str,"exit",4)==0)
368 {
369 str+=4;
370 r->tclass=MI_CL_EXIT;
371 }
372 else
373 {
374 mi_error=MI_UNKNOWN_RESULT;
375 return NULL;
376 }
377
378 return mi_get_results_alone(r,str);
379}
380
381mi_output *mi_parse_asyn(mi_output *r,const char *str)
382{
383 r->type=MI_T_OUT_OF_BAND;
384 r->stype=MI_ST_ASYNC;
385 /* async-class. */
386 if (strncmp(str,"stopped",7)==0)
387 {
388 r->tclass=MI_CL_STOPPED;
389 str+=7;
390 return mi_get_results_alone(r,str);
391 }
392 if (strncmp(str,"download",8)==0)
393 {
394 r->tclass=MI_CL_DOWNLOAD;
395 str+=8;
396 return mi_get_results_alone(r,str);
397 }
398 mi_error=MI_UNKNOWN_ASYNC;
399 mi_free_output(r);
400 return NULL;
401}
402
403mi_output *mi_parse_exec_asyn(mi_output *r,const char *str)
404{
405 r->sstype=MI_SST_EXEC;
406 return mi_parse_asyn(r,str);
407}
408
409mi_output *mi_parse_status_asyn(mi_output *r,const char *str)
410{
411 r->sstype=MI_SST_STATUS;
412 return mi_parse_asyn(r,str);
413}
414
415mi_output *mi_parse_notify_asyn(mi_output *r,const char *str)
416{
417 r->sstype=MI_SST_NOTIFY;
418 return mi_parse_asyn(r,str);
419}
420
421mi_output *mi_console(mi_output *r,const char *str)
422{
423 r->type=MI_T_OUT_OF_BAND;
424 r->stype=MI_ST_STREAM;
425 r->c=mi_alloc_results();
426 if (!r->c || !mi_get_cstring_r(r->c,str,NULL))
427 {
428 mi_free_output(r);
429 return NULL;
430 }
431 return r;
432}
433
434mi_output *mi_console_stream(mi_output *r,const char *str)
435{
436 r->sstype=MI_SST_CONSOLE;
437 return mi_console(r,str);
438}
439
440mi_output *mi_target_stream(mi_output *r,const char *str)
441{
442 r->sstype=MI_SST_TARGET;
443 return mi_console(r,str);
444}
445
446mi_output *mi_log_stream(mi_output *r,const char *str)
447{
448 r->sstype=MI_SST_LOG;
449 return mi_console(r,str);
450}
451
452mi_output *mi_parse_gdb_output(const char *str)
453{
454 char type=str[0];
455
456 mi_output *r=mi_alloc_output();
457 if (!r)
458 {
459 mi_error=MI_OUT_OF_MEMORY;
460 return NULL;
461 }
462 str++;
463 switch (type)
464 {
465 case '^':
466 return mi_parse_result_record(r,str);
467 case '*':
468 return mi_parse_exec_asyn(r,str);
469 case '+':
470 return mi_parse_status_asyn(r,str);
471 case '=':
472 return mi_parse_notify_asyn(r,str);
473 case '~':
474 return mi_console_stream(r,str);
475 case '@':
476 return mi_target_stream(r,str);
477 case '&':
478 return mi_log_stream(r,str);
479 }
480 mi_error=MI_PARSER;
481 return NULL;
482}
483
484mi_output *mi_get_rrecord(mi_output *r)
485{
486 if (!r)
487 return NULL;
488 while (r)
489 {
490 if (r->type==MI_T_RESULT_RECORD)
491 return r;
492 r=r->next;
493 }
494 return r;
495}
496
497mi_results *mi_get_var_r(mi_results *r, const char *var)
498{
499 while (r)
500 {
501 if (strcmp(r->var,var)==0)
502 return r;
503 r=r->next;
504 }
505 return NULL;
506}
507
508mi_results *mi_get_var(mi_output *res, const char *var)
509{
510 if (!res)
511 return NULL;
512 return mi_get_var_r(res->c,var);
513}
514
515int mi_get_async_stop_reason(mi_output *r, char **reason)
516{
517 int found_stopped=0;
518
519 *reason=NULL;
520 while (r)
521 {
522 if (r->type==MI_T_RESULT_RECORD && r->tclass==MI_CL_ERROR)
523 {
524 if (r->c->type==t_const)
525 *reason=r->c->v.cstr;
526 return 0;
527 }
528 if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
529 r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
530 {
531 mi_results *p=r->c;
532 found_stopped=1;
533 while (p)
534 {
535 if (strcmp(p->var,"reason")==0)
536 {
537 *reason=p->v.cstr;
538 return 1;
539 }
540 p=p->next;
541 }
542 }
543 r=r->next;
544 }
545 if (*reason==NULL && found_stopped)
546 {
547 *reason=strdup("unknown (temp bkpt?)");
548 return 1;
549 }
550 return 0;
551}
552
553mi_frames *mi_get_async_frame(mi_output *r)
554{
555 while (r)
556 {
557 if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
558 r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
559 {
560 mi_results *p=r->c;
561 while (p)
562 {
563 if (strcmp(p->var,"frame")==0)
564 return mi_parse_frame(p->v.rs);
565 p=p->next;
566 }
567 }
568 r=r->next;
569 }
570 return NULL;
571}
572
573int mi_res_simple(mi_h *h, int tclass, int accert_ret)
574{
575 mi_output *r, *res;
576 int ret=0;
577
578 r=mi_get_response_blk(h);
579 res=mi_get_rrecord(r);
580
581 if (res)
582 ret=res->tclass==tclass;
583 mi_free_output(r);
584
585 return ret;
586}
587
588
589int mi_res_simple_done(mi_h *h)
590{
591 return mi_res_simple(h,MI_CL_DONE,0);
592}
593
594int mi_res_simple_exit(mi_h *h)
595{
596 return mi_res_simple(h,MI_CL_EXIT,1);
597}
598
599int mi_res_simple_running(mi_h *h)
600{
601 return mi_res_simple(h,MI_CL_RUNNING,0);
602}
603
604int mi_res_simple_connected(mi_h *h)
605{
606 return mi_res_simple(h,MI_CL_CONNECTED,0);
607}
608
609mi_results *mi_res_var(mi_h *h, const char *var, int tclass)
610{
611 mi_output *r, *res;
612 mi_results *the_var=NULL;
613
614 r=mi_get_response_blk(h);
615 /* All the code that follows is "NULL" tolerant. */
616 /* Look for the result-record. */
617 res=mi_get_rrecord(r);
618 /* Look for the desired var. */
619 if (res && res->tclass==tclass)
620 the_var=mi_get_var(res,var);
621 /* Release all but the one we want. */
622 mi_free_output_but(r,NULL,the_var);
623 return the_var;
624}
625
626mi_results *mi_res_done_var(mi_h *h, const char *var)
627{
628 return mi_res_var(h,var,MI_CL_DONE);
629}
630
631mi_frames *mi_parse_frame(mi_results *c)
632{
633 mi_frames *res=mi_alloc_frames();
634 char *end;
635
636 if (res)
637 {
638 while (c)
639 {
640 if (c->type==t_const)
641 {
642 if (strcmp(c->var,"level")==0)
643 res->level=atoi(c->v.cstr);
644 else if (strcmp(c->var,"addr")==0)
645 res->addr=(void *)strtoul(c->v.cstr,&end,0);
646 else if (strcmp(c->var,"func")==0)
647 {
648 res->func=c->v.cstr;
649 c->v.cstr=NULL;
650 }
651 else if (strcmp(c->var,"file")==0)
652 {
653 res->file=c->v.cstr;
654 c->v.cstr=NULL;
655 }
656 else if (strcmp(c->var,"from")==0)
657 {
658 res->from=c->v.cstr;
659 c->v.cstr=NULL;
660 }
661 else if (strcmp(c->var,"line")==0)
662 res->line=atoi(c->v.cstr);
663 }
664 else if (c->type==t_list && strcmp(c->var,"args")==0)
665 {
666 res->args=c->v.rs;
667 c->v.rs=NULL;
668 }
669 c=c->next;
670 }
671 }
672 return res;
673}
674
675mi_frames *mi_res_frame(mi_h *h)
676{
677 mi_results *r=mi_res_done_var(h,"frame");
678 mi_frames *f=NULL;
679
680 if (r && r->type==t_tuple)
681 f=mi_parse_frame(r->v.rs);
682 mi_free_results(r);
683 return f;
684}
685
686mi_frames *mi_res_frames_array(mi_h *h, const char *var)
687{
688 mi_results *r=mi_res_done_var(h,var), *c;
689 mi_frames *res=NULL, *nframe, *last=NULL;
690
691 if (!r)
692 return NULL;
693#ifdef __APPLE__
694 if (r->type!=t_list && r->type!=t_tuple)
695#else
696 if (r->type!=t_list)
697#endif
698 {
699 mi_free_results(r);
700 return NULL;
701 }
702 c=r->v.rs;
703 while (c)
704 {
705 if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
706 {
707 nframe=mi_parse_frame(c->v.rs);
708 if (nframe)
709 {
710 if (!last)
711 res=nframe;
712 else
713 last->next=nframe;
714 last=nframe;
715 }
716 }
717 c=c->next;
718 }
719 mi_free_results(r);
720 return res;
721}
722
723mi_frames *mi_res_frames_list(mi_h *h)
724{
725 mi_output *r, *res;
726 mi_frames *ret=NULL, *nframe, *last=NULL;
727 mi_results *c;
728
729 r=mi_get_response_blk(h);
730 res=mi_get_rrecord(r);
731 if (res && res->tclass==MI_CL_DONE)
732 {
733 c=res->c;
734 while (c)
735 {
736 if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
737 {
738 nframe=mi_parse_frame(c->v.rs);
739 if (nframe)
740 {
741 if (!last)
742 ret=nframe;
743 else
744 last->next=nframe;
745 last=nframe;
746 }
747 }
748 c=c->next;
749 }
750 }
751 mi_free_output(r);
752 return ret;
753}
754
755int mi_get_thread_ids(mi_output *res, int **list)
756{
757 mi_results *vids, *lids;
758 int ids=-1, i;
759
760 *list=NULL;
761 vids=mi_get_var(res,"number-of-threads");
762 lids=mi_get_var(res,"thread-ids");
763 if (vids && vids->type==t_const &&
764 lids && lids->type==t_tuple)
765 {
766 ids=atoi(vids->v.cstr);
767 if (ids)
768 {
769 int *lst;
770 lst=(int *)mi_calloc(ids,sizeof(int));
771 if (lst)
772 {
773 lids=lids->v.rs;
774 i=0;
775 while (lids)
776 {
777 if (strcmp(lids->var,"thread-id")==0 && lids->type==t_const)
778 lst[i++]=atoi(lids->v.cstr);
779 lids=lids->next;
780 }
781 *list=lst;
782 }
783 else
784 ids=-1;
785 }
786 }
787 return ids;
788}
789
790int mi_res_thread_ids(mi_h *h, int **list)
791{
792 mi_output *r, *res;
793 int ids=-1;
794
795 r=mi_get_response_blk(h);
796 res=mi_get_rrecord(r);
797 if (res && res->tclass==MI_CL_DONE)
798 ids=mi_get_thread_ids(res,list);
799 mi_free_output(r);
800 return ids;
801}
802
803enum mi_gvar_lang mi_lang_str_to_enum(const char *lang)
804{
805 enum mi_gvar_lang lg=lg_unknown;
806
807 if (strcmp(lang,"C")==0)
808 lg=lg_c;
809 else if (strcmp(lang,"C++")==0)
810 lg=lg_cpp;
811 else if (strcmp(lang,"Java")==0)
812 lg=lg_java;
813
814 return lg;
815}
816
817const char *mi_lang_enum_to_str(enum mi_gvar_lang lang)
818{
819 const char *lg;
820
821 switch (lang)
822 {
823 case lg_c:
824 lg="C";
825 break;
826 case lg_cpp:
827 lg="C++";
828 break;
829 case lg_java:
830 lg="Java";
831 break;
832 /*case lg_unknown:*/
833 default:
834 lg="unknown";
835 break;
836 }
837 return lg;
838}
839
840enum mi_gvar_fmt mi_format_str_to_enum(const char *format)
841{
842 enum mi_gvar_fmt fmt=fm_natural;
843
844 if (strcmp(format,"binary")==0)
845 fmt=fm_binary;
846 else if (strcmp(format,"decimal")==0)
847 fmt=fm_decimal;
848 else if (strcmp(format,"hexadecimal")==0)
849 fmt=fm_hexadecimal;
850 else if (strcmp(format,"octal")==0)
851 fmt=fm_octal;
852
853 return fmt;
854}
855
856const char *mi_format_enum_to_str(enum mi_gvar_fmt format)
857{
858 const char *fmt;
859
860 switch (format)
861 {
862 case fm_natural:
863 fmt="natural";
864 break;
865 case fm_binary:
866 fmt="binary";
867 break;
868 case fm_decimal:
869 fmt="decimal";
870 break;
871 case fm_hexadecimal:
872 fmt="hexadecimal";
873 break;
874 case fm_octal:
875 fmt="octal";
876 break;
877 case fm_raw:
878 fmt="raw";
879 break;
880 default:
881 fmt="unknown";
882 }
883 return fmt;
884}
885
886char mi_format_enum_to_char(enum mi_gvar_fmt format)
887{
888 char fmt;
889
890 switch (format)
891 {
892 case fm_natural:
893 fmt='N';
894 break;
895 case fm_binary:
896 fmt='t';
897 break;
898 case fm_decimal:
899 fmt='d';
900 break;
901 case fm_hexadecimal:
902 fmt='x';
903 break;
904 case fm_octal:
905 fmt='o';
906 break;
907 case fm_raw:
908 fmt='r';
909 break;
910 default:
911 fmt=' ';
912 }
913 return fmt;
914}
915
916mi_gvar *mi_get_gvar(mi_output *o, mi_gvar *cur, const char *expression)
917{
918 mi_results *r;
919 mi_gvar *res=cur ? cur : mi_alloc_gvar();
920 int l;
921
922 if (!res)
923 return res;
924 r=o->c;
925 if (expression)
926 res->exp=strdup(expression);
927 while (r)
928 {
929 if (r->type==t_const)
930 {
931 if (strcmp(r->var,"name")==0)
932 {
933 free(res->name);
934 res->name=r->v.cstr;
935 r->v.cstr=NULL;
936 }
937 else if (strcmp(r->var,"numchild")==0)
938 {
939 res->numchild=atoi(r->v.cstr);
940 }
941 else if (strcmp(r->var,"type")==0)
942 {
943 free(res->type);
944 res->type=r->v.cstr;
945 r->v.cstr=NULL;
946 l=strlen(res->type);
947 if (l && res->type[l-1]=='*')
948 res->ispointer=1;
949 }
950 else if (strcmp(r->var,"lang")==0)
951 {
952 res->lang=mi_lang_str_to_enum(r->v.cstr);
953 }
954 else if (strcmp(r->var,"exp")==0)
955 {
956 free(res->exp);
957 res->exp=r->v.cstr;
958 r->v.cstr=NULL;
959 }
960 else if (strcmp(r->var,"format")==0)
961 {
962 res->format=mi_format_str_to_enum(r->v.cstr);
963 }
964 else if (strcmp(r->var,"attr")==0)
965 { /* Note: gdb 6.1.1 have only this: */
966 if (strcmp(r->v.cstr,"editable")==0)
967 res->attr=MI_ATTR_EDITABLE;
968 else /* noneditable */
969 res->attr=MI_ATTR_NONEDITABLE;
970 }
971 }
972 r=r->next;
973 }
974 return res;
975}
976
977mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression)
978{
979 mi_output *r, *res;
980 mi_gvar *gvar=NULL;
981
982 r=mi_get_response_blk(h);
983 res=mi_get_rrecord(r);
984 if (res && res->tclass==MI_CL_DONE)
985 gvar=mi_get_gvar(res,cur,expression);
986 mi_free_output(r);
987 return gvar;
988}
989
990mi_gvar_chg *mi_get_gvar_chg(mi_results *r)
991{
992 mi_gvar_chg *n;
993
994 if (r->type!=t_const)
995 return NULL;
996 n=mi_alloc_gvar_chg();
997 if (n)
998 {
999 while (r)
1000 {
1001 if (r->type==t_const)
1002 {
1003 if (strcmp(r->var,"name")==0)
1004 {
1005 n->name=r->v.cstr;
1006 r->v.cstr=NULL;
1007 }
1008 else if (strcmp(r->var,"in_scope")==0)
1009 {
1010 n->in_scope=strcmp(r->v.cstr,"true")==0;
1011 }
1012 else if (strcmp(r->var,"new_type")==0)
1013 {
1014 n->new_type=r->v.cstr;
1015 r->v.cstr=NULL;
1016 }
1017 else if (strcmp(r->var,"new_num_children")==0)
1018 {
1019 n->new_num_children=atoi(r->v.cstr);
1020 }
1021 // type_changed="false" is the default
1022 }
1023 r=r->next;
1024 }
1025 }
1026 return n;
1027}
1028
1029int mi_res_changelist(mi_h *h, mi_gvar_chg **changed)
1030{
1031 mi_gvar_chg *last, *n;
1032 mi_results *res=mi_res_done_var(h,"changelist"), *r;
1033 int count=0;
1034
1035 *changed=NULL;
1036 if (!res)
1037 return 0;
1038 last=NULL;
1039 count=1;
1040 n=NULL;
1041 r=res->v.rs;
1042
1043 if (res->type==t_list)
1044 {// MI v2 a list of tuples
1045 while (r)
1046 {
1047 if (r->type==t_tuple)
1048 {
1049 n=mi_get_gvar_chg(r->v.rs);
1050 if (n)
1051 {
1052 if (last)
1053 last->next=n;
1054 else
1055 *changed=n;
1056 last=n;
1057 count++;
1058 }
1059 }
1060 r=r->next;
1061 }
1062 }
1063 else if (res->type==t_tuple)
1064 {// MI v1 a tuple with all together *8-P
1065 while (r)
1066 {
1067 if (r->type==t_const) /* Just in case. */
1068 {/* Get one var. */
1069 if (strcmp(r->var,"name")==0)
1070 {
1071 if (n)
1072 {/* Add to the list*/
1073 if (last)
1074 last->next=n;
1075 else
1076 *changed=n;
1077 last=n;
1078 count++;
1079 }
1080 n=mi_alloc_gvar_chg();
1081 if (!n)
1082 {
1083 mi_free_gvar_chg(*changed);
1084 return 0;
1085 }
1086 n->name=r->v.cstr;
1087 r->v.cstr=NULL;
1088 }
1089 else if (strcmp(r->var,"in_scope")==0)
1090 {
1091 n->in_scope=strcmp(r->v.cstr,"true")==0;
1092 }
1093 else if (strcmp(r->var,"new_type")==0)
1094 {
1095 n->new_type=r->v.cstr;
1096 r->v.cstr=NULL;
1097 }
1098 else if (strcmp(r->var,"new_num_children")==0)
1099 {
1100 n->new_num_children=atoi(r->v.cstr);
1101 }
1102 // type_changed="false" is the default
1103 }
1104 r=r->next;
1105 }
1106 if (n)
1107 {/* Add to the list*/
1108 if (last)
1109 last->next=n;
1110 else
1111 *changed=n;
1112 last=n;
1113 count++;
1114 }
1115 }
1116 mi_free_results(res);
1117
1118 return count;
1119}
1120
1121int mi_get_children(mi_results *ch, mi_gvar *v)
1122{
1123 mi_gvar *cur=NULL, *aux;
1124 int i=0, count=v->numchild, l;
1125
1126 while (ch)
1127 {
1128 if (strcmp(ch->var,"child")==0 && ch->type==t_tuple && i<count)
1129 {
1130 mi_results *r=ch->v.rs;
1131 aux=mi_alloc_gvar();
1132 if (!aux)
1133 return 0;
1134 if (!v->child)
1135 v->child=aux;
1136 else
1137 cur->next=aux;
1138 cur=aux;
1139 cur->parent=v;
1140 cur->depth=v->depth+1;
1141
1142 while (r)
1143 {
1144 if (r->type==t_const)
1145 {
1146 if (strcmp(r->var,"name")==0)
1147 {
1148 cur->name=r->v.cstr;
1149 r->v.cstr=NULL;
1150 }
1151 else if (strcmp(r->var,"exp")==0)
1152 {
1153 cur->exp=r->v.cstr;
1154 r->v.cstr=NULL;
1155 }
1156 else if (strcmp(r->var,"type")==0)
1157 {
1158 cur->type=r->v.cstr;
1159 r->v.cstr=NULL;
1160 l=strlen(cur->type);
1161 if (l && cur->type[l-1]=='*')
1162 cur->ispointer=1;
1163 }
1164 else if (strcmp(r->var,"value")==0)
1165 {
1166 cur->value=r->v.cstr;
1167 r->v.cstr=NULL;
1168 }
1169 else if (strcmp(r->var,"numchild")==0)
1170 {
1171 cur->numchild=atoi(r->v.cstr);
1172 }
1173 }
1174 r=r->next;
1175 }
1176 i++;
1177 }
1178 ch=ch->next;
1179 }
1180 v->vischild=i;
1181 v->opened=1;
1182 return i==v->numchild;
1183}
1184
1185int mi_res_children(mi_h *h, mi_gvar *v)
1186{
1187 mi_output *r, *res;
1188 int ok=0;
1189
1190 r=mi_get_response_blk(h);
1191 res=mi_get_rrecord(r);
1192 if (res && res->tclass==MI_CL_DONE)
1193 {
1194 mi_results *num=mi_get_var(res,"numchild");
1195 if (num && num->type==t_const)
1196 {
1197 v->numchild=atoi(num->v.cstr);
1198 if (v->child)
1199 {
1200 mi_free_gvar(v->child);
1201 v->child=NULL;
1202 }
1203 if (v->numchild)
1204 {
1205 mi_results *ch =mi_get_var(res,"children");
1206 if (ch && ch->type!=t_const) /* MI v1 tuple, MI v2 list */
1207 ok=mi_get_children(ch->v.rs,v);
1208 }
1209 else
1210 ok=1;
1211 }
1212 }
1213 mi_free_output(r);
1214 return ok;
1215}
1216
1217mi_bkpt *mi_get_bkpt(mi_results *p)
1218{
1219 mi_bkpt *res;
1220 char *end;
1221
1222 res=mi_alloc_bkpt();
1223 if (!res)
1224 return NULL;
1225 while (p)
1226 {
1227 if (p->type==t_const && p->var)
1228 {
1229 if (strcmp(p->var,"number")==0)
1230 res->number=atoi(p->v.cstr);
1231 else if (strcmp(p->var,"type")==0)
1232 {
1233 if (strcmp(p->v.cstr,"breakpoint")==0)
1234 res->type=t_breakpoint;
1235 else
1236 res->type=t_unknown;
1237 }
1238 else if (strcmp(p->var,"disp")==0)
1239 {
1240 if (strcmp(p->v.cstr,"keep")==0)
1241 res->disp=d_keep;
1242 else if (strcmp(p->v.cstr,"del")==0)
1243 res->disp=d_del;
1244 else
1245 res->disp=d_unknown;
1246 }
1247 else if (strcmp(p->var,"enabled")==0)
1248 res->enabled=p->v.cstr[0]=='y';
1249 else if (strcmp(p->var,"addr")==0)
1250 res->addr=(void *)strtoul(p->v.cstr,&end,0);
1251 else if (strcmp(p->var,"func")==0)
1252 {
1253 res->func=p->v.cstr;
1254 p->v.cstr=NULL;
1255 }
1256 else if (strcmp(p->var,"file")==0)
1257 {
1258 res->file=p->v.cstr;
1259 p->v.cstr=NULL;
1260 }
1261 else if (strcmp(p->var,"line")==0)
1262 res->line=atoi(p->v.cstr);
1263 else if (strcmp(p->var,"times")==0)
1264 res->times=atoi(p->v.cstr);
1265 else if (strcmp(p->var,"ignore")==0)
1266 res->ignore=atoi(p->v.cstr);
1267 else if (strcmp(p->var,"cond")==0)
1268 {
1269 res->cond=p->v.cstr;
1270 p->v.cstr=NULL;
1271 }
1272 }
1273 p=p->next;
1274 }
1275 return res;
1276}
1277
1278mi_bkpt *mi_res_bkpt(mi_h *h)
1279{
1280 mi_results *r=mi_res_done_var(h,"bkpt");
1281 mi_bkpt *b=NULL;
1282
1283 if (r && r->type==t_tuple)
1284 b=mi_get_bkpt(r->v.rs);
1285 mi_free_results(r);
1286 return b;
1287}
1288
1289mi_wp *mi_get_wp(mi_results *p, enum mi_wp_mode m)
1290{
1291 mi_wp *res=mi_alloc_wp();
1292
1293 if (res)
1294 {
1295 res->mode=m;
1296 while (p)
1297 {
1298 if (p->type==t_const && p->var)
1299 {
1300 if (strcmp(p->var,"number")==0)
1301 {
1302 res->number=atoi(p->v.cstr);
1303 res->enabled=1;
1304 }
1305 else if (strcmp(p->var,"exp")==0)
1306 {
1307 res->exp=p->v.cstr;
1308 p->v.cstr=NULL;
1309 }
1310 }
1311 p=p->next;
1312 }
1313 }
1314 return res;
1315}
1316
1317mi_wp *mi_parse_wp_res(mi_output *r)
1318{
1319 mi_results *p;
1320 enum mi_wp_mode m=wm_unknown;
1321
1322 /* The info is in a result wpt=... */
1323 p=r->c;
1324 while (p)
1325 {
1326 if (p->var)
1327 {
1328 if (strcmp(p->var,"wpt")==0)
1329 m=wm_write;
1330 else if (strcmp(p->var,"hw-rwpt")==0)
1331 m=wm_read;
1332 else if (strcmp(p->var,"hw-awpt")==0)
1333 m=wm_rw;
1334 if (m!=wm_unknown)
1335 break;
1336 }
1337 p=p->next;
1338 }
1339 if (!p || p->type!=t_tuple)
1340 return NULL;
1341 /* Scan the values inside it. */
1342 return mi_get_wp(p->v.rs,m);
1343}
1344
1345mi_wp *mi_res_wp(mi_h *h)
1346{
1347 mi_output *r, *res;
1348 mi_wp *ret=NULL;
1349
1350 r=mi_get_response_blk(h);
1351 res=mi_get_rrecord(r);
1352
1353 if (res)
1354 ret=mi_parse_wp_res(res);
1355
1356 mi_free_output(r);
1357 return ret;
1358}
1359
1360char *mi_res_value(mi_h *h)
1361{
1362 mi_results *r=mi_res_done_var(h,"value");
1363 char *s=NULL;
1364
1365 if (r && r->type==t_const)
1366 {
1367 s=r->v.cstr;
1368 r->v.rs=NULL;
1369 }
1370 mi_free_results(r);
1371 return s;
1372}
1373
1374mi_output *mi_get_stop_record(mi_output *r)
1375{
1376 while (r)
1377 {
1378 if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
1379 r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
1380 return r;
1381 r=r->next;
1382 }
1383 return r;
1384}
1385
1386static
1387char *reason_names[]=
1388{
1389 "breakpoint-hit",
1390 "watchpoint-trigger",
1391 "read-watchpoint-trigger",
1392 "access-watchpoint-trigger",
1393 "watchpoint-scope",
1394 "function-finished",
1395 "location-reached",
1396 "end-stepping-range",
1397 "exited-signalled",
1398 "exited",
1399 "exited-normally",
1400 "signal-received"
1401};
1402
1403static
1404enum mi_stop_reason reason_values[]=
1405{
1406 sr_bkpt_hit,
1407 sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
1408 sr_function_finished, sr_location_reached, sr_end_stepping_range,
1409 sr_exited_signalled, sr_exited, sr_exited_normally,
1410 sr_signal_received
1411};
1412
1413static
1414char *reason_expl[]=
1415{
1416 "Hit a breakpoint",
1417 "Write watchpoint",
1418 "Read watchpoint",
1419 "Access watchpoint",
1420 "Watchpoint out of scope",
1421 "Function finished",
1422 "Location reached",
1423 "End of stepping",
1424 "Exited signalled",
1425 "Exited with error",
1426 "Exited normally",
1427 "Signal received"
1428};
1429
1430enum mi_stop_reason mi_reason_str_to_enum(const char *s)
1431{
1432 int i;
1433
1434 for (i=0; i<sizeof(reason_names)/sizeof(char *); i++)
1435 if (strcmp(reason_names[i],s)==0)
1436 return reason_values[i];
1437 return sr_unknown;
1438}
1439
1440const char *mi_reason_enum_to_str(enum mi_stop_reason r)
1441{
1442 int i;
1443
1444 if (r==sr_unknown)
1445 return "Unknown (temp bkp?)";
1446 for (i=0; i<sizeof(reason_values)/sizeof(char *); i++)
1447 if (reason_values[i]==r)
1448 return reason_expl[i];
1449 return NULL;
1450}
1451
1452mi_stop *mi_get_stopped(mi_results *r)
1453{
1454 mi_stop *res=mi_alloc_stop();
1455
1456 if (res)
1457 {
1458 while (r)
1459 {
1460 if (r->type==t_const)
1461 {
1462 if (strcmp(r->var,"reason")==0)
1463 res->reason=mi_reason_str_to_enum(r->v.cstr);
1464 else if (!res->have_thread_id && strcmp(r->var,"thread-id")==0)
1465 {
1466 res->have_thread_id=1;
1467 res->thread_id=atoi(r->v.cstr);
1468 }
1469 else if (!res->have_bkptno && strcmp(r->var,"bkptno")==0)
1470 {
1471 res->have_bkptno=1;
1472 res->bkptno=atoi(r->v.cstr);
1473 }
1474 else if (!res->have_bkptno && strcmp(r->var,"wpnum")==0)
1475 {
1476 res->have_wpno=1;
1477 res->wpno=atoi(r->v.cstr);
1478 }
1479 else if (strcmp(r->var,"gdb-result-var")==0)
1480 {
1481 res->gdb_result_var=r->v.cstr;
1482 r->v.cstr=NULL;
1483 }
1484 else if (strcmp(r->var,"return-value")==0)
1485 {
1486 res->return_value=r->v.cstr;
1487 r->v.cstr=NULL;
1488 }
1489 else if (strcmp(r->var,"signal-name")==0)
1490 {
1491 res->signal_name=r->v.cstr;
1492 r->v.cstr=NULL;
1493 }
1494 else if (strcmp(r->var,"signal-meaning")==0)
1495 {
1496 res->signal_meaning=r->v.cstr;
1497 r->v.cstr=NULL;
1498 }
1499 else if (!res->have_exit_code && strcmp(r->var,"exit-code")==0)
1500 {
1501 res->have_exit_code=1;
1502 res->exit_code=atoi(r->v.cstr);
1503 }
1504 }
1505 else // tuple or list
1506 {
1507 if (strcmp(r->var,"frame")==0)
1508 res->frame=mi_parse_frame(r->v.rs);
1509 else if (!res->wp && strcmp(r->var,"wpt")==0)
1510 res->wp=mi_get_wp(r->v.rs,wm_write);
1511 else if (!res->wp && strcmp(r->var,"hw-rwpt")==0)
1512 res->wp=mi_get_wp(r->v.rs,wm_read);
1513 else if (!res->wp && strcmp(r->var,"hw-awpt")==0)
1514 res->wp=mi_get_wp(r->v.rs,wm_rw);
1515 else if (!(res->wp_old || res->wp_val) && strcmp(r->var,"value")==0)
1516 {
1517 mi_results *p=r->v.rs;
1518 while (p)
1519 {
1520 if (strcmp(p->var,"value")==0 || strcmp(p->var,"new")==0)
1521 {
1522 res->wp_val=p->v.cstr;
1523 p->v.cstr=NULL;
1524 }
1525 else if (strcmp(p->var,"old")==0)
1526 {
1527 res->wp_old=p->v.cstr;
1528 p->v.cstr=NULL;
1529 }
1530 p=p->next;
1531 }
1532 }
1533 }
1534 r=r->next;
1535 }
1536 }
1537 return res;
1538}
1539
1540mi_stop *mi_res_stop(mi_h *h)
1541{
1542 mi_output *o=mi_retire_response(h);
1543 mi_stop *stop=NULL;
1544
1545 if (o)
1546 {
1547 mi_output *sr=mi_get_stop_record(o);
1548 if (sr)
1549 stop=mi_get_stopped(sr->c);
1550 }
1551 mi_free_output(o);
1552
1553 return stop;
1554}
1555
1556int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
1557 unsigned long *addr)
1558{
1559 char *end;
1560 mi_results *res=mi_res_done_var(h,"memory"), *r;
1561 int ok=0;
1562
1563 *na=0;
1564 r=res;
1565 if (r && r->type==t_list && ws==1)
1566 {
1567 r=r->v.rs;
1568 if (r->type!=t_tuple)
1569 {
1570 mi_free_results(res);
1571 return 0;
1572 }
1573 r=r->v.rs;
1574 while (r)
1575 {
1576 if (r->type==t_list && strcmp(r->var,"data")==0)
1577 {
1578 mi_results *data=r->v.rs;
1579 ok++;
1580 if (data && data->type==t_const &&
1581 strcmp(data->v.cstr,"N/A")==0)
1582 *na=1;
1583 else
1584 while (data)
1585 {
1586 if (data->type==t_const)
1587 *(dest++)=strtol(data->v.cstr,&end,0);
1588 data=data->next;
1589 }
1590 }
1591 else if (r->type==t_const && strcmp(r->var,"addr")==0)
1592 {
1593 ok++;
1594 if (addr)
1595 *addr=strtoul(r->v.cstr,&end,0);
1596 }
1597 r=r->next;
1598 }
1599
1600 }
1601 mi_free_results(res);
1602 return ok==2;
1603}
1604
1605mi_asm_insn *mi_parse_insn(mi_results *c)
1606{
1607 mi_asm_insn *res=NULL, *cur=NULL;
1608 mi_results *sub;
1609 char *end;
1610
1611 while (c)
1612 {
1613 if (c->type==t_tuple)
1614 {
1615 if (!res)
1616 res=cur=mi_alloc_asm_insn();
1617 else
1618 {
1619 cur->next=mi_alloc_asm_insn();
1620 cur=cur->next;
1621 }
1622 if (!cur)
1623 {
1624 mi_free_asm_insn(res);
1625 return NULL;
1626 }
1627 sub=c->v.rs;
1628 while (sub)
1629 {
1630 if (sub->type==t_const)
1631 {
1632 if (strcmp(sub->var,"address")==0)
1633 cur->addr=(void *)strtoul(sub->v.cstr,&end,0);
1634 else if (strcmp(sub->var,"func-name")==0)
1635 {
1636 cur->func=sub->v.cstr;
1637 sub->v.cstr=NULL;
1638 }
1639 else if (strcmp(sub->var,"offset")==0)
1640 cur->offset=atoi(sub->v.cstr);
1641 else if (strcmp(sub->var,"inst")==0)
1642 {
1643 cur->inst=sub->v.cstr;
1644 sub->v.cstr=NULL;
1645 }
1646 }
1647 sub=sub->next;
1648 }
1649 }
1650 c=c->next;
1651 }
1652 return res;
1653}
1654
1655mi_asm_insns *mi_parse_insns(mi_results *c)
1656{
1657 mi_asm_insns *res=NULL, *cur=NULL;
1658 mi_results *sub;
1659
1660 while (c)
1661 {
1662 if (c->var)
1663 {
1664 if (strcmp(c->var,"src_and_asm_line")==0 && c->type==t_tuple)
1665 {
1666 if (!res)
1667 res=cur=mi_alloc_asm_insns();
1668 else
1669 {
1670 cur->next=mi_alloc_asm_insns();
1671 cur=cur->next;
1672 }
1673 if (!cur)
1674 {
1675 mi_free_asm_insns(res);
1676 return NULL;
1677 }
1678 sub=c->v.rs;
1679 while (sub)
1680 {
1681 if (sub->var)
1682 {
1683 if (sub->type==t_const)
1684 {
1685 if (strcmp(sub->var,"line")==0)
1686 cur->line=atoi(sub->v.cstr);
1687 else if (strcmp(sub->var,"file")==0)
1688 {
1689 cur->file=sub->v.cstr;
1690 sub->v.cstr=NULL;
1691 }
1692 }
1693 else if (sub->type==t_list)
1694 {
1695 if (strcmp(sub->var,"line_asm_insn")==0)
1696 cur->ins=mi_parse_insn(sub->v.rs);
1697 }
1698 }
1699 sub=sub->next;
1700 }
1701 }
1702 }
1703 else
1704 {/* No source line, just instructions */
1705 res=mi_alloc_asm_insns();
1706 res->ins=mi_parse_insn(c);
1707 break;
1708 }
1709 c=c->next;
1710 }
1711 return res;
1712}
1713
1714
1715mi_asm_insns *mi_get_asm_insns(mi_h *h)
1716{
1717 mi_results *r=mi_res_done_var(h,"asm_insns");
1718 mi_asm_insns *f=NULL;
1719
1720 if (r && r->type==t_list)
1721 f=mi_parse_insns(r->v.rs);
1722 mi_free_results(r);
1723 return f;
1724}
1725
1726mi_chg_reg *mi_parse_list_regs(mi_results *r, int *how_many)
1727{
1728 mi_results *c=r;
1729 int cregs=0;
1730 mi_chg_reg *first=NULL, *cur=NULL;
1731
1732 /* Create the list. */
1733 while (c)
1734 {
1735 if (c->type==t_const && !c->var)
1736 {
1737 if (first)
1738 cur=cur->next=mi_alloc_chg_reg();
1739 else
1740 first=cur=mi_alloc_chg_reg();
1741 cur->name=c->v.cstr;
1742 cur->reg=cregs++;
1743 c->v.cstr=NULL;
1744 }
1745 c=c->next;
1746 }
1747 if (how_many)
1748 *how_many=cregs;
1749
1750 return first;
1751}
1752
1753mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many)
1754{
1755 mi_results *r=mi_res_done_var(h,"register-names");
1756 mi_chg_reg *l=NULL;
1757
1758 if (r && r->type==t_list)
1759 l=mi_parse_list_regs(r->v.rs,how_many);
1760 mi_free_results(r);
1761 return l;
1762}
1763
1764mi_chg_reg *mi_parse_list_changed_regs(mi_results *r)
1765{
1766 mi_results *c=r;
1767 mi_chg_reg *first=NULL, *cur=NULL;
1768
1769 /* Create the list. */
1770 while (c)
1771 {
1772 if (c->type==t_const && !c->var)
1773 {
1774 if (first)
1775 cur=cur->next=mi_alloc_chg_reg();
1776 else
1777 first=cur=mi_alloc_chg_reg();
1778 cur->reg=atoi(c->v.cstr);
1779 }
1780 c=c->next;
1781 }
1782
1783 return first;
1784}
1785
1786mi_chg_reg *mi_get_list_changed_regs(mi_h *h)
1787{
1788 mi_results *r=mi_res_done_var(h,"changed-registers");
1789 mi_chg_reg *changed=NULL;
1790
1791 if (r && r->type==t_list)
1792 changed=mi_parse_list_changed_regs(r->v.rs);
1793 mi_free_results(r);
1794 return changed;
1795}
1796
1797int mi_parse_reg_values(mi_results *r, mi_chg_reg *l)
1798{
1799 mi_results *c;
1800
1801 while (r && l)
1802 {
1803 if (r->type==t_tuple && !r->var)
1804 {
1805 c=r->v.rs;
1806 while (c)
1807 {
1808 if (c->type==t_const && c->var)
1809 {
1810 if (strcmp(c->var,"number")==0)
1811 {
1812 if (atoi(c->v.cstr)!=l->reg)
1813 {
1814 mi_error=MI_PARSER;
1815 return 0;
1816 }
1817 }
1818 else if (strcmp(c->var,"value")==0)
1819 {
1820 l->val=c->v.cstr;
1821 c->v.cstr=NULL;
1822 }
1823 }
1824 c=c->next;
1825 }
1826 }
1827 r=r->next;
1828 l=l->next;
1829 }
1830
1831 return !l && !r;
1832}
1833
1834int mi_get_reg_values(mi_h *h, mi_chg_reg *l)
1835{
1836 mi_results *r=mi_res_done_var(h,"register-values");
1837 int ok=0;
1838
1839 if (r && r->type==t_list)
1840 ok=mi_parse_reg_values(r->v.rs,l);
1841 mi_free_results(r);
1842 return ok;
1843}
1844
1845int mi_parse_list_regs_l(mi_results *r, mi_chg_reg *l)
1846{
1847 while (r && l)
1848 {
1849 if (r->type==t_const && !r->var)
1850 {
1851 free(l->name);
1852 l->name=r->v.cstr;
1853 r->v.cstr=NULL;
1854 l=l->next;
1855 }
1856 r=r->next;
1857 }
1858
1859 return !l && !r;
1860}
1861
1862int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l)
1863{
1864 mi_results *r=mi_res_done_var(h,"register-names");
1865 int ok=0;
1866
1867 if (r && r->type==t_list)
1868 ok=mi_parse_list_regs_l(r->v.rs,l);
1869 mi_free_results(r);
1870 return ok;
1871}
1872
1873mi_chg_reg *mi_parse_reg_values_l(mi_results *r, int *how_many)
1874{
1875 mi_results *c;
1876 mi_chg_reg *first=NULL, *cur=NULL;
1877 *how_many=0;
1878
1879 while (r)
1880 {
1881 if (r->type==t_tuple && !r->var)
1882 {
1883 c=r->v.rs;
1884 if (first)
1885 cur=cur->next=mi_alloc_chg_reg();
1886 else
1887 first=cur=mi_alloc_chg_reg();
1888 while (c)
1889 {
1890 if (c->type==t_const && c->var)
1891 {
1892 if (strcmp(c->var,"number")==0)
1893 {
1894 cur->reg=atoi(c->v.cstr);
1895 (*how_many)++;
1896 }
1897 else if (strcmp(c->var,"value")==0)
1898 {
1899 cur->val=c->v.cstr;
1900 c->v.cstr=NULL;
1901 }
1902 }
1903 c=c->next;
1904 }
1905 }
1906 r=r->next;
1907 }
1908
1909 return first;
1910}
1911
1912mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many)
1913{
1914 mi_results *r=mi_res_done_var(h,"register-values");
1915 mi_chg_reg *rgs=NULL;
1916
1917 if (r && r->type==t_list)
1918 rgs=mi_parse_reg_values_l(r->v.rs,how_many);
1919 mi_free_results(r);
1920 return rgs;
1921}
1922
1923
diff --git a/src/monkey/prg_control.c b/src/monkey/prg_control.c
new file mode 100644
index 000000000..671725f94
--- /dev/null
+++ b/src/monkey/prg_control.c
@@ -0,0 +1,454 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Program control.
7 Comments:
8 GDB/MI commands for the "Program Control" section.@p
9
10@<pre>
11gdb command: Implemented?
12
13-exec-abort N.A. (*) (kill, but with non-interactive options)
14-exec-arguments Yes
15-exec-continue Yes ASYNC
16-exec-finish Yes ASYNC
17-exec-interrupt Yes ASYNC
18-exec-next Yes ASYNC
19-exec-next-instruction Yes ASYNC
20-exec-return Yes
21-exec-run Yes ASYNC
22-exec-show-arguments N.A. (show args) see gmi_stack_info_frame
23-exec-step Yes ASYNC
24-exec-step-instruction Yes ASYNC
25-exec-until Yes ASYNC
26-file-exec-and-symbols Yes
27-file-exec-file No
28-file-list-exec-sections N.A. (info file)
29-file-list-exec-source-files N.A.
30-file-list-shared-libraries N.A.
31-file-list-symbol-files N.A.
32-file-symbol-file Yes
33@</pre>
34
35(*) gmi_exec_kill implements it, but you should ensure that
36gmi_gdb_set("confirm","off") was called.@p
37
38GDB Bug workaround for -file-exec-and-symbols and -file-symbol-file: This
39is complex, but a real bug. When you set a breakpoint you never know the
40name of the file as it appears in the debug info. So you can be specifying
41an absolute file name or a relative file name. The reference point could be
42different than the one used in the debug info. To solve all the combinations
43gdb does a search trying various combinations. GDB isn't very smart so you
44must at least specify the working directory and the directory where the
45binary is located to get a good chance (+ user options to solve the rest).
46Once you did it gdb can find the file by doing transformations to the
47"canonical" filename. This search works OK for already loaded symtabs
48(symbol tables), but it have a bug when the search is done for psymtabs
49(partial symtabs). The bug is in the use of source_full_path_of (source.c).
50This function calls openp indicating try_cwd_first. It makes the search file
51if the psymtab file name have at least one dirseparator. It means that
52psymtabs for files compiled with relative paths will fail. The search for
53symtabs uses symtab_to_filename, it calls open_source_file which finally
54calls openp without try_cwd_first.@*
55To workaround this bug we must ensure gdb loads *all* the symtabs to memory.
56And here comes another problem -file-exec-and-symbols doesn't support it
57according to docs. In real life that's a wrapper for "file", but as nobody
58can say it won't change we must use the CLI command.
59
60***************************************************************************/
61
62#include <signal.h>
63#include "mi_gdb.h"
64
65/* Low level versions. */
66
67void mi_file_exec_and_symbols(mi_h *h, const char *file)
68{
69 if (mi_get_workaround(MI_PSYM_SEARCH))
70 mi_send(h,"file %s -readnow\n",file);
71 else
72 mi_send(h,"-file-exec-and-symbols %s\n",file);
73}
74
75void mi_exec_arguments(mi_h *h, const char *args)
76{
77 mi_send(h,"-exec-arguments %s\n",args);
78}
79
80void mi_exec_run(mi_h *h)
81{
82 mi_send(h,"-exec-run\n");
83}
84
85void mi_exec_continue(mi_h *h)
86{
87 mi_send(h,"-exec-continue\n");
88}
89
90void mi_target_terminal(mi_h *h, const char *tty_name)
91{
92 mi_send(h,"tty %s\n",tty_name);
93}
94
95void mi_file_symbol_file(mi_h *h, const char *file)
96{
97 if (mi_get_workaround(MI_PSYM_SEARCH))
98 mi_send(h,"symbol-file %s -readnow\n",file);
99 else
100 mi_send(h,"-file-symbol-file %s\n",file);
101}
102
103void mi_exec_finish(mi_h *h)
104{
105 mi_send(h,"-exec-finish\n");
106}
107
108void mi_exec_interrupt(mi_h *h)
109{
110 mi_send(h,"-exec-interrupt\n");
111}
112
113void mi_exec_next(mi_h *h, int count)
114{
115 if (count>1)
116 mi_send(h,"-exec-next %d\n",count);
117 else
118 mi_send(h,"-exec-next\n");
119}
120
121void mi_exec_next_instruction(mi_h *h)
122{
123 mi_send(h,"-exec-next-instruction\n");
124}
125
126void mi_exec_step(mi_h *h, int count)
127{
128 if (count>1)
129 mi_send(h,"-exec-step %d\n",count);
130 else
131 mi_send(h,"-exec-step\n");
132}
133
134void mi_exec_step_instruction(mi_h *h)
135{
136 mi_send(h,"-exec-step-instruction\n");
137}
138
139void mi_exec_until(mi_h *h, const char *file, int line)
140{
141 if (!file)
142 mi_send(h,"-exec-until\n");
143 else
144 mi_send(h,"-exec-until %s:%d\n",file,line);
145}
146
147void mi_exec_until_addr(mi_h *h, void *addr)
148{
149 mi_send(h,"-exec-until *%p\n",addr);
150}
151
152void mi_exec_return(mi_h *h)
153{
154 mi_send(h,"-exec-return\n");
155}
156
157void mi_exec_kill(mi_h *h)
158{
159 mi_send(h,"kill\n");
160}
161
162/* High level versions. */
163
164/**[txh]********************************************************************
165
166 Description:
167 Specify the executable and arguments for local debug.
168
169 Command: -file-exec-and-symbols + -exec-arguments
170 Return: !=0 OK
171
172***************************************************************************/
173
174int gmi_set_exec(mi_h *h, const char *file, const char *args)
175{
176 mi_file_exec_and_symbols(h,file);
177 if (!mi_res_simple_done(h))
178 return 0;
179 if (!args)
180 return 1;
181 mi_exec_arguments(h,args);
182 return mi_res_simple_done(h);
183}
184
185/**[txh]********************************************************************
186
187 Description:
188 Start running the executable. Remote sessions starts running.
189
190 Command: -exec-run
191 Return: !=0 OK
192
193***************************************************************************/
194
195int gmi_exec_run(mi_h *h)
196{
197 mi_exec_run(h);
198 return mi_res_simple_running(h);
199}
200
201/**[txh]********************************************************************
202
203 Description:
204 Continue the execution after a "stop".
205
206 Command: -exec-continue
207 Return: !=0 OK
208
209***************************************************************************/
210
211int gmi_exec_continue(mi_h *h)
212{
213 mi_exec_continue(h);
214 return mi_res_simple_running(h);
215}
216
217/**[txh]********************************************************************
218
219 Description:
220 Indicate which terminal will use the target program. For local sessions.
221
222 Command: tty
223 Return: !=0 OK
224 Example:
225
226***************************************************************************/
227
228int gmi_target_terminal(mi_h *h, const char *tty_name)
229{
230 mi_target_terminal(h,tty_name);
231 return mi_res_simple_done(h);
232}
233
234/**[txh]********************************************************************
235
236 Description:
237 Specify what's the local copy that have debug info. For remote sessions.
238
239 Command: -file-symbol-file
240 Return: !=0 OK
241
242***************************************************************************/
243
244int gmi_file_symbol_file(mi_h *h, const char *file)
245{
246 mi_file_symbol_file(h,file);
247 return mi_res_simple_done(h);
248}
249
250/**[txh]********************************************************************
251
252 Description:
253 Continue until function return, the return value is included in the async
254response.
255
256 Command: -exec-finish
257 Return: !=0 OK.
258
259***************************************************************************/
260
261int gmi_exec_finish(mi_h *h)
262{
263 mi_exec_finish(h);
264 return mi_res_simple_running(h);
265}
266
267/**[txh]********************************************************************
268
269 Description:
270 Stop the program using SIGINT. The corresponding command should be
271-exec-interrupt but not even gdb 6.1.1 can do it because the "async" mode
272isn't really working.
273
274 Command: -exec-interrupt [replacement]
275 Return: Always 1
276 Example:
277
278***************************************************************************/
279
280int gmi_exec_interrupt(mi_h *h)
281{
282 // **** IMPORTANT!!! **** Not even gdb 6.1.1 can do it because the "async"
283 // mode isn't really working.
284 //mi_exec_interrupt(h);
285 //return mi_res_simple_running(h);
286
287 kill(h->pid,SIGINT);
288 return 1; // How can I know?
289}
290
291/**[txh]********************************************************************
292
293 Description:
294 Next line of code.
295
296 Command: -exec-next
297 Return: !=0 OK
298
299***************************************************************************/
300
301int gmi_exec_next(mi_h *h)
302{
303 mi_exec_next(h,1);
304 return mi_res_simple_running(h);
305}
306
307/**[txh]********************************************************************
308
309 Description:
310 Skip count lines of code.
311
312 Command: -exec-next count
313 Return: !=0 OK
314
315***************************************************************************/
316
317int gmi_exec_next_cnt(mi_h *h, int count)
318{
319 mi_exec_next(h,count);
320 return mi_res_simple_running(h);
321}
322
323/**[txh]********************************************************************
324
325 Description:
326 Next line of assembler code.
327
328 Command: -exec-next-instruction
329 Return: !=0 OK
330
331***************************************************************************/
332
333int gmi_exec_next_instruction(mi_h *h)
334{
335 mi_exec_next_instruction(h);
336 return mi_res_simple_running(h);
337}
338
339/**[txh]********************************************************************
340
341 Description:
342 Next line of code. Get inside functions.
343
344 Command: -exec-step
345 Return: !=0 OK
346
347***************************************************************************/
348
349int gmi_exec_step(mi_h *h)
350{
351 mi_exec_step(h,1);
352 return mi_res_simple_running(h);
353}
354
355/**[txh]********************************************************************
356
357 Description:
358 Next count lines of code. Get inside functions.
359
360 Command: -exec-step count
361 Return: !=0 OK
362
363***************************************************************************/
364
365int gmi_exec_step_cnt(mi_h *h, int count)
366{
367 mi_exec_step(h,count);
368 return mi_res_simple_running(h);
369}
370
371/**[txh]********************************************************************
372
373 Description:
374 Next line of assembler code. Get inside calls.
375
376 Command: -exec-step-instruction
377 Return: !=0 OK
378
379***************************************************************************/
380
381int gmi_exec_step_instruction(mi_h *h)
382{
383 mi_exec_step_instruction(h);
384 return mi_res_simple_running(h);
385}
386
387/**[txh]********************************************************************
388
389 Description:
390 Execute until location is reached. If file is NULL then is until next
391line.
392
393 Command: -exec-until
394 Return: !=0 OK
395
396***************************************************************************/
397
398int gmi_exec_until(mi_h *h, const char *file, int line)
399{
400 mi_exec_until(h,file,line);
401 return mi_res_simple_running(h);
402}
403
404/**[txh]********************************************************************
405
406 Description:
407 Execute until location is reached.
408
409 Command: -exec-until (using *address)
410 Return: !=0 OK
411
412***************************************************************************/
413
414int gmi_exec_until_addr(mi_h *h, void *addr)
415{
416 mi_exec_until_addr(h,addr);
417 return mi_res_simple_running(h);
418}
419
420/**[txh]********************************************************************
421
422 Description:
423 Return to previous frame inmediatly.
424
425 Command: -exec-return
426 Return: A pointer to a new mi_frames structure indicating the current
427location. NULL on error.
428
429***************************************************************************/
430
431mi_frames *gmi_exec_return(mi_h *h)
432{
433 mi_exec_return(h);
434 return mi_res_frame(h);
435}
436
437/**[txh]********************************************************************
438
439 Description:
440 Just kill the program. That's what -exec-abort should do, but it isn't
441implemented by gdb. This implementation only works if the interactive mode
442is disabled (gmi_gdb_set("confirm","off")).
443
444 Command: -exec-abort [using kill]
445 Return: !=0 OK
446
447***************************************************************************/
448
449int gmi_exec_kill(mi_h *h)
450{
451 mi_exec_kill(h);
452 return mi_res_simple_done(h);
453}
454
diff --git a/src/monkey/stack_man.c b/src/monkey/stack_man.c
new file mode 100644
index 000000000..8e8ed0691
--- /dev/null
+++ b/src/monkey/stack_man.c
@@ -0,0 +1,222 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Stack manipulation.
7 Comments:
8 GDB/MI commands for the "Stack Manipulation" section.@p
9
10@<pre>
11gdb command: Implemented?
12
13-stack-info-frame Yes, implemented as "frame"
14-stack-info-depth Yes
15-stack-list-arguments Yes
16-stack-list-frames Yes
17-stack-list-locals Yes
18-stack-select-frame Yes
19@</pre>
20
21***************************************************************************/
22
23#include "mi_gdb.h"
24
25/* Low level versions. */
26
27void mi_stack_list_frames(mi_h *h, int from, int to)
28{
29 if (from<0)
30 mi_send(h,"-stack-list-frames\n");
31 else
32 mi_send(h,"-stack-list-frames %d %d\n",from,to);
33}
34
35void mi_stack_list_arguments(mi_h *h, int show, int from, int to)
36{
37 if (from<0)
38 mi_send(h,"-stack-list-arguments %d\n",show);
39 else
40 mi_send(h,"-stack-list-arguments %d %d %d\n",show,from,to);
41}
42
43void mi_stack_info_frame(mi_h *h)
44{
45 mi_send(h,"frame\n");
46}
47
48void mi_stack_info_depth(mi_h *h, int depth)
49{
50 if (depth<0)
51 mi_send(h,"-stack-info-depth\n");
52 else
53 mi_send(h,"-stack-info-depth %d\n",depth);
54}
55
56void mi_stack_select_frame(mi_h *h, int framenum)
57{
58 mi_send(h,"-stack-select-frame %d\n",framenum);
59}
60
61void mi_stack_list_locals(mi_h *h, int show)
62{
63 mi_send(h,"-stack-list-locals %d\n",show);
64}
65
66/* High level versions. */
67
68/**[txh]********************************************************************
69
70 Description:
71 List of frames. Arguments aren't filled.
72
73 Command: -stack-list-frames
74 Return: A new list of mi_frames or NULL on error.
75
76***************************************************************************/
77
78mi_frames *gmi_stack_list_frames(mi_h *h)
79{
80 mi_stack_list_frames(h,-1,-1);
81 return mi_res_frames_array(h,"stack");
82}
83
84/**[txh]********************************************************************
85
86 Description:
87 List of frames. Arguments aren't filled. Only the frames in the @var{from}
88 - @var{to} range are returned.
89
90 Command: -stack-list-frames
91 Return: A new list of mi_frames or NULL on error.
92
93***************************************************************************/
94
95mi_frames *gmi_stack_list_frames_r(mi_h *h, int from, int to)
96{
97 mi_stack_list_frames(h,from,to);
98 return mi_res_frames_array(h,"stack");
99}
100
101/**[txh]********************************************************************
102
103 Description:
104 List arguments. Only @var{level} and @var{args} filled.
105
106 Command: -stack-list-arguments
107 Return: A new list of mi_frames or NULL on error.
108
109***************************************************************************/
110
111mi_frames *gmi_stack_list_arguments(mi_h *h, int show)
112{
113 mi_stack_list_arguments(h,show,-1,-1);
114 return mi_res_frames_array(h,"stack-args");
115}
116
117/**[txh]********************************************************************
118
119 Description:
120 List arguments. Only @var{level} and @var{args} filled. Only for the
121frames in the @var{from} - @var{to} range.
122
123 Command: -stack-list-arguments
124 Return: A new list of mi_frames or NULL on error.
125
126***************************************************************************/
127
128mi_frames *gmi_stack_list_arguments_r(mi_h *h, int show, int from, int to)
129{
130 mi_stack_list_arguments(h,show,from,to);
131 return mi_res_frames_array(h,"stack-args");
132}
133
134/**[txh]********************************************************************
135
136 Description:
137 Information about the current frame, including args.
138
139 Command: -stack-info-frame [using frame]
140 Return: A new mi_frames or NULL on error.
141
142***************************************************************************/
143
144mi_frames *gmi_stack_info_frame(mi_h *h)
145{
146 mi_stack_info_frame(h);
147 return mi_res_frame(h);
148}
149
150/**[txh]********************************************************************
151
152 Description:
153 Stack info depth.
154
155 Command: -stack-info-depth
156 Return: The depth or -1 on error.
157
158***************************************************************************/
159
160int gmi_stack_info_depth(mi_h *h, int max_depth)
161{
162 mi_results *r;
163 int ret=-1;
164
165 mi_stack_info_depth(h,max_depth);
166 r=mi_res_done_var(h,"depth");
167 if (r && r->type==t_const)
168 {
169 ret=atoi(r->v.cstr);
170 mi_free_results(r);
171 }
172 return ret;
173}
174
175/**[txh]********************************************************************
176
177 Description:
178 Set stack info depth.
179
180 Command: -stack-info-depth [no args]
181 Return: The depth or -1 on error.
182 Example:
183
184***************************************************************************/
185
186int gmi_stack_info_depth_get(mi_h *h)
187{
188 return gmi_stack_info_depth(h,-1);
189}
190
191/**[txh]********************************************************************
192
193 Description:
194 Change current frame.
195
196 Command: -stack-select-frame
197 Return: !=0 OK
198
199***************************************************************************/
200
201int gmi_stack_select_frame(mi_h *h, int framenum)
202{
203 mi_stack_select_frame(h,framenum);
204 return mi_res_simple_done(h);
205}
206
207/**[txh]********************************************************************
208
209 Description:
210 List of local vars.
211
212 Command: -stack-list-locals
213 Return: A new mi_results tree containing the variables or NULL on error.
214
215***************************************************************************/
216
217mi_results *gmi_stack_list_locals(mi_h *h, int show)
218{
219 mi_stack_list_locals(h,show);
220 return mi_res_done_var(h,"locals");
221}
222
diff --git a/src/monkey/symbol_query.c b/src/monkey/symbol_query.c
new file mode 100644
index 000000000..55e145f87
--- /dev/null
+++ b/src/monkey/symbol_query.c
@@ -0,0 +1,32 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Symbol query.
7 Comments:
8 GDB/MI commands for the "Symbol Query" section.@p
9
10@<pre>
11gdb command: Implemented?
12-symbol-info-address N.A. (info address, human readable)
13-symbol-info-file N.A.
14-symbol-info-function N.A.
15-symbol-info-line N.A. (info line, human readable)
16-symbol-info-symbol N.A. (info symbol, human readable)
17-symbol-list-functions N.A. (info functions, human readable)
18-symbol-list-types N.A. (info types, human readable)
19-symbol-list-variables N.A. (info variables, human readable)
20-symbol-list-lines No (gdb 6.x)
21-symbol-locate N.A.
22-symbol-type N.A. (ptype, human readable)
23@</pre>
24
25Note:@p
26
27Only one is implemented and not in gdb 5.x.@p
28
29***************************************************************************/
30
31#include "mi_gdb.h"
32
diff --git a/src/monkey/target_man.c b/src/monkey/target_man.c
new file mode 100644
index 000000000..cf6c815b2
--- /dev/null
+++ b/src/monkey/target_man.c
@@ -0,0 +1,119 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2007 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Target manipulation.
7 Comments:
8 GDB/MI commands for the "Target Manipulation" section.@p
9
10@<pre>
11-target-attach Yes (implemented using attach)
12-target-compare-sections N.A. (compare-sections)
13-target-detach Yes
14-target-download Yes
15-target-exec-status N.A.
16-target-list-available-targets N.A. (help target)
17-target-list-current-targets N.A. (info file among other things)
18-target-list-parameters N.A.
19-target-select Yes
20@</pre>
21
22***************************************************************************/
23
24#include "mi_gdb.h"
25
26/* Low level versions. */
27
28void mi_target_select(mi_h *h, const char *type, const char *params)
29{
30 mi_send(h,"-target-select %s %s\n",type,params);
31}
32
33/* Note: -target-attach isn't currently implemented :-( (gdb 6.1.1) */
34void mi_target_attach(mi_h *h, pid_t pid)
35{
36 mi_send(h,"attach %d\n",pid);
37}
38
39void mi_target_detach(mi_h *h)
40{
41 mi_send(h,"-target-detach\n");
42}
43
44void mi_target_download(mi_h *h)
45{
46 mi_send(h,"-target-download\n");
47}
48
49/* High level versions. */
50
51/**[txh]********************************************************************
52
53 Description:
54 Connect to a remote gdbserver using the specified methode.
55
56 Command: -target-select
57 Return: !=0 OK
58
59***************************************************************************/
60
61int gmi_target_select(mi_h *h, const char *type, const char *params)
62{
63 mi_target_select(h,type,params);
64 if (!mi_res_simple_connected(h))
65 return 0;
66 mi_send_target_commands(h);
67 return 1;
68}
69
70/**[txh]********************************************************************
71
72 Description:
73 Attach to an already running process.
74
75 Command: -target-attach [using attach]
76 Return: The frame of the current location, NULL on error.
77
78***************************************************************************/
79
80mi_frames *gmi_target_attach(mi_h *h, pid_t pid)
81{
82 mi_target_attach(h,pid);
83 //return mi_res_simple_done(h);
84 return mi_res_frame(h);
85}
86
87/**[txh]********************************************************************
88
89 Description:
90 Detach from an attached process.
91
92 Command: -target-detach
93 Return: !=0 OK
94
95***************************************************************************/
96
97int gmi_target_detach(mi_h *h)
98{
99 mi_target_detach(h);
100 return mi_res_simple_done(h);
101}
102
103/**[txh]********************************************************************
104
105 Description:
106 Loads the executable onto the remote target.
107
108 Command: -target-download
109 Return: !=0 OK
110
111***************************************************************************/
112
113int gmi_target_download(mi_h *h)
114{
115 mi_target_download(h);
116 // TODO: this response have some data
117 return mi_res_simple_done(h);
118}
119
diff --git a/src/monkey/test_gnunet_monkey.sh b/src/monkey/test_gnunet_monkey.sh
new file mode 100755
index 000000000..7595a68fb
--- /dev/null
+++ b/src/monkey/test_gnunet_monkey.sh
@@ -0,0 +1,199 @@
1#!/bin/sh
2
3rm -rf /tmp/test-gnunetd-monkey/
4exe="./gnunet-monkey -c test_monkey_api_data.conf"
5out=`mktemp /tmp/test-gnunet-monkey-logXXXXXXXX`
6arm="gnunet-arm -c test_monkey_api_data.conf $DEBUG"
7#DEBUG="-L DEBUG"
8# -----------------------------------
9echo -n "Preparing: Starting service..."
10
11$arm -s > /dev/null
12sleep 1
13$arm -i monkey > /dev/null
14sleep 1
15echo "DONE"
16
17# ----------------------------------------------------------------------------------
18echo -n "TEST: Bad argument checking..."
19
20if $exe -x 2> /dev/null; then
21 echo "FAIL: error running $exe"
22 $arm -e
23 exit 1
24fi
25echo "PASS"
26
27# ----------------------------------------------------------------------------------
28echo -n "TEST: Set value..."
29
30if ! $exe $DEBUG -n test -s subsystem 42 ; then
31 echo "FAIL: error running $exe"
32 $arm -e
33 exit 1
34fi
35echo "PASS"
36
37# ----------------------------------------------------------------------------------
38echo -n "TEST: Set another value..."
39
40if ! $exe $DEBUG -n other -s osystem 43 ; then
41 echo "FAIL: error running $exe"
42 $arm -e
43 exit 1
44fi
45echo "PASS"
46
47# ----------------------------------------------------------------------------------
48echo -n "TEST: viewing all stats..."
49
50if ! $exe $DEBUG > $out; then
51 echo "FAIL: error running $exe"
52 $arm -e
53 exit 1
54fi
55LINES=`cat $out | wc -l`
56if test $LINES -ne 2; then
57 echo "FAIL: unexpected output"
58 $arm -e
59 exit 1
60fi
61echo "PASS"
62
63# ----------------------------------------------------------------------------------
64echo -n "TEST: viewing stats by name..."
65
66if ! $exe $DEBUG -n other > $out; then
67 echo "FAIL: error running $exe"
68 $arm -e
69 exit 1
70fi
71LINES=`cat $out | grep 43 | wc -l`
72if test $LINES -ne 1; then
73 echo "FAIL: unexpected output"
74 $arm -e
75 exit 1
76fi
77echo "PASS"
78
79# ----------------------------------------------------------------------------------
80echo -n "TEST: viewing stats by subsystem..."
81
82if ! $exe $DEBUG -s subsystem > $out; then
83 echo "FAIL: error running $exe"
84 $arm -e
85 exit 1
86fi
87LINES=`cat $out | grep 42 | wc -l`
88if test $LINES -ne 1; then
89 echo "FAIL: unexpected output"
90 $arm -e
91 exit 1
92fi
93echo "PASS"
94
95
96# ----------------------------------------------------------------------------------
97echo -n "TEST: Set persistent value..."
98
99if ! $exe $DEBUG -n lasting -s subsystem 40 -p; then
100 echo "FAIL: error running $exe"
101 $arm -e
102 exit 1
103fi
104if ! $exe $DEBUG > $out; then
105 echo "FAIL: error running $exe"
106 $arm -e
107 exit 1
108fi
109LINES=`cat $out | grep 40 | wc -l`
110if test $LINES -ne 1; then
111 echo "FAIL: unexpected output"
112 cat $out
113 $arm -e
114 exit 1
115fi
116echo "PASS"
117
118# -----------------------------------
119echo -n "Restarting service..."
120$arm -k monkey > /dev/null
121sleep 1
122$arm -i monkey > /dev/null
123sleep 1
124echo "DONE"
125
126# ----------------------------------------------------------------------------------
127echo -n "TEST: checking persistence..."
128
129if ! $exe $DEBUG > $out; then
130 echo "FAIL: error running $exe"
131 $arm -e
132 exit 1
133fi
134LINES=`cat $out | grep 40 | wc -l`
135if test $LINES -ne 1; then
136 echo "FAIL: unexpected output"
137 cat $out
138 $arm -e
139 exit 1
140fi
141echo "PASS"
142
143
144
145# ----------------------------------------------------------------------------------
146echo -n "TEST: Removing persistence..."
147
148if ! $exe $DEBUG -n lasting -s subsystem 40; then
149 echo "FAIL: error running $exe"
150 $arm -e
151 exit 1
152fi
153if ! $exe $DEBUG > $out; then
154 echo "FAIL: error running $exe"
155 $arm -e
156 exit 1
157fi
158LINES=`cat $out | grep \! | wc -l`
159if test $LINES -ne 0; then
160 echo "FAIL: unexpected output"
161 cat $out
162 $arm -e
163 exit 1
164fi
165echo "PASS"
166
167
168# -----------------------------------
169echo -n "Restarting service..."
170$arm -k monkey > /dev/null
171sleep 1
172$arm -i monkey > /dev/null
173sleep 1
174echo "DONE"
175
176# ----------------------------------------------------------------------------------
177echo -n "TEST: checking removed persistence..."
178
179if ! $exe $DEBUG > $out; then
180 echo "FAIL: error running $exe"
181 $arm -e
182 exit 1
183fi
184LINES=`cat $out | grep 40 | wc -l`
185if test $LINES -ne 0; then
186 echo "FAIL: unexpected output"
187 cat $out
188 $arm -e
189 exit 1
190fi
191echo "PASS"
192
193# -----------------------------------
194echo -n "Stopping service..."
195$arm -e > /dev/null
196sleep 1
197echo "DONE"
198rm -f $out
199rm -rf /tmp/test-gnunetd-monkey/
diff --git a/src/monkey/test_monkey_api.c b/src/monkey/test_monkey_api.c
new file mode 100644
index 000000000..d63453bee
--- /dev/null
+++ b/src/monkey/test_monkey_api.c
@@ -0,0 +1,6 @@
1
2
3int main(int argc, char *argv[])
4{
5 return 0;
6} \ No newline at end of file
diff --git a/src/monkey/thread.c b/src/monkey/thread.c
new file mode 100644
index 000000000..51a333f5b
--- /dev/null
+++ b/src/monkey/thread.c
@@ -0,0 +1,89 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Thread commands.
7 Comments:
8 GDB/MI commands for the "Thread Commands" section.@p
9
10@<pre>
11gdb command: Implemented?
12-thread-info N.A.
13-thread-list-all-threads Yes, implemented as "info threads"
14-thread-list-ids Yes
15-thread-select Yes
16@</pre>
17
18***************************************************************************/
19
20#include "mi_gdb.h"
21
22/* Low level versions. */
23
24void mi_thread_list_ids(mi_h *h)
25{
26 mi_send(h,"-thread-list-ids\n");
27}
28
29void mi_thread_select(mi_h *h, int id)
30{
31 mi_send(h,"-thread-select %d\n",id);
32}
33
34void mi_thread_list_all_threads(mi_h *h)
35{
36 mi_send(h,"info threads\n");
37}
38
39/* High level versions. */
40
41/**[txh]********************************************************************
42
43 Description:
44 List available thread ids.
45
46 Command: -thread-list-ids
47 Return: !=0 OK
48
49***************************************************************************/
50
51int gmi_thread_list_ids(mi_h *h, int **list)
52{
53 mi_thread_list_ids(h);
54 return mi_res_thread_ids(h,list);
55}
56
57/**[txh]********************************************************************
58
59 Description:
60 Select a thread.
61
62 Command: -thread-select
63 Return: A new mi_frames or NULL on error.
64
65***************************************************************************/
66
67mi_frames *gmi_thread_select(mi_h *h, int id)
68{
69 mi_thread_select(h,id);
70 return mi_res_frame(h);
71}
72
73/**[txh]********************************************************************
74
75 Description:
76 Get a list of frames for each available thread. Implemented using "info
77thread".
78
79 Command: -thread-list-all-threads
80 Return: A kist of frames, NULL on error
81
82***************************************************************************/
83
84mi_frames *gmi_thread_list_all_threads(mi_h *h)
85{
86 mi_thread_list_all_threads(h);
87 return mi_res_frames_list(h);
88}
89
diff --git a/src/monkey/var_obj.c b/src/monkey/var_obj.c
new file mode 100644
index 000000000..a027d6751
--- /dev/null
+++ b/src/monkey/var_obj.c
@@ -0,0 +1,369 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Variable objects.
7 Comments:
8 GDB/MI commands for the "Variable Objects" section.@p
9
10@<pre>
11gdb command: Imp? Description:
12-var-create Yes create a variable object
13-var-delete Yes delete the variable object and its children
14-var-set-format Yes set the display format of this variable
15-var-show-format Yes show the display format of this variable
16-var-info-num-children Yes tells how many children this object has
17-var-list-children Yes* return a list of the object's children
18-var-info-type Yes show the type of this variable object
19-var-info-expression Yes print what this variable object represents
20-var-show-attributes Yes is this variable editable?
21-var-evaluate-expression Yes get the value of this variable
22-var-assign Yes set the value of this variable
23-var-update Yes* update the variable and its children
24@</pre>
25
26Notes:@p
271) I suggest letting gdb to choose the names for the variables.@*
282) -var-list-children supports an optional "show values" argument in MI v2.
29It isn't implemented.@*
30@p
31
32* MI v1 and v2 result formats supported.@p
33
34***************************************************************************/
35
36#include "mi_gdb.h"
37
38/* Low level versions. */
39
40void mi_var_create(mi_h *h, const char *name, int frame, const char *exp)
41{
42 const char *n=name ? name : "-";
43
44 if (frame<0)
45 mi_send(h,"-var-create %s * %s\n",n,exp);
46 else
47 mi_send(h,"-var-create %s %d %s\n",n,frame,exp);
48}
49
50void mi_var_delete(mi_h *h, const char *name)
51{
52 mi_send(h,"-var-delete %s\n",name);
53}
54
55void mi_var_set_format(mi_h *h, const char *name, const char *format)
56{
57 mi_send(h,"-var-set-format \"%s\" %s\n",name,format);
58}
59
60void mi_var_show_format(mi_h *h, const char *name)
61{
62 mi_send(h,"-var-show-format \"%s\"\n",name);
63}
64
65void mi_var_info_num_children(mi_h *h, const char *name)
66{
67 mi_send(h,"-var-info-num-children \"%s\"\n",name);
68}
69
70void mi_var_info_type(mi_h *h, const char *name)
71{
72 mi_send(h,"-var-info-type \"%s\"\n",name);
73}
74
75void mi_var_info_expression(mi_h *h, const char *name)
76{
77 mi_send(h,"-var-info-expression \"%s\"\n",name);
78}
79
80void mi_var_show_attributes(mi_h *h, const char *name)
81{
82 mi_send(h,"-var-show-attributes \"%s\"\n",name);
83}
84
85void mi_var_update(mi_h *h, const char *name)
86{
87 if (name)
88 mi_send(h,"-var-update %s\n",name);
89 else
90 mi_send(h,"-var-update *\n");
91}
92
93void mi_var_assign(mi_h *h, const char *name, const char *expression)
94{
95 mi_send(h,"-var-assign \"%s\" \"%s\"\n",name,expression);
96}
97
98void mi_var_evaluate_expression(mi_h *h, const char *name)
99{
100 mi_send(h,"-var-evaluate-expression \"%s\"\n",name);
101}
102
103void mi_var_list_children(mi_h *h, const char *name)
104{
105 if (h->version>=MI_VERSION2U(2,0,0))
106 mi_send(h,"-var-list-children --all-values \"%s\"\n",name);
107 else
108 mi_send(h,"-var-list-children \"%s\"\n",name);
109}
110
111/* High level versions. */
112
113/**[txh]********************************************************************
114
115 Description:
116 Create a variable object. I recommend using @x{gmi_var_create} and letting
117gdb choose the names.
118
119 Command: -var-create
120 Return: A new mi_gvar strcture or NULL on error.
121
122***************************************************************************/
123
124mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp)
125{
126 mi_var_create(h,name,frame,exp);
127 return mi_res_gvar(h,NULL,exp);
128}
129
130/**[txh]********************************************************************
131
132 Description:
133 Create a variable object. The name is selected by gdb. Alternative:
134@x{gmi_full_var_create}.
135
136 Command: -var-create [auto name]
137 Return: A new mi_gvar strcture or NULL on error.
138
139***************************************************************************/
140
141mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp)
142{
143 return gmi_var_create_nm(h,NULL,frame,exp);
144}
145
146/**[txh]********************************************************************
147
148 Description:
149 Delete a variable object. Doesn't free the mi_gvar data.
150
151 Command: -var-delete
152 Return: !=0 OK
153
154***************************************************************************/
155
156int gmi_var_delete(mi_h *h, mi_gvar *var)
157{
158 mi_var_delete(h,var->name);
159 return mi_res_simple_done(h);
160}
161
162/**[txh]********************************************************************
163
164 Description:
165 Set the format used to represent the result.
166
167 Command: -var-set-format
168 Return: !=0 OK
169
170***************************************************************************/
171
172int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format)
173{
174 int ret;
175
176 mi_var_set_format(h,var->name,mi_format_enum_to_str(format));
177 ret=mi_res_simple_done(h);
178 if (ret)
179 var->format=format;
180 return ret;
181}
182
183/**[txh]********************************************************************
184
185 Description:
186 Fill the format field with info from gdb.
187
188 Command: -var-show-format
189 Return: !=0 OK.
190
191***************************************************************************/
192
193int gmi_var_show_format(mi_h *h, mi_gvar *var)
194{
195 mi_var_show_format(h,var->name);
196 return mi_res_gvar(h,var,NULL)!=NULL;
197}
198
199/**[txh]********************************************************************
200
201 Description:
202 Fill the numchild field with info from gdb.
203
204 Command: -var-info-num-children
205 Return: !=0 OK
206
207***************************************************************************/
208
209int gmi_var_info_num_children(mi_h *h, mi_gvar *var)
210{
211 mi_var_info_num_children(h,var->name);
212 return mi_res_gvar(h,var,NULL)!=NULL;
213}
214
215/**[txh]********************************************************************
216
217 Description:
218 Fill the type field with info from gdb.
219
220 Command: -var-info-type
221 Return: !=0 OK
222
223***************************************************************************/
224
225int gmi_var_info_type(mi_h *h, mi_gvar *var)
226{
227 mi_var_info_type(h,var->name);
228 return mi_res_gvar(h,var,NULL)!=NULL;
229}
230
231/**[txh]********************************************************************
232
233 Description:
234 Fill the expression and lang fields with info from gdb. Note that lang
235isn't filled during creation.
236
237 Command: -var-info-expression
238 Return: !=0 OK
239
240***************************************************************************/
241
242int gmi_var_info_expression(mi_h *h, mi_gvar *var)
243{
244 mi_var_info_expression(h,var->name);
245 return mi_res_gvar(h,var,NULL)!=NULL;
246}
247
248
249/**[txh]********************************************************************
250
251 Description:
252 Fill the attr field with info from gdb. Note that attr isn't filled
253during creation.
254
255 Command: -var-show-attributes
256 Return: !=0 OK
257
258***************************************************************************/
259
260int gmi_var_show_attributes(mi_h *h, mi_gvar *var)
261{
262 mi_var_show_attributes(h,var->name);
263 return mi_res_gvar(h,var,NULL)!=NULL;
264}
265
266/**[txh]********************************************************************
267
268 Description:
269 Create the variable and also fill the lang and attr fields. The name is
270selected by gdb.
271
272 Command: -var-create + -var-info-expression + -var-show-attributes
273 Return: A new mi_gvar strcture or NULL on error.
274
275***************************************************************************/
276
277mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp)
278{
279 mi_gvar *var=gmi_var_create_nm(h,NULL,frame,exp);
280 if (var)
281 {/* What if it fails? */
282 gmi_var_info_expression(h,var);
283 gmi_var_show_attributes(h,var);
284 }
285 return var;
286}
287
288/**[txh]********************************************************************
289
290 Description:
291 Update variable. Use NULL for all. Note that *changed can be NULL if none
292updated.
293
294 Command: -var-update
295 Return: !=0 OK. The @var{changed} list contains the list of changed vars.
296
297***************************************************************************/
298
299int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed)
300{
301 mi_var_update(h,var ? var->name : NULL);
302 return mi_res_changelist(h,changed);
303}
304
305/**[txh]********************************************************************
306
307 Description:
308 Change variable. The new value replaces the @var{value} field.
309
310 Command: -var-assign
311 Return: !=0 OK
312
313***************************************************************************/
314
315int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression)
316{
317 char *res;
318 mi_var_assign(h,var->name,expression);
319 res=mi_res_value(h);
320 if (res)
321 {
322 free(var->value);
323 var->value=res;
324 return 1;
325 }
326 return 0;
327}
328
329/**[txh]********************************************************************
330
331 Description:
332 Fill the value field getting the current value for a variable.
333
334 Command: -var-evaluate-expression
335 Return: !=0 OK, value contains the result.
336
337***************************************************************************/
338
339int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var)
340{
341 char *s;
342
343 mi_var_evaluate_expression(h,var->name);
344 s=mi_res_value(h);
345 if (s)
346 {
347 free(var->value);
348 var->value=s;
349 }
350 return s!=NULL;
351}
352
353/**[txh]********************************************************************
354
355 Description:
356 List children. It ONLY returns the first level information. :-(@*
357 On success the child field contains the list of children.
358
359 Command: -var-list-children
360 Return: !=0 OK
361
362***************************************************************************/
363
364int gmi_var_list_children(mi_h *h, mi_gvar *var)
365{
366 mi_var_list_children(h,var->name);
367 return mi_res_children(h,var);
368}
369