diff options
Diffstat (limited to 'src/monkey/parse.c')
-rw-r--r-- | src/monkey/parse.c | 1923 |
1 files changed, 1923 insertions, 0 deletions
diff --git a/src/monkey/parse.c b/src/monkey/parse.c new file mode 100644 index 000000000..0dea6cb5d --- /dev/null +++ b/src/monkey/parse.c | |||
@@ -0,0 +1,1923 @@ | |||
1 | /**[txh]******************************************************************** | ||
2 | |||
3 | Copyright (c) 2004-2007 by Salvador E. Tropea. | ||
4 | Covered by the GPL license. | ||
5 | |||
6 | Module: Parser. | ||
7 | Comments: | ||
8 | Parses the output of gdb. It basically converts the text from gdb into a | ||
9 | tree (could be a complex one) that we can easily interpret using C code. | ||
10 | |||
11 | ***************************************************************************/ | ||
12 | |||
13 | #include <ctype.h> | ||
14 | #include <string.h> | ||
15 | #include <assert.h> | ||
16 | #include "mi_gdb.h" | ||
17 | |||
18 | mi_results *mi_get_result(const char *str, const char **end); | ||
19 | int 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""" | ||
24 | Afects gdb 2002-04-01-cvs and 6.1.1 for sure. | ||
25 | That's an heuristical workaround. | ||
26 | */ | ||
27 | static inline | ||
28 | int EndOfStr(const char *s) | ||
29 | { | ||
30 | if (*s=='"') | ||
31 | { | ||
32 | s++; | ||
33 | return !*s || *s==',' || *s==']' || *s=='}'; | ||
34 | } | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | int mi_get_cstring_r(mi_results *r, const char *str, const char **end) | ||
39 | { | ||
40 | const char *s; | ||
41 | char *d; | ||
42 | int len; | ||
43 | |||
44 | if (*str!='"') | ||
45 | { | ||
46 | mi_error=MI_PARSER; | ||
47 | return 0; | ||
48 | } | ||
49 | str++; | ||
50 | /* Meassure. */ | ||
51 | for (s=str, len=0; *s && !EndOfStr(s); s++) | ||
52 | { | ||
53 | if (*s=='\\') | ||
54 | { | ||
55 | if (!*s) | ||
56 | { | ||
57 | mi_error=MI_PARSER; | ||
58 | return 0; | ||
59 | } | ||
60 | s++; | ||
61 | } | ||
62 | len++; | ||
63 | } | ||
64 | /* Copy. */ | ||
65 | r->type=t_const; | ||
66 | d=r->v.cstr=mi_malloc(len+1); | ||
67 | if (!r->v.cstr) | ||
68 | return 0; | ||
69 | for (s=str; *s && !EndOfStr(s); s++, d++) | ||
70 | { | ||
71 | if (*s=='\\') | ||
72 | { | ||
73 | s++; | ||
74 | switch (*s) | ||
75 | { | ||
76 | case 'n': | ||
77 | *d='\n'; | ||
78 | break; | ||
79 | case 't': | ||
80 | *d='\t'; | ||
81 | break; | ||
82 | default: | ||
83 | *d=*s; | ||
84 | } | ||
85 | } | ||
86 | else | ||
87 | *d=*s; | ||
88 | } | ||
89 | *d=0; | ||
90 | if (end) | ||
91 | *end=s+1; | ||
92 | |||
93 | return 1; | ||
94 | } | ||
95 | |||
96 | /* TODO: What's a valid variable name? | ||
97 | I'll assume a-zA-Z0-9_- */ | ||
98 | inline | ||
99 | int mi_is_var_name_char(char c) | ||
100 | { | ||
101 | return isalnum(c) || c=='-' || c=='_'; | ||
102 | } | ||
103 | |||
104 | char *mi_get_var_name(const char *str, const char **end) | ||
105 | { | ||
106 | const char *s; | ||
107 | char *r; | ||
108 | int l; | ||
109 | /* Meassure. */ | ||
110 | for (s=str; *s && mi_is_var_name_char(*s); s++); | ||
111 | if (*s!='=') | ||
112 | { | ||
113 | mi_error=MI_PARSER; | ||
114 | return NULL; | ||
115 | } | ||
116 | /* Allocate. */ | ||
117 | l=s-str; | ||
118 | r=mi_malloc(l+1); | ||
119 | /* Copy. */ | ||
120 | memcpy(r,str,l); | ||
121 | r[l]=0; | ||
122 | if (end) | ||
123 | *end=s+1; | ||
124 | return r; | ||
125 | } | ||
126 | |||
127 | |||
128 | int mi_get_list_res(mi_results *r, const char *str, const char **end, char closeC) | ||
129 | { | ||
130 | mi_results *last_r, *rs; | ||
131 | |||
132 | last_r=NULL; | ||
133 | do | ||
134 | { | ||
135 | rs=mi_get_result(str,&str); | ||
136 | if (last_r) | ||
137 | last_r->next=rs; | ||
138 | else | ||
139 | r->v.rs=rs; | ||
140 | last_r=rs; | ||
141 | if (*str==closeC) | ||
142 | { | ||
143 | *end=str+1; | ||
144 | return 1; | ||
145 | } | ||
146 | if (*str!=',') | ||
147 | break; | ||
148 | str++; | ||
149 | } | ||
150 | while (1); | ||
151 | |||
152 | mi_error=MI_PARSER; | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | #ifdef __APPLE__ | ||
157 | int mi_get_tuple_val(mi_results *r, const char *str, const char **end) | ||
158 | { | ||
159 | mi_results *last_r, *rs; | ||
160 | |||
161 | last_r=NULL; | ||
162 | do | ||
163 | { | ||
164 | rs=mi_alloc_results(); | ||
165 | if (!rs || !mi_get_value(rs,str,&str)) | ||
166 | { | ||
167 | mi_free_results(rs); | ||
168 | return 0; | ||
169 | } | ||
170 | /* Note that rs->var is NULL, that indicates that's just a value and not | ||
171 | a result. */ | ||
172 | if (last_r) | ||
173 | last_r->next=rs; | ||
174 | else | ||
175 | r->v.rs=rs; | ||
176 | last_r=rs; | ||
177 | if (*str=='}') | ||
178 | { | ||
179 | *end=str+1; | ||
180 | return 1; | ||
181 | } | ||
182 | if (*str!=',') | ||
183 | break; | ||
184 | str++; | ||
185 | } | ||
186 | while (1); | ||
187 | |||
188 | mi_error=MI_PARSER; | ||
189 | return 0; | ||
190 | } | ||
191 | #endif /* __APPLE__ */ | ||
192 | |||
193 | int mi_get_tuple(mi_results *r, const char *str, const char **end) | ||
194 | { | ||
195 | if (*str!='{') | ||
196 | { | ||
197 | mi_error=MI_PARSER; | ||
198 | return 0; | ||
199 | } | ||
200 | r->type=t_tuple; | ||
201 | str++; | ||
202 | if (*str=='}') | ||
203 | {/* Special case: empty tuple */ | ||
204 | *end=str+1; | ||
205 | return 1; | ||
206 | } | ||
207 | #ifdef __APPLE__ | ||
208 | if (mi_is_var_name_char(*str)) | ||
209 | return mi_get_list_res(r,str,end,'}'); | ||
210 | return mi_get_tuple_val(r,str,end); | ||
211 | #else /* __APPLE__ */ | ||
212 | return mi_get_list_res(r,str,end,'}'); | ||
213 | #endif /* __APPLE__ */ | ||
214 | } | ||
215 | |||
216 | int mi_get_list_val(mi_results *r, const char *str, const char **end) | ||
217 | { | ||
218 | mi_results *last_r, *rs; | ||
219 | |||
220 | last_r=NULL; | ||
221 | do | ||
222 | { | ||
223 | rs=mi_alloc_results(); | ||
224 | if (!rs || !mi_get_value(rs,str,&str)) | ||
225 | { | ||
226 | mi_free_results(rs); | ||
227 | return 0; | ||
228 | } | ||
229 | /* Note that rs->var is NULL, that indicates that's just a value and not | ||
230 | a result. */ | ||
231 | if (last_r) | ||
232 | last_r->next=rs; | ||
233 | else | ||
234 | r->v.rs=rs; | ||
235 | last_r=rs; | ||
236 | if (*str==']') | ||
237 | { | ||
238 | *end=str+1; | ||
239 | return 1; | ||
240 | } | ||
241 | if (*str!=',') | ||
242 | break; | ||
243 | str++; | ||
244 | } | ||
245 | while (1); | ||
246 | |||
247 | mi_error=MI_PARSER; | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | int mi_get_list(mi_results *r, const char *str, const char **end) | ||
252 | { | ||
253 | if (*str!='[') | ||
254 | { | ||
255 | mi_error=MI_PARSER; | ||
256 | return 0; | ||
257 | } | ||
258 | r->type=t_list; | ||
259 | str++; | ||
260 | if (*str==']') | ||
261 | {/* Special case: empty list */ | ||
262 | *end=str+1; | ||
263 | return 1; | ||
264 | } | ||
265 | /* Comment: I think they could choose () for values. Is confusing in this way. */ | ||
266 | if (mi_is_var_name_char(*str)) | ||
267 | return mi_get_list_res(r,str,end,']'); | ||
268 | return mi_get_list_val(r,str,end); | ||
269 | } | ||
270 | |||
271 | int mi_get_value(mi_results *r, const char *str, const char **end) | ||
272 | { | ||
273 | switch (str[0]) | ||
274 | { | ||
275 | case '"': | ||
276 | return mi_get_cstring_r(r,str,end); | ||
277 | case '{': | ||
278 | return mi_get_tuple(r,str,end); | ||
279 | case '[': | ||
280 | return mi_get_list(r,str,end); | ||
281 | } | ||
282 | mi_error=MI_PARSER; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | mi_results *mi_get_result(const char *str, const char **end) | ||
287 | { | ||
288 | char *var; | ||
289 | mi_results *r; | ||
290 | |||
291 | var=mi_get_var_name(str,&str); | ||
292 | if (!var) | ||
293 | return NULL; | ||
294 | |||
295 | r=mi_alloc_results(); | ||
296 | if (!r) | ||
297 | { | ||
298 | free(var); | ||
299 | return NULL; | ||
300 | } | ||
301 | r->var=var; | ||
302 | |||
303 | if (!mi_get_value(r,str,end)) | ||
304 | { | ||
305 | mi_free_results(r); | ||
306 | return NULL; | ||
307 | } | ||
308 | |||
309 | return r; | ||
310 | } | ||
311 | |||
312 | mi_output *mi_get_results_alone(mi_output *r,const char *str) | ||
313 | { | ||
314 | mi_results *last_r, *rs; | ||
315 | |||
316 | /* * results */ | ||
317 | last_r=NULL; | ||
318 | do | ||
319 | { | ||
320 | if (!*str) | ||
321 | return r; | ||
322 | if (*str!=',') | ||
323 | { | ||
324 | mi_error=MI_PARSER; | ||
325 | break; | ||
326 | } | ||
327 | str++; | ||
328 | rs=mi_get_result(str,&str); | ||
329 | if (!rs) | ||
330 | break; | ||
331 | if (!last_r) | ||
332 | r->c=rs; | ||
333 | else | ||
334 | last_r->next=rs; | ||
335 | last_r=rs; | ||
336 | } | ||
337 | while (1); | ||
338 | mi_free_output(r); | ||
339 | return NULL; | ||
340 | } | ||
341 | |||
342 | mi_output *mi_parse_result_record(mi_output *r,const char *str) | ||
343 | { | ||
344 | r->type=MI_T_RESULT_RECORD; | ||
345 | |||
346 | /* Solve the result-class. */ | ||
347 | if (strncmp(str,"done",4)==0) | ||
348 | { | ||
349 | str+=4; | ||
350 | r->tclass=MI_CL_DONE; | ||
351 | } | ||
352 | else if (strncmp(str,"running",7)==0) | ||
353 | { | ||
354 | str+=7; | ||
355 | r->tclass=MI_CL_RUNNING; | ||
356 | } | ||
357 | else if (strncmp(str,"connected",9)==0) | ||
358 | { | ||
359 | str+=9; | ||
360 | r->tclass=MI_CL_CONNECTED; | ||
361 | } | ||
362 | else if (strncmp(str,"error",5)==0) | ||
363 | { | ||
364 | str+=5; | ||
365 | r->tclass=MI_CL_ERROR; | ||
366 | } | ||
367 | else if (strncmp(str,"exit",4)==0) | ||
368 | { | ||
369 | str+=4; | ||
370 | r->tclass=MI_CL_EXIT; | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 | mi_error=MI_UNKNOWN_RESULT; | ||
375 | return NULL; | ||
376 | } | ||
377 | |||
378 | return mi_get_results_alone(r,str); | ||
379 | } | ||
380 | |||
381 | mi_output *mi_parse_asyn(mi_output *r,const char *str) | ||
382 | { | ||
383 | r->type=MI_T_OUT_OF_BAND; | ||
384 | r->stype=MI_ST_ASYNC; | ||
385 | /* async-class. */ | ||
386 | if (strncmp(str,"stopped",7)==0) | ||
387 | { | ||
388 | r->tclass=MI_CL_STOPPED; | ||
389 | str+=7; | ||
390 | return mi_get_results_alone(r,str); | ||
391 | } | ||
392 | if (strncmp(str,"download",8)==0) | ||
393 | { | ||
394 | r->tclass=MI_CL_DOWNLOAD; | ||
395 | str+=8; | ||
396 | return mi_get_results_alone(r,str); | ||
397 | } | ||
398 | mi_error=MI_UNKNOWN_ASYNC; | ||
399 | mi_free_output(r); | ||
400 | return NULL; | ||
401 | } | ||
402 | |||
403 | mi_output *mi_parse_exec_asyn(mi_output *r,const char *str) | ||
404 | { | ||
405 | r->sstype=MI_SST_EXEC; | ||
406 | return mi_parse_asyn(r,str); | ||
407 | } | ||
408 | |||
409 | mi_output *mi_parse_status_asyn(mi_output *r,const char *str) | ||
410 | { | ||
411 | r->sstype=MI_SST_STATUS; | ||
412 | return mi_parse_asyn(r,str); | ||
413 | } | ||
414 | |||
415 | mi_output *mi_parse_notify_asyn(mi_output *r,const char *str) | ||
416 | { | ||
417 | r->sstype=MI_SST_NOTIFY; | ||
418 | return mi_parse_asyn(r,str); | ||
419 | } | ||
420 | |||
421 | mi_output *mi_console(mi_output *r,const char *str) | ||
422 | { | ||
423 | r->type=MI_T_OUT_OF_BAND; | ||
424 | r->stype=MI_ST_STREAM; | ||
425 | r->c=mi_alloc_results(); | ||
426 | if (!r->c || !mi_get_cstring_r(r->c,str,NULL)) | ||
427 | { | ||
428 | mi_free_output(r); | ||
429 | return NULL; | ||
430 | } | ||
431 | return r; | ||
432 | } | ||
433 | |||
434 | mi_output *mi_console_stream(mi_output *r,const char *str) | ||
435 | { | ||
436 | r->sstype=MI_SST_CONSOLE; | ||
437 | return mi_console(r,str); | ||
438 | } | ||
439 | |||
440 | mi_output *mi_target_stream(mi_output *r,const char *str) | ||
441 | { | ||
442 | r->sstype=MI_SST_TARGET; | ||
443 | return mi_console(r,str); | ||
444 | } | ||
445 | |||
446 | mi_output *mi_log_stream(mi_output *r,const char *str) | ||
447 | { | ||
448 | r->sstype=MI_SST_LOG; | ||
449 | return mi_console(r,str); | ||
450 | } | ||
451 | |||
452 | mi_output *mi_parse_gdb_output(const char *str) | ||
453 | { | ||
454 | char type=str[0]; | ||
455 | |||
456 | mi_output *r=mi_alloc_output(); | ||
457 | if (!r) | ||
458 | { | ||
459 | mi_error=MI_OUT_OF_MEMORY; | ||
460 | return NULL; | ||
461 | } | ||
462 | str++; | ||
463 | switch (type) | ||
464 | { | ||
465 | case '^': | ||
466 | return mi_parse_result_record(r,str); | ||
467 | case '*': | ||
468 | return mi_parse_exec_asyn(r,str); | ||
469 | case '+': | ||
470 | return mi_parse_status_asyn(r,str); | ||
471 | case '=': | ||
472 | return mi_parse_notify_asyn(r,str); | ||
473 | case '~': | ||
474 | return mi_console_stream(r,str); | ||
475 | case '@': | ||
476 | return mi_target_stream(r,str); | ||
477 | case '&': | ||
478 | return mi_log_stream(r,str); | ||
479 | } | ||
480 | mi_error=MI_PARSER; | ||
481 | return NULL; | ||
482 | } | ||
483 | |||
484 | mi_output *mi_get_rrecord(mi_output *r) | ||
485 | { | ||
486 | if (!r) | ||
487 | return NULL; | ||
488 | while (r) | ||
489 | { | ||
490 | if (r->type==MI_T_RESULT_RECORD) | ||
491 | return r; | ||
492 | r=r->next; | ||
493 | } | ||
494 | return r; | ||
495 | } | ||
496 | |||
497 | mi_results *mi_get_var_r(mi_results *r, const char *var) | ||
498 | { | ||
499 | while (r) | ||
500 | { | ||
501 | if (strcmp(r->var,var)==0) | ||
502 | return r; | ||
503 | r=r->next; | ||
504 | } | ||
505 | return NULL; | ||
506 | } | ||
507 | |||
508 | mi_results *mi_get_var(mi_output *res, const char *var) | ||
509 | { | ||
510 | if (!res) | ||
511 | return NULL; | ||
512 | return mi_get_var_r(res->c,var); | ||
513 | } | ||
514 | |||
515 | int mi_get_async_stop_reason(mi_output *r, char **reason) | ||
516 | { | ||
517 | int found_stopped=0; | ||
518 | |||
519 | *reason=NULL; | ||
520 | while (r) | ||
521 | { | ||
522 | if (r->type==MI_T_RESULT_RECORD && r->tclass==MI_CL_ERROR) | ||
523 | { | ||
524 | if (r->c->type==t_const) | ||
525 | *reason=r->c->v.cstr; | ||
526 | return 0; | ||
527 | } | ||
528 | if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC && | ||
529 | r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED) | ||
530 | { | ||
531 | mi_results *p=r->c; | ||
532 | found_stopped=1; | ||
533 | while (p) | ||
534 | { | ||
535 | if (strcmp(p->var,"reason")==0) | ||
536 | { | ||
537 | *reason=p->v.cstr; | ||
538 | return 1; | ||
539 | } | ||
540 | p=p->next; | ||
541 | } | ||
542 | } | ||
543 | r=r->next; | ||
544 | } | ||
545 | if (*reason==NULL && found_stopped) | ||
546 | { | ||
547 | *reason=strdup("unknown (temp bkpt?)"); | ||
548 | return 1; | ||
549 | } | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | mi_frames *mi_get_async_frame(mi_output *r) | ||
554 | { | ||
555 | while (r) | ||
556 | { | ||
557 | if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC && | ||
558 | r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED) | ||
559 | { | ||
560 | mi_results *p=r->c; | ||
561 | while (p) | ||
562 | { | ||
563 | if (strcmp(p->var,"frame")==0) | ||
564 | return mi_parse_frame(p->v.rs); | ||
565 | p=p->next; | ||
566 | } | ||
567 | } | ||
568 | r=r->next; | ||
569 | } | ||
570 | return NULL; | ||
571 | } | ||
572 | |||
573 | int mi_res_simple(mi_h *h, int tclass, int accert_ret) | ||
574 | { | ||
575 | mi_output *r, *res; | ||
576 | int ret=0; | ||
577 | |||
578 | r=mi_get_response_blk(h); | ||
579 | res=mi_get_rrecord(r); | ||
580 | |||
581 | if (res) | ||
582 | ret=res->tclass==tclass; | ||
583 | mi_free_output(r); | ||
584 | |||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | |||
589 | int mi_res_simple_done(mi_h *h) | ||
590 | { | ||
591 | return mi_res_simple(h,MI_CL_DONE,0); | ||
592 | } | ||
593 | |||
594 | int mi_res_simple_exit(mi_h *h) | ||
595 | { | ||
596 | return mi_res_simple(h,MI_CL_EXIT,1); | ||
597 | } | ||
598 | |||
599 | int mi_res_simple_running(mi_h *h) | ||
600 | { | ||
601 | return mi_res_simple(h,MI_CL_RUNNING,0); | ||
602 | } | ||
603 | |||
604 | int mi_res_simple_connected(mi_h *h) | ||
605 | { | ||
606 | return mi_res_simple(h,MI_CL_CONNECTED,0); | ||
607 | } | ||
608 | |||
609 | mi_results *mi_res_var(mi_h *h, const char *var, int tclass) | ||
610 | { | ||
611 | mi_output *r, *res; | ||
612 | mi_results *the_var=NULL; | ||
613 | |||
614 | r=mi_get_response_blk(h); | ||
615 | /* All the code that follows is "NULL" tolerant. */ | ||
616 | /* Look for the result-record. */ | ||
617 | res=mi_get_rrecord(r); | ||
618 | /* Look for the desired var. */ | ||
619 | if (res && res->tclass==tclass) | ||
620 | the_var=mi_get_var(res,var); | ||
621 | /* Release all but the one we want. */ | ||
622 | mi_free_output_but(r,NULL,the_var); | ||
623 | return the_var; | ||
624 | } | ||
625 | |||
626 | mi_results *mi_res_done_var(mi_h *h, const char *var) | ||
627 | { | ||
628 | return mi_res_var(h,var,MI_CL_DONE); | ||
629 | } | ||
630 | |||
631 | mi_frames *mi_parse_frame(mi_results *c) | ||
632 | { | ||
633 | mi_frames *res=mi_alloc_frames(); | ||
634 | char *end; | ||
635 | |||
636 | if (res) | ||
637 | { | ||
638 | while (c) | ||
639 | { | ||
640 | if (c->type==t_const) | ||
641 | { | ||
642 | if (strcmp(c->var,"level")==0) | ||
643 | res->level=atoi(c->v.cstr); | ||
644 | else if (strcmp(c->var,"addr")==0) | ||
645 | res->addr=(void *)strtoul(c->v.cstr,&end,0); | ||
646 | else if (strcmp(c->var,"func")==0) | ||
647 | { | ||
648 | res->func=c->v.cstr; | ||
649 | c->v.cstr=NULL; | ||
650 | } | ||
651 | else if (strcmp(c->var,"file")==0) | ||
652 | { | ||
653 | res->file=c->v.cstr; | ||
654 | c->v.cstr=NULL; | ||
655 | } | ||
656 | else if (strcmp(c->var,"from")==0) | ||
657 | { | ||
658 | res->from=c->v.cstr; | ||
659 | c->v.cstr=NULL; | ||
660 | } | ||
661 | else if (strcmp(c->var,"line")==0) | ||
662 | res->line=atoi(c->v.cstr); | ||
663 | } | ||
664 | else if (c->type==t_list && strcmp(c->var,"args")==0) | ||
665 | { | ||
666 | res->args=c->v.rs; | ||
667 | c->v.rs=NULL; | ||
668 | } | ||
669 | c=c->next; | ||
670 | } | ||
671 | } | ||
672 | return res; | ||
673 | } | ||
674 | |||
675 | mi_frames *mi_res_frame(mi_h *h) | ||
676 | { | ||
677 | mi_results *r=mi_res_done_var(h,"frame"); | ||
678 | mi_frames *f=NULL; | ||
679 | |||
680 | if (r && r->type==t_tuple) | ||
681 | f=mi_parse_frame(r->v.rs); | ||
682 | mi_free_results(r); | ||
683 | return f; | ||
684 | } | ||
685 | |||
686 | mi_frames *mi_res_frames_array(mi_h *h, const char *var) | ||
687 | { | ||
688 | mi_results *r=mi_res_done_var(h,var), *c; | ||
689 | mi_frames *res=NULL, *nframe, *last=NULL; | ||
690 | |||
691 | if (!r) | ||
692 | return NULL; | ||
693 | #ifdef __APPLE__ | ||
694 | if (r->type!=t_list && r->type!=t_tuple) | ||
695 | #else | ||
696 | if (r->type!=t_list) | ||
697 | #endif | ||
698 | { | ||
699 | mi_free_results(r); | ||
700 | return NULL; | ||
701 | } | ||
702 | c=r->v.rs; | ||
703 | while (c) | ||
704 | { | ||
705 | if (strcmp(c->var,"frame")==0 && c->type==t_tuple) | ||
706 | { | ||
707 | nframe=mi_parse_frame(c->v.rs); | ||
708 | if (nframe) | ||
709 | { | ||
710 | if (!last) | ||
711 | res=nframe; | ||
712 | else | ||
713 | last->next=nframe; | ||
714 | last=nframe; | ||
715 | } | ||
716 | } | ||
717 | c=c->next; | ||
718 | } | ||
719 | mi_free_results(r); | ||
720 | return res; | ||
721 | } | ||
722 | |||
723 | mi_frames *mi_res_frames_list(mi_h *h) | ||
724 | { | ||
725 | mi_output *r, *res; | ||
726 | mi_frames *ret=NULL, *nframe, *last=NULL; | ||
727 | mi_results *c; | ||
728 | |||
729 | r=mi_get_response_blk(h); | ||
730 | res=mi_get_rrecord(r); | ||
731 | if (res && res->tclass==MI_CL_DONE) | ||
732 | { | ||
733 | c=res->c; | ||
734 | while (c) | ||
735 | { | ||
736 | if (strcmp(c->var,"frame")==0 && c->type==t_tuple) | ||
737 | { | ||
738 | nframe=mi_parse_frame(c->v.rs); | ||
739 | if (nframe) | ||
740 | { | ||
741 | if (!last) | ||
742 | ret=nframe; | ||
743 | else | ||
744 | last->next=nframe; | ||
745 | last=nframe; | ||
746 | } | ||
747 | } | ||
748 | c=c->next; | ||
749 | } | ||
750 | } | ||
751 | mi_free_output(r); | ||
752 | return ret; | ||
753 | } | ||
754 | |||
755 | int mi_get_thread_ids(mi_output *res, int **list) | ||
756 | { | ||
757 | mi_results *vids, *lids; | ||
758 | int ids=-1, i; | ||
759 | |||
760 | *list=NULL; | ||
761 | vids=mi_get_var(res,"number-of-threads"); | ||
762 | lids=mi_get_var(res,"thread-ids"); | ||
763 | if (vids && vids->type==t_const && | ||
764 | lids && lids->type==t_tuple) | ||
765 | { | ||
766 | ids=atoi(vids->v.cstr); | ||
767 | if (ids) | ||
768 | { | ||
769 | int *lst; | ||
770 | lst=(int *)mi_calloc(ids,sizeof(int)); | ||
771 | if (lst) | ||
772 | { | ||
773 | lids=lids->v.rs; | ||
774 | i=0; | ||
775 | while (lids) | ||
776 | { | ||
777 | if (strcmp(lids->var,"thread-id")==0 && lids->type==t_const) | ||
778 | lst[i++]=atoi(lids->v.cstr); | ||
779 | lids=lids->next; | ||
780 | } | ||
781 | *list=lst; | ||
782 | } | ||
783 | else | ||
784 | ids=-1; | ||
785 | } | ||
786 | } | ||
787 | return ids; | ||
788 | } | ||
789 | |||
790 | int mi_res_thread_ids(mi_h *h, int **list) | ||
791 | { | ||
792 | mi_output *r, *res; | ||
793 | int ids=-1; | ||
794 | |||
795 | r=mi_get_response_blk(h); | ||
796 | res=mi_get_rrecord(r); | ||
797 | if (res && res->tclass==MI_CL_DONE) | ||
798 | ids=mi_get_thread_ids(res,list); | ||
799 | mi_free_output(r); | ||
800 | return ids; | ||
801 | } | ||
802 | |||
803 | enum mi_gvar_lang mi_lang_str_to_enum(const char *lang) | ||
804 | { | ||
805 | enum mi_gvar_lang lg=lg_unknown; | ||
806 | |||
807 | if (strcmp(lang,"C")==0) | ||
808 | lg=lg_c; | ||
809 | else if (strcmp(lang,"C++")==0) | ||
810 | lg=lg_cpp; | ||
811 | else if (strcmp(lang,"Java")==0) | ||
812 | lg=lg_java; | ||
813 | |||
814 | return lg; | ||
815 | } | ||
816 | |||
817 | const char *mi_lang_enum_to_str(enum mi_gvar_lang lang) | ||
818 | { | ||
819 | const char *lg; | ||
820 | |||
821 | switch (lang) | ||
822 | { | ||
823 | case lg_c: | ||
824 | lg="C"; | ||
825 | break; | ||
826 | case lg_cpp: | ||
827 | lg="C++"; | ||
828 | break; | ||
829 | case lg_java: | ||
830 | lg="Java"; | ||
831 | break; | ||
832 | /*case lg_unknown:*/ | ||
833 | default: | ||
834 | lg="unknown"; | ||
835 | break; | ||
836 | } | ||
837 | return lg; | ||
838 | } | ||
839 | |||
840 | enum mi_gvar_fmt mi_format_str_to_enum(const char *format) | ||
841 | { | ||
842 | enum mi_gvar_fmt fmt=fm_natural; | ||
843 | |||
844 | if (strcmp(format,"binary")==0) | ||
845 | fmt=fm_binary; | ||
846 | else if (strcmp(format,"decimal")==0) | ||
847 | fmt=fm_decimal; | ||
848 | else if (strcmp(format,"hexadecimal")==0) | ||
849 | fmt=fm_hexadecimal; | ||
850 | else if (strcmp(format,"octal")==0) | ||
851 | fmt=fm_octal; | ||
852 | |||
853 | return fmt; | ||
854 | } | ||
855 | |||
856 | const char *mi_format_enum_to_str(enum mi_gvar_fmt format) | ||
857 | { | ||
858 | const char *fmt; | ||
859 | |||
860 | switch (format) | ||
861 | { | ||
862 | case fm_natural: | ||
863 | fmt="natural"; | ||
864 | break; | ||
865 | case fm_binary: | ||
866 | fmt="binary"; | ||
867 | break; | ||
868 | case fm_decimal: | ||
869 | fmt="decimal"; | ||
870 | break; | ||
871 | case fm_hexadecimal: | ||
872 | fmt="hexadecimal"; | ||
873 | break; | ||
874 | case fm_octal: | ||
875 | fmt="octal"; | ||
876 | break; | ||
877 | case fm_raw: | ||
878 | fmt="raw"; | ||
879 | break; | ||
880 | default: | ||
881 | fmt="unknown"; | ||
882 | } | ||
883 | return fmt; | ||
884 | } | ||
885 | |||
886 | char mi_format_enum_to_char(enum mi_gvar_fmt format) | ||
887 | { | ||
888 | char fmt; | ||
889 | |||
890 | switch (format) | ||
891 | { | ||
892 | case fm_natural: | ||
893 | fmt='N'; | ||
894 | break; | ||
895 | case fm_binary: | ||
896 | fmt='t'; | ||
897 | break; | ||
898 | case fm_decimal: | ||
899 | fmt='d'; | ||
900 | break; | ||
901 | case fm_hexadecimal: | ||
902 | fmt='x'; | ||
903 | break; | ||
904 | case fm_octal: | ||
905 | fmt='o'; | ||
906 | break; | ||
907 | case fm_raw: | ||
908 | fmt='r'; | ||
909 | break; | ||
910 | default: | ||
911 | fmt=' '; | ||
912 | } | ||
913 | return fmt; | ||
914 | } | ||
915 | |||
916 | mi_gvar *mi_get_gvar(mi_output *o, mi_gvar *cur, const char *expression) | ||
917 | { | ||
918 | mi_results *r; | ||
919 | mi_gvar *res=cur ? cur : mi_alloc_gvar(); | ||
920 | int l; | ||
921 | |||
922 | if (!res) | ||
923 | return res; | ||
924 | r=o->c; | ||
925 | if (expression) | ||
926 | res->exp=strdup(expression); | ||
927 | while (r) | ||
928 | { | ||
929 | if (r->type==t_const) | ||
930 | { | ||
931 | if (strcmp(r->var,"name")==0) | ||
932 | { | ||
933 | free(res->name); | ||
934 | res->name=r->v.cstr; | ||
935 | r->v.cstr=NULL; | ||
936 | } | ||
937 | else if (strcmp(r->var,"numchild")==0) | ||
938 | { | ||
939 | res->numchild=atoi(r->v.cstr); | ||
940 | } | ||
941 | else if (strcmp(r->var,"type")==0) | ||
942 | { | ||
943 | free(res->type); | ||
944 | res->type=r->v.cstr; | ||
945 | r->v.cstr=NULL; | ||
946 | l=strlen(res->type); | ||
947 | if (l && res->type[l-1]=='*') | ||
948 | res->ispointer=1; | ||
949 | } | ||
950 | else if (strcmp(r->var,"lang")==0) | ||
951 | { | ||
952 | res->lang=mi_lang_str_to_enum(r->v.cstr); | ||
953 | } | ||
954 | else if (strcmp(r->var,"exp")==0) | ||
955 | { | ||
956 | free(res->exp); | ||
957 | res->exp=r->v.cstr; | ||
958 | r->v.cstr=NULL; | ||
959 | } | ||
960 | else if (strcmp(r->var,"format")==0) | ||
961 | { | ||
962 | res->format=mi_format_str_to_enum(r->v.cstr); | ||
963 | } | ||
964 | else if (strcmp(r->var,"attr")==0) | ||
965 | { /* Note: gdb 6.1.1 have only this: */ | ||
966 | if (strcmp(r->v.cstr,"editable")==0) | ||
967 | res->attr=MI_ATTR_EDITABLE; | ||
968 | else /* noneditable */ | ||
969 | res->attr=MI_ATTR_NONEDITABLE; | ||
970 | } | ||
971 | } | ||
972 | r=r->next; | ||
973 | } | ||
974 | return res; | ||
975 | } | ||
976 | |||
977 | mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression) | ||
978 | { | ||
979 | mi_output *r, *res; | ||
980 | mi_gvar *gvar=NULL; | ||
981 | |||
982 | r=mi_get_response_blk(h); | ||
983 | res=mi_get_rrecord(r); | ||
984 | if (res && res->tclass==MI_CL_DONE) | ||
985 | gvar=mi_get_gvar(res,cur,expression); | ||
986 | mi_free_output(r); | ||
987 | return gvar; | ||
988 | } | ||
989 | |||
990 | mi_gvar_chg *mi_get_gvar_chg(mi_results *r) | ||
991 | { | ||
992 | mi_gvar_chg *n; | ||
993 | |||
994 | if (r->type!=t_const) | ||
995 | return NULL; | ||
996 | n=mi_alloc_gvar_chg(); | ||
997 | if (n) | ||
998 | { | ||
999 | while (r) | ||
1000 | { | ||
1001 | if (r->type==t_const) | ||
1002 | { | ||
1003 | if (strcmp(r->var,"name")==0) | ||
1004 | { | ||
1005 | n->name=r->v.cstr; | ||
1006 | r->v.cstr=NULL; | ||
1007 | } | ||
1008 | else if (strcmp(r->var,"in_scope")==0) | ||
1009 | { | ||
1010 | n->in_scope=strcmp(r->v.cstr,"true")==0; | ||
1011 | } | ||
1012 | else if (strcmp(r->var,"new_type")==0) | ||
1013 | { | ||
1014 | n->new_type=r->v.cstr; | ||
1015 | r->v.cstr=NULL; | ||
1016 | } | ||
1017 | else if (strcmp(r->var,"new_num_children")==0) | ||
1018 | { | ||
1019 | n->new_num_children=atoi(r->v.cstr); | ||
1020 | } | ||
1021 | // type_changed="false" is the default | ||
1022 | } | ||
1023 | r=r->next; | ||
1024 | } | ||
1025 | } | ||
1026 | return n; | ||
1027 | } | ||
1028 | |||
1029 | int mi_res_changelist(mi_h *h, mi_gvar_chg **changed) | ||
1030 | { | ||
1031 | mi_gvar_chg *last, *n; | ||
1032 | mi_results *res=mi_res_done_var(h,"changelist"), *r; | ||
1033 | int count=0; | ||
1034 | |||
1035 | *changed=NULL; | ||
1036 | if (!res) | ||
1037 | return 0; | ||
1038 | last=NULL; | ||
1039 | count=1; | ||
1040 | n=NULL; | ||
1041 | r=res->v.rs; | ||
1042 | |||
1043 | if (res->type==t_list) | ||
1044 | {// MI v2 a list of tuples | ||
1045 | while (r) | ||
1046 | { | ||
1047 | if (r->type==t_tuple) | ||
1048 | { | ||
1049 | n=mi_get_gvar_chg(r->v.rs); | ||
1050 | if (n) | ||
1051 | { | ||
1052 | if (last) | ||
1053 | last->next=n; | ||
1054 | else | ||
1055 | *changed=n; | ||
1056 | last=n; | ||
1057 | count++; | ||
1058 | } | ||
1059 | } | ||
1060 | r=r->next; | ||
1061 | } | ||
1062 | } | ||
1063 | else if (res->type==t_tuple) | ||
1064 | {// MI v1 a tuple with all together *8-P | ||
1065 | while (r) | ||
1066 | { | ||
1067 | if (r->type==t_const) /* Just in case. */ | ||
1068 | {/* Get one var. */ | ||
1069 | if (strcmp(r->var,"name")==0) | ||
1070 | { | ||
1071 | if (n) | ||
1072 | {/* Add to the list*/ | ||
1073 | if (last) | ||
1074 | last->next=n; | ||
1075 | else | ||
1076 | *changed=n; | ||
1077 | last=n; | ||
1078 | count++; | ||
1079 | } | ||
1080 | n=mi_alloc_gvar_chg(); | ||
1081 | if (!n) | ||
1082 | { | ||
1083 | mi_free_gvar_chg(*changed); | ||
1084 | return 0; | ||
1085 | } | ||
1086 | n->name=r->v.cstr; | ||
1087 | r->v.cstr=NULL; | ||
1088 | } | ||
1089 | else if (strcmp(r->var,"in_scope")==0) | ||
1090 | { | ||
1091 | n->in_scope=strcmp(r->v.cstr,"true")==0; | ||
1092 | } | ||
1093 | else if (strcmp(r->var,"new_type")==0) | ||
1094 | { | ||
1095 | n->new_type=r->v.cstr; | ||
1096 | r->v.cstr=NULL; | ||
1097 | } | ||
1098 | else if (strcmp(r->var,"new_num_children")==0) | ||
1099 | { | ||
1100 | n->new_num_children=atoi(r->v.cstr); | ||
1101 | } | ||
1102 | // type_changed="false" is the default | ||
1103 | } | ||
1104 | r=r->next; | ||
1105 | } | ||
1106 | if (n) | ||
1107 | {/* Add to the list*/ | ||
1108 | if (last) | ||
1109 | last->next=n; | ||
1110 | else | ||
1111 | *changed=n; | ||
1112 | last=n; | ||
1113 | count++; | ||
1114 | } | ||
1115 | } | ||
1116 | mi_free_results(res); | ||
1117 | |||
1118 | return count; | ||
1119 | } | ||
1120 | |||
1121 | int mi_get_children(mi_results *ch, mi_gvar *v) | ||
1122 | { | ||
1123 | mi_gvar *cur=NULL, *aux; | ||
1124 | int i=0, count=v->numchild, l; | ||
1125 | |||
1126 | while (ch) | ||
1127 | { | ||
1128 | if (strcmp(ch->var,"child")==0 && ch->type==t_tuple && i<count) | ||
1129 | { | ||
1130 | mi_results *r=ch->v.rs; | ||
1131 | aux=mi_alloc_gvar(); | ||
1132 | if (!aux) | ||
1133 | return 0; | ||
1134 | if (!v->child) | ||
1135 | v->child=aux; | ||
1136 | else | ||
1137 | cur->next=aux; | ||
1138 | cur=aux; | ||
1139 | cur->parent=v; | ||
1140 | cur->depth=v->depth+1; | ||
1141 | |||
1142 | while (r) | ||
1143 | { | ||
1144 | if (r->type==t_const) | ||
1145 | { | ||
1146 | if (strcmp(r->var,"name")==0) | ||
1147 | { | ||
1148 | cur->name=r->v.cstr; | ||
1149 | r->v.cstr=NULL; | ||
1150 | } | ||
1151 | else if (strcmp(r->var,"exp")==0) | ||
1152 | { | ||
1153 | cur->exp=r->v.cstr; | ||
1154 | r->v.cstr=NULL; | ||
1155 | } | ||
1156 | else if (strcmp(r->var,"type")==0) | ||
1157 | { | ||
1158 | cur->type=r->v.cstr; | ||
1159 | r->v.cstr=NULL; | ||
1160 | l=strlen(cur->type); | ||
1161 | if (l && cur->type[l-1]=='*') | ||
1162 | cur->ispointer=1; | ||
1163 | } | ||
1164 | else if (strcmp(r->var,"value")==0) | ||
1165 | { | ||
1166 | cur->value=r->v.cstr; | ||
1167 | r->v.cstr=NULL; | ||
1168 | } | ||
1169 | else if (strcmp(r->var,"numchild")==0) | ||
1170 | { | ||
1171 | cur->numchild=atoi(r->v.cstr); | ||
1172 | } | ||
1173 | } | ||
1174 | r=r->next; | ||
1175 | } | ||
1176 | i++; | ||
1177 | } | ||
1178 | ch=ch->next; | ||
1179 | } | ||
1180 | v->vischild=i; | ||
1181 | v->opened=1; | ||
1182 | return i==v->numchild; | ||
1183 | } | ||
1184 | |||
1185 | int mi_res_children(mi_h *h, mi_gvar *v) | ||
1186 | { | ||
1187 | mi_output *r, *res; | ||
1188 | int ok=0; | ||
1189 | |||
1190 | r=mi_get_response_blk(h); | ||
1191 | res=mi_get_rrecord(r); | ||
1192 | if (res && res->tclass==MI_CL_DONE) | ||
1193 | { | ||
1194 | mi_results *num=mi_get_var(res,"numchild"); | ||
1195 | if (num && num->type==t_const) | ||
1196 | { | ||
1197 | v->numchild=atoi(num->v.cstr); | ||
1198 | if (v->child) | ||
1199 | { | ||
1200 | mi_free_gvar(v->child); | ||
1201 | v->child=NULL; | ||
1202 | } | ||
1203 | if (v->numchild) | ||
1204 | { | ||
1205 | mi_results *ch =mi_get_var(res,"children"); | ||
1206 | if (ch && ch->type!=t_const) /* MI v1 tuple, MI v2 list */ | ||
1207 | ok=mi_get_children(ch->v.rs,v); | ||
1208 | } | ||
1209 | else | ||
1210 | ok=1; | ||
1211 | } | ||
1212 | } | ||
1213 | mi_free_output(r); | ||
1214 | return ok; | ||
1215 | } | ||
1216 | |||
1217 | mi_bkpt *mi_get_bkpt(mi_results *p) | ||
1218 | { | ||
1219 | mi_bkpt *res; | ||
1220 | char *end; | ||
1221 | |||
1222 | res=mi_alloc_bkpt(); | ||
1223 | if (!res) | ||
1224 | return NULL; | ||
1225 | while (p) | ||
1226 | { | ||
1227 | if (p->type==t_const && p->var) | ||
1228 | { | ||
1229 | if (strcmp(p->var,"number")==0) | ||
1230 | res->number=atoi(p->v.cstr); | ||
1231 | else if (strcmp(p->var,"type")==0) | ||
1232 | { | ||
1233 | if (strcmp(p->v.cstr,"breakpoint")==0) | ||
1234 | res->type=t_breakpoint; | ||
1235 | else | ||
1236 | res->type=t_unknown; | ||
1237 | } | ||
1238 | else if (strcmp(p->var,"disp")==0) | ||
1239 | { | ||
1240 | if (strcmp(p->v.cstr,"keep")==0) | ||
1241 | res->disp=d_keep; | ||
1242 | else if (strcmp(p->v.cstr,"del")==0) | ||
1243 | res->disp=d_del; | ||
1244 | else | ||
1245 | res->disp=d_unknown; | ||
1246 | } | ||
1247 | else if (strcmp(p->var,"enabled")==0) | ||
1248 | res->enabled=p->v.cstr[0]=='y'; | ||
1249 | else if (strcmp(p->var,"addr")==0) | ||
1250 | res->addr=(void *)strtoul(p->v.cstr,&end,0); | ||
1251 | else if (strcmp(p->var,"func")==0) | ||
1252 | { | ||
1253 | res->func=p->v.cstr; | ||
1254 | p->v.cstr=NULL; | ||
1255 | } | ||
1256 | else if (strcmp(p->var,"file")==0) | ||
1257 | { | ||
1258 | res->file=p->v.cstr; | ||
1259 | p->v.cstr=NULL; | ||
1260 | } | ||
1261 | else if (strcmp(p->var,"line")==0) | ||
1262 | res->line=atoi(p->v.cstr); | ||
1263 | else if (strcmp(p->var,"times")==0) | ||
1264 | res->times=atoi(p->v.cstr); | ||
1265 | else if (strcmp(p->var,"ignore")==0) | ||
1266 | res->ignore=atoi(p->v.cstr); | ||
1267 | else if (strcmp(p->var,"cond")==0) | ||
1268 | { | ||
1269 | res->cond=p->v.cstr; | ||
1270 | p->v.cstr=NULL; | ||
1271 | } | ||
1272 | } | ||
1273 | p=p->next; | ||
1274 | } | ||
1275 | return res; | ||
1276 | } | ||
1277 | |||
1278 | mi_bkpt *mi_res_bkpt(mi_h *h) | ||
1279 | { | ||
1280 | mi_results *r=mi_res_done_var(h,"bkpt"); | ||
1281 | mi_bkpt *b=NULL; | ||
1282 | |||
1283 | if (r && r->type==t_tuple) | ||
1284 | b=mi_get_bkpt(r->v.rs); | ||
1285 | mi_free_results(r); | ||
1286 | return b; | ||
1287 | } | ||
1288 | |||
1289 | mi_wp *mi_get_wp(mi_results *p, enum mi_wp_mode m) | ||
1290 | { | ||
1291 | mi_wp *res=mi_alloc_wp(); | ||
1292 | |||
1293 | if (res) | ||
1294 | { | ||
1295 | res->mode=m; | ||
1296 | while (p) | ||
1297 | { | ||
1298 | if (p->type==t_const && p->var) | ||
1299 | { | ||
1300 | if (strcmp(p->var,"number")==0) | ||
1301 | { | ||
1302 | res->number=atoi(p->v.cstr); | ||
1303 | res->enabled=1; | ||
1304 | } | ||
1305 | else if (strcmp(p->var,"exp")==0) | ||
1306 | { | ||
1307 | res->exp=p->v.cstr; | ||
1308 | p->v.cstr=NULL; | ||
1309 | } | ||
1310 | } | ||
1311 | p=p->next; | ||
1312 | } | ||
1313 | } | ||
1314 | return res; | ||
1315 | } | ||
1316 | |||
1317 | mi_wp *mi_parse_wp_res(mi_output *r) | ||
1318 | { | ||
1319 | mi_results *p; | ||
1320 | enum mi_wp_mode m=wm_unknown; | ||
1321 | |||
1322 | /* The info is in a result wpt=... */ | ||
1323 | p=r->c; | ||
1324 | while (p) | ||
1325 | { | ||
1326 | if (p->var) | ||
1327 | { | ||
1328 | if (strcmp(p->var,"wpt")==0) | ||
1329 | m=wm_write; | ||
1330 | else if (strcmp(p->var,"hw-rwpt")==0) | ||
1331 | m=wm_read; | ||
1332 | else if (strcmp(p->var,"hw-awpt")==0) | ||
1333 | m=wm_rw; | ||
1334 | if (m!=wm_unknown) | ||
1335 | break; | ||
1336 | } | ||
1337 | p=p->next; | ||
1338 | } | ||
1339 | if (!p || p->type!=t_tuple) | ||
1340 | return NULL; | ||
1341 | /* Scan the values inside it. */ | ||
1342 | return mi_get_wp(p->v.rs,m); | ||
1343 | } | ||
1344 | |||
1345 | mi_wp *mi_res_wp(mi_h *h) | ||
1346 | { | ||
1347 | mi_output *r, *res; | ||
1348 | mi_wp *ret=NULL; | ||
1349 | |||
1350 | r=mi_get_response_blk(h); | ||
1351 | res=mi_get_rrecord(r); | ||
1352 | |||
1353 | if (res) | ||
1354 | ret=mi_parse_wp_res(res); | ||
1355 | |||
1356 | mi_free_output(r); | ||
1357 | return ret; | ||
1358 | } | ||
1359 | |||
1360 | char *mi_res_value(mi_h *h) | ||
1361 | { | ||
1362 | mi_results *r=mi_res_done_var(h,"value"); | ||
1363 | char *s=NULL; | ||
1364 | |||
1365 | if (r && r->type==t_const) | ||
1366 | { | ||
1367 | s=r->v.cstr; | ||
1368 | r->v.rs=NULL; | ||
1369 | } | ||
1370 | mi_free_results(r); | ||
1371 | return s; | ||
1372 | } | ||
1373 | |||
1374 | mi_output *mi_get_stop_record(mi_output *r) | ||
1375 | { | ||
1376 | while (r) | ||
1377 | { | ||
1378 | if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC && | ||
1379 | r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED) | ||
1380 | return r; | ||
1381 | r=r->next; | ||
1382 | } | ||
1383 | return r; | ||
1384 | } | ||
1385 | |||
1386 | static | ||
1387 | char *reason_names[]= | ||
1388 | { | ||
1389 | "breakpoint-hit", | ||
1390 | "watchpoint-trigger", | ||
1391 | "read-watchpoint-trigger", | ||
1392 | "access-watchpoint-trigger", | ||
1393 | "watchpoint-scope", | ||
1394 | "function-finished", | ||
1395 | "location-reached", | ||
1396 | "end-stepping-range", | ||
1397 | "exited-signalled", | ||
1398 | "exited", | ||
1399 | "exited-normally", | ||
1400 | "signal-received" | ||
1401 | }; | ||
1402 | |||
1403 | static | ||
1404 | enum mi_stop_reason reason_values[]= | ||
1405 | { | ||
1406 | sr_bkpt_hit, | ||
1407 | sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope, | ||
1408 | sr_function_finished, sr_location_reached, sr_end_stepping_range, | ||
1409 | sr_exited_signalled, sr_exited, sr_exited_normally, | ||
1410 | sr_signal_received | ||
1411 | }; | ||
1412 | |||
1413 | static | ||
1414 | char *reason_expl[]= | ||
1415 | { | ||
1416 | "Hit a breakpoint", | ||
1417 | "Write watchpoint", | ||
1418 | "Read watchpoint", | ||
1419 | "Access watchpoint", | ||
1420 | "Watchpoint out of scope", | ||
1421 | "Function finished", | ||
1422 | "Location reached", | ||
1423 | "End of stepping", | ||
1424 | "Exited signalled", | ||
1425 | "Exited with error", | ||
1426 | "Exited normally", | ||
1427 | "Signal received" | ||
1428 | }; | ||
1429 | |||
1430 | enum mi_stop_reason mi_reason_str_to_enum(const char *s) | ||
1431 | { | ||
1432 | int i; | ||
1433 | |||
1434 | for (i=0; i<sizeof(reason_names)/sizeof(char *); i++) | ||
1435 | if (strcmp(reason_names[i],s)==0) | ||
1436 | return reason_values[i]; | ||
1437 | return sr_unknown; | ||
1438 | } | ||
1439 | |||
1440 | const char *mi_reason_enum_to_str(enum mi_stop_reason r) | ||
1441 | { | ||
1442 | int i; | ||
1443 | |||
1444 | if (r==sr_unknown) | ||
1445 | return "Unknown (temp bkp?)"; | ||
1446 | for (i=0; i<sizeof(reason_values)/sizeof(char *); i++) | ||
1447 | if (reason_values[i]==r) | ||
1448 | return reason_expl[i]; | ||
1449 | return NULL; | ||
1450 | } | ||
1451 | |||
1452 | mi_stop *mi_get_stopped(mi_results *r) | ||
1453 | { | ||
1454 | mi_stop *res=mi_alloc_stop(); | ||
1455 | |||
1456 | if (res) | ||
1457 | { | ||
1458 | while (r) | ||
1459 | { | ||
1460 | if (r->type==t_const) | ||
1461 | { | ||
1462 | if (strcmp(r->var,"reason")==0) | ||
1463 | res->reason=mi_reason_str_to_enum(r->v.cstr); | ||
1464 | else if (!res->have_thread_id && strcmp(r->var,"thread-id")==0) | ||
1465 | { | ||
1466 | res->have_thread_id=1; | ||
1467 | res->thread_id=atoi(r->v.cstr); | ||
1468 | } | ||
1469 | else if (!res->have_bkptno && strcmp(r->var,"bkptno")==0) | ||
1470 | { | ||
1471 | res->have_bkptno=1; | ||
1472 | res->bkptno=atoi(r->v.cstr); | ||
1473 | } | ||
1474 | else if (!res->have_bkptno && strcmp(r->var,"wpnum")==0) | ||
1475 | { | ||
1476 | res->have_wpno=1; | ||
1477 | res->wpno=atoi(r->v.cstr); | ||
1478 | } | ||
1479 | else if (strcmp(r->var,"gdb-result-var")==0) | ||
1480 | { | ||
1481 | res->gdb_result_var=r->v.cstr; | ||
1482 | r->v.cstr=NULL; | ||
1483 | } | ||
1484 | else if (strcmp(r->var,"return-value")==0) | ||
1485 | { | ||
1486 | res->return_value=r->v.cstr; | ||
1487 | r->v.cstr=NULL; | ||
1488 | } | ||
1489 | else if (strcmp(r->var,"signal-name")==0) | ||
1490 | { | ||
1491 | res->signal_name=r->v.cstr; | ||
1492 | r->v.cstr=NULL; | ||
1493 | } | ||
1494 | else if (strcmp(r->var,"signal-meaning")==0) | ||
1495 | { | ||
1496 | res->signal_meaning=r->v.cstr; | ||
1497 | r->v.cstr=NULL; | ||
1498 | } | ||
1499 | else if (!res->have_exit_code && strcmp(r->var,"exit-code")==0) | ||
1500 | { | ||
1501 | res->have_exit_code=1; | ||
1502 | res->exit_code=atoi(r->v.cstr); | ||
1503 | } | ||
1504 | } | ||
1505 | else // tuple or list | ||
1506 | { | ||
1507 | if (strcmp(r->var,"frame")==0) | ||
1508 | res->frame=mi_parse_frame(r->v.rs); | ||
1509 | else if (!res->wp && strcmp(r->var,"wpt")==0) | ||
1510 | res->wp=mi_get_wp(r->v.rs,wm_write); | ||
1511 | else if (!res->wp && strcmp(r->var,"hw-rwpt")==0) | ||
1512 | res->wp=mi_get_wp(r->v.rs,wm_read); | ||
1513 | else if (!res->wp && strcmp(r->var,"hw-awpt")==0) | ||
1514 | res->wp=mi_get_wp(r->v.rs,wm_rw); | ||
1515 | else if (!(res->wp_old || res->wp_val) && strcmp(r->var,"value")==0) | ||
1516 | { | ||
1517 | mi_results *p=r->v.rs; | ||
1518 | while (p) | ||
1519 | { | ||
1520 | if (strcmp(p->var,"value")==0 || strcmp(p->var,"new")==0) | ||
1521 | { | ||
1522 | res->wp_val=p->v.cstr; | ||
1523 | p->v.cstr=NULL; | ||
1524 | } | ||
1525 | else if (strcmp(p->var,"old")==0) | ||
1526 | { | ||
1527 | res->wp_old=p->v.cstr; | ||
1528 | p->v.cstr=NULL; | ||
1529 | } | ||
1530 | p=p->next; | ||
1531 | } | ||
1532 | } | ||
1533 | } | ||
1534 | r=r->next; | ||
1535 | } | ||
1536 | } | ||
1537 | return res; | ||
1538 | } | ||
1539 | |||
1540 | mi_stop *mi_res_stop(mi_h *h) | ||
1541 | { | ||
1542 | mi_output *o=mi_retire_response(h); | ||
1543 | mi_stop *stop=NULL; | ||
1544 | |||
1545 | if (o) | ||
1546 | { | ||
1547 | mi_output *sr=mi_get_stop_record(o); | ||
1548 | if (sr) | ||
1549 | stop=mi_get_stopped(sr->c); | ||
1550 | } | ||
1551 | mi_free_output(o); | ||
1552 | |||
1553 | return stop; | ||
1554 | } | ||
1555 | |||
1556 | int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na, | ||
1557 | unsigned long *addr) | ||
1558 | { | ||
1559 | char *end; | ||
1560 | mi_results *res=mi_res_done_var(h,"memory"), *r; | ||
1561 | int ok=0; | ||
1562 | |||
1563 | *na=0; | ||
1564 | r=res; | ||
1565 | if (r && r->type==t_list && ws==1) | ||
1566 | { | ||
1567 | r=r->v.rs; | ||
1568 | if (r->type!=t_tuple) | ||
1569 | { | ||
1570 | mi_free_results(res); | ||
1571 | return 0; | ||
1572 | } | ||
1573 | r=r->v.rs; | ||
1574 | while (r) | ||
1575 | { | ||
1576 | if (r->type==t_list && strcmp(r->var,"data")==0) | ||
1577 | { | ||
1578 | mi_results *data=r->v.rs; | ||
1579 | ok++; | ||
1580 | if (data && data->type==t_const && | ||
1581 | strcmp(data->v.cstr,"N/A")==0) | ||
1582 | *na=1; | ||
1583 | else | ||
1584 | while (data) | ||
1585 | { | ||
1586 | if (data->type==t_const) | ||
1587 | *(dest++)=strtol(data->v.cstr,&end,0); | ||
1588 | data=data->next; | ||
1589 | } | ||
1590 | } | ||
1591 | else if (r->type==t_const && strcmp(r->var,"addr")==0) | ||
1592 | { | ||
1593 | ok++; | ||
1594 | if (addr) | ||
1595 | *addr=strtoul(r->v.cstr,&end,0); | ||
1596 | } | ||
1597 | r=r->next; | ||
1598 | } | ||
1599 | |||
1600 | } | ||
1601 | mi_free_results(res); | ||
1602 | return ok==2; | ||
1603 | } | ||
1604 | |||
1605 | mi_asm_insn *mi_parse_insn(mi_results *c) | ||
1606 | { | ||
1607 | mi_asm_insn *res=NULL, *cur=NULL; | ||
1608 | mi_results *sub; | ||
1609 | char *end; | ||
1610 | |||
1611 | while (c) | ||
1612 | { | ||
1613 | if (c->type==t_tuple) | ||
1614 | { | ||
1615 | if (!res) | ||
1616 | res=cur=mi_alloc_asm_insn(); | ||
1617 | else | ||
1618 | { | ||
1619 | cur->next=mi_alloc_asm_insn(); | ||
1620 | cur=cur->next; | ||
1621 | } | ||
1622 | if (!cur) | ||
1623 | { | ||
1624 | mi_free_asm_insn(res); | ||
1625 | return NULL; | ||
1626 | } | ||
1627 | sub=c->v.rs; | ||
1628 | while (sub) | ||
1629 | { | ||
1630 | if (sub->type==t_const) | ||
1631 | { | ||
1632 | if (strcmp(sub->var,"address")==0) | ||
1633 | cur->addr=(void *)strtoul(sub->v.cstr,&end,0); | ||
1634 | else if (strcmp(sub->var,"func-name")==0) | ||
1635 | { | ||
1636 | cur->func=sub->v.cstr; | ||
1637 | sub->v.cstr=NULL; | ||
1638 | } | ||
1639 | else if (strcmp(sub->var,"offset")==0) | ||
1640 | cur->offset=atoi(sub->v.cstr); | ||
1641 | else if (strcmp(sub->var,"inst")==0) | ||
1642 | { | ||
1643 | cur->inst=sub->v.cstr; | ||
1644 | sub->v.cstr=NULL; | ||
1645 | } | ||
1646 | } | ||
1647 | sub=sub->next; | ||
1648 | } | ||
1649 | } | ||
1650 | c=c->next; | ||
1651 | } | ||
1652 | return res; | ||
1653 | } | ||
1654 | |||
1655 | mi_asm_insns *mi_parse_insns(mi_results *c) | ||
1656 | { | ||
1657 | mi_asm_insns *res=NULL, *cur=NULL; | ||
1658 | mi_results *sub; | ||
1659 | |||
1660 | while (c) | ||
1661 | { | ||
1662 | if (c->var) | ||
1663 | { | ||
1664 | if (strcmp(c->var,"src_and_asm_line")==0 && c->type==t_tuple) | ||
1665 | { | ||
1666 | if (!res) | ||
1667 | res=cur=mi_alloc_asm_insns(); | ||
1668 | else | ||
1669 | { | ||
1670 | cur->next=mi_alloc_asm_insns(); | ||
1671 | cur=cur->next; | ||
1672 | } | ||
1673 | if (!cur) | ||
1674 | { | ||
1675 | mi_free_asm_insns(res); | ||
1676 | return NULL; | ||
1677 | } | ||
1678 | sub=c->v.rs; | ||
1679 | while (sub) | ||
1680 | { | ||
1681 | if (sub->var) | ||
1682 | { | ||
1683 | if (sub->type==t_const) | ||
1684 | { | ||
1685 | if (strcmp(sub->var,"line")==0) | ||
1686 | cur->line=atoi(sub->v.cstr); | ||
1687 | else if (strcmp(sub->var,"file")==0) | ||
1688 | { | ||
1689 | cur->file=sub->v.cstr; | ||
1690 | sub->v.cstr=NULL; | ||
1691 | } | ||
1692 | } | ||
1693 | else if (sub->type==t_list) | ||
1694 | { | ||
1695 | if (strcmp(sub->var,"line_asm_insn")==0) | ||
1696 | cur->ins=mi_parse_insn(sub->v.rs); | ||
1697 | } | ||
1698 | } | ||
1699 | sub=sub->next; | ||
1700 | } | ||
1701 | } | ||
1702 | } | ||
1703 | else | ||
1704 | {/* No source line, just instructions */ | ||
1705 | res=mi_alloc_asm_insns(); | ||
1706 | res->ins=mi_parse_insn(c); | ||
1707 | break; | ||
1708 | } | ||
1709 | c=c->next; | ||
1710 | } | ||
1711 | return res; | ||
1712 | } | ||
1713 | |||
1714 | |||
1715 | mi_asm_insns *mi_get_asm_insns(mi_h *h) | ||
1716 | { | ||
1717 | mi_results *r=mi_res_done_var(h,"asm_insns"); | ||
1718 | mi_asm_insns *f=NULL; | ||
1719 | |||
1720 | if (r && r->type==t_list) | ||
1721 | f=mi_parse_insns(r->v.rs); | ||
1722 | mi_free_results(r); | ||
1723 | return f; | ||
1724 | } | ||
1725 | |||
1726 | mi_chg_reg *mi_parse_list_regs(mi_results *r, int *how_many) | ||
1727 | { | ||
1728 | mi_results *c=r; | ||
1729 | int cregs=0; | ||
1730 | mi_chg_reg *first=NULL, *cur=NULL; | ||
1731 | |||
1732 | /* Create the list. */ | ||
1733 | while (c) | ||
1734 | { | ||
1735 | if (c->type==t_const && !c->var) | ||
1736 | { | ||
1737 | if (first) | ||
1738 | cur=cur->next=mi_alloc_chg_reg(); | ||
1739 | else | ||
1740 | first=cur=mi_alloc_chg_reg(); | ||
1741 | cur->name=c->v.cstr; | ||
1742 | cur->reg=cregs++; | ||
1743 | c->v.cstr=NULL; | ||
1744 | } | ||
1745 | c=c->next; | ||
1746 | } | ||
1747 | if (how_many) | ||
1748 | *how_many=cregs; | ||
1749 | |||
1750 | return first; | ||
1751 | } | ||
1752 | |||
1753 | mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many) | ||
1754 | { | ||
1755 | mi_results *r=mi_res_done_var(h,"register-names"); | ||
1756 | mi_chg_reg *l=NULL; | ||
1757 | |||
1758 | if (r && r->type==t_list) | ||
1759 | l=mi_parse_list_regs(r->v.rs,how_many); | ||
1760 | mi_free_results(r); | ||
1761 | return l; | ||
1762 | } | ||
1763 | |||
1764 | mi_chg_reg *mi_parse_list_changed_regs(mi_results *r) | ||
1765 | { | ||
1766 | mi_results *c=r; | ||
1767 | mi_chg_reg *first=NULL, *cur=NULL; | ||
1768 | |||
1769 | /* Create the list. */ | ||
1770 | while (c) | ||
1771 | { | ||
1772 | if (c->type==t_const && !c->var) | ||
1773 | { | ||
1774 | if (first) | ||
1775 | cur=cur->next=mi_alloc_chg_reg(); | ||
1776 | else | ||
1777 | first=cur=mi_alloc_chg_reg(); | ||
1778 | cur->reg=atoi(c->v.cstr); | ||
1779 | } | ||
1780 | c=c->next; | ||
1781 | } | ||
1782 | |||
1783 | return first; | ||
1784 | } | ||
1785 | |||
1786 | mi_chg_reg *mi_get_list_changed_regs(mi_h *h) | ||
1787 | { | ||
1788 | mi_results *r=mi_res_done_var(h,"changed-registers"); | ||
1789 | mi_chg_reg *changed=NULL; | ||
1790 | |||
1791 | if (r && r->type==t_list) | ||
1792 | changed=mi_parse_list_changed_regs(r->v.rs); | ||
1793 | mi_free_results(r); | ||
1794 | return changed; | ||
1795 | } | ||
1796 | |||
1797 | int mi_parse_reg_values(mi_results *r, mi_chg_reg *l) | ||
1798 | { | ||
1799 | mi_results *c; | ||
1800 | |||
1801 | while (r && l) | ||
1802 | { | ||
1803 | if (r->type==t_tuple && !r->var) | ||
1804 | { | ||
1805 | c=r->v.rs; | ||
1806 | while (c) | ||
1807 | { | ||
1808 | if (c->type==t_const && c->var) | ||
1809 | { | ||
1810 | if (strcmp(c->var,"number")==0) | ||
1811 | { | ||
1812 | if (atoi(c->v.cstr)!=l->reg) | ||
1813 | { | ||
1814 | mi_error=MI_PARSER; | ||
1815 | return 0; | ||
1816 | } | ||
1817 | } | ||
1818 | else if (strcmp(c->var,"value")==0) | ||
1819 | { | ||
1820 | l->val=c->v.cstr; | ||
1821 | c->v.cstr=NULL; | ||
1822 | } | ||
1823 | } | ||
1824 | c=c->next; | ||
1825 | } | ||
1826 | } | ||
1827 | r=r->next; | ||
1828 | l=l->next; | ||
1829 | } | ||
1830 | |||
1831 | return !l && !r; | ||
1832 | } | ||
1833 | |||
1834 | int mi_get_reg_values(mi_h *h, mi_chg_reg *l) | ||
1835 | { | ||
1836 | mi_results *r=mi_res_done_var(h,"register-values"); | ||
1837 | int ok=0; | ||
1838 | |||
1839 | if (r && r->type==t_list) | ||
1840 | ok=mi_parse_reg_values(r->v.rs,l); | ||
1841 | mi_free_results(r); | ||
1842 | return ok; | ||
1843 | } | ||
1844 | |||
1845 | int mi_parse_list_regs_l(mi_results *r, mi_chg_reg *l) | ||
1846 | { | ||
1847 | while (r && l) | ||
1848 | { | ||
1849 | if (r->type==t_const && !r->var) | ||
1850 | { | ||
1851 | free(l->name); | ||
1852 | l->name=r->v.cstr; | ||
1853 | r->v.cstr=NULL; | ||
1854 | l=l->next; | ||
1855 | } | ||
1856 | r=r->next; | ||
1857 | } | ||
1858 | |||
1859 | return !l && !r; | ||
1860 | } | ||
1861 | |||
1862 | int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l) | ||
1863 | { | ||
1864 | mi_results *r=mi_res_done_var(h,"register-names"); | ||
1865 | int ok=0; | ||
1866 | |||
1867 | if (r && r->type==t_list) | ||
1868 | ok=mi_parse_list_regs_l(r->v.rs,l); | ||
1869 | mi_free_results(r); | ||
1870 | return ok; | ||
1871 | } | ||
1872 | |||
1873 | mi_chg_reg *mi_parse_reg_values_l(mi_results *r, int *how_many) | ||
1874 | { | ||
1875 | mi_results *c; | ||
1876 | mi_chg_reg *first=NULL, *cur=NULL; | ||
1877 | *how_many=0; | ||
1878 | |||
1879 | while (r) | ||
1880 | { | ||
1881 | if (r->type==t_tuple && !r->var) | ||
1882 | { | ||
1883 | c=r->v.rs; | ||
1884 | if (first) | ||
1885 | cur=cur->next=mi_alloc_chg_reg(); | ||
1886 | else | ||
1887 | first=cur=mi_alloc_chg_reg(); | ||
1888 | while (c) | ||
1889 | { | ||
1890 | if (c->type==t_const && c->var) | ||
1891 | { | ||
1892 | if (strcmp(c->var,"number")==0) | ||
1893 | { | ||
1894 | cur->reg=atoi(c->v.cstr); | ||
1895 | (*how_many)++; | ||
1896 | } | ||
1897 | else if (strcmp(c->var,"value")==0) | ||
1898 | { | ||
1899 | cur->val=c->v.cstr; | ||
1900 | c->v.cstr=NULL; | ||
1901 | } | ||
1902 | } | ||
1903 | c=c->next; | ||
1904 | } | ||
1905 | } | ||
1906 | r=r->next; | ||
1907 | } | ||
1908 | |||
1909 | return first; | ||
1910 | } | ||
1911 | |||
1912 | mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many) | ||
1913 | { | ||
1914 | mi_results *r=mi_res_done_var(h,"register-values"); | ||
1915 | mi_chg_reg *rgs=NULL; | ||
1916 | |||
1917 | if (r && r->type==t_list) | ||
1918 | rgs=mi_parse_reg_values_l(r->v.rs,how_many); | ||
1919 | mi_free_results(r); | ||
1920 | return rgs; | ||
1921 | } | ||
1922 | |||
1923 | |||