aboutsummaryrefslogtreecommitdiff
path: root/pathologist/src/mi
diff options
context:
space:
mode:
Diffstat (limited to 'pathologist/src/mi')
-rw-r--r--pathologist/src/mi/Makefile.am29
-rw-r--r--pathologist/src/mi/gdbmi_alloc.c308
-rw-r--r--pathologist/src/mi/gdbmi_breakpoint.c265
-rw-r--r--pathologist/src/mi/gdbmi_connect.c885
-rw-r--r--pathologist/src/mi/gdbmi_data_man.c243
-rw-r--r--pathologist/src/mi/gdbmi_error.c38
-rw-r--r--pathologist/src/mi/gdbmi_get_free_pty.c132
-rw-r--r--pathologist/src/mi/gdbmi_get_free_vt.c156
-rw-r--r--pathologist/src/mi/gdbmi_misc.c118
-rw-r--r--pathologist/src/mi/gdbmi_parse.c1927
-rw-r--r--pathologist/src/mi/gdbmi_prg_control.c598
-rw-r--r--pathologist/src/mi/gdbmi_stack_man.c222
-rw-r--r--pathologist/src/mi/gdbmi_symbol_query.c32
-rw-r--r--pathologist/src/mi/gdbmi_target_man.c119
-rw-r--r--pathologist/src/mi/gdbmi_thread.c89
-rw-r--r--pathologist/src/mi/gdbmi_var_obj.c371
16 files changed, 5532 insertions, 0 deletions
diff --git a/pathologist/src/mi/Makefile.am b/pathologist/src/mi/Makefile.am
new file mode 100644
index 0000000..1248080
--- /dev/null
+++ b/pathologist/src/mi/Makefile.am
@@ -0,0 +1,29 @@
1INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/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
12lib_LTLIBRARIES = libmi.la
13
14libmi_la_SOURCES = \
15 gdbmi_alloc.c \
16 gdbmi_breakpoint.c \
17 gdbmi_connect.c \
18 gdbmi_data_man.c \
19 gdbmi_error.c \
20 gdbmi_get_free_pty.c \
21 gdbmi_get_free_vt.c \
22 gdbmi_misc.c \
23 gdbmi_parse.c \
24 gdbmi_prg_control.c \
25 gdbmi_stack_man.c \
26 gdbmi_symbol_query.c \
27 gdbmi_target_man.c \
28 gdbmi_thread.c \
29 gdbmi_var_obj.c \ No newline at end of file
diff --git a/pathologist/src/mi/gdbmi_alloc.c b/pathologist/src/mi/gdbmi_alloc.c
new file mode 100644
index 0000000..0fe6e14
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.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/pathologist/src/mi/gdbmi_breakpoint.c b/pathologist/src/mi/gdbmi_breakpoint.c
new file mode 100644
index 0000000..f91cc3e
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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.
9 @<p>
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 "gdbmi.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/pathologist/src/mi/gdbmi_connect.c b/pathologist/src/mi/gdbmi_connect.c
new file mode 100644
index 0000000..b9f3754
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_connect.c
@@ -0,0 +1,885 @@
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.
10 @<p>
11
12GDB Bug workaround for "file -readnow": I tried to workaround a bug using
13it but looks like this option also have bugs!!!! so I have to use the
14command line option --readnow.
15It also have a bug!!!! when the binary is changed and gdb must reload it
16this option is ignored. So it looks like we have no solution but 3 gdb bugs
17in a row.
18
19***************************************************************************/
20
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 "plibc.h"
35
36#include "gdbmi.h"
37#ifndef _GNU_SOURCE
38#define _GNU_SOURCE
39#endif
40
41#ifndef TEMP_FAILURE_RETRY
42 #define TEMP_FAILURE_RETRY(a) (a)
43#endif
44
45int mi_error=MI_OK;
46char *mi_error_from_gdb=NULL;
47static char *gdb_exe=NULL;
48static char *xterm_exe=NULL;
49static char *gdb_start=NULL;
50static char *gdb_conn=NULL;
51static char *main_func=NULL;
52static char disable_psym_search_workaround=0;
53
54mi_h *mi_alloc_h()
55{
56 mi_h *h=(mi_h *)calloc(1,sizeof(mi_h));
57 if (!h)
58 {
59 mi_error=MI_OUT_OF_MEMORY;
60 return NULL;
61 }
62 h->to_gdb[0]=h->to_gdb[1]=h->from_gdb[0]=h->from_gdb[1]=-1;
63 h->pid=-1;
64 return h;
65}
66
67int mi_check_running_pid(pid_t pid)
68{
69 int status;
70
71 if (pid<=0)
72 return 0;
73 /* If waitpid returns the number of our child means it communicated
74 to as a termination status. */
75 if (waitpid(pid,&status,WNOHANG)==pid)
76 {
77 pid=0;
78 return 0;
79 }
80 return 1;
81}
82
83int mi_check_running(mi_h *h)
84{
85 return !h->died && mi_check_running_pid(h->pid);
86}
87
88void mi_kill_child(pid_t pid)
89{
90 kill(pid,SIGTERM);
91 usleep(100000);
92 if (mi_check_running_pid(pid))
93 {
94 int status;
95 kill(pid,SIGKILL);
96 waitpid(pid,&status,0);
97 }
98}
99
100void mi_free_h(mi_h **handle)
101{
102 mi_h *h=*handle;
103 if (h->to_gdb[0]>=0)
104 close(h->to_gdb[0]);
105 if (h->to)
106 fclose(h->to);
107 else if (h->to_gdb[1]>=0)
108 close(h->to_gdb[1]);
109 if (h->from)
110 fclose(h->from);
111 else if (h->from_gdb[0]>=0)
112 close(h->from_gdb[0]);
113 if (h->from_gdb[1]>=0)
114 close(h->from_gdb[1]);
115 if (mi_check_running(h))
116 {/* GDB is running! */
117 mi_kill_child(h->pid);
118 }
119 if (h->line)
120 free(h->line);
121 mi_free_output(h->po);
122 free(h->catched_console);
123 free(h);
124 *handle=NULL;
125}
126
127void mi_set_nonblk(int h)
128{
129 int flf;
130 flf=fcntl(h,F_GETFL,0);
131 flf=flf | O_NONBLOCK;
132 fcntl(h,F_SETFL,flf);
133}
134
135int mi_getline(mi_h *h)
136{
137 char c;
138
139 while (read(h->from_gdb[0],&c,1)==1)
140 {
141 if (h->lread>=h->llen)
142 {
143 h->llen=h->lread+128;
144 h->line=(char *)realloc(h->line,h->llen);
145 if (!h->line)
146 {
147 h->llen=0;
148 h->lread=0;
149 return -1;
150 }
151 }
152 if (c=='\n')
153 {
154 int ret=h->lread;
155 h->line[ret]=0;
156 h->lread=0;
157 return ret;
158 }
159 h->line[h->lread]=c;
160 h->lread++;
161 }
162 return 0;
163}
164
165char *get_cstr(mi_output *o)
166{
167 if (!o->c || o->c->type!=t_const)
168 return NULL;
169 return o->c->v.cstr;
170}
171
172int mi_get_response(mi_h *h)
173{
174 int l=mi_getline(h);
175 if (!l)
176 return 0;
177
178 if (h->from_gdb_echo)
179 h->from_gdb_echo(h->line,h->from_gdb_echo_data);
180 if (strncmp(h->line,"(gdb)",5)==0)
181 {/* End of response. */
182 return 1;
183 }
184 else
185 {/* Add to the response. */
186 mi_output *o;
187 int add=1, is_exit=0;
188 o=mi_parse_gdb_output(h->line);
189
190 if (!o)
191 return 0;
192 /* Tunneled streams callbacks. */
193 if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_STREAM)
194 {
195 char *aux;
196 add=0;
197 switch (o->sstype)
198 {
199 case MI_SST_CONSOLE:
200 aux=get_cstr(o);
201 if (h->console)
202 h->console(aux,h->console_data);
203 if (h->catch_console && aux)
204 {
205 h->catch_console--;
206 if (!h->catch_console)
207 {
208 free(h->catched_console);
209 h->catched_console=strdup(aux);
210 }
211 }
212 break;
213 case MI_SST_TARGET:
214 /* This one seems to be useless. */
215 if (h->target)
216 h->target(get_cstr(o),h->target_data);
217 break;
218 case MI_SST_LOG:
219 if (h->log)
220 h->log(get_cstr(o),h->log_data);
221 break;
222 }
223 }
224 else if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_ASYNC)
225 {
226 if (h->async)
227 h->async(o,h->async_data);
228 }
229 else if (o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_ERROR)
230 {/* Error from gdb, record it. */
231 mi_error=MI_FROM_GDB;
232 free(mi_error_from_gdb);
233 mi_error_from_gdb=NULL;
234 if (o->c && strcmp(o->c->var,"msg")==0 && o->c->type==t_const)
235 mi_error_from_gdb=strdup(o->c->v.cstr);
236 }
237 is_exit=(o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_EXIT);
238 /* Add to the list of responses. */
239 if (add)
240 {
241 if (h->last)
242 h->last->next=o;
243 else
244 h->po=o;
245 h->last=o;
246 }
247 else
248 mi_free_output(o);
249 /* Exit RR means gdb exited, we won't get a new prompt ;-) */
250 if (is_exit)
251 return 1;
252 }
253
254 return 0;
255}
256
257mi_output *mi_retire_response(mi_h *h)
258{
259 mi_output *ret=h->po;
260 h->po=h->last=NULL;
261 return ret;
262}
263
264mi_output *mi_get_response_blk(mi_h *h)
265{
266 int r;
267 /* Sometimes gdb dies. */
268 if (!mi_check_running(h))
269 {
270 h->died=1;
271 mi_error=MI_GDB_DIED;
272 return NULL;
273 }
274 do
275 {
276 /*
277 That's a must. If we just keep trying to read and failing things
278 become really sloooowwww. Instead we try and if it fails we wait
279 until something is available.
280 TODO: Implement something with the time out, a callback to ask the
281 application is we have to wait or not could be a good thing.
282 */
283 fd_set set;
284 struct timeval timeout;
285 int ret;
286
287 r=mi_get_response(h);
288 if (r)
289 return mi_retire_response(h);
290
291 FD_ZERO(&set);
292 FD_SET(h->from_gdb[0],&set);
293 timeout.tv_sec=h->time_out;
294 timeout.tv_usec=0;
295 ret=TEMP_FAILURE_RETRY(select(FD_SETSIZE,&set,NULL,NULL,&timeout));
296 if (!ret)
297 {
298 if (!mi_check_running(h))
299 {
300 h->died=1;
301 mi_error=MI_GDB_DIED;
302 return NULL;
303 }
304 if (h->time_out_cb)
305 ret=h->time_out_cb(h->time_out_cb_data);
306 if (!ret)
307 {
308 mi_error=MI_GDB_TIME_OUT;
309 return NULL;
310 }
311 }
312 }
313 while (!r);
314
315 return NULL;
316}
317
318void mi_send_commands(mi_h *h, const char *file)
319{
320 FILE *f;
321 char b[PATH_MAX];
322
323 //printf("File: %s\n",file);
324 if (!file)
325 return;
326 f=fopen(file,"rt");
327 if (!f)
328 return;
329 while (!feof(f))
330 {
331 if (fgets(b,PATH_MAX,f))
332 {
333 //printf("Send: %s\n",b);
334 mi_send (h, "%s", b);
335 mi_res_simple_done(h);
336 }
337 }
338 fclose(f);
339}
340
341void mi_send_target_commands(mi_h *h)
342{
343 mi_send_commands(h,gdb_conn);
344}
345
346/**[txh]********************************************************************
347
348 Description:
349 Connect to a local copy of gdb. Note that the mi_h structure is something
350similar to a "FILE *" for stdio.
351
352 Return: A new mi_h structure or NULL on error.
353
354***************************************************************************/
355
356mi_h *mi_connect_local()
357{
358 mi_h *h;
359 const char *gdb=mi_get_gdb_exe();
360
361 /* Start without error. */
362 mi_error=MI_OK;
363 /* Verify we have a GDB binary. */
364 if (access(gdb,X_OK))
365 {
366 mi_error=MI_MISSING_GDB;
367 return NULL;
368 }
369 /* Alloc the handle structure. */
370 h=mi_alloc_h();
371 if (!h)
372 return h;
373 h->time_out=MI_DEFAULT_TIME_OUT;
374 /* Create the pipes to connect with the child. */
375 if (pipe(h->to_gdb) || pipe(h->from_gdb))
376 {
377 mi_error=MI_PIPE_CREATE;
378 mi_free_h(&h);
379 return NULL;
380 }
381 mi_set_nonblk(h->to_gdb[1]);
382 mi_set_nonblk(h->from_gdb[0]);
383 /* Associate streams to the file handles. */
384 h->to=fdopen(h->to_gdb[1],"w");
385 h->from=fdopen(h->from_gdb[0],"r");
386 if (!h->to || !h->from)
387 {
388 mi_error=MI_PIPE_CREATE;
389 mi_free_h(&h);
390 return NULL;
391 }
392 /* Create the child. */
393 h->pid=fork();
394 if (h->pid==0)
395 {/* We are the child. */
396 char *argv[5];
397 /* Connect stdin/out to the pipes. */
398 dup2(h->to_gdb[0],STDIN_FILENO);
399 dup2(h->from_gdb[1],STDOUT_FILENO);
400 /* Pass the control to gdb. */
401 argv[0]=(char *)gdb; /* Is that OK? */
402 argv[1]="--interpreter=mi";
403 argv[2]="--quiet";
404 argv[3]=disable_psym_search_workaround ? 0 : "--readnow";
405 argv[4]=0;
406 execvp(argv[0],argv);
407 /* We get here only if exec failed. */
408 _exit(127);
409 }
410 /* We are the parent. */
411 if (h->pid==-1)
412 {/* Fork failed. */
413 mi_error=MI_FORK;
414 mi_free_h(&h);
415 return NULL;
416 }
417 if (!mi_check_running(h))
418 {
419 mi_error=MI_DEBUGGER_RUN;
420 mi_free_h(&h);
421 return NULL;
422 }
423 /* Wait for the prompt. */
424 mi_get_response_blk(h);
425 /* Send the start-up commands */
426 mi_send_commands(h,gdb_start);
427
428 return h;
429}
430
431/**[txh]********************************************************************
432
433 Description:
434 Close connection. You should ask gdb to quit first gmi_gdb_exit.
435
436***************************************************************************/
437
438void mi_disconnect(mi_h *h)
439{
440 mi_free_h(&h);
441 free(mi_error_from_gdb);
442 mi_error_from_gdb=NULL;
443}
444
445void mi_set_console_cb(mi_h *h, stream_cb cb, void *data)
446{
447 h->console=cb;
448 h->console_data=data;
449}
450
451void mi_set_target_cb(mi_h *h, stream_cb cb, void *data)
452{
453 h->target=cb;
454 h->target_data=data;
455}
456
457void mi_set_log_cb(mi_h *h, stream_cb cb, void *data)
458{
459 h->log=cb;
460 h->log_data=data;
461}
462
463stream_cb mi_get_console_cb(mi_h *h, void **data)
464{
465 if (data)
466 *data=h->console_data;
467 return h->console;
468}
469
470stream_cb mi_get_target_cb(mi_h *h, void **data)
471{
472 if (data)
473 *data=h->target_data;
474 return h->target;
475}
476
477stream_cb mi_get_log_cb(mi_h *h, void **data)
478{
479 if (data)
480 *data=h->log_data;
481 return h->log;
482}
483
484void mi_set_async_cb(mi_h *h, async_cb cb, void *data)
485{
486 h->async=cb;
487 h->async_data=data;
488}
489
490async_cb mi_get_async_cb(mi_h *h, void **data)
491{
492 if (data)
493 *data=h->async_data;
494 return h->async;
495}
496
497void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data)
498{
499 h->to_gdb_echo=cb;
500 h->to_gdb_echo_data=data;
501}
502
503void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data)
504{
505 h->from_gdb_echo=cb;
506 h->from_gdb_echo_data=data;
507}
508
509stream_cb mi_get_to_gdb_cb(mi_h *h, void **data)
510{
511 if (data)
512 *data=h->to_gdb_echo_data;
513 return h->to_gdb_echo;
514}
515
516stream_cb mi_get_from_gdb_cb(mi_h *h, void **data)
517{
518 if (data)
519 *data=h->from_gdb_echo_data;
520 return h->from_gdb_echo;
521}
522
523void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data)
524{
525 h->time_out_cb=cb;
526 h->time_out_cb_data=data;
527}
528
529tm_cb mi_get_time_out_cb(mi_h *h, void **data)
530{
531 if (data)
532 *data=h->time_out_cb_data;
533 return h->time_out_cb;
534}
535
536void mi_set_time_out(mi_h *h, int to)
537{
538 h->time_out=to;
539}
540
541int mi_get_time_out(mi_h *h)
542{
543 return h->time_out;
544}
545
546int mi_send(mi_h *h, const char *format, ...)
547{
548 int ret;
549 char *str;
550 va_list argptr;
551
552 if (h->died)
553 return 0;
554
555 va_start(argptr,format);
556 ret=vasprintf(&str,format,argptr);
557 va_end(argptr);
558 if (-1 != ret)
559 {
560 fputs(str,h->to);
561 fflush(h->to);
562 if (h->to_gdb_echo)
563 h->to_gdb_echo(str,h->to_gdb_echo_data);
564 free(str);
565 }
566 else
567 {
568 abort ();
569 }
570
571 return ret;
572}
573
574void mi_clean_up_globals()
575{
576 free(gdb_exe);
577 gdb_exe=NULL;
578 free(xterm_exe);
579 xterm_exe=NULL;
580 free(gdb_start);
581 gdb_start=NULL;
582 free(gdb_conn);
583 gdb_conn=NULL;
584 free(main_func);
585 main_func=NULL;
586}
587
588void mi_register_exit()
589{
590 static int registered=0;
591 if (!registered)
592 {
593 registered=1;
594 atexit(mi_clean_up_globals);
595 }
596}
597
598void mi_set_gdb_exe(const char *name)
599{
600 free(gdb_exe);
601 gdb_exe=name ? strdup(name) : NULL;
602 mi_register_exit();
603}
604
605void mi_set_gdb_start(const char *name)
606{
607 free(gdb_start);
608 gdb_start=name ? strdup(name) : NULL;
609 mi_register_exit();
610}
611
612void mi_set_gdb_conn(const char *name)
613{
614 free(gdb_conn);
615 gdb_conn=name ? strdup(name) : NULL;
616 mi_register_exit();
617}
618
619static
620char *mi_search_in_path(const char *file)
621{
622 char *path, *pt, *r;
623 char test[PATH_MAX];
624 struct stat st;
625
626 path=getenv("PATH");
627 if (!path)
628 return NULL;
629 pt=strdup(path);
630 r=strtok(pt,PATH_SEPARATOR_STR);
631 while (r)
632 {
633 strcpy(test,r);
634 strcat(test,"/");
635 strcat(test,file);
636 if (stat(test,&st)==0 && S_ISREG(st.st_mode))
637 {
638 free(pt);
639 return strdup(test);
640 }
641 r=strtok(NULL,PATH_SEPARATOR_STR);
642 }
643 free(pt);
644 return NULL;
645}
646
647const char *mi_get_gdb_exe()
648{
649 if (!gdb_exe)
650 {/* Look for gdb in path */
651 gdb_exe=mi_search_in_path("gdb");
652 if (!gdb_exe)
653 return "/usr/bin/gdb";
654 }
655 return gdb_exe;
656}
657
658const char *mi_get_gdb_start()
659{
660 return gdb_start;
661}
662
663const char *mi_get_gdb_conn()
664{
665 return gdb_conn;
666}
667
668void mi_set_xterm_exe(const char *name)
669{
670 free(xterm_exe);
671 xterm_exe=name ? strdup(name) : NULL;
672 mi_register_exit();
673}
674
675const char *mi_get_xterm_exe()
676{
677 if (!xterm_exe)
678 {/* Look for xterm in path */
679 xterm_exe=mi_search_in_path("xterm");
680 if (!xterm_exe)
681 return "/usr/bin/X11/xterm";
682 }
683 return xterm_exe;
684}
685
686void mi_set_main_func(const char *name)
687{
688 free(main_func);
689 main_func=name ? strdup(name) : NULL;
690 mi_register_exit();
691}
692
693const char *mi_get_main_func()
694{
695 if (main_func)
696 return main_func;
697 return "main";
698}
699
700/**[txh]********************************************************************
701
702 Description:
703 Opens a new xterm to be used by the child process to debug.
704
705 Return: A new mi_aux_term structure, you can use gmi_end_aux_term to
706release it.
707
708***************************************************************************/
709
710mi_aux_term *gmi_start_xterm()
711{
712 char nsh[14]="/tmp/shXXXXXX";
713 char ntt[14]="/tmp/ttXXXXXX";
714 const char *xterm;
715 struct stat st;
716 int hsh, htt=-1;
717 mi_aux_term *res=NULL;
718 FILE *f;
719 pid_t pid;
720 char buf[PATH_MAX];
721
722 /* Verify we have an X terminal. */
723 xterm=mi_get_xterm_exe();
724 if (access(xterm,X_OK))
725 {
726 mi_error=MI_MISSING_XTERM;
727 return NULL;
728 }
729
730 /* Create 2 temporals. */
731 hsh=mkstemp(nsh);
732 if (hsh==-1)
733 {
734 mi_error=MI_CREATE_TEMPORAL;
735 return NULL;
736 }
737 htt=mkstemp(ntt);
738 if (htt==-1)
739 {
740 close(hsh);
741 unlink(nsh);
742 mi_error=MI_CREATE_TEMPORAL;
743 return NULL;
744 }
745 close(htt);
746 /* Create the script. */
747 f=fdopen(hsh,"w");
748 if (!f)
749 {
750 close(hsh);
751 unlink(nsh);
752 unlink(ntt);
753 mi_error=MI_CREATE_TEMPORAL;
754 return NULL;
755 }
756 fprintf(f,"#!/bin/sh\n");
757 fprintf(f,"tty > %s\n",ntt);
758 fprintf(f,"rm %s\n",nsh);
759 fprintf(f,"sleep 365d\n");
760 fclose(f);
761 /* Spawn xterm. */
762 /* Create the child. */
763 pid=fork();
764 if (pid==0)
765 {/* We are the child. */
766 char *argv[5];
767 /* Pass the control to gdb. */
768 argv[0]=(char *)mi_get_xterm_exe(); /* Is that ok? */
769 argv[1]="-e";
770 argv[2]="/bin/sh";
771 argv[3]=nsh;
772 argv[4]=0;
773 execvp(argv[0],argv);
774 /* We get here only if exec failed. */
775 unlink(nsh);
776 unlink(ntt);
777 _exit(127);
778 }
779 /* We are the parent. */
780 if (pid==-1)
781 {/* Fork failed. */
782 unlink(nsh);
783 unlink(ntt);
784 mi_error=MI_FORK;
785 return NULL;
786 }
787 /* Wait until the shell is deleted. */
788 while (stat(nsh,&st)==0)
789 usleep(1000);
790 /* Try to read the tty name. */
791 f=fopen(ntt,"rt");
792 if (f)
793 {
794 if (fgets(buf,PATH_MAX,f))
795 {
796 char *s; /* Strip the \n. */
797 for (s=buf; *s && *s!='\n'; s++);
798 *s=0;
799 res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
800 if (res)
801 {
802 res->pid=pid;
803 res->tty=strdup(buf);
804 }
805 }
806 fclose(f);
807 }
808 unlink(ntt);
809 return res;
810}
811
812void mi_free_aux_term(mi_aux_term *t)
813{
814 if (!t)
815 return;
816 free(t->tty);
817 free(t);
818}
819
820/**[txh]********************************************************************
821
822 Description:
823 Closes the auxiliar terminal and releases the allocated memory.
824
825***************************************************************************/
826
827void gmi_end_aux_term(mi_aux_term *t)
828{
829 if (!t)
830 return;
831 if (t->pid!=-1 && mi_check_running_pid(t->pid))
832 mi_kill_child(t->pid);
833 mi_free_aux_term(t);
834}
835
836/**[txh]********************************************************************
837
838 Description:
839 Forces the MI version. Currently the library can't detect it so you must
840force it manually. GDB 5.x implemented MI v1 and 6.x v2.
841
842***************************************************************************/
843
844void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
845 unsigned vMinor)
846{
847 h->version=MI_VERSION2U(vMajor,vMiddle,vMinor);
848}
849
850/**[txh]********************************************************************
851
852 Description:
853 Dis/Enables the workaround for a bug in gdb.
854
855***************************************************************************/
856
857void mi_set_workaround(unsigned wa, int enable)
858{
859 switch (wa)
860 {
861 case MI_PSYM_SEARCH:
862 disable_psym_search_workaround=enable ? 0 : 1;
863 break;
864 }
865}
866
867/**[txh]********************************************************************
868
869 Description:
870 Finds if the workaround for a bug in gdb is enabled.
871
872 Return: !=0 if enabled.
873
874***************************************************************************/
875
876int mi_get_workaround(unsigned wa)
877{
878 switch (wa)
879 {
880 case MI_PSYM_SEARCH:
881 return disable_psym_search_workaround==0;
882 }
883 return 0;
884}
885
diff --git a/pathologist/src/mi/gdbmi_data_man.c b/pathologist/src/mi/gdbmi_data_man.c
new file mode 100644
index 0000000..06e1377
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_data_man.c
@@ -0,0 +1,243 @@
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.
9
10 @<p>
11
12@<pre>
13gdb command: Implemented?
14
15-data-disassemble Yes
16-data-evaluate-expression Yes
17-data-list-changed-registers No
18-data-list-register-names Yes
19-data-list-register-values No
20-data-read-memory No
21-display-delete N.A. (delete display)
22-display-disable N.A. (disable display)
23-display-enable N.A. (enable display)
24-display-insert N.A. (display)
25-display-list N.A. (info display)
26-environment-cd No
27-environment-directory Yes, MI v1 implementation
28-environment-path No
29@</pre>
30
31Notes: @<p>
32
331) -display* aren't implemented. You can use CLI command display, but the
34results are sent to the console. So it looks like the best is to manually
35use -data-evaluate-expression to emulate it. @<p>
36
372) GDB bug mi/1770: Affects gdb<=6.2, when you ask for the names of the
38registers you get it plus the name of the "pseudo-registers", but if you
39try to get the value of a pseudo-register you get an error saying the
40register number is invalid. I reported to gdb-patches@sources.redhat.com
41on 2004/08/25 and as I didn't get any answer I filled a bug report on
422004/09/02. The patch to fix this annoying bug is:
43
44Index: gdb/mi/mi-main.c
45===================================================================
46RCS file: /cvs/src/src/gdb/mi/mi-main.c,v
47retrieving revision 1.64
48diff -u -r1.64 mi-main.c
49--- gdb/mi/mi-main.c 3 Aug 2004 00:57:27 -0000 1.64
50+++ gdb/mi/mi-main.c 25 Aug 2004 14:12:50 -0000
51@@ -423,7 +423,7 @@
52 case, some entries of REGISTER_NAME will change depending upon
53 the particular processor being debugged.
54
55- numregs = NUM_REGS;
56+ numregs = NUM_REGS + NUM_PSEUDO_REGS;
57
58 if (argc == 0)
59 {
60----
61
62Note I had to remove an end of comment in the patch to include it here.
63This bug forced me to create another set of functions. The only way is to
64first get the values and then the names.
65Fixed by Changelog entry:
66
672004-09-12 Salvador E. Tropea <set@users.sf.net>
68 Andrew Cagney <cagney@gnu.org>
69
70 * mi/mi-main.c (mi_cmd_data_list_changed_registers)
71 (mi_cmd_data_list_register_values)
72 (mi_cmd_data_write_register_values): Include the PSEUDO_REGS in
73 the register number computation.
74
75***************************************************************************/
76
77#include "gdbmi.h"
78
79/* Low level versions. */
80
81void mi_data_evaluate_expression(mi_h *h, const char *expression)
82{
83 mi_send(h,"-data-evaluate-expression \"%s\"\n",expression);
84}
85
86void mi_dir(mi_h *h, const char *path)
87{
88 if (h->version>=MI_VERSION2U(2,0,0))
89 {// MI v2
90 if (path)
91 mi_send(h,"-environment-directory \"%s\"\n",path);
92 else
93 mi_send(h,"-environment-directory -r\n");
94 }
95 else
96 {
97 mi_send(h,"-environment-directory %s\n",path ? path : "");
98 }
99}
100
101void mi_data_read_memory_hx(mi_h *h, const char *exp, unsigned ws,
102 unsigned c, int convAddr)
103{
104 if (convAddr)
105 mi_send(h,"-data-read-memory \"&%s\" x %d 1 %d\n",exp,ws,c);
106 else
107 mi_send(h,"-data-read-memory \"%s\" x %d 1 %d\n",exp,ws,c);
108}
109
110void mi_data_disassemble_se(mi_h *h, const char *start, const char *end,
111 int mode)
112{
113 mi_send(h,"-data-disassemble -s \"%s\" -e \"%s\" -- %d\n",start,end,mode);
114}
115
116void mi_data_disassemble_fl(mi_h *h, const char *file, int line, int lines,
117 int mode)
118{
119 mi_send(h,"-data-disassemble -f \"%s\" -l %d -n %d -- %d\n",file,line,lines,
120 mode);
121}
122
123void mi_data_list_register_names(mi_h *h)
124{
125 mi_send(h,"-data-list-register-names\n");
126}
127
128void mi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
129{
130 mi_send(h,"-data-list-register-names ");
131 while (l)
132 {
133 mi_send(h,"%d ",l->reg);
134 l=l->next;
135 }
136 mi_send(h,"\n");
137}
138
139void mi_data_list_changed_registers(mi_h *h)
140{
141 mi_send(h,"-data-list-changed-registers\n");
142}
143
144void mi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
145{
146 mi_send(h,"-data-list-register-values %c ",mi_format_enum_to_char(fmt));
147 while (l)
148 {
149 mi_send(h,"%d ",l->reg);
150 l=l->next;
151 }
152 mi_send(h,"\n");
153}
154
155/* High level versions. */
156
157/**[txh]********************************************************************
158
159 Description:
160 Evaluate an expression. Returns a parsed tree.
161
162 Command: -data-evaluate-expression
163 Return: The resulting value (as plain text) or NULL on error.
164
165***************************************************************************/
166
167char *gmi_data_evaluate_expression(mi_h *h, const char *expression)
168{
169 mi_data_evaluate_expression(h,expression);
170 return mi_res_value(h);
171}
172
173/**[txh]********************************************************************
174
175 Description:
176 Path for sources. You must use it to indicate where are the sources for
177the program to debug. Only the MI v1 implementation is available.
178
179 Command: -environment-directory
180 Return: !=0 OK
181
182***************************************************************************/
183
184int gmi_dir(mi_h *h, const char *path)
185{
186 mi_dir(h,path);
187 return mi_res_simple_done(h);
188}
189
190int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
191 unsigned char *dest, int *na, int convAddr,
192 unsigned long *addr)
193{
194 mi_data_read_memory_hx(h,exp,1,size,convAddr);
195 return mi_get_read_memory(h,dest,1,na,addr);
196}
197
198mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
199 const char *end, int mode)
200{
201 mi_data_disassemble_se(h,start,end,mode);
202 return mi_get_asm_insns(h);
203}
204
205mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
206 int lines, int mode)
207{
208 mi_data_disassemble_fl(h,file,line,lines,mode);
209 return mi_get_asm_insns(h);
210}
211
212// Affected by gdb bug mi/1770
213mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many)
214{
215 mi_data_list_register_names(h);
216 return mi_get_list_registers(h,how_many);
217}
218
219int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
220{
221 mi_data_list_register_names_l(h,l);
222 return mi_get_list_registers_l(h,l);
223}
224
225mi_chg_reg *gmi_data_list_changed_registers(mi_h *h)
226{
227 mi_error=MI_OK;
228 mi_data_list_changed_registers(h);
229 return mi_get_list_changed_regs(h);
230}
231
232int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
233{
234 mi_data_list_register_values(h,fmt,l);
235 return mi_get_reg_values(h,l);
236}
237
238mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many)
239{
240 mi_data_list_register_values(h,fmt,NULL);
241 return mi_get_reg_values_l(h,how_many);
242}
243
diff --git a/pathologist/src/mi/gdbmi_error.c b/pathologist/src/mi/gdbmi_error.c
new file mode 100644
index 0000000..abb20f6
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.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/pathologist/src/mi/gdbmi_get_free_pty.c b/pathologist/src/mi/gdbmi_get_free_pty.c
new file mode 100644
index 0000000..4274c78
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.h"
32
33/**[txh]********************************************************************
34
35 Description:
36 Look for a free and usable pseudo terminal. Low level, use
37 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 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/pathologist/src/mi/gdbmi_get_free_vt.c b/pathologist/src/mi/gdbmi_get_free_vt.c
new file mode 100644
index 0000000..25e5e75
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_get_free_vt.c
@@ -0,0 +1,156 @@
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 "gdbmi.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 close(console_fd);
97 return -2;
98 }
99 close(console_fd);
100
101 /* We attempt to set our euid to 0; if we were run with euid 0 to
102 * start with, we'll be able to do this now. Otherwise, we'll just
103 * ignore the error returned since it might not be a problem if the
104 * ttys we look at are owned by the user running the program. */
105 seteuid(0);
106
107 /* tty0 is not really a console, so start counting at 2. */
108 fd=-1;
109 for (tty=1, mask=2; mask; tty++, mask<<=1)
110 if (!(vts.v_state & mask))
111 {
112 snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",tty);
113 fd=open(tty_name,O_RDWR);
114 if (fd!=-1)
115 {
116 close(fd);
117 break;
118 }
119 }
120
121 seteuid(getuid());
122
123 if (!mask)
124 return -3;
125
126 return tty;
127}
128
129/**[txh]********************************************************************
130
131 Description:
132 Look for a free and usable Linux VT to be used by the child.
133
134 Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
135release it.
136
137***************************************************************************/
138
139mi_aux_term *gmi_look_for_free_vt()
140{
141 int ret;
142 int vt=mi_look_for_free_vt();
143 mi_aux_term *res;
144
145 if (vt<0)
146 return NULL;
147 res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
148 if (!res)
149 return NULL;
150 res->pid=-1;
151 ret = asprintf(&res->tty,"/dev/tty%d",vt);
152 return res;
153}
154
155#endif
156
diff --git a/pathologist/src/mi/gdbmi_misc.c b/pathologist/src/mi/gdbmi_misc.c
new file mode 100644
index 0000000..51088a7
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.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/pathologist/src/mi/gdbmi_parse.c b/pathologist/src/mi/gdbmi_parse.c
new file mode 100644
index 0000000..d30bd22
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_parse.c
@@ -0,0 +1,1927 @@
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 "gdbmi.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 mi_error = MI_PARSER;
55 return 0;
56 }
57 if (*s=='\\')
58 s++;
59 len++;
60 }
61 /* Copy. */
62 r->type=t_const;
63 d=r->v.cstr=mi_malloc(len+1);
64 if (!r->v.cstr)
65 return 0;
66 for (s=str; *s && !EndOfStr(s); s++, d++)
67 {
68 if (*s=='\\')
69 {
70 s++;
71 switch (*s)
72 {
73 case 'n':
74 *d='\n';
75 break;
76 case 't':
77 *d='\t';
78 break;
79 default:
80 *d=*s;
81 }
82 }
83 else
84 *d=*s;
85 }
86 *d=0;
87 if (end)
88 *end=s+1;
89
90 return 1;
91}
92
93/* TODO: What's a valid variable name?
94 I'll assume a-zA-Z0-9_- */
95//inline
96int mi_is_var_name_char(char c)
97{
98 return isalnum(c) || c=='-' || c=='_';
99}
100
101char *mi_get_var_name(const char *str, const char **end)
102{
103 const char *s;
104 char *r;
105 int l;
106 /* Meassure. */
107 for (s=str; *s && mi_is_var_name_char(*s); s++);
108 if (*s!='=')
109 {
110 mi_error=MI_PARSER;
111 return NULL;
112 }
113 /* Allocate. */
114 l=s-str;
115 r=mi_malloc(l+1);
116 /* Copy. */
117 if (NULL != r) {
118 memcpy(r,str,l);
119 r[l]=0;
120 }
121 if (end)
122 *end=s+1;
123 return r;
124}
125
126
127int mi_get_list_res(mi_results *r, const char *str, const char **end, char closeC)
128{
129 mi_results *last_r, *rs;
130
131 last_r=NULL;
132 do
133 {
134 rs=mi_get_result(str,&str);
135 if (last_r)
136 last_r->next=rs;
137 else
138 r->v.rs=rs;
139 last_r=rs;
140 if (*str==closeC)
141 {
142 *end=str+1;
143 return 1;
144 }
145 if (*str!=',')
146 break;
147 str++;
148 }
149 while (1);
150
151 mi_error=MI_PARSER;
152 return 0;
153}
154
155#ifdef __APPLE__
156int mi_get_tuple_val(mi_results *r, const char *str, const char **end)
157{
158 mi_results *last_r, *rs;
159
160 last_r=NULL;
161 do
162 {
163 rs=mi_alloc_results();
164 if (!rs || !mi_get_value(rs,str,&str))
165 {
166 mi_free_results(rs);
167 return 0;
168 }
169 /* Note that rs->var is NULL, that indicates that's just a value and not
170 a result. */
171 if (last_r)
172 last_r->next=rs;
173 else
174 r->v.rs=rs;
175 last_r=rs;
176 if (*str=='}')
177 {
178 *end=str+1;
179 return 1;
180 }
181 if (*str!=',')
182 break;
183 str++;
184 }
185 while (1);
186
187 mi_error=MI_PARSER;
188 return 0;
189}
190#endif /* __APPLE__ */
191
192int mi_get_tuple(mi_results *r, const char *str, const char **end)
193{
194 if (*str!='{')
195 {
196 mi_error=MI_PARSER;
197 return 0;
198 }
199 r->type=t_tuple;
200 str++;
201 if (*str=='}')
202 {/* Special case: empty tuple */
203 *end=str+1;
204 return 1;
205 }
206 #ifdef __APPLE__
207 if (mi_is_var_name_char(*str))
208 return mi_get_list_res(r,str,end,'}');
209 return mi_get_tuple_val(r,str,end);
210 #else /* __APPLE__ */
211 return mi_get_list_res(r,str,end,'}');
212 #endif /* __APPLE__ */
213}
214
215int mi_get_list_val(mi_results *r, const char *str, const char **end)
216{
217 mi_results *last_r, *rs;
218
219 last_r=NULL;
220 do
221 {
222 rs=mi_alloc_results();
223 if (!rs || !mi_get_value(rs,str,&str))
224 {
225 mi_free_results(rs);
226 return 0;
227 }
228 /* Note that rs->var is NULL, that indicates that's just a value and not
229 a result. */
230 if (last_r)
231 last_r->next=rs;
232 else
233 r->v.rs=rs;
234 last_r=rs;
235 if (*str==']')
236 {
237 *end=str+1;
238 return 1;
239 }
240 if (*str!=',')
241 break;
242 str++;
243 }
244 while (1);
245
246 mi_error=MI_PARSER;
247 return 0;
248}
249
250int mi_get_list(mi_results *r, const char *str, const char **end)
251{
252 if (*str!='[')
253 {
254 mi_error=MI_PARSER;
255 return 0;
256 }
257 r->type=t_list;
258 str++;
259 if (*str==']')
260 {/* Special case: empty list */
261 *end=str+1;
262 return 1;
263 }
264 /* Comment: I think they could choose () for values. Is confusing in this way. */
265 if (mi_is_var_name_char(*str))
266 return mi_get_list_res(r,str,end,']');
267 return mi_get_list_val(r,str,end);
268}
269
270int mi_get_value(mi_results *r, const char *str, const char **end)
271{
272 switch (str[0])
273 {
274 case '"':
275 return mi_get_cstring_r(r,str,end);
276 case '{':
277 return mi_get_tuple(r,str,end);
278 case '[':
279 return mi_get_list(r,str,end);
280 }
281 mi_error=MI_PARSER;
282 return 0;
283}
284
285mi_results *mi_get_result(const char *str, const char **end)
286{
287 char *var;
288 mi_results *r;
289
290 var=mi_get_var_name(str,&str);
291 if (!var)
292 return NULL;
293
294 r=mi_alloc_results();
295 if (!r)
296 {
297 free(var);
298 return NULL;
299 }
300 r->var=var;
301
302 if (!mi_get_value(r,str,end))
303 {
304 mi_free_results(r);
305 return NULL;
306 }
307
308 return r;
309}
310
311mi_output *mi_get_results_alone(mi_output *r,const char *str)
312{
313 mi_results *last_r, *rs;
314
315 /* * results */
316 last_r=NULL;
317 do
318 {
319 if (!*str)
320 return r;
321 if (*str!=',')
322 {
323 mi_error=MI_PARSER;
324 break;
325 }
326 str++;
327 rs=mi_get_result(str,&str);
328 if (!rs)
329 break;
330 if (!last_r)
331 r->c=rs;
332 else
333 last_r->next=rs;
334 last_r=rs;
335 }
336 while (1);
337 mi_free_output(r);
338 return NULL;
339}
340
341mi_output *mi_parse_result_record(mi_output *r,const char *str)
342{
343 r->type=MI_T_RESULT_RECORD;
344
345 /* Solve the result-class. */
346 if (strncmp(str,"done",4)==0)
347 {
348 str+=4;
349 r->tclass=MI_CL_DONE;
350 }
351 else if (strncmp(str,"running",7)==0)
352 {
353 str+=7;
354 r->tclass=MI_CL_RUNNING;
355 }
356 else if (strncmp(str,"connected",9)==0)
357 {
358 str+=9;
359 r->tclass=MI_CL_CONNECTED;
360 }
361 else if (strncmp(str,"error",5)==0)
362 {
363 str+=5;
364 r->tclass=MI_CL_ERROR;
365 }
366 else if (strncmp(str,"exit",4)==0)
367 {
368 str+=4;
369 r->tclass=MI_CL_EXIT;
370 }
371 else
372 {
373 mi_error=MI_UNKNOWN_RESULT;
374 return NULL;
375 }
376
377 return mi_get_results_alone(r,str);
378}
379
380mi_output *mi_parse_asyn(mi_output *r,const char *str)
381{
382 r->type=MI_T_OUT_OF_BAND;
383 r->stype=MI_ST_ASYNC;
384 /* async-class. */
385 if (strncmp(str,"stopped",7)==0)
386 {
387 r->tclass=MI_CL_STOPPED;
388 str+=7;
389 return mi_get_results_alone(r,str);
390 }
391 if (strncmp(str,"download",8)==0)
392 {
393 r->tclass=MI_CL_DOWNLOAD;
394 str+=8;
395 return mi_get_results_alone(r,str);
396 }
397 mi_error=MI_UNKNOWN_ASYNC;
398 mi_free_output(r);
399 return NULL;
400}
401
402mi_output *mi_parse_exec_asyn(mi_output *r,const char *str)
403{
404 r->sstype=MI_SST_EXEC;
405 return mi_parse_asyn(r,str);
406}
407
408mi_output *mi_parse_status_asyn(mi_output *r,const char *str)
409{
410 r->sstype=MI_SST_STATUS;
411 return mi_parse_asyn(r,str);
412}
413
414mi_output *mi_parse_notify_asyn(mi_output *r,const char *str)
415{
416 r->sstype=MI_SST_NOTIFY;
417 return mi_parse_asyn(r,str);
418}
419
420mi_output *mi_console(mi_output *r,const char *str)
421{
422 r->type=MI_T_OUT_OF_BAND;
423 r->stype=MI_ST_STREAM;
424 r->c=mi_alloc_results();
425 if (!r->c || !mi_get_cstring_r(r->c,str,NULL))
426 {
427 mi_free_output(r);
428 return NULL;
429 }
430 return r;
431}
432
433mi_output *mi_console_stream(mi_output *r,const char *str)
434{
435 r->sstype=MI_SST_CONSOLE;
436 return mi_console(r,str);
437}
438
439mi_output *mi_target_stream(mi_output *r,const char *str)
440{
441 r->sstype=MI_SST_TARGET;
442 return mi_console(r,str);
443}
444
445mi_output *mi_log_stream(mi_output *r,const char *str)
446{
447 r->sstype=MI_SST_LOG;
448 return mi_console(r,str);
449}
450
451mi_output *mi_parse_gdb_output(const char *str)
452{
453 char type=str[0];
454
455 mi_output *r=mi_alloc_output();
456 if (!r)
457 {
458 mi_error=MI_OUT_OF_MEMORY;
459 return NULL;
460 }
461 str++;
462 switch (type)
463 {
464 case '^':
465 return mi_parse_result_record(r,str);
466 case '*':
467 return mi_parse_exec_asyn(r,str);
468 case '+':
469 return mi_parse_status_asyn(r,str);
470 case '=':
471 return mi_parse_notify_asyn(r,str);
472 case '~':
473 return mi_console_stream(r,str);
474 case '@':
475 return mi_target_stream(r,str);
476 case '&':
477 return mi_log_stream(r,str);
478 }
479 mi_error=MI_PARSER;
480 return NULL;
481}
482
483mi_output *mi_get_rrecord(mi_output *r)
484{
485 if (!r)
486 return NULL;
487 while (r)
488 {
489 if (r->type==MI_T_RESULT_RECORD)
490 return r;
491 r=r->next;
492 }
493 return r;
494}
495
496mi_results *mi_get_var_r(mi_results *r, const char *var)
497{
498 while (r)
499 {
500 if (strcmp(r->var,var)==0)
501 return r;
502 r=r->next;
503 }
504 return NULL;
505}
506
507mi_results *mi_get_var(mi_output *res, const char *var)
508{
509 if (!res)
510 return NULL;
511 return mi_get_var_r(res->c,var);
512}
513
514int mi_get_async_stop_reason(mi_output *r, char **reason)
515{
516 int found_stopped=0;
517
518 *reason=NULL;
519 while (r)
520 {
521 if (r->type==MI_T_RESULT_RECORD && r->tclass==MI_CL_ERROR)
522 {
523 if (r->c->type==t_const)
524 *reason=r->c->v.cstr;
525 return 0;
526 }
527 if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
528 r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
529 {
530 mi_results *p=r->c;
531 found_stopped=1;
532 while (p)
533 {
534 if (strcmp(p->var,"reason")==0)
535 {
536 *reason=p->v.cstr;
537 return 1;
538 }
539 p=p->next;
540 }
541 }
542 r=r->next;
543 }
544 if (*reason==NULL && found_stopped)
545 {
546 *reason=strdup("unknown (temp bkpt?)");
547 return 1;
548 }
549 return 0;
550}
551
552mi_frames *mi_get_async_frame(mi_output *r)
553{
554 while (r)
555 {
556 if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
557 r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
558 {
559 mi_results *p=r->c;
560 while (p)
561 {
562 if (strcmp(p->var,"frame")==0)
563 return mi_parse_frame(p->v.rs);
564 p=p->next;
565 }
566 }
567 r=r->next;
568 }
569 return NULL;
570}
571
572int mi_res_simple(mi_h *h, int tclass, int accert_ret)
573{
574 mi_output *r, *res;
575 int ret=0;
576
577 r=mi_get_response_blk(h);
578 res=mi_get_rrecord(r);
579
580 if (res)
581 ret=res->tclass==tclass;
582 mi_free_output(r);
583
584 return ret;
585}
586
587
588int mi_res_simple_done(mi_h *h)
589{
590 return mi_res_simple(h,MI_CL_DONE,0);
591}
592
593int mi_res_simple_exit(mi_h *h)
594{
595 return mi_res_simple(h,MI_CL_EXIT,1);
596}
597
598int mi_res_simple_running(mi_h *h)
599{
600 return mi_res_simple(h,MI_CL_RUNNING,0);
601}
602
603int mi_res_simple_connected(mi_h *h)
604{
605 return mi_res_simple(h,MI_CL_CONNECTED,0);
606}
607
608mi_results *mi_res_var(mi_h *h, const char *var, int tclass)
609{
610 mi_output *r, *res;
611 mi_results *the_var=NULL;
612
613 r=mi_get_response_blk(h);
614 /* All the code that follows is "NULL" tolerant. */
615 /* Look for the result-record. */
616 res=mi_get_rrecord(r);
617 /* Look for the desired var. */
618 if (res && res->tclass==tclass)
619 the_var=mi_get_var(res,var);
620 /* Release all but the one we want. */
621 mi_free_output_but(r,NULL,the_var);
622 return the_var;
623}
624
625mi_results *mi_res_done_var(mi_h *h, const char *var)
626{
627 return mi_res_var(h,var,MI_CL_DONE);
628}
629
630mi_frames *mi_parse_frame(mi_results *c)
631{
632 mi_frames *res=mi_alloc_frames();
633 char *end;
634
635 if (res)
636 {
637 while (c)
638 {
639 if (c->type==t_const)
640 {
641 if (strcmp(c->var,"level")==0)
642 res->level=atoi(c->v.cstr);
643 else if (strcmp(c->var,"addr")==0)
644 res->addr=(void *)strtoul(c->v.cstr,&end,0);
645 else if (strcmp(c->var,"func")==0)
646 {
647 res->func=c->v.cstr;
648 c->v.cstr=NULL;
649 }
650 else if (strcmp(c->var,"file")==0)
651 {
652 res->file=c->v.cstr;
653 c->v.cstr=NULL;
654 }
655 else if (strcmp(c->var,"from")==0)
656 {
657 res->from=c->v.cstr;
658 c->v.cstr=NULL;
659 }
660 else if (strcmp(c->var,"line")==0)
661 res->line=atoi(c->v.cstr);
662 }
663 else if (c->type==t_list && strcmp(c->var,"args")==0)
664 {
665 res->args=c->v.rs;
666 c->v.rs=NULL;
667 }
668 c=c->next;
669 }
670 }
671 return res;
672}
673
674mi_frames *mi_res_frame(mi_h *h)
675{
676 mi_results *r=mi_res_done_var(h,"frame");
677 mi_frames *f=NULL;
678
679 if (r && r->type==t_tuple)
680 f=mi_parse_frame(r->v.rs);
681 mi_free_results(r);
682 return f;
683}
684
685mi_frames *mi_res_frames_array(mi_h *h, const char *var)
686{
687 mi_results *r=mi_res_done_var(h,var), *c;
688 mi_frames *res=NULL, *nframe, *last=NULL;
689
690 if (!r)
691 return NULL;
692#ifdef __APPLE__
693 if (r->type!=t_list && r->type!=t_tuple)
694#else
695 if (r->type!=t_list)
696#endif
697 {
698 mi_free_results(r);
699 return NULL;
700 }
701 c=r->v.rs;
702 while (c)
703 {
704 if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
705 {
706 nframe=mi_parse_frame(c->v.rs);
707 if (nframe)
708 {
709 if (!last)
710 res=nframe;
711 else
712 last->next=nframe;
713 last=nframe;
714 }
715 }
716 c=c->next;
717 }
718 mi_free_results(r);
719 return res;
720}
721
722mi_frames *mi_res_frames_list(mi_h *h)
723{
724 mi_output *r, *res;
725 mi_frames *ret=NULL, *nframe, *last=NULL;
726 mi_results *c;
727
728 r=mi_get_response_blk(h);
729 res=mi_get_rrecord(r);
730 if (res && res->tclass==MI_CL_DONE)
731 {
732 c=res->c;
733 while (c)
734 {
735 if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
736 {
737 nframe=mi_parse_frame(c->v.rs);
738 if (nframe)
739 {
740 if (!last)
741 ret=nframe;
742 else
743 last->next=nframe;
744 last=nframe;
745 }
746 }
747 c=c->next;
748 }
749 }
750 mi_free_output(r);
751 return ret;
752}
753
754int mi_get_thread_ids(mi_output *res, int **list)
755{
756 mi_results *vids, *lids;
757 int ids=-1, i;
758
759 *list=NULL;
760 vids=mi_get_var(res,"number-of-threads");
761 lids=mi_get_var(res,"thread-ids");
762 if (vids && vids->type==t_const &&
763 lids && lids->type==t_tuple)
764 {
765 ids=atoi(vids->v.cstr);
766 if (ids)
767 {
768 int *lst;
769 lst=(int *)mi_calloc(ids,sizeof(int));
770 if (lst)
771 {
772 lids=lids->v.rs;
773 i=0;
774 while (lids)
775 {
776 if (strcmp(lids->var,"thread-id")==0 && lids->type==t_const)
777 lst[i++]=atoi(lids->v.cstr);
778 lids=lids->next;
779 }
780 *list=lst;
781 }
782 else
783 ids=-1;
784 }
785 }
786 return ids;
787}
788
789int mi_res_thread_ids(mi_h *h, int **list)
790{
791 mi_output *r, *res;
792 int ids=-1;
793
794 r=mi_get_response_blk(h);
795 res=mi_get_rrecord(r);
796 if (res && res->tclass==MI_CL_DONE)
797 ids=mi_get_thread_ids(res,list);
798 mi_free_output(r);
799 return ids;
800}
801
802enum mi_gvar_lang mi_lang_str_to_enum(const char *lang)
803{
804 enum mi_gvar_lang lg=lg_unknown;
805
806 if (strcmp(lang,"C")==0)
807 lg=lg_c;
808 else if (strcmp(lang,"C++")==0)
809 lg=lg_cpp;
810 else if (strcmp(lang,"Java")==0)
811 lg=lg_java;
812
813 return lg;
814}
815
816const char *mi_lang_enum_to_str(enum mi_gvar_lang lang)
817{
818 const char *lg;
819
820 switch (lang)
821 {
822 case lg_c:
823 lg="C";
824 break;
825 case lg_cpp:
826 lg="C++";
827 break;
828 case lg_java:
829 lg="Java";
830 break;
831 /*case lg_unknown:*/
832 default:
833 lg="unknown";
834 break;
835 }
836 return lg;
837}
838
839enum mi_gvar_fmt mi_format_str_to_enum(const char *format)
840{
841 enum mi_gvar_fmt fmt=fm_natural;
842
843 if (strcmp(format,"binary")==0)
844 fmt=fm_binary;
845 else if (strcmp(format,"decimal")==0)
846 fmt=fm_decimal;
847 else if (strcmp(format,"hexadecimal")==0)
848 fmt=fm_hexadecimal;
849 else if (strcmp(format,"octal")==0)
850 fmt=fm_octal;
851
852 return fmt;
853}
854
855const char *mi_format_enum_to_str(enum mi_gvar_fmt format)
856{
857 const char *fmt;
858
859 switch (format)
860 {
861 case fm_natural:
862 fmt="natural";
863 break;
864 case fm_binary:
865 fmt="binary";
866 break;
867 case fm_decimal:
868 fmt="decimal";
869 break;
870 case fm_hexadecimal:
871 fmt="hexadecimal";
872 break;
873 case fm_octal:
874 fmt="octal";
875 break;
876 case fm_raw:
877 fmt="raw";
878 break;
879 default:
880 fmt="unknown";
881 }
882 return fmt;
883}
884
885char mi_format_enum_to_char(enum mi_gvar_fmt format)
886{
887 char fmt;
888
889 switch (format)
890 {
891 case fm_natural:
892 fmt='N';
893 break;
894 case fm_binary:
895 fmt='t';
896 break;
897 case fm_decimal:
898 fmt='d';
899 break;
900 case fm_hexadecimal:
901 fmt='x';
902 break;
903 case fm_octal:
904 fmt='o';
905 break;
906 case fm_raw:
907 fmt='r';
908 break;
909 default:
910 fmt=' ';
911 }
912 return fmt;
913}
914
915mi_gvar *mi_get_gvar(mi_output *o, mi_gvar *cur, const char *expression)
916{
917 mi_results *r;
918 mi_gvar *res=cur ? cur : mi_alloc_gvar();
919 int l;
920
921 if (!res)
922 return res;
923 r=o->c;
924 if (expression)
925 res->exp=strdup(expression);
926 while (r)
927 {
928 if (r->type==t_const)
929 {
930 if (strcmp(r->var,"name")==0)
931 {
932 free(res->name);
933 res->name=r->v.cstr;
934 r->v.cstr=NULL;
935 }
936 else if (strcmp(r->var,"numchild")==0)
937 {
938 res->numchild=atoi(r->v.cstr);
939 }
940 else if (strcmp(r->var,"type")==0)
941 {
942 free(res->type);
943 res->type=r->v.cstr;
944 r->v.cstr=NULL;
945 l=strlen(res->type);
946 if (l && res->type[l-1]=='*')
947 res->ispointer=1;
948 }
949 else if (strcmp(r->var,"lang")==0)
950 {
951 res->lang=mi_lang_str_to_enum(r->v.cstr);
952 }
953 else if (strcmp(r->var,"exp")==0)
954 {
955 free(res->exp);
956 res->exp=r->v.cstr;
957 r->v.cstr=NULL;
958 }
959 else if (strcmp(r->var,"format")==0)
960 {
961 res->format=mi_format_str_to_enum(r->v.cstr);
962 }
963 else if (strcmp(r->var,"attr")==0)
964 { /* Note: gdb 6.1.1 have only this: */
965 if (strcmp(r->v.cstr,"editable")==0)
966 res->attr=MI_ATTR_EDITABLE;
967 else /* noneditable */
968 res->attr=MI_ATTR_NONEDITABLE;
969 }
970 }
971 r=r->next;
972 }
973 return res;
974}
975
976mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression)
977{
978 mi_output *r, *res;
979 mi_gvar *gvar=NULL;
980
981 r=mi_get_response_blk(h);
982 res=mi_get_rrecord(r);
983 if (res && res->tclass==MI_CL_DONE)
984 gvar=mi_get_gvar(res,cur,expression);
985 mi_free_output(r);
986 return gvar;
987}
988
989mi_gvar_chg *mi_get_gvar_chg(mi_results *r)
990{
991 mi_gvar_chg *n;
992
993 if (r->type!=t_const)
994 return NULL;
995 n=mi_alloc_gvar_chg();
996 if (n)
997 {
998 while (r)
999 {
1000 if (r->type==t_const)
1001 {
1002 if (strcmp(r->var,"name")==0)
1003 {
1004 n->name=r->v.cstr;
1005 r->v.cstr=NULL;
1006 }
1007 else if (strcmp(r->var,"in_scope")==0)
1008 {
1009 n->in_scope=strcmp(r->v.cstr,"true")==0;
1010 }
1011 else if (strcmp(r->var,"new_type")==0)
1012 {
1013 n->new_type=r->v.cstr;
1014 r->v.cstr=NULL;
1015 }
1016 else if (strcmp(r->var,"new_num_children")==0)
1017 {
1018 n->new_num_children=atoi(r->v.cstr);
1019 }
1020 // type_changed="false" is the default
1021 }
1022 r=r->next;
1023 }
1024 }
1025 return n;
1026}
1027
1028int mi_res_changelist(mi_h *h, mi_gvar_chg **changed)
1029{
1030 mi_gvar_chg *last, *n;
1031 mi_results *res=mi_res_done_var(h,"changelist"), *r;
1032 int count=0;
1033
1034 *changed=NULL;
1035 if (!res)
1036 return 0;
1037 last=NULL;
1038 count=1;
1039 n=NULL;
1040 r=res->v.rs;
1041
1042 if (res->type==t_list)
1043 {// MI v2 a list of tuples
1044 while (r)
1045 {
1046 if (r->type==t_tuple)
1047 {
1048 n=mi_get_gvar_chg(r->v.rs);
1049 if (n)
1050 {
1051 if (last)
1052 last->next=n;
1053 else
1054 *changed=n;
1055 last=n;
1056 count++;
1057 }
1058 }
1059 r=r->next;
1060 }
1061 }
1062 else if (res->type==t_tuple)
1063 {// MI v1 a tuple with all together *8-P
1064 while (r)
1065 {
1066 if (r->type==t_const) /* Just in case. */
1067 {/* Get one var. */
1068 if (strcmp(r->var,"name")==0)
1069 {
1070 if (n)
1071 {/* Add to the list*/
1072 if (last)
1073 last->next=n;
1074 else
1075 *changed=n;
1076 last=n;
1077 count++;
1078 }
1079 n=mi_alloc_gvar_chg();
1080 if (!n)
1081 {
1082 mi_free_gvar_chg(*changed);
1083 return 0;
1084 }
1085 n->name=r->v.cstr;
1086 r->v.cstr=NULL;
1087 }
1088 else if ((NULL != n) && (strcmp(r->var,"in_scope")==0))
1089 {
1090 n->in_scope=strcmp(r->v.cstr,"true")==0;
1091 }
1092 else if ((NULL != n) && (strcmp(r->var,"new_type")==0))
1093 {
1094 n->new_type=r->v.cstr;
1095 r->v.cstr=NULL;
1096 }
1097 else if ((NULL != n) && (strcmp(r->var,"new_num_children")==0))
1098 {
1099 n->new_num_children=atoi(r->v.cstr);
1100 }
1101 // type_changed="false" is the default
1102 }
1103 r=r->next;
1104 }
1105 if (n)
1106 {/* Add to the list*/
1107 if (last)
1108 last->next=n;
1109 else
1110 *changed=n;
1111 last=n;
1112 count++;
1113 }
1114 }
1115 mi_free_results(res);
1116
1117 return count;
1118}
1119
1120int mi_get_children(mi_results *ch, mi_gvar *v)
1121{
1122 mi_gvar *cur=NULL, *aux;
1123 int i=0, count=v->numchild, l;
1124
1125 while (ch)
1126 {
1127 if (strcmp(ch->var,"child")==0 && ch->type==t_tuple && i<count)
1128 {
1129 mi_results *r=ch->v.rs;
1130 aux=mi_alloc_gvar();
1131 if (!aux)
1132 return 0;
1133 if (!v->child)
1134 v->child=aux;
1135 else if (NULL != cur)
1136 cur->next=aux;
1137 cur=aux;
1138 cur->parent=v;
1139 cur->depth=v->depth+1;
1140
1141 while (r)
1142 {
1143 if (r->type==t_const)
1144 {
1145 if (strcmp(r->var,"name")==0)
1146 {
1147 cur->name=r->v.cstr;
1148 r->v.cstr=NULL;
1149 }
1150 else if (strcmp(r->var,"exp")==0)
1151 {
1152 cur->exp=r->v.cstr;
1153 r->v.cstr=NULL;
1154 }
1155 else if (strcmp(r->var,"type")==0)
1156 {
1157 cur->type=r->v.cstr;
1158 r->v.cstr=NULL;
1159 l=strlen(cur->type);
1160 if (l && cur->type[l-1]=='*')
1161 cur->ispointer=1;
1162 }
1163 else if (strcmp(r->var,"value")==0)
1164 {
1165 cur->value=r->v.cstr;
1166 r->v.cstr=NULL;
1167 }
1168 else if (strcmp(r->var,"numchild")==0)
1169 {
1170 cur->numchild=atoi(r->v.cstr);
1171 }
1172 }
1173 r=r->next;
1174 }
1175 i++;
1176 }
1177 ch=ch->next;
1178 }
1179 v->vischild=i;
1180 v->opened=1;
1181 return i==v->numchild;
1182}
1183
1184int mi_res_children(mi_h *h, mi_gvar *v)
1185{
1186 mi_output *r, *res;
1187 int ok=0;
1188
1189 r=mi_get_response_blk(h);
1190 res=mi_get_rrecord(r);
1191 if (res && res->tclass==MI_CL_DONE)
1192 {
1193 mi_results *num=mi_get_var(res,"numchild");
1194 if (num && num->type==t_const)
1195 {
1196 v->numchild=atoi(num->v.cstr);
1197 if (v->child)
1198 {
1199 mi_free_gvar(v->child);
1200 v->child=NULL;
1201 }
1202 if (v->numchild)
1203 {
1204 mi_results *ch =mi_get_var(res,"children");
1205 if (ch && ch->type!=t_const) /* MI v1 tuple, MI v2 list */
1206 ok=mi_get_children(ch->v.rs,v);
1207 }
1208 else
1209 ok=1;
1210 }
1211 }
1212 mi_free_output(r);
1213 return ok;
1214}
1215
1216mi_bkpt *mi_get_bkpt(mi_results *p)
1217{
1218 mi_bkpt *res;
1219 char *end;
1220
1221 res=mi_alloc_bkpt();
1222 if (!res)
1223 return NULL;
1224 while (p)
1225 {
1226 if (p->type==t_const && p->var)
1227 {
1228 if (strcmp(p->var,"number")==0)
1229 res->number=atoi(p->v.cstr);
1230 else if (strcmp(p->var,"type")==0)
1231 {
1232 if (strcmp(p->v.cstr,"breakpoint")==0)
1233 res->type=t_breakpoint;
1234 else
1235 res->type=t_unknown;
1236 }
1237 else if (strcmp(p->var,"disp")==0)
1238 {
1239 if (strcmp(p->v.cstr,"keep")==0)
1240 res->disp=d_keep;
1241 else if (strcmp(p->v.cstr,"del")==0)
1242 res->disp=d_del;
1243 else
1244 res->disp=d_unknown;
1245 }
1246 else if (strcmp(p->var,"enabled")==0)
1247 res->enabled=p->v.cstr[0]=='y';
1248 else if (strcmp(p->var,"addr")==0)
1249 res->addr=(void *)strtoul(p->v.cstr,&end,0);
1250 else if (strcmp(p->var,"func")==0)
1251 {
1252 res->func=p->v.cstr;
1253 p->v.cstr=NULL;
1254 }
1255 else if (strcmp(p->var,"file")==0)
1256 {
1257 res->file=p->v.cstr;
1258 p->v.cstr=NULL;
1259 }
1260 else if (strcmp(p->var,"line")==0)
1261 res->line=atoi(p->v.cstr);
1262 else if (strcmp(p->var,"times")==0)
1263 res->times=atoi(p->v.cstr);
1264 else if (strcmp(p->var,"ignore")==0)
1265 res->ignore=atoi(p->v.cstr);
1266 else if (strcmp(p->var,"cond")==0)
1267 {
1268 res->cond=p->v.cstr;
1269 p->v.cstr=NULL;
1270 }
1271 }
1272 p=p->next;
1273 }
1274 return res;
1275}
1276
1277mi_bkpt *mi_res_bkpt(mi_h *h)
1278{
1279 mi_results *r=mi_res_done_var(h,"bkpt");
1280 mi_bkpt *b=NULL;
1281
1282 if (r && r->type==t_tuple)
1283 b=mi_get_bkpt(r->v.rs);
1284 mi_free_results(r);
1285 return b;
1286}
1287
1288mi_wp *mi_get_wp(mi_results *p, enum mi_wp_mode m)
1289{
1290 mi_wp *res=mi_alloc_wp();
1291
1292 if (res)
1293 {
1294 res->mode=m;
1295 while (p)
1296 {
1297 if (p->type==t_const && p->var)
1298 {
1299 if (strcmp(p->var,"number")==0)
1300 {
1301 res->number=atoi(p->v.cstr);
1302 res->enabled=1;
1303 }
1304 else if (strcmp(p->var,"exp")==0)
1305 {
1306 res->exp=p->v.cstr;
1307 p->v.cstr=NULL;
1308 }
1309 }
1310 p=p->next;
1311 }
1312 }
1313 return res;
1314}
1315
1316mi_wp *mi_parse_wp_res(mi_output *r)
1317{
1318 mi_results *p;
1319 enum mi_wp_mode m=wm_unknown;
1320
1321 /* The info is in a result wpt=... */
1322 p=r->c;
1323 while (p)
1324 {
1325 if (p->var)
1326 {
1327 if (strcmp(p->var,"wpt")==0)
1328 m=wm_write;
1329 else if (strcmp(p->var,"hw-rwpt")==0)
1330 m=wm_read;
1331 else if (strcmp(p->var,"hw-awpt")==0)
1332 m=wm_rw;
1333 if (m!=wm_unknown)
1334 break;
1335 }
1336 p=p->next;
1337 }
1338 if (!p || p->type!=t_tuple)
1339 return NULL;
1340 /* Scan the values inside it. */
1341 return mi_get_wp(p->v.rs,m);
1342}
1343
1344mi_wp *mi_res_wp(mi_h *h)
1345{
1346 mi_output *r, *res;
1347 mi_wp *ret=NULL;
1348
1349 r=mi_get_response_blk(h);
1350 res=mi_get_rrecord(r);
1351
1352 if (res)
1353 ret=mi_parse_wp_res(res);
1354
1355 mi_free_output(r);
1356 return ret;
1357}
1358
1359char *mi_res_value(mi_h *h)
1360{
1361 mi_results *r=mi_res_done_var(h,"value");
1362 char *s=NULL;
1363
1364 if (r && r->type==t_const)
1365 {
1366 s=r->v.cstr;
1367 r->v.rs=NULL;
1368 }
1369 mi_free_results(r);
1370 return s;
1371}
1372
1373mi_output *mi_get_stop_record(mi_output *r)
1374{
1375 while (r)
1376 {
1377 if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
1378 r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
1379 return r;
1380 r=r->next;
1381 }
1382 return r;
1383}
1384
1385static
1386char *reason_names[]=
1387{
1388 "breakpoint-hit",
1389 "watchpoint-trigger",
1390 "read-watchpoint-trigger",
1391 "access-watchpoint-trigger",
1392 "watchpoint-scope",
1393 "function-finished",
1394 "location-reached",
1395 "end-stepping-range",
1396 "exited-signalled",
1397 "exited",
1398 "exited-normally",
1399 "signal-received"
1400};
1401
1402static
1403enum mi_stop_reason reason_values[]=
1404{
1405 sr_bkpt_hit,
1406 sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
1407 sr_function_finished, sr_location_reached, sr_end_stepping_range,
1408 sr_exited_signalled, sr_exited, sr_exited_normally,
1409 sr_signal_received
1410};
1411
1412static
1413char *reason_expl[]=
1414{
1415 "Hit a breakpoint",
1416 "Write watchpoint",
1417 "Read watchpoint",
1418 "Access watchpoint",
1419 "Watchpoint out of scope",
1420 "Function finished",
1421 "Location reached",
1422 "End of stepping",
1423 "Exited signalled",
1424 "Exited with error",
1425 "Exited normally",
1426 "Signal received"
1427};
1428
1429enum mi_stop_reason mi_reason_str_to_enum(const char *s)
1430{
1431 int i;
1432
1433 for (i=0; i<sizeof(reason_names)/sizeof(char *); i++)
1434 if (strcmp(reason_names[i],s)==0)
1435 return reason_values[i];
1436 return sr_unknown;
1437}
1438
1439const char *mi_reason_enum_to_str(enum mi_stop_reason r)
1440{
1441 int i;
1442
1443 if (r==sr_unknown)
1444 return "Unknown (temp bkp?)";
1445 for (i=0; i<sizeof(reason_values)/sizeof(char *); i++)
1446 if (reason_values[i]==r)
1447 return reason_expl[i];
1448 return NULL;
1449}
1450
1451mi_stop *mi_get_stopped(mi_results *r)
1452{
1453 mi_stop *res=mi_alloc_stop();
1454
1455 if (res)
1456 {
1457 while (r)
1458 {
1459 if (r->type==t_const)
1460 {
1461 if (strcmp(r->var,"reason")==0)
1462 res->reason=mi_reason_str_to_enum(r->v.cstr);
1463 else if (!res->have_thread_id && strcmp(r->var,"thread-id")==0)
1464 {
1465 res->have_thread_id=1;
1466 res->thread_id=atoi(r->v.cstr);
1467 }
1468 else if (!res->have_bkptno && strcmp(r->var,"bkptno")==0)
1469 {
1470 res->have_bkptno=1;
1471 res->bkptno=atoi(r->v.cstr);
1472 }
1473 else if (!res->have_bkptno && strcmp(r->var,"wpnum")==0)
1474 {
1475 res->have_wpno=1;
1476 res->wpno=atoi(r->v.cstr);
1477 }
1478 else if (strcmp(r->var,"gdb-result-var")==0)
1479 {
1480 res->gdb_result_var=r->v.cstr;
1481 r->v.cstr=NULL;
1482 }
1483 else if (strcmp(r->var,"return-value")==0)
1484 {
1485 res->return_value=r->v.cstr;
1486 r->v.cstr=NULL;
1487 }
1488 else if (strcmp(r->var,"signal-name")==0)
1489 {
1490 res->signal_name=r->v.cstr;
1491 r->v.cstr=NULL;
1492 }
1493 else if (strcmp(r->var,"signal-meaning")==0)
1494 {
1495 res->signal_meaning=r->v.cstr;
1496 r->v.cstr=NULL;
1497 }
1498 else if (!res->have_exit_code && strcmp(r->var,"exit-code")==0)
1499 {
1500 res->have_exit_code=1;
1501 res->exit_code=atoi(r->v.cstr);
1502 }
1503 }
1504 else // tuple or list
1505 {
1506 if (strcmp(r->var,"frame")==0)
1507 res->frame=mi_parse_frame(r->v.rs);
1508 else if (!res->wp && strcmp(r->var,"wpt")==0)
1509 res->wp=mi_get_wp(r->v.rs,wm_write);
1510 else if (!res->wp && strcmp(r->var,"hw-rwpt")==0)
1511 res->wp=mi_get_wp(r->v.rs,wm_read);
1512 else if (!res->wp && strcmp(r->var,"hw-awpt")==0)
1513 res->wp=mi_get_wp(r->v.rs,wm_rw);
1514 else if (!(res->wp_old || res->wp_val) && strcmp(r->var,"value")==0)
1515 {
1516 mi_results *p=r->v.rs;
1517 while (p)
1518 {
1519 if (strcmp(p->var,"value")==0 || strcmp(p->var,"new")==0)
1520 {
1521 res->wp_val=p->v.cstr;
1522 p->v.cstr=NULL;
1523 }
1524 else if (strcmp(p->var,"old")==0)
1525 {
1526 res->wp_old=p->v.cstr;
1527 p->v.cstr=NULL;
1528 }
1529 p=p->next;
1530 }
1531 }
1532 }
1533 r=r->next;
1534 }
1535 }
1536 return res;
1537}
1538
1539mi_stop *mi_res_stop(mi_h *h)
1540{
1541 mi_output *o=mi_retire_response(h);
1542 mi_stop *stop=NULL;
1543
1544 if (o)
1545 {
1546 mi_output *sr=mi_get_stop_record(o);
1547 if (sr)
1548 stop=mi_get_stopped(sr->c);
1549 }
1550 mi_free_output(o);
1551
1552 return stop;
1553}
1554
1555int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
1556 unsigned long *addr)
1557{
1558 char *end;
1559 mi_results *res=mi_res_done_var(h,"memory"), *r;
1560 int ok=0;
1561
1562 *na=0;
1563 r=res;
1564 if (r && r->type==t_list && ws==1)
1565 {
1566 r=r->v.rs;
1567 if (r->type!=t_tuple)
1568 {
1569 mi_free_results(res);
1570 return 0;
1571 }
1572 r=r->v.rs;
1573 while (r)
1574 {
1575 if (r->type==t_list && strcmp(r->var,"data")==0)
1576 {
1577 mi_results *data=r->v.rs;
1578 ok++;
1579 if (data && data->type==t_const &&
1580 strcmp(data->v.cstr,"N/A")==0)
1581 *na=1;
1582 else
1583 while (data)
1584 {
1585 if (data->type==t_const)
1586 *(dest++)=strtol(data->v.cstr,&end,0);
1587 data=data->next;
1588 }
1589 }
1590 else if (r->type==t_const && strcmp(r->var,"addr")==0)
1591 {
1592 ok++;
1593 if (addr)
1594 *addr=strtoul(r->v.cstr,&end,0);
1595 }
1596 r=r->next;
1597 }
1598
1599 }
1600 mi_free_results(res);
1601 return ok==2;
1602}
1603
1604mi_asm_insn *mi_parse_insn(mi_results *c)
1605{
1606 mi_asm_insn *res=NULL, *cur=NULL;
1607 mi_results *sub;
1608 char *end;
1609
1610 while (c)
1611 {
1612 if (c->type==t_tuple)
1613 {
1614 if (!res)
1615 res=cur=mi_alloc_asm_insn();
1616 else
1617 {
1618 cur->next=mi_alloc_asm_insn();
1619 cur=cur->next;
1620 }
1621 if (!cur)
1622 {
1623 mi_free_asm_insn(res);
1624 return NULL;
1625 }
1626 sub=c->v.rs;
1627 while (sub)
1628 {
1629 if (sub->type==t_const)
1630 {
1631 if (strcmp(sub->var,"address")==0)
1632 cur->addr=(void *)strtoul(sub->v.cstr,&end,0);
1633 else if (strcmp(sub->var,"func-name")==0)
1634 {
1635 cur->func=sub->v.cstr;
1636 sub->v.cstr=NULL;
1637 }
1638 else if (strcmp(sub->var,"offset")==0)
1639 cur->offset=atoi(sub->v.cstr);
1640 else if (strcmp(sub->var,"inst")==0)
1641 {
1642 cur->inst=sub->v.cstr;
1643 sub->v.cstr=NULL;
1644 }
1645 }
1646 sub=sub->next;
1647 }
1648 }
1649 c=c->next;
1650 }
1651 return res;
1652}
1653
1654mi_asm_insns *mi_parse_insns(mi_results *c)
1655{
1656 mi_asm_insns *res=NULL, *cur=NULL;
1657 mi_results *sub;
1658
1659 while (c)
1660 {
1661 if (c->var)
1662 {
1663 if (strcmp(c->var,"src_and_asm_line")==0 && c->type==t_tuple)
1664 {
1665 if (!res)
1666 res=cur=mi_alloc_asm_insns();
1667 else
1668 {
1669 cur->next=mi_alloc_asm_insns();
1670 cur=cur->next;
1671 }
1672 if (!cur)
1673 {
1674 mi_free_asm_insns(res);
1675 return NULL;
1676 }
1677 sub=c->v.rs;
1678 while (sub)
1679 {
1680 if (sub->var)
1681 {
1682 if (sub->type==t_const)
1683 {
1684 if (strcmp(sub->var,"line")==0)
1685 cur->line=atoi(sub->v.cstr);
1686 else if (strcmp(sub->var,"file")==0)
1687 {
1688 cur->file=sub->v.cstr;
1689 sub->v.cstr=NULL;
1690 }
1691 }
1692 else if (sub->type==t_list)
1693 {
1694 if (strcmp(sub->var,"line_asm_insn")==0)
1695 cur->ins=mi_parse_insn(sub->v.rs);
1696 }
1697 }
1698 sub=sub->next;
1699 }
1700 }
1701 }
1702 else
1703 {/* No source line, just instructions */
1704 res=mi_alloc_asm_insns();
1705 res->ins=mi_parse_insn(c);
1706 break;
1707 }
1708 c=c->next;
1709 }
1710 return res;
1711}
1712
1713
1714mi_asm_insns *mi_get_asm_insns(mi_h *h)
1715{
1716 mi_results *r=mi_res_done_var(h,"asm_insns");
1717 mi_asm_insns *f=NULL;
1718
1719 if (r && r->type==t_list)
1720 f=mi_parse_insns(r->v.rs);
1721 mi_free_results(r);
1722 return f;
1723}
1724
1725mi_chg_reg *mi_parse_list_regs(mi_results *r, int *how_many)
1726{
1727 mi_results *c=r;
1728 int cregs=0;
1729 mi_chg_reg *first=NULL, *cur=NULL;
1730
1731 /* Create the list. */
1732 while (c)
1733 {
1734 if (c->type==t_const && !c->var)
1735 {
1736 if (first)
1737 cur=cur->next=mi_alloc_chg_reg();
1738 else
1739 first=cur=mi_alloc_chg_reg();
1740
1741 if (NULL != cur) {
1742 cur->name=c->v.cstr;
1743 cur->reg=cregs++;
1744 c->v.cstr=NULL;
1745 }
1746 }
1747 c=c->next;
1748 }
1749 if (how_many)
1750 *how_many=cregs;
1751
1752 return first;
1753}
1754
1755mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many)
1756{
1757 mi_results *r=mi_res_done_var(h,"register-names");
1758 mi_chg_reg *l=NULL;
1759
1760 if (r && r->type==t_list)
1761 l=mi_parse_list_regs(r->v.rs,how_many);
1762 mi_free_results(r);
1763 return l;
1764}
1765
1766mi_chg_reg *mi_parse_list_changed_regs(mi_results *r)
1767{
1768 mi_results *c=r;
1769 mi_chg_reg *first=NULL, *cur=NULL;
1770
1771 /* Create the list. */
1772 while (c)
1773 {
1774 if (c->type==t_const && !c->var)
1775 {
1776 if (first)
1777 cur=cur->next=mi_alloc_chg_reg();
1778 else
1779 first=cur=mi_alloc_chg_reg();
1780 cur->reg=atoi(c->v.cstr);
1781 }
1782 c=c->next;
1783 }
1784
1785 return first;
1786}
1787
1788mi_chg_reg *mi_get_list_changed_regs(mi_h *h)
1789{
1790 mi_results *r=mi_res_done_var(h,"changed-registers");
1791 mi_chg_reg *changed=NULL;
1792
1793 if (r && r->type==t_list)
1794 changed=mi_parse_list_changed_regs(r->v.rs);
1795 mi_free_results(r);
1796 return changed;
1797}
1798
1799int mi_parse_reg_values(mi_results *r, mi_chg_reg *l)
1800{
1801 mi_results *c;
1802
1803 while (r && l)
1804 {
1805 if (r->type==t_tuple && !r->var)
1806 {
1807 c=r->v.rs;
1808 while (c)
1809 {
1810 if (c->type==t_const && c->var)
1811 {
1812 if (strcmp(c->var,"number")==0)
1813 {
1814 if (atoi(c->v.cstr)!=l->reg)
1815 {
1816 mi_error=MI_PARSER;
1817 return 0;
1818 }
1819 }
1820 else if (strcmp(c->var,"value")==0)
1821 {
1822 l->val=c->v.cstr;
1823 c->v.cstr=NULL;
1824 }
1825 }
1826 c=c->next;
1827 }
1828 }
1829 r=r->next;
1830 l=l->next;
1831 }
1832
1833 return !l && !r;
1834}
1835
1836int mi_get_reg_values(mi_h *h, mi_chg_reg *l)
1837{
1838 mi_results *r=mi_res_done_var(h,"register-values");
1839 int ok=0;
1840
1841 if (r && r->type==t_list)
1842 ok=mi_parse_reg_values(r->v.rs,l);
1843 mi_free_results(r);
1844 return ok;
1845}
1846
1847int mi_parse_list_regs_l(mi_results *r, mi_chg_reg *l)
1848{
1849 while (r && l)
1850 {
1851 if (r->type==t_const && !r->var)
1852 {
1853 free(l->name);
1854 l->name=r->v.cstr;
1855 r->v.cstr=NULL;
1856 l=l->next;
1857 }
1858 r=r->next;
1859 }
1860
1861 return !l && !r;
1862}
1863
1864int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l)
1865{
1866 mi_results *r=mi_res_done_var(h,"register-names");
1867 int ok=0;
1868
1869 if (r && r->type==t_list)
1870 ok=mi_parse_list_regs_l(r->v.rs,l);
1871 mi_free_results(r);
1872 return ok;
1873}
1874
1875mi_chg_reg *mi_parse_reg_values_l(mi_results *r, int *how_many)
1876{
1877 mi_results *c;
1878 mi_chg_reg *first=NULL, *cur=NULL;
1879 *how_many=0;
1880
1881 while (r)
1882 {
1883 if (r->type==t_tuple && !r->var)
1884 {
1885 c=r->v.rs;
1886 if (first)
1887 cur=cur->next=mi_alloc_chg_reg();
1888 else
1889 first=cur=mi_alloc_chg_reg();
1890 while (c)
1891 {
1892 if (c->type==t_const && c->var)
1893 {
1894 if (strcmp(c->var,"number")==0)
1895 {
1896 if (NULL != cur)
1897 cur->reg=atoi(c->v.cstr);
1898 (*how_many)++;
1899 }
1900 else if (strcmp(c->var,"value")==0)
1901 {
1902 if (NULL != cur)
1903 cur->val=c->v.cstr;
1904 c->v.cstr=NULL;
1905 }
1906 }
1907 c=c->next;
1908 }
1909 }
1910 r=r->next;
1911 }
1912
1913 return first;
1914}
1915
1916mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many)
1917{
1918 mi_results *r=mi_res_done_var(h,"register-values");
1919 mi_chg_reg *rgs=NULL;
1920
1921 if (r && r->type==t_list)
1922 rgs=mi_parse_reg_values_l(r->v.rs,how_many);
1923 mi_free_results(r);
1924 return rgs;
1925}
1926
1927
diff --git a/pathologist/src/mi/gdbmi_prg_control.c b/pathologist/src/mi/gdbmi_prg_control.c
new file mode 100644
index 0000000..80ac7af
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_prg_control.c
@@ -0,0 +1,598 @@
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 "gdbmi.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_set_unwind_on_signal_on(mi_h *h)
76{
77 mi_send(h, "set unwindonsignal on\n");
78}
79
80void mi_exec_arguments(mi_h *h, const char *args)
81{
82 mi_send(h,"-exec-arguments %s\n",args);
83}
84
85void mi_exec_run(mi_h *h)
86{
87 mi_send(h,"-exec-run\n");
88}
89
90void mi_exec_continue(mi_h *h)
91{
92 mi_send(h,"-exec-continue\n");
93}
94
95void mi_exec_continue_reverse(mi_h *h)
96{
97 mi_send(h, "-exec-continue --reverse\n");
98}
99
100void mi_target_terminal(mi_h *h, const char *tty_name)
101{
102 mi_send(h,"tty %s\n",tty_name);
103}
104
105void mi_file_symbol_file(mi_h *h, const char *file)
106{
107 if (mi_get_workaround(MI_PSYM_SEARCH))
108 mi_send(h,"symbol-file %s -readnow\n",file);
109 else
110 mi_send(h,"-file-symbol-file %s\n",file);
111}
112
113void mi_exec_finish(mi_h *h)
114{
115 mi_send(h,"-exec-finish\n");
116}
117
118void mi_exec_finish_reverse(mi_h * h)
119{
120 mi_send(h, "-exec-finish --reverse\n");
121}
122void mi_exec_interrupt(mi_h *h)
123{
124 mi_send(h,"-exec-interrupt\n");
125}
126
127void mi_exec_record_process(mi_h *h)
128{
129mi_send(h, "-interpreter-exec mi record\n");
130}
131
132void mi_exec_record_stop(mi_h *h)
133{
134mi_send(h, "-interpreter-exec mi record stop\n");
135}
136
137void mi_exec_next(mi_h *h, int count)
138{
139 if (count>1)
140 mi_send(h,"-exec-next %d\n",count);
141 else
142 mi_send(h,"-exec-next\n");
143}
144
145void mi_exec_next_instruction(mi_h *h)
146{
147 mi_send(h,"-exec-next-instruction\n");
148}
149
150void mi_exec_step(mi_h *h, int count)
151{
152 if (count>1)
153 mi_send(h,"-exec-step %d\n",count);
154 else
155 mi_send(h,"-exec-step\n");
156}
157
158
159void mi_exec_step_back(mi_h *h, int count)
160{
161 if (count>1)
162 mi_send(h, "-exec-step %d --reverse\n", count);
163 else
164 mi_send(h, "-exec-step --reverse\n");
165}
166
167
168void mi_exec_next_reverse(mi_h *h, int count)
169{
170 if (count>1)
171 mi_send(h, "-exec-next %d --reverse\n", count);
172 else
173 mi_send(h, "-exec-next --reverse\n");
174}
175
176
177void mi_exec_step_instruction(mi_h *h)
178{
179 mi_send(h,"-exec-step-instruction\n");
180}
181
182void mi_exec_until(mi_h *h, const char *file, int line)
183{
184 if (!file)
185 mi_send(h,"-exec-until\n");
186 else
187 mi_send(h,"-exec-until %s:%d\n",file,line);
188}
189
190void mi_exec_until_addr(mi_h *h, void *addr)
191{
192 mi_send(h,"-exec-until *%p\n",addr);
193}
194
195void mi_exec_return(mi_h *h)
196{
197 mi_send(h,"-exec-return\n");
198}
199
200void mi_exec_kill(mi_h *h)
201{
202 mi_send(h,"kill\n");
203}
204
205/* High level versions. */
206
207/**[txh]********************************************************************
208
209 Description:
210 Specify the executable and arguments for local debug.
211
212 Command: -file-exec-and-symbols + -exec-arguments
213 Return: !=0 OK
214
215***************************************************************************/
216
217int gmi_set_exec(mi_h *h, const char *file, const char *args)
218{
219 mi_file_exec_and_symbols(h,file);
220 if (!mi_res_simple_done(h))
221 return 0;
222 if (!args)
223 return 1;
224 mi_exec_arguments(h,args);
225 return mi_res_simple_done(h);
226}
227
228int gmi_set_unwind_on_signal_on(mi_h * h)
229{
230 mi_set_unwind_on_signal_on(h);
231 return mi_res_simple_running(h);
232}
233
234/**[txh]********************************************************************
235
236 Description:
237 Start running the executable. Remote sessions starts running.
238
239 Command: -exec-run
240 Return: !=0 OK
241
242***************************************************************************/
243
244int gmi_exec_run(mi_h *h)
245{
246 mi_exec_run(h);
247 return mi_res_simple_running(h);
248}
249
250/**[txh]********************************************************************
251
252 Description:
253 Continue the execution after a "stop".
254
255 Command: -exec-continue
256 Return: !=0 OK
257
258***************************************************************************/
259
260int gmi_exec_continue(mi_h *h)
261{
262 mi_exec_continue(h);
263 return mi_res_simple_running(h);
264}
265
266/**[txh]********************************************************************
267
268 Description:
269 Continue the execution in reverse order after a "stop".
270
271 Command: -exec-continue --reverse
272 Return: !=0 OK
273
274***************************************************************************/
275int gmi_exec_continue_reverse(mi_h *h)
276{
277 mi_exec_continue_reverse(h);
278 return mi_res_simple_running(h);
279}
280
281/**[txh]********************************************************************
282
283 Description:
284 Indicate which terminal will use the target program. For local sessions.
285
286 Command: tty
287 Return: !=0 OK
288 Example:
289
290***************************************************************************/
291
292int gmi_target_terminal(mi_h *h, const char *tty_name)
293{
294 mi_target_terminal(h,tty_name);
295 return mi_res_simple_done(h);
296}
297
298/**[txh]********************************************************************
299
300 Description:
301 Specify what's the local copy that have debug info. For remote sessions.
302
303 Command: -file-symbol-file
304 Return: !=0 OK
305
306***************************************************************************/
307
308int gmi_file_symbol_file(mi_h *h, const char *file)
309{
310 mi_file_symbol_file(h,file);
311 return mi_res_simple_done(h);
312}
313
314/**[txh]********************************************************************
315
316 Description:
317 Continue until function return, the return value is included in the async
318response.
319
320 Command: -exec-finish
321 Return: !=0 OK.
322
323***************************************************************************/
324
325int gmi_exec_finish(mi_h *h)
326{
327 mi_exec_finish(h);
328 return mi_res_simple_running(h);
329}
330
331/**[txh]********************************************************************
332
333 Description:
334 Continue backwardly until function return, the return value is included in
335 the async response.
336
337 Command: -exec-finish --reverse
338 Return: !=0 OK.
339
340***************************************************************************/
341int gmi_exec_finish_reverse(mi_h *h)
342{
343 mi_exec_finish_reverse(h);
344 return mi_res_simple_running(h);
345}
346
347/**[txh]********************************************************************
348
349 Description:
350 Stop the program using SIGINT. The corresponding command should be
351-exec-interrupt but not even gdb 6.1.1 can do it because the "async" mode
352isn't really working.
353
354 Command: -exec-interrupt [replacement]
355 Return: Always 1
356 Example:
357
358***************************************************************************/
359
360int gmi_exec_interrupt(mi_h *h)
361{
362 // **** IMPORTANT!!! **** Not even gdb 6.1.1 can do it because the "async"
363 // mode isn't really working.
364 //mi_exec_interrupt(h);
365 //return mi_res_simple_running(h);
366
367 kill(h->pid,SIGINT);
368 return 1; // How can I know?
369}
370
371/**[txh]********************************************************************
372
373 Description:
374 Next line of code.
375
376 Command: -exec-next
377 Return: !=0 OK
378
379***************************************************************************/
380
381int gmi_exec_next(mi_h *h)
382{
383 mi_exec_next(h,1);
384 return mi_res_simple_running(h);
385}
386
387/**[txh]********************************************************************
388
389 Description:
390 Start recording a process
391
392 Command: -interpreter-exec mi record
393 Return: !=0 OK
394
395***************************************************************************/
396int gmi_exec_record_process(mi_h *h)
397{
398 mi_exec_record_process(h);
399 return 1;
400}
401
402/**[txh]********************************************************************
403
404 Description:
405 Start recording a process
406
407 Command: -interpreter-exec mi record stop
408 Return: !=0 OK
409
410***************************************************************************/
411int gmi_exec_record_stop(mi_h *h)
412{
413 mi_exec_record_stop(h);
414 return 1;
415}
416
417/**[txh]********************************************************************
418
419 Description:
420 Skip count lines of code.
421
422 Command: -exec-next count
423 Return: !=0 OK
424
425***************************************************************************/
426
427int gmi_exec_next_cnt(mi_h *h, int count)
428{
429 mi_exec_next(h,count);
430 return mi_res_simple_running(h);
431}
432
433/**[txh]********************************************************************
434
435 Description:
436 Next line of assembler code.
437
438 Command: -exec-next-instruction
439 Return: !=0 OK
440
441***************************************************************************/
442
443int gmi_exec_next_instruction(mi_h *h)
444{
445 mi_exec_next_instruction(h);
446 return mi_res_simple_running(h);
447}
448
449/**[txh]********************************************************************
450
451 Description:
452 Next line of code. Get inside functions.
453
454 Command: -exec-step
455 Return: !=0 OK
456
457***************************************************************************/
458
459int gmi_exec_step(mi_h *h)
460{
461 mi_exec_step(h,1);
462 return mi_res_simple_running(h);
463}
464
465
466
467/**[txh]********************************************************************
468
469 Description:
470 Previous line of code. Get inside functions.
471
472 Command: -exec-step --reverse
473 Return: !=0 OK
474
475***************************************************************************/
476int gmi_exec_step_back(mi_h *h)
477{
478 mi_exec_step_back(h,1);
479 return mi_res_simple_running(h);
480}
481
482
483/**[txh]********************************************************************
484
485 Description:
486 Previous line of code (do not step into).
487
488 Command: -exec-next --reverse
489 Return: !=0 OK
490
491***************************************************************************/
492int gmi_exec_next_reverse(mi_h *h)
493{
494 mi_exec_next_reverse(h,1);
495 return mi_res_simple_running(h);
496}
497
498
499/**[txh]********************************************************************
500
501 Description:
502 Next count lines of code. Get inside functions.
503
504 Command: -exec-step count
505 Return: !=0 OK
506
507***************************************************************************/
508
509int gmi_exec_step_cnt(mi_h *h, int count)
510{
511 mi_exec_step(h,count);
512 return mi_res_simple_running(h);
513}
514
515/**[txh]********************************************************************
516
517 Description:
518 Next line of assembler code. Get inside calls.
519
520 Command: -exec-step-instruction
521 Return: !=0 OK
522
523***************************************************************************/
524
525int gmi_exec_step_instruction(mi_h *h)
526{
527 mi_exec_step_instruction(h);
528 return mi_res_simple_running(h);
529}
530
531/**[txh]********************************************************************
532
533 Description:
534 Execute until location is reached. If file is NULL then is until next
535line.
536
537 Command: -exec-until
538 Return: !=0 OK
539
540***************************************************************************/
541
542int gmi_exec_until(mi_h *h, const char *file, int line)
543{
544 mi_exec_until(h,file,line);
545 return mi_res_simple_running(h);
546}
547
548/**[txh]********************************************************************
549
550 Description:
551 Execute until location is reached.
552
553 Command: -exec-until (using *address)
554 Return: !=0 OK
555
556***************************************************************************/
557
558int gmi_exec_until_addr(mi_h *h, void *addr)
559{
560 mi_exec_until_addr(h,addr);
561 return mi_res_simple_running(h);
562}
563
564/**[txh]********************************************************************
565
566 Description:
567 Return to previous frame inmediatly.
568
569 Command: -exec-return
570 Return: A pointer to a new mi_frames structure indicating the current
571location. NULL on error.
572
573***************************************************************************/
574
575mi_frames *gmi_exec_return(mi_h *h)
576{
577 mi_exec_return(h);
578 return mi_res_frame(h);
579}
580
581/**[txh]********************************************************************
582
583 Description:
584 Just kill the program. That's what -exec-abort should do, but it isn't
585implemented by gdb. This implementation only works if the interactive mode
586is disabled (gmi_gdb_set("confirm","off")).
587
588 Command: -exec-abort [using kill]
589 Return: !=0 OK
590
591***************************************************************************/
592
593int gmi_exec_kill(mi_h *h)
594{
595 mi_exec_kill(h);
596 return mi_res_simple_done(h);
597}
598
diff --git a/pathologist/src/mi/gdbmi_stack_man.c b/pathologist/src/mi/gdbmi_stack_man.c
new file mode 100644
index 0000000..977ea5e
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.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 from
88 - 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 level and 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 level and args filled. Only for the
121frames in the from - 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/pathologist/src/mi/gdbmi_symbol_query.c b/pathologist/src/mi/gdbmi_symbol_query.c
new file mode 100644
index 0000000..8910517
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.h"
32
diff --git a/pathologist/src/mi/gdbmi_target_man.c b/pathologist/src/mi/gdbmi_target_man.c
new file mode 100644
index 0000000..bbb2b98
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.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/pathologist/src/mi/gdbmi_thread.c b/pathologist/src/mi/gdbmi_thread.c
new file mode 100644
index 0000000..b8fa63d
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_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 "gdbmi.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/pathologist/src/mi/gdbmi_var_obj.c b/pathologist/src/mi/gdbmi_var_obj.c
new file mode 100644
index 0000000..435feec
--- /dev/null
+++ b/pathologist/src/mi/gdbmi_var_obj.c
@@ -0,0 +1,371 @@
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.
9 @<p>
10
11@<pre>
12gdb command: Imp? Description:
13-var-create Yes create a variable object
14-var-delete Yes delete the variable object and its children
15-var-set-format Yes set the display format of this variable
16-var-show-format Yes show the display format of this variable
17-var-info-num-children Yes tells how many children this object has
18-var-list-children Yes* return a list of the object's children
19-var-info-type Yes show the type of this variable object
20-var-info-expression Yes print what this variable object represents
21-var-show-attributes Yes is this variable editable?
22-var-evaluate-expression Yes get the value of this variable
23-var-assign Yes set the value of this variable
24-var-update Yes* update the variable and its children
25@</pre>
26
27Notes: @<p>
281) I suggest letting gdb to choose the names for the variables.@*
292) -var-list-children supports an optional "show values" argument in MI v2.
30It isn't implemented.@*
31
32 @<p>
33
34* MI v1 and v2 result formats supported. @<p>
35
36***************************************************************************/
37
38#include "gdbmi.h"
39
40/* Low level versions. */
41
42void mi_var_create(mi_h *h, const char *name, int frame, const char *exp)
43{
44 const char *n=name ? name : "-";
45
46 if (frame<0)
47 mi_send(h,"-var-create %s * %s\n",n,exp);
48 else
49 mi_send(h,"-var-create %s %d %s\n",n,frame,exp);
50}
51
52void mi_var_delete(mi_h *h, const char *name)
53{
54 mi_send(h,"-var-delete %s\n",name);
55}
56
57void mi_var_set_format(mi_h *h, const char *name, const char *format)
58{
59 mi_send(h,"-var-set-format \"%s\" %s\n",name,format);
60}
61
62void mi_var_show_format(mi_h *h, const char *name)
63{
64 mi_send(h,"-var-show-format \"%s\"\n",name);
65}
66
67void mi_var_info_num_children(mi_h *h, const char *name)
68{
69 mi_send(h,"-var-info-num-children \"%s\"\n",name);
70}
71
72void mi_var_info_type(mi_h *h, const char *name)
73{
74 mi_send(h,"-var-info-type \"%s\"\n",name);
75}
76
77void mi_var_info_expression(mi_h *h, const char *name)
78{
79 mi_send(h,"-var-info-expression \"%s\"\n",name);
80}
81
82void mi_var_show_attributes(mi_h *h, const char *name)
83{
84 mi_send(h,"-var-show-attributes \"%s\"\n",name);
85}
86
87void mi_var_update(mi_h *h, const char *name)
88{
89 if (name)
90 mi_send(h,"-var-update %s\n",name);
91 else
92 mi_send(h,"-var-update *\n");
93}
94
95void mi_var_assign(mi_h *h, const char *name, const char *expression)
96{
97 mi_send(h,"-var-assign \"%s\" \"%s\"\n",name,expression);
98}
99
100void mi_var_evaluate_expression(mi_h *h, const char *name)
101{
102 mi_send(h,"-var-evaluate-expression \"%s\"\n",name);
103}
104
105void mi_var_list_children(mi_h *h, const char *name)
106{
107 if (h->version>=MI_VERSION2U(2,0,0))
108 mi_send(h,"-var-list-children --all-values \"%s\"\n",name);
109 else
110 mi_send(h,"-var-list-children \"%s\"\n",name);
111}
112
113/* High level versions. */
114
115/**[txh]********************************************************************
116
117 Description:
118 Create a variable object. I recommend using gmi_var_create and letting
119gdb choose the names.
120
121 Command: -var-create
122 Return: A new mi_gvar strcture or NULL on error.
123
124***************************************************************************/
125
126mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp)
127{
128 mi_var_create(h,name,frame,exp);
129 return mi_res_gvar(h,NULL,exp);
130}
131
132/**[txh]********************************************************************
133
134 Description:
135 Create a variable object. The name is selected by gdb. Alternative:
136 gmi_full_var_create.
137
138 Command: -var-create [auto name]
139 Return: A new mi_gvar strcture or NULL on error.
140
141***************************************************************************/
142
143mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp)
144{
145 return gmi_var_create_nm(h,NULL,frame,exp);
146}
147
148/**[txh]********************************************************************
149
150 Description:
151 Delete a variable object. Doesn't free the mi_gvar data.
152
153 Command: -var-delete
154 Return: !=0 OK
155
156***************************************************************************/
157
158int gmi_var_delete(mi_h *h, mi_gvar *var)
159{
160 mi_var_delete(h,var->name);
161 return mi_res_simple_done(h);
162}
163
164/**[txh]********************************************************************
165
166 Description:
167 Set the format used to represent the result.
168
169 Command: -var-set-format
170 Return: !=0 OK
171
172***************************************************************************/
173
174int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format)
175{
176 int ret;
177
178 mi_var_set_format(h,var->name,mi_format_enum_to_str(format));
179 ret=mi_res_simple_done(h);
180 if (ret)
181 var->format=format;
182 return ret;
183}
184
185/**[txh]********************************************************************
186
187 Description:
188 Fill the format field with info from gdb.
189
190 Command: -var-show-format
191 Return: !=0 OK.
192
193***************************************************************************/
194
195int gmi_var_show_format(mi_h *h, mi_gvar *var)
196{
197 mi_var_show_format(h,var->name);
198 return mi_res_gvar(h,var,NULL)!=NULL;
199}
200
201/**[txh]********************************************************************
202
203 Description:
204 Fill the numchild field with info from gdb.
205
206 Command: -var-info-num-children
207 Return: !=0 OK
208
209***************************************************************************/
210
211int gmi_var_info_num_children(mi_h *h, mi_gvar *var)
212{
213 mi_var_info_num_children(h,var->name);
214 return mi_res_gvar(h,var,NULL)!=NULL;
215}
216
217/**[txh]********************************************************************
218
219 Description:
220 Fill the type field with info from gdb.
221
222 Command: -var-info-type
223 Return: !=0 OK
224
225***************************************************************************/
226
227int gmi_var_info_type(mi_h *h, mi_gvar *var)
228{
229 mi_var_info_type(h,var->name);
230 return mi_res_gvar(h,var,NULL)!=NULL;
231}
232
233/**[txh]********************************************************************
234
235 Description:
236 Fill the expression and lang fields with info from gdb. Note that lang
237isn't filled during creation.
238
239 Command: -var-info-expression
240 Return: !=0 OK
241
242***************************************************************************/
243
244int gmi_var_info_expression(mi_h *h, mi_gvar *var)
245{
246 mi_var_info_expression(h,var->name);
247 return mi_res_gvar(h,var,NULL)!=NULL;
248}
249
250
251/**[txh]********************************************************************
252
253 Description:
254 Fill the attr field with info from gdb. Note that attr isn't filled
255during creation.
256
257 Command: -var-show-attributes
258 Return: !=0 OK
259
260***************************************************************************/
261
262int gmi_var_show_attributes(mi_h *h, mi_gvar *var)
263{
264 mi_var_show_attributes(h,var->name);
265 return mi_res_gvar(h,var,NULL)!=NULL;
266}
267
268/**[txh]********************************************************************
269
270 Description:
271 Create the variable and also fill the lang and attr fields. The name is
272selected by gdb.
273
274 Command: -var-create + -var-info-expression + -var-show-attributes
275 Return: A new mi_gvar strcture or NULL on error.
276
277***************************************************************************/
278
279mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp)
280{
281 mi_gvar *var=gmi_var_create_nm(h,NULL,frame,exp);
282 if (var)
283 {/* What if it fails? */
284 gmi_var_info_expression(h,var);
285 gmi_var_show_attributes(h,var);
286 }
287 return var;
288}
289
290/**[txh]********************************************************************
291
292 Description:
293 Update variable. Use NULL for all. Note that *changed can be NULL if none
294updated.
295
296 Command: -var-update
297 Return: !=0 OK. The changed list contains the list of changed vars.
298
299***************************************************************************/
300
301int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed)
302{
303 mi_var_update(h,var ? var->name : NULL);
304 return mi_res_changelist(h,changed);
305}
306
307/**[txh]********************************************************************
308
309 Description:
310 Change variable. The new value replaces the value field.
311
312 Command: -var-assign
313 Return: !=0 OK
314
315***************************************************************************/
316
317int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression)
318{
319 char *res;
320 mi_var_assign(h,var->name,expression);
321 res=mi_res_value(h);
322 if (res)
323 {
324 free(var->value);
325 var->value=res;
326 return 1;
327 }
328 return 0;
329}
330
331/**[txh]********************************************************************
332
333 Description:
334 Fill the value field getting the current value for a variable.
335
336 Command: -var-evaluate-expression
337 Return: !=0 OK, value contains the result.
338
339***************************************************************************/
340
341int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var)
342{
343 char *s;
344
345 mi_var_evaluate_expression(h,var->name);
346 s=mi_res_value(h);
347 if (s)
348 {
349 free(var->value);
350 var->value=s;
351 }
352 return s!=NULL;
353}
354
355/**[txh]********************************************************************
356
357 Description:
358 List children. It ONLY returns the first level information. :-(@*
359 On success the child field contains the list of children.
360
361 Command: -var-list-children
362 Return: !=0 OK
363
364***************************************************************************/
365
366int gmi_var_list_children(mi_h *h, mi_gvar *var)
367{
368 mi_var_list_children(h,var->name);
369 return mi_res_children(h,var);
370}
371