aboutsummaryrefslogtreecommitdiff
path: root/src/monkey/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/monkey/connect.c')
-rw-r--r--src/monkey/connect.c884
1 files changed, 884 insertions, 0 deletions
diff --git a/src/monkey/connect.c b/src/monkey/connect.c
new file mode 100644
index 000000000..eaca967da
--- /dev/null
+++ b/src/monkey/connect.c
@@ -0,0 +1,884 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2009 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: Connect.
7 Comments:
8 This module handles the dialog with gdb, including starting and stopping
9gdb.@p
10
11GDB Bug workaround for "file -readnow": I tried to workaround a bug using
12it but looks like this option also have bugs!!!! so I have to use the
13command line option --readnow.
14It also have a bug!!!! when the binary is changed and gdb must reload it
15this option is ignored. So it looks like we have no solution but 3 gdb bugs
16in a row.
17
18***************************************************************************/
19
20#define _GNU_SOURCE
21#include <sys/types.h>
22#include <unistd.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/wait.h>
26#include <fcntl.h>
27#include <string.h>
28#include <stdarg.h>
29#include <limits.h>
30#include <errno.h>
31#include <signal.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include "mi_gdb.h"
35
36#ifndef TEMP_FAILURE_RETRY
37 #define TEMP_FAILURE_RETRY(a) (a)
38#endif
39
40int mi_error=MI_OK;
41char *mi_error_from_gdb=NULL;
42static char *gdb_exe=NULL;
43static char *xterm_exe=NULL;
44static char *gdb_start=NULL;
45static char *gdb_conn=NULL;
46static char *main_func=NULL;
47static char disable_psym_search_workaround=0;
48
49mi_h *mi_alloc_h()
50{
51 mi_h *h=(mi_h *)calloc(1,sizeof(mi_h));
52 if (!h)
53 {
54 mi_error=MI_OUT_OF_MEMORY;
55 return NULL;
56 }
57 h->to_gdb[0]=h->to_gdb[1]=h->from_gdb[0]=h->from_gdb[1]=-1;
58 h->pid=-1;
59 return h;
60}
61
62int mi_check_running_pid(pid_t pid)
63{
64 int status;
65
66 if (pid<=0)
67 return 0;
68 /* If waitpid returns the number of our child means it communicated
69 to as a termination status. */
70 if (waitpid(pid,&status,WNOHANG)==pid)
71 {
72 pid=0;
73 return 0;
74 }
75 return 1;
76}
77
78int mi_check_running(mi_h *h)
79{
80 return !h->died && mi_check_running_pid(h->pid);
81}
82
83void mi_kill_child(pid_t pid)
84{
85 kill(pid,SIGTERM);
86 usleep(100000);
87 if (mi_check_running_pid(pid))
88 {
89 int status;
90 kill(pid,SIGKILL);
91 waitpid(pid,&status,0);
92 }
93}
94
95void mi_free_h(mi_h **handle)
96{
97 mi_h *h=*handle;
98 if (h->to_gdb[0]>=0)
99 close(h->to_gdb[0]);
100 if (h->to)
101 fclose(h->to);
102 else if (h->to_gdb[1]>=0)
103 close(h->to_gdb[1]);
104 if (h->from)
105 fclose(h->from);
106 else if (h->from_gdb[0]>=0)
107 close(h->from_gdb[0]);
108 if (h->from_gdb[1]>=0)
109 close(h->from_gdb[1]);
110 if (mi_check_running(h))
111 {/* GDB is running! */
112 mi_kill_child(h->pid);
113 }
114 if (h->line)
115 free(h->line);
116 mi_free_output(h->po);
117 free(h->catched_console);
118 free(h);
119 *handle=NULL;
120}
121
122void mi_set_nonblk(int h)
123{
124 int flf;
125 flf=fcntl(h,F_GETFL,0);
126 flf=flf | O_NONBLOCK;
127 fcntl(h,F_SETFL,flf);
128}
129
130int mi_getline(mi_h *h)
131{
132 char c;
133
134 while (read(h->from_gdb[0],&c,1)==1)
135 {
136 if (h->lread>=h->llen)
137 {
138 h->llen=h->lread+128;
139 h->line=(char *)realloc(h->line,h->llen);
140 if (!h->line)
141 {
142 h->llen=0;
143 h->lread=0;
144 return -1;
145 }
146 }
147 if (c=='\n')
148 {
149 int ret=h->lread;
150 h->line[ret]=0;
151 h->lread=0;
152 return ret;
153 }
154 h->line[h->lread]=c;
155 h->lread++;
156 }
157 return 0;
158}
159
160char *get_cstr(mi_output *o)
161{
162 if (!o->c || o->c->type!=t_const)
163 return NULL;
164 return o->c->v.cstr;
165}
166
167int mi_get_response(mi_h *h)
168{
169 int l=mi_getline(h);
170 if (!l)
171 return 0;
172
173 if (h->from_gdb_echo)
174 h->from_gdb_echo(h->line,h->from_gdb_echo_data);
175 if (strncmp(h->line,"(gdb)",5)==0)
176 {/* End of response. */
177 return 1;
178 }
179 else
180 {/* Add to the response. */
181 mi_output *o;
182 int add=1, is_exit=0;
183 o=mi_parse_gdb_output(h->line);
184
185 if (!o)
186 return 0;
187 /* Tunneled streams callbacks. */
188 if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_STREAM)
189 {
190 char *aux;
191 add=0;
192 switch (o->sstype)
193 {
194 case MI_SST_CONSOLE:
195 aux=get_cstr(o);
196 if (h->console)
197 h->console(aux,h->console_data);
198 if (h->catch_console && aux)
199 {
200 h->catch_console--;
201 if (!h->catch_console)
202 {
203 free(h->catched_console);
204 h->catched_console=strdup(aux);
205 }
206 }
207 break;
208 case MI_SST_TARGET:
209 /* This one seems to be useless. */
210 if (h->target)
211 h->target(get_cstr(o),h->target_data);
212 break;
213 case MI_SST_LOG:
214 if (h->log)
215 h->log(get_cstr(o),h->log_data);
216 break;
217 }
218 }
219 else if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_ASYNC)
220 {
221 if (h->async)
222 h->async(o,h->async_data);
223 }
224 else if (o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_ERROR)
225 {/* Error from gdb, record it. */
226 mi_error=MI_FROM_GDB;
227 free(mi_error_from_gdb);
228 mi_error_from_gdb=NULL;
229 if (o->c && strcmp(o->c->var,"msg")==0 && o->c->type==t_const)
230 mi_error_from_gdb=strdup(o->c->v.cstr);
231 }
232 is_exit=(o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_EXIT);
233 /* Add to the list of responses. */
234 if (add)
235 {
236 if (h->last)
237 h->last->next=o;
238 else
239 h->po=o;
240 h->last=o;
241 }
242 else
243 mi_free_output(o);
244 /* Exit RR means gdb exited, we won't get a new prompt ;-) */
245 if (is_exit)
246 return 1;
247 }
248
249 return 0;
250}
251
252mi_output *mi_retire_response(mi_h *h)
253{
254 mi_output *ret=h->po;
255 h->po=h->last=NULL;
256 return ret;
257}
258
259mi_output *mi_get_response_blk(mi_h *h)
260{
261 int r;
262 /* Sometimes gdb dies. */
263 if (!mi_check_running(h))
264 {
265 h->died=1;
266 mi_error=MI_GDB_DIED;
267 return NULL;
268 }
269 do
270 {
271 if (1)
272 {
273 /*
274 That's a must. If we just keep trying to read and failing things
275 become really sloooowwww. Instead we try and if it fails we wait
276 until something is available.
277 TODO: Implement something with the time out, a callback to ask the
278 application is we have to wait or not could be a good thing.
279 */
280 fd_set set;
281 struct timeval timeout;
282 int ret;
283
284 r=mi_get_response(h);
285 if (r)
286 return mi_retire_response(h);
287
288 FD_ZERO(&set);
289 FD_SET(h->from_gdb[0],&set);
290 timeout.tv_sec=h->time_out;
291 timeout.tv_usec=0;
292 ret=TEMP_FAILURE_RETRY(select(FD_SETSIZE,&set,NULL,NULL,&timeout));
293 if (!ret)
294 {
295 if (!mi_check_running(h))
296 {
297 h->died=1;
298 mi_error=MI_GDB_DIED;
299 return NULL;
300 }
301 if (h->time_out_cb)
302 ret=h->time_out_cb(h->time_out_cb_data);
303 if (!ret)
304 {
305 mi_error=MI_GDB_TIME_OUT;
306 return NULL;
307 }
308 }
309 }
310 else
311 {
312 r=mi_get_response(h);
313 if (r)
314 return mi_retire_response(h);
315 else
316 usleep(100);
317 }
318 }
319 while (!r);
320
321 return NULL;
322}
323
324void mi_send_commands(mi_h *h, const char *file)
325{
326 FILE *f;
327 char b[PATH_MAX];
328
329 //printf("File: %s\n",file);
330 if (!file)
331 return;
332 f=fopen(file,"rt");
333 if (!f)
334 return;
335 while (!feof(f))
336 {
337 if (fgets(b,PATH_MAX,f))
338 {
339 //printf("Send: %s\n",b);
340 mi_send(h,b);
341 mi_res_simple_done(h);
342 }
343 }
344 fclose(f);
345}
346
347void mi_send_target_commands(mi_h *h)
348{
349 mi_send_commands(h,gdb_conn);
350}
351
352/**[txh]********************************************************************
353
354 Description:
355 Connect to a local copy of gdb. Note that the mi_h structure is something
356similar to a "FILE *" for stdio.
357
358 Return: A new mi_h structure or NULL on error.
359
360***************************************************************************/
361
362mi_h *mi_connect_local()
363{
364 mi_h *h;
365 const char *gdb=mi_get_gdb_exe();
366
367 /* Start without error. */
368 mi_error=MI_OK;
369 /* Verify we have a GDB binary. */
370 if (access(gdb,X_OK))
371 {
372 mi_error=MI_MISSING_GDB;
373 return NULL;
374 }
375 /* Alloc the handle structure. */
376 h=mi_alloc_h();
377 if (!h)
378 return h;
379 h->time_out=MI_DEFAULT_TIME_OUT;
380 /* Create the pipes to connect with the child. */
381 if (pipe(h->to_gdb) || pipe(h->from_gdb))
382 {
383 mi_error=MI_PIPE_CREATE;
384 mi_free_h(&h);
385 return NULL;
386 }
387 mi_set_nonblk(h->to_gdb[1]);
388 mi_set_nonblk(h->from_gdb[0]);
389 /* Associate streams to the file handles. */
390 h->to=fdopen(h->to_gdb[1],"w");
391 h->from=fdopen(h->from_gdb[0],"r");
392 if (!h->to || !h->from)
393 {
394 mi_error=MI_PIPE_CREATE;
395 mi_free_h(&h);
396 return NULL;
397 }
398 /* Create the child. */
399 h->pid=fork();
400 if (h->pid==0)
401 {/* We are the child. */
402 char *argv[5];
403 /* Connect stdin/out to the pipes. */
404 dup2(h->to_gdb[0],STDIN_FILENO);
405 dup2(h->from_gdb[1],STDOUT_FILENO);
406 /* Pass the control to gdb. */
407 argv[0]=(char *)gdb; /* Is that OK? */
408 argv[1]="--interpreter=mi";
409 argv[2]="--quiet";
410 argv[3]=disable_psym_search_workaround ? 0 : "--readnow";
411 argv[4]=0;
412 execvp(argv[0],argv);
413 /* We get here only if exec failed. */
414 _exit(127);
415 }
416 /* We are the parent. */
417 if (h->pid==-1)
418 {/* Fork failed. */
419 mi_error=MI_FORK;
420 mi_free_h(&h);
421 return NULL;
422 }
423 if (!mi_check_running(h))
424 {
425 mi_error=MI_DEBUGGER_RUN;
426 mi_free_h(&h);
427 return NULL;
428 }
429 /* Wait for the prompt. */
430 mi_get_response_blk(h);
431 /* Send the start-up commands */
432 mi_send_commands(h,gdb_start);
433
434 return h;
435}
436
437/**[txh]********************************************************************
438
439 Description:
440 Close connection. You should ask gdb to quit first @x{gmi_gdb_exit}.
441
442***************************************************************************/
443
444void mi_disconnect(mi_h *h)
445{
446 mi_free_h(&h);
447 free(mi_error_from_gdb);
448 mi_error_from_gdb=NULL;
449}
450
451void mi_set_console_cb(mi_h *h, stream_cb cb, void *data)
452{
453 h->console=cb;
454 h->console_data=data;
455}
456
457void mi_set_target_cb(mi_h *h, stream_cb cb, void *data)
458{
459 h->target=cb;
460 h->target_data=data;
461}
462
463void mi_set_log_cb(mi_h *h, stream_cb cb, void *data)
464{
465 h->log=cb;
466 h->log_data=data;
467}
468
469stream_cb mi_get_console_cb(mi_h *h, void **data)
470{
471 if (data)
472 *data=h->console_data;
473 return h->console;
474}
475
476stream_cb mi_get_target_cb(mi_h *h, void **data)
477{
478 if (data)
479 *data=h->target_data;
480 return h->target;
481}
482
483stream_cb mi_get_log_cb(mi_h *h, void **data)
484{
485 if (data)
486 *data=h->log_data;
487 return h->log;
488}
489
490void mi_set_async_cb(mi_h *h, async_cb cb, void *data)
491{
492 h->async=cb;
493 h->async_data=data;
494}
495
496async_cb mi_get_async_cb(mi_h *h, void **data)
497{
498 if (data)
499 *data=h->async_data;
500 return h->async;
501}
502
503void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data)
504{
505 h->to_gdb_echo=cb;
506 h->to_gdb_echo_data=data;
507}
508
509void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data)
510{
511 h->from_gdb_echo=cb;
512 h->from_gdb_echo_data=data;
513}
514
515stream_cb mi_get_to_gdb_cb(mi_h *h, void **data)
516{
517 if (data)
518 *data=h->to_gdb_echo_data;
519 return h->to_gdb_echo;
520}
521
522stream_cb mi_get_from_gdb_cb(mi_h *h, void **data)
523{
524 if (data)
525 *data=h->from_gdb_echo_data;
526 return h->from_gdb_echo;
527}
528
529void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data)
530{
531 h->time_out_cb=cb;
532 h->time_out_cb_data=data;
533}
534
535tm_cb mi_get_time_out_cb(mi_h *h, void **data)
536{
537 if (data)
538 *data=h->time_out_cb_data;
539 return h->time_out_cb;
540}
541
542void mi_set_time_out(mi_h *h, int to)
543{
544 h->time_out=to;
545}
546
547int mi_get_time_out(mi_h *h)
548{
549 return h->time_out;
550}
551
552int mi_send(mi_h *h, const char *format, ...)
553{
554 int ret;
555 char *str;
556 va_list argptr;
557
558 if (h->died)
559 return 0;
560
561 va_start(argptr,format);
562 ret=vasprintf(&str,format,argptr);
563 va_end(argptr);
564 fputs(str,h->to);
565 fflush(h->to);
566 if (h->to_gdb_echo)
567 h->to_gdb_echo(str,h->to_gdb_echo_data);
568 free(str);
569
570 return ret;
571}
572
573void mi_clean_up_globals()
574{
575 free(gdb_exe);
576 gdb_exe=NULL;
577 free(xterm_exe);
578 xterm_exe=NULL;
579 free(gdb_start);
580 gdb_start=NULL;
581 free(gdb_conn);
582 gdb_conn=NULL;
583 free(main_func);
584 main_func=NULL;
585}
586
587void mi_register_exit()
588{
589 static int registered=0;
590 if (!registered)
591 {
592 registered=1;
593 atexit(mi_clean_up_globals);
594 }
595}
596
597void mi_set_gdb_exe(const char *name)
598{
599 free(gdb_exe);
600 gdb_exe=name ? strdup(name) : NULL;
601 mi_register_exit();
602}
603
604void mi_set_gdb_start(const char *name)
605{
606 free(gdb_start);
607 gdb_start=name ? strdup(name) : NULL;
608 mi_register_exit();
609}
610
611void mi_set_gdb_conn(const char *name)
612{
613 free(gdb_conn);
614 gdb_conn=name ? strdup(name) : NULL;
615 mi_register_exit();
616}
617
618static
619char *mi_search_in_path(const char *file)
620{
621 char *path, *pt, *r;
622 char test[PATH_MAX];
623 struct stat st;
624
625 path=getenv("PATH");
626 if (!path)
627 return NULL;
628 pt=strdup(path);
629 r=strtok(pt,":");
630 while (r)
631 {
632 strcpy(test,r);
633 strcat(test,"/");
634 strcat(test,file);
635 if (stat(test,&st)==0 && S_ISREG(st.st_mode))
636 {
637 free(pt);
638 return strdup(test);
639 }
640 r=strtok(NULL,":");
641 }
642 free(pt);
643 return NULL;
644}
645
646const char *mi_get_gdb_exe()
647{
648 if (!gdb_exe)
649 {/* Look for gdb in path */
650 gdb_exe=mi_search_in_path("gdb");
651 if (!gdb_exe)
652 return "/usr/bin/gdb";
653 }
654 return gdb_exe;
655}
656
657const char *mi_get_gdb_start()
658{
659 return gdb_start;
660}
661
662const char *mi_get_gdb_conn()
663{
664 return gdb_conn;
665}
666
667void mi_set_xterm_exe(const char *name)
668{
669 free(xterm_exe);
670 xterm_exe=name ? strdup(name) : NULL;
671 mi_register_exit();
672}
673
674const char *mi_get_xterm_exe()
675{
676 if (!xterm_exe)
677 {/* Look for xterm in path */
678 xterm_exe=mi_search_in_path("xterm");
679 if (!xterm_exe)
680 return "/usr/bin/X11/xterm";
681 }
682 return xterm_exe;
683}
684
685void mi_set_main_func(const char *name)
686{
687 free(main_func);
688 main_func=name ? strdup(name) : NULL;
689 mi_register_exit();
690}
691
692const char *mi_get_main_func()
693{
694 if (main_func)
695 return main_func;
696 return "main";
697}
698
699/**[txh]********************************************************************
700
701 Description:
702 Opens a new xterm to be used by the child process to debug.
703
704 Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
705release it.
706
707***************************************************************************/
708
709mi_aux_term *gmi_start_xterm()
710{
711 char nsh[14]="/tmp/shXXXXXX";
712 char ntt[14]="/tmp/ttXXXXXX";
713 const char *xterm;
714 struct stat st;
715 int hsh, htt=-1;
716 mi_aux_term *res=NULL;
717 FILE *f;
718 pid_t pid;
719 char buf[PATH_MAX];
720
721 /* Verify we have an X terminal. */
722 xterm=mi_get_xterm_exe();
723 if (access(xterm,X_OK))
724 {
725 mi_error=MI_MISSING_XTERM;
726 return NULL;
727 }
728
729 /* Create 2 temporals. */
730 hsh=mkstemp(nsh);
731 if (hsh==-1)
732 {
733 mi_error=MI_CREATE_TEMPORAL;
734 return NULL;
735 }
736 htt=mkstemp(ntt);
737 if (htt==-1)
738 {
739 close(hsh);
740 unlink(nsh);
741 mi_error=MI_CREATE_TEMPORAL;
742 return NULL;
743 }
744 close(htt);
745 /* Create the script. */
746 f=fdopen(hsh,"w");
747 if (!f)
748 {
749 close(hsh);
750 unlink(nsh);
751 unlink(ntt);
752 mi_error=MI_CREATE_TEMPORAL;
753 return NULL;
754 }
755 fprintf(f,"#!/bin/sh\n");
756 fprintf(f,"tty > %s\n",ntt);
757 fprintf(f,"rm %s\n",nsh);
758 fprintf(f,"sleep 365d\n");
759 fclose(f);
760 /* Spawn xterm. */
761 /* Create the child. */
762 pid=fork();
763 if (pid==0)
764 {/* We are the child. */
765 char *argv[5];
766 /* Pass the control to gdb. */
767 argv[0]=(char *)mi_get_xterm_exe(); /* Is that ok? */
768 argv[1]="-e";
769 argv[2]="/bin/sh";
770 argv[3]=nsh;
771 argv[4]=0;
772 execvp(argv[0],argv);
773 /* We get here only if exec failed. */
774 unlink(nsh);
775 unlink(ntt);
776 _exit(127);
777 }
778 /* We are the parent. */
779 if (pid==-1)
780 {/* Fork failed. */
781 unlink(nsh);
782 unlink(ntt);
783 mi_error=MI_FORK;
784 return NULL;
785 }
786 /* Wait until the shell is deleted. */
787 while (stat(nsh,&st)==0)
788 usleep(1000);
789 /* Try to read the tty name. */
790 f=fopen(ntt,"rt");
791 if (f)
792 {
793 if (fgets(buf,PATH_MAX,f))
794 {
795 char *s; /* Strip the \n. */
796 for (s=buf; *s && *s!='\n'; s++);
797 *s=0;
798 res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
799 if (res)
800 {
801 res->pid=pid;
802 res->tty=strdup(buf);
803 }
804 }
805 fclose(f);
806 }
807 unlink(ntt);
808 return res;
809}
810
811void mi_free_aux_term(mi_aux_term *t)
812{
813 if (!t)
814 return;
815 free(t->tty);
816 free(t);
817}
818
819/**[txh]********************************************************************
820
821 Description:
822 Closes the auxiliar terminal and releases the allocated memory.
823
824***************************************************************************/
825
826void gmi_end_aux_term(mi_aux_term *t)
827{
828 if (!t)
829 return;
830 if (t->pid!=-1 && mi_check_running_pid(t->pid))
831 mi_kill_child(t->pid);
832 mi_free_aux_term(t);
833}
834
835/**[txh]********************************************************************
836
837 Description:
838 Forces the MI version. Currently the library can't detect it so you must
839force it manually. GDB 5.x implemented MI v1 and 6.x v2.
840
841***************************************************************************/
842
843void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
844 unsigned vMinor)
845{
846 h->version=MI_VERSION2U(vMajor,vMiddle,vMinor);
847}
848
849/**[txh]********************************************************************
850
851 Description:
852 Dis/Enables the @var{wa} workaround for a bug in gdb.
853
854***************************************************************************/
855
856void mi_set_workaround(unsigned wa, int enable)
857{
858 switch (wa)
859 {
860 case MI_PSYM_SEARCH:
861 disable_psym_search_workaround=enable ? 0 : 1;
862 break;
863 }
864}
865
866/**[txh]********************************************************************
867
868 Description:
869 Finds if the @var{wa} workaround for a bug in gdb is enabled.
870
871 Return: !=0 if enabled.
872
873***************************************************************************/
874
875int mi_get_workaround(unsigned wa)
876{
877 switch (wa)
878 {
879 case MI_PSYM_SEARCH:
880 return disable_psym_search_workaround==0;
881 }
882 return 0;
883}
884