|
|
1.1 root 1: /* Interface from GDB to X windows.
2: Copyright (C) 1987 Free Software Foundation, Inc.
3:
4: GDB is distributed in the hope that it will be useful, but WITHOUT ANY
5: WARRANTY. No author or distributor accepts responsibility to anyone
6: for the consequences of using it or for whether it serves any
7: particular purpose or works at all, unless he says so in writing.
8: Refer to the GDB General Public License for full details.
9:
10: Everyone is granted permission to copy, modify and redistribute GDB,
11: but only under the conditions described in the GDB General Public
12: License. A copy of this license is supposed to have been given to you
13: along with GDB so you can know your rights and responsibilities. It
14: should be in a file named COPYING. Among other things, the copyright
15: notice and this notice must be preserved on all copies.
16:
17: In other words, go ahead and share GDB, but don't try to stop
18: anyone else from sharing it farther. Help stamp out software hoarding!
19: */
20:
21: /* Original version was contributed by Derek Beatty, 30 June 87. */
22:
23: #include "defs.h"
24: #include "initialize.h"
25: #include "param.h"
26: #include "symtab.h"
27: #include "frame.h"
28:
29: #include <X11/IntrinsicP.h>
30: #include <X11/StringDefs.h>
31: #include <X11/Label.h>
32: #include <X11/Command.h>
33: #include <X11/TextP.h>
34: #include <X11/Box.h>
35: #include <X11/VPaned.h>
36:
37: #include <stdio.h>
38:
39: /* Cursor used in GDB window. */
40:
41: #define gdb_width 16
42: #define gdb_height 16
43: #define gdb_x_hot 7
44: #define gdb_y_hot 0
45: static short gdb_bits[] = {
46: 0x0000, 0x0140, 0x0220, 0x0220,
47: 0x23e2, 0x13e4, 0x09c8, 0x0ff8,
48: 0x0220, 0x3ffe, 0x0630, 0x03e0,
49: 0x0220, 0x1ffc, 0x2632, 0x01c0};
50:
51: #define gdb_mask_width 16
52: #define gdb_mask_height 16
53: #define gdb_mask_x_hot 7
54: #define gdb_mask_y_hot 0
55: static short gdb_mask_bits[] = {
56: 0x0360, 0x07f0, 0x07f0, 0x77f7,
57: 0x7fff, 0x7fff, 0x1ffc, 0x1ffc,
58: 0x7fff, 0x7fff, 0x7fff, 0x0ff8,
59: 0x3ffe, 0x7fff, 0x7fff, 0x7fff};
60:
61: /* The X display on which the window appears. */
62:
63: static Display *screen_display;
64:
65: /* Windows manipulated by this package. */
66:
67: static Widget main_widget;
68: static Widget containing_widget;
69: static Widget title_widget;
70: static Widget source_name_widget;
71: static Widget source_text_widget;
72: static Widget exec_name_widget;
73: static Widget button_box_widget;
74:
75: #ifdef VTFD
76: /* Interaction Window */
77:
78: static Widget interactive_widget;
79: XtTextSource PseudoDiskSourceCreate();
80: XtTextSource TSource;
81: static int vtfd[2], vifd[2];
82: #endif
83:
84: /* Source text display. */
85:
86: static struct symtab *source_window_symtab = 0;
87:
88: /* Forward declarations */
89:
90: static Widget create_text_widget ();
91:
92: START_FILE
93:
94: /* Return number of text lines displayed in text widget W. */
95:
96: int /* was XtTextPosition */
97: XtTextLines (w)
98: Widget w;
99: {
100: TextWidget ctx = (TextWidget)w;
101:
102: return ctx->text.lt.lines;
103: }
104:
105: /* Display an appropriate piece of source code in the source window. */
106:
107: xgdb_display_source ()
108: {
109: char *filename;
110: Arg args[1];
111: Arg labelArgs[1];
112: int linenumbers_changed = 0;
113: int must_scroll = 0;
114: int height = XtTextLines (source_text_widget);
115:
116: struct symtab_and_line get_selected_frame_sal ();
117: struct symtab_and_line sal;
118: struct frame_info fi;
119:
120: /* Do nothing if called before we are initialized */
121:
122: if (!containing_widget) return;
123:
124: /* Get the symtab and line number of the selected frame. */
125:
126: fi = get_frame_info (selected_frame);
127: sal = find_pc_line (fi.pc, fi.next_frame);
128:
129: /* Strictly this is wrong, but better than a blank display */
130:
131: if (sal.symtab == NULL)
132: {
133: sal.symtab = current_source_symtab;
134: /* current_source_line may be off by a small number like 4 */
135: sal.line = current_source_line;
136: }
137:
138: /* Do a path search and get the exact filename of this source file.
139: Also scan it and find its source lines if not already done. */
140:
141: if (sal.symtab)
142: linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line,
143: &filename);
144:
145: if (!filename) sal.symtab = NULL;
146:
147: /* If the source window may be wrong, destroy it (and make a new one). */
148:
149: if (linenumbers_changed || source_window_symtab != sal.symtab)
150: {
151: Arg fileArgs[1];
152: XtTextSource src;
153:
154: must_scroll = 1;
155: source_window_symtab = sal.symtab;
156:
157: src = XtTextGetSource (source_text_widget);
158: XtDiskSourceDestroy (src);
159:
160: XtSetArg (fileArgs[0], XtNfile, filename);
161: src = XtDiskSourceCreate (source_text_widget->core.parent, fileArgs, 1);
162: XtTextSetSource (source_text_widget, src, 0);
163:
164: XtSetArg (labelArgs[0], XtNlabel,
165: filename ? filename : "No source displayed.");
166: XtSetValues (source_name_widget, labelArgs, XtNumber (labelArgs));
167: if (filename) free (filename);
168: }
169:
170: /* Update display and cursor positions as necessary.
171: Cursor should be placed on line sal.line. */
172:
173: /* Find out where the display is positioned (in case user scrolled it). */
174:
175: if (! must_scroll)
176: {
177: int top_line_number;
178:
179: XtSetArg (args[0], XtNdisplayPosition, NULL);
180: XtGetValues (source_text_widget, args, 1);
181: top_line_number = source_charpos_line (source_window_symtab,
182: (int) args[0].value);
183: /* If desired position is off screen, we must scroll. */
184: if (sal.line < top_line_number
185: || sal.line >= top_line_number + height)
186: must_scroll = 1;
187: }
188:
189: /* If appropriate, scroll the text display. */
190:
191: if (must_scroll)
192: {
193: int top_line_number = (sal.line > height/3) ? sal.line - height/3 : 1;
194:
195: XtSetArg (args[0], XtNdisplayPosition,
196: source_line_charpos (source_window_symtab, top_line_number));
197: XtSetValues (source_text_widget, args, 1);
198: }
199:
200: /* Set the text display cursor position within the text. */
201:
202: XtSetArg (args[0], XtNinsertPosition,
203: source_line_charpos (source_window_symtab, sal.line));
204: XtSetValues (source_text_widget, args, 1);
205: }
206:
207: /* Display FILENAME in the title bar at bottom of window. */
208:
209: xgdb_display_exec_file (filename)
210: char *filename;
211: {
212: static Arg labelArgs[1];
213:
214: XtSetArg (labelArgs[0], XtNlabel, filename);
215: XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs));
216: }
217:
218: /* Do any necessary prompting, etc. */
219:
220: static char *prompt_string;
221:
222: static void
223: print_prompt ()
224: {
225: if (prompt_string)
226: {
227: printf ("%s", prompt_string);
228: fflush (stdout);
229: }
230: }
231:
232: /* Handlers for buttons. */
233:
234: /* Subroutine used by "print" and "print*" buttons.
235: STARFLAG is 1 for print*, 0 for print.
236: Get the "selection" from X and use it as the operand of a print command. */
237:
238: static void
239: print_button (w, starflag, call_data)
240: Widget w;
241: int starflag;
242: caddr_t call_data;
243: {
244: int selected_length;
245: char *selected_text;
246: char *cmd = starflag ? "print * " : "print ";
247: register int cmdlen = strlen (cmd);
248:
249: selected_text = XFetchBytes (screen_display, &selected_length);
250: if (selected_length)
251: {
252: char *line = xmalloc (cmdlen + selected_length + 1);
253: strcpy (line, cmd);
254: strncpy (line + cmdlen, selected_text, selected_length);
255: line[cmdlen + selected_length] = 0;
256:
257: execute_command (line, 0);
258:
259: free (selected_text);
260: free (line);
261: }
262:
263: print_prompt ();
264: }
265:
266:
267: /* Subroutine used by "stop at" and "go till" buttons.
268: Set a breakpoint at the position indicated by the "selection"
269: in the source window, and, if RUNFLAG is nonzero, continue. */
270:
271: static void
272: breakpoint_button (w, runflag, call_data)
273: Widget w;
274: int runflag;
275: caddr_t call_data;
276: {
277: XtTextPosition start, finish;
278:
279: XtTextGetSelectionPos (source_text_widget, &start, &finish);
280: if (!source_window_symtab)
281: printf ("No source file displayed.\n");
282: else
283: {
284: set_breakpoint (source_window_symtab,
285: source_charpos_line (source_window_symtab, start),
286: runflag);
287: if (runflag)
288: {
289: cont_command (0, 1);
290: xgdb_display_source ();
291: }
292: }
293: print_prompt ();
294: }
295:
296: /* decide if a character is trash */
297: static int
298: garbage (c)
299: char c;
300: {
301: if ('a' <= c && c <= 'z') return 0;
302: if ('A' <= c && c <= 'Z') return 0;
303: if ('0' <= c && c <= '9') return 0;
304: if (c == '_') return 0;
305: return 1;
306: }
307:
308: /* Set a breakpoint at the place specified by the "selection" in X. */
309:
310: static void
311: explicit_breakpoint_button ()
312: {
313: int selected_length;
314: char *selected_text;
315:
316: selected_text = XFetchBytes (screen_display, &selected_length);
317: if (selected_length)
318: {
319: char *line = (char *) xmalloc (selected_length + 6);
320: register char *p, *sp, *end;
321:
322: strcpy (line, "break ");
323:
324: /* Copy selection but exclude "garbage" characters. */
325:
326: p = selected_text;
327: end = p + selected_length;
328: sp = line + strlen (line);
329:
330: while (garbage (*p) && p != end) p++;
331: while (!garbage (*p) && p != end)
332: *sp++ = *p++;
333: *sp = 0;
334:
335: execute_command (line, 0);
336: free (selected_text);
337: free (line);
338: }
339: print_prompt ();
340: }
341:
342: /* Handle a button by running the command COMMAND. */
343:
344: static void
345: do_command (w, command, call_data)
346: Widget w;
347: char *command;
348: caddr_t call_data;
349: {
350: execute_command (command, 0);
351: xgdb_display_source ();
352: print_prompt ();
353: }
354:
355: static void
356: redisplay_button()
357: {
358: xgdb_display_source();
359: }
360:
361: /* Define and display all the buttons. */
362:
363: static void
364: addbutton (parent, name, function, closure)
365: Widget parent;
366: char *name;
367: void (*function) ();
368: caddr_t closure;
369: {
370: static XtCallbackRec Callback[] =
371: {
372: {NULL, (caddr_t)NULL},
373: {NULL, (caddr_t)NULL},
374: };
375: static Arg commandArgs[] =
376: {
377: {XtNlabel, (XtArgVal)NULL},
378: {XtNcallback, (XtArgVal)Callback},
379: };
380:
381: Callback[0].callback = (XtCallbackProc)function;
382: Callback[0].closure = (caddr_t)closure;
383: commandArgs[0].value = (XtArgVal)name;
384: XtCreateManagedWidget (name, commandWidgetClass, parent,
385: commandArgs, XtNumber(commandArgs));
386: }
387:
388: /* Create the button windows and store them in `buttons'. */
389:
390: static void
391: create_buttons (parent)
392: Widget parent;
393: {
394: addbutton (parent, "run", do_command, "run");
395: addbutton (parent, "quit", do_command, "quit");
396:
397: addbutton (parent, "break in", explicit_breakpoint_button, NULL);
398: addbutton (parent, "break at", breakpoint_button, 0);
399: addbutton (parent, "go until", breakpoint_button, 1);
400:
401: addbutton (parent, "print", print_button, 0);
402: addbutton (parent, "print*", print_button, 1);
403:
404: addbutton (parent, "next", do_command, "next");
405: addbutton (parent, "step", do_command, "step");
406: addbutton (parent, "cont", do_command, "cont");
407: addbutton (parent, "finish", do_command, "finish");
408:
409: addbutton (parent, "up", do_command, "up");
410: addbutton (parent, "down", do_command, "down");
411:
412: addbutton (parent, "redisplay", redisplay_button, NULL);
413: }
414:
415: /* Create a "label window" that just displays the string LABEL. */
416:
417: static Widget
418: create_label (name, label)
419: char *name, *label;
420: {
421: Arg labelArgs[2];
422: Widget w;
423:
424: XtSetArg (labelArgs[0], XtNname, name);
425: XtSetArg (labelArgs[1], XtNlabel, label);
426:
427: w = XtCreateManagedWidget ("label", labelWidgetClass, containing_widget,
428: labelArgs, XtNumber (labelArgs));
429: XtPanedSetMinMax (w, w->core.height, w->core.height);
430: return w;
431: }
432:
433: /* Create a subwindow of PARENT that displays and scrolls the contents
434: of file FILENAME. */
435:
436: static Widget
437: create_text_widget (parent, filename)
438: Widget parent;
439: char *filename;
440: {
441: static Arg fileArgs[3];
442: XtTextSource src;
443: XtTextSink sink;
444:
445: XtSetArg (fileArgs[0], XtNfile, filename);
446: src = XtDiskSourceCreate(parent, fileArgs, 1);
447: sink = XtAsciiSinkCreate(parent, NULL, 0);
448:
449: XtSetArg (fileArgs[0], XtNtextOptions, scrollVertical);
450: XtSetArg (fileArgs[1], XtNtextSource, src);
451: XtSetArg (fileArgs[2], XtNtextSink, sink);
452: return XtCreateManagedWidget ("disk", textWidgetClass, parent,
453: fileArgs, XtNumber (fileArgs));
454:
455: #if 0 /* This is tucker's method. */
456:
457: /* Create an empty source-display window and add to containing_widget */
458: XtSetArg (argl[0], XtNfile, "/dev/null");
459: XtSetArg (argl[1], XtNtextOptions, scrollVertical);
460: XtSetArg (argl[2], XtNheight, (XtArgVal)sheight);
461: source_text_widget = XtCreateManagedWidget (NULL, asciiDiskWidgetClass,
462: containing_widget, argl,
463: XtNumber (argl));
464:
465: /* Create NULL disk source */
466: XtSetArg (argl[0], XtNfile, "/dev/null");
467: NullSource = XtDiskSourceCreate (source_text_widget, argl, ONE);
468: #endif
469: }
470:
471: /* window manager argument parsing */
472: extern int *win_argc;
473: extern char **win_argv;
474:
475: /* Entry point to create the widgets representing our display. */
476: int
477: xgdb_create_window ()
478: {
479: int width, height;
480: int sheight;
481: Arg argl[3];
482:
483: /* initialize toolkit, setup defaults */
484: main_widget = XtInitialize ("gdb", "gdb", NULL, 0, win_argc, win_argv);
485: screen_display = XtDisplay (main_widget);
486:
487: /* Find out what size the user specified. */
488:
489: XtSetArg (argl[0], XtNwidth, (XtArgVal)&width);
490: XtSetArg (argl[1], XtNheight, (XtArgVal)&height);
491: XtGetValues (main_widget, argl, XtNumber(argl));
492:
493: /* If none specified, set a default size. */
494:
495: if (!width || !height)
496: {
497: width = 500, height = 700;
498: XtSetArg (argl[0], XtNwidth, (XtArgVal)width);
499: XtSetArg (argl[1], XtNheight, (XtArgVal)height);
500: XtSetValues (main_widget, argl, XtNumber(argl));
501: }
502: sheight = (float)height / 2.5;
503:
504: /* Create the (toplevel) main_widget */
505: XtSetArg (argl[0], XtNwidth, (XtArgVal)width);
506: XtSetArg (argl[1], XtNheight, (XtArgVal)height);
507: containing_widget
508: = XtCreateManagedWidget ("vpaned", vPanedWidgetClass,
509: main_widget, argl, XtNumber (argl));
510: XtPanedSetRefigureMode (containing_widget, FALSE);
511:
512: /* Create title */
513: {
514: char buf[200];
515: extern char *version;
516: sprintf (buf, "GDB %s", version);
517: title_widget =
518: create_label ("Title", buf);
519: }
520:
521: /* Create exec file name window and add */
522: exec_name_widget =
523: create_label ("Executable", "No executable specified");
524:
525: /* Create window full of buttons. */
526: button_box_widget = XtCreateManagedWidget ("buttons", boxWidgetClass,
527: containing_widget, NULL, 0);
528: create_buttons (button_box_widget);
529:
530: /* Create source file name window and add to containing_widget */
531: source_name_widget =
532: create_label ("Source File", "No source file yet.");
533:
534: /* Create an empty source-display window and add to containing_widget */
535: source_text_widget = create_text_widget (containing_widget, "/dev/null");
536:
537: #ifdef VFTD
538: /* Create Fake Text source */
539: {
540: extern XtTextSource TCreateApAsSource();
541: TSource = TCreateApAsSource();
542: }
543:
544: /* Create interactive box */
545: XtSetArg (argl[0], XtNtextSource, (XtArgVal)TSource);
546: XtSetArg (argl[1], XtNtextSink,
547: (XtArgVal)XtAsciiSinkCreate(containing_widget, NULL, 0));
548: XtSetArg (argl[2], XtNtextOptions,
549: (XtArgVal)(scrollVertical | wordBreak));
550: interactive_widget = XtCreateManagedWidget ("gdbWindow", textWidgetClass,
551: containing_widget, argl, THREE);
552: #endif
553:
554: /* Put them one screen */
555: XtPanedSetRefigureMode(containing_widget, TRUE);
556: XtRealizeWidget (main_widget);
557:
558: /* Define GDB cursor */
559: #if 0
560: XDefineCursor (screen_display, XtWindow (main_widget),
561: XCreateFontCursor (screen_display, XC_circle));
562: #endif
563:
564: XFlush (screen_display);
565: return 1;
566: }
567:
568: #define MAX_XGDB_READ 128
569:
570: /* xgdb_dispatch -- Loop, dispatching on window events,
571: until data is available on FP (which is normally stdin).
572: Then return, so the data on FP can be processed. */
573:
574: void
575: xgdb_dispatch (fp)
576: FILE *fp;
577: {
578: int inmask = 1 << fileno (fp);
579: int xmask = 1 << ConnectionNumber (screen_display);
580: int rfds = 0;
581: int nfds;
582: XEvent ev;
583: int pend;
584: int nread;
585: char buf[1024];
586: int ipmask;
587:
588: #ifdef VTFD
589: ipmask = 1 << vtfd[0];
590: #endif
591:
592: while (! (rfds & inmask))
593: {
594: pend = XPending (screen_display);
595: if (!pend)
596: {
597: rfds = inmask | xmask | ipmask;
598: /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */
599: nfds = select (32, &rfds, 0, 0, (struct timeval *) 0);
600: }
601: if (pend || rfds & xmask)
602: {
603: XNextEvent (screen_display, &ev);
604: XtDispatchEvent (&ev);
605: }
606:
607: #ifdef VTFD
608: /* Handle I/O through the command window. */
609: if (pend == 0 && (rfds & ipmask))
610: {
611: nread = read (vtfd[0], buf, sizeof(buf));
612: xgdb_write (buf, nread);
613: }
614: nread = xgdb_read (buf, MAX_XGDB_READ);
615: if (pend == 0 && nread > 0)
616: {
617: write (vifd[1], buf, nread);
618: }
619: #endif
620: }
621: }
622:
623: #ifdef VTFD
624:
625: static int output_size;
626: static int used_size;
627: static char *output_string;
628:
629: static void
630: xgdb_init_text ()
631: {
632: Arg args[2];
633:
634: output_size = 1000;
635: output_string = (char *) xmalloc (output_size);
636: used_size = 0;
637:
638: XtSetArg (args[0], XtNstring, (XtArgVal) output_string);
639: XtSetArg (args[1], XtNlength, (XtArgVal) output_size);
640: TSource
641: = XtStringSourceCreate (toplevel, args, 2);
642:
643: XtSetArg (args[0], XtNtextSource, TSource);
644: XtSetValues (interaction_widget, Args, 1);
645: }
646:
647: static void
648: xgdb_grow_text (size)
649: int size;
650: {
651: if (output_size < used_size + size + 200)
652: {
653: Arg args[2];
654:
655: XtStringSourceDestroy (TSource);
656:
657: output_size = (used_size + size + 1010 + 512) / 1010 * 1010;
658: output_string = xrealloc (output_string, output_size);
659:
660: XtSetArg (args[0], XtNstring, (XtArgVal) output_string);
661: XtSetArg (args[1], XtNlength, (XtArgVal) output_size);
662: TSource
663: = XtStringSourceCreate (toplevel, args, 2);
664:
665: XtSetArg (args[0], XtNtextSource, TSource);
666: XtSetValues (interaction_widget, Args, 1);
667: }
668: }
669:
670: /*VARARGS*/
671: xgdb_printf (fmt, arg1, arg2, arg3, arg4)
672: char *fmt;
673: {
674: char buf[1024];
675: XtTextBlock text;
676: XtTextPosition pos;
677:
678: /* ??? This will crash on the wrong data. */
679: pos = (*TSource->Scan)(TSource, 0, XtstAll, XtsdRight, 1, 0);
680: sprintf (buf, fmt, arg1, arg2, arg3, arg4);
681: text.length = strlen (buf);
682: text.ptr = buf;
683: xgdb_grow_text (text.length);
684: used_size += text.length;
685: XtTextReplace (interactive_widget, pos, pos, &text);
686: XtTextSetInsertionPoint (interactive_widget, pos + text.length);
687: XFlush (screen_display);
688: }
689:
690: int
691: xgdb_write (buf, len)
692: char *buf;
693: int len;
694: {
695: XtTextBlock text;
696: XtTextPosition pos;
697:
698: pos = (*TSource->Scan)(TSource, 0, XtstAll, XtsdRight, 1, 0);
699: text.length = len;
700: text.ptr = buf;
701: xgdb_grow_text (text.length);
702: used_size += text.length;
703: XtTextReplace (interactive_widget, pos, pos, &text);
704: XtTextSetInsertionPoint (interactive_widget, pos + text.length);
705: XFlush (screen_display);
706: }
707:
708: int
709: xgdb_read (buf, maxlen)
710: char *buf;
711: int maxlen;
712: {
713: XtTextBlock text;
714: XtTextPosition endpos;
715: int length = 0;
716:
717: xgdb_grow_text (maxlen);
718: endpos = XtTextGetInsertionPoint (interactive_widget);
719: length = endpos - used_size;
720: if (length > 0)
721: {
722: (*TSource->Read) (TSource, lastpos, &text, maxlen - 10);
723: length = text.length;
724: strncpy(buf, text.ptr, length);
725: buf[length] = NULL;
726: used_size += length;
727: }
728: return length;
729: }
730: #endif /* VTFD */
731:
732: /* If we use an X window, the GDB command loop is told to call this function
733: before reading a command from stdin.
734: PROMPT is saved for later use so buttons can print a prompt-string. */
735:
736: void
737: xgdb_window_hook (infile, prompt)
738: FILE *infile;
739: char *prompt;
740: {
741: prompt_string = prompt;
742: xgdb_display_source ();
743: xgdb_dispatch (infile);
744: }
745:
746: static
747: initialize ()
748: {
749: extern void (*window_hook) ();
750: extern int inhibit_windows;
751:
752: if (getenv ("DISPLAY") && ! inhibit_windows)
753: if (xgdb_create_window ())
754: window_hook = xgdb_window_hook;
755:
756: specify_exec_file_hook (xgdb_display_exec_file);
757: }
758:
759: END_FILE
760:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.