1998-07-01 19:29:14 +00:00
|
|
|
|
/* Startup code for gdbtk.
|
|
|
|
|
Copyright 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Written by Stu Grossman <grossman@cygnus.com> of Cygnus Support.
|
|
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
|
#include "symtab.h"
|
|
|
|
|
#include "inferior.h"
|
|
|
|
|
#include "command.h"
|
|
|
|
|
#include "bfd.h"
|
|
|
|
|
#include "symfile.h"
|
|
|
|
|
#include "objfiles.h"
|
|
|
|
|
#include "target.h"
|
|
|
|
|
#include "gdbcore.h"
|
|
|
|
|
#include "tracepoint.h"
|
|
|
|
|
#include "demangle.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <winuser.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
#include <tcl.h>
|
|
|
|
|
#include <tk.h>
|
|
|
|
|
#include <itcl.h>
|
|
|
|
|
#include <tix.h>
|
|
|
|
|
#include "guitcl.h"
|
|
|
|
|
#include "gdbtk.h"
|
|
|
|
|
|
|
|
|
|
#ifdef IDE
|
|
|
|
|
/* start-sanitize-ide */
|
|
|
|
|
#include "event.h"
|
|
|
|
|
#include "idetcl.h"
|
|
|
|
|
#include "ilutk.h"
|
|
|
|
|
/* end-sanitize-ide */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef ANSI_PROTOTYPES
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <varargs.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <setjmp.h>
|
|
|
|
|
#include "top.h"
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include "gdb_string.h"
|
|
|
|
|
#include "dis-asm.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "gdbcmd.h"
|
|
|
|
|
|
|
|
|
|
#include "annotate.h"
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
|
|
int in_fputs = 0;
|
|
|
|
|
|
1998-08-19 02:25:21 +00:00
|
|
|
|
extern int (*ui_load_progress_hook) PARAMS ((char *, unsigned long));
|
|
|
|
|
extern void (*pre_add_symbol_hook) PARAMS ((char *));
|
|
|
|
|
extern void (*post_add_symbol_hook) PARAMS ((void));
|
|
|
|
|
extern void (*selected_frame_level_changed_hook) PARAMS ((int));
|
1998-07-01 19:29:14 +00:00
|
|
|
|
#ifdef __CYGWIN32__
|
|
|
|
|
extern void (*ui_loop_hook) PARAMS ((int));
|
|
|
|
|
#endif
|
1998-08-19 02:25:21 +00:00
|
|
|
|
|
1998-07-01 19:29:14 +00:00
|
|
|
|
static void gdbtk_create_tracepoint PARAMS ((struct tracepoint *));
|
|
|
|
|
static void gdbtk_delete_tracepoint PARAMS ((struct tracepoint *));
|
|
|
|
|
static void gdbtk_modify_tracepoint PARAMS ((struct tracepoint *));
|
|
|
|
|
static void gdbtk_create_breakpoint PARAMS ((struct breakpoint *));
|
|
|
|
|
static void gdbtk_delete_breakpoint PARAMS ((struct breakpoint *));
|
|
|
|
|
static void gdbtk_modify_breakpoint PARAMS ((struct breakpoint *));
|
1998-10-08 23:05:32 +00:00
|
|
|
|
static void gdbtk_file_changed PARAMS ((char *));
|
|
|
|
|
static void gdbtk_exec_file_display PARAMS ((char *));
|
1998-07-01 19:29:14 +00:00
|
|
|
|
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 *));
|
|
|
|
|
void x_event PARAMS ((int));
|
|
|
|
|
static int gdbtk_query PARAMS ((const char *, va_list));
|
|
|
|
|
static void gdbtk_warning PARAMS ((const char *, va_list));
|
|
|
|
|
void gdbtk_ignorable_warning PARAMS ((const char *));
|
|
|
|
|
static char* gdbtk_readline PARAMS ((char *));
|
|
|
|
|
static void
|
|
|
|
|
#ifdef ANSI_PROTOTYPES
|
|
|
|
|
gdbtk_readline_begin (char *format, ...);
|
|
|
|
|
#else
|
|
|
|
|
gdbtk_readline_begin ();
|
|
|
|
|
#endif
|
|
|
|
|
static void gdbtk_readline_end PARAMS ((void));
|
|
|
|
|
static void gdbtk_flush PARAMS ((FILE *));
|
|
|
|
|
static void gdbtk_pre_add_symbol PARAMS ((char *));
|
|
|
|
|
static void gdbtk_print_frame_info PARAMS ((struct symtab *, int, int, int));
|
|
|
|
|
static void gdbtk_post_add_symbol PARAMS ((void));
|
|
|
|
|
static void pc_changed PARAMS ((void));
|
|
|
|
|
static void tracepoint_notify PARAMS ((struct tracepoint *, const char *));
|
1998-08-19 02:25:21 +00:00
|
|
|
|
static void gdbtk_selected_frame_changed PARAMS ((int));
|
1998-08-30 07:53:29 +00:00
|
|
|
|
static void gdbtk_context_change PARAMS ((int));
|
1998-07-01 19:29:14 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* gdbtk_fputs can't be static, because we need to call it in gdbtk.c.
|
|
|
|
|
* See note there for details.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void gdbtk_fputs PARAMS ((const char *, FILE *));
|
|
|
|
|
int gdbtk_load_hash PARAMS ((char *, unsigned long));
|
|
|
|
|
static void breakpoint_notify PARAMS ((struct breakpoint *, const char *));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* gdbtk_add_hooks - add all the hooks to gdb. This will get called by the
|
|
|
|
|
* startup code to fill in the hooks needed by core gdb.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gdbtk_add_hooks(void)
|
|
|
|
|
{
|
|
|
|
|
command_loop_hook = tk_command_loop;
|
|
|
|
|
call_command_hook = gdbtk_call_command;
|
|
|
|
|
readline_begin_hook = gdbtk_readline_begin;
|
|
|
|
|
readline_hook = gdbtk_readline;
|
|
|
|
|
readline_end_hook = gdbtk_readline_end;
|
|
|
|
|
|
|
|
|
|
print_frame_info_listing_hook = gdbtk_print_frame_info;
|
|
|
|
|
query_hook = gdbtk_query;
|
|
|
|
|
warning_hook = gdbtk_warning;
|
|
|
|
|
flush_hook = gdbtk_flush;
|
|
|
|
|
|
|
|
|
|
create_breakpoint_hook = gdbtk_create_breakpoint;
|
|
|
|
|
delete_breakpoint_hook = gdbtk_delete_breakpoint;
|
|
|
|
|
modify_breakpoint_hook = gdbtk_modify_breakpoint;
|
|
|
|
|
|
1998-10-02 19:55:41 +00:00
|
|
|
|
interactive_hook = gdbtk_interactive;
|
|
|
|
|
target_wait_hook = gdbtk_wait;
|
|
|
|
|
ui_load_progress_hook = gdbtk_load_hash;
|
|
|
|
|
|
1998-07-01 19:29:14 +00:00
|
|
|
|
#ifdef __CYGWIN32__
|
|
|
|
|
ui_loop_hook = x_event;
|
|
|
|
|
#endif
|
1998-10-02 19:55:41 +00:00
|
|
|
|
pre_add_symbol_hook = gdbtk_pre_add_symbol;
|
|
|
|
|
post_add_symbol_hook = gdbtk_post_add_symbol;
|
1998-10-08 23:05:32 +00:00
|
|
|
|
file_changed_hook = gdbtk_file_changed;
|
|
|
|
|
exec_file_display_hook = gdbtk_exec_file_display;
|
1998-07-01 19:29:14 +00:00
|
|
|
|
|
|
|
|
|
create_tracepoint_hook = gdbtk_create_tracepoint;
|
|
|
|
|
delete_tracepoint_hook = gdbtk_delete_tracepoint;
|
|
|
|
|
modify_tracepoint_hook = gdbtk_modify_tracepoint;
|
1998-10-02 19:55:41 +00:00
|
|
|
|
|
1998-07-01 19:29:14 +00:00
|
|
|
|
pc_changed_hook = pc_changed;
|
1998-08-19 02:25:21 +00:00
|
|
|
|
selected_frame_level_changed_hook = gdbtk_selected_frame_changed;
|
1998-08-30 07:53:29 +00:00
|
|
|
|
context_hook = gdbtk_context_change;
|
1998-07-01 19:29:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* These control where to put the gdb output which is created by
|
|
|
|
|
{f}printf_{un}filtered and friends. gdbtk_fputs and gdbtk_flush are the
|
|
|
|
|
lowest level of these routines and capture all output from the rest of GDB.
|
|
|
|
|
|
|
|
|
|
The reason to use the result_ptr rather than the gdbtk_interp's result
|
|
|
|
|
directly is so that a call_wrapper invoked function can preserve its result
|
|
|
|
|
across calls into Tcl which might be made in the course of the function's
|
|
|
|
|
execution.
|
|
|
|
|
|
|
|
|
|
* result_ptr->obj_ptr is where to accumulate the result.
|
|
|
|
|
* GDBTK_TO_RESULT flag means the output goes to the gdbtk_tcl_fputs proc
|
|
|
|
|
instead of to the result_ptr.
|
|
|
|
|
* GDBTK_MAKES_LIST flag means add to the result as a list element.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
gdbtk_result *result_ptr = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This allows you to Tcl_Eval a tcl command which takes
|
|
|
|
|
a command word, and then a single argument. */
|
|
|
|
|
|
|
|
|
|
int gdbtk_two_elem_cmd (cmd_name, argv1)
|
|
|
|
|
char *cmd_name;
|
|
|
|
|
char * argv1;
|
|
|
|
|
{
|
|
|
|
|
char *command;
|
|
|
|
|
int result, flags_ptr, arg_len, cmd_len;
|
|
|
|
|
|
|
|
|
|
arg_len = Tcl_ScanElement (argv1, &flags_ptr);
|
|
|
|
|
cmd_len = strlen (cmd_name);
|
|
|
|
|
command = malloc(arg_len + cmd_len + 2);
|
|
|
|
|
strcpy (command, cmd_name);
|
|
|
|
|
strcat (command, " ");
|
|
|
|
|
|
|
|
|
|
Tcl_ConvertElement (argv1, command + cmd_len + 1, flags_ptr);
|
|
|
|
|
|
|
|
|
|
result = Tcl_Eval (gdbtk_interp, command);
|
|
|
|
|
free (command);
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_flush (stream)
|
|
|
|
|
FILE *stream;
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
/* Force immediate screen update */
|
|
|
|
|
|
|
|
|
|
Tcl_VarEval (gdbtk_interp, "gdbtk_tcl_flush", NULL);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This handles all the output from gdb. All the gdb printf_xxx functions
|
|
|
|
|
* eventually end up here. The output is either passed to the result_ptr
|
|
|
|
|
* where it will go to the result of some gdbtk command, or passed to the
|
|
|
|
|
* Tcl proc gdbtk_tcl_fputs (where it is usually just dumped to the console
|
|
|
|
|
* window.
|
|
|
|
|
*
|
|
|
|
|
* The cases are:
|
|
|
|
|
*
|
|
|
|
|
* 1) result_ptr == NULL - This happens when some output comes from gdb which
|
1998-07-01 20:17:31 +00:00
|
|
|
|
* is not generated by a command in gdbtk-cmds, usually startup stuff.
|
1998-07-01 19:29:14 +00:00
|
|
|
|
* In this case we just route the data to gdbtk_tcl_fputs.
|
|
|
|
|
* 2) The GDBTK_TO_RESULT flag is set - The result is supposed to go to Tcl.
|
|
|
|
|
* We place the data into the result_ptr, either as a string,
|
|
|
|
|
* or a list, depending whether the GDBTK_MAKES_LIST bit is set.
|
|
|
|
|
* 3) The GDBTK_TO_RESULT flag is unset - We route the data to gdbtk_tcl_fputs
|
|
|
|
|
* UNLESS it was coming to stderr. Then we place it in the result_ptr
|
|
|
|
|
* anyway, so it can be dealt with.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gdbtk_fputs (ptr, stream)
|
|
|
|
|
const char *ptr;
|
|
|
|
|
FILE *stream;
|
|
|
|
|
{
|
|
|
|
|
in_fputs = 1;
|
|
|
|
|
|
|
|
|
|
if (result_ptr != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (result_ptr->flags & GDBTK_TO_RESULT)
|
|
|
|
|
{
|
|
|
|
|
if (result_ptr->flags & GDBTK_MAKES_LIST)
|
|
|
|
|
Tcl_ListObjAppendElement(NULL, result_ptr->obj_ptr,
|
|
|
|
|
Tcl_NewStringObj((char *) ptr, -1));
|
|
|
|
|
else
|
|
|
|
|
Tcl_AppendToObj (result_ptr->obj_ptr, (char *) ptr, -1);
|
|
|
|
|
}
|
|
|
|
|
else if (stream == gdb_stderr)
|
|
|
|
|
{
|
|
|
|
|
if (result_ptr->flags & GDBTK_ERROR_STARTED)
|
|
|
|
|
Tcl_AppendToObj (result_ptr->obj_ptr, (char *) ptr, -1);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Tcl_SetStringObj (result_ptr->obj_ptr, (char *) ptr, -1);
|
|
|
|
|
result_ptr->flags |= GDBTK_ERROR_STARTED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", (char *) ptr);
|
|
|
|
|
if (result_ptr->flags & GDBTK_MAKES_LIST)
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", " ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", (char *) ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
in_fputs = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This routes all warnings to the Tcl function "gdbtk_tcl_warning".
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_warning (warning, args)
|
|
|
|
|
const char *warning;
|
|
|
|
|
va_list args;
|
|
|
|
|
{
|
|
|
|
|
char buf[200];
|
|
|
|
|
|
|
|
|
|
vsprintf (buf, warning, args);
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_warning", buf);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This routes all ignorable warnings to the Tcl function
|
|
|
|
|
* "gdbtk_tcl_ignorable_warning".
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gdbtk_ignorable_warning (warning)
|
|
|
|
|
const char *warning;
|
|
|
|
|
{
|
1998-07-27 20:23:58 +00:00
|
|
|
|
char buf[512];
|
1998-07-01 19:29:14 +00:00
|
|
|
|
sprintf (buf, warning);
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_ignorable_warning", buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
pc_changed()
|
|
|
|
|
{
|
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_pc_changed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function is called instead of gdb's internal command loop. This is the
|
|
|
|
|
last chance to do anything before entering the main Tk event loop.
|
|
|
|
|
At the end of the command, we enter the main loop. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tk_command_loop ()
|
|
|
|
|
{
|
|
|
|
|
extern GDB_FILE *instream;
|
|
|
|
|
|
|
|
|
|
/* We no longer want to use stdin as the command input stream */
|
|
|
|
|
instream = NULL;
|
|
|
|
|
|
|
|
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_tcl_preloop") != TCL_OK)
|
|
|
|
|
{
|
|
|
|
|
char *msg;
|
|
|
|
|
|
|
|
|
|
/* Force errorInfo to be set up propertly. */
|
|
|
|
|
Tcl_AddErrorInfo (gdbtk_interp, "");
|
|
|
|
|
|
|
|
|
|
msg = Tcl_GetVar (gdbtk_interp, "errorInfo", TCL_GLOBAL_ONLY);
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
MessageBox (NULL, msg, NULL, MB_OK | MB_ICONERROR | MB_TASKMODAL);
|
|
|
|
|
#else
|
|
|
|
|
fputs_unfiltered (msg, gdb_stderr);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
close_bfds ();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Tk_MainLoop ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Come here when there is activity on the X file descriptor. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
x_event (signo)
|
|
|
|
|
int signo;
|
|
|
|
|
{
|
|
|
|
|
static int in_x_event = 0;
|
|
|
|
|
static Tcl_Obj *varname = NULL;
|
|
|
|
|
if (in_x_event || in_fputs)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
in_x_event = 1;
|
|
|
|
|
|
|
|
|
|
#ifdef __CYGWIN32__
|
|
|
|
|
if (signo == -2)
|
|
|
|
|
gdbtk_stop_timer ();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Process pending events */
|
|
|
|
|
while (Tcl_DoOneEvent (TCL_DONT_WAIT|TCL_ALL_EVENTS) != 0)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
if (load_in_progress)
|
|
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
if (varname == NULL)
|
|
|
|
|
{
|
|
|
|
|
Tcl_Obj *varnamestrobj = Tcl_NewStringObj("download_cancel_ok",-1);
|
|
|
|
|
varname = Tcl_ObjGetVar2(gdbtk_interp,varnamestrobj,NULL,TCL_GLOBAL_ONLY);
|
|
|
|
|
}
|
|
|
|
|
if ((Tcl_GetIntFromObj(gdbtk_interp,varname,&val) == TCL_OK) && val)
|
|
|
|
|
{
|
|
|
|
|
quit_flag = 1;
|
|
|
|
|
#ifdef REQUEST_QUIT
|
|
|
|
|
REQUEST_QUIT;
|
|
|
|
|
#else
|
|
|
|
|
if (immediate_quit)
|
|
|
|
|
quit ();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
in_x_event = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VARARGS */
|
|
|
|
|
static void
|
|
|
|
|
#ifdef ANSI_PROTOTYPES
|
|
|
|
|
gdbtk_readline_begin (char *format, ...)
|
|
|
|
|
#else
|
|
|
|
|
gdbtk_readline_begin (va_alist)
|
|
|
|
|
va_dcl
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
1998-07-27 20:23:58 +00:00
|
|
|
|
char buf[200];
|
1998-07-01 19:29:14 +00:00
|
|
|
|
|
|
|
|
|
#ifdef ANSI_PROTOTYPES
|
|
|
|
|
va_start (args, format);
|
|
|
|
|
#else
|
|
|
|
|
char *format;
|
|
|
|
|
va_start (args);
|
|
|
|
|
format = va_arg (args, char *);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
vsprintf (buf, format, args);
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_readline_begin", buf);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
gdbtk_readline (prompt)
|
|
|
|
|
char *prompt;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
close_bfds ();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
result = gdbtk_two_elem_cmd ("gdbtk_tcl_readline", prompt);
|
|
|
|
|
|
|
|
|
|
if (result == TCL_OK)
|
|
|
|
|
{
|
|
|
|
|
return (strdup (gdbtk_interp -> result));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gdbtk_fputs (gdbtk_interp -> result, gdb_stdout);
|
|
|
|
|
gdbtk_fputs ("\n", gdb_stdout);
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_readline_end ()
|
|
|
|
|
{
|
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_readline_end");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_call_command (cmdblk, arg, from_tty)
|
|
|
|
|
struct cmd_list_element *cmdblk;
|
|
|
|
|
char *arg;
|
|
|
|
|
int from_tty;
|
|
|
|
|
{
|
|
|
|
|
running_now = 0;
|
|
|
|
|
if (cmdblk->class == class_run || cmdblk->class == class_trace)
|
|
|
|
|
{
|
|
|
|
|
|
1998-08-19 02:25:21 +00:00
|
|
|
|
/* HACK! HACK! This is to get the gui to update the tstart/tstop
|
|
|
|
|
button only incase of tstart/tstop commands issued from the console
|
|
|
|
|
We don't want to update the src window, so we need to have specific
|
|
|
|
|
procedures to do tstart and tstop
|
|
|
|
|
Unfortunately this will not display errors from tstart or tstop in the
|
|
|
|
|
console window itself, but as dialogs.*/
|
1998-07-01 19:29:14 +00:00
|
|
|
|
|
|
|
|
|
if (!strcmp(cmdblk->name, "tstart") && !No_Update)
|
|
|
|
|
{
|
1998-08-19 02:25:21 +00:00
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_tstart");
|
|
|
|
|
(*cmdblk->function.cfunc)(arg, from_tty);
|
1998-07-01 19:29:14 +00:00
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(cmdblk->name, "tstop") && !No_Update)
|
1998-08-19 02:25:21 +00:00
|
|
|
|
{
|
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_tstop");
|
|
|
|
|
(*cmdblk->function.cfunc)(arg, from_tty);
|
|
|
|
|
}
|
|
|
|
|
/* end of hack */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
running_now = 1;
|
|
|
|
|
if (!No_Update)
|
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_busy");
|
|
|
|
|
(*cmdblk->function.cfunc)(arg, from_tty);
|
|
|
|
|
running_now = 0;
|
|
|
|
|
if (!No_Update)
|
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_idle");
|
|
|
|
|
}
|
1998-07-01 19:29:14 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
(*cmdblk->function.cfunc)(arg, from_tty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The next three functions use breakpoint_notify to allow the GUI
|
|
|
|
|
* to handle creating, deleting and modifying breakpoints. These three
|
|
|
|
|
* functions are put into the appropriate gdb hooks in gdbtk_init.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_create_breakpoint(b)
|
|
|
|
|
struct breakpoint *b;
|
|
|
|
|
{
|
|
|
|
|
breakpoint_notify (b, "create");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_delete_breakpoint(b)
|
|
|
|
|
struct breakpoint *b;
|
|
|
|
|
{
|
|
|
|
|
breakpoint_notify (b, "delete");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_modify_breakpoint(b)
|
|
|
|
|
struct breakpoint *b;
|
|
|
|
|
{
|
|
|
|
|
breakpoint_notify (b, "modify");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is the generic function for handling changes in
|
|
|
|
|
* a breakpoint. It routes the information to the Tcl
|
|
|
|
|
* command "gdbtk_tcl_breakpoint" in the form:
|
|
|
|
|
* gdbtk_tcl_breakpoint action b_number b_address b_line b_file
|
|
|
|
|
* On error, the error string is written to gdb_stdout.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
breakpoint_notify(b, action)
|
|
|
|
|
struct breakpoint *b;
|
|
|
|
|
const char *action;
|
|
|
|
|
{
|
|
|
|
|
char buf[256];
|
|
|
|
|
int v;
|
|
|
|
|
struct symtab_and_line sal;
|
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
|
|
if (b->type != bp_breakpoint)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* We ensure that ACTION contains no special Tcl characters, so we
|
|
|
|
|
can do this. */
|
|
|
|
|
sal = find_pc_line (b->address, 0);
|
|
|
|
|
filename = symtab_to_filename (sal.symtab);
|
|
|
|
|
if (filename == NULL)
|
|
|
|
|
filename = "";
|
|
|
|
|
|
|
|
|
|
sprintf (buf, "gdbtk_tcl_breakpoint %s %d 0x%lx %d {%s}", action, b->number,
|
|
|
|
|
(long)b->address, b->line_number, filename);
|
|
|
|
|
|
|
|
|
|
v = Tcl_Eval (gdbtk_interp, buf);
|
|
|
|
|
|
|
|
|
|
if (v != TCL_OK)
|
|
|
|
|
{
|
|
|
|
|
gdbtk_fputs (Tcl_GetStringResult (gdbtk_interp), gdb_stdout);
|
|
|
|
|
gdbtk_fputs ("\n", gdb_stdout);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
gdbtk_load_hash (section, num)
|
|
|
|
|
char *section;
|
|
|
|
|
unsigned long num;
|
|
|
|
|
{
|
|
|
|
|
char buf[128];
|
|
|
|
|
sprintf (buf, "download_hash %s %ld", section, num);
|
|
|
|
|
Tcl_Eval (gdbtk_interp, buf);
|
|
|
|
|
return atoi (gdbtk_interp->result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This hook is called whenever we are ready to load a symbol file so that
|
|
|
|
|
the UI can notify the user... */
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_pre_add_symbol (name)
|
|
|
|
|
char *name;
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
gdbtk_two_elem_cmd("gdbtk_tcl_pre_add_symbol", name);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This hook is called whenever we finish loading a symbol file. */
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_post_add_symbol ()
|
|
|
|
|
{
|
|
|
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_post_add_symbol");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This hook function is called whenever we want to wait for the
|
|
|
|
|
target. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
gdbtk_wait (pid, ourstatus)
|
|
|
|
|
int pid;
|
|
|
|
|
struct target_waitstatus *ourstatus;
|
|
|
|
|
{
|
1998-09-25 15:22:23 +00:00
|
|
|
|
/* Don't run the timer on various targets... */
|
|
|
|
|
if (!STREQ (target_shortname, "ice"))
|
|
|
|
|
gdbtk_start_timer ();
|
1998-07-01 19:29:14 +00:00
|
|
|
|
pid = target_wait (pid, ourstatus);
|
|
|
|
|
gdbtk_stop_timer ();
|
|
|
|
|
return pid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This handles all queries from gdb.
|
|
|
|
|
* The first argument is a printf style format statement, the rest are its
|
|
|
|
|
* arguments. The resultant formatted string is passed to the Tcl function
|
|
|
|
|
* "gdbtk_tcl_query".
|
|
|
|
|
* It returns the users response to the query, as well as putting the value
|
|
|
|
|
* in the result field of the Tcl interpreter.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
gdbtk_query (query, args)
|
|
|
|
|
const char *query;
|
|
|
|
|
va_list args;
|
|
|
|
|
{
|
|
|
|
|
char buf[200];
|
|
|
|
|
long val;
|
|
|
|
|
|
|
|
|
|
vsprintf (buf, query, args);
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_query", buf);
|
|
|
|
|
|
|
|
|
|
val = atol (gdbtk_interp->result);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_print_frame_info (s, line, stopline, noerror)
|
|
|
|
|
struct symtab *s;
|
|
|
|
|
int line;
|
|
|
|
|
int stopline;
|
|
|
|
|
int noerror;
|
|
|
|
|
{
|
|
|
|
|
current_source_symtab = s;
|
|
|
|
|
current_source_line = line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_create_tracepoint (tp)
|
|
|
|
|
struct tracepoint *tp;
|
|
|
|
|
{
|
|
|
|
|
tracepoint_notify (tp, "create");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_delete_tracepoint (tp)
|
|
|
|
|
struct tracepoint *tp;
|
|
|
|
|
{
|
|
|
|
|
tracepoint_notify (tp, "delete");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_modify_tracepoint (tp)
|
|
|
|
|
struct tracepoint *tp;
|
|
|
|
|
{
|
|
|
|
|
tracepoint_notify (tp, "modify");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tracepoint_notify(tp, action)
|
|
|
|
|
struct tracepoint *tp;
|
|
|
|
|
const char *action;
|
|
|
|
|
{
|
|
|
|
|
char buf[256];
|
|
|
|
|
int v;
|
|
|
|
|
struct symtab_and_line sal;
|
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
|
|
/* We ensure that ACTION contains no special Tcl characters, so we
|
|
|
|
|
can do this. */
|
|
|
|
|
sal = find_pc_line (tp->address, 0);
|
|
|
|
|
|
|
|
|
|
filename = symtab_to_filename (sal.symtab);
|
|
|
|
|
if (filename == NULL)
|
|
|
|
|
filename = "N/A";
|
1998-07-27 20:23:58 +00:00
|
|
|
|
sprintf (buf, "gdbtk_tcl_tracepoint %s %d 0x%lx %d {%s} %d", action, tp->number,
|
1998-07-01 19:29:14 +00:00
|
|
|
|
(long)tp->address, sal.line, filename, tp->pass_count);
|
|
|
|
|
|
|
|
|
|
v = Tcl_Eval (gdbtk_interp, buf);
|
|
|
|
|
|
|
|
|
|
if (v != TCL_OK)
|
|
|
|
|
{
|
|
|
|
|
gdbtk_fputs (gdbtk_interp->result, gdb_stdout);
|
|
|
|
|
gdbtk_fputs ("\n", gdb_stdout);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-08-19 02:25:21 +00:00
|
|
|
|
static void
|
|
|
|
|
gdbtk_selected_frame_changed (level)
|
|
|
|
|
int level;
|
|
|
|
|
{
|
|
|
|
|
Tcl_UpdateLinkedVar (gdbtk_interp, "gdb_selected_frame_level");
|
|
|
|
|
}
|
1998-08-30 07:53:29 +00:00
|
|
|
|
|
|
|
|
|
/* Called when the current thread changes. */
|
|
|
|
|
/* gdb_context is linked to the tcl variable "gdb_context_id" */
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_context_change (num)
|
|
|
|
|
int num;
|
|
|
|
|
{
|
|
|
|
|
gdb_context = num;
|
|
|
|
|
}
|
1998-10-02 19:55:41 +00:00
|
|
|
|
|
1998-10-08 23:05:32 +00:00
|
|
|
|
/* Called from file_command */
|
|
|
|
|
static void
|
|
|
|
|
gdbtk_file_changed (filename)
|
|
|
|
|
char *filename;
|
|
|
|
|
{
|
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_file_changed", filename);
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-02 19:55:41 +00:00
|
|
|
|
/* Called from exec_file_command */
|
|
|
|
|
static void
|
1998-10-08 23:05:32 +00:00
|
|
|
|
gdbtk_exec_file_display (filename)
|
1998-10-02 19:55:41 +00:00
|
|
|
|
char *filename;
|
|
|
|
|
{
|
1998-10-08 23:05:32 +00:00
|
|
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_exec_file_display", filename);
|
1998-10-02 19:55:41 +00:00
|
|
|
|
}
|