Sat Jan 24 23:52:08 1998 Martin M. Hunt <hunt@cygnus.com>
authorMartin Hunt <hunt@redhat.com>
Sun, 25 Jan 1998 08:56:08 +0000 (08:56 +0000)
committerMartin Hunt <hunt@redhat.com>
Sun, 25 Jan 1998 08:56:08 +0000 (08:56 +0000)
* gdbtk.c: Merge from Foundry branch.
(TclDebug): New debugging function.
(gdb_loc): For frames, find address of calling function
instead of whatever is on the stack (usually the next
instruction).
(gdb_listfiles): Takes an optional pathname argument and
returns an alphabetized list of basenames of files in the
path.

gdb/ChangeLog-gdbtk
gdb/gdbtk.c

index 152634d91ab897548a5296baecc2d84e92886588..8bcc3910ae640a1b39973714e7301f15d6aaf007 100644 (file)
@@ -1,9 +1,21 @@
+Sat Jan 24 23:52:08 1998  Martin M. Hunt  <hunt@cygnus.com>
+
+       * gdbtk.c: Merge from Foundry branch.
+       (TclDebug): New debugging function.
+       (gdb_loc): For frames, find address of calling function
+       instead of whatever is on the stack (usually the next
+       instruction).
+       (gdb_listfiles): Takes an optional pathname argument and 
+       returns an alphabetized list of basenames of files in the
+       path.
+
 Wed Jan 22  10:37:02 1998  Keith Seitz  <keiths@onions.cygnus.com>
 
-       * symfile.c: Define two new hooks for symbol reading: "pre_add_symbol_hook"
-       and "post_add_symbol_hook". These hooks are called before we begin reading
-       symbols, and after we finish.
-       (generic_load): Use new symbol reading hooks and get rid of compiler warning.
+       * symfile.c: Define two new hooks for symbol reading: 
+       "pre_add_symbol_hook" and "post_add_symbol_hook". These hooks 
+       are called before we begin reading symbols, and after we finish.
+       (generic_load): Use new symbol reading hooks and get rid of 
+       compiler warning.
 
        * gdbtk.c (gdbtk_init): Add hooks for pre- and post-symbol reading.
        (gdbtk_pre_add_symbol): New function: the pre-add-symbol hook.
index 93a3eb378a0282a1389b27fdeaf9bdf2107a4a80..2697ff4ef661cfb0c21bbcdcf41124c734359330 100644 (file)
@@ -86,6 +86,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #undef SIOCSPGRP
 #endif
 
+static int load_in_progress = 0;
+
 int gdbtk_load_hash PARAMS ((char *, unsigned long));
 int (*ui_load_progress_hook) PARAMS ((char *, unsigned long));
 void (*pre_add_symbol_hook) PARAMS ((char *));
@@ -111,7 +113,7 @@ static int gdb_path_conv PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
 static int gdb_stop PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
 static int gdb_confirm_quit PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
 static int gdb_force_quit PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
-static int gdb_listfiles PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int gdb_listfiles PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]));
 static int gdb_listfuncs PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
 static int call_wrapper PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
 static int gdb_cmd PARAMS ((ClientData, Tcl_Interp *, int, char *argv[]));
@@ -135,6 +137,7 @@ static int gdb_regnames PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
 static void get_register PARAMS ((int, void *));
 static int gdb_target_has_execution_command PARAMS ((ClientData, Tcl_Interp *, int, char *argv[]));
 static int gdb_load_info PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]));
+void TclDebug PARAMS ((const char *fmt, ...));
 static int gdb_get_vars_command PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]));
 static int gdb_get_function_command PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]));
 static int gdb_get_line_command PARAMS ((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]));
@@ -160,6 +163,19 @@ static Tcl_Interp *interp = NULL;
 static int x_fd;               /* X network socket */
 #endif
 
+#ifdef __CYGWIN32__
+
+/* On Windows we use timer interrupts when gdb might otherwise hang
+   for a long time.  See the comment above gdbtk_start_timer.  This
+   variable is true when timer interrupts are being used.  */
+
+static int gdbtk_timer_going = 0;
+
+static void gdbtk_start_timer PARAMS ((void));
+static void gdbtk_stop_timer PARAMS ((void));
+
+#endif
+
 /* This variable is true when the inferior is running.  Although it's
    possible to disable most input from widgets and thus prevent
    attempts to do anything while the inferior is running, any commands
@@ -588,8 +604,15 @@ gdb_loc (clientData, interp, argc, argv)
 
   if (argc == 1)
     {
-      pc = selected_frame ? selected_frame->pc : stop_pc;
-      sal = find_pc_line (pc, 0);
+      if (selected_frame)
+       {
+         sal = find_pc_line (selected_frame->pc,
+                             selected_frame->next != NULL
+                             && !selected_frame->next->signal_handler_caller
+                             && !frame_in_dummy (selected_frame->next));
+       }
+      else
+       sal = find_pc_line (stop_pc, 0);
     }
   else if (argc == 2)
     {
@@ -604,12 +627,11 @@ gdb_loc (clientData, interp, argc, argv)
 
       if (sals.nelts != 1)
        error ("Ambiguous line spec");
-
-      pc = sal.pc;
     }
   else
     error ("wrong # args");
 
+  pc = sal.pc;
   if (sal.symtab)
     Tcl_DStringAppendElement (result_ptr, sal.symtab->filename);
   else
@@ -618,19 +640,14 @@ gdb_loc (clientData, interp, argc, argv)
   find_pc_partial_function (pc, &funcname, NULL, NULL);
   Tcl_DStringAppendElement (result_ptr, funcname);
 
-  /* Would it be better to use "find_file_in_dir"? */
   filename = symtab_to_filename (sal.symtab);
-
   if (filename == NULL)
     filename = "N/A";
-  Tcl_DStringAppendElement (result_ptr, filename);
 
+  Tcl_DStringAppendElement (result_ptr, filename);
   dsprintf_append_element (result_ptr, "%d", sal.line); /* line number */
-
   dsprintf_append_element (result_ptr, "0x%s", paddr_nz(pc)); /* PC in current frame */
-
   dsprintf_append_element (result_ptr, "0x%s", paddr_nz(stop_pc)); /* Real PC */
-
   return TCL_OK;
 }
 \f
@@ -1043,10 +1060,24 @@ gdb_cmd (clientData, interp, argc, argv)
       Tcl_DStringAppend (result_ptr, "", -1);
       save_ptr = result_ptr;
       result_ptr = NULL;
+      load_in_progress = 1;
+      
+      /* On Windows, use timer interrupts so that the user can cancel
+        the download.  FIXME: We may have to do something on other
+        systems.  */
+#ifdef __CYGWIN32__
+      gdbtk_start_timer ();
+#endif
     }
 
   execute_command (argv[1], 1);
 
+#ifdef __CYGWIN32__
+  if (load_in_progress)
+    gdbtk_stop_timer ();
+#endif
+
+  load_in_progress = 0;
   bpstat_do_actions (&stop_bpstat);
   
   if (save_ptr) 
@@ -1111,8 +1142,13 @@ call_wrapper (clientData, interp, argc, argv)
     {
       wrapped_args.val = TCL_ERROR;    /* Flag an error for TCL */
 
-      gdb_flush (gdb_stderr);  /* Flush error output */
+#ifdef __CYGWIN32__
+      /* Make sure the timer interrupts are turned off.  */
+      if (gdbtk_timer_going)
+       gdbtk_stop_timer ();
+#endif
 
+      gdb_flush (gdb_stderr);  /* Flush error output */
       gdb_flush (gdb_stdout);  /* Sometimes error output comes here as well */
 
       /* In case of an error, we may need to force the GUI into idle
@@ -1123,6 +1159,14 @@ call_wrapper (clientData, interp, argc, argv)
       Tcl_Eval (interp, "gdbtk_tcl_idle");
     }
 
+  /* if the download was cancelled, don't print the error */
+  if (load_in_progress) 
+    {
+      Tcl_DStringInit (&error_string);
+      wrapped_args.val = TCL_OK;
+      load_in_progress = 0;
+    }
+
   if (Tcl_DStringLength (&error_string) == 0)
     {
       Tcl_DStringResult (interp, &result);
@@ -1132,6 +1176,7 @@ call_wrapper (clientData, interp, argc, argv)
     {
       Tcl_DStringResult (interp, &error_string);
       Tcl_DStringFree (&result);
+      Tcl_DStringFree (&error_string);
     }
   else
     {
@@ -1153,22 +1198,73 @@ call_wrapper (clientData, interp, argc, argv)
 }
 
 static int
-gdb_listfiles (clientData, interp, argc, argv)
-     ClientData clientData;
-     Tcl_Interp *interp;
-     int argc;
-     char *argv[];
+comp_files (file1, file2)
+     const char *file1[], *file2[];
+{
+  return strcmp(*file1,*file2);
+}
+
+
+static int
+gdb_listfiles (clientData, interp, objc, objv)
+  ClientData clientData;
+  Tcl_Interp *interp;
+  int objc;
+  Tcl_Obj *CONST objv[];
 {
   struct objfile *objfile;
   struct partial_symtab *psymtab;
   struct symtab *symtab;
+  char *lastfile, *pathname, *files[1000];
+  int i, numfiles = 0, len = 0;
+  Tcl_Obj *mylist;
+  
+  if (objc > 2)
+    {
+      Tcl_WrongNumArgs (interp, 1, objv, "Usage: gdb_listfiles ?pathname?");
+      return TCL_ERROR;
+    }
+  else if (objc == 2)
+    pathname = Tcl_GetStringFromObj (objv[1], &len);
+
+  mylist = Tcl_NewListObj (0, NULL);
 
   ALL_PSYMTABS (objfile, psymtab)
-    Tcl_DStringAppendElement (result_ptr, psymtab->filename);
+    {
+      if (len == 0)
+       {
+         if (psymtab->filename)
+           files[numfiles++] = basename(psymtab->filename);
+       }
+      else if (!strcmp(psymtab->filename,basename(psymtab->filename))
+              || !strncmp(pathname,psymtab->filename,len))
+       if (psymtab->filename)
+         files[numfiles++] = basename(psymtab->filename);
+    }
 
   ALL_SYMTABS (objfile, symtab)
-    Tcl_DStringAppendElement (result_ptr, symtab->filename);
+    {
+      if (len == 0)
+       {
+         if (symtab->filename)
+           files[numfiles++] = basename(symtab->filename);
+       }
+      else if (!strcmp(symtab->filename,basename(symtab->filename))
+              || !strncmp(pathname,symtab->filename,len))
+       if (symtab->filename)
+         files[numfiles++] = basename(symtab->filename);
+    }
+
+  qsort (files, numfiles, sizeof(char *), comp_files);
 
+  lastfile = "";
+  for (i = 0; i < numfiles; i++)
+    {
+      if (strcmp(files[i],lastfile))
+       Tcl_ListObjAppendElement (interp, mylist, Tcl_NewStringObj(files[i], -1));
+      lastfile = files[i];
+    }
+  Tcl_SetObjResult (interp, mylist);
   return TCL_OK;
 }
 
@@ -1253,6 +1349,11 @@ gdb_clear_file (clientData, interp, argc, argv)
 
   symbol_file_command (NULL, 0);
 
+  /* gdb_loc refers to stop_pc, but nothing seems to clear it, so we
+     clear it here.  FIXME: This seems like an abstraction violation
+     somewhere.  */
+  stop_pc = 0;
+
   return TCL_OK;
 }
 
@@ -1591,7 +1692,27 @@ x_event (signo)
 {
   /* Process pending events */
 
-  while (Tcl_DoOneEvent (TCL_DONT_WAIT|TCL_ALL_EVENTS) != 0);
+  while (Tcl_DoOneEvent (TCL_DONT_WAIT|TCL_ALL_EVENTS) != 0)
+    ;
+
+  /* If we are doing a download, see if the download should be
+     cancelled.  FIXME: We should use a better variable name.  */
+  if (load_in_progress)
+    {
+      char *val;
+
+      val = Tcl_GetVar (interp, "download_cancel_ok", TCL_GLOBAL_ONLY);
+      if (val != NULL && atoi (val))
+       {
+         quit_flag = 1;
+#ifdef REQUEST_QUIT
+         REQUEST_QUIT;
+#else
+         if (immediate_quit) 
+           quit ();
+#endif
+       }
+    }
 }
 
 #ifdef __CYGWIN32__
@@ -1622,6 +1743,8 @@ gdbtk_start_timer ()
   it.it_value.tv_usec = 500 * 1000;
 
   setitimer (ITIMER_REAL, &it, NULL);
+
+  gdbtk_timer_going = 1;
 }
 
 static void
@@ -1631,6 +1754,8 @@ gdbtk_stop_timer ()
   struct sigaction action;
   struct itimerval it;
 
+  gdbtk_timer_going = 0;
+
   sigemptyset (&nullsigmask);
 
   action.sa_handler = SIG_IGN;
@@ -1672,6 +1797,11 @@ gdbtk_wait (pid, ourstatus)
 #endif /* WINNT */
 
 #ifdef __CYGWIN32__
+  /* Call x_event ourselves now, as well as starting the timer;
+     otherwise, if single stepping, we may never wait long enough for
+     the timer to trigger.  */
+  x_event (SIGALRM);
+
   gdbtk_start_timer ();
 #endif
 
@@ -1895,8 +2025,7 @@ gdbtk_init ( argv0 )
   Tcl_CreateCommand (interp, "gdb_path_conv", call_wrapper, gdb_path_conv, NULL);
   Tcl_CreateCommand (interp, "gdb_sourcelines", call_wrapper, gdb_sourcelines,
                     NULL);
-  Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles,
-                    NULL);
+  Tcl_CreateObjCommand (interp, "gdb_listfiles", gdb_listfiles, NULL, NULL);
   Tcl_CreateCommand (interp, "gdb_listfuncs", call_wrapper, gdb_listfuncs,
                     NULL);
   Tcl_CreateCommand (interp, "gdb_get_mem", call_wrapper, gdb_get_mem,
@@ -2206,11 +2335,10 @@ gdbtk_load_hash (section, num)
      char *section;
      unsigned long num;
 {
-  int result;
   char buf[128];
   sprintf (buf, "download_hash %s %ld", section, num);
-  result = Tcl_Eval (interp, buf); 
-  return result;
+  Tcl_Eval (interp, buf); 
+  return  atoi (interp->result);
 }
 
 /* gdb_get_vars_command -
@@ -2761,6 +2889,37 @@ gdbtk_post_add_symbol ()
   Tcl_Eval (interp, "gdbtk_tcl_post_add_symbol");
 }
 
+
+/* TclDebug (const char *fmt, ...) works just like printf() but */
+/* sends the output to the GDB TK debug window. */
+/* Not for normal use; just a convenient tool for debugging */
+void
+#ifdef ANSI_PROTOTYPES
+TclDebug (const char *fmt, ...)
+#else
+TclDebug (va_alist)
+     va_dcl
+#endif
+{
+  va_list args;
+  char buf[512];
+
+#ifdef ANSI_PROTOTYPES
+  va_start (args, fmt);
+#else
+  char *fmt;
+  va_start (args);
+  fmt = va_arg (args, char *);
+#endif
+
+  strcpy (buf, "debug \"");
+  vsprintf (&buf[7], fmt, args);
+  va_end (args);
+  strcat (buf, "\"");
+  Tcl_Eval (interp, buf);
+}
+
+
 /* Come here during initialize_all_files () */
 
 void