/**[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. @

@

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
@
(*) gmi_exec_kill implements it, but you should ensure that gmi_gdb_set("confirm","off") was called. @

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 #include "gdbmi.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); }