if !MINGW
-lib_LTLIBRARIES = libgnunetmonkey.la
-
-libgnunetmonkey_la_SOURCES = \
- monkey_api.c monkey.h
-libgnunetmonkey_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- -lesmtp
-libgnunetmonkey_la_LDFLAGS = \
- $(GN_LIB_LDFLAGS) $(WINFLAGS) \
- -version-info 0:0:0
-
-
bin_PROGRAMS = \
gnunet-monkey \
- gnunet-service-monkey \
- bug_null_pointer_exception \
- mail_sender
+ gnunet-service-monkey
+
+noinst_PROGRAMS = \
+ bug_null_pointer_exception
gnunet_monkey_SOURCES = \
- mi_gdb.h \
- alloc.c \
- breakpoint.c \
- connect.c \
- cpp_int.cc \
- data_man.c \
- error.c \
- get_free_pty.c \
- get_free_vt.c \
- gnunet-monkey.c \
- misc.c \
- parse.c \
- prg_control.c \
- stack_man.c \
- symbol_query.c \
- target_man.c \
- thread.c \
- var_obj.c
-
+ gdbmi.h \
+ gdbmi_alloc.c \
+ gdbmi_breakpoint.c \
+ gdbmi_connect.c \
+ gdbmi_cpp_int.cc \
+ gdbmi_data_man.c \
+ gdbmi_error.c \
+ gdbmi_get_free_pty.c \
+ gdbmi_get_free_vt.c \
+ gdbmi_misc.c \
+ gdbmi_parse.c \
+ gdbmi_prg_control.c \
+ gdbmi_stack_man.c \
+ gdbmi_symbol_query.c \
+ gdbmi_target_man.c \
+ gdbmi_thread.c \
+ gdbmi_var_obj.c \
+ gnunet-monkey.c
+
gnunet_monkey_LDADD = \
- $(top_builddir)/src/monkey/libgnunetmonkey.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
-
gnunet_service_monkey_SOURCES = \
gnunet-service-monkey.c
gnunet_service_monkey_LDADD = \
- $(top_builddir)/src/monkey/libgnunetmonkey.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
mail_sender_SOURCES = \
mail_sender.c
mail_sender_LDADD = \
- $(top_builddir)/src/monkey/libgnunetmonkey.la \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(GN_LIBINTL)
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
bug_null_pointer_exception_SOURCES = \
bug_null_pointer_exception.c
bug_null_pointer_exception_LDADD = \
- $(top_builddir)/src/monkey/libgnunetmonkey.la \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(GN_LIBINTL)
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
-
-check_PROGRAMS = \
- test_monkey_api
-
#TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
-test_monkey_api_SOURCES = \
- test_monkey_api.c
-test_monkey_api_LDADD = \
- $(top_builddir)/src/monkey/libgnunetmonkey.la \
- $(top_builddir)/src/util/libgnunetutil.la
-
check_SCRIPTS = \
test_gnunet_monkey.sh
EXTRA_DIST = \
- test_monkey_api_data.conf \
+ test_gnunet_monkey_data.conf \
$(check_SCRIPTS)
endif
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Allocator.
- Comments:
- Most alloc/free routines are here. Free routines must accept NULL
-pointers. Alloc functions must set mi_error.@p
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-void *mi_calloc(size_t count, size_t sz)
-{
- void *res=calloc(count,sz);
- if (!res)
- mi_error=MI_OUT_OF_MEMORY;
- return res;
-}
-
-void *mi_calloc1(size_t sz)
-{
- return mi_calloc(1,sz);
-}
-
-char *mi_malloc(size_t sz)
-{
- char *res=malloc(sz);
- if (!res)
- mi_error=MI_OUT_OF_MEMORY;
- return res;
-}
-
-mi_results *mi_alloc_results(void)
-{
- return (mi_results *)mi_calloc1(sizeof(mi_results));
-}
-
-mi_output *mi_alloc_output(void)
-{
- return (mi_output *)mi_calloc1(sizeof(mi_output));
-}
-
-mi_frames *mi_alloc_frames(void)
-{
- return (mi_frames *)mi_calloc1(sizeof(mi_frames));
-}
-
-mi_gvar *mi_alloc_gvar(void)
-{
- return (mi_gvar *)mi_calloc1(sizeof(mi_gvar));
-}
-
-mi_gvar_chg *mi_alloc_gvar_chg(void)
-{
- return (mi_gvar_chg *)mi_calloc1(sizeof(mi_gvar_chg));
-}
-
-mi_bkpt *mi_alloc_bkpt(void)
-{
- mi_bkpt *b=(mi_bkpt *)mi_calloc1(sizeof(mi_bkpt));
- if (b)
- {
- b->thread=-1;
- b->ignore=-1;
- }
- return b;
-}
-
-mi_wp *mi_alloc_wp(void)
-{
- return (mi_wp *)mi_calloc1(sizeof(mi_wp));
-}
-
-mi_stop *mi_alloc_stop(void)
-{
- return (mi_stop *)mi_calloc1(sizeof(mi_stop));
-}
-
-mi_asm_insns *mi_alloc_asm_insns(void)
-{
- return (mi_asm_insns *)mi_calloc1(sizeof(mi_asm_insns));
-}
-
-mi_asm_insn *mi_alloc_asm_insn(void)
-{
- return (mi_asm_insn *)mi_calloc1(sizeof(mi_asm_insn));
-}
-
-mi_chg_reg *mi_alloc_chg_reg(void)
-{
- return (mi_chg_reg *)mi_calloc1(sizeof(mi_chg_reg));
-}
-
-/*****************************************************************************
- Free functions
-*****************************************************************************/
-
-void mi_free_frames(mi_frames *f)
-{
- mi_frames *aux;
-
- while (f)
- {
- free(f->func);
- free(f->file);
- free(f->from);
- mi_free_results(f->args);
- aux=f->next;
- free(f);
- f=aux;
- }
-}
-
-void mi_free_bkpt(mi_bkpt *b)
-{
- mi_bkpt *aux;
-
- while (b)
- {
- free(b->func);
- free(b->file);
- free(b->file_abs);
- free(b->cond);
- aux=b->next;
- free(b);
- b=aux;
- }
-}
-
-void mi_free_gvar(mi_gvar *v)
-{
- mi_gvar *aux;
-
- while (v)
- {
- free(v->name);
- free(v->type);
- free(v->exp);
- free(v->value);
- if (v->numchild && v->child)
- mi_free_gvar(v->child);
- aux=v->next;
- free(v);
- v=aux;
- }
-}
-
-void mi_free_gvar_chg(mi_gvar_chg *p)
-{
- mi_gvar_chg *aux;
-
- while (p)
- {
- free(p->name);
- free(p->new_type);
- aux=p->next;
- free(p);
- p=aux;
- }
-}
-
-void mi_free_results_but(mi_results *r, mi_results *no)
-{
- mi_results *aux;
-
- while (r)
- {
- if (r==no)
- {
- aux=r->next;
- r->next=NULL;
- r=aux;
- }
- else
- {
- free(r->var);
- switch (r->type)
- {
- case t_const:
- free(r->v.cstr);
- break;
- case t_tuple:
- case t_list:
- mi_free_results_but(r->v.rs,no);
- break;
- }
- aux=r->next;
- free(r);
- r=aux;
- }
- }
-}
-
-void mi_free_results(mi_results *r)
-{
- mi_free_results_but(r,NULL);
-}
-
-void mi_free_output_but(mi_output *r, mi_output *no, mi_results *no_r)
-{
- mi_output *aux;
-
- while (r)
- {
- if (r==no)
- {
- aux=r->next;
- r->next=NULL;
- r=aux;
- }
- else
- {
- if (r->c)
- mi_free_results_but(r->c,no_r);
- aux=r->next;
- free(r);
- r=aux;
- }
- }
-}
-
-void mi_free_output(mi_output *r)
-{
- mi_free_output_but(r,NULL,NULL);
-}
-
-void mi_free_stop(mi_stop *s)
-{
- if (!s)
- return;
- mi_free_frames(s->frame);
- mi_free_wp(s->wp);
- free(s->wp_old);
- free(s->wp_val);
- free(s->gdb_result_var);
- free(s->return_value);
- free(s->signal_name);
- free(s->signal_meaning);
- free(s);
-}
-
-void mi_free_wp(mi_wp *wp)
-{
- mi_wp *aux;
- while (wp)
- {
- free(wp->exp);
- aux=wp->next;
- free(wp);
- wp=aux;
- }
-}
-
-void mi_free_asm_insns(mi_asm_insns *i)
-{
- mi_asm_insns *aux;
-
- while (i)
- {
- free(i->file);
- mi_free_asm_insn(i->ins);
- aux=i->next;
- free(i);
- i=aux;
- }
-}
-
-void mi_free_asm_insn(mi_asm_insn *i)
-{
- mi_asm_insn *aux;
-
- while (i)
- {
- free(i->func);
- free(i->inst);
- aux=i->next;
- free(i);
- i=aux;
- }
-}
-
-/*void mi_free_charp_list(char **l)
-{
- char **c=l;
- while (c)
- {
- free(*c);
- c++;
- }
- free(l);
-}*/
-
-void mi_free_chg_reg(mi_chg_reg *r)
-{
- mi_chg_reg *aux;
- while (r)
- {
- free(r->val);
- free(r->name);
- aux=r->next;
- free(r);
- r=aux;
- }
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Breakpoint table commands.
- Comments:
- GDB/MI commands for the "Breakpoint Table Commands" section.@p
-
-@<pre>
-gdb command: Implemented?
-
--break-after Yes
--break-condition Yes
--break-delete Yes
--break-disable Yes
--break-enable Yes
--break-info N.A. (info break NUMBER) (*)
--break-insert Yes
--break-list No (*)
--break-watch Yes
-@</pre>
-
-(*) I think the program should keep track of the breakpoints, so it will
-be implemented when I have more time.@p
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_break_insert_fl(mi_h *h, const char *file, int line)
-{
- mi_send(h,"-break-insert %s:%d\n",file,line);
-}
-
-void mi_break_insert(mi_h *h, int temporary, int hard_assist,
- const char *cond, int count, int thread,
- const char *where)
-{
- char s_count[32];
- char s_thread[32];
-
- if (count>=0)
- snprintf(s_count,32,"%d",count);
- if (thread>=0)
- snprintf(s_thread,32,"%d",thread);
- if (cond)
- // Conditions may contain spaces, in fact, if they don't gdb will add
- // them after parsing. Enclosing the expression with "" solves the
- // problem.
- mi_send(h,"-break-insert %s %s -c \"%s\" %s %s %s %s %s\n",
- temporary ? "-t" : "",
- hard_assist ? "-h" : "",
- cond,
- count>=0 ? "-i" : "", count>=0 ? s_count : "",
- thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
- where);
- else
- mi_send(h,"-break-insert %s %s %s %s %s %s %s\n",
- temporary ? "-t" : "",
- hard_assist ? "-h" : "",
- count>=0 ? "-i" : "", count>=0 ? s_count : "",
- thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
- where);
-}
-
-void mi_break_insert_flf(mi_h *h, const char *file, int line, int temporary,
- int hard_assist, const char *cond, int count,
- int thread)
-{
- char s_count[32];
- char s_thread[32];
-
- if (count>=0)
- snprintf(s_count,32,"%d",count);
- if (thread>=0)
- snprintf(s_thread,32,"%d",thread);
- mi_send(h,"-break-insert %s %s %s %s %s %s %s %s %s:%d\n",
- temporary ? "-t" : "",
- hard_assist ? "-h" : "",
- cond ? "-c" : "", cond ? cond : "",
- count>=0 ? "-i" : "", count>=0 ? s_count : "",
- thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
- file,line);
-}
-
-void mi_break_delete(mi_h *h, int number)
-{
- mi_send(h,"-break-delete %d\n",number);
-}
-
-void mi_break_after(mi_h *h, int number, int count)
-{
- mi_send(h,"-break-after %d %d\n",number,count);
-}
-
-void mi_break_condition(mi_h *h, int number, const char *condition)
-{
- mi_send(h,"-break-condition %d %s\n",number,condition);
-}
-
-void mi_break_enable(mi_h *h, int number)
-{
- mi_send(h,"-break-enable %d\n",number);
-}
-
-void mi_break_disable(mi_h *h, int number)
-{
- mi_send(h,"-break-disable %d\n",number);
-}
-
-void mi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp)
-{
- if (mode==wm_write)
- mi_send(h,"-break-watch \"%s\"\n",exp);
- else
- mi_send(h,"-break-watch -%c \"%s\"\n",mode==wm_rw ? 'a' : 'r',exp);
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- Insert a breakpoint at file:line.
-
- Command: -break-insert file:line
- Return: A new mi_bkpt structure with info about the breakpoint. NULL on
-error.
-
-***************************************************************************/
-
-mi_bkpt *gmi_break_insert(mi_h *h, const char *file, int line)
-{
- mi_break_insert_fl(h,file,line);
- return mi_res_bkpt(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Insert a breakpoint, all available options.
-
- Command: -break-insert
- Return: A new mi_bkpt structure with info about the breakpoint. NULL on
-error.
-
-***************************************************************************/
-
-mi_bkpt *gmi_break_insert_full(mi_h *h, int temporary, int hard_assist,
- const char *cond, int count, int thread,
- const char *where)
-{
- mi_break_insert(h,temporary,hard_assist,cond,count,thread,where);
- return mi_res_bkpt(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Insert a breakpoint, all available options.
-
- Command: -break-insert [ops] file:line
- Return: A new mi_bkpt structure with info about the breakpoint. NULL on
-error.
-
-***************************************************************************/
-
-mi_bkpt *gmi_break_insert_full_fl(mi_h *h, const char *file, int line,
- int temporary, int hard_assist,
- const char *cond, int count, int thread)
-{
- mi_break_insert_flf(h,file,line,temporary,hard_assist,cond,count,thread);
- return mi_res_bkpt(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Remove a breakpoint.
-
- Command: -break-delete
- Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
-console.
-
-***************************************************************************/
-
-int gmi_break_delete(mi_h *h, int number)
-{
- mi_break_delete(h,number);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Modify the "ignore" count for a breakpoint.
-
- Command: -break-after
- Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
-console.
-
-***************************************************************************/
-
-int gmi_break_set_times(mi_h *h, int number, int count)
-{
- mi_break_after(h,number,count);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Associate a condition with the breakpoint.
-
- Command: -break-condition
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_break_set_condition(mi_h *h, int number, const char *condition)
-{
- mi_break_condition(h,number,condition);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Enable or disable a breakpoint.
-
- Command: -break-enable + -break-disable
- Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
-console.
-
-***************************************************************************/
-
-int gmi_break_state(mi_h *h, int number, int enable)
-{
- if (enable)
- mi_break_enable(h,number);
- else
- mi_break_disable(h,number);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Set a watchpoint. It doesn't work for remote targets!
-
- Command: -break-watch
- Return: A new mi_wp structure with info about the watchpoint. NULL on
-error.
-
-***************************************************************************/
-
-mi_wp *gmi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp)
-{
- mi_break_watch(h,mode,exp);
- return mi_res_wp(h);
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004-2009 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Connect.
- Comments:
- This module handles the dialog with gdb, including starting and stopping
-gdb.@p
-
-GDB Bug workaround for "file -readnow": I tried to workaround a bug using
-it but looks like this option also have bugs!!!! so I have to use the
-command line option --readnow.
-It also have a bug!!!! when the binary is changed and gdb must reload it
-this option is ignored. So it looks like we have no solution but 3 gdb bugs
-in a row.
-
-***************************************************************************/
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include "mi_gdb.h"
-
-#ifndef TEMP_FAILURE_RETRY
- #define TEMP_FAILURE_RETRY(a) (a)
-#endif
-
-int mi_error=MI_OK;
-char *mi_error_from_gdb=NULL;
-static char *gdb_exe=NULL;
-static char *xterm_exe=NULL;
-static char *gdb_start=NULL;
-static char *gdb_conn=NULL;
-static char *main_func=NULL;
-static char disable_psym_search_workaround=0;
-
-mi_h *mi_alloc_h()
-{
- mi_h *h=(mi_h *)calloc(1,sizeof(mi_h));
- if (!h)
- {
- mi_error=MI_OUT_OF_MEMORY;
- return NULL;
- }
- h->to_gdb[0]=h->to_gdb[1]=h->from_gdb[0]=h->from_gdb[1]=-1;
- h->pid=-1;
- return h;
-}
-
-int mi_check_running_pid(pid_t pid)
-{
- int status;
-
- if (pid<=0)
- return 0;
- /* If waitpid returns the number of our child means it communicated
- to as a termination status. */
- if (waitpid(pid,&status,WNOHANG)==pid)
- {
- pid=0;
- return 0;
- }
- return 1;
-}
-
-int mi_check_running(mi_h *h)
-{
- return !h->died && mi_check_running_pid(h->pid);
-}
-
-void mi_kill_child(pid_t pid)
-{
- kill(pid,SIGTERM);
- usleep(100000);
- if (mi_check_running_pid(pid))
- {
- int status;
- kill(pid,SIGKILL);
- waitpid(pid,&status,0);
- }
-}
-
-void mi_free_h(mi_h **handle)
-{
- mi_h *h=*handle;
- if (h->to_gdb[0]>=0)
- close(h->to_gdb[0]);
- if (h->to)
- fclose(h->to);
- else if (h->to_gdb[1]>=0)
- close(h->to_gdb[1]);
- if (h->from)
- fclose(h->from);
- else if (h->from_gdb[0]>=0)
- close(h->from_gdb[0]);
- if (h->from_gdb[1]>=0)
- close(h->from_gdb[1]);
- if (mi_check_running(h))
- {/* GDB is running! */
- mi_kill_child(h->pid);
- }
- if (h->line)
- free(h->line);
- mi_free_output(h->po);
- free(h->catched_console);
- free(h);
- *handle=NULL;
-}
-
-void mi_set_nonblk(int h)
-{
- int flf;
- flf=fcntl(h,F_GETFL,0);
- flf=flf | O_NONBLOCK;
- fcntl(h,F_SETFL,flf);
-}
-
-int mi_getline(mi_h *h)
-{
- char c;
-
- while (read(h->from_gdb[0],&c,1)==1)
- {
- if (h->lread>=h->llen)
- {
- h->llen=h->lread+128;
- h->line=(char *)realloc(h->line,h->llen);
- if (!h->line)
- {
- h->llen=0;
- h->lread=0;
- return -1;
- }
- }
- if (c=='\n')
- {
- int ret=h->lread;
- h->line[ret]=0;
- h->lread=0;
- return ret;
- }
- h->line[h->lread]=c;
- h->lread++;
- }
- return 0;
-}
-
-char *get_cstr(mi_output *o)
-{
- if (!o->c || o->c->type!=t_const)
- return NULL;
- return o->c->v.cstr;
-}
-
-int mi_get_response(mi_h *h)
-{
- int l=mi_getline(h);
- if (!l)
- return 0;
-
- if (h->from_gdb_echo)
- h->from_gdb_echo(h->line,h->from_gdb_echo_data);
- if (strncmp(h->line,"(gdb)",5)==0)
- {/* End of response. */
- return 1;
- }
- else
- {/* Add to the response. */
- mi_output *o;
- int add=1, is_exit=0;
- o=mi_parse_gdb_output(h->line);
-
- if (!o)
- return 0;
- /* Tunneled streams callbacks. */
- if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_STREAM)
- {
- char *aux;
- add=0;
- switch (o->sstype)
- {
- case MI_SST_CONSOLE:
- aux=get_cstr(o);
- if (h->console)
- h->console(aux,h->console_data);
- if (h->catch_console && aux)
- {
- h->catch_console--;
- if (!h->catch_console)
- {
- free(h->catched_console);
- h->catched_console=strdup(aux);
- }
- }
- break;
- case MI_SST_TARGET:
- /* This one seems to be useless. */
- if (h->target)
- h->target(get_cstr(o),h->target_data);
- break;
- case MI_SST_LOG:
- if (h->log)
- h->log(get_cstr(o),h->log_data);
- break;
- }
- }
- else if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_ASYNC)
- {
- if (h->async)
- h->async(o,h->async_data);
- }
- else if (o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_ERROR)
- {/* Error from gdb, record it. */
- mi_error=MI_FROM_GDB;
- free(mi_error_from_gdb);
- mi_error_from_gdb=NULL;
- if (o->c && strcmp(o->c->var,"msg")==0 && o->c->type==t_const)
- mi_error_from_gdb=strdup(o->c->v.cstr);
- }
- is_exit=(o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_EXIT);
- /* Add to the list of responses. */
- if (add)
- {
- if (h->last)
- h->last->next=o;
- else
- h->po=o;
- h->last=o;
- }
- else
- mi_free_output(o);
- /* Exit RR means gdb exited, we won't get a new prompt ;-) */
- if (is_exit)
- return 1;
- }
-
- return 0;
-}
-
-mi_output *mi_retire_response(mi_h *h)
-{
- mi_output *ret=h->po;
- h->po=h->last=NULL;
- return ret;
-}
-
-mi_output *mi_get_response_blk(mi_h *h)
-{
- int r;
- /* Sometimes gdb dies. */
- if (!mi_check_running(h))
- {
- h->died=1;
- mi_error=MI_GDB_DIED;
- return NULL;
- }
- do
- {
- if (1)
- {
- /*
- That's a must. If we just keep trying to read and failing things
- become really sloooowwww. Instead we try and if it fails we wait
- until something is available.
- TODO: Implement something with the time out, a callback to ask the
- application is we have to wait or not could be a good thing.
- */
- fd_set set;
- struct timeval timeout;
- int ret;
-
- r=mi_get_response(h);
- if (r)
- return mi_retire_response(h);
-
- FD_ZERO(&set);
- FD_SET(h->from_gdb[0],&set);
- timeout.tv_sec=h->time_out;
- timeout.tv_usec=0;
- ret=TEMP_FAILURE_RETRY(select(FD_SETSIZE,&set,NULL,NULL,&timeout));
- if (!ret)
- {
- if (!mi_check_running(h))
- {
- h->died=1;
- mi_error=MI_GDB_DIED;
- return NULL;
- }
- if (h->time_out_cb)
- ret=h->time_out_cb(h->time_out_cb_data);
- if (!ret)
- {
- mi_error=MI_GDB_TIME_OUT;
- return NULL;
- }
- }
- }
- else
- {
- r=mi_get_response(h);
- if (r)
- return mi_retire_response(h);
- else
- usleep(100);
- }
- }
- while (!r);
-
- return NULL;
-}
-
-void mi_send_commands(mi_h *h, const char *file)
-{
- FILE *f;
- char b[PATH_MAX];
-
- //printf("File: %s\n",file);
- if (!file)
- return;
- f=fopen(file,"rt");
- if (!f)
- return;
- while (!feof(f))
- {
- if (fgets(b,PATH_MAX,f))
- {
- //printf("Send: %s\n",b);
- mi_send(h,b);
- mi_res_simple_done(h);
- }
- }
- fclose(f);
-}
-
-void mi_send_target_commands(mi_h *h)
-{
- mi_send_commands(h,gdb_conn);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Connect to a local copy of gdb. Note that the mi_h structure is something
-similar to a "FILE *" for stdio.
-
- Return: A new mi_h structure or NULL on error.
-
-***************************************************************************/
-
-mi_h *mi_connect_local()
-{
- mi_h *h;
- const char *gdb=mi_get_gdb_exe();
-
- /* Start without error. */
- mi_error=MI_OK;
- /* Verify we have a GDB binary. */
- if (access(gdb,X_OK))
- {
- mi_error=MI_MISSING_GDB;
- return NULL;
- }
- /* Alloc the handle structure. */
- h=mi_alloc_h();
- if (!h)
- return h;
- h->time_out=MI_DEFAULT_TIME_OUT;
- /* Create the pipes to connect with the child. */
- if (pipe(h->to_gdb) || pipe(h->from_gdb))
- {
- mi_error=MI_PIPE_CREATE;
- mi_free_h(&h);
- return NULL;
- }
- mi_set_nonblk(h->to_gdb[1]);
- mi_set_nonblk(h->from_gdb[0]);
- /* Associate streams to the file handles. */
- h->to=fdopen(h->to_gdb[1],"w");
- h->from=fdopen(h->from_gdb[0],"r");
- if (!h->to || !h->from)
- {
- mi_error=MI_PIPE_CREATE;
- mi_free_h(&h);
- return NULL;
- }
- /* Create the child. */
- h->pid=fork();
- if (h->pid==0)
- {/* We are the child. */
- char *argv[5];
- /* Connect stdin/out to the pipes. */
- dup2(h->to_gdb[0],STDIN_FILENO);
- dup2(h->from_gdb[1],STDOUT_FILENO);
- /* Pass the control to gdb. */
- argv[0]=(char *)gdb; /* Is that OK? */
- argv[1]="--interpreter=mi";
- argv[2]="--quiet";
- argv[3]=disable_psym_search_workaround ? 0 : "--readnow";
- argv[4]=0;
- execvp(argv[0],argv);
- /* We get here only if exec failed. */
- _exit(127);
- }
- /* We are the parent. */
- if (h->pid==-1)
- {/* Fork failed. */
- mi_error=MI_FORK;
- mi_free_h(&h);
- return NULL;
- }
- if (!mi_check_running(h))
- {
- mi_error=MI_DEBUGGER_RUN;
- mi_free_h(&h);
- return NULL;
- }
- /* Wait for the prompt. */
- mi_get_response_blk(h);
- /* Send the start-up commands */
- mi_send_commands(h,gdb_start);
-
- return h;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Close connection. You should ask gdb to quit first @x{gmi_gdb_exit}.
-
-***************************************************************************/
-
-void mi_disconnect(mi_h *h)
-{
- mi_free_h(&h);
- free(mi_error_from_gdb);
- mi_error_from_gdb=NULL;
-}
-
-void mi_set_console_cb(mi_h *h, stream_cb cb, void *data)
-{
- h->console=cb;
- h->console_data=data;
-}
-
-void mi_set_target_cb(mi_h *h, stream_cb cb, void *data)
-{
- h->target=cb;
- h->target_data=data;
-}
-
-void mi_set_log_cb(mi_h *h, stream_cb cb, void *data)
-{
- h->log=cb;
- h->log_data=data;
-}
-
-stream_cb mi_get_console_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->console_data;
- return h->console;
-}
-
-stream_cb mi_get_target_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->target_data;
- return h->target;
-}
-
-stream_cb mi_get_log_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->log_data;
- return h->log;
-}
-
-void mi_set_async_cb(mi_h *h, async_cb cb, void *data)
-{
- h->async=cb;
- h->async_data=data;
-}
-
-async_cb mi_get_async_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->async_data;
- return h->async;
-}
-
-void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data)
-{
- h->to_gdb_echo=cb;
- h->to_gdb_echo_data=data;
-}
-
-void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data)
-{
- h->from_gdb_echo=cb;
- h->from_gdb_echo_data=data;
-}
-
-stream_cb mi_get_to_gdb_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->to_gdb_echo_data;
- return h->to_gdb_echo;
-}
-
-stream_cb mi_get_from_gdb_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->from_gdb_echo_data;
- return h->from_gdb_echo;
-}
-
-void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data)
-{
- h->time_out_cb=cb;
- h->time_out_cb_data=data;
-}
-
-tm_cb mi_get_time_out_cb(mi_h *h, void **data)
-{
- if (data)
- *data=h->time_out_cb_data;
- return h->time_out_cb;
-}
-
-void mi_set_time_out(mi_h *h, int to)
-{
- h->time_out=to;
-}
-
-int mi_get_time_out(mi_h *h)
-{
- return h->time_out;
-}
-
-int mi_send(mi_h *h, const char *format, ...)
-{
- int ret;
- char *str;
- va_list argptr;
-
- if (h->died)
- return 0;
-
- va_start(argptr,format);
- ret=vasprintf(&str,format,argptr);
- va_end(argptr);
- fputs(str,h->to);
- fflush(h->to);
- if (h->to_gdb_echo)
- h->to_gdb_echo(str,h->to_gdb_echo_data);
- free(str);
-
- return ret;
-}
-
-void mi_clean_up_globals()
-{
- free(gdb_exe);
- gdb_exe=NULL;
- free(xterm_exe);
- xterm_exe=NULL;
- free(gdb_start);
- gdb_start=NULL;
- free(gdb_conn);
- gdb_conn=NULL;
- free(main_func);
- main_func=NULL;
-}
-
-void mi_register_exit()
-{
- static int registered=0;
- if (!registered)
- {
- registered=1;
- atexit(mi_clean_up_globals);
- }
-}
-
-void mi_set_gdb_exe(const char *name)
-{
- free(gdb_exe);
- gdb_exe=name ? strdup(name) : NULL;
- mi_register_exit();
-}
-
-void mi_set_gdb_start(const char *name)
-{
- free(gdb_start);
- gdb_start=name ? strdup(name) : NULL;
- mi_register_exit();
-}
-
-void mi_set_gdb_conn(const char *name)
-{
- free(gdb_conn);
- gdb_conn=name ? strdup(name) : NULL;
- mi_register_exit();
-}
-
-static
-char *mi_search_in_path(const char *file)
-{
- char *path, *pt, *r;
- char test[PATH_MAX];
- struct stat st;
-
- path=getenv("PATH");
- if (!path)
- return NULL;
- pt=strdup(path);
- r=strtok(pt,":");
- while (r)
- {
- strcpy(test,r);
- strcat(test,"/");
- strcat(test,file);
- if (stat(test,&st)==0 && S_ISREG(st.st_mode))
- {
- free(pt);
- return strdup(test);
- }
- r=strtok(NULL,":");
- }
- free(pt);
- return NULL;
-}
-
-const char *mi_get_gdb_exe()
-{
- if (!gdb_exe)
- {/* Look for gdb in path */
- gdb_exe=mi_search_in_path("gdb");
- if (!gdb_exe)
- return "/usr/bin/gdb";
- }
- return gdb_exe;
-}
-
-const char *mi_get_gdb_start()
-{
- return gdb_start;
-}
-
-const char *mi_get_gdb_conn()
-{
- return gdb_conn;
-}
-
-void mi_set_xterm_exe(const char *name)
-{
- free(xterm_exe);
- xterm_exe=name ? strdup(name) : NULL;
- mi_register_exit();
-}
-
-const char *mi_get_xterm_exe()
-{
- if (!xterm_exe)
- {/* Look for xterm in path */
- xterm_exe=mi_search_in_path("xterm");
- if (!xterm_exe)
- return "/usr/bin/X11/xterm";
- }
- return xterm_exe;
-}
-
-void mi_set_main_func(const char *name)
-{
- free(main_func);
- main_func=name ? strdup(name) : NULL;
- mi_register_exit();
-}
-
-const char *mi_get_main_func()
-{
- if (main_func)
- return main_func;
- return "main";
-}
-
-/**[txh]********************************************************************
-
- Description:
- Opens a new xterm to be used by the child process to debug.
-
- Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
-release it.
-
-***************************************************************************/
-
-mi_aux_term *gmi_start_xterm()
-{
- char nsh[14]="/tmp/shXXXXXX";
- char ntt[14]="/tmp/ttXXXXXX";
- const char *xterm;
- struct stat st;
- int hsh, htt=-1;
- mi_aux_term *res=NULL;
- FILE *f;
- pid_t pid;
- char buf[PATH_MAX];
-
- /* Verify we have an X terminal. */
- xterm=mi_get_xterm_exe();
- if (access(xterm,X_OK))
- {
- mi_error=MI_MISSING_XTERM;
- return NULL;
- }
-
- /* Create 2 temporals. */
- hsh=mkstemp(nsh);
- if (hsh==-1)
- {
- mi_error=MI_CREATE_TEMPORAL;
- return NULL;
- }
- htt=mkstemp(ntt);
- if (htt==-1)
- {
- close(hsh);
- unlink(nsh);
- mi_error=MI_CREATE_TEMPORAL;
- return NULL;
- }
- close(htt);
- /* Create the script. */
- f=fdopen(hsh,"w");
- if (!f)
- {
- close(hsh);
- unlink(nsh);
- unlink(ntt);
- mi_error=MI_CREATE_TEMPORAL;
- return NULL;
- }
- fprintf(f,"#!/bin/sh\n");
- fprintf(f,"tty > %s\n",ntt);
- fprintf(f,"rm %s\n",nsh);
- fprintf(f,"sleep 365d\n");
- fclose(f);
- /* Spawn xterm. */
- /* Create the child. */
- pid=fork();
- if (pid==0)
- {/* We are the child. */
- char *argv[5];
- /* Pass the control to gdb. */
- argv[0]=(char *)mi_get_xterm_exe(); /* Is that ok? */
- argv[1]="-e";
- argv[2]="/bin/sh";
- argv[3]=nsh;
- argv[4]=0;
- execvp(argv[0],argv);
- /* We get here only if exec failed. */
- unlink(nsh);
- unlink(ntt);
- _exit(127);
- }
- /* We are the parent. */
- if (pid==-1)
- {/* Fork failed. */
- unlink(nsh);
- unlink(ntt);
- mi_error=MI_FORK;
- return NULL;
- }
- /* Wait until the shell is deleted. */
- while (stat(nsh,&st)==0)
- usleep(1000);
- /* Try to read the tty name. */
- f=fopen(ntt,"rt");
- if (f)
- {
- if (fgets(buf,PATH_MAX,f))
- {
- char *s; /* Strip the \n. */
- for (s=buf; *s && *s!='\n'; s++);
- *s=0;
- res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
- if (res)
- {
- res->pid=pid;
- res->tty=strdup(buf);
- }
- }
- fclose(f);
- }
- unlink(ntt);
- return res;
-}
-
-void mi_free_aux_term(mi_aux_term *t)
-{
- if (!t)
- return;
- free(t->tty);
- free(t);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Closes the auxiliar terminal and releases the allocated memory.
-
-***************************************************************************/
-
-void gmi_end_aux_term(mi_aux_term *t)
-{
- if (!t)
- return;
- if (t->pid!=-1 && mi_check_running_pid(t->pid))
- mi_kill_child(t->pid);
- mi_free_aux_term(t);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Forces the MI version. Currently the library can't detect it so you must
-force it manually. GDB 5.x implemented MI v1 and 6.x v2.
-
-***************************************************************************/
-
-void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
- unsigned vMinor)
-{
- h->version=MI_VERSION2U(vMajor,vMiddle,vMinor);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Dis/Enables the @var{wa} workaround for a bug in gdb.
-
-***************************************************************************/
-
-void mi_set_workaround(unsigned wa, int enable)
-{
- switch (wa)
- {
- case MI_PSYM_SEARCH:
- disable_psym_search_workaround=enable ? 0 : 1;
- break;
- }
-}
-
-/**[txh]********************************************************************
-
- Description:
- Finds if the @var{wa} workaround for a bug in gdb is enabled.
-
- Return: !=0 if enabled.
-
-***************************************************************************/
-
-int mi_get_workaround(unsigned wa)
-{
- switch (wa)
- {
- case MI_PSYM_SEARCH:
- return disable_psym_search_workaround==0;
- }
- return 0;
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004-2007 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: C++ Interface.
- Comments:
- Implements a very simple (naive ;-) C++ wrapper.@p
-
-***************************************************************************/
-
-#include <string.h>
-#include <limits.h>
-#include "mi_gdb.h"
-
-/**[txh]********************************************************************
-
- Description:
- Initializes a debugger object. It starts in the "disconnected" state.
-Use @x{::Connect} after it.
-
-***************************************************************************/
-
-MIDebugger::MIDebugger()
-{
- state=disconnected;
- h=NULL;
- aux_tty=NULL;
- waitingTempBkpt=0;
- targetEndian=enUnknown;
- targetArch=arUnknown;
-}
-
-/**[txh]********************************************************************
-
- Description:
- This is the destructor for the class. It tries to change the state to
-"disconnected" doing the needed actions.
-
-***************************************************************************/
-
-MIDebugger::~MIDebugger()
-{
- if (state==running)
- {
- Stop();
- mi_stop *rs;
- // TODO: Some kind of time-out
- while (!Poll(rs));
- mi_free_stop(rs);
- state=stopped;
- }
- if (state==stopped)
- {
- Kill();
- state=target_specified;
- }
- if (state==target_specified)
- {
- TargetUnselect();
- state=connected;
- }
- if (state==connected)
- Disconnect();
- // Here state==disconnected
-}
-
-/**[txh]********************************************************************
-
- Description:
- Connects to gdb. Currently only local connections are supported, that's
-a gdb limitation. Call it when in "unconnected" state, on success it will
-change to the "connected" state. After it you should call one of the
-SelectTarget members. @x{::SelectTargetX11}, @x{::SelectTargetLinux} or
-@x{::SelectTargetRemote}. To finish the connection use @x{::Disconnect}.
-
- Return: !=0 OK.
-
-***************************************************************************/
-
-int MIDebugger::Connect(bool )
-{
- if (state==disconnected)
- {
- h=mi_connect_local();
- if (h!=NULL)
- {
- state=connected;
- return 1;
- }
- }
- return 0;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Finishes the connection to gdb. Call when in "connected" state, on success
-it will change to "disconnected" state. This function first tries to exit
-from gdb and then close the connection. But if gdb fails to exit it will be
-killed.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::Disconnect()
-{
- if (state==connected)
- {
- gmi_gdb_exit(h);
- mi_disconnect(h);
- state=disconnected;
- return 1;
- }
- return 0;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Protected member that implements @x{::SelectTargetX11} and
-@x{::SelectTargetLinux}.
-
- Return: !=0 OK.
-
-***************************************************************************/
-
-int MIDebugger::SelectTargetTTY(const char *exec, const char *args,
- const char *auxtty, dMode m)
-{
- if (state!=connected)
- return 0;
-
- targetEndian=enUnknown;
- targetArch=arUnknown;
- mode=m;
- if (!gmi_set_exec(h,exec,args))
- return 0;
-
- const char *tty_name;
- #ifndef __CYGWIN__
- if (!auxtty)
- {
- aux_tty=m==dmLinux ? gmi_look_for_free_vt() : gmi_start_xterm();
- if (!aux_tty)
- return 0;
- tty_name=aux_tty->tty;
- }
- else
- {
- tty_name=auxtty;
- }
- if (!gmi_target_terminal(h,tty_name))
- return 0;
- #else
- tty_name=NULL;
- if (!gmi_gdb_set(h,"new-console","on"))
- return 0;
- #endif
-
- state=target_specified;
- preRun=false;
- return 1;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Starts a debug session for X11. It opens an xterm console for the program
-to debug and tells gdb which executable to debug and the command line
-options to pass. You can specify an already existing tty console to be used.
-Can be called when the state is "connected". On success will change to the
-"target_specified" state. After it you can use @x{::Run} or use the members
-to define breakpoints and similar stuff. To finish it use
-@x{::TargetUnselect}.
-
- Return: !=0 OK.
-
-***************************************************************************/
-
-int MIDebugger::SelectTargetX11(const char *exec, const char *args,
- const char *auxtty)
-{
- return SelectTargetTTY(exec,args,auxtty,dmX11);
-}
-
-
-/**[txh]********************************************************************
-
- Description:
- Starts a debug session for Linux console. It selects an empty VT for the
-program to debug and tells gdb which executable to debug and the command line
-options to pass. You can specify an already existing tty console to be used.
-Can be called when the state is "connected". On success will change to the
-"target_specified" state. After it you can use @x{::Run} or use the members
-to define breakpoints and similar stuff. To finish it use
-@x{::TargetUnselect}.
-
- Return: !=0 OK.
-
-***************************************************************************/
-
-int MIDebugger::SelectTargetLinux(const char *exec, const char *args,
- const char *auxtty)
-{
- return SelectTargetTTY(exec,args,auxtty,dmLinux);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Starts a remote session. The other end should be running gdbserver. You
-must specify a local copy of the program to debug with debug info. The remote
-copy can be stripped. The @var{rtype} and @var{rparams} selects the protocol
-and the remote machine. Read gdb docs to know more about the available
-options. If @var{rtype} is omitted "extended-remote" protocol is used.
-Can be called when the state is "connected". On success will change to the
-"target_specified" state. After it you can use @x{::Run} or use the members
-to define breakpoints and similar stuff. To finish it use
-@x{::TargetUnselect}. Note that when gdb uses remote debugging the remote
-program starts running. The @x{::Run} member knows about it.
-
- Return: !=0 OK.
- Example:
- o->SelectTargetRemote("./exec_file","192.168.1.65:5000");
-
-***************************************************************************/
-
-int MIDebugger::SelectTargetRemote(const char *exec, const char *rparams,
- const char *rtype, bool download)
-{
- if (state!=connected)
- return 0;
-
- mode=dmRemote;
- preRun=true;
- targetEndian=enUnknown;
- targetArch=arUnknown;
- if (rtype==NULL)
- rtype="extended-remote";
-
- /* Tell gdb to load symbols from the local copy. */
- int res=download ? gmi_set_exec(h,exec,NULL) : gmi_file_symbol_file(h,exec);
- if (!res)
- return 0;
- /* Select the target */
- if (!gmi_target_select(h,rtype,rparams))
- return 0;
- /* Download the binary */
- if (download)
- {
- if (!gmi_target_download(h))
- return 0;
- }
-
- state=target_specified;
- return 1;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Starts a local session using an already running process.
-
- Return: !=0 OK.
-
-***************************************************************************/
-
-mi_frames *MIDebugger::SelectTargetPID(const char *exec, int pid)
-{
- if (state!=connected)
- return NULL;
-
- mode=dmPID;
- preRun=false;
- targetEndian=enUnknown;
- targetArch=arUnknown;
-
- mi_frames *res=gmi_target_attach(h,pid);
- if (res)
- {
- state=stopped;
-
- /* Tell gdb to load symbols from the local copy. */
- if (!gmi_file_symbol_file(h,exec))
- {
- mi_free_frames(res);
- return NULL;
- }
- }
-
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Used to unselect the current target. When X11 mode it closes the auxiliar
-terminal. For remote debugging it uses "detach". Can be called when in
-"target_specified" state. On success it changes to "connected" state.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::TargetUnselect()
-{
- switch (mode)
- {
- case dmX11:
- case dmLinux:
- if (state!=target_specified)
- return 0;
- if (aux_tty)
- {
- gmi_end_aux_term(aux_tty);
- aux_tty=NULL;
- }
- break;
- case dmPID:
- case dmRemote:
- if (state!=target_specified)
- {
- if (state!=stopped || !gmi_target_detach(h))
- return 0;
- }
- break;
- }
- state=connected;
- return 1;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Starts running the program. You should set breakpoint before it. Can be
-called when state is "target_specified". On success will change to "running"
-state. After it you should poll for async responses using @x{::Poll}. The
-program can stop for many reasons asynchronously and also exit. This
-information is known using Poll. You can stop the program using @x{::Stop}.
-
- Return: !=0 OK.
-
-***************************************************************************/
-
-int MIDebugger::Run()
-{
- if (state!=target_specified)
- return 0;
-
- int res;
- if (preRun)
- res=gmi_exec_continue(h);
- else
- res=gmi_exec_run(h);
- if (res)
- state=running;
-
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Stops the program execution. GDB sends an interrupt signal to the program.
-Can be called when the state is "running". It won't switch to "stopped"
-state automatically. Instead you must poll for async events and wait for a
-stopped notification. After it you can call @x{::Continue} to resume
-execution.
-
- Return:
- Example: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::Stop()
-{
- if (state!=running)
- return 0;
- return gmi_exec_interrupt(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Polls gdb looking for async responses. Currently it just looks for
-"stopped" messages. You must call it when the state is "running". But the
-function will poll gdb even if the state isn't "running". When a stopped
-message is received the state changes to stopped or target_specified (the
-last is when we get some exit).
-
- Return: !=0 if we got a response. The @var{rs} pointer will point to an
-mi_stop structure if we got it or will be NULL if we didn't.
-
-***************************************************************************/
-
-int MIDebugger::Poll(mi_stop *&rs)
-{
- if (state==disconnected || !mi_get_response(h))
- return 0;
-
- mi_stop *res=mi_res_stop(h);
- if (res)
- {
- if (res->reason==sr_exited_signalled ||
- res->reason==sr_exited ||
- res->reason==sr_exited_normally)
- // When we use a PID the exit makes it invalid, so we don't have a
- // valid target to re-run.
- state=mode==dmPID ? connected : target_specified;
- else
- state=stopped;
- if (res->reason==sr_unknown && waitingTempBkpt)
- {
- waitingTempBkpt=0;
- res->reason=sr_bkpt_hit;
- }
- }
- else
- {// We got an error. It looks like most async commands returns running even
- // before they are sure the process is running. Latter we get the real
- // error. So I'm assuming the program is stopped.
- // Lamentably -target-exec-status isn't implemented and even in this case
- // if the program is really running as real async isn't implemented it
- // will fail anyways.
- if (state==running)
- state=stopped;
- }
- rs=res;
- return 1;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Resumes execution after the program "stopped". Can be called when the state
-is stopped. On success will change to "running" state.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::Continue()
-{
- if (state!=stopped)
- return 0;
- int res=gmi_exec_continue(h);
- if (res)
- state=running;
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Starts program execution or resumes it. When the state is target_specified
-it calls @x{::Run} otherwise it uses @x{::Continue}. Can be called when the
-state is "target_specified" or "stopped". On success will change to
-"running" state.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::RunOrContinue()
-{
- if (state==target_specified)
- return Run();
- return Continue();
-}
-
-/**[txh]********************************************************************
-
- Description:
- Kills the program you are debugging. Can be called when the state is
-"stopped" or "running". On success changes the state to "target_specified".
-Note that if you want to restart the program you can just call @x{::Run} and
-if you want to just stop the program call @x{::Stop}.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::Kill()
-{
- if (state!=stopped && state!=running)
- return 0;
- /* GDB/MI doesn't implement it (yet), so we use the regular kill. */
- /* Ensure confirm is off. */
- char *prev=gmi_gdb_show(h,"confirm");
- if (!prev)
- return 0;
- if (strcmp(prev,"off"))
- {
- if (!gmi_gdb_set(h,"confirm","off"))
- {
- free(prev);
- return 0;
- }
- }
- else
- {
- free(prev);
- prev=NULL;
- }
- /* Do the kill. */
- int res=gmi_exec_kill(h);
- /* Revert confirm option if needed. */
- if (prev)
- {
- gmi_gdb_set(h,"confirm",prev);
- free(prev);
- }
-
- if (res)
- state=target_specified;
-
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Inserts a breakpoint at @var{file} and @var{line}. Can be called when the
-state is "stopped" or "target_specified".
-
- Return: An mi_bkpt structure or NULL if error.
-
-***************************************************************************/
-
-mi_bkpt *MIDebugger::Breakpoint(const char *file, int line)
-{
- if (state!=stopped && state!=target_specified)
- return NULL;
- return gmi_break_insert(h,file,line);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Inserts a breakpoint at @var{where}, all options available. Can be called
-when the state is "stopped" or "target_specified".
-
- Return: An mi_bkpt structure or NULL if error.
-
-***************************************************************************/
-
-mi_bkpt *MIDebugger::Breakpoint(const char *where, bool temporary,
- const char *cond, int count, int thread,
- bool hard_assist)
-{
- if (state!=stopped && state!=target_specified)
- return NULL;
- return gmi_break_insert_full(h,temporary,hard_assist,cond,count,thread,where);
-}
-
-
-const int maxWhere=PATH_MAX+256;
-
-mi_bkpt *MIDebugger::Breakpoint(mi_bkpt *b)
-{
- if (state!=stopped && state!=target_specified)
- return NULL;
-
- char buf[maxWhere];
- buf[0]=0;
- switch (b->mode)
- {
- case m_file_line:
- snprintf(buf,maxWhere,"%s:%d",b->file,b->line);
- break;
- case m_function:
- snprintf(buf,maxWhere,"%s",b->func);
- break;
- case m_file_function:
- snprintf(buf,maxWhere,"%s:%s",b->file,b->func);
- break;
- case m_address:
- snprintf(buf,maxWhere,"*%p",b->addr);
- break;
- }
- return Breakpoint(buf,b->disp==d_del,b->cond,b->ignore,b->thread,
- b->type==t_hw);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Inserts a breakpoint at @var{file} and @var{line} all options available.
-Can be called when the state is "stopped" or "target_specified".
-
- Return: An mi_bkpt structure or NULL if error.
-
-***************************************************************************/
-
-mi_bkpt *MIDebugger::BreakpointFull(const char *file, int line,
- bool temporary, const char *cond,
- int count, int thread, bool hard_assist)
-{
- if (state!=stopped && state!=target_specified)
- return NULL;
- return gmi_break_insert_full_fl(h,file,line,temporary,hard_assist,cond,
- count,thread);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Removes the specified breakpoint. It doesn't free the structure. Can be
-called when the state is "stopped" or "target_specified".
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::BreakDelete(mi_bkpt *b)
-{
- if ((state!=stopped && state!=target_specified) || !b)
- return 0;
- return gmi_break_delete(h,b->number);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Inserts a watchpoint for the specified expression. Can be called when the
-state is "stopped" or "target_specified".
-
- Return: An mi_wp structure or NULL if error.
-
-***************************************************************************/
-
-mi_wp *MIDebugger::Watchpoint(enum mi_wp_mode mode, const char *exp)
-{
- if (state!=stopped && state!=target_specified)
- return NULL;
- return gmi_break_watch(h,mode,exp);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Removes the specified watchpoint. It doesn't free the structure. Can be
-called when the state is "stopped" or "target_specified".
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::WatchDelete(mi_wp *w)
-{
- if ((state!=stopped && state!=target_specified) || !w)
- return 0;
- return gmi_break_delete(h,w->number);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Puts a temporal breakpoint in main function and starts running. Can be
-called when the state is "target_specified". If successful the state will
-change to "running".
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::RunToMain()
-{
- if (state!=target_specified)
- return 0;
- mi_bkpt *b=Breakpoint(mi_get_main_func(),true);
- if (!b)
- return 0;
- mi_free_bkpt(b);
- waitingTempBkpt=1;
- return Run();
-}
-
-/**[txh]********************************************************************
-
- Description:
- Executes upto the next line, doesn't follow function calls. The @var{inst}
-argument is for assembler. If the state is "target_specified" it will go to
-the first line in the main function. If the state is "stopped" will use the
-next command. If successfully the state will change to "running".
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::StepOver(bool inst)
-{
- int res=0;
-
- if (state==target_specified)
- {// We aren't running
- // Walk to main
- return RunToMain();
- }
- if (state==stopped)
- {
- if (inst)
- res=gmi_exec_next_instruction(h);
- else
- res=gmi_exec_next(h);
- if (res)
- state=running;
- }
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Executes until the specified point. If the state is "target_specified" it
-uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
-Fails for any other state.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::GoTo(const char *file, int line)
-{
- int res=0;
-
- if (state==target_specified)
- {// We aren't running
- // Use a temporal breakpoint
- int l=strlen(file)+32;
- char buf[l];
- snprintf(buf,l,"%s:%d",file,line);
- mi_bkpt *b=Breakpoint(buf,true);
- if (b)
- {
- mi_free_bkpt(b);
- waitingTempBkpt=1;
- res=Run();
- }
- }
- else if (state==stopped)
- {
- res=gmi_exec_until(h,file,line);
- if (res)
- state=running;
- }
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Executes until the specified point. If the state is "target_specified" it
-uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
-Fails for any other state.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::GoTo(void *addr)
-{
- int res=0;
-
- if (state==target_specified)
- {// We aren't running
- // Use a temporal breakpoint
- char buf[32];
- snprintf(buf,32,"*%p",addr);
- mi_bkpt *b=Breakpoint(buf,true);
- if (b)
- {
- mi_free_bkpt(b);
- waitingTempBkpt=1;
- res=Run();
- }
- }
- else if (state==stopped)
- {
- res=gmi_exec_until_addr(h,addr);
- if (res)
- state=running;
- }
- return res;
-}
-
-
-/**[txh]********************************************************************
-
- Description:
- Resumes execution until the end of the current funtion is reached. Only
-usable when we are in the "stopped" state.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::FinishFun()
-{
- if (state!=stopped)
- return 0;
- int res=gmi_exec_finish(h);
- if (res)
- state=running;
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Returns immediately. Only usable when we are in the "stopped" state.
-
- Return: !=NULL OK, the returned frame is the current location. That's a
-synchronous function.
-
-***************************************************************************/
-
-mi_frames *MIDebugger::ReturnNow()
-{
- if (state!=stopped)
- return 0;
- return gmi_exec_return(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Returns the current list of frames.
-
- Return: !=NULL OK, the list of frames is returned.
-
-***************************************************************************/
-
-mi_frames *MIDebugger::CallStack(bool args)
-{
- if (state!=stopped)
- return 0;
- mi_frames *fr1=gmi_stack_list_frames(h);
- if (fr1 && args)
- {// Get the function arguments
- mi_frames *fr2=gmi_stack_list_arguments(h,1);
- if (fr2)
- {// Transfer them to the other list
- mi_frames *p=fr1, *p2=fr2;
- while (p2 && p)
- {
- p->args=p2->args;
- p2->args=NULL;
- p2=p2->next;
- p=p->next;
- }
- mi_free_frames(fr2);
- }
- }
- return fr1;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Executes upto the next line, it follows function calls. The @var{inst}
-argument is for assembler. If the state is "target_specified" it will go to
-the first line in the main function. If the state is "stopped" will use the
-next command. If successfully the state will change to "running".
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::TraceInto(bool inst)
-{
- int res=0;
-
- if (state==target_specified)
- {// We aren't running
- // Walk to main
- return RunToMain();
- }
- if (state==stopped)
- {
- if (inst)
- res=gmi_exec_step_instruction(h);
- else
- res=gmi_exec_step(h);
- if (res)
- state=running;
- }
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Evaluates the provided expression. If we get an error the error
-description is returned instead. Can't be called if "disconnected" or
-"running".
-
- Return: The result of the expression (use free) or NULL.
-
-***************************************************************************/
-
-char *MIDebugger::EvalExpression(const char *exp)
-{
- if (state==disconnected ||
- state==running) // No async :-(
- return NULL;
- // Evaluate it
- mi_error=MI_OK;
- char *res=gmi_data_evaluate_expression(h,exp);
- if (!res && mi_error_from_gdb)
- {// Not valid, return the error
- res=strdup(mi_error_from_gdb);
- }
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Modifies the provided expression. If we get an error the error
-description is returned instead. Can't be called if "disconnected" or
-"running".
-
- Return: The result of the expression (use free) or NULL.
-
-***************************************************************************/
-
-char *MIDebugger::ModifyExpression(char *exp, char *newVal)
-{
- if (state==disconnected ||
- state==running) // No async :-(
- return NULL;
- // Create an assignment
- int l1=strlen(exp);
- int l2=strlen(newVal);
- char b[l1+l2+2], *s=b;
- memcpy(s,exp,l1);
- s+=l1;
- *s='=';
- memcpy(++s,newVal,l2);
- s[l2]=0;
- // Evaluate it
- char *res=gmi_data_evaluate_expression(h,b);
- if (!res && mi_error_from_gdb)
- {// Not valid, return the error
- res=strdup(mi_error_from_gdb);
- }
- return res;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Sends a command to gdb.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::Send(const char *command)
-{
- if (state==disconnected ||
- state==running) // No async :-(
- return 0;
- // TODO: detect and use -interpreter-exec?
- mi_send(h,"%s\n",command);
- return mi_res_simple_done(h);
-}
-
-
-/**[txh]********************************************************************
-
- Description:
- Fills the type and value fields of the mi_gvar provided list.
-
- Return: !=0 OK
-
-***************************************************************************/
-
-int MIDebugger::FillTypeVal(mi_gvar *var)
-{
- while (var)
- {
- if (!var->type && !gmi_var_info_type(h,var))
- return 0;
- if (!var->value && !gmi_var_evaluate_expression(h,var))
- return 0;
- var=var->next;
- }
- return 1;
-}
-
-int MIDebugger::FillOneTypeVal(mi_gvar *var)
-{
- if (!var)
- return 0;
-
- int ok=1;
- if (!var->type && !gmi_var_info_type(h,var))
- {
- var->type=strdup("");
- ok=0;
- }
- if (!var->value && !gmi_var_evaluate_expression(h,var))
- {
- var->value=strdup("");
- ok=0;
- }
- return ok;
-}
-
-int MIDebugger::AssigngVar(mi_gvar *var, const char *exp)
-{
- if (state!=stopped)
- return 0;
- return gmi_var_assign(h,var,exp);
-}
-
-char *MIDebugger::Show(const char *var)
-{
- if (state==running || state==disconnected)
- return 0;
- // GDB 5.x doesn't reply all in the response record, just to the console :-(
- h->catch_console=1;
- if (h->catched_console)
- {
- free(h->catched_console);
- h->catched_console=NULL;
- }
- char *res=gmi_gdb_show(h,var);
- h->catch_console=0;
- if (!res && h->catched_console)
- {
- res=h->catched_console;
- h->catched_console=NULL;
- }
- return res;
-}
-
-MIDebugger::endianType MIDebugger::GetTargetEndian()
-{
- if (targetEndian!=enUnknown)
- return targetEndian;
- if (state!=stopped && state!=target_specified)
- return enUnknown;
-
- char *end=Show("endian");
- if (end)
- {
- if (strstr(end,"big"))
- targetEndian=enBig;
- else if (strstr(end,"little"))
- targetEndian=enLittle;
- free(end);
- }
- return targetEndian;
-}
-
-MIDebugger::archType MIDebugger::GetTargetArchitecture()
-{
- if (targetArch!=arUnknown)
- return targetArch;
- if (state!=stopped && state!=target_specified)
- return arUnknown;
-
- char *end=Show("architecture");
- if (end)
- {
- if (strstr(end,"i386"))
- targetArch=arIA32;
- else if (strstr(end,"sparc"))
- targetArch=arSPARC;
- else if (strstr(end,"pic14"))
- targetArch=arPIC14;
- else if (strstr(end,"avr"))
- targetArch=arAVR;
- free(end);
- }
- return targetArch;
-}
-
-int MIDebugger::GetErrorNumberSt()
-{
- if (mi_error==MI_GDB_DIED)
- {
- state=target_specified;
- TargetUnselect();
- state=connected;
- Disconnect();
- }
- return mi_error;
-}
-
-int MIDebugger::UpdateRegisters(mi_chg_reg *regs)
-{
- int updated=0;
- mi_chg_reg *chg=GetChangedRegisters();
- if (chg)
- {
- mi_chg_reg *r=regs, *c;
- while (r)
- {
- c=chg;
- while (c && c->reg!=r->reg)
- c=c->next;
- if (c)
- {
- r->updated=1;
- free(r->val);
- r->val=c->val;
- c->val=NULL;
- updated++;
- }
- else
- r->updated=0;
- r=r->next;
- }
- }
- return updated;
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Data manipulation.
- Comments:
- GDB/MI commands for the "Data manipulation" section.@p
-
-@<pre>
-gdb command: Implemented?
-
--data-disassemble Yes
--data-evaluate-expression Yes
--data-list-changed-registers No
--data-list-register-names Yes
--data-list-register-values No
--data-read-memory No
--display-delete N.A. (delete display)
--display-disable N.A. (disable display)
--display-enable N.A. (enable display)
--display-insert N.A. (display)
--display-list N.A. (info display)
--environment-cd No
--environment-directory Yes, MI v1 implementation
--environment-path No
-@</pre>
-
-Notes:@p
-
-1) -display* aren't implemented. You can use CLI command display, but the
-results are sent to the console. So it looks like the best is to manually
-use -data-evaluate-expression to emulate it.@p
-
-2) GDB bug mi/1770: Affects gdb<=6.2, when you ask for the names of the
-registers you get it plus the name of the "pseudo-registers", but if you
-try to get the value of a pseudo-register you get an error saying the
-register number is invalid. I reported to gdb-patches@sources.redhat.com
-on 2004/08/25 and as I didn't get any answer I filled a bug report on
-2004/09/02. The patch to fix this annoying bug is:
-
-Index: gdb/mi/mi-main.c
-===================================================================
-RCS file: /cvs/src/src/gdb/mi/mi-main.c,v
-retrieving revision 1.64
-diff -u -r1.64 mi-main.c
---- gdb/mi/mi-main.c 3 Aug 2004 00:57:27 -0000 1.64
-+++ gdb/mi/mi-main.c 25 Aug 2004 14:12:50 -0000
-@@ -423,7 +423,7 @@
- case, some entries of REGISTER_NAME will change depending upon
- the particular processor being debugged.
-
-- numregs = NUM_REGS;
-+ numregs = NUM_REGS + NUM_PSEUDO_REGS;
-
- if (argc == 0)
- {
-----
-
-Note I had to remove an end of comment in the patch to include it here.
-This bug forced me to create another set of functions. The only way is to
-first get the values and then the names.
-Fixed by Changelog entry:
-
-2004-09-12 Salvador E. Tropea <set@users.sf.net>
- Andrew Cagney <cagney@gnu.org>
-
- * mi/mi-main.c (mi_cmd_data_list_changed_registers)
- (mi_cmd_data_list_register_values)
- (mi_cmd_data_write_register_values): Include the PSEUDO_REGS in
- the register number computation.
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_data_evaluate_expression(mi_h *h, const char *expression)
-{
- mi_send(h,"-data-evaluate-expression \"%s\"\n",expression);
-}
-
-void mi_dir(mi_h *h, const char *path)
-{
- if (h->version>=MI_VERSION2U(2,0,0))
- {// MI v2
- if (path)
- mi_send(h,"-environment-directory \"%s\"\n",path);
- else
- mi_send(h,"-environment-directory -r\n");
- }
- else
- {
- mi_send(h,"-environment-directory %s\n",path ? path : "");
- }
-}
-
-void mi_data_read_memory_hx(mi_h *h, const char *exp, unsigned ws,
- unsigned c, int convAddr)
-{
- if (convAddr)
- mi_send(h,"-data-read-memory \"&%s\" x %d 1 %d\n",exp,ws,c);
- else
- mi_send(h,"-data-read-memory \"%s\" x %d 1 %d\n",exp,ws,c);
-}
-
-void mi_data_disassemble_se(mi_h *h, const char *start, const char *end,
- int mode)
-{
- mi_send(h,"-data-disassemble -s \"%s\" -e \"%s\" -- %d\n",start,end,mode);
-}
-
-void mi_data_disassemble_fl(mi_h *h, const char *file, int line, int lines,
- int mode)
-{
- mi_send(h,"-data-disassemble -f \"%s\" -l %d -n %d -- %d\n",file,line,lines,
- mode);
-}
-
-void mi_data_list_register_names(mi_h *h)
-{
- mi_send(h,"-data-list-register-names\n");
-}
-
-void mi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
-{
- mi_send(h,"-data-list-register-names ");
- while (l)
- {
- mi_send(h,"%d ",l->reg);
- l=l->next;
- }
- mi_send(h,"\n");
-}
-
-void mi_data_list_changed_registers(mi_h *h)
-{
- mi_send(h,"-data-list-changed-registers\n");
-}
-
-void mi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
-{
- mi_send(h,"-data-list-register-values %c ",mi_format_enum_to_char(fmt));
- while (l)
- {
- mi_send(h,"%d ",l->reg);
- l=l->next;
- }
- mi_send(h,"\n");
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- Evaluate an expression. Returns a parsed tree.
-
- Command: -data-evaluate-expression
- Return: The resulting value (as plain text) or NULL on error.
-
-***************************************************************************/
-
-char *gmi_data_evaluate_expression(mi_h *h, const char *expression)
-{
- mi_data_evaluate_expression(h,expression);
- return mi_res_value(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Path for sources. You must use it to indicate where are the sources for
-the program to debug. Only the MI v1 implementation is available.
-
- Command: -environment-directory
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_dir(mi_h *h, const char *path)
-{
- mi_dir(h,path);
- return mi_res_simple_done(h);
-}
-
-int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
- unsigned char *dest, int *na, int convAddr,
- unsigned long *addr)
-{
- mi_data_read_memory_hx(h,exp,1,size,convAddr);
- return mi_get_read_memory(h,dest,1,na,addr);
-}
-
-mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
- const char *end, int mode)
-{
- mi_data_disassemble_se(h,start,end,mode);
- return mi_get_asm_insns(h);
-}
-
-mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
- int lines, int mode)
-{
- mi_data_disassemble_fl(h,file,line,lines,mode);
- return mi_get_asm_insns(h);
-}
-
-// Affected by gdb bug mi/1770
-mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many)
-{
- mi_data_list_register_names(h);
- return mi_get_list_registers(h,how_many);
-}
-
-int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
-{
- mi_data_list_register_names_l(h,l);
- return mi_get_list_registers_l(h,l);
-}
-
-mi_chg_reg *gmi_data_list_changed_registers(mi_h *h)
-{
- mi_error=MI_OK;
- mi_data_list_changed_registers(h);
- return mi_get_list_changed_regs(h);
-}
-
-int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
-{
- mi_data_list_register_values(h,fmt,l);
- return mi_get_reg_values(h,l);
-}
-
-mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many)
-{
- mi_data_list_register_values(h,fmt,NULL);
- return mi_get_reg_values_l(h,how_many);
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Error.
- Comment:
- Translates error numbers into messages.
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-static
-const char *error_strs[]=
-{
- "Ok",
- "Out of memory",
- "Pipe creation",
- "Fork failed",
- "GDB not running",
- "Parser failed",
- "Unknown asyn response",
- "Unknown result response",
- "Error from gdb",
- "Time out in gdb response",
- "GDB suddenly died",
- "Can't execute X terminal",
- "Failed to create temporal",
- "Can't execute the debugger"
-};
-
-const char *mi_get_error_str()
-{
- if (mi_error<0 || mi_error>MI_LAST_ERROR)
- return "Unknown";
- return error_strs[mi_error];
-}
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004-2009 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Comments:
+ Main header for libmigdb.
+
+***************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> /* pid_t */
+
+#define MI_OK 0
+#define MI_OUT_OF_MEMORY 1
+#define MI_PIPE_CREATE 2
+#define MI_FORK 3
+#define MI_DEBUGGER_RUN 4
+#define MI_PARSER 5
+#define MI_UNKNOWN_ASYNC 6
+#define MI_UNKNOWN_RESULT 7
+#define MI_FROM_GDB 8
+#define MI_GDB_TIME_OUT 9
+#define MI_GDB_DIED 10
+#define MI_MISSING_XTERM 11
+#define MI_CREATE_TEMPORAL 12
+#define MI_MISSING_GDB 13
+#define MI_LAST_ERROR 13
+
+#define MI_R_NONE 0 /* We are no waiting any response. */
+#define MI_R_SKIP 1 /* We want to discard it. */
+#define MI_R_FE_AND_S 2 /* Wait for done. */
+#define MI_R_E_ARGS 3
+
+enum mi_val_type { t_const, t_tuple, t_list };
+
+/* Types and subtypes. */
+/* Type. */
+#define MI_T_OUT_OF_BAND 0
+#define MI_T_RESULT_RECORD 1
+/* Out of band subtypes. */
+#define MI_ST_ASYNC 0
+#define MI_ST_STREAM 1
+/* Async sub-subtypes. */
+#define MI_SST_EXEC 0
+#define MI_SST_STATUS 1
+#define MI_SST_NOTIFY 2
+/* Stream sub-subtypes. */
+#define MI_SST_CONSOLE 3
+#define MI_SST_TARGET 4
+#define MI_SST_LOG 5
+/* Classes. */
+/* Async classes. */
+#define MI_CL_UNKNOWN 0
+#define MI_CL_STOPPED 1
+#define MI_CL_DOWNLOAD 2
+/* Result classes. */
+#define MI_CL_DONE 2
+#define MI_CL_RUNNING 3
+#define MI_CL_CONNECTED 4
+#define MI_CL_ERROR 5
+#define MI_CL_EXIT 6
+
+#define MI_DEFAULT_TIME_OUT 10
+
+#define MI_DIS_ASM 0
+#define MI_DIS_SRC_ASM 1
+
+/* Implemented workaround for gdb bugs that we can dis/enable. */
+/* At least gdb<=6.1.1 fails to find a source file with absolute path if the
+ name is for a psym instead of a sym. psym==partially loaded symbol table. */
+#define MI_PSYM_SEARCH 0
+
+#define MI_VERSION_STR "0.8.12"
+#define MI_VERSION_MAJOR 0
+#define MI_VERSION_MIDDLE 8
+#define MI_VERSION_MINOR 12
+
+struct mi_results_struct
+{
+ char *var; /* Result name or NULL if just a value. */
+ enum mi_val_type type;
+ union
+ {
+ char *cstr;
+ struct mi_results_struct *rs;
+ } v;
+ struct mi_results_struct *next;
+};
+typedef struct mi_results_struct mi_results;
+
+struct mi_output_struct
+{
+ /* Type of output. */
+ char type;
+ char stype;
+ char sstype;
+ char tclass;
+ /* Content. */
+ mi_results *c;
+ /* Always modeled as a list. */
+ struct mi_output_struct *next;
+};
+typedef struct mi_output_struct mi_output;
+
+typedef void (*stream_cb)(const char *, void *);
+typedef void (*async_cb)(mi_output *o, void *);
+typedef int (*tm_cb)(void *);
+
+/* Values of this structure shouldn't be manipulated by the user. */
+struct mi_h_struct
+{
+ /* Pipes connected to gdb. */
+ int to_gdb[2];
+ int from_gdb[2];
+ /* Streams for the pipes. */
+ FILE *to, *from;
+ /* PID of child gdb. */
+ pid_t pid;
+ char died;
+ /* Which rensponse we are waiting for. */
+ /*int response;*/
+ /* The line we are reading. */
+ char *line;
+ int llen, lread;
+ /* Parsed output. */
+ mi_output *po, *last;
+ /* Tunneled streams callbacks. */
+ stream_cb console;
+ void *console_data;
+ stream_cb target;
+ void *target_data;
+ stream_cb log;
+ void *log_data;
+ /* Async responses callback. */
+ async_cb async;
+ void *async_data;
+ /* Callbacks to get echo of gdb dialog. */
+ stream_cb to_gdb_echo;
+ void *to_gdb_echo_data;
+ stream_cb from_gdb_echo;
+ void *from_gdb_echo_data;
+ /* Time out */
+ tm_cb time_out_cb;
+ void *time_out_cb_data;
+ int time_out;
+ /* Ugly workaround for some of the show responses :-( */
+ int catch_console;
+ char *catched_console;
+ /* MI version, currently unknown but the user can force v2 */
+ unsigned version;
+};
+typedef struct mi_h_struct mi_h;
+
+#define MI_TO(a) ((a)->to_gdb[1])
+
+enum mi_bkp_type { t_unknown=0, t_breakpoint=1, t_hw=2 };
+enum mi_bkp_disp { d_unknown=0, d_keep=1, d_del=2 };
+enum mi_bkp_mode { m_file_line=0, m_function=1, m_file_function=2, m_address=3 };
+
+struct mi_bkpt_struct
+{
+ int number;
+ enum mi_bkp_type type;
+ enum mi_bkp_disp disp; /* keep or del if temporal */
+ char enabled;
+ void *addr;
+ char *func;
+ char *file;
+ int line;
+ int ignore;
+ int times;
+
+ /* For the user: */
+ char *cond;
+ char *file_abs;
+ int thread;
+ enum mi_bkp_mode mode;
+ struct mi_bkpt_struct *next;
+};
+typedef struct mi_bkpt_struct mi_bkpt;
+
+enum mi_wp_mode { wm_unknown=0, wm_write=1, wm_read=2, wm_rw=3 };
+
+struct mi_wp_struct
+{
+ int number;
+ char *exp;
+ enum mi_wp_mode mode;
+
+ /* For the user: */
+ struct mi_wp_struct *next;
+ char enabled;
+};
+typedef struct mi_wp_struct mi_wp;
+
+struct mi_frames_struct
+{
+ int level; /* The frame number, 0 being the topmost frame, i.e. the innermost
+ function. */
+ void *addr; /* The `$pc' value for that frame. */
+ char *func; /* Function name. */
+ char *file; /* File name of the source file where the function lives. */
+ char *from;
+ int line; /* Line number corresponding to the `$pc'. */
+ /* When arguments are available: */
+ mi_results *args;
+ int thread_id;
+ /* When more than one is provided: */
+ struct mi_frames_struct *next;
+};
+typedef struct mi_frames_struct mi_frames;
+
+struct mi_aux_term_struct
+{
+ pid_t pid;
+ char *tty;
+};
+typedef struct mi_aux_term_struct mi_aux_term;
+
+struct mi_pty_struct
+{
+ char *slave;
+ int master;
+};
+typedef struct mi_pty_struct mi_pty;
+
+enum mi_gvar_fmt { fm_natural=0, fm_binary=1, fm_decimal=2, fm_hexadecimal=3,
+ fm_octal=4,
+ /* Only for registers format: */
+ fm_raw=5 };
+enum mi_gvar_lang { lg_unknown=0, lg_c, lg_cpp, lg_java };
+
+#define MI_ATTR_DONT_KNOW 0
+#define MI_ATTR_NONEDITABLE 1
+#define MI_ATTR_EDITABLE 2
+
+struct mi_gvar_struct
+{
+ char *name;
+ int numchild;
+ char *type;
+ enum mi_gvar_fmt format;
+ enum mi_gvar_lang lang;
+ char *exp;
+ int attr;
+
+ /* MI v2 fills it, not yet implemented here. */
+ /* Use gmi_var_evaluate_expression. */
+ char *value;
+
+ /* Pointer to the parent. NULL if none. */
+ struct mi_gvar_struct *parent;
+ /* List containing the children.
+ Filled by gmi_var_list_children.
+ NULL if numchild==0 or not yet filled. */
+ struct mi_gvar_struct *child;
+ /* Next var in the list. */
+ struct mi_gvar_struct *next;
+
+ /* For the user: */
+ char opened; /* We will show its children. 1 when we fill "child" */
+ char changed; /* Needs to be updated. 0 when created. */
+ int vischild; /* How many items visible. numchild when we fill "child" */
+ int depth; /* How deep is this var. */
+ char ispointer;
+};
+typedef struct mi_gvar_struct mi_gvar;
+
+struct mi_gvar_chg_struct
+{
+ char *name;
+ int in_scope; /* if true the other fields apply. */
+ char *new_type; /* NULL if type_changed==false */
+ int new_num_children; /* only when new_type!=NULL */
+
+ struct mi_gvar_chg_struct *next;
+};
+typedef struct mi_gvar_chg_struct mi_gvar_chg;
+
+
+/* A list of assembler instructions. */
+struct mi_asm_insn_struct
+{
+ void *addr;
+ char *func;
+ unsigned offset;
+ char *inst;
+
+ struct mi_asm_insn_struct *next;
+};
+typedef struct mi_asm_insn_struct mi_asm_insn;
+
+/* A list of source lines containing assembler instructions. */
+struct mi_asm_insns_struct
+{
+ char *file;
+ int line;
+ mi_asm_insn *ins;
+
+ struct mi_asm_insns_struct *next;
+};
+typedef struct mi_asm_insns_struct mi_asm_insns;
+
+/* Changed register. */
+struct mi_chg_reg_struct
+{
+ int reg;
+ char *val;
+ char *name;
+ char updated;
+
+ struct mi_chg_reg_struct *next;
+};
+typedef struct mi_chg_reg_struct mi_chg_reg;
+
+/*
+ Examining gdb sources and looking at docs I can see the following "stop"
+reasons:
+
+Breakpoints:
+a) breakpoint-hit (bkptno) + frame
+Also: without reason for temporal breakpoints.
+
+Watchpoints:
+b) watchpoint-trigger (wpt={number,exp};value={old,new}) + frame
+c) read-watchpoint-trigger (hw-rwpt{number,exp};value={value}) + frame
+d) access-watchpoint-trigger (hw-awpt{number,exp};value={[old,]new}) + frame
+e) watchpoint-scope (wpnum) + frame
+
+Movement:
+f) function-finished ([gdb-result-var,return-value]) + frame
+g) location-reached + frame
+h) end-stepping-range + frame
+
+Exit:
+i) exited-signalled (signal-name,signal-meaning)
+j) exited (exit-code)
+k) exited-normally
+
+Signal:
+l) signal-received (signal-name,signal-meaning) + frame
+
+Plus: thread-id
+*/
+enum mi_stop_reason
+{
+ sr_unknown=0,
+ sr_bkpt_hit,
+ sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
+ sr_function_finished, sr_location_reached, sr_end_stepping_range,
+ sr_exited_signalled, sr_exited, sr_exited_normally,
+ sr_signal_received
+};
+
+struct mi_stop_struct
+{
+ enum mi_stop_reason reason; /* If more than one reason just the last. */
+ /* Flags indicating if non-pointer fields are filled. */
+ char have_thread_id;
+ char have_bkptno;
+ char have_exit_code;
+ char have_wpno;
+ /* Where stopped. Doesn't exist for sr_exited*. */
+ int thread_id;
+ mi_frames *frame;
+ /* sr_bkpt_hit */
+ int bkptno;
+ /* sr_*wp_* no scope */
+ mi_wp *wp;
+ char *wp_old;
+ char *wp_val;
+ /* sr_wp_scope */
+ int wpno;
+ /* sr_function_finished. Not for void func. */
+ char *gdb_result_var;
+ char *return_value;
+ /* sr_exited_signalled, sr_signal_received */
+ char *signal_name;
+ char *signal_meaning;
+ /* sr_exited */
+ int exit_code;
+};
+typedef struct mi_stop_struct mi_stop;
+
+/* Variable containing the last error. */
+extern int mi_error;
+extern char *mi_error_from_gdb;
+const char *mi_get_error_str();
+
+/* Indicate the name of gdb exe. Default is /usr/bin/gdb */
+void mi_set_gdb_exe(const char *name);
+const char *mi_get_gdb_exe();
+/* Indicate the name of a file containing commands to send at start-up */
+void mi_set_gdb_start(const char *name);
+const char *mi_get_gdb_start();
+/* Indicate the name of a file containing commands to send after connection */
+void mi_set_gdb_conn(const char *name);
+const char *mi_get_gdb_conn();
+void mi_send_target_commands(mi_h *h);
+/* Connect to a local copy of gdb. */
+mi_h *mi_connect_local();
+/* Close connection. You should ask gdb to quit first. */
+void mi_disconnect(mi_h *h);
+/* Force MI version. */
+#define MI_VERSION2U(maj,mid,min) (maj*0x1000000+mid*0x10000+min)
+void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
+ unsigned vMinor);
+void mi_set_workaround(unsigned wa, int enable);
+int mi_get_workaround(unsigned wa);
+/* Parse gdb output. */
+mi_output *mi_parse_gdb_output(const char *str);
+/* Functions to set/get the tunneled streams callbacks. */
+void mi_set_console_cb(mi_h *h, stream_cb cb, void *data);
+void mi_set_target_cb(mi_h *h, stream_cb cb, void *data);
+void mi_set_log_cb(mi_h *h, stream_cb cb, void *data);
+stream_cb mi_get_console_cb(mi_h *h, void **data);
+stream_cb mi_get_target_cb(mi_h *h, void **data);
+stream_cb mi_get_log_cb(mi_h *h, void **data);
+/* The callback to deal with async events. */
+void mi_set_async_cb(mi_h *h, async_cb cb, void *data);
+async_cb mi_get_async_cb(mi_h *h, void **data);
+/* Time out in gdb responses. */
+void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data);
+tm_cb mi_get_time_out_cb(mi_h *h, void **data);
+void mi_set_time_out(mi_h *h, int to);
+int mi_get_time_out(mi_h *h);
+/* Callbacks to "see" the dialog with gdb. */
+void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data);
+void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data);
+stream_cb mi_get_to_gdb_cb(mi_h *h, void **data);
+stream_cb mi_get_from_gdb_cb(mi_h *h, void **data);
+/* Sends a message to gdb. */
+int mi_send(mi_h *h, const char *format, ...);
+/* Wait until gdb sends a response. */
+mi_output *mi_get_response_blk(mi_h *h);
+/* Check if gdb sent a complete response. Use with mi_retire_response. */
+int mi_get_response(mi_h *h);
+/* Get the last response. Use with mi_get_response. */
+mi_output *mi_retire_response(mi_h *h);
+/* Look for a result record in gdb output. */
+mi_output *mi_get_rrecord(mi_output *r);
+/* Look if the output contains an async stop.
+ If that's the case return the reason for the stop.
+ If the output contains an error the description is returned in reason. */
+int mi_get_async_stop_reason(mi_output *r, char **reason);
+mi_stop *mi_get_stopped(mi_results *r);
+mi_frames *mi_get_async_frame(mi_output *r);
+/* Wait until gdb sends a response.
+ Then check if the response is of the desired type. */
+int mi_res_simple_exit(mi_h *h);
+int mi_res_simple_done(mi_h *h);
+int mi_res_simple_running(mi_h *h);
+int mi_res_simple_connected(mi_h *h);
+/* It additionally extracts an specified variable. */
+mi_results *mi_res_done_var(mi_h *h, const char *var);
+/* Extract a frames list from the response. */
+mi_frames *mi_res_frames_array(mi_h *h, const char *var);
+mi_frames *mi_res_frames_list(mi_h *h);
+mi_frames *mi_parse_frame(mi_results *c);
+mi_frames *mi_res_frame(mi_h *h);
+/* Create an auxiliar terminal using xterm. */
+mi_aux_term *gmi_start_xterm();
+/* Indicate the name of xterm exe. Default is /usr/bin/X11/xterm */
+void mi_set_xterm_exe(const char *name);
+const char *mi_get_xterm_exe();
+/* Kill the auxiliar terminal and release the structure. */
+void gmi_end_aux_term(mi_aux_term *t);
+/* Look for a free Linux VT for the child. */
+mi_aux_term *gmi_look_for_free_vt();
+/* Look for a free and usable Linux VT. */
+int mi_look_for_free_vt();
+/* Close master and release the structure. */
+void gmi_end_pty(mi_pty *p);
+/* Look for a free pseudo terminal. */
+mi_pty *gmi_look_for_free_pty();
+/* Extract a list of thread IDs from response. */
+int mi_res_thread_ids(mi_h *h, int **list);
+int mi_get_thread_ids(mi_output *res, int **list);
+/* A variable response. */
+mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression);
+enum mi_gvar_fmt mi_format_str_to_enum(const char *format);
+const char *mi_format_enum_to_str(enum mi_gvar_fmt format);
+char mi_format_enum_to_char(enum mi_gvar_fmt format);
+enum mi_gvar_lang mi_lang_str_to_enum(const char *lang);
+const char *mi_lang_enum_to_str(enum mi_gvar_lang lang);
+int mi_res_changelist(mi_h *h, mi_gvar_chg **changed);
+int mi_res_children(mi_h *h, mi_gvar *v);
+mi_bkpt *mi_res_bkpt(mi_h *h);
+mi_wp *mi_res_wp(mi_h *h);
+char *mi_res_value(mi_h *h);
+mi_stop *mi_res_stop(mi_h *h);
+enum mi_stop_reason mi_reason_str_to_enum(const char *s);
+const char *mi_reason_enum_to_str(enum mi_stop_reason r);
+int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
+ unsigned long *addr);
+mi_asm_insns *mi_get_asm_insns(mi_h *h);
+/* Starting point of the program. */
+void mi_set_main_func(const char *name);
+const char *mi_get_main_func();
+mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many);
+int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l);
+mi_chg_reg *mi_get_list_changed_regs(mi_h *h);
+int mi_get_reg_values(mi_h *h, mi_chg_reg *l);
+mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many);
+int gmi_target_download(mi_h *h);
+
+/* Allocation functions: */
+void *mi_calloc(size_t count, size_t sz);
+void *mi_calloc1(size_t sz);
+char *mi_malloc(size_t sz);
+mi_results *mi_alloc_results(void);
+mi_output *mi_alloc_output(void);
+mi_frames *mi_alloc_frames(void);
+mi_gvar *mi_alloc_gvar(void);
+mi_gvar_chg *mi_alloc_gvar_chg(void);
+mi_bkpt *mi_alloc_bkpt(void);
+mi_wp *mi_alloc_wp(void);
+mi_stop *mi_alloc_stop(void);
+mi_asm_insns *mi_alloc_asm_insns(void);
+mi_asm_insn *mi_alloc_asm_insn(void);
+mi_chg_reg *mi_alloc_chg_reg(void);
+void mi_free_output(mi_output *r);
+void mi_free_output_but(mi_output *r, mi_output *no, mi_results *no_r);
+void mi_free_frames(mi_frames *f);
+void mi_free_aux_term(mi_aux_term *t);
+void mi_free_results(mi_results *r);
+void mi_free_results_but(mi_results *r, mi_results *no);
+void mi_free_gvar(mi_gvar *v);
+void mi_free_gvar_chg(mi_gvar_chg *p);
+void mi_free_wp(mi_wp *wp);
+void mi_free_stop(mi_stop *s);
+void mi_free_asm_insns(mi_asm_insns *i);
+void mi_free_asm_insn(mi_asm_insn *i);
+void mi_free_charp_list(char **l);
+void mi_free_chg_reg(mi_chg_reg *r);
+
+/* Porgram control: */
+/* Specify the executable and arguments for local debug. */
+int gmi_set_exec(mi_h *h, const char *file, const char *args);
+/* Start running the executable. Remote sessions starts running. */
+int gmi_exec_run(mi_h *h);
+/* Continue the execution after a "stop". */
+int gmi_exec_continue(mi_h *h);
+/* Indicate which terminal will use the target program. For local sessions. */
+int gmi_target_terminal(mi_h *h, const char *tty_name);
+/* Specify what's the local copy that have debug info. For remote sessions. */
+int gmi_file_symbol_file(mi_h *h, const char *file);
+/* Continue until function return, the return value is included in the async
+ response. */
+int gmi_exec_finish(mi_h *h);
+/* Stop the program using SIGINT. */
+int gmi_exec_interrupt(mi_h *h);
+/* Next line of code. */
+int gmi_exec_next(mi_h *h);
+/* Next count lines of code. */
+int gmi_exec_next_cnt(mi_h *h, int count);
+/* Next line of assembler code. */
+int gmi_exec_next_instruction(mi_h *h);
+/* Next line of code. Get inside functions. */
+int gmi_exec_step(mi_h *h);
+/* Next count lines of code. Get inside functions. */
+int gmi_exec_step_cnt(mi_h *h, int count);
+/* Next line of assembler code. Get inside calls. */
+int gmi_exec_step_instruction(mi_h *h);
+/* Execute until location is reached. If file is NULL then is until next line. */
+int gmi_exec_until(mi_h *h, const char *file, int line);
+int gmi_exec_until_addr(mi_h *h, void *addr);
+/* Return to previous frame inmediatly. */
+mi_frames *gmi_exec_return(mi_h *h);
+/* Just kill the program. Please read the notes in prg_control.c. */
+int gmi_exec_kill(mi_h *h);
+
+/* Target manipulation: */
+/* Connect to a remote gdbserver using the specified methode. */
+int gmi_target_select(mi_h *h, const char *type, const char *params);
+/* Attach to an already running process. */
+mi_frames *gmi_target_attach(mi_h *h, pid_t pid);
+/* Detach from an attached process. */
+int gmi_target_detach(mi_h *h);
+
+/* Miscellaneous commands: */
+/* Exit gdb killing the child is it is running. */
+void gmi_gdb_exit(mi_h *h);
+/* Send the version to the console. */
+int gmi_gdb_version(mi_h *h);
+/* Set a gdb variable. */
+int gmi_gdb_set(mi_h *h, const char *var, const char *val);
+/* Get a gdb variable. */
+char *gmi_gdb_show(mi_h *h, const char *var);
+
+/* Breakpoints manipulation: */
+/* Insert a breakpoint at file:line. */
+mi_bkpt *gmi_break_insert(mi_h *h, const char *file, int line);
+/* Insert a breakpoint, all available options. */
+mi_bkpt *gmi_break_insert_full(mi_h *h, int temporary, int hard_assist,
+ const char *cond, int count, int thread,
+ const char *where);
+mi_bkpt *gmi_break_insert_full_fl(mi_h *h, const char *file, int line,
+ int temporary, int hard_assist,
+ const char *cond, int count, int thread);
+/* Remove a breakpoint. */
+int gmi_break_delete(mi_h *h, int number);
+/* Free the memory used for a breakpoint description. */
+void mi_free_bkpt(mi_bkpt *b);
+/* Modify the "ignore" count for a breakpoint. */
+int gmi_break_set_times(mi_h *h, int number, int count);
+/* Associate a condition with the breakpoint. */
+int gmi_break_set_condition(mi_h *h, int number, const char *condition);
+/* Enable or disable a breakpoint. */
+int gmi_break_state(mi_h *h, int number, int enable);
+/* Set a watchpoint. It doesn't work for remote targets! */
+mi_wp *gmi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp);
+
+/* Data Manipulation. */
+/* Evaluate an expression. Returns a parsed tree. */
+char *gmi_data_evaluate_expression(mi_h *h, const char *expression);
+/* Path for sources. */
+int gmi_dir(mi_h *h, const char *path);
+/* A very limited "data read memory" implementation. */
+int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
+ unsigned char *dest, int *na, int convAddr,
+ unsigned long *addr);
+mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
+ const char *end, int mode);
+mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
+ int lines, int mode);
+mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many);
+int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l);
+mi_chg_reg *gmi_data_list_changed_registers(mi_h *h);
+int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l);
+mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many);
+
+/* Stack manipulation. */
+/* List of frames. Arguments aren't filled. */
+mi_frames *gmi_stack_list_frames(mi_h *h);
+/* List of frames. Indicating a range. */
+mi_frames *gmi_stack_list_frames_r(mi_h *h, int from, int to);
+/* List arguments. Only level and args filled. */
+mi_frames *gmi_stack_list_arguments(mi_h *h, int show);
+/* List arguments. Indicating a range. Only level and args filled. */
+mi_frames *gmi_stack_list_arguments_r(mi_h *h, int show, int from, int to);
+/* Information about the current frame, including args. */
+mi_frames *gmi_stack_info_frame(mi_h *h);
+/* Stack info depth. error => -1 */
+int gmi_stack_info_depth_get(mi_h *h);
+/* Set stack info depth. error => -1 */
+int gmi_stack_info_depth(mi_h *h, int max_depth);
+/* Change current frame. */
+int gmi_stack_select_frame(mi_h *h, int framenum);
+/* List of local vars. */
+mi_results *gmi_stack_list_locals(mi_h *h, int show);
+
+/* Thread. */
+/* List available thread ids. */
+int gmi_thread_list_ids(mi_h *h, int **list);
+/* Select a thread. */
+mi_frames *gmi_thread_select(mi_h *h, int id);
+/* List available threads. */
+mi_frames *gmi_thread_list_all_threads(mi_h *h);
+
+/* Variable objects. */
+/* Create a variable object. */
+mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp);
+mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp);
+/* Create the variable and also fill the lang and attr fields. */
+mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp);
+/* Delete a variable object. Doesn't free the mi_gvar data. */
+int gmi_var_delete(mi_h *h, mi_gvar *var);
+/* Set the format used to represent the result. */
+int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format);
+/* Fill the format field with info from gdb. */
+int gmi_var_show_format(mi_h *h, mi_gvar *var);
+/* Fill the numchild field with info from gdb. */
+int gmi_var_info_num_children(mi_h *h, mi_gvar *var);
+/* Fill the type field with info from gdb. */
+int gmi_var_info_type(mi_h *h, mi_gvar *var);
+/* Fill the expression and lang fields with info from gdb.
+ Note that lang isn't filled during creation. */
+int gmi_var_info_expression(mi_h *h, mi_gvar *var);
+/* Fill the attr field with info from gdb.
+ Note that attr isn't filled during creation. */
+int gmi_var_show_attributes(mi_h *h, mi_gvar *var);
+/* Update variable. Use NULL for all.
+ Note that *changed can be NULL if none updated. */
+int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed);
+/* Change variable. Fills the value field. */
+int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression);
+/* Get current value for a variable. */
+int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var);
+/* List children. It ONLY returns the first level information. :-( */
+int gmi_var_list_children(mi_h *h, mi_gvar *var);
+
+#ifdef __cplusplus
+};
+
+/* C++ interface */
+
+/*
+ State Can:
+ disconnected Connect
+ connected SelectTarget, Disconnect
+ target_specified TargetUnselect, Run, Set breakpoints/watchpoints, etc.
+ running Stop
+ stopped Kill, Restart?, Step, Trace, Continue, etc.
+ [auto exit]
+
+ Modes:
+ dmX11 Local debug for X11.
+ dmLinux Local debug for Linux console.
+ dmRemote Remote debug.
+*/
+class MIDebugger
+{
+public:
+ MIDebugger();
+ ~MIDebugger();
+
+ enum eState { disconnected, connected, target_specified, running, stopped };
+ enum dMode { dmX11, dmLinux, dmRemote, dmPID };
+ enum endianType { enUnknown, enLittle, enBig };
+ // Currently tested architectures
+ enum archType { arUnknown, arIA32, arSPARC, arPIC14, arAVR, arUnsupported };
+
+ int Connect(bool remote=false); /* remote is currently ignored. */
+ int Disconnect();
+ /* SelectTarget* */
+ int SelectTargetX11(const char *exec, const char *args=NULL,
+ const char *auxtty=NULL);
+ int SelectTargetLinux(const char *exec, const char *args,
+ const char *auxtty=NULL);
+ int SelectTargetRemote(const char *exec, const char *rparams,
+ const char *rtype=NULL, bool download=false);
+ // TODO: Linux PIDs can be represented as intergers. What should I use?
+ // ato_pid_t doesn't exist ;-)
+ mi_frames *SelectTargetPID(const char *exec, int pid);
+ int TargetUnselect();
+ int Run();
+ int Stop();
+ int Poll(mi_stop *&rs);
+ int Continue();
+ int RunOrContinue();
+ int Kill();
+ mi_bkpt *Breakpoint(const char *file, int line);
+ mi_bkpt *Breakpoint(const char *where, bool temporary=false, const char *cond=NULL,
+ int count=-1, int thread=-1, bool hard_assist=false);
+ mi_bkpt *BreakpointFull(const char *file, int line, bool temporary=false,
+ const char *cond=NULL, int count=-1, int thread=-1,
+ bool hard_assist=false);
+ mi_bkpt *Breakpoint(mi_bkpt *b);
+ int BreakDelete(mi_bkpt *b);
+ int BreakAfter(mi_bkpt *b)
+ {
+ if (state!=target_specified && state!=stopped)
+ return 0;
+ return gmi_break_set_times(h,b->number,b->ignore);
+ }
+ mi_wp *Watchpoint(enum mi_wp_mode mode, const char *exp);
+ int WatchDelete(mi_wp *w);
+ int RunToMain();
+ int StepOver(bool inst=false);
+ int TraceInto(bool inst=false);
+ int GoTo(const char *file, int line);
+ int GoTo(void *addr);
+ int FinishFun();
+ mi_frames *ReturnNow();
+ mi_frames *CallStack(bool args);
+ char *EvalExpression(const char *exp);
+ char *ModifyExpression(char *exp, char *newVal);
+ mi_gvar *AddgVar(const char *exp, int frame=-1)
+ {
+ if (state!=stopped)
+ return NULL;
+ return gmi_full_var_create(h,frame,exp);
+ }
+ int DelgVar(mi_gvar *var)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_delete(h,var);
+ }
+ int EvalgVar(mi_gvar *var)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_evaluate_expression(h,var);
+ }
+ int GetChildgVar(mi_gvar *var)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_list_children(h,var);
+ }
+ int FillTypeVal(mi_gvar *var);
+ int FillOneTypeVal(mi_gvar *var);
+ int FillAttr(mi_gvar *var)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_show_attributes(h,var);
+ }
+ int FillFormat(mi_gvar *var)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_show_format(h,var);
+ }
+ int SetFormatgVar(mi_gvar *var, enum mi_gvar_fmt format)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_set_format(h,var,format);
+ }
+ int ListChangedgVar(mi_gvar_chg *&changed)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_var_update(h,NULL,&changed);
+ }
+ int AssigngVar(mi_gvar *var, const char *exp);
+ int Send(const char *command);
+ int Version()
+ {
+ if (state==running || state==disconnected)
+ return 0;
+ return gmi_gdb_version(h);
+ }
+ int PathSources(const char *path)
+ {
+ if (state==running || state==disconnected)
+ return 0;
+ return gmi_dir(h,path);
+ }
+ int ReadMemory(const char *exp, unsigned size, unsigned char *dest,
+ int &na, int convAddr, unsigned long *addr)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_read_memory(h,exp,size,dest,&na,convAddr,addr);
+ }
+ char *Show(const char *var);
+ int ThreadListIDs(int *&list)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_thread_list_ids(h,&list);
+ }
+ mi_frames *ThreadList()
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_thread_list_all_threads(h);
+ }
+ mi_frames *ThreadSelect(int id)
+ {
+ if (state!=stopped)
+ return NULL;
+ return gmi_thread_select(h,id);
+ }
+ mi_asm_insns *Disassemble(const char *start, const char *end, int mode)
+ {
+ if (state!=stopped)
+ return NULL;
+ return gmi_data_disassemble_se(h,start,end,mode);
+ }
+ mi_asm_insns *Disassemble(const char *file, int line, int lines, int mode)
+ {
+ if (state!=stopped)
+ return NULL;
+ return gmi_data_disassemble_fl(h,file,line,lines,mode);
+ }
+ mi_chg_reg *GetRegisterNames(int *how_many)
+ {
+ if (state!=target_specified && state!=stopped)
+ return NULL;
+ return gmi_data_list_register_names(h,how_many);
+ }
+ int GetRegisterNames(mi_chg_reg *chg)
+ {
+ if (state!=target_specified && state!=stopped)
+ return 0;
+ return gmi_data_list_register_names_l(h,chg);
+ }
+ int GetRegisterValues(mi_chg_reg *chg)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_data_list_register_values(h,fm_natural,chg);
+ }
+ mi_chg_reg *GetRegisterValues(int *how_many)
+ {
+ if (state!=stopped)
+ return 0;
+ return gmi_data_list_all_register_values(h,fm_natural,how_many);
+ }
+ mi_chg_reg *GetChangedRegisters()
+ {
+ if (state!=stopped)
+ return NULL;
+ mi_chg_reg *chg=gmi_data_list_changed_registers(h);
+ if (chg && !gmi_data_list_register_values(h,fm_natural,chg))
+ {
+ mi_free_chg_reg(chg);
+ chg=NULL;
+ }
+ return chg;
+ }
+ int UpdateRegisters(mi_chg_reg *regs);
+
+ endianType GetTargetEndian();
+ archType GetTargetArchitecture();
+ eState GetState() { return state; }
+
+ /* Some wrappers */
+ static void SetGDBExe(const char *name) { mi_set_gdb_exe(name); }
+ static const char *GetGDBExe() { return mi_get_gdb_exe(); }
+ static void SetXTermExe(const char *name) { mi_set_xterm_exe(name); }
+ static const char *GetXTermExe() { return mi_get_xterm_exe(); }
+ static void SetGDBStartFile(const char *name) { mi_set_gdb_start(name); }
+ static const char *GetGDBStartFile() { return mi_get_gdb_start(); }
+ static void SetGDBConnFile(const char *name) { mi_set_gdb_conn(name); }
+ static const char *GetGDBConnFile() { return mi_get_gdb_conn(); }
+ static void SetMainFunc(const char *name) { mi_set_main_func(name); }
+ static const char *GetMainFunc() { return mi_get_main_func(); }
+
+ static const char *GetErrorStr() { return mi_get_error_str(); }
+ static const char *GetGDBError() { return mi_error_from_gdb; }
+ static int GetErrorNumber() { return mi_error; }
+ int GetErrorNumberSt();
+ void SetConsoleCB(stream_cb cb, void *data=NULL)
+ { mi_set_console_cb(h,cb,data); }
+ void SetTargetCB(stream_cb cb, void *data=NULL)
+ { mi_set_target_cb(h,cb,data); }
+ void SetLogCB(stream_cb cb, void *data=NULL)
+ { mi_set_log_cb(h,cb,data); }
+ void SetAsyncCB(async_cb cb, void *data=NULL)
+ { mi_set_async_cb(h,cb,data); }
+ void SetToGDBCB(stream_cb cb, void *data=NULL)
+ { mi_set_to_gdb_cb(h,cb,data); }
+ void SetFromGDBCB(stream_cb cb, void *data=NULL)
+ { mi_set_from_gdb_cb(h,cb,data); }
+ void SetTimeOutCB(tm_cb cb, void *data)
+ { mi_set_time_out_cb(h,cb,data); }
+ void SetTimeOut(int to)
+ { mi_set_time_out(h,to); }
+ void ForceMIVersion(unsigned vMajor, unsigned vMiddle, unsigned vMinor)
+ { mi_force_version(h,vMajor,vMiddle,vMinor); }
+
+ const char *GetAuxTTY()
+ { return aux_tty ? aux_tty->tty : NULL; }
+
+protected:
+ eState state;
+ dMode mode;
+ endianType targetEndian;
+ archType targetArch;
+ bool preRun; // Remote targets starts running but outside main.
+ mi_h *h;
+ mi_aux_term *aux_tty;
+ int waitingTempBkpt;
+
+ int SelectTargetTTY(const char *exec, const char *args, const char *auxtty,
+ dMode m);
+};
+
+#endif
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Allocator.
+ Comments:
+ Most alloc/free routines are here. Free routines must accept NULL
+pointers. Alloc functions must set mi_error.@p
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+void *mi_calloc(size_t count, size_t sz)
+{
+ void *res=calloc(count,sz);
+ if (!res)
+ mi_error=MI_OUT_OF_MEMORY;
+ return res;
+}
+
+void *mi_calloc1(size_t sz)
+{
+ return mi_calloc(1,sz);
+}
+
+char *mi_malloc(size_t sz)
+{
+ char *res=malloc(sz);
+ if (!res)
+ mi_error=MI_OUT_OF_MEMORY;
+ return res;
+}
+
+mi_results *mi_alloc_results(void)
+{
+ return (mi_results *)mi_calloc1(sizeof(mi_results));
+}
+
+mi_output *mi_alloc_output(void)
+{
+ return (mi_output *)mi_calloc1(sizeof(mi_output));
+}
+
+mi_frames *mi_alloc_frames(void)
+{
+ return (mi_frames *)mi_calloc1(sizeof(mi_frames));
+}
+
+mi_gvar *mi_alloc_gvar(void)
+{
+ return (mi_gvar *)mi_calloc1(sizeof(mi_gvar));
+}
+
+mi_gvar_chg *mi_alloc_gvar_chg(void)
+{
+ return (mi_gvar_chg *)mi_calloc1(sizeof(mi_gvar_chg));
+}
+
+mi_bkpt *mi_alloc_bkpt(void)
+{
+ mi_bkpt *b=(mi_bkpt *)mi_calloc1(sizeof(mi_bkpt));
+ if (b)
+ {
+ b->thread=-1;
+ b->ignore=-1;
+ }
+ return b;
+}
+
+mi_wp *mi_alloc_wp(void)
+{
+ return (mi_wp *)mi_calloc1(sizeof(mi_wp));
+}
+
+mi_stop *mi_alloc_stop(void)
+{
+ return (mi_stop *)mi_calloc1(sizeof(mi_stop));
+}
+
+mi_asm_insns *mi_alloc_asm_insns(void)
+{
+ return (mi_asm_insns *)mi_calloc1(sizeof(mi_asm_insns));
+}
+
+mi_asm_insn *mi_alloc_asm_insn(void)
+{
+ return (mi_asm_insn *)mi_calloc1(sizeof(mi_asm_insn));
+}
+
+mi_chg_reg *mi_alloc_chg_reg(void)
+{
+ return (mi_chg_reg *)mi_calloc1(sizeof(mi_chg_reg));
+}
+
+/*****************************************************************************
+ Free functions
+*****************************************************************************/
+
+void mi_free_frames(mi_frames *f)
+{
+ mi_frames *aux;
+
+ while (f)
+ {
+ free(f->func);
+ free(f->file);
+ free(f->from);
+ mi_free_results(f->args);
+ aux=f->next;
+ free(f);
+ f=aux;
+ }
+}
+
+void mi_free_bkpt(mi_bkpt *b)
+{
+ mi_bkpt *aux;
+
+ while (b)
+ {
+ free(b->func);
+ free(b->file);
+ free(b->file_abs);
+ free(b->cond);
+ aux=b->next;
+ free(b);
+ b=aux;
+ }
+}
+
+void mi_free_gvar(mi_gvar *v)
+{
+ mi_gvar *aux;
+
+ while (v)
+ {
+ free(v->name);
+ free(v->type);
+ free(v->exp);
+ free(v->value);
+ if (v->numchild && v->child)
+ mi_free_gvar(v->child);
+ aux=v->next;
+ free(v);
+ v=aux;
+ }
+}
+
+void mi_free_gvar_chg(mi_gvar_chg *p)
+{
+ mi_gvar_chg *aux;
+
+ while (p)
+ {
+ free(p->name);
+ free(p->new_type);
+ aux=p->next;
+ free(p);
+ p=aux;
+ }
+}
+
+void mi_free_results_but(mi_results *r, mi_results *no)
+{
+ mi_results *aux;
+
+ while (r)
+ {
+ if (r==no)
+ {
+ aux=r->next;
+ r->next=NULL;
+ r=aux;
+ }
+ else
+ {
+ free(r->var);
+ switch (r->type)
+ {
+ case t_const:
+ free(r->v.cstr);
+ break;
+ case t_tuple:
+ case t_list:
+ mi_free_results_but(r->v.rs,no);
+ break;
+ }
+ aux=r->next;
+ free(r);
+ r=aux;
+ }
+ }
+}
+
+void mi_free_results(mi_results *r)
+{
+ mi_free_results_but(r,NULL);
+}
+
+void mi_free_output_but(mi_output *r, mi_output *no, mi_results *no_r)
+{
+ mi_output *aux;
+
+ while (r)
+ {
+ if (r==no)
+ {
+ aux=r->next;
+ r->next=NULL;
+ r=aux;
+ }
+ else
+ {
+ if (r->c)
+ mi_free_results_but(r->c,no_r);
+ aux=r->next;
+ free(r);
+ r=aux;
+ }
+ }
+}
+
+void mi_free_output(mi_output *r)
+{
+ mi_free_output_but(r,NULL,NULL);
+}
+
+void mi_free_stop(mi_stop *s)
+{
+ if (!s)
+ return;
+ mi_free_frames(s->frame);
+ mi_free_wp(s->wp);
+ free(s->wp_old);
+ free(s->wp_val);
+ free(s->gdb_result_var);
+ free(s->return_value);
+ free(s->signal_name);
+ free(s->signal_meaning);
+ free(s);
+}
+
+void mi_free_wp(mi_wp *wp)
+{
+ mi_wp *aux;
+ while (wp)
+ {
+ free(wp->exp);
+ aux=wp->next;
+ free(wp);
+ wp=aux;
+ }
+}
+
+void mi_free_asm_insns(mi_asm_insns *i)
+{
+ mi_asm_insns *aux;
+
+ while (i)
+ {
+ free(i->file);
+ mi_free_asm_insn(i->ins);
+ aux=i->next;
+ free(i);
+ i=aux;
+ }
+}
+
+void mi_free_asm_insn(mi_asm_insn *i)
+{
+ mi_asm_insn *aux;
+
+ while (i)
+ {
+ free(i->func);
+ free(i->inst);
+ aux=i->next;
+ free(i);
+ i=aux;
+ }
+}
+
+/*void mi_free_charp_list(char **l)
+{
+ char **c=l;
+ while (c)
+ {
+ free(*c);
+ c++;
+ }
+ free(l);
+}*/
+
+void mi_free_chg_reg(mi_chg_reg *r)
+{
+ mi_chg_reg *aux;
+ while (r)
+ {
+ free(r->val);
+ free(r->name);
+ aux=r->next;
+ free(r);
+ r=aux;
+ }
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Breakpoint table commands.
+ Comments:
+ GDB/MI commands for the "Breakpoint Table Commands" section.@p
+
+@<pre>
+gdb command: Implemented?
+
+-break-after Yes
+-break-condition Yes
+-break-delete Yes
+-break-disable Yes
+-break-enable Yes
+-break-info N.A. (info break NUMBER) (*)
+-break-insert Yes
+-break-list No (*)
+-break-watch Yes
+@</pre>
+
+(*) I think the program should keep track of the breakpoints, so it will
+be implemented when I have more time.@p
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_break_insert_fl(mi_h *h, const char *file, int line)
+{
+ mi_send(h,"-break-insert %s:%d\n",file,line);
+}
+
+void mi_break_insert(mi_h *h, int temporary, int hard_assist,
+ const char *cond, int count, int thread,
+ const char *where)
+{
+ char s_count[32];
+ char s_thread[32];
+
+ if (count>=0)
+ snprintf(s_count,32,"%d",count);
+ if (thread>=0)
+ snprintf(s_thread,32,"%d",thread);
+ if (cond)
+ // Conditions may contain spaces, in fact, if they don't gdb will add
+ // them after parsing. Enclosing the expression with "" solves the
+ // problem.
+ mi_send(h,"-break-insert %s %s -c \"%s\" %s %s %s %s %s\n",
+ temporary ? "-t" : "",
+ hard_assist ? "-h" : "",
+ cond,
+ count>=0 ? "-i" : "", count>=0 ? s_count : "",
+ thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
+ where);
+ else
+ mi_send(h,"-break-insert %s %s %s %s %s %s %s\n",
+ temporary ? "-t" : "",
+ hard_assist ? "-h" : "",
+ count>=0 ? "-i" : "", count>=0 ? s_count : "",
+ thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
+ where);
+}
+
+void mi_break_insert_flf(mi_h *h, const char *file, int line, int temporary,
+ int hard_assist, const char *cond, int count,
+ int thread)
+{
+ char s_count[32];
+ char s_thread[32];
+
+ if (count>=0)
+ snprintf(s_count,32,"%d",count);
+ if (thread>=0)
+ snprintf(s_thread,32,"%d",thread);
+ mi_send(h,"-break-insert %s %s %s %s %s %s %s %s %s:%d\n",
+ temporary ? "-t" : "",
+ hard_assist ? "-h" : "",
+ cond ? "-c" : "", cond ? cond : "",
+ count>=0 ? "-i" : "", count>=0 ? s_count : "",
+ thread>=0 ? "-p" : "", thread>=0 ? s_thread : "",
+ file,line);
+}
+
+void mi_break_delete(mi_h *h, int number)
+{
+ mi_send(h,"-break-delete %d\n",number);
+}
+
+void mi_break_after(mi_h *h, int number, int count)
+{
+ mi_send(h,"-break-after %d %d\n",number,count);
+}
+
+void mi_break_condition(mi_h *h, int number, const char *condition)
+{
+ mi_send(h,"-break-condition %d %s\n",number,condition);
+}
+
+void mi_break_enable(mi_h *h, int number)
+{
+ mi_send(h,"-break-enable %d\n",number);
+}
+
+void mi_break_disable(mi_h *h, int number)
+{
+ mi_send(h,"-break-disable %d\n",number);
+}
+
+void mi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp)
+{
+ if (mode==wm_write)
+ mi_send(h,"-break-watch \"%s\"\n",exp);
+ else
+ mi_send(h,"-break-watch -%c \"%s\"\n",mode==wm_rw ? 'a' : 'r',exp);
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ Insert a breakpoint at file:line.
+
+ Command: -break-insert file:line
+ Return: A new mi_bkpt structure with info about the breakpoint. NULL on
+error.
+
+***************************************************************************/
+
+mi_bkpt *gmi_break_insert(mi_h *h, const char *file, int line)
+{
+ mi_break_insert_fl(h,file,line);
+ return mi_res_bkpt(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Insert a breakpoint, all available options.
+
+ Command: -break-insert
+ Return: A new mi_bkpt structure with info about the breakpoint. NULL on
+error.
+
+***************************************************************************/
+
+mi_bkpt *gmi_break_insert_full(mi_h *h, int temporary, int hard_assist,
+ const char *cond, int count, int thread,
+ const char *where)
+{
+ mi_break_insert(h,temporary,hard_assist,cond,count,thread,where);
+ return mi_res_bkpt(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Insert a breakpoint, all available options.
+
+ Command: -break-insert [ops] file:line
+ Return: A new mi_bkpt structure with info about the breakpoint. NULL on
+error.
+
+***************************************************************************/
+
+mi_bkpt *gmi_break_insert_full_fl(mi_h *h, const char *file, int line,
+ int temporary, int hard_assist,
+ const char *cond, int count, int thread)
+{
+ mi_break_insert_flf(h,file,line,temporary,hard_assist,cond,count,thread);
+ return mi_res_bkpt(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Remove a breakpoint.
+
+ Command: -break-delete
+ Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
+console.
+
+***************************************************************************/
+
+int gmi_break_delete(mi_h *h, int number)
+{
+ mi_break_delete(h,number);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Modify the "ignore" count for a breakpoint.
+
+ Command: -break-after
+ Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
+console.
+
+***************************************************************************/
+
+int gmi_break_set_times(mi_h *h, int number, int count)
+{
+ mi_break_after(h,number,count);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Associate a condition with the breakpoint.
+
+ Command: -break-condition
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_break_set_condition(mi_h *h, int number, const char *condition)
+{
+ mi_break_condition(h,number,condition);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Enable or disable a breakpoint.
+
+ Command: -break-enable + -break-disable
+ Return: !=0 OK. Note that gdb always says OK, but errors can be sent to the
+console.
+
+***************************************************************************/
+
+int gmi_break_state(mi_h *h, int number, int enable)
+{
+ if (enable)
+ mi_break_enable(h,number);
+ else
+ mi_break_disable(h,number);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Set a watchpoint. It doesn't work for remote targets!
+
+ Command: -break-watch
+ Return: A new mi_wp structure with info about the watchpoint. NULL on
+error.
+
+***************************************************************************/
+
+mi_wp *gmi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp)
+{
+ mi_break_watch(h,mode,exp);
+ return mi_res_wp(h);
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004-2009 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Connect.
+ Comments:
+ This module handles the dialog with gdb, including starting and stopping
+gdb.@p
+
+GDB Bug workaround for "file -readnow": I tried to workaround a bug using
+it but looks like this option also have bugs!!!! so I have to use the
+command line option --readnow.
+It also have a bug!!!! when the binary is changed and gdb must reload it
+this option is ignored. So it looks like we have no solution but 3 gdb bugs
+in a row.
+
+***************************************************************************/
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "mi_gdb.h"
+
+#ifndef TEMP_FAILURE_RETRY
+ #define TEMP_FAILURE_RETRY(a) (a)
+#endif
+
+int mi_error=MI_OK;
+char *mi_error_from_gdb=NULL;
+static char *gdb_exe=NULL;
+static char *xterm_exe=NULL;
+static char *gdb_start=NULL;
+static char *gdb_conn=NULL;
+static char *main_func=NULL;
+static char disable_psym_search_workaround=0;
+
+mi_h *mi_alloc_h()
+{
+ mi_h *h=(mi_h *)calloc(1,sizeof(mi_h));
+ if (!h)
+ {
+ mi_error=MI_OUT_OF_MEMORY;
+ return NULL;
+ }
+ h->to_gdb[0]=h->to_gdb[1]=h->from_gdb[0]=h->from_gdb[1]=-1;
+ h->pid=-1;
+ return h;
+}
+
+int mi_check_running_pid(pid_t pid)
+{
+ int status;
+
+ if (pid<=0)
+ return 0;
+ /* If waitpid returns the number of our child means it communicated
+ to as a termination status. */
+ if (waitpid(pid,&status,WNOHANG)==pid)
+ {
+ pid=0;
+ return 0;
+ }
+ return 1;
+}
+
+int mi_check_running(mi_h *h)
+{
+ return !h->died && mi_check_running_pid(h->pid);
+}
+
+void mi_kill_child(pid_t pid)
+{
+ kill(pid,SIGTERM);
+ usleep(100000);
+ if (mi_check_running_pid(pid))
+ {
+ int status;
+ kill(pid,SIGKILL);
+ waitpid(pid,&status,0);
+ }
+}
+
+void mi_free_h(mi_h **handle)
+{
+ mi_h *h=*handle;
+ if (h->to_gdb[0]>=0)
+ close(h->to_gdb[0]);
+ if (h->to)
+ fclose(h->to);
+ else if (h->to_gdb[1]>=0)
+ close(h->to_gdb[1]);
+ if (h->from)
+ fclose(h->from);
+ else if (h->from_gdb[0]>=0)
+ close(h->from_gdb[0]);
+ if (h->from_gdb[1]>=0)
+ close(h->from_gdb[1]);
+ if (mi_check_running(h))
+ {/* GDB is running! */
+ mi_kill_child(h->pid);
+ }
+ if (h->line)
+ free(h->line);
+ mi_free_output(h->po);
+ free(h->catched_console);
+ free(h);
+ *handle=NULL;
+}
+
+void mi_set_nonblk(int h)
+{
+ int flf;
+ flf=fcntl(h,F_GETFL,0);
+ flf=flf | O_NONBLOCK;
+ fcntl(h,F_SETFL,flf);
+}
+
+int mi_getline(mi_h *h)
+{
+ char c;
+
+ while (read(h->from_gdb[0],&c,1)==1)
+ {
+ if (h->lread>=h->llen)
+ {
+ h->llen=h->lread+128;
+ h->line=(char *)realloc(h->line,h->llen);
+ if (!h->line)
+ {
+ h->llen=0;
+ h->lread=0;
+ return -1;
+ }
+ }
+ if (c=='\n')
+ {
+ int ret=h->lread;
+ h->line[ret]=0;
+ h->lread=0;
+ return ret;
+ }
+ h->line[h->lread]=c;
+ h->lread++;
+ }
+ return 0;
+}
+
+char *get_cstr(mi_output *o)
+{
+ if (!o->c || o->c->type!=t_const)
+ return NULL;
+ return o->c->v.cstr;
+}
+
+int mi_get_response(mi_h *h)
+{
+ int l=mi_getline(h);
+ if (!l)
+ return 0;
+
+ if (h->from_gdb_echo)
+ h->from_gdb_echo(h->line,h->from_gdb_echo_data);
+ if (strncmp(h->line,"(gdb)",5)==0)
+ {/* End of response. */
+ return 1;
+ }
+ else
+ {/* Add to the response. */
+ mi_output *o;
+ int add=1, is_exit=0;
+ o=mi_parse_gdb_output(h->line);
+
+ if (!o)
+ return 0;
+ /* Tunneled streams callbacks. */
+ if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_STREAM)
+ {
+ char *aux;
+ add=0;
+ switch (o->sstype)
+ {
+ case MI_SST_CONSOLE:
+ aux=get_cstr(o);
+ if (h->console)
+ h->console(aux,h->console_data);
+ if (h->catch_console && aux)
+ {
+ h->catch_console--;
+ if (!h->catch_console)
+ {
+ free(h->catched_console);
+ h->catched_console=strdup(aux);
+ }
+ }
+ break;
+ case MI_SST_TARGET:
+ /* This one seems to be useless. */
+ if (h->target)
+ h->target(get_cstr(o),h->target_data);
+ break;
+ case MI_SST_LOG:
+ if (h->log)
+ h->log(get_cstr(o),h->log_data);
+ break;
+ }
+ }
+ else if (o->type==MI_T_OUT_OF_BAND && o->stype==MI_ST_ASYNC)
+ {
+ if (h->async)
+ h->async(o,h->async_data);
+ }
+ else if (o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_ERROR)
+ {/* Error from gdb, record it. */
+ mi_error=MI_FROM_GDB;
+ free(mi_error_from_gdb);
+ mi_error_from_gdb=NULL;
+ if (o->c && strcmp(o->c->var,"msg")==0 && o->c->type==t_const)
+ mi_error_from_gdb=strdup(o->c->v.cstr);
+ }
+ is_exit=(o->type==MI_T_RESULT_RECORD && o->tclass==MI_CL_EXIT);
+ /* Add to the list of responses. */
+ if (add)
+ {
+ if (h->last)
+ h->last->next=o;
+ else
+ h->po=o;
+ h->last=o;
+ }
+ else
+ mi_free_output(o);
+ /* Exit RR means gdb exited, we won't get a new prompt ;-) */
+ if (is_exit)
+ return 1;
+ }
+
+ return 0;
+}
+
+mi_output *mi_retire_response(mi_h *h)
+{
+ mi_output *ret=h->po;
+ h->po=h->last=NULL;
+ return ret;
+}
+
+mi_output *mi_get_response_blk(mi_h *h)
+{
+ int r;
+ /* Sometimes gdb dies. */
+ if (!mi_check_running(h))
+ {
+ h->died=1;
+ mi_error=MI_GDB_DIED;
+ return NULL;
+ }
+ do
+ {
+ if (1)
+ {
+ /*
+ That's a must. If we just keep trying to read and failing things
+ become really sloooowwww. Instead we try and if it fails we wait
+ until something is available.
+ TODO: Implement something with the time out, a callback to ask the
+ application is we have to wait or not could be a good thing.
+ */
+ fd_set set;
+ struct timeval timeout;
+ int ret;
+
+ r=mi_get_response(h);
+ if (r)
+ return mi_retire_response(h);
+
+ FD_ZERO(&set);
+ FD_SET(h->from_gdb[0],&set);
+ timeout.tv_sec=h->time_out;
+ timeout.tv_usec=0;
+ ret=TEMP_FAILURE_RETRY(select(FD_SETSIZE,&set,NULL,NULL,&timeout));
+ if (!ret)
+ {
+ if (!mi_check_running(h))
+ {
+ h->died=1;
+ mi_error=MI_GDB_DIED;
+ return NULL;
+ }
+ if (h->time_out_cb)
+ ret=h->time_out_cb(h->time_out_cb_data);
+ if (!ret)
+ {
+ mi_error=MI_GDB_TIME_OUT;
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ r=mi_get_response(h);
+ if (r)
+ return mi_retire_response(h);
+ else
+ usleep(100);
+ }
+ }
+ while (!r);
+
+ return NULL;
+}
+
+void mi_send_commands(mi_h *h, const char *file)
+{
+ FILE *f;
+ char b[PATH_MAX];
+
+ //printf("File: %s\n",file);
+ if (!file)
+ return;
+ f=fopen(file,"rt");
+ if (!f)
+ return;
+ while (!feof(f))
+ {
+ if (fgets(b,PATH_MAX,f))
+ {
+ //printf("Send: %s\n",b);
+ mi_send(h,b);
+ mi_res_simple_done(h);
+ }
+ }
+ fclose(f);
+}
+
+void mi_send_target_commands(mi_h *h)
+{
+ mi_send_commands(h,gdb_conn);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Connect to a local copy of gdb. Note that the mi_h structure is something
+similar to a "FILE *" for stdio.
+
+ Return: A new mi_h structure or NULL on error.
+
+***************************************************************************/
+
+mi_h *mi_connect_local()
+{
+ mi_h *h;
+ const char *gdb=mi_get_gdb_exe();
+
+ /* Start without error. */
+ mi_error=MI_OK;
+ /* Verify we have a GDB binary. */
+ if (access(gdb,X_OK))
+ {
+ mi_error=MI_MISSING_GDB;
+ return NULL;
+ }
+ /* Alloc the handle structure. */
+ h=mi_alloc_h();
+ if (!h)
+ return h;
+ h->time_out=MI_DEFAULT_TIME_OUT;
+ /* Create the pipes to connect with the child. */
+ if (pipe(h->to_gdb) || pipe(h->from_gdb))
+ {
+ mi_error=MI_PIPE_CREATE;
+ mi_free_h(&h);
+ return NULL;
+ }
+ mi_set_nonblk(h->to_gdb[1]);
+ mi_set_nonblk(h->from_gdb[0]);
+ /* Associate streams to the file handles. */
+ h->to=fdopen(h->to_gdb[1],"w");
+ h->from=fdopen(h->from_gdb[0],"r");
+ if (!h->to || !h->from)
+ {
+ mi_error=MI_PIPE_CREATE;
+ mi_free_h(&h);
+ return NULL;
+ }
+ /* Create the child. */
+ h->pid=fork();
+ if (h->pid==0)
+ {/* We are the child. */
+ char *argv[5];
+ /* Connect stdin/out to the pipes. */
+ dup2(h->to_gdb[0],STDIN_FILENO);
+ dup2(h->from_gdb[1],STDOUT_FILENO);
+ /* Pass the control to gdb. */
+ argv[0]=(char *)gdb; /* Is that OK? */
+ argv[1]="--interpreter=mi";
+ argv[2]="--quiet";
+ argv[3]=disable_psym_search_workaround ? 0 : "--readnow";
+ argv[4]=0;
+ execvp(argv[0],argv);
+ /* We get here only if exec failed. */
+ _exit(127);
+ }
+ /* We are the parent. */
+ if (h->pid==-1)
+ {/* Fork failed. */
+ mi_error=MI_FORK;
+ mi_free_h(&h);
+ return NULL;
+ }
+ if (!mi_check_running(h))
+ {
+ mi_error=MI_DEBUGGER_RUN;
+ mi_free_h(&h);
+ return NULL;
+ }
+ /* Wait for the prompt. */
+ mi_get_response_blk(h);
+ /* Send the start-up commands */
+ mi_send_commands(h,gdb_start);
+
+ return h;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Close connection. You should ask gdb to quit first @x{gmi_gdb_exit}.
+
+***************************************************************************/
+
+void mi_disconnect(mi_h *h)
+{
+ mi_free_h(&h);
+ free(mi_error_from_gdb);
+ mi_error_from_gdb=NULL;
+}
+
+void mi_set_console_cb(mi_h *h, stream_cb cb, void *data)
+{
+ h->console=cb;
+ h->console_data=data;
+}
+
+void mi_set_target_cb(mi_h *h, stream_cb cb, void *data)
+{
+ h->target=cb;
+ h->target_data=data;
+}
+
+void mi_set_log_cb(mi_h *h, stream_cb cb, void *data)
+{
+ h->log=cb;
+ h->log_data=data;
+}
+
+stream_cb mi_get_console_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->console_data;
+ return h->console;
+}
+
+stream_cb mi_get_target_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->target_data;
+ return h->target;
+}
+
+stream_cb mi_get_log_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->log_data;
+ return h->log;
+}
+
+void mi_set_async_cb(mi_h *h, async_cb cb, void *data)
+{
+ h->async=cb;
+ h->async_data=data;
+}
+
+async_cb mi_get_async_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->async_data;
+ return h->async;
+}
+
+void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data)
+{
+ h->to_gdb_echo=cb;
+ h->to_gdb_echo_data=data;
+}
+
+void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data)
+{
+ h->from_gdb_echo=cb;
+ h->from_gdb_echo_data=data;
+}
+
+stream_cb mi_get_to_gdb_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->to_gdb_echo_data;
+ return h->to_gdb_echo;
+}
+
+stream_cb mi_get_from_gdb_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->from_gdb_echo_data;
+ return h->from_gdb_echo;
+}
+
+void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data)
+{
+ h->time_out_cb=cb;
+ h->time_out_cb_data=data;
+}
+
+tm_cb mi_get_time_out_cb(mi_h *h, void **data)
+{
+ if (data)
+ *data=h->time_out_cb_data;
+ return h->time_out_cb;
+}
+
+void mi_set_time_out(mi_h *h, int to)
+{
+ h->time_out=to;
+}
+
+int mi_get_time_out(mi_h *h)
+{
+ return h->time_out;
+}
+
+int mi_send(mi_h *h, const char *format, ...)
+{
+ int ret;
+ char *str;
+ va_list argptr;
+
+ if (h->died)
+ return 0;
+
+ va_start(argptr,format);
+ ret=vasprintf(&str,format,argptr);
+ va_end(argptr);
+ fputs(str,h->to);
+ fflush(h->to);
+ if (h->to_gdb_echo)
+ h->to_gdb_echo(str,h->to_gdb_echo_data);
+ free(str);
+
+ return ret;
+}
+
+void mi_clean_up_globals()
+{
+ free(gdb_exe);
+ gdb_exe=NULL;
+ free(xterm_exe);
+ xterm_exe=NULL;
+ free(gdb_start);
+ gdb_start=NULL;
+ free(gdb_conn);
+ gdb_conn=NULL;
+ free(main_func);
+ main_func=NULL;
+}
+
+void mi_register_exit()
+{
+ static int registered=0;
+ if (!registered)
+ {
+ registered=1;
+ atexit(mi_clean_up_globals);
+ }
+}
+
+void mi_set_gdb_exe(const char *name)
+{
+ free(gdb_exe);
+ gdb_exe=name ? strdup(name) : NULL;
+ mi_register_exit();
+}
+
+void mi_set_gdb_start(const char *name)
+{
+ free(gdb_start);
+ gdb_start=name ? strdup(name) : NULL;
+ mi_register_exit();
+}
+
+void mi_set_gdb_conn(const char *name)
+{
+ free(gdb_conn);
+ gdb_conn=name ? strdup(name) : NULL;
+ mi_register_exit();
+}
+
+static
+char *mi_search_in_path(const char *file)
+{
+ char *path, *pt, *r;
+ char test[PATH_MAX];
+ struct stat st;
+
+ path=getenv("PATH");
+ if (!path)
+ return NULL;
+ pt=strdup(path);
+ r=strtok(pt,":");
+ while (r)
+ {
+ strcpy(test,r);
+ strcat(test,"/");
+ strcat(test,file);
+ if (stat(test,&st)==0 && S_ISREG(st.st_mode))
+ {
+ free(pt);
+ return strdup(test);
+ }
+ r=strtok(NULL,":");
+ }
+ free(pt);
+ return NULL;
+}
+
+const char *mi_get_gdb_exe()
+{
+ if (!gdb_exe)
+ {/* Look for gdb in path */
+ gdb_exe=mi_search_in_path("gdb");
+ if (!gdb_exe)
+ return "/usr/bin/gdb";
+ }
+ return gdb_exe;
+}
+
+const char *mi_get_gdb_start()
+{
+ return gdb_start;
+}
+
+const char *mi_get_gdb_conn()
+{
+ return gdb_conn;
+}
+
+void mi_set_xterm_exe(const char *name)
+{
+ free(xterm_exe);
+ xterm_exe=name ? strdup(name) : NULL;
+ mi_register_exit();
+}
+
+const char *mi_get_xterm_exe()
+{
+ if (!xterm_exe)
+ {/* Look for xterm in path */
+ xterm_exe=mi_search_in_path("xterm");
+ if (!xterm_exe)
+ return "/usr/bin/X11/xterm";
+ }
+ return xterm_exe;
+}
+
+void mi_set_main_func(const char *name)
+{
+ free(main_func);
+ main_func=name ? strdup(name) : NULL;
+ mi_register_exit();
+}
+
+const char *mi_get_main_func()
+{
+ if (main_func)
+ return main_func;
+ return "main";
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Opens a new xterm to be used by the child process to debug.
+
+ Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
+release it.
+
+***************************************************************************/
+
+mi_aux_term *gmi_start_xterm()
+{
+ char nsh[14]="/tmp/shXXXXXX";
+ char ntt[14]="/tmp/ttXXXXXX";
+ const char *xterm;
+ struct stat st;
+ int hsh, htt=-1;
+ mi_aux_term *res=NULL;
+ FILE *f;
+ pid_t pid;
+ char buf[PATH_MAX];
+
+ /* Verify we have an X terminal. */
+ xterm=mi_get_xterm_exe();
+ if (access(xterm,X_OK))
+ {
+ mi_error=MI_MISSING_XTERM;
+ return NULL;
+ }
+
+ /* Create 2 temporals. */
+ hsh=mkstemp(nsh);
+ if (hsh==-1)
+ {
+ mi_error=MI_CREATE_TEMPORAL;
+ return NULL;
+ }
+ htt=mkstemp(ntt);
+ if (htt==-1)
+ {
+ close(hsh);
+ unlink(nsh);
+ mi_error=MI_CREATE_TEMPORAL;
+ return NULL;
+ }
+ close(htt);
+ /* Create the script. */
+ f=fdopen(hsh,"w");
+ if (!f)
+ {
+ close(hsh);
+ unlink(nsh);
+ unlink(ntt);
+ mi_error=MI_CREATE_TEMPORAL;
+ return NULL;
+ }
+ fprintf(f,"#!/bin/sh\n");
+ fprintf(f,"tty > %s\n",ntt);
+ fprintf(f,"rm %s\n",nsh);
+ fprintf(f,"sleep 365d\n");
+ fclose(f);
+ /* Spawn xterm. */
+ /* Create the child. */
+ pid=fork();
+ if (pid==0)
+ {/* We are the child. */
+ char *argv[5];
+ /* Pass the control to gdb. */
+ argv[0]=(char *)mi_get_xterm_exe(); /* Is that ok? */
+ argv[1]="-e";
+ argv[2]="/bin/sh";
+ argv[3]=nsh;
+ argv[4]=0;
+ execvp(argv[0],argv);
+ /* We get here only if exec failed. */
+ unlink(nsh);
+ unlink(ntt);
+ _exit(127);
+ }
+ /* We are the parent. */
+ if (pid==-1)
+ {/* Fork failed. */
+ unlink(nsh);
+ unlink(ntt);
+ mi_error=MI_FORK;
+ return NULL;
+ }
+ /* Wait until the shell is deleted. */
+ while (stat(nsh,&st)==0)
+ usleep(1000);
+ /* Try to read the tty name. */
+ f=fopen(ntt,"rt");
+ if (f)
+ {
+ if (fgets(buf,PATH_MAX,f))
+ {
+ char *s; /* Strip the \n. */
+ for (s=buf; *s && *s!='\n'; s++);
+ *s=0;
+ res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
+ if (res)
+ {
+ res->pid=pid;
+ res->tty=strdup(buf);
+ }
+ }
+ fclose(f);
+ }
+ unlink(ntt);
+ return res;
+}
+
+void mi_free_aux_term(mi_aux_term *t)
+{
+ if (!t)
+ return;
+ free(t->tty);
+ free(t);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Closes the auxiliar terminal and releases the allocated memory.
+
+***************************************************************************/
+
+void gmi_end_aux_term(mi_aux_term *t)
+{
+ if (!t)
+ return;
+ if (t->pid!=-1 && mi_check_running_pid(t->pid))
+ mi_kill_child(t->pid);
+ mi_free_aux_term(t);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Forces the MI version. Currently the library can't detect it so you must
+force it manually. GDB 5.x implemented MI v1 and 6.x v2.
+
+***************************************************************************/
+
+void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
+ unsigned vMinor)
+{
+ h->version=MI_VERSION2U(vMajor,vMiddle,vMinor);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Dis/Enables the @var{wa} workaround for a bug in gdb.
+
+***************************************************************************/
+
+void mi_set_workaround(unsigned wa, int enable)
+{
+ switch (wa)
+ {
+ case MI_PSYM_SEARCH:
+ disable_psym_search_workaround=enable ? 0 : 1;
+ break;
+ }
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Finds if the @var{wa} workaround for a bug in gdb is enabled.
+
+ Return: !=0 if enabled.
+
+***************************************************************************/
+
+int mi_get_workaround(unsigned wa)
+{
+ switch (wa)
+ {
+ case MI_PSYM_SEARCH:
+ return disable_psym_search_workaround==0;
+ }
+ return 0;
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004-2007 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: C++ Interface.
+ Comments:
+ Implements a very simple (naive ;-) C++ wrapper.@p
+
+***************************************************************************/
+
+#include <string.h>
+#include <limits.h>
+#include "mi_gdb.h"
+
+/**[txh]********************************************************************
+
+ Description:
+ Initializes a debugger object. It starts in the "disconnected" state.
+Use @x{::Connect} after it.
+
+***************************************************************************/
+
+MIDebugger::MIDebugger()
+{
+ state=disconnected;
+ h=NULL;
+ aux_tty=NULL;
+ waitingTempBkpt=0;
+ targetEndian=enUnknown;
+ targetArch=arUnknown;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ This is the destructor for the class. It tries to change the state to
+"disconnected" doing the needed actions.
+
+***************************************************************************/
+
+MIDebugger::~MIDebugger()
+{
+ if (state==running)
+ {
+ Stop();
+ mi_stop *rs;
+ // TODO: Some kind of time-out
+ while (!Poll(rs));
+ mi_free_stop(rs);
+ state=stopped;
+ }
+ if (state==stopped)
+ {
+ Kill();
+ state=target_specified;
+ }
+ if (state==target_specified)
+ {
+ TargetUnselect();
+ state=connected;
+ }
+ if (state==connected)
+ Disconnect();
+ // Here state==disconnected
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Connects to gdb. Currently only local connections are supported, that's
+a gdb limitation. Call it when in "unconnected" state, on success it will
+change to the "connected" state. After it you should call one of the
+SelectTarget members. @x{::SelectTargetX11}, @x{::SelectTargetLinux} or
+@x{::SelectTargetRemote}. To finish the connection use @x{::Disconnect}.
+
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int MIDebugger::Connect(bool )
+{
+ if (state==disconnected)
+ {
+ h=mi_connect_local();
+ if (h!=NULL)
+ {
+ state=connected;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Finishes the connection to gdb. Call when in "connected" state, on success
+it will change to "disconnected" state. This function first tries to exit
+from gdb and then close the connection. But if gdb fails to exit it will be
+killed.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::Disconnect()
+{
+ if (state==connected)
+ {
+ gmi_gdb_exit(h);
+ mi_disconnect(h);
+ state=disconnected;
+ return 1;
+ }
+ return 0;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Protected member that implements @x{::SelectTargetX11} and
+@x{::SelectTargetLinux}.
+
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int MIDebugger::SelectTargetTTY(const char *exec, const char *args,
+ const char *auxtty, dMode m)
+{
+ if (state!=connected)
+ return 0;
+
+ targetEndian=enUnknown;
+ targetArch=arUnknown;
+ mode=m;
+ if (!gmi_set_exec(h,exec,args))
+ return 0;
+
+ const char *tty_name;
+ #ifndef __CYGWIN__
+ if (!auxtty)
+ {
+ aux_tty=m==dmLinux ? gmi_look_for_free_vt() : gmi_start_xterm();
+ if (!aux_tty)
+ return 0;
+ tty_name=aux_tty->tty;
+ }
+ else
+ {
+ tty_name=auxtty;
+ }
+ if (!gmi_target_terminal(h,tty_name))
+ return 0;
+ #else
+ tty_name=NULL;
+ if (!gmi_gdb_set(h,"new-console","on"))
+ return 0;
+ #endif
+
+ state=target_specified;
+ preRun=false;
+ return 1;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Starts a debug session for X11. It opens an xterm console for the program
+to debug and tells gdb which executable to debug and the command line
+options to pass. You can specify an already existing tty console to be used.
+Can be called when the state is "connected". On success will change to the
+"target_specified" state. After it you can use @x{::Run} or use the members
+to define breakpoints and similar stuff. To finish it use
+@x{::TargetUnselect}.
+
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int MIDebugger::SelectTargetX11(const char *exec, const char *args,
+ const char *auxtty)
+{
+ return SelectTargetTTY(exec,args,auxtty,dmX11);
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Starts a debug session for Linux console. It selects an empty VT for the
+program to debug and tells gdb which executable to debug and the command line
+options to pass. You can specify an already existing tty console to be used.
+Can be called when the state is "connected". On success will change to the
+"target_specified" state. After it you can use @x{::Run} or use the members
+to define breakpoints and similar stuff. To finish it use
+@x{::TargetUnselect}.
+
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int MIDebugger::SelectTargetLinux(const char *exec, const char *args,
+ const char *auxtty)
+{
+ return SelectTargetTTY(exec,args,auxtty,dmLinux);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Starts a remote session. The other end should be running gdbserver. You
+must specify a local copy of the program to debug with debug info. The remote
+copy can be stripped. The @var{rtype} and @var{rparams} selects the protocol
+and the remote machine. Read gdb docs to know more about the available
+options. If @var{rtype} is omitted "extended-remote" protocol is used.
+Can be called when the state is "connected". On success will change to the
+"target_specified" state. After it you can use @x{::Run} or use the members
+to define breakpoints and similar stuff. To finish it use
+@x{::TargetUnselect}. Note that when gdb uses remote debugging the remote
+program starts running. The @x{::Run} member knows about it.
+
+ Return: !=0 OK.
+ Example:
+ o->SelectTargetRemote("./exec_file","192.168.1.65:5000");
+
+***************************************************************************/
+
+int MIDebugger::SelectTargetRemote(const char *exec, const char *rparams,
+ const char *rtype, bool download)
+{
+ if (state!=connected)
+ return 0;
+
+ mode=dmRemote;
+ preRun=true;
+ targetEndian=enUnknown;
+ targetArch=arUnknown;
+ if (rtype==NULL)
+ rtype="extended-remote";
+
+ /* Tell gdb to load symbols from the local copy. */
+ int res=download ? gmi_set_exec(h,exec,NULL) : gmi_file_symbol_file(h,exec);
+ if (!res)
+ return 0;
+ /* Select the target */
+ if (!gmi_target_select(h,rtype,rparams))
+ return 0;
+ /* Download the binary */
+ if (download)
+ {
+ if (!gmi_target_download(h))
+ return 0;
+ }
+
+ state=target_specified;
+ return 1;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Starts a local session using an already running process.
+
+ Return: !=0 OK.
+
+***************************************************************************/
+
+mi_frames *MIDebugger::SelectTargetPID(const char *exec, int pid)
+{
+ if (state!=connected)
+ return NULL;
+
+ mode=dmPID;
+ preRun=false;
+ targetEndian=enUnknown;
+ targetArch=arUnknown;
+
+ mi_frames *res=gmi_target_attach(h,pid);
+ if (res)
+ {
+ state=stopped;
+
+ /* Tell gdb to load symbols from the local copy. */
+ if (!gmi_file_symbol_file(h,exec))
+ {
+ mi_free_frames(res);
+ return NULL;
+ }
+ }
+
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Used to unselect the current target. When X11 mode it closes the auxiliar
+terminal. For remote debugging it uses "detach". Can be called when in
+"target_specified" state. On success it changes to "connected" state.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::TargetUnselect()
+{
+ switch (mode)
+ {
+ case dmX11:
+ case dmLinux:
+ if (state!=target_specified)
+ return 0;
+ if (aux_tty)
+ {
+ gmi_end_aux_term(aux_tty);
+ aux_tty=NULL;
+ }
+ break;
+ case dmPID:
+ case dmRemote:
+ if (state!=target_specified)
+ {
+ if (state!=stopped || !gmi_target_detach(h))
+ return 0;
+ }
+ break;
+ }
+ state=connected;
+ return 1;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Starts running the program. You should set breakpoint before it. Can be
+called when state is "target_specified". On success will change to "running"
+state. After it you should poll for async responses using @x{::Poll}. The
+program can stop for many reasons asynchronously and also exit. This
+information is known using Poll. You can stop the program using @x{::Stop}.
+
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int MIDebugger::Run()
+{
+ if (state!=target_specified)
+ return 0;
+
+ int res;
+ if (preRun)
+ res=gmi_exec_continue(h);
+ else
+ res=gmi_exec_run(h);
+ if (res)
+ state=running;
+
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Stops the program execution. GDB sends an interrupt signal to the program.
+Can be called when the state is "running". It won't switch to "stopped"
+state automatically. Instead you must poll for async events and wait for a
+stopped notification. After it you can call @x{::Continue} to resume
+execution.
+
+ Return:
+ Example: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::Stop()
+{
+ if (state!=running)
+ return 0;
+ return gmi_exec_interrupt(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Polls gdb looking for async responses. Currently it just looks for
+"stopped" messages. You must call it when the state is "running". But the
+function will poll gdb even if the state isn't "running". When a stopped
+message is received the state changes to stopped or target_specified (the
+last is when we get some exit).
+
+ Return: !=0 if we got a response. The @var{rs} pointer will point to an
+mi_stop structure if we got it or will be NULL if we didn't.
+
+***************************************************************************/
+
+int MIDebugger::Poll(mi_stop *&rs)
+{
+ if (state==disconnected || !mi_get_response(h))
+ return 0;
+
+ mi_stop *res=mi_res_stop(h);
+ if (res)
+ {
+ if (res->reason==sr_exited_signalled ||
+ res->reason==sr_exited ||
+ res->reason==sr_exited_normally)
+ // When we use a PID the exit makes it invalid, so we don't have a
+ // valid target to re-run.
+ state=mode==dmPID ? connected : target_specified;
+ else
+ state=stopped;
+ if (res->reason==sr_unknown && waitingTempBkpt)
+ {
+ waitingTempBkpt=0;
+ res->reason=sr_bkpt_hit;
+ }
+ }
+ else
+ {// We got an error. It looks like most async commands returns running even
+ // before they are sure the process is running. Latter we get the real
+ // error. So I'm assuming the program is stopped.
+ // Lamentably -target-exec-status isn't implemented and even in this case
+ // if the program is really running as real async isn't implemented it
+ // will fail anyways.
+ if (state==running)
+ state=stopped;
+ }
+ rs=res;
+ return 1;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Resumes execution after the program "stopped". Can be called when the state
+is stopped. On success will change to "running" state.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::Continue()
+{
+ if (state!=stopped)
+ return 0;
+ int res=gmi_exec_continue(h);
+ if (res)
+ state=running;
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Starts program execution or resumes it. When the state is target_specified
+it calls @x{::Run} otherwise it uses @x{::Continue}. Can be called when the
+state is "target_specified" or "stopped". On success will change to
+"running" state.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::RunOrContinue()
+{
+ if (state==target_specified)
+ return Run();
+ return Continue();
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Kills the program you are debugging. Can be called when the state is
+"stopped" or "running". On success changes the state to "target_specified".
+Note that if you want to restart the program you can just call @x{::Run} and
+if you want to just stop the program call @x{::Stop}.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::Kill()
+{
+ if (state!=stopped && state!=running)
+ return 0;
+ /* GDB/MI doesn't implement it (yet), so we use the regular kill. */
+ /* Ensure confirm is off. */
+ char *prev=gmi_gdb_show(h,"confirm");
+ if (!prev)
+ return 0;
+ if (strcmp(prev,"off"))
+ {
+ if (!gmi_gdb_set(h,"confirm","off"))
+ {
+ free(prev);
+ return 0;
+ }
+ }
+ else
+ {
+ free(prev);
+ prev=NULL;
+ }
+ /* Do the kill. */
+ int res=gmi_exec_kill(h);
+ /* Revert confirm option if needed. */
+ if (prev)
+ {
+ gmi_gdb_set(h,"confirm",prev);
+ free(prev);
+ }
+
+ if (res)
+ state=target_specified;
+
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Inserts a breakpoint at @var{file} and @var{line}. Can be called when the
+state is "stopped" or "target_specified".
+
+ Return: An mi_bkpt structure or NULL if error.
+
+***************************************************************************/
+
+mi_bkpt *MIDebugger::Breakpoint(const char *file, int line)
+{
+ if (state!=stopped && state!=target_specified)
+ return NULL;
+ return gmi_break_insert(h,file,line);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Inserts a breakpoint at @var{where}, all options available. Can be called
+when the state is "stopped" or "target_specified".
+
+ Return: An mi_bkpt structure or NULL if error.
+
+***************************************************************************/
+
+mi_bkpt *MIDebugger::Breakpoint(const char *where, bool temporary,
+ const char *cond, int count, int thread,
+ bool hard_assist)
+{
+ if (state!=stopped && state!=target_specified)
+ return NULL;
+ return gmi_break_insert_full(h,temporary,hard_assist,cond,count,thread,where);
+}
+
+
+const int maxWhere=PATH_MAX+256;
+
+mi_bkpt *MIDebugger::Breakpoint(mi_bkpt *b)
+{
+ if (state!=stopped && state!=target_specified)
+ return NULL;
+
+ char buf[maxWhere];
+ buf[0]=0;
+ switch (b->mode)
+ {
+ case m_file_line:
+ snprintf(buf,maxWhere,"%s:%d",b->file,b->line);
+ break;
+ case m_function:
+ snprintf(buf,maxWhere,"%s",b->func);
+ break;
+ case m_file_function:
+ snprintf(buf,maxWhere,"%s:%s",b->file,b->func);
+ break;
+ case m_address:
+ snprintf(buf,maxWhere,"*%p",b->addr);
+ break;
+ }
+ return Breakpoint(buf,b->disp==d_del,b->cond,b->ignore,b->thread,
+ b->type==t_hw);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Inserts a breakpoint at @var{file} and @var{line} all options available.
+Can be called when the state is "stopped" or "target_specified".
+
+ Return: An mi_bkpt structure or NULL if error.
+
+***************************************************************************/
+
+mi_bkpt *MIDebugger::BreakpointFull(const char *file, int line,
+ bool temporary, const char *cond,
+ int count, int thread, bool hard_assist)
+{
+ if (state!=stopped && state!=target_specified)
+ return NULL;
+ return gmi_break_insert_full_fl(h,file,line,temporary,hard_assist,cond,
+ count,thread);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Removes the specified breakpoint. It doesn't free the structure. Can be
+called when the state is "stopped" or "target_specified".
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::BreakDelete(mi_bkpt *b)
+{
+ if ((state!=stopped && state!=target_specified) || !b)
+ return 0;
+ return gmi_break_delete(h,b->number);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Inserts a watchpoint for the specified expression. Can be called when the
+state is "stopped" or "target_specified".
+
+ Return: An mi_wp structure or NULL if error.
+
+***************************************************************************/
+
+mi_wp *MIDebugger::Watchpoint(enum mi_wp_mode mode, const char *exp)
+{
+ if (state!=stopped && state!=target_specified)
+ return NULL;
+ return gmi_break_watch(h,mode,exp);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Removes the specified watchpoint. It doesn't free the structure. Can be
+called when the state is "stopped" or "target_specified".
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::WatchDelete(mi_wp *w)
+{
+ if ((state!=stopped && state!=target_specified) || !w)
+ return 0;
+ return gmi_break_delete(h,w->number);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Puts a temporal breakpoint in main function and starts running. Can be
+called when the state is "target_specified". If successful the state will
+change to "running".
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::RunToMain()
+{
+ if (state!=target_specified)
+ return 0;
+ mi_bkpt *b=Breakpoint(mi_get_main_func(),true);
+ if (!b)
+ return 0;
+ mi_free_bkpt(b);
+ waitingTempBkpt=1;
+ return Run();
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Executes upto the next line, doesn't follow function calls. The @var{inst}
+argument is for assembler. If the state is "target_specified" it will go to
+the first line in the main function. If the state is "stopped" will use the
+next command. If successfully the state will change to "running".
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::StepOver(bool inst)
+{
+ int res=0;
+
+ if (state==target_specified)
+ {// We aren't running
+ // Walk to main
+ return RunToMain();
+ }
+ if (state==stopped)
+ {
+ if (inst)
+ res=gmi_exec_next_instruction(h);
+ else
+ res=gmi_exec_next(h);
+ if (res)
+ state=running;
+ }
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Executes until the specified point. If the state is "target_specified" it
+uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
+Fails for any other state.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::GoTo(const char *file, int line)
+{
+ int res=0;
+
+ if (state==target_specified)
+ {// We aren't running
+ // Use a temporal breakpoint
+ int l=strlen(file)+32;
+ char buf[l];
+ snprintf(buf,l,"%s:%d",file,line);
+ mi_bkpt *b=Breakpoint(buf,true);
+ if (b)
+ {
+ mi_free_bkpt(b);
+ waitingTempBkpt=1;
+ res=Run();
+ }
+ }
+ else if (state==stopped)
+ {
+ res=gmi_exec_until(h,file,line);
+ if (res)
+ state=running;
+ }
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Executes until the specified point. If the state is "target_specified" it
+uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
+Fails for any other state.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::GoTo(void *addr)
+{
+ int res=0;
+
+ if (state==target_specified)
+ {// We aren't running
+ // Use a temporal breakpoint
+ char buf[32];
+ snprintf(buf,32,"*%p",addr);
+ mi_bkpt *b=Breakpoint(buf,true);
+ if (b)
+ {
+ mi_free_bkpt(b);
+ waitingTempBkpt=1;
+ res=Run();
+ }
+ }
+ else if (state==stopped)
+ {
+ res=gmi_exec_until_addr(h,addr);
+ if (res)
+ state=running;
+ }
+ return res;
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Resumes execution until the end of the current funtion is reached. Only
+usable when we are in the "stopped" state.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::FinishFun()
+{
+ if (state!=stopped)
+ return 0;
+ int res=gmi_exec_finish(h);
+ if (res)
+ state=running;
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Returns immediately. Only usable when we are in the "stopped" state.
+
+ Return: !=NULL OK, the returned frame is the current location. That's a
+synchronous function.
+
+***************************************************************************/
+
+mi_frames *MIDebugger::ReturnNow()
+{
+ if (state!=stopped)
+ return 0;
+ return gmi_exec_return(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Returns the current list of frames.
+
+ Return: !=NULL OK, the list of frames is returned.
+
+***************************************************************************/
+
+mi_frames *MIDebugger::CallStack(bool args)
+{
+ if (state!=stopped)
+ return 0;
+ mi_frames *fr1=gmi_stack_list_frames(h);
+ if (fr1 && args)
+ {// Get the function arguments
+ mi_frames *fr2=gmi_stack_list_arguments(h,1);
+ if (fr2)
+ {// Transfer them to the other list
+ mi_frames *p=fr1, *p2=fr2;
+ while (p2 && p)
+ {
+ p->args=p2->args;
+ p2->args=NULL;
+ p2=p2->next;
+ p=p->next;
+ }
+ mi_free_frames(fr2);
+ }
+ }
+ return fr1;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Executes upto the next line, it follows function calls. The @var{inst}
+argument is for assembler. If the state is "target_specified" it will go to
+the first line in the main function. If the state is "stopped" will use the
+next command. If successfully the state will change to "running".
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::TraceInto(bool inst)
+{
+ int res=0;
+
+ if (state==target_specified)
+ {// We aren't running
+ // Walk to main
+ return RunToMain();
+ }
+ if (state==stopped)
+ {
+ if (inst)
+ res=gmi_exec_step_instruction(h);
+ else
+ res=gmi_exec_step(h);
+ if (res)
+ state=running;
+ }
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Evaluates the provided expression. If we get an error the error
+description is returned instead. Can't be called if "disconnected" or
+"running".
+
+ Return: The result of the expression (use free) or NULL.
+
+***************************************************************************/
+
+char *MIDebugger::EvalExpression(const char *exp)
+{
+ if (state==disconnected ||
+ state==running) // No async :-(
+ return NULL;
+ // Evaluate it
+ mi_error=MI_OK;
+ char *res=gmi_data_evaluate_expression(h,exp);
+ if (!res && mi_error_from_gdb)
+ {// Not valid, return the error
+ res=strdup(mi_error_from_gdb);
+ }
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Modifies the provided expression. If we get an error the error
+description is returned instead. Can't be called if "disconnected" or
+"running".
+
+ Return: The result of the expression (use free) or NULL.
+
+***************************************************************************/
+
+char *MIDebugger::ModifyExpression(char *exp, char *newVal)
+{
+ if (state==disconnected ||
+ state==running) // No async :-(
+ return NULL;
+ // Create an assignment
+ int l1=strlen(exp);
+ int l2=strlen(newVal);
+ char b[l1+l2+2], *s=b;
+ memcpy(s,exp,l1);
+ s+=l1;
+ *s='=';
+ memcpy(++s,newVal,l2);
+ s[l2]=0;
+ // Evaluate it
+ char *res=gmi_data_evaluate_expression(h,b);
+ if (!res && mi_error_from_gdb)
+ {// Not valid, return the error
+ res=strdup(mi_error_from_gdb);
+ }
+ return res;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Sends a command to gdb.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::Send(const char *command)
+{
+ if (state==disconnected ||
+ state==running) // No async :-(
+ return 0;
+ // TODO: detect and use -interpreter-exec?
+ mi_send(h,"%s\n",command);
+ return mi_res_simple_done(h);
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Fills the type and value fields of the mi_gvar provided list.
+
+ Return: !=0 OK
+
+***************************************************************************/
+
+int MIDebugger::FillTypeVal(mi_gvar *var)
+{
+ while (var)
+ {
+ if (!var->type && !gmi_var_info_type(h,var))
+ return 0;
+ if (!var->value && !gmi_var_evaluate_expression(h,var))
+ return 0;
+ var=var->next;
+ }
+ return 1;
+}
+
+int MIDebugger::FillOneTypeVal(mi_gvar *var)
+{
+ if (!var)
+ return 0;
+
+ int ok=1;
+ if (!var->type && !gmi_var_info_type(h,var))
+ {
+ var->type=strdup("");
+ ok=0;
+ }
+ if (!var->value && !gmi_var_evaluate_expression(h,var))
+ {
+ var->value=strdup("");
+ ok=0;
+ }
+ return ok;
+}
+
+int MIDebugger::AssigngVar(mi_gvar *var, const char *exp)
+{
+ if (state!=stopped)
+ return 0;
+ return gmi_var_assign(h,var,exp);
+}
+
+char *MIDebugger::Show(const char *var)
+{
+ if (state==running || state==disconnected)
+ return 0;
+ // GDB 5.x doesn't reply all in the response record, just to the console :-(
+ h->catch_console=1;
+ if (h->catched_console)
+ {
+ free(h->catched_console);
+ h->catched_console=NULL;
+ }
+ char *res=gmi_gdb_show(h,var);
+ h->catch_console=0;
+ if (!res && h->catched_console)
+ {
+ res=h->catched_console;
+ h->catched_console=NULL;
+ }
+ return res;
+}
+
+MIDebugger::endianType MIDebugger::GetTargetEndian()
+{
+ if (targetEndian!=enUnknown)
+ return targetEndian;
+ if (state!=stopped && state!=target_specified)
+ return enUnknown;
+
+ char *end=Show("endian");
+ if (end)
+ {
+ if (strstr(end,"big"))
+ targetEndian=enBig;
+ else if (strstr(end,"little"))
+ targetEndian=enLittle;
+ free(end);
+ }
+ return targetEndian;
+}
+
+MIDebugger::archType MIDebugger::GetTargetArchitecture()
+{
+ if (targetArch!=arUnknown)
+ return targetArch;
+ if (state!=stopped && state!=target_specified)
+ return arUnknown;
+
+ char *end=Show("architecture");
+ if (end)
+ {
+ if (strstr(end,"i386"))
+ targetArch=arIA32;
+ else if (strstr(end,"sparc"))
+ targetArch=arSPARC;
+ else if (strstr(end,"pic14"))
+ targetArch=arPIC14;
+ else if (strstr(end,"avr"))
+ targetArch=arAVR;
+ free(end);
+ }
+ return targetArch;
+}
+
+int MIDebugger::GetErrorNumberSt()
+{
+ if (mi_error==MI_GDB_DIED)
+ {
+ state=target_specified;
+ TargetUnselect();
+ state=connected;
+ Disconnect();
+ }
+ return mi_error;
+}
+
+int MIDebugger::UpdateRegisters(mi_chg_reg *regs)
+{
+ int updated=0;
+ mi_chg_reg *chg=GetChangedRegisters();
+ if (chg)
+ {
+ mi_chg_reg *r=regs, *c;
+ while (r)
+ {
+ c=chg;
+ while (c && c->reg!=r->reg)
+ c=c->next;
+ if (c)
+ {
+ r->updated=1;
+ free(r->val);
+ r->val=c->val;
+ c->val=NULL;
+ updated++;
+ }
+ else
+ r->updated=0;
+ r=r->next;
+ }
+ }
+ return updated;
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Data manipulation.
+ Comments:
+ GDB/MI commands for the "Data manipulation" section.@p
+
+@<pre>
+gdb command: Implemented?
+
+-data-disassemble Yes
+-data-evaluate-expression Yes
+-data-list-changed-registers No
+-data-list-register-names Yes
+-data-list-register-values No
+-data-read-memory No
+-display-delete N.A. (delete display)
+-display-disable N.A. (disable display)
+-display-enable N.A. (enable display)
+-display-insert N.A. (display)
+-display-list N.A. (info display)
+-environment-cd No
+-environment-directory Yes, MI v1 implementation
+-environment-path No
+@</pre>
+
+Notes:@p
+
+1) -display* aren't implemented. You can use CLI command display, but the
+results are sent to the console. So it looks like the best is to manually
+use -data-evaluate-expression to emulate it.@p
+
+2) GDB bug mi/1770: Affects gdb<=6.2, when you ask for the names of the
+registers you get it plus the name of the "pseudo-registers", but if you
+try to get the value of a pseudo-register you get an error saying the
+register number is invalid. I reported to gdb-patches@sources.redhat.com
+on 2004/08/25 and as I didn't get any answer I filled a bug report on
+2004/09/02. The patch to fix this annoying bug is:
+
+Index: gdb/mi/mi-main.c
+===================================================================
+RCS file: /cvs/src/src/gdb/mi/mi-main.c,v
+retrieving revision 1.64
+diff -u -r1.64 mi-main.c
+--- gdb/mi/mi-main.c 3 Aug 2004 00:57:27 -0000 1.64
++++ gdb/mi/mi-main.c 25 Aug 2004 14:12:50 -0000
+@@ -423,7 +423,7 @@
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged.
+
+- numregs = NUM_REGS;
++ numregs = NUM_REGS + NUM_PSEUDO_REGS;
+
+ if (argc == 0)
+ {
+----
+
+Note I had to remove an end of comment in the patch to include it here.
+This bug forced me to create another set of functions. The only way is to
+first get the values and then the names.
+Fixed by Changelog entry:
+
+2004-09-12 Salvador E. Tropea <set@users.sf.net>
+ Andrew Cagney <cagney@gnu.org>
+
+ * mi/mi-main.c (mi_cmd_data_list_changed_registers)
+ (mi_cmd_data_list_register_values)
+ (mi_cmd_data_write_register_values): Include the PSEUDO_REGS in
+ the register number computation.
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_data_evaluate_expression(mi_h *h, const char *expression)
+{
+ mi_send(h,"-data-evaluate-expression \"%s\"\n",expression);
+}
+
+void mi_dir(mi_h *h, const char *path)
+{
+ if (h->version>=MI_VERSION2U(2,0,0))
+ {// MI v2
+ if (path)
+ mi_send(h,"-environment-directory \"%s\"\n",path);
+ else
+ mi_send(h,"-environment-directory -r\n");
+ }
+ else
+ {
+ mi_send(h,"-environment-directory %s\n",path ? path : "");
+ }
+}
+
+void mi_data_read_memory_hx(mi_h *h, const char *exp, unsigned ws,
+ unsigned c, int convAddr)
+{
+ if (convAddr)
+ mi_send(h,"-data-read-memory \"&%s\" x %d 1 %d\n",exp,ws,c);
+ else
+ mi_send(h,"-data-read-memory \"%s\" x %d 1 %d\n",exp,ws,c);
+}
+
+void mi_data_disassemble_se(mi_h *h, const char *start, const char *end,
+ int mode)
+{
+ mi_send(h,"-data-disassemble -s \"%s\" -e \"%s\" -- %d\n",start,end,mode);
+}
+
+void mi_data_disassemble_fl(mi_h *h, const char *file, int line, int lines,
+ int mode)
+{
+ mi_send(h,"-data-disassemble -f \"%s\" -l %d -n %d -- %d\n",file,line,lines,
+ mode);
+}
+
+void mi_data_list_register_names(mi_h *h)
+{
+ mi_send(h,"-data-list-register-names\n");
+}
+
+void mi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
+{
+ mi_send(h,"-data-list-register-names ");
+ while (l)
+ {
+ mi_send(h,"%d ",l->reg);
+ l=l->next;
+ }
+ mi_send(h,"\n");
+}
+
+void mi_data_list_changed_registers(mi_h *h)
+{
+ mi_send(h,"-data-list-changed-registers\n");
+}
+
+void mi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
+{
+ mi_send(h,"-data-list-register-values %c ",mi_format_enum_to_char(fmt));
+ while (l)
+ {
+ mi_send(h,"%d ",l->reg);
+ l=l->next;
+ }
+ mi_send(h,"\n");
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ Evaluate an expression. Returns a parsed tree.
+
+ Command: -data-evaluate-expression
+ Return: The resulting value (as plain text) or NULL on error.
+
+***************************************************************************/
+
+char *gmi_data_evaluate_expression(mi_h *h, const char *expression)
+{
+ mi_data_evaluate_expression(h,expression);
+ return mi_res_value(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Path for sources. You must use it to indicate where are the sources for
+the program to debug. Only the MI v1 implementation is available.
+
+ Command: -environment-directory
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_dir(mi_h *h, const char *path)
+{
+ mi_dir(h,path);
+ return mi_res_simple_done(h);
+}
+
+int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
+ unsigned char *dest, int *na, int convAddr,
+ unsigned long *addr)
+{
+ mi_data_read_memory_hx(h,exp,1,size,convAddr);
+ return mi_get_read_memory(h,dest,1,na,addr);
+}
+
+mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
+ const char *end, int mode)
+{
+ mi_data_disassemble_se(h,start,end,mode);
+ return mi_get_asm_insns(h);
+}
+
+mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
+ int lines, int mode)
+{
+ mi_data_disassemble_fl(h,file,line,lines,mode);
+ return mi_get_asm_insns(h);
+}
+
+// Affected by gdb bug mi/1770
+mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many)
+{
+ mi_data_list_register_names(h);
+ return mi_get_list_registers(h,how_many);
+}
+
+int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l)
+{
+ mi_data_list_register_names_l(h,l);
+ return mi_get_list_registers_l(h,l);
+}
+
+mi_chg_reg *gmi_data_list_changed_registers(mi_h *h)
+{
+ mi_error=MI_OK;
+ mi_data_list_changed_registers(h);
+ return mi_get_list_changed_regs(h);
+}
+
+int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l)
+{
+ mi_data_list_register_values(h,fmt,l);
+ return mi_get_reg_values(h,l);
+}
+
+mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many)
+{
+ mi_data_list_register_values(h,fmt,NULL);
+ return mi_get_reg_values_l(h,how_many);
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Error.
+ Comment:
+ Translates error numbers into messages.
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+static
+const char *error_strs[]=
+{
+ "Ok",
+ "Out of memory",
+ "Pipe creation",
+ "Fork failed",
+ "GDB not running",
+ "Parser failed",
+ "Unknown asyn response",
+ "Unknown result response",
+ "Error from gdb",
+ "Time out in gdb response",
+ "GDB suddenly died",
+ "Can't execute X terminal",
+ "Failed to create temporal",
+ "Can't execute the debugger"
+};
+
+const char *mi_get_error_str()
+{
+ if (mi_error<0 || mi_error>MI_LAST_ERROR)
+ return "Unknown";
+ return error_strs[mi_error];
+}
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: pseudo terminal
+ Comments:
+ Helper to find a free pseudo terminal. Use this if you need to manage
+ input *and* output to the target process. If you just need output then
+ define a handler for target output stream records (assuming that this
+ is working for your particular version of gdb).
+ Usage:
+
+ mi_pty *pty = gmi_look_for_free_pty();
+ if (pty) gmi_target_terminal(mih, pty->slave);
+ ...
+ * reading from pty->master will get stdout from target *
+ * writing to pty->master will send to target stdin *
+
+ Note: Contributed by Greg Watson (gwatson lanl gov)
+
+***************************************************************************/
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "mi_gdb.h"
+
+/**[txh]********************************************************************
+
+ Description:
+ Look for a free and usable pseudo terminal. Low level, use
+@x{gmi_look_for_free_pty}.
+
+ Return: A file descriptor connected to the master pty and the name of the slave device, or <0 on error.
+
+***************************************************************************/
+
+#ifdef __APPLE__
+
+#include <util.h>
+
+int mi_look_for_free_pty(int *master, char **slave)
+{
+ int fdmaster;
+ int fdslave;
+ static char name[BUFSIZ];
+
+ if (openpty(&fdmaster,&fdslave,name,NULL,NULL)<0)
+ return -1;
+
+ (void)close(fdslave); /* this will be reopened by gdb */
+ *master=fdmaster;
+ *slave =name;
+
+ return 0;
+}
+
+#elif defined(__linux__)
+
+int mi_look_for_free_pty(int *master, char **slave)
+{
+ if ((*master=open("/dev/ptmx",O_RDWR))<0)
+ return -1;
+ if (grantpt(*master)<0 || unlockpt(*master)<0)
+ return -1;
+ *slave = ptsname(*master);
+
+ return 0;
+}
+
+#else /* undefined o/s */
+
+int mi_look_for_free_pty(int *master, char **slave)
+{
+ return -1;
+}
+#endif
+
+/**[txh]********************************************************************
+
+ Description:
+ Look for a free and usable pseudo terminal to be used by the child.
+
+ Return: A new mi_pty structure, you can use @x{gmi_end_pty} to
+release it.
+
+***************************************************************************/
+
+mi_pty *gmi_look_for_free_pty()
+{
+ int master;
+ char *slave;
+ int pty=mi_look_for_free_pty(&master,&slave);
+ mi_pty *res;
+
+ if (pty<0)
+ return NULL;
+ res=(mi_pty *)malloc(sizeof(mi_pty));
+ if (!res)
+ return NULL;
+ res->slave=strdup(slave);
+ res->master=master;
+ return res;
+}
+
+void mi_free_pty(mi_pty *p)
+{
+ if (!p)
+ return;
+ free(p->slave);
+ free(p);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Closes the pseudo termial master and releases the allocated memory.
+
+***************************************************************************/
+
+void gmi_end_pty(mi_pty *p)
+{
+ if (!p)
+ return;
+ close(p->master);
+ mi_free_pty(p);
+}
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Linux VT.
+ Comments:
+ Helper to find a free VT. That's 100% Linux specific.@p
+ The code comes from "lconsole.c" from Allegro project and was originally
+created by Marek Habersack and then modified by George Foot. I addapted it
+to my needs and changed license from giftware to GPL.@p
+
+***************************************************************************/
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#ifdef __APPLE__
+#include <util.h>
+#endif /* __APPLE__ */
+
+#include "mi_gdb.h"
+
+#if !defined(__linux__)
+
+int mi_look_for_free_vt()
+{
+ return -1;
+}
+
+mi_aux_term *gmi_look_for_free_vt()
+{
+ return NULL;
+}
+
+#else
+
+#include <linux/vt.h>
+
+/**[txh]********************************************************************
+
+ Description:
+ Look for a free and usable Linux VT. Low level, use
+@x{gmi_look_for_free_vt}.
+
+ Return: The VT number or <0 on error.
+
+***************************************************************************/
+
+int mi_look_for_free_vt()
+{/* Code from Allegro. */
+ int tty, console_fd, fd;
+ unsigned short mask;
+ char tty_name[16];
+ struct vt_stat vts;
+
+ /* Now we need to find a VT we can use. It must be readable and
+ * writable by us, if we're not setuid root. VT_OPENQRY itself
+ * isn't too useful because it'll only ever come up with one
+ * suggestion, with no guarrantee that we actually have access
+ * to it.
+ *
+ * At some stage I think this is a candidate for config
+ * file overriding, but for now we'll stat the first N consoles
+ * to see which ones we can write to (hopefully at least one!),
+ * so that we can use that one to do ioctls. We used to use
+ * /dev/console for that purpose but it looks like it's not
+ * always writable by enough people.
+ *
+ * Having found and opened a writable device, we query the state
+ * of the first sixteen (fifteen really) consoles, and try
+ * opening each unused one in turn.
+ */
+
+ console_fd=open("/dev/console",O_WRONLY);
+ if (console_fd<0)
+ {
+ int n;
+ /* Try some ttys instead... */
+ for (n=1; n<=24; n++)
+ {
+ snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",n);
+ console_fd=open(tty_name,O_WRONLY);
+ if (console_fd>=0)
+ break;
+ }
+ if (n>24)
+ return -1;
+ }
+
+ /* Get the state of the console -- in particular, the free VT field */
+ if (ioctl(console_fd,VT_GETSTATE,&vts))
+ return -2;
+ close(console_fd);
+
+ /* We attempt to set our euid to 0; if we were run with euid 0 to
+ * start with, we'll be able to do this now. Otherwise, we'll just
+ * ignore the error returned since it might not be a problem if the
+ * ttys we look at are owned by the user running the program. */
+ seteuid(0);
+
+ /* tty0 is not really a console, so start counting at 2. */
+ fd=-1;
+ for (tty=1, mask=2; mask; tty++, mask<<=1)
+ if (!(vts.v_state & mask))
+ {
+ snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",tty);
+ fd=open(tty_name,O_RDWR);
+ if (fd!=-1)
+ {
+ close(fd);
+ break;
+ }
+ }
+
+ seteuid(getuid());
+
+ if (!mask)
+ return -3;
+
+ return tty;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Look for a free and usable Linux VT to be used by the child.
+
+ Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
+release it.
+
+***************************************************************************/
+
+mi_aux_term *gmi_look_for_free_vt()
+{
+ int vt=mi_look_for_free_vt();
+ mi_aux_term *res;
+
+ if (vt<0)
+ return NULL;
+ res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
+ if (!res)
+ return NULL;
+ res->pid=-1;
+ asprintf(&res->tty,"/dev/tty%d",vt);
+ return res;
+}
+
+#endif
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Miscellaneous commands.
+ Comments:
+ GDB/MI commands for the "Miscellaneous Commands" section.@p
+
+@<pre>
+gdb command: Implemented?
+
+-gdb-exit Yes
+-gdb-set Yes
+-gdb-show Yes
+-gdb-version Yes
+@</pre>
+
+GDB Bug workaround for "-gdb-show architecture": gdb 6.1 and olders doesn't
+report it in "value", but they give the output of "show architecture". In
+6.4 we observed that not even a clue is reported. So now we always use
+"show architecture".
+
+***************************************************************************/
+
+#include <string.h>
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_gdb_exit(mi_h *h)
+{
+ mi_send(h,"-gdb-exit\n");
+}
+
+void mi_gdb_version(mi_h *h)
+{
+ mi_send(h,"-gdb-version\n");
+}
+
+void mi_gdb_set(mi_h *h, const char *var, const char *val)
+{
+ mi_send(h,"-gdb-set %s %s\n",var,val);
+}
+
+void mi_gdb_show(mi_h *h, const char *var)
+{
+ if (strcmp(var,"architecture")==0)
+ mi_send(h,"show %s\n",var);
+ else
+ mi_send(h,"-gdb-show %s\n",var);
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ Exit gdb killing the child is it is running.
+
+ Command: -gdb-exit
+
+***************************************************************************/
+
+void gmi_gdb_exit(mi_h *h)
+{
+ mi_gdb_exit(h);
+ mi_res_simple_exit(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Send the version to the console.
+
+ Command: -gdb-version
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_gdb_version(mi_h *h)
+{
+ mi_gdb_version(h);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Set a gdb variable.
+
+ Command: -gdb-set
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_gdb_set(mi_h *h, const char *var, const char *val)
+{
+ mi_gdb_set(h,var,val);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Get a gdb variable.
+
+ Command: -gdb-show
+ Return: The current value of the variable or NULL on error.
+
+***************************************************************************/
+
+char *gmi_gdb_show(mi_h *h, const char *var)
+{
+ mi_gdb_show(h,var);
+ return mi_res_value(h);
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004-2007 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Parser.
+ Comments:
+ Parses the output of gdb. It basically converts the text from gdb into a
+tree (could be a complex one) that we can easily interpret using C code.
+
+***************************************************************************/
+
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include "mi_gdb.h"
+
+mi_results *mi_get_result(const char *str, const char **end);
+int mi_get_value(mi_results *r, const char *str, const char **end);
+
+
+/* GDB BUG!!!! I got:
+^error,msg="Problem parsing arguments: data-evaluate-expression ""1+2"""
+Afects gdb 2002-04-01-cvs and 6.1.1 for sure.
+That's an heuristical workaround.
+*/
+static inline
+int EndOfStr(const char *s)
+{
+ if (*s=='"')
+ {
+ s++;
+ return !*s || *s==',' || *s==']' || *s=='}';
+ }
+ return 0;
+}
+
+int mi_get_cstring_r(mi_results *r, const char *str, const char **end)
+{
+ const char *s;
+ char *d;
+ int len;
+
+ if (*str!='"')
+ {
+ mi_error=MI_PARSER;
+ return 0;
+ }
+ str++;
+ /* Meassure. */
+ for (s=str, len=0; *s && !EndOfStr(s); s++)
+ {
+ if (*s=='\\')
+ {
+ if (!*s)
+ {
+ mi_error=MI_PARSER;
+ return 0;
+ }
+ s++;
+ }
+ len++;
+ }
+ /* Copy. */
+ r->type=t_const;
+ d=r->v.cstr=mi_malloc(len+1);
+ if (!r->v.cstr)
+ return 0;
+ for (s=str; *s && !EndOfStr(s); s++, d++)
+ {
+ if (*s=='\\')
+ {
+ s++;
+ switch (*s)
+ {
+ case 'n':
+ *d='\n';
+ break;
+ case 't':
+ *d='\t';
+ break;
+ default:
+ *d=*s;
+ }
+ }
+ else
+ *d=*s;
+ }
+ *d=0;
+ if (end)
+ *end=s+1;
+
+ return 1;
+}
+
+/* TODO: What's a valid variable name?
+ I'll assume a-zA-Z0-9_- */
+inline
+int mi_is_var_name_char(char c)
+{
+ return isalnum(c) || c=='-' || c=='_';
+}
+
+char *mi_get_var_name(const char *str, const char **end)
+{
+ const char *s;
+ char *r;
+ int l;
+ /* Meassure. */
+ for (s=str; *s && mi_is_var_name_char(*s); s++);
+ if (*s!='=')
+ {
+ mi_error=MI_PARSER;
+ return NULL;
+ }
+ /* Allocate. */
+ l=s-str;
+ r=mi_malloc(l+1);
+ /* Copy. */
+ memcpy(r,str,l);
+ r[l]=0;
+ if (end)
+ *end=s+1;
+ return r;
+}
+
+
+int mi_get_list_res(mi_results *r, const char *str, const char **end, char closeC)
+{
+ mi_results *last_r, *rs;
+
+ last_r=NULL;
+ do
+ {
+ rs=mi_get_result(str,&str);
+ if (last_r)
+ last_r->next=rs;
+ else
+ r->v.rs=rs;
+ last_r=rs;
+ if (*str==closeC)
+ {
+ *end=str+1;
+ return 1;
+ }
+ if (*str!=',')
+ break;
+ str++;
+ }
+ while (1);
+
+ mi_error=MI_PARSER;
+ return 0;
+}
+
+#ifdef __APPLE__
+int mi_get_tuple_val(mi_results *r, const char *str, const char **end)
+{
+ mi_results *last_r, *rs;
+
+ last_r=NULL;
+ do
+ {
+ rs=mi_alloc_results();
+ if (!rs || !mi_get_value(rs,str,&str))
+ {
+ mi_free_results(rs);
+ return 0;
+ }
+ /* Note that rs->var is NULL, that indicates that's just a value and not
+ a result. */
+ if (last_r)
+ last_r->next=rs;
+ else
+ r->v.rs=rs;
+ last_r=rs;
+ if (*str=='}')
+ {
+ *end=str+1;
+ return 1;
+ }
+ if (*str!=',')
+ break;
+ str++;
+ }
+ while (1);
+
+ mi_error=MI_PARSER;
+ return 0;
+}
+#endif /* __APPLE__ */
+
+int mi_get_tuple(mi_results *r, const char *str, const char **end)
+{
+ if (*str!='{')
+ {
+ mi_error=MI_PARSER;
+ return 0;
+ }
+ r->type=t_tuple;
+ str++;
+ if (*str=='}')
+ {/* Special case: empty tuple */
+ *end=str+1;
+ return 1;
+ }
+ #ifdef __APPLE__
+ if (mi_is_var_name_char(*str))
+ return mi_get_list_res(r,str,end,'}');
+ return mi_get_tuple_val(r,str,end);
+ #else /* __APPLE__ */
+ return mi_get_list_res(r,str,end,'}');
+ #endif /* __APPLE__ */
+}
+
+int mi_get_list_val(mi_results *r, const char *str, const char **end)
+{
+ mi_results *last_r, *rs;
+
+ last_r=NULL;
+ do
+ {
+ rs=mi_alloc_results();
+ if (!rs || !mi_get_value(rs,str,&str))
+ {
+ mi_free_results(rs);
+ return 0;
+ }
+ /* Note that rs->var is NULL, that indicates that's just a value and not
+ a result. */
+ if (last_r)
+ last_r->next=rs;
+ else
+ r->v.rs=rs;
+ last_r=rs;
+ if (*str==']')
+ {
+ *end=str+1;
+ return 1;
+ }
+ if (*str!=',')
+ break;
+ str++;
+ }
+ while (1);
+
+ mi_error=MI_PARSER;
+ return 0;
+}
+
+int mi_get_list(mi_results *r, const char *str, const char **end)
+{
+ if (*str!='[')
+ {
+ mi_error=MI_PARSER;
+ return 0;
+ }
+ r->type=t_list;
+ str++;
+ if (*str==']')
+ {/* Special case: empty list */
+ *end=str+1;
+ return 1;
+ }
+ /* Comment: I think they could choose () for values. Is confusing in this way. */
+ if (mi_is_var_name_char(*str))
+ return mi_get_list_res(r,str,end,']');
+ return mi_get_list_val(r,str,end);
+}
+
+int mi_get_value(mi_results *r, const char *str, const char **end)
+{
+ switch (str[0])
+ {
+ case '"':
+ return mi_get_cstring_r(r,str,end);
+ case '{':
+ return mi_get_tuple(r,str,end);
+ case '[':
+ return mi_get_list(r,str,end);
+ }
+ mi_error=MI_PARSER;
+ return 0;
+}
+
+mi_results *mi_get_result(const char *str, const char **end)
+{
+ char *var;
+ mi_results *r;
+
+ var=mi_get_var_name(str,&str);
+ if (!var)
+ return NULL;
+
+ r=mi_alloc_results();
+ if (!r)
+ {
+ free(var);
+ return NULL;
+ }
+ r->var=var;
+
+ if (!mi_get_value(r,str,end))
+ {
+ mi_free_results(r);
+ return NULL;
+ }
+
+ return r;
+}
+
+mi_output *mi_get_results_alone(mi_output *r,const char *str)
+{
+ mi_results *last_r, *rs;
+
+ /* * results */
+ last_r=NULL;
+ do
+ {
+ if (!*str)
+ return r;
+ if (*str!=',')
+ {
+ mi_error=MI_PARSER;
+ break;
+ }
+ str++;
+ rs=mi_get_result(str,&str);
+ if (!rs)
+ break;
+ if (!last_r)
+ r->c=rs;
+ else
+ last_r->next=rs;
+ last_r=rs;
+ }
+ while (1);
+ mi_free_output(r);
+ return NULL;
+}
+
+mi_output *mi_parse_result_record(mi_output *r,const char *str)
+{
+ r->type=MI_T_RESULT_RECORD;
+
+ /* Solve the result-class. */
+ if (strncmp(str,"done",4)==0)
+ {
+ str+=4;
+ r->tclass=MI_CL_DONE;
+ }
+ else if (strncmp(str,"running",7)==0)
+ {
+ str+=7;
+ r->tclass=MI_CL_RUNNING;
+ }
+ else if (strncmp(str,"connected",9)==0)
+ {
+ str+=9;
+ r->tclass=MI_CL_CONNECTED;
+ }
+ else if (strncmp(str,"error",5)==0)
+ {
+ str+=5;
+ r->tclass=MI_CL_ERROR;
+ }
+ else if (strncmp(str,"exit",4)==0)
+ {
+ str+=4;
+ r->tclass=MI_CL_EXIT;
+ }
+ else
+ {
+ mi_error=MI_UNKNOWN_RESULT;
+ return NULL;
+ }
+
+ return mi_get_results_alone(r,str);
+}
+
+mi_output *mi_parse_asyn(mi_output *r,const char *str)
+{
+ r->type=MI_T_OUT_OF_BAND;
+ r->stype=MI_ST_ASYNC;
+ /* async-class. */
+ if (strncmp(str,"stopped",7)==0)
+ {
+ r->tclass=MI_CL_STOPPED;
+ str+=7;
+ return mi_get_results_alone(r,str);
+ }
+ if (strncmp(str,"download",8)==0)
+ {
+ r->tclass=MI_CL_DOWNLOAD;
+ str+=8;
+ return mi_get_results_alone(r,str);
+ }
+ mi_error=MI_UNKNOWN_ASYNC;
+ mi_free_output(r);
+ return NULL;
+}
+
+mi_output *mi_parse_exec_asyn(mi_output *r,const char *str)
+{
+ r->sstype=MI_SST_EXEC;
+ return mi_parse_asyn(r,str);
+}
+
+mi_output *mi_parse_status_asyn(mi_output *r,const char *str)
+{
+ r->sstype=MI_SST_STATUS;
+ return mi_parse_asyn(r,str);
+}
+
+mi_output *mi_parse_notify_asyn(mi_output *r,const char *str)
+{
+ r->sstype=MI_SST_NOTIFY;
+ return mi_parse_asyn(r,str);
+}
+
+mi_output *mi_console(mi_output *r,const char *str)
+{
+ r->type=MI_T_OUT_OF_BAND;
+ r->stype=MI_ST_STREAM;
+ r->c=mi_alloc_results();
+ if (!r->c || !mi_get_cstring_r(r->c,str,NULL))
+ {
+ mi_free_output(r);
+ return NULL;
+ }
+ return r;
+}
+
+mi_output *mi_console_stream(mi_output *r,const char *str)
+{
+ r->sstype=MI_SST_CONSOLE;
+ return mi_console(r,str);
+}
+
+mi_output *mi_target_stream(mi_output *r,const char *str)
+{
+ r->sstype=MI_SST_TARGET;
+ return mi_console(r,str);
+}
+
+mi_output *mi_log_stream(mi_output *r,const char *str)
+{
+ r->sstype=MI_SST_LOG;
+ return mi_console(r,str);
+}
+
+mi_output *mi_parse_gdb_output(const char *str)
+{
+ char type=str[0];
+
+ mi_output *r=mi_alloc_output();
+ if (!r)
+ {
+ mi_error=MI_OUT_OF_MEMORY;
+ return NULL;
+ }
+ str++;
+ switch (type)
+ {
+ case '^':
+ return mi_parse_result_record(r,str);
+ case '*':
+ return mi_parse_exec_asyn(r,str);
+ case '+':
+ return mi_parse_status_asyn(r,str);
+ case '=':
+ return mi_parse_notify_asyn(r,str);
+ case '~':
+ return mi_console_stream(r,str);
+ case '@':
+ return mi_target_stream(r,str);
+ case '&':
+ return mi_log_stream(r,str);
+ }
+ mi_error=MI_PARSER;
+ return NULL;
+}
+
+mi_output *mi_get_rrecord(mi_output *r)
+{
+ if (!r)
+ return NULL;
+ while (r)
+ {
+ if (r->type==MI_T_RESULT_RECORD)
+ return r;
+ r=r->next;
+ }
+ return r;
+}
+
+mi_results *mi_get_var_r(mi_results *r, const char *var)
+{
+ while (r)
+ {
+ if (strcmp(r->var,var)==0)
+ return r;
+ r=r->next;
+ }
+ return NULL;
+}
+
+mi_results *mi_get_var(mi_output *res, const char *var)
+{
+ if (!res)
+ return NULL;
+ return mi_get_var_r(res->c,var);
+}
+
+int mi_get_async_stop_reason(mi_output *r, char **reason)
+{
+ int found_stopped=0;
+
+ *reason=NULL;
+ while (r)
+ {
+ if (r->type==MI_T_RESULT_RECORD && r->tclass==MI_CL_ERROR)
+ {
+ if (r->c->type==t_const)
+ *reason=r->c->v.cstr;
+ return 0;
+ }
+ if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
+ r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
+ {
+ mi_results *p=r->c;
+ found_stopped=1;
+ while (p)
+ {
+ if (strcmp(p->var,"reason")==0)
+ {
+ *reason=p->v.cstr;
+ return 1;
+ }
+ p=p->next;
+ }
+ }
+ r=r->next;
+ }
+ if (*reason==NULL && found_stopped)
+ {
+ *reason=strdup("unknown (temp bkpt?)");
+ return 1;
+ }
+ return 0;
+}
+
+mi_frames *mi_get_async_frame(mi_output *r)
+{
+ while (r)
+ {
+ if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
+ r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
+ {
+ mi_results *p=r->c;
+ while (p)
+ {
+ if (strcmp(p->var,"frame")==0)
+ return mi_parse_frame(p->v.rs);
+ p=p->next;
+ }
+ }
+ r=r->next;
+ }
+ return NULL;
+}
+
+int mi_res_simple(mi_h *h, int tclass, int accert_ret)
+{
+ mi_output *r, *res;
+ int ret=0;
+
+ r=mi_get_response_blk(h);
+ res=mi_get_rrecord(r);
+
+ if (res)
+ ret=res->tclass==tclass;
+ mi_free_output(r);
+
+ return ret;
+}
+
+
+int mi_res_simple_done(mi_h *h)
+{
+ return mi_res_simple(h,MI_CL_DONE,0);
+}
+
+int mi_res_simple_exit(mi_h *h)
+{
+ return mi_res_simple(h,MI_CL_EXIT,1);
+}
+
+int mi_res_simple_running(mi_h *h)
+{
+ return mi_res_simple(h,MI_CL_RUNNING,0);
+}
+
+int mi_res_simple_connected(mi_h *h)
+{
+ return mi_res_simple(h,MI_CL_CONNECTED,0);
+}
+
+mi_results *mi_res_var(mi_h *h, const char *var, int tclass)
+{
+ mi_output *r, *res;
+ mi_results *the_var=NULL;
+
+ r=mi_get_response_blk(h);
+ /* All the code that follows is "NULL" tolerant. */
+ /* Look for the result-record. */
+ res=mi_get_rrecord(r);
+ /* Look for the desired var. */
+ if (res && res->tclass==tclass)
+ the_var=mi_get_var(res,var);
+ /* Release all but the one we want. */
+ mi_free_output_but(r,NULL,the_var);
+ return the_var;
+}
+
+mi_results *mi_res_done_var(mi_h *h, const char *var)
+{
+ return mi_res_var(h,var,MI_CL_DONE);
+}
+
+mi_frames *mi_parse_frame(mi_results *c)
+{
+ mi_frames *res=mi_alloc_frames();
+ char *end;
+
+ if (res)
+ {
+ while (c)
+ {
+ if (c->type==t_const)
+ {
+ if (strcmp(c->var,"level")==0)
+ res->level=atoi(c->v.cstr);
+ else if (strcmp(c->var,"addr")==0)
+ res->addr=(void *)strtoul(c->v.cstr,&end,0);
+ else if (strcmp(c->var,"func")==0)
+ {
+ res->func=c->v.cstr;
+ c->v.cstr=NULL;
+ }
+ else if (strcmp(c->var,"file")==0)
+ {
+ res->file=c->v.cstr;
+ c->v.cstr=NULL;
+ }
+ else if (strcmp(c->var,"from")==0)
+ {
+ res->from=c->v.cstr;
+ c->v.cstr=NULL;
+ }
+ else if (strcmp(c->var,"line")==0)
+ res->line=atoi(c->v.cstr);
+ }
+ else if (c->type==t_list && strcmp(c->var,"args")==0)
+ {
+ res->args=c->v.rs;
+ c->v.rs=NULL;
+ }
+ c=c->next;
+ }
+ }
+ return res;
+}
+
+mi_frames *mi_res_frame(mi_h *h)
+{
+ mi_results *r=mi_res_done_var(h,"frame");
+ mi_frames *f=NULL;
+
+ if (r && r->type==t_tuple)
+ f=mi_parse_frame(r->v.rs);
+ mi_free_results(r);
+ return f;
+}
+
+mi_frames *mi_res_frames_array(mi_h *h, const char *var)
+{
+ mi_results *r=mi_res_done_var(h,var), *c;
+ mi_frames *res=NULL, *nframe, *last=NULL;
+
+ if (!r)
+ return NULL;
+#ifdef __APPLE__
+ if (r->type!=t_list && r->type!=t_tuple)
+#else
+ if (r->type!=t_list)
+#endif
+ {
+ mi_free_results(r);
+ return NULL;
+ }
+ c=r->v.rs;
+ while (c)
+ {
+ if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
+ {
+ nframe=mi_parse_frame(c->v.rs);
+ if (nframe)
+ {
+ if (!last)
+ res=nframe;
+ else
+ last->next=nframe;
+ last=nframe;
+ }
+ }
+ c=c->next;
+ }
+ mi_free_results(r);
+ return res;
+}
+
+mi_frames *mi_res_frames_list(mi_h *h)
+{
+ mi_output *r, *res;
+ mi_frames *ret=NULL, *nframe, *last=NULL;
+ mi_results *c;
+
+ r=mi_get_response_blk(h);
+ res=mi_get_rrecord(r);
+ if (res && res->tclass==MI_CL_DONE)
+ {
+ c=res->c;
+ while (c)
+ {
+ if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
+ {
+ nframe=mi_parse_frame(c->v.rs);
+ if (nframe)
+ {
+ if (!last)
+ ret=nframe;
+ else
+ last->next=nframe;
+ last=nframe;
+ }
+ }
+ c=c->next;
+ }
+ }
+ mi_free_output(r);
+ return ret;
+}
+
+int mi_get_thread_ids(mi_output *res, int **list)
+{
+ mi_results *vids, *lids;
+ int ids=-1, i;
+
+ *list=NULL;
+ vids=mi_get_var(res,"number-of-threads");
+ lids=mi_get_var(res,"thread-ids");
+ if (vids && vids->type==t_const &&
+ lids && lids->type==t_tuple)
+ {
+ ids=atoi(vids->v.cstr);
+ if (ids)
+ {
+ int *lst;
+ lst=(int *)mi_calloc(ids,sizeof(int));
+ if (lst)
+ {
+ lids=lids->v.rs;
+ i=0;
+ while (lids)
+ {
+ if (strcmp(lids->var,"thread-id")==0 && lids->type==t_const)
+ lst[i++]=atoi(lids->v.cstr);
+ lids=lids->next;
+ }
+ *list=lst;
+ }
+ else
+ ids=-1;
+ }
+ }
+ return ids;
+}
+
+int mi_res_thread_ids(mi_h *h, int **list)
+{
+ mi_output *r, *res;
+ int ids=-1;
+
+ r=mi_get_response_blk(h);
+ res=mi_get_rrecord(r);
+ if (res && res->tclass==MI_CL_DONE)
+ ids=mi_get_thread_ids(res,list);
+ mi_free_output(r);
+ return ids;
+}
+
+enum mi_gvar_lang mi_lang_str_to_enum(const char *lang)
+{
+ enum mi_gvar_lang lg=lg_unknown;
+
+ if (strcmp(lang,"C")==0)
+ lg=lg_c;
+ else if (strcmp(lang,"C++")==0)
+ lg=lg_cpp;
+ else if (strcmp(lang,"Java")==0)
+ lg=lg_java;
+
+ return lg;
+}
+
+const char *mi_lang_enum_to_str(enum mi_gvar_lang lang)
+{
+ const char *lg;
+
+ switch (lang)
+ {
+ case lg_c:
+ lg="C";
+ break;
+ case lg_cpp:
+ lg="C++";
+ break;
+ case lg_java:
+ lg="Java";
+ break;
+ /*case lg_unknown:*/
+ default:
+ lg="unknown";
+ break;
+ }
+ return lg;
+}
+
+enum mi_gvar_fmt mi_format_str_to_enum(const char *format)
+{
+ enum mi_gvar_fmt fmt=fm_natural;
+
+ if (strcmp(format,"binary")==0)
+ fmt=fm_binary;
+ else if (strcmp(format,"decimal")==0)
+ fmt=fm_decimal;
+ else if (strcmp(format,"hexadecimal")==0)
+ fmt=fm_hexadecimal;
+ else if (strcmp(format,"octal")==0)
+ fmt=fm_octal;
+
+ return fmt;
+}
+
+const char *mi_format_enum_to_str(enum mi_gvar_fmt format)
+{
+ const char *fmt;
+
+ switch (format)
+ {
+ case fm_natural:
+ fmt="natural";
+ break;
+ case fm_binary:
+ fmt="binary";
+ break;
+ case fm_decimal:
+ fmt="decimal";
+ break;
+ case fm_hexadecimal:
+ fmt="hexadecimal";
+ break;
+ case fm_octal:
+ fmt="octal";
+ break;
+ case fm_raw:
+ fmt="raw";
+ break;
+ default:
+ fmt="unknown";
+ }
+ return fmt;
+}
+
+char mi_format_enum_to_char(enum mi_gvar_fmt format)
+{
+ char fmt;
+
+ switch (format)
+ {
+ case fm_natural:
+ fmt='N';
+ break;
+ case fm_binary:
+ fmt='t';
+ break;
+ case fm_decimal:
+ fmt='d';
+ break;
+ case fm_hexadecimal:
+ fmt='x';
+ break;
+ case fm_octal:
+ fmt='o';
+ break;
+ case fm_raw:
+ fmt='r';
+ break;
+ default:
+ fmt=' ';
+ }
+ return fmt;
+}
+
+mi_gvar *mi_get_gvar(mi_output *o, mi_gvar *cur, const char *expression)
+{
+ mi_results *r;
+ mi_gvar *res=cur ? cur : mi_alloc_gvar();
+ int l;
+
+ if (!res)
+ return res;
+ r=o->c;
+ if (expression)
+ res->exp=strdup(expression);
+ while (r)
+ {
+ if (r->type==t_const)
+ {
+ if (strcmp(r->var,"name")==0)
+ {
+ free(res->name);
+ res->name=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"numchild")==0)
+ {
+ res->numchild=atoi(r->v.cstr);
+ }
+ else if (strcmp(r->var,"type")==0)
+ {
+ free(res->type);
+ res->type=r->v.cstr;
+ r->v.cstr=NULL;
+ l=strlen(res->type);
+ if (l && res->type[l-1]=='*')
+ res->ispointer=1;
+ }
+ else if (strcmp(r->var,"lang")==0)
+ {
+ res->lang=mi_lang_str_to_enum(r->v.cstr);
+ }
+ else if (strcmp(r->var,"exp")==0)
+ {
+ free(res->exp);
+ res->exp=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"format")==0)
+ {
+ res->format=mi_format_str_to_enum(r->v.cstr);
+ }
+ else if (strcmp(r->var,"attr")==0)
+ { /* Note: gdb 6.1.1 have only this: */
+ if (strcmp(r->v.cstr,"editable")==0)
+ res->attr=MI_ATTR_EDITABLE;
+ else /* noneditable */
+ res->attr=MI_ATTR_NONEDITABLE;
+ }
+ }
+ r=r->next;
+ }
+ return res;
+}
+
+mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression)
+{
+ mi_output *r, *res;
+ mi_gvar *gvar=NULL;
+
+ r=mi_get_response_blk(h);
+ res=mi_get_rrecord(r);
+ if (res && res->tclass==MI_CL_DONE)
+ gvar=mi_get_gvar(res,cur,expression);
+ mi_free_output(r);
+ return gvar;
+}
+
+mi_gvar_chg *mi_get_gvar_chg(mi_results *r)
+{
+ mi_gvar_chg *n;
+
+ if (r->type!=t_const)
+ return NULL;
+ n=mi_alloc_gvar_chg();
+ if (n)
+ {
+ while (r)
+ {
+ if (r->type==t_const)
+ {
+ if (strcmp(r->var,"name")==0)
+ {
+ n->name=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"in_scope")==0)
+ {
+ n->in_scope=strcmp(r->v.cstr,"true")==0;
+ }
+ else if (strcmp(r->var,"new_type")==0)
+ {
+ n->new_type=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"new_num_children")==0)
+ {
+ n->new_num_children=atoi(r->v.cstr);
+ }
+ // type_changed="false" is the default
+ }
+ r=r->next;
+ }
+ }
+ return n;
+}
+
+int mi_res_changelist(mi_h *h, mi_gvar_chg **changed)
+{
+ mi_gvar_chg *last, *n;
+ mi_results *res=mi_res_done_var(h,"changelist"), *r;
+ int count=0;
+
+ *changed=NULL;
+ if (!res)
+ return 0;
+ last=NULL;
+ count=1;
+ n=NULL;
+ r=res->v.rs;
+
+ if (res->type==t_list)
+ {// MI v2 a list of tuples
+ while (r)
+ {
+ if (r->type==t_tuple)
+ {
+ n=mi_get_gvar_chg(r->v.rs);
+ if (n)
+ {
+ if (last)
+ last->next=n;
+ else
+ *changed=n;
+ last=n;
+ count++;
+ }
+ }
+ r=r->next;
+ }
+ }
+ else if (res->type==t_tuple)
+ {// MI v1 a tuple with all together *8-P
+ while (r)
+ {
+ if (r->type==t_const) /* Just in case. */
+ {/* Get one var. */
+ if (strcmp(r->var,"name")==0)
+ {
+ if (n)
+ {/* Add to the list*/
+ if (last)
+ last->next=n;
+ else
+ *changed=n;
+ last=n;
+ count++;
+ }
+ n=mi_alloc_gvar_chg();
+ if (!n)
+ {
+ mi_free_gvar_chg(*changed);
+ return 0;
+ }
+ n->name=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"in_scope")==0)
+ {
+ n->in_scope=strcmp(r->v.cstr,"true")==0;
+ }
+ else if (strcmp(r->var,"new_type")==0)
+ {
+ n->new_type=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"new_num_children")==0)
+ {
+ n->new_num_children=atoi(r->v.cstr);
+ }
+ // type_changed="false" is the default
+ }
+ r=r->next;
+ }
+ if (n)
+ {/* Add to the list*/
+ if (last)
+ last->next=n;
+ else
+ *changed=n;
+ last=n;
+ count++;
+ }
+ }
+ mi_free_results(res);
+
+ return count;
+}
+
+int mi_get_children(mi_results *ch, mi_gvar *v)
+{
+ mi_gvar *cur=NULL, *aux;
+ int i=0, count=v->numchild, l;
+
+ while (ch)
+ {
+ if (strcmp(ch->var,"child")==0 && ch->type==t_tuple && i<count)
+ {
+ mi_results *r=ch->v.rs;
+ aux=mi_alloc_gvar();
+ if (!aux)
+ return 0;
+ if (!v->child)
+ v->child=aux;
+ else
+ cur->next=aux;
+ cur=aux;
+ cur->parent=v;
+ cur->depth=v->depth+1;
+
+ while (r)
+ {
+ if (r->type==t_const)
+ {
+ if (strcmp(r->var,"name")==0)
+ {
+ cur->name=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"exp")==0)
+ {
+ cur->exp=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"type")==0)
+ {
+ cur->type=r->v.cstr;
+ r->v.cstr=NULL;
+ l=strlen(cur->type);
+ if (l && cur->type[l-1]=='*')
+ cur->ispointer=1;
+ }
+ else if (strcmp(r->var,"value")==0)
+ {
+ cur->value=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"numchild")==0)
+ {
+ cur->numchild=atoi(r->v.cstr);
+ }
+ }
+ r=r->next;
+ }
+ i++;
+ }
+ ch=ch->next;
+ }
+ v->vischild=i;
+ v->opened=1;
+ return i==v->numchild;
+}
+
+int mi_res_children(mi_h *h, mi_gvar *v)
+{
+ mi_output *r, *res;
+ int ok=0;
+
+ r=mi_get_response_blk(h);
+ res=mi_get_rrecord(r);
+ if (res && res->tclass==MI_CL_DONE)
+ {
+ mi_results *num=mi_get_var(res,"numchild");
+ if (num && num->type==t_const)
+ {
+ v->numchild=atoi(num->v.cstr);
+ if (v->child)
+ {
+ mi_free_gvar(v->child);
+ v->child=NULL;
+ }
+ if (v->numchild)
+ {
+ mi_results *ch =mi_get_var(res,"children");
+ if (ch && ch->type!=t_const) /* MI v1 tuple, MI v2 list */
+ ok=mi_get_children(ch->v.rs,v);
+ }
+ else
+ ok=1;
+ }
+ }
+ mi_free_output(r);
+ return ok;
+}
+
+mi_bkpt *mi_get_bkpt(mi_results *p)
+{
+ mi_bkpt *res;
+ char *end;
+
+ res=mi_alloc_bkpt();
+ if (!res)
+ return NULL;
+ while (p)
+ {
+ if (p->type==t_const && p->var)
+ {
+ if (strcmp(p->var,"number")==0)
+ res->number=atoi(p->v.cstr);
+ else if (strcmp(p->var,"type")==0)
+ {
+ if (strcmp(p->v.cstr,"breakpoint")==0)
+ res->type=t_breakpoint;
+ else
+ res->type=t_unknown;
+ }
+ else if (strcmp(p->var,"disp")==0)
+ {
+ if (strcmp(p->v.cstr,"keep")==0)
+ res->disp=d_keep;
+ else if (strcmp(p->v.cstr,"del")==0)
+ res->disp=d_del;
+ else
+ res->disp=d_unknown;
+ }
+ else if (strcmp(p->var,"enabled")==0)
+ res->enabled=p->v.cstr[0]=='y';
+ else if (strcmp(p->var,"addr")==0)
+ res->addr=(void *)strtoul(p->v.cstr,&end,0);
+ else if (strcmp(p->var,"func")==0)
+ {
+ res->func=p->v.cstr;
+ p->v.cstr=NULL;
+ }
+ else if (strcmp(p->var,"file")==0)
+ {
+ res->file=p->v.cstr;
+ p->v.cstr=NULL;
+ }
+ else if (strcmp(p->var,"line")==0)
+ res->line=atoi(p->v.cstr);
+ else if (strcmp(p->var,"times")==0)
+ res->times=atoi(p->v.cstr);
+ else if (strcmp(p->var,"ignore")==0)
+ res->ignore=atoi(p->v.cstr);
+ else if (strcmp(p->var,"cond")==0)
+ {
+ res->cond=p->v.cstr;
+ p->v.cstr=NULL;
+ }
+ }
+ p=p->next;
+ }
+ return res;
+}
+
+mi_bkpt *mi_res_bkpt(mi_h *h)
+{
+ mi_results *r=mi_res_done_var(h,"bkpt");
+ mi_bkpt *b=NULL;
+
+ if (r && r->type==t_tuple)
+ b=mi_get_bkpt(r->v.rs);
+ mi_free_results(r);
+ return b;
+}
+
+mi_wp *mi_get_wp(mi_results *p, enum mi_wp_mode m)
+{
+ mi_wp *res=mi_alloc_wp();
+
+ if (res)
+ {
+ res->mode=m;
+ while (p)
+ {
+ if (p->type==t_const && p->var)
+ {
+ if (strcmp(p->var,"number")==0)
+ {
+ res->number=atoi(p->v.cstr);
+ res->enabled=1;
+ }
+ else if (strcmp(p->var,"exp")==0)
+ {
+ res->exp=p->v.cstr;
+ p->v.cstr=NULL;
+ }
+ }
+ p=p->next;
+ }
+ }
+ return res;
+}
+
+mi_wp *mi_parse_wp_res(mi_output *r)
+{
+ mi_results *p;
+ enum mi_wp_mode m=wm_unknown;
+
+ /* The info is in a result wpt=... */
+ p=r->c;
+ while (p)
+ {
+ if (p->var)
+ {
+ if (strcmp(p->var,"wpt")==0)
+ m=wm_write;
+ else if (strcmp(p->var,"hw-rwpt")==0)
+ m=wm_read;
+ else if (strcmp(p->var,"hw-awpt")==0)
+ m=wm_rw;
+ if (m!=wm_unknown)
+ break;
+ }
+ p=p->next;
+ }
+ if (!p || p->type!=t_tuple)
+ return NULL;
+ /* Scan the values inside it. */
+ return mi_get_wp(p->v.rs,m);
+}
+
+mi_wp *mi_res_wp(mi_h *h)
+{
+ mi_output *r, *res;
+ mi_wp *ret=NULL;
+
+ r=mi_get_response_blk(h);
+ res=mi_get_rrecord(r);
+
+ if (res)
+ ret=mi_parse_wp_res(res);
+
+ mi_free_output(r);
+ return ret;
+}
+
+char *mi_res_value(mi_h *h)
+{
+ mi_results *r=mi_res_done_var(h,"value");
+ char *s=NULL;
+
+ if (r && r->type==t_const)
+ {
+ s=r->v.cstr;
+ r->v.rs=NULL;
+ }
+ mi_free_results(r);
+ return s;
+}
+
+mi_output *mi_get_stop_record(mi_output *r)
+{
+ while (r)
+ {
+ if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
+ r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
+ return r;
+ r=r->next;
+ }
+ return r;
+}
+
+static
+char *reason_names[]=
+{
+ "breakpoint-hit",
+ "watchpoint-trigger",
+ "read-watchpoint-trigger",
+ "access-watchpoint-trigger",
+ "watchpoint-scope",
+ "function-finished",
+ "location-reached",
+ "end-stepping-range",
+ "exited-signalled",
+ "exited",
+ "exited-normally",
+ "signal-received"
+};
+
+static
+enum mi_stop_reason reason_values[]=
+{
+ sr_bkpt_hit,
+ sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
+ sr_function_finished, sr_location_reached, sr_end_stepping_range,
+ sr_exited_signalled, sr_exited, sr_exited_normally,
+ sr_signal_received
+};
+
+static
+char *reason_expl[]=
+{
+ "Hit a breakpoint",
+ "Write watchpoint",
+ "Read watchpoint",
+ "Access watchpoint",
+ "Watchpoint out of scope",
+ "Function finished",
+ "Location reached",
+ "End of stepping",
+ "Exited signalled",
+ "Exited with error",
+ "Exited normally",
+ "Signal received"
+};
+
+enum mi_stop_reason mi_reason_str_to_enum(const char *s)
+{
+ int i;
+
+ for (i=0; i<sizeof(reason_names)/sizeof(char *); i++)
+ if (strcmp(reason_names[i],s)==0)
+ return reason_values[i];
+ return sr_unknown;
+}
+
+const char *mi_reason_enum_to_str(enum mi_stop_reason r)
+{
+ int i;
+
+ if (r==sr_unknown)
+ return "Unknown (temp bkp?)";
+ for (i=0; i<sizeof(reason_values)/sizeof(char *); i++)
+ if (reason_values[i]==r)
+ return reason_expl[i];
+ return NULL;
+}
+
+mi_stop *mi_get_stopped(mi_results *r)
+{
+ mi_stop *res=mi_alloc_stop();
+
+ if (res)
+ {
+ while (r)
+ {
+ if (r->type==t_const)
+ {
+ if (strcmp(r->var,"reason")==0)
+ res->reason=mi_reason_str_to_enum(r->v.cstr);
+ else if (!res->have_thread_id && strcmp(r->var,"thread-id")==0)
+ {
+ res->have_thread_id=1;
+ res->thread_id=atoi(r->v.cstr);
+ }
+ else if (!res->have_bkptno && strcmp(r->var,"bkptno")==0)
+ {
+ res->have_bkptno=1;
+ res->bkptno=atoi(r->v.cstr);
+ }
+ else if (!res->have_bkptno && strcmp(r->var,"wpnum")==0)
+ {
+ res->have_wpno=1;
+ res->wpno=atoi(r->v.cstr);
+ }
+ else if (strcmp(r->var,"gdb-result-var")==0)
+ {
+ res->gdb_result_var=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"return-value")==0)
+ {
+ res->return_value=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"signal-name")==0)
+ {
+ res->signal_name=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (strcmp(r->var,"signal-meaning")==0)
+ {
+ res->signal_meaning=r->v.cstr;
+ r->v.cstr=NULL;
+ }
+ else if (!res->have_exit_code && strcmp(r->var,"exit-code")==0)
+ {
+ res->have_exit_code=1;
+ res->exit_code=atoi(r->v.cstr);
+ }
+ }
+ else // tuple or list
+ {
+ if (strcmp(r->var,"frame")==0)
+ res->frame=mi_parse_frame(r->v.rs);
+ else if (!res->wp && strcmp(r->var,"wpt")==0)
+ res->wp=mi_get_wp(r->v.rs,wm_write);
+ else if (!res->wp && strcmp(r->var,"hw-rwpt")==0)
+ res->wp=mi_get_wp(r->v.rs,wm_read);
+ else if (!res->wp && strcmp(r->var,"hw-awpt")==0)
+ res->wp=mi_get_wp(r->v.rs,wm_rw);
+ else if (!(res->wp_old || res->wp_val) && strcmp(r->var,"value")==0)
+ {
+ mi_results *p=r->v.rs;
+ while (p)
+ {
+ if (strcmp(p->var,"value")==0 || strcmp(p->var,"new")==0)
+ {
+ res->wp_val=p->v.cstr;
+ p->v.cstr=NULL;
+ }
+ else if (strcmp(p->var,"old")==0)
+ {
+ res->wp_old=p->v.cstr;
+ p->v.cstr=NULL;
+ }
+ p=p->next;
+ }
+ }
+ }
+ r=r->next;
+ }
+ }
+ return res;
+}
+
+mi_stop *mi_res_stop(mi_h *h)
+{
+ mi_output *o=mi_retire_response(h);
+ mi_stop *stop=NULL;
+
+ if (o)
+ {
+ mi_output *sr=mi_get_stop_record(o);
+ if (sr)
+ stop=mi_get_stopped(sr->c);
+ }
+ mi_free_output(o);
+
+ return stop;
+}
+
+int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
+ unsigned long *addr)
+{
+ char *end;
+ mi_results *res=mi_res_done_var(h,"memory"), *r;
+ int ok=0;
+
+ *na=0;
+ r=res;
+ if (r && r->type==t_list && ws==1)
+ {
+ r=r->v.rs;
+ if (r->type!=t_tuple)
+ {
+ mi_free_results(res);
+ return 0;
+ }
+ r=r->v.rs;
+ while (r)
+ {
+ if (r->type==t_list && strcmp(r->var,"data")==0)
+ {
+ mi_results *data=r->v.rs;
+ ok++;
+ if (data && data->type==t_const &&
+ strcmp(data->v.cstr,"N/A")==0)
+ *na=1;
+ else
+ while (data)
+ {
+ if (data->type==t_const)
+ *(dest++)=strtol(data->v.cstr,&end,0);
+ data=data->next;
+ }
+ }
+ else if (r->type==t_const && strcmp(r->var,"addr")==0)
+ {
+ ok++;
+ if (addr)
+ *addr=strtoul(r->v.cstr,&end,0);
+ }
+ r=r->next;
+ }
+
+ }
+ mi_free_results(res);
+ return ok==2;
+}
+
+mi_asm_insn *mi_parse_insn(mi_results *c)
+{
+ mi_asm_insn *res=NULL, *cur=NULL;
+ mi_results *sub;
+ char *end;
+
+ while (c)
+ {
+ if (c->type==t_tuple)
+ {
+ if (!res)
+ res=cur=mi_alloc_asm_insn();
+ else
+ {
+ cur->next=mi_alloc_asm_insn();
+ cur=cur->next;
+ }
+ if (!cur)
+ {
+ mi_free_asm_insn(res);
+ return NULL;
+ }
+ sub=c->v.rs;
+ while (sub)
+ {
+ if (sub->type==t_const)
+ {
+ if (strcmp(sub->var,"address")==0)
+ cur->addr=(void *)strtoul(sub->v.cstr,&end,0);
+ else if (strcmp(sub->var,"func-name")==0)
+ {
+ cur->func=sub->v.cstr;
+ sub->v.cstr=NULL;
+ }
+ else if (strcmp(sub->var,"offset")==0)
+ cur->offset=atoi(sub->v.cstr);
+ else if (strcmp(sub->var,"inst")==0)
+ {
+ cur->inst=sub->v.cstr;
+ sub->v.cstr=NULL;
+ }
+ }
+ sub=sub->next;
+ }
+ }
+ c=c->next;
+ }
+ return res;
+}
+
+mi_asm_insns *mi_parse_insns(mi_results *c)
+{
+ mi_asm_insns *res=NULL, *cur=NULL;
+ mi_results *sub;
+
+ while (c)
+ {
+ if (c->var)
+ {
+ if (strcmp(c->var,"src_and_asm_line")==0 && c->type==t_tuple)
+ {
+ if (!res)
+ res=cur=mi_alloc_asm_insns();
+ else
+ {
+ cur->next=mi_alloc_asm_insns();
+ cur=cur->next;
+ }
+ if (!cur)
+ {
+ mi_free_asm_insns(res);
+ return NULL;
+ }
+ sub=c->v.rs;
+ while (sub)
+ {
+ if (sub->var)
+ {
+ if (sub->type==t_const)
+ {
+ if (strcmp(sub->var,"line")==0)
+ cur->line=atoi(sub->v.cstr);
+ else if (strcmp(sub->var,"file")==0)
+ {
+ cur->file=sub->v.cstr;
+ sub->v.cstr=NULL;
+ }
+ }
+ else if (sub->type==t_list)
+ {
+ if (strcmp(sub->var,"line_asm_insn")==0)
+ cur->ins=mi_parse_insn(sub->v.rs);
+ }
+ }
+ sub=sub->next;
+ }
+ }
+ }
+ else
+ {/* No source line, just instructions */
+ res=mi_alloc_asm_insns();
+ res->ins=mi_parse_insn(c);
+ break;
+ }
+ c=c->next;
+ }
+ return res;
+}
+
+
+mi_asm_insns *mi_get_asm_insns(mi_h *h)
+{
+ mi_results *r=mi_res_done_var(h,"asm_insns");
+ mi_asm_insns *f=NULL;
+
+ if (r && r->type==t_list)
+ f=mi_parse_insns(r->v.rs);
+ mi_free_results(r);
+ return f;
+}
+
+mi_chg_reg *mi_parse_list_regs(mi_results *r, int *how_many)
+{
+ mi_results *c=r;
+ int cregs=0;
+ mi_chg_reg *first=NULL, *cur=NULL;
+
+ /* Create the list. */
+ while (c)
+ {
+ if (c->type==t_const && !c->var)
+ {
+ if (first)
+ cur=cur->next=mi_alloc_chg_reg();
+ else
+ first=cur=mi_alloc_chg_reg();
+ cur->name=c->v.cstr;
+ cur->reg=cregs++;
+ c->v.cstr=NULL;
+ }
+ c=c->next;
+ }
+ if (how_many)
+ *how_many=cregs;
+
+ return first;
+}
+
+mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many)
+{
+ mi_results *r=mi_res_done_var(h,"register-names");
+ mi_chg_reg *l=NULL;
+
+ if (r && r->type==t_list)
+ l=mi_parse_list_regs(r->v.rs,how_many);
+ mi_free_results(r);
+ return l;
+}
+
+mi_chg_reg *mi_parse_list_changed_regs(mi_results *r)
+{
+ mi_results *c=r;
+ mi_chg_reg *first=NULL, *cur=NULL;
+
+ /* Create the list. */
+ while (c)
+ {
+ if (c->type==t_const && !c->var)
+ {
+ if (first)
+ cur=cur->next=mi_alloc_chg_reg();
+ else
+ first=cur=mi_alloc_chg_reg();
+ cur->reg=atoi(c->v.cstr);
+ }
+ c=c->next;
+ }
+
+ return first;
+}
+
+mi_chg_reg *mi_get_list_changed_regs(mi_h *h)
+{
+ mi_results *r=mi_res_done_var(h,"changed-registers");
+ mi_chg_reg *changed=NULL;
+
+ if (r && r->type==t_list)
+ changed=mi_parse_list_changed_regs(r->v.rs);
+ mi_free_results(r);
+ return changed;
+}
+
+int mi_parse_reg_values(mi_results *r, mi_chg_reg *l)
+{
+ mi_results *c;
+
+ while (r && l)
+ {
+ if (r->type==t_tuple && !r->var)
+ {
+ c=r->v.rs;
+ while (c)
+ {
+ if (c->type==t_const && c->var)
+ {
+ if (strcmp(c->var,"number")==0)
+ {
+ if (atoi(c->v.cstr)!=l->reg)
+ {
+ mi_error=MI_PARSER;
+ return 0;
+ }
+ }
+ else if (strcmp(c->var,"value")==0)
+ {
+ l->val=c->v.cstr;
+ c->v.cstr=NULL;
+ }
+ }
+ c=c->next;
+ }
+ }
+ r=r->next;
+ l=l->next;
+ }
+
+ return !l && !r;
+}
+
+int mi_get_reg_values(mi_h *h, mi_chg_reg *l)
+{
+ mi_results *r=mi_res_done_var(h,"register-values");
+ int ok=0;
+
+ if (r && r->type==t_list)
+ ok=mi_parse_reg_values(r->v.rs,l);
+ mi_free_results(r);
+ return ok;
+}
+
+int mi_parse_list_regs_l(mi_results *r, mi_chg_reg *l)
+{
+ while (r && l)
+ {
+ if (r->type==t_const && !r->var)
+ {
+ free(l->name);
+ l->name=r->v.cstr;
+ r->v.cstr=NULL;
+ l=l->next;
+ }
+ r=r->next;
+ }
+
+ return !l && !r;
+}
+
+int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l)
+{
+ mi_results *r=mi_res_done_var(h,"register-names");
+ int ok=0;
+
+ if (r && r->type==t_list)
+ ok=mi_parse_list_regs_l(r->v.rs,l);
+ mi_free_results(r);
+ return ok;
+}
+
+mi_chg_reg *mi_parse_reg_values_l(mi_results *r, int *how_many)
+{
+ mi_results *c;
+ mi_chg_reg *first=NULL, *cur=NULL;
+ *how_many=0;
+
+ while (r)
+ {
+ if (r->type==t_tuple && !r->var)
+ {
+ c=r->v.rs;
+ if (first)
+ cur=cur->next=mi_alloc_chg_reg();
+ else
+ first=cur=mi_alloc_chg_reg();
+ while (c)
+ {
+ if (c->type==t_const && c->var)
+ {
+ if (strcmp(c->var,"number")==0)
+ {
+ cur->reg=atoi(c->v.cstr);
+ (*how_many)++;
+ }
+ else if (strcmp(c->var,"value")==0)
+ {
+ cur->val=c->v.cstr;
+ c->v.cstr=NULL;
+ }
+ }
+ c=c->next;
+ }
+ }
+ r=r->next;
+ }
+
+ return first;
+}
+
+mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many)
+{
+ mi_results *r=mi_res_done_var(h,"register-values");
+ mi_chg_reg *rgs=NULL;
+
+ if (r && r->type==t_list)
+ rgs=mi_parse_reg_values_l(r->v.rs,how_many);
+ mi_free_results(r);
+ return rgs;
+}
+
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Program control.
+ Comments:
+ GDB/MI commands for the "Program Control" section.@p
+
+@<pre>
+gdb command: Implemented?
+
+-exec-abort N.A. (*) (kill, but with non-interactive options)
+-exec-arguments Yes
+-exec-continue Yes ASYNC
+-exec-finish Yes ASYNC
+-exec-interrupt Yes ASYNC
+-exec-next Yes ASYNC
+-exec-next-instruction Yes ASYNC
+-exec-return Yes
+-exec-run Yes ASYNC
+-exec-show-arguments N.A. (show args) see gmi_stack_info_frame
+-exec-step Yes ASYNC
+-exec-step-instruction Yes ASYNC
+-exec-until Yes ASYNC
+-file-exec-and-symbols Yes
+-file-exec-file No
+-file-list-exec-sections N.A. (info file)
+-file-list-exec-source-files N.A.
+-file-list-shared-libraries N.A.
+-file-list-symbol-files N.A.
+-file-symbol-file Yes
+@</pre>
+
+(*) gmi_exec_kill implements it, but you should ensure that
+gmi_gdb_set("confirm","off") was called.@p
+
+GDB Bug workaround for -file-exec-and-symbols and -file-symbol-file: This
+is complex, but a real bug. When you set a breakpoint you never know the
+name of the file as it appears in the debug info. So you can be specifying
+an absolute file name or a relative file name. The reference point could be
+different than the one used in the debug info. To solve all the combinations
+gdb does a search trying various combinations. GDB isn't very smart so you
+must at least specify the working directory and the directory where the
+binary is located to get a good chance (+ user options to solve the rest).
+Once you did it gdb can find the file by doing transformations to the
+"canonical" filename. This search works OK for already loaded symtabs
+(symbol tables), but it have a bug when the search is done for psymtabs
+(partial symtabs). The bug is in the use of source_full_path_of (source.c).
+This function calls openp indicating try_cwd_first. It makes the search file
+if the psymtab file name have at least one dirseparator. It means that
+psymtabs for files compiled with relative paths will fail. The search for
+symtabs uses symtab_to_filename, it calls open_source_file which finally
+calls openp without try_cwd_first.@*
+To workaround this bug we must ensure gdb loads *all* the symtabs to memory.
+And here comes another problem -file-exec-and-symbols doesn't support it
+according to docs. In real life that's a wrapper for "file", but as nobody
+can say it won't change we must use the CLI command.
+
+***************************************************************************/
+
+#include <signal.h>
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_file_exec_and_symbols(mi_h *h, const char *file)
+{
+ if (mi_get_workaround(MI_PSYM_SEARCH))
+ mi_send(h,"file %s -readnow\n",file);
+ else
+ mi_send(h,"-file-exec-and-symbols %s\n",file);
+}
+
+void mi_exec_arguments(mi_h *h, const char *args)
+{
+ mi_send(h,"-exec-arguments %s\n",args);
+}
+
+void mi_exec_run(mi_h *h)
+{
+ mi_send(h,"-exec-run\n");
+}
+
+void mi_exec_continue(mi_h *h)
+{
+ mi_send(h,"-exec-continue\n");
+}
+
+void mi_target_terminal(mi_h *h, const char *tty_name)
+{
+ mi_send(h,"tty %s\n",tty_name);
+}
+
+void mi_file_symbol_file(mi_h *h, const char *file)
+{
+ if (mi_get_workaround(MI_PSYM_SEARCH))
+ mi_send(h,"symbol-file %s -readnow\n",file);
+ else
+ mi_send(h,"-file-symbol-file %s\n",file);
+}
+
+void mi_exec_finish(mi_h *h)
+{
+ mi_send(h,"-exec-finish\n");
+}
+
+void mi_exec_interrupt(mi_h *h)
+{
+ mi_send(h,"-exec-interrupt\n");
+}
+
+void mi_exec_next(mi_h *h, int count)
+{
+ if (count>1)
+ mi_send(h,"-exec-next %d\n",count);
+ else
+ mi_send(h,"-exec-next\n");
+}
+
+void mi_exec_next_instruction(mi_h *h)
+{
+ mi_send(h,"-exec-next-instruction\n");
+}
+
+void mi_exec_step(mi_h *h, int count)
+{
+ if (count>1)
+ mi_send(h,"-exec-step %d\n",count);
+ else
+ mi_send(h,"-exec-step\n");
+}
+
+void mi_exec_step_instruction(mi_h *h)
+{
+ mi_send(h,"-exec-step-instruction\n");
+}
+
+void mi_exec_until(mi_h *h, const char *file, int line)
+{
+ if (!file)
+ mi_send(h,"-exec-until\n");
+ else
+ mi_send(h,"-exec-until %s:%d\n",file,line);
+}
+
+void mi_exec_until_addr(mi_h *h, void *addr)
+{
+ mi_send(h,"-exec-until *%p\n",addr);
+}
+
+void mi_exec_return(mi_h *h)
+{
+ mi_send(h,"-exec-return\n");
+}
+
+void mi_exec_kill(mi_h *h)
+{
+ mi_send(h,"kill\n");
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ Specify the executable and arguments for local debug.
+
+ Command: -file-exec-and-symbols + -exec-arguments
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_set_exec(mi_h *h, const char *file, const char *args)
+{
+ mi_file_exec_and_symbols(h,file);
+ if (!mi_res_simple_done(h))
+ return 0;
+ if (!args)
+ return 1;
+ mi_exec_arguments(h,args);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Start running the executable. Remote sessions starts running.
+
+ Command: -exec-run
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_run(mi_h *h)
+{
+ mi_exec_run(h);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Continue the execution after a "stop".
+
+ Command: -exec-continue
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_continue(mi_h *h)
+{
+ mi_exec_continue(h);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Indicate which terminal will use the target program. For local sessions.
+
+ Command: tty
+ Return: !=0 OK
+ Example:
+
+***************************************************************************/
+
+int gmi_target_terminal(mi_h *h, const char *tty_name)
+{
+ mi_target_terminal(h,tty_name);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Specify what's the local copy that have debug info. For remote sessions.
+
+ Command: -file-symbol-file
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_file_symbol_file(mi_h *h, const char *file)
+{
+ mi_file_symbol_file(h,file);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Continue until function return, the return value is included in the async
+response.
+
+ Command: -exec-finish
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int gmi_exec_finish(mi_h *h)
+{
+ mi_exec_finish(h);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Stop the program using SIGINT. The corresponding command should be
+-exec-interrupt but not even gdb 6.1.1 can do it because the "async" mode
+isn't really working.
+
+ Command: -exec-interrupt [replacement]
+ Return: Always 1
+ Example:
+
+***************************************************************************/
+
+int gmi_exec_interrupt(mi_h *h)
+{
+ // **** IMPORTANT!!! **** Not even gdb 6.1.1 can do it because the "async"
+ // mode isn't really working.
+ //mi_exec_interrupt(h);
+ //return mi_res_simple_running(h);
+
+ kill(h->pid,SIGINT);
+ return 1; // How can I know?
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Next line of code.
+
+ Command: -exec-next
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_next(mi_h *h)
+{
+ mi_exec_next(h,1);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Skip count lines of code.
+
+ Command: -exec-next count
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_next_cnt(mi_h *h, int count)
+{
+ mi_exec_next(h,count);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Next line of assembler code.
+
+ Command: -exec-next-instruction
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_next_instruction(mi_h *h)
+{
+ mi_exec_next_instruction(h);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Next line of code. Get inside functions.
+
+ Command: -exec-step
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_step(mi_h *h)
+{
+ mi_exec_step(h,1);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Next count lines of code. Get inside functions.
+
+ Command: -exec-step count
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_step_cnt(mi_h *h, int count)
+{
+ mi_exec_step(h,count);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Next line of assembler code. Get inside calls.
+
+ Command: -exec-step-instruction
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_step_instruction(mi_h *h)
+{
+ mi_exec_step_instruction(h);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Execute until location is reached. If file is NULL then is until next
+line.
+
+ Command: -exec-until
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_until(mi_h *h, const char *file, int line)
+{
+ mi_exec_until(h,file,line);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Execute until location is reached.
+
+ Command: -exec-until (using *address)
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_until_addr(mi_h *h, void *addr)
+{
+ mi_exec_until_addr(h,addr);
+ return mi_res_simple_running(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Return to previous frame inmediatly.
+
+ Command: -exec-return
+ Return: A pointer to a new mi_frames structure indicating the current
+location. NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_exec_return(mi_h *h)
+{
+ mi_exec_return(h);
+ return mi_res_frame(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Just kill the program. That's what -exec-abort should do, but it isn't
+implemented by gdb. This implementation only works if the interactive mode
+is disabled (gmi_gdb_set("confirm","off")).
+
+ Command: -exec-abort [using kill]
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_exec_kill(mi_h *h)
+{
+ mi_exec_kill(h);
+ return mi_res_simple_done(h);
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Stack manipulation.
+ Comments:
+ GDB/MI commands for the "Stack Manipulation" section.@p
+
+@<pre>
+gdb command: Implemented?
+
+-stack-info-frame Yes, implemented as "frame"
+-stack-info-depth Yes
+-stack-list-arguments Yes
+-stack-list-frames Yes
+-stack-list-locals Yes
+-stack-select-frame Yes
+@</pre>
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_stack_list_frames(mi_h *h, int from, int to)
+{
+ if (from<0)
+ mi_send(h,"-stack-list-frames\n");
+ else
+ mi_send(h,"-stack-list-frames %d %d\n",from,to);
+}
+
+void mi_stack_list_arguments(mi_h *h, int show, int from, int to)
+{
+ if (from<0)
+ mi_send(h,"-stack-list-arguments %d\n",show);
+ else
+ mi_send(h,"-stack-list-arguments %d %d %d\n",show,from,to);
+}
+
+void mi_stack_info_frame(mi_h *h)
+{
+ mi_send(h,"frame\n");
+}
+
+void mi_stack_info_depth(mi_h *h, int depth)
+{
+ if (depth<0)
+ mi_send(h,"-stack-info-depth\n");
+ else
+ mi_send(h,"-stack-info-depth %d\n",depth);
+}
+
+void mi_stack_select_frame(mi_h *h, int framenum)
+{
+ mi_send(h,"-stack-select-frame %d\n",framenum);
+}
+
+void mi_stack_list_locals(mi_h *h, int show)
+{
+ mi_send(h,"-stack-list-locals %d\n",show);
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ List of frames. Arguments aren't filled.
+
+ Command: -stack-list-frames
+ Return: A new list of mi_frames or NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_stack_list_frames(mi_h *h)
+{
+ mi_stack_list_frames(h,-1,-1);
+ return mi_res_frames_array(h,"stack");
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ List of frames. Arguments aren't filled. Only the frames in the @var{from}
+ - @var{to} range are returned.
+
+ Command: -stack-list-frames
+ Return: A new list of mi_frames or NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_stack_list_frames_r(mi_h *h, int from, int to)
+{
+ mi_stack_list_frames(h,from,to);
+ return mi_res_frames_array(h,"stack");
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ List arguments. Only @var{level} and @var{args} filled.
+
+ Command: -stack-list-arguments
+ Return: A new list of mi_frames or NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_stack_list_arguments(mi_h *h, int show)
+{
+ mi_stack_list_arguments(h,show,-1,-1);
+ return mi_res_frames_array(h,"stack-args");
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ List arguments. Only @var{level} and @var{args} filled. Only for the
+frames in the @var{from} - @var{to} range.
+
+ Command: -stack-list-arguments
+ Return: A new list of mi_frames or NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_stack_list_arguments_r(mi_h *h, int show, int from, int to)
+{
+ mi_stack_list_arguments(h,show,from,to);
+ return mi_res_frames_array(h,"stack-args");
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Information about the current frame, including args.
+
+ Command: -stack-info-frame [using frame]
+ Return: A new mi_frames or NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_stack_info_frame(mi_h *h)
+{
+ mi_stack_info_frame(h);
+ return mi_res_frame(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Stack info depth.
+
+ Command: -stack-info-depth
+ Return: The depth or -1 on error.
+
+***************************************************************************/
+
+int gmi_stack_info_depth(mi_h *h, int max_depth)
+{
+ mi_results *r;
+ int ret=-1;
+
+ mi_stack_info_depth(h,max_depth);
+ r=mi_res_done_var(h,"depth");
+ if (r && r->type==t_const)
+ {
+ ret=atoi(r->v.cstr);
+ mi_free_results(r);
+ }
+ return ret;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Set stack info depth.
+
+ Command: -stack-info-depth [no args]
+ Return: The depth or -1 on error.
+ Example:
+
+***************************************************************************/
+
+int gmi_stack_info_depth_get(mi_h *h)
+{
+ return gmi_stack_info_depth(h,-1);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Change current frame.
+
+ Command: -stack-select-frame
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_stack_select_frame(mi_h *h, int framenum)
+{
+ mi_stack_select_frame(h,framenum);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ List of local vars.
+
+ Command: -stack-list-locals
+ Return: A new mi_results tree containing the variables or NULL on error.
+
+***************************************************************************/
+
+mi_results *gmi_stack_list_locals(mi_h *h, int show)
+{
+ mi_stack_list_locals(h,show);
+ return mi_res_done_var(h,"locals");
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Symbol query.
+ Comments:
+ GDB/MI commands for the "Symbol Query" section.@p
+
+@<pre>
+gdb command: Implemented?
+-symbol-info-address N.A. (info address, human readable)
+-symbol-info-file N.A.
+-symbol-info-function N.A.
+-symbol-info-line N.A. (info line, human readable)
+-symbol-info-symbol N.A. (info symbol, human readable)
+-symbol-list-functions N.A. (info functions, human readable)
+-symbol-list-types N.A. (info types, human readable)
+-symbol-list-variables N.A. (info variables, human readable)
+-symbol-list-lines No (gdb 6.x)
+-symbol-locate N.A.
+-symbol-type N.A. (ptype, human readable)
+@</pre>
+
+Note:@p
+
+Only one is implemented and not in gdb 5.x.@p
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004-2007 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Target manipulation.
+ Comments:
+ GDB/MI commands for the "Target Manipulation" section.@p
+
+@<pre>
+-target-attach Yes (implemented using attach)
+-target-compare-sections N.A. (compare-sections)
+-target-detach Yes
+-target-download Yes
+-target-exec-status N.A.
+-target-list-available-targets N.A. (help target)
+-target-list-current-targets N.A. (info file among other things)
+-target-list-parameters N.A.
+-target-select Yes
+@</pre>
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_target_select(mi_h *h, const char *type, const char *params)
+{
+ mi_send(h,"-target-select %s %s\n",type,params);
+}
+
+/* Note: -target-attach isn't currently implemented :-( (gdb 6.1.1) */
+void mi_target_attach(mi_h *h, pid_t pid)
+{
+ mi_send(h,"attach %d\n",pid);
+}
+
+void mi_target_detach(mi_h *h)
+{
+ mi_send(h,"-target-detach\n");
+}
+
+void mi_target_download(mi_h *h)
+{
+ mi_send(h,"-target-download\n");
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ Connect to a remote gdbserver using the specified methode.
+
+ Command: -target-select
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_target_select(mi_h *h, const char *type, const char *params)
+{
+ mi_target_select(h,type,params);
+ if (!mi_res_simple_connected(h))
+ return 0;
+ mi_send_target_commands(h);
+ return 1;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Attach to an already running process.
+
+ Command: -target-attach [using attach]
+ Return: The frame of the current location, NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_target_attach(mi_h *h, pid_t pid)
+{
+ mi_target_attach(h,pid);
+ //return mi_res_simple_done(h);
+ return mi_res_frame(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Detach from an attached process.
+
+ Command: -target-detach
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_target_detach(mi_h *h)
+{
+ mi_target_detach(h);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Loads the executable onto the remote target.
+
+ Command: -target-download
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_target_download(mi_h *h)
+{
+ mi_target_download(h);
+ // TODO: this response have some data
+ return mi_res_simple_done(h);
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Thread commands.
+ Comments:
+ GDB/MI commands for the "Thread Commands" section.@p
+
+@<pre>
+gdb command: Implemented?
+-thread-info N.A.
+-thread-list-all-threads Yes, implemented as "info threads"
+-thread-list-ids Yes
+-thread-select Yes
+@</pre>
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_thread_list_ids(mi_h *h)
+{
+ mi_send(h,"-thread-list-ids\n");
+}
+
+void mi_thread_select(mi_h *h, int id)
+{
+ mi_send(h,"-thread-select %d\n",id);
+}
+
+void mi_thread_list_all_threads(mi_h *h)
+{
+ mi_send(h,"info threads\n");
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ List available thread ids.
+
+ Command: -thread-list-ids
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_thread_list_ids(mi_h *h, int **list)
+{
+ mi_thread_list_ids(h);
+ return mi_res_thread_ids(h,list);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Select a thread.
+
+ Command: -thread-select
+ Return: A new mi_frames or NULL on error.
+
+***************************************************************************/
+
+mi_frames *gmi_thread_select(mi_h *h, int id)
+{
+ mi_thread_select(h,id);
+ return mi_res_frame(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Get a list of frames for each available thread. Implemented using "info
+thread".
+
+ Command: -thread-list-all-threads
+ Return: A kist of frames, NULL on error
+
+***************************************************************************/
+
+mi_frames *gmi_thread_list_all_threads(mi_h *h)
+{
+ mi_thread_list_all_threads(h);
+ return mi_res_frames_list(h);
+}
+
--- /dev/null
+/**[txh]********************************************************************
+
+ Copyright (c) 2004 by Salvador E. Tropea.
+ Covered by the GPL license.
+
+ Module: Variable objects.
+ Comments:
+ GDB/MI commands for the "Variable Objects" section.@p
+
+@<pre>
+gdb command: Imp? Description:
+-var-create Yes create a variable object
+-var-delete Yes delete the variable object and its children
+-var-set-format Yes set the display format of this variable
+-var-show-format Yes show the display format of this variable
+-var-info-num-children Yes tells how many children this object has
+-var-list-children Yes* return a list of the object's children
+-var-info-type Yes show the type of this variable object
+-var-info-expression Yes print what this variable object represents
+-var-show-attributes Yes is this variable editable?
+-var-evaluate-expression Yes get the value of this variable
+-var-assign Yes set the value of this variable
+-var-update Yes* update the variable and its children
+@</pre>
+
+Notes:@p
+1) I suggest letting gdb to choose the names for the variables.@*
+2) -var-list-children supports an optional "show values" argument in MI v2.
+It isn't implemented.@*
+@p
+
+* MI v1 and v2 result formats supported.@p
+
+***************************************************************************/
+
+#include "mi_gdb.h"
+
+/* Low level versions. */
+
+void mi_var_create(mi_h *h, const char *name, int frame, const char *exp)
+{
+ const char *n=name ? name : "-";
+
+ if (frame<0)
+ mi_send(h,"-var-create %s * %s\n",n,exp);
+ else
+ mi_send(h,"-var-create %s %d %s\n",n,frame,exp);
+}
+
+void mi_var_delete(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-delete %s\n",name);
+}
+
+void mi_var_set_format(mi_h *h, const char *name, const char *format)
+{
+ mi_send(h,"-var-set-format \"%s\" %s\n",name,format);
+}
+
+void mi_var_show_format(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-show-format \"%s\"\n",name);
+}
+
+void mi_var_info_num_children(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-info-num-children \"%s\"\n",name);
+}
+
+void mi_var_info_type(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-info-type \"%s\"\n",name);
+}
+
+void mi_var_info_expression(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-info-expression \"%s\"\n",name);
+}
+
+void mi_var_show_attributes(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-show-attributes \"%s\"\n",name);
+}
+
+void mi_var_update(mi_h *h, const char *name)
+{
+ if (name)
+ mi_send(h,"-var-update %s\n",name);
+ else
+ mi_send(h,"-var-update *\n");
+}
+
+void mi_var_assign(mi_h *h, const char *name, const char *expression)
+{
+ mi_send(h,"-var-assign \"%s\" \"%s\"\n",name,expression);
+}
+
+void mi_var_evaluate_expression(mi_h *h, const char *name)
+{
+ mi_send(h,"-var-evaluate-expression \"%s\"\n",name);
+}
+
+void mi_var_list_children(mi_h *h, const char *name)
+{
+ if (h->version>=MI_VERSION2U(2,0,0))
+ mi_send(h,"-var-list-children --all-values \"%s\"\n",name);
+ else
+ mi_send(h,"-var-list-children \"%s\"\n",name);
+}
+
+/* High level versions. */
+
+/**[txh]********************************************************************
+
+ Description:
+ Create a variable object. I recommend using @x{gmi_var_create} and letting
+gdb choose the names.
+
+ Command: -var-create
+ Return: A new mi_gvar strcture or NULL on error.
+
+***************************************************************************/
+
+mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp)
+{
+ mi_var_create(h,name,frame,exp);
+ return mi_res_gvar(h,NULL,exp);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Create a variable object. The name is selected by gdb. Alternative:
+@x{gmi_full_var_create}.
+
+ Command: -var-create [auto name]
+ Return: A new mi_gvar strcture or NULL on error.
+
+***************************************************************************/
+
+mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp)
+{
+ return gmi_var_create_nm(h,NULL,frame,exp);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Delete a variable object. Doesn't free the mi_gvar data.
+
+ Command: -var-delete
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_delete(mi_h *h, mi_gvar *var)
+{
+ mi_var_delete(h,var->name);
+ return mi_res_simple_done(h);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Set the format used to represent the result.
+
+ Command: -var-set-format
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format)
+{
+ int ret;
+
+ mi_var_set_format(h,var->name,mi_format_enum_to_str(format));
+ ret=mi_res_simple_done(h);
+ if (ret)
+ var->format=format;
+ return ret;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Fill the format field with info from gdb.
+
+ Command: -var-show-format
+ Return: !=0 OK.
+
+***************************************************************************/
+
+int gmi_var_show_format(mi_h *h, mi_gvar *var)
+{
+ mi_var_show_format(h,var->name);
+ return mi_res_gvar(h,var,NULL)!=NULL;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Fill the numchild field with info from gdb.
+
+ Command: -var-info-num-children
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_info_num_children(mi_h *h, mi_gvar *var)
+{
+ mi_var_info_num_children(h,var->name);
+ return mi_res_gvar(h,var,NULL)!=NULL;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Fill the type field with info from gdb.
+
+ Command: -var-info-type
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_info_type(mi_h *h, mi_gvar *var)
+{
+ mi_var_info_type(h,var->name);
+ return mi_res_gvar(h,var,NULL)!=NULL;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Fill the expression and lang fields with info from gdb. Note that lang
+isn't filled during creation.
+
+ Command: -var-info-expression
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_info_expression(mi_h *h, mi_gvar *var)
+{
+ mi_var_info_expression(h,var->name);
+ return mi_res_gvar(h,var,NULL)!=NULL;
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Fill the attr field with info from gdb. Note that attr isn't filled
+during creation.
+
+ Command: -var-show-attributes
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_show_attributes(mi_h *h, mi_gvar *var)
+{
+ mi_var_show_attributes(h,var->name);
+ return mi_res_gvar(h,var,NULL)!=NULL;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Create the variable and also fill the lang and attr fields. The name is
+selected by gdb.
+
+ Command: -var-create + -var-info-expression + -var-show-attributes
+ Return: A new mi_gvar strcture or NULL on error.
+
+***************************************************************************/
+
+mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp)
+{
+ mi_gvar *var=gmi_var_create_nm(h,NULL,frame,exp);
+ if (var)
+ {/* What if it fails? */
+ gmi_var_info_expression(h,var);
+ gmi_var_show_attributes(h,var);
+ }
+ return var;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Update variable. Use NULL for all. Note that *changed can be NULL if none
+updated.
+
+ Command: -var-update
+ Return: !=0 OK. The @var{changed} list contains the list of changed vars.
+
+***************************************************************************/
+
+int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed)
+{
+ mi_var_update(h,var ? var->name : NULL);
+ return mi_res_changelist(h,changed);
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Change variable. The new value replaces the @var{value} field.
+
+ Command: -var-assign
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression)
+{
+ char *res;
+ mi_var_assign(h,var->name,expression);
+ res=mi_res_value(h);
+ if (res)
+ {
+ free(var->value);
+ var->value=res;
+ return 1;
+ }
+ return 0;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ Fill the value field getting the current value for a variable.
+
+ Command: -var-evaluate-expression
+ Return: !=0 OK, value contains the result.
+
+***************************************************************************/
+
+int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var)
+{
+ char *s;
+
+ mi_var_evaluate_expression(h,var->name);
+ s=mi_res_value(h);
+ if (s)
+ {
+ free(var->value);
+ var->value=s;
+ }
+ return s!=NULL;
+}
+
+/**[txh]********************************************************************
+
+ Description:
+ List children. It ONLY returns the first level information. :-(@*
+ On success the child field contains the list of children.
+
+ Command: -var-list-children
+ Return: !=0 OK
+
+***************************************************************************/
+
+int gmi_var_list_children(mi_h *h, mi_gvar *var)
+{
+ mi_var_list_children(h,var->name);
+ return mi_res_children(h,var);
+}
+
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: pseudo terminal
- Comments:
- Helper to find a free pseudo terminal. Use this if you need to manage
- input *and* output to the target process. If you just need output then
- define a handler for target output stream records (assuming that this
- is working for your particular version of gdb).
- Usage:
-
- mi_pty *pty = gmi_look_for_free_pty();
- if (pty) gmi_target_terminal(mih, pty->slave);
- ...
- * reading from pty->master will get stdout from target *
- * writing to pty->master will send to target stdin *
-
- Note: Contributed by Greg Watson (gwatson lanl gov)
-
-***************************************************************************/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include "mi_gdb.h"
-
-/**[txh]********************************************************************
-
- Description:
- Look for a free and usable pseudo terminal. Low level, use
-@x{gmi_look_for_free_pty}.
-
- Return: A file descriptor connected to the master pty and the name of the slave device, or <0 on error.
-
-***************************************************************************/
-
-#ifdef __APPLE__
-
-#include <util.h>
-
-int mi_look_for_free_pty(int *master, char **slave)
-{
- int fdmaster;
- int fdslave;
- static char name[BUFSIZ];
-
- if (openpty(&fdmaster,&fdslave,name,NULL,NULL)<0)
- return -1;
-
- (void)close(fdslave); /* this will be reopened by gdb */
- *master=fdmaster;
- *slave =name;
-
- return 0;
-}
-
-#elif defined(__linux__)
-
-int mi_look_for_free_pty(int *master, char **slave)
-{
- if ((*master=open("/dev/ptmx",O_RDWR))<0)
- return -1;
- if (grantpt(*master)<0 || unlockpt(*master)<0)
- return -1;
- *slave = ptsname(*master);
-
- return 0;
-}
-
-#else /* undefined o/s */
-
-int mi_look_for_free_pty(int *master, char **slave)
-{
- return -1;
-}
-#endif
-
-/**[txh]********************************************************************
-
- Description:
- Look for a free and usable pseudo terminal to be used by the child.
-
- Return: A new mi_pty structure, you can use @x{gmi_end_pty} to
-release it.
-
-***************************************************************************/
-
-mi_pty *gmi_look_for_free_pty()
-{
- int master;
- char *slave;
- int pty=mi_look_for_free_pty(&master,&slave);
- mi_pty *res;
-
- if (pty<0)
- return NULL;
- res=(mi_pty *)malloc(sizeof(mi_pty));
- if (!res)
- return NULL;
- res->slave=strdup(slave);
- res->master=master;
- return res;
-}
-
-void mi_free_pty(mi_pty *p)
-{
- if (!p)
- return;
- free(p->slave);
- free(p);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Closes the pseudo termial master and releases the allocated memory.
-
-***************************************************************************/
-
-void gmi_end_pty(mi_pty *p)
-{
- if (!p)
- return;
- close(p->master);
- mi_free_pty(p);
-}
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Linux VT.
- Comments:
- Helper to find a free VT. That's 100% Linux specific.@p
- The code comes from "lconsole.c" from Allegro project and was originally
-created by Marek Habersack and then modified by George Foot. I addapted it
-to my needs and changed license from giftware to GPL.@p
-
-***************************************************************************/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#ifdef __APPLE__
-#include <util.h>
-#endif /* __APPLE__ */
-
-#include "mi_gdb.h"
-
-#if !defined(__linux__)
-
-int mi_look_for_free_vt()
-{
- return -1;
-}
-
-mi_aux_term *gmi_look_for_free_vt()
-{
- return NULL;
-}
-
-#else
-
-#include <linux/vt.h>
-
-/**[txh]********************************************************************
-
- Description:
- Look for a free and usable Linux VT. Low level, use
-@x{gmi_look_for_free_vt}.
-
- Return: The VT number or <0 on error.
-
-***************************************************************************/
-
-int mi_look_for_free_vt()
-{/* Code from Allegro. */
- int tty, console_fd, fd;
- unsigned short mask;
- char tty_name[16];
- struct vt_stat vts;
-
- /* Now we need to find a VT we can use. It must be readable and
- * writable by us, if we're not setuid root. VT_OPENQRY itself
- * isn't too useful because it'll only ever come up with one
- * suggestion, with no guarrantee that we actually have access
- * to it.
- *
- * At some stage I think this is a candidate for config
- * file overriding, but for now we'll stat the first N consoles
- * to see which ones we can write to (hopefully at least one!),
- * so that we can use that one to do ioctls. We used to use
- * /dev/console for that purpose but it looks like it's not
- * always writable by enough people.
- *
- * Having found and opened a writable device, we query the state
- * of the first sixteen (fifteen really) consoles, and try
- * opening each unused one in turn.
- */
-
- console_fd=open("/dev/console",O_WRONLY);
- if (console_fd<0)
- {
- int n;
- /* Try some ttys instead... */
- for (n=1; n<=24; n++)
- {
- snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",n);
- console_fd=open(tty_name,O_WRONLY);
- if (console_fd>=0)
- break;
- }
- if (n>24)
- return -1;
- }
-
- /* Get the state of the console -- in particular, the free VT field */
- if (ioctl(console_fd,VT_GETSTATE,&vts))
- return -2;
- close(console_fd);
-
- /* We attempt to set our euid to 0; if we were run with euid 0 to
- * start with, we'll be able to do this now. Otherwise, we'll just
- * ignore the error returned since it might not be a problem if the
- * ttys we look at are owned by the user running the program. */
- seteuid(0);
-
- /* tty0 is not really a console, so start counting at 2. */
- fd=-1;
- for (tty=1, mask=2; mask; tty++, mask<<=1)
- if (!(vts.v_state & mask))
- {
- snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",tty);
- fd=open(tty_name,O_RDWR);
- if (fd!=-1)
- {
- close(fd);
- break;
- }
- }
-
- seteuid(getuid());
-
- if (!mask)
- return -3;
-
- return tty;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Look for a free and usable Linux VT to be used by the child.
-
- Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
-release it.
-
-***************************************************************************/
-
-mi_aux_term *gmi_look_for_free_vt()
-{
- int vt=mi_look_for_free_vt();
- mi_aux_term *res;
-
- if (vt<0)
- return NULL;
- res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
- if (!res)
- return NULL;
- res->pid=-1;
- asprintf(&res->tty,"/dev/tty%d",vt);
- return res;
-}
-
-#endif
-
+++ /dev/null
-#ifndef LIBMIGDB_H_
-#define LIBMIGDB_H_
-
-#endif /*LIBMIGDB_H_*/
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004-2009 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Comments:
- Main header for libmigdb.
-
-***************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h> /* pid_t */
-
-#define MI_OK 0
-#define MI_OUT_OF_MEMORY 1
-#define MI_PIPE_CREATE 2
-#define MI_FORK 3
-#define MI_DEBUGGER_RUN 4
-#define MI_PARSER 5
-#define MI_UNKNOWN_ASYNC 6
-#define MI_UNKNOWN_RESULT 7
-#define MI_FROM_GDB 8
-#define MI_GDB_TIME_OUT 9
-#define MI_GDB_DIED 10
-#define MI_MISSING_XTERM 11
-#define MI_CREATE_TEMPORAL 12
-#define MI_MISSING_GDB 13
-#define MI_LAST_ERROR 13
-
-#define MI_R_NONE 0 /* We are no waiting any response. */
-#define MI_R_SKIP 1 /* We want to discard it. */
-#define MI_R_FE_AND_S 2 /* Wait for done. */
-#define MI_R_E_ARGS 3
-
-enum mi_val_type { t_const, t_tuple, t_list };
-
-/* Types and subtypes. */
-/* Type. */
-#define MI_T_OUT_OF_BAND 0
-#define MI_T_RESULT_RECORD 1
-/* Out of band subtypes. */
-#define MI_ST_ASYNC 0
-#define MI_ST_STREAM 1
-/* Async sub-subtypes. */
-#define MI_SST_EXEC 0
-#define MI_SST_STATUS 1
-#define MI_SST_NOTIFY 2
-/* Stream sub-subtypes. */
-#define MI_SST_CONSOLE 3
-#define MI_SST_TARGET 4
-#define MI_SST_LOG 5
-/* Classes. */
-/* Async classes. */
-#define MI_CL_UNKNOWN 0
-#define MI_CL_STOPPED 1
-#define MI_CL_DOWNLOAD 2
-/* Result classes. */
-#define MI_CL_DONE 2
-#define MI_CL_RUNNING 3
-#define MI_CL_CONNECTED 4
-#define MI_CL_ERROR 5
-#define MI_CL_EXIT 6
-
-#define MI_DEFAULT_TIME_OUT 10
-
-#define MI_DIS_ASM 0
-#define MI_DIS_SRC_ASM 1
-
-/* Implemented workaround for gdb bugs that we can dis/enable. */
-/* At least gdb<=6.1.1 fails to find a source file with absolute path if the
- name is for a psym instead of a sym. psym==partially loaded symbol table. */
-#define MI_PSYM_SEARCH 0
-
-#define MI_VERSION_STR "0.8.12"
-#define MI_VERSION_MAJOR 0
-#define MI_VERSION_MIDDLE 8
-#define MI_VERSION_MINOR 12
-
-struct mi_results_struct
-{
- char *var; /* Result name or NULL if just a value. */
- enum mi_val_type type;
- union
- {
- char *cstr;
- struct mi_results_struct *rs;
- } v;
- struct mi_results_struct *next;
-};
-typedef struct mi_results_struct mi_results;
-
-struct mi_output_struct
-{
- /* Type of output. */
- char type;
- char stype;
- char sstype;
- char tclass;
- /* Content. */
- mi_results *c;
- /* Always modeled as a list. */
- struct mi_output_struct *next;
-};
-typedef struct mi_output_struct mi_output;
-
-typedef void (*stream_cb)(const char *, void *);
-typedef void (*async_cb)(mi_output *o, void *);
-typedef int (*tm_cb)(void *);
-
-/* Values of this structure shouldn't be manipulated by the user. */
-struct mi_h_struct
-{
- /* Pipes connected to gdb. */
- int to_gdb[2];
- int from_gdb[2];
- /* Streams for the pipes. */
- FILE *to, *from;
- /* PID of child gdb. */
- pid_t pid;
- char died;
- /* Which rensponse we are waiting for. */
- /*int response;*/
- /* The line we are reading. */
- char *line;
- int llen, lread;
- /* Parsed output. */
- mi_output *po, *last;
- /* Tunneled streams callbacks. */
- stream_cb console;
- void *console_data;
- stream_cb target;
- void *target_data;
- stream_cb log;
- void *log_data;
- /* Async responses callback. */
- async_cb async;
- void *async_data;
- /* Callbacks to get echo of gdb dialog. */
- stream_cb to_gdb_echo;
- void *to_gdb_echo_data;
- stream_cb from_gdb_echo;
- void *from_gdb_echo_data;
- /* Time out */
- tm_cb time_out_cb;
- void *time_out_cb_data;
- int time_out;
- /* Ugly workaround for some of the show responses :-( */
- int catch_console;
- char *catched_console;
- /* MI version, currently unknown but the user can force v2 */
- unsigned version;
-};
-typedef struct mi_h_struct mi_h;
-
-#define MI_TO(a) ((a)->to_gdb[1])
-
-enum mi_bkp_type { t_unknown=0, t_breakpoint=1, t_hw=2 };
-enum mi_bkp_disp { d_unknown=0, d_keep=1, d_del=2 };
-enum mi_bkp_mode { m_file_line=0, m_function=1, m_file_function=2, m_address=3 };
-
-struct mi_bkpt_struct
-{
- int number;
- enum mi_bkp_type type;
- enum mi_bkp_disp disp; /* keep or del if temporal */
- char enabled;
- void *addr;
- char *func;
- char *file;
- int line;
- int ignore;
- int times;
-
- /* For the user: */
- char *cond;
- char *file_abs;
- int thread;
- enum mi_bkp_mode mode;
- struct mi_bkpt_struct *next;
-};
-typedef struct mi_bkpt_struct mi_bkpt;
-
-enum mi_wp_mode { wm_unknown=0, wm_write=1, wm_read=2, wm_rw=3 };
-
-struct mi_wp_struct
-{
- int number;
- char *exp;
- enum mi_wp_mode mode;
-
- /* For the user: */
- struct mi_wp_struct *next;
- char enabled;
-};
-typedef struct mi_wp_struct mi_wp;
-
-struct mi_frames_struct
-{
- int level; /* The frame number, 0 being the topmost frame, i.e. the innermost
- function. */
- void *addr; /* The `$pc' value for that frame. */
- char *func; /* Function name. */
- char *file; /* File name of the source file where the function lives. */
- char *from;
- int line; /* Line number corresponding to the `$pc'. */
- /* When arguments are available: */
- mi_results *args;
- int thread_id;
- /* When more than one is provided: */
- struct mi_frames_struct *next;
-};
-typedef struct mi_frames_struct mi_frames;
-
-struct mi_aux_term_struct
-{
- pid_t pid;
- char *tty;
-};
-typedef struct mi_aux_term_struct mi_aux_term;
-
-struct mi_pty_struct
-{
- char *slave;
- int master;
-};
-typedef struct mi_pty_struct mi_pty;
-
-enum mi_gvar_fmt { fm_natural=0, fm_binary=1, fm_decimal=2, fm_hexadecimal=3,
- fm_octal=4,
- /* Only for registers format: */
- fm_raw=5 };
-enum mi_gvar_lang { lg_unknown=0, lg_c, lg_cpp, lg_java };
-
-#define MI_ATTR_DONT_KNOW 0
-#define MI_ATTR_NONEDITABLE 1
-#define MI_ATTR_EDITABLE 2
-
-struct mi_gvar_struct
-{
- char *name;
- int numchild;
- char *type;
- enum mi_gvar_fmt format;
- enum mi_gvar_lang lang;
- char *exp;
- int attr;
-
- /* MI v2 fills it, not yet implemented here. */
- /* Use gmi_var_evaluate_expression. */
- char *value;
-
- /* Pointer to the parent. NULL if none. */
- struct mi_gvar_struct *parent;
- /* List containing the children.
- Filled by gmi_var_list_children.
- NULL if numchild==0 or not yet filled. */
- struct mi_gvar_struct *child;
- /* Next var in the list. */
- struct mi_gvar_struct *next;
-
- /* For the user: */
- char opened; /* We will show its children. 1 when we fill "child" */
- char changed; /* Needs to be updated. 0 when created. */
- int vischild; /* How many items visible. numchild when we fill "child" */
- int depth; /* How deep is this var. */
- char ispointer;
-};
-typedef struct mi_gvar_struct mi_gvar;
-
-struct mi_gvar_chg_struct
-{
- char *name;
- int in_scope; /* if true the other fields apply. */
- char *new_type; /* NULL if type_changed==false */
- int new_num_children; /* only when new_type!=NULL */
-
- struct mi_gvar_chg_struct *next;
-};
-typedef struct mi_gvar_chg_struct mi_gvar_chg;
-
-
-/* A list of assembler instructions. */
-struct mi_asm_insn_struct
-{
- void *addr;
- char *func;
- unsigned offset;
- char *inst;
-
- struct mi_asm_insn_struct *next;
-};
-typedef struct mi_asm_insn_struct mi_asm_insn;
-
-/* A list of source lines containing assembler instructions. */
-struct mi_asm_insns_struct
-{
- char *file;
- int line;
- mi_asm_insn *ins;
-
- struct mi_asm_insns_struct *next;
-};
-typedef struct mi_asm_insns_struct mi_asm_insns;
-
-/* Changed register. */
-struct mi_chg_reg_struct
-{
- int reg;
- char *val;
- char *name;
- char updated;
-
- struct mi_chg_reg_struct *next;
-};
-typedef struct mi_chg_reg_struct mi_chg_reg;
-
-/*
- Examining gdb sources and looking at docs I can see the following "stop"
-reasons:
-
-Breakpoints:
-a) breakpoint-hit (bkptno) + frame
-Also: without reason for temporal breakpoints.
-
-Watchpoints:
-b) watchpoint-trigger (wpt={number,exp};value={old,new}) + frame
-c) read-watchpoint-trigger (hw-rwpt{number,exp};value={value}) + frame
-d) access-watchpoint-trigger (hw-awpt{number,exp};value={[old,]new}) + frame
-e) watchpoint-scope (wpnum) + frame
-
-Movement:
-f) function-finished ([gdb-result-var,return-value]) + frame
-g) location-reached + frame
-h) end-stepping-range + frame
-
-Exit:
-i) exited-signalled (signal-name,signal-meaning)
-j) exited (exit-code)
-k) exited-normally
-
-Signal:
-l) signal-received (signal-name,signal-meaning) + frame
-
-Plus: thread-id
-*/
-enum mi_stop_reason
-{
- sr_unknown=0,
- sr_bkpt_hit,
- sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
- sr_function_finished, sr_location_reached, sr_end_stepping_range,
- sr_exited_signalled, sr_exited, sr_exited_normally,
- sr_signal_received
-};
-
-struct mi_stop_struct
-{
- enum mi_stop_reason reason; /* If more than one reason just the last. */
- /* Flags indicating if non-pointer fields are filled. */
- char have_thread_id;
- char have_bkptno;
- char have_exit_code;
- char have_wpno;
- /* Where stopped. Doesn't exist for sr_exited*. */
- int thread_id;
- mi_frames *frame;
- /* sr_bkpt_hit */
- int bkptno;
- /* sr_*wp_* no scope */
- mi_wp *wp;
- char *wp_old;
- char *wp_val;
- /* sr_wp_scope */
- int wpno;
- /* sr_function_finished. Not for void func. */
- char *gdb_result_var;
- char *return_value;
- /* sr_exited_signalled, sr_signal_received */
- char *signal_name;
- char *signal_meaning;
- /* sr_exited */
- int exit_code;
-};
-typedef struct mi_stop_struct mi_stop;
-
-/* Variable containing the last error. */
-extern int mi_error;
-extern char *mi_error_from_gdb;
-const char *mi_get_error_str();
-
-/* Indicate the name of gdb exe. Default is /usr/bin/gdb */
-void mi_set_gdb_exe(const char *name);
-const char *mi_get_gdb_exe();
-/* Indicate the name of a file containing commands to send at start-up */
-void mi_set_gdb_start(const char *name);
-const char *mi_get_gdb_start();
-/* Indicate the name of a file containing commands to send after connection */
-void mi_set_gdb_conn(const char *name);
-const char *mi_get_gdb_conn();
-void mi_send_target_commands(mi_h *h);
-/* Connect to a local copy of gdb. */
-mi_h *mi_connect_local();
-/* Close connection. You should ask gdb to quit first. */
-void mi_disconnect(mi_h *h);
-/* Force MI version. */
-#define MI_VERSION2U(maj,mid,min) (maj*0x1000000+mid*0x10000+min)
-void mi_force_version(mi_h *h, unsigned vMajor, unsigned vMiddle,
- unsigned vMinor);
-void mi_set_workaround(unsigned wa, int enable);
-int mi_get_workaround(unsigned wa);
-/* Parse gdb output. */
-mi_output *mi_parse_gdb_output(const char *str);
-/* Functions to set/get the tunneled streams callbacks. */
-void mi_set_console_cb(mi_h *h, stream_cb cb, void *data);
-void mi_set_target_cb(mi_h *h, stream_cb cb, void *data);
-void mi_set_log_cb(mi_h *h, stream_cb cb, void *data);
-stream_cb mi_get_console_cb(mi_h *h, void **data);
-stream_cb mi_get_target_cb(mi_h *h, void **data);
-stream_cb mi_get_log_cb(mi_h *h, void **data);
-/* The callback to deal with async events. */
-void mi_set_async_cb(mi_h *h, async_cb cb, void *data);
-async_cb mi_get_async_cb(mi_h *h, void **data);
-/* Time out in gdb responses. */
-void mi_set_time_out_cb(mi_h *h, tm_cb cb, void *data);
-tm_cb mi_get_time_out_cb(mi_h *h, void **data);
-void mi_set_time_out(mi_h *h, int to);
-int mi_get_time_out(mi_h *h);
-/* Callbacks to "see" the dialog with gdb. */
-void mi_set_to_gdb_cb(mi_h *h, stream_cb cb, void *data);
-void mi_set_from_gdb_cb(mi_h *h, stream_cb cb, void *data);
-stream_cb mi_get_to_gdb_cb(mi_h *h, void **data);
-stream_cb mi_get_from_gdb_cb(mi_h *h, void **data);
-/* Sends a message to gdb. */
-int mi_send(mi_h *h, const char *format, ...);
-/* Wait until gdb sends a response. */
-mi_output *mi_get_response_blk(mi_h *h);
-/* Check if gdb sent a complete response. Use with mi_retire_response. */
-int mi_get_response(mi_h *h);
-/* Get the last response. Use with mi_get_response. */
-mi_output *mi_retire_response(mi_h *h);
-/* Look for a result record in gdb output. */
-mi_output *mi_get_rrecord(mi_output *r);
-/* Look if the output contains an async stop.
- If that's the case return the reason for the stop.
- If the output contains an error the description is returned in reason. */
-int mi_get_async_stop_reason(mi_output *r, char **reason);
-mi_stop *mi_get_stopped(mi_results *r);
-mi_frames *mi_get_async_frame(mi_output *r);
-/* Wait until gdb sends a response.
- Then check if the response is of the desired type. */
-int mi_res_simple_exit(mi_h *h);
-int mi_res_simple_done(mi_h *h);
-int mi_res_simple_running(mi_h *h);
-int mi_res_simple_connected(mi_h *h);
-/* It additionally extracts an specified variable. */
-mi_results *mi_res_done_var(mi_h *h, const char *var);
-/* Extract a frames list from the response. */
-mi_frames *mi_res_frames_array(mi_h *h, const char *var);
-mi_frames *mi_res_frames_list(mi_h *h);
-mi_frames *mi_parse_frame(mi_results *c);
-mi_frames *mi_res_frame(mi_h *h);
-/* Create an auxiliar terminal using xterm. */
-mi_aux_term *gmi_start_xterm();
-/* Indicate the name of xterm exe. Default is /usr/bin/X11/xterm */
-void mi_set_xterm_exe(const char *name);
-const char *mi_get_xterm_exe();
-/* Kill the auxiliar terminal and release the structure. */
-void gmi_end_aux_term(mi_aux_term *t);
-/* Look for a free Linux VT for the child. */
-mi_aux_term *gmi_look_for_free_vt();
-/* Look for a free and usable Linux VT. */
-int mi_look_for_free_vt();
-/* Close master and release the structure. */
-void gmi_end_pty(mi_pty *p);
-/* Look for a free pseudo terminal. */
-mi_pty *gmi_look_for_free_pty();
-/* Extract a list of thread IDs from response. */
-int mi_res_thread_ids(mi_h *h, int **list);
-int mi_get_thread_ids(mi_output *res, int **list);
-/* A variable response. */
-mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression);
-enum mi_gvar_fmt mi_format_str_to_enum(const char *format);
-const char *mi_format_enum_to_str(enum mi_gvar_fmt format);
-char mi_format_enum_to_char(enum mi_gvar_fmt format);
-enum mi_gvar_lang mi_lang_str_to_enum(const char *lang);
-const char *mi_lang_enum_to_str(enum mi_gvar_lang lang);
-int mi_res_changelist(mi_h *h, mi_gvar_chg **changed);
-int mi_res_children(mi_h *h, mi_gvar *v);
-mi_bkpt *mi_res_bkpt(mi_h *h);
-mi_wp *mi_res_wp(mi_h *h);
-char *mi_res_value(mi_h *h);
-mi_stop *mi_res_stop(mi_h *h);
-enum mi_stop_reason mi_reason_str_to_enum(const char *s);
-const char *mi_reason_enum_to_str(enum mi_stop_reason r);
-int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
- unsigned long *addr);
-mi_asm_insns *mi_get_asm_insns(mi_h *h);
-/* Starting point of the program. */
-void mi_set_main_func(const char *name);
-const char *mi_get_main_func();
-mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many);
-int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l);
-mi_chg_reg *mi_get_list_changed_regs(mi_h *h);
-int mi_get_reg_values(mi_h *h, mi_chg_reg *l);
-mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many);
-int gmi_target_download(mi_h *h);
-
-/* Allocation functions: */
-void *mi_calloc(size_t count, size_t sz);
-void *mi_calloc1(size_t sz);
-char *mi_malloc(size_t sz);
-mi_results *mi_alloc_results(void);
-mi_output *mi_alloc_output(void);
-mi_frames *mi_alloc_frames(void);
-mi_gvar *mi_alloc_gvar(void);
-mi_gvar_chg *mi_alloc_gvar_chg(void);
-mi_bkpt *mi_alloc_bkpt(void);
-mi_wp *mi_alloc_wp(void);
-mi_stop *mi_alloc_stop(void);
-mi_asm_insns *mi_alloc_asm_insns(void);
-mi_asm_insn *mi_alloc_asm_insn(void);
-mi_chg_reg *mi_alloc_chg_reg(void);
-void mi_free_output(mi_output *r);
-void mi_free_output_but(mi_output *r, mi_output *no, mi_results *no_r);
-void mi_free_frames(mi_frames *f);
-void mi_free_aux_term(mi_aux_term *t);
-void mi_free_results(mi_results *r);
-void mi_free_results_but(mi_results *r, mi_results *no);
-void mi_free_gvar(mi_gvar *v);
-void mi_free_gvar_chg(mi_gvar_chg *p);
-void mi_free_wp(mi_wp *wp);
-void mi_free_stop(mi_stop *s);
-void mi_free_asm_insns(mi_asm_insns *i);
-void mi_free_asm_insn(mi_asm_insn *i);
-void mi_free_charp_list(char **l);
-void mi_free_chg_reg(mi_chg_reg *r);
-
-/* Porgram control: */
-/* Specify the executable and arguments for local debug. */
-int gmi_set_exec(mi_h *h, const char *file, const char *args);
-/* Start running the executable. Remote sessions starts running. */
-int gmi_exec_run(mi_h *h);
-/* Continue the execution after a "stop". */
-int gmi_exec_continue(mi_h *h);
-/* Indicate which terminal will use the target program. For local sessions. */
-int gmi_target_terminal(mi_h *h, const char *tty_name);
-/* Specify what's the local copy that have debug info. For remote sessions. */
-int gmi_file_symbol_file(mi_h *h, const char *file);
-/* Continue until function return, the return value is included in the async
- response. */
-int gmi_exec_finish(mi_h *h);
-/* Stop the program using SIGINT. */
-int gmi_exec_interrupt(mi_h *h);
-/* Next line of code. */
-int gmi_exec_next(mi_h *h);
-/* Next count lines of code. */
-int gmi_exec_next_cnt(mi_h *h, int count);
-/* Next line of assembler code. */
-int gmi_exec_next_instruction(mi_h *h);
-/* Next line of code. Get inside functions. */
-int gmi_exec_step(mi_h *h);
-/* Next count lines of code. Get inside functions. */
-int gmi_exec_step_cnt(mi_h *h, int count);
-/* Next line of assembler code. Get inside calls. */
-int gmi_exec_step_instruction(mi_h *h);
-/* Execute until location is reached. If file is NULL then is until next line. */
-int gmi_exec_until(mi_h *h, const char *file, int line);
-int gmi_exec_until_addr(mi_h *h, void *addr);
-/* Return to previous frame inmediatly. */
-mi_frames *gmi_exec_return(mi_h *h);
-/* Just kill the program. Please read the notes in prg_control.c. */
-int gmi_exec_kill(mi_h *h);
-
-/* Target manipulation: */
-/* Connect to a remote gdbserver using the specified methode. */
-int gmi_target_select(mi_h *h, const char *type, const char *params);
-/* Attach to an already running process. */
-mi_frames *gmi_target_attach(mi_h *h, pid_t pid);
-/* Detach from an attached process. */
-int gmi_target_detach(mi_h *h);
-
-/* Miscellaneous commands: */
-/* Exit gdb killing the child is it is running. */
-void gmi_gdb_exit(mi_h *h);
-/* Send the version to the console. */
-int gmi_gdb_version(mi_h *h);
-/* Set a gdb variable. */
-int gmi_gdb_set(mi_h *h, const char *var, const char *val);
-/* Get a gdb variable. */
-char *gmi_gdb_show(mi_h *h, const char *var);
-
-/* Breakpoints manipulation: */
-/* Insert a breakpoint at file:line. */
-mi_bkpt *gmi_break_insert(mi_h *h, const char *file, int line);
-/* Insert a breakpoint, all available options. */
-mi_bkpt *gmi_break_insert_full(mi_h *h, int temporary, int hard_assist,
- const char *cond, int count, int thread,
- const char *where);
-mi_bkpt *gmi_break_insert_full_fl(mi_h *h, const char *file, int line,
- int temporary, int hard_assist,
- const char *cond, int count, int thread);
-/* Remove a breakpoint. */
-int gmi_break_delete(mi_h *h, int number);
-/* Free the memory used for a breakpoint description. */
-void mi_free_bkpt(mi_bkpt *b);
-/* Modify the "ignore" count for a breakpoint. */
-int gmi_break_set_times(mi_h *h, int number, int count);
-/* Associate a condition with the breakpoint. */
-int gmi_break_set_condition(mi_h *h, int number, const char *condition);
-/* Enable or disable a breakpoint. */
-int gmi_break_state(mi_h *h, int number, int enable);
-/* Set a watchpoint. It doesn't work for remote targets! */
-mi_wp *gmi_break_watch(mi_h *h, enum mi_wp_mode mode, const char *exp);
-
-/* Data Manipulation. */
-/* Evaluate an expression. Returns a parsed tree. */
-char *gmi_data_evaluate_expression(mi_h *h, const char *expression);
-/* Path for sources. */
-int gmi_dir(mi_h *h, const char *path);
-/* A very limited "data read memory" implementation. */
-int gmi_read_memory(mi_h *h, const char *exp, unsigned size,
- unsigned char *dest, int *na, int convAddr,
- unsigned long *addr);
-mi_asm_insns *gmi_data_disassemble_se(mi_h *h, const char *start,
- const char *end, int mode);
-mi_asm_insns *gmi_data_disassemble_fl(mi_h *h, const char *file, int line,
- int lines, int mode);
-mi_chg_reg *gmi_data_list_register_names(mi_h *h, int *how_many);
-int gmi_data_list_register_names_l(mi_h *h, mi_chg_reg *l);
-mi_chg_reg *gmi_data_list_changed_registers(mi_h *h);
-int gmi_data_list_register_values(mi_h *h, enum mi_gvar_fmt fmt, mi_chg_reg *l);
-mi_chg_reg *gmi_data_list_all_register_values(mi_h *h, enum mi_gvar_fmt fmt, int *how_many);
-
-/* Stack manipulation. */
-/* List of frames. Arguments aren't filled. */
-mi_frames *gmi_stack_list_frames(mi_h *h);
-/* List of frames. Indicating a range. */
-mi_frames *gmi_stack_list_frames_r(mi_h *h, int from, int to);
-/* List arguments. Only level and args filled. */
-mi_frames *gmi_stack_list_arguments(mi_h *h, int show);
-/* List arguments. Indicating a range. Only level and args filled. */
-mi_frames *gmi_stack_list_arguments_r(mi_h *h, int show, int from, int to);
-/* Information about the current frame, including args. */
-mi_frames *gmi_stack_info_frame(mi_h *h);
-/* Stack info depth. error => -1 */
-int gmi_stack_info_depth_get(mi_h *h);
-/* Set stack info depth. error => -1 */
-int gmi_stack_info_depth(mi_h *h, int max_depth);
-/* Change current frame. */
-int gmi_stack_select_frame(mi_h *h, int framenum);
-/* List of local vars. */
-mi_results *gmi_stack_list_locals(mi_h *h, int show);
-
-/* Thread. */
-/* List available thread ids. */
-int gmi_thread_list_ids(mi_h *h, int **list);
-/* Select a thread. */
-mi_frames *gmi_thread_select(mi_h *h, int id);
-/* List available threads. */
-mi_frames *gmi_thread_list_all_threads(mi_h *h);
-
-/* Variable objects. */
-/* Create a variable object. */
-mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp);
-mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp);
-/* Create the variable and also fill the lang and attr fields. */
-mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp);
-/* Delete a variable object. Doesn't free the mi_gvar data. */
-int gmi_var_delete(mi_h *h, mi_gvar *var);
-/* Set the format used to represent the result. */
-int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format);
-/* Fill the format field with info from gdb. */
-int gmi_var_show_format(mi_h *h, mi_gvar *var);
-/* Fill the numchild field with info from gdb. */
-int gmi_var_info_num_children(mi_h *h, mi_gvar *var);
-/* Fill the type field with info from gdb. */
-int gmi_var_info_type(mi_h *h, mi_gvar *var);
-/* Fill the expression and lang fields with info from gdb.
- Note that lang isn't filled during creation. */
-int gmi_var_info_expression(mi_h *h, mi_gvar *var);
-/* Fill the attr field with info from gdb.
- Note that attr isn't filled during creation. */
-int gmi_var_show_attributes(mi_h *h, mi_gvar *var);
-/* Update variable. Use NULL for all.
- Note that *changed can be NULL if none updated. */
-int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed);
-/* Change variable. Fills the value field. */
-int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression);
-/* Get current value for a variable. */
-int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var);
-/* List children. It ONLY returns the first level information. :-( */
-int gmi_var_list_children(mi_h *h, mi_gvar *var);
-
-#ifdef __cplusplus
-};
-
-/* C++ interface */
-
-/*
- State Can:
- disconnected Connect
- connected SelectTarget, Disconnect
- target_specified TargetUnselect, Run, Set breakpoints/watchpoints, etc.
- running Stop
- stopped Kill, Restart?, Step, Trace, Continue, etc.
- [auto exit]
-
- Modes:
- dmX11 Local debug for X11.
- dmLinux Local debug for Linux console.
- dmRemote Remote debug.
-*/
-class MIDebugger
-{
-public:
- MIDebugger();
- ~MIDebugger();
-
- enum eState { disconnected, connected, target_specified, running, stopped };
- enum dMode { dmX11, dmLinux, dmRemote, dmPID };
- enum endianType { enUnknown, enLittle, enBig };
- // Currently tested architectures
- enum archType { arUnknown, arIA32, arSPARC, arPIC14, arAVR, arUnsupported };
-
- int Connect(bool remote=false); /* remote is currently ignored. */
- int Disconnect();
- /* SelectTarget* */
- int SelectTargetX11(const char *exec, const char *args=NULL,
- const char *auxtty=NULL);
- int SelectTargetLinux(const char *exec, const char *args,
- const char *auxtty=NULL);
- int SelectTargetRemote(const char *exec, const char *rparams,
- const char *rtype=NULL, bool download=false);
- // TODO: Linux PIDs can be represented as intergers. What should I use?
- // ato_pid_t doesn't exist ;-)
- mi_frames *SelectTargetPID(const char *exec, int pid);
- int TargetUnselect();
- int Run();
- int Stop();
- int Poll(mi_stop *&rs);
- int Continue();
- int RunOrContinue();
- int Kill();
- mi_bkpt *Breakpoint(const char *file, int line);
- mi_bkpt *Breakpoint(const char *where, bool temporary=false, const char *cond=NULL,
- int count=-1, int thread=-1, bool hard_assist=false);
- mi_bkpt *BreakpointFull(const char *file, int line, bool temporary=false,
- const char *cond=NULL, int count=-1, int thread=-1,
- bool hard_assist=false);
- mi_bkpt *Breakpoint(mi_bkpt *b);
- int BreakDelete(mi_bkpt *b);
- int BreakAfter(mi_bkpt *b)
- {
- if (state!=target_specified && state!=stopped)
- return 0;
- return gmi_break_set_times(h,b->number,b->ignore);
- }
- mi_wp *Watchpoint(enum mi_wp_mode mode, const char *exp);
- int WatchDelete(mi_wp *w);
- int RunToMain();
- int StepOver(bool inst=false);
- int TraceInto(bool inst=false);
- int GoTo(const char *file, int line);
- int GoTo(void *addr);
- int FinishFun();
- mi_frames *ReturnNow();
- mi_frames *CallStack(bool args);
- char *EvalExpression(const char *exp);
- char *ModifyExpression(char *exp, char *newVal);
- mi_gvar *AddgVar(const char *exp, int frame=-1)
- {
- if (state!=stopped)
- return NULL;
- return gmi_full_var_create(h,frame,exp);
- }
- int DelgVar(mi_gvar *var)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_delete(h,var);
- }
- int EvalgVar(mi_gvar *var)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_evaluate_expression(h,var);
- }
- int GetChildgVar(mi_gvar *var)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_list_children(h,var);
- }
- int FillTypeVal(mi_gvar *var);
- int FillOneTypeVal(mi_gvar *var);
- int FillAttr(mi_gvar *var)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_show_attributes(h,var);
- }
- int FillFormat(mi_gvar *var)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_show_format(h,var);
- }
- int SetFormatgVar(mi_gvar *var, enum mi_gvar_fmt format)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_set_format(h,var,format);
- }
- int ListChangedgVar(mi_gvar_chg *&changed)
- {
- if (state!=stopped)
- return 0;
- return gmi_var_update(h,NULL,&changed);
- }
- int AssigngVar(mi_gvar *var, const char *exp);
- int Send(const char *command);
- int Version()
- {
- if (state==running || state==disconnected)
- return 0;
- return gmi_gdb_version(h);
- }
- int PathSources(const char *path)
- {
- if (state==running || state==disconnected)
- return 0;
- return gmi_dir(h,path);
- }
- int ReadMemory(const char *exp, unsigned size, unsigned char *dest,
- int &na, int convAddr, unsigned long *addr)
- {
- if (state!=stopped)
- return 0;
- return gmi_read_memory(h,exp,size,dest,&na,convAddr,addr);
- }
- char *Show(const char *var);
- int ThreadListIDs(int *&list)
- {
- if (state!=stopped)
- return 0;
- return gmi_thread_list_ids(h,&list);
- }
- mi_frames *ThreadList()
- {
- if (state!=stopped)
- return 0;
- return gmi_thread_list_all_threads(h);
- }
- mi_frames *ThreadSelect(int id)
- {
- if (state!=stopped)
- return NULL;
- return gmi_thread_select(h,id);
- }
- mi_asm_insns *Disassemble(const char *start, const char *end, int mode)
- {
- if (state!=stopped)
- return NULL;
- return gmi_data_disassemble_se(h,start,end,mode);
- }
- mi_asm_insns *Disassemble(const char *file, int line, int lines, int mode)
- {
- if (state!=stopped)
- return NULL;
- return gmi_data_disassemble_fl(h,file,line,lines,mode);
- }
- mi_chg_reg *GetRegisterNames(int *how_many)
- {
- if (state!=target_specified && state!=stopped)
- return NULL;
- return gmi_data_list_register_names(h,how_many);
- }
- int GetRegisterNames(mi_chg_reg *chg)
- {
- if (state!=target_specified && state!=stopped)
- return 0;
- return gmi_data_list_register_names_l(h,chg);
- }
- int GetRegisterValues(mi_chg_reg *chg)
- {
- if (state!=stopped)
- return 0;
- return gmi_data_list_register_values(h,fm_natural,chg);
- }
- mi_chg_reg *GetRegisterValues(int *how_many)
- {
- if (state!=stopped)
- return 0;
- return gmi_data_list_all_register_values(h,fm_natural,how_many);
- }
- mi_chg_reg *GetChangedRegisters()
- {
- if (state!=stopped)
- return NULL;
- mi_chg_reg *chg=gmi_data_list_changed_registers(h);
- if (chg && !gmi_data_list_register_values(h,fm_natural,chg))
- {
- mi_free_chg_reg(chg);
- chg=NULL;
- }
- return chg;
- }
- int UpdateRegisters(mi_chg_reg *regs);
-
- endianType GetTargetEndian();
- archType GetTargetArchitecture();
- eState GetState() { return state; }
-
- /* Some wrappers */
- static void SetGDBExe(const char *name) { mi_set_gdb_exe(name); }
- static const char *GetGDBExe() { return mi_get_gdb_exe(); }
- static void SetXTermExe(const char *name) { mi_set_xterm_exe(name); }
- static const char *GetXTermExe() { return mi_get_xterm_exe(); }
- static void SetGDBStartFile(const char *name) { mi_set_gdb_start(name); }
- static const char *GetGDBStartFile() { return mi_get_gdb_start(); }
- static void SetGDBConnFile(const char *name) { mi_set_gdb_conn(name); }
- static const char *GetGDBConnFile() { return mi_get_gdb_conn(); }
- static void SetMainFunc(const char *name) { mi_set_main_func(name); }
- static const char *GetMainFunc() { return mi_get_main_func(); }
-
- static const char *GetErrorStr() { return mi_get_error_str(); }
- static const char *GetGDBError() { return mi_error_from_gdb; }
- static int GetErrorNumber() { return mi_error; }
- int GetErrorNumberSt();
- void SetConsoleCB(stream_cb cb, void *data=NULL)
- { mi_set_console_cb(h,cb,data); }
- void SetTargetCB(stream_cb cb, void *data=NULL)
- { mi_set_target_cb(h,cb,data); }
- void SetLogCB(stream_cb cb, void *data=NULL)
- { mi_set_log_cb(h,cb,data); }
- void SetAsyncCB(async_cb cb, void *data=NULL)
- { mi_set_async_cb(h,cb,data); }
- void SetToGDBCB(stream_cb cb, void *data=NULL)
- { mi_set_to_gdb_cb(h,cb,data); }
- void SetFromGDBCB(stream_cb cb, void *data=NULL)
- { mi_set_from_gdb_cb(h,cb,data); }
- void SetTimeOutCB(tm_cb cb, void *data)
- { mi_set_time_out_cb(h,cb,data); }
- void SetTimeOut(int to)
- { mi_set_time_out(h,to); }
- void ForceMIVersion(unsigned vMajor, unsigned vMiddle, unsigned vMinor)
- { mi_force_version(h,vMajor,vMiddle,vMinor); }
-
- const char *GetAuxTTY()
- { return aux_tty ? aux_tty->tty : NULL; }
-
-protected:
- eState state;
- dMode mode;
- endianType targetEndian;
- archType targetArch;
- bool preRun; // Remote targets starts running but outside main.
- mi_h *h;
- mi_aux_term *aux_tty;
- int waitingTempBkpt;
-
- int SelectTargetTTY(const char *exec, const char *args, const char *auxtty,
- dMode m);
-};
-
-#endif
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Miscellaneous commands.
- Comments:
- GDB/MI commands for the "Miscellaneous Commands" section.@p
-
-@<pre>
-gdb command: Implemented?
-
--gdb-exit Yes
--gdb-set Yes
--gdb-show Yes
--gdb-version Yes
-@</pre>
-
-GDB Bug workaround for "-gdb-show architecture": gdb 6.1 and olders doesn't
-report it in "value", but they give the output of "show architecture". In
-6.4 we observed that not even a clue is reported. So now we always use
-"show architecture".
-
-***************************************************************************/
-
-#include <string.h>
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_gdb_exit(mi_h *h)
-{
- mi_send(h,"-gdb-exit\n");
-}
-
-void mi_gdb_version(mi_h *h)
-{
- mi_send(h,"-gdb-version\n");
-}
-
-void mi_gdb_set(mi_h *h, const char *var, const char *val)
-{
- mi_send(h,"-gdb-set %s %s\n",var,val);
-}
-
-void mi_gdb_show(mi_h *h, const char *var)
-{
- if (strcmp(var,"architecture")==0)
- mi_send(h,"show %s\n",var);
- else
- mi_send(h,"-gdb-show %s\n",var);
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- Exit gdb killing the child is it is running.
-
- Command: -gdb-exit
-
-***************************************************************************/
-
-void gmi_gdb_exit(mi_h *h)
-{
- mi_gdb_exit(h);
- mi_res_simple_exit(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Send the version to the console.
-
- Command: -gdb-version
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_gdb_version(mi_h *h)
-{
- mi_gdb_version(h);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Set a gdb variable.
-
- Command: -gdb-set
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_gdb_set(mi_h *h, const char *var, const char *val)
-{
- mi_gdb_set(h,var,val);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Get a gdb variable.
-
- Command: -gdb-show
- Return: The current value of the variable or NULL on error.
-
-***************************************************************************/
-
-char *gmi_gdb_show(mi_h *h, const char *var)
-{
- mi_gdb_show(h,var);
- return mi_res_value(h);
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004-2007 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Parser.
- Comments:
- Parses the output of gdb. It basically converts the text from gdb into a
-tree (could be a complex one) that we can easily interpret using C code.
-
-***************************************************************************/
-
-#include <ctype.h>
-#include <string.h>
-#include <assert.h>
-#include "mi_gdb.h"
-
-mi_results *mi_get_result(const char *str, const char **end);
-int mi_get_value(mi_results *r, const char *str, const char **end);
-
-
-/* GDB BUG!!!! I got:
-^error,msg="Problem parsing arguments: data-evaluate-expression ""1+2"""
-Afects gdb 2002-04-01-cvs and 6.1.1 for sure.
-That's an heuristical workaround.
-*/
-static inline
-int EndOfStr(const char *s)
-{
- if (*s=='"')
- {
- s++;
- return !*s || *s==',' || *s==']' || *s=='}';
- }
- return 0;
-}
-
-int mi_get_cstring_r(mi_results *r, const char *str, const char **end)
-{
- const char *s;
- char *d;
- int len;
-
- if (*str!='"')
- {
- mi_error=MI_PARSER;
- return 0;
- }
- str++;
- /* Meassure. */
- for (s=str, len=0; *s && !EndOfStr(s); s++)
- {
- if (*s=='\\')
- {
- if (!*s)
- {
- mi_error=MI_PARSER;
- return 0;
- }
- s++;
- }
- len++;
- }
- /* Copy. */
- r->type=t_const;
- d=r->v.cstr=mi_malloc(len+1);
- if (!r->v.cstr)
- return 0;
- for (s=str; *s && !EndOfStr(s); s++, d++)
- {
- if (*s=='\\')
- {
- s++;
- switch (*s)
- {
- case 'n':
- *d='\n';
- break;
- case 't':
- *d='\t';
- break;
- default:
- *d=*s;
- }
- }
- else
- *d=*s;
- }
- *d=0;
- if (end)
- *end=s+1;
-
- return 1;
-}
-
-/* TODO: What's a valid variable name?
- I'll assume a-zA-Z0-9_- */
-inline
-int mi_is_var_name_char(char c)
-{
- return isalnum(c) || c=='-' || c=='_';
-}
-
-char *mi_get_var_name(const char *str, const char **end)
-{
- const char *s;
- char *r;
- int l;
- /* Meassure. */
- for (s=str; *s && mi_is_var_name_char(*s); s++);
- if (*s!='=')
- {
- mi_error=MI_PARSER;
- return NULL;
- }
- /* Allocate. */
- l=s-str;
- r=mi_malloc(l+1);
- /* Copy. */
- memcpy(r,str,l);
- r[l]=0;
- if (end)
- *end=s+1;
- return r;
-}
-
-
-int mi_get_list_res(mi_results *r, const char *str, const char **end, char closeC)
-{
- mi_results *last_r, *rs;
-
- last_r=NULL;
- do
- {
- rs=mi_get_result(str,&str);
- if (last_r)
- last_r->next=rs;
- else
- r->v.rs=rs;
- last_r=rs;
- if (*str==closeC)
- {
- *end=str+1;
- return 1;
- }
- if (*str!=',')
- break;
- str++;
- }
- while (1);
-
- mi_error=MI_PARSER;
- return 0;
-}
-
-#ifdef __APPLE__
-int mi_get_tuple_val(mi_results *r, const char *str, const char **end)
-{
- mi_results *last_r, *rs;
-
- last_r=NULL;
- do
- {
- rs=mi_alloc_results();
- if (!rs || !mi_get_value(rs,str,&str))
- {
- mi_free_results(rs);
- return 0;
- }
- /* Note that rs->var is NULL, that indicates that's just a value and not
- a result. */
- if (last_r)
- last_r->next=rs;
- else
- r->v.rs=rs;
- last_r=rs;
- if (*str=='}')
- {
- *end=str+1;
- return 1;
- }
- if (*str!=',')
- break;
- str++;
- }
- while (1);
-
- mi_error=MI_PARSER;
- return 0;
-}
-#endif /* __APPLE__ */
-
-int mi_get_tuple(mi_results *r, const char *str, const char **end)
-{
- if (*str!='{')
- {
- mi_error=MI_PARSER;
- return 0;
- }
- r->type=t_tuple;
- str++;
- if (*str=='}')
- {/* Special case: empty tuple */
- *end=str+1;
- return 1;
- }
- #ifdef __APPLE__
- if (mi_is_var_name_char(*str))
- return mi_get_list_res(r,str,end,'}');
- return mi_get_tuple_val(r,str,end);
- #else /* __APPLE__ */
- return mi_get_list_res(r,str,end,'}');
- #endif /* __APPLE__ */
-}
-
-int mi_get_list_val(mi_results *r, const char *str, const char **end)
-{
- mi_results *last_r, *rs;
-
- last_r=NULL;
- do
- {
- rs=mi_alloc_results();
- if (!rs || !mi_get_value(rs,str,&str))
- {
- mi_free_results(rs);
- return 0;
- }
- /* Note that rs->var is NULL, that indicates that's just a value and not
- a result. */
- if (last_r)
- last_r->next=rs;
- else
- r->v.rs=rs;
- last_r=rs;
- if (*str==']')
- {
- *end=str+1;
- return 1;
- }
- if (*str!=',')
- break;
- str++;
- }
- while (1);
-
- mi_error=MI_PARSER;
- return 0;
-}
-
-int mi_get_list(mi_results *r, const char *str, const char **end)
-{
- if (*str!='[')
- {
- mi_error=MI_PARSER;
- return 0;
- }
- r->type=t_list;
- str++;
- if (*str==']')
- {/* Special case: empty list */
- *end=str+1;
- return 1;
- }
- /* Comment: I think they could choose () for values. Is confusing in this way. */
- if (mi_is_var_name_char(*str))
- return mi_get_list_res(r,str,end,']');
- return mi_get_list_val(r,str,end);
-}
-
-int mi_get_value(mi_results *r, const char *str, const char **end)
-{
- switch (str[0])
- {
- case '"':
- return mi_get_cstring_r(r,str,end);
- case '{':
- return mi_get_tuple(r,str,end);
- case '[':
- return mi_get_list(r,str,end);
- }
- mi_error=MI_PARSER;
- return 0;
-}
-
-mi_results *mi_get_result(const char *str, const char **end)
-{
- char *var;
- mi_results *r;
-
- var=mi_get_var_name(str,&str);
- if (!var)
- return NULL;
-
- r=mi_alloc_results();
- if (!r)
- {
- free(var);
- return NULL;
- }
- r->var=var;
-
- if (!mi_get_value(r,str,end))
- {
- mi_free_results(r);
- return NULL;
- }
-
- return r;
-}
-
-mi_output *mi_get_results_alone(mi_output *r,const char *str)
-{
- mi_results *last_r, *rs;
-
- /* * results */
- last_r=NULL;
- do
- {
- if (!*str)
- return r;
- if (*str!=',')
- {
- mi_error=MI_PARSER;
- break;
- }
- str++;
- rs=mi_get_result(str,&str);
- if (!rs)
- break;
- if (!last_r)
- r->c=rs;
- else
- last_r->next=rs;
- last_r=rs;
- }
- while (1);
- mi_free_output(r);
- return NULL;
-}
-
-mi_output *mi_parse_result_record(mi_output *r,const char *str)
-{
- r->type=MI_T_RESULT_RECORD;
-
- /* Solve the result-class. */
- if (strncmp(str,"done",4)==0)
- {
- str+=4;
- r->tclass=MI_CL_DONE;
- }
- else if (strncmp(str,"running",7)==0)
- {
- str+=7;
- r->tclass=MI_CL_RUNNING;
- }
- else if (strncmp(str,"connected",9)==0)
- {
- str+=9;
- r->tclass=MI_CL_CONNECTED;
- }
- else if (strncmp(str,"error",5)==0)
- {
- str+=5;
- r->tclass=MI_CL_ERROR;
- }
- else if (strncmp(str,"exit",4)==0)
- {
- str+=4;
- r->tclass=MI_CL_EXIT;
- }
- else
- {
- mi_error=MI_UNKNOWN_RESULT;
- return NULL;
- }
-
- return mi_get_results_alone(r,str);
-}
-
-mi_output *mi_parse_asyn(mi_output *r,const char *str)
-{
- r->type=MI_T_OUT_OF_BAND;
- r->stype=MI_ST_ASYNC;
- /* async-class. */
- if (strncmp(str,"stopped",7)==0)
- {
- r->tclass=MI_CL_STOPPED;
- str+=7;
- return mi_get_results_alone(r,str);
- }
- if (strncmp(str,"download",8)==0)
- {
- r->tclass=MI_CL_DOWNLOAD;
- str+=8;
- return mi_get_results_alone(r,str);
- }
- mi_error=MI_UNKNOWN_ASYNC;
- mi_free_output(r);
- return NULL;
-}
-
-mi_output *mi_parse_exec_asyn(mi_output *r,const char *str)
-{
- r->sstype=MI_SST_EXEC;
- return mi_parse_asyn(r,str);
-}
-
-mi_output *mi_parse_status_asyn(mi_output *r,const char *str)
-{
- r->sstype=MI_SST_STATUS;
- return mi_parse_asyn(r,str);
-}
-
-mi_output *mi_parse_notify_asyn(mi_output *r,const char *str)
-{
- r->sstype=MI_SST_NOTIFY;
- return mi_parse_asyn(r,str);
-}
-
-mi_output *mi_console(mi_output *r,const char *str)
-{
- r->type=MI_T_OUT_OF_BAND;
- r->stype=MI_ST_STREAM;
- r->c=mi_alloc_results();
- if (!r->c || !mi_get_cstring_r(r->c,str,NULL))
- {
- mi_free_output(r);
- return NULL;
- }
- return r;
-}
-
-mi_output *mi_console_stream(mi_output *r,const char *str)
-{
- r->sstype=MI_SST_CONSOLE;
- return mi_console(r,str);
-}
-
-mi_output *mi_target_stream(mi_output *r,const char *str)
-{
- r->sstype=MI_SST_TARGET;
- return mi_console(r,str);
-}
-
-mi_output *mi_log_stream(mi_output *r,const char *str)
-{
- r->sstype=MI_SST_LOG;
- return mi_console(r,str);
-}
-
-mi_output *mi_parse_gdb_output(const char *str)
-{
- char type=str[0];
-
- mi_output *r=mi_alloc_output();
- if (!r)
- {
- mi_error=MI_OUT_OF_MEMORY;
- return NULL;
- }
- str++;
- switch (type)
- {
- case '^':
- return mi_parse_result_record(r,str);
- case '*':
- return mi_parse_exec_asyn(r,str);
- case '+':
- return mi_parse_status_asyn(r,str);
- case '=':
- return mi_parse_notify_asyn(r,str);
- case '~':
- return mi_console_stream(r,str);
- case '@':
- return mi_target_stream(r,str);
- case '&':
- return mi_log_stream(r,str);
- }
- mi_error=MI_PARSER;
- return NULL;
-}
-
-mi_output *mi_get_rrecord(mi_output *r)
-{
- if (!r)
- return NULL;
- while (r)
- {
- if (r->type==MI_T_RESULT_RECORD)
- return r;
- r=r->next;
- }
- return r;
-}
-
-mi_results *mi_get_var_r(mi_results *r, const char *var)
-{
- while (r)
- {
- if (strcmp(r->var,var)==0)
- return r;
- r=r->next;
- }
- return NULL;
-}
-
-mi_results *mi_get_var(mi_output *res, const char *var)
-{
- if (!res)
- return NULL;
- return mi_get_var_r(res->c,var);
-}
-
-int mi_get_async_stop_reason(mi_output *r, char **reason)
-{
- int found_stopped=0;
-
- *reason=NULL;
- while (r)
- {
- if (r->type==MI_T_RESULT_RECORD && r->tclass==MI_CL_ERROR)
- {
- if (r->c->type==t_const)
- *reason=r->c->v.cstr;
- return 0;
- }
- if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
- r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
- {
- mi_results *p=r->c;
- found_stopped=1;
- while (p)
- {
- if (strcmp(p->var,"reason")==0)
- {
- *reason=p->v.cstr;
- return 1;
- }
- p=p->next;
- }
- }
- r=r->next;
- }
- if (*reason==NULL && found_stopped)
- {
- *reason=strdup("unknown (temp bkpt?)");
- return 1;
- }
- return 0;
-}
-
-mi_frames *mi_get_async_frame(mi_output *r)
-{
- while (r)
- {
- if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
- r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
- {
- mi_results *p=r->c;
- while (p)
- {
- if (strcmp(p->var,"frame")==0)
- return mi_parse_frame(p->v.rs);
- p=p->next;
- }
- }
- r=r->next;
- }
- return NULL;
-}
-
-int mi_res_simple(mi_h *h, int tclass, int accert_ret)
-{
- mi_output *r, *res;
- int ret=0;
-
- r=mi_get_response_blk(h);
- res=mi_get_rrecord(r);
-
- if (res)
- ret=res->tclass==tclass;
- mi_free_output(r);
-
- return ret;
-}
-
-
-int mi_res_simple_done(mi_h *h)
-{
- return mi_res_simple(h,MI_CL_DONE,0);
-}
-
-int mi_res_simple_exit(mi_h *h)
-{
- return mi_res_simple(h,MI_CL_EXIT,1);
-}
-
-int mi_res_simple_running(mi_h *h)
-{
- return mi_res_simple(h,MI_CL_RUNNING,0);
-}
-
-int mi_res_simple_connected(mi_h *h)
-{
- return mi_res_simple(h,MI_CL_CONNECTED,0);
-}
-
-mi_results *mi_res_var(mi_h *h, const char *var, int tclass)
-{
- mi_output *r, *res;
- mi_results *the_var=NULL;
-
- r=mi_get_response_blk(h);
- /* All the code that follows is "NULL" tolerant. */
- /* Look for the result-record. */
- res=mi_get_rrecord(r);
- /* Look for the desired var. */
- if (res && res->tclass==tclass)
- the_var=mi_get_var(res,var);
- /* Release all but the one we want. */
- mi_free_output_but(r,NULL,the_var);
- return the_var;
-}
-
-mi_results *mi_res_done_var(mi_h *h, const char *var)
-{
- return mi_res_var(h,var,MI_CL_DONE);
-}
-
-mi_frames *mi_parse_frame(mi_results *c)
-{
- mi_frames *res=mi_alloc_frames();
- char *end;
-
- if (res)
- {
- while (c)
- {
- if (c->type==t_const)
- {
- if (strcmp(c->var,"level")==0)
- res->level=atoi(c->v.cstr);
- else if (strcmp(c->var,"addr")==0)
- res->addr=(void *)strtoul(c->v.cstr,&end,0);
- else if (strcmp(c->var,"func")==0)
- {
- res->func=c->v.cstr;
- c->v.cstr=NULL;
- }
- else if (strcmp(c->var,"file")==0)
- {
- res->file=c->v.cstr;
- c->v.cstr=NULL;
- }
- else if (strcmp(c->var,"from")==0)
- {
- res->from=c->v.cstr;
- c->v.cstr=NULL;
- }
- else if (strcmp(c->var,"line")==0)
- res->line=atoi(c->v.cstr);
- }
- else if (c->type==t_list && strcmp(c->var,"args")==0)
- {
- res->args=c->v.rs;
- c->v.rs=NULL;
- }
- c=c->next;
- }
- }
- return res;
-}
-
-mi_frames *mi_res_frame(mi_h *h)
-{
- mi_results *r=mi_res_done_var(h,"frame");
- mi_frames *f=NULL;
-
- if (r && r->type==t_tuple)
- f=mi_parse_frame(r->v.rs);
- mi_free_results(r);
- return f;
-}
-
-mi_frames *mi_res_frames_array(mi_h *h, const char *var)
-{
- mi_results *r=mi_res_done_var(h,var), *c;
- mi_frames *res=NULL, *nframe, *last=NULL;
-
- if (!r)
- return NULL;
-#ifdef __APPLE__
- if (r->type!=t_list && r->type!=t_tuple)
-#else
- if (r->type!=t_list)
-#endif
- {
- mi_free_results(r);
- return NULL;
- }
- c=r->v.rs;
- while (c)
- {
- if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
- {
- nframe=mi_parse_frame(c->v.rs);
- if (nframe)
- {
- if (!last)
- res=nframe;
- else
- last->next=nframe;
- last=nframe;
- }
- }
- c=c->next;
- }
- mi_free_results(r);
- return res;
-}
-
-mi_frames *mi_res_frames_list(mi_h *h)
-{
- mi_output *r, *res;
- mi_frames *ret=NULL, *nframe, *last=NULL;
- mi_results *c;
-
- r=mi_get_response_blk(h);
- res=mi_get_rrecord(r);
- if (res && res->tclass==MI_CL_DONE)
- {
- c=res->c;
- while (c)
- {
- if (strcmp(c->var,"frame")==0 && c->type==t_tuple)
- {
- nframe=mi_parse_frame(c->v.rs);
- if (nframe)
- {
- if (!last)
- ret=nframe;
- else
- last->next=nframe;
- last=nframe;
- }
- }
- c=c->next;
- }
- }
- mi_free_output(r);
- return ret;
-}
-
-int mi_get_thread_ids(mi_output *res, int **list)
-{
- mi_results *vids, *lids;
- int ids=-1, i;
-
- *list=NULL;
- vids=mi_get_var(res,"number-of-threads");
- lids=mi_get_var(res,"thread-ids");
- if (vids && vids->type==t_const &&
- lids && lids->type==t_tuple)
- {
- ids=atoi(vids->v.cstr);
- if (ids)
- {
- int *lst;
- lst=(int *)mi_calloc(ids,sizeof(int));
- if (lst)
- {
- lids=lids->v.rs;
- i=0;
- while (lids)
- {
- if (strcmp(lids->var,"thread-id")==0 && lids->type==t_const)
- lst[i++]=atoi(lids->v.cstr);
- lids=lids->next;
- }
- *list=lst;
- }
- else
- ids=-1;
- }
- }
- return ids;
-}
-
-int mi_res_thread_ids(mi_h *h, int **list)
-{
- mi_output *r, *res;
- int ids=-1;
-
- r=mi_get_response_blk(h);
- res=mi_get_rrecord(r);
- if (res && res->tclass==MI_CL_DONE)
- ids=mi_get_thread_ids(res,list);
- mi_free_output(r);
- return ids;
-}
-
-enum mi_gvar_lang mi_lang_str_to_enum(const char *lang)
-{
- enum mi_gvar_lang lg=lg_unknown;
-
- if (strcmp(lang,"C")==0)
- lg=lg_c;
- else if (strcmp(lang,"C++")==0)
- lg=lg_cpp;
- else if (strcmp(lang,"Java")==0)
- lg=lg_java;
-
- return lg;
-}
-
-const char *mi_lang_enum_to_str(enum mi_gvar_lang lang)
-{
- const char *lg;
-
- switch (lang)
- {
- case lg_c:
- lg="C";
- break;
- case lg_cpp:
- lg="C++";
- break;
- case lg_java:
- lg="Java";
- break;
- /*case lg_unknown:*/
- default:
- lg="unknown";
- break;
- }
- return lg;
-}
-
-enum mi_gvar_fmt mi_format_str_to_enum(const char *format)
-{
- enum mi_gvar_fmt fmt=fm_natural;
-
- if (strcmp(format,"binary")==0)
- fmt=fm_binary;
- else if (strcmp(format,"decimal")==0)
- fmt=fm_decimal;
- else if (strcmp(format,"hexadecimal")==0)
- fmt=fm_hexadecimal;
- else if (strcmp(format,"octal")==0)
- fmt=fm_octal;
-
- return fmt;
-}
-
-const char *mi_format_enum_to_str(enum mi_gvar_fmt format)
-{
- const char *fmt;
-
- switch (format)
- {
- case fm_natural:
- fmt="natural";
- break;
- case fm_binary:
- fmt="binary";
- break;
- case fm_decimal:
- fmt="decimal";
- break;
- case fm_hexadecimal:
- fmt="hexadecimal";
- break;
- case fm_octal:
- fmt="octal";
- break;
- case fm_raw:
- fmt="raw";
- break;
- default:
- fmt="unknown";
- }
- return fmt;
-}
-
-char mi_format_enum_to_char(enum mi_gvar_fmt format)
-{
- char fmt;
-
- switch (format)
- {
- case fm_natural:
- fmt='N';
- break;
- case fm_binary:
- fmt='t';
- break;
- case fm_decimal:
- fmt='d';
- break;
- case fm_hexadecimal:
- fmt='x';
- break;
- case fm_octal:
- fmt='o';
- break;
- case fm_raw:
- fmt='r';
- break;
- default:
- fmt=' ';
- }
- return fmt;
-}
-
-mi_gvar *mi_get_gvar(mi_output *o, mi_gvar *cur, const char *expression)
-{
- mi_results *r;
- mi_gvar *res=cur ? cur : mi_alloc_gvar();
- int l;
-
- if (!res)
- return res;
- r=o->c;
- if (expression)
- res->exp=strdup(expression);
- while (r)
- {
- if (r->type==t_const)
- {
- if (strcmp(r->var,"name")==0)
- {
- free(res->name);
- res->name=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"numchild")==0)
- {
- res->numchild=atoi(r->v.cstr);
- }
- else if (strcmp(r->var,"type")==0)
- {
- free(res->type);
- res->type=r->v.cstr;
- r->v.cstr=NULL;
- l=strlen(res->type);
- if (l && res->type[l-1]=='*')
- res->ispointer=1;
- }
- else if (strcmp(r->var,"lang")==0)
- {
- res->lang=mi_lang_str_to_enum(r->v.cstr);
- }
- else if (strcmp(r->var,"exp")==0)
- {
- free(res->exp);
- res->exp=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"format")==0)
- {
- res->format=mi_format_str_to_enum(r->v.cstr);
- }
- else if (strcmp(r->var,"attr")==0)
- { /* Note: gdb 6.1.1 have only this: */
- if (strcmp(r->v.cstr,"editable")==0)
- res->attr=MI_ATTR_EDITABLE;
- else /* noneditable */
- res->attr=MI_ATTR_NONEDITABLE;
- }
- }
- r=r->next;
- }
- return res;
-}
-
-mi_gvar *mi_res_gvar(mi_h *h, mi_gvar *cur, const char *expression)
-{
- mi_output *r, *res;
- mi_gvar *gvar=NULL;
-
- r=mi_get_response_blk(h);
- res=mi_get_rrecord(r);
- if (res && res->tclass==MI_CL_DONE)
- gvar=mi_get_gvar(res,cur,expression);
- mi_free_output(r);
- return gvar;
-}
-
-mi_gvar_chg *mi_get_gvar_chg(mi_results *r)
-{
- mi_gvar_chg *n;
-
- if (r->type!=t_const)
- return NULL;
- n=mi_alloc_gvar_chg();
- if (n)
- {
- while (r)
- {
- if (r->type==t_const)
- {
- if (strcmp(r->var,"name")==0)
- {
- n->name=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"in_scope")==0)
- {
- n->in_scope=strcmp(r->v.cstr,"true")==0;
- }
- else if (strcmp(r->var,"new_type")==0)
- {
- n->new_type=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"new_num_children")==0)
- {
- n->new_num_children=atoi(r->v.cstr);
- }
- // type_changed="false" is the default
- }
- r=r->next;
- }
- }
- return n;
-}
-
-int mi_res_changelist(mi_h *h, mi_gvar_chg **changed)
-{
- mi_gvar_chg *last, *n;
- mi_results *res=mi_res_done_var(h,"changelist"), *r;
- int count=0;
-
- *changed=NULL;
- if (!res)
- return 0;
- last=NULL;
- count=1;
- n=NULL;
- r=res->v.rs;
-
- if (res->type==t_list)
- {// MI v2 a list of tuples
- while (r)
- {
- if (r->type==t_tuple)
- {
- n=mi_get_gvar_chg(r->v.rs);
- if (n)
- {
- if (last)
- last->next=n;
- else
- *changed=n;
- last=n;
- count++;
- }
- }
- r=r->next;
- }
- }
- else if (res->type==t_tuple)
- {// MI v1 a tuple with all together *8-P
- while (r)
- {
- if (r->type==t_const) /* Just in case. */
- {/* Get one var. */
- if (strcmp(r->var,"name")==0)
- {
- if (n)
- {/* Add to the list*/
- if (last)
- last->next=n;
- else
- *changed=n;
- last=n;
- count++;
- }
- n=mi_alloc_gvar_chg();
- if (!n)
- {
- mi_free_gvar_chg(*changed);
- return 0;
- }
- n->name=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"in_scope")==0)
- {
- n->in_scope=strcmp(r->v.cstr,"true")==0;
- }
- else if (strcmp(r->var,"new_type")==0)
- {
- n->new_type=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"new_num_children")==0)
- {
- n->new_num_children=atoi(r->v.cstr);
- }
- // type_changed="false" is the default
- }
- r=r->next;
- }
- if (n)
- {/* Add to the list*/
- if (last)
- last->next=n;
- else
- *changed=n;
- last=n;
- count++;
- }
- }
- mi_free_results(res);
-
- return count;
-}
-
-int mi_get_children(mi_results *ch, mi_gvar *v)
-{
- mi_gvar *cur=NULL, *aux;
- int i=0, count=v->numchild, l;
-
- while (ch)
- {
- if (strcmp(ch->var,"child")==0 && ch->type==t_tuple && i<count)
- {
- mi_results *r=ch->v.rs;
- aux=mi_alloc_gvar();
- if (!aux)
- return 0;
- if (!v->child)
- v->child=aux;
- else
- cur->next=aux;
- cur=aux;
- cur->parent=v;
- cur->depth=v->depth+1;
-
- while (r)
- {
- if (r->type==t_const)
- {
- if (strcmp(r->var,"name")==0)
- {
- cur->name=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"exp")==0)
- {
- cur->exp=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"type")==0)
- {
- cur->type=r->v.cstr;
- r->v.cstr=NULL;
- l=strlen(cur->type);
- if (l && cur->type[l-1]=='*')
- cur->ispointer=1;
- }
- else if (strcmp(r->var,"value")==0)
- {
- cur->value=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"numchild")==0)
- {
- cur->numchild=atoi(r->v.cstr);
- }
- }
- r=r->next;
- }
- i++;
- }
- ch=ch->next;
- }
- v->vischild=i;
- v->opened=1;
- return i==v->numchild;
-}
-
-int mi_res_children(mi_h *h, mi_gvar *v)
-{
- mi_output *r, *res;
- int ok=0;
-
- r=mi_get_response_blk(h);
- res=mi_get_rrecord(r);
- if (res && res->tclass==MI_CL_DONE)
- {
- mi_results *num=mi_get_var(res,"numchild");
- if (num && num->type==t_const)
- {
- v->numchild=atoi(num->v.cstr);
- if (v->child)
- {
- mi_free_gvar(v->child);
- v->child=NULL;
- }
- if (v->numchild)
- {
- mi_results *ch =mi_get_var(res,"children");
- if (ch && ch->type!=t_const) /* MI v1 tuple, MI v2 list */
- ok=mi_get_children(ch->v.rs,v);
- }
- else
- ok=1;
- }
- }
- mi_free_output(r);
- return ok;
-}
-
-mi_bkpt *mi_get_bkpt(mi_results *p)
-{
- mi_bkpt *res;
- char *end;
-
- res=mi_alloc_bkpt();
- if (!res)
- return NULL;
- while (p)
- {
- if (p->type==t_const && p->var)
- {
- if (strcmp(p->var,"number")==0)
- res->number=atoi(p->v.cstr);
- else if (strcmp(p->var,"type")==0)
- {
- if (strcmp(p->v.cstr,"breakpoint")==0)
- res->type=t_breakpoint;
- else
- res->type=t_unknown;
- }
- else if (strcmp(p->var,"disp")==0)
- {
- if (strcmp(p->v.cstr,"keep")==0)
- res->disp=d_keep;
- else if (strcmp(p->v.cstr,"del")==0)
- res->disp=d_del;
- else
- res->disp=d_unknown;
- }
- else if (strcmp(p->var,"enabled")==0)
- res->enabled=p->v.cstr[0]=='y';
- else if (strcmp(p->var,"addr")==0)
- res->addr=(void *)strtoul(p->v.cstr,&end,0);
- else if (strcmp(p->var,"func")==0)
- {
- res->func=p->v.cstr;
- p->v.cstr=NULL;
- }
- else if (strcmp(p->var,"file")==0)
- {
- res->file=p->v.cstr;
- p->v.cstr=NULL;
- }
- else if (strcmp(p->var,"line")==0)
- res->line=atoi(p->v.cstr);
- else if (strcmp(p->var,"times")==0)
- res->times=atoi(p->v.cstr);
- else if (strcmp(p->var,"ignore")==0)
- res->ignore=atoi(p->v.cstr);
- else if (strcmp(p->var,"cond")==0)
- {
- res->cond=p->v.cstr;
- p->v.cstr=NULL;
- }
- }
- p=p->next;
- }
- return res;
-}
-
-mi_bkpt *mi_res_bkpt(mi_h *h)
-{
- mi_results *r=mi_res_done_var(h,"bkpt");
- mi_bkpt *b=NULL;
-
- if (r && r->type==t_tuple)
- b=mi_get_bkpt(r->v.rs);
- mi_free_results(r);
- return b;
-}
-
-mi_wp *mi_get_wp(mi_results *p, enum mi_wp_mode m)
-{
- mi_wp *res=mi_alloc_wp();
-
- if (res)
- {
- res->mode=m;
- while (p)
- {
- if (p->type==t_const && p->var)
- {
- if (strcmp(p->var,"number")==0)
- {
- res->number=atoi(p->v.cstr);
- res->enabled=1;
- }
- else if (strcmp(p->var,"exp")==0)
- {
- res->exp=p->v.cstr;
- p->v.cstr=NULL;
- }
- }
- p=p->next;
- }
- }
- return res;
-}
-
-mi_wp *mi_parse_wp_res(mi_output *r)
-{
- mi_results *p;
- enum mi_wp_mode m=wm_unknown;
-
- /* The info is in a result wpt=... */
- p=r->c;
- while (p)
- {
- if (p->var)
- {
- if (strcmp(p->var,"wpt")==0)
- m=wm_write;
- else if (strcmp(p->var,"hw-rwpt")==0)
- m=wm_read;
- else if (strcmp(p->var,"hw-awpt")==0)
- m=wm_rw;
- if (m!=wm_unknown)
- break;
- }
- p=p->next;
- }
- if (!p || p->type!=t_tuple)
- return NULL;
- /* Scan the values inside it. */
- return mi_get_wp(p->v.rs,m);
-}
-
-mi_wp *mi_res_wp(mi_h *h)
-{
- mi_output *r, *res;
- mi_wp *ret=NULL;
-
- r=mi_get_response_blk(h);
- res=mi_get_rrecord(r);
-
- if (res)
- ret=mi_parse_wp_res(res);
-
- mi_free_output(r);
- return ret;
-}
-
-char *mi_res_value(mi_h *h)
-{
- mi_results *r=mi_res_done_var(h,"value");
- char *s=NULL;
-
- if (r && r->type==t_const)
- {
- s=r->v.cstr;
- r->v.rs=NULL;
- }
- mi_free_results(r);
- return s;
-}
-
-mi_output *mi_get_stop_record(mi_output *r)
-{
- while (r)
- {
- if (r->type==MI_T_OUT_OF_BAND && r->stype==MI_ST_ASYNC &&
- r->sstype==MI_SST_EXEC && r->tclass==MI_CL_STOPPED)
- return r;
- r=r->next;
- }
- return r;
-}
-
-static
-char *reason_names[]=
-{
- "breakpoint-hit",
- "watchpoint-trigger",
- "read-watchpoint-trigger",
- "access-watchpoint-trigger",
- "watchpoint-scope",
- "function-finished",
- "location-reached",
- "end-stepping-range",
- "exited-signalled",
- "exited",
- "exited-normally",
- "signal-received"
-};
-
-static
-enum mi_stop_reason reason_values[]=
-{
- sr_bkpt_hit,
- sr_wp_trigger, sr_read_wp_trigger, sr_access_wp_trigger, sr_wp_scope,
- sr_function_finished, sr_location_reached, sr_end_stepping_range,
- sr_exited_signalled, sr_exited, sr_exited_normally,
- sr_signal_received
-};
-
-static
-char *reason_expl[]=
-{
- "Hit a breakpoint",
- "Write watchpoint",
- "Read watchpoint",
- "Access watchpoint",
- "Watchpoint out of scope",
- "Function finished",
- "Location reached",
- "End of stepping",
- "Exited signalled",
- "Exited with error",
- "Exited normally",
- "Signal received"
-};
-
-enum mi_stop_reason mi_reason_str_to_enum(const char *s)
-{
- int i;
-
- for (i=0; i<sizeof(reason_names)/sizeof(char *); i++)
- if (strcmp(reason_names[i],s)==0)
- return reason_values[i];
- return sr_unknown;
-}
-
-const char *mi_reason_enum_to_str(enum mi_stop_reason r)
-{
- int i;
-
- if (r==sr_unknown)
- return "Unknown (temp bkp?)";
- for (i=0; i<sizeof(reason_values)/sizeof(char *); i++)
- if (reason_values[i]==r)
- return reason_expl[i];
- return NULL;
-}
-
-mi_stop *mi_get_stopped(mi_results *r)
-{
- mi_stop *res=mi_alloc_stop();
-
- if (res)
- {
- while (r)
- {
- if (r->type==t_const)
- {
- if (strcmp(r->var,"reason")==0)
- res->reason=mi_reason_str_to_enum(r->v.cstr);
- else if (!res->have_thread_id && strcmp(r->var,"thread-id")==0)
- {
- res->have_thread_id=1;
- res->thread_id=atoi(r->v.cstr);
- }
- else if (!res->have_bkptno && strcmp(r->var,"bkptno")==0)
- {
- res->have_bkptno=1;
- res->bkptno=atoi(r->v.cstr);
- }
- else if (!res->have_bkptno && strcmp(r->var,"wpnum")==0)
- {
- res->have_wpno=1;
- res->wpno=atoi(r->v.cstr);
- }
- else if (strcmp(r->var,"gdb-result-var")==0)
- {
- res->gdb_result_var=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"return-value")==0)
- {
- res->return_value=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"signal-name")==0)
- {
- res->signal_name=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (strcmp(r->var,"signal-meaning")==0)
- {
- res->signal_meaning=r->v.cstr;
- r->v.cstr=NULL;
- }
- else if (!res->have_exit_code && strcmp(r->var,"exit-code")==0)
- {
- res->have_exit_code=1;
- res->exit_code=atoi(r->v.cstr);
- }
- }
- else // tuple or list
- {
- if (strcmp(r->var,"frame")==0)
- res->frame=mi_parse_frame(r->v.rs);
- else if (!res->wp && strcmp(r->var,"wpt")==0)
- res->wp=mi_get_wp(r->v.rs,wm_write);
- else if (!res->wp && strcmp(r->var,"hw-rwpt")==0)
- res->wp=mi_get_wp(r->v.rs,wm_read);
- else if (!res->wp && strcmp(r->var,"hw-awpt")==0)
- res->wp=mi_get_wp(r->v.rs,wm_rw);
- else if (!(res->wp_old || res->wp_val) && strcmp(r->var,"value")==0)
- {
- mi_results *p=r->v.rs;
- while (p)
- {
- if (strcmp(p->var,"value")==0 || strcmp(p->var,"new")==0)
- {
- res->wp_val=p->v.cstr;
- p->v.cstr=NULL;
- }
- else if (strcmp(p->var,"old")==0)
- {
- res->wp_old=p->v.cstr;
- p->v.cstr=NULL;
- }
- p=p->next;
- }
- }
- }
- r=r->next;
- }
- }
- return res;
-}
-
-mi_stop *mi_res_stop(mi_h *h)
-{
- mi_output *o=mi_retire_response(h);
- mi_stop *stop=NULL;
-
- if (o)
- {
- mi_output *sr=mi_get_stop_record(o);
- if (sr)
- stop=mi_get_stopped(sr->c);
- }
- mi_free_output(o);
-
- return stop;
-}
-
-int mi_get_read_memory(mi_h *h, unsigned char *dest, unsigned ws, int *na,
- unsigned long *addr)
-{
- char *end;
- mi_results *res=mi_res_done_var(h,"memory"), *r;
- int ok=0;
-
- *na=0;
- r=res;
- if (r && r->type==t_list && ws==1)
- {
- r=r->v.rs;
- if (r->type!=t_tuple)
- {
- mi_free_results(res);
- return 0;
- }
- r=r->v.rs;
- while (r)
- {
- if (r->type==t_list && strcmp(r->var,"data")==0)
- {
- mi_results *data=r->v.rs;
- ok++;
- if (data && data->type==t_const &&
- strcmp(data->v.cstr,"N/A")==0)
- *na=1;
- else
- while (data)
- {
- if (data->type==t_const)
- *(dest++)=strtol(data->v.cstr,&end,0);
- data=data->next;
- }
- }
- else if (r->type==t_const && strcmp(r->var,"addr")==0)
- {
- ok++;
- if (addr)
- *addr=strtoul(r->v.cstr,&end,0);
- }
- r=r->next;
- }
-
- }
- mi_free_results(res);
- return ok==2;
-}
-
-mi_asm_insn *mi_parse_insn(mi_results *c)
-{
- mi_asm_insn *res=NULL, *cur=NULL;
- mi_results *sub;
- char *end;
-
- while (c)
- {
- if (c->type==t_tuple)
- {
- if (!res)
- res=cur=mi_alloc_asm_insn();
- else
- {
- cur->next=mi_alloc_asm_insn();
- cur=cur->next;
- }
- if (!cur)
- {
- mi_free_asm_insn(res);
- return NULL;
- }
- sub=c->v.rs;
- while (sub)
- {
- if (sub->type==t_const)
- {
- if (strcmp(sub->var,"address")==0)
- cur->addr=(void *)strtoul(sub->v.cstr,&end,0);
- else if (strcmp(sub->var,"func-name")==0)
- {
- cur->func=sub->v.cstr;
- sub->v.cstr=NULL;
- }
- else if (strcmp(sub->var,"offset")==0)
- cur->offset=atoi(sub->v.cstr);
- else if (strcmp(sub->var,"inst")==0)
- {
- cur->inst=sub->v.cstr;
- sub->v.cstr=NULL;
- }
- }
- sub=sub->next;
- }
- }
- c=c->next;
- }
- return res;
-}
-
-mi_asm_insns *mi_parse_insns(mi_results *c)
-{
- mi_asm_insns *res=NULL, *cur=NULL;
- mi_results *sub;
-
- while (c)
- {
- if (c->var)
- {
- if (strcmp(c->var,"src_and_asm_line")==0 && c->type==t_tuple)
- {
- if (!res)
- res=cur=mi_alloc_asm_insns();
- else
- {
- cur->next=mi_alloc_asm_insns();
- cur=cur->next;
- }
- if (!cur)
- {
- mi_free_asm_insns(res);
- return NULL;
- }
- sub=c->v.rs;
- while (sub)
- {
- if (sub->var)
- {
- if (sub->type==t_const)
- {
- if (strcmp(sub->var,"line")==0)
- cur->line=atoi(sub->v.cstr);
- else if (strcmp(sub->var,"file")==0)
- {
- cur->file=sub->v.cstr;
- sub->v.cstr=NULL;
- }
- }
- else if (sub->type==t_list)
- {
- if (strcmp(sub->var,"line_asm_insn")==0)
- cur->ins=mi_parse_insn(sub->v.rs);
- }
- }
- sub=sub->next;
- }
- }
- }
- else
- {/* No source line, just instructions */
- res=mi_alloc_asm_insns();
- res->ins=mi_parse_insn(c);
- break;
- }
- c=c->next;
- }
- return res;
-}
-
-
-mi_asm_insns *mi_get_asm_insns(mi_h *h)
-{
- mi_results *r=mi_res_done_var(h,"asm_insns");
- mi_asm_insns *f=NULL;
-
- if (r && r->type==t_list)
- f=mi_parse_insns(r->v.rs);
- mi_free_results(r);
- return f;
-}
-
-mi_chg_reg *mi_parse_list_regs(mi_results *r, int *how_many)
-{
- mi_results *c=r;
- int cregs=0;
- mi_chg_reg *first=NULL, *cur=NULL;
-
- /* Create the list. */
- while (c)
- {
- if (c->type==t_const && !c->var)
- {
- if (first)
- cur=cur->next=mi_alloc_chg_reg();
- else
- first=cur=mi_alloc_chg_reg();
- cur->name=c->v.cstr;
- cur->reg=cregs++;
- c->v.cstr=NULL;
- }
- c=c->next;
- }
- if (how_many)
- *how_many=cregs;
-
- return first;
-}
-
-mi_chg_reg *mi_get_list_registers(mi_h *h, int *how_many)
-{
- mi_results *r=mi_res_done_var(h,"register-names");
- mi_chg_reg *l=NULL;
-
- if (r && r->type==t_list)
- l=mi_parse_list_regs(r->v.rs,how_many);
- mi_free_results(r);
- return l;
-}
-
-mi_chg_reg *mi_parse_list_changed_regs(mi_results *r)
-{
- mi_results *c=r;
- mi_chg_reg *first=NULL, *cur=NULL;
-
- /* Create the list. */
- while (c)
- {
- if (c->type==t_const && !c->var)
- {
- if (first)
- cur=cur->next=mi_alloc_chg_reg();
- else
- first=cur=mi_alloc_chg_reg();
- cur->reg=atoi(c->v.cstr);
- }
- c=c->next;
- }
-
- return first;
-}
-
-mi_chg_reg *mi_get_list_changed_regs(mi_h *h)
-{
- mi_results *r=mi_res_done_var(h,"changed-registers");
- mi_chg_reg *changed=NULL;
-
- if (r && r->type==t_list)
- changed=mi_parse_list_changed_regs(r->v.rs);
- mi_free_results(r);
- return changed;
-}
-
-int mi_parse_reg_values(mi_results *r, mi_chg_reg *l)
-{
- mi_results *c;
-
- while (r && l)
- {
- if (r->type==t_tuple && !r->var)
- {
- c=r->v.rs;
- while (c)
- {
- if (c->type==t_const && c->var)
- {
- if (strcmp(c->var,"number")==0)
- {
- if (atoi(c->v.cstr)!=l->reg)
- {
- mi_error=MI_PARSER;
- return 0;
- }
- }
- else if (strcmp(c->var,"value")==0)
- {
- l->val=c->v.cstr;
- c->v.cstr=NULL;
- }
- }
- c=c->next;
- }
- }
- r=r->next;
- l=l->next;
- }
-
- return !l && !r;
-}
-
-int mi_get_reg_values(mi_h *h, mi_chg_reg *l)
-{
- mi_results *r=mi_res_done_var(h,"register-values");
- int ok=0;
-
- if (r && r->type==t_list)
- ok=mi_parse_reg_values(r->v.rs,l);
- mi_free_results(r);
- return ok;
-}
-
-int mi_parse_list_regs_l(mi_results *r, mi_chg_reg *l)
-{
- while (r && l)
- {
- if (r->type==t_const && !r->var)
- {
- free(l->name);
- l->name=r->v.cstr;
- r->v.cstr=NULL;
- l=l->next;
- }
- r=r->next;
- }
-
- return !l && !r;
-}
-
-int mi_get_list_registers_l(mi_h *h, mi_chg_reg *l)
-{
- mi_results *r=mi_res_done_var(h,"register-names");
- int ok=0;
-
- if (r && r->type==t_list)
- ok=mi_parse_list_regs_l(r->v.rs,l);
- mi_free_results(r);
- return ok;
-}
-
-mi_chg_reg *mi_parse_reg_values_l(mi_results *r, int *how_many)
-{
- mi_results *c;
- mi_chg_reg *first=NULL, *cur=NULL;
- *how_many=0;
-
- while (r)
- {
- if (r->type==t_tuple && !r->var)
- {
- c=r->v.rs;
- if (first)
- cur=cur->next=mi_alloc_chg_reg();
- else
- first=cur=mi_alloc_chg_reg();
- while (c)
- {
- if (c->type==t_const && c->var)
- {
- if (strcmp(c->var,"number")==0)
- {
- cur->reg=atoi(c->v.cstr);
- (*how_many)++;
- }
- else if (strcmp(c->var,"value")==0)
- {
- cur->val=c->v.cstr;
- c->v.cstr=NULL;
- }
- }
- c=c->next;
- }
- }
- r=r->next;
- }
-
- return first;
-}
-
-mi_chg_reg *mi_get_reg_values_l(mi_h *h, int *how_many)
-{
- mi_results *r=mi_res_done_var(h,"register-values");
- mi_chg_reg *rgs=NULL;
-
- if (r && r->type==t_list)
- rgs=mi_parse_reg_values_l(r->v.rs,how_many);
- mi_free_results(r);
- return rgs;
-}
-
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Program control.
- Comments:
- GDB/MI commands for the "Program Control" section.@p
-
-@<pre>
-gdb command: Implemented?
-
--exec-abort N.A. (*) (kill, but with non-interactive options)
--exec-arguments Yes
--exec-continue Yes ASYNC
--exec-finish Yes ASYNC
--exec-interrupt Yes ASYNC
--exec-next Yes ASYNC
--exec-next-instruction Yes ASYNC
--exec-return Yes
--exec-run Yes ASYNC
--exec-show-arguments N.A. (show args) see gmi_stack_info_frame
--exec-step Yes ASYNC
--exec-step-instruction Yes ASYNC
--exec-until Yes ASYNC
--file-exec-and-symbols Yes
--file-exec-file No
--file-list-exec-sections N.A. (info file)
--file-list-exec-source-files N.A.
--file-list-shared-libraries N.A.
--file-list-symbol-files N.A.
--file-symbol-file Yes
-@</pre>
-
-(*) gmi_exec_kill implements it, but you should ensure that
-gmi_gdb_set("confirm","off") was called.@p
-
-GDB Bug workaround for -file-exec-and-symbols and -file-symbol-file: This
-is complex, but a real bug. When you set a breakpoint you never know the
-name of the file as it appears in the debug info. So you can be specifying
-an absolute file name or a relative file name. The reference point could be
-different than the one used in the debug info. To solve all the combinations
-gdb does a search trying various combinations. GDB isn't very smart so you
-must at least specify the working directory and the directory where the
-binary is located to get a good chance (+ user options to solve the rest).
-Once you did it gdb can find the file by doing transformations to the
-"canonical" filename. This search works OK for already loaded symtabs
-(symbol tables), but it have a bug when the search is done for psymtabs
-(partial symtabs). The bug is in the use of source_full_path_of (source.c).
-This function calls openp indicating try_cwd_first. It makes the search file
-if the psymtab file name have at least one dirseparator. It means that
-psymtabs for files compiled with relative paths will fail. The search for
-symtabs uses symtab_to_filename, it calls open_source_file which finally
-calls openp without try_cwd_first.@*
-To workaround this bug we must ensure gdb loads *all* the symtabs to memory.
-And here comes another problem -file-exec-and-symbols doesn't support it
-according to docs. In real life that's a wrapper for "file", but as nobody
-can say it won't change we must use the CLI command.
-
-***************************************************************************/
-
-#include <signal.h>
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_file_exec_and_symbols(mi_h *h, const char *file)
-{
- if (mi_get_workaround(MI_PSYM_SEARCH))
- mi_send(h,"file %s -readnow\n",file);
- else
- mi_send(h,"-file-exec-and-symbols %s\n",file);
-}
-
-void mi_exec_arguments(mi_h *h, const char *args)
-{
- mi_send(h,"-exec-arguments %s\n",args);
-}
-
-void mi_exec_run(mi_h *h)
-{
- mi_send(h,"-exec-run\n");
-}
-
-void mi_exec_continue(mi_h *h)
-{
- mi_send(h,"-exec-continue\n");
-}
-
-void mi_target_terminal(mi_h *h, const char *tty_name)
-{
- mi_send(h,"tty %s\n",tty_name);
-}
-
-void mi_file_symbol_file(mi_h *h, const char *file)
-{
- if (mi_get_workaround(MI_PSYM_SEARCH))
- mi_send(h,"symbol-file %s -readnow\n",file);
- else
- mi_send(h,"-file-symbol-file %s\n",file);
-}
-
-void mi_exec_finish(mi_h *h)
-{
- mi_send(h,"-exec-finish\n");
-}
-
-void mi_exec_interrupt(mi_h *h)
-{
- mi_send(h,"-exec-interrupt\n");
-}
-
-void mi_exec_next(mi_h *h, int count)
-{
- if (count>1)
- mi_send(h,"-exec-next %d\n",count);
- else
- mi_send(h,"-exec-next\n");
-}
-
-void mi_exec_next_instruction(mi_h *h)
-{
- mi_send(h,"-exec-next-instruction\n");
-}
-
-void mi_exec_step(mi_h *h, int count)
-{
- if (count>1)
- mi_send(h,"-exec-step %d\n",count);
- else
- mi_send(h,"-exec-step\n");
-}
-
-void mi_exec_step_instruction(mi_h *h)
-{
- mi_send(h,"-exec-step-instruction\n");
-}
-
-void mi_exec_until(mi_h *h, const char *file, int line)
-{
- if (!file)
- mi_send(h,"-exec-until\n");
- else
- mi_send(h,"-exec-until %s:%d\n",file,line);
-}
-
-void mi_exec_until_addr(mi_h *h, void *addr)
-{
- mi_send(h,"-exec-until *%p\n",addr);
-}
-
-void mi_exec_return(mi_h *h)
-{
- mi_send(h,"-exec-return\n");
-}
-
-void mi_exec_kill(mi_h *h)
-{
- mi_send(h,"kill\n");
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- Specify the executable and arguments for local debug.
-
- Command: -file-exec-and-symbols + -exec-arguments
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_set_exec(mi_h *h, const char *file, const char *args)
-{
- mi_file_exec_and_symbols(h,file);
- if (!mi_res_simple_done(h))
- return 0;
- if (!args)
- return 1;
- mi_exec_arguments(h,args);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Start running the executable. Remote sessions starts running.
-
- Command: -exec-run
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_run(mi_h *h)
-{
- mi_exec_run(h);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Continue the execution after a "stop".
-
- Command: -exec-continue
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_continue(mi_h *h)
-{
- mi_exec_continue(h);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Indicate which terminal will use the target program. For local sessions.
-
- Command: tty
- Return: !=0 OK
- Example:
-
-***************************************************************************/
-
-int gmi_target_terminal(mi_h *h, const char *tty_name)
-{
- mi_target_terminal(h,tty_name);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Specify what's the local copy that have debug info. For remote sessions.
-
- Command: -file-symbol-file
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_file_symbol_file(mi_h *h, const char *file)
-{
- mi_file_symbol_file(h,file);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Continue until function return, the return value is included in the async
-response.
-
- Command: -exec-finish
- Return: !=0 OK.
-
-***************************************************************************/
-
-int gmi_exec_finish(mi_h *h)
-{
- mi_exec_finish(h);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Stop the program using SIGINT. The corresponding command should be
--exec-interrupt but not even gdb 6.1.1 can do it because the "async" mode
-isn't really working.
-
- Command: -exec-interrupt [replacement]
- Return: Always 1
- Example:
-
-***************************************************************************/
-
-int gmi_exec_interrupt(mi_h *h)
-{
- // **** IMPORTANT!!! **** Not even gdb 6.1.1 can do it because the "async"
- // mode isn't really working.
- //mi_exec_interrupt(h);
- //return mi_res_simple_running(h);
-
- kill(h->pid,SIGINT);
- return 1; // How can I know?
-}
-
-/**[txh]********************************************************************
-
- Description:
- Next line of code.
-
- Command: -exec-next
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_next(mi_h *h)
-{
- mi_exec_next(h,1);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Skip count lines of code.
-
- Command: -exec-next count
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_next_cnt(mi_h *h, int count)
-{
- mi_exec_next(h,count);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Next line of assembler code.
-
- Command: -exec-next-instruction
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_next_instruction(mi_h *h)
-{
- mi_exec_next_instruction(h);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Next line of code. Get inside functions.
-
- Command: -exec-step
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_step(mi_h *h)
-{
- mi_exec_step(h,1);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Next count lines of code. Get inside functions.
-
- Command: -exec-step count
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_step_cnt(mi_h *h, int count)
-{
- mi_exec_step(h,count);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Next line of assembler code. Get inside calls.
-
- Command: -exec-step-instruction
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_step_instruction(mi_h *h)
-{
- mi_exec_step_instruction(h);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Execute until location is reached. If file is NULL then is until next
-line.
-
- Command: -exec-until
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_until(mi_h *h, const char *file, int line)
-{
- mi_exec_until(h,file,line);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Execute until location is reached.
-
- Command: -exec-until (using *address)
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_until_addr(mi_h *h, void *addr)
-{
- mi_exec_until_addr(h,addr);
- return mi_res_simple_running(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Return to previous frame inmediatly.
-
- Command: -exec-return
- Return: A pointer to a new mi_frames structure indicating the current
-location. NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_exec_return(mi_h *h)
-{
- mi_exec_return(h);
- return mi_res_frame(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Just kill the program. That's what -exec-abort should do, but it isn't
-implemented by gdb. This implementation only works if the interactive mode
-is disabled (gmi_gdb_set("confirm","off")).
-
- Command: -exec-abort [using kill]
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_exec_kill(mi_h *h)
-{
- mi_exec_kill(h);
- return mi_res_simple_done(h);
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Stack manipulation.
- Comments:
- GDB/MI commands for the "Stack Manipulation" section.@p
-
-@<pre>
-gdb command: Implemented?
-
--stack-info-frame Yes, implemented as "frame"
--stack-info-depth Yes
--stack-list-arguments Yes
--stack-list-frames Yes
--stack-list-locals Yes
--stack-select-frame Yes
-@</pre>
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_stack_list_frames(mi_h *h, int from, int to)
-{
- if (from<0)
- mi_send(h,"-stack-list-frames\n");
- else
- mi_send(h,"-stack-list-frames %d %d\n",from,to);
-}
-
-void mi_stack_list_arguments(mi_h *h, int show, int from, int to)
-{
- if (from<0)
- mi_send(h,"-stack-list-arguments %d\n",show);
- else
- mi_send(h,"-stack-list-arguments %d %d %d\n",show,from,to);
-}
-
-void mi_stack_info_frame(mi_h *h)
-{
- mi_send(h,"frame\n");
-}
-
-void mi_stack_info_depth(mi_h *h, int depth)
-{
- if (depth<0)
- mi_send(h,"-stack-info-depth\n");
- else
- mi_send(h,"-stack-info-depth %d\n",depth);
-}
-
-void mi_stack_select_frame(mi_h *h, int framenum)
-{
- mi_send(h,"-stack-select-frame %d\n",framenum);
-}
-
-void mi_stack_list_locals(mi_h *h, int show)
-{
- mi_send(h,"-stack-list-locals %d\n",show);
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- List of frames. Arguments aren't filled.
-
- Command: -stack-list-frames
- Return: A new list of mi_frames or NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_stack_list_frames(mi_h *h)
-{
- mi_stack_list_frames(h,-1,-1);
- return mi_res_frames_array(h,"stack");
-}
-
-/**[txh]********************************************************************
-
- Description:
- List of frames. Arguments aren't filled. Only the frames in the @var{from}
- - @var{to} range are returned.
-
- Command: -stack-list-frames
- Return: A new list of mi_frames or NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_stack_list_frames_r(mi_h *h, int from, int to)
-{
- mi_stack_list_frames(h,from,to);
- return mi_res_frames_array(h,"stack");
-}
-
-/**[txh]********************************************************************
-
- Description:
- List arguments. Only @var{level} and @var{args} filled.
-
- Command: -stack-list-arguments
- Return: A new list of mi_frames or NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_stack_list_arguments(mi_h *h, int show)
-{
- mi_stack_list_arguments(h,show,-1,-1);
- return mi_res_frames_array(h,"stack-args");
-}
-
-/**[txh]********************************************************************
-
- Description:
- List arguments. Only @var{level} and @var{args} filled. Only for the
-frames in the @var{from} - @var{to} range.
-
- Command: -stack-list-arguments
- Return: A new list of mi_frames or NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_stack_list_arguments_r(mi_h *h, int show, int from, int to)
-{
- mi_stack_list_arguments(h,show,from,to);
- return mi_res_frames_array(h,"stack-args");
-}
-
-/**[txh]********************************************************************
-
- Description:
- Information about the current frame, including args.
-
- Command: -stack-info-frame [using frame]
- Return: A new mi_frames or NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_stack_info_frame(mi_h *h)
-{
- mi_stack_info_frame(h);
- return mi_res_frame(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Stack info depth.
-
- Command: -stack-info-depth
- Return: The depth or -1 on error.
-
-***************************************************************************/
-
-int gmi_stack_info_depth(mi_h *h, int max_depth)
-{
- mi_results *r;
- int ret=-1;
-
- mi_stack_info_depth(h,max_depth);
- r=mi_res_done_var(h,"depth");
- if (r && r->type==t_const)
- {
- ret=atoi(r->v.cstr);
- mi_free_results(r);
- }
- return ret;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Set stack info depth.
-
- Command: -stack-info-depth [no args]
- Return: The depth or -1 on error.
- Example:
-
-***************************************************************************/
-
-int gmi_stack_info_depth_get(mi_h *h)
-{
- return gmi_stack_info_depth(h,-1);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Change current frame.
-
- Command: -stack-select-frame
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_stack_select_frame(mi_h *h, int framenum)
-{
- mi_stack_select_frame(h,framenum);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- List of local vars.
-
- Command: -stack-list-locals
- Return: A new mi_results tree containing the variables or NULL on error.
-
-***************************************************************************/
-
-mi_results *gmi_stack_list_locals(mi_h *h, int show)
-{
- mi_stack_list_locals(h,show);
- return mi_res_done_var(h,"locals");
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Symbol query.
- Comments:
- GDB/MI commands for the "Symbol Query" section.@p
-
-@<pre>
-gdb command: Implemented?
--symbol-info-address N.A. (info address, human readable)
--symbol-info-file N.A.
--symbol-info-function N.A.
--symbol-info-line N.A. (info line, human readable)
--symbol-info-symbol N.A. (info symbol, human readable)
--symbol-list-functions N.A. (info functions, human readable)
--symbol-list-types N.A. (info types, human readable)
--symbol-list-variables N.A. (info variables, human readable)
--symbol-list-lines No (gdb 6.x)
--symbol-locate N.A.
--symbol-type N.A. (ptype, human readable)
-@</pre>
-
-Note:@p
-
-Only one is implemented and not in gdb 5.x.@p
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004-2007 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Target manipulation.
- Comments:
- GDB/MI commands for the "Target Manipulation" section.@p
-
-@<pre>
--target-attach Yes (implemented using attach)
--target-compare-sections N.A. (compare-sections)
--target-detach Yes
--target-download Yes
--target-exec-status N.A.
--target-list-available-targets N.A. (help target)
--target-list-current-targets N.A. (info file among other things)
--target-list-parameters N.A.
--target-select Yes
-@</pre>
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_target_select(mi_h *h, const char *type, const char *params)
-{
- mi_send(h,"-target-select %s %s\n",type,params);
-}
-
-/* Note: -target-attach isn't currently implemented :-( (gdb 6.1.1) */
-void mi_target_attach(mi_h *h, pid_t pid)
-{
- mi_send(h,"attach %d\n",pid);
-}
-
-void mi_target_detach(mi_h *h)
-{
- mi_send(h,"-target-detach\n");
-}
-
-void mi_target_download(mi_h *h)
-{
- mi_send(h,"-target-download\n");
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- Connect to a remote gdbserver using the specified methode.
-
- Command: -target-select
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_target_select(mi_h *h, const char *type, const char *params)
-{
- mi_target_select(h,type,params);
- if (!mi_res_simple_connected(h))
- return 0;
- mi_send_target_commands(h);
- return 1;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Attach to an already running process.
-
- Command: -target-attach [using attach]
- Return: The frame of the current location, NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_target_attach(mi_h *h, pid_t pid)
-{
- mi_target_attach(h,pid);
- //return mi_res_simple_done(h);
- return mi_res_frame(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Detach from an attached process.
-
- Command: -target-detach
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_target_detach(mi_h *h)
-{
- mi_target_detach(h);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Loads the executable onto the remote target.
-
- Command: -target-download
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_target_download(mi_h *h)
-{
- mi_target_download(h);
- // TODO: this response have some data
- return mi_res_simple_done(h);
-}
-
--- /dev/null
+[PATHS]
+SERVICEHOME = /tmp/test-gnunetd-arm/
+DEFAULTCONFIG = test_arm_api_data.conf
+
+[arm]
+PORT = 23354
+DEFAULTSERVICES =
+BINARY = gnunet-service-arm
+OPTIONS = -L ERROR
+# DEBUG = YES
+#PREFIX = valgrind --tool=memcheck --leak-check=yes
+
+[gnunet-monkey]
+# DEBUG = YES
+PORT = 23355
+BINARY = gnunet-monkey
+# PREFIX = valgrind
+
+
+[fs]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[core]
+AUTOSTART = NO
+
+[transport]
+AUTOSTART = NO
+
+[peerinfo]
+AUTOSTART = NO
+
+[statistics]
+AUTOSTART = YES
+# DEBUG = NO
+
+++ /dev/null
-
-
-int main(int argc, char *argv[])
-{
- return 0;
-}
\ No newline at end of file
+++ /dev/null
-[PATHS]
-SERVICEHOME = /tmp/test-gnunetd-arm/
-DEFAULTCONFIG = test_arm_api_data.conf
-
-[arm]
-PORT = 23354
-DEFAULTSERVICES =
-BINARY = gnunet-service-arm
-OPTIONS = -L ERROR
-# DEBUG = YES
-#PREFIX = valgrind --tool=memcheck --leak-check=yes
-
-[gnunet-monkey]
-# DEBUG = YES
-PORT = 23355
-BINARY = gnunet-monkey
-# PREFIX = valgrind
-
-
-[fs]
-AUTOSTART = NO
-
-[datastore]
-AUTOSTART = NO
-
-[core]
-AUTOSTART = NO
-
-[transport]
-AUTOSTART = NO
-
-[peerinfo]
-AUTOSTART = NO
-
-[statistics]
-AUTOSTART = YES
-# DEBUG = NO
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Thread commands.
- Comments:
- GDB/MI commands for the "Thread Commands" section.@p
-
-@<pre>
-gdb command: Implemented?
--thread-info N.A.
--thread-list-all-threads Yes, implemented as "info threads"
--thread-list-ids Yes
--thread-select Yes
-@</pre>
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_thread_list_ids(mi_h *h)
-{
- mi_send(h,"-thread-list-ids\n");
-}
-
-void mi_thread_select(mi_h *h, int id)
-{
- mi_send(h,"-thread-select %d\n",id);
-}
-
-void mi_thread_list_all_threads(mi_h *h)
-{
- mi_send(h,"info threads\n");
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- List available thread ids.
-
- Command: -thread-list-ids
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_thread_list_ids(mi_h *h, int **list)
-{
- mi_thread_list_ids(h);
- return mi_res_thread_ids(h,list);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Select a thread.
-
- Command: -thread-select
- Return: A new mi_frames or NULL on error.
-
-***************************************************************************/
-
-mi_frames *gmi_thread_select(mi_h *h, int id)
-{
- mi_thread_select(h,id);
- return mi_res_frame(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Get a list of frames for each available thread. Implemented using "info
-thread".
-
- Command: -thread-list-all-threads
- Return: A kist of frames, NULL on error
-
-***************************************************************************/
-
-mi_frames *gmi_thread_list_all_threads(mi_h *h)
-{
- mi_thread_list_all_threads(h);
- return mi_res_frames_list(h);
-}
-
+++ /dev/null
-/**[txh]********************************************************************
-
- Copyright (c) 2004 by Salvador E. Tropea.
- Covered by the GPL license.
-
- Module: Variable objects.
- Comments:
- GDB/MI commands for the "Variable Objects" section.@p
-
-@<pre>
-gdb command: Imp? Description:
--var-create Yes create a variable object
--var-delete Yes delete the variable object and its children
--var-set-format Yes set the display format of this variable
--var-show-format Yes show the display format of this variable
--var-info-num-children Yes tells how many children this object has
--var-list-children Yes* return a list of the object's children
--var-info-type Yes show the type of this variable object
--var-info-expression Yes print what this variable object represents
--var-show-attributes Yes is this variable editable?
--var-evaluate-expression Yes get the value of this variable
--var-assign Yes set the value of this variable
--var-update Yes* update the variable and its children
-@</pre>
-
-Notes:@p
-1) I suggest letting gdb to choose the names for the variables.@*
-2) -var-list-children supports an optional "show values" argument in MI v2.
-It isn't implemented.@*
-@p
-
-* MI v1 and v2 result formats supported.@p
-
-***************************************************************************/
-
-#include "mi_gdb.h"
-
-/* Low level versions. */
-
-void mi_var_create(mi_h *h, const char *name, int frame, const char *exp)
-{
- const char *n=name ? name : "-";
-
- if (frame<0)
- mi_send(h,"-var-create %s * %s\n",n,exp);
- else
- mi_send(h,"-var-create %s %d %s\n",n,frame,exp);
-}
-
-void mi_var_delete(mi_h *h, const char *name)
-{
- mi_send(h,"-var-delete %s\n",name);
-}
-
-void mi_var_set_format(mi_h *h, const char *name, const char *format)
-{
- mi_send(h,"-var-set-format \"%s\" %s\n",name,format);
-}
-
-void mi_var_show_format(mi_h *h, const char *name)
-{
- mi_send(h,"-var-show-format \"%s\"\n",name);
-}
-
-void mi_var_info_num_children(mi_h *h, const char *name)
-{
- mi_send(h,"-var-info-num-children \"%s\"\n",name);
-}
-
-void mi_var_info_type(mi_h *h, const char *name)
-{
- mi_send(h,"-var-info-type \"%s\"\n",name);
-}
-
-void mi_var_info_expression(mi_h *h, const char *name)
-{
- mi_send(h,"-var-info-expression \"%s\"\n",name);
-}
-
-void mi_var_show_attributes(mi_h *h, const char *name)
-{
- mi_send(h,"-var-show-attributes \"%s\"\n",name);
-}
-
-void mi_var_update(mi_h *h, const char *name)
-{
- if (name)
- mi_send(h,"-var-update %s\n",name);
- else
- mi_send(h,"-var-update *\n");
-}
-
-void mi_var_assign(mi_h *h, const char *name, const char *expression)
-{
- mi_send(h,"-var-assign \"%s\" \"%s\"\n",name,expression);
-}
-
-void mi_var_evaluate_expression(mi_h *h, const char *name)
-{
- mi_send(h,"-var-evaluate-expression \"%s\"\n",name);
-}
-
-void mi_var_list_children(mi_h *h, const char *name)
-{
- if (h->version>=MI_VERSION2U(2,0,0))
- mi_send(h,"-var-list-children --all-values \"%s\"\n",name);
- else
- mi_send(h,"-var-list-children \"%s\"\n",name);
-}
-
-/* High level versions. */
-
-/**[txh]********************************************************************
-
- Description:
- Create a variable object. I recommend using @x{gmi_var_create} and letting
-gdb choose the names.
-
- Command: -var-create
- Return: A new mi_gvar strcture or NULL on error.
-
-***************************************************************************/
-
-mi_gvar *gmi_var_create_nm(mi_h *h, const char *name, int frame, const char *exp)
-{
- mi_var_create(h,name,frame,exp);
- return mi_res_gvar(h,NULL,exp);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Create a variable object. The name is selected by gdb. Alternative:
-@x{gmi_full_var_create}.
-
- Command: -var-create [auto name]
- Return: A new mi_gvar strcture or NULL on error.
-
-***************************************************************************/
-
-mi_gvar *gmi_var_create(mi_h *h, int frame, const char *exp)
-{
- return gmi_var_create_nm(h,NULL,frame,exp);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Delete a variable object. Doesn't free the mi_gvar data.
-
- Command: -var-delete
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_delete(mi_h *h, mi_gvar *var)
-{
- mi_var_delete(h,var->name);
- return mi_res_simple_done(h);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Set the format used to represent the result.
-
- Command: -var-set-format
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_set_format(mi_h *h, mi_gvar *var, enum mi_gvar_fmt format)
-{
- int ret;
-
- mi_var_set_format(h,var->name,mi_format_enum_to_str(format));
- ret=mi_res_simple_done(h);
- if (ret)
- var->format=format;
- return ret;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Fill the format field with info from gdb.
-
- Command: -var-show-format
- Return: !=0 OK.
-
-***************************************************************************/
-
-int gmi_var_show_format(mi_h *h, mi_gvar *var)
-{
- mi_var_show_format(h,var->name);
- return mi_res_gvar(h,var,NULL)!=NULL;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Fill the numchild field with info from gdb.
-
- Command: -var-info-num-children
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_info_num_children(mi_h *h, mi_gvar *var)
-{
- mi_var_info_num_children(h,var->name);
- return mi_res_gvar(h,var,NULL)!=NULL;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Fill the type field with info from gdb.
-
- Command: -var-info-type
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_info_type(mi_h *h, mi_gvar *var)
-{
- mi_var_info_type(h,var->name);
- return mi_res_gvar(h,var,NULL)!=NULL;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Fill the expression and lang fields with info from gdb. Note that lang
-isn't filled during creation.
-
- Command: -var-info-expression
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_info_expression(mi_h *h, mi_gvar *var)
-{
- mi_var_info_expression(h,var->name);
- return mi_res_gvar(h,var,NULL)!=NULL;
-}
-
-
-/**[txh]********************************************************************
-
- Description:
- Fill the attr field with info from gdb. Note that attr isn't filled
-during creation.
-
- Command: -var-show-attributes
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_show_attributes(mi_h *h, mi_gvar *var)
-{
- mi_var_show_attributes(h,var->name);
- return mi_res_gvar(h,var,NULL)!=NULL;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Create the variable and also fill the lang and attr fields. The name is
-selected by gdb.
-
- Command: -var-create + -var-info-expression + -var-show-attributes
- Return: A new mi_gvar strcture or NULL on error.
-
-***************************************************************************/
-
-mi_gvar *gmi_full_var_create(mi_h *h, int frame, const char *exp)
-{
- mi_gvar *var=gmi_var_create_nm(h,NULL,frame,exp);
- if (var)
- {/* What if it fails? */
- gmi_var_info_expression(h,var);
- gmi_var_show_attributes(h,var);
- }
- return var;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Update variable. Use NULL for all. Note that *changed can be NULL if none
-updated.
-
- Command: -var-update
- Return: !=0 OK. The @var{changed} list contains the list of changed vars.
-
-***************************************************************************/
-
-int gmi_var_update(mi_h *h, mi_gvar *var, mi_gvar_chg **changed)
-{
- mi_var_update(h,var ? var->name : NULL);
- return mi_res_changelist(h,changed);
-}
-
-/**[txh]********************************************************************
-
- Description:
- Change variable. The new value replaces the @var{value} field.
-
- Command: -var-assign
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_assign(mi_h *h, mi_gvar *var, const char *expression)
-{
- char *res;
- mi_var_assign(h,var->name,expression);
- res=mi_res_value(h);
- if (res)
- {
- free(var->value);
- var->value=res;
- return 1;
- }
- return 0;
-}
-
-/**[txh]********************************************************************
-
- Description:
- Fill the value field getting the current value for a variable.
-
- Command: -var-evaluate-expression
- Return: !=0 OK, value contains the result.
-
-***************************************************************************/
-
-int gmi_var_evaluate_expression(mi_h *h, mi_gvar *var)
-{
- char *s;
-
- mi_var_evaluate_expression(h,var->name);
- s=mi_res_value(h);
- if (s)
- {
- free(var->value);
- var->value=s;
- }
- return s!=NULL;
-}
-
-/**[txh]********************************************************************
-
- Description:
- List children. It ONLY returns the first level information. :-(@*
- On success the child field contains the list of children.
-
- Command: -var-list-children
- Return: !=0 OK
-
-***************************************************************************/
-
-int gmi_var_list_children(mi_h *h, mi_gvar *var)
-{
- mi_var_list_children(h,var->name);
- return mi_res_children(h,var);
-}
-