GDB (API)
/home/stan/gdb/src/gdb/gdbtk/generic/gdbtk-cmds.c
Go to the documentation of this file.
00001 /* Tcl/Tk command definitions for Insight.
00002    Copyright (C) 1994-2013 Free Software Foundation, Inc.
00003 
00004    Written by Stu Grossman <grossman@cygnus.com> of Cygnus Support.
00005    Substantially augmented by Martin Hunt, Keith Seitz & Jim Ingham of
00006    Cygnus Support.
00007 
00008    This file is part of GDB.
00009 
00010    This program is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2 of the License, or
00013    (at your option) any later version.
00014 
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019 
00020    You should have received a copy of the GNU General Public License
00021    along with this program; if not, write to the Free Software
00022    Foundation, Inc., 51 Franklin Street, Fifth Floor,
00023    Boston, MA 02110-1301, USA.  */
00024 
00025 #include "defs.h"
00026 #include "inferior.h"
00027 #include "source.h"
00028 #include "symfile.h"
00029 #include "objfiles.h"
00030 #include "gdbcore.h"
00031 #include "demangle.h"
00032 #include "linespec.h"
00033 #include "top.h"
00034 #include "annotate.h"
00035 #include "block.h"
00036 #include "dictionary.h"
00037 #include "filenames.h"
00038 #include "disasm.h"
00039 #include "value.h"
00040 #include "varobj.h"
00041 #include "exceptions.h"
00042 #include "language.h"
00043 #include "target.h"
00044 #include "valprint.h"
00045 #include "regcache.h"
00046 #include "arch-utils.h"
00047 #include "psymtab.h"
00048 #include <ctype.h>
00049 
00050 /* tcl header files includes varargs.h unless HAS_STDARG is defined,
00051    but gdb uses stdarg.h, so make sure HAS_STDARG is defined.  */
00052 #define HAS_STDARG 1
00053 
00054 #include <tcl.h>
00055 #include <tk.h>
00056 
00057 #include "guitcl.h"
00058 #include "gdbtk.h"
00059 #include "gdbtk-wrapper.h"
00060 #include "gdbtk-cmds.h"
00061 
00062 #include <signal.h>
00063 #include <fcntl.h>
00064 #ifdef HAVE_SYS_IOCTL_H
00065 #include <sys/ioctl.h>
00066 #endif
00067 #include <sys/time.h>
00068 #include "gdb_stat.h"
00069 
00070 #include "gdb_string.h"
00071 #include "dis-asm.h"
00072 #include "gdbcmd.h"
00073 
00074 #ifdef __CYGWIN__
00075 #include <sys/cygwin.h>         /* for cygwin_conv_to_full_win32_path */
00076 #include <cygwin/version.h>
00077 # if CYGWIN_VERSION_DLL_MAKE_COMBINED(CYGWIN_VERSION_API_MAJOR,CYGWIN_VERSION_API_MINOR) >= 181
00078 #   define __USEWIDE
00079 # else
00080 #   define CCP_POSIX_TO_WIN_A 0 
00081 #   define CCP_POSIX_TO_WIN_W 1
00082 #   define CCP_WIN_A_TO_POSIX 2 
00083 #   define CCP_WIN_W_TO_POSIX 3
00084 #   define cygwin_conv_path(op, from, to, size)  \
00085          (op == CCP_WIN_A_TO_POSIX) ? \
00086          cygwin_conv_to_full_posix_path (from, to) : \
00087          cygwin_conv_to_win32_path (from, to)
00088 #   define CW_SET_DOS_FILE_WARNING -1   /* no-op this for older Cygwin */
00089 # endif
00090 #endif
00091 
00092 #ifdef _WIN32
00093 #include <windows.h>    /* For gdb_list_processes() */
00094 #include <tlhelp32.h>
00095 #endif
00096 
00097 /* Various globals we reference.  */
00098 extern char *source_path;
00099 
00100 /* These two objects hold boolean true and false,
00101    and are shared by all the list objects that gdb_listfuncs
00102    returns. */
00103 
00104 static Tcl_Obj *mangled, *not_mangled;
00105 
00106 /* These two control how the GUI behaves when gdb is either tracing or loading.
00107    They are used in this file & gdbtk_hooks.c */
00108 
00109 int No_Update = 0;
00110 int load_in_progress = 0;
00111 
00112 /* This Structure is used in gdb_disassemble_driver.
00113    We need a different sort of line table from the normal one cuz we can't
00114    depend upon implicit line-end pc's for lines to do the
00115    reordering in this function.  */
00116 
00117 struct my_line_entry
00118 {
00119   int line;
00120   CORE_ADDR start_pc;
00121   CORE_ADDR end_pc;
00122 };
00123 
00124 /* Use this to pass the Tcl Text widget command and the open file
00125    descriptor to the disassembly load command. */
00126 
00127 struct disassembly_client_data 
00128 {
00129   FILE *fp;
00130   int file_opened_p;
00131   int widget_line_no;
00132   Tcl_Interp *interp;
00133   char *widget;
00134   Tcl_Obj *result_obj[3];
00135   const char *asm_argv[14];
00136   const char *source_argv[7];
00137   char *map_arr;
00138   Tcl_DString src_to_line_prefix;
00139   Tcl_DString pc_to_line_prefix;
00140   Tcl_DString line_to_pc_prefix;
00141   Tcl_CmdInfo cmd;
00142 };
00143 
00144 /* This variable determines where memory used for disassembly is read
00145    from.  See note in gdbtk.h for details.  */
00146 /* NOTE: cagney/2003-09-08: This variable is unused.  */
00147 int disassemble_from_exec = -1;
00148 
00149 extern int gdb_variable_init (Tcl_Interp * interp);
00150 
00151 /*
00152  * Declarations for routines exported from this file
00153  */
00154 
00155 int Gdbtk_Init (Tcl_Interp * interp);
00156 
00157 /*
00158  * Declarations for routines used only in this file.
00159  */
00160 
00161 static int compare_lines (const PTR, const PTR);
00162 static int comp_files (const void *, const void *);
00163 static int gdb_clear_file (ClientData, Tcl_Interp * interp, int,
00164                            Tcl_Obj * CONST[]);
00165 static int gdb_cmd (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00166 static int gdb_confirm_quit (ClientData, Tcl_Interp *, int,
00167                              Tcl_Obj * CONST[]);
00168 static int gdb_entry_point (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00169 static int gdb_eval (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00170 static int gdb_find_file_command (ClientData, Tcl_Interp *, int,
00171                                   Tcl_Obj * CONST objv[]);
00172 static int gdb_force_quit (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00173 static int gdb_get_file_command (ClientData, Tcl_Interp *, int,
00174                                  Tcl_Obj * CONST objv[]);
00175 static int gdb_get_function_command (ClientData, Tcl_Interp *, int,
00176                                      Tcl_Obj * CONST objv[]);
00177 static int gdb_get_line_command (ClientData, Tcl_Interp *, int,
00178                                  Tcl_Obj * CONST objv[]);
00179 static int gdb_update_mem (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00180 static int gdb_set_mem (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00181 static int gdb_immediate_command (ClientData, Tcl_Interp *, int,
00182                                   Tcl_Obj * CONST[]);
00183 static int gdb_incr_addr (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00184 static int gdb_CA_to_TAS (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00185 static int gdb_listfiles (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00186 static int gdb_listfuncs (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00187 static int gdb_loadfile (ClientData, Tcl_Interp *, int,
00188                          Tcl_Obj * CONST objv[]);
00189 static int gdb_load_disassembly (ClientData clientData, Tcl_Interp
00190                                  * interp, int objc, Tcl_Obj * CONST objv[]);
00191 static int gdb_get_inferior_args (ClientData clientData,
00192                                   Tcl_Interp *interp,
00193                                   int objc, Tcl_Obj * CONST objv[]);
00194 static int gdb_set_inferior_args (ClientData clientData,
00195                                   Tcl_Interp *interp,
00196                                   int objc, Tcl_Obj * CONST objv[]);
00197 static int gdb_load_info (ClientData, Tcl_Interp *, int,
00198                           Tcl_Obj * CONST objv[]);
00199 static int gdb_loc (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00200 static int gdb_path_conv (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00201 static int gdb_prompt_command (ClientData, Tcl_Interp *, int,
00202                                Tcl_Obj * CONST objv[]);
00203 static int gdb_restore_fputs (ClientData, Tcl_Interp *, int,
00204                               Tcl_Obj * CONST[]);
00205 static int gdb_search (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST objv[]);
00206 static int gdb_stop (ClientData, Tcl_Interp *, int, Tcl_Obj * CONST[]);
00207 static int gdb_target_has_execution_command (ClientData,
00208                                              Tcl_Interp *, int,
00209                                              Tcl_Obj * CONST[]);
00210 static void gdbtk_load_source (ClientData clientData,
00211                                struct symtab *symtab,
00212                                int start_line, int end_line);
00213 static CORE_ADDR gdbtk_load_asm (ClientData clientData, CORE_ADDR pc,
00214                                  struct disassemble_info *di);
00215 static int gdb_disassemble_driver (CORE_ADDR low, CORE_ADDR high,
00216                                    int mixed_source_and_assembly,
00217                                    ClientData clientData,
00218                                    void (*print_source_fn) (ClientData, struct
00219                                                             symtab *, int,
00220                                                             int),
00221                                    CORE_ADDR (*print_asm_fn) (ClientData,
00222                                                               CORE_ADDR,
00223                                                               struct
00224                                                               disassemble_info
00225                                                               *));
00226 static int perror_with_name_wrapper (PTR args);
00227 static int wrapped_call (PTR opaque_args);
00228 static int hex2bin (const char *hex, char *bin, int count);
00229 static int fromhex (int a);
00230 static int gdb_list_processes (ClientData,
00231                                Tcl_Interp *,
00232                                int,
00233                                Tcl_Obj * CONST[]);
00234 
00235 
00236 
00237 /* Gdbtk_Init
00238  *    This loads all the Tcl commands into the Tcl interpreter.
00239  *
00240  * Arguments:
00241  *    interp - The interpreter into which to load the commands.
00242  *
00243  * Result:
00244  *     A standard Tcl result.
00245  */
00246 
00247 int
00248 Gdbtk_Init (Tcl_Interp *interp)
00249 {
00250   Tcl_CreateObjCommand (interp, "gdb_cmd", gdbtk_call_wrapper, gdb_cmd, NULL);
00251   Tcl_CreateObjCommand (interp, "gdb_immediate", gdbtk_call_wrapper,
00252                         gdb_immediate_command, NULL);
00253   Tcl_CreateObjCommand (interp, "gdb_loc", gdbtk_call_wrapper, gdb_loc, NULL);
00254   Tcl_CreateObjCommand (interp, "gdb_path_conv", gdbtk_call_wrapper, gdb_path_conv,
00255                         NULL);
00256   Tcl_CreateObjCommand (interp, "gdb_listfiles", gdbtk_call_wrapper, gdb_listfiles,
00257                         NULL);
00258   Tcl_CreateObjCommand (interp, "gdb_listfuncs", gdbtk_call_wrapper, gdb_listfuncs,
00259                         NULL);
00260   Tcl_CreateObjCommand (interp, "gdb_entry_point", gdbtk_call_wrapper,
00261                         gdb_entry_point, NULL);
00262   Tcl_CreateObjCommand (interp, "gdb_update_mem", gdbtk_call_wrapper, gdb_update_mem,
00263                         NULL);
00264   Tcl_CreateObjCommand (interp, "gdb_set_mem", gdbtk_call_wrapper, gdb_set_mem,
00265                         NULL);
00266   Tcl_CreateObjCommand (interp, "gdb_stop", gdbtk_call_wrapper, gdb_stop, NULL);
00267   Tcl_CreateObjCommand (interp, "gdb_restore_fputs", gdbtk_call_wrapper, gdb_restore_fputs,
00268                         NULL);
00269   Tcl_CreateObjCommand (interp, "gdb_eval", gdbtk_call_wrapper, gdb_eval, NULL);
00270   Tcl_CreateObjCommand (interp, "gdb_incr_addr", gdbtk_call_wrapper, gdb_incr_addr, NULL);
00271   Tcl_CreateObjCommand (interp, "gdb_CA_to_TAS", gdbtk_call_wrapper, gdb_CA_to_TAS, NULL);
00272   Tcl_CreateObjCommand (interp, "gdb_clear_file", gdbtk_call_wrapper,
00273                         gdb_clear_file, NULL);
00274   Tcl_CreateObjCommand (interp, "gdb_confirm_quit", gdbtk_call_wrapper,
00275                         gdb_confirm_quit, NULL);
00276   Tcl_CreateObjCommand (interp, "gdb_force_quit", gdbtk_call_wrapper,
00277                         gdb_force_quit, NULL);
00278   Tcl_CreateObjCommand (interp, "gdb_target_has_execution",
00279                         gdbtk_call_wrapper,
00280                         gdb_target_has_execution_command, NULL);
00281   Tcl_CreateObjCommand (interp, "gdb_load_info", gdbtk_call_wrapper, gdb_load_info,
00282                         NULL);
00283   Tcl_CreateObjCommand (interp, "gdb_get_function", gdbtk_call_wrapper,
00284                         gdb_get_function_command, NULL);
00285   Tcl_CreateObjCommand (interp, "gdb_get_line", gdbtk_call_wrapper,
00286                         gdb_get_line_command, NULL);
00287   Tcl_CreateObjCommand (interp, "gdb_get_file", gdbtk_call_wrapper,
00288                         gdb_get_file_command, NULL);
00289   Tcl_CreateObjCommand (interp, "gdb_prompt",
00290                         gdbtk_call_wrapper, gdb_prompt_command, NULL);
00291   Tcl_CreateObjCommand (interp, "gdb_find_file",
00292                         gdbtk_call_wrapper, gdb_find_file_command, NULL);
00293   Tcl_CreateObjCommand (interp, "gdb_loadfile", gdbtk_call_wrapper, gdb_loadfile,
00294                         NULL);
00295   Tcl_CreateObjCommand (interp, "gdb_load_disassembly", gdbtk_call_wrapper,
00296                         gdb_load_disassembly,  NULL);
00297   Tcl_CreateObjCommand (gdbtk_interp, "gdb_search", gdbtk_call_wrapper,
00298                         gdb_search, NULL);
00299   Tcl_CreateObjCommand (interp, "gdb_get_inferior_args", gdbtk_call_wrapper,
00300                         gdb_get_inferior_args, NULL);
00301   Tcl_CreateObjCommand (interp, "gdb_set_inferior_args", gdbtk_call_wrapper,
00302                         gdb_set_inferior_args, NULL);
00303   Tcl_CreateObjCommand (interp, "gdb_list_processes", gdbtk_call_wrapper,
00304                         gdb_list_processes, NULL);
00305 
00306   /* gdb_context is used for debugging multiple threads or tasks */
00307   Tcl_LinkVar (interp, "gdb_context_id",
00308                (char *) &gdb_context,
00309                TCL_LINK_INT | TCL_LINK_READ_ONLY);
00310 
00311   /* Make gdb's notion of the pwd visible.  This is read-only because
00312      (1) it doesn't make sense to change it directly and (2) it is
00313      allocated using xmalloc and not Tcl_Alloc.  You might think we
00314      could just use the Tcl `pwd' command.  However, Tcl (erroneously,
00315      imho) maintains a cache of the current directory name, and
00316      doesn't provide a way for gdb to invalidate the cache.  */
00317   Tcl_LinkVar (interp, "gdb_current_directory",
00318                (char *) &current_directory,
00319                TCL_LINK_STRING | TCL_LINK_READ_ONLY);
00320 
00321   /* Current gdb source file search path.  This is read-only for
00322      reasons similar to those for gdb_current_directory.  */
00323   Tcl_LinkVar (interp, "gdb_source_path",
00324                (char *) &source_path,
00325                TCL_LINK_STRING | TCL_LINK_READ_ONLY);
00326 
00327   /* Init variable interface... */
00328   if (gdb_variable_init (interp) != TCL_OK)
00329     return TCL_ERROR;
00330 
00331   /* Init breakpoint module */
00332   if (Gdbtk_Breakpoint_Init (interp) != TCL_OK)
00333     return TCL_ERROR;
00334 
00335   /* Init stack module */
00336   if (Gdbtk_Stack_Init (interp) != TCL_OK)
00337     return TCL_ERROR;
00338 
00339   /* Init register module */
00340   if (Gdbtk_Register_Init (interp) != TCL_OK)
00341     return TCL_ERROR;
00342 
00343   /* Determine where to disassemble from */
00344   Tcl_LinkVar (gdbtk_interp, "disassemble-from-exec",
00345                (char *) &disassemble_from_exec,
00346                TCL_LINK_INT);
00347 
00348   Tcl_PkgProvide (interp, "Gdbtk", GDBTK_VERSION);
00349   return TCL_OK;
00350 }
00351 
00352 /* This routine acts as a top-level for all GDB code called by Tcl/Tk.  It
00353    handles cleanups, and uses catch_errors to trap calls to return_to_top_level
00354    (usually via error).
00355    This is necessary in order to prevent a longjmp out of the bowels of Tk,
00356    possibly leaving things in a bad state.  Since this routine can be called
00357    recursively, it needs to save and restore the contents of the result_ptr as
00358    necessary. */
00359 
00360 int
00361 gdbtk_call_wrapper (ClientData clientData, Tcl_Interp *interp,
00362                     int objc, Tcl_Obj *CONST objv[])
00363 {
00364   struct wrapped_call_args wrapped_args;
00365   gdbtk_result new_result, *old_result_ptr;
00366   int wrapped_returned_error = 0;
00367 
00368   old_result_ptr = result_ptr;
00369   result_ptr = &new_result;
00370   result_ptr->obj_ptr = Tcl_NewObj ();
00371   result_ptr->flags = GDBTK_TO_RESULT;
00372 
00373   wrapped_args.func = (Tcl_ObjCmdProc *) clientData;
00374   wrapped_args.interp = interp;
00375   wrapped_args.objc = objc;
00376   wrapped_args.objv = objv;
00377   wrapped_args.val = TCL_OK;
00378 
00379   if (!catch_errors (wrapped_call, &wrapped_args, "", RETURN_MASK_ALL))
00380     {
00381 
00382       wrapped_args.val = TCL_ERROR;     /* Flag an error for TCL */
00383 
00384       /* Make sure the timer interrupts are turned off.  */
00385       gdbtk_stop_timer ();
00386 
00387       gdb_flush (gdb_stderr);   /* Flush error output */
00388       gdb_flush (gdb_stdout);   /* Sometimes error output comes here as well */
00389 
00390       /* If we errored out here, and the results were going to the
00391          console, then gdbtk_fputs will have gathered the result into the
00392          result_ptr.  We also need to echo them out to the console here */
00393 
00394       gdb_flush (gdb_stderr);   /* Flush error output */
00395       gdb_flush (gdb_stdout);   /* Sometimes error output comes here as well */
00396 
00397       /* In case of an error, we may need to force the GUI into idle
00398          mode because gdbtk_call_command may have bombed out while in
00399          the command routine.  */
00400 
00401       running_now = 0;
00402       Tcl_Eval (interp, "gdbtk_tcl_idle");
00403 
00404     }
00405   else
00406     {
00407       /* If the wrapped call returned an error directly, then we don't
00408          want to reset the result.  */
00409       wrapped_returned_error = wrapped_args.val == TCL_ERROR;
00410     }
00411 
00412   /* do not suppress any errors -- a remote target could have errored */
00413   load_in_progress = 0;
00414 
00415   /*
00416    * Now copy the result over to the true Tcl result.  If
00417    * GDBTK_TO_RESULT flag bit is set, this just copies a null object
00418    * over to the Tcl result, which is fine because we should reset the
00419    * result in this case anyway.  If the wrapped command returned an
00420    * error, then we assume that the result is already set correctly.
00421    */
00422   if ((result_ptr->flags & GDBTK_IN_TCL_RESULT) || wrapped_returned_error)
00423     {
00424       Tcl_DecrRefCount (result_ptr->obj_ptr);
00425     }
00426   else
00427     {
00428       Tcl_SetObjResult (interp, result_ptr->obj_ptr);
00429     }
00430 
00431   result_ptr = old_result_ptr;
00432 
00433 #ifdef _WIN32
00434   close_bfds ();
00435 #endif
00436 
00437   return wrapped_args.val;
00438 }
00439 
00440 /*
00441  * This is the wrapper that is passed to catch_errors.
00442  */
00443 
00444 static int
00445 wrapped_call (PTR opaque_args)
00446 {
00447   struct wrapped_call_args *args = (struct wrapped_call_args *) opaque_args;
00448   args->val = (*args->func) (args->func, args->interp, args->objc, args->objv);
00449   return 1;
00450 }
00451 
00452 
00453 /*
00454  * This section contains the commands that control execution.
00455  */
00456 
00457 /* This implements the tcl command gdb_clear_file.
00458 
00459 * Prepare to accept a new executable file.  This is called when we
00460 * want to clear away everything we know about the old file, without
00461 * asking the user.  The Tcl code will have already asked the user if
00462 * necessary.  After this is called, we should be able to run the
00463 * `file' command without getting any questions.  
00464 *
00465 * Arguments:
00466 *    None
00467 * Tcl Result:
00468 *    None
00469 */
00470 
00471 static int
00472 gdb_clear_file (ClientData clientData, Tcl_Interp *interp,
00473                 int objc, Tcl_Obj *CONST objv[])
00474 {
00475   if (objc != 1)
00476     {
00477       Tcl_WrongNumArgs (interp, 1, objv, NULL);
00478       return TCL_ERROR;
00479     }
00480 
00481   if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
00482     {
00483       struct inferior *inf = current_inferior ();
00484       if (inf->attach_flag)
00485         target_detach (NULL, 0);
00486       else
00487         target_kill ();
00488     }
00489 
00490   delete_command (NULL, 0);
00491   exec_file_clear (0);
00492   symbol_file_clear (0);
00493 
00494   return TCL_OK;
00495 }
00496 
00497 /* This implements the tcl command gdb_confirm_quit
00498  * Ask the user to confirm an exit request.
00499  *
00500  * Arguments:
00501  *    None
00502  * Tcl Result:
00503  *    A boolean, 1 if the user answered yes, 0 if no.
00504  */
00505 
00506 static int
00507 gdb_confirm_quit (ClientData clientData, Tcl_Interp *interp,
00508                   int objc, Tcl_Obj *CONST objv[])
00509 {
00510   int ret;
00511 
00512   if (objc != 1)
00513     {
00514       Tcl_WrongNumArgs (interp, 1, objv, NULL);
00515       return TCL_ERROR;
00516     }
00517 
00518   ret = quit_confirm ();
00519   Tcl_SetBooleanObj (result_ptr->obj_ptr, ret);
00520   return TCL_OK;
00521 }
00522 
00523 /* This implements the tcl command gdb_force_quit
00524  * Quit without asking for confirmation.
00525  *
00526  * Arguments:
00527  *    None
00528  * Tcl Result:
00529  *    None
00530  */
00531 
00532 static int
00533 gdb_force_quit (ClientData clientData, Tcl_Interp *interp,
00534                 int objc, Tcl_Obj *CONST objv[])
00535 {
00536   if (objc != 1)
00537     {
00538       Tcl_WrongNumArgs (interp, 1, objv, NULL);
00539       return TCL_ERROR;
00540     }
00541 
00542   quit_force ((char *) NULL, 1);
00543   return TCL_OK;
00544 }
00545 
00546 /* Pressing the stop button on the source window should attempt to
00547  * stop the target. If, after some short time, this fails, a dialog
00548  * should appear allowing the user to detach.
00549  *
00550  * The global GDBTK_FORCE_DETACH is set when we wish to detach from a
00551  * target. This value is returned by deprecated_ui_loop_hook
00552  * (x_event), indicating to callers that they should detach.
00553  *
00554  * Read the comments before x_event to find out how we (try) to keep
00555  * gdbtk alive while some other event loop has stolen control from us.
00556  */
00557 
00558 /*
00559  * This command implements the tcl command gdb_stop, which
00560  * is used to either stop the target or detach.
00561  * Note that it is assumed that a simulator or native target
00562  * can ALWAYS be stopped. Doing a "detach" on them has no effect.
00563  * 
00564  * Arguments:
00565  *    None or "detach"
00566  * Tcl Result:
00567  *    None
00568  */
00569 
00570 static int
00571 gdb_stop (ClientData clientData, Tcl_Interp *interp,
00572           int objc, Tcl_Obj *CONST objv[])
00573 {
00574   int force = 0;
00575   char *s;
00576 
00577   if (objc > 1)
00578     {
00579       s = Tcl_GetStringFromObj (objv[1], NULL);
00580       if (strcmp (s, "detach") == 0)
00581         force = 1;
00582     }
00583 
00584   if (force)
00585     {
00586       /* Set the "forcibly detach from target" flag. x_event will
00587          return this value to callers when they should forcibly detach. */
00588       gdbtk_force_detach = 1;
00589     }
00590   else
00591     {
00592       if (target_ignore != (void (*) (void)) current_target.to_stop)
00593         target_stop (gdbtk_get_ptid ());
00594       else
00595         set_quit_flag ();               /* hope something sees this */
00596     }
00597 
00598   return TCL_OK;
00599 }
00600 
00601 /*
00602  * This command lists all processes in a system. Yet only implemented
00603  * for windows as the *nix part is handled directly from tcl code.
00604  *
00605  * Arguments:
00606  *    None
00607  * Tcl Result:
00608  *    A list of 2 elemented lists containing all running processes 
00609  *    and their pids.
00610  */
00611  
00612 static int 
00613 gdb_list_processes (ClientData clientData, Tcl_Interp *interp, 
00614                     int objc, Tcl_Obj * CONST objv[])
00615 {
00616   if (objc != 1)
00617     {
00618       Tcl_WrongNumArgs (interp, 1, objv, NULL);
00619       return TCL_ERROR;
00620     }
00621 
00622   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
00623 
00624   #ifdef _WIN32
00625     {
00626       HANDLE processSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
00627       if (processSnap != INVALID_HANDLE_VALUE)
00628         {
00629           PROCESSENTRY32 processEntry;
00630  
00631           processEntry.dwSize = sizeof(PROCESSENTRY32);
00632  
00633           if (Process32First (processSnap, &processEntry))
00634             {
00635               do
00636                 {
00637                   Tcl_Obj *pidProc[2];
00638                   pidProc[0] = Tcl_NewIntObj (processEntry.th32ProcessID);
00639                   pidProc[1] = Tcl_NewStringObj (processEntry.szExeFile, -1);
00640 
00641                   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
00642                     Tcl_NewListObj (2, pidProc));
00643 
00644                 } while(Process32Next (processSnap, &processEntry));
00645             }
00646 
00647           CloseHandle (processSnap);
00648         }
00649     }
00650   #endif
00651 
00652   return TCL_OK;
00653 }
00654 
00655 
00656 
00657 /*
00658  * This section contains Tcl commands that are wrappers for invoking
00659  * the GDB command interpreter.
00660  */
00661 
00662 
00663 /* This implements the tcl command `gdb_eval'.
00664  * It uses the gdb evaluator to return the value of
00665  * an expression in the current language
00666  *
00667  * Tcl Arguments:
00668  *     expression - the expression to evaluate.
00669  *     format - optional format character.  Valid chars are:
00670  *      o - octal
00671  *      x - hex
00672  *      d - decimal
00673  *      u - unsigned decimal
00674  *      t - binary
00675  *      f - float
00676  *      a - address
00677  *      c - char
00678  * Tcl Result:
00679  *     The result of the evaluation.
00680  */
00681 
00682 static int
00683 gdb_eval (ClientData clientData, Tcl_Interp *interp,
00684           int objc, Tcl_Obj *CONST objv[])
00685 {
00686   struct expression *expr;
00687   struct cleanup *old_chain = NULL;
00688   int format = 0;
00689   value_ptr val;
00690   struct ui_file *stb;
00691   long dummy;
00692   char *result;
00693   struct value_print_options opts;
00694 
00695   if (objc != 2 && objc != 3)
00696     {
00697       Tcl_WrongNumArgs (interp, 1, objv, "expression [format]");
00698       return TCL_ERROR;
00699     }
00700 
00701   if (objc == 3)
00702     format = *(Tcl_GetStringFromObj (objv[2], NULL));
00703 
00704   get_formatted_print_options (&opts, format);
00705 
00706   expr = parse_expression (Tcl_GetStringFromObj (objv[1], NULL));
00707   old_chain = make_cleanup (free_current_contents, &expr);
00708   val = evaluate_expression (expr);
00709 
00710   /* "Print" the result of the expression evaluation. */
00711   stb = mem_fileopen ();
00712   make_cleanup_ui_file_delete (stb);
00713   common_val_print (val, stb, 0, &opts, current_language);
00714   result = ui_file_xstrdup (stb, &dummy);
00715   Tcl_SetObjResult (interp, Tcl_NewStringObj (result, -1));
00716   xfree (result);
00717   result_ptr->flags |= GDBTK_IN_TCL_RESULT;
00718 
00719   do_cleanups (old_chain);
00720   return TCL_OK;
00721 }
00722 
00723 /* This implements the tcl command "gdb_cmd".
00724 
00725 * It sends its argument to the GDB command scanner for execution. 
00726 * This command will never cause the update, idle and busy hooks to be called
00727 * within the GUI.
00728 * 
00729 * Tcl Arguments:
00730 *    command - The GDB command to execute
00731 *    from_tty - 1 indicates this comes to the console.
00732 *               Pass this to the gdb command.
00733 * Tcl Result:
00734 *    The output from the gdb command (except for the "load" & "while"
00735 *    which dump their output to the console.
00736 */
00737 
00738 static int
00739 gdb_cmd (ClientData clientData, Tcl_Interp *interp,
00740          int objc, Tcl_Obj *CONST objv[])
00741 {
00742   int from_tty = 0;
00743 
00744   if (objc < 2 || objc > 3)
00745     {
00746       Tcl_WrongNumArgs (interp, 1, objv, "command ?from_tty?");
00747       return TCL_ERROR;
00748     }
00749 
00750   if (objc == 3)
00751     {
00752       if (Tcl_GetBooleanFromObj (NULL, objv[2], &from_tty) != TCL_OK)
00753         {
00754           gdbtk_set_result (interp, "from_tty must be a boolean.");
00755           return TCL_ERROR;
00756         }
00757     }
00758 
00759   if (running_now || load_in_progress)
00760     return TCL_OK;
00761 
00762   No_Update = 1;
00763 
00764   /* for the load instruction (and possibly others later) we
00765      set turn off the GDBTK_TO_RESULT flag bit so gdbtk_fputs() 
00766      will not buffer all the data until the command is finished. */
00767 
00768   if ((strncmp ("load ", Tcl_GetStringFromObj (objv[1], NULL), 5) == 0))
00769     {
00770       result_ptr->flags &= ~GDBTK_TO_RESULT;
00771       load_in_progress = 1;
00772     }
00773 
00774   execute_command (Tcl_GetStringFromObj (objv[1], NULL), from_tty);
00775 
00776   if (load_in_progress)
00777     {
00778       load_in_progress = 0;
00779       result_ptr->flags |= GDBTK_TO_RESULT;
00780     }
00781 
00782   bpstat_do_actions ();
00783 
00784   return TCL_OK;
00785 }
00786 
00787 /*
00788  * This implements the tcl command "gdb_immediate"
00789  *  
00790  * It does exactly the same thing as gdb_cmd, except NONE of its outut 
00791  * is buffered.  This will also ALWAYS cause the busy, update, and idle 
00792  * hooks to be called, contrasted with gdb_cmd, which NEVER calls them.
00793  * It turns off the GDBTK_TO_RESULT flag, which diverts the result
00794  * to the console window.
00795  *
00796  * Tcl Arguments:
00797  *    command - The GDB command to execute
00798  *    from_tty - 1 to indicate this is from the console.
00799  * Tcl Result:
00800  *    None.
00801  */
00802 
00803 static int
00804 gdb_immediate_command (ClientData clientData, Tcl_Interp *interp,
00805                        int objc, Tcl_Obj *CONST objv[])
00806 {
00807   int from_tty = 0;
00808 
00809   if (objc < 2 || objc > 3)
00810     {
00811       Tcl_WrongNumArgs (interp, 1, objv, "command ?from_tty?");
00812       return TCL_ERROR;
00813     }
00814 
00815   if (objc == 3)
00816     {
00817       if (Tcl_GetBooleanFromObj (NULL, objv[2], &from_tty) != TCL_OK)
00818         {
00819           gdbtk_set_result (interp, "from_tty must be a boolean.");
00820           return TCL_ERROR;
00821         }
00822     }
00823 
00824   if (running_now || load_in_progress)
00825     return TCL_OK;
00826 
00827   No_Update = 0;
00828 
00829   result_ptr->flags &= ~GDBTK_TO_RESULT;
00830 
00831   execute_command (Tcl_GetStringFromObj (objv[1], NULL), from_tty);
00832 
00833   bpstat_do_actions ();
00834 
00835   result_ptr->flags |= GDBTK_TO_RESULT;
00836 
00837   return TCL_OK;
00838 }
00839 
00840 /* This implements the tcl command "gdb_prompt"
00841 
00842 * It returns the gdb interpreter's prompt.
00843 *
00844 * Tcl Arguments:
00845 *    None.
00846 * Tcl Result:
00847 *    The prompt.
00848 */
00849 
00850 static int
00851 gdb_prompt_command (ClientData clientData, Tcl_Interp *interp,
00852                     int objc, Tcl_Obj *CONST objv[])
00853 {
00854   Tcl_SetStringObj (result_ptr->obj_ptr, get_prompt (), -1);
00855   return TCL_OK;
00856 }
00857 
00858 
00859 /*
00860  * This section contains general informational commands.
00861  */
00862 
00863 /* This implements the tcl command "gdb_target_has_execution"
00864 
00865 * Tells whether the target is executing.
00866 *
00867 * Tcl Arguments:
00868 *    None
00869 * Tcl Result:
00870 *    A boolean indicating whether the target is executing.
00871 */
00872 
00873 static int
00874 gdb_target_has_execution_command (ClientData clientData, Tcl_Interp *interp,
00875                                   int objc, Tcl_Obj *CONST objv[])
00876 {
00877   int result = 0;
00878 
00879   if (target_has_execution && ! ptid_equal (inferior_ptid, null_ptid))
00880     result = 1;
00881 
00882   Tcl_SetBooleanObj (result_ptr->obj_ptr, result);
00883   return TCL_OK;
00884 }
00885 
00886 /* This implements the tcl command "gdb_get_inferior_args"
00887 
00888 * Returns inferior command line arguments as a string
00889 *
00890 * Tcl Arguments:
00891 *    None
00892 * Tcl Result:
00893 *    A string containing the inferior command line arguments
00894 */
00895 
00896 static int
00897 gdb_get_inferior_args (ClientData clientData, Tcl_Interp *interp,
00898                        int objc, Tcl_Obj *CONST objv[])
00899 {
00900   if (objc != 1)
00901     {
00902       Tcl_WrongNumArgs (interp, 1, objv, NULL);
00903       return TCL_ERROR;
00904     }
00905 
00906   Tcl_SetStringObj (result_ptr->obj_ptr, get_inferior_args (), -1);
00907   return TCL_OK;
00908 }
00909 
00910 /* This implements the tcl command "gdb_set_inferior_args"
00911 
00912 * Sets inferior command line arguments
00913 *
00914 * Tcl Arguments:
00915 *    A string containing the inferior command line arguments
00916 * Tcl Result:
00917 *    None
00918 */
00919 
00920 static int
00921 gdb_set_inferior_args (ClientData clientData, Tcl_Interp *interp,
00922                        int objc, Tcl_Obj *CONST objv[])
00923 {
00924   char *args;
00925 
00926   if (objc != 2)
00927     {
00928       Tcl_WrongNumArgs (interp, 1, objv, "argument");
00929       return TCL_ERROR;
00930     }
00931 
00932   args = Tcl_GetStringFromObj (objv[1], NULL);
00933   set_inferior_args (args);
00934 
00935   return TCL_OK;
00936 }
00937 
00938 /* This implements the tcl command "gdb_load_info"
00939 
00940 * It returns information about the file about to be downloaded.
00941 *
00942 * Tcl Arguments:
00943 *    filename: The file to open & get the info on.
00944 * Tcl Result:
00945 *    A list consisting of the name and size of each section.
00946 */
00947 
00948 static int
00949 gdb_load_info (ClientData clientData, Tcl_Interp *interp,
00950                int objc, Tcl_Obj *CONST objv[])
00951 {
00952   bfd *loadfile_bfd;
00953   struct cleanup *old_cleanups;
00954   asection *s;
00955   Tcl_Obj *ob[2];
00956 
00957   char *filename = Tcl_GetStringFromObj (objv[1], NULL);
00958 
00959   loadfile_bfd = bfd_openr (filename, gnutarget);
00960   if (loadfile_bfd == NULL)
00961     {
00962       gdbtk_set_result (interp, "Open of %s failed", filename);
00963       return TCL_ERROR;
00964     }
00965   old_cleanups = make_cleanup_bfd_unref (loadfile_bfd);
00966 
00967   if (!bfd_check_format (loadfile_bfd, bfd_object))
00968     {
00969       do_cleanups (old_cleanups);
00970       gdbtk_set_result (interp, "Bad Object File");
00971       return TCL_ERROR;
00972     }
00973 
00974   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
00975 
00976   for (s = loadfile_bfd->sections; s; s = s->next)
00977     {
00978       if (s->flags & SEC_LOAD)
00979         {
00980           bfd_size_type size = bfd_get_section_size (s);
00981           if (size > 0)
00982             {
00983               ob[0] = Tcl_NewStringObj ((char *)
00984                                         bfd_get_section_name (loadfile_bfd, s),
00985                                         -1);
00986               ob[1] = Tcl_NewLongObj ((long) size);
00987               Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
00988                                         Tcl_NewListObj (2, ob));
00989             }
00990         }
00991     }
00992 
00993   do_cleanups (old_cleanups);
00994   return TCL_OK;
00995 }
00996 
00997 
00998 /* This implements the tcl command "gdb_get_line"
00999 
01000 * It returns the linenumber for a given linespec.  It will take any spec
01001 * that can be passed to decode_line_1
01002 *
01003 * Tcl Arguments:
01004 *    linespec - the line specification
01005 * Tcl Result:
01006 *    The line number for that spec.
01007 */
01008 static int
01009 gdb_get_line_command (ClientData clientData, Tcl_Interp *interp,
01010                       int objc, Tcl_Obj *CONST objv[])
01011 {
01012   struct symtabs_and_lines sals;
01013   char *args;
01014 
01015   if (objc != 2)
01016     {
01017       Tcl_WrongNumArgs (interp, 1, objv, "linespec");
01018       return TCL_ERROR;
01019     }
01020 
01021   args = Tcl_GetStringFromObj (objv[1], NULL);
01022   sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
01023   if (sals.nelts == 1)
01024     {
01025       Tcl_SetIntObj (result_ptr->obj_ptr, sals.sals[0].line);
01026       return TCL_OK;
01027     }
01028 
01029   Tcl_SetStringObj (result_ptr->obj_ptr, "N/A", -1);
01030   return TCL_OK;
01031 
01032 }
01033 
01034 /* This implements the tcl command "gdb_get_file"
01035 
01036 * It returns the file containing a given line spec.
01037 *
01038 * Tcl Arguments:
01039 *    linespec - The linespec to look up
01040 * Tcl Result:
01041 *    The file containing it.
01042 */
01043 
01044 static int
01045 gdb_get_file_command (ClientData clientData, Tcl_Interp *interp,
01046                       int objc, Tcl_Obj *CONST objv[])
01047 {
01048   struct symtabs_and_lines sals;
01049   char *args;
01050 
01051   if (objc != 2)
01052     {
01053       Tcl_WrongNumArgs (interp, 1, objv, "linespec");
01054       return TCL_ERROR;
01055     }
01056 
01057   args = Tcl_GetStringFromObj (objv[1], NULL);
01058   sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
01059   if (sals.nelts == 1)
01060     {
01061       Tcl_SetStringObj (result_ptr->obj_ptr,
01062                         sals.sals[0].symtab->filename, -1);
01063       return TCL_OK;
01064     }
01065 
01066   Tcl_SetStringObj (result_ptr->obj_ptr, "N/A", -1);
01067   return TCL_OK;
01068 }
01069 
01070 /* This implements the tcl command "gdb_get_function"
01071 
01072 * It finds the function containing the given line spec.
01073 *
01074 * Tcl Arguments:
01075 *    linespec - The line specification
01076 * Tcl Result:
01077 *    The function that contains it, or "N/A" if it is not in a function.
01078 */
01079 static int
01080 gdb_get_function_command (ClientData clientData, Tcl_Interp *interp,
01081                           int objc, Tcl_Obj *CONST objv[])
01082 {
01083   const char *function;
01084   struct symtabs_and_lines sals;
01085   char *args;
01086 
01087   if (objc != 2)
01088     {
01089       Tcl_WrongNumArgs (interp, 1, objv, "linespec");
01090       return TCL_ERROR;
01091     }
01092 
01093   args = Tcl_GetStringFromObj (objv[1], NULL);
01094   sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
01095   if (sals.nelts == 1)
01096     {
01097       resolve_sal_pc (&sals.sals[0]);
01098       function = pc_function_name (sals.sals[0].pc);
01099       Tcl_SetStringObj (result_ptr->obj_ptr, function, -1);
01100       return TCL_OK;
01101     }
01102 
01103   Tcl_SetStringObj (result_ptr->obj_ptr, "N/A", -1);
01104   return TCL_OK;
01105 }
01106 
01107 /* This implements the tcl command "gdb_find_file"
01108 
01109 * It searches the symbol tables to get the full pathname to a file.
01110 *
01111 * Tcl Arguments:
01112 *    filename: the file name to search for.
01113 * Tcl Result:
01114 *    The full path to the file, an empty string if the file was not
01115 *    available or an error message if the file is not found in the symtab.
01116 */
01117 
01118 static int
01119 gdb_find_file_command (ClientData clientData, Tcl_Interp *interp,
01120                        int objc, Tcl_Obj *CONST objv[])
01121 {
01122   struct symtab *st;
01123   char *filename, *fullname = NULL;
01124 
01125   if (objc != 2)
01126     {
01127       Tcl_WrongNumArgs (interp, 1, objv, "filename");
01128       return TCL_ERROR;
01129     }
01130 
01131   filename = Tcl_GetStringFromObj (objv[1], NULL);
01132 
01133   /* Shortcut: There seems to be some mess in gdb dealing with
01134      files. While we should let gdb sort it out, it doesn't hurt
01135      to be a little defensive here.
01136 
01137      If the filename is already an absolute filename, just try
01138      to stat it. If it's not found, then ask gdb to find it for us. */
01139   if (IS_ABSOLUTE_PATH (filename))
01140     {
01141       struct stat st;
01142       const int status = stat (filename, &st);
01143 
01144       if (status == 0)
01145         {
01146           if (S_ISREG (st.st_mode))
01147             fullname = filename;
01148         }
01149     }
01150   else
01151     {
01152       /* Ask gdb to find the file for us. */
01153       st = lookup_symtab (filename);
01154 
01155       /* We should always get a symtab. */
01156       if (!st)
01157         {
01158           gdbtk_set_result (interp, "File not found in symtab (2)");
01159           return TCL_ERROR;
01160         }
01161 
01162       fullname =
01163         (st->fullname == NULL ? symtab_to_filename (st) : st->fullname);
01164     }
01165   
01166   /* We may not be able to open the file (not available). */
01167   if (fullname == NULL)
01168     {
01169       Tcl_SetStringObj (result_ptr->obj_ptr, "", -1);
01170       return TCL_OK;
01171     }
01172 
01173   Tcl_SetStringObj (result_ptr->obj_ptr, fullname, -1);
01174 
01175   return TCL_OK;
01176 }
01177 
01178 /* An object of this type is passed to do_listfiles.  */
01179 
01180 struct listfiles_info
01181 {
01182   int *numfilesp;
01183   int *files_sizep;
01184   const char ***filesp;
01185   int len;
01186   const char *pathname;
01187 };
01188 
01189 /* This is a helper function for gdb_listfiles that is used via
01190    map_partial_symbol_filenames.  */
01191 
01192 static void
01193 do_listfiles (const char *filename, const char *fullname, void *data)
01194 {
01195   struct listfiles_info *info = data;
01196 
01197   if (*info->numfilesp == *info->files_sizep)
01198     {
01199       *info->files_sizep *= 2;
01200       *info->filesp = xrealloc (*info->filesp,
01201                                 *info->files_sizep * sizeof (char *));
01202     }
01203 
01204   if (filename)
01205     {
01206       if (!info->len || !strncmp (info->pathname, filename, info->len)
01207           || !strcmp (filename, lbasename (filename)))
01208         {
01209           (*info->filesp)[(*info->numfilesp)++] = lbasename (filename);
01210         }
01211     }
01212 }
01213 
01214 /* This implements the tcl command "gdb_listfiles"
01215 
01216 * This lists all the files in the current executible.
01217 *
01218 * Note that this currently pulls in all sorts of filenames
01219 * that aren't really part of the executable.  It would be
01220 * best if we could check each file to see if it actually
01221 * contains executable lines of code, but we can't do that
01222 * with psymtabs.
01223 *
01224 * Arguments:
01225 *    ?pathname? - If provided, only files which match pathname
01226 *        (up to strlen(pathname)) are included. THIS DOES NOT
01227 *        CURRENTLY WORK BECAUSE PARTIAL_SYMTABS DON'T SUPPLY
01228 *        THE FULL PATHNAME!!!
01229 *
01230 * Tcl Result:
01231 *    A list of all matching files.
01232 */
01233 static int
01234 gdb_listfiles (ClientData clientData, Tcl_Interp *interp,
01235                int objc, Tcl_Obj *CONST objv[])
01236 {
01237   struct objfile *objfile;
01238   struct partial_symtab *psymtab;
01239   struct symtab *symtab;
01240   const char *lastfile, *pathname = NULL;
01241   const char **files;
01242   int files_size;
01243   int i, numfiles = 0, len = 0;
01244   struct listfiles_info info;
01245 
01246   files_size = 1000;
01247   files = (const char **) xmalloc (sizeof (char *) * files_size);
01248 
01249   if (objc > 2)
01250     {
01251       Tcl_WrongNumArgs (interp, 1, objv, "?pathname?");
01252       return TCL_ERROR;
01253     }
01254   else if (objc == 2)
01255     pathname = Tcl_GetStringFromObj (objv[1], &len);
01256 
01257   info.numfilesp = &numfiles;
01258   info.files_sizep = &files_size;
01259   info.filesp = &files;
01260   info.len = len;
01261   info.pathname = pathname;
01262   map_partial_symbol_filenames (do_listfiles, &info, 0);
01263 
01264   ALL_SYMTABS (objfile, symtab)
01265     {
01266       if (numfiles == files_size)
01267         {
01268           files_size = files_size * 2;
01269           files = (const char **) xrealloc (files, sizeof (char *) * files_size);
01270         }
01271       if (symtab->filename && symtab->linetable && symtab->linetable->nitems)
01272         {
01273           if (!len || !strncmp (pathname, symtab->filename, len)
01274               || !strcmp (symtab->filename, lbasename (symtab->filename)))
01275             {
01276               files[numfiles++] = lbasename (symtab->filename);
01277             }
01278         }
01279     }
01280 
01281   qsort (files, numfiles, sizeof (char *), comp_files);
01282 
01283   lastfile = "";
01284 
01285   /* Discard the old result pointer, in case it has accumulated anything
01286      and set it to a new list object */
01287 
01288   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
01289 
01290   for (i = 0; i < numfiles; i++)
01291     {
01292       if (strcmp (files[i], lastfile))
01293         Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr,
01294                                   Tcl_NewStringObj (files[i], -1));
01295       lastfile = files[i];
01296     }
01297 
01298   free (files);
01299   return TCL_OK;
01300 }
01301 
01302 static int
01303 comp_files (const void *file1, const void *file2)
01304 {
01305   return strcmp (*(char **) file1, *(char **) file2);
01306 }
01307 
01308 
01309 /* This implements the tcl command "gdb_search"
01310 
01311 
01312 * Tcl Arguments:
01313 *    option - One of "functions", "variables" or "types"
01314 *    regexp - The regular expression to look for.
01315 * Then, optionally:
01316 *    -files fileList
01317 *    -static 1/0
01318 *    -filename 1/0
01319 * Tcl Result:
01320 *    A list of all the matches found.  Optionally, if -filename is set to 1,
01321 *    then the output is a list of two element lists, with the symbol first,
01322 *    and the file in which it is found second.
01323 */
01324 
01325 static int
01326 gdb_search (ClientData clientData, Tcl_Interp *interp,
01327             int objc, Tcl_Obj *CONST objv[])
01328 {
01329   struct symbol_search *ss = NULL;
01330   struct symbol_search *p;
01331   struct cleanup *old_chain = NULL;
01332   Tcl_Obj *CONST * switch_objv;
01333   int index, switch_objc, i, show_files = 0;
01334   domain_enum space = 0;
01335   char *regexp;
01336   int static_only, nfiles;
01337   Tcl_Obj **file_list;
01338   char **files;
01339   static const char *search_options[] =
01340     {"functions", "variables", "types", (char *) NULL};
01341   static const char *switches[] =
01342     {"-files", "-filename", "-static", (char *) NULL};
01343   enum search_opts
01344     {
01345       SEARCH_FUNCTIONS, SEARCH_VARIABLES, SEARCH_TYPES
01346     };
01347   enum switches_opts
01348     {
01349       SWITCH_FILES, SWITCH_FILENAME, SWITCH_STATIC_ONLY
01350     };
01351 
01352   if (objc < 3)
01353     {
01354       Tcl_WrongNumArgs (interp, 1, objv, "option regexp ?arg ...?");
01355       return TCL_ERROR;
01356     }
01357 
01358   if (Tcl_GetIndexFromObj (interp, objv[1], search_options, "option", 0,
01359                            &index) != TCL_OK)
01360     {
01361       result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01362       return TCL_ERROR;
01363     }
01364 
01365   /* Unfortunately, we cannot teach search_symbols to search on
01366      multiple regexps, so we have to do a two-tier search for
01367      any searches which choose to narrow the playing field. */
01368   switch ((enum search_opts) index)
01369     {
01370     case SEARCH_FUNCTIONS:
01371       space = FUNCTIONS_DOMAIN;
01372       break;
01373     case SEARCH_VARIABLES:
01374       space = VARIABLES_DOMAIN;
01375       break;
01376     case SEARCH_TYPES:
01377       space = TYPES_DOMAIN;
01378       break;
01379     }
01380 
01381   regexp = Tcl_GetStringFromObj (objv[2], NULL);
01382   /* Process any switches that refine the search */
01383   switch_objc = objc - 3;
01384   switch_objv = objv + 3;
01385 
01386   static_only = 0;
01387   nfiles = 0;
01388   files = (char **) NULL;
01389   while (switch_objc > 0)
01390     {
01391       if (Tcl_GetIndexFromObj (interp, switch_objv[0], switches,
01392                                "option", 0, &index) != TCL_OK)
01393         {
01394           result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01395           return TCL_ERROR;
01396         }
01397 
01398       switch ((enum switches_opts) index)
01399         {
01400         case SWITCH_FILENAME:
01401           {
01402             if (switch_objc < 2)
01403               {
01404                 Tcl_WrongNumArgs (interp, 3, objv,
01405                                   "?-files fileList  -filename 1|0 -static 1|0?");
01406                 result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01407                 return TCL_ERROR;
01408               }
01409             if (Tcl_GetBooleanFromObj (interp, switch_objv[1], &show_files)
01410                 != TCL_OK)
01411               {
01412                 result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01413                 return TCL_ERROR;
01414               }
01415             switch_objc--;
01416             switch_objv++;
01417           }
01418           break;
01419         case SWITCH_FILES:
01420           {
01421             int result;
01422             if (switch_objc < 2)
01423               {
01424                 Tcl_WrongNumArgs (interp, 3, objv,
01425                                   "?-files fileList  -filename 1|0 -static 1|0?");
01426                 result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01427                 return TCL_ERROR;
01428               }
01429             result = Tcl_ListObjGetElements (interp, switch_objv[1],
01430                                              &nfiles, &file_list);
01431             if (result != TCL_OK)
01432               return result;
01433 
01434             files = (char **) xmalloc (nfiles * sizeof (char *));
01435             for (i = 0; i < nfiles; i++)
01436               files[i] = Tcl_GetStringFromObj (file_list[i], NULL);
01437             switch_objc--;
01438             switch_objv++;
01439           }
01440           break;
01441         case SWITCH_STATIC_ONLY:
01442           if (switch_objc < 2)
01443             {
01444               Tcl_WrongNumArgs (interp, 3, objv,
01445                                 "?-files fileList  -filename 1|0 -static 1|0?");
01446               result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01447               return TCL_ERROR;
01448             }
01449           if (Tcl_GetBooleanFromObj (interp, switch_objv[1], &static_only)
01450               != TCL_OK)
01451             {
01452               result_ptr->flags |= GDBTK_IN_TCL_RESULT;
01453               return TCL_ERROR;
01454             }
01455           switch_objc--;
01456           switch_objv++;
01457         }
01458       switch_objc--;
01459       switch_objv++;
01460     }
01461 
01462   search_symbols (regexp, space, nfiles, files, &ss);
01463   if (ss != NULL)
01464     old_chain = make_cleanup_free_search_symbols (&ss);
01465 
01466   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
01467 
01468   for (p = ss; p != NULL; p = p->next)
01469     {
01470       Tcl_Obj *elem;
01471 
01472       if (static_only && p->block != STATIC_BLOCK)
01473         continue;
01474 
01475       /* Strip off some C++ special symbols, like RTTI and global
01476          constructors/destructors. */
01477       if ((p->symbol != NULL
01478            && strncmp (SYMBOL_LINKAGE_NAME (p->symbol), "__tf", 4) != 0
01479            && strncmp (SYMBOL_LINKAGE_NAME (p->symbol), "_GLOBAL_", 8) != 0)
01480           || p->msymbol.minsym != NULL)
01481         {
01482           elem = Tcl_NewListObj (0, NULL);
01483 
01484           if (p->msymbol.minsym == NULL)
01485             Tcl_ListObjAppendElement (interp, elem,
01486                                       Tcl_NewStringObj (SYMBOL_PRINT_NAME (p->symbol), -1));
01487           else
01488             Tcl_ListObjAppendElement (interp, elem,
01489                                       Tcl_NewStringObj (SYMBOL_PRINT_NAME (p->msymbol.minsym), -1));
01490 
01491           if (show_files)
01492             {
01493               if ((p->symtab != NULL) && (p->symtab->filename != NULL))
01494                 {
01495                   Tcl_ListObjAppendElement (interp, elem, Tcl_NewStringObj
01496                                             (p->symtab->filename, -1));
01497                 }
01498               else
01499                 {
01500                   Tcl_ListObjAppendElement (interp, elem,
01501                                             Tcl_NewStringObj ("", 0));
01502                 }
01503             }
01504 
01505           Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, elem);
01506         }
01507     }
01508 
01509   if (ss != NULL)
01510     do_cleanups (old_chain);
01511 
01512   return TCL_OK;
01513 }
01514 
01515 /* This implements the tcl command gdb_listfuncs
01516 
01517 * It lists all the functions defined in a given file
01518 * 
01519 * Arguments:
01520 *    file - the file to look in
01521 * Tcl Result:
01522 *    A list of two element lists, the first element is
01523 *    the symbol name, and the second is a boolean indicating
01524 *    whether the symbol is demangled (1 for yes).
01525 */
01526 
01527 static int
01528 gdb_listfuncs (ClientData clientData, Tcl_Interp *interp,
01529                int objc, Tcl_Obj *CONST objv[])
01530 {
01531   struct symtab *symtab;
01532   struct blockvector *bv;
01533   struct block *b;
01534   struct symbol *sym;
01535   int i;
01536   struct block_iterator iter;
01537   Tcl_Obj *funcVals[2];
01538 
01539   if (objc != 2)
01540     {
01541       Tcl_WrongNumArgs (interp, 1, objv, "file");
01542       return TCL_ERROR;
01543     }
01544 
01545   symtab = lookup_symtab (Tcl_GetStringFromObj (objv[1], NULL));
01546   if (!symtab)
01547     {
01548       gdbtk_set_result (interp, "No such file (%s)", 
01549                         Tcl_GetStringFromObj (objv[1], NULL));
01550       return TCL_ERROR;
01551     }
01552   
01553   if (mangled == NULL)
01554     {
01555       mangled = Tcl_NewBooleanObj (1);
01556       not_mangled = Tcl_NewBooleanObj (0);
01557       Tcl_IncrRefCount (mangled);
01558       Tcl_IncrRefCount (not_mangled);
01559     }
01560 
01561   Tcl_SetListObj (result_ptr->obj_ptr, 0, NULL);
01562 
01563   bv = BLOCKVECTOR (symtab);
01564   for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
01565     {
01566       b = BLOCKVECTOR_BLOCK (bv, i);
01567       ALL_BLOCK_SYMBOLS (b, iter, sym)
01568         {
01569           if (SYMBOL_CLASS (sym) == LOC_BLOCK)
01570             {
01571 
01572               const char *name = SYMBOL_DEMANGLED_NAME (sym);
01573 
01574               if (name)
01575                 {
01576                   /* strip out "global constructors" and
01577                    * "global destructors"
01578                    * because we aren't interested in them. */
01579                   
01580                   if (strncmp (name, "global ", 7))
01581                     {
01582                       /* If the function is overloaded,
01583                        * print out the functions
01584                        * declaration, not just its name. */
01585 
01586                       funcVals[0] = Tcl_NewStringObj (name, -1);
01587                       funcVals[1] = mangled;
01588                     }
01589                   else
01590                     continue;
01591 
01592                 }
01593               else
01594                 {
01595                   funcVals[0] = Tcl_NewStringObj (SYMBOL_PRINT_NAME (sym), -1);
01596                   funcVals[1] = not_mangled;
01597                 }
01598               Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
01599                                         Tcl_NewListObj (2, funcVals));
01600             }
01601         }
01602     }
01603   return TCL_OK;
01604 }
01605 
01606 /* This implements the TCL command `gdb_restore_fputs'
01607    It sets the fputs_unfiltered hook back to gdbtk_fputs.
01608    Its sole reason for being is that sometimes we move the
01609    fputs hook out of the way to specially trap output, and if
01610    we get an error which we weren't expecting, it won't get put
01611    back, so we run this at idle time as insurance.
01612 */
01613 
01614 static int
01615 gdb_restore_fputs (ClientData clientData, Tcl_Interp *interp,
01616                    int objc, Tcl_Obj *CONST objv[])
01617 {
01618   gdbtk_disable_fputs = 0;
01619   return TCL_OK;
01620 }
01621 
01622 
01623 /* This implements the tcl command gdb_load_disassembly
01624  *
01625  * Arguments:
01626  *    widget - the name of a text widget into which to load the data
01627  *    source_with_assm - must be "source" or "nosource"
01628  *    low_address - the CORE_ADDR from which to start disassembly
01629  *    ?hi_address? - the CORE_ADDR to which to disassemble, defaults
01630  *                   to the end of the function containing low_address.
01631  * Tcl Result:
01632  *    The text widget is loaded with the data, and a list is returned.
01633  *    The first element of the list is a two element list containing the
01634  *    real low & high elements, the rest is a mapping between line number
01635  *    in the text widget, and either the source line number of that line,
01636  *    if it is a source line, or the assembly address.  You can distinguish
01637  *    between the two, because the address will start with 0x...
01638  */
01639 
01640 static int
01641 gdb_load_disassembly (ClientData clientData, Tcl_Interp *interp,
01642                       int objc, Tcl_Obj *CONST objv[])
01643 {
01644   CORE_ADDR low, high, orig;
01645   struct disassembly_client_data client_data;
01646   int mixed_source_and_assembly, ret_val, i;
01647   char *arg_ptr;
01648   char *map_name;
01649   Tcl_WideInt waddr;
01650 
01651   if (objc != 6 && objc != 7)
01652     {
01653       Tcl_WrongNumArgs (interp, 1, objv, "[source|nosource] map_arr index_prefix low_address ?hi_address");
01654       return TCL_ERROR;
01655     }
01656 
01657   client_data.widget = Tcl_GetStringFromObj (objv[1], NULL);
01658   if ( Tk_NameToWindow (interp, client_data.widget,
01659                         Tk_MainWindow (interp)) == NULL)
01660     {
01661       gdbtk_set_result (interp, "Invalid widget name.");
01662       return TCL_ERROR;
01663     }
01664 
01665   if (!Tcl_GetCommandInfo (interp, client_data.widget, &client_data.cmd))
01666     {
01667       gdbtk_set_result (interp, "Can't get widget command info");
01668       return TCL_ERROR;
01669     }
01670 
01671   arg_ptr = Tcl_GetStringFromObj (objv[2], NULL);
01672   if (*arg_ptr == 's' && strcmp (arg_ptr, "source") == 0)
01673     mixed_source_and_assembly = 1;
01674   else if (*arg_ptr == 'n' && strcmp (arg_ptr, "nosource") == 0)
01675     mixed_source_and_assembly = 0;
01676   else
01677     {
01678       gdbtk_set_result (interp, "Second arg must be 'source' or 'nosource'");
01679       return TCL_ERROR;
01680     }
01681 
01682   /* As we populate the text widget, we will also create an array in the
01683      caller's scope.  The name is given by objv[3].
01684      Each source line gets an entry or the form:
01685      array($prefix,srcline=$src_line_no) = $widget_line_no
01686 
01687      Each assembly line gets two entries of the form:
01688      array($prefix,pc=$pc) = $widget_line_no
01689      array($prefix,line=$widget_line_no) = $src_line_no
01690 
01691      Where prefix is objv[4].
01692   */
01693     
01694   map_name = Tcl_GetStringFromObj (objv[3], NULL);
01695 
01696   if (*map_name != '\0')
01697     {
01698       char *prefix;
01699       int prefix_len;
01700       
01701       client_data.map_arr = "map_array";
01702       if (Tcl_UpVar (interp, "1", map_name, client_data.map_arr, 0) != TCL_OK)
01703         {
01704           gdbtk_set_result (interp, "Can't link map array.");
01705           return TCL_ERROR;
01706         }
01707 
01708       prefix = Tcl_GetStringFromObj (objv[4], &prefix_len);
01709       
01710       Tcl_DStringInit(&client_data.src_to_line_prefix);
01711       Tcl_DStringAppend (&client_data.src_to_line_prefix,
01712                          prefix, prefix_len);
01713       Tcl_DStringAppend (&client_data.src_to_line_prefix, ",srcline=",
01714                          sizeof (",srcline=") - 1);
01715                               
01716       Tcl_DStringInit(&client_data.pc_to_line_prefix);
01717       Tcl_DStringAppend (&client_data.pc_to_line_prefix,
01718                          prefix, prefix_len);
01719       Tcl_DStringAppend (&client_data.pc_to_line_prefix, ",pc=",
01720                          sizeof (",pc=") - 1);
01721       
01722       Tcl_DStringInit(&client_data.line_to_pc_prefix);
01723       Tcl_DStringAppend (&client_data.line_to_pc_prefix,
01724                          prefix, prefix_len);
01725       Tcl_DStringAppend (&client_data.line_to_pc_prefix, ",line=",
01726                          sizeof (",line=") - 1);
01727 
01728     }
01729   else
01730     {
01731       client_data.map_arr = "";
01732     }
01733 
01734   /* Now parse the addresses */
01735   if (Tcl_GetWideIntFromObj (interp, objv[5], &waddr) != TCL_OK)
01736     return TCL_ERROR;
01737   low = waddr;
01738 
01739   orig = low;
01740 
01741   if (objc == 6)
01742     {
01743       if (find_pc_partial_function (low, NULL, &low, &high) == 0)
01744         error ("No function contains address 0x%s", core_addr_to_string (orig));
01745     }
01746   else
01747     {
01748       if (Tcl_GetWideIntFromObj (interp, objv[6], &waddr) != TCL_OK)
01749         return TCL_ERROR;
01750       high = waddr;
01751     }
01752   
01753   /* Setup the client_data structure, and call the driver function. */
01754   
01755   client_data.file_opened_p = 0;
01756   client_data.widget_line_no = 0;
01757   client_data.interp = interp;
01758   for (i = 0; i < 3; i++)
01759     {
01760       client_data.result_obj[i] = Tcl_NewObj();
01761       Tcl_IncrRefCount (client_data.result_obj[i]);
01762     }
01763 
01764   /* Fill up the constant parts of the argv structures */
01765   client_data.asm_argv[0] = client_data.widget;
01766   client_data.asm_argv[1] = "insert";
01767   client_data.asm_argv[2] = "end";
01768   client_data.asm_argv[3] = "-\t";
01769   client_data.asm_argv[4] = "break_rgn_tag";
01770   /* client_data.asm_argv[5] = address; */
01771   client_data.asm_argv[6] = "break_rgn_tag";
01772   /* client_data.asm_argv[7] = offset; */
01773   client_data.asm_argv[8] = "break_rgn_tag";
01774   client_data.asm_argv[9] = ":\t\t";
01775   client_data.asm_argv[10] = "source_tag";
01776   /* client_data.asm_argv[11] = code; */
01777   client_data.asm_argv[12] = "source_tag";
01778   client_data.asm_argv[13] = "\n";
01779 
01780   if (mixed_source_and_assembly)
01781     {
01782       client_data.source_argv[0] = client_data.widget;
01783       client_data.source_argv[1] = "insert";
01784       client_data.source_argv[2] = "end";
01785       /* client_data.source_argv[3] = line_number; */
01786       client_data.source_argv[4] = "";
01787       /* client_data.source_argv[5] = line; */
01788       client_data.source_argv[6] = "source_tag2";
01789     }
01790   
01791   ret_val = gdb_disassemble_driver (low, high, mixed_source_and_assembly, 
01792                                     (ClientData) &client_data,
01793                                     gdbtk_load_source, gdbtk_load_asm);
01794 
01795   /* Now clean up the opened file, and the Tcl data structures */
01796   
01797   if (client_data.file_opened_p == 1) 
01798     fclose(client_data.fp);
01799   
01800   if (*client_data.map_arr != '\0')
01801     {
01802       Tcl_DStringFree(&client_data.src_to_line_prefix);
01803       Tcl_DStringFree(&client_data.pc_to_line_prefix);
01804       Tcl_DStringFree(&client_data.line_to_pc_prefix);
01805     }
01806   
01807   for (i = 0; i < 3; i++)
01808     {
01809       Tcl_DecrRefCount (client_data.result_obj[i]);
01810     }
01811   
01812   /* Finally, if we were successful, stick the low & high addresses
01813      into the Tcl result. */
01814 
01815   if (ret_val == TCL_OK) 
01816     {
01817       Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
01818                                 Tcl_NewStringObj (core_addr_to_string (low), -1));
01819       Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
01820                                 Tcl_NewStringObj (core_addr_to_string (high), -1));
01821     }
01822   return ret_val;
01823 }
01824 
01825 static void
01826 gdbtk_load_source (ClientData clientData, struct symtab *symtab, 
01827                    int start_line, int end_line)
01828 {
01829   struct disassembly_client_data *client_data =
01830     (struct disassembly_client_data *) clientData;
01831   char *buffer;
01832   int index_len;
01833 
01834   index_len = Tcl_DStringLength (&client_data->src_to_line_prefix);
01835   
01836   if (client_data->file_opened_p == 1)
01837     {
01838       const char **text_argv;
01839       char line[10000], line_number[18];
01840       int found_carriage_return = 1;
01841 
01842       /* First do some sanity checks on the requested lines */
01843 
01844       if (start_line < 1
01845           || end_line < start_line || end_line > symtab->nlines)
01846         {
01847           return;
01848         }
01849 
01850       line_number[0] = '\t';
01851       line[0] = '\t';
01852 
01853       text_argv = client_data->source_argv;
01854       
01855       text_argv[3] = line_number;
01856       text_argv[5] = line;
01857 
01858       if (fseek (client_data->fp, symtab->line_charpos[start_line - 1],
01859                  SEEK_SET) < 0)
01860         {
01861           fclose(client_data->fp);
01862           client_data->file_opened_p = -1;
01863           return;
01864         }
01865       
01866       for (; start_line < end_line; start_line++)
01867         {
01868           if (!fgets (line + 1, 9980, client_data->fp))
01869             {
01870               fclose(client_data->fp);
01871               client_data->file_opened_p = -1;
01872               return;
01873             }
01874 
01875           client_data->widget_line_no++;
01876           
01877           sprintf (line_number + 1, "%d", start_line);
01878           
01879           if (found_carriage_return)
01880             {
01881               char *p = strrchr(line, '\0') - 2;
01882               if (*p == '\r')
01883                 {
01884                   *p = '\n';
01885                   *(p + 1) = '\0';
01886                 }
01887               else 
01888                 found_carriage_return = 0;
01889             }
01890           
01891           /* Run the command, then add an entry to the map array in
01892              the caller's scope, if requested. */
01893           
01894           client_data->cmd.proc (client_data->cmd.clientData, 
01895                                  client_data->interp, 7, text_argv);
01896           
01897           if (*client_data->map_arr != '\0')
01898             {
01899               
01900               Tcl_DStringAppend (&client_data->src_to_line_prefix,
01901                                  line_number + 1, -1);
01902               
01903               /* FIXME: Convert to Tcl_SetVar2Ex when we move to 8.2.  This
01904                  will allow us avoid converting widget_line_no into a string. */
01905               
01906               buffer = xstrprintf ("%d", client_data->widget_line_no);
01907               
01908               Tcl_SetVar2 (client_data->interp, client_data->map_arr,
01909                            Tcl_DStringValue (&client_data->src_to_line_prefix),
01910                            buffer, 0);
01911               free(buffer);
01912               
01913               Tcl_DStringSetLength (&client_data->src_to_line_prefix, index_len);
01914             }
01915         }
01916       
01917     }
01918   else if (!client_data->file_opened_p)
01919     {
01920       int fdes;
01921       /* The file is not yet open, try to open it, then print the
01922          first line.  If we fail, set FILE_OPEN_P to -1. */
01923       
01924       fdes = open_source_file (symtab);
01925       if (fdes < 0)
01926         {
01927           client_data->file_opened_p = -1;
01928         }
01929       else
01930         {
01931           /* FIXME: Convert to a Tcl File Channel and read from there.
01932              This will allow us to get the line endings and conversion
01933              to UTF8 right automatically when we move to 8.2.
01934              Need a Cygwin call to convert a file descriptor to the native
01935              Windows handler to do this. */
01936              
01937           client_data->file_opened_p = 1;
01938           client_data->fp = fdopen (fdes, FOPEN_RB);
01939           clearerr (client_data->fp);
01940           
01941           if (symtab->line_charpos == 0)
01942             find_source_lines (symtab, fdes);
01943 
01944           /* We are called with an actual load request, so call ourselves
01945              to load the first line. */
01946           
01947           gdbtk_load_source (clientData, symtab, start_line, end_line);
01948         }
01949     }
01950   else 
01951     {
01952       /* If we couldn't open the file, or got some prior error, just exit. */
01953       return;
01954     }
01955 }
01956 
01957 
01958 /* FIXME: cagney/2003-09-08: "di" is not used and unneeded.  */
01959 static CORE_ADDR
01960 gdbtk_load_asm (ClientData clientData, CORE_ADDR pc, 
01961                 struct disassemble_info *di)
01962 {
01963   struct disassembly_client_data * client_data
01964     = (struct disassembly_client_data *) clientData;
01965   const char **text_argv;
01966   int i, pc_to_line_len, line_to_pc_len;
01967   gdbtk_result new_result;
01968   int insn;
01969   struct cleanup *old_chain = NULL;
01970 
01971   pc_to_line_len = Tcl_DStringLength (&client_data->pc_to_line_prefix);
01972   line_to_pc_len = Tcl_DStringLength (&client_data->line_to_pc_prefix);
01973     
01974   text_argv = client_data->asm_argv;
01975   
01976   /* Preserve the current Tcl result object, print out what we need, and then
01977      suck it out of the result, and replace... */
01978 
01979   old_chain = make_cleanup (gdbtk_restore_result_ptr, (void *) result_ptr);
01980   result_ptr = &new_result;
01981   result_ptr->obj_ptr = client_data->result_obj[0];
01982   result_ptr->flags = GDBTK_TO_RESULT;
01983 
01984   /* Null out the three return objects we will use. */
01985 
01986   for (i = 0; i < 3; i++)
01987     Tcl_SetObjLength (client_data->result_obj[i], 0);
01988 
01989   fputs_filtered (paddress (get_current_arch (), pc), gdb_stdout);
01990   gdb_flush (gdb_stdout);
01991 
01992   result_ptr->obj_ptr = client_data->result_obj[1];
01993   print_address_symbolic (get_current_arch (), pc, gdb_stdout, 1, "\t");
01994   gdb_flush (gdb_stdout);
01995 
01996   result_ptr->obj_ptr = client_data->result_obj[2];
01997   /* FIXME: cagney/2003-09-08: This should use gdb_disassembly.  */
01998   insn = gdb_print_insn (get_current_arch (), pc, gdb_stdout, NULL);
01999   gdb_flush (gdb_stdout);
02000 
02001   client_data->widget_line_no++;
02002 
02003   text_argv[5] = Tcl_GetStringFromObj (client_data->result_obj[0], NULL);
02004   text_argv[7] = Tcl_GetStringFromObj (client_data->result_obj[1], NULL);
02005   text_argv[11] = Tcl_GetStringFromObj (client_data->result_obj[2], NULL);
02006 
02007   client_data->cmd.proc (client_data->cmd.clientData, 
02008                          client_data->interp, 14, text_argv);
02009 
02010   if (*client_data->map_arr != '\0')
02011     {
02012       char *buffer;
02013       
02014       /* Run the command, then add an entry to the map array in
02015          the caller's scope. */
02016       
02017       Tcl_DStringAppend (&client_data->pc_to_line_prefix, core_addr_to_string (pc), -1);
02018       
02019       /* FIXME: Convert to Tcl_SetVar2Ex when we move to 8.2.  This
02020          will allow us avoid converting widget_line_no into a string. */
02021       
02022       buffer = xstrprintf ("%d", client_data->widget_line_no);
02023       
02024       Tcl_SetVar2 (client_data->interp, client_data->map_arr,
02025                    Tcl_DStringValue (&client_data->pc_to_line_prefix),
02026                    buffer, 0);
02027 
02028       Tcl_DStringAppend (&client_data->line_to_pc_prefix, buffer, -1);
02029       
02030 
02031       Tcl_SetVar2 (client_data->interp, client_data->map_arr,
02032                    Tcl_DStringValue (&client_data->line_to_pc_prefix),
02033                    core_addr_to_string (pc), 0);
02034       
02035       /* Restore the prefixes to their initial state. */
02036       
02037       Tcl_DStringSetLength (&client_data->pc_to_line_prefix, pc_to_line_len);      
02038       Tcl_DStringSetLength (&client_data->line_to_pc_prefix, line_to_pc_len);      
02039       
02040       xfree (buffer);
02041     }
02042   
02043   do_cleanups (old_chain);
02044 
02045   return pc + insn;
02046 }
02047 
02048 static int
02049 gdb_disassemble_driver (CORE_ADDR low, CORE_ADDR high, 
02050                         int mixed_source_and_assembly,
02051                         ClientData clientData, 
02052                         void (*print_source_fn) (ClientData, struct symtab *, int, int),
02053                         CORE_ADDR (*print_asm_fn) (ClientData, CORE_ADDR, struct disassemble_info *))
02054 {
02055   CORE_ADDR pc;
02056 
02057   /* If just doing straight assembly, all we need to do is disassemble
02058      everything between low and high.  If doing mixed source/assembly, we've
02059      got a totally different path to follow.  */
02060 
02061   if (mixed_source_and_assembly)
02062     {                           /* Come here for mixed source/assembly */
02063       /* The idea here is to present a source-O-centric view of a function to
02064          the user.  This means that things are presented in source order, with
02065          (possibly) out of order assembly immediately following.  */
02066       struct symtab *symtab;
02067       struct linetable_entry *le;
02068       int nlines;
02069       int newlines;
02070       struct my_line_entry *mle;
02071       struct symtab_and_line sal;
02072       int i;
02073       int out_of_order;
02074       int next_line;
02075       
02076       /* Assume symtab is valid for whole PC range */
02077       symtab = find_pc_symtab (low); 
02078 
02079       if (!symtab || !symtab->linetable)
02080         goto assembly_only;
02081 
02082       /* First, convert the linetable to a bunch of my_line_entry's.  */
02083 
02084       le = symtab->linetable->item;
02085       nlines = symtab->linetable->nitems;
02086 
02087       if (nlines <= 0)
02088         goto assembly_only;
02089 
02090       mle = (struct my_line_entry *) alloca (nlines *
02091                                              sizeof (struct my_line_entry));
02092 
02093       out_of_order = 0;
02094       
02095       /* Copy linetable entries for this function into our data structure,
02096          creating end_pc's and setting out_of_order as appropriate.  */
02097 
02098       /* First, skip all the preceding functions.  */
02099 
02100       for (i = 0; i < nlines - 1 && le[i].pc < low; i++) ;
02101 
02102       /* Now, copy all entries before the end of this function.  */
02103 
02104       newlines = 0;
02105       for (; i < nlines - 1 && le[i].pc < high; i++)
02106         {
02107           if (le[i].line == le[i + 1].line
02108               && le[i].pc == le[i + 1].pc)
02109             continue;           /* Ignore duplicates */
02110 
02111           /* Skip any end-of-function markers.  */
02112           if (le[i].line == 0)
02113             continue;
02114 
02115           mle[newlines].line = le[i].line;
02116           if (le[i].line > le[i + 1].line)
02117             out_of_order = 1;
02118           mle[newlines].start_pc = le[i].pc;
02119           mle[newlines].end_pc = le[i + 1].pc;
02120           newlines++;
02121         }
02122 
02123       /* If we're on the last line, and it's part of the function, then we 
02124          need to get the end pc in a special way.  */
02125 
02126       if (i == nlines - 1
02127           && le[i].pc < high)
02128         {
02129           mle[newlines].line = le[i].line;
02130           mle[newlines].start_pc = le[i].pc;
02131           sal = find_pc_line (le[i].pc, 0);
02132           mle[newlines].end_pc = sal.end;
02133           newlines++;
02134         }
02135 
02136       /* Now, sort mle by line #s (and, then by addresses within lines). */
02137 
02138       if (out_of_order)
02139         qsort (mle, newlines, sizeof (struct my_line_entry), compare_lines);
02140 
02141       /* Now, for each line entry, emit the specified lines (unless they have
02142          been emitted before), followed by the assembly code for that line.  */
02143 
02144       next_line = 0;            /* Force out first line */
02145       for (i = 0; i < newlines; i++)
02146         {
02147           /* Print out everything from next_line to the current line.  */
02148 
02149           if (mle[i].line >= next_line)
02150             {
02151               if (next_line != 0)
02152                 print_source_fn (clientData, symtab, next_line,
02153                                  mle[i].line + 1);
02154               else
02155                 print_source_fn (clientData, symtab, mle[i].line,
02156                                  mle[i].line + 1);
02157 
02158               next_line = mle[i].line + 1;
02159             }
02160 
02161           for (pc = mle[i].start_pc; pc < mle[i].end_pc; )
02162             {
02163               QUIT;
02164               /* FIXME: cagney/2003-09-08: This entire function should
02165                  be replaced by gdb_disassembly.  */
02166               pc = print_asm_fn (clientData, pc, NULL);
02167             }
02168         }
02169     }
02170   else
02171     {
02172     assembly_only:
02173       for (pc = low; pc < high; )
02174         {
02175           QUIT;
02176           /* FIXME: cagney/2003-09-08: This entire function should be
02177              replaced by gdb_disassembly.  */
02178           pc = print_asm_fn (clientData, pc, NULL);
02179         }
02180     }
02181 
02182   return TCL_OK;
02183 }
02184 
02185 /* This will be passed to qsort to sort the results of the disassembly */
02186 
02187 static int
02188 compare_lines (const PTR mle1p, const PTR mle2p)
02189 {
02190   struct my_line_entry *mle1, *mle2;
02191   int val;
02192 
02193   mle1 = (struct my_line_entry *) mle1p;
02194   mle2 = (struct my_line_entry *) mle2p;
02195 
02196   val = mle1->line - mle2->line;
02197 
02198   if (val != 0)
02199     return val;
02200 
02201   return mle1->start_pc - mle2->start_pc;
02202 }
02203 
02204 /* This implements the TCL command `gdb_loc',
02205 
02206 * Arguments:
02207 *    ?symbol? The symbol or address to locate - defaults to pc
02208 * Tcl Return:
02209 *    a list consisting of the following:                                  
02210 *       basename, function name, filename, line number, address, current pc
02211 */
02212 
02213 static int
02214 gdb_loc (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
02215 {
02216   char *filename;
02217   struct symtab_and_line sal;
02218   const char *fname;
02219   CORE_ADDR pc;
02220 
02221   if (objc == 1)
02222     {
02223       /* This function can be called, before the target is properly
02224          set-up, the following prevents an error, by trying to
02225          read_pc when there is no pc to read. It defaults pc, 
02226          before the target is connected to the entry point of the
02227          program */
02228       if (!target_has_registers)
02229         {
02230           pc = entry_point_address ();
02231           sal = find_pc_line (pc, 0);
02232         }  
02233       else
02234         {
02235           struct frame_info *frame;
02236           CORE_ADDR frame_pc, current_pc;
02237 
02238           frame = get_selected_frame (NULL);
02239           current_pc = regcache_read_pc (get_current_regcache ());
02240           frame_pc = get_frame_pc (frame);
02241  
02242           if (frame_pc != current_pc)
02243             {
02244               /* Note - this next line is not correct on all architectures.
02245                  For a graphical debugger we really want to highlight the 
02246                  assembly line that called the next function on the stack.
02247                  Many architectures have the next instruction saved as the
02248                  pc on the stack, so what happens is the next instruction 
02249                  is highlighted. FIXME */
02250               pc = frame_pc;
02251               find_frame_sal (frame, &sal);
02252             }
02253           else
02254             {
02255               pc = current_pc;
02256               sal = find_pc_line (pc, 0);
02257             }
02258         }
02259     }
02260   else if (objc == 2)
02261     {
02262       struct symtabs_and_lines sals;
02263       int nelts;
02264 
02265       sals = decode_line_with_current_source (Tcl_GetStringFromObj (objv[1], NULL), 1);
02266 
02267       nelts = sals.nelts;
02268       sal = sals.sals[0];
02269       free (sals.sals);
02270 
02271       if (sals.nelts != 1)
02272         {
02273           gdbtk_set_result (interp, "Ambiguous line spec", -1);
02274           return TCL_ERROR;
02275         }
02276       resolve_sal_pc (&sal);
02277       pc = sal.pc;
02278     }
02279   else
02280     {
02281       Tcl_WrongNumArgs (interp, 1, objv, "?symbol?");
02282       return TCL_ERROR;
02283     }
02284 
02285   if (sal.symtab)
02286     Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
02287                               Tcl_NewStringObj (sal.symtab->filename, -1));
02288   else
02289     Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
02290                               Tcl_NewStringObj ("", 0));
02291 
02292   fname = pc_function_name (pc);
02293   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
02294                             Tcl_NewStringObj (fname, -1));
02295 
02296   filename = symtab_to_filename (sal.symtab);
02297   if (filename == NULL)
02298     filename = "";
02299 
02300   /* file name */
02301   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, Tcl_NewStringObj (filename, -1));
02302   /* line number */
02303   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, Tcl_NewIntObj (sal.line));
02304   /* PC in current frame */
02305   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 
02306                             Tcl_NewStringObj (core_addr_to_string (pc), -1));
02307   /* Real PC */
02308   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr, 
02309                             Tcl_NewStringObj (core_addr_to_string (stop_pc), -1));
02310   /* shared library */
02311 #ifdef PC_SOLIB
02312   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
02313                             Tcl_NewStringObj (PC_SOLIB (pc), -1));
02314 #else
02315   Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
02316                             Tcl_NewStringObj ("", -1));
02317 #endif
02318   return TCL_OK;
02319 }
02320 
02321 /* This implements the TCL command gdb_entry_point.  It returns the current
02322    entry point address.  */
02323 
02324 static int
02325 gdb_entry_point (ClientData clientData, Tcl_Interp *interp,
02326                  int objc, Tcl_Obj *CONST objv[])
02327 {
02328   char *addrstr;
02329 
02330   /* If we have not yet loaded an exec file, then we have no
02331      entry point, so return an empty string.*/
02332   if ((int) current_target.to_stratum > (int) dummy_stratum)
02333     {
02334       addrstr = (char *)core_addr_to_string (entry_point_address ());
02335       Tcl_SetStringObj (result_ptr->obj_ptr, addrstr, -1);
02336     }
02337   else
02338     Tcl_SetStringObj (result_ptr->obj_ptr, "", -1);
02339 
02340   return TCL_OK;
02341 }
02342 
02343 /* Covert hex to binary. Stolen from remote.c,
02344    but added error handling */
02345 static int
02346 fromhex (int a)
02347 {
02348   if (a >= '0' && a <= '9')
02349     return a - '0';
02350   else if (a >= 'a' && a <= 'f')
02351     return a - 'a' + 10;
02352   else if (a >= 'A' && a <= 'F')
02353     return a - 'A' + 10;
02354 
02355   return -1;
02356 }
02357 
02358 static int
02359 hex2bin (const char *hex, char *bin, int count)
02360 {
02361   int i, m, n;
02362   int incr = 2;
02363 
02364 
02365   if (gdbarch_byte_order (get_current_arch ()) == BFD_ENDIAN_LITTLE)
02366     {
02367       /* need to read string in reverse */
02368       hex += count - 2;
02369       incr = -2;
02370     }
02371 
02372   for (i = 0; i < count; i += 2)
02373     {
02374       if (hex[0] == 0 || hex[1] == 0)
02375         {
02376           /* Hex string is short, or of uneven length.
02377              Return the count that has been converted so far. */
02378           return i;
02379         }
02380       m = fromhex (hex[0]);
02381       n = fromhex (hex[1]);
02382       if (m == -1 || n == -1)
02383         return -1;
02384       *bin++ = m * 16 + n;
02385       hex += incr;
02386     }
02387 
02388   return i;
02389 }
02390 
02391 /* This implements the Tcl command 'gdb_set_mem', which
02392  * sets some chunk of memory.
02393  *
02394  * Arguments:
02395  *   gdb_set_mem addr hexstr len
02396  *
02397  *   addr:   address of data to set
02398  *   hexstr: ascii string of data to set
02399  *   len:    number of bytes of data to set
02400  */
02401 static int
02402 gdb_set_mem (ClientData clientData, Tcl_Interp *interp,
02403              int objc, Tcl_Obj *CONST objv[])
02404 {
02405   CORE_ADDR addr;
02406   gdb_byte buf[128];
02407   char *hexstr;
02408   int len, size;
02409 
02410   if (objc != 4)
02411     {
02412       Tcl_WrongNumArgs (interp, 1, objv, "addr hex_data len");
02413       return TCL_ERROR;
02414     }
02415 
02416   /* Address to write */
02417   addr = string_to_core_addr (Tcl_GetStringFromObj (objv[1], NULL));
02418 
02419   /* String value to write: it's in hex */
02420   hexstr = Tcl_GetStringFromObj (objv[2], NULL);
02421   if (hexstr == NULL)
02422     return TCL_ERROR;
02423 
02424   /* Length of buf */
02425   if (Tcl_GetIntFromObj (interp, objv[3], &len) != TCL_OK)
02426     return TCL_ERROR;
02427 
02428   /* Convert hexstr to binary and write */
02429   if (hexstr[0] == '0' && hexstr[1] == 'x')
02430     hexstr += 2;
02431   size = hex2bin (hexstr, (char *) buf, strlen (hexstr));
02432   if (size < 0)
02433     {
02434       /* Error in input */
02435       gdbtk_set_result (interp, "Invalid hexadecimal input: \"0x%s\"", hexstr);
02436       return TCL_ERROR;
02437     }
02438 
02439   target_write_memory (addr, buf, len);
02440   return TCL_OK;
02441 }
02442 
02443 /* This implements the Tcl command 'gdb_update_mem', which 
02444  * updates a block of memory in the memory window
02445  *
02446  * Arguments:
02447  *   gdb_update_mem data addr form size nbytes bpr aschar
02448  *
02449  *   1 data: variable that holds table's data
02450  *   2 addr: address of data to dump
02451  *   3 mform: a char indicating format
02452  *   4 size: size of each element; 1,2,4, or 8 bytes
02453  *   5 nbytes: the number of bytes to read 
02454  *   6 bpr: bytes per row
02455  *   7 aschar: if present, an ASCII dump of the row is included.  ASCHAR
02456  *              used for unprintable characters.
02457  * 
02458  * Return:
02459  * a list of three integers: {border_col_width data_col_width ascii_col_width}
02460  * which can be used to set the table's column widths. */
02461 
02462 static int
02463 gdb_update_mem (ClientData clientData, Tcl_Interp *interp,
02464                 int objc, Tcl_Obj *CONST objv[])
02465 {
02466   long dummy;
02467   char index[20];
02468   CORE_ADDR addr;
02469   int nbytes, rnum, bpr;
02470   int size, asize, i, j, bc;
02471   int max_ascii_len, max_val_len, max_label_len;
02472   char format, aschar;
02473   char *data, *tmp;
02474   char buff[128], *bptr;
02475   gdb_byte *mbuf, *mptr, *cptr;
02476   struct ui_file *stb;
02477   struct type *val_type;
02478   struct cleanup *old_chain;
02479 
02480   if (objc < 7 || objc > 8)
02481     {
02482       Tcl_WrongNumArgs (interp, 1, objv, "data addr format size bytes bytes_per_row ?ascii_char?");
02483       return TCL_ERROR;
02484     }
02485 
02486   /* Get table data and link to a local variable */
02487   data = Tcl_GetStringFromObj (objv[1], NULL);
02488   if (data == NULL)
02489     {
02490       gdbtk_set_result (interp, "could not get data variable");
02491       return TCL_ERROR;
02492     }
02493 
02494   if (Tcl_UpVar (interp, "1", data, "data", 0) != TCL_OK)
02495     {
02496       gdbtk_set_result (interp, "could not link table data");
02497       return TCL_ERROR;
02498     }
02499 
02500   if (Tcl_GetIntFromObj (interp, objv[4], &size) != TCL_OK)
02501     return TCL_ERROR;
02502   else if (size <= 0)
02503     {
02504       gdbtk_set_result (interp, "Invalid size, must be > 0");
02505       return TCL_ERROR;
02506     }
02507 
02508   if (Tcl_GetIntFromObj (interp, objv[5], &nbytes) != TCL_OK)
02509     return TCL_ERROR;
02510   else if (nbytes <= 0)
02511     {
02512       gdbtk_set_result (interp, "Invalid number of bytes, must be > 0");
02513       return TCL_ERROR;
02514     }
02515 
02516   if (Tcl_GetIntFromObj (interp, objv[6], &bpr) != TCL_OK)
02517     return TCL_ERROR;
02518   else if (bpr <= 0)
02519     {
02520       gdbtk_set_result (interp, "Invalid bytes per row, must be > 0");
02521       return TCL_ERROR;
02522     }
02523 
02524   tmp = Tcl_GetStringFromObj (objv[2], NULL);
02525   if (tmp == NULL)
02526     {
02527       gdbtk_set_result (interp, "could not get address");
02528       return TCL_ERROR;
02529     }
02530   addr = string_to_core_addr (tmp);
02531 
02532   format = *(Tcl_GetStringFromObj (objv[3], NULL));
02533   mbuf = (gdb_byte *) xmalloc (nbytes + 32);
02534   if (!mbuf)
02535     {
02536       gdbtk_set_result (interp, "Out of memory.");
02537       return TCL_ERROR;
02538     }
02539 
02540   memset (mbuf, 0, nbytes + 32);
02541   mptr = cptr = mbuf;
02542 
02543   /* Dispatch memory reads to the topmost target, not the flattened
02544      current_target.  */
02545   rnum = target_read (current_target.beneath, TARGET_OBJECT_MEMORY, NULL,
02546                       mbuf, addr, nbytes);
02547   if (rnum <= 0)
02548     {
02549       gdbtk_set_result (interp, "Unable to read memory.");
02550       return TCL_ERROR;
02551     }
02552 
02553   if (objc == 8)
02554     aschar = *(Tcl_GetStringFromObj (objv[7], NULL));
02555   else
02556     aschar = 0;
02557 
02558   switch (size)
02559     {
02560     case 1:
02561       val_type = builtin_type (get_current_arch ())->builtin_int8;
02562       asize = 'b';
02563       break;
02564     case 2:
02565       val_type = builtin_type (get_current_arch ())->builtin_int16;
02566       asize = 'h';
02567       break;
02568     case 4:
02569       val_type = builtin_type (get_current_arch ())->builtin_int32;
02570       asize = 'w';
02571       break;
02572     case 8:
02573       val_type = builtin_type (get_current_arch ())->builtin_int64;
02574       asize = 'g';
02575       break;
02576     default:
02577       val_type = builtin_type (get_current_arch ())->builtin_int8;
02578       asize = 'b';
02579     }
02580 
02581   bc = 0;                       /* count of bytes in a row */
02582   bptr = &buff[0];              /* pointer for ascii dump */
02583 
02584   /* Open a memory ui_file that we can use to print memory values */
02585   stb = mem_fileopen ();
02586   old_chain = make_cleanup_ui_file_delete (stb);
02587   
02588   /* A little macro to do column indices. As a rule, given the current
02589      byte, i, of a total nbytes and the bytes per row, bpr, and the size of
02590      each cell, size, the row and column will be given by:
02591 
02592      row = i/bpr
02593      col = (i%bpr)/size
02594   */
02595 #define INDEX(row,col) sprintf (index, "%d,%d",(row),(col))
02596 
02597   /* Fill in address labels */
02598   max_label_len = 0;
02599   for (i = 0; i < nbytes; i += bpr)
02600     {
02601       char s[130];
02602       sprintf (s, "%s", core_addr_to_string (addr + i));
02603       INDEX ((int) i/bpr, -1);
02604       Tcl_SetVar2 (interp, "data", index, s, 0);
02605 
02606       /* The tcl code in MemWin::update_addr used to track the size
02607          of each cell. I don't see how these could change for any given
02608          update, so we don't loop over all cells. We just note the first
02609          size. */
02610       if (max_label_len == 0)
02611         max_label_len = strlen (s);
02612     }
02613 
02614   /* Fill in memory */
02615   max_val_len   = 0;            /* Ditto the above comments about max_label_len */
02616   max_ascii_len = 0;
02617   for (i = 0; i < nbytes; i += size)
02618     {
02619       INDEX ((int) i/bpr, (int) (i%bpr)/size);
02620 
02621       if (i >= rnum)
02622         {
02623           /* Read fewer bytes than requested */
02624           tmp = "N/A";
02625 
02626           if (aschar)
02627             {
02628               for (j = 0; j < size; j++)
02629                 *bptr++ = 'X';
02630             }
02631         }
02632       else
02633         {
02634           struct value_print_options opts;
02635 
02636           get_formatted_print_options (&opts, format);
02637 
02638           /* print memory to our uiout file and set the table's variable */
02639           ui_file_rewind (stb);
02640           print_scalar_formatted (mptr, val_type, &opts, asize, stb);
02641           tmp = ui_file_xstrdup (stb, &dummy);
02642 
02643           /* See comments above on max_*_len */
02644           if (max_val_len == 0)
02645             max_val_len = strlen (tmp);
02646 
02647           if (aschar)
02648             {
02649               for (j = 0; j < size; j++)
02650                 {
02651                   if (isprint (*cptr))
02652                     *bptr++ = *cptr++;
02653                   else
02654                     {
02655                       *bptr++ = aschar;
02656                       cptr++;;
02657                     }
02658                 }
02659             }
02660         }
02661       Tcl_SetVar2 (interp, "data", index, tmp, 0);
02662 
02663       mptr += size;
02664       bc += size;
02665 
02666       if (aschar && (bc >= bpr))
02667         {
02668           /* end of row. Add it to the result and reset variables */
02669           *bptr = '\000';
02670           INDEX (i/bpr, bpr/size);
02671           Tcl_SetVar2 (interp, "data", index, buff, 0);
02672 
02673           /* See comments above on max_*_len */
02674           if (max_ascii_len == 0)
02675             max_ascii_len = strlen (buff);
02676 
02677           bc = 0;
02678           bptr = &buff[0];
02679         }
02680     }
02681 
02682   /* return max_*_len so that column widths can be set */
02683   Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, Tcl_NewIntObj (max_label_len + 1));
02684   Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, Tcl_NewIntObj (max_val_len + 1));
02685   Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, Tcl_NewIntObj (max_ascii_len + 1));
02686   do_cleanups (old_chain);
02687   xfree (mbuf);
02688   return TCL_OK;
02689 #undef INDEX
02690 }
02691 
02692 
02693 /* This implements the tcl command "gdb_loadfile"
02694  * It loads a c source file into a text widget.
02695  *
02696  * Tcl Arguments:
02697  *    widget: the name of the text widget to fill
02698  *    filename: the name of the file to load
02699  *    linenumbers: A boolean indicating whether or not to display line numbers.
02700  * Tcl Result:
02701  *
02702  */
02703 
02704 /* In this routine, we will build up a "line table", i.e. a
02705  * table of bits showing which lines in the source file are executible.
02706  * LTABLE_SIZE is the number of bytes to allocate for the line table.
02707  *
02708  * Its size limits the maximum number of lines 
02709  * in a file to 8 * LTABLE_SIZE.  This memory is freed after 
02710  * the file is loaded, so it is OK to make this very large. 
02711  * Additional memory will be allocated if needed. */
02712 #define LTABLE_SIZE 20000
02713 static int
02714 gdb_loadfile (ClientData clientData, Tcl_Interp *interp, int objc,
02715               Tcl_Obj *CONST objv[])
02716 {
02717   char *file, *widget;
02718   int linenumbers, ln, lnum, ltable_size;
02719   FILE *fp;
02720   char *ltable;
02721   struct symtab *symtab;
02722   struct linetable_entry *le;
02723   long mtime = 0;
02724   struct stat st;
02725   char line[10000], line_num_buf[18];
02726   const char *text_argv[9];
02727   Tcl_CmdInfo text_cmd;
02728 
02729  
02730   if (objc != 4)
02731     {
02732       Tcl_WrongNumArgs(interp, 1, objv, "widget filename linenumbers");
02733       return TCL_ERROR; 
02734     }
02735 
02736   widget = Tcl_GetStringFromObj (objv[1], NULL);
02737   if ( Tk_NameToWindow (interp, widget, Tk_MainWindow (interp)) == NULL)
02738     {
02739       return TCL_ERROR;
02740     }
02741 
02742   if (!Tcl_GetCommandInfo (interp, widget, &text_cmd))
02743     {
02744       gdbtk_set_result (interp, "Can't get widget command info");
02745       return TCL_ERROR;
02746     }
02747   
02748   file  = Tcl_GetStringFromObj (objv[2], NULL);
02749   Tcl_GetBooleanFromObj (interp, objv[3], &linenumbers);
02750 
02751   symtab = lookup_symtab (file);
02752   if (!symtab)
02753     {
02754       gdbtk_set_result (interp, "File not found in symtab");
02755       return TCL_ERROR;
02756     }
02757 
02758   file = symtab_to_filename ( symtab );
02759   if ((fp = fopen ( file, "r" )) == NULL)
02760     {
02761       gdbtk_set_result (interp, "Can't open file for reading");
02762       return TCL_ERROR;
02763     }
02764 
02765   if (stat (file, &st) < 0)
02766     {
02767       catch_errors (perror_with_name_wrapper, "gdbtk: get time stamp", "",
02768                     RETURN_MASK_ALL);
02769       return TCL_ERROR;
02770     }
02771 
02772   if (symtab && symtab->objfile && symtab->objfile->obfd)
02773     mtime = bfd_get_mtime(symtab->objfile->obfd);
02774   else if (exec_bfd)
02775     mtime = bfd_get_mtime(exec_bfd);
02776  
02777   if (mtime && mtime < st.st_mtime)
02778     {
02779       gdbtk_ignorable_warning("file_times",\
02780                               "Source file is more recent than executable.\n");
02781     }
02782   
02783   
02784   /* Source linenumbers don't appear to be in order, and a sort is */
02785   /* too slow so the fastest solution is just to allocate a huge */
02786   /* array and set the array entry for each linenumber */
02787 
02788   ltable_size = LTABLE_SIZE;
02789   ltable = (char *)malloc (LTABLE_SIZE);
02790   if (ltable == NULL)
02791     {
02792       fclose (fp);
02793       gdbtk_set_result (interp, "Out of memory.");
02794       return TCL_ERROR;
02795     }
02796 
02797   memset (ltable, 0, LTABLE_SIZE);
02798 
02799   if (symtab->linetable && symtab->linetable->nitems)
02800     {
02801       le = symtab->linetable->item;
02802       for (ln = symtab->linetable->nitems ;ln > 0; ln--, le++)
02803         {
02804           lnum = le->line >> 3;
02805           if (lnum >= ltable_size)
02806             {
02807               char *new_ltable;
02808               new_ltable = (char *)realloc (ltable, ltable_size*2);
02809               memset (new_ltable + ltable_size, 0, ltable_size);
02810               ltable_size *= 2;
02811               if (new_ltable == NULL)
02812                 {
02813                   free (ltable);
02814                   fclose (fp);
02815                   gdbtk_set_result (interp, "Out of memory.");
02816                   return TCL_ERROR;
02817                 }
02818               ltable = new_ltable;
02819             }
02820           ltable[lnum] |= 1 << (le->line % 8);
02821         }
02822     }
02823       
02824   ln = 1;
02825 
02826   line[0] = '\t'; 
02827   text_argv[0] = widget;
02828   text_argv[1] = "insert";
02829   text_argv[2] = "end";
02830   text_argv[5] = line;
02831   text_argv[6] = "source_tag";
02832   text_argv[8] = NULL;
02833   
02834   if (linenumbers)
02835     {
02836       int found_carriage_return = 1;
02837       
02838       line_num_buf[1] = '\t';
02839        
02840       text_argv[3] = line_num_buf;
02841       
02842       while (fgets (line + 1, 9980, fp))
02843         {
02844           /* Look for DOS style \r\n endings, and if found,
02845            * strip off the \r.  We assume (for the sake of
02846            * speed) that ALL lines in the file have DOS endings,
02847            * or none do.
02848            */
02849           
02850           if (found_carriage_return)
02851             {
02852               char *p = strrchr(line, '\0') - 2;
02853               if (*p == '\r')
02854                 {
02855                   *p = '\n';
02856                   *(p + 1) = '\0';
02857                 } 
02858               else 
02859                 found_carriage_return = 0;
02860             }
02861           
02862           sprintf (line_num_buf+2, "%d", ln);
02863           if (ltable[ln >> 3] & (1 << (ln % 8)))
02864             {
02865               line_num_buf[0] = '-';
02866               text_argv[4] = "break_rgn_tag";
02867             }
02868           else
02869             {
02870               line_num_buf[0] = ' ';
02871               text_argv[4] = "";
02872             }
02873 
02874           text_cmd.proc(text_cmd.clientData, interp, 7, text_argv);
02875           ln++;
02876         }
02877     }
02878   else
02879     {
02880       int found_carriage_return = 1;
02881             
02882       while (fgets (line + 1, 9980, fp))
02883         {
02884           if (found_carriage_return)
02885             {
02886               char *p = strrchr(line, '\0') - 2;
02887               if (*p == '\r')
02888                 {
02889                   *p = '\n';
02890                   *(p + 1) = '\0';
02891                 } 
02892               else
02893                 found_carriage_return = 0;
02894             }
02895 
02896           if (ltable[ln >> 3] & (1 << (ln % 8)))
02897             {
02898               text_argv[3] = "- ";
02899               text_argv[4] = "break_rgn_tag";
02900             }
02901           else
02902             {
02903               text_argv[3] = "  ";
02904               text_argv[4] = "";
02905             }
02906 
02907           text_cmd.proc(text_cmd.clientData, interp, 7, text_argv);
02908           ln++;
02909         }
02910     }
02911 
02912   free (ltable);
02913   fclose (fp);
02914   return TCL_OK;
02915 }
02916 
02917 /*
02918  * This section contains a bunch of miscellaneous utility commands
02919  */
02920 
02921 /* This implements the tcl command gdb_path_conv
02922 
02923 * On Windows, it canonicalizes the pathname,
02924 * On Unix, it is a no op.
02925 *
02926 * Arguments:
02927 *    path
02928 * Tcl Result:
02929 *    The canonicalized path.
02930 */
02931 
02932 static int
02933 gdb_path_conv (ClientData clientData, Tcl_Interp *interp,
02934                int objc, Tcl_Obj *CONST objv[])
02935 {
02936   if (objc != 2)
02937     {
02938       Tcl_WrongNumArgs (interp, 1, objv, NULL);
02939       return TCL_ERROR;
02940     }
02941 
02942 #ifdef __CYGWIN__
02943   {
02944     char pathname[256], *ptr;
02945 
02946     cygwin_conv_path (CCP_POSIX_TO_WIN_A, Tcl_GetStringFromObj (objv[1], NULL),
02947                       pathname, 256);
02948     for (ptr = pathname; *ptr; ptr++)
02949       {
02950         if (*ptr == '\\')
02951           *ptr = '/';
02952       }
02953     Tcl_SetStringObj (result_ptr->obj_ptr, pathname, -1);
02954   }
02955 #else
02956   Tcl_SetStringObj (result_ptr->obj_ptr, Tcl_GetStringFromObj (objv[1], NULL),
02957                     -1);
02958 #endif
02959 
02960   return TCL_OK;
02961 }
02962 
02963 /*
02964  * This section has utility routines that are not Tcl commands.
02965  */
02966 
02967 static int
02968 perror_with_name_wrapper (PTR args)
02969 {
02970   perror_with_name (args);
02971   return 1;
02972 }
02973 
02974 /* Look for the function that contains PC and return the source
02975    (demangled) name for this function.
02976 
02977    If no symbol is found, it returns an empty string. In either
02978    case, memory is owned by gdb. Do not attempt to free it. */
02979 const char *
02980 pc_function_name (CORE_ADDR pc)
02981 {
02982   struct symbol *sym;
02983   const char *funcname = NULL;
02984 
02985   /* First lookup the address in the symbol table... */
02986   sym = find_pc_function (pc);
02987   if (sym != NULL)
02988     funcname = GDBTK_SYMBOL_SOURCE_NAME (sym);
02989   else
02990     {
02991       /* ... if that fails, look it up in the minimal symbols. */
02992       struct bound_minimal_symbol msym;
02993 
02994       msym = lookup_minimal_symbol_by_pc (pc);
02995       if (msym.minsym != NULL)
02996         funcname = GDBTK_SYMBOL_SOURCE_NAME (msym.minsym);
02997     }
02998 
02999   if (funcname == NULL)
03000     funcname = "";
03001 
03002   return funcname;
03003 }
03004 
03005 void
03006 gdbtk_set_result (Tcl_Interp *interp, const char *fmt,...)
03007 {
03008   va_list args;
03009   char *buf;
03010 
03011   va_start (args, fmt);
03012   buf = xstrvprintf (fmt, args);
03013   va_end (args);
03014   Tcl_SetObjResult (interp, Tcl_NewStringObj (buf, -1));
03015   xfree(buf);
03016 }
03017 
03018 
03019 /* This implements the tcl command 'gdb_incr_addr'.
03020  * It does address arithmetic and outputs a proper
03021  * hex string.  This was originally implemented
03022  * when tcl did not support 64-bit values, but we keep
03023  * it because it saves us from having to call incr 
03024  * followed by format to get the result in hex.
03025  * Also, it may be true in the future that CORE_ADDRs
03026  * will have their own ALU to deal properly with
03027  * architecture-specific address arithmetic.
03028  *
03029  * Tcl Arguments:
03030  *     addr   - CORE_ADDR
03031  *     number - optional number to add to the address
03032  *      default is 1.
03033  *
03034  * Tcl Result:
03035  *     hex string containing the result of addr + number
03036  */
03037 
03038 static int
03039 gdb_incr_addr (ClientData clientData, Tcl_Interp *interp,
03040                int objc, Tcl_Obj *CONST objv[])
03041 {
03042   CORE_ADDR address;
03043   int number = 1;
03044 
03045   if (objc != 2 && objc != 3)
03046     {
03047       Tcl_WrongNumArgs (interp, 1, objv, "CORE_ADDR [number]");
03048       return TCL_ERROR;
03049     }
03050 
03051   address = string_to_core_addr (Tcl_GetStringFromObj (objv[1], NULL));
03052 
03053   if (objc == 3)
03054     {
03055       if (Tcl_GetIntFromObj (interp, objv[2], &number) != TCL_OK)
03056         return TCL_ERROR;
03057     }
03058   
03059   address += number;
03060 
03061   Tcl_SetStringObj (result_ptr->obj_ptr, (char *)core_addr_to_string (address), -1);
03062   
03063   return TCL_OK;
03064 }
03065 
03066 /* This implements the tcl command 'gdb_CAS_to_TAS'.
03067  * It takes a CORE_ADDR and outputs a string suitable
03068  * for displaying as the target address.
03069  *
03070  * Note that CORE_ADDRs are internal addresses which map
03071  * to target addresses in different ways depending on the 
03072  * architecture. The target address string is a user-readable
03073  * string may be quite different than the CORE_ADDR. For example,
03074  * a CORE_ADDR of 0x02001234 might indicate a data address of
03075  * 0x1234 which this function might someday output as something
03076  * like "D:1234".
03077  *
03078  * Tcl Arguments:
03079  *     address   - CORE_ADDR
03080  *
03081  * Tcl Result:
03082  *     string
03083  */
03084 
03085 static int
03086 gdb_CA_to_TAS (ClientData clientData, Tcl_Interp *interp,
03087                int objc, Tcl_Obj *CONST objv[])
03088 {
03089   CORE_ADDR address;
03090   Tcl_WideInt wide_addr;
03091 
03092   if (objc != 2)
03093     {
03094       Tcl_WrongNumArgs (interp, 1, objv, "CORE_ADDR");
03095       return TCL_ERROR;
03096     }
03097 
03098   /* Read address into a wideint, which is the largest tcl supports
03099      then convert to a CORE_ADDR */
03100   if (Tcl_GetWideIntFromObj (interp, objv[1], &wide_addr) != TCL_OK)
03101     return TCL_ERROR;
03102   address = wide_addr;
03103 
03104   /* This is not really correct.  Using paddr_nz() will convert to hex and truncate 
03105      to 32-bits when required but will otherwise not do what we really want. */
03106   
03107   Tcl_SetStringObj (result_ptr->obj_ptr,
03108                     paddress (get_current_arch (), address),
03109                     -1);
03110 
03111   return TCL_OK;
03112 }
03113 
03114 /* Another function that was removed in GDB and replaced
03115  * with something similar, but different enough to break
03116  * Insight.
03117  */
03118 char *
03119 symtab_to_filename (struct symtab *s)
03120 {
03121   int r;
03122 
03123   if (!s)
03124     return NULL;
03125 
03126   /* Don't check s->fullname here, the file could have been 
03127      deleted/moved/..., look for it again */
03128   r = open_source_file (s);
03129   if (r)
03130     close (r);
03131 
03132   if (s->fullname && *s->fullname)
03133       return s->fullname;
03134   return s->filename;
03135 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines