diff options
Diffstat (limited to 'pathologist/src/mi/gdbmi_parse.c')
-rw-r--r-- | pathologist/src/mi/gdbmi_parse.c | 1927 |
1 files changed, 1927 insertions, 0 deletions
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 | ||
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 "gdbmi.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 | 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 | ||
96 | int mi_is_var_name_char(char c) | ||
97 | { | ||
98 | return isalnum(c) || c=='-' || c=='_'; | ||
99 | } | ||
100 | |||
101 | char *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 | |||
127 | int 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__ | ||
156 | int 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 | |||
192 | int 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 | |||
215 | int 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 | |||
250 | int 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 | |||
270 | int 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 | |||
285 | mi_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 | |||
311 | mi_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 | |||
341 | mi_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 | |||
380 | mi_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 | |||
402 | mi_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 | |||
408 | mi_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 | |||
414 | mi_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 | |||
420 | mi_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 | |||
433 | mi_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 | |||
439 | mi_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 | |||
445 | mi_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 | |||
451 | mi_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 | |||
483 | mi_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 | |||
496 | mi_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 | |||
507 | mi_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 | |||
514 | int 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 | |||
552 | mi_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 | |||
572 | int 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 | |||
588 | int mi_res_simple_done(mi_h *h) | ||
589 | { | ||
590 | return mi_res_simple(h,MI_CL_DONE,0); | ||
591 | } | ||
592 | |||
593 | int mi_res_simple_exit(mi_h *h) | ||
594 | { | ||
595 | return mi_res_simple(h,MI_CL_EXIT,1); | ||
596 | } | ||
597 | |||
598 | int mi_res_simple_running(mi_h *h) | ||
599 | { | ||
600 | return mi_res_simple(h,MI_CL_RUNNING,0); | ||
601 | } | ||
602 | |||
603 | int mi_res_simple_connected(mi_h *h) | ||
604 | { | ||
605 | return mi_res_simple(h,MI_CL_CONNECTED,0); | ||
606 | } | ||
607 | |||
608 | mi_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 | |||
625 | mi_results *mi_res_done_var(mi_h *h, const char *var) | ||
626 | { | ||
627 | return mi_res_var(h,var,MI_CL_DONE); | ||
628 | } | ||
629 | |||
630 | mi_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 | |||
674 | mi_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 | |||
685 | mi_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 | |||
722 | mi_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 | |||
754 | int 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 | |||
789 | int 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 | |||
802 | enum 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 | |||
816 | const 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 | |||
839 | enum 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 | |||
855 | const 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 | |||
885 | char 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 | |||
915 | mi_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 | |||
976 | mi_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 | |||
989 | mi_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 | |||
1028 | int 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 | |||
1120 | int 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 | |||
1184 | int 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 | |||
1216 | mi_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 | |||
1277 | mi_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 | |||
1288 | mi_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 | |||
1316 | mi_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 | |||
1344 | mi_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 | |||
1359 | char *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 | |||
1373 | mi_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 | |||
1385 | static | ||
1386 | char *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 | |||
1402 | static | ||
1403 | enum 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 | |||
1412 | static | ||
1413 | char *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 | |||
1429 | enum 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 | |||
1439 | const 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 | |||
1451 | mi_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 | |||
1539 | mi_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 | |||
1555 | int 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 | |||
1604 | mi_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 | |||
1654 | mi_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 | |||
1714 | mi_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 | |||
1725 | mi_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 | |||
1755 | mi_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 | |||
1766 | mi_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 | |||
1788 | mi_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 | |||
1799 | int 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 | |||
1836 | int 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 | |||
1847 | int 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 | |||
1864 | int 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 | |||
1875 | mi_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 | |||
1916 | mi_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 | |||