]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / gdb / tui / tui.c
1 /*
2 ** tui.c
3 ** General functions for the WDB TUI
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <malloc.h>
10 #include <curses.h>
11 #ifdef HAVE_TERM_H
12 #include <term.h>
13 #endif
14 #include <signal.h>
15 #include <fcntl.h>
16 #include <termio.h>
17 #include <setjmp.h>
18 #include "defs.h"
19 #include "gdbcmd.h"
20 #include "tui.h"
21 #include "tuiData.h"
22 #include "tuiLayout.h"
23 #include "tuiIO.h"
24 #include "tuiRegs.h"
25 #include "tuiWin.h"
26
27 /* The Solaris header files seem to provide no declaration for this at
28 all when __STDC__ is defined. This shouldn't conflict with
29 anything. */
30 extern char *tgoto ();
31
32 /***********************
33 ** Local Definitions
34 ************************/
35 #define FILEDES 2
36 /* Solaris <sys/termios.h> defines CTRL. */
37 #ifndef CTRL
38 #define CTRL(x) (x & ~0140)
39 #endif
40 #define CHK(val, dft) (val<=0 ? dft : val)
41
42 #define TOGGLE_USAGE "Usage:toggle breakpoints"
43 #define TUI_TOGGLE_USAGE "Usage:\ttoggle $fregs\n\ttoggle breakpoints"
44
45 /*****************************
46 ** Local static forward decls
47 ******************************/
48 static void _tuiReset PARAMS ((void));
49 static void _toggle_command PARAMS ((char *, int));
50 static void _tui_vToggle_command PARAMS ((va_list));
51 static Opaque _tui_vDo PARAMS ((TuiOpaqueFuncPtr, va_list));
52
53
54
55 /***********************
56 ** Public Functions
57 ************************/
58
59 /*
60 ** tuiInit().
61 */
62 void
63 #ifdef __STDC__
64 tuiInit (char *argv0)
65 #else
66 tuiInit (argv0)
67 char *argv0;
68 #endif
69 {
70 extern void init_page_info ();
71 extern void initialize_tui_files PARAMS ((void));
72
73 initialize_tui_files ();
74 initializeStaticData ();
75 initscr ();
76 refresh ();
77 setTermHeightTo (LINES);
78 setTermWidthTo (COLS);
79 tuiInitWindows ();
80 wrefresh (cmdWin->generic.handle);
81 init_page_info ();
82 /* Don't hook debugger output if doing command-window
83 * the XDB way. However, one thing we do want to do in
84 * XDB style is set up the scrolling region to be
85 * the bottom of the screen (tuiTermUnsetup()).
86 */
87 fputs_unfiltered_hook = NULL;
88 flush_hook = NULL;
89 rl_initialize (); /* need readline initialization to
90 * create termcap sequences
91 */
92 tuiTermUnsetup (1, cmdWin->detail.commandInfo.curch);
93
94 return;
95 } /* tuiInit */
96
97
98 /*
99 ** tuiInitWindows().
100 */
101 void
102 #ifdef __STDC__
103 tuiInitWindows (void)
104 #else
105 tuiInitWindows ()
106 #endif
107 {
108 TuiWinType type;
109
110 tuiSetLocatorContent (0);
111 showLayout (SRC_COMMAND);
112 keypad (cmdWin->generic.handle, TRUE);
113 echo ();
114 crmode ();
115 nl ();
116 tuiSetWinFocusTo (srcWin);
117
118 return;
119 } /* tuiInitWindows */
120
121
122 /*
123 ** tuiCleanUp().
124 ** Kill signal handler and cleanup termination method
125 */
126 void
127 #ifdef __STDC__
128 tuiResetScreen (void)
129 #else
130 tuiResetScreen ()
131 #endif
132 {
133 TuiWinType type = SRC_WIN;
134
135 keypad (cmdWin->generic.handle, FALSE);
136 for (; type < MAX_MAJOR_WINDOWS; type++)
137 {
138 if (m_winPtrNotNull (winList[type]) &&
139 winList[type]->generic.type != UNDEFINED_WIN &&
140 !winList[type]->generic.isVisible)
141 tuiDelWindow (winList[type]);
142 }
143 endwin ();
144 initscr ();
145 refresh ();
146 echo ();
147 crmode ();
148 nl ();
149
150 return;
151 } /* tuiResetScreen */
152
153
154 /*
155 ** tuiCleanUp().
156 ** Kill signal handler and cleanup termination method
157 */
158 void
159 #ifdef __STDC__
160 tuiCleanUp (void)
161 #else
162 tuiCleanUp ()
163 #endif
164 {
165 char *buffer;
166 extern char *term_cursor_move;
167
168 signal (SIGINT, SIG_IGN);
169 tuiTermSetup (0); /* Restore scrolling region to whole screen */
170 keypad (cmdWin->generic.handle, FALSE);
171 freeAllWindows ();
172 endwin ();
173 buffer = tgoto (term_cursor_move, 0, termHeight ());
174 tputs (buffer, 1, putchar);
175 _tuiReset ();
176
177 return;
178 } /* tuiCleanUp */
179
180
181 /*
182 ** tuiError().
183 */
184 void
185 #ifdef __STDC__
186 tuiError (
187 char *string,
188 int exitGdb)
189 #else
190 tuiError (string, exitGdb)
191 char *string;
192 int exitGdb;
193 #endif
194 {
195 puts_unfiltered (string);
196 if (exitGdb)
197 {
198 tuiCleanUp ();
199 exit (-1);
200 }
201
202 return;
203 } /* tuiError */
204
205
206 /*
207 ** tui_vError()
208 ** tuiError with args in a va_list.
209 */
210 void
211 #ifdef __STDC__
212 tui_vError (
213 va_list args)
214 #else
215 tui_vError (args)
216 va_list args;
217 #endif
218 {
219 char *string;
220 int exitGdb;
221
222 string = va_arg (args, char *);
223 exitGdb = va_arg (args, int);
224
225 tuiError (string, exitGdb);
226
227 return;
228 } /* tui_vError */
229
230
231 /*
232 ** tuiFree()
233 ** Wrapper on top of free() to ensure that input address is greater than 0x0
234 */
235 void
236 #ifdef __STDC__
237 tuiFree (
238 char *ptr)
239 #else
240 tuiFree (ptr)
241 char *ptr;
242 #endif
243 {
244 if (ptr != (char *) NULL)
245 {
246 free (ptr);
247 }
248
249 return;
250 } /* tuiFree */
251
252
253 /* tuiGetLowDisassemblyAddress().
254 ** Determine what the low address will be to display in the TUI's
255 ** disassembly window. This may or may not be the same as the
256 ** low address input.
257 */
258 Opaque
259 #ifdef __STDC__
260 tuiGetLowDisassemblyAddress (
261 Opaque low,
262 Opaque pc)
263 #else
264 tuiGetLowDisassemblyAddress (low, pc)
265 Opaque low;
266 Opaque pc;
267 #endif
268 {
269 int line;
270 Opaque newLow;
271
272 /*
273 ** Determine where to start the disassembly so that the pc is about in the
274 ** middle of the viewport.
275 */
276 for (line = 0, newLow = pc;
277 (newLow > low &&
278 line < (tuiDefaultWinViewportHeight (DISASSEM_WIN,
279 DISASSEM_COMMAND) / 2));)
280 {
281 bfd_byte buffer[4];
282
283 newLow -= sizeof (bfd_getb32 (buffer));
284 line++;
285 }
286
287 return newLow;
288 } /* tuiGetLowDisassemblyAddress */
289
290
291 /* tui_vGetLowDisassemblyAddress().
292 ** Determine what the low address will be to display in the TUI's
293 ** disassembly window with args in a va_list.
294 */
295 Opaque
296 #ifdef __STDC__
297 tui_vGetLowDisassemblyAddress (
298 va_list args)
299 #else
300 tui_vGetLowDisassemblyAddress (args)
301 va_list args;
302 #endif
303 {
304 int line;
305 Opaque newLow;
306 Opaque low;
307 Opaque pc;
308
309 low = va_arg (args, Opaque);
310 pc = va_arg (args, Opaque);
311
312 return (tuiGetLowDisassemblyAddress (low, pc));
313
314 } /* tui_vGetLowDisassemblyAddress */
315
316
317 /*
318 ** tuiDo().
319 ** General purpose function to execute a tui function. Transitions
320 ** between curses and the are handled here. This function is called
321 ** by non-tui gdb functions.
322 **
323 ** Errors are caught here.
324 ** If there is no error, the value returned by 'func' is returned.
325 ** If there is an error, then zero is returned.
326 **
327 ** Must not be called with immediate_quit in effect (bad things might
328 ** happen, say we got a signal in the middle of a memcpy to quit_return).
329 ** This is an OK restriction; with very few exceptions immediate_quit can
330 ** be replaced by judicious use of QUIT.
331 */
332 Opaque
333 #ifdef __STDC__
334 tuiDo (
335 TuiOpaqueFuncPtr func,...)
336 #else
337 tuiDo (func, va_alist)
338 TuiOpaqueFuncPtr func;
339 va_dcl
340 #endif
341 {
342 extern int terminal_is_ours;
343
344 Opaque ret = (Opaque) NULL;
345
346 /* It is an error to be tuiDo'ing if we
347 * don't own the terminal.
348 */
349 if (!terminal_is_ours)
350 return ret;
351
352 if (tui_version)
353 {
354 va_list args;
355
356 #ifdef __STDC__
357 va_start (args, func);
358 #else
359 va_start (args);
360 #endif
361 ret = _tui_vDo (func, args);
362 va_end (args);
363 }
364
365 return ret;
366 } /* tuiDo */
367
368
369 /*
370 ** tuiDoAndReturnToTop().
371 ** General purpose function to execute a tui function. Transitions
372 ** between curses and the are handled here. This function is called
373 ** by non-tui gdb functions who wish to reset gdb to the top level.
374 ** After the tuiDo is performed, a return to the top level occurs.
375 **
376 ** Errors are caught here.
377 ** If there is no error, the value returned by 'func' is returned.
378 ** If there is an error, then zero is returned.
379 **
380 ** Must not be called with immediate_quit in effect (bad things might
381 ** happen, say we got a signal in the middle of a memcpy to quit_return).
382 ** This is an OK restriction; with very few exceptions immediate_quit can
383 ** be replaced by judicious use of QUIT.
384 **
385 */
386 Opaque
387 #ifdef __STDC__
388 tuiDoAndReturnToTop (
389 TuiOpaqueFuncPtr func,...)
390 #else
391 tuiDoAndReturnToTop (func, va_alist)
392 TuiOpaqueFuncPtr func;
393 va_dcl
394 #endif
395 {
396 extern int terminal_is_ours;
397
398 Opaque ret = (Opaque) NULL;
399
400 /* It is an error to be tuiDo'ing if we
401 * don't own the terminal.
402 */
403 if (!terminal_is_ours)
404 return ret;
405
406 if (tui_version)
407 {
408 va_list args;
409
410 #ifdef __STDC__
411 va_start (args, func);
412 #else
413 va_start (args);
414 #endif
415 ret = _tui_vDo (func, args);
416
417 /* force a return to the top level */
418 return_to_top_level (RETURN_ERROR);
419 }
420
421 return ret;
422 } /* tuiDoAndReturnToTop */
423
424
425 void
426 #ifdef __STDC__
427 tui_vSelectSourceSymtab (
428 va_list args)
429 #else
430 tui_vSelectSourceSymtab (args)
431 va_list args;
432 #endif
433 {
434 struct symtab *s = va_arg (args, struct symtab *);
435
436 select_source_symtab (s);
437 return;
438 } /* tui_vSelectSourceSymtab */
439
440
441 /*
442 ** _initialize_tui().
443 ** Function to initialize gdb commands, for tui window manipulation.
444 */
445 void
446 _initialize_tui ()
447 {
448 #if 0
449 if (tui_version)
450 {
451 add_com ("toggle", class_tui, _toggle_command,
452 "Toggle Terminal UI Features\n\
453 Usage: Toggle $fregs\n\
454 \tToggles between single and double precision floating point registers.\n");
455 }
456 #endif
457 char *helpStr;
458
459 if (tui_version)
460 helpStr = "Toggle Specified Features\n\
461 Usage:\ttoggle $fregs\n\ttoggle breakpoints";
462 else
463 helpStr = "Toggle Specified Features\nUsage:toggle breakpoints";
464 add_abbrev_prefix_cmd ("toggle",
465 class_tui,
466 _toggle_command,
467 helpStr,
468 &togglelist,
469 "toggle ",
470 1,
471 &cmdlist);
472 } /* _initialize_tui*/
473
474
475 /*
476 ** va_catch_errors().
477 ** General purpose function to execute a function, catching errors.
478 ** If there is no error, the value returned by 'func' is returned.
479 ** If there is error, then zero is returned.
480 ** Note that 'func' must take a variable argument list as well.
481 **
482 ** Must not be called with immediate_quit in effect (bad things might
483 ** happen, say we got a signal in the middle of a memcpy to quit_return).
484 ** This is an OK restriction; with very few exceptions immediate_quit can
485 ** be replaced by judicious use of QUIT.
486 */
487 Opaque
488 #ifdef __STDC__
489 va_catch_errors (
490 TuiOpaqueFuncPtr func,
491 va_list args)
492 #else
493 va_catch_errors (func, args)
494 TuiOpaqueFuncPtr func;
495 va_list args;
496 #endif
497 {
498 Opaque ret = (Opaque) NULL;
499
500 /*
501 ** We could have used catch_errors(), but it doesn't handle variable args.
502 ** Also, for the tui, we always want to catch all errors, so we don't
503 ** need to pass a mask, or an error string.
504 */
505 jmp_buf saved_error;
506 jmp_buf saved_quit;
507 jmp_buf tmp_jmp;
508 struct cleanup *saved_cleanup_chain;
509 char *saved_error_pre_print;
510 char *saved_quit_pre_print;
511 extern jmp_buf error_return;
512 extern jmp_buf quit_return;
513
514 saved_cleanup_chain = save_cleanups ();
515 saved_error_pre_print = error_pre_print;
516 saved_quit_pre_print = quit_pre_print;
517
518 memcpy ((char *) saved_error, (char *) error_return, sizeof (jmp_buf));
519 error_pre_print = "";
520 memcpy (saved_quit, quit_return, sizeof (jmp_buf));
521 quit_pre_print = "";
522
523 if (setjmp (tmp_jmp) == 0)
524 {
525 va_list argList = args;
526 memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
527 memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
528 ret = func (argList);
529 }
530 restore_cleanups (saved_cleanup_chain);
531 memcpy (error_return, saved_error, sizeof (jmp_buf));
532 error_pre_print = saved_error_pre_print;
533 memcpy (quit_return, saved_quit, sizeof (jmp_buf));
534 quit_pre_print = saved_quit_pre_print;
535
536 return ret;
537 }
538
539 /*
540 ** vcatch_errors().
541 ** Catch errors occurring in tui or non tui function, handling
542 ** variable param lists. Note that 'func' must take a variable
543 ** argument list as well.
544 */
545 Opaque
546 #ifdef __STDC__
547 vcatch_errors (
548 OpaqueFuncPtr func,...)
549 #else
550 vcatch_errors (va_alist)
551 va_dcl
552 /*
553 vcatch_errors(func, va_alist)
554 OpaqueFuncPtr func;
555 va_dcl
556 */
557 #endif
558 {
559 Opaque ret = (Opaque) NULL;
560 va_list args;
561 #ifdef __STDC__
562 va_start (args, func);
563 /*
564 va_arg(args, OpaqueFuncPtr);
565 */
566 #else
567 OpaqueFuncPtr func;
568
569 va_start (args);
570 func = va_arg (args, OpaqueFuncPtr);
571 #endif
572 ret = va_catch_errors (func, args);
573 va_end (args);
574
575 return ret;
576 }
577
578
579 void
580 #ifdef __STDC__
581 strcat_to_buf (
582 char *buf,
583 int buflen,
584 char *itemToAdd)
585 #else
586 strcat_to_buf (buf, buflen, itemToAdd)
587 char *buf;
588 int buflen;
589 char *itemToAdd;
590 #endif
591 {
592 if (itemToAdd != (char *) NULL && buf != (char *) NULL)
593 {
594 if ((strlen (buf) + strlen (itemToAdd)) <= buflen)
595 strcat (buf, itemToAdd);
596 else
597 strncat (buf, itemToAdd, (buflen - strlen (buf)));
598 }
599
600 return;
601 } /* strcat_to_buf */
602
603 /* VARARGS */
604 void
605 #ifdef ANSI_PROTOTYPES
606 strcat_to_buf_with_fmt (
607 char *buf,
608 int bufLen,
609 char *format,...)
610 #else
611 strcat_to_buf_with_fmt (va_alist)
612 va_dcl
613 #endif
614 {
615 char *linebuffer;
616 struct cleanup *old_cleanups;
617 va_list args;
618 #ifdef ANSI_PROTOTYPES
619 va_start (args, format);
620 #else
621 char *buf;
622 int bufLen;
623 char *format;
624
625 va_start (args);
626 buf = va_arg (args, char *);
627 bufLen = va_arg (args, int);
628 format = va_arg (args, char *);
629 #endif
630 vasprintf (&linebuffer, format, args);
631 old_cleanups = make_cleanup (free, linebuffer);
632 strcat_to_buf (buf, bufLen, linebuffer);
633 do_cleanups (old_cleanups);
634 va_end (args);
635 }
636
637
638
639
640
641 /***********************
642 ** Static Functions
643 ************************/
644
645
646 /*
647 ** _tui_vDo().
648 ** General purpose function to execute a tui function. Transitions
649 ** between curses and the are handled here. This function is called
650 ** by non-tui gdb functions.
651 **
652 ** Errors are caught here.
653 ** If there is no error, the value returned by 'func' is returned.
654 ** If there is an error, then zero is returned.
655 **
656 ** Must not be called with immediate_quit in effect (bad things might
657 ** happen, say we got a signal in the middle of a memcpy to quit_return).
658 ** This is an OK restriction; with very few exceptions immediate_quit can
659 ** be replaced by judicious use of QUIT.
660 */
661 static Opaque
662 #ifdef __STDC__
663 _tui_vDo (
664 TuiOpaqueFuncPtr func,
665 va_list args)
666 #else
667 _tui_vDo (func, args)
668 TuiOpaqueFuncPtr func;
669 va_list args;
670 #endif
671 {
672 extern int terminal_is_ours;
673
674 Opaque ret = (Opaque) NULL;
675
676 /* It is an error to be tuiDo'ing if we
677 * don't own the terminal.
678 */
679 if (!terminal_is_ours)
680 return ret;
681
682 if (tui_version)
683 {
684 /* If doing command window the "XDB way" (command window
685 * is unmanaged by curses...
686 */
687 /* Set up terminal for TUI */
688 tuiTermSetup (1);
689
690 ret = va_catch_errors (func, args);
691
692 /* Set up terminal for command window */
693 tuiTermUnsetup (1, cmdWin->detail.commandInfo.curch);
694 }
695
696 return ret;
697 } /* _tui_vDo */
698
699
700 static void
701 #ifdef __STDC__
702 _toggle_command (
703 char *arg,
704 int fromTTY)
705 #else
706 _toggle_command (arg, fromTTY)
707 char *arg;
708 int fromTTY;
709 #endif
710 {
711 printf_filtered ("Specify feature to toggle.\n%s\n",
712 (tui_version) ? TUI_TOGGLE_USAGE : TOGGLE_USAGE);
713 /*
714 tuiDo((TuiOpaqueFuncPtr)_Toggle_command, arg, fromTTY);
715 */
716 }
717
718 /*
719 ** _tui_vToggle_command().
720 */
721 static void
722 #ifdef __STDC__
723 _tui_vToggle_command (
724 va_list args)
725 #else
726 _tui_vToggle_command (args)
727 va_list args;
728 #endif
729 {
730 char *arg;
731 int fromTTY;
732
733 arg = va_arg (args, char *);
734
735 if (arg == (char *) NULL)
736 printf_filtered (TOGGLE_USAGE);
737 else
738 {
739 char *ptr = (char *) tuiStrDup (arg);
740 int i;
741
742 for (i = 0; (ptr[i]); i++)
743 ptr[i] = toupper (arg[i]);
744
745 if (subsetCompare (ptr, TUI_FLOAT_REGS_NAME))
746 tuiToggleFloatRegs ();
747 /* else if (subsetCompare(ptr, "ANOTHER TOGGLE OPTION"))
748 ...
749 */
750 else
751 printf_filtered (TOGGLE_USAGE);
752 tuiFree (ptr);
753 }
754
755 return;
756 } /* _tuiToggle_command */
757
758
759 static void
760 #ifdef __STDC__
761 _tuiReset (void)
762 #else
763 _tuiReset ()
764 #endif
765 {
766 struct termio mode;
767
768 /*
769 ** reset the teletype mode bits to a sensible state.
770 ** Copied tset.c
771 */
772 #if ! defined (USG) && defined (TIOCGETC)
773 struct tchars tbuf;
774 #endif /* !USG && TIOCGETC */
775 #ifdef UCB_NTTY
776 struct ltchars ltc;
777
778 if (ldisc == NTTYDISC)
779 {
780 ioctl (FILEDES, TIOCGLTC, &ltc);
781 ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
782 ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
783 ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
784 ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
785 ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
786 ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
787 ioctl (FILEDES, TIOCSLTC, &ltc);
788 }
789 #endif /* UCB_NTTY */
790 #ifndef USG
791 #ifdef TIOCGETC
792 ioctl (FILEDES, TIOCGETC, &tbuf);
793 tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
794 tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
795 tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
796 tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
797 tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
798 /* brkc is left alone */
799 ioctl (FILEDES, TIOCSETC, &tbuf);
800 #endif /* TIOCGETC */
801 mode.sg_flags &= ~(RAW
802 #ifdef CBREAK
803 | CBREAK
804 #endif /* CBREAK */
805 | VTDELAY | ALLDELAY);
806 mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
807 #else /*USG*/
808 ioctl (FILEDES, TCGETA, &mode);
809 mode.c_cc[VINTR] = CHK (mode.c_cc[VINTR], CTRL ('?'));
810 mode.c_cc[VQUIT] = CHK (mode.c_cc[VQUIT], CTRL ('\\'));
811 mode.c_cc[VEOF] = CHK (mode.c_cc[VEOF], CTRL ('D'));
812
813 mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF);
814 mode.c_iflag |= (BRKINT | ISTRIP | ICRNL | IXON);
815 mode.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |
816 NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
817 mode.c_oflag |= (OPOST | ONLCR);
818 mode.c_cflag &= ~(CSIZE | PARODD | CLOCAL);
819 #ifndef hp9000s800
820 mode.c_cflag |= (CS8 | CREAD);
821 #else /*hp9000s800*/
822 mode.c_cflag |= (CS8 | CSTOPB | CREAD);
823 #endif /* hp9000s800 */
824 mode.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
825 mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOK);
826 ioctl (FILEDES, TCSETAW, &mode);
827 #endif /* USG */
828
829 return;
830 } /* _tuiReset */