]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui-winsource.c
2004-02-07 Andrew Cagney <cagney@redhat.com>
[thirdparty/binutils-gdb.git] / gdb / tui / tui-winsource.c
1 /* TUI display source/assembly window.
2
3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4 Foundation, Inc.
5
6 Contributed by Hewlett-Packard Company.
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
24
25 #include "defs.h"
26 #include <ctype.h>
27 #include "symtab.h"
28 #include "frame.h"
29 #include "breakpoint.h"
30 #include "value.h"
31 #include "source.h"
32
33 #include "tui/tui.h"
34 #include "tui/tui-data.h"
35 #include "tui/tui-stack.h"
36 #include "tui/tui-win.h"
37 #include "tui/tui-wingeneral.h"
38 #include "tui/tui-winsource.h"
39 #include "tui/tui-source.h"
40 #include "tui/tui-disasm.h"
41
42 #ifdef HAVE_NCURSES_H
43 #include <ncurses.h>
44 #else
45 #ifdef HAVE_CURSES_H
46 #include <curses.h>
47 #endif
48 #endif
49
50 /* Function to display the "main" routine. */
51 void
52 tui_display_main (void)
53 {
54 if ((tui_source_windows ())->count > 0)
55 {
56 CORE_ADDR addr;
57
58 addr = tui_get_begin_asm_address ();
59 if (addr != (CORE_ADDR) 0)
60 {
61 struct symtab_and_line sal;
62
63 tui_update_source_windows_with_addr (addr);
64 sal = find_pc_line (addr, 0);
65 if (sal.symtab)
66 tui_update_locator_filename (sal.symtab->filename);
67 else
68 tui_update_locator_filename ("??");
69 }
70 }
71 }
72
73
74
75 /* Function to display source in the source window. This function
76 initializes the horizontal scroll to 0. */
77 void
78 tui_update_source_window (struct tui_win_info * winInfo, struct symtab *s,
79 union tui_line_or_address lineOrAddr, int noerror)
80 {
81 winInfo->detail.sourceInfo.horizontalOffset = 0;
82 tui_update_source_window_as_is (winInfo, s, lineOrAddr, noerror);
83
84 return;
85 }
86
87
88 /* Function to display source in the source/asm window. This function
89 shows the source as specified by the horizontal offset. */
90 void
91 tui_update_source_window_as_is (struct tui_win_info * winInfo, struct symtab *s,
92 union tui_line_or_address lineOrAddr, int noerror)
93 {
94 enum tui_status ret;
95
96 if (winInfo->generic.type == SRC_WIN)
97 ret = tui_set_source_content (s, lineOrAddr.lineNo, noerror);
98 else
99 ret = tui_set_disassem_content (lineOrAddr.addr);
100
101 if (ret == TUI_FAILURE)
102 {
103 tui_clear_source_content (winInfo, EMPTY_SOURCE_PROMPT);
104 tui_clear_exec_info_content (winInfo);
105 }
106 else
107 {
108 tui_update_breakpoint_info (winInfo, 0);
109 tui_show_source_content (winInfo);
110 tui_update_exec_info (winInfo);
111 if (winInfo->generic.type == SRC_WIN)
112 {
113 struct symtab_and_line sal;
114
115 sal.line = lineOrAddr.lineNo +
116 (winInfo->generic.contentSize - 2);
117 sal.symtab = s;
118 set_current_source_symtab_and_line (&sal);
119 /*
120 ** If the focus was in the asm win, put it in the src
121 ** win if we don't have a split layout
122 */
123 if (tui_win_with_focus () == disassemWin &&
124 tui_current_layout () != SRC_DISASSEM_COMMAND)
125 tui_set_win_focus_to (srcWin);
126 }
127 }
128
129
130 return;
131 }
132
133
134 /* Function to ensure that the source and/or disassemly windows
135 reflect the input address. */
136 void
137 tui_update_source_windows_with_addr (CORE_ADDR addr)
138 {
139 if (addr != 0)
140 {
141 struct symtab_and_line sal;
142 union tui_line_or_address l;
143
144 switch (tui_current_layout ())
145 {
146 case DISASSEM_COMMAND:
147 case DISASSEM_DATA_COMMAND:
148 tui_show_disassem (addr);
149 break;
150 case SRC_DISASSEM_COMMAND:
151 tui_show_disassem_and_update_source (addr);
152 break;
153 default:
154 sal = find_pc_line (addr, 0);
155 l.lineNo = sal.line;
156 tui_show_symtab_source (sal.symtab, l, FALSE);
157 break;
158 }
159 }
160 else
161 {
162 int i;
163
164 for (i = 0; i < (tui_source_windows ())->count; i++)
165 {
166 struct tui_win_info * winInfo = (struct tui_win_info *) (tui_source_windows ())->list[i];
167
168 tui_clear_source_content (winInfo, EMPTY_SOURCE_PROMPT);
169 tui_clear_exec_info_content (winInfo);
170 }
171 }
172
173 return;
174 } /* tuiUpdateSourceWindowsWithAddr */
175
176 /* Function to ensure that the source and/or disassemly windows
177 reflect the input address. */
178 void
179 tui_update_source_windows_with_line (struct symtab *s, int line)
180 {
181 CORE_ADDR pc;
182 union tui_line_or_address l;
183
184 switch (tui_current_layout ())
185 {
186 case DISASSEM_COMMAND:
187 case DISASSEM_DATA_COMMAND:
188 find_line_pc (s, line, &pc);
189 tui_update_source_windows_with_addr (pc);
190 break;
191 default:
192 l.lineNo = line;
193 tui_show_symtab_source (s, l, FALSE);
194 if (tui_current_layout () == SRC_DISASSEM_COMMAND)
195 {
196 find_line_pc (s, line, &pc);
197 tui_show_disassem (pc);
198 }
199 break;
200 }
201
202 return;
203 }
204
205 void
206 tui_clear_source_content (struct tui_win_info * winInfo, int displayPrompt)
207 {
208 if (m_winPtrNotNull (winInfo))
209 {
210 register int i;
211
212 winInfo->generic.contentInUse = FALSE;
213 tui_erase_source_content (winInfo, displayPrompt);
214 for (i = 0; i < winInfo->generic.contentSize; i++)
215 {
216 struct tui_win_element * element =
217 (struct tui_win_element *) winInfo->generic.content[i];
218 element->whichElement.source.hasBreak = FALSE;
219 element->whichElement.source.isExecPoint = FALSE;
220 }
221 }
222
223 return;
224 } /* tuiClearSourceContent */
225
226
227 void
228 tui_erase_source_content (struct tui_win_info * winInfo, int displayPrompt)
229 {
230 int xPos;
231 int halfWidth = (winInfo->generic.width - 2) / 2;
232
233 if (winInfo->generic.handle != (WINDOW *) NULL)
234 {
235 werase (winInfo->generic.handle);
236 tui_check_and_display_highlight_if_needed (winInfo);
237 if (displayPrompt == EMPTY_SOURCE_PROMPT)
238 {
239 char *noSrcStr;
240
241 if (winInfo->generic.type == SRC_WIN)
242 noSrcStr = NO_SRC_STRING;
243 else
244 noSrcStr = NO_DISASSEM_STRING;
245 if (strlen (noSrcStr) >= halfWidth)
246 xPos = 1;
247 else
248 xPos = halfWidth - strlen (noSrcStr);
249 mvwaddstr (winInfo->generic.handle,
250 (winInfo->generic.height / 2),
251 xPos,
252 noSrcStr);
253
254 /* elz: added this function call to set the real contents of
255 the window to what is on the screen, so that later calls
256 to refresh, do display
257 the correct stuff, and not the old image */
258
259 tui_set_source_content_nil (winInfo, noSrcStr);
260 }
261 tui_refresh_win (&winInfo->generic);
262 }
263 return;
264 } /* tuiEraseSourceContent */
265
266
267 /* Redraw the complete line of a source or disassembly window. */
268 static void
269 tui_show_source_line (struct tui_win_info * winInfo, int lineno)
270 {
271 struct tui_win_element * line;
272 int x, y;
273
274 line = (struct tui_win_element *) winInfo->generic.content[lineno - 1];
275 if (line->whichElement.source.isExecPoint)
276 wattron (winInfo->generic.handle, A_STANDOUT);
277
278 mvwaddstr (winInfo->generic.handle, lineno, 1,
279 line->whichElement.source.line);
280 if (line->whichElement.source.isExecPoint)
281 wattroff (winInfo->generic.handle, A_STANDOUT);
282
283 /* Clear to end of line but stop before the border. */
284 getyx (winInfo->generic.handle, y, x);
285 while (x + 1 < winInfo->generic.width)
286 {
287 waddch (winInfo->generic.handle, ' ');
288 getyx (winInfo->generic.handle, y, x);
289 }
290 }
291
292 void
293 tui_show_source_content (struct tui_win_info * winInfo)
294 {
295 if (winInfo->generic.contentSize > 0)
296 {
297 int lineno;
298
299 for (lineno = 1; lineno <= winInfo->generic.contentSize; lineno++)
300 tui_show_source_line (winInfo, lineno);
301 }
302 else
303 tui_erase_source_content (winInfo, TRUE);
304
305 tui_check_and_display_highlight_if_needed (winInfo);
306 tui_refresh_win (&winInfo->generic);
307 winInfo->generic.contentInUse = TRUE;
308 }
309
310
311 /* Scroll the source forward or backward horizontally. */
312 void
313 tui_horizontal_source_scroll (struct tui_win_info * winInfo,
314 enum tui_scroll_direction direction,
315 int numToScroll)
316 {
317 if (winInfo->generic.content != NULL)
318 {
319 int offset;
320 struct symtab *s;
321 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
322
323 if (cursal.symtab == (struct symtab *) NULL)
324 s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
325 else
326 s = cursal.symtab;
327
328 if (direction == LEFT_SCROLL)
329 offset = winInfo->detail.sourceInfo.horizontalOffset + numToScroll;
330 else
331 {
332 if ((offset =
333 winInfo->detail.sourceInfo.horizontalOffset - numToScroll) < 0)
334 offset = 0;
335 }
336 winInfo->detail.sourceInfo.horizontalOffset = offset;
337 tui_update_source_window_as_is (winInfo, s,
338 ((struct tui_win_element *)
339 winInfo->generic.content[0])->whichElement.source.lineOrAddr,
340 FALSE);
341 }
342
343 return;
344 } /* tuiHorizontalSourceScroll */
345
346
347 /* Set or clear the hasBreak flag in the line whose line is lineNo. */
348 void
349 tui_set_is_exec_point_at (union tui_line_or_address l, struct tui_win_info * winInfo)
350 {
351 int changed = 0;
352 int i;
353 tui_win_content content = (tui_win_content) winInfo->generic.content;
354
355 i = 0;
356 while (i < winInfo->generic.contentSize)
357 {
358 int newState;
359
360 if (content[i]->whichElement.source.lineOrAddr.addr == l.addr)
361 newState = TRUE;
362 else
363 newState = FALSE;
364 if (newState != content[i]->whichElement.source.isExecPoint)
365 {
366 changed++;
367 content[i]->whichElement.source.isExecPoint = newState;
368 tui_show_source_line (winInfo, i + 1);
369 }
370 i++;
371 }
372 if (changed)
373 tui_refresh_win (&winInfo->generic);
374 }
375
376 /* Update the execution windows to show the active breakpoints.
377 This is called whenever a breakpoint is inserted, removed or
378 has its state changed. */
379 void
380 tui_update_all_breakpoint_info ()
381 {
382 struct tui_list *list = tui_source_windows ();
383 int i;
384
385 for (i = 0; i < list->count; i++)
386 {
387 struct tui_win_info * win = (struct tui_win_info *) list->list[i];
388
389 if (tui_update_breakpoint_info (win, FALSE))
390 {
391 tui_update_exec_info (win);
392 }
393 }
394 }
395
396
397 /* Scan the source window and the breakpoints to update the
398 hasBreak information for each line.
399 Returns 1 if something changed and the execution window
400 must be refreshed. */
401 int
402 tui_update_breakpoint_info (struct tui_win_info * win, int current_only)
403 {
404 int i;
405 int need_refresh = 0;
406 struct tui_source_info * src = &win->detail.sourceInfo;
407
408 for (i = 0; i < win->generic.contentSize; i++)
409 {
410 struct breakpoint *bp;
411 extern struct breakpoint *breakpoint_chain;
412 int mode;
413 struct tui_source_element* line;
414
415 line = &((struct tui_win_element *) win->generic.content[i])->whichElement.source;
416 if (current_only && !line->isExecPoint)
417 continue;
418
419 /* Scan each breakpoint to see if the current line has something to
420 do with it. Identify enable/disabled breakpoints as well as
421 those that we already hit. */
422 mode = 0;
423 for (bp = breakpoint_chain;
424 bp != (struct breakpoint *) NULL;
425 bp = bp->next)
426 {
427 if ((win == srcWin
428 && bp->source_file
429 && (strcmp (src->filename, bp->source_file) == 0)
430 && bp->line_number == line->lineOrAddr.lineNo)
431 || (win == disassemWin
432 && bp->loc->address == line->lineOrAddr.addr))
433 {
434 if (bp->enable_state == bp_disabled)
435 mode |= TUI_BP_DISABLED;
436 else
437 mode |= TUI_BP_ENABLED;
438 if (bp->hit_count)
439 mode |= TUI_BP_HIT;
440 if (bp->cond)
441 mode |= TUI_BP_CONDITIONAL;
442 if (bp->type == bp_hardware_breakpoint)
443 mode |= TUI_BP_HARDWARE;
444 }
445 }
446 if (line->hasBreak != mode)
447 {
448 line->hasBreak = mode;
449 need_refresh = 1;
450 }
451 }
452 return need_refresh;
453 }
454
455
456 /*
457 ** tuiSetExecInfoContent().
458 ** Function to initialize the content of the execution info window,
459 ** based upon the input window which is either the source or
460 ** disassembly window.
461 */
462 enum tui_status
463 tuiSetExecInfoContent (struct tui_win_info * winInfo)
464 {
465 enum tui_status ret = TUI_SUCCESS;
466
467 if (winInfo->detail.sourceInfo.executionInfo != (struct tui_gen_win_info *) NULL)
468 {
469 struct tui_gen_win_info * execInfoPtr = winInfo->detail.sourceInfo.executionInfo;
470
471 if (execInfoPtr->content == NULL)
472 execInfoPtr->content =
473 (void **) tui_alloc_content (winInfo->generic.height,
474 execInfoPtr->type);
475 if (execInfoPtr->content != NULL)
476 {
477 int i;
478
479 tui_update_breakpoint_info (winInfo, 1);
480 for (i = 0; i < winInfo->generic.contentSize; i++)
481 {
482 struct tui_win_element * element;
483 struct tui_win_element * srcElement;
484 int mode;
485
486 element = (struct tui_win_element *) execInfoPtr->content[i];
487 srcElement = (struct tui_win_element *) winInfo->generic.content[i];
488
489 memset(element->whichElement.simpleString, ' ',
490 sizeof(element->whichElement.simpleString));
491 element->whichElement.simpleString[TUI_EXECINFO_SIZE - 1] = 0;
492
493 /* Now update the exec info content based upon the state
494 of each line as indicated by the source content. */
495 mode = srcElement->whichElement.source.hasBreak;
496 if (mode & TUI_BP_HIT)
497 element->whichElement.simpleString[TUI_BP_HIT_POS] =
498 (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
499 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
500 element->whichElement.simpleString[TUI_BP_HIT_POS] =
501 (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
502
503 if (mode & TUI_BP_ENABLED)
504 element->whichElement.simpleString[TUI_BP_BREAK_POS] = '+';
505 else if (mode & TUI_BP_DISABLED)
506 element->whichElement.simpleString[TUI_BP_BREAK_POS] = '-';
507
508 if (srcElement->whichElement.source.isExecPoint)
509 element->whichElement.simpleString[TUI_EXEC_POS] = '>';
510 }
511 execInfoPtr->contentSize = winInfo->generic.contentSize;
512 }
513 else
514 ret = TUI_FAILURE;
515 }
516
517 return ret;
518 }
519
520
521 /*
522 ** tuiShowExecInfoContent().
523 */
524 void
525 tuiShowExecInfoContent (struct tui_win_info * winInfo)
526 {
527 struct tui_gen_win_info * execInfo = winInfo->detail.sourceInfo.executionInfo;
528 int curLine;
529
530 werase (execInfo->handle);
531 tui_refresh_win (execInfo);
532 for (curLine = 1; (curLine <= execInfo->contentSize); curLine++)
533 mvwaddstr (execInfo->handle,
534 curLine,
535 0,
536 ((struct tui_win_element *)
537 execInfo->content[curLine - 1])->whichElement.simpleString);
538 tui_refresh_win (execInfo);
539 execInfo->contentInUse = TRUE;
540
541 return;
542 }
543
544
545 void
546 tui_erase_exec_info_content (struct tui_win_info * winInfo)
547 {
548 struct tui_gen_win_info * execInfo = winInfo->detail.sourceInfo.executionInfo;
549
550 werase (execInfo->handle);
551 tui_refresh_win (execInfo);
552
553 return;
554 }
555
556 void
557 tui_clear_exec_info_content (struct tui_win_info * winInfo)
558 {
559 winInfo->detail.sourceInfo.executionInfo->contentInUse = FALSE;
560 tui_erase_exec_info_content (winInfo);
561
562 return;
563 }
564
565 /* Function to update the execution info window. */
566 void
567 tui_update_exec_info (struct tui_win_info * winInfo)
568 {
569 tuiSetExecInfoContent (winInfo);
570 tuiShowExecInfoContent (winInfo);
571 } /* tuiUpdateExecInfo */
572
573 enum tui_status
574 tui_alloc_source_buffer (struct tui_win_info *winInfo)
575 {
576 register char *srcLineBuf;
577 register int i, lineWidth, maxLines;
578 enum tui_status ret = TUI_FAILURE;
579
580 maxLines = winInfo->generic.height; /* less the highlight box */
581 lineWidth = winInfo->generic.width - 1;
582 /*
583 ** Allocate the buffer for the source lines. Do this only once since they
584 ** will be re-used for all source displays. The only other time this will
585 ** be done is when a window's size changes.
586 */
587 if (winInfo->generic.content == NULL)
588 {
589 srcLineBuf = (char *) xmalloc ((maxLines * lineWidth) * sizeof (char));
590 if (srcLineBuf == (char *) NULL)
591 fputs_unfiltered (
592 "Unable to Allocate Memory for Source or Disassembly Display.\n",
593 gdb_stderr);
594 else
595 {
596 /* allocate the content list */
597 if ((winInfo->generic.content =
598 (void **) tui_alloc_content (maxLines, SRC_WIN)) == NULL)
599 {
600 xfree (srcLineBuf);
601 srcLineBuf = (char *) NULL;
602 fputs_unfiltered (
603 "Unable to Allocate Memory for Source or Disassembly Display.\n",
604 gdb_stderr);
605 }
606 }
607 for (i = 0; i < maxLines; i++)
608 ((struct tui_win_element *)
609 winInfo->generic.content[i])->whichElement.source.line =
610 srcLineBuf + (lineWidth * i);
611 ret = TUI_SUCCESS;
612 }
613 else
614 ret = TUI_SUCCESS;
615
616 return ret;
617 } /* tuiAllocSourceBuffer */
618
619
620 /* Answer whether the a particular line number or address is displayed
621 in the current source window. */
622 int
623 tui_line_is_displayed (int line, struct tui_win_info * winInfo,
624 int checkThreshold)
625 {
626 int isDisplayed = FALSE;
627 int i, threshold;
628
629 if (checkThreshold)
630 threshold = SCROLL_THRESHOLD;
631 else
632 threshold = 0;
633 i = 0;
634 while (i < winInfo->generic.contentSize - threshold && !isDisplayed)
635 {
636 isDisplayed = (((struct tui_win_element *)
637 winInfo->generic.content[i])->whichElement.source.lineOrAddr.lineNo
638 == (int) line);
639 i++;
640 }
641
642 return isDisplayed;
643 }
644
645
646 /* Answer whether the a particular line number or address is displayed
647 in the current source window. */
648 int
649 tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info * winInfo,
650 int checkThreshold)
651 {
652 int isDisplayed = FALSE;
653 int i, threshold;
654
655 if (checkThreshold)
656 threshold = SCROLL_THRESHOLD;
657 else
658 threshold = 0;
659 i = 0;
660 while (i < winInfo->generic.contentSize - threshold && !isDisplayed)
661 {
662 isDisplayed = (((struct tui_win_element *)
663 winInfo->generic.content[i])->whichElement.source.lineOrAddr.addr
664 == addr);
665 i++;
666 }
667
668 return isDisplayed;
669 }
670
671
672 /*****************************************
673 ** STATIC LOCAL FUNCTIONS **
674 ******************************************/