2007-08-14 Michael Snyder <msnyder@access-company.com>
[binutils-gdb.git] / gdb / tui / tui-winsource.c
1 /* TUI display source/assembly window.
2
3 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007
4 Free Software 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., 51 Franklin Street, Fifth Floor,
23 Boston, MA 02110-1301, 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 #include "gdb_string.h"
43 #include "gdb_curses.h"
44 #include "gdb_assert.h"
45
46 /* Function to display the "main" routine. */
47 void
48 tui_display_main (void)
49 {
50 if ((tui_source_windows ())->count > 0)
51 {
52 CORE_ADDR addr;
53
54 addr = tui_get_begin_asm_address ();
55 if (addr != (CORE_ADDR) 0)
56 {
57 struct symtab_and_line sal;
58
59 tui_update_source_windows_with_addr (addr);
60 sal = find_pc_line (addr, 0);
61 if (sal.symtab)
62 tui_update_locator_filename (sal.symtab->filename);
63 else
64 tui_update_locator_filename ("??");
65 }
66 }
67 }
68
69
70
71 /* Function to display source in the source window. This function
72 initializes the horizontal scroll to 0. */
73 void
74 tui_update_source_window (struct tui_win_info *win_info, struct symtab *s,
75 struct tui_line_or_address line_or_addr, int noerror)
76 {
77 win_info->detail.source_info.horizontal_offset = 0;
78 tui_update_source_window_as_is (win_info, s, line_or_addr, noerror);
79
80 return;
81 }
82
83
84 /* Function to display source in the source/asm window. This function
85 shows the source as specified by the horizontal offset. */
86 void
87 tui_update_source_window_as_is (struct tui_win_info *win_info, struct symtab *s,
88 struct tui_line_or_address line_or_addr, int noerror)
89 {
90 enum tui_status ret;
91
92 if (win_info->generic.type == SRC_WIN)
93 ret = tui_set_source_content (s, line_or_addr.u.line_no, noerror);
94 else
95 ret = tui_set_disassem_content (line_or_addr.u.addr);
96
97 if (ret == TUI_FAILURE)
98 {
99 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
100 tui_clear_exec_info_content (win_info);
101 }
102 else
103 {
104 tui_update_breakpoint_info (win_info, 0);
105 tui_show_source_content (win_info);
106 tui_update_exec_info (win_info);
107 if (win_info->generic.type == SRC_WIN)
108 {
109 struct symtab_and_line sal;
110
111 sal.line = line_or_addr.u.line_no +
112 (win_info->generic.content_size - 2);
113 sal.symtab = s;
114 set_current_source_symtab_and_line (&sal);
115 /* If the focus was in the asm win, put it in the src win if
116 we don't have a split layout. */
117 if (tui_win_with_focus () == TUI_DISASM_WIN &&
118 tui_current_layout () != SRC_DISASSEM_COMMAND)
119 tui_set_win_focus_to (TUI_SRC_WIN);
120 }
121 }
122
123
124 return;
125 }
126
127
128 /* Function to ensure that the source and/or disassemly windows
129 reflect the input address. */
130 void
131 tui_update_source_windows_with_addr (CORE_ADDR addr)
132 {
133 if (addr != 0)
134 {
135 struct symtab_and_line sal;
136 struct tui_line_or_address l;
137
138 switch (tui_current_layout ())
139 {
140 case DISASSEM_COMMAND:
141 case DISASSEM_DATA_COMMAND:
142 tui_show_disassem (addr);
143 break;
144 case SRC_DISASSEM_COMMAND:
145 tui_show_disassem_and_update_source (addr);
146 break;
147 default:
148 sal = find_pc_line (addr, 0);
149 l.loa = LOA_LINE;
150 l.u.line_no = sal.line;
151 tui_show_symtab_source (sal.symtab, l, FALSE);
152 break;
153 }
154 }
155 else
156 {
157 int i;
158
159 for (i = 0; i < (tui_source_windows ())->count; i++)
160 {
161 struct tui_win_info *win_info = (tui_source_windows ())->list[i];
162
163 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
164 tui_clear_exec_info_content (win_info);
165 }
166 }
167 }
168
169 /* Function to ensure that the source and/or disassemly windows
170 reflect the input address. */
171 void
172 tui_update_source_windows_with_line (struct symtab *s, int line)
173 {
174 CORE_ADDR pc;
175 struct tui_line_or_address l;
176
177 switch (tui_current_layout ())
178 {
179 case DISASSEM_COMMAND:
180 case DISASSEM_DATA_COMMAND:
181 find_line_pc (s, line, &pc);
182 tui_update_source_windows_with_addr (pc);
183 break;
184 default:
185 l.loa = LOA_LINE;
186 l.u.line_no = line;
187 tui_show_symtab_source (s, l, FALSE);
188 if (tui_current_layout () == SRC_DISASSEM_COMMAND)
189 {
190 find_line_pc (s, line, &pc);
191 tui_show_disassem (pc);
192 }
193 break;
194 }
195
196 return;
197 }
198
199 void
200 tui_clear_source_content (struct tui_win_info *win_info, int display_prompt)
201 {
202 if (win_info != NULL)
203 {
204 int i;
205
206 win_info->generic.content_in_use = FALSE;
207 tui_erase_source_content (win_info, display_prompt);
208 for (i = 0; i < win_info->generic.content_size; i++)
209 {
210 struct tui_win_element *element =
211 (struct tui_win_element *) win_info->generic.content[i];
212 element->which_element.source.has_break = FALSE;
213 element->which_element.source.is_exec_point = FALSE;
214 }
215 }
216 }
217
218
219 void
220 tui_erase_source_content (struct tui_win_info *win_info, int display_prompt)
221 {
222 int x_pos;
223 int half_width = (win_info->generic.width - 2) / 2;
224
225 if (win_info->generic.handle != (WINDOW *) NULL)
226 {
227 werase (win_info->generic.handle);
228 tui_check_and_display_highlight_if_needed (win_info);
229 if (display_prompt == EMPTY_SOURCE_PROMPT)
230 {
231 char *no_src_str;
232
233 if (win_info->generic.type == SRC_WIN)
234 no_src_str = NO_SRC_STRING;
235 else
236 no_src_str = NO_DISASSEM_STRING;
237 if (strlen (no_src_str) >= half_width)
238 x_pos = 1;
239 else
240 x_pos = half_width - strlen (no_src_str);
241 mvwaddstr (win_info->generic.handle,
242 (win_info->generic.height / 2),
243 x_pos,
244 no_src_str);
245
246 /* elz: Added this function call to set the real contents of
247 the window to what is on the screen, so that later calls
248 to refresh, do display the correct stuff, and not the old
249 image. */
250
251 tui_set_source_content_nil (win_info, no_src_str);
252 }
253 tui_refresh_win (&win_info->generic);
254 }
255 }
256
257
258 /* Redraw the complete line of a source or disassembly window. */
259 static void
260 tui_show_source_line (struct tui_win_info *win_info, int lineno)
261 {
262 struct tui_win_element *line;
263 int x, y;
264
265 line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
266 if (line->which_element.source.is_exec_point)
267 wattron (win_info->generic.handle, A_STANDOUT);
268
269 mvwaddstr (win_info->generic.handle, lineno, 1,
270 line->which_element.source.line);
271 if (line->which_element.source.is_exec_point)
272 wattroff (win_info->generic.handle, A_STANDOUT);
273
274 /* Clear to end of line but stop before the border. */
275 getyx (win_info->generic.handle, y, x);
276 while (x + 1 < win_info->generic.width)
277 {
278 waddch (win_info->generic.handle, ' ');
279 getyx (win_info->generic.handle, y, x);
280 }
281 }
282
283 void
284 tui_show_source_content (struct tui_win_info *win_info)
285 {
286 if (win_info->generic.content_size > 0)
287 {
288 int lineno;
289
290 for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
291 tui_show_source_line (win_info, lineno);
292 }
293 else
294 tui_erase_source_content (win_info, TRUE);
295
296 tui_check_and_display_highlight_if_needed (win_info);
297 tui_refresh_win (&win_info->generic);
298 win_info->generic.content_in_use = TRUE;
299 }
300
301
302 /* Scroll the source forward or backward horizontally. */
303 void
304 tui_horizontal_source_scroll (struct tui_win_info *win_info,
305 enum tui_scroll_direction direction,
306 int num_to_scroll)
307 {
308 if (win_info->generic.content != NULL)
309 {
310 int offset;
311 struct symtab *s;
312 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
313
314 if (cursal.symtab == (struct symtab *) NULL)
315 s = find_pc_symtab (get_frame_pc (get_selected_frame (NULL)));
316 else
317 s = cursal.symtab;
318
319 if (direction == LEFT_SCROLL)
320 offset = win_info->detail.source_info.horizontal_offset + num_to_scroll;
321 else
322 {
323 if ((offset =
324 win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0)
325 offset = 0;
326 }
327 win_info->detail.source_info.horizontal_offset = offset;
328 tui_update_source_window_as_is (win_info, s,
329 ((struct tui_win_element *)
330 win_info->generic.content[0])->which_element.source.line_or_addr,
331 FALSE);
332 }
333
334 return;
335 }
336
337
338 /* Set or clear the has_break flag in the line whose line is
339 line_no. */
340
341 void
342 tui_set_is_exec_point_at (struct tui_line_or_address l, struct tui_win_info *win_info)
343 {
344 int changed = 0;
345 int i;
346 tui_win_content content = (tui_win_content) win_info->generic.content;
347
348 i = 0;
349 while (i < win_info->generic.content_size)
350 {
351 int new_state;
352 struct tui_line_or_address content_loa =
353 content[i]->which_element.source.line_or_addr;
354
355 gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE);
356 gdb_assert (content_loa.loa == LOA_LINE
357 || content_loa.loa == LOA_ADDRESS);
358 if (content_loa.loa == l.loa
359 && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
360 || (content_loa.u.addr == l.u.addr)))
361 new_state = TRUE;
362 else
363 new_state = FALSE;
364 if (new_state != content[i]->which_element.source.is_exec_point)
365 {
366 changed++;
367 content[i]->which_element.source.is_exec_point = new_state;
368 tui_show_source_line (win_info, i + 1);
369 }
370 i++;
371 }
372 if (changed)
373 tui_refresh_win (&win_info->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 (void)
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 = 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 has_break
398 information for each line.
399
400 Returns 1 if something changed and the execution window must be
401 refreshed. */
402
403 int
404 tui_update_breakpoint_info (struct tui_win_info *win, int current_only)
405 {
406 int i;
407 int need_refresh = 0;
408 struct tui_source_info *src = &win->detail.source_info;
409
410 for (i = 0; i < win->generic.content_size; i++)
411 {
412 struct breakpoint *bp;
413 extern struct breakpoint *breakpoint_chain;
414 int mode;
415 struct tui_source_element *line;
416
417 line = &((struct tui_win_element *) win->generic.content[i])->which_element.source;
418 if (current_only && !line->is_exec_point)
419 continue;
420
421 /* Scan each breakpoint to see if the current line has something to
422 do with it. Identify enable/disabled breakpoints as well as
423 those that we already hit. */
424 mode = 0;
425 for (bp = breakpoint_chain;
426 bp != (struct breakpoint *) NULL;
427 bp = bp->next)
428 {
429 gdb_assert (line->line_or_addr.loa == LOA_LINE
430 || line->line_or_addr.loa == LOA_ADDRESS);
431 if ((win == TUI_SRC_WIN
432 && bp->source_file
433 && (strcmp (src->filename, bp->source_file) == 0)
434 && line->line_or_addr.loa == LOA_LINE
435 && bp->line_number == line->line_or_addr.u.line_no)
436 || (win == TUI_DISASM_WIN
437 && line->line_or_addr.loa == LOA_ADDRESS
438 && bp->loc->address == line->line_or_addr.u.addr))
439 {
440 if (bp->enable_state == bp_disabled)
441 mode |= TUI_BP_DISABLED;
442 else
443 mode |= TUI_BP_ENABLED;
444 if (bp->hit_count)
445 mode |= TUI_BP_HIT;
446 if (bp->cond)
447 mode |= TUI_BP_CONDITIONAL;
448 if (bp->type == bp_hardware_breakpoint)
449 mode |= TUI_BP_HARDWARE;
450 }
451 }
452 if (line->has_break != mode)
453 {
454 line->has_break = mode;
455 need_refresh = 1;
456 }
457 }
458 return need_refresh;
459 }
460
461
462 /* Function to initialize the content of the execution info window,
463 based upon the input window which is either the source or
464 disassembly window. */
465 enum tui_status
466 tui_set_exec_info_content (struct tui_win_info *win_info)
467 {
468 enum tui_status ret = TUI_SUCCESS;
469
470 if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL)
471 {
472 struct tui_gen_win_info *exec_info_ptr = win_info->detail.source_info.execution_info;
473
474 if (exec_info_ptr->content == NULL)
475 exec_info_ptr->content =
476 (void **) tui_alloc_content (win_info->generic.height,
477 exec_info_ptr->type);
478 if (exec_info_ptr->content != NULL)
479 {
480 int i;
481
482 tui_update_breakpoint_info (win_info, 1);
483 for (i = 0; i < win_info->generic.content_size; i++)
484 {
485 struct tui_win_element *element;
486 struct tui_win_element *src_element;
487 int mode;
488
489 element = (struct tui_win_element *) exec_info_ptr->content[i];
490 src_element = (struct tui_win_element *) win_info->generic.content[i];
491
492 memset(element->which_element.simple_string, ' ',
493 sizeof(element->which_element.simple_string));
494 element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
495
496 /* Now update the exec info content based upon the state
497 of each line as indicated by the source content. */
498 mode = src_element->which_element.source.has_break;
499 if (mode & TUI_BP_HIT)
500 element->which_element.simple_string[TUI_BP_HIT_POS] =
501 (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
502 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
503 element->which_element.simple_string[TUI_BP_HIT_POS] =
504 (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
505
506 if (mode & TUI_BP_ENABLED)
507 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
508 else if (mode & TUI_BP_DISABLED)
509 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
510
511 if (src_element->which_element.source.is_exec_point)
512 element->which_element.simple_string[TUI_EXEC_POS] = '>';
513 }
514 exec_info_ptr->content_size = win_info->generic.content_size;
515 }
516 else
517 ret = TUI_FAILURE;
518 }
519
520 return ret;
521 }
522
523
524 void
525 tui_show_exec_info_content (struct tui_win_info *win_info)
526 {
527 struct tui_gen_win_info *exec_info = win_info->detail.source_info.execution_info;
528 int cur_line;
529
530 werase (exec_info->handle);
531 tui_refresh_win (exec_info);
532 for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
533 mvwaddstr (exec_info->handle,
534 cur_line,
535 0,
536 ((struct tui_win_element *)
537 exec_info->content[cur_line - 1])->which_element.simple_string);
538 tui_refresh_win (exec_info);
539 exec_info->content_in_use = TRUE;
540 }
541
542
543 void
544 tui_erase_exec_info_content (struct tui_win_info *win_info)
545 {
546 struct tui_gen_win_info *exec_info = win_info->detail.source_info.execution_info;
547
548 werase (exec_info->handle);
549 tui_refresh_win (exec_info);
550 }
551
552 void
553 tui_clear_exec_info_content (struct tui_win_info *win_info)
554 {
555 win_info->detail.source_info.execution_info->content_in_use = FALSE;
556 tui_erase_exec_info_content (win_info);
557
558 return;
559 }
560
561 /* Function to update the execution info window. */
562 void
563 tui_update_exec_info (struct tui_win_info *win_info)
564 {
565 tui_set_exec_info_content (win_info);
566 tui_show_exec_info_content (win_info);
567 }
568
569 enum tui_status
570 tui_alloc_source_buffer (struct tui_win_info *win_info)
571 {
572 char *src_line_buf;
573 int i, line_width, max_lines;
574
575 max_lines = win_info->generic.height; /* Less the highlight box. */
576 line_width = win_info->generic.width - 1;
577 /*
578 * Allocate the buffer for the source lines. Do this only once
579 * since they will be re-used for all source displays. The only
580 * other time this will be done is when a window's size changes.
581 */
582 if (win_info->generic.content == NULL)
583 {
584 src_line_buf = (char *)
585 xmalloc ((max_lines * line_width) * sizeof (char));
586 if (src_line_buf == (char *) NULL)
587 {
588 fputs_unfiltered ("Unable to Allocate Memory for Source or Disassembly Display.\n",
589 gdb_stderr);
590 return TUI_FAILURE;
591 }
592 /* Allocate the content list. */
593 if ((win_info->generic.content =
594 (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
595 {
596 xfree (src_line_buf);
597 fputs_unfiltered ("Unable to Allocate Memory for Source or Disassembly Display.\n",
598 gdb_stderr);
599 return TUI_FAILURE;
600 }
601 for (i = 0; i < max_lines; i++)
602 ((struct tui_win_element *)
603 win_info->generic.content[i])->which_element.source.line =
604 src_line_buf + (line_width * i);
605 }
606
607 return TUI_SUCCESS;
608 }
609
610
611 /* Answer whether the a particular line number or address is displayed
612 in the current source window. */
613 int
614 tui_line_is_displayed (int line, struct tui_win_info *win_info,
615 int check_threshold)
616 {
617 int is_displayed = FALSE;
618 int i, threshold;
619
620 if (check_threshold)
621 threshold = SCROLL_THRESHOLD;
622 else
623 threshold = 0;
624 i = 0;
625 while (i < win_info->generic.content_size - threshold && !is_displayed)
626 {
627 is_displayed = (((struct tui_win_element *)
628 win_info->generic.content[i])->which_element.source.line_or_addr.loa
629 == LOA_LINE)
630 && (((struct tui_win_element *)
631 win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no
632 == (int) line);
633 i++;
634 }
635
636 return is_displayed;
637 }
638
639
640 /* Answer whether the a particular line number or address is displayed
641 in the current source window. */
642 int
643 tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info *win_info,
644 int check_threshold)
645 {
646 int is_displayed = FALSE;
647 int i, threshold;
648
649 if (check_threshold)
650 threshold = SCROLL_THRESHOLD;
651 else
652 threshold = 0;
653 i = 0;
654 while (i < win_info->generic.content_size - threshold && !is_displayed)
655 {
656 is_displayed = (((struct tui_win_element *)
657 win_info->generic.content[i])->which_element.source.line_or_addr.loa
658 == LOA_ADDRESS)
659 && (((struct tui_win_element *)
660 win_info->generic.content[i])->which_element.source.line_or_addr.u.addr
661 == addr);
662 i++;
663 }
664
665 return is_displayed;
666 }
667
668
669 /*****************************************
670 ** STATIC LOCAL FUNCTIONS **
671 ******************************************/