#include "target.h"
#include <tcl.h>
#include <tk.h>
-/* #include <itcl.h> */
+#include <itcl.h>
+#include <tix.h>
+
+#ifdef IDE
+#include "event.h"
+#include "idetcl.h"
+#endif
+
#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
#else
static void gdbtk_fputs PARAMS ((const char *, FILE *));
static int gdbtk_query PARAMS ((const char *, va_list));
static char *gdbtk_readline PARAMS ((char *));
-static void gdbtk_init PARAMS ((void));
+static void gdbtk_init PARAMS ((char *));
static void tk_command_loop PARAMS ((void));
static void gdbtk_call_command PARAMS ((struct cmd_list_element *, char *, int));
static int gdbtk_wait PARAMS ((int, struct target_waitstatus *));
static int gdb_path_conv PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
static int gdb_stop PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
static int gdb_listfiles PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+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[]));
static int gdb_fetch_registers PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
static int disassemble_from_exec = -1;
-static char *Gdbtk_Library;
+#ifndef _WIN32
-/* Supply malloc calls for tcl/tk. */
+/* Supply malloc calls for tcl/tk. We do not want to do this on
+ Windows, because Tcl_Alloc is probably in a DLL which will not call
+ the mmalloc routines. */
char *
Tcl_Alloc (size)
free (ptr);
}
+#endif /* _WIN32 */
+
static void
null_routine(arg)
int arg;
const char *ptr;
FILE *stream;
{
-
if (result_ptr)
Tcl_DStringAppend (result_ptr, (char *)ptr, -1);
else
Tcl_DStringAppend (&str, "gdbtk_tcl_fputs", -1);
Tcl_DStringAppendElement (&str, (char *)ptr);
- Tcl_Eval (interp, Tcl_DStringValue (&str));
+ Tcl_Eval (interp, Tcl_DStringValue (&str));
Tcl_DStringFree (&str);
}
}
struct breakpoint *b;
const char *action;
{
- char buf[100];
+ char buf[256];
int v;
+ struct symtab_and_line sal;
if (b->type != bp_breakpoint)
return;
/* We ensure that ACTION contains no special Tcl characters, so we
can do this. */
- sprintf (buf, "gdbtk_tcl_breakpoint %s %d", action, b->number);
+ sal = find_pc_line (b->address, 0);
+ sprintf (buf, "gdbtk_tcl_breakpoint %s %d 0x%lx %d {%s}", action, b->number,
+ (long)b->address, sal.line, symtab_to_filename (sal.symtab));
v = Tcl_Eval (interp, buf);
dsprintf_append_element (result_ptr, "%d", sal.line); /* line number */
- dsprintf_append_element (result_ptr, "0x%s", paddr_nz(pc)); /* PC */
+ 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;
}
return TCL_OK;
}
+static int
+gdb_listfuncs (clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ struct symtab *symtab;
+ struct blockvector *bv;
+ struct block *b;
+ struct symbol *sym;
+ int i,j;
+
+ if (argc != 2)
+ error ("wrong # args");
+
+ symtab = lookup_symtab (argv[1]);
+
+ if (!symtab)
+ error ("No such file");
+
+ bv = BLOCKVECTOR (symtab);
+ for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ /* Skip the sort if this block is always sorted. */
+ if (!BLOCK_SHOULD_SORT (b))
+ sort_block_syms (b);
+ for (j = 0; j < BLOCK_NSYMS (b); j++)
+ {
+ sym = BLOCK_SYM (b, j);
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ Tcl_DStringAppendElement (result_ptr, SYMBOL_NAME(sym));
+ }
+ }
+ }
+ return TCL_OK;
+}
+
static int
gdb_stop (clientData, interp, argc, argv)
ClientData clientData;
running_now = 1;
Tcl_Eval (interp, "gdbtk_tcl_busy");
(*cmdblk->function.cfunc)(arg, from_tty);
- Tcl_Eval (interp, "gdbtk_tcl_idle");
running_now = 0;
+ Tcl_Eval (interp, "gdbtk_tcl_idle");
}
else
(*cmdblk->function.cfunc)(arg, from_tty);
Tk_MainLoop ();
}
+/* gdbtk_init installs this function as a final cleanup. */
+
+static void
+gdbtk_cleanup (dummy)
+ PTR dummy;
+{
+ Tcl_Finalize ();
+}
+
+/* Initialize gdbtk. */
+
static void
-gdbtk_init ()
+gdbtk_init ( argv0 )
+ char *argv0;
{
struct cleanup *old_chain;
- char *lib, *gdbtk_lib, gdbtk_lib_tmp[1024],gdbtk_file[128];
+ char *lib, *gdbtk_lib, *gdbtk_lib_tmp, *gdbtk_file;
int i, found_main;
struct sigaction action;
static sigset_t nullsigmask = {0};
+#ifdef IDE
+ struct ide_event_handle *h;
+ const char *errmsg;
+ char *libexecdir;
+#endif
/* If there is no DISPLAY environment variable, Tk_Init below will fail,
causing gdb to abort. If instead we simply return here, gdb will
old_chain = make_cleanup (cleanup_init, 0);
/* First init tcl and tk. */
-
+ Tcl_FindExecutable (argv0);
interp = Tcl_CreateInterp ();
if (!interp)
if (Tcl_Init(interp) != TCL_OK)
error ("Tcl_Init failed: %s", interp->result);
- /*
- if (Itcl_Init(interp) == TCL_ERROR)
- error ("Itcl_Init failed: %s", interp->result);
- */
-
+ make_final_cleanup (gdbtk_cleanup, NULL);
+
+#ifdef IDE
+ /* Initialize the Paths variable. */
+ if (ide_initialize_paths (interp, "gdbtcl") != TCL_OK)
+ error ("ide_initialize_paths failed: %s", interp->result);
+
+ /* Find the directory where we expect to find idemanager. We ignore
+ errors since it doesn't really matter if this fails. */
+ libexecdir = Tcl_GetVar2 (interp, "Paths", "libexecdir", TCL_GLOBAL_ONLY);
+
+ IluTk_Init ();
+
+ h = ide_event_init_from_environment (&errmsg, libexecdir);
+ if (h == NULL)
+ {
+ Tcl_AppendResult (interp, "can't initialize event system: ", errmsg,
+ (char *) NULL);
+ fprintf(stderr, "WARNING: ide_event_init_client failed: %s\n", interp->result);
+
+ Tcl_SetVar (interp, "GDBTK_IDE", "0", 0);
+ }
+ else
+ {
+ if (ide_create_tclevent_command (interp, h) != TCL_OK)
+ error ("ide_create_tclevent_command failed: %s", interp->result);
+ if (ide_create_edit_command (interp, h) != TCL_OK)
+ error ("ide_create_edit_command failed: %s", interp->result);
+
+ if (ide_create_property_command (interp, h) != TCL_OK)
+ error ("ide_create_property_command failed: %s", interp->result);
+
+ if (ide_create_window_register_command (interp, h) != TCL_OK)
+ error ("ide_create_window_register_command failed: %s",
+ interp->result);
+
+ if (ide_create_window_command (interp, h) != TCL_OK)
+ error ("ide_create_window_command failed: %s", interp->result);
+
+ /*
+ if (ide_initialize (interp, "gdb") != TCL_OK)
+ error ("ide_initialize failed: %s", interp->result);
+ */
+
+ Tcl_SetVar (interp, "GDBTK_IDE", "1", 0);
+ }
+#else
+ Tcl_SetVar (interp, "GDBTK_IDE", "0", 0);
+#endif /* IDE */
+
+ /* We don't want to open the X connection until we've done all the
+ IDE initialization. Otherwise, goofy looking unfinished windows
+ pop up when ILU drops into the TCL event loop. */
+
if (Tk_Init(interp) != TCL_OK)
error ("Tk_Init failed: %s", interp->result);
+ if (Itcl_Init(interp) == TCL_ERROR)
+ error ("Itcl_Init failed: %s", interp->result);
+
+ if (Tix_Init(interp) != TCL_OK)
+ error ("Tix_Init failed: %s", interp->result);
+
Tcl_CreateCommand (interp, "gdb_cmd", call_wrapper, gdb_cmd, NULL);
Tcl_CreateCommand (interp, "gdb_loc", call_wrapper, gdb_loc, NULL);
Tcl_CreateCommand (interp, "gdb_path_conv", call_wrapper, gdb_path_conv, NULL);
NULL);
Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles,
NULL);
+ Tcl_CreateCommand (interp, "gdb_listfuncs", call_wrapper, gdb_listfuncs,
+ NULL);
Tcl_CreateCommand (interp, "gdb_stop", call_wrapper, gdb_stop, NULL);
Tcl_CreateCommand (interp, "gdb_regnames", call_wrapper, gdb_regnames, NULL);
Tcl_CreateCommand (interp, "gdb_fetch_registers", call_wrapper,
else
gdbtk_lib = GDBTK_LIBRARY;
- strcpy (gdbtk_lib_tmp, gdbtk_lib);
+ gdbtk_lib_tmp = xstrdup (gdbtk_lib);
+
found_main = 0;
/* see if GDBTK_LIBRARY is a path list */
lib = strtok (gdbtk_lib_tmp, GDBTK_PATH_SEP);
}
if (!found_main)
{
- strcpy (gdbtk_file, lib);
- strcat (gdbtk_file, "/main.tcl");
+ gdbtk_file = concat (lib, "/main.tcl", (char *) NULL);
if (access (gdbtk_file, R_OK) == 0)
{
found_main++;
}
}
}
- while (lib = strtok (NULL, ":"));
-
+ while ((lib = strtok (NULL, ":")) != NULL);
+
+ free (gdbtk_lib_tmp);
+
+#ifdef IDE
+ if (!found_main)
+ {
+ /* Try finding it with the auto path. */
+
+ static const char script[] ="\
+proc gdbtk_find_main {} {\n\
+ global auto_path GDBTK_LIBRARY\n\
+ foreach dir $auto_path {\n\
+ set f [file join $dir main.tcl]\n\
+ if {[file exists $f]} then {\n\
+ set GDBTK_LIBRARY $dir\n\
+ return $f\n\
+ }\n\
+ }\n\
+ return ""\n\
+}\n\
+gdbtk_find_main";
+
+ if (Tcl_GlobalEval (interp, (char *) script) != TCL_OK)
+ {
+ fputs_unfiltered (Tcl_GetVar (interp, "errorInfo", 0), gdb_stderr);
+ error ("");
+ }
+
+ if (interp->result[0] != '\0')
+ {
+ gdbtk_file = xstrdup (interp->result);
+ found_main++;
+ }
+ }
+#endif
+
if (!found_main)
{
fputs_unfiltered_hook = NULL; /* Force errors to stdout/stderr */
error ("");
}
+ free (gdbtk_file);
+
discard_cleanups (old_chain);
}