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