2004-02-07 Andrew Cagney <cagney@redhat.com>
[deliverable/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 * win_info, struct symtab *s,
79 union tui_line_or_address line_or_addr, int noerror)
80 {
81 win_info->detail.source_info.horizontal_offset = 0;
82 tui_update_source_window_as_is (win_info, s, line_or_addr, 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 * win_info, struct symtab *s,
92 union tui_line_or_address line_or_addr, int noerror)
93 {
94 enum tui_status ret;
95
96 if (win_info->generic.type == SRC_WIN)
97 ret = tui_set_source_content (s, line_or_addr.line_no, noerror);
98 else
99 ret = tui_set_disassem_content (line_or_addr.addr);
100
101 if (ret == TUI_FAILURE)
102 {
103 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
104 tui_clear_exec_info_content (win_info);
105 }
106 else
107 {
108 tui_update_breakpoint_info (win_info, 0);
109 tui_show_source_content (win_info);
110 tui_update_exec_info (win_info);
111 if (win_info->generic.type == SRC_WIN)
112 {
113 struct symtab_and_line sal;
114
115 sal.line = line_or_addr.line_no +
116 (win_info->generic.content_size - 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 () == TUI_DISASM_WIN &&
124 tui_current_layout () != SRC_DISASSEM_COMMAND)
125 tui_set_win_focus_to (TUI_SRC_WIN);
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.line_no = 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 * win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
167
168 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
169 tui_clear_exec_info_content (win_info);
170 }
171 }
172 }
173
174 /* Function to ensure that the source and/or disassemly windows
175 reflect the input address. */
176 void
177 tui_update_source_windows_with_line (struct symtab *s, int line)
178 {
179 CORE_ADDR pc;
180 union tui_line_or_address l;
181
182 switch (tui_current_layout ())
183 {
184 case DISASSEM_COMMAND:
185 case DISASSEM_DATA_COMMAND:
186 find_line_pc (s, line, &pc);
187 tui_update_source_windows_with_addr (pc);
188 break;
189 default:
190 l.line_no = line;
191 tui_show_symtab_source (s, l, FALSE);
192 if (tui_current_layout () == SRC_DISASSEM_COMMAND)
193 {
194 find_line_pc (s, line, &pc);
195 tui_show_disassem (pc);
196 }
197 break;
198 }
199
200 return;
201 }
202
203 void
204 tui_clear_source_content (struct tui_win_info * win_info, int display_prompt)
205 {
206 if (win_info != NULL)
207 {
208 register int i;
209
210 win_info->generic.content_in_use = FALSE;
211 tui_erase_source_content (win_info, display_prompt);
212 for (i = 0; i < win_info->generic.content_size; i++)
213 {
214 struct tui_win_element * element =
215 (struct tui_win_element *) win_info->generic.content[i];
216 element->which_element.source.has_break = FALSE;
217 element->which_element.source.is_exec_point = FALSE;
218 }
219 }
220 }
221
222
223 void
224 tui_erase_source_content (struct tui_win_info * win_info, int display_prompt)
225 {
226 int x_pos;
227 int half_width = (win_info->generic.width - 2) / 2;
228
229 if (win_info->generic.handle != (WINDOW *) NULL)
230 {
231 werase (win_info->generic.handle);
232 tui_check_and_display_highlight_if_needed (win_info);
233 if (display_prompt == EMPTY_SOURCE_PROMPT)
234 {
235 char *no_src_str;
236
237 if (win_info->generic.type == SRC_WIN)
238 no_src_str = NO_SRC_STRING;
239 else
240 no_src_str = NO_DISASSEM_STRING;
241 if (strlen (no_src_str) >= half_width)
242 x_pos = 1;
243 else
244 x_pos = half_width - strlen (no_src_str);
245 mvwaddstr (win_info->generic.handle,
246 (win_info->generic.height / 2),
247 x_pos,
248 no_src_str);
249
250 /* elz: added this function call to set the real contents of
251 the window to what is on the screen, so that later calls
252 to refresh, do display
253 the correct stuff, and not the old image */
254
255 tui_set_source_content_nil (win_info, no_src_str);
256 }
257 tui_refresh_win (&win_info->generic);
258 }
259 }
260
261
262 /* Redraw the complete line of a source or disassembly window. */
263 static void
264 tui_show_source_line (struct tui_win_info * win_info, int lineno)
265 {
266 struct tui_win_element * line;
267 int x, y;
268
269 line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
270 if (line->which_element.source.is_exec_point)
271 wattron (win_info->generic.handle, A_STANDOUT);
272
273 mvwaddstr (win_info->generic.handle, lineno, 1,
274 line->which_element.source.line);
275 if (line->which_element.source.is_exec_point)
276 wattroff (win_info->generic.handle, A_STANDOUT);
277
278 /* Clear to end of line but stop before the border. */
279 getyx (win_info->generic.handle, y, x);
280 while (x + 1 < win_info->generic.width)
281 {
282 waddch (win_info->generic.handle, ' ');
283 getyx (win_info->generic.handle, y, x);
284 }
285 }
286
287 void
288 tui_show_source_content (struct tui_win_info * win_info)
289 {
290 if (win_info->generic.content_size > 0)
291 {
292 int lineno;
293
294 for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
295 tui_show_source_line (win_info, lineno);
296 }
297 else
298 tui_erase_source_content (win_info, TRUE);
299
300 tui_check_and_display_highlight_if_needed (win_info);
301 tui_refresh_win (&win_info->generic);
302 win_info->generic.content_in_use = TRUE;
303 }
304
305
306 /* Scroll the source forward or backward horizontally. */
307 void
308 tui_horizontal_source_scroll (struct tui_win_info * win_info,
309 enum tui_scroll_direction direction,
310 int num_to_scroll)
311 {
312 if (win_info->generic.content != NULL)
313 {
314 int offset;
315 struct symtab *s;
316 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
317
318 if (cursal.symtab == (struct symtab *) NULL)
319 s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
320 else
321 s = cursal.symtab;
322
323 if (direction == LEFT_SCROLL)
324 offset = win_info->detail.source_info.horizontal_offset + num_to_scroll;
325 else
326 {
327 if ((offset =
328 win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0)
329 offset = 0;
330 }
331 win_info->detail.source_info.horizontal_offset = offset;
332 tui_update_source_window_as_is (win_info, s,
333 ((struct tui_win_element *)
334 win_info->generic.content[0])->which_element.source.line_or_addr,
335 FALSE);
336 }
337
338 return;
339 }
340
341
342 /* Set or clear the has_break flag in the line whose line is line_no. */
343 void
344 tui_set_is_exec_point_at (union tui_line_or_address l, struct tui_win_info * win_info)
345 {
346 int changed = 0;
347 int i;
348 tui_win_content content = (tui_win_content) win_info->generic.content;
349
350 i = 0;
351 while (i < win_info->generic.content_size)
352 {
353 int new_state;
354
355 if (content[i]->which_element.source.line_or_addr.addr == l.addr)
356 new_state = TRUE;
357 else
358 new_state = FALSE;
359 if (new_state != content[i]->which_element.source.is_exec_point)
360 {
361 changed++;
362 content[i]->which_element.source.is_exec_point = new_state;
363 tui_show_source_line (win_info, i + 1);
364 }
365 i++;
366 }
367 if (changed)
368 tui_refresh_win (&win_info->generic);
369 }
370
371 /* Update the execution windows to show the active breakpoints.
372 This is called whenever a breakpoint is inserted, removed or
373 has its state changed. */
374 void
375 tui_update_all_breakpoint_info ()
376 {
377 struct tui_list *list = tui_source_windows ();
378 int i;
379
380 for (i = 0; i < list->count; i++)
381 {
382 struct tui_win_info * win = (struct tui_win_info *) list->list[i];
383
384 if (tui_update_breakpoint_info (win, FALSE))
385 {
386 tui_update_exec_info (win);
387 }
388 }
389 }
390
391
392 /* Scan the source window and the breakpoints to update the
393 has_break information for each line.
394 Returns 1 if something changed and the execution window
395 must be refreshed. */
396 int
397 tui_update_breakpoint_info (struct tui_win_info * win, int current_only)
398 {
399 int i;
400 int need_refresh = 0;
401 struct tui_source_info * src = &win->detail.source_info;
402
403 for (i = 0; i < win->generic.content_size; i++)
404 {
405 struct breakpoint *bp;
406 extern struct breakpoint *breakpoint_chain;
407 int mode;
408 struct tui_source_element* line;
409
410 line = &((struct tui_win_element *) win->generic.content[i])->which_element.source;
411 if (current_only && !line->is_exec_point)
412 continue;
413
414 /* Scan each breakpoint to see if the current line has something to
415 do with it. Identify enable/disabled breakpoints as well as
416 those that we already hit. */
417 mode = 0;
418 for (bp = breakpoint_chain;
419 bp != (struct breakpoint *) NULL;
420 bp = bp->next)
421 {
422 if ((win == TUI_SRC_WIN
423 && bp->source_file
424 && (strcmp (src->filename, bp->source_file) == 0)
425 && bp->line_number == line->line_or_addr.line_no)
426 || (win == TUI_DISASM_WIN
427 && bp->loc->address == line->line_or_addr.addr))
428 {
429 if (bp->enable_state == bp_disabled)
430 mode |= TUI_BP_DISABLED;
431 else
432 mode |= TUI_BP_ENABLED;
433 if (bp->hit_count)
434 mode |= TUI_BP_HIT;
435 if (bp->cond)
436 mode |= TUI_BP_CONDITIONAL;
437 if (bp->type == bp_hardware_breakpoint)
438 mode |= TUI_BP_HARDWARE;
439 }
440 }
441 if (line->has_break != mode)
442 {
443 line->has_break = mode;
444 need_refresh = 1;
445 }
446 }
447 return need_refresh;
448 }
449
450
451 /* Function to initialize the content of the execution info window,
452 based upon the input window which is either the source or
453 disassembly window. */
454 enum tui_status
455 tui_set_exec_info_content (struct tui_win_info * win_info)
456 {
457 enum tui_status ret = TUI_SUCCESS;
458
459 if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL)
460 {
461 struct tui_gen_win_info * exec_info_ptr = win_info->detail.source_info.execution_info;
462
463 if (exec_info_ptr->content == NULL)
464 exec_info_ptr->content =
465 (void **) tui_alloc_content (win_info->generic.height,
466 exec_info_ptr->type);
467 if (exec_info_ptr->content != NULL)
468 {
469 int i;
470
471 tui_update_breakpoint_info (win_info, 1);
472 for (i = 0; i < win_info->generic.content_size; i++)
473 {
474 struct tui_win_element * element;
475 struct tui_win_element * src_element;
476 int mode;
477
478 element = (struct tui_win_element *) exec_info_ptr->content[i];
479 src_element = (struct tui_win_element *) win_info->generic.content[i];
480
481 memset(element->which_element.simple_string, ' ',
482 sizeof(element->which_element.simple_string));
483 element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
484
485 /* Now update the exec info content based upon the state
486 of each line as indicated by the source content. */
487 mode = src_element->which_element.source.has_break;
488 if (mode & TUI_BP_HIT)
489 element->which_element.simple_string[TUI_BP_HIT_POS] =
490 (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
491 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
492 element->which_element.simple_string[TUI_BP_HIT_POS] =
493 (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
494
495 if (mode & TUI_BP_ENABLED)
496 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
497 else if (mode & TUI_BP_DISABLED)
498 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
499
500 if (src_element->which_element.source.is_exec_point)
501 element->which_element.simple_string[TUI_EXEC_POS] = '>';
502 }
503 exec_info_ptr->content_size = win_info->generic.content_size;
504 }
505 else
506 ret = TUI_FAILURE;
507 }
508
509 return ret;
510 }
511
512
513 void
514 tui_show_exec_info_content (struct tui_win_info * win_info)
515 {
516 struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
517 int cur_line;
518
519 werase (exec_info->handle);
520 tui_refresh_win (exec_info);
521 for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
522 mvwaddstr (exec_info->handle,
523 cur_line,
524 0,
525 ((struct tui_win_element *)
526 exec_info->content[cur_line - 1])->which_element.simple_string);
527 tui_refresh_win (exec_info);
528 exec_info->content_in_use = TRUE;
529 }
530
531
532 void
533 tui_erase_exec_info_content (struct tui_win_info * win_info)
534 {
535 struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
536
537 werase (exec_info->handle);
538 tui_refresh_win (exec_info);
539 }
540
541 void
542 tui_clear_exec_info_content (struct tui_win_info * win_info)
543 {
544 win_info->detail.source_info.execution_info->content_in_use = FALSE;
545 tui_erase_exec_info_content (win_info);
546
547 return;
548 }
549
550 /* Function to update the execution info window. */
551 void
552 tui_update_exec_info (struct tui_win_info * win_info)
553 {
554 tui_set_exec_info_content (win_info);
555 tui_show_exec_info_content (win_info);
556 }
557
558 enum tui_status
559 tui_alloc_source_buffer (struct tui_win_info *win_info)
560 {
561 register char *src_line_buf;
562 register int i, line_width, max_lines;
563 enum tui_status ret = TUI_FAILURE;
564
565 max_lines = win_info->generic.height; /* less the highlight box */
566 line_width = win_info->generic.width - 1;
567 /*
568 ** Allocate the buffer for the source lines. Do this only once since they
569 ** will be re-used for all source displays. The only other time this will
570 ** be done is when a window's size changes.
571 */
572 if (win_info->generic.content == NULL)
573 {
574 src_line_buf = (char *) xmalloc ((max_lines * line_width) * sizeof (char));
575 if (src_line_buf == (char *) NULL)
576 fputs_unfiltered (
577 "Unable to Allocate Memory for Source or Disassembly Display.\n",
578 gdb_stderr);
579 else
580 {
581 /* allocate the content list */
582 if ((win_info->generic.content =
583 (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
584 {
585 xfree (src_line_buf);
586 src_line_buf = (char *) NULL;
587 fputs_unfiltered (
588 "Unable to Allocate Memory for Source or Disassembly Display.\n",
589 gdb_stderr);
590 }
591 }
592 for (i = 0; i < max_lines; i++)
593 ((struct tui_win_element *)
594 win_info->generic.content[i])->which_element.source.line =
595 src_line_buf + (line_width * i);
596 ret = TUI_SUCCESS;
597 }
598 else
599 ret = TUI_SUCCESS;
600
601 return ret;
602 }
603
604
605 /* Answer whether the a particular line number or address is displayed
606 in the current source window. */
607 int
608 tui_line_is_displayed (int line, struct tui_win_info * win_info,
609 int check_threshold)
610 {
611 int is_displayed = FALSE;
612 int i, threshold;
613
614 if (check_threshold)
615 threshold = SCROLL_THRESHOLD;
616 else
617 threshold = 0;
618 i = 0;
619 while (i < win_info->generic.content_size - threshold && !is_displayed)
620 {
621 is_displayed = (((struct tui_win_element *)
622 win_info->generic.content[i])->which_element.source.line_or_addr.line_no
623 == (int) line);
624 i++;
625 }
626
627 return is_displayed;
628 }
629
630
631 /* Answer whether the a particular line number or address is displayed
632 in the current source window. */
633 int
634 tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info * win_info,
635 int check_threshold)
636 {
637 int is_displayed = FALSE;
638 int i, threshold;
639
640 if (check_threshold)
641 threshold = SCROLL_THRESHOLD;
642 else
643 threshold = 0;
644 i = 0;
645 while (i < win_info->generic.content_size - threshold && !is_displayed)
646 {
647 is_displayed = (((struct tui_win_element *)
648 win_info->generic.content[i])->which_element.source.line_or_addr.addr
649 == addr);
650 i++;
651 }
652
653 return is_displayed;
654 }
655
656
657 /*****************************************
658 ** STATIC LOCAL FUNCTIONS **
659 ******************************************/
This page took 0.042939 seconds and 5 git commands to generate.