aboutsummaryrefslogtreecommitdiff
path: root/gdb/xgdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/xgdb.c')
-rw-r--r--gdb/xgdb.c672
1 files changed, 672 insertions, 0 deletions
diff --git a/gdb/xgdb.c b/gdb/xgdb.c
new file mode 100644
index 0000000..1b858e8
--- /dev/null
+++ b/gdb/xgdb.c
@@ -0,0 +1,672 @@
+/* Interface from GDB to X windows.
+ Copyright (C) 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+/* Original version was contributed by Derek Beatty, 30 June 87. */
+
+#include "defs.h"
+#include "initialize.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xresource.h>
+#include <X11/Atoms.h>
+#include <X11/TopLevel.h>
+#include <X11/VPane.h>
+#include <X11/Label.h>
+#include <X11/Text.h>
+#include <X11/Command.h>
+#include <X11/ButtonBox.h>
+
+#include <stdio.h>
+
+/* Cursor used in GDB window. */
+
+#define gdb_width 16
+#define gdb_height 16
+#define gdb_x_hot 7
+#define gdb_y_hot 0
+static short gdb_bits[] = {
+ 0x0000, 0x0140, 0x0220, 0x0220,
+ 0x23e2, 0x13e4, 0x09c8, 0x0ff8,
+ 0x0220, 0x3ffe, 0x0630, 0x03e0,
+ 0x0220, 0x1ffc, 0x2632, 0x01c0};
+
+#define gdb_mask_width 16
+#define gdb_mask_height 16
+#define gdb_mask_x_hot 7
+#define gdb_mask_y_hot 0
+static short gdb_mask_bits[] = {
+ 0x0360, 0x07f0, 0x07f0, 0x77f7,
+ 0x7fff, 0x7fff, 0x1ffc, 0x1ffc,
+ 0x7fff, 0x7fff, 0x7fff, 0x0ff8,
+ 0x3ffe, 0x7fff, 0x7fff, 0x7fff};
+
+/* The X display on which the window appears. */
+
+Display *screen_display;
+
+/* The graphics context. */
+
+GC default_gc;
+
+/* Windows manipulated by this package. */
+
+static Window icon_window;
+static Widget containing_widget;
+static Widget source_name_widget;
+static Widget source_text_widget;
+static Widget exec_name_widget;
+static Widget button_box_widget;
+
+/* Source text display. */
+
+static struct symtab *source_window_symtab = 0;
+
+/* Forward declarations */
+
+static Widget create_text_widget ();
+
+START_FILE
+
+/* Display an appropriate piece of source code in the source window. */
+
+xgdb_display_source ()
+{
+ char *filename;
+ static Arg labelArgs[1];
+ int linenumbers_changed = 0;
+ static int new = 1;
+
+ struct symtab_and_line get_selected_frame_sal ();
+ struct symtab_and_line sal;
+ struct frame_info fi;
+
+ /* Do nothing if called before we are initialized */
+
+ if (!containing_widget) return;
+
+ /* Get the symtab and line number of the selected frame. */
+
+ fi = get_frame_info (selected_frame);
+ sal = find_pc_line (fi.pc, fi.next_frame);
+
+ /* Strictly this is wrong, but better than a blank display */
+
+ if (sal.symtab == NULL)
+ {
+ sal.symtab = current_source_symtab;
+ /* current_source_line may be off by a small number like 4 */
+ sal.line = current_source_line;
+ }
+
+ /* Do a path search and get the exact filename of this source file.
+ Also scan it and find its source lines if not already done. */
+
+ if (sal.symtab)
+ linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line,
+ &filename);
+
+ if (!filename) sal.symtab = NULL;
+
+ /* If the source window may be wrong, destroy it (and make a new one). */
+
+ if (linenumbers_changed || source_window_symtab != sal.symtab)
+ {
+ static Arg fileArgs[1];
+ new = 1;
+ source_window_symtab = sal.symtab;
+
+ XtSetArg (fileArgs[0], XtNfile, filename);
+ XtSetValues (source_text_widget, fileArgs, XtNumber (fileArgs));
+
+ XtSetArg (labelArgs[0], XtNlabel,
+ filename ? filename : "No source displayed.");
+ XtSetValues (source_name_widget, labelArgs, XtNumber (labelArgs));
+ if (filename) free (filename);
+ }
+
+ /* Update display and cursor positions as necessary.
+ Cursor should be placed on line sal.line. */
+
+ {
+ static int top_line_number, bottom_line_number;
+ int current_top;
+ Arg textArgs[1];
+
+ if (! new)
+ {
+ int new_top;
+
+ /* Get positions of start of display, and caret */
+ XtSetArg (textArgs[0], XtNdisplayPosition, NULL);
+ XtGetValues (source_text_widget, textArgs, XtNumber (textArgs));
+ new_top = source_charpos_line (source_window_symtab,
+ (int) textArgs[0].value);
+ bottom_line_number += new_top - top_line_number;
+ top_line_number = new_top;
+ }
+
+ /* If appropriate, scroll the text display. */
+ if (sal.line < top_line_number
+ || sal.line > bottom_line_number
+ || new)
+ {
+ /* yes, these magic numbers are ugly, but I don't know how
+ * to get the height of a text widget in a V11-portable way
+ */
+ top_line_number = (sal.line > 15) ? sal.line - 15 : 0;
+ bottom_line_number = top_line_number + 35;
+
+ XtSetArg (textArgs[0], XtNdisplayPosition,
+ source_line_charpos (source_window_symtab, top_line_number));
+ XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
+ }
+
+ /* Set the text display cursor position within the text. */
+
+ XtSetArg (textArgs[0], XtNinsertPosition,
+ source_line_charpos (source_window_symtab, sal.line));
+ XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
+ }
+}
+
+/* Display FILENAME in the title bar at bottom of window. */
+
+xgdb_display_exec_file (filename)
+ char *filename;
+{
+ static Arg labelArgs[1];
+
+ XtSetArg (labelArgs[0], XtNlabel, filename);
+ XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs));
+}
+
+/* Do any necessary prompting, etc. */
+
+static char *prompt_string;
+
+static void
+print_prompt ()
+{
+ if (prompt_string)
+ printf ("%s", prompt_string);
+}
+
+/* Handlers for buttons. */
+
+/* Subroutine used by "print" and "print*" buttons.
+ STARFLAG is 1 for print*, 0 for print.
+ Get the "selection" from X and use it as the operand of a print command. */
+
+static void
+print_1 (starflag)
+ int starflag;
+{
+ int selected_length;
+ char *selected_text;
+
+ char *cmd = starflag ? "print * " : "print ";
+ register int cmdlen = strlen (cmd);
+
+ selected_text = XFetchBytes (&selected_length);
+ if (selected_length)
+ {
+ char *line = xmalloc (cmdlen + selected_length + 1);
+ strcpy (line, cmd);
+ strncpy (line + cmdlen, selected_text, selected_length);
+ line[cmdlen + selected_length] = 0;
+
+ execute_command (line, 0);
+
+ free (selected_text);
+ free (line);
+ }
+
+ print_prompt ();
+}
+
+static void
+print_button ()
+{
+ print_1 (0);
+}
+
+static void
+print_star_button ()
+{
+ print_1 (1);
+}
+
+/* Subroutine used by "stop at" and "go till" buttons.
+ Set a breakpoint at the position indicated by the "selection"
+ in the source window, and, if RUNFLAG is nonzero, continue. */
+
+static void
+breakpoint_button_1 (runflag)
+ int runflag;
+{
+ XtTextPosition start, finish;
+
+ XtTextGetSelectionPos (screen_display, source_text_widget, &start, &finish);
+ if (!source_window_symtab)
+ printf ("No source file displayed.\n");
+ else
+ {
+ set_breakpoint (source_window_symtab,
+ source_charpos_line (source_window_symtab, start),
+ runflag);
+ if (runflag)
+ {
+ cont_command (0, 1);
+ xgdb_display_source ();
+ }
+ }
+ print_prompt ();
+}
+
+static void
+breakpoint_button ()
+{
+ breakpoint_button_1 (0);
+}
+
+static void
+until_button ()
+{
+ breakpoint_button_1 (1);
+}
+
+/* decide if a character is trash */
+static int
+garbage (c)
+ char c;
+{
+ if ('a' <= c && c <= 'z') return 0;
+ if ('A' <= c && c <= 'Z') return 0;
+ if ('0' <= c && c <= '9') return 0;
+ if (c == '_') return 0;
+ return 1;
+}
+
+/* Set a breakpoint at the place specified by the "selection" in X. */
+
+static void
+explicit_breakpoint_button ()
+{
+ int selected_length;
+ char *selected_text;
+
+ selected_text = XFetchBytes (screen_display, &selected_length);
+ if (selected_length)
+ {
+ char *line = (char *) xmalloc (selected_length + 6);
+ register char *p, *sp, *end;
+
+ strcpy (line, "break ");
+
+ /* Copy selection but exclude "garbage" characters. */
+
+ p = selected_text;
+ end = p + selected_length;
+ sp = line + strlen (line);
+
+ while (garbage (*p) && p != end) p++;
+ while (!garbage (*p) && p != end)
+ *sp++ = *p++;
+ *sp = 0;
+
+ execute_command (line, 0);
+ free (selected_text);
+ free (line);
+ }
+ print_prompt ();
+}
+
+/* Various trivial buttons,
+ most of which just run one GDB command with no arg. */
+
+static void
+next_button ()
+{
+ execute_command ("next", 0);
+ xgdb_display_source ();
+ print_prompt ();
+}
+
+static void
+step_button ()
+{
+ execute_command ("step", 0);
+ xgdb_display_source ();
+ print_prompt ();
+}
+
+static void
+cont_button ()
+{
+ execute_command ("cont", 0);
+ xgdb_display_source ();
+ print_prompt ();
+}
+
+static void
+finish_button ()
+{
+ execute_command ("finish", 0);
+ xgdb_display_source ();
+ print_prompt ();
+}
+
+#if 0
+static void
+deiconify_button ()
+{
+ XUnmapWindow (screen_display, icon_window);
+ XMapWindow (screen_display, containing_widget);
+}
+
+static void
+iconify_button ()
+{
+#if 0
+ static Arg iconArgs[1];
+ XtSetArg (iconArgs[0], XtNlabel, prompt_string);
+ XtCommandSetValues (icon_window, iconArgs, XtNumber (iconArgs));
+#endif 0
+ XUnmapWindow (screen_display, containing_widget);
+ XMapWindow (screen_display, icon_window);
+}
+#endif 0
+
+static void
+up_button ()
+{
+ execute_command ("up", 0);
+ xgdb_display_source ();
+ print_prompt ();
+}
+
+static void
+down_button ()
+{
+ execute_command ("down", 0);
+ xgdb_display_source ();
+ print_prompt ();
+}
+
+/* Define and display all the buttons. */
+
+static void
+addbutton (parent, name, function)
+ Widget parent;
+ char *name;
+ void (*function) ();
+{
+ static Arg commandArgs[2];
+
+ XtSetArg (commandArgs[0], XtNlabel, name);
+ XtSetArg (commandArgs[1], XtNfunction, function);
+ XtCreateWidget (name, commandWidgetClass, parent,
+ commandArgs, XtNumber (commandArgs));
+}
+
+/* Create the button windows and store them in `buttons'. */
+
+static void
+create_buttons (parent)
+ Widget parent;
+{
+ addbutton (parent, "Brk At", breakpoint_button);
+ addbutton (parent, "Brk In", explicit_breakpoint_button);
+ addbutton (parent, "Go 'til", until_button);
+
+ addbutton (parent, "Print", print_button);
+ addbutton (parent, "Print*", print_star_button);
+
+ addbutton (parent, "Next", next_button);
+ addbutton (parent, "Step", step_button);
+ addbutton (parent, "Cont", cont_button);
+ addbutton (parent, "Finish", finish_button);
+
+ addbutton (parent, "Up", up_button);
+ addbutton (parent, "Down", down_button);
+
+/* addbutton (parent, "Iconify", iconify_button); */
+}
+
+/* Create a "label window" that just displays the string LABEL. */
+
+static Widget
+create_label (name, label)
+ char *name, *label;
+{
+ static Arg labelArgs[2];
+
+ XtSetArg (labelArgs[0], XtNname, name);
+ XtSetArg (labelArgs[1], XtNlabel, label);
+ return XtCreateWidget ("label1", labelWidgetClass, containing_widget,
+ labelArgs, XtNumber (labelArgs));
+}
+
+/* Create a subwindow of PARENT that displays and scrolls the contents
+ of file FILENAME. */
+
+static Widget
+create_text_widget (parent, filename)
+ Window parent;
+ char *filename;
+{
+ static Arg fileArgs[2];
+
+ XtSetArg (fileArgs[0], XtNfile, filename);
+ XtSetArg (fileArgs[1], XtNtextOptions, scrollVertical);
+ return XtTextDiskCreate (parent, fileArgs, XtNumber (fileArgs));
+}
+
+/* Entry point to create the widgets representing our display. */
+
+int
+xgdb_create_window ()
+{
+ static Arg frameArgs[]= {
+ {XtNwidth, (XtArgVal) 600},
+ {XtNheight, (XtArgVal) 700},
+ };
+
+ XrmResourceDataBase db;
+ FILE *rdb_file;
+ XGCValues dummy;
+
+ /* Init and database stuff. */
+ screen_display = XOpenDisplay (NULL);
+ if (screen_display == 0)
+ {
+ fprintf (stderr, "Cannot connect to X server");
+ return 0;
+ }
+
+ {
+ char *dummy1[1];
+ dummy1[0] = 0;
+ XtInitialize ("gdb", "gdb", 0, 0, 0, dummy1);
+ }
+
+ /* should be checking .Xdefaults in $HOME */
+ rdb_file = fopen (".Xresources", "r");
+ if (rdb_file != NULL)
+ {
+ XrmGetDataBase (rdb_file, &db);
+ XrmSetCurrentDataBase (db);
+ fclose (rdb_file);
+ }
+
+ /* Create the containing_widget. */
+
+ containing_widget = XtCreateWidget ("frame", vPaneWidgetClass, 0,
+ frameArgs, XtNumber (frameArgs));
+
+ default_gc = XCreateGC (screen_display, containing_widget, 0, dummy);
+
+ /* Create source file name window and add to containing_widget */
+ source_name_widget
+ = create_label ("Source File", "No source file yet.");
+
+ /* Create an empty source-display window and add to containing_widget */
+ source_text_widget = create_text_widget (containing_widget, "/dev/null");
+
+ /* Create window full of buttons. */
+ button_box_widget = XtCreateWidget ("Buttons", buttonBoxWidgetClass,
+ containing_widget, NULL, 0);
+ create_buttons (button_box_widget);
+
+ /* Create exec file name window and add */
+ exec_name_widget = create_label ("Executable", "No executable specified.");
+
+#if 0
+ /* Create icon window. */
+ {
+ static Arg iconArgs[2];
+ void (*compiler_bug) () = deiconify_button;
+ XtSetArg (iconArgs[0], XtNlabel, "(gdb)");
+ XtSetArg (iconArgs[1], XtNfunction, compiler_bug);
+ icon_window = XtCommandCreate (DefaultRootWindow (screen_display),
+ iconArgs, XtNumber (iconArgs));
+ XMoveWindow (screen_display, icon_window, 100, 100); /* HACK */
+#if 0
+ XSetIconWindow (screen_display, containing_widget, icon_window);
+#endif 0
+ }
+#endif 0
+
+#if 0
+ /* Now make the whole thing appear on the display. */
+ {
+ Pixmap pm1, pm2;
+ XImage image;
+ Cursor curse;
+
+ image.width = gdb_width;
+ image.height = gdb_height;
+ image.xoffset = 0;
+ image.format = XYBitmap;
+ image.byte_order = LSBFirst;
+ image.bitmap_unit = 16;
+ image.bitmap_bit_order = LSBFirst;
+ image.depth = 1;
+ image.bytes_per_line = 2;
+ image.bits_per_pixel = 1;
+
+ pm1 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
+ gdb_width, gdb_height, 1);
+ pm2 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
+ gdb_width, gdb_height, 1);
+
+ image.data = (char *) gdb_bits;
+ XPutImage (screen_display, pm1, default_gc, &image, 0, 0, 0, 0,
+ gdb_width, gdb_height);
+
+ image.data = (char *) gdb_mask_bits;
+ XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0,
+ gdb_width, gdb_height);
+
+ curse = XCreatePixmapCursor (screen_display, pm1, pm2,
+ BlackPixel (screen_display,
+ DefaultScreen (screen_display)),
+ WhitePixel (screen_display,
+ DefaultScreen (screen_display)),
+ gdb_x_hot, gdb_y_hot);
+
+ XFreePixmap (screen_display, pm1);
+ XFreePixmap (screen_display, pm2);
+
+ XDefineCursor (screen_display, containing_widget, curse);
+ XDefineCursor (screen_display, icon_window, curse);
+ }
+#endif 0
+
+ XtRealizeWidget (containing_widget);
+ XFlush (screen_display);
+
+ return 1;
+}
+
+/* xgdb_dispatch -- Loop, dispatching on window events,
+ until data is available on FP (which is normally stdin).
+ Then return, so the data on FP can be processed. */
+
+void
+xgdb_dispatch (fp)
+ FILE *fp;
+{
+ int inmask = 1 << fileno (fp);
+ int xmask = 1 << ConnectionNumber (screen_display);
+ int rfds = 0;
+ int nfds;
+ XEvent ev;
+ int pend;
+
+ while (! (rfds & inmask))
+ {
+ pend = XPending ();
+ if (!pend)
+ {
+ rfds = inmask | xmask;
+ /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */
+ nfds = select (32, &rfds, 0, 0, (struct timeval *) 0);
+ }
+ if (pend || rfds & xmask)
+ {
+ XNextEvent (screen_display, &ev);
+ XtDispatchEvent (&ev);
+ }
+ }
+}
+
+/* If we use an X window, the GDB command loop is told to call this function
+ before reading a command from stdin.
+ PROMPT is saved for later use so buttons can print a prompt-string. */
+
+void
+xgdb_window_hook (infile, prompt)
+ FILE *infile;
+ char *prompt;
+{
+ prompt_string = prompt;
+ xgdb_display_source ();
+ xgdb_dispatch (infile);
+}
+
+static
+initialize ()
+{
+ extern void (*window_hook) ();
+ extern int inhibit_windows;
+
+ if (getenv ("DISPLAY") && ! inhibit_windows)
+ if (xgdb_create_window ())
+ window_hook = xgdb_window_hook;
+
+ specify_exec_file_hook (xgdb_display_exec_file);
+}
+
+END_FILE