1 /* TUI display source/assembly window. 2 3 Copyright (C) 1998-2004, 2006-2012 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 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_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, 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 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 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 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 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 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 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 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 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 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 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 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->source_file 466 && (filename_cmp (src->filename, loc->source_file) == 0) 467 && line->line_or_addr.loa == LOA_LINE 468 && loc->line_number == line->line_or_addr.u.line_no) 469 || (win == TUI_DISASM_WIN 470 && line->line_or_addr.loa == LOA_ADDRESS 471 && loc->address == line->line_or_addr.u.addr)) 472 { 473 if (bp->enable_state == bp_disabled) 474 mode |= TUI_BP_DISABLED; 475 else 476 mode |= TUI_BP_ENABLED; 477 if (bp->hit_count) 478 mode |= TUI_BP_HIT; 479 if (bp->loc->cond) 480 mode |= TUI_BP_CONDITIONAL; 481 if (bp->type == bp_hardware_breakpoint) 482 mode |= TUI_BP_HARDWARE; 483 } 484 } 485 } 486 if (line->has_break != mode) 487 { 488 line->has_break = mode; 489 need_refresh = 1; 490 } 491 } 492 return need_refresh; 493 } 494 495 496 /* Function to initialize the content of the execution info window, 497 based upon the input window which is either the source or 498 disassembly window. */ 499 enum tui_status 500 tui_set_exec_info_content (struct tui_win_info *win_info) 501 { 502 enum tui_status ret = TUI_SUCCESS; 503 504 if (win_info->detail.source_info.execution_info 505 != (struct tui_gen_win_info *) NULL) 506 { 507 struct tui_gen_win_info *exec_info_ptr 508 = win_info->detail.source_info.execution_info; 509 510 if (exec_info_ptr->content == NULL) 511 exec_info_ptr->content = 512 (void **) tui_alloc_content (win_info->generic.height, 513 exec_info_ptr->type); 514 if (exec_info_ptr->content != NULL) 515 { 516 int i; 517 518 tui_update_breakpoint_info (win_info, 1); 519 for (i = 0; i < win_info->generic.content_size; i++) 520 { 521 struct tui_win_element *element; 522 struct tui_win_element *src_element; 523 int mode; 524 525 element = (struct tui_win_element *) exec_info_ptr->content[i]; 526 src_element = (struct tui_win_element *) 527 win_info->generic.content[i]; 528 529 memset(element->which_element.simple_string, ' ', 530 sizeof(element->which_element.simple_string)); 531 element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0; 532 533 /* Now update the exec info content based upon the state 534 of each line as indicated by the source content. */ 535 mode = src_element->which_element.source.has_break; 536 if (mode & TUI_BP_HIT) 537 element->which_element.simple_string[TUI_BP_HIT_POS] = 538 (mode & TUI_BP_HARDWARE) ? 'H' : 'B'; 539 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED)) 540 element->which_element.simple_string[TUI_BP_HIT_POS] = 541 (mode & TUI_BP_HARDWARE) ? 'h' : 'b'; 542 543 if (mode & TUI_BP_ENABLED) 544 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+'; 545 else if (mode & TUI_BP_DISABLED) 546 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-'; 547 548 if (src_element->which_element.source.is_exec_point) 549 element->which_element.simple_string[TUI_EXEC_POS] = '>'; 550 } 551 exec_info_ptr->content_size = win_info->generic.content_size; 552 } 553 else 554 ret = TUI_FAILURE; 555 } 556 557 return ret; 558 } 559 560 561 void 562 tui_show_exec_info_content (struct tui_win_info *win_info) 563 { 564 struct tui_gen_win_info *exec_info 565 = win_info->detail.source_info.execution_info; 566 int cur_line; 567 568 werase (exec_info->handle); 569 tui_refresh_win (exec_info); 570 for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++) 571 mvwaddstr (exec_info->handle, 572 cur_line, 573 0, 574 ((struct tui_win_element *) 575 exec_info->content[cur_line - 1])->which_element.simple_string); 576 tui_refresh_win (exec_info); 577 exec_info->content_in_use = TRUE; 578 } 579 580 581 void 582 tui_erase_exec_info_content (struct tui_win_info *win_info) 583 { 584 struct tui_gen_win_info *exec_info 585 = win_info->detail.source_info.execution_info; 586 587 werase (exec_info->handle); 588 tui_refresh_win (exec_info); 589 } 590 591 void 592 tui_clear_exec_info_content (struct tui_win_info *win_info) 593 { 594 win_info->detail.source_info.execution_info->content_in_use = FALSE; 595 tui_erase_exec_info_content (win_info); 596 597 return; 598 } 599 600 /* Function to update the execution info window. */ 601 void 602 tui_update_exec_info (struct tui_win_info *win_info) 603 { 604 tui_set_exec_info_content (win_info); 605 tui_show_exec_info_content (win_info); 606 } 607 608 enum tui_status 609 tui_alloc_source_buffer (struct tui_win_info *win_info) 610 { 611 char *src_line_buf; 612 int i, line_width, max_lines; 613 614 max_lines = win_info->generic.height; /* Less the highlight box. */ 615 line_width = win_info->generic.width - 1; 616 /* 617 * Allocate the buffer for the source lines. Do this only once 618 * since they will be re-used for all source displays. The only 619 * other time this will be done is when a window's size changes. 620 */ 621 if (win_info->generic.content == NULL) 622 { 623 src_line_buf = (char *) 624 xmalloc ((max_lines * line_width) * sizeof (char)); 625 if (src_line_buf == (char *) NULL) 626 { 627 fputs_unfiltered ("Unable to Allocate Memory for " 628 "Source or Disassembly Display.\n", 629 gdb_stderr); 630 return TUI_FAILURE; 631 } 632 /* Allocate the content list. */ 633 if ((win_info->generic.content = 634 (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL) 635 { 636 xfree (src_line_buf); 637 fputs_unfiltered ("Unable to Allocate Memory for " 638 "Source or Disassembly Display.\n", 639 gdb_stderr); 640 return TUI_FAILURE; 641 } 642 for (i = 0; i < max_lines; i++) 643 ((struct tui_win_element *) 644 win_info->generic.content[i])->which_element.source.line = 645 src_line_buf + (line_width * i); 646 } 647 648 return TUI_SUCCESS; 649 } 650 651 652 /* Answer whether a particular line number or address is displayed 653 in the current source window. */ 654 int 655 tui_line_is_displayed (int line, 656 struct tui_win_info *win_info, 657 int check_threshold) 658 { 659 int is_displayed = FALSE; 660 int i, threshold; 661 662 if (check_threshold) 663 threshold = SCROLL_THRESHOLD; 664 else 665 threshold = 0; 666 i = 0; 667 while (i < win_info->generic.content_size - threshold 668 && !is_displayed) 669 { 670 is_displayed = (((struct tui_win_element *) 671 win_info->generic.content[i])->which_element.source.line_or_addr.loa 672 == LOA_LINE) 673 && (((struct tui_win_element *) 674 win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no 675 == (int) line); 676 i++; 677 } 678 679 return is_displayed; 680 } 681 682 683 /* Answer whether a particular line number or address is displayed 684 in the current source window. */ 685 int 686 tui_addr_is_displayed (CORE_ADDR addr, 687 struct tui_win_info *win_info, 688 int check_threshold) 689 { 690 int is_displayed = FALSE; 691 int i, threshold; 692 693 if (check_threshold) 694 threshold = SCROLL_THRESHOLD; 695 else 696 threshold = 0; 697 i = 0; 698 while (i < win_info->generic.content_size - threshold 699 && !is_displayed) 700 { 701 is_displayed = (((struct tui_win_element *) 702 win_info->generic.content[i])->which_element.source.line_or_addr.loa 703 == LOA_ADDRESS) 704 && (((struct tui_win_element *) 705 win_info->generic.content[i])->which_element.source.line_or_addr.u.addr 706 == addr); 707 i++; 708 } 709 710 return is_displayed; 711 } 712 713 714 /***************************************** 715 ** STATIC LOCAL FUNCTIONS ** 716 ******************************************/ 717