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