1 |
578 |
markom |
/* Startup code for Insight.
|
2 |
|
|
Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001
|
3 |
|
|
Free Software Foundation, Inc.
|
4 |
|
|
|
5 |
|
|
Written by Stu Grossman <grossman@cygnus.com> of Cygnus Support.
|
6 |
|
|
|
7 |
|
|
This file is part of GDB.
|
8 |
|
|
|
9 |
|
|
This program is free software; you can redistribute it and/or modify
|
10 |
|
|
it under the terms of the GNU General Public License as published by
|
11 |
|
|
the Free Software Foundation; either version 2 of the License, or
|
12 |
|
|
(at your option) any later version.
|
13 |
|
|
|
14 |
|
|
This program is distributed in the hope that it will be useful,
|
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17 |
|
|
GNU General Public License for more details.
|
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU General Public License
|
20 |
|
|
along with this program; if not, write to the Free Software
|
21 |
|
|
Foundation, Inc., 59 Temple Place - Suite 330,
|
22 |
|
|
Boston, MA 02111-1307, USA. */
|
23 |
|
|
|
24 |
|
|
#include "defs.h"
|
25 |
|
|
#include "symtab.h"
|
26 |
|
|
#include "inferior.h"
|
27 |
|
|
#include "command.h"
|
28 |
|
|
#include "bfd.h"
|
29 |
|
|
#include "symfile.h"
|
30 |
|
|
#include "objfiles.h"
|
31 |
|
|
#include "target.h"
|
32 |
|
|
#include "gdbcore.h"
|
33 |
|
|
#include "tracepoint.h"
|
34 |
|
|
#include "demangle.h"
|
35 |
|
|
#include "gdb-events.h"
|
36 |
|
|
|
37 |
|
|
#ifdef _WIN32
|
38 |
|
|
#define WIN32_LEAN_AND_MEAN
|
39 |
|
|
#include <windows.h>
|
40 |
|
|
#endif
|
41 |
|
|
|
42 |
|
|
#include <sys/stat.h>
|
43 |
|
|
|
44 |
|
|
#include <tcl.h>
|
45 |
|
|
#include <tk.h>
|
46 |
|
|
#include <itcl.h>
|
47 |
|
|
#include <tix.h>
|
48 |
|
|
#include "guitcl.h"
|
49 |
|
|
#include "gdbtk.h"
|
50 |
|
|
|
51 |
|
|
#include <stdarg.h>
|
52 |
|
|
#include <signal.h>
|
53 |
|
|
#include <fcntl.h>
|
54 |
|
|
#include "top.h"
|
55 |
|
|
#include <sys/ioctl.h>
|
56 |
|
|
#include "gdb_string.h"
|
57 |
|
|
#include "dis-asm.h"
|
58 |
|
|
#include <stdio.h>
|
59 |
|
|
#include "gdbcmd.h"
|
60 |
|
|
|
61 |
|
|
#include "annotate.h"
|
62 |
|
|
#include <sys/time.h>
|
63 |
|
|
|
64 |
|
|
volatile int in_fputs = 0;
|
65 |
|
|
|
66 |
|
|
/* Set by gdb_stop, this flag informs x_event to tell its caller
|
67 |
|
|
that it should forcibly detach from the target. */
|
68 |
|
|
int gdbtk_force_detach = 0;
|
69 |
|
|
|
70 |
|
|
/* From gdbtk-bp.c */
|
71 |
|
|
extern void gdbtk_create_breakpoint (int);
|
72 |
|
|
extern void gdbtk_delete_breakpoint (int);
|
73 |
|
|
extern void gdbtk_modify_breakpoint (int);
|
74 |
|
|
extern void gdbtk_create_tracepoint (int);
|
75 |
|
|
extern void gdbtk_delete_tracepoint (int);
|
76 |
|
|
extern void gdbtk_modify_tracepoint (int);
|
77 |
|
|
|
78 |
|
|
extern void (*pre_add_symbol_hook) (char *);
|
79 |
|
|
extern void (*post_add_symbol_hook) (void);
|
80 |
|
|
extern void (*selected_frame_level_changed_hook) (int);
|
81 |
|
|
extern int (*ui_loop_hook) (int);
|
82 |
|
|
|
83 |
|
|
static void gdbtk_trace_find (char *arg, int from_tty);
|
84 |
|
|
static void gdbtk_trace_start_stop (int, int);
|
85 |
|
|
static void gdbtk_attach (void);
|
86 |
|
|
static void gdbtk_detach (void);
|
87 |
|
|
static void gdbtk_file_changed (char *);
|
88 |
|
|
static void gdbtk_exec_file_display (char *);
|
89 |
|
|
static void tk_command_loop (void);
|
90 |
|
|
static void gdbtk_call_command (struct cmd_list_element *, char *, int);
|
91 |
|
|
static ptid_t gdbtk_wait (ptid_t, struct target_waitstatus *);
|
92 |
|
|
int x_event (int);
|
93 |
|
|
static int gdbtk_query (const char *, va_list);
|
94 |
|
|
static void gdbtk_warning (const char *, va_list);
|
95 |
|
|
static char *gdbtk_readline (char *);
|
96 |
|
|
static void gdbtk_readline_begin (char *format,...);
|
97 |
|
|
static void gdbtk_readline_end (void);
|
98 |
|
|
static void gdbtk_pre_add_symbol (char *);
|
99 |
|
|
static void gdbtk_print_frame_info (struct symtab *, int, int, int);
|
100 |
|
|
static void gdbtk_post_add_symbol (void);
|
101 |
|
|
static void gdbtk_register_changed (int regno);
|
102 |
|
|
static void gdbtk_memory_changed (CORE_ADDR addr, int len);
|
103 |
|
|
static void gdbtk_selected_frame_changed (int);
|
104 |
|
|
static void gdbtk_context_change (int);
|
105 |
|
|
static void gdbtk_error_begin (void);
|
106 |
|
|
void report_error (void);
|
107 |
|
|
static void gdbtk_annotate_signal (void);
|
108 |
|
|
static void gdbtk_set_hook (struct cmd_list_element *cmdblk);
|
109 |
|
|
|
110 |
|
|
/*
|
111 |
|
|
* gdbtk_fputs can't be static, because we need to call it in gdbtk.c.
|
112 |
|
|
* See note there for details.
|
113 |
|
|
*/
|
114 |
|
|
|
115 |
|
|
void gdbtk_fputs (const char *, struct ui_file *);
|
116 |
|
|
static int gdbtk_load_hash (const char *, unsigned long);
|
117 |
|
|
|
118 |
|
|
/*
|
119 |
|
|
* gdbtk_add_hooks - add all the hooks to gdb. This will get called by the
|
120 |
|
|
* startup code to fill in the hooks needed by core gdb.
|
121 |
|
|
*/
|
122 |
|
|
|
123 |
|
|
void
|
124 |
|
|
gdbtk_add_hooks (void)
|
125 |
|
|
{
|
126 |
|
|
static struct gdb_events handlers;
|
127 |
|
|
|
128 |
|
|
/* Gdb event handlers */
|
129 |
|
|
handlers.breakpoint_create = gdbtk_create_breakpoint;
|
130 |
|
|
handlers.breakpoint_modify = gdbtk_modify_breakpoint;
|
131 |
|
|
handlers.breakpoint_delete = gdbtk_delete_breakpoint;
|
132 |
|
|
handlers.tracepoint_create = gdbtk_create_tracepoint;
|
133 |
|
|
handlers.tracepoint_modify = gdbtk_modify_tracepoint;
|
134 |
|
|
handlers.tracepoint_delete = gdbtk_delete_tracepoint;
|
135 |
|
|
set_gdb_event_hooks (&handlers);
|
136 |
|
|
|
137 |
|
|
/* Hooks */
|
138 |
|
|
command_loop_hook = tk_command_loop;
|
139 |
|
|
call_command_hook = gdbtk_call_command;
|
140 |
|
|
set_hook = gdbtk_set_hook;
|
141 |
|
|
readline_begin_hook = gdbtk_readline_begin;
|
142 |
|
|
readline_hook = gdbtk_readline;
|
143 |
|
|
readline_end_hook = gdbtk_readline_end;
|
144 |
|
|
|
145 |
|
|
print_frame_info_listing_hook = gdbtk_print_frame_info;
|
146 |
|
|
query_hook = gdbtk_query;
|
147 |
|
|
warning_hook = gdbtk_warning;
|
148 |
|
|
|
149 |
|
|
interactive_hook = gdbtk_interactive;
|
150 |
|
|
target_wait_hook = gdbtk_wait;
|
151 |
|
|
ui_load_progress_hook = gdbtk_load_hash;
|
152 |
|
|
|
153 |
|
|
ui_loop_hook = x_event;
|
154 |
|
|
pre_add_symbol_hook = gdbtk_pre_add_symbol;
|
155 |
|
|
post_add_symbol_hook = gdbtk_post_add_symbol;
|
156 |
|
|
file_changed_hook = gdbtk_file_changed;
|
157 |
|
|
specify_exec_file_hook (gdbtk_exec_file_display);
|
158 |
|
|
|
159 |
|
|
trace_find_hook = gdbtk_trace_find;
|
160 |
|
|
trace_start_stop_hook = gdbtk_trace_start_stop;
|
161 |
|
|
|
162 |
|
|
attach_hook = gdbtk_attach;
|
163 |
|
|
detach_hook = gdbtk_detach;
|
164 |
|
|
|
165 |
|
|
register_changed_hook = gdbtk_register_changed;
|
166 |
|
|
memory_changed_hook = gdbtk_memory_changed;
|
167 |
|
|
selected_frame_level_changed_hook = gdbtk_selected_frame_changed;
|
168 |
|
|
context_hook = gdbtk_context_change;
|
169 |
|
|
|
170 |
|
|
error_begin_hook = gdbtk_error_begin;
|
171 |
|
|
|
172 |
|
|
annotate_signal_hook = gdbtk_annotate_signal;
|
173 |
|
|
}
|
174 |
|
|
|
175 |
|
|
/* These control where to put the gdb output which is created by
|
176 |
|
|
{f}printf_{un}filtered and friends. gdbtk_fputs is the lowest
|
177 |
|
|
level of these routines and capture all output from the rest of
|
178 |
|
|
GDB.
|
179 |
|
|
|
180 |
|
|
The reason to use the result_ptr rather than the gdbtk_interp's result
|
181 |
|
|
directly is so that a call_wrapper invoked function can preserve its result
|
182 |
|
|
across calls into Tcl which might be made in the course of the function's
|
183 |
|
|
execution.
|
184 |
|
|
|
185 |
|
|
* result_ptr->obj_ptr is where to accumulate the result.
|
186 |
|
|
* GDBTK_TO_RESULT flag means the output goes to the gdbtk_tcl_fputs proc
|
187 |
|
|
instead of to the result_ptr.
|
188 |
|
|
* GDBTK_MAKES_LIST flag means add to the result as a list element.
|
189 |
|
|
|
190 |
|
|
*/
|
191 |
|
|
|
192 |
|
|
gdbtk_result *result_ptr = NULL;
|
193 |
|
|
|
194 |
|
|
/* If you want to restore an old value of result_ptr whenever cleanups
|
195 |
|
|
are run, pass this function to make_cleanup, along with the value
|
196 |
|
|
of result_ptr you'd like to reinstate. */
|
197 |
|
|
void
|
198 |
|
|
gdbtk_restore_result_ptr (void *old_result_ptr)
|
199 |
|
|
{
|
200 |
|
|
result_ptr = (gdbtk_result *) old_result_ptr;
|
201 |
|
|
}
|
202 |
|
|
|
203 |
|
|
/* This allows you to Tcl_Eval a tcl command which takes
|
204 |
|
|
a command word, and then a single argument. */
|
205 |
|
|
int
|
206 |
|
|
gdbtk_two_elem_cmd (cmd_name, argv1)
|
207 |
|
|
char *cmd_name;
|
208 |
|
|
char *argv1;
|
209 |
|
|
{
|
210 |
|
|
char *command;
|
211 |
|
|
int result, flags_ptr, arg_len, cmd_len;
|
212 |
|
|
|
213 |
|
|
arg_len = Tcl_ScanElement (argv1, &flags_ptr);
|
214 |
|
|
cmd_len = strlen (cmd_name);
|
215 |
|
|
command = malloc (arg_len + cmd_len + 2);
|
216 |
|
|
strcpy (command, cmd_name);
|
217 |
|
|
strcat (command, " ");
|
218 |
|
|
|
219 |
|
|
Tcl_ConvertElement (argv1, command + cmd_len + 1, flags_ptr);
|
220 |
|
|
|
221 |
|
|
result = Tcl_Eval (gdbtk_interp, command);
|
222 |
|
|
if (result != TCL_OK)
|
223 |
|
|
report_error ();
|
224 |
|
|
free (command);
|
225 |
|
|
return result;
|
226 |
|
|
}
|
227 |
|
|
|
228 |
|
|
struct ui_file *
|
229 |
|
|
gdbtk_fileopen (void)
|
230 |
|
|
{
|
231 |
|
|
struct ui_file *file = ui_file_new ();
|
232 |
|
|
set_ui_file_fputs (file, gdbtk_fputs);
|
233 |
|
|
return file;
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
/* This handles all the output from gdb. All the gdb printf_xxx functions
|
237 |
|
|
* eventually end up here. The output is either passed to the result_ptr
|
238 |
|
|
* where it will go to the result of some gdbtk command, or passed to the
|
239 |
|
|
* Tcl proc gdbtk_tcl_fputs (where it is usually just dumped to the console
|
240 |
|
|
* window.
|
241 |
|
|
*
|
242 |
|
|
* The cases are:
|
243 |
|
|
*
|
244 |
|
|
* 1) result_ptr == NULL - This happens when some output comes from gdb which
|
245 |
|
|
* is not generated by a command in gdbtk-cmds, usually startup stuff.
|
246 |
|
|
* In this case we just route the data to gdbtk_tcl_fputs.
|
247 |
|
|
* 2) The GDBTK_TO_RESULT flag is set - The result is supposed to go to Tcl.
|
248 |
|
|
* We place the data into the result_ptr, either as a string,
|
249 |
|
|
* or a list, depending whether the GDBTK_MAKES_LIST bit is set.
|
250 |
|
|
* 3) The GDBTK_TO_RESULT flag is unset - We route the data to gdbtk_tcl_fputs
|
251 |
|
|
* UNLESS it was coming to gdb_stderr. Then we place it in the result_ptr
|
252 |
|
|
* anyway, so it can be dealt with.
|
253 |
|
|
*
|
254 |
|
|
*/
|
255 |
|
|
|
256 |
|
|
void
|
257 |
|
|
gdbtk_fputs (const char *ptr, struct ui_file *stream)
|
258 |
|
|
{
|
259 |
|
|
if (gdbtk_disable_fputs)
|
260 |
|
|
return;
|
261 |
|
|
|
262 |
|
|
in_fputs = 1;
|
263 |
|
|
|
264 |
|
|
if (stream == gdb_stdlog)
|
265 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs_log", (char *) ptr);
|
266 |
|
|
else if (stream == gdb_stdtarg)
|
267 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs_target", (char *) ptr);
|
268 |
|
|
else if (result_ptr != NULL)
|
269 |
|
|
{
|
270 |
|
|
if (result_ptr->flags & GDBTK_TO_RESULT)
|
271 |
|
|
{
|
272 |
|
|
if (result_ptr->flags & GDBTK_MAKES_LIST)
|
273 |
|
|
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
|
274 |
|
|
Tcl_NewStringObj ((char *) ptr, -1));
|
275 |
|
|
else
|
276 |
|
|
Tcl_AppendToObj (result_ptr->obj_ptr, (char *) ptr, -1);
|
277 |
|
|
}
|
278 |
|
|
else if (stream == gdb_stderr || result_ptr->flags & GDBTK_ERROR_ONLY)
|
279 |
|
|
{
|
280 |
|
|
if (result_ptr->flags & GDBTK_ERROR_STARTED)
|
281 |
|
|
Tcl_AppendToObj (result_ptr->obj_ptr, (char *) ptr, -1);
|
282 |
|
|
else
|
283 |
|
|
{
|
284 |
|
|
Tcl_SetStringObj (result_ptr->obj_ptr, (char *) ptr, -1);
|
285 |
|
|
result_ptr->flags |= GDBTK_ERROR_STARTED;
|
286 |
|
|
}
|
287 |
|
|
}
|
288 |
|
|
else
|
289 |
|
|
{
|
290 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", (char *) ptr);
|
291 |
|
|
if (result_ptr->flags & GDBTK_MAKES_LIST)
|
292 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", " ");
|
293 |
|
|
}
|
294 |
|
|
}
|
295 |
|
|
else
|
296 |
|
|
{
|
297 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", (char *) ptr);
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
in_fputs = 0;
|
301 |
|
|
}
|
302 |
|
|
|
303 |
|
|
/*
|
304 |
|
|
* This routes all warnings to the Tcl function "gdbtk_tcl_warning".
|
305 |
|
|
*/
|
306 |
|
|
|
307 |
|
|
static void
|
308 |
|
|
gdbtk_warning (warning, args)
|
309 |
|
|
const char *warning;
|
310 |
|
|
va_list args;
|
311 |
|
|
{
|
312 |
|
|
char *buf;
|
313 |
|
|
|
314 |
|
|
xvasprintf (&buf, warning, args);
|
315 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_warning", buf);
|
316 |
|
|
|
317 |
|
|
free(buf);
|
318 |
|
|
}
|
319 |
|
|
|
320 |
|
|
|
321 |
|
|
/* Error-handling function for all hooks */
|
322 |
|
|
/* Hooks are not like tcl functions, they do not simply return */
|
323 |
|
|
/* TCL_OK or TCL_ERROR. Also, the calling function typically */
|
324 |
|
|
/* doesn't care about errors in the hook functions. Therefore */
|
325 |
|
|
/* after every hook function, report_error should be called. */
|
326 |
|
|
/* report_error can just call Tcl_BackgroundError() which will */
|
327 |
|
|
/* pop up a messagebox, or it can silently log the errors through */
|
328 |
|
|
/* the gdbtk dbug command. */
|
329 |
|
|
|
330 |
|
|
void
|
331 |
|
|
report_error ()
|
332 |
|
|
{
|
333 |
|
|
TclDebug ('E', Tcl_GetVar (gdbtk_interp, "errorInfo", TCL_GLOBAL_ONLY));
|
334 |
|
|
/* Tcl_BackgroundError(gdbtk_interp); */
|
335 |
|
|
}
|
336 |
|
|
|
337 |
|
|
/*
|
338 |
|
|
* This routes all ignorable warnings to the Tcl function
|
339 |
|
|
* "gdbtk_tcl_ignorable_warning".
|
340 |
|
|
*/
|
341 |
|
|
|
342 |
|
|
void
|
343 |
|
|
gdbtk_ignorable_warning (class, warning)
|
344 |
|
|
const char *class;
|
345 |
|
|
const char *warning;
|
346 |
|
|
{
|
347 |
|
|
char *buf;
|
348 |
|
|
xasprintf (&buf, "gdbtk_tcl_ignorable_warning {%s} {%s}", class, warning);
|
349 |
|
|
if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK)
|
350 |
|
|
report_error ();
|
351 |
|
|
free(buf);
|
352 |
|
|
}
|
353 |
|
|
|
354 |
|
|
static void
|
355 |
|
|
gdbtk_register_changed (regno)
|
356 |
|
|
int regno;
|
357 |
|
|
{
|
358 |
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_register_changed") != TCL_OK)
|
359 |
|
|
report_error ();
|
360 |
|
|
}
|
361 |
|
|
|
362 |
|
|
static void
|
363 |
|
|
gdbtk_memory_changed (addr, len)
|
364 |
|
|
CORE_ADDR addr;
|
365 |
|
|
int len;
|
366 |
|
|
{
|
367 |
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_memory_changed") != TCL_OK)
|
368 |
|
|
report_error ();
|
369 |
|
|
}
|
370 |
|
|
|
371 |
|
|
|
372 |
|
|
/* This function is called instead of gdb's internal command loop. This is the
|
373 |
|
|
last chance to do anything before entering the main Tk event loop.
|
374 |
|
|
At the end of the command, we enter the main loop. */
|
375 |
|
|
|
376 |
|
|
static void
|
377 |
|
|
tk_command_loop ()
|
378 |
|
|
{
|
379 |
|
|
extern FILE *instream;
|
380 |
|
|
|
381 |
|
|
/* We no longer want to use stdin as the command input stream */
|
382 |
|
|
instream = NULL;
|
383 |
|
|
|
384 |
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_tcl_preloop") != TCL_OK)
|
385 |
|
|
{
|
386 |
|
|
char *msg;
|
387 |
|
|
|
388 |
|
|
/* Force errorInfo to be set up propertly. */
|
389 |
|
|
Tcl_AddErrorInfo (gdbtk_interp, "");
|
390 |
|
|
|
391 |
|
|
msg = Tcl_GetVar (gdbtk_interp, "errorInfo", TCL_GLOBAL_ONLY);
|
392 |
|
|
#ifdef _WIN32
|
393 |
|
|
MessageBox (NULL, msg, NULL, MB_OK | MB_ICONERROR | MB_TASKMODAL);
|
394 |
|
|
#else
|
395 |
|
|
fputs_unfiltered (msg, gdb_stderr);
|
396 |
|
|
#endif
|
397 |
|
|
}
|
398 |
|
|
|
399 |
|
|
#ifdef _WIN32
|
400 |
|
|
close_bfds ();
|
401 |
|
|
#endif
|
402 |
|
|
|
403 |
|
|
Tk_MainLoop ();
|
404 |
|
|
}
|
405 |
|
|
|
406 |
|
|
/* This hook is installed as the ui_loop_hook, which is used in several
|
407 |
|
|
* places to keep the gui alive (x_event runs gdbtk's event loop). Users
|
408 |
|
|
* include:
|
409 |
|
|
* - ser-tcp.c in socket reading code
|
410 |
|
|
* - ser-unix.c in serial port reading code
|
411 |
|
|
* - built-in simulators while executing
|
412 |
|
|
*
|
413 |
|
|
* x_event used to be called on SIGIO on the socket to the X server
|
414 |
|
|
* for unix. Unfortunately, Linux does not deliver SIGIO, so we resort
|
415 |
|
|
* to an elaborate scheme to keep the gui alive.
|
416 |
|
|
*
|
417 |
|
|
* For simulators and socket or serial connections on all hosts, we
|
418 |
|
|
* rely on ui_loop_hook (x_event) to keep us going. If the user
|
419 |
|
|
* requests a detach (as a result of pressing the stop button -- see
|
420 |
|
|
* comments before gdb_stop in gdbtk-cmds.c), it sets the global
|
421 |
|
|
* GDBTK_FORCE_DETACH, which is the value that x_event returns to
|
422 |
|
|
* it's caller. It is up to the caller of x_event to act on this
|
423 |
|
|
* information.
|
424 |
|
|
*
|
425 |
|
|
* For native unix, we simply set an interval timer which calls
|
426 |
|
|
* x_event to allow the debugger to run through the Tcl event
|
427 |
|
|
* loop. See comments before gdbtk_start_timer and gdb_stop_timer
|
428 |
|
|
* in gdbtk.c.
|
429 |
|
|
*
|
430 |
|
|
* For native windows (and a few other targets, like the v850 ICE),
|
431 |
|
|
* we rely on the target_wait loops to call ui_loop_hook to keep us alive. */
|
432 |
|
|
int
|
433 |
|
|
x_event (signo)
|
434 |
|
|
int signo;
|
435 |
|
|
{
|
436 |
|
|
static volatile int in_x_event = 0;
|
437 |
|
|
static Tcl_Obj *varname = NULL;
|
438 |
|
|
|
439 |
|
|
/* Do nor re-enter this code or enter it while collecting gdb output. */
|
440 |
|
|
if (in_x_event || in_fputs)
|
441 |
|
|
return 0;
|
442 |
|
|
|
443 |
|
|
/* Also, only do things while the target is running (stops and redraws).
|
444 |
|
|
FIXME: We wold like to at least redraw at other times but this is bundled
|
445 |
|
|
together in the TCL_WINDOW_EVENTS group and we would also process user
|
446 |
|
|
input. We will have to prevent (unwanted) user input to be generated
|
447 |
|
|
in order to be able to redraw (removing this test here). */
|
448 |
|
|
if (!running_now)
|
449 |
|
|
return 0;
|
450 |
|
|
|
451 |
|
|
in_x_event = 1;
|
452 |
|
|
gdbtk_force_detach = 0;
|
453 |
|
|
|
454 |
|
|
/* Process pending events */
|
455 |
|
|
while (Tcl_DoOneEvent (TCL_DONT_WAIT | TCL_ALL_EVENTS) != 0)
|
456 |
|
|
;
|
457 |
|
|
|
458 |
|
|
if (load_in_progress)
|
459 |
|
|
{
|
460 |
|
|
int val;
|
461 |
|
|
if (varname == NULL)
|
462 |
|
|
{
|
463 |
|
|
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 1
|
464 |
|
|
Tcl_Obj *varnamestrobj = Tcl_NewStringObj ("download_cancel_ok", -1);
|
465 |
|
|
varname = Tcl_ObjGetVar2 (gdbtk_interp, varnamestrobj, NULL, TCL_GLOBAL_ONLY);
|
466 |
|
|
#else
|
467 |
|
|
varname = Tcl_GetObjVar2 (gdbtk_interp, "download_cancel_ok", NULL, TCL_GLOBAL_ONLY);
|
468 |
|
|
#endif
|
469 |
|
|
}
|
470 |
|
|
if ((Tcl_GetIntFromObj (gdbtk_interp, varname, &val) == TCL_OK) && val)
|
471 |
|
|
{
|
472 |
|
|
quit_flag = 1;
|
473 |
|
|
#ifdef REQUEST_QUIT
|
474 |
|
|
REQUEST_QUIT;
|
475 |
|
|
#else
|
476 |
|
|
if (immediate_quit)
|
477 |
|
|
quit ();
|
478 |
|
|
#endif
|
479 |
|
|
}
|
480 |
|
|
}
|
481 |
|
|
in_x_event = 0;
|
482 |
|
|
|
483 |
|
|
return gdbtk_force_detach;
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
/* VARARGS */
|
487 |
|
|
static void
|
488 |
|
|
gdbtk_readline_begin (char *format,...)
|
489 |
|
|
{
|
490 |
|
|
va_list args;
|
491 |
|
|
char *buf;
|
492 |
|
|
|
493 |
|
|
va_start (args, format);
|
494 |
|
|
xvasprintf (&buf, format, args);
|
495 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_readline_begin", buf);
|
496 |
|
|
free(buf);
|
497 |
|
|
}
|
498 |
|
|
|
499 |
|
|
static char *
|
500 |
|
|
gdbtk_readline (prompt)
|
501 |
|
|
char *prompt;
|
502 |
|
|
{
|
503 |
|
|
int result;
|
504 |
|
|
|
505 |
|
|
#ifdef _WIN32
|
506 |
|
|
close_bfds ();
|
507 |
|
|
#endif
|
508 |
|
|
|
509 |
|
|
result = gdbtk_two_elem_cmd ("gdbtk_tcl_readline", prompt);
|
510 |
|
|
|
511 |
|
|
if (result == TCL_OK)
|
512 |
|
|
{
|
513 |
|
|
return (xstrdup (gdbtk_interp->result));
|
514 |
|
|
}
|
515 |
|
|
else
|
516 |
|
|
{
|
517 |
|
|
gdbtk_fputs (gdbtk_interp->result, gdb_stdout);
|
518 |
|
|
gdbtk_fputs ("\n", gdb_stdout);
|
519 |
|
|
return (NULL);
|
520 |
|
|
}
|
521 |
|
|
}
|
522 |
|
|
|
523 |
|
|
static void
|
524 |
|
|
gdbtk_readline_end ()
|
525 |
|
|
{
|
526 |
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_tcl_readline_end") != TCL_OK)
|
527 |
|
|
report_error ();
|
528 |
|
|
}
|
529 |
|
|
|
530 |
|
|
static void
|
531 |
|
|
gdbtk_call_command (cmdblk, arg, from_tty)
|
532 |
|
|
struct cmd_list_element *cmdblk;
|
533 |
|
|
char *arg;
|
534 |
|
|
int from_tty;
|
535 |
|
|
{
|
536 |
|
|
running_now = 0;
|
537 |
|
|
if (cmdblk->class == class_run || cmdblk->class == class_trace)
|
538 |
|
|
{
|
539 |
|
|
|
540 |
|
|
running_now = 1;
|
541 |
|
|
if (!No_Update)
|
542 |
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_busy");
|
543 |
|
|
(*cmdblk->function.cfunc) (arg, from_tty);
|
544 |
|
|
running_now = 0;
|
545 |
|
|
if (!No_Update)
|
546 |
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_tcl_idle");
|
547 |
|
|
}
|
548 |
|
|
else
|
549 |
|
|
(*cmdblk->function.cfunc) (arg, from_tty);
|
550 |
|
|
}
|
551 |
|
|
|
552 |
|
|
/* Called after a `set' command succeeds. Runs the Tcl hook
|
553 |
|
|
`gdb_set_hook' with the full name of the variable (a Tcl list) as
|
554 |
|
|
the first argument and the new value as the second argument. */
|
555 |
|
|
|
556 |
|
|
static void
|
557 |
|
|
gdbtk_set_hook (struct cmd_list_element *cmdblk)
|
558 |
|
|
{
|
559 |
|
|
Tcl_DString cmd;
|
560 |
|
|
char *p;
|
561 |
|
|
char *buffer = NULL;
|
562 |
|
|
|
563 |
|
|
Tcl_DStringInit (&cmd);
|
564 |
|
|
Tcl_DStringAppendElement (&cmd, "gdbtk_tcl_set_variable");
|
565 |
|
|
|
566 |
|
|
/* Append variable name as sublist. */
|
567 |
|
|
Tcl_DStringStartSublist (&cmd);
|
568 |
|
|
p = cmdblk->prefixname;
|
569 |
|
|
while (p && *p)
|
570 |
|
|
{
|
571 |
|
|
char *q = strchr (p, ' ');
|
572 |
|
|
char save = '\0';
|
573 |
|
|
if (q)
|
574 |
|
|
{
|
575 |
|
|
save = *q;
|
576 |
|
|
*q = '\0';
|
577 |
|
|
}
|
578 |
|
|
Tcl_DStringAppendElement (&cmd, p);
|
579 |
|
|
if (q)
|
580 |
|
|
*q = save;
|
581 |
|
|
p = q + 1;
|
582 |
|
|
}
|
583 |
|
|
Tcl_DStringAppendElement (&cmd, cmdblk->name);
|
584 |
|
|
Tcl_DStringEndSublist (&cmd);
|
585 |
|
|
|
586 |
|
|
switch (cmdblk->var_type)
|
587 |
|
|
{
|
588 |
|
|
case var_string_noescape:
|
589 |
|
|
case var_filename:
|
590 |
|
|
case var_enum:
|
591 |
|
|
case var_string:
|
592 |
|
|
Tcl_DStringAppendElement (&cmd, (*(char **) cmdblk->var
|
593 |
|
|
? *(char **) cmdblk->var
|
594 |
|
|
: "(null)"));
|
595 |
|
|
break;
|
596 |
|
|
|
597 |
|
|
case var_boolean:
|
598 |
|
|
Tcl_DStringAppendElement (&cmd, (*(int *) cmdblk->var ? "1" : "0"));
|
599 |
|
|
break;
|
600 |
|
|
|
601 |
|
|
case var_uinteger:
|
602 |
|
|
case var_zinteger:
|
603 |
|
|
xasprintf (&buffer, "%u", *(unsigned int *) cmdblk->var);
|
604 |
|
|
Tcl_DStringAppendElement (&cmd, buffer);
|
605 |
|
|
break;
|
606 |
|
|
|
607 |
|
|
case var_integer:
|
608 |
|
|
xasprintf (&buffer, "%d", *(int *) cmdblk->var);
|
609 |
|
|
Tcl_DStringAppendElement (&cmd, buffer);
|
610 |
|
|
break;
|
611 |
|
|
|
612 |
|
|
default:
|
613 |
|
|
/* This case should already be trapped by the hook caller. */
|
614 |
|
|
Tcl_DStringAppendElement (&cmd, "error");
|
615 |
|
|
break;
|
616 |
|
|
}
|
617 |
|
|
|
618 |
|
|
if (Tcl_Eval (gdbtk_interp, Tcl_DStringValue (&cmd)) != TCL_OK)
|
619 |
|
|
report_error ();
|
620 |
|
|
|
621 |
|
|
Tcl_DStringFree (&cmd);
|
622 |
|
|
|
623 |
|
|
if (buffer != NULL)
|
624 |
|
|
{
|
625 |
|
|
free(buffer);
|
626 |
|
|
}
|
627 |
|
|
}
|
628 |
|
|
|
629 |
|
|
int
|
630 |
|
|
gdbtk_load_hash (const char *section, unsigned long num)
|
631 |
|
|
{
|
632 |
|
|
char *buf;
|
633 |
|
|
xasprintf (&buf, "Download::download_hash %s %ld", section, num);
|
634 |
|
|
if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK)
|
635 |
|
|
report_error ();
|
636 |
|
|
free(buf);
|
637 |
|
|
|
638 |
|
|
return atoi (gdbtk_interp->result);
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
|
642 |
|
|
/* This hook is called whenever we are ready to load a symbol file so that
|
643 |
|
|
the UI can notify the user... */
|
644 |
|
|
static void
|
645 |
|
|
gdbtk_pre_add_symbol (name)
|
646 |
|
|
char *name;
|
647 |
|
|
{
|
648 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_pre_add_symbol", name);
|
649 |
|
|
}
|
650 |
|
|
|
651 |
|
|
/* This hook is called whenever we finish loading a symbol file. */
|
652 |
|
|
static void
|
653 |
|
|
gdbtk_post_add_symbol ()
|
654 |
|
|
{
|
655 |
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_tcl_post_add_symbol") != TCL_OK)
|
656 |
|
|
report_error ();
|
657 |
|
|
}
|
658 |
|
|
|
659 |
|
|
/* This hook function is called whenever we want to wait for the
|
660 |
|
|
target. */
|
661 |
|
|
|
662 |
|
|
static ptid_t
|
663 |
|
|
gdbtk_wait (ptid, ourstatus)
|
664 |
|
|
ptid_t ptid;
|
665 |
|
|
struct target_waitstatus *ourstatus;
|
666 |
|
|
{
|
667 |
|
|
gdbtk_force_detach = 0;
|
668 |
|
|
gdbtk_start_timer ();
|
669 |
|
|
ptid = target_wait (ptid, ourstatus);
|
670 |
|
|
gdbtk_stop_timer ();
|
671 |
|
|
|
672 |
|
|
return ptid;
|
673 |
|
|
}
|
674 |
|
|
|
675 |
|
|
/*
|
676 |
|
|
* This handles all queries from gdb.
|
677 |
|
|
* The first argument is a printf style format statement, the rest are its
|
678 |
|
|
* arguments. The resultant formatted string is passed to the Tcl function
|
679 |
|
|
* "gdbtk_tcl_query".
|
680 |
|
|
* It returns the users response to the query, as well as putting the value
|
681 |
|
|
* in the result field of the Tcl interpreter.
|
682 |
|
|
*/
|
683 |
|
|
|
684 |
|
|
static int
|
685 |
|
|
gdbtk_query (query, args)
|
686 |
|
|
const char *query;
|
687 |
|
|
va_list args;
|
688 |
|
|
{
|
689 |
|
|
char *buf;
|
690 |
|
|
long val;
|
691 |
|
|
|
692 |
|
|
xvasprintf (&buf, query, args);
|
693 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_query", buf);
|
694 |
|
|
free(buf);
|
695 |
|
|
|
696 |
|
|
val = atol (gdbtk_interp->result);
|
697 |
|
|
return val;
|
698 |
|
|
}
|
699 |
|
|
|
700 |
|
|
|
701 |
|
|
static void
|
702 |
|
|
gdbtk_print_frame_info (s, line, stopline, noerror)
|
703 |
|
|
struct symtab *s;
|
704 |
|
|
int line;
|
705 |
|
|
int stopline;
|
706 |
|
|
int noerror;
|
707 |
|
|
{
|
708 |
|
|
current_source_symtab = s;
|
709 |
|
|
current_source_line = line;
|
710 |
|
|
}
|
711 |
|
|
|
712 |
|
|
/*
|
713 |
|
|
* gdbtk_trace_find
|
714 |
|
|
*
|
715 |
|
|
* This is run by the trace_find_command. arg is the argument that was passed
|
716 |
|
|
* to that command, from_tty is 1 if the command was run from a tty, 0 if it
|
717 |
|
|
* was run from a script. It runs gdbtk_tcl_tfind_hook passing on these two
|
718 |
|
|
* arguments.
|
719 |
|
|
*
|
720 |
|
|
*/
|
721 |
|
|
|
722 |
|
|
static void
|
723 |
|
|
gdbtk_trace_find (arg, from_tty)
|
724 |
|
|
char *arg;
|
725 |
|
|
int from_tty;
|
726 |
|
|
{
|
727 |
|
|
Tcl_Obj *cmdObj;
|
728 |
|
|
|
729 |
|
|
cmdObj = Tcl_NewListObj (0, NULL);
|
730 |
|
|
Tcl_ListObjAppendElement (gdbtk_interp, cmdObj,
|
731 |
|
|
Tcl_NewStringObj ("gdbtk_tcl_trace_find_hook", -1));
|
732 |
|
|
Tcl_ListObjAppendElement (gdbtk_interp, cmdObj, Tcl_NewStringObj (arg, -1));
|
733 |
|
|
Tcl_ListObjAppendElement (gdbtk_interp, cmdObj, Tcl_NewIntObj (from_tty));
|
734 |
|
|
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 1
|
735 |
|
|
if (Tcl_GlobalEvalObj (gdbtk_interp, cmdObj) != TCL_OK)
|
736 |
|
|
report_error ();
|
737 |
|
|
#else
|
738 |
|
|
if (Tcl_EvalObj (gdbtk_interp, cmdObj, TCL_EVAL_GLOBAL) != TCL_OK)
|
739 |
|
|
report_error ();
|
740 |
|
|
#endif
|
741 |
|
|
}
|
742 |
|
|
|
743 |
|
|
/*
|
744 |
|
|
* gdbtk_trace_start_stop
|
745 |
|
|
*
|
746 |
|
|
* This is run by the trace_start_command and trace_stop_command.
|
747 |
|
|
* The START variable determines which, 1 meaning trace_start was run,
|
748 |
|
|
* 0 meaning trace_stop was run.
|
749 |
|
|
*
|
750 |
|
|
*/
|
751 |
|
|
|
752 |
|
|
static void
|
753 |
|
|
gdbtk_trace_start_stop (start, from_tty)
|
754 |
|
|
int start;
|
755 |
|
|
int from_tty;
|
756 |
|
|
{
|
757 |
|
|
|
758 |
|
|
if (start)
|
759 |
|
|
Tcl_GlobalEval (gdbtk_interp, "gdbtk_tcl_tstart");
|
760 |
|
|
else
|
761 |
|
|
Tcl_GlobalEval (gdbtk_interp, "gdbtk_tcl_tstop");
|
762 |
|
|
|
763 |
|
|
}
|
764 |
|
|
|
765 |
|
|
static void
|
766 |
|
|
gdbtk_selected_frame_changed (level)
|
767 |
|
|
int level;
|
768 |
|
|
{
|
769 |
|
|
Tcl_UpdateLinkedVar (gdbtk_interp, "gdb_selected_frame_level");
|
770 |
|
|
}
|
771 |
|
|
|
772 |
|
|
/* Called when the current thread changes. */
|
773 |
|
|
/* gdb_context is linked to the tcl variable "gdb_context_id" */
|
774 |
|
|
static void
|
775 |
|
|
gdbtk_context_change (num)
|
776 |
|
|
int num;
|
777 |
|
|
{
|
778 |
|
|
gdb_context = num;
|
779 |
|
|
}
|
780 |
|
|
|
781 |
|
|
/* Called from file_command */
|
782 |
|
|
static void
|
783 |
|
|
gdbtk_file_changed (filename)
|
784 |
|
|
char *filename;
|
785 |
|
|
{
|
786 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_file_changed", filename);
|
787 |
|
|
}
|
788 |
|
|
|
789 |
|
|
/* Called from exec_file_command */
|
790 |
|
|
static void
|
791 |
|
|
gdbtk_exec_file_display (filename)
|
792 |
|
|
char *filename;
|
793 |
|
|
{
|
794 |
|
|
gdbtk_two_elem_cmd ("gdbtk_tcl_exec_file_display", filename);
|
795 |
|
|
}
|
796 |
|
|
|
797 |
|
|
/* Called from error_begin, this hook is used to warn the gui
|
798 |
|
|
about multi-line error messages */
|
799 |
|
|
static void
|
800 |
|
|
gdbtk_error_begin ()
|
801 |
|
|
{
|
802 |
|
|
if (result_ptr != NULL)
|
803 |
|
|
result_ptr->flags |= GDBTK_ERROR_ONLY;
|
804 |
|
|
}
|
805 |
|
|
|
806 |
|
|
/* notify GDBtk when a signal occurs */
|
807 |
|
|
static void
|
808 |
|
|
gdbtk_annotate_signal ()
|
809 |
|
|
{
|
810 |
|
|
char *buf;
|
811 |
|
|
|
812 |
|
|
/* Inform gui that the target has stopped. This is
|
813 |
|
|
a necessary stop button evil. We don't want signal notification
|
814 |
|
|
to interfere with the elaborate and painful stop button detach
|
815 |
|
|
timeout. */
|
816 |
|
|
Tcl_Eval (gdbtk_interp, "gdbtk_stop_idle_callback");
|
817 |
|
|
|
818 |
|
|
xasprintf (&buf, "gdbtk_signal %s {%s}", target_signal_to_name (stop_signal),
|
819 |
|
|
target_signal_to_string (stop_signal));
|
820 |
|
|
if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK)
|
821 |
|
|
report_error ();
|
822 |
|
|
free(buf);
|
823 |
|
|
}
|
824 |
|
|
|
825 |
|
|
static void
|
826 |
|
|
gdbtk_attach ()
|
827 |
|
|
{
|
828 |
|
|
if (Tcl_Eval (gdbtk_interp, "after idle \"update idletasks;gdbtk_attached\"") != TCL_OK)
|
829 |
|
|
{
|
830 |
|
|
report_error ();
|
831 |
|
|
}
|
832 |
|
|
}
|
833 |
|
|
|
834 |
|
|
static void
|
835 |
|
|
gdbtk_detach ()
|
836 |
|
|
{
|
837 |
|
|
if (Tcl_Eval (gdbtk_interp, "gdbtk_detached") != TCL_OK)
|
838 |
|
|
{
|
839 |
|
|
report_error ();
|
840 |
|
|
}
|
841 |
|
|
}
|
842 |
|
|
|