]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui-winsource.c
Copyright updates for 2007.
[thirdparty/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 /*
116 ** If the focus was in the asm win, put it in the src
117 ** win if we don't have a split layout
118 */
119 if (tui_win_with_focus () == TUI_DISASM_WIN &&
120 tui_current_layout () != SRC_DISASSEM_COMMAND)
121 tui_set_win_focus_to (TUI_SRC_WIN);
122 }
123 }
124
125
126 return;
127 }
128
129
130 /* Function to ensure that the source and/or disassemly windows
131 reflect the input address. */
132 void
133 tui_update_source_windows_with_addr (CORE_ADDR addr)
134 {
135 if (addr != 0)
136 {
137 struct symtab_and_line sal;
138 struct tui_line_or_address l;
139
140 switch (tui_current_layout ())
141 {
142 case DISASSEM_COMMAND:
143 case DISASSEM_DATA_COMMAND:
144 tui_show_disassem (addr);
145 break;
146 case SRC_DISASSEM_COMMAND:
147 tui_show_disassem_and_update_source (addr);
148 break;
149 default:
150 sal = find_pc_line (addr, 0);
151 l.loa = LOA_LINE;
152 l.u.line_no = sal.line;
153 tui_show_symtab_source (sal.symtab, l, FALSE);
154 break;
155 }
156 }
157 else
158 {
159 int i;
160
161 for (i = 0; i < (tui_source_windows ())->count; i++)
162 {
163 struct tui_win_info * win_info = (tui_source_windows ())->list[i];
164
165 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
166 tui_clear_exec_info_content (win_info);
167 }
168 }
169 }
170
171 /* Function to ensure that the source and/or disassemly windows
172 reflect the input address. */
173 void
174 tui_update_source_windows_with_line (struct symtab *s, int line)
175 {
176 CORE_ADDR pc;
177 struct tui_line_or_address l;
178
179 switch (tui_current_layout ())
180 {
181 case DISASSEM_COMMAND:
182 case DISASSEM_DATA_COMMAND:
183 find_line_pc (s, line, &pc);
184 tui_update_source_windows_with_addr (pc);
185 break;
186 default:
187 l.loa = LOA_LINE;
188 l.u.line_no = line;
189 tui_show_symtab_source (s, l, FALSE);
190 if (tui_current_layout () == SRC_DISASSEM_COMMAND)
191 {
192 find_line_pc (s, line, &pc);
193 tui_show_disassem (pc);
194 }
195 break;
196 }
197
198 return;
199 }
200
201 void
202 tui_clear_source_content (struct tui_win_info * win_info, int display_prompt)
203 {
204 if (win_info != NULL)
205 {
206 int i;
207
208 win_info->generic.content_in_use = FALSE;
209 tui_erase_source_content (win_info, display_prompt);
210 for (i = 0; i < win_info->generic.content_size; i++)
211 {
212 struct tui_win_element * element =
213 (struct tui_win_element *) win_info->generic.content[i];
214 element->which_element.source.has_break = FALSE;
215 element->which_element.source.is_exec_point = FALSE;
216 }
217 }
218 }
219
220
221 void
222 tui_erase_source_content (struct tui_win_info * win_info, int display_prompt)
223 {
224 int x_pos;
225 int half_width = (win_info->generic.width - 2) / 2;
226
227 if (win_info->generic.handle != (WINDOW *) NULL)
228 {
229 werase (win_info->generic.handle);
230 tui_check_and_display_highlight_if_needed (win_info);
231 if (display_prompt == EMPTY_SOURCE_PROMPT)
232 {
233 char *no_src_str;
234
235 if (win_info->generic.type == SRC_WIN)
236 no_src_str = NO_SRC_STRING;
237 else
238 no_src_str = NO_DISASSEM_STRING;
239 if (strlen (no_src_str) >= half_width)
240 x_pos = 1;
241 else
242 x_pos = half_width - strlen (no_src_str);
243 mvwaddstr (win_info->generic.handle,
244 (win_info->generic.height / 2),
245 x_pos,
246 no_src_str);
247
248 /* elz: added this function call to set the real contents of
249 the window to what is on the screen, so that later calls
250 to refresh, do display
251 the correct stuff, and not the old image */
252
253 tui_set_source_content_nil (win_info, no_src_str);
254 }
255 tui_refresh_win (&win_info->generic);
256 }
257 }
258
259
260 /* Redraw the complete line of a source or disassembly window. */
261 static void
262 tui_show_source_line (struct tui_win_info * win_info, int lineno)
263 {
264 struct tui_win_element * line;
265 int x, y;
266
267 line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
268 if (line->which_element.source.is_exec_point)
269 wattron (win_info->generic.handle, A_STANDOUT);
270
271 mvwaddstr (win_info->generic.handle, lineno, 1,
272 line->which_element.source.line);
273 if (line->which_element.source.is_exec_point)
274 wattroff (win_info->generic.handle, A_STANDOUT);
275
276 /* Clear to end of line but stop before the border. */
277 getyx (win_info->generic.handle, y, x);
278 while (x + 1 < win_info->generic.width)
279 {
280 waddch (win_info->generic.handle, ' ');
281 getyx (win_info->generic.handle, y, x);
282 }
283 }
284
285 void
286 tui_show_source_content (struct tui_win_info * win_info)
287 {
288 if (win_info->generic.content_size > 0)
289 {
290 int lineno;
291
292 for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
293 tui_show_source_line (win_info, lineno);
294 }
295 else
296 tui_erase_source_content (win_info, TRUE);
297
298 tui_check_and_display_highlight_if_needed (win_info);
299 tui_refresh_win (&win_info->generic);
300 win_info->generic.content_in_use = TRUE;
301 }
302
303
304 /* Scroll the source forward or backward horizontally. */
305 void
306 tui_horizontal_source_scroll (struct tui_win_info * win_info,
307 enum tui_scroll_direction direction,
308 int num_to_scroll)
309 {
310 if (win_info->generic.content != NULL)
311 {
312 int offset;
313 struct symtab *s;
314 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
315
316 if (cursal.symtab == (struct symtab *) NULL)
317 s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
318 else
319 s = cursal.symtab;
320
321 if (direction == LEFT_SCROLL)
322 offset = win_info->detail.source_info.horizontal_offset + num_to_scroll;
323 else
324 {
325 if ((offset =
326 win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0)
327 offset = 0;
328 }
329 win_info->detail.source_info.horizontal_offset = offset;
330 tui_update_source_window_as_is (win_info, s,
331 ((struct tui_win_element *)
332 win_info->generic.content[0])->which_element.source.line_or_addr,
333 FALSE);
334 }
335
336 return;
337 }
338
339
340 /* Set or clear the has_break flag in the line whose line is line_no. */
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
398 has_break 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.source_info;
407
408 for (i = 0; i < win->generic.content_size; 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])->which_element.source;
416 if (current_only && !line->is_exec_point)
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 gdb_assert (line->line_or_addr.loa == LOA_LINE
428 || line->line_or_addr.loa == LOA_ADDRESS);
429 if ((win == TUI_SRC_WIN
430 && bp->source_file
431 && (strcmp (src->filename, bp->source_file) == 0)
432 && line->line_or_addr.loa == LOA_LINE
433 && bp->line_number == line->line_or_addr.u.line_no)
434 || (win == TUI_DISASM_WIN
435 && line->line_or_addr.loa == LOA_ADDRESS
436 && bp->loc->address == line->line_or_addr.u.addr))
437 {
438 if (bp->enable_state == bp_disabled)
439 mode |= TUI_BP_DISABLED;
440 else
441 mode |= TUI_BP_ENABLED;
442 if (bp->hit_count)
443 mode |= TUI_BP_HIT;
444 if (bp->cond)
445 mode |= TUI_BP_CONDITIONAL;
446 if (bp->type == bp_hardware_breakpoint)
447 mode |= TUI_BP_HARDWARE;
448 }
449 }
450 if (line->has_break != mode)
451 {
452 line->has_break = mode;
453 need_refresh = 1;
454 }
455 }
456 return need_refresh;
457 }
458
459
460 /* Function to initialize the content of the execution info window,
461 based upon the input window which is either the source or
462 disassembly window. */
463 enum tui_status
464 tui_set_exec_info_content (struct tui_win_info * win_info)
465 {
466 enum tui_status ret = TUI_SUCCESS;
467
468 if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL)
469 {
470 struct tui_gen_win_info * exec_info_ptr = win_info->detail.source_info.execution_info;
471
472 if (exec_info_ptr->content == NULL)
473 exec_info_ptr->content =
474 (void **) tui_alloc_content (win_info->generic.height,
475 exec_info_ptr->type);
476 if (exec_info_ptr->content != NULL)
477 {
478 int i;
479
480 tui_update_breakpoint_info (win_info, 1);
481 for (i = 0; i < win_info->generic.content_size; i++)
482 {
483 struct tui_win_element * element;
484 struct tui_win_element * src_element;
485 int mode;
486
487 element = (struct tui_win_element *) exec_info_ptr->content[i];
488 src_element = (struct tui_win_element *) win_info->generic.content[i];
489
490 memset(element->which_element.simple_string, ' ',
491 sizeof(element->which_element.simple_string));
492 element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
493
494 /* Now update the exec info content based upon the state
495 of each line as indicated by the source content. */
496 mode = src_element->which_element.source.has_break;
497 if (mode & TUI_BP_HIT)
498 element->which_element.simple_string[TUI_BP_HIT_POS] =
499 (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
500 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
501 element->which_element.simple_string[TUI_BP_HIT_POS] =
502 (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
503
504 if (mode & TUI_BP_ENABLED)
505 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
506 else if (mode & TUI_BP_DISABLED)
507 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
508
509 if (src_element->which_element.source.is_exec_point)
510 element->which_element.simple_string[TUI_EXEC_POS] = '>';
511 }
512 exec_info_ptr->content_size = win_info->generic.content_size;
513 }
514 else
515 ret = TUI_FAILURE;
516 }
517
518 return ret;
519 }
520
521
522 void
523 tui_show_exec_info_content (struct tui_win_info * win_info)
524 {
525 struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
526 int cur_line;
527
528 werase (exec_info->handle);
529 tui_refresh_win (exec_info);
530 for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
531 mvwaddstr (exec_info->handle,
532 cur_line,
533 0,
534 ((struct tui_win_element *)
535 exec_info->content[cur_line - 1])->which_element.simple_string);
536 tui_refresh_win (exec_info);
537 exec_info->content_in_use = TRUE;
538 }
539
540
541 void
542 tui_erase_exec_info_content (struct tui_win_info * win_info)
543 {
544 struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
545
546 werase (exec_info->handle);
547 tui_refresh_win (exec_info);
548 }
549
550 void
551 tui_clear_exec_info_content (struct tui_win_info * win_info)
552 {
553 win_info->detail.source_info.execution_info->content_in_use = FALSE;
554 tui_erase_exec_info_content (win_info);
555
556 return;
557 }
558
559 /* Function to update the execution info window. */
560 void
561 tui_update_exec_info (struct tui_win_info * win_info)
562 {
563 tui_set_exec_info_content (win_info);
564 tui_show_exec_info_content (win_info);
565 }
566
567 enum tui_status
568 tui_alloc_source_buffer (struct tui_win_info *win_info)
569 {
570 char *src_line_buf;
571 int i, line_width, max_lines;
572 enum tui_status ret = TUI_FAILURE;
573
574 max_lines = win_info->generic.height; /* less the highlight box */
575 line_width = win_info->generic.width - 1;
576 /*
577 ** Allocate the buffer for the source lines. Do this only once since they
578 ** will be re-used for all source displays. The only other time this will
579 ** be done is when a window's size changes.
580 */
581 if (win_info->generic.content == NULL)
582 {
583 src_line_buf = (char *) xmalloc ((max_lines * line_width) * sizeof (char));
584 if (src_line_buf == (char *) NULL)
585 fputs_unfiltered (
586 "Unable to Allocate Memory for Source or Disassembly Display.\n",
587 gdb_stderr);
588 else
589 {
590 /* allocate the content list */
591 if ((win_info->generic.content =
592 (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
593 {
594 xfree (src_line_buf);
595 src_line_buf = (char *) NULL;
596 fputs_unfiltered (
597 "Unable to Allocate Memory for Source or Disassembly Display.\n",
598 gdb_stderr);
599 }
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 ret = TUI_SUCCESS;
606 }
607 else
608 ret = TUI_SUCCESS;
609
610 return ret;
611 }
612
613
614 /* Answer whether the a particular line number or address is displayed
615 in the current source window. */
616 int
617 tui_line_is_displayed (int line, struct tui_win_info * win_info,
618 int check_threshold)
619 {
620 int is_displayed = FALSE;
621 int i, threshold;
622
623 if (check_threshold)
624 threshold = SCROLL_THRESHOLD;
625 else
626 threshold = 0;
627 i = 0;
628 while (i < win_info->generic.content_size - threshold && !is_displayed)
629 {
630 is_displayed = (((struct tui_win_element *)
631 win_info->generic.content[i])->which_element.source.line_or_addr.loa
632 == LOA_LINE)
633 && (((struct tui_win_element *)
634 win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no
635 == (int) line);
636 i++;
637 }
638
639 return is_displayed;
640 }
641
642
643 /* Answer whether the a particular line number or address is displayed
644 in the current source window. */
645 int
646 tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info * win_info,
647 int check_threshold)
648 {
649 int is_displayed = FALSE;
650 int i, threshold;
651
652 if (check_threshold)
653 threshold = SCROLL_THRESHOLD;
654 else
655 threshold = 0;
656 i = 0;
657 while (i < win_info->generic.content_size - threshold && !is_displayed)
658 {
659 is_displayed = (((struct tui_win_element *)
660 win_info->generic.content[i])->which_element.source.line_or_addr.loa
661 == LOA_ADDRESS)
662 && (((struct tui_win_element *)
663 win_info->generic.content[i])->which_element.source.line_or_addr.u.addr
664 == addr);
665 i++;
666 }
667
668 return is_displayed;
669 }
670
671
672 /*****************************************
673 ** STATIC LOCAL FUNCTIONS **
674 ******************************************/