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