diff options
Diffstat (limited to 'gdb/xgdb.c')
-rw-r--r-- | gdb/xgdb.c | 672 |
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 |