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