***************************************************************************/
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
#endif
#include <stdio.h>
/* 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);
-};
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
#endif
+
+++ /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 "gdbmi.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;
-}
-